Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
a1da2d3
feat: REST API layer for web dashboard
BillChirico Feb 17, 2026
8aaa933
fix: use timing-safe comparison for API secret validation
BillChirico Feb 17, 2026
baed233
fix: use safeSend for mention sanitization and validate content length
BillChirico Feb 17, 2026
d57908d
fix: filter sensitive data from config endpoints
BillChirico Feb 17, 2026
77e8c1f
fix: only send CORS preflight 204 when DASHBOARD_URL is configured
BillChirico Feb 17, 2026
5b45bd1
fix: close orphaned server before starting a new one
BillChirico Feb 17, 2026
ba57163
fix: use cursor-based pagination for guild members endpoint
BillChirico Feb 17, 2026
2b0e545
fix: hide detailed memory usage behind auth on health endpoint
BillChirico Feb 17, 2026
021e1be
fix: prevent REST API startup failure from crashing the bot
BillChirico Feb 17, 2026
0b9a7ba
fix: scope conversations stats query to guild channels
BillChirico Feb 17, 2026
79de322
fix: restore fake timers in afterEach to prevent test pollution
BillChirico Feb 17, 2026
5ba0753
fix: centralize vi.unstubAllEnvs in afterEach for server tests
BillChirico Feb 17, 2026
bbbcb47
fix: scope conversations stats query to guild channel IDs
BillChirico Feb 17, 2026
caf1e52
fix: remove redundant content length validation in sendMessage action
BillChirico Feb 17, 2026
ab16588
fix: return sent message content instead of echoing request body
BillChirico Feb 17, 2026
83637d0
fix: add destroy method to rate limiter for interval cleanup
BillChirico Feb 17, 2026
96a87bc
fix: remove DELETE from CORS allowed methods
BillChirico Feb 17, 2026
58e7037
fix: move discord WebSocket details behind auth on health endpoint
BillChirico Feb 17, 2026
4445a24
fix: centralize vi.unstubAllEnvs in afterEach for health tests
BillChirico Feb 17, 2026
8685bcb
fix: add guild_id column to conversations table for guild-scoped queries
BillChirico Feb 17, 2026
f83b0ac
fix: harden server startup and shutdown in server.js
BillChirico Feb 17, 2026
8300a21
fix: validate Discord message content length (2000 char limit)
BillChirico Feb 17, 2026
bcb1fcf
fix: avoid reflecting user input in action error response
BillChirico Feb 17, 2026
319654a
fix: remove 'logging' from SAFE_CONFIG_KEYS in guilds route
BillChirico Feb 17, 2026
ee2e84c
fix: handle CORS preflight without DASHBOARD_URL
BillChirico Feb 17, 2026
255145e
refactor: extract shared isValidSecret helper, use in health route
BillChirico Feb 17, 2026
a9dd4ae
refactor: use shared isValidSecret helper in health route
BillChirico Feb 17, 2026
4aad93e
fix: guard against undefined req.body in actions endpoint
BillChirico Feb 17, 2026
7a4d6be
fix: raise content length limit to 10000 chars in actions endpoint
BillChirico Feb 17, 2026
bbc780d
style: fix chain formatting in health tests
BillChirico Feb 17, 2026
ab8f6b4
refactor: add isValidSecret helper to auth middleware
BillChirico Feb 17, 2026
118bdd9
fix: add ALTER TABLE migration for guild_id column in conversations
BillChirico Feb 17, 2026
79851a1
fix: prevent moderation config writes via PATCH endpoint
BillChirico Feb 17, 2026
501918f
fix: guard against undefined req.body in PATCH config endpoint
BillChirico Feb 17, 2026
d68f669
docs: note parsePagination is only used by moderation endpoint
BillChirico Feb 17, 2026
86fc94c
fix: only send CORS preflight when DASHBOARD_URL is configured
BillChirico Feb 17, 2026
f821367
fix: destroy rate limiter on server shutdown
BillChirico Feb 17, 2026
35d7ae9
Merge remote-tracking branch 'origin/feat/rest-api-batch-b' into feat…
BillChirico Feb 17, 2026
c542737
Merge branch 'main' into feat/rest-api
BillChirico Feb 17, 2026
e75ddcb
fix: remove DELETE from CORS Allow-Methods and set header on all resp…
BillChirico Feb 17, 2026
134de65
fix: wrap ALTER TABLE guild_id backfill in try-catch for PG < 9.6
BillChirico Feb 17, 2026
75c4665
fix: document NULL guild_id caveat on stats conversations query
BillChirico Feb 17, 2026
24c3751
fix: extract content length limit to named constant
BillChirico Feb 17, 2026
b1a42d5
fix: sanitize mentions in API sendMessage before calling safeSend
BillChirico Feb 17, 2026
b9989e7
fix: clarify config endpoint is global scope, not per-guild
BillChirico Feb 17, 2026
9b781bf
fix: reject single-segment config paths in PATCH endpoint
BillChirico Feb 17, 2026
6a93df6
fix: destroy leaked rate limiter on repeated createApp calls
BillChirico Feb 17, 2026
17f2048
chore: apply biome formatting fixes
BillChirico Feb 17, 2026
42a64c6
fix: remove redundant sanitizeMentions in actions route
BillChirico Feb 17, 2026
dedb6f1
docs: update JSDoc return type to include destroy method
BillChirico Feb 17, 2026
c59722f
fix: cap channel list in guild info response
BillChirico Feb 17, 2026
69d1e85
fix: guard guild_id index creation against missing column
BillChirico Feb 17, 2026
be78c27
docs: add API files to AGENTS.md Key Files table
BillChirico Feb 17, 2026
661cf4b
fix: use explicit columns in moderation query
BillChirico Feb 17, 2026
2435e64
test: assert capped limit forwarded to guild.members.list
BillChirico Feb 17, 2026
1adb144
test: use vi.stubEnv instead of delete process.env
BillChirico Feb 17, 2026
0d9a8a5
fix(api): pass through error status codes in global error handler
BillChirico Feb 17, 2026
1fc69e7
fix(api): reset server variable on listen failure
BillChirico Feb 17, 2026
58c889a
fix(api): use err.status only for valid 4xx codes in error handler
BillChirico Feb 17, 2026
557b5f4
fix(api): use Buffer.byteLength for timingSafeEqual guard
BillChirico Feb 17, 2026
3194071
fix(db): ensure guild_id index is always created
BillChirico Feb 17, 2026
e8af0b2
fix(api): move CORS middleware before body parser
BillChirico Feb 17, 2026
6166a1f
fix(api): validate BOT_API_PORT range (0-65535)
BillChirico Feb 17, 2026
20897d6
fix(api): use once() for server startup error listener
BillChirico Feb 17, 2026
ba19613
fix(api): add timeout and force-close to prevent server.close() hanging
BillChirico Feb 17, 2026
fafb83d
fix(api): add string type check for message content
BillChirico Feb 17, 2026
b7ded26
fix(api): set CORS allow-headers on all responses not just preflight
BillChirico Feb 17, 2026
f382875
fix(api): limit channel iteration instead of materializing full array
BillChirico Feb 17, 2026
baccd88
docs: update README to reflect new REST API server
BillChirico Feb 17, 2026
d12272b
fix(api): add trust proxy configuration for rate limiting behind reve…
BillChirico Feb 17, 2026
f41bf18
fix: address round 5 review comments
BillChirico Feb 17, 2026
5255c94
fix: address round 6 review nitpicks
BillChirico Feb 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,20 @@ NEXTAUTH_SECRET=your_nextauth_secret
# Docker Compose overrides this to http://localhost:3000 automatically.
NEXTAUTH_URL=http://localhost:3000

# Bot REST API port (optional — default: 3001)
BOT_API_PORT=3001

# Bot API URL for web dashboard → bot communication (required for web dashboard)
# Not yet implemented — the bot does not expose an HTTP API yet (see Issue #29).
# Docker Compose overrides this when the bot API is available.
# BOT_API_URL=http://localhost:3001
BOT_API_URL=http://localhost:3001

# Shared secret for bot ↔ web dashboard API authentication
# Required when running the web dashboard.
BOT_API_SECRET=your_bot_api_secret

# Dashboard URL for CORS origin (required for web dashboard)
DASHBOARD_URL=http://localhost:3000

# Discord client ID exposed to browser (required for web dashboard)
NEXT_PUBLIC_DISCORD_CLIENT_ID=your_discord_client_id

Expand Down
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
| `src/modules/moderation.js` | Moderation — case creation, DM notifications, mod log embeds, escalation, tempban scheduler |
| `src/modules/config.js` | Config loading/saving (DB + file), runtime updates |
| `src/modules/events.js` | Event handler registration (wires modules to Discord events) |
| `src/api/server.js` | Express API server setup (createApp, startServer, stopServer) |
| `src/api/index.js` | API route mounting |
| `src/api/routes/guilds.js` | Guild REST API endpoints (info, config, stats, members, moderation, actions) |
| `src/api/middleware/auth.js` | API authentication middleware |
| `src/api/middleware/rateLimit.js` | Rate limiting middleware |
| `src/utils/errors.js` | Error classes and handling utilities |
| `src/utils/health.js` | Health monitoring singleton |
| `src/utils/permissions.js` | Permission checking for commands |
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,13 +371,13 @@ Set these in the Railway dashboard for the Web Dashboard service:

### Private Networking

Railway services within the same project can communicate over a private internal network. When the bot exposes an HTTP API (planned), the Web Dashboard will reach it at:
Railway services within the same project can communicate over a private internal network. The bot exposes a REST API server, and the Web Dashboard reaches it at:

```text
http://bot.railway.internal:<PORT>
```

> **Note:** The bot does not currently expose an HTTP API server — it connects to Discord via WebSocket only. `BOT_API_URL` is used by the web dashboard to query bot state; this feature requires the bot API to be implemented first.
> **Note:** The bot exposes a REST API server on `BOT_API_PORT` (default `3001`) alongside its Discord WebSocket connection. `BOT_API_URL` is used by the web dashboard to query bot state.

### Slash Command Registration

Expand Down Expand Up @@ -444,7 +444,7 @@ docker compose up --build

| Service | URL | Description |
|---------|-----|-------------|
| **bot** | — (internal) | Discord bot, no HTTP server |
| **bot** | `localhost:3001` | Discord bot with REST API server (`BOT_API_PORT`) |
| **db** | `localhost:5432` | PostgreSQL 17, user: `postgres`, password: `postgres`, database: `billsbot` |
| **web** | `localhost:3000` | Next.js web dashboard (requires `--profile full`) |

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"dependencies": {
"discord.js": "^14.25.1",
"dotenv": "^17.3.1",
"express": "^5.2.1",
"mem0ai": "^2.2.2",
"pg": "^8.18.0",
"winston": "^3.19.0",
Expand All @@ -36,6 +37,7 @@
"devDependencies": {
"@biomejs/biome": "^2.4.0",
"@vitest/coverage-v8": "^4.0.18",
"supertest": "^7.2.2",
"vitest": "^4.0.18"
}
}
Loading
Loading