Skip to Content
ReferenceClient APIRealtimeAdapter

RealtimeAdapter

Interface for WebSocket-based real-time sync updates.

Import

import type { RealtimeAdapter } from '@gluonic/client'

Interface Definition

Exact definition from implementation:

export type RealtimeAdapter = { connect: ( token: string, onFrames: (frames: SyncFrame[]) => void, onError?: (e: any) => void, onClose?: () => void ) => { close: () => void } }

Single method: connect() establishes WebSocket connection and returns close handler.


Methods

connect()

connect( token: string, onFrames: (frames: SyncFrame[]) => void, onError?: (e: any) => void, onClose?: () => void ): { close: () => void }

Establish WebSocket connection for real-time updates.

Parameters:

ParameterTypeDescription
tokenstringJWT auth token
onFrames(frames: SyncFrame[]) => voidCallback when frames received
onError(e: any) => voidOptional error callback
onClose() => voidOptional close callback

Returns: { close: () => void } - Handler to close connection

Example:

const connection = realtimeAdapter.connect( token, (frames) => { // Received real-time updates store.applyFrames(frames) }, (error) => { console.error('WebSocket error:', error) }, () => { console.log('WebSocket closed, reconnecting...') } ) // Later: Close connection connection.close()

Default Implementation

Default WebSocket adapter:

const defaultRealtimeAdapter: RealtimeAdapter = { connect(token, onFrames, onError, onClose) { const ws = new WebSocket(`wss://api.example.com/sync/v1/ws`) ws.onopen = () => { // Send auth ws.send(JSON.stringify({ type: 'auth', token })) } ws.onmessage = (event) => { const data = JSON.parse(event.data) if (data.type === 'frames') { onFrames(data.frames) } } ws.onerror = (error) => { onError?.(error) } ws.onclose = () => { onClose?.() } return { close: () => ws.close() } } }

Custom Implementation

With Heartbeat

import type { RealtimeAdapter } from '@gluonic/client' class HeartbeatRealtimeAdapter implements RealtimeAdapter { connect(token, onFrames, onError, onClose) { const ws = new WebSocket('wss://api.example.com/sync/v1/ws') let heartbeatTimer: any ws.onopen = () => { ws.send(JSON.stringify({ type: 'auth', token })) // Start heartbeat heartbeatTimer = setInterval(() => { ws.send(JSON.stringify({ type: 'ping' })) }, 30000) // Every 30s } ws.onmessage = (event) => { const data = JSON.parse(event.data) if (data.type === 'frames') { onFrames(data.frames) } else if (data.type === 'pong') { // Heartbeat acknowledged } } ws.onerror = (error) => { clearInterval(heartbeatTimer) onError?.(error) } ws.onclose = () => { clearInterval(heartbeatTimer) onClose?.() } return { close: () => { clearInterval(heartbeatTimer) ws.close() } } } }

With Reconnect

class ReconnectRealtimeAdapter implements RealtimeAdapter { connect(token, onFrames, onError, onClose) { let ws: WebSocket let shouldReconnect = true let reconnectAttempts = 0 const connect = () => { ws = new WebSocket('wss://api.example.com/sync/v1/ws') ws.onopen = () => { reconnectAttempts = 0 // Reset on successful connection ws.send(JSON.stringify({ type: 'auth', token })) } ws.onmessage = (event) => { const data = JSON.parse(event.data) if (data.type === 'frames') { onFrames(data.frames) } } ws.onerror = (error) => { onError?.(error) } ws.onclose = () => { onClose?.() if (shouldReconnect) { reconnectAttempts++ const backoff = Math.min(Math.pow(2, reconnectAttempts) * 1000, 30000) setTimeout(connect, backoff) } } } connect() return { close: () => { shouldReconnect = false ws.close() } } } }

Usage in Gluonic

RealtimeAdapter is used by Store for:

Real-Time Updates

// Store manages WebSocket lifecycle store.startRealtime() // Calls realtimeAdapter.connect() // Frames received via WebSocket ws.onmessage → onFrames(frames) → store.applyFrames(frames) // Stop real-time store.stopRealtime() // Calls connection.close()

Token Changes

// SyncProvider manages real-time lifecycle <SyncProvider token={token}> // When token changes: // 1. Close existing connection // 2. Open new connection with new token

Frame Delivery

Frames are pushed from server in real-time:

// Server broadcasts change // WebSocket message: { type: 'frames', frames: [ { sid: 42, t: 'task', id: 'abc', op: 'u', p: { done: true } } ] } // Client receives and applies immediately onFrames([frame]) → store.applyFrames([frame])

Configuration

const client = SyncClient({ server: 'https://api.example.com/sync/v1', storage, models, realtime: { connect: (token, onFrames, onError, onClose) => { // Custom WebSocket implementation const ws = new WebSocket('wss://custom.com/ws') ws.onmessage = (event) => { const frames = parseCustomFormat(event.data) onFrames(frames) } return { close: () => ws.close() } } } })

Note: If not provided, Gluonic creates default WebSocket adapter from server URL.


Error Handling

Authentication Errors

connect(token, onFrames, onError, onClose) { const ws = new WebSocket('wss://api.example.com/sync/v1/ws') ws.onmessage = (event) => { const data = JSON.parse(event.data) if (data.type === 'error' && data.code === 401) { // Server rejected auth onError?.(new Error('Unauthenticated')) ws.close() } } }

Network Errors

ws.onerror = (error) => { onError?.(error) // Connection will close, trigger onClose for reconnect }

Performance

Instant Updates

WebSocket delivers updates within milliseconds:

// User 1 creates task await store.create('task', id, { title: 'New' }) // Server broadcasts via WebSocket // User 2 receives frame immediately // User 2's UI updates < 100ms âś“

Efficient Protocol

Only changed data sent:

// Traditional polling: Full dataset every 5s GET /api/tasks → 1MB // WebSocket: Only changes ws → { frame: { op: 'u', p: { done: true } } } → 50 bytes

See Also

Last updated on