@vuer-ai/vuer-rtc 0.7.0 → 0.8.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.md +3 -2
- package/dist/client/EditBuffer.d.ts +4 -4
- package/dist/client/EditBuffer.d.ts.map +1 -1
- package/dist/client/EditBuffer.js +26 -25
- package/dist/client/EditBuffer.js.map +1 -1
- package/dist/client/actions.d.ts +3 -3
- package/dist/client/actions.d.ts.map +1 -1
- package/dist/client/actions.js +71 -70
- package/dist/client/actions.js.map +1 -1
- package/dist/client/coalesceGraphOps.d.ts +4 -4
- package/dist/client/coalesceGraphOps.js +4 -4
- package/dist/client/coalesceTextOperations.d.ts.map +1 -1
- package/dist/client/coalesceTextOperations.js +23 -20
- package/dist/client/coalesceTextOperations.js.map +1 -1
- package/dist/client/coalescence/lwwOperations.js +3 -3
- package/dist/client/coalescence/lwwOperations.js.map +1 -1
- package/dist/client/coalescence/numberOperations.js +2 -2
- package/dist/client/coalescence/numberOperations.js.map +1 -1
- package/dist/client/coalescence/registry.d.ts +3 -3
- package/dist/client/coalescence/registry.d.ts.map +1 -1
- package/dist/client/coalescence/registry.js +11 -11
- package/dist/client/coalescence/registry.js.map +1 -1
- package/dist/client/coalescence/textDeletes.d.ts +8 -7
- package/dist/client/coalescence/textDeletes.d.ts.map +1 -1
- package/dist/client/coalescence/textDeletes.js +11 -11
- package/dist/client/coalescence/textDeletes.js.map +1 -1
- package/dist/client/coalescence/textInserts.d.ts +8 -5
- package/dist/client/coalescence/textInserts.d.ts.map +1 -1
- package/dist/client/coalescence/textInserts.js +32 -12
- package/dist/client/coalescence/textInserts.js.map +1 -1
- package/dist/client/coalescence/utils.d.ts +3 -9
- package/dist/client/coalescence/utils.d.ts.map +1 -1
- package/dist/client/coalescence/utils.js +10 -8
- package/dist/client/coalescence/utils.js.map +1 -1
- package/dist/client/coalescence/vector3Operations.js +2 -2
- package/dist/client/coalescence/vector3Operations.js.map +1 -1
- package/dist/client/createGraph.d.ts +2 -2
- package/dist/client/createGraph.js +4 -4
- package/dist/client/createGraph.js.map +1 -1
- package/dist/client/createTextDocument.d.ts +1 -1
- package/dist/client/createTextDocument.js +3 -3
- package/dist/client/createTextDocument.js.map +1 -1
- package/dist/client/hooks.d.ts +3 -3
- package/dist/client/hooks.d.ts.map +1 -1
- package/dist/client/hooks.js +4 -4
- package/dist/client/hooks.js.map +1 -1
- package/dist/client/textActions.d.ts +2 -2
- package/dist/client/textActions.d.ts.map +1 -1
- package/dist/client/textActions.js +47 -47
- package/dist/client/textActions.js.map +1 -1
- package/dist/client/textTypes.d.ts +8 -8
- package/dist/client/textTypes.d.ts.map +1 -1
- package/dist/client/types.d.ts +4 -4
- package/dist/client/types.d.ts.map +1 -1
- package/dist/crdt/GraphTextCRDT.d.ts +2 -2
- package/dist/crdt/GraphTextCRDT.d.ts.map +1 -1
- package/dist/crdt/GraphTextCRDT.js +6 -6
- package/dist/crdt/GraphTextCRDT.js.map +1 -1
- package/dist/crdt/Rope.d.ts +13 -14
- package/dist/crdt/Rope.d.ts.map +1 -1
- package/dist/crdt/Rope.js +130 -59
- package/dist/crdt/Rope.js.map +1 -1
- package/dist/crdt/index.d.ts +1 -1
- package/dist/crdt/index.d.ts.map +1 -1
- package/dist/crdt/index.js +1 -1
- package/dist/crdt/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/operations/OperationTypes.d.ts +45 -48
- package/dist/operations/OperationTypes.d.ts.map +1 -1
- package/dist/operations/OperationValidator.js +11 -11
- package/dist/operations/OperationValidator.js.map +1 -1
- package/dist/operations/apply/node.js +3 -3
- package/dist/operations/apply/node.js.map +1 -1
- package/dist/operations/apply/text.d.ts.map +1 -1
- package/dist/operations/apply/text.js +35 -32
- package/dist/operations/apply/text.js.map +1 -1
- package/dist/operations/apply/types.d.ts +4 -4
- package/dist/operations/apply/types.d.ts.map +1 -1
- package/dist/operations/apply/types.js +8 -8
- package/dist/operations/apply/types.js.map +1 -1
- package/dist/operations/dispatcher.d.ts.map +1 -1
- package/dist/operations/dispatcher.js +52 -13
- package/dist/operations/dispatcher.js.map +1 -1
- package/dist/serdes.d.ts +1 -1
- package/dist/serdes.d.ts.map +1 -1
- package/dist/state/ConflictResolver.d.ts +9 -9
- package/dist/state/ConflictResolver.d.ts.map +1 -1
- package/dist/state/ConflictResolver.js +20 -20
- package/dist/state/ConflictResolver.js.map +1 -1
- package/dist/state/DType.d.ts +2 -2
- package/dist/state/DType.d.ts.map +1 -1
- package/dist/state/DType.js +14 -14
- package/dist/state/DType.js.map +1 -1
- package/dist/state/VectorClock.d.ts +6 -6
- package/dist/state/VectorClock.d.ts.map +1 -1
- package/dist/state/VectorClock.js +14 -14
- package/dist/state/VectorClock.js.map +1 -1
- package/dist/state/index.d.ts +1 -1
- package/dist/state/index.js +1 -1
- package/examples/01-basic-usage.ts +16 -16
- package/examples/02-concurrent-edits.ts +29 -29
- package/examples/03-scene-building.ts +28 -28
- package/examples/04-conflict-resolution.ts +56 -56
- package/examples/05-coalescence-usage.ts +23 -23
- package/examples/README.md +12 -12
- package/package.json +1 -1
- package/src/client/EditBuffer.ts +28 -27
- package/src/client/TEXT_DOCUMENT_API.md +9 -9
- package/src/client/actions.ts +74 -70
- package/src/client/coalesceGraphOps.ts +4 -4
- package/src/client/coalesceTextOperations.ts +26 -22
- package/src/client/coalescence/lwwOperations.ts +3 -3
- package/src/client/coalescence/numberOperations.ts +2 -2
- package/src/client/coalescence/registry.ts +13 -12
- package/src/client/coalescence/textDeletes.ts +22 -18
- package/src/client/coalescence/textInserts.ts +49 -25
- package/src/client/coalescence/utils.ts +14 -11
- package/src/client/coalescence/vector3Operations.ts +2 -2
- package/src/client/createGraph.ts +4 -4
- package/src/client/createTextDocument.ts +3 -3
- package/src/client/hooks.tsx +5 -5
- package/src/client/textActions.ts +47 -47
- package/src/client/textTypes.ts +8 -8
- package/src/client/types.ts +4 -4
- package/src/crdt/GraphTextCRDT.ts +6 -6
- package/src/crdt/Rope.ts +156 -71
- package/src/crdt/index.ts +2 -0
- package/src/index.ts +2 -0
- package/src/operations/OperationTypes.ts +47 -47
- package/src/operations/OperationValidator.ts +11 -11
- package/src/operations/apply/node.ts +3 -3
- package/src/operations/apply/text.ts +38 -32
- package/src/operations/apply/types.ts +11 -11
- package/src/operations/dispatcher.ts +57 -13
- package/src/serdes.ts +1 -1
- package/src/state/ConflictResolver.ts +23 -23
- package/src/state/DType.ts +16 -16
- package/src/state/VectorClock.ts +14 -14
- package/src/state/index.ts +1 -1
- package/tests/client/actions.test.ts +76 -76
- package/tests/client/coalesce-graph-operations.test.ts +84 -84
- package/tests/client/coalesce-text-operations.test.ts +91 -114
- package/tests/client/compaction.test.ts +18 -18
- package/tests/client/delete-coalescence-bug.test.ts +34 -34
- package/tests/client/edit-buffer.test.ts +27 -30
- package/tests/client/graph-coalescence-phase1.test.ts +66 -66
- package/tests/client/graph-coalescence.test.ts +50 -50
- package/tests/client/journal-benchmark.test.ts +5 -5
- package/tests/crdt/graph-text-crdt.test.ts +60 -64
- package/tests/crdt/rope.test.ts +9 -8
- package/tests/crdt/text-operations.test.ts +28 -28
- package/tests/fixtures/array-ops.jsonl +6 -6
- package/tests/fixtures/boolean-ops.jsonl +6 -6
- package/tests/fixtures/color-ops.jsonl +4 -4
- package/tests/fixtures/edit-buffer.jsonl +3 -3
- package/tests/fixtures/node-ops.jsonl +6 -6
- package/tests/fixtures/number-ops.jsonl +7 -7
- package/tests/fixtures/object-ops.jsonl +4 -4
- package/tests/fixtures/operations.jsonl +7 -7
- package/tests/fixtures/string-ops.jsonl +4 -4
- package/tests/fixtures/undo-redo.jsonl +3 -3
- package/tests/fixtures/vector-ops.jsonl +17 -17
- package/tests/operations/collections.test.ts +4 -4
- package/tests/operations/nodes.test.ts +5 -5
- package/tests/operations/operation-ordering.test.ts +406 -0
- package/tests/operations/primitives.test.ts +4 -4
- package/tests/operations/unified-schema.test.ts +27 -27
- package/tests/operations/vectors.test.ts +4 -4
- package/tests/sync/digest.test.ts +5 -5
|
@@ -69,7 +69,7 @@ export function TextInit(draft, op, meta) {
|
|
|
69
69
|
const node = draft.nodes[op.key];
|
|
70
70
|
if (!node)
|
|
71
71
|
return;
|
|
72
|
-
const rope = getOrCreateRope(node, op.path, meta.
|
|
72
|
+
const rope = getOrCreateRope(node, op.path, meta.client);
|
|
73
73
|
if (op.value && op.value.length > 0) {
|
|
74
74
|
insert(rope, 0, op.value);
|
|
75
75
|
}
|
|
@@ -82,25 +82,25 @@ export function TextInsert(draft, op, meta) {
|
|
|
82
82
|
const node = draft.nodes[op.key];
|
|
83
83
|
if (!node)
|
|
84
84
|
return;
|
|
85
|
-
const rope = getOrCreateRope(node, op.path, meta.
|
|
86
|
-
|
|
85
|
+
const rope = getOrCreateRope(node, op.path, meta.client);
|
|
86
|
+
const value = op.value;
|
|
87
|
+
if (op.id !== undefined && value !== undefined && op.seq !== undefined) {
|
|
87
88
|
// CRDT metadata format (replay from journal)
|
|
89
|
+
// Value is already [anchor, content] tuple
|
|
88
90
|
apply(rope, {
|
|
89
|
-
|
|
91
|
+
ot: 'insert',
|
|
90
92
|
id: op.id,
|
|
91
|
-
|
|
92
|
-
parentId: op.parentId ?? null,
|
|
93
|
+
value, // Pass tuple as-is
|
|
93
94
|
seq: op.seq,
|
|
94
95
|
ts: op.ts ?? Date.now() / 1000,
|
|
95
96
|
});
|
|
96
97
|
}
|
|
97
98
|
else if (op.position !== undefined && op.value !== undefined) {
|
|
98
99
|
// Position-based format (local edit) → convert to CRDT metadata in-place
|
|
99
|
-
|
|
100
|
-
const crdtOp = insertWithSplit(rope, op.position, op.value, meta.sessionId);
|
|
100
|
+
const crdtOp = insertWithSplit(rope, op.position, op.value, meta.client);
|
|
101
101
|
op.id = crdtOp.id;
|
|
102
|
-
|
|
103
|
-
op.
|
|
102
|
+
// Pack tuple: [anchor, content] - crdtOp.value is already [anchor, content]
|
|
103
|
+
op.value = crdtOp.value;
|
|
104
104
|
op.seq = crdtOp.seq;
|
|
105
105
|
op.ts = crdtOp.ts;
|
|
106
106
|
}
|
|
@@ -116,14 +116,17 @@ export function TextDelete(draft, op, meta) {
|
|
|
116
116
|
const rope = getRope(node, op.path);
|
|
117
117
|
if (!rope)
|
|
118
118
|
return;
|
|
119
|
-
|
|
119
|
+
const deletionsArray = op.rm;
|
|
120
|
+
if (deletionsArray !== undefined) {
|
|
120
121
|
// CRDT metadata format (replay from journal)
|
|
121
|
-
|
|
122
|
+
// rm is already in tuple format: [[id, len], ...]
|
|
123
|
+
applyDelete(rope, { ot: 'delete', rm: deletionsArray });
|
|
122
124
|
}
|
|
123
125
|
else if (op.position !== undefined && op.length !== undefined) {
|
|
124
126
|
// Position-based format (local edit) → convert to CRDT metadata in-place
|
|
125
127
|
const crdtOp = remove(rope, op.position, op.length);
|
|
126
|
-
|
|
128
|
+
// rm is already in tuple format from remove()
|
|
129
|
+
op.rm = crdtOp.rm;
|
|
127
130
|
}
|
|
128
131
|
// node[path] is the mutated TextRope
|
|
129
132
|
}
|
|
@@ -134,31 +137,31 @@ export function TextReplace(draft, op, meta) {
|
|
|
134
137
|
const node = draft.nodes[op.key];
|
|
135
138
|
if (!node)
|
|
136
139
|
return;
|
|
137
|
-
const rope = getOrCreateRope(node, op.path, meta.
|
|
138
|
-
|
|
140
|
+
const rope = getOrCreateRope(node, op.path, meta.client);
|
|
141
|
+
const deletionsArray = op.rm;
|
|
142
|
+
const value = op.value;
|
|
143
|
+
if (deletionsArray !== undefined && op.id !== undefined && op.seq !== undefined) {
|
|
139
144
|
// CRDT metadata format (replay from journal)
|
|
145
|
+
// Value is already [anchor, content] tuple
|
|
140
146
|
applyReplace(rope, {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
parentId: op.parentId ?? null,
|
|
148
|
-
seq: op.seq,
|
|
149
|
-
ts: op.ts ?? Date.now() / 1000,
|
|
150
|
-
},
|
|
147
|
+
ot: 'replace',
|
|
148
|
+
rm: deletionsArray,
|
|
149
|
+
id: op.id,
|
|
150
|
+
value: value ?? [null, ''], // Pass tuple as-is
|
|
151
|
+
seq: op.seq,
|
|
152
|
+
ts: op.ts ?? Date.now() / 1000,
|
|
151
153
|
});
|
|
152
154
|
}
|
|
153
155
|
else if (op.position !== undefined && op.length !== undefined && op.value !== undefined) {
|
|
154
156
|
// Position-based format (local edit) → convert to CRDT metadata in-place
|
|
155
|
-
const crdtOp = replace(rope, op.position, op.length, op.value, meta.
|
|
156
|
-
|
|
157
|
-
op.
|
|
158
|
-
op.
|
|
159
|
-
|
|
160
|
-
op.
|
|
161
|
-
op.
|
|
157
|
+
const crdtOp = replace(rope, op.position, op.length, op.value, meta.client);
|
|
158
|
+
// rm is already in tuple format from replace()
|
|
159
|
+
op.rm = crdtOp.rm;
|
|
160
|
+
op.id = crdtOp.id;
|
|
161
|
+
// Pack tuple: [anchor, content] - crdtOp.value is already [anchor, content]
|
|
162
|
+
op.value = crdtOp.value;
|
|
163
|
+
op.seq = crdtOp.seq;
|
|
164
|
+
op.ts = crdtOp.ts;
|
|
162
165
|
}
|
|
163
166
|
// node[path] is the mutated TextRope
|
|
164
167
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/operations/apply/text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAWH,OAAO,EACL,MAAM,EAEN,MAAM,EACN,eAAe,EACf,MAAM,EACN,OAAO,EACP,KAAK,EACL,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,IAAe,EAAE,IAAY,EAAE,OAAe;IACrE,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IAEzB,kCAAkC;IAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qBAAqB;IACrB,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+EAA+E;IAC/E,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;YAChC,+DAA+D;YAC/D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,4DAA4D;YAC5D,OAAO,CAAC,IAAI,CAAC,iCAAiC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,OAAO,CAAC,IAAe,EAAE,IAAY;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,KAAK,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CACtB,KAAiB,EACjB,EAAc,EACd,IAAY;IAEZ,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,CAAC,IAAI;QAAE,OAAO;IAElB,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/operations/apply/text.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,10 +7,10 @@ import type { SceneGraph, SceneNode } from '../OperationTypes.js';
|
|
|
7
7
|
* Operation metadata from the CRDTMessage envelope
|
|
8
8
|
*/
|
|
9
9
|
export interface OpMeta {
|
|
10
|
-
|
|
10
|
+
client: string;
|
|
11
11
|
clock: VectorClock;
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
lt: number;
|
|
13
|
+
ts: number;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Apply function signature - mutates draft in place (immer)
|
|
@@ -30,7 +30,7 @@ export declare function setNodeProperty(node: SceneNode, path: string, value: un
|
|
|
30
30
|
*
|
|
31
31
|
* Resolution is **per-property**: concurrent writes to different paths
|
|
32
32
|
* on the same node never conflict. For two writes to the same path,
|
|
33
|
-
* higher lamportTime wins. On tie, higher
|
|
33
|
+
* higher lamportTime wins. On tie, higher client ID wins (lexicographic).
|
|
34
34
|
* This ensures deterministic conflict resolution regardless of
|
|
35
35
|
* message arrival order.
|
|
36
36
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/operations/apply/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/operations/apply/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,MAAM,OAAO,CAAC,GAAG,IAAI,CACzB,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,GAAG,EACP,IAAI,EAAE,MAAM,KACT,IAAI,CAAC;AAEV;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,CAGpF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,GACX,IAAI,CAEN;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,GACX,IAAI,CAsBN"}
|
|
@@ -22,8 +22,8 @@ function getLWW(graph, nodeKey, path) {
|
|
|
22
22
|
function setLWW(graph, nodeKey, path, meta) {
|
|
23
23
|
const key = `${nodeKey}.${path}`;
|
|
24
24
|
graph.lww[key] = {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
lt: meta.lt,
|
|
26
|
+
client: meta.client,
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
@@ -31,7 +31,7 @@ function setLWW(graph, nodeKey, path, meta) {
|
|
|
31
31
|
*
|
|
32
32
|
* Resolution is **per-property**: concurrent writes to different paths
|
|
33
33
|
* on the same node never conflict. For two writes to the same path,
|
|
34
|
-
* higher lamportTime wins. On tie, higher
|
|
34
|
+
* higher lamportTime wins. On tie, higher client ID wins (lexicographic).
|
|
35
35
|
* This ensures deterministic conflict resolution regardless of
|
|
36
36
|
* message arrival order.
|
|
37
37
|
*/
|
|
@@ -43,18 +43,18 @@ export function setNodePropertyLWW(graph, node, path, value, meta) {
|
|
|
43
43
|
setLWW(graph, node.key, path, meta);
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
|
-
if (meta.
|
|
46
|
+
if (meta.lt > current.lt) {
|
|
47
47
|
// Strictly higher — always wins
|
|
48
48
|
node[path] = value;
|
|
49
49
|
setLWW(graph, node.key, path, meta);
|
|
50
50
|
}
|
|
51
|
-
else if (meta.
|
|
52
|
-
// Tie: higher
|
|
53
|
-
if (meta.
|
|
51
|
+
else if (meta.lt === current.lt) {
|
|
52
|
+
// Tie: higher client wins, or same client (last-write-wins within message)
|
|
53
|
+
if (meta.client >= current.client) {
|
|
54
54
|
node[path] = value;
|
|
55
55
|
setLWW(graph, node.key, path, meta);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
// meta.
|
|
58
|
+
// meta.lt < current.lt → skip (stale write)
|
|
59
59
|
}
|
|
60
60
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/operations/apply/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwBH;;GAEG;AACH,MAAM,UAAU,eAAe,CAAI,IAAe,EAAE,IAAY,EAAE,YAAe;IAC/E,MAAM,KAAK,GAAG,IAAI,CAAC,IAAuB,CAAC,CAAC;IAC5C,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAE,KAAW,CAAC,CAAC,CAAC,YAAY,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAe,EACf,IAAY,EACZ,KAAc,EACd,IAAY;IAEZ,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;AACrB,CAAC;AAQD,SAAS,MAAM,CAAC,KAAiB,EAAE,OAAe,EAAE,IAAY;IAC9D,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC;IACjC,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,MAAM,CAAC,KAAiB,EAAE,OAAe,EAAE,IAAY,EAAE,IAAY;IAC5E,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC;IACjC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG;QACf,
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/operations/apply/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwBH;;GAEG;AACH,MAAM,UAAU,eAAe,CAAI,IAAe,EAAE,IAAY,EAAE,YAAe;IAC/E,MAAM,KAAK,GAAG,IAAI,CAAC,IAAuB,CAAC,CAAC;IAC5C,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAE,KAAW,CAAC,CAAC,CAAC,YAAY,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAe,EACf,IAAY,EACZ,KAAc,EACd,IAAY;IAEZ,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;AACrB,CAAC;AAQD,SAAS,MAAM,CAAC,KAAiB,EAAE,OAAe,EAAE,IAAY;IAC9D,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC;IACjC,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,MAAM,CAAC,KAAiB,EAAE,OAAe,EAAE,IAAY,EAAE,IAAY;IAC5E,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC;IACjC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG;QACf,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAiB,EACjB,IAAe,EACf,IAAY,EACZ,KAAc,EACd,IAAY;IAEZ,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAE9C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,sDAAsD;QACtD,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QACnB,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACpC,OAAO;IACT,CAAC;IAED,IAAI,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,EAAE,CAAC;QACzB,gCAAgC;QAChC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QACnB,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;SAAM,IAAI,IAAI,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,EAAE,CAAC;QAClC,2EAA2E;QAC3E,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;YACnB,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,4CAA4C;AAC9C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/operations/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAgE/C;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,MAAM,GACX,IAAI,CAON;
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/operations/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAgE/C;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,MAAM,GACX,IAAI,CAON;AAgDD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,WAAW,GAAG,UAAU,CA4C5E;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAczE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,UAAU,CAMpF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI,CAIjF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAO7C"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import * as registry from './apply/index.js';
|
|
10
10
|
/**
|
|
11
|
-
* Handler map:
|
|
11
|
+
* Handler map: ot -> apply function
|
|
12
12
|
*/
|
|
13
13
|
const handlers = {
|
|
14
14
|
// Number operations
|
|
@@ -61,14 +61,47 @@ const handlers = {
|
|
|
61
61
|
* Apply a single operation to a SceneGraph (mutates in place)
|
|
62
62
|
*/
|
|
63
63
|
export function applyOperation(graph, op, meta) {
|
|
64
|
-
const handler = handlers[op.
|
|
64
|
+
const handler = handlers[op.ot];
|
|
65
65
|
if (handler) {
|
|
66
66
|
handler(graph, op, meta);
|
|
67
67
|
}
|
|
68
68
|
else {
|
|
69
|
-
console.warn(`Unknown
|
|
69
|
+
console.warn(`Unknown ot: ${op.ot}`);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Compare operations for sorting by Lamport timestamp.
|
|
74
|
+
* CRDT invariant: operations must be applied in causal order (seq → ts → id).
|
|
75
|
+
*
|
|
76
|
+
* This ensures that:
|
|
77
|
+
* 1. Operations with lower Lamport clocks are applied first
|
|
78
|
+
* 2. If Lamport clocks are equal, wall-clock time breaks the tie
|
|
79
|
+
* 3. If both are equal, lexicographic ID order ensures determinism
|
|
80
|
+
*
|
|
81
|
+
* @param a - First operation
|
|
82
|
+
* @param b - Second operation
|
|
83
|
+
* @returns Negative if a < b, positive if a > b, 0 if equal
|
|
84
|
+
*/
|
|
85
|
+
function compareOperations(a, b) {
|
|
86
|
+
const aOp = a;
|
|
87
|
+
const bOp = b;
|
|
88
|
+
// Compare by Lamport clock (seq)
|
|
89
|
+
if (aOp.seq !== undefined && bOp.seq !== undefined) {
|
|
90
|
+
if (aOp.seq !== bOp.seq)
|
|
91
|
+
return aOp.seq - bOp.seq;
|
|
92
|
+
}
|
|
93
|
+
// If equal or missing, compare by wall-clock time (ts)
|
|
94
|
+
if (aOp.ts !== undefined && bOp.ts !== undefined) {
|
|
95
|
+
if (aOp.ts !== bOp.ts)
|
|
96
|
+
return aOp.ts - bOp.ts;
|
|
97
|
+
}
|
|
98
|
+
// Final fallback: compare by ID (lexicographic)
|
|
99
|
+
if (aOp.id && bOp.id) {
|
|
100
|
+
return String(aOp.id).localeCompare(String(bOp.id));
|
|
101
|
+
}
|
|
102
|
+
// If no metadata, preserve original order
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
72
105
|
/**
|
|
73
106
|
* Shallow clone the graph and modified nodes
|
|
74
107
|
*/
|
|
@@ -91,25 +124,29 @@ export function applyMessage(graph, msg) {
|
|
|
91
124
|
// Shallow clone for immutability
|
|
92
125
|
const newGraph = shallowCloneGraph(graph);
|
|
93
126
|
const meta = {
|
|
94
|
-
|
|
127
|
+
client: msg.client,
|
|
95
128
|
clock: msg.clock,
|
|
96
|
-
|
|
97
|
-
|
|
129
|
+
lt: msg.lt,
|
|
130
|
+
ts: msg.ts,
|
|
98
131
|
};
|
|
99
|
-
|
|
132
|
+
// Sort operations by Lamport timestamp to ensure causal order
|
|
133
|
+
// This is critical for CRDT correctness, especially for text operations
|
|
134
|
+
// where replace ops may reference IDs from insert ops
|
|
135
|
+
const sortedOps = [...msg.ops].sort(compareOperations);
|
|
136
|
+
for (const op of sortedOps) {
|
|
100
137
|
// Determine all node keys that this operation will mutate
|
|
101
138
|
const keysToClone = [];
|
|
102
139
|
if (op.key && newGraph.nodes[op.key]) {
|
|
103
140
|
keysToClone.push(op.key);
|
|
104
141
|
}
|
|
105
|
-
if (op.
|
|
142
|
+
if (op.ot === 'node.move') {
|
|
106
143
|
const { nodeKey, newParent } = op.value;
|
|
107
144
|
if (nodeKey && newGraph.nodes[nodeKey])
|
|
108
145
|
keysToClone.push(nodeKey);
|
|
109
146
|
if (newParent && newGraph.nodes[newParent])
|
|
110
147
|
keysToClone.push(newParent);
|
|
111
148
|
}
|
|
112
|
-
if (op.
|
|
149
|
+
if (op.ot === 'node.remove') {
|
|
113
150
|
const nodeKey = op.value;
|
|
114
151
|
if (typeof nodeKey === 'string' && newGraph.nodes[nodeKey])
|
|
115
152
|
keysToClone.push(nodeKey);
|
|
@@ -135,12 +172,14 @@ export function applyMessage(graph, msg) {
|
|
|
135
172
|
*/
|
|
136
173
|
export function applyMessageMut(graph, msg) {
|
|
137
174
|
const meta = {
|
|
138
|
-
|
|
175
|
+
client: msg.client,
|
|
139
176
|
clock: msg.clock,
|
|
140
|
-
|
|
141
|
-
|
|
177
|
+
lt: msg.lt,
|
|
178
|
+
ts: msg.ts,
|
|
142
179
|
};
|
|
143
|
-
|
|
180
|
+
// Sort operations by Lamport timestamp to ensure causal order
|
|
181
|
+
const sortedOps = [...msg.ops].sort(compareOperations);
|
|
182
|
+
for (const op of sortedOps) {
|
|
144
183
|
applyOperation(graph, op, meta);
|
|
145
184
|
}
|
|
146
185
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/operations/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C;;GAEG;AACH,MAAM,QAAQ,GAA6E;IACzF,oBAAoB;IACpB,YAAY,EAAE,QAAQ,CAAC,SAAqE;IAC5F,YAAY,EAAE,QAAQ,CAAC,SAAqE;IAC5F,iBAAiB,EAAE,QAAQ,CAAC,cAA0E;IACtG,YAAY,EAAE,QAAQ,CAAC,SAAqE;IAC5F,YAAY,EAAE,QAAQ,CAAC,SAAqE;IAE5F,oBAAoB;IACpB,YAAY,EAAE,QAAQ,CAAC,SAAqE;IAC5F,eAAe,EAAE,QAAQ,CAAC,YAAwE;IAElG,+DAA+D;IAC/D,WAAW,EAAE,QAAQ,CAAC,QAAoE;IAC1F,aAAa,EAAE,QAAQ,CAAC,UAAsE;IAC9F,aAAa,EAAE,QAAQ,CAAC,UAAsE;IAC9F,cAAc,EAAE,QAAQ,CAAC,WAAuE;IAEhG,qBAAqB;IACrB,aAAa,EAAE,QAAQ,CAAC,UAAsE;IAC9F,YAAY,EAAE,QAAQ,CAAC,SAAqE;IAC5F,aAAa,EAAE,QAAQ,CAAC,UAAsE;IAE9F,qBAAqB;IACrB,aAAa,EAAE,QAAQ,CAAC,UAAsE;IAC9F,aAAa,EAAE,QAAQ,CAAC,UAAsE;IAC9F,kBAAkB,EAAE,QAAQ,CAAC,eAA2E;IACxG,oBAAoB,EAAE,QAAQ,CAAC,iBAA6E;IAC5G,yBAAyB,EAAE,QAAQ,CAAC,sBAAkF;IAEtH,mBAAmB;IACnB,WAAW,EAAE,QAAQ,CAAC,QAAoE;IAC1F,WAAW,EAAE,QAAQ,CAAC,QAAoE;IAE1F,wBAAwB;IACxB,gBAAgB,EAAE,QAAQ,CAAC,aAAyE;IACpG,qBAAqB,EAAE,QAAQ,CAAC,kBAA8E;IAE9G,mBAAmB;IACnB,WAAW,EAAE,QAAQ,CAAC,QAAoE;IAC1F,aAAa,EAAE,QAAQ,CAAC,UAAsE;IAE9F,mBAAmB;IACnB,WAAW,EAAE,QAAQ,CAAC,QAAoE;IAC1F,YAAY,EAAE,QAAQ,CAAC,SAAqE;IAC5F,cAAc,EAAE,QAAQ,CAAC,WAAuE;IAChG,aAAa,EAAE,QAAQ,CAAC,UAAsE;IAE9F,oBAAoB;IACpB,YAAY,EAAE,QAAQ,CAAC,SAAqE;IAC5F,cAAc,EAAE,QAAQ,CAAC,WAAuE;IAEhG,kBAAkB;IAClB,aAAa,EAAE,QAAQ,CAAC,UAAsE;IAC9F,aAAa,EAAE,QAAQ,CAAC,UAAsE;IAC9F,WAAW,EAAE,QAAQ,CAAC,QAAoE;CAC3F,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAiB,EACjB,EAAa,EACb,IAAY;IAEZ,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/operations/dispatcher.ts"],"names":[],"mappings":"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"}
|
package/dist/serdes.d.ts
CHANGED
package/dist/serdes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serdes.d.ts","sourceRoot":"","sources":["../src/serdes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,gCAAgC,CAAC;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAgB,MAAM,mBAAmB,CAAC;AAIhE,MAAM,MAAM,WAAW,GACnB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,WAAW,CAAA;CAAE,GACnC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,WAAW,CAAA;CAAE,GACxC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,WAAW,EAAE,CAAA;CAAE,GAC9D;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,
|
|
1
|
+
{"version":3,"file":"serdes.d.ts","sourceRoot":"","sources":["../src/serdes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,gCAAgC,CAAC;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAgB,MAAM,mBAAmB,CAAC;AAIhE,MAAM,MAAM,WAAW,GACnB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,WAAW,CAAA;CAAE,GACnC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,WAAW,CAAA;CAAE,GACxC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,WAAW,EAAE,CAAA;CAAE,GAC9D;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,WAAW,CAAA;CAAE,GAChE;IAAE,KAAK,EAAE,YAAY,CAAA;CAAE,GACvB;IAAE,KAAK,EAAE,sBAAsB,CAAC;IAAC,SAAS,EAAE,WAAW,CAAA;CAAE,CAAC;AAI9D,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,UAAU,CAKtD;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,WAAW,CAGvE"}
|
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
* ConflictResolver - Operation-based property conflict resolution
|
|
3
3
|
*
|
|
4
4
|
* Merges concurrent property updates based on:
|
|
5
|
-
* - Operation type (
|
|
5
|
+
* - Operation type (ot) which encodes dtype.operation
|
|
6
6
|
* - DType merge functions
|
|
7
7
|
*
|
|
8
|
-
* Schema-less: dtype and operation are derived from
|
|
8
|
+
* Schema-less: dtype and operation are derived from ot.
|
|
9
9
|
*/
|
|
10
10
|
import { type ValueWithMeta } from './DType.js';
|
|
11
11
|
/**
|
|
12
|
-
* Parse
|
|
12
|
+
* Parse ot string into dtype and operation
|
|
13
13
|
*
|
|
14
14
|
* @example
|
|
15
15
|
* parseOtype('vector3.add') // { dtype: 'vector3', operation: 'add' }
|
|
16
16
|
* parseOtype('number.set') // { dtype: 'number', operation: 'set' }
|
|
17
17
|
*/
|
|
18
|
-
export declare function parseOtype(
|
|
18
|
+
export declare function parseOtype(ot: string): {
|
|
19
19
|
dtype: string;
|
|
20
20
|
operation: string;
|
|
21
21
|
};
|
|
@@ -23,11 +23,11 @@ export declare class ConflictResolver {
|
|
|
23
23
|
/**
|
|
24
24
|
* Merge a single property from multiple concurrent updates
|
|
25
25
|
*
|
|
26
|
-
* @param
|
|
26
|
+
* @param ot - Operation type (e.g., 'vector3.add', 'number.set')
|
|
27
27
|
* @param values - Array of values with metadata
|
|
28
28
|
* @returns Merged value
|
|
29
29
|
*/
|
|
30
|
-
mergeProperty<T = any>(
|
|
30
|
+
mergeProperty<T = any>(ot: string, values: ValueWithMeta<T>[]): T;
|
|
31
31
|
/**
|
|
32
32
|
* Merge multiple properties from concurrent updates
|
|
33
33
|
*
|
|
@@ -36,9 +36,9 @@ export declare class ConflictResolver {
|
|
|
36
36
|
*/
|
|
37
37
|
mergeProperties(updates: Array<{
|
|
38
38
|
properties: Record<string, any>;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
ots: Record<string, string>;
|
|
40
|
+
lt: number;
|
|
41
|
+
client: string;
|
|
42
42
|
}>): Record<string, any>;
|
|
43
43
|
/**
|
|
44
44
|
* Get merge function for dtype and operation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConflictResolver.d.ts","sourceRoot":"","sources":["../../src/state/ConflictResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAS,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"ConflictResolver.d.ts","sourceRoot":"","sources":["../../src/state/ConflictResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAS,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAS3E;AAED,qBAAa,gBAAgB;IAC3B;;;;;;OAMG;IACH,aAAa,CAAC,CAAC,GAAG,GAAG,EACnB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,GACzB,CAAC;IAwBJ;;;;;OAKG;IACH,eAAe,CACb,OAAO,EAAE,KAAK,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC5B,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,GACD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAmCtB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAkGzB"}
|
|
@@ -2,45 +2,45 @@
|
|
|
2
2
|
* ConflictResolver - Operation-based property conflict resolution
|
|
3
3
|
*
|
|
4
4
|
* Merges concurrent property updates based on:
|
|
5
|
-
* - Operation type (
|
|
5
|
+
* - Operation type (ot) which encodes dtype.operation
|
|
6
6
|
* - DType merge functions
|
|
7
7
|
*
|
|
8
|
-
* Schema-less: dtype and operation are derived from
|
|
8
|
+
* Schema-less: dtype and operation are derived from ot.
|
|
9
9
|
*/
|
|
10
10
|
import { DType } from './DType.js';
|
|
11
11
|
/**
|
|
12
|
-
* Parse
|
|
12
|
+
* Parse ot string into dtype and operation
|
|
13
13
|
*
|
|
14
14
|
* @example
|
|
15
15
|
* parseOtype('vector3.add') // { dtype: 'vector3', operation: 'add' }
|
|
16
16
|
* parseOtype('number.set') // { dtype: 'number', operation: 'set' }
|
|
17
17
|
*/
|
|
18
|
-
export function parseOtype(
|
|
19
|
-
const dotIndex =
|
|
18
|
+
export function parseOtype(ot) {
|
|
19
|
+
const dotIndex = ot.indexOf('.');
|
|
20
20
|
if (dotIndex === -1) {
|
|
21
|
-
return { dtype:
|
|
21
|
+
return { dtype: ot, operation: 'set' };
|
|
22
22
|
}
|
|
23
23
|
return {
|
|
24
|
-
dtype:
|
|
25
|
-
operation:
|
|
24
|
+
dtype: ot.slice(0, dotIndex),
|
|
25
|
+
operation: ot.slice(dotIndex + 1),
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
export class ConflictResolver {
|
|
29
29
|
/**
|
|
30
30
|
* Merge a single property from multiple concurrent updates
|
|
31
31
|
*
|
|
32
|
-
* @param
|
|
32
|
+
* @param ot - Operation type (e.g., 'vector3.add', 'number.set')
|
|
33
33
|
* @param values - Array of values with metadata
|
|
34
34
|
* @returns Merged value
|
|
35
35
|
*/
|
|
36
|
-
mergeProperty(
|
|
36
|
+
mergeProperty(ot, values) {
|
|
37
37
|
if (values.length === 0) {
|
|
38
|
-
throw new Error(`Cannot merge empty values for
|
|
38
|
+
throw new Error(`Cannot merge empty values for ot: ${ot}`);
|
|
39
39
|
}
|
|
40
40
|
if (values.length === 1) {
|
|
41
41
|
return values[0].value;
|
|
42
42
|
}
|
|
43
|
-
const { dtype, operation } = parseOtype(
|
|
43
|
+
const { dtype, operation } = parseOtype(ot);
|
|
44
44
|
// Get merge function based on dtype and operation
|
|
45
45
|
const mergeFn = this.getMergeFunction(dtype, operation);
|
|
46
46
|
if (!mergeFn) {
|
|
@@ -58,7 +58,7 @@ export class ConflictResolver {
|
|
|
58
58
|
mergeProperties(updates) {
|
|
59
59
|
// Group values by property name
|
|
60
60
|
const valuesByProperty = new Map();
|
|
61
|
-
const
|
|
61
|
+
const otByProperty = new Map();
|
|
62
62
|
for (const update of updates) {
|
|
63
63
|
for (const [key, value] of Object.entries(update.properties)) {
|
|
64
64
|
if (!valuesByProperty.has(key)) {
|
|
@@ -66,20 +66,20 @@ export class ConflictResolver {
|
|
|
66
66
|
}
|
|
67
67
|
valuesByProperty.get(key).push({
|
|
68
68
|
value,
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
lt: update.lt,
|
|
70
|
+
client: update.client,
|
|
71
71
|
});
|
|
72
|
-
// Store
|
|
73
|
-
if (update.
|
|
74
|
-
|
|
72
|
+
// Store ot for this property
|
|
73
|
+
if (update.ots?.[key]) {
|
|
74
|
+
otByProperty.set(key, update.ots[key]);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
// Merge each property
|
|
79
79
|
const result = {};
|
|
80
80
|
for (const [propertyName, values] of valuesByProperty.entries()) {
|
|
81
|
-
const
|
|
82
|
-
result[propertyName] = this.mergeProperty(
|
|
81
|
+
const ot = otByProperty.get(propertyName) || 'any.set';
|
|
82
|
+
result[propertyName] = this.mergeProperty(ot, values);
|
|
83
83
|
}
|
|
84
84
|
return result;
|
|
85
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConflictResolver.js","sourceRoot":"","sources":["../../src/state/ConflictResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,EAAsB,MAAM,YAAY,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"ConflictResolver.js","sourceRoot":"","sources":["../../src/state/ConflictResolver.ts"],"names":[],"mappings":"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"}
|
package/dist/state/DType.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DType.d.ts","sourceRoot":"","sources":["../../src/state/DType.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,GAAG;IACpC,KAAK,EAAE,CAAC,CAAC;IACT,
|
|
1
|
+
{"version":3,"file":"DType.d.ts","sourceRoot":"","sources":["../../src/state/DType.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,GAAG;IACpC,KAAK,EAAE,CAAC,CAAC;IACT,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAEjE;;GAEG;AACH,eAAO,MAAM,KAAK;IAKhB;;OAEG;;QAED;;WAEG;aAIG,OAAO,CAAC,MAAM,CAAC;QAErB;;WAEG;aAGG,OAAO,CAAC,MAAM,CAAC;QAErB;;WAEG;kBAGG,OAAO,CAAC,MAAM,CAAC;QAErB;;WAEG;aAGG,OAAO,CAAC,MAAM,CAAC;QAErB;;WAEG;aAGG,OAAO,CAAC,MAAM,CAAC;;IAGvB;;OAEG;;QAED;;WAEG;aAIG,OAAO,CAAC,MAAM,CAAC;QAErB;;WAEG;gBAIG,OAAO,CAAC,MAAM,CAAC;;IAGvB;;OAEG;;QAED;;WAEG;aAIG,OAAO,CAAC,OAAO,CAAC;QAEtB;;WAEG;YAGG,OAAO,CAAC,OAAO,CAAC;QAEtB;;WAEG;aAGG,OAAO,CAAC,OAAO,CAAC;;IAOxB;;OAEG;;QAED;;WAEG;aAIG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAEvC;;WAEG;aASG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAEvC;;WAEG;kBASG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;;IAGzC;;OAEG;;QAED;;WAEG;aAIG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAE/C;;WAEG;kBAUG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;;IAGjD;;OAEG;;QAED;;WAEG;aAIG,OAAO,CAAC,MAAM,CAAC;QAErB;;WAEG;eAOG,OAAO,CAAC,MAAM,CAAC;;IAOvB;;OAEG;;QAED;;WAEG;aAIG,OAAO,CAAC,GAAG,EAAE,CAAC;QAEpB;;WAEG;eAIG,OAAO,CAAC,GAAG,EAAE,CAAC;QAEpB;;WAEG;gBAIG,OAAO,CAAC,GAAG,EAAE,CAAC;;IAGtB;;OAEG;;QAED;;WAEG;aAIG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAElC;;WAEG;mBAeG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;;IAOpC;;OAEG;;aAMK,OAAO;;CAEhB,CAAC"}
|