Repository navigation
Discord
Typed Discord API client for Deno,
Bun, Node.js and Cloudflare Workers, scoped to sending notification messages
into a channel through a channel webhook or the bot REST API, and to
verifying Ed25519-signed interaction webhooks. It needs no Gateway connection,
so it suits alerts and notifications where discord.js would be more than you
need.
Discord supports two structurally different ways to post a message into a channel, and this connect covers both:
-
Webhook mode — a per-channel URL
(
https://discord.com/api/webhooks/{id}/{token}) that needs noAuthorizationheader at all; the id + token embedded in the URL/path is the credential.sendWebhookMessage()callsPOST /webhooks/{id}/{token}. -
Bot mode — a bot token sent as
Authorization: Bot {token}.sendChannelMessage()callsPOST /channels/{channelId}/messages.
A single Discord client is configured for exactly one of these modes —
never both, never neither — validated at construction time. It uses
RESTler for transport and Guardian for runtime request/response
validation.
Your tests don't need to fake HTTP. Have your code take a Discord instance
and pass in a stand-in that returns the shapes from
@tundraconnect/discord/schemas or throws a real DiscordError:
import { DiscordError } from '@tundraconnect/discord/errors';
const outage = new DiscordError('SERVICE_UNAVAILABLE', { status: 503 });
console.log(outage.code);To exercise the client itself against a fake transport, subclass it and
reassign the protected _fetch.
| Topic | Description |
|---|---|
| API | Client configuration and endpoint methods |
| Errors | Error codes and diagnostic metadata |
| Schemas | Public Guardian schemas and inferred types |
Deno:
deno add jsr:@tundraconnect/discordBun:
bunx jsr add @tundraconnect/discordNode.js:
npx jsr add @tundraconnect/discordimport { Discord } from '@tundraconnect/discord';
const client = new Discord({
webhookUrl: 'https://discord.com/api/webhooks/123456789012345678/abcDEF...',
});
// Discord's own default: fire-and-forget, resolves to `undefined`.
await client.sendWebhookMessage({ content: 'Deploy succeeded' });
// Pass `{ wait: true }` to get the created message back.
const message = await client.sendWebhookMessage(
{
content: 'Deploy succeeded',
embeds: [{ title: 'Build #482', color: 0x57f287 }],
},
{ wait: true },
);
console.log(message?.id);import { Discord } from '@tundraconnect/discord';
const client = new Discord({ botToken: 'your-bot-token' });
const message = await client.sendChannelMessage('234567890123456789', {
content: 'Deploy succeeded',
});
console.log(message.id, message.timestamp);import { Discord } from '@tundraconnect/discord';
const client = new Discord({
webhookUrl: 'https://discord.com/api/webhooks/123456789012345678/abcDEF...',
});
export async function onInteraction(req: Request): Promise<void> {
const raw = await req.text(); // text(), never json()
const interaction = await client.verifyWebhook({
payload: raw,
headers: req.headers,
publicKey: 'your-application-public-key',
});
// `interaction` is now trustworthy.
}See API → Webhooks.
MIT. Part of Tundra Connect, typed vendor API clients for Deno, Bun, Node.js and Cloudflare Workers.