Learn · Publish and subscribe

Subscriptions

Give each consumer an authorized selection, ordered handlers, and its own lifetime.

A subscription is one consumer's authorized view of room history. It selects records, invokes handlers in order, and tracks a processed cursor. Give a transcript, work panel, and activity feed separate subscriptions when they need independent progress or lifetimes.

Select an authorized view

TypeScript
// room is the shared RoomClient; applyMessage is your async reducer.
const transcript = room.subscribe({
  id: "transcript-view",
  selector: {
    channelIds: ["chat", "support"],
    channelTypes: ["text"],
    eventTypes: ["text.message.*"],
  },
  afterSeq: 0,
  onEvent: event => applyMessage(event),
});

Values inside one dimension combine with OR. Dimensions combine with AND. This selection admits a matching message in either topic, provided that topic has type text and the participant may read the event. Empty dimensions impose no restriction.

Channel IDs and types match exactly. Event types accept exact values or a trailing * prefix. Selection narrows access; it never overrides grants or visibility. room.channel("chat").subscribe(...) is a shortcut for a channel-only selection. Use room.subscribe() to combine channel and event-type filters.

Complete work before advancing

RMC reads after the exclusive afterSeq position and continues with new commits. The SDK awaits each onEvent before processing the next callback for this subscription. Its cursor advances only after successful completion. Ordered checkpoints also advance past records the consumer does not see.

The room contains chat at sequence 41, filtered vision at 42, hidden private data at 43, chat at 44, and filtered work at 45. The consumer processes events 41 and 44, then checkpoint 45. It can resume after 45 without rescanning hidden history.
A checkpoint advances through scanned history after earlier visible events are processed.Open SVG ↗Excalidraw source ↓

Return or await the promise for your application work. Starting an untracked asynchronous write and returning immediately lets progress advance before that write finishes. An external side effect still needs its own duplicate policy; see cursors.

Own the consumer lifetime

Call transcript.close() when its view ends, or pass an AbortSignal at creation. This closes only that subscription. Other consumers on the same handle continue.

An application handler failure or a pending-queue overflow closes the affected subscription at its last processed cursor. Recover explicitly by creating a new subscription after fixing the cause. A transient socket error has different behavior: the SDK reconnects and restores active consumers. Read the recovery table.

A subscription ID identifies a local handle. It is not a server-persisted checkpoint or a consumer-group name. Continue with multiplexing, selector.go, subscription.go, and SDK stream tests.

Search the documentation

Type to search all guides.

Diagram

100%Open original ↗