@vuer-ai/vuer-rtc 0.1.3 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +14 -0
- package/.claude-plugin/plugin.json +12 -0
- package/.claude-plugin/skills/vuer-rtc.md +158 -0
- package/.pytest_cache/README.md +8 -0
- package/README.md +27 -12
- package/dist/client/EditBuffer.d.ts +10 -0
- package/dist/client/EditBuffer.d.ts.map +1 -1
- package/dist/client/EditBuffer.js +19 -1
- package/dist/client/EditBuffer.js.map +1 -1
- package/dist/client/actions.d.ts +12 -14
- package/dist/client/actions.d.ts.map +1 -1
- package/dist/client/actions.js +298 -164
- package/dist/client/actions.js.map +1 -1
- package/dist/client/createGraph.d.ts.map +1 -1
- package/dist/client/createGraph.js +4 -7
- package/dist/client/createGraph.js.map +1 -1
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/types.d.ts +2 -1
- package/dist/client/types.d.ts.map +1 -1
- package/dist/crdt/BTree.d.ts +102 -0
- package/dist/crdt/BTree.d.ts.map +1 -0
- package/dist/crdt/BTree.js +461 -0
- package/dist/crdt/BTree.js.map +1 -0
- package/dist/crdt/ContentTree.d.ts +102 -0
- package/dist/crdt/ContentTree.d.ts.map +1 -0
- package/dist/crdt/ContentTree.js +461 -0
- package/dist/crdt/ContentTree.js.map +1 -0
- package/dist/crdt/Rope.d.ts +31 -63
- package/dist/crdt/Rope.d.ts.map +1 -1
- package/dist/crdt/Rope.js +429 -306
- package/dist/crdt/Rope.js.map +1 -1
- package/dist/crdt/index.d.ts +2 -2
- package/dist/crdt/index.d.ts.map +1 -1
- package/dist/crdt/index.js +2 -2
- package/dist/crdt/index.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/operations/OperationTypes.d.ts +70 -9
- package/dist/operations/OperationTypes.d.ts.map +1 -1
- package/dist/operations/OperationValidator.d.ts +2 -0
- package/dist/operations/OperationValidator.d.ts.map +1 -1
- package/dist/operations/OperationValidator.js +37 -5
- package/dist/operations/OperationValidator.js.map +1 -1
- package/dist/operations/apply/array.js +4 -4
- package/dist/operations/apply/array.js.map +1 -1
- package/dist/operations/apply/boolean.js +3 -3
- package/dist/operations/apply/boolean.js.map +1 -1
- package/dist/operations/apply/color.js +2 -2
- package/dist/operations/apply/color.js.map +1 -1
- package/dist/operations/apply/euler.js +2 -2
- package/dist/operations/apply/euler.js.map +1 -1
- package/dist/operations/apply/index.d.ts +2 -2
- package/dist/operations/apply/index.d.ts.map +1 -1
- package/dist/operations/apply/index.js +2 -2
- package/dist/operations/apply/index.js.map +1 -1
- package/dist/operations/apply/node.d.ts +11 -1
- package/dist/operations/apply/node.d.ts.map +1 -1
- package/dist/operations/apply/node.js +62 -8
- package/dist/operations/apply/node.js.map +1 -1
- package/dist/operations/apply/number.js +5 -5
- package/dist/operations/apply/number.js.map +1 -1
- package/dist/operations/apply/object.js +5 -5
- package/dist/operations/apply/object.js.map +1 -1
- package/dist/operations/apply/quaternion.js +2 -2
- package/dist/operations/apply/quaternion.js.map +1 -1
- package/dist/operations/apply/string.js +2 -2
- package/dist/operations/apply/string.js.map +1 -1
- package/dist/operations/apply/text.d.ts +6 -2
- package/dist/operations/apply/text.d.ts.map +1 -1
- package/dist/operations/apply/text.js +48 -11
- package/dist/operations/apply/text.js.map +1 -1
- package/dist/operations/apply/types.d.ts +7 -3
- package/dist/operations/apply/types.d.ts.map +1 -1
- package/dist/operations/apply/types.js +47 -8
- package/dist/operations/apply/types.js.map +1 -1
- package/dist/operations/apply/vector3.js +5 -5
- package/dist/operations/apply/vector3.js.map +1 -1
- package/dist/operations/dispatcher.d.ts.map +1 -1
- package/dist/operations/dispatcher.js +25 -2
- package/dist/operations/dispatcher.js.map +1 -1
- package/dist/operations/index.d.ts +1 -1
- package/dist/operations/index.d.ts.map +1 -1
- package/dist/operations/index.js.map +1 -1
- package/dist/serdes.d.ts +47 -0
- package/dist/serdes.d.ts.map +1 -0
- package/dist/serdes.js +21 -0
- package/dist/serdes.js.map +1 -0
- package/dist/sync/BloomFilter.d.ts +31 -0
- package/dist/sync/BloomFilter.d.ts.map +1 -0
- package/dist/sync/BloomFilter.js +113 -0
- package/dist/sync/BloomFilter.js.map +1 -0
- package/dist/sync/digest.d.ts +28 -0
- package/dist/sync/digest.d.ts.map +1 -0
- package/dist/sync/digest.js +33 -0
- package/dist/sync/digest.js.map +1 -0
- package/dist/sync/index.d.ts +3 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +3 -0
- package/dist/sync/index.js.map +1 -0
- package/docs/RETRY.md +1 -1
- package/docs/rope-optimization-plan.md +329 -0
- package/examples/01-basic-usage.ts +4 -4
- package/examples/02-concurrent-edits.ts +7 -7
- package/examples/03-scene-building.ts +8 -8
- package/examples/04-conflict-resolution.ts +19 -19
- package/examples/README.md +5 -0
- package/package.json +4 -2
- package/skills/vuer-rtc/SKILL.md +164 -0
- package/src/client/EditBuffer.ts +17 -1
- package/src/client/actions.ts +307 -171
- package/src/client/createGraph.ts +5 -15
- package/src/client/index.ts +13 -0
- package/src/client/types.ts +2 -1
- package/src/crdt/BTree.ts +567 -0
- package/src/crdt/Rope.ts +470 -355
- package/src/crdt/index.ts +6 -2
- package/src/index.ts +11 -1
- package/src/operations/OperationTypes.ts +63 -11
- package/src/operations/OperationValidator.ts +45 -5
- package/src/operations/apply/array.ts +4 -4
- package/src/operations/apply/boolean.ts +3 -3
- package/src/operations/apply/color.ts +2 -2
- package/src/operations/apply/euler.ts +2 -2
- package/src/operations/apply/index.ts +2 -1
- package/src/operations/apply/node.ts +69 -9
- package/src/operations/apply/number.ts +5 -5
- package/src/operations/apply/object.ts +5 -5
- package/src/operations/apply/quaternion.ts +2 -2
- package/src/operations/apply/string.ts +2 -2
- package/src/operations/apply/text.ts +56 -10
- package/src/operations/apply/types.ts +56 -8
- package/src/operations/apply/vector3.ts +5 -5
- package/src/operations/dispatcher.ts +24 -2
- package/src/operations/index.ts +5 -0
- package/src/serdes.ts +39 -0
- package/src/sync/BloomFilter.ts +124 -0
- package/src/sync/digest.ts +45 -0
- package/src/sync/index.ts +2 -0
- package/tests/client/actions.test.ts +269 -5
- package/tests/crdt/btree.test.ts +455 -0
- package/tests/crdt/rope-benchmark.test.ts +67 -0
- package/tests/crdt/rope.test.ts +682 -13
- package/tests/crdt/text-operations.test.ts +3 -2
- package/tests/fixtures/benchmark_data/automerge-paper.json.gz +0 -0
- package/tests/fixtures/benchmark_data/clownschool_flat.json.gz +0 -0
- package/tests/fixtures/benchmark_data/friendsforever_flat.json.gz +0 -0
- package/tests/fixtures/benchmark_data/rustcode.json.gz +0 -0
- package/tests/fixtures/benchmark_data/seph-blog1.json.gz +0 -0
- package/tests/fixtures/benchmark_data/sveltecomponent.json.gz +0 -0
- package/tests/helpers/loadBenchmarkData.ts +63 -0
- package/tests/operations/collections.test.ts +1 -1
- package/tests/operations/nodes.test.ts +3 -3
- package/tests/operations/primitives.test.ts +1 -1
- package/tests/operations/unified-schema.test.ts +1 -1
- package/tests/operations/vectors.test.ts +1 -1
- package/tests/sync/bloom-filter.test.ts +83 -0
- package/tests/sync/digest.test.ts +77 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vuer-rtc",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "Ge Yang"
|
|
5
|
+
},
|
|
6
|
+
"description": "CRDT-based real-time collaborative state management for 3D scenes",
|
|
7
|
+
"plugins": [
|
|
8
|
+
{
|
|
9
|
+
"name": "vuer-rtc",
|
|
10
|
+
"source": "./",
|
|
11
|
+
"description": "vuer-rtc skills for real-time collaborative 3D scene editing"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vuer-rtc",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "CRDT-based real-time collaborative state management for 3D scenes",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Ge Yang"
|
|
7
|
+
},
|
|
8
|
+
"repository": "https://github.com/vuer-ai/vuer-rtc-workspace",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"keywords": ["crdt", "real-time", "collaboration", "3d", "scene-graph"],
|
|
11
|
+
"skills": "./skills/"
|
|
12
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# vuer-rtc Skill
|
|
2
|
+
|
|
3
|
+
CRDT-based real-time collaborative state management for 3D scenes and text.
|
|
4
|
+
|
|
5
|
+
## When to Use This Skill
|
|
6
|
+
|
|
7
|
+
Use when the user is working with:
|
|
8
|
+
- Real-time collaborative editing (multiplayer)
|
|
9
|
+
- Scene graph state management
|
|
10
|
+
- Collaborative text editing (TextRope CRDT)
|
|
11
|
+
- Undo/redo that syncs across clients
|
|
12
|
+
- React hooks for vuer-rtc
|
|
13
|
+
|
|
14
|
+
## Package Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
@vuer-ai/vuer-rtc
|
|
18
|
+
├── client/ → State management, actions, journal
|
|
19
|
+
├── crdt/ → TextRope for collaborative text
|
|
20
|
+
├── operations/ → Scene graph CRDT operations
|
|
21
|
+
├── hooks.ts → React integration
|
|
22
|
+
└── index.ts → Main exports
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Patterns
|
|
26
|
+
|
|
27
|
+
### 1. Basic Setup
|
|
28
|
+
```typescript
|
|
29
|
+
import { createGraph } from '@vuer-ai/vuer-rtc';
|
|
30
|
+
|
|
31
|
+
const store = createGraph({
|
|
32
|
+
sessionId: 'user-123',
|
|
33
|
+
onSend: (msg) => websocket.send(JSON.stringify(msg)),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
websocket.onmessage = (e) => store.receive(JSON.parse(e.data));
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Edit → Commit Flow
|
|
40
|
+
```typescript
|
|
41
|
+
// Edits are local-only until committed
|
|
42
|
+
store.edit({ otype: 'vector3.set', key: 'cube', path: 'position', value: [1, 2, 3] });
|
|
43
|
+
store.edit({ otype: 'number.set', key: 'cube', path: 'opacity', value: 0.5 });
|
|
44
|
+
|
|
45
|
+
// Commit sends all edits as one message
|
|
46
|
+
store.commit('Update cube');
|
|
47
|
+
|
|
48
|
+
// Or cancel uncommitted edits
|
|
49
|
+
store.cancel();
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3. Undo/Redo (Synced)
|
|
53
|
+
```typescript
|
|
54
|
+
store.undo(); // Creates meta.undo message, syncs to all clients
|
|
55
|
+
store.redo(); // Creates meta.redo message, syncs to all clients
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 4. React Hooks
|
|
59
|
+
```typescript
|
|
60
|
+
import { useGraph, useNode, useUndo } from '@vuer-ai/vuer-rtc';
|
|
61
|
+
|
|
62
|
+
function Component() {
|
|
63
|
+
const store = useGraph();
|
|
64
|
+
const cube = useNode('cube-1');
|
|
65
|
+
const { undo, redo, canUndo, canRedo } = useUndo();
|
|
66
|
+
|
|
67
|
+
return <mesh position={cube?.position} />;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 5. TextRope (Collaborative Text)
|
|
72
|
+
```typescript
|
|
73
|
+
import { create, getText, insertWithSplit, remove, replace } from '@vuer-ai/vuer-rtc/crdt';
|
|
74
|
+
|
|
75
|
+
const rope = create('agent-1');
|
|
76
|
+
insertWithSplit(rope, 0, 'Hello');
|
|
77
|
+
replace(rope, 0, 5, 'Hi'); // Atomic delete+insert
|
|
78
|
+
console.log(getText(rope)); // "Hi"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Operation Types (Quick Reference)
|
|
82
|
+
|
|
83
|
+
| Category | Operations |
|
|
84
|
+
|----------|------------|
|
|
85
|
+
| **Numbers** | `number.set`, `number.add`, `number.multiply`, `number.min`, `number.max` |
|
|
86
|
+
| **Vectors** | `vector3.set`, `vector3.add`, `vector3.multiply` |
|
|
87
|
+
| **Rotations** | `quaternion.set`, `euler.set` |
|
|
88
|
+
| **Booleans** | `boolean.set`, `boolean.and`, `boolean.or` |
|
|
89
|
+
| **Collections** | `array.set`, `array.push`, `array.remove`, `object.set`, `object.merge` |
|
|
90
|
+
| **Nodes** | `node.insert`, `node.remove` |
|
|
91
|
+
| **Text** | `text.init`, `text.insert`, `text.delete` |
|
|
92
|
+
| **Meta** | `meta.undo`, `meta.redo` |
|
|
93
|
+
|
|
94
|
+
## Conflict Resolution
|
|
95
|
+
|
|
96
|
+
| Pattern | Strategy |
|
|
97
|
+
|---------|----------|
|
|
98
|
+
| `*.set` | Last-Write-Wins (higher lamport timestamp) |
|
|
99
|
+
| `*.add`, `*.multiply` | Commutative merge |
|
|
100
|
+
| `meta.undo/redo` | Marks `deletedAt` on target message |
|
|
101
|
+
|
|
102
|
+
## Detailed Documentation
|
|
103
|
+
|
|
104
|
+
For in-depth API references, fetch these docs:
|
|
105
|
+
|
|
106
|
+
| Topic | URL |
|
|
107
|
+
|-------|-----|
|
|
108
|
+
| **Architecture** | https://rtc.vuer.ai/architecture |
|
|
109
|
+
| **Operations** | https://rtc.vuer.ai/operations |
|
|
110
|
+
| **TextRope CRDT** | https://rtc.vuer.ai/rope |
|
|
111
|
+
| **React Hooks** | https://rtc.vuer.ai/react-hooks |
|
|
112
|
+
| **Server Setup** | https://rtc.vuer.ai/server |
|
|
113
|
+
| **Examples** | https://rtc.vuer.ai/examples |
|
|
114
|
+
|
|
115
|
+
## Common Tasks
|
|
116
|
+
|
|
117
|
+
### Add a node to scene
|
|
118
|
+
```typescript
|
|
119
|
+
store.edit({
|
|
120
|
+
otype: 'node.insert',
|
|
121
|
+
key: 'parent-key', // Parent node ('' for root)
|
|
122
|
+
path: 'children',
|
|
123
|
+
value: { key: 'new-node', tag: 'Mesh', name: 'Cube' },
|
|
124
|
+
});
|
|
125
|
+
store.commit('Add cube');
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Update node property
|
|
129
|
+
```typescript
|
|
130
|
+
store.edit({
|
|
131
|
+
otype: 'vector3.set',
|
|
132
|
+
key: 'cube-1',
|
|
133
|
+
path: 'position',
|
|
134
|
+
value: [1, 2, 3],
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Initialize collaborative text
|
|
139
|
+
```typescript
|
|
140
|
+
store.edit({ otype: 'text.init', key: 'doc-1', path: 'content', value: 'Hello' });
|
|
141
|
+
store.edit({ otype: 'text.insert', key: 'doc-1', path: 'content', position: 5, value: ' World' });
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Handle reconnection
|
|
145
|
+
```typescript
|
|
146
|
+
// Get unacked messages to resend
|
|
147
|
+
const pending = store.getUnackedMessages();
|
|
148
|
+
pending.forEach(msg => websocket.send(JSON.stringify(msg)));
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Troubleshooting
|
|
152
|
+
|
|
153
|
+
| Issue | Solution |
|
|
154
|
+
|-------|----------|
|
|
155
|
+
| Edits not syncing | Check `store.commit()` was called |
|
|
156
|
+
| Undo not working | Ensure target message is acked by server |
|
|
157
|
+
| Text interleaving | Use `insertWithSplit()` instead of `insert()` |
|
|
158
|
+
| State divergence | Verify all clients receive same messages |
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# pytest cache directory #
|
|
2
|
+
|
|
3
|
+
This directory contains data from the pytest's cache plugin,
|
|
4
|
+
which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
|
|
5
|
+
|
|
6
|
+
**Do not** commit this to version control.
|
|
7
|
+
|
|
8
|
+
See [the docs](https://docs.pytest.org/en/stable/how-to/cache.html) for more information.
|
package/README.md
CHANGED
|
@@ -8,6 +8,19 @@ CRDT-based real-time collaborative state management for 3D scenes.
|
|
|
8
8
|
pnpm add @vuer-ai/vuer-rtc
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
## Claude Code Skill
|
|
12
|
+
|
|
13
|
+
Add vuer-rtc knowledge to Claude Code for CRDT-based real-time collaboration assistance:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Plugin marketplace
|
|
17
|
+
/plugin marketplace add vuer-ai/vuer-rtc-workspace
|
|
18
|
+
/plugin install vuer-rtc@vuer-rtc
|
|
19
|
+
|
|
20
|
+
# Or add to your CLAUDE.md
|
|
21
|
+
# @import https://raw.githubusercontent.com/vuer-ai/vuer-rtc-workspace/main/skill/vuer-rtc.md
|
|
22
|
+
```
|
|
23
|
+
|
|
11
24
|
## Quick Start
|
|
12
25
|
|
|
13
26
|
```typescript
|
|
@@ -80,18 +93,20 @@ function Node({ nodeKey }: { nodeKey: string }) {
|
|
|
80
93
|
|
|
81
94
|
## Operation Types
|
|
82
95
|
|
|
83
|
-
| Category | Operations |
|
|
84
|
-
|
|
85
|
-
|
|
|
86
|
-
|
|
|
87
|
-
|
|
|
88
|
-
|
|
|
89
|
-
|
|
|
90
|
-
|
|
|
91
|
-
|
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
|
96
|
+
| Category | Operations | Merge Behavior |
|
|
97
|
+
|----------|-----------|----------------|
|
|
98
|
+
| Node | `node.insert`, `node.remove`, `node.move` | Idempotent / Tombstone |
|
|
99
|
+
| Text | `text.init`, `text.insert`, `text.delete`, `text.replace` | CRDT (YATA) |
|
|
100
|
+
| Number | `number.set`, `number.add`, `number.multiply`, `number.min`, `number.max` | LWW / Commutative |
|
|
101
|
+
| String | `string.set`, `string.concat` | LWW / Append |
|
|
102
|
+
| Boolean | `boolean.set`, `boolean.or`, `boolean.and` | LWW / Commutative |
|
|
103
|
+
| Vector3 | `vector3.set`, `vector3.add`, `vector3.multiply`, `vector3.applyEuler`, `vector3.applyQuaternion` | LWW / Commutative |
|
|
104
|
+
| Euler | `euler.set`, `euler.add` | LWW / Commutative |
|
|
105
|
+
| Quaternion | `quaternion.set`, `quaternion.multiply` | LWW / Commutative |
|
|
106
|
+
| Color | `color.set`, `color.blend` | LWW / Blend |
|
|
107
|
+
| Array | `array.set`, `array.push`, `array.union`, `array.remove` | LWW / Set ops |
|
|
108
|
+
| Object | `object.set`, `object.merge` | LWW / Merge |
|
|
109
|
+
| Meta | `meta.undo`, `meta.redo` | Journal-based |
|
|
95
110
|
|
|
96
111
|
## Documentation
|
|
97
112
|
|
|
@@ -5,6 +5,16 @@
|
|
|
5
5
|
* Merges additive operations to reduce message size.
|
|
6
6
|
*/
|
|
7
7
|
import type { Operation } from '../operations/OperationTypes.js';
|
|
8
|
+
/**
|
|
9
|
+
* Compute the dedup key for an operation.
|
|
10
|
+
*
|
|
11
|
+
* Property operations use `key:path` — e.g. two `vector3.set` on the
|
|
12
|
+
* same node+path should merge/replace.
|
|
13
|
+
*
|
|
14
|
+
* Node structural operations include the target node key so that
|
|
15
|
+
* multiple inserts/removes under the same parent are NOT deduped.
|
|
16
|
+
*/
|
|
17
|
+
export declare function opDedupKey(op: Operation): string;
|
|
8
18
|
/**
|
|
9
19
|
* Check if an operation type is additive (can be merged)
|
|
10
20
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditBuffer.d.ts","sourceRoot":"","sources":["../../src/client/EditBuffer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAKnD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAyB1E;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,OAAO,CAAgB;IAE/B;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IAiBxB;;OAEG;IACH,MAAM,IAAI,SAAS,EAAE;IAIrB;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,IAAI,IAAI,MAAM;CAGf"}
|
|
1
|
+
{"version":3,"file":"EditBuffer.d.ts","sourceRoot":"","sources":["../../src/client/EditBuffer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAKhD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAKnD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAyB1E;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,OAAO,CAAgB;IAE/B;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IAiBxB;;OAEG;IACH,MAAM,IAAI,SAAS,EAAE;IAIrB;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,IAAI,IAAI,MAAM;CAGf"}
|
|
@@ -4,6 +4,24 @@
|
|
|
4
4
|
* Accumulates uncommitted operations during gestures (e.g., dragging).
|
|
5
5
|
* Merges additive operations to reduce message size.
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* Compute the dedup key for an operation.
|
|
9
|
+
*
|
|
10
|
+
* Property operations use `key:path` — e.g. two `vector3.set` on the
|
|
11
|
+
* same node+path should merge/replace.
|
|
12
|
+
*
|
|
13
|
+
* Node structural operations include the target node key so that
|
|
14
|
+
* multiple inserts/removes under the same parent are NOT deduped.
|
|
15
|
+
*/
|
|
16
|
+
export function opDedupKey(op) {
|
|
17
|
+
if (op.otype === 'node.insert')
|
|
18
|
+
return `${op.key}:${op.path}:insert:${op.value.key}`;
|
|
19
|
+
if (op.otype === 'node.remove')
|
|
20
|
+
return `${op.key}:${op.path}:remove:${op.value}`;
|
|
21
|
+
if (op.otype === 'node.move')
|
|
22
|
+
return `${op.key}:${op.path}:move:${op.value.nodeKey}`;
|
|
23
|
+
return `${op.key}:${op.path}`;
|
|
24
|
+
}
|
|
7
25
|
/**
|
|
8
26
|
* Check if an operation type is additive (can be merged)
|
|
9
27
|
*/
|
|
@@ -52,7 +70,7 @@ export class EditBufferImpl {
|
|
|
52
70
|
* Add or merge an operation
|
|
53
71
|
*/
|
|
54
72
|
add(op) {
|
|
55
|
-
const key =
|
|
73
|
+
const key = opDedupKey(op);
|
|
56
74
|
const existing = this.opsMap.get(key);
|
|
57
75
|
if (existing && existing.otype === op.otype && isAdditiveOp(op.otype)) {
|
|
58
76
|
// Merge additive ops
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditBuffer.js","sourceRoot":"","sources":["../../src/client/EditBuffer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,KAAK,KAAK,aAAa;QACvB,KAAK,KAAK,YAAY;QACtB,KAAK,KAAK,iBAAiB;QAC3B,KAAK,KAAK,qBAAqB,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,CAAU,EAAE,CAAU;IAC/D,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,EAAE,GAAG,CAA6B,CAAC;YACzC,MAAM,EAAE,GAAG,CAA6B,CAAC;YACzC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC;QACD,KAAK,YAAY;YACf,OAAQ,CAAY,GAAI,CAAY,CAAC;QACvC,KAAK,iBAAiB;YACpB,OAAQ,CAAY,GAAI,CAAY,CAAC;QACvC,KAAK,qBAAqB,CAAC,CAAC,CAAC;YAC3B,qCAAqC;YACrC,MAAM,EAAE,GAAG,CAAqC,CAAC;YACjD,MAAM,EAAE,GAAG,CAAqC,CAAC;YACjD,OAAO;gBACL,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC7D,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC7D,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC7D,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;aAC9D,CAAC;QACJ,CAAC;QACD;YACE,OAAO,CAAC,CAAC,CAAC,4BAA4B;IAC1C,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,cAAc;IACjB,MAAM,GAA2B,IAAI,GAAG,EAAE,CAAC;IAC3C,OAAO,GAAa,EAAE,CAAC;IAE/B;;OAEG;IACH,GAAG,CAAC,EAAa;QACf,MAAM,GAAG,GAAG,
|
|
1
|
+
{"version":3,"file":"EditBuffer.js","sourceRoot":"","sources":["../../src/client/EditBuffer.ts"],"names":[],"mappings":"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"}
|
package/dist/client/actions.d.ts
CHANGED
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Pure functions that transform ClientState.
|
|
5
5
|
* Used by createGraph and React hooks.
|
|
6
|
+
*
|
|
7
|
+
* No Immer — manual immutable state construction to avoid proxy issues
|
|
8
|
+
* with mutable CRDT structures (TextRope, B-tree back-pointers, WeakMaps).
|
|
6
9
|
*/
|
|
7
10
|
import type { CRDTMessage, Operation, SceneGraph } from '../operations/OperationTypes.js';
|
|
8
11
|
import type { ClientState, JournalEntry, Snapshot } from './types.js';
|
|
9
12
|
/**
|
|
10
|
-
* Generate a
|
|
13
|
+
* Generate a compact session ID (12-char nanoid, 2^72 entropy)
|
|
11
14
|
*/
|
|
12
15
|
export declare function generateUUID(): string;
|
|
13
16
|
/**
|
|
@@ -56,31 +59,26 @@ export declare function redo(state: ClientState): {
|
|
|
56
59
|
msg: CRDTMessage | null;
|
|
57
60
|
};
|
|
58
61
|
/**
|
|
59
|
-
* Action: Compact (create snapshot from acked entries)
|
|
62
|
+
* Action: Compact (create snapshot from acked entries).
|
|
63
|
+
*
|
|
64
|
+
* Folds all acknowledged entries into the snapshot and removes them from
|
|
65
|
+
* the journal. This reduces journal size (and bloom filter size for sync)
|
|
66
|
+
* but compacted entries can no longer be undone.
|
|
67
|
+
*
|
|
68
|
+
* Call this manually or on a periodic timer. Not called automatically
|
|
69
|
+
* because undo() requires target entries to be in the journal.
|
|
60
70
|
*/
|
|
61
71
|
export declare function compact(state: ClientState): ClientState;
|
|
62
72
|
/**
|
|
63
73
|
* Get unacknowledged messages for retry
|
|
64
|
-
*
|
|
65
|
-
* Returns messages that haven't been acknowledged by the server.
|
|
66
|
-
* Use this for implementing retry logic on network failures.
|
|
67
|
-
*
|
|
68
|
-
* @param state - Current client state
|
|
69
|
-
* @returns Array of messages that need to be (re)sent to server
|
|
70
74
|
*/
|
|
71
75
|
export declare function getUnackedMessages(state: ClientState): CRDTMessage[];
|
|
72
76
|
/**
|
|
73
77
|
* Check if there are pending messages to send
|
|
74
|
-
*
|
|
75
|
-
* @param state - Current client state
|
|
76
|
-
* @returns True if there are unacknowledged messages
|
|
77
78
|
*/
|
|
78
79
|
export declare function hasPendingMessages(state: ClientState): boolean;
|
|
79
80
|
/**
|
|
80
81
|
* Get count of pending (unacked) messages
|
|
81
|
-
*
|
|
82
|
-
* @param state - Current client state
|
|
83
|
-
* @returns Number of unacknowledged messages
|
|
84
82
|
*/
|
|
85
83
|
export declare function getPendingCount(state: ClientState): number;
|
|
86
84
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/client/actions.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/client/actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAa,MAAM,iCAAiC,CAAC;AACrG,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAQtE;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,QAAQ,GAAG,WAAW,CAkB7F;AAmGD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,YAAY,EAAE,EACvB,UAAU,EAAE,SAAS,EAAE,GACtB,UAAU,CAkCZ;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,GAAG,WAAW,CAiErE;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAA;CAAE,CA0BjD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAU3D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,CAK1E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,WAAW,GAAG,WAAW,CA8BjF;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAA;CAAE,CAyDxF;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAA;CAAE,CAoDxF;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CA0BvD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,EAAE,CAIpE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE9D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,WAAW,EAAE,GACrB,WAAW,CAqCb"}
|