@vuer-ai/vuer-rtc-server 0.2.0 → 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.
Files changed (76) hide show
  1. package/.env +1 -0
  2. package/S3_COMPRESSION_GUIDE.md +233 -0
  3. package/dist/archive/ArchivalService.d.ts +117 -0
  4. package/dist/archive/ArchivalService.d.ts.map +1 -0
  5. package/dist/archive/ArchivalService.js +181 -0
  6. package/dist/archive/ArchivalService.js.map +1 -0
  7. package/dist/broker/InMemoryBroker.d.ts +2 -0
  8. package/dist/broker/InMemoryBroker.d.ts.map +1 -1
  9. package/dist/broker/InMemoryBroker.js +4 -0
  10. package/dist/broker/InMemoryBroker.js.map +1 -1
  11. package/dist/compression/CompressionUtils.d.ts +57 -0
  12. package/dist/compression/CompressionUtils.d.ts.map +1 -0
  13. package/dist/compression/CompressionUtils.js +90 -0
  14. package/dist/compression/CompressionUtils.js.map +1 -0
  15. package/dist/compression/index.d.ts +7 -0
  16. package/dist/compression/index.d.ts.map +1 -0
  17. package/dist/compression/index.js +7 -0
  18. package/dist/compression/index.js.map +1 -0
  19. package/dist/journal/CoalescingService.d.ts +63 -0
  20. package/dist/journal/CoalescingService.d.ts.map +1 -0
  21. package/dist/journal/CoalescingService.js +507 -0
  22. package/dist/journal/CoalescingService.js.map +1 -0
  23. package/dist/journal/JournalRLE.d.ts +81 -0
  24. package/dist/journal/JournalRLE.d.ts.map +1 -0
  25. package/dist/journal/JournalRLE.js +199 -0
  26. package/dist/journal/JournalRLE.js.map +1 -0
  27. package/dist/journal/JournalService.d.ts +7 -3
  28. package/dist/journal/JournalService.d.ts.map +1 -1
  29. package/dist/journal/JournalService.js +152 -12
  30. package/dist/journal/JournalService.js.map +1 -1
  31. package/dist/journal/RLECompression.d.ts +73 -0
  32. package/dist/journal/RLECompression.d.ts.map +1 -0
  33. package/dist/journal/RLECompression.js +152 -0
  34. package/dist/journal/RLECompression.js.map +1 -0
  35. package/dist/journal/rle-demo.d.ts +8 -0
  36. package/dist/journal/rle-demo.d.ts.map +1 -0
  37. package/dist/journal/rle-demo.js +159 -0
  38. package/dist/journal/rle-demo.js.map +1 -0
  39. package/dist/persistence/S3ColdStorage.d.ts +62 -0
  40. package/dist/persistence/S3ColdStorage.d.ts.map +1 -0
  41. package/dist/persistence/S3ColdStorage.js +88 -0
  42. package/dist/persistence/S3ColdStorage.js.map +1 -0
  43. package/dist/persistence/S3ColdStorageIntegration.d.ts +78 -0
  44. package/dist/persistence/S3ColdStorageIntegration.d.ts.map +1 -0
  45. package/dist/persistence/S3ColdStorageIntegration.js +93 -0
  46. package/dist/persistence/S3ColdStorageIntegration.js.map +1 -0
  47. package/dist/serve.d.ts +2 -0
  48. package/dist/serve.d.ts.map +1 -1
  49. package/dist/serve.js +623 -15
  50. package/dist/serve.js.map +1 -1
  51. package/docs/RLE_COMPRESSION.md +397 -0
  52. package/examples/compression-example.ts +259 -0
  53. package/package.json +14 -14
  54. package/src/archive/ArchivalService.ts +250 -0
  55. package/src/broker/InMemoryBroker.ts +5 -0
  56. package/src/compression/CompressionUtils.ts +113 -0
  57. package/src/compression/index.ts +14 -0
  58. package/src/journal/COALESCING.md +267 -0
  59. package/src/journal/CoalescingService.ts +626 -0
  60. package/src/journal/JournalRLE.ts +265 -0
  61. package/src/journal/JournalService.ts +163 -11
  62. package/src/journal/RLECompression.ts +210 -0
  63. package/src/journal/rle-demo.ts +193 -0
  64. package/src/serve.ts +702 -15
  65. package/tests/benchmark/journal-optimization-benchmark.test.ts +482 -0
  66. package/tests/compression/compression.test.ts +343 -0
  67. package/tests/integration/repositories.test.ts +89 -0
  68. package/tests/journal/compaction-load-bug.test.ts +409 -0
  69. package/tests/journal/compaction.test.ts +42 -2
  70. package/tests/journal/journal-rle.test.ts +511 -0
  71. package/tests/journal/lww-ordering-bug.test.ts +248 -0
  72. package/tests/journal/multi-session-coalescing.test.ts +871 -0
  73. package/tests/journal/rle-compression.test.ts +526 -0
  74. package/tests/journal/text-coalescing.test.ts +210 -0
  75. package/tests/unit/s3-compression.test.ts +257 -0
  76. package/PHASE1_SUMMARY.md +0 -94
@@ -0,0 +1,193 @@
1
+ /**
2
+ * RLE Compression Demonstration
3
+ *
4
+ * Shows real-world compression stats for different journal patterns.
5
+ * Run with: node --loader ts-node/esm src/journal/rle-demo.ts
6
+ */
7
+
8
+ import type { CRDTMessage } from '@vuer-ai/vuer-rtc';
9
+ import {
10
+ encodeJournalRLE,
11
+ getCompressionStats,
12
+ verifyRLEIntegrity,
13
+ } from './JournalRLE.js';
14
+
15
+ /**
16
+ * Create a test message
17
+ */
18
+ function createMessage(
19
+ id: string,
20
+ sessionId: string,
21
+ lamportTime: number,
22
+ timestamp: number,
23
+ key: string = 'cube-1',
24
+ value: any = [lamportTime, 0, 0]
25
+ ): CRDTMessage {
26
+ return {
27
+ id,
28
+ sessionId,
29
+ clock: { [sessionId]: lamportTime },
30
+ lamportTime,
31
+ timestamp,
32
+ ops: [
33
+ {
34
+ key,
35
+ otype: 'vector3.set',
36
+ path: 'position',
37
+ value,
38
+ },
39
+ ],
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Run demonstrations
45
+ */
46
+ function main() {
47
+ console.log('\n=== RLE Journal Compression Demo ===\n');
48
+
49
+ // Scenario 1: Single user, sequential edits
50
+ console.log('SCENARIO 1: Single user (50 sequential edits)');
51
+ console.log('─'.repeat(50));
52
+ {
53
+ const messages = Array.from({ length: 50 }, (_, i) =>
54
+ createMessage(`msg-${i}`, 'user-1', i, 1000 + i)
55
+ );
56
+
57
+ const encoded = encodeJournalRLE(messages);
58
+ const stats = getCompressionStats(encoded);
59
+ const verification = verifyRLEIntegrity(messages, encoded);
60
+
61
+ console.log(`Messages: ${stats.originalBytes.toLocaleString()} bytes`);
62
+ console.log(`Encoded: ${stats.compressedBytes.toLocaleString()} bytes`);
63
+ console.log(`Segments: ${stats.segmentCount}`);
64
+ console.log(`Avg/Segment: ${stats.avgMessagesPerSegment.toFixed(1)}`);
65
+ console.log(`Ratio: ${stats.ratio.toFixed(3)}`);
66
+ console.log(`Saved: ${stats.percentSaved.toFixed(1)}%`);
67
+ console.log(`Integrity: ${verification.valid ? 'PASS' : 'FAIL'}`);
68
+ }
69
+
70
+ // Scenario 2: Two users, alternating edits
71
+ console.log('\n\nSCENARIO 2: Two users (50 alternating edits)');
72
+ console.log('─'.repeat(50));
73
+ {
74
+ const messages: CRDTMessage[] = [];
75
+ for (let i = 0; i < 50; i++) {
76
+ const user = i % 2 === 0 ? 'user-1' : 'user-2';
77
+ messages.push(createMessage(`msg-${i}`, user, i, 1000 + i));
78
+ }
79
+
80
+ const encoded = encodeJournalRLE(messages);
81
+ const stats = getCompressionStats(encoded);
82
+ const verification = verifyRLEIntegrity(messages, encoded);
83
+
84
+ console.log(`Messages: ${stats.originalBytes.toLocaleString()} bytes`);
85
+ console.log(`Encoded: ${stats.compressedBytes.toLocaleString()} bytes`);
86
+ console.log(`Segments: ${stats.segmentCount}`);
87
+ console.log(`Avg/Segment: ${stats.avgMessagesPerSegment.toFixed(1)}`);
88
+ console.log(`Ratio: ${stats.ratio.toFixed(3)}`);
89
+ console.log(`Saved: ${stats.percentSaved.toFixed(1)}%`);
90
+ console.log(`Integrity: ${verification.valid ? 'PASS' : 'FAIL'}`);
91
+ }
92
+
93
+ // Scenario 3: Four users, burst patterns
94
+ console.log('\n\nSCENARIO 3: Four users (100 bursts of 5 edits)');
95
+ console.log('─'.repeat(50));
96
+ {
97
+ const messages: CRDTMessage[] = [];
98
+ let msgId = 0;
99
+ let lamportTime = 0;
100
+
101
+ for (let burst = 0; burst < 20; burst++) {
102
+ const user = `user-${(burst % 4) + 1}`;
103
+ for (let i = 0; i < 5; i++) {
104
+ messages.push(
105
+ createMessage(`msg-${msgId++}`, user, lamportTime++, 1000 + lamportTime)
106
+ );
107
+ }
108
+ }
109
+
110
+ const encoded = encodeJournalRLE(messages);
111
+ const stats = getCompressionStats(encoded);
112
+ const verification = verifyRLEIntegrity(messages, encoded);
113
+
114
+ console.log(`Messages: ${stats.originalBytes.toLocaleString()} bytes`);
115
+ console.log(`Encoded: ${stats.compressedBytes.toLocaleString()} bytes`);
116
+ console.log(`Segments: ${stats.segmentCount}`);
117
+ console.log(`Avg/Segment: ${stats.avgMessagesPerSegment.toFixed(1)}`);
118
+ console.log(`Ratio: ${stats.ratio.toFixed(3)}`);
119
+ console.log(`Saved: ${stats.percentSaved.toFixed(1)}%`);
120
+ console.log(`Integrity: ${verification.valid ? 'PASS' : 'FAIL'}`);
121
+ }
122
+
123
+ // Scenario 4: Realistic editing with large ops
124
+ console.log('\n\nSCENARIO 4: Large operations (node tree modifications)');
125
+ console.log('─'.repeat(50));
126
+ {
127
+ const messages: CRDTMessage[] = [];
128
+
129
+ for (let i = 0; i < 30; i++) {
130
+ const user = i < 15 ? 'user-1' : 'user-2';
131
+ const msg: CRDTMessage = {
132
+ id: `msg-${i}`,
133
+ sessionId: user,
134
+ clock: { [user]: i },
135
+ lamportTime: i,
136
+ timestamp: 1000 + i,
137
+ ops: [
138
+ {
139
+ key: `node-${i % 5}`,
140
+ otype: 'node.insert',
141
+ path: 'children',
142
+ value: {
143
+ key: `child-${i}`,
144
+ tag: 'Mesh',
145
+ name: `Node ${i}`,
146
+ position: [i * 0.1, 0, 0],
147
+ rotation: [0, Math.PI * (i % 4) / 4, 0],
148
+ scale: [1, 1, 1],
149
+ },
150
+ },
151
+ {
152
+ key: `node-${i % 5}`,
153
+ otype: 'vector3.set',
154
+ path: 'color',
155
+ value: [Math.random(), Math.random(), Math.random()],
156
+ },
157
+ ],
158
+ };
159
+ messages.push(msg);
160
+ }
161
+
162
+ const encoded = encodeJournalRLE(messages);
163
+ const stats = getCompressionStats(encoded);
164
+ const verification = verifyRLEIntegrity(messages, encoded);
165
+
166
+ console.log(`Messages: ${stats.originalBytes.toLocaleString()} bytes`);
167
+ console.log(`Encoded: ${stats.compressedBytes.toLocaleString()} bytes`);
168
+ console.log(`Segments: ${stats.segmentCount}`);
169
+ console.log(`Avg/Segment: ${stats.avgMessagesPerSegment.toFixed(1)}`);
170
+ console.log(`Ratio: ${stats.ratio.toFixed(3)}`);
171
+ console.log(`Saved: ${stats.percentSaved.toFixed(1)}%`);
172
+ console.log(`Integrity: ${verification.valid ? 'PASS' : 'FAIL'}`);
173
+ }
174
+
175
+ // Summary
176
+ console.log('\n\n=== Summary ===');
177
+ console.log('─'.repeat(50));
178
+ console.log(`
179
+ RLE encoding works by:
180
+ 1. Grouping consecutive messages from the same agent
181
+ 2. Storing agent ID once per segment instead of per message
182
+ 3. Reducing redundancy in causality metadata
183
+
184
+ Key insights:
185
+ - More effective with binary codecs (not JSON strings)
186
+ - Best for single-agent or burst patterns
187
+ - Maintains all CRDT semantics and causality
188
+ - Zero overhead for integrity verification
189
+ - Ready for integration with storage backends
190
+ `);
191
+ }
192
+
193
+ main();