@unifydesk/extension-discord
Discord connector — clean rewrite on the current @unifydesk/server SDK. A
standalone process that hosts many connections (one Discord bot token each) and
pairs to the host from the panel.
Layout
src/
server.ts process entry — boots the definition, nothing else
extension.ts the definition (import-safe: manifest, routes, capabilities)
config.ts per-connection fields (identity, scope, policy) — no global level
runtime.ts DiscordConnection — client lifecycle, talking to the host via ctx
discord/
client.ts gateway intents/partials
filters.ts inbound accept/reject (explicit allowlist)
reference.ts account reference (<userId> DM, <userId>:<channelId> channel)
ticket-owner.ts who owns a ticket channel (overwrite → topic → history)
identity.ts role/metadata/scope of a message
media.ts fetch + store attachments (classify by mime)
handlers/
inbound.ts Discord message → host ticket message
outbound.ts host ticket message → Discord (text + files)
Run (dev)
cd extensions/discord
bun install
PORT=3010 bun src/server.ts
On first start it prints a pairing string — paste it in the panel (Extensions → Pair). Then create a connection, set its Bot token + guild/ channel scope, and power it on.
Privileged intents to enable in the Discord Dev Portal: Message Content (+ Presence/Server Members if you later add those features).
Scope (v1)
Inbound DMs + guild channels → tickets (attachments/stickers), outbound text +
file uploads, typing both ways, listGuilds / start_conversation commands.
Deliberately omitted for now (add incrementally): Components V2 rich messages,
reactions, presence-by-user, threads, slash commands.
Tests
bun x rstest run extensions/discord
__tests__/conformance.test.ts runs the SDK's shared lifecycle suite
(runConformance) against a fake host: the connection has to report a status,
stop has to report stopped and stay stopped, a restart must not leave two
live connections, and every command in the manifest must exist on the runtime.
It imports src/extension.ts — the definition, which boots nothing — so the
suite needs no panel and no Discord token.