SDK

SDK Overview

Client SDK for browser and Node.js — subscribe to topics, manage documents, and send messages.

The Realtime Platform SDK (@smarterservices/realtime) provides a unified client for all three platform services: domain subscriptions, sync documents, and socket messaging.

Installation

npm install @smarterservices/realtime

Quick Start

import { RealtimeClient } from '@smarterservices/realtime';

const realtime = new RealtimeClient({
  url: 'http://localhost:3000',
  token: 'your-jwt-token',
});

// Subscribe to a domain topic
const subId = realtime.subscribe({ topic: 'session.status' });

// Listen for events
realtime.on('event', (event) => {
  console.log('Received:', event.topic, event.payload);
});

// Topic-specific listener
realtime.on('event:session.status', (event) => {
  console.log('Session update:', event.payload);
});

Constructor

new RealtimeClient(options: RealtimeClientOptions)

RealtimeClientOptions

OptionTypeRequiredDefaultDescription
urlstringYesBackend API base URL (e.g. "http://localhost:3000")
tokenstringYesJWT authentication token used for the WebSocket handshake and API requests
autoConnectbooleanNotrueIf true, the client connects immediately on construction. Set to false to connect manually via connect()
reconnectionbooleanNotrueEnable automatic reconnection on disconnect
reconnectionAttemptsnumberNo10Maximum number of reconnection attempts before giving up
reconnectionDelaynumberNo1000Base delay in milliseconds between reconnection attempts
const realtime = new RealtimeClient({
  url: 'http://localhost:3000',
  token: 'your-jwt-token',
  autoConnect: false,           // Don't connect until we call connect()
  reconnection: true,
  reconnectionAttempts: 20,
  reconnectionDelay: 2000,
});

realtime.connect(); // Connect manually

Service Accessors

The client exposes two sub-clients as read-only properties:

PropertyTypeDescription
realtime.syncSyncClientDocument CRUD with revision tracking — see Sync Client
realtime.socketClientSocketClientChannel messaging and direct messages — see Socket Client

Methods

connect()

Open the WebSocket connection. Called automatically unless autoConnect is false.

connect(): void

Returns: void — sets the connection state to 'connecting'.

realtime.connect();

disconnect()

Close the WebSocket connection. Does not clear subscriptions — they are re-established on reconnect.

disconnect(): void

Returns: void — sets the connection state to 'disconnected'.

realtime.disconnect();

subscribe(options)

Subscribe to a domain topic. Events matching the topic (and optional filter) are delivered to your event listeners. Subscriptions are automatically re-established after reconnection.

subscribe(options: SubscribeOptions): string
ParameterTypeRequiredDescription
optionsSubscribeOptionsYesSubscription configuration object (see below)

SubscribeOptions:

FieldTypeRequiredDescription
topicstringYesDomain topic to subscribe to (e.g. "session.status", "order.updated")
filterSubscriptionFilterNoKey-value filter — only events whose payload matches the filter are delivered. Supports equality and in operators

Returns: string — a unique subscription ID (e.g. "sub_1") used to unsubscribe later.

// Simple subscription
const subId = realtime.subscribe({ topic: 'session.status' });

// With a filter — only receive events where campusId = 12
const filtered = realtime.subscribe({
  topic: 'session.status',
  filter: { campusId: 12 },
});

unsubscribe(subscriptionId)

Remove a subscription by its ID. The server stops delivering events for this subscription.

unsubscribe(subscriptionId: string): void
ParameterTypeRequiredDescription
subscriptionIdstringYesThe subscription ID returned by subscribe()

Returns: void

realtime.unsubscribe('sub_1');

on(event, handler)

Register an event listener.

on(event: string, handler: EventHandler): void
ParameterTypeRequiredDescription
eventstringYesEvent name to listen for (see event names below)
handlerEventHandlerYesCallback function (data: unknown) => void

Event Names:

EventPayloadDescription
'event'RealtimeEventFires for every event from any subscribed topic
'event:<topic>'RealtimeEventFires only for events matching the specific topic (e.g. 'event:session.status')
'connection'{ state: ConnectionState, reason?: string }Fires on connection state changes
'error'unknownFires on connection or protocol errors
realtime.on('event:session.status', (event) => {
  console.log(event.payload);
});

realtime.on('connection', ({ state }) => {
  console.log('State:', state); // 'connecting' | 'connected' | 'disconnected' | 'reconnecting'
});

realtime.on('error', (err) => {
  console.error('Error:', err);
});

off(event, handler)

Remove a previously registered event listener.

off(event: string, handler: EventHandler): void
ParameterTypeRequiredDescription
eventstringYesEvent name to stop listening for
handlerEventHandlerYesThe exact same function reference passed to on()

Returns: void

const handler = (event) => console.log(event);
realtime.on('event:session.status', handler);

// Later...
realtime.off('event:session.status', handler);

destroy()

Disconnect, clear all subscriptions, and remove all event listeners. Call this when you're done with the client to release resources.

destroy(): void

Returns: void

realtime.destroy();

Read-Only Properties

PropertyTypeDescription
realtime.stateConnectionStateCurrent connection state: 'disconnected', 'connecting', 'connected', or 'reconnecting'
realtime.connectedbooleantrue if the connection state is 'connected'
if (realtime.connected) {
  console.log('We are live');
}
console.log('Current state:', realtime.state);

Event Envelope: RealtimeEvent

All events received by the client follow the RealtimeEvent envelope:

interface RealtimeEvent {
  id: string;                              // Unique event ID
  topic: string;                           // Domain topic (e.g. "session.status")
  source: 'database' | 'sync' | 'socket'; // Which service produced the event
  type: string;                            // Event type (e.g. "database.update")
  payload: Record<string, unknown>;        // Event data
  metadata: {
    timestamp: number;                     // Unix timestamp (ms)
    table?: string;                        // Source table (database events)
    operation?: 'insert' | 'update' | 'delete'; // DB operation type
    revision?: number;                     // Document revision (sync events)
  };
}

Server-Side Utilities

The SDK also includes utilities for server-side use:

ExportDescription
WebhookReceiverVerify and parse incoming webhook deliveries with HMAC-SHA256 signature validation and replay protection — see Webhook Receiver
verifyWebhook()Standalone function for one-off webhook verification
WebhookVerificationErrorTyped error thrown when webhook verification fails
import { WebhookReceiver } from '@smarterservices/realtime';

const receiver = new WebhookReceiver('whsec_your_secret');
const { event } = receiver.verify(rawBody, headers);

TypeScript Support

The SDK is written in TypeScript and ships with full type definitions. All public APIs are typed, including event payloads and options.

import type {
  RealtimeClientOptions,
  SubscribeOptions,
  ConnectionState,
  WebhookReceiverOptions,
  WebhookEvent,
} from '@smarterservices/realtime';

import type {
  RealtimeEvent,
  SubscriptionFilter,
} from '@realtime/shared-types';