@thunderclapjs/client

thunderclapJS, for browsers, React Native, Node.js 22+, Deno and Bun. No dependencies. Install it with npm install @thunderclapjs/client.

Thunderclap

The client. It connects to Thunderclap, keeps subscriptions alive across reconnects and reports gaps so your app can backfill from its own store.

constructornew Thunderclap

Creates a client and, unless autoConnect is false, connects right away.

new Thunderclap(options: ThunderclapOptions)

Parameters

  • keystringrequired

    Your app's public key.

  • tokenstring | (() => Promise<string>)

    A connection token granting private and presence channels up front, or a function fetching a fresh one on every connect.

  • authorize(input: { channel, socketId }) => Promise<string>

    Fetches a token for one private or presence channel the connection token doesn't cover. Called only when a subscription is refused.

  • autoConnectbooleandefault true

    Connect immediately.

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

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

  • reconnect.minDelayMsnumberdefault 500

    Base delay of the exponential backoff (with full jitter).

  • reconnect.maxDelayMsnumberdefault 30000

    Backoff ceiling.

  • pongTimeoutMsnumberdefault 15000

    How long to wait for a pong before considering the connection dead.

  • WebSocketWebSocketFactory

    WebSocket implementation, for runtimes without a global one.

Example

const thunderclap = new Thunderclap({
  key: process.env.NEXT_PUBLIC_THUNDERCLAP_KEY,
  token: () => fetch("/api/realtime-token").then((r) => r.text()),
});

methodsubscribe

Subscribes to a channel, or returns the existing subscription. Subscriptions are restored after every reconnect. presence-* channels return a PresenceChannel.

subscribe<Events, Info>(name: string): Channel<Events> | PresenceChannel<Events, Info>

Parameters

  • namestringrequired

    Channel name.

Returns

The channel.

Example

const room = thunderclap.subscribe<{ message: { text: string } }>("room-42");

methodunsubscribe

Unsubscribes from a channel and forgets it.

unsubscribe(name: string): void

Parameters

  • namestringrequired

    Channel name.

methodchannel

Finds an existing subscription without creating one.

channel<Events>(name: string): Channel<Events> | undefined

Parameters

  • namestringrequired

    Channel name.

Returns

The channel, or undefined when not subscribed.

methodconnect

Connects, or reconnects now if a reconnect is pending. Does nothing while connecting or connected. Needed after autoConnect: false or disconnect().

connect(): void

methoddisconnect

Closes the connection and stops reconnecting. Subscriptions are kept for the next connect().

disconnect(): void

methodon

Listens to connection events.

on(event: "state" | "error", listener): () => void

Events

EventListenerDescription
state({ previous, current }: StateChange) => voidThe connection state changed: initialized, connecting, connected, reconnecting, closed or failed.
error({ code, message }: ThunderclapError) => voidA connection-level error, such as a rejected key or token. See error codes.

Returns

A function removing the listener.

propertystate

The current connection state.

readonly state: ConnectionState

propertysocketId

The current connection's id, null while not connected. Send it to your server and pass it as exclude to skip this client when publishing.

readonly socketId: string | null

Channel

A subscription, returned by subscribe. It survives reconnects.

methodbind

Listens to one event. meta carries the event name, the channel and its sequence seq; for client events, seq is null and userId names the sender on presence channels.

bind<K>(event: K, listener: (data: Events[K], meta: EventMeta) => void): () => void

Parameters

  • eventstringrequired

    Event name.

  • listener(data, meta) => voidrequired

    Called with each event.

Returns

A function removing the listener.

methodbindAll

Listens to every event on the channel.

bindAll(listener: (event: string, data: unknown, meta: EventMeta) => void): () => void

Returns

A function removing the listener.

methodtrigger

Sends a client event to the channel's other subscribers. The name must start with client-, the channel must be private or presence, and client events must be enabled for the app.

trigger<K>(event: K, data: Events[K]): boolean

Parameters

  • eventstringrequired

    Event name, starting with client-.

  • dataunknownrequired

    JSON-serializable data, up to 10 KB.

Returns

true when sent, false when the channel isn't subscribed or can't carry client events. Refusals by the server arrive as error events (code 4306).

methodonGap

Called when events may have been missed: { from, to } for a range of sequences, or { reset: true } when the channel's counter restarted.

onGap(listener: (gap: Gap) => void): () => void

Returns

A function removing the listener.

methodon

Listens to the subscription's status.

on(event: "subscribed" | "error" | "gap" | "cache_miss", listener): () => void

Events

EventListenerDescription
subscribed() => voidThe server confirmed the subscription, again after each reconnect.
error({ code, message }: ChannelError) => voidThe subscription was refused or failed, or a client event was refused.
gap(gap: Gap) => voidSame as onGap.
cache_miss() => voidCache channels: nothing is cached, so your server may publish a fresh value.

Returns

A function removing the listener.

propertyname

The channel's name.

readonly name: string

propertysubscribed

Whether the server confirmed the subscription on the current connection.

readonly subscribed: boolean

propertylastSeq

The last sequence received, null before the first event or confirmation.

readonly lastSeq: [epoch: number, n: number] | null

PresenceChannel

A subscription to a presence-* channel: everything a Channel does, plus who is subscribed. A user connected from several devices is one member.

propertymembers

Current members keyed by user id, the subscriber included. Empty until the first confirmation, and kept as last known while reconnecting.

readonly members: ReadonlyMap<string, Member<Info>>

Fields

  • idstring

    The user id, from the token's uid.

  • infoInfo | undefined

    Public user info, from the token's info.

propertyme

The subscriber's own member entry, null before the first confirmation.

readonly me: Member<Info> | null

methodon

Listens to status events, like Channel.on, and to membership changes.

on(event: "member_added" | "member_removed" | ChannelEvent, listener): () => void

Events

EventListenerDescription
member_added(member: Member<Info>) => voidA user joined, including joins missed while reconnecting.
member_removed(member: Member<Info>) => voidA user's last connection left.

Returns

A function removing the listener.