Skip to content

Commit fb12cce

Browse files
Copilothotlong
andcommitted
feat: implement WebSocket and Collaboration protocols
- Created websocket.zod.ts with comprehensive WebSocket event protocol - Created collaboration.zod.ts with OT, CRDT, cursor sharing, and awareness - Added comprehensive test coverage for both protocols - Updated exports in index files - All tests passing and build successful Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent a39cebe commit fb12cce

67 files changed

Lines changed: 8515 additions & 1 deletion

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

content/docs/references/api/index.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ This section contains all protocol schemas for the api layer of ObjectStack.
1515
<Card href="./odata" title="Odata" description="Source: packages/spec/src/api/odata.zod.ts" />
1616
<Card href="./realtime" title="Realtime" description="Source: packages/spec/src/api/realtime.zod.ts" />
1717
<Card href="./router" title="Router" description="Source: packages/spec/src/api/router.zod.ts" />
18+
<Card href="./websocket" title="Websocket" description="Source: packages/spec/src/api/websocket.zod.ts" />
1819
</Cards>
1920

content/docs/references/api/meta.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"graphql",
88
"odata",
99
"realtime",
10-
"router"
10+
"router",
11+
"websocket"
1112
]
1213
}
Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
---
2+
title: Websocket
3+
description: Websocket protocol schemas
4+
---
5+
6+
# Websocket
7+
8+
<Callout type="info">
9+
**Source:** `packages/spec/src/api/websocket.zod.ts`
10+
</Callout>
11+
12+
## TypeScript Usage
13+
14+
```typescript
15+
import { AckMessageSchema, CursorMessageSchema, CursorPositionSchema, DocumentStateSchema, EditMessageSchema, EditOperationSchema, EditOperationTypeSchema, ErrorMessageSchema, EventFilterSchema, EventFilterConditionSchema, EventMessageSchema, EventPatternSchema, EventSubscriptionSchema, FilterOperatorSchema, PingMessageSchema, PongMessageSchema, PresenceMessageSchema, PresenceStateSchema, PresenceUpdateSchema, SubscribeMessageSchema, UnsubscribeMessageSchema, UnsubscribeRequestSchema, WebSocketConfigSchema, WebSocketMessageSchema, WebSocketMessageTypeSchema, WebSocketPresenceStatusSchema } from '@objectstack/spec/api';
16+
import type { AckMessage, CursorMessage, CursorPosition, DocumentState, EditMessage, EditOperation, EditOperationType, ErrorMessage, EventFilter, EventFilterCondition, EventMessage, EventPattern, EventSubscription, FilterOperator, PingMessage, PongMessage, PresenceMessage, PresenceState, PresenceUpdate, SubscribeMessage, UnsubscribeMessage, UnsubscribeRequest, WebSocketConfig, WebSocketMessage, WebSocketMessageType, WebSocketPresenceStatus } from '@objectstack/spec/api';
17+
18+
// Validate data
19+
const result = AckMessageSchema.parse(data);
20+
```
21+
22+
---
23+
24+
## AckMessage
25+
26+
### Properties
27+
28+
| Property | Type | Required | Description |
29+
| :--- | :--- | :--- | :--- |
30+
| **messageId** | `string` || Unique message identifier |
31+
| **type** | `string` || |
32+
| **timestamp** | `string` || ISO 8601 datetime when message was sent |
33+
| **ackMessageId** | `string` || ID of the message being acknowledged |
34+
| **success** | `boolean` || Whether the operation was successful |
35+
| **error** | `string` | optional | Error message if operation failed |
36+
37+
---
38+
39+
## CursorMessage
40+
41+
### Properties
42+
43+
| Property | Type | Required | Description |
44+
| :--- | :--- | :--- | :--- |
45+
| **messageId** | `string` || Unique message identifier |
46+
| **type** | `string` || |
47+
| **timestamp** | `string` || ISO 8601 datetime when message was sent |
48+
| **cursor** | `object` || Cursor position |
49+
50+
---
51+
52+
## CursorPosition
53+
54+
### Properties
55+
56+
| Property | Type | Required | Description |
57+
| :--- | :--- | :--- | :--- |
58+
| **userId** | `string` || User identifier |
59+
| **sessionId** | `string` || Session identifier |
60+
| **documentId** | `string` || Document identifier being edited |
61+
| **position** | `object` | optional | Cursor position in document |
62+
| **selection** | `object` | optional | Selection range (if text is selected) |
63+
| **color** | `string` | optional | Cursor color for visual representation |
64+
| **userName** | `string` | optional | Display name of user |
65+
| **lastUpdate** | `string` || ISO 8601 datetime of last cursor update |
66+
67+
---
68+
69+
## DocumentState
70+
71+
### Properties
72+
73+
| Property | Type | Required | Description |
74+
| :--- | :--- | :--- | :--- |
75+
| **documentId** | `string` || Document identifier |
76+
| **version** | `integer` || Current document version |
77+
| **content** | `string` || Current document content |
78+
| **lastModified** | `string` || ISO 8601 datetime of last modification |
79+
| **activeSessions** | `string[]` || Active editing session IDs |
80+
| **checksum** | `string` | optional | Content checksum for integrity verification |
81+
82+
---
83+
84+
## EditMessage
85+
86+
### Properties
87+
88+
| Property | Type | Required | Description |
89+
| :--- | :--- | :--- | :--- |
90+
| **messageId** | `string` || Unique message identifier |
91+
| **type** | `string` || |
92+
| **timestamp** | `string` || ISO 8601 datetime when message was sent |
93+
| **operation** | `object` || Edit operation |
94+
95+
---
96+
97+
## EditOperation
98+
99+
### Properties
100+
101+
| Property | Type | Required | Description |
102+
| :--- | :--- | :--- | :--- |
103+
| **operationId** | `string` || Unique operation identifier |
104+
| **documentId** | `string` || Document identifier |
105+
| **userId** | `string` || User who performed the edit |
106+
| **sessionId** | `string` || Session identifier |
107+
| **type** | `Enum<'insert' \| 'delete' \| 'replace'>` || Type of edit operation |
108+
| **position** | `object` || Starting position of the operation |
109+
| **endPosition** | `object` | optional | Ending position (for delete/replace operations) |
110+
| **content** | `string` | optional | Content to insert/replace |
111+
| **version** | `integer` || Document version before this operation |
112+
| **timestamp** | `string` || ISO 8601 datetime when operation was created |
113+
| **baseOperationId** | `string` | optional | Previous operation ID this builds upon (for OT) |
114+
115+
---
116+
117+
## EditOperationType
118+
119+
### Allowed Values
120+
121+
* `insert`
122+
* `delete`
123+
* `replace`
124+
125+
---
126+
127+
## ErrorMessage
128+
129+
### Properties
130+
131+
| Property | Type | Required | Description |
132+
| :--- | :--- | :--- | :--- |
133+
| **messageId** | `string` || Unique message identifier |
134+
| **type** | `string` || |
135+
| **timestamp** | `string` || ISO 8601 datetime when message was sent |
136+
| **code** | `string` || Error code |
137+
| **message** | `string` || Error message |
138+
| **details** | `any` | optional | Additional error details |
139+
140+
---
141+
142+
## EventFilter
143+
144+
### Properties
145+
146+
| Property | Type | Required | Description |
147+
| :--- | :--- | :--- | :--- |
148+
| **conditions** | `object[]` | optional | Array of filter conditions |
149+
| **and** | `any[]` | optional | AND logical combination of filters |
150+
| **or** | `any[]` | optional | OR logical combination of filters |
151+
| **not** | `any` | optional | NOT logical negation of filter |
152+
153+
---
154+
155+
## EventFilterCondition
156+
157+
### Properties
158+
159+
| Property | Type | Required | Description |
160+
| :--- | :--- | :--- | :--- |
161+
| **field** | `string` || Field path to filter on (supports dot notation, e.g., "user.email") |
162+
| **operator** | `Enum<'eq' \| 'ne' \| 'gt' \| 'gte' \| 'lt' \| 'lte' \| 'in' \| 'nin' \| 'contains' \| 'startsWith' \| 'endsWith' \| 'exists' \| 'regex'>` || Comparison operator |
163+
| **value** | `any` | optional | Value to compare against (not needed for "exists" operator) |
164+
165+
---
166+
167+
## EventMessage
168+
169+
### Properties
170+
171+
| Property | Type | Required | Description |
172+
| :--- | :--- | :--- | :--- |
173+
| **messageId** | `string` || Unique message identifier |
174+
| **type** | `string` || |
175+
| **timestamp** | `string` || ISO 8601 datetime when message was sent |
176+
| **subscriptionId** | `string` || Subscription ID this event belongs to |
177+
| **eventName** | `string` || Event name |
178+
| **object** | `string` | optional | Object name the event relates to |
179+
| **payload** | `any` | optional | Event payload data |
180+
| **userId** | `string` | optional | User who triggered the event |
181+
182+
---
183+
184+
## EventPattern
185+
186+
Event pattern (supports wildcards like "record.*" or "*.created")
187+
188+
---
189+
190+
## EventSubscription
191+
192+
### Properties
193+
194+
| Property | Type | Required | Description |
195+
| :--- | :--- | :--- | :--- |
196+
| **subscriptionId** | `string` || Unique subscription identifier |
197+
| **events** | `string[]` || Event patterns to subscribe to (supports wildcards, e.g., "record.*", "user.created") |
198+
| **objects** | `string[]` | optional | Object names to filter events by (e.g., ["account", "contact"]) |
199+
| **filters** | `object` | optional | Advanced filter conditions for event payloads |
200+
| **channels** | `string[]` | optional | Channel names for scoped subscriptions |
201+
202+
---
203+
204+
## FilterOperator
205+
206+
### Allowed Values
207+
208+
* `eq`
209+
* `ne`
210+
* `gt`
211+
* `gte`
212+
* `lt`
213+
* `lte`
214+
* `in`
215+
* `nin`
216+
* `contains`
217+
* `startsWith`
218+
* `endsWith`
219+
* `exists`
220+
* `regex`
221+
222+
---
223+
224+
## PingMessage
225+
226+
### Properties
227+
228+
| Property | Type | Required | Description |
229+
| :--- | :--- | :--- | :--- |
230+
| **messageId** | `string` || Unique message identifier |
231+
| **type** | `string` || |
232+
| **timestamp** | `string` || ISO 8601 datetime when message was sent |
233+
234+
---
235+
236+
## PongMessage
237+
238+
### Properties
239+
240+
| Property | Type | Required | Description |
241+
| :--- | :--- | :--- | :--- |
242+
| **messageId** | `string` || Unique message identifier |
243+
| **type** | `string` || |
244+
| **timestamp** | `string` || ISO 8601 datetime when message was sent |
245+
| **pingMessageId** | `string` | optional | ID of ping message being responded to |
246+
247+
---
248+
249+
## PresenceMessage
250+
251+
### Properties
252+
253+
| Property | Type | Required | Description |
254+
| :--- | :--- | :--- | :--- |
255+
| **messageId** | `string` || Unique message identifier |
256+
| **type** | `string` || |
257+
| **timestamp** | `string` || ISO 8601 datetime when message was sent |
258+
| **presence** | `object` || Presence state |
259+
260+
---
261+
262+
## PresenceState
263+
264+
### Properties
265+
266+
| Property | Type | Required | Description |
267+
| :--- | :--- | :--- | :--- |
268+
| **userId** | `string` || User identifier |
269+
| **sessionId** | `string` || Unique session identifier |
270+
| **status** | `Enum<'online' \| 'away' \| 'busy' \| 'offline'>` || Current presence status |
271+
| **lastSeen** | `string` || ISO 8601 datetime of last activity |
272+
| **currentLocation** | `string` | optional | Current page/route user is viewing |
273+
| **device** | `Enum<'desktop' \| 'mobile' \| 'tablet' \| 'other'>` | optional | Device type |
274+
| **customStatus** | `string` | optional | Custom user status message |
275+
| **metadata** | `Record<string, any>` | optional | Additional custom presence data |
276+
277+
---
278+
279+
## PresenceUpdate
280+
281+
### Properties
282+
283+
| Property | Type | Required | Description |
284+
| :--- | :--- | :--- | :--- |
285+
| **status** | `Enum<'online' \| 'away' \| 'busy' \| 'offline'>` | optional | Updated presence status |
286+
| **currentLocation** | `string` | optional | Updated current location |
287+
| **customStatus** | `string` | optional | Updated custom status message |
288+
| **metadata** | `Record<string, any>` | optional | Updated metadata |
289+
290+
---
291+
292+
## SubscribeMessage
293+
294+
### Properties
295+
296+
| Property | Type | Required | Description |
297+
| :--- | :--- | :--- | :--- |
298+
| **messageId** | `string` || Unique message identifier |
299+
| **type** | `string` || |
300+
| **timestamp** | `string` || ISO 8601 datetime when message was sent |
301+
| **subscription** | `object` || Subscription configuration |
302+
303+
---
304+
305+
## UnsubscribeMessage
306+
307+
### Properties
308+
309+
| Property | Type | Required | Description |
310+
| :--- | :--- | :--- | :--- |
311+
| **messageId** | `string` || Unique message identifier |
312+
| **type** | `string` || |
313+
| **timestamp** | `string` || ISO 8601 datetime when message was sent |
314+
| **request** | `object` || Unsubscribe request |
315+
316+
---
317+
318+
## UnsubscribeRequest
319+
320+
### Properties
321+
322+
| Property | Type | Required | Description |
323+
| :--- | :--- | :--- | :--- |
324+
| **subscriptionId** | `string` || Subscription ID to unsubscribe from |
325+
326+
---
327+
328+
## WebSocketConfig
329+
330+
### Properties
331+
332+
| Property | Type | Required | Description |
333+
| :--- | :--- | :--- | :--- |
334+
| **url** | `string` || WebSocket server URL |
335+
| **protocols** | `string[]` | optional | WebSocket sub-protocols |
336+
| **reconnect** | `boolean` | optional | Enable automatic reconnection |
337+
| **reconnectInterval** | `integer` | optional | Reconnection interval in milliseconds |
338+
| **maxReconnectAttempts** | `integer` | optional | Maximum reconnection attempts |
339+
| **pingInterval** | `integer` | optional | Ping interval in milliseconds |
340+
| **timeout** | `integer` | optional | Message timeout in milliseconds |
341+
| **headers** | `Record<string, string>` | optional | Custom headers for WebSocket handshake |
342+
343+
---
344+
345+
## WebSocketMessage
346+
347+
---
348+
349+
## WebSocketMessageType
350+
351+
### Allowed Values
352+
353+
* `subscribe`
354+
* `unsubscribe`
355+
* `event`
356+
* `ping`
357+
* `pong`
358+
* `ack`
359+
* `error`
360+
* `presence`
361+
* `cursor`
362+
* `edit`
363+
364+
---
365+
366+
## WebSocketPresenceStatus
367+
368+
### Allowed Values
369+
370+
* `online`
371+
* `away`
372+
* `busy`
373+
* `offline`
374+

0 commit comments

Comments
 (0)