SDK

SSE Client

Receive server-pushed events over HTTP using the SDK's SSE client with automatic token management and reconnection.

The SseClient provides a high-level API for receiving events via Server-Sent Events (SSE). Unlike the WebSocket-based RealtimeClient (bidirectional), the SSE client is receive-only — ideal for dashboards, monitoring tools, and any scenario where you only need to consume events without sending messages.

Info

The SSE client handles token creation, stream connection, event parsing, auto-reconnection (via native EventSource), and automatic token extension. It's a standalone class — you don't need a RealtimeClient to use it.

Quick Start

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

const sse = new SseClient({
  url: 'https://api.example.com',
  applicationId: 'app_abc123',
  environment: 'production',
  subscriptions: [
    { events: ['proctoring.session.created', 'proctoring.session.updated'] },
    { events: ['document.*'] },
  ],
});

// Listen for events
sse.on('event:proctoring.session.updated', (event) => {
  console.log('Session updated:', event);
});

sse.on('event', (event) => {
  console.log('Any event:', event.type, event);
});

// Connect — creates a token and opens the SSE stream
await sse.connect();

Constructor

new SseClient(options: SseClientOptions)

SseClientOptions

OptionTypeRequiredDefaultDescription
urlstringYesBackend API base URL (e.g. "https://api.example.com")
applicationIdstringYesApplication ID for scoping
environmentstringYesEnvironment ("development", "staging", "production")
subscriptionsSseSubscriptionInput[]YesEvent subscriptions (at least one required)
ttlMinutesnumberNo30Token lifetime in minutes (5–60)
bufferSizenumberNo1000Replay buffer size (max 5000)
autoExtendbooleanNotrueAutomatically extend the token 60s before expiry
authHeaderstringNoAuthorization header value (e.g. "Bearer <jwt>")

SseSubscriptionInput

FieldTypeRequiredDescription
eventsstring[]YesEvent type patterns (e.g. ["session.updated", "document.*"])
filterSubscriptionFilterNoPayload filter — only events matching all key/value pairs are delivered
const sse = new SseClient({
  url: 'https://api.example.com',
  applicationId: 'app_abc123',
  environment: 'production',
  subscriptions: [
    {
      events: ['proctoring.session.created', 'proctoring.session.updated'],
      filter: { installSid: 'AI4b56b78...' },
    },
  ],
  ttlMinutes: 60,
  bufferSize: 2000,
  autoExtend: true,
  authHeader: 'Bearer eyJhbGci...',
});

Methods

connect()

Creates a stream token via the SSE API and opens the EventSource connection. Resolves when the connection is established.

await sse.connect();

disconnect()

Closes the SSE stream and stops auto-extend timers. Does not revoke the token.

sse.disconnect();

extendToken(ttlMinutes?, addSubscriptions?, removeSubscriptions?)

Extends the current token's TTL. Can also add or remove subscriptions dynamically.

// Extend by 30 minutes
await sse.extendToken(30);

// Extend and add a new subscription
await sse.extendToken(30, [{ events: ['audit.*'] }]);

// Extend and remove a subscription
await sse.extendToken(30, undefined, ['ssub_002']);

revoke()

Revokes the current token and disconnects. Connected streams receive a token_revoked event.

await sse.revoke();

destroy()

Disconnects, revokes the token, and removes all event listeners. Call when the client is no longer needed.

await sse.destroy();

on(event, handler) / off(event, handler)

Register or remove event listeners.

sse.on('event:session.updated', handler);
sse.off('event:session.updated', handler);

Event Names

EventPayloadDescription
'event'SseEventFires for every received event
'event:<type>'SseEventFires for events matching a specific type (e.g. 'event:session.updated')
'connection'{ state: SseConnectionState }Fires on connection state changes
'token_expiring'{ expiresAt, message }Fires ~30s before token expiry
'token_extended'{ expiresAt }Fires when the token is successfully extended
'error'{ message: string }Fires on connection errors, token expiry, or revocation

Read-Only Properties

PropertyTypeDescription
sse.stateSseConnectionState'disconnected', 'connecting', 'connected', or 'reconnecting'
sse.connectedbooleantrue if connected
sse.tokenSseTokenInfo | nullCurrent token metadata

SseEvent

Events received from the SSE stream have this shape:

interface SseEvent {
  type: string;           // e.g. "proctoring.session.updated"
  subscriptionId?: string; // which subscription matched (e.g. "ssub_001")
  [key: string]: unknown;  // event payload fields
}

The type field is always present — the server includes it in the data payload (self-describing events), so clients can identify the event type regardless of which EventSource listener pattern they use.

Automatic Reconnection

The SSE client uses the browser's native EventSource API, which automatically reconnects when the connection drops. On reconnect, the Last-Event-ID header is sent automatically, and the server replays any missed events from the replay buffer.

sse.on('connection', ({ state }) => {
  if (state === 'reconnecting') {
    console.log('Connection lost, auto-reconnecting...');
  }
  if (state === 'connected') {
    console.log('Connected — events flowing');
  }
});

Token Auto-Extension

When autoExtend is true (the default), the client automatically extends the token 60 seconds before it expires. This keeps the stream alive indefinitely without manual intervention.

To handle extension failures:

sse.on('error', ({ message }) => {
  if (message.startsWith('Auto-extend failed')) {
    // Token extension failed — stream will close when token expires
    console.warn(message);
  }
});

Entity Key Filtering

Use filter in subscriptions to scope events to specific tenants:

const sse = new SseClient({
  url: 'https://api.example.com',
  applicationId: 'app_abc123',
  environment: 'production',
  subscriptions: [
    {
      events: ['proctoring.session.created', 'proctoring.session.updated'],
      filter: {
        installSid: 'AI4b56b78...',
        proctorAccountLocationSid: 'PAL_xyz789',
      },
    },
  ],
});

Filter rules use AND logic — all key/value pairs must match the event payload for the event to be delivered.

SSE vs WebSocket

FeatureSseClientRealtimeClient
DirectionServer → Client (receive only)Bidirectional
ProtocolHTTP streaming (EventSource)WebSocket (Socket.IO)
AuthToken-based (per-stream)JWT (per-connection)
ReconnectionNative EventSource auto-reconnectSocket.IO auto-reconnect
ReplayLast-Event-ID replay bufferNo built-in replay
Proxy supportStandard HTTP — no special configMay need WebSocket-aware proxy
Use caseDashboards, monitoring, event feedsInteractive apps, document sync, chat

Use SseClient when you only need to receive events (dashboards, webhooks-over-HTTP, monitoring). Use RealtimeClient when you need bidirectional communication (document sync, socket messaging, presence).

TypeScript Types

All types are exported from the SDK:

import type {
  SseClientOptions,
  SseSubscriptionInput,
  SseConnectionState,
  SseTokenInfo,
  SseEvent,
} from '@smarterservices/realtime';

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