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
| Property | Type | Required | Description |
|---|---|---|---|
| eventId | string | ✅ | Event identifier |
| sessionId | string | ✅ | Session identifier |
| eventType | Enum<'user.joined' | 'user.left' | 'user.updated' | 'session.created' | 'session.ended'> | ✅ | Type of awareness event |
| userId | string | optional | User involved in event |
| timestamp | string | ✅ | ISO 8601 datetime of event |
| payload | any | ✅ | Event payload |
AwarenessSession
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| sessionId | string | ✅ | Session identifier |
| documentId | string | optional | Document ID this session is for |
| users | { userId: string; sessionId: string; userName: string; userAvatar?: string; … }[] | ✅ | Active users in session |
| startedAt | string | ✅ | ISO 8601 datetime when session started |
| lastUpdate | string | ✅ | ISO 8601 datetime of last update |
| metadata | Record<string, any> | optional | Session metadata |
AwarenessUpdate
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| status | Enum<'active' | 'idle' | 'viewing' | 'disconnected'> | optional | Updated status |
| currentDocument | string | optional | Updated current document |
| currentView | string | optional | Updated current view |
| metadata | Record<string, any> | optional | Updated metadata |
AwarenessUserState
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| userId | string | ✅ | User identifier |
| sessionId | string | ✅ | Session identifier |
| userName | string | ✅ | Display name |
| userAvatar | string | optional | User avatar URL |
| status | Enum<'active' | 'idle' | 'viewing' | 'disconnected'> | ✅ | Current activity status |
| currentDocument | string | optional | Document ID user is currently editing |
| currentView | string | optional | Current view/page user is on |
| lastActivity | string | ✅ | ISO 8601 datetime of last activity |
| joinedAt | string | ✅ | ISO 8601 datetime when user joined session |
| permissions | string[] | optional | User permissions in this session |
| metadata | Record<string, any> | optional | Additional user state metadata |
CRDTMergeResult
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| 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 more | ✅ | Merged CRDT state |
| conflicts | { type: string; description: string; resolved: boolean }[] | optional | Conflicts encountered during merge |
CRDTState
Union Options
This schema accepts one of the following structures:
Option 1
Type: lww-register
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'lww-register' | ✅ | |
| value | any | ✅ | Current register value |
| timestamp | string | ✅ | ISO 8601 datetime of last write |
| replicaId | string | ✅ | ID of replica that performed last write |
| vectorClock | { clock: Record<string, integer> } | optional | Optional vector clock for causality tracking |
Option 2
Type: g-counter
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'g-counter' | ✅ | |
| counts | Record<string, integer> | ✅ | Map of replica ID to count |
Option 3
Type: pn-counter
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'pn-counter' | ✅ | |
| positive | Record<string, integer> | ✅ | Positive increments per replica |
| negative | Record<string, integer> | ✅ | Negative increments per replica |
Option 4
Type: or-set
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'or-set' | ✅ | |
| elements | { value: any; timestamp: string; replicaId: string; uid: string; … }[] | ✅ | Set elements with metadata |
Option 5
Type: text
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'text' | ✅ | |
| documentId | string | ✅ | Document identifier |
| content | string | ✅ | Current text content |
| operations | { operationId: string; replicaId: string; position: integer; insert?: string; … }[] | ✅ | History of operations |
| lamportClock | integer | ✅ | Current Lamport clock value |
| vectorClock | { clock: Record<string, integer> } | ✅ | Vector clock for causality |
CRDTType
Allowed Values
lww-registerg-counterpn-counterg-setor-setlww-maptexttreejson
CollaborationMode
Allowed Values
otcrdtlockhybrid
CollaborationSession
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| sessionId | string | ✅ | Session identifier |
| documentId | string | ✅ | Document 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 |
| version | integer | ✅ | Current document version |
| operations | ({ operationId: string; documentId: string; userId: string; sessionId: string; … } | { operationId: string; replicaId: string; position: integer; insert?: string; … })[] | optional | Recent operations |
| createdAt | string | ✅ | ISO 8601 datetime when session was created |
| lastActivity | string | ✅ | ISO 8601 datetime of last activity |
| status | Enum<'active' | 'idle' | 'ended'> | ✅ | Session status |
CollaborationSessionConfig
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| mode | Enum<'ot' | 'crdt' | 'lock' | 'hybrid'> | ✅ | Collaboration mode to use |
| enableCursorSharing | boolean | ✅ | Enable cursor sharing |
| enablePresence | boolean | ✅ | Enable presence tracking |
| enableAwareness | boolean | ✅ | Enable awareness state |
| maxUsers | integer | optional | Maximum concurrent users |
| idleTimeout | integer | ✅ | Idle timeout in milliseconds |
| conflictResolution | Enum<'ot' | 'crdt' | 'manual'> | ✅ | Conflict resolution strategy |
| persistence | boolean | ✅ | Enable operation persistence |
| snapshot | { enabled: boolean; interval: integer } | optional | Snapshot configuration |
CollaborativeCursor
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| userId | string | ✅ | User identifier |
| sessionId | string | ✅ | Session identifier |
| documentId | string | ✅ | Document identifier |
| userName | string | ✅ | Display name of user |
| position | { line: integer; column: integer } | ✅ | Current cursor position |
| selection | { anchor: object; focus: object; direction?: Enum<'forward' | 'backward'> } | optional | Current 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 |
| isTyping | boolean | ✅ | Whether user is currently typing |
| lastUpdate | string | ✅ | ISO 8601 datetime of last cursor update |
| metadata | Record<string, any> | optional | Additional cursor metadata |
CounterOperation
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| replicaId | string | ✅ | Replica identifier |
| delta | integer | ✅ | Change amount (positive for increment, negative for decrement) |
| timestamp | string | ✅ | ISO 8601 datetime of operation |
CursorColorPreset
Allowed Values
bluegreenredyellowpurpleorangepinktealindigocyan
CursorSelection
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| anchor | { line: integer; column: integer } | ✅ | Selection anchor (start point) |
| focus | { line: integer; column: integer } | ✅ | Selection focus (end point) |
| direction | Enum<'forward' | 'backward'> | optional | Selection direction |
CursorStyle
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| color | Enum<'blue' | 'green' | 'red' | 'yellow' | 'purple' | 'orange' | 'pink' | 'teal' | 'indigo' | 'cyan'> | string | ✅ | Cursor color (preset or custom hex) |
| opacity | number | ✅ | Cursor opacity (0-1) |
| label | string | optional | Label to display with cursor (usually username) |
| showLabel | boolean | ✅ | Whether to show label |
| pulseOnUpdate | boolean | ✅ | Whether to pulse when cursor moves |
CursorUpdate
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| position | { line: integer; column: integer } | optional | Updated cursor position |
| selection | { anchor: object; focus: object; direction?: Enum<'forward' | 'backward'> } | optional | Updated selection |
| isTyping | boolean | optional | Updated typing state |
| metadata | Record<string, any> | optional | Updated metadata |
GCounter
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'g-counter' | ✅ | |
| counts | Record<string, integer> | ✅ | Map of replica ID to count |
LWWRegister
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'lww-register' | ✅ | |
| value | any | ✅ | Current register value |
| timestamp | string | ✅ | ISO 8601 datetime of last write |
| replicaId | string | ✅ | ID of replica that performed last write |
| vectorClock | { clock: Record<string, integer> } | optional | Optional vector clock for causality tracking |
ORSet
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'or-set' | ✅ | |
| elements | { value: any; timestamp: string; replicaId: string; uid: string; … }[] | ✅ | Set elements with metadata |
ORSetElement
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| value | any | ✅ | Element value |
| timestamp | string | ✅ | Addition timestamp |
| replicaId | string | ✅ | Replica that added the element |
| uid | string | ✅ | Unique identifier for this addition |
| removed | boolean | ✅ | Whether element has been removed |
OTComponent
Union Options
This schema accepts one of the following structures:
Option 1
Type: insert
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'insert' | ✅ | |
| text | string | ✅ | Text to insert |
| attributes | Record<string, any> | optional | Text formatting attributes (e.g., bold, italic) |
Option 2
Type: delete
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'delete' | ✅ | |
| count | integer | ✅ | Number of characters to delete |
Option 3
Type: retain
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'retain' | ✅ | |
| count | integer | ✅ | Number of characters to retain |
| attributes | Record<string, any> | optional | Attribute changes to apply |
OTOperation
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| operationId | string | ✅ | Unique operation identifier |
| documentId | string | ✅ | Document identifier |
| userId | string | ✅ | User who created the operation |
| sessionId | string | ✅ | Session identifier |
| components | ({ type: 'insert'; text: string; attributes?: Record<string, any> } | { type: 'delete'; count: integer } | { type: 'retain'; count: integer; attributes?: Record<string, any> })[] | ✅ | Operation components |
| baseVersion | integer | ✅ | Document version this operation is based on |
| timestamp | string | ✅ | ISO 8601 datetime when operation was created |
| metadata | Record<string, any> | optional | Additional operation metadata |
OTOperationType
Allowed Values
insertdeleteretain
OTTransformResult
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| operation | { operationId: string; documentId: string; userId: string; sessionId: string; … } | ✅ | Transformed operation |
| transformed | boolean | ✅ | Whether transformation was applied |
| conflicts | string[] | optional | Conflict descriptions if any |
PNCounter
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'pn-counter' | ✅ | |
| positive | Record<string, integer> | ✅ | Positive increments per replica |
| negative | Record<string, integer> | ✅ | Negative increments per replica |
TextCRDTOperation
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| operationId | string | ✅ | Unique operation identifier |
| replicaId | string | ✅ | Replica identifier |
| position | integer | ✅ | Position in document |
| insert | string | optional | Text to insert |
| delete | integer | optional | Number of characters to delete |
| timestamp | string | ✅ | ISO 8601 datetime of operation |
| lamportTimestamp | integer | ✅ | Lamport timestamp for ordering |
TextCRDTState
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'text' | ✅ | |
| documentId | string | ✅ | Document identifier |
| content | string | ✅ | Current text content |
| operations | { operationId: string; replicaId: string; position: integer; insert?: string; … }[] | ✅ | History of operations |
| lamportClock | integer | ✅ | Current Lamport clock value |
| vectorClock | { clock: Record<string, integer> } | ✅ | Vector clock for causality |
UserActivityStatus
Allowed Values
activeidleviewingdisconnected
VectorClock
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| clock | Record<string, integer> | ✅ | Map of replica ID to logical timestamp |