Real-time subscriptions

Stream collection changes into your UI with SSE or WebSocket subscriptions from the EmuView SDK.

#Real-time subscriptions

The SDK offers two ways to receive live collection events — record created, updated, and deleted — without polling. By the end of this guide you'll have a list in your UI that updates the moment data changes.

#Choosing a transport

SSE subscribe() WebSocket subscribeWS()
Best for Dashboards, admin UIs, live lists Chat, collaboration, presence
Direction Server → client only Bi-directional
Presence tracking No Yes, built-in
Auto-reconnect No — reconnect manually Yes (default on)
Server setup None Requires the SUBSCRIPTION_DO Durable Object binding

#Prerequisites

  • A configured SDK instance (see installation)
  • An authenticated user or API key with read access to the collection

#Steps

#1. Subscribe with SSE

subscribe() opens a Server-Sent Events stream and invokes your handlers as events arrive. It returns an unsubscribe function.

import sdk from '$lib/sveltesync';

let orders: Record<string, unknown>[] = [];

const unsubscribe = sdk.collection('orders').subscribe({
	filter: { status: 'pending' }, // Only receive matching records
	fields: ['id', 'total', 'status'], // Trim event payloads
	onConnected: ({ connectionId }) => console.log('Stream open:', connectionId),
	onCreated: (record) => {
		orders = [record, ...orders];
	},
	onUpdated: (record) => {
		orders = orders.map((o) => (o.id === record.id ? record : o));
	},
	onDeleted: ({ id }) => {
		orders = orders.filter((o) => o.id !== id);
	},
	onError: (err) => console.error('Stream error:', err)
});
#subscribe() options
Option Type Description
filter Record<string, unknown> Filter object — only events for matching records are delivered
fields string[] Limit event payloads to these fields
onCreated (record) => void A record matching the filter was created
onUpdated (record) => void A record was updated. The record may include a changes object with the modified fields
onDeleted (data) => void A record was deleted. data is { id, deleted_at, permanent? }
onConnected (data) => void The stream opened. data is { connectionId, collection }
onError (error: Error) => void The connection failed or dropped

#2. Stop listening

Call the returned function when the component unmounts:

unsubscribe();
Note

SSE streams don't reconnect automatically. If onError fires, call subscribe() again to open a new stream — or use subscribeWS(), which reconnects for you.

#3. Subscribe with WebSocket

subscribeWS() connects through a Durable Object for globally consistent delivery, presence tracking, and automatic reconnection. It returns a handle with close, ping, requestPresence, and send methods.

import sdk from '$lib/sveltesync';

const ws = sdk.collection('orders').subscribeWS({
	filter: { status: 'pending' },
	fields: ['id', 'total', 'status'],
	onConnected: (info) => console.log('Connected:', info.connectionId, 'seq:', info.seq),
	onCreated: (record) => console.log('New order:', record),
	onUpdated: (record, changes) => console.log('Updated fields:', changes),
	onDeleted: ({ id }) => console.log('Deleted:', id),
	onPresence: (users) => console.log(`${users.length} users online`),
	onClose: (code, reason) => console.log('Closed:', code, reason),
	onError: (err) => console.error('WS error:', err),
	autoReconnect: true, // Default: true
	reconnectDelay: 2000 // Default: 2000ms
});

// Bi-directional messaging
ws.ping(); // Keepalive
ws.requestPresence(); // Ask who else is connected — answered via onPresence
ws.close(); // Disconnect (disables auto-reconnect)
#subscribeWS() options
Option Type Description
filter Record<string, unknown> Filter object sent with the subscribe message
fields string[] Limit event payloads to these fields
onCreated (record) => void A matching record was created
onUpdated (record, changes?) => void A record was updated. changes holds only the modified fields
onDeleted (data) => void A record was deleted. data includes id
onPresence (users) => void Presence update. Each user is { userId, email, connectedAt }
onConnected (info) => void Connection established. info is { connectionId, seq }
onClose (code, reason) => void The socket closed
onError (error: Error) => void Connection or protocol error
autoReconnect boolean Reconnect after unexpected disconnects. Default: true
reconnectDelay number Milliseconds to wait before reconnecting. Default: 2000
#Returned handle
Method Description
close() Close the connection and cancel any pending reconnect
ping() Send a keepalive ping
requestPresence() Request the current presence list (delivered via onPresence)
send(msg) Send a raw JSON message to the server
Tip

The WebSocket sends the auth token via the Sec-WebSocket-Protocol header rather than the URL, so tokens never appear in server access logs.

#Filtering events

Both transports accept the same filter operators as list(). Events are only delivered for records that match:

const unsubscribe = sdk.collection('products').subscribe({
	filter: { price: { _gte: 100 }, status: 'active' },
	onCreated: (record) => console.log('New premium product:', record)
});

#What you learned

  • subscribe() opens an SSE stream and returns an unsubscribe function
  • subscribeWS() connects via WebSocket with auto-reconnect, presence, and a control handle
  • Both accept filter and fields to scope what you receive
  • Use SSE for one-way dashboards, WebSocket for chat and collaboration

#Next steps