Skip to content

feat: add discord service emulator#90

Open
mvanhorn wants to merge 2 commits intovercel-labs:mainfrom
mvanhorn:feat/discord-emulator
Open

feat: add discord service emulator#90
mvanhorn wants to merge 2 commits intovercel-labs:mainfrom
mvanhorn:feat/discord-emulator

Conversation

@mvanhorn
Copy link
Copy Markdown
Contributor

@mvanhorn mvanhorn commented Apr 29, 2026

Summary

Adds a Discord service emulator with stateful guilds, channels, members, roles, and messages, plus full OAuth 2.0 (authorization code flow) and a Message / Guild Inspector. Snowflake IDs match Discord's documented 64-bit format. Both Authorization: Bot <token> and Authorization: Bearer <token> are supported.

Closes the OAuth + REST surface — interactions / signature verification, guild webhooks, and Gateway WebSocket are intentionally separate follow-ups.

Why this matters

Discord has become the community plane for most modern SaaS — community bots, role automation, slash-command integrations, magic-link sign-ins through Discord OAuth. The official discord.js SDK has ~700K weekly npm downloads and @discordjs/rest is in every modern bot stack. CI tests against Discord today either hit production (rate limits, real users, real channels) or stub at the HTTP level. No general-purpose emulator covers Discord — WireMock is too low-level and MSW is browser-only.

emulate's Store gives us stateful guilds + channels + messages; the shared OAuth helpers give us a real authorization_code + Bearer/Bot token flow.

Inspector

Browse seeded guilds, channels, messages, members, and roles. Tabbed navigation, terminal-green aesthetic from core/src/ui.ts.

Discord Inspector

OAuth Consent

Standard /oauth2/authorize flow with a user picker.

Discord OAuth

Discord API Coverage

Method Description
GET /api/v10/users/@me Authenticated user (Bot or Bearer)
GET /api/v10/guilds / POST List and create guilds
GET /api/v10/guilds/:id Get guild
PATCH /api/v10/guilds/:id / DELETE Update / delete guild
GET /api/v10/guilds/:id/channels / POST List / create channels
GET /api/v10/channels/:id / PATCH / DELETE Channel CRUD
GET /api/v10/channels/:id/messages / POST List / send messages
GET /api/v10/channels/:id/messages/:id / PATCH / DELETE Message CRUD
GET /api/v10/guilds/:id/members List members
PUT /api/v10/guilds/:id/members/:userId Add member
PATCH /api/v10/guilds/:id/members/:userId / DELETE Update / remove member
GET /api/v10/guilds/:id/roles / POST List / create roles
PATCH /api/v10/guilds/:id/roles/:roleId / DELETE Role CRUD
GET /oauth2/authorize OAuth consent page (Universal Login style)
POST /api/oauth2/token OAuth token exchange (authorization_code)

Bot tokens

Configure applications in seed config; bot tokens auto-register with the emulator's tokenMap so Authorization: Bot <token> works immediately:

discord:
  applications:
    - id: "123456789012345678"
      client_id: discord-client-id
      client_secret: discord-client-secret
      name: My Discord Bot
      bot_token: discord-bot-token
      redirect_uris: [http://localhost:3000/api/auth/callback/discord]
  users:
    - id: "222222222222222222"
      username: developer
      email: dev@example.com
  guilds:
    - id: "333333333333333333"
      name: My Server
      members:
        - { user_id: "222222222222222222", roles: ["444444444444444444"] }
      roles:
        - { id: "444444444444444444", name: admin, permissions: "8" }
      channels:
        - { id: "555555555555555555", name: general, type: GUILD_TEXT }

Default port

4012 (appended at the end of SERVICE_NAME_LIST after clerk — no other service's port shifts).

What's not yet covered

  • Slash commands + interactions HTTP callback with Ed25519 signature verification (separate PR)
  • Guild webhooks via WebhookDispatcher (separate PR)
  • Gateway WebSocket — most modern Discord bots have migrated to interactions-over-HTTP, so deferring this keeps the diff focused

Tests

35 Vitest tests covering guild / channel / message / member / role CRUD, OAuth code flow, snowflake bit layout, both auth header shapes (Bot and Bearer), inspector rendering, and seed-config token registration.

pnpm --filter @emulators/discord test    # 35 passed
pnpm --filter @emulators/discord build   # passes
pnpm --filter emulate build              # registry integration verified
pnpm format:check                        # passes
pnpm lint                                # passes

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 29, 2026

@mvanhorn is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

@mvanhorn mvanhorn force-pushed the feat/discord-emulator branch from 81d88ae to bd75dd5 Compare April 29, 2026 14:00
@mvanhorn mvanhorn changed the title feat: add Discord emulator (Phase 1) feat: add discord service emulator Apr 29, 2026
Type-check failure on the GitHub Actions build caught a stale 5-arg
seedFromConfig() call in the test. The signature is now 4 args (the
tokenMap parameter moved to a closure captured during plugin.register
to match the slack pattern, see this branch's earlier rebase commit).
Tests still set up tokenMap correctly via the prior register() call --
this is just removing the redundant trailing arg.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant