| title |
Websocket |
| description |
Websocket protocol schemas |
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
WebSocket Event Protocol
Defines the schema for WebSocket-based real-time communication in ObjectStack.
Supports event subscriptions, filtering, presence tracking, and collaborative editing.
Industry alignment: Firebase Realtime Database, Socket.IO, Pusher
⚠️ NOT YET SERVED — this protocol is declared but no WebSocket server is
mounted anywhere in the runtime (#2462, #3197): IRealtimeService.handleUpgrade
is deliberately unimplemented and discovery advertises websockets: false.
These schemas define the future wire contract; nothing consumes them at
runtime today.
**Source:** `packages/spec/src/api/websocket.zod.ts`
import { AckMessage, CursorMessage, CursorPosition, DocumentState, EditMessage, EditOperation, EditOperationType, ErrorMessage, EventFilter, EventFilterCondition, EventMessage, EventPattern, EventSubscription, FilterOperator, PingMessage, PongMessage, PresenceMessage, PresenceState, PresenceUpdate, SimpleCursorPosition, SimplePresenceState, SubscribeMessage, UnsubscribeMessage, UnsubscribeRequest, WebSocketConfig, WebSocketEvent, WebSocketMessage, WebSocketMessageType, WebSocketPresenceStatus, WebSocketServerConfig } from '@objectstack/spec/api';
import type { AckMessage, CursorMessage, CursorPosition, DocumentState, EditMessage, EditOperation, EditOperationType, ErrorMessage, EventFilter, EventFilterCondition, EventMessage, EventPattern, EventSubscription, FilterOperator, PingMessage, PongMessage, PresenceMessage, PresenceState, PresenceUpdate, SimpleCursorPosition, SimplePresenceState, SubscribeMessage, UnsubscribeMessage, UnsubscribeRequest, WebSocketConfig, WebSocketEvent, WebSocketMessage, WebSocketMessageType, WebSocketPresenceStatus, WebSocketServerConfig } from '@objectstack/spec/api';
// Validate data
const result = AckMessage.parse(data);
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'ack' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| ackMessageId |
string |
✅ |
ID of the message being acknowledged |
| success |
boolean |
✅ |
Whether the operation was successful |
| error |
string |
optional |
Error message if operation failed |
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'cursor' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| cursor |
{ userId: string; sessionId: string; documentId: string; position?: object; … } |
✅ |
Cursor position |
| Property |
Type |
Required |
Description |
| userId |
string |
✅ |
User identifier |
| sessionId |
string |
✅ |
Session identifier |
| documentId |
string |
✅ |
Document identifier being edited |
| position |
{ line: integer; column: integer } |
optional |
Cursor position in document |
| selection |
{ start: object; end: object } |
optional |
Selection range (if text is selected) |
| color |
string |
optional |
Cursor color for visual representation |
| userName |
string |
optional |
Display name of user |
| lastUpdate |
string |
✅ |
ISO 8601 datetime of last cursor update |
| Property |
Type |
Required |
Description |
| documentId |
string |
✅ |
Document identifier |
| version |
integer |
✅ |
Current document version |
| content |
string |
✅ |
Current document content |
| lastModified |
string |
✅ |
ISO 8601 datetime of last modification |
| activeSessions |
string[] |
✅ |
Active editing session IDs |
| checksum |
string |
optional |
Content checksum for integrity verification |
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'edit' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| operation |
{ operationId: string; documentId: string; userId: string; sessionId: string; … } |
✅ |
Edit operation |
| Property |
Type |
Required |
Description |
| operationId |
string |
✅ |
Unique operation identifier |
| documentId |
string |
✅ |
Document identifier |
| userId |
string |
✅ |
User who performed the edit |
| sessionId |
string |
✅ |
Session identifier |
| type |
Enum<'insert' | 'delete' | 'replace'> |
✅ |
Type of edit operation |
| position |
{ line: integer; column: integer } |
✅ |
Starting position of the operation |
| endPosition |
{ line: integer; column: integer } |
optional |
Ending position (for delete/replace operations) |
| content |
string |
optional |
Content to insert/replace |
| version |
integer |
✅ |
Document version before this operation |
| timestamp |
string |
✅ |
ISO 8601 datetime when operation was created |
| baseOperationId |
string |
optional |
Previous operation ID this builds upon (for OT) |
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'error' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| code |
string |
✅ |
Error code |
| message |
string |
✅ |
Error message |
| details |
any |
optional |
Additional error details |
| Property |
Type |
Required |
Description |
| conditions |
{ field: string; operator: Enum<'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'nin' | 'contains' | 'startsWith' | 'endsWith' | 'exists' | 'regex'>; value?: any }[] |
optional |
Array of filter conditions |
| and |
[EventFilter](#eventfilter)[] |
optional |
AND logical combination of filters |
| or |
[EventFilter](#eventfilter)[] |
optional |
OR logical combination of filters |
| not |
[EventFilter](#eventfilter) |
optional |
NOT logical negation of filter |
| Property |
Type |
Required |
Description |
| field |
string |
✅ |
Field path to filter on (supports dot notation, e.g., "user.email") |
| operator |
Enum<'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'nin' | 'contains' | 'startsWith' | 'endsWith' | 'exists' | 'regex'> |
✅ |
Comparison operator |
| value |
any |
optional |
Value to compare against (not needed for "exists" operator) |
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'event' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| subscriptionId |
string |
✅ |
Subscription ID this event belongs to |
| eventName |
string |
✅ |
Event name |
| object |
string |
optional |
Object name the event relates to |
| payload |
any |
✅ |
Event payload data |
| userId |
string |
optional |
User who triggered the event |
| Property |
Type |
Required |
Description |
| subscriptionId |
string |
✅ |
Unique subscription identifier |
| events |
string[] |
✅ |
Event patterns to subscribe to (supports wildcards, e.g., "record.*", "user.created") |
| objects |
string[] |
optional |
Object names to filter events by (e.g., ["account", "contact"]) |
| filters |
{ conditions?: { field: string; operator: Enum<'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'nin' | 'contains' | 'startsWith' | 'endsWith' | 'exists' | 'regex'>; value?: any }[]; and?: object[]; or?: object[]; not?: object } |
optional |
Advanced filter conditions for event payloads |
| channels |
string[] |
optional |
Channel names for scoped subscriptions |
eq
ne
gt
gte
lt
lte
in
nin
contains
startsWith
endsWith
exists
regex
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'ping' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'pong' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| pingMessageId |
string |
optional |
ID of ping message being responded to |
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'presence' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| presence |
{ userId: string; sessionId: string; status: Enum<'online' | 'away' | 'busy' | 'offline'>; lastSeen: string; … } |
✅ |
Presence state |
| Property |
Type |
Required |
Description |
| userId |
string |
✅ |
User identifier |
| sessionId |
string |
✅ |
Unique session identifier |
| status |
Enum<'online' | 'away' | 'busy' | 'offline'> |
✅ |
Current presence status |
| lastSeen |
string |
✅ |
ISO 8601 datetime of last activity |
| currentLocation |
string |
optional |
Current page/route user is viewing |
| device |
Enum<'desktop' | 'mobile' | 'tablet' | 'other'> |
optional |
Device type |
| customStatus |
string |
optional |
Custom user status message |
| metadata |
Record<string, any> |
optional |
Additional custom presence data |
| Property |
Type |
Required |
Description |
| status |
Enum<'online' | 'away' | 'busy' | 'offline'> |
optional |
Updated presence status |
| currentLocation |
string |
optional |
Updated current location |
| customStatus |
string |
optional |
Updated custom status message |
| metadata |
Record<string, any> |
optional |
Updated metadata |
| Property |
Type |
Required |
Description |
| userId |
string |
✅ |
User identifier |
| recordId |
string |
✅ |
Record identifier being edited |
| fieldName |
string |
✅ |
Field name being edited |
| position |
number |
✅ |
Cursor position (character offset from start) |
| selection |
{ start: number; end: number } |
optional |
Text selection range (if text is selected) |
| Property |
Type |
Required |
Description |
| userId |
string |
✅ |
User identifier |
| userName |
string |
✅ |
User display name |
| status |
Enum<'online' | 'away' | 'offline'> |
✅ |
User presence status |
| lastSeen |
number |
✅ |
Unix timestamp of last activity in milliseconds |
| metadata |
Record<string, any> |
optional |
Additional presence metadata (e.g., current page, custom status) |
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'subscribe' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| subscription |
{ subscriptionId: string; events: string[]; objects?: string[]; filters?: { conditions?: { field: string; operator: Enum<'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'nin' | 'contains' | 'startsWith' | 'endsWith' | 'exists' | 'regex'>; value?: any }[]; and?: object[]; or?: object[]; not?: object }; … } |
✅ |
Subscription configuration |
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'unsubscribe' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| request |
{ subscriptionId: string } |
✅ |
Unsubscribe request |
| Property |
Type |
Required |
Description |
| subscriptionId |
string |
✅ |
Subscription ID to unsubscribe from |
| Property |
Type |
Required |
Description |
| url |
string |
✅ |
WebSocket server URL |
| protocols |
string[] |
optional |
WebSocket sub-protocols |
| reconnect |
boolean |
✅ |
Enable automatic reconnection |
| reconnectInterval |
integer |
✅ |
Reconnection interval in milliseconds |
| maxReconnectAttempts |
integer |
✅ |
Maximum reconnection attempts |
| pingInterval |
integer |
✅ |
Ping interval in milliseconds |
| timeout |
integer |
✅ |
Message timeout in milliseconds |
| headers |
Record<string, string> |
optional |
Custom headers for WebSocket handshake |
| Property |
Type |
Required |
Description |
| type |
Enum<'subscribe' | 'unsubscribe' | 'data-change' | 'presence-update' | 'cursor-update' | 'error'> |
✅ |
Event type |
| channel |
string |
✅ |
Channel identifier (e.g., "record.account.123", "user.456") |
| payload |
any |
✅ |
Event payload data |
| timestamp |
number |
✅ |
Unix timestamp in milliseconds |
This schema accepts one of the following structures:
Type: subscribe
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'subscribe' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| subscription |
{ subscriptionId: string; events: string[]; objects?: string[]; filters?: { conditions?: { field: string; operator: Enum<'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'nin' | 'contains' | 'startsWith' | 'endsWith' | 'exists' | 'regex'>; value?: any }[]; and?: object[]; or?: object[]; not?: object }; … } |
✅ |
Subscription configuration |
Type: unsubscribe
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'unsubscribe' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| request |
{ subscriptionId: string } |
✅ |
Unsubscribe request |
Type: event
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'event' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| subscriptionId |
string |
✅ |
Subscription ID this event belongs to |
| eventName |
string |
✅ |
Event name |
| object |
string |
optional |
Object name the event relates to |
| payload |
any |
✅ |
Event payload data |
| userId |
string |
optional |
User who triggered the event |
Type: presence
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'presence' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| presence |
{ userId: string; sessionId: string; status: Enum<'online' | 'away' | 'busy' | 'offline'>; lastSeen: string; … } |
✅ |
Presence state |
Type: cursor
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'cursor' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| cursor |
{ userId: string; sessionId: string; documentId: string; position?: object; … } |
✅ |
Cursor position |
Type: edit
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'edit' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| operation |
{ operationId: string; documentId: string; userId: string; sessionId: string; … } |
✅ |
Edit operation |
Type: ack
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'ack' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| ackMessageId |
string |
✅ |
ID of the message being acknowledged |
| success |
boolean |
✅ |
Whether the operation was successful |
| error |
string |
optional |
Error message if operation failed |
Type: error
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'error' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| code |
string |
✅ |
Error code |
| message |
string |
✅ |
Error message |
| details |
any |
optional |
Additional error details |
Type: ping
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'ping' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
Type: pong
| Property |
Type |
Required |
Description |
| messageId |
string |
✅ |
Unique message identifier |
| type |
'pong' |
✅ |
|
| timestamp |
string |
✅ |
ISO 8601 datetime when message was sent |
| pingMessageId |
string |
optional |
ID of ping message being responded to |
subscribe
unsubscribe
event
ping
pong
ack
error
presence
cursor
edit
| Property |
Type |
Required |
Description |
| enabled |
boolean |
✅ |
Enable WebSocket server |
| path |
string |
✅ |
WebSocket endpoint path |
| heartbeatInterval |
number |
✅ |
Heartbeat interval in milliseconds |
| reconnectAttempts |
number |
✅ |
Maximum reconnection attempts for clients |
| presence |
boolean |
✅ |
Enable presence tracking |
| cursorSharing |
boolean |
✅ |
Enable collaborative cursor sharing |