← All @molecule/* packages · App templates

@molecule/api-channel-discord

Provider bond · channel · API (Node) · v1.0.1 · Apache-2.0

Discord channel bond — implements @molecule/api-channel for sendMessage, ed25519 webhook signature verification, and inbound interaction parsing.

npm install @molecule/api-channel-discord

npm · Source on GitHub · Implements @molecule/api-channel

How it works

@molecule/api-channel-discord is a provider bond on the API (Node) side: it implements the channel core interface (@molecule/api-channel) with a concrete vendor or library behind it.

Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.

import { setProvider } from '@molecule/api-channel'
import { provider } from '@molecule/api-channel-discord'

setProvider('discord', provider)

Works with: @molecule/api-channel, @molecule/api-secrets

Secrets: CHANNEL_DISCORD_BOT_TOKEN, CHANNEL_DISCORD_PUBLIC_KEY

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Discord channel bond for molecule.dev.

Implements the {@link ChannelProvider} interface defined by @molecule/api-channel, posting outbound messages via Discord's REST API and verifying inbound interaction webhooks against the application's ed25519 public key.

Quick Start

import { setProvider } from '@molecule/api-channel'
import { provider } from '@molecule/api-channel-discord'

setProvider('discord', provider)

Type

provider

Installation

npm install @molecule/api-channel-discord @molecule/api-channel @molecule/api-secrets discord.js

API

Interfaces

DiscordConfig

Configuration for the Discord channel provider.

Discord uses two distinct credentials:

  • {@link botToken} — used as the Authorization: Bot <token> header for REST calls (sending messages, fetching channels, etc.). Required to send messages.
  • {@link publicKey} — the application's hex-encoded ed25519 public key, used to verify the signature on inbound interaction webhook requests. Required to verify webhooks.

Either credential may be omitted at construction time and supplied via environment variables (CHANNEL_DISCORD_BOT_TOKEN, CHANNEL_DISCORD_PUBLIC_KEY).

interface DiscordConfig {
  /**
   * Bot token for the Discord application. Used as the `Bot <token>`
   * authentication header on REST calls. Defaults to the
   * `CHANNEL_DISCORD_BOT_TOKEN` environment variable.
   */
  botToken?: string

  /**
   * Application public key (hex-encoded ed25519) used to verify inbound
   * interaction webhook signatures. Defaults to the
   * `CHANNEL_DISCORD_PUBLIC_KEY` environment variable.
   */
  publicKey?: string

  /**
   * Optional override for the Discord REST API base URL. Defaults to
   * `https://discord.com/api/v10`. Primarily useful for testing.
   */
  apiBaseUrl?: string

  /**
   * Optional REST client. If provided, the bond delegates message sends to
   * it (e.g. an instance of `discord.js`'s `REST`). When omitted, the bond
   * falls back to a built-in `fetch` implementation. Primarily useful for
   * tests that need to mock the `discord.js` client without having a live
   * dependency.
   */
  rest?: DiscordRestLike

  /**
   * Optional request timeout for built-in REST calls in milliseconds.
   * Defaults to `10000`. Ignored when {@link rest} is supplied.
   */
  timeoutMs?: number
}

DiscordRestLike

Minimal REST-client shape the provider depends on. Compatible with the REST class from discord.js (new REST().setToken(token).post(...)).

interface DiscordRestLike {
  /**
   * Issues a POST request against the Discord REST API at the given route.
   *
   * @param route - REST route relative to the Discord API base (e.g.
   *   `'/channels/123/messages'`).
   * @param options - Request options including a JSON-serialisable body.
   * @returns The parsed JSON response.
   */
  post(route: string, options: { body: unknown }): Promise<unknown>
}

ProcessEnv

Environment variables consumed by the Discord channel provider.

interface ProcessEnv {
  /** Bot token used for REST authentication. */
  CHANNEL_DISCORD_BOT_TOKEN: string
  /** Application public key (hex-encoded) used for webhook verification. */
  CHANNEL_DISCORD_PUBLIC_KEY: string
}

Types

DiscordInteractionType

Discord interaction types relevant to inbound webhook parsing.

Mirrors the subset of Discord's InteractionType enum used by this bond:

  • 1PING (handshake; not converted to an InboundMessage).
  • 2APPLICATION_COMMAND (slash command).
  • 3MESSAGE_COMPONENT (button click, select-menu, etc.).

Any other types (modal submit, autocomplete, …) are passed through as the original payload and treated as an empty inbound message.

type DiscordInteractionType = 1 | 2 | 3 | number

Classes

DiscordChannelProvider

Concrete Discord implementation of {@link ChannelProvider}.

Functions

createProvider(config)

Convenience factory for {@link DiscordChannelProvider}.

function createProvider(config?: DiscordConfig): DiscordChannelProvider
  • config — Optional configuration.

Returns: A configured Discord channel provider.

Constants

channelDiscordSecretDefinitions

Secret definitions required by the Discord channel bond.

const channelDiscordSecretDefinitions: SecretDefinition[]

provider

Lazily-instantiated, default-configured Discord channel provider.

The proxy defers construction until first use so importing this module has no side effects (e.g. consuming env vars at import time).

const provider: ChannelProvider

Core Interface

Implements @molecule/api-channel interface.

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-channel ^1.0.1
  • discord.js ^14.0.0
  • @molecule/api-secrets ^1.0.1

Environment Variables

Runtime Dependencies

  • @molecule/api-channel
  • @molecule/api-secrets
  • discord.js

E2E Tests

Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:

  • Each channel-notifying flow the app defines (a Slack/Discord alert on a new order, a status-change message) actually produces a message. The sandbox CAPTURES channel messages instead of sending — read them with the read_activity tool (filter type 'channel'); never mock the flow or modify production code to expose the message.
  • The captured message targets the configured channel/provider name and carries the app's real content (readable text, no undefined placeholders, no secrets).
  • A failed send (unbonded or misconfigured provider) is visible in logs/UI — never silently swallowed.