mirror of
https://github.com/marceloeatworld/discord-bridge.git
synced 2026-10-27 20:41:10 +00:00
Discord Gateway bridge for ClopinetteAI — forwards messages to Cloudflare Workers via HMAC-signed HTTP. Bun, Docker, ~180 lines.
https://clopinette.app
- TypeScript 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Root cause: Invalid Session (op 9) scheduled its own connect() AND the subsequent WS close event scheduled another — two reconnect paths racing endlessly. Each one killed the other's fresh connection, accumulating stale heartbeat timers that spammed "not ACKed" forever. Changes: - Single reconnect path: op 7/9/zombie all close the WS, only the close handler calls scheduleReconnect() — no more dual-connect races - scheduleReconnect() deduplicates (refuses if timer already pending) - All timers (heartbeat jitter, interval, reconnect) tracked and cleared atomically in clearAllTimers() on every connect() - heartbeatAcked reset to true on new connections (prevents instant zombie detection on fresh WS) - send() guards readyState === OPEN (prevents InvalidStateError crash) - Custom close code 4900 for self-initiated reconnects (close handler ignores these to avoid double-scheduling) - Unhandled exception/rejection handlers prevent silent process death |
||
| docker-compose.yml | ||
| index.ts | ||
| README.md | ||
Discord Gateway Bridge
Lightweight bridge that connects to the Discord Gateway WebSocket and forwards messages to a ClopinetteAI worker via HTTP.
Discord requires a persistent WebSocket connection (Gateway) to receive regular messages — there is no webhook push like Telegram or WhatsApp. This bridge maintains that connection and forwards MESSAGE_CREATE events to the Clopinette worker.
How it works
Discord Gateway (WSS)
|
v
Bridge (Bun, ~180 lines)
| - Maintains WebSocket + heartbeat
| - Handles reconnect/resume
| - Filters: DMs forwarded directly,
| guilds only on @mention or reply
|
v (HTTP POST, HMAC-SHA256 signed)
Clopinette Worker (/webhook/discord-bridge)
|
v
Durable Object (per-user or per-guild)
Security
- HMAC-SHA256 signature over
timestamp + body— the shared secret never transits in the request - Anti-replay — worker rejects requests older than 5 minutes
- Timing-safe comparison on the worker side
- No public ports — the bridge only initiates outbound connections (Discord WSS + Worker HTTPS)
- Health check returns only
okordisconnected, no sensitive data
Setup
1. Deploy the Clopinette worker
Follow the core setup to configure Discord secrets and register slash commands:
# In clopinette-ai-dev/
wrangler secret put DISCORD_TOKEN
wrangler secret put DISCORD_PUBLIC_KEY
wrangler secret put DISCORD_APPLICATION_ID
bun run deploy
# Register slash commands + generate bridge secret
curl -X POST https://your-worker/api/admin/setup-discord \
-H "Authorization: Bearer YOUR_API_AUTH_KEY"
# → returns { bridgeSecret, interactionsUrl, bridgeUrl }
2. Deploy the bridge
Set these environment variables on your Docker host (Coolify, etc.):
| Variable | Description |
|---|---|
DISCORD_TOKEN |
Bot token from Discord Developer Portal |
BRIDGE_SECRET |
From the setup-discord response above |
WORKER_URL |
Your worker URL, e.g. https://agent.clopinette.app |
docker compose up -d
3. Discord Developer Portal
- Bot tab → enable Message Content Intent
- General Information → set Interactions Endpoint URL to
https://your-worker/webhook/discord - OAuth2 → URL Generator → scopes
bot+applications.commands, permissions: View Channels, Send Messages, Embed Links, Attach Files, Read Message History, Add Reactions, Use Slash Commands
Behavior
| Context | Trigger | Response |
|---|---|---|
| DM | Any message | Forwarded to worker |
| Server | @mention or reply to bot | Forwarded to worker |
| Server | Regular message | Ignored |
| Any | Bot messages | Ignored |
Gateway features
- Heartbeat with ACK tracking (zombie connection detection)
- Automatic reconnect with exponential backoff (max 30s)
- Session resume on disconnect (no message loss)
- Graceful shutdown on SIGTERM/SIGINT
Requirements
- Bun runtime (via
oven/bun:1-slimDocker image) - A running ClopinetteAI worker with Discord secrets configured
License
MIT