@thunderclapjs/server

For your backend: anything with fetch and Web Crypto, including Node.js 22+ and edge runtimes. No dependencies. Install it with npm install @thunderclapjs/server.

ThunderclapServer

Server-side access to one app: publish events, mint client tokens and verify webhooks.

constructornew ThunderclapServer

Creates an SDK instance for one app.

new ThunderclapServer(options: ThunderclapServerOptions)

Parameters

  • appIdstringrequired

    The app id (THUNDERCLAP_APP_ID).

  • secretstringrequired

    An active secret of the app (THUNDERCLAP_SECRET). Keep it on your server.

  • urlstringdefault "https://realtime.thunderclap.dev"

    The Thunderclap endpoint. Set it only for a custom domain.

  • fetchtypeof fetch

    Fetch implementation; the global one by default.

Example

const thunderclap = new ThunderclapServer({
  appId: process.env.THUNDERCLAP_APP_ID,
  secret: process.env.THUNDERCLAP_SECRET,
});

methodpublish

Publishes one event to one or more channels. Fan-out to subscribers is free.

publish(input: PublishInput): Promise<PublishResult>

Parameters

  • channelstring | string[]required

    One channel, or up to 100 to publish the same event to.

  • eventstring

    Event name, up to 200 characters. Defaults to message.

  • dataunknownrequired

    JSON-serializable data, up to 10 KB.

  • excludestring

    A client's socketId to skip, typically the one that triggered the event.

Returns

{ seq }: the sequence the event got on each channel, as { [channel]: [epoch, n] }. Store it with your copy of the message.

Throws

ThunderclapApiError when the request is refused.

Example

const { seq } = await thunderclap.publish({ channel: "room-42", data: { text: "Hi" } });

methodbatch

Publishes up to 10 events in one request, in order. Cheaper than separate publishes.

batch(events: BatchEvent[]): Promise<BatchResult>

Parameters

  • eventsArray<{ channel, event?, data, exclude? }>required

    The events, each to a single channel. event defaults to message.

Returns

{ results }: one { seq } per event, in order.

Throws

ThunderclapApiError when the request is refused.

methodtoken

Mints a token: a connection token for thunderclapJS's token option, or a per-channel token for its authorize callback.

token(options?: TokenOptions): Promise<string>

Parameters

  • uidstring

    User id. Required to join presence channels, where it identifies the member.

  • infounknown

    Public user info shown to the other members of presence channels, up to 1 KB as JSON.

  • channelsstring[]

    Channel grants: exact names, or prefixes ending in * (private-team-7-*).

  • ttlSecondsnumberdefault 3600

    Lifetime. Tokens are checked at connect and subscribe time only.

Returns

The signed token.

Throws

RangeError when info is over 1 KB.

Example

const token = await thunderclap.token({ uid: user.id, channels: [`private-user-${user.id}`] });

methodverifyWebhook

Verifies a webhook request and returns its events. Requests are signed with every active secret, so this works with whichever one the instance holds, also during a rotation.

verifyWebhook(input: VerifyWebhookInput): Promise<WebhookPayload>

Parameters

  • bodystring | Uint8Arrayrequired

    The raw body, exactly as received: parsing and re-serializing it breaks the signature.

  • signaturestring | null | undefinedrequired

    The Thunderclap-Signature header.

  • toleranceSecondsnumberdefault 300

    Oldest signature accepted, against replayed requests.

Returns

The payload: { app, events }, each event with a unique id for deduplication.

Throws

ThunderclapWebhookError when the signature is missing, wrong or too old, or the app differs.

methodverifyWebhookRequest

Verifies a webhook delivered as a standard Request (Next.js route handlers, Workers, Bun, Deno), reading its body and signature header.

verifyWebhookRequest(request: Request): Promise<WebhookPayload>

Returns

The payload, like verifyWebhook.

Throws

ThunderclapWebhookError, like verifyWebhook.

ThunderclapApiError

Thrown when the REST API refuses a request.

propertystatus

The HTTP status: 400 for invalid input, 401 for a wrong secret or a suspended app.

readonly status: number

ThunderclapWebhookError

Thrown by verifyWebhook and verifyWebhookRequest when a request isn't a valid, recent one from Thunderclap for this app. Answer such requests with 401.

Constants

Values exported by the package.

constantWEBHOOK_SIGNATURE_HEADER

The header carrying a webhook request's signature.

const WEBHOOK_SIGNATURE_HEADER = "Thunderclap-Signature"