Discord bot built with Carbon on Cloudflare Workers.
@buape/carbon- Cloudflare Workers (
@buape/carbon/adapters/fetch) - Gateway forwarding:
forwarder/Bun process usingGatewayForwarderPlugin - Cloudflare D1 + Drizzle ORM
- Install deps:
bun install- Create
.envfrom.env.example.
Required:
BASE_URL=
DEPLOY_SECRET=
DISCORD_CLIENT_ID=
DISCORD_PUBLIC_KEY=
DISCORD_BOT_TOKEN=Optional:
DISCORD_DEV_GUILDS=
FORWARDER_PUBLIC_KEY=
ANSWER_OVERFLOW_API_KEY=
HELPER_THREAD_WELCOME_PARENT_ID=
HELPER_THREAD_WELCOME_TEMPLATE=
THREAD_LENGTH_CHECK_INTERVAL_HOURS=- Configure
wrangler.jsoncD1 binding:
- set
d1_databases[0].database_idto your real D1 database id - keep
binding = "DB"
- Apply D1 migrations:
bun run db:apply:local
# or
bun run db:apply:remote- Run locally:
bun run devbun run dev→wrangler dev --env-file .envbun run deploy→ deploy worker locally with.envbun run deploy:cf→ apply remote D1 migrations, then deploy Worker for Cloudflare Buildsbun run deploy:dry-run→ validate the Worker bundle without deployingbun run cf-typegen→ regenerateworker-configuration.d.tsbun run typecheck→ TypeScript checkbun run db:generate→ generate Drizzle SQLbun run db:apply:local/db:apply:remote→ apply D1 migrations
Cloudflare Workers Builds deploys pushes to main. The deploy command should apply D1 migrations before deploying the Worker:
bun run deploy:cfDrizzle only generates SQL migrations. Wrangler applies them to D1:
bun run db:generate
bun run db:apply:remoteThe main bot runs as a Cloudflare Worker. Gateway events are forwarded by the Bun app in forwarder/, usually running on Krill's machine.
Forwarder setup:
cd forwarder
bun install
bun run devForwarder production start:
cd forwarder
bun run startForwarder env:
BASE_URL=
DEPLOY_SECRET=
DISCORD_CLIENT_ID=
DISCORD_PUBLIC_KEY=
DISCORD_BOT_TOKEN=
FORWARDER_PRIVATE_KEY=The Worker must have the matching public key:
bunx wrangler secret put FORWARDER_PUBLIC_KEY- Answer Overflow base URL is hardcoded to
https://www.answeroverflow.com. - Helper thread monitor runs via Worker cron (
wrangler.jsonctriggers.crons). - The old Cloudflare Gateway Durable Object path is not the active gateway setup.