Skip re-processing when the same X-GitHub-Delivery id is seen (KV, 300s TTL)
to stop double pushes when both an org and an App webhook target the worker.
Pass ExecutionContext through so dispatch runs via waitUntil instead of a
fire-and-forget that gets frozen. Cache the imported HMAC key per secret.
Replace the App-identity !gh text command with native slash and message
context-menu commands. /gh login|logout link a Discord user to their GitHub
account; /gh comment add|edit|del and the right-click 'GitHub' commands open
a modal and create/edit/delete comments using the user's own OAuth token,
delegating permission checks to GitHub (surfacing 401/403/404). The gateway
registers guild commands on connect and handles interactions in the DO.
Add an admin WebUI (Nuxt static SPA in admin/, served via the ASSETS
binding) for managing routes and viewing send logs. Access is gated by
GitHub OAuth plus an ADMIN_USER_IDS whitelist with cookie sessions
(admin-session.ts). Expose routes/logs CRUD API (admin-routes.ts), add a
discord-link mapping in token-store.ts, and mount admin routes with an
SPA assets fallback in the server.
Gateway is now an opt-in feature (DISCORD_GATEWAY_ENABLED); when disabled,
messages are delivered via the Discord REST API (discord-rest.ts) instead of
the Durable Object. Record per-route delivery results (send-log.ts) for the
WebUI. Configure assets binding, DO sqlite migration and cron trigger.
Remove hardcoded DEFAULT_ROUTES and Config.discord.defaultChannelId so
forwarding is driven entirely by user-defined routes (empty KV = no
forwarding). Add ADMIN_USER_IDS, DISCORD_GATEWAY_ENABLED and ASSETS to Env.