ObjectStackObjectStack

Collaboration

Collaboration protocol schemas

Real-Time Collaboration Protocol

Defines schemas for real-time collaborative editing in ObjectStack. Supports Operational Transformation (OT), CRDT (Conflict-free Replicated Data Types), cursor sharing, and awareness state for collaborative applications.

Industry alignment: Google Docs, Figma, VSCode Live Share, Yjs

Source: packages/spec/src/system/collaboration.zod.ts

TypeScript Usage

import { AwarenessEventSchema, AwarenessSessionSchema, AwarenessUpdateSchema, AwarenessUserStateSchema, CRDTMergeResultSchema, CRDTStateSchema, CRDTType, CollaborationMode, CollaborationSessionSchema, CollaborationSessionConfigSchema, CollaborativeCursorSchema, CounterOperationSchema, CursorColorPreset, CursorSelectionSchema, CursorStyleSchema, CursorUpdateSchema, GCounterSchema, LWWRegisterSchema, ORSetSchema, ORSetElementSchema, OTComponentSchema, OTOperationSchema, OTOperationType, OTTransformResultSchema, PNCounterSchema, TextCRDTOperationSchema, TextCRDTStateSchema, UserActivityStatus, VectorClockSchema } from '@objectstack/spec/system';
import type { AwarenessEvent, AwarenessSession, AwarenessUpdate, AwarenessUserState, CRDTMergeResult, CRDTState, CRDTType, CollaborationMode, CollaborationSession, CollaborationSessionConfig, CollaborativeCursor, CounterOperation, CursorColorPreset, CursorSelection, CursorStyle, CursorUpdate, GCounter, LWWRegister, ORSet, ORSetElement, OTComponent, OTOperation, OTOperationType, OTTransformResult, PNCounter, TextCRDTOperation, TextCRDTState, UserActivityStatus, VectorClock } from '@objectstack/spec/system';

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

AwarenessEvent

Properties

PropertyTypeRequiredDescription
eventIdstringEvent identifier
sessionIdstringSession identifier
eventTypeEnum<'user.joined' | 'user.left' | 'user.updated' | 'session.created' | 'session.ended'>Type of awareness event
userIdstringoptionalUser involved in event
timestampstringISO 8601 datetime of event
payloadanyEvent payload

AwarenessSession

Properties

PropertyTypeRequiredDescription
sessionIdstringSession identifier
documentIdstringoptionalDocument ID this session is for
users{ userId: string; sessionId: string; userName: string; userAvatar?: string; … }[]Active users in session
startedAtstringISO 8601 datetime when session started
lastUpdatestringISO 8601 datetime of last update
metadataRecord<string, any>optionalSession metadata

AwarenessUpdate

Properties

PropertyTypeRequiredDescription
statusEnum<'active' | 'idle' | 'viewing' | 'disconnected'>optionalUpdated status
currentDocumentstringoptionalUpdated current document
currentViewstringoptionalUpdated current view
metadataRecord<string, any>optionalUpdated metadata

AwarenessUserState

Properties

PropertyTypeRequiredDescription
userIdstringUser identifier
sessionIdstringSession identifier
userNamestringDisplay name
userAvatarstringoptionalUser avatar URL
statusEnum<'active' | 'idle' | 'viewing' | 'disconnected'>Current activity status
currentDocumentstringoptionalDocument ID user is currently editing
currentViewstringoptionalCurrent view/page user is on
lastActivitystringISO 8601 datetime of last activity
joinedAtstringISO 8601 datetime when user joined session
permissionsstring[]optionalUser permissions in this session
metadataRecord<string, any>optionalAdditional user state metadata

CRDTMergeResult

Properties

PropertyTypeRequiredDescription
state{ type: 'lww-register'; value: any; timestamp: string; replicaId: string; … } | { type: 'g-counter'; counts: Record<string, integer> } | { type: 'pn-counter'; positive: Record<string, integer>; negative: Record<string, integer> } | { type: 'or-set'; elements: object[] } | … +1 moreMerged CRDT state
conflicts{ type: string; description: string; resolved: boolean }[]optionalConflicts encountered during merge

CRDTState

Union Options

This schema accepts one of the following structures:

Option 1

Type: lww-register

Properties

PropertyTypeRequiredDescription
type'lww-register'
valueanyCurrent register value
timestampstringISO 8601 datetime of last write
replicaIdstringID of replica that performed last write
vectorClock{ clock: Record<string, integer> }optionalOptional vector clock for causality tracking

Option 2

Type: g-counter

Properties

PropertyTypeRequiredDescription
type'g-counter'
countsRecord<string, integer>Map of replica ID to count

Option 3

Type: pn-counter

Properties

PropertyTypeRequiredDescription
type'pn-counter'
positiveRecord<string, integer>Positive increments per replica
negativeRecord<string, integer>Negative increments per replica

Option 4

Type: or-set

Properties

PropertyTypeRequiredDescription
type'or-set'
elements{ value: any; timestamp: string; replicaId: string; uid: string; … }[]Set elements with metadata

Option 5

Type: text

Properties

PropertyTypeRequiredDescription
type'text'
documentIdstringDocument identifier
contentstringCurrent text content
operations{ operationId: string; replicaId: string; position: integer; insert?: string; … }[]History of operations
lamportClockintegerCurrent Lamport clock value
vectorClock{ clock: Record<string, integer> }Vector clock for causality


CRDTType

Allowed Values

  • lww-register
  • g-counter
  • pn-counter
  • g-set
  • or-set
  • lww-map
  • text
  • tree
  • json

CollaborationMode

Allowed Values

  • ot
  • crdt
  • lock
  • hybrid

CollaborationSession

Properties

PropertyTypeRequiredDescription
sessionIdstringSession identifier
documentIdstringDocument identifier
config{ mode: Enum<'ot' | 'crdt' | 'lock' | 'hybrid'>; enableCursorSharing: boolean; enablePresence: boolean; enableAwareness: boolean; … }Session configuration
users{ userId: string; sessionId: string; userName: string; userAvatar?: string; … }[]Active users
cursors{ userId: string; sessionId: string; documentId: string; userName: string; … }[]Active cursors
versionintegerCurrent document version
operations({ operationId: string; documentId: string; userId: string; sessionId: string; … } | { operationId: string; replicaId: string; position: integer; insert?: string; … })[]optionalRecent operations
createdAtstringISO 8601 datetime when session was created
lastActivitystringISO 8601 datetime of last activity
statusEnum<'active' | 'idle' | 'ended'>Session status

CollaborationSessionConfig

Properties

PropertyTypeRequiredDescription
modeEnum<'ot' | 'crdt' | 'lock' | 'hybrid'>Collaboration mode to use
enableCursorSharingbooleanEnable cursor sharing
enablePresencebooleanEnable presence tracking
enableAwarenessbooleanEnable awareness state
maxUsersintegeroptionalMaximum concurrent users
idleTimeoutintegerIdle timeout in milliseconds
conflictResolutionEnum<'ot' | 'crdt' | 'manual'>Conflict resolution strategy
persistencebooleanEnable operation persistence
snapshot{ enabled: boolean; interval: integer }optionalSnapshot configuration

CollaborativeCursor

Properties

PropertyTypeRequiredDescription
userIdstringUser identifier
sessionIdstringSession identifier
documentIdstringDocument identifier
userNamestringDisplay name of user
position{ line: integer; column: integer }Current cursor position
selection{ anchor: object; focus: object; direction?: Enum<'forward' | 'backward'> }optionalCurrent text selection
style{ color: Enum<'blue' | 'green' | 'red' | 'yellow' | 'purple' | 'orange' | 'pink' | 'teal' | 'indigo' | 'cyan'> | string; opacity: number; label?: string; showLabel: boolean; … }Visual style for this cursor
isTypingbooleanWhether user is currently typing
lastUpdatestringISO 8601 datetime of last cursor update
metadataRecord<string, any>optionalAdditional cursor metadata

CounterOperation

Properties

PropertyTypeRequiredDescription
replicaIdstringReplica identifier
deltaintegerChange amount (positive for increment, negative for decrement)
timestampstringISO 8601 datetime of operation

CursorColorPreset

Allowed Values

  • blue
  • green
  • red
  • yellow
  • purple
  • orange
  • pink
  • teal
  • indigo
  • cyan

CursorSelection

Properties

PropertyTypeRequiredDescription
anchor{ line: integer; column: integer }Selection anchor (start point)
focus{ line: integer; column: integer }Selection focus (end point)
directionEnum<'forward' | 'backward'>optionalSelection direction

CursorStyle

Properties

PropertyTypeRequiredDescription
colorEnum<'blue' | 'green' | 'red' | 'yellow' | 'purple' | 'orange' | 'pink' | 'teal' | 'indigo' | 'cyan'> | stringCursor color (preset or custom hex)
opacitynumberCursor opacity (0-1)
labelstringoptionalLabel to display with cursor (usually username)
showLabelbooleanWhether to show label
pulseOnUpdatebooleanWhether to pulse when cursor moves

CursorUpdate

Properties

PropertyTypeRequiredDescription
position{ line: integer; column: integer }optionalUpdated cursor position
selection{ anchor: object; focus: object; direction?: Enum<'forward' | 'backward'> }optionalUpdated selection
isTypingbooleanoptionalUpdated typing state
metadataRecord<string, any>optionalUpdated metadata

GCounter

Properties

PropertyTypeRequiredDescription
type'g-counter'
countsRecord<string, integer>Map of replica ID to count

LWWRegister

Properties

PropertyTypeRequiredDescription
type'lww-register'
valueanyCurrent register value
timestampstringISO 8601 datetime of last write
replicaIdstringID of replica that performed last write
vectorClock{ clock: Record<string, integer> }optionalOptional vector clock for causality tracking

ORSet

Properties

PropertyTypeRequiredDescription
type'or-set'
elements{ value: any; timestamp: string; replicaId: string; uid: string; … }[]Set elements with metadata

ORSetElement

Properties

PropertyTypeRequiredDescription
valueanyElement value
timestampstringAddition timestamp
replicaIdstringReplica that added the element
uidstringUnique identifier for this addition
removedbooleanWhether element has been removed

OTComponent

Union Options

This schema accepts one of the following structures:

Option 1

Type: insert

Properties

PropertyTypeRequiredDescription
type'insert'
textstringText to insert
attributesRecord<string, any>optionalText formatting attributes (e.g., bold, italic)

Option 2

Type: delete

Properties

PropertyTypeRequiredDescription
type'delete'
countintegerNumber of characters to delete

Option 3

Type: retain

Properties

PropertyTypeRequiredDescription
type'retain'
countintegerNumber of characters to retain
attributesRecord<string, any>optionalAttribute changes to apply


OTOperation

Properties

PropertyTypeRequiredDescription
operationIdstringUnique operation identifier
documentIdstringDocument identifier
userIdstringUser who created the operation
sessionIdstringSession identifier
components({ type: 'insert'; text: string; attributes?: Record<string, any> } | { type: 'delete'; count: integer } | { type: 'retain'; count: integer; attributes?: Record<string, any> })[]Operation components
baseVersionintegerDocument version this operation is based on
timestampstringISO 8601 datetime when operation was created
metadataRecord<string, any>optionalAdditional operation metadata

OTOperationType

Allowed Values

  • insert
  • delete
  • retain

OTTransformResult

Properties

PropertyTypeRequiredDescription
operation{ operationId: string; documentId: string; userId: string; sessionId: string; … }Transformed operation
transformedbooleanWhether transformation was applied
conflictsstring[]optionalConflict descriptions if any

PNCounter

Properties

PropertyTypeRequiredDescription
type'pn-counter'
positiveRecord<string, integer>Positive increments per replica
negativeRecord<string, integer>Negative increments per replica

TextCRDTOperation

Properties

PropertyTypeRequiredDescription
operationIdstringUnique operation identifier
replicaIdstringReplica identifier
positionintegerPosition in document
insertstringoptionalText to insert
deleteintegeroptionalNumber of characters to delete
timestampstringISO 8601 datetime of operation
lamportTimestampintegerLamport timestamp for ordering

TextCRDTState

Properties

PropertyTypeRequiredDescription
type'text'
documentIdstringDocument identifier
contentstringCurrent text content
operations{ operationId: string; replicaId: string; position: integer; insert?: string; … }[]History of operations
lamportClockintegerCurrent Lamport clock value
vectorClock{ clock: Record<string, integer> }Vector clock for causality

UserActivityStatus

Allowed Values

  • active
  • idle
  • viewing
  • disconnected

VectorClock

Properties

PropertyTypeRequiredDescription
clockRecord<string, integer>Map of replica ID to logical timestamp

On this page