Skip to content

Commit 0305b08

Browse files
authored
Merge pull request #386 from objectstack-ai/copilot/add-websocket-collaboration-features
2 parents 00174f1 + 850e555 commit 0305b08

File tree

10 files changed

+710
-4
lines changed

10 files changed

+710
-4
lines changed

content/docs/references/api/websocket.mdx

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ description: Websocket protocol schemas
1212
## TypeScript Usage
1313

1414
```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';
15+
import { AckMessageSchema, CursorMessageSchema, CursorPositionSchema, DocumentStateSchema, EditMessageSchema, EditOperationSchema, EditOperationTypeSchema, ErrorMessageSchema, EventFilterSchema, EventFilterConditionSchema, EventMessageSchema, EventPatternSchema, EventSubscriptionSchema, FilterOperatorSchema, PingMessageSchema, PongMessageSchema, PresenceMessageSchema, PresenceStateSchema, PresenceUpdateSchema, SimpleCursorPositionSchema, SimplePresenceStateSchema, SubscribeMessageSchema, UnsubscribeMessageSchema, UnsubscribeRequestSchema, WebSocketConfigSchema, WebSocketEventSchema, WebSocketMessageSchema, WebSocketMessageTypeSchema, WebSocketPresenceStatusSchema, WebSocketServerConfigSchema } 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, SimpleCursorPosition, SimplePresenceState, SubscribeMessage, UnsubscribeMessage, UnsubscribeRequest, WebSocketConfig, WebSocketEvent, WebSocketMessage, WebSocketMessageType, WebSocketPresenceStatus, WebSocketServerConfig } from '@objectstack/spec/api';
1717

1818
// Validate data
1919
const result = AckMessageSchema.parse(data);
@@ -289,6 +289,34 @@ Event pattern (supports wildcards like "record.*" or "*.created")
289289

290290
---
291291

292+
## SimpleCursorPosition
293+
294+
### Properties
295+
296+
| Property | Type | Required | Description |
297+
| :--- | :--- | :--- | :--- |
298+
| **userId** | `string` || User identifier |
299+
| **recordId** | `string` || Record identifier being edited |
300+
| **fieldName** | `string` || Field name being edited |
301+
| **position** | `number` || Cursor position (character offset from start) |
302+
| **selection** | `object` | optional | Text selection range (if text is selected) |
303+
304+
---
305+
306+
## SimplePresenceState
307+
308+
### Properties
309+
310+
| Property | Type | Required | Description |
311+
| :--- | :--- | :--- | :--- |
312+
| **userId** | `string` || User identifier |
313+
| **userName** | `string` || User display name |
314+
| **status** | `Enum<'online' \| 'away' \| 'offline'>` || User presence status |
315+
| **lastSeen** | `number` || Unix timestamp of last activity in milliseconds |
316+
| **metadata** | `Record<string, any>` | optional | Additional presence metadata (e.g., current page, custom status) |
317+
318+
---
319+
292320
## SubscribeMessage
293321

294322
### Properties
@@ -342,6 +370,19 @@ Event pattern (supports wildcards like "record.*" or "*.created")
342370

343371
---
344372

373+
## WebSocketEvent
374+
375+
### Properties
376+
377+
| Property | Type | Required | Description |
378+
| :--- | :--- | :--- | :--- |
379+
| **type** | `Enum<'subscribe' \| 'unsubscribe' \| 'data-change' \| 'presence-update' \| 'cursor-update' \| 'error'>` || Event type |
380+
| **channel** | `string` || Channel identifier (e.g., "record.account.123", "user.456") |
381+
| **payload** | `any` | optional | Event payload data |
382+
| **timestamp** | `number` || Unix timestamp in milliseconds |
383+
384+
---
385+
345386
## WebSocketMessage
346387

347388
---
@@ -372,3 +413,18 @@ Event pattern (supports wildcards like "record.*" or "*.created")
372413
* `busy`
373414
* `offline`
374415

416+
---
417+
418+
## WebSocketServerConfig
419+
420+
### Properties
421+
422+
| Property | Type | Required | Description |
423+
| :--- | :--- | :--- | :--- |
424+
| **enabled** | `boolean` | optional | Enable WebSocket server |
425+
| **path** | `string` | optional | WebSocket endpoint path |
426+
| **heartbeatInterval** | `number` | optional | Heartbeat interval in milliseconds |
427+
| **reconnectAttempts** | `number` | optional | Maximum reconnection attempts for clients |
428+
| **presence** | `boolean` | optional | Enable presence tracking |
429+
| **cursorSharing** | `boolean` | optional | Enable collaborative cursor sharing |
430+

content/docs/references/permission/permission.mdx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ description: Permission protocol schemas
1212
## TypeScript Usage
1313

1414
```typescript
15-
import { FieldPermissionSchema, ObjectPermissionSchema, PermissionSetSchema } from '@objectstack/spec/permission';
16-
import type { FieldPermission, ObjectPermission, PermissionSet } from '@objectstack/spec/permission';
15+
import { FieldPermissionSchema, ObjectPermissionSchema, PermissionSetSchema, RLSRuleSchema } from '@objectstack/spec/permission';
16+
import type { FieldPermission, ObjectPermission, PermissionSet, RLSRule } from '@objectstack/spec/permission';
1717

1818
// Validate data
1919
const result = FieldPermissionSchema.parse(data);
@@ -62,4 +62,21 @@ const result = FieldPermissionSchema.parse(data);
6262
| **objects** | `Record<string, object>` || Entity permissions |
6363
| **fields** | `Record<string, object>` | optional | Field level security |
6464
| **systemPermissions** | `string[]` | optional | System level capabilities |
65+
| **rls** | `object[]` | optional | Row-level security rules |
66+
| **contextVariables** | `Record<string, any>` | optional | Context variables for RLS evaluation |
67+
68+
---
69+
70+
## RLSRule
71+
72+
### Properties
73+
74+
| Property | Type | Required | Description |
75+
| :--- | :--- | :--- | :--- |
76+
| **name** | `string` || Rule unique identifier (snake_case) |
77+
| **objectName** | `string` || Target object name |
78+
| **operation** | `Enum<'read' \| 'create' \| 'update' \| 'delete'>` || Database operation this rule applies to |
79+
| **filter** | `object` || Filter condition for row-level access |
80+
| **enabled** | `boolean` | optional | Whether this rule is active |
81+
| **priority** | `number` | optional | Rule evaluation priority (higher = evaluated first) |
6582

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"$ref": "#/definitions/SimpleCursorPosition",
3+
"definitions": {
4+
"SimpleCursorPosition": {
5+
"type": "object",
6+
"properties": {
7+
"userId": {
8+
"type": "string",
9+
"description": "User identifier"
10+
},
11+
"recordId": {
12+
"type": "string",
13+
"description": "Record identifier being edited"
14+
},
15+
"fieldName": {
16+
"type": "string",
17+
"description": "Field name being edited"
18+
},
19+
"position": {
20+
"type": "number",
21+
"description": "Cursor position (character offset from start)"
22+
},
23+
"selection": {
24+
"type": "object",
25+
"properties": {
26+
"start": {
27+
"type": "number",
28+
"description": "Selection start position"
29+
},
30+
"end": {
31+
"type": "number",
32+
"description": "Selection end position"
33+
}
34+
},
35+
"required": [
36+
"start",
37+
"end"
38+
],
39+
"additionalProperties": false,
40+
"description": "Text selection range (if text is selected)"
41+
}
42+
},
43+
"required": [
44+
"userId",
45+
"recordId",
46+
"fieldName",
47+
"position"
48+
],
49+
"additionalProperties": false
50+
}
51+
},
52+
"$schema": "http://json-schema.org/draft-07/schema#"
53+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"$ref": "#/definitions/SimplePresenceState",
3+
"definitions": {
4+
"SimplePresenceState": {
5+
"type": "object",
6+
"properties": {
7+
"userId": {
8+
"type": "string",
9+
"description": "User identifier"
10+
},
11+
"userName": {
12+
"type": "string",
13+
"description": "User display name"
14+
},
15+
"status": {
16+
"type": "string",
17+
"enum": [
18+
"online",
19+
"away",
20+
"offline"
21+
],
22+
"description": "User presence status"
23+
},
24+
"lastSeen": {
25+
"type": "number",
26+
"description": "Unix timestamp of last activity in milliseconds"
27+
},
28+
"metadata": {
29+
"type": "object",
30+
"additionalProperties": {},
31+
"description": "Additional presence metadata (e.g., current page, custom status)"
32+
}
33+
},
34+
"required": [
35+
"userId",
36+
"userName",
37+
"status",
38+
"lastSeen"
39+
],
40+
"additionalProperties": false
41+
}
42+
},
43+
"$schema": "http://json-schema.org/draft-07/schema#"
44+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"$ref": "#/definitions/WebSocketEvent",
3+
"definitions": {
4+
"WebSocketEvent": {
5+
"type": "object",
6+
"properties": {
7+
"type": {
8+
"type": "string",
9+
"enum": [
10+
"subscribe",
11+
"unsubscribe",
12+
"data-change",
13+
"presence-update",
14+
"cursor-update",
15+
"error"
16+
],
17+
"description": "Event type"
18+
},
19+
"channel": {
20+
"type": "string",
21+
"description": "Channel identifier (e.g., \"record.account.123\", \"user.456\")"
22+
},
23+
"payload": {
24+
"description": "Event payload data"
25+
},
26+
"timestamp": {
27+
"type": "number",
28+
"description": "Unix timestamp in milliseconds"
29+
}
30+
},
31+
"required": [
32+
"type",
33+
"channel",
34+
"timestamp"
35+
],
36+
"additionalProperties": false
37+
}
38+
},
39+
"$schema": "http://json-schema.org/draft-07/schema#"
40+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"$ref": "#/definitions/WebSocketServerConfig",
3+
"definitions": {
4+
"WebSocketServerConfig": {
5+
"type": "object",
6+
"properties": {
7+
"enabled": {
8+
"type": "boolean",
9+
"default": false,
10+
"description": "Enable WebSocket server"
11+
},
12+
"path": {
13+
"type": "string",
14+
"default": "/ws",
15+
"description": "WebSocket endpoint path"
16+
},
17+
"heartbeatInterval": {
18+
"type": "number",
19+
"default": 30000,
20+
"description": "Heartbeat interval in milliseconds"
21+
},
22+
"reconnectAttempts": {
23+
"type": "number",
24+
"default": 5,
25+
"description": "Maximum reconnection attempts for clients"
26+
},
27+
"presence": {
28+
"type": "boolean",
29+
"default": false,
30+
"description": "Enable presence tracking"
31+
},
32+
"cursorSharing": {
33+
"type": "boolean",
34+
"default": false,
35+
"description": "Enable collaborative cursor sharing"
36+
}
37+
},
38+
"additionalProperties": false
39+
}
40+
},
41+
"$schema": "http://json-schema.org/draft-07/schema#"
42+
}

0 commit comments

Comments
 (0)