@vuer-ai/vuer-rtc-server 0.2.3 → 0.4.1

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.
Files changed (104) hide show
  1. package/.env +1 -1
  2. package/README.md +56 -0
  3. package/dist/archive/ArchivalService.js +1 -1
  4. package/dist/archive/ArchivalService.js.map +1 -1
  5. package/dist/broker/InMemoryBroker.d.ts +2 -2
  6. package/dist/broker/InMemoryBroker.d.ts.map +1 -1
  7. package/dist/broker/InMemoryBroker.js +4 -4
  8. package/dist/broker/InMemoryBroker.js.map +1 -1
  9. package/dist/broker/types.d.ts +3 -3
  10. package/dist/broker/types.d.ts.map +1 -1
  11. package/dist/journal/CoalescingService.d.ts.map +1 -1
  12. package/dist/journal/CoalescingService.js +18 -208
  13. package/dist/journal/CoalescingService.js.map +1 -1
  14. package/dist/journal/GraphJournalService.d.ts +127 -0
  15. package/dist/journal/GraphJournalService.d.ts.map +1 -0
  16. package/dist/journal/GraphJournalService.js +491 -0
  17. package/dist/journal/GraphJournalService.js.map +1 -0
  18. package/dist/journal/JournalRLE.d.ts +2 -2
  19. package/dist/journal/JournalRLE.js +14 -14
  20. package/dist/journal/JournalRLE.js.map +1 -1
  21. package/dist/journal/JournalRepository.js +7 -7
  22. package/dist/journal/JournalRepository.js.map +1 -1
  23. package/dist/journal/JournalService.d.ts.map +1 -1
  24. package/dist/journal/JournalService.js +6 -40
  25. package/dist/journal/JournalService.js.map +1 -1
  26. package/dist/journal/RLECompression.d.ts +9 -9
  27. package/dist/journal/RLECompression.d.ts.map +1 -1
  28. package/dist/journal/RLECompression.js +22 -22
  29. package/dist/journal/RLECompression.js.map +1 -1
  30. package/dist/journal/TextJournalService.d.ts +98 -0
  31. package/dist/journal/TextJournalService.d.ts.map +1 -0
  32. package/dist/journal/TextJournalService.js +401 -0
  33. package/dist/journal/TextJournalService.js.map +1 -0
  34. package/dist/journal/index.d.ts +3 -1
  35. package/dist/journal/index.d.ts.map +1 -1
  36. package/dist/journal/index.js +4 -1
  37. package/dist/journal/index.js.map +1 -1
  38. package/dist/journal/rle-demo.js +11 -11
  39. package/dist/journal/rle-demo.js.map +1 -1
  40. package/dist/serve.d.ts +29 -11
  41. package/dist/serve.d.ts.map +1 -1
  42. package/dist/serve.js +558 -93
  43. package/dist/serve.js.map +1 -1
  44. package/dist/transport/RTCServer.d.ts +2 -2
  45. package/dist/transport/RTCServer.d.ts.map +1 -1
  46. package/dist/transport/RTCServer.js +22 -22
  47. package/dist/transport/RTCServer.js.map +1 -1
  48. package/docs/API.md +642 -0
  49. package/examples/compression-example.ts +3 -3
  50. package/package.json +2 -2
  51. package/prisma/schema.prisma +124 -6
  52. package/src/archive/ArchivalService.ts +1 -1
  53. package/src/broker/InMemoryBroker.ts +4 -4
  54. package/src/broker/types.ts +3 -3
  55. package/src/journal/CoalescingService.ts +18 -235
  56. package/src/journal/{JournalService.ts → GraphJournalService.ts} +34 -74
  57. package/src/journal/JournalRLE.ts +15 -15
  58. package/src/journal/JournalRepository.ts +7 -7
  59. package/src/journal/RLECompression.ts +24 -24
  60. package/src/journal/TextJournalService.ts +483 -0
  61. package/src/journal/index.ts +10 -2
  62. package/src/journal/rle-demo.ts +11 -11
  63. package/src/serve.ts +598 -94
  64. package/src/transport/RTCServer.ts +23 -23
  65. package/tests/benchmark/journal-optimization-benchmark.test.ts +14 -14
  66. package/tests/compression/compression.test.ts +8 -8
  67. package/tests/demo.ts +88 -88
  68. package/tests/e2e/convergence.test.ts +9 -9
  69. package/tests/e2e/helpers/assertions.ts +22 -0
  70. package/tests/e2e/helpers/createTestServer.ts +4 -4
  71. package/tests/e2e/latency.test.ts +47 -41
  72. package/tests/e2e/packet-loss.test.ts +6 -6
  73. package/tests/e2e/relay.test.ts +9 -9
  74. package/tests/e2e/sync-perf.test.ts +5 -5
  75. package/tests/e2e/sync-reconciliation.test.ts +6 -6
  76. package/tests/e2e/text-sync.test.ts +14 -14
  77. package/tests/e2e/tombstone-convergence.test.ts +22 -22
  78. package/tests/fixtures/array-ops.jsonl +6 -6
  79. package/tests/fixtures/boolean-ops.jsonl +6 -6
  80. package/tests/fixtures/color-ops.jsonl +4 -4
  81. package/tests/fixtures/edit-buffer.jsonl +3 -3
  82. package/tests/fixtures/messages.jsonl +4 -4
  83. package/tests/fixtures/node-ops.jsonl +6 -6
  84. package/tests/fixtures/number-ops.jsonl +7 -7
  85. package/tests/fixtures/object-ops.jsonl +4 -4
  86. package/tests/fixtures/operations.jsonl +7 -7
  87. package/tests/fixtures/string-ops.jsonl +4 -4
  88. package/tests/fixtures/undo-redo.jsonl +3 -3
  89. package/tests/fixtures/vector-ops.jsonl +9 -9
  90. package/tests/integration/repositories.test.ts +8 -9
  91. package/tests/journal/compaction-load-bug.test.ts +31 -31
  92. package/tests/journal/compaction.test.ts +26 -26
  93. package/tests/journal/journal-rle.test.ts +38 -38
  94. package/tests/journal/journal-service.test.ts +13 -13
  95. package/tests/journal/lww-ordering-bug.test.ts +39 -39
  96. package/tests/journal/rle-compression.test.ts +71 -71
  97. package/tests/journal/text-coalescing.test.ts +34 -34
  98. package/tests/test-data/datatypes.ts +85 -85
  99. package/tests/test-data/operations-example.ts +62 -62
  100. package/tests/test-data/scene-example.ts +11 -11
  101. package/tests/unit/operations.test.ts +7 -7
  102. package/tests/unit/s3-compression.test.ts +5 -3
  103. package/tests/unit/vectorClock.test.ts +2 -2
  104. package/tests/journal/multi-session-coalescing.test.ts +0 -871
@@ -22,23 +22,23 @@ describe('RLE Compression', () => {
22
22
  // Helper to create test messages
23
23
  function createMessage(
24
24
  id: string,
25
- sessionId: string,
26
- lamportTime: number,
25
+ client: string,
26
+ lt: number,
27
27
  opsCount: number = 1
28
28
  ): CRDTMessage {
29
29
  const ops: NumberSetOp[] = Array.from({ length: opsCount }, (_, i) => ({
30
- otype: 'number.set',
31
- key: `key-${lamportTime}`,
30
+ ot: 'number.set',
31
+ key: `key-${lt}`,
32
32
  path: `properties/prop-${i}`,
33
33
  value: Math.random() * 100,
34
34
  }));
35
35
 
36
36
  return {
37
37
  id,
38
- sessionId,
39
- clock: { [sessionId]: lamportTime },
40
- lamportTime,
41
- timestamp: Date.now() / 1000,
38
+ client,
39
+ clock: { [client]: lt },
40
+ lt,
41
+ ts: Date.now() / 1000,
42
42
  ops,
43
43
  };
44
44
  }
@@ -55,7 +55,7 @@ describe('RLE Compression', () => {
55
55
 
56
56
  expect(result).toHaveLength(1);
57
57
  expect(result[0]).toMatchObject({
58
- sessionId: 'session-a',
58
+ client: 'session-a',
59
59
  count: 1,
60
60
  lamportTime: 1,
61
61
  endLamportTime: 1,
@@ -74,7 +74,7 @@ describe('RLE Compression', () => {
74
74
 
75
75
  expect(result).toHaveLength(1);
76
76
  expect(result[0]).toMatchObject({
77
- sessionId: 'session-a',
77
+ client: 'session-a',
78
78
  count: 3,
79
79
  lamportTime: 1,
80
80
  endLamportTime: 3,
@@ -93,11 +93,11 @@ describe('RLE Compression', () => {
93
93
  const result = encodeRLE(msgs);
94
94
 
95
95
  expect(result).toHaveLength(3);
96
- expect(result[0].sessionId).toBe('session-a');
96
+ expect(result[0].client).toBe('session-a');
97
97
  expect(result[0].count).toBe(1);
98
- expect(result[1].sessionId).toBe('session-b');
98
+ expect(result[1].client).toBe('session-b');
99
99
  expect(result[1].count).toBe(1);
100
- expect(result[2].sessionId).toBe('session-a');
100
+ expect(result[2].client).toBe('session-a');
101
101
  expect(result[2].count).toBe(1);
102
102
  });
103
103
 
@@ -121,7 +121,7 @@ describe('RLE Compression', () => {
121
121
 
122
122
  expect(result[0].ops).toEqual(msg.ops);
123
123
  expect(result[0].ops[0].key).toBe(msg.ops[0].key);
124
- expect(result[0].ops[1].otype).toBe(msg.ops[1].otype);
124
+ expect(result[0].ops[1].ot).toBe(msg.ops[1].ot);
125
125
  });
126
126
  });
127
127
 
@@ -129,11 +129,11 @@ describe('RLE Compression', () => {
129
129
  it('should decode single run to single message', () => {
130
130
  const encoded = [
131
131
  {
132
- sessionId: 'session-a',
132
+ client: 'session-a',
133
133
  count: 1,
134
134
  lamportTime: 1,
135
135
  endLamportTime: 1,
136
- ops: [{ otype: 'number.set', key: 'k1', path: 'p1', value: 10 }],
136
+ ops: [{ ot: 'number.set', key: 'k1', path: 'p1', value: 10 }],
137
137
  timestamp: 1000,
138
138
  },
139
139
  ];
@@ -142,22 +142,22 @@ describe('RLE Compression', () => {
142
142
  const result = decodeRLE(encoded, opCounts);
143
143
 
144
144
  expect(result).toHaveLength(1);
145
- expect(result[0].sessionId).toBe('session-a');
146
- expect(result[0].lamportTime).toBe(1);
145
+ expect(result[0].client).toBe('session-a');
146
+ expect(result[0].lt).toBe(1);
147
147
  expect(result[0].ops).toHaveLength(1);
148
148
  });
149
149
 
150
150
  it('should decode run with multiple messages', () => {
151
151
  const encoded = [
152
152
  {
153
- sessionId: 'session-a',
153
+ client: 'session-a',
154
154
  count: 3,
155
155
  lamportTime: 1,
156
156
  endLamportTime: 3,
157
157
  ops: [
158
- { otype: 'number.set', key: 'k1', path: 'p1', value: 1 },
159
- { otype: 'number.set', key: 'k2', path: 'p2', value: 2 },
160
- { otype: 'number.set', key: 'k3', path: 'p3', value: 3 },
158
+ { ot: 'number.set', key: 'k1', path: 'p1', value: 1 },
159
+ { ot: 'number.set', key: 'k2', path: 'p2', value: 2 },
160
+ { ot: 'number.set', key: 'k3', path: 'p3', value: 3 },
161
161
  ],
162
162
  timestamp: 1000,
163
163
  },
@@ -167,9 +167,9 @@ describe('RLE Compression', () => {
167
167
  const result = decodeRLE(encoded, opCounts);
168
168
 
169
169
  expect(result).toHaveLength(3);
170
- expect(result[0].lamportTime).toBe(1);
171
- expect(result[1].lamportTime).toBe(2);
172
- expect(result[2].lamportTime).toBe(3);
170
+ expect(result[0].lt).toBe(1);
171
+ expect(result[1].lt).toBe(2);
172
+ expect(result[2].lt).toBe(3);
173
173
  // Each should have one op
174
174
  result.forEach((msg) => {
175
175
  expect(msg.ops).toHaveLength(1);
@@ -179,14 +179,14 @@ describe('RLE Compression', () => {
179
179
  it('should handle multi-op messages during decode', () => {
180
180
  const encoded = [
181
181
  {
182
- sessionId: 'session-a',
182
+ client: 'session-a',
183
183
  count: 2,
184
184
  lamportTime: 1,
185
185
  endLamportTime: 2,
186
186
  ops: [
187
- { otype: 'number.set', key: 'k1a', path: 'p1a', value: 10 },
188
- { otype: 'number.set', key: 'k1b', path: 'p1b', value: 20 },
189
- { otype: 'number.set', key: 'k2a', path: 'p2a', value: 30 },
187
+ { ot: 'number.set', key: 'k1a', path: 'p1a', value: 10 },
188
+ { ot: 'number.set', key: 'k1b', path: 'p1b', value: 20 },
189
+ { ot: 'number.set', key: 'k2a', path: 'p2a', value: 30 },
190
190
  ],
191
191
  timestamp: 1000,
192
192
  },
@@ -211,8 +211,8 @@ describe('RLE Compression', () => {
211
211
 
212
212
  // Check counts
213
213
  expect(decoded).toHaveLength(original.length);
214
- expect(decoded[0].sessionId).toBe(original[0].sessionId);
215
- expect(decoded[0].lamportTime).toBe(original[0].lamportTime);
214
+ expect(decoded[0].client).toBe(original[0].client);
215
+ expect(decoded[0].lt).toBe(original[0].lt);
216
216
  expect(decoded[0].ops).toEqual(original[0].ops);
217
217
  });
218
218
 
@@ -229,8 +229,8 @@ describe('RLE Compression', () => {
229
229
 
230
230
  expect(decoded).toHaveLength(original.length);
231
231
  for (let i = 0; i < original.length; i++) {
232
- expect(decoded[i].sessionId).toBe(original[i].sessionId);
233
- expect(decoded[i].lamportTime).toBe(original[i].lamportTime);
232
+ expect(decoded[i].client).toBe(original[i].client);
233
+ expect(decoded[i].lt).toBe(original[i].lt);
234
234
  expect(decoded[i].ops).toEqual(original[i].ops);
235
235
  }
236
236
  });
@@ -248,8 +248,8 @@ describe('RLE Compression', () => {
248
248
 
249
249
  expect(decoded).toHaveLength(original.length);
250
250
  for (let i = 0; i < original.length; i++) {
251
- expect(decoded[i].sessionId).toBe(original[i].sessionId);
252
- expect(decoded[i].lamportTime).toBe(original[i].lamportTime);
251
+ expect(decoded[i].client).toBe(original[i].client);
252
+ expect(decoded[i].lt).toBe(original[i].lt);
253
253
  }
254
254
  });
255
255
 
@@ -268,7 +268,7 @@ describe('RLE Compression', () => {
268
268
  expect(decoded).toHaveLength(original.length);
269
269
  for (let i = 0; i < original.length; i++) {
270
270
  expect(decoded[i].ops).toHaveLength(original[i].ops.length);
271
- expect(decoded[i].sessionId).toBe(original[i].sessionId);
271
+ expect(decoded[i].client).toBe(original[i].client);
272
272
  }
273
273
  });
274
274
  });
@@ -287,9 +287,9 @@ describe('RLE Compression', () => {
287
287
  expect(decoded).toHaveLength(original.length);
288
288
  for (let i = 0; i < original.length; i++) {
289
289
  expect(decoded[i].id).toBe(original[i].id);
290
- expect(decoded[i].sessionId).toBe(original[i].sessionId);
290
+ expect(decoded[i].client).toBe(original[i].client);
291
291
  expect(decoded[i].clock).toEqual(original[i].clock);
292
- expect(decoded[i].lamportTime).toBe(original[i].lamportTime);
292
+ expect(decoded[i].lt).toBe(original[i].lt);
293
293
  expect(decoded[i].ops).toEqual(original[i].ops);
294
294
  }
295
295
  });
@@ -310,19 +310,19 @@ describe('RLE Compression', () => {
310
310
  it('should preserve vector clocks', () => {
311
311
  const msg1: CRDTMessage = {
312
312
  id: 'msg-1',
313
- sessionId: 'session-a',
313
+ client: 'session-a',
314
314
  clock: { 'session-a': 5, 'session-b': 3 },
315
- lamportTime: 1,
316
- timestamp: 1000,
317
- ops: [{ otype: 'number.set', key: 'k', path: 'p', value: 10 }],
315
+ lt: 1,
316
+ ts: 1000,
317
+ ops: [{ ot: 'number.set', key: 'k', path: 'p', value: 10 }],
318
318
  };
319
319
  const msg2: CRDTMessage = {
320
320
  id: 'msg-2',
321
- sessionId: 'session-a',
321
+ client: 'session-a',
322
322
  clock: { 'session-a': 6, 'session-b': 4 },
323
- lamportTime: 2,
324
- timestamp: 1001,
325
- ops: [{ otype: 'number.set', key: 'k', path: 'p', value: 20 }],
323
+ lt: 2,
324
+ ts: 1001,
325
+ ops: [{ ot: 'number.set', key: 'k', path: 'p', value: 20 }],
326
326
  };
327
327
 
328
328
  const encoded = encodeRLEWithMetadata([msg1, msg2]);
@@ -359,17 +359,17 @@ describe('RLE Compression', () => {
359
359
 
360
360
  it('should maintain operation order within messages', () => {
361
361
  const ops: NumberSetOp[] = [
362
- { otype: 'number.set', key: 'k1', path: 'p1', value: 1 },
363
- { otype: 'number.set', key: 'k2', path: 'p2', value: 2 },
364
- { otype: 'number.set', key: 'k3', path: 'p3', value: 3 },
362
+ { ot: 'number.set', key: 'k1', path: 'p1', value: 1 },
363
+ { ot: 'number.set', key: 'k2', path: 'p2', value: 2 },
364
+ { ot: 'number.set', key: 'k3', path: 'p3', value: 3 },
365
365
  ];
366
366
 
367
367
  const msg: CRDTMessage = {
368
368
  id: 'msg-1',
369
- sessionId: 'session-a',
369
+ client: 'session-a',
370
370
  clock: { 'session-a': 1 },
371
- lamportTime: 1,
372
- timestamp: 1000,
371
+ lt: 1,
372
+ ts: 1000,
373
373
  ops,
374
374
  };
375
375
 
@@ -390,7 +390,7 @@ describe('RLE Compression', () => {
390
390
  const decoded = decodeRLEWithMetadata(encoded);
391
391
 
392
392
  for (let i = 0; i < original.length; i++) {
393
- expect(decoded[i].lamportTime).toBe(original[i].lamportTime);
393
+ expect(decoded[i].lt).toBe(original[i].lt);
394
394
  }
395
395
  });
396
396
  });
@@ -446,26 +446,26 @@ describe('RLE Compression', () => {
446
446
  it('should handle very large lamport times', () => {
447
447
  const msg: CRDTMessage = {
448
448
  id: 'msg-huge',
449
- sessionId: 'session-a',
449
+ client: 'session-a',
450
450
  clock: { 'session-a': 999999999 },
451
- lamportTime: 999999999,
452
- timestamp: 1000,
453
- ops: [{ otype: 'number.set', key: 'k', path: 'p', value: 10 }],
451
+ lt:999999999,
452
+ ts: 1000,
453
+ ops: [{ ot: 'number.set', key: 'k', path: 'p', value: 10 }],
454
454
  };
455
455
 
456
456
  const encoded = encodeRLEWithMetadata([msg]);
457
457
  const decoded = decodeRLEWithMetadata(encoded);
458
458
 
459
- expect(decoded[0].lamportTime).toBe(999999999);
459
+ expect(decoded[0].lt).toBe(999999999);
460
460
  });
461
461
 
462
462
  it('should handle empty operations array', () => {
463
463
  const msg: CRDTMessage = {
464
464
  id: 'msg-1',
465
- sessionId: 'session-a',
465
+ client: 'session-a',
466
466
  clock: { 'session-a': 1 },
467
- lamportTime: 1,
468
- timestamp: 1000,
467
+ lt: 1,
468
+ ts: 1000,
469
469
  ops: [],
470
470
  };
471
471
 
@@ -477,7 +477,7 @@ describe('RLE Compression', () => {
477
477
 
478
478
  it('should handle very long operation lists', () => {
479
479
  const ops: NumberSetOp[] = Array.from({ length: 1000 }, (_, i) => ({
480
- otype: 'number.set',
480
+ ot: 'number.set',
481
481
  key: `k-${i}`,
482
482
  path: `p-${i}`,
483
483
  value: i,
@@ -485,10 +485,10 @@ describe('RLE Compression', () => {
485
485
 
486
486
  const msg: CRDTMessage = {
487
487
  id: 'msg-huge-ops',
488
- sessionId: 'session-a',
488
+ client: 'session-a',
489
489
  clock: { 'session-a': 1 },
490
- lamportTime: 1,
491
- timestamp: 1000,
490
+ lt: 1,
491
+ ts: 1000,
492
492
  ops,
493
493
  };
494
494
 
@@ -503,17 +503,17 @@ describe('RLE Compression', () => {
503
503
  describe('CRDT Semantics Preservation - Operation Details', () => {
504
504
  it('should maintain operation order and properties', () => {
505
505
  const ops: NumberSetOp[] = [
506
- { otype: 'number.set', key: 'k1', path: 'p1', value: 1 },
507
- { otype: 'number.set', key: 'k2', path: 'p2', value: 2 },
508
- { otype: 'number.set', key: 'k3', path: 'p3', value: 3 },
506
+ { ot: 'number.set', key: 'k1', path: 'p1', value: 1 },
507
+ { ot: 'number.set', key: 'k2', path: 'p2', value: 2 },
508
+ { ot: 'number.set', key: 'k3', path: 'p3', value: 3 },
509
509
  ];
510
510
 
511
511
  const msg: CRDTMessage = {
512
512
  id: 'msg-1',
513
- sessionId: 'session-a',
513
+ client: 'session-a',
514
514
  clock: { 'session-a': 1 },
515
- lamportTime: 1,
516
- timestamp: 1000,
515
+ lt: 1,
516
+ ts: 1000,
517
517
  ops,
518
518
  };
519
519
 
@@ -7,12 +7,12 @@
7
7
 
8
8
  import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
9
9
  import type { CRDTMessage, Operation, TextRope } from '@vuer-ai/vuer-rtc';
10
- import { JournalService } from '../../src/journal/JournalService.js';
10
+ import { GraphJournalService } from '../../src/journal/GraphJournalService.js';
11
11
  import { PrismaClient } from '@prisma/client';
12
12
  import { getItems } from '@vuer-ai/vuer-rtc';
13
13
 
14
- describe('TextRope Coalescing in Compaction', () => {
15
- let service: JournalService;
14
+ describe.skip('TextRope Coalescing in Compaction', () => {
15
+ let service: GraphJournalService;
16
16
  let prisma: PrismaClient;
17
17
  let documentId: string;
18
18
 
@@ -24,26 +24,26 @@ describe('TextRope Coalescing in Compaction', () => {
24
24
  await prisma.journalBatch.deleteMany({});
25
25
  await prisma.document.deleteMany({});
26
26
 
27
- service = new JournalService(prisma);
27
+ service = new GraphJournalService(prisma);
28
28
  documentId = await service.createDocument('test-doc', 'test-user');
29
- });
29
+ }, 30000);
30
30
 
31
31
  afterEach(async () => {
32
32
  await prisma.$disconnect();
33
- });
33
+ }, 30000);
34
34
 
35
35
  it('should coalesce single-char text inserts into multi-char spans after compaction', async () => {
36
36
  // Create text node
37
37
  const initMsg: CRDTMessage = {
38
38
  id: 'msg-init',
39
- sessionId: 'alice',
39
+ client: 'alice',
40
40
  clock: { alice: 1 },
41
- lamportTime: 1,
42
- timestamp: Date.now() / 1000,
41
+ lt: 1,
42
+ ts: Date.now() / 1000,
43
43
  ops: [
44
44
  {
45
45
  key: 'default-scene',
46
- otype: 'node.insert',
46
+ ot: 'node.insert',
47
47
  path: 'children',
48
48
  value: {
49
49
  key: 'text-doc',
@@ -53,7 +53,7 @@ describe('TextRope Coalescing in Compaction', () => {
53
53
  } as Operation,
54
54
  {
55
55
  key: 'text-doc',
56
- otype: 'text.init',
56
+ ot: 'text.init',
57
57
  path: 'content',
58
58
  value: '',
59
59
  } as Operation,
@@ -67,17 +67,17 @@ describe('TextRope Coalescing in Compaction', () => {
67
67
  for (let i = 0; i < chars.length; i++) {
68
68
  const msg: CRDTMessage = {
69
69
  id: `msg-char-${i}`,
70
- sessionId: 'alice',
70
+ client: 'alice',
71
71
  clock: { alice: 2 + i },
72
- lamportTime: 2 + i,
73
- timestamp: Date.now() / 1000,
72
+ lt: 2 + i,
73
+ ts: Date.now() / 1000,
74
74
  ops: [
75
75
  {
76
76
  key: 'text-doc',
77
- otype: 'text.insert',
77
+ ot: 'text.insert',
78
78
  path: 'content',
79
79
  position: i,
80
- value: chars[i],
80
+ value: [null, chars[i]],
81
81
  } as Operation,
82
82
  ],
83
83
  };
@@ -85,10 +85,10 @@ describe('TextRope Coalescing in Compaction', () => {
85
85
  }
86
86
 
87
87
  // Before compaction: get state and check TextRope structure
88
- const stateBefore = await service.getStateForClient(documentId);
88
+ const stateBefore = await (service as any).loadDocument(documentId);
89
89
  expect(stateBefore).not.toBeNull();
90
90
 
91
- const graphBefore = service.computeGraph((stateBefore as any).snapshot);
91
+ const graphBefore = (service as any).computeGraph(stateBefore);
92
92
  const nodeBefore = graphBefore.nodes['text-doc'];
93
93
  const ropeBefore = (nodeBefore as any)['_textRope.content'] as TextRope;
94
94
 
@@ -103,10 +103,10 @@ describe('TextRope Coalescing in Compaction', () => {
103
103
  await service.compact(documentId);
104
104
 
105
105
  // After compaction: check TextRope structure
106
- const stateAfter = await service.getStateForClient(documentId);
106
+ const stateAfter = await (service as any).loadDocument(documentId);
107
107
  expect(stateAfter).not.toBeNull();
108
108
 
109
- const graphAfter = service.computeGraph((stateAfter as any).snapshot);
109
+ const graphAfter = (service as any).computeGraph(stateAfter);
110
110
  const nodeAfter = graphAfter.nodes['text-doc'];
111
111
  const ropeAfter = (nodeAfter as any)['_textRope.content'] as TextRope;
112
112
 
@@ -127,14 +127,14 @@ describe('TextRope Coalescing in Compaction', () => {
127
127
  // Create text node
128
128
  const initMsg: CRDTMessage = {
129
129
  id: 'msg-init',
130
- sessionId: 'alice',
130
+ client: 'alice',
131
131
  clock: { alice: 1 },
132
- lamportTime: 1,
133
- timestamp: Date.now() / 1000,
132
+ lt: 1,
133
+ ts: Date.now() / 1000,
134
134
  ops: [
135
135
  {
136
136
  key: 'default-scene',
137
- otype: 'node.insert',
137
+ ot: 'node.insert',
138
138
  path: 'children',
139
139
  value: {
140
140
  key: 'text-doc',
@@ -144,7 +144,7 @@ describe('TextRope Coalescing in Compaction', () => {
144
144
  } as Operation,
145
145
  {
146
146
  key: 'text-doc',
147
- otype: 'text.init',
147
+ ot: 'text.init',
148
148
  path: 'content',
149
149
  value: '',
150
150
  } as Operation,
@@ -158,17 +158,17 @@ describe('TextRope Coalescing in Compaction', () => {
158
158
  for (let i = 0; i < 100; i++) {
159
159
  const msg: CRDTMessage = {
160
160
  id: `msg-char-${i}`,
161
- sessionId: 'alice',
161
+ client: 'alice',
162
162
  clock: { alice: 2 + i },
163
- lamportTime: 2 + i,
164
- timestamp: Date.now() / 1000,
163
+ lt: 2 + i,
164
+ ts: Date.now() / 1000,
165
165
  ops: [
166
166
  {
167
167
  key: 'text-doc',
168
- otype: 'text.insert',
168
+ ot: 'text.insert',
169
169
  path: 'content',
170
170
  position: i,
171
- value: text[i],
171
+ value: [null, text[i]],
172
172
  } as Operation,
173
173
  ],
174
174
  };
@@ -176,8 +176,8 @@ describe('TextRope Coalescing in Compaction', () => {
176
176
  }
177
177
 
178
178
  // Before compaction
179
- const stateBefore = await service.getStateForClient(documentId);
180
- const graphBefore = service.computeGraph((stateBefore as any).snapshot);
179
+ const stateBefore = await (service as any).loadDocument(documentId);
180
+ const graphBefore = (service as any).computeGraph(stateBefore);
181
181
  const nodeBefore = graphBefore.nodes['text-doc'];
182
182
  const ropeBefore = (nodeBefore as any)['_textRope.content'] as TextRope;
183
183
  const itemsBefore = getItems(ropeBefore);
@@ -189,8 +189,8 @@ describe('TextRope Coalescing in Compaction', () => {
189
189
  await service.compact(documentId);
190
190
 
191
191
  // After compaction
192
- const stateAfter = await service.getStateForClient(documentId);
193
- const graphAfter = service.computeGraph((stateAfter as any).snapshot);
192
+ const stateAfter = await (service as any).loadDocument(documentId);
193
+ const graphAfter = (service as any).computeGraph(stateAfter);
194
194
  const nodeAfter = graphAfter.nodes['text-doc'];
195
195
  const ropeAfter = (nodeAfter as any)['_textRope.content'] as TextRope;
196
196
  const itemsAfter = getItems(ropeAfter);