ObjectStackObjectStack

Websocket

Websocket protocol schemas

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

TypeScript Usage

import { AckMessageSchema, CursorMessageSchema, CursorPositionSchema, DocumentStateSchema, EditMessageSchema, EditOperationSchema, EditOperationType, ErrorMessageSchema, EventMessageSchema, EventPatternSchema, EventSubscriptionSchema, PingMessageSchema, PongMessageSchema, PresenceMessageSchema, PresenceStateSchema, PresenceUpdateSchema, SimpleCursorPositionSchema, SimplePresenceStateSchema, SubscribeMessageSchema, UnsubscribeMessageSchema, UnsubscribeRequestSchema, WebSocketConfigSchema, WebSocketEventSchema, WebSocketMessageSchema, WebSocketMessageType, WebSocketPresenceStatus, WebSocketServerConfigSchema } from '@objectstack/spec/api';
import type { AckMessage, CursorMessage, CursorPosition, DocumentState, EditMessage, EditOperation, EditOperationType, ErrorMessage, EventMessage, EventPattern, EventSubscription, PingMessage, PongMessage, PresenceMessage, PresenceState, PresenceUpdate, SimpleCursorPosition, SimplePresenceState, SubscribeMessage, UnsubscribeMessage, UnsubscribeRequest, WebSocketConfig, WebSocketEvent, WebSocketMessage, WebSocketMessageType, WebSocketPresenceStatus, WebSocketServerConfig } from '@objectstack/spec/api';

// Validate data
const result = AckMessageSchema.parse(data);

AckMessage

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'ack'
timestampstringISO 8601 datetime when message was sent
ackMessageIdstringID of the message being acknowledged
successbooleanWhether the operation was successful
errorstringoptionalError message if operation failed

CursorMessage

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'cursor'
timestampstringISO 8601 datetime when message was sent
cursor{ userId: string; sessionId: string; documentId: string; position?: object; … }Cursor position

Nested Shape: CursorMessage.cursor

PropertyTypeRequiredDescription
userIdstringUser identifier
sessionIdstringSession identifier
documentIdstringDocument identifier being edited
position{ line: integer; column: integer }optionalCursor position in document
selection{ start: object; end: object }optionalSelection range (if text is selected)
colorstringoptionalCursor color for visual representation
userNamestringoptionalDisplay name of user
lastUpdatestringISO 8601 datetime of last cursor update

CursorPosition

Properties

PropertyTypeRequiredDescription
userIdstringUser identifier
sessionIdstringSession identifier
documentIdstringDocument identifier being edited
position{ line: integer; column: integer }optionalCursor position in document
selection{ start: object; end: object }optionalSelection range (if text is selected)
colorstringoptionalCursor color for visual representation
userNamestringoptionalDisplay name of user
lastUpdatestringISO 8601 datetime of last cursor update

Nested Shape: CursorPosition.position

PropertyTypeRequiredDescription
lineintegerLine number (0-indexed)
columnintegerColumn number (0-indexed)

DocumentState

Properties

PropertyTypeRequiredDescription
documentIdstringDocument identifier
versionintegerCurrent document version
contentstringCurrent document content
lastModifiedstringISO 8601 datetime of last modification
activeSessionsstring[]Active editing session IDs
checksumstringoptionalContent checksum for integrity verification

EditMessage

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'edit'
timestampstringISO 8601 datetime when message was sent
operation{ operationId: string; documentId: string; userId: string; sessionId: string; … }Edit operation

Nested Shape: EditMessage.operation

PropertyTypeRequiredDescription
operationIdstringUnique operation identifier
documentIdstringDocument identifier
userIdstringUser who performed the edit
sessionIdstringSession identifier
typeEnum<'insert' | 'delete' | 'replace'>Type of edit operation
position{ line: integer; column: integer }Starting position of the operation
endPosition{ line: integer; column: integer }optionalEnding position (for delete/replace operations)
contentstringoptionalContent to insert/replace
versionintegerDocument version before this operation
timestampstringISO 8601 datetime when operation was created
baseOperationIdstringoptionalPrevious operation ID this builds upon (for OT)

EditOperation

Properties

PropertyTypeRequiredDescription
operationIdstringUnique operation identifier
documentIdstringDocument identifier
userIdstringUser who performed the edit
sessionIdstringSession identifier
typeEnum<'insert' | 'delete' | 'replace'>Type of edit operation
position{ line: integer; column: integer }Starting position of the operation
endPosition{ line: integer; column: integer }optionalEnding position (for delete/replace operations)
contentstringoptionalContent to insert/replace
versionintegerDocument version before this operation
timestampstringISO 8601 datetime when operation was created
baseOperationIdstringoptionalPrevious operation ID this builds upon (for OT)

Nested Shape: EditOperation.position

PropertyTypeRequiredDescription
lineintegerLine number (0-indexed)
columnintegerColumn number (0-indexed)

EditOperationType

Allowed Values

  • insert
  • delete
  • replace

ErrorMessage

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'error'
timestampstringISO 8601 datetime when message was sent
codestringError code
messagestringError message
detailsanyoptionalAdditional error details

EventMessage

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'event'
timestampstringISO 8601 datetime when message was sent
subscriptionIdstringSubscription ID this event belongs to
eventNamestringEvent name
objectstringoptionalObject name the event relates to
payloadanyEvent payload data
userIdstringoptionalUser who triggered the event

EventPattern

Event pattern (supports wildcards like "record." or ".created")

Type: string


EventSubscription

Properties

PropertyTypeRequiredDescription
subscriptionIdstringUnique subscription identifier
eventsstring[]Event patterns to subscribe to (supports wildcards, e.g., "record.*", "user.created")
objectsstring[]optionalObject names to filter events by (e.g., ["account", "contact"])
filtersanyoptionalFilter conditions for event payloads (not yet enforced — the runtime filters by object name and event type only)
channelsstring[]optionalChannel names for scoped subscriptions

PingMessage

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'ping'
timestampstringISO 8601 datetime when message was sent

PongMessage

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'pong'
timestampstringISO 8601 datetime when message was sent
pingMessageIdstringoptionalID of ping message being responded to

PresenceMessage

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'presence'
timestampstringISO 8601 datetime when message was sent
presence{ userId: string; sessionId: string; status: Enum<'online' | 'away' | 'busy' | 'offline'>; lastSeen: string; … }Presence state

Nested Shape: PresenceMessage.presence

PropertyTypeRequiredDescription
userIdstringUser identifier
sessionIdstringUnique session identifier
statusEnum<'online' | 'away' | 'busy' | 'offline'>Current presence status
lastSeenstringISO 8601 datetime of last activity
currentLocationstringoptionalCurrent page/route user is viewing
deviceEnum<'desktop' | 'mobile' | 'tablet' | 'other'>optionalDevice type
customStatusstringoptionalCustom user status message
metadataRecord<string, any>optionalAdditional custom presence data

PresenceState

Properties

PropertyTypeRequiredDescription
userIdstringUser identifier
sessionIdstringUnique session identifier
statusEnum<'online' | 'away' | 'busy' | 'offline'>Current presence status
lastSeenstringISO 8601 datetime of last activity
currentLocationstringoptionalCurrent page/route user is viewing
deviceEnum<'desktop' | 'mobile' | 'tablet' | 'other'>optionalDevice type
customStatusstringoptionalCustom user status message
metadataRecord<string, any>optionalAdditional custom presence data

PresenceUpdate

Properties

PropertyTypeRequiredDescription
statusEnum<'online' | 'away' | 'busy' | 'offline'>optionalUpdated presence status
currentLocationstringoptionalUpdated current location
customStatusstringoptionalUpdated custom status message
metadataRecord<string, any>optionalUpdated metadata

SimpleCursorPosition

Properties

PropertyTypeRequiredDescription
userIdstringUser identifier
recordIdstringRecord identifier being edited
fieldNamestringField name being edited
positionnumberCursor position (character offset from start)
selection{ start: number; end: number }optionalText selection range (if text is selected)

Nested Shape: SimpleCursorPosition.selection

PropertyTypeRequiredDescription
startnumberSelection start position
endnumberSelection end position

SimplePresenceState

Properties

PropertyTypeRequiredDescription
userIdstringUser identifier
userNamestringUser display name
statusEnum<'online' | 'away' | 'offline'>User presence status
lastSeennumberUnix timestamp of last activity in milliseconds
metadataRecord<string, any>optionalAdditional presence metadata (e.g., current page, custom status)

SubscribeMessage

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'subscribe'
timestampstringISO 8601 datetime when message was sent
subscription{ subscriptionId: string; events: string[]; objects?: string[]; filters?: any; … }Subscription configuration

Nested Shape: SubscribeMessage.subscription

PropertyTypeRequiredDescription
subscriptionIdstringUnique subscription identifier
eventsstring[]Event patterns to subscribe to (supports wildcards, e.g., "record.*", "user.created")
objectsstring[]optionalObject names to filter events by (e.g., ["account", "contact"])
filtersanyoptionalFilter conditions for event payloads (not yet enforced — the runtime filters by object name and event type only)
channelsstring[]optionalChannel names for scoped subscriptions

UnsubscribeMessage

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'unsubscribe'
timestampstringISO 8601 datetime when message was sent
request{ subscriptionId: string }Unsubscribe request

Nested Shape: UnsubscribeMessage.request

PropertyTypeRequiredDescription
subscriptionIdstringSubscription ID to unsubscribe from

UnsubscribeRequest

Properties

PropertyTypeRequiredDescription
subscriptionIdstringSubscription ID to unsubscribe from

WebSocketConfig

Properties

PropertyTypeRequiredDescription
urlstringWebSocket server URL
protocolsstring[]optionalWebSocket sub-protocols
reconnectbooleanoptional (default: true)Enable automatic reconnection
reconnectIntervalintegeroptional (default: 1000)Reconnection interval in milliseconds
maxReconnectAttemptsintegeroptional (default: 5)Maximum reconnection attempts
pingIntervalintegeroptional (default: 30000)Ping interval in milliseconds
timeoutintegeroptional (default: 5000)Message timeout in milliseconds
headersRecord<string, string>optionalCustom headers for WebSocket handshake

WebSocketEvent

Properties

PropertyTypeRequiredDescription
typeEnum<'subscribe' | 'unsubscribe' | 'data-change' | 'presence-update' | 'cursor-update' | 'error'>Event type
channelstringChannel identifier (e.g., "record.account.123", "user.456")
payloadanyEvent payload data
timestampnumberUnix timestamp in milliseconds

WebSocketMessage

Union Options

This schema accepts one of the following structures:

Option 1

Type: subscribe

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'subscribe'
timestampstringISO 8601 datetime when message was sent
subscription{ subscriptionId: string; events: string[]; objects?: string[]; filters?: any; … }Subscription configuration

Nested Shape: WebSocketMessage[type='subscribe'].subscription

PropertyTypeRequiredDescription
subscriptionIdstringUnique subscription identifier
eventsstring[]Event patterns to subscribe to (supports wildcards, e.g., "record.*", "user.created")
objectsstring[]optionalObject names to filter events by (e.g., ["account", "contact"])
filtersanyoptionalFilter conditions for event payloads (not yet enforced — the runtime filters by object name and event type only)
channelsstring[]optionalChannel names for scoped subscriptions

Option 2

Type: unsubscribe

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'unsubscribe'
timestampstringISO 8601 datetime when message was sent
request{ subscriptionId: string }Unsubscribe request

Nested Shape: WebSocketMessage[type='unsubscribe'].request

PropertyTypeRequiredDescription
subscriptionIdstringSubscription ID to unsubscribe from

Option 3

Type: event

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'event'
timestampstringISO 8601 datetime when message was sent
subscriptionIdstringSubscription ID this event belongs to
eventNamestringEvent name
objectstringoptionalObject name the event relates to
payloadanyEvent payload data
userIdstringoptionalUser who triggered the event

Option 4

Type: presence

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'presence'
timestampstringISO 8601 datetime when message was sent
presence{ userId: string; sessionId: string; status: Enum<'online' | 'away' | 'busy' | 'offline'>; lastSeen: string; … }Presence state

Nested Shape: WebSocketMessage[type='presence'].presence

PropertyTypeRequiredDescription
userIdstringUser identifier
sessionIdstringUnique session identifier
statusEnum<'online' | 'away' | 'busy' | 'offline'>Current presence status
lastSeenstringISO 8601 datetime of last activity
currentLocationstringoptionalCurrent page/route user is viewing
deviceEnum<'desktop' | 'mobile' | 'tablet' | 'other'>optionalDevice type
customStatusstringoptionalCustom user status message
metadataRecord<string, any>optionalAdditional custom presence data

Option 5

Type: cursor

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'cursor'
timestampstringISO 8601 datetime when message was sent
cursor{ userId: string; sessionId: string; documentId: string; position?: object; … }Cursor position

Nested Shape: WebSocketMessage[type='cursor'].cursor

PropertyTypeRequiredDescription
userIdstringUser identifier
sessionIdstringSession identifier
documentIdstringDocument identifier being edited
position{ line: integer; column: integer }optionalCursor position in document
selection{ start: object; end: object }optionalSelection range (if text is selected)
colorstringoptionalCursor color for visual representation
userNamestringoptionalDisplay name of user
lastUpdatestringISO 8601 datetime of last cursor update

Option 6

Type: edit

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'edit'
timestampstringISO 8601 datetime when message was sent
operation{ operationId: string; documentId: string; userId: string; sessionId: string; … }Edit operation

Nested Shape: WebSocketMessage[type='edit'].operation

PropertyTypeRequiredDescription
operationIdstringUnique operation identifier
documentIdstringDocument identifier
userIdstringUser who performed the edit
sessionIdstringSession identifier
typeEnum<'insert' | 'delete' | 'replace'>Type of edit operation
position{ line: integer; column: integer }Starting position of the operation
endPosition{ line: integer; column: integer }optionalEnding position (for delete/replace operations)
contentstringoptionalContent to insert/replace
versionintegerDocument version before this operation
timestampstringISO 8601 datetime when operation was created
baseOperationIdstringoptionalPrevious operation ID this builds upon (for OT)

Option 7

Type: ack

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'ack'
timestampstringISO 8601 datetime when message was sent
ackMessageIdstringID of the message being acknowledged
successbooleanWhether the operation was successful
errorstringoptionalError message if operation failed

Option 8

Type: error

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'error'
timestampstringISO 8601 datetime when message was sent
codestringError code
messagestringError message
detailsanyoptionalAdditional error details

Option 9

Type: ping

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'ping'
timestampstringISO 8601 datetime when message was sent

Option 10

Type: pong

Properties

PropertyTypeRequiredDescription
messageIdstringUnique message identifier
type'pong'
timestampstringISO 8601 datetime when message was sent
pingMessageIdstringoptionalID of ping message being responded to


WebSocketMessageType

Allowed Values

  • subscribe
  • unsubscribe
  • event
  • ping
  • pong
  • ack
  • error
  • presence
  • cursor
  • edit

WebSocketPresenceStatus

Allowed Values

  • online
  • away
  • busy
  • offline

WebSocketServerConfig

Properties

PropertyTypeRequiredDescription
enabledbooleanoptional (default: false)Enable WebSocket server
pathstringoptional (default: "/ws")WebSocket endpoint path
heartbeatIntervalnumberoptional (default: 30000)Heartbeat interval in milliseconds
reconnectAttemptsnumberoptional (default: 5)Maximum reconnection attempts for clients
presencebooleanoptional (default: false)Enable presence tracking
cursorSharingbooleanoptional (default: false)Enable collaborative cursor sharing

On this page