cojson 0.18.32 → 0.18.33

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 (117) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +9 -0
  3. package/dist/SyncStateManager.d.ts.map +1 -1
  4. package/dist/SyncStateManager.js +2 -2
  5. package/dist/SyncStateManager.js.map +1 -1
  6. package/dist/coValueCore/SessionMap.d.ts +1 -0
  7. package/dist/coValueCore/SessionMap.d.ts.map +1 -1
  8. package/dist/coValueCore/SessionMap.js +17 -1
  9. package/dist/coValueCore/SessionMap.js.map +1 -1
  10. package/dist/coValueCore/coValueCore.d.ts +14 -9
  11. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  12. package/dist/coValueCore/coValueCore.js +62 -47
  13. package/dist/coValueCore/coValueCore.js.map +1 -1
  14. package/dist/coValueCore/verifiedState.d.ts +2 -2
  15. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  16. package/dist/coValueCore/verifiedState.js +86 -75
  17. package/dist/coValueCore/verifiedState.js.map +1 -1
  18. package/dist/coValues/group.d.ts +1 -0
  19. package/dist/coValues/group.d.ts.map +1 -1
  20. package/dist/coValues/group.js +24 -4
  21. package/dist/coValues/group.js.map +1 -1
  22. package/dist/knownState.d.ts +1 -1
  23. package/dist/knownState.d.ts.map +1 -1
  24. package/dist/knownState.js +1 -1
  25. package/dist/knownState.js.map +1 -1
  26. package/dist/localNode.d.ts.map +1 -1
  27. package/dist/localNode.js +1 -2
  28. package/dist/localNode.js.map +1 -1
  29. package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -1
  30. package/dist/queue/LocalTransactionsSyncQueue.js +16 -1
  31. package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -1
  32. package/dist/storage/knownState.js +2 -2
  33. package/dist/storage/knownState.js.map +1 -1
  34. package/dist/sync.d.ts.map +1 -1
  35. package/dist/sync.js +8 -2
  36. package/dist/sync.js.map +1 -1
  37. package/dist/tests/PureJSCrypto.test.js +1 -1
  38. package/dist/tests/PureJSCrypto.test.js.map +1 -1
  39. package/dist/tests/StorageApiAsync.test.js +11 -11
  40. package/dist/tests/StorageApiAsync.test.js.map +1 -1
  41. package/dist/tests/StorageApiSync.test.js +3 -3
  42. package/dist/tests/StorageApiSync.test.js.map +1 -1
  43. package/dist/tests/WasmCrypto.test.js +1 -1
  44. package/dist/tests/WasmCrypto.test.js.map +1 -1
  45. package/dist/tests/coPlainText.test.js +1 -1
  46. package/dist/tests/coStream.test.js +12 -12
  47. package/dist/tests/coStream.test.js.map +1 -1
  48. package/dist/tests/coValueCore.isCompletelyDownloaded.test.d.ts +2 -0
  49. package/dist/tests/coValueCore.isCompletelyDownloaded.test.d.ts.map +1 -0
  50. package/dist/tests/coValueCore.isCompletelyDownloaded.test.js +421 -0
  51. package/dist/tests/coValueCore.isCompletelyDownloaded.test.js.map +1 -0
  52. package/dist/tests/coValueCore.isStreaming.test.d.ts +2 -0
  53. package/dist/tests/coValueCore.isStreaming.test.d.ts.map +1 -0
  54. package/dist/tests/coValueCore.isStreaming.test.js +181 -0
  55. package/dist/tests/coValueCore.isStreaming.test.js.map +1 -0
  56. package/dist/tests/coValueCore.newContentSince.test.d.ts +2 -0
  57. package/dist/tests/coValueCore.newContentSince.test.d.ts.map +1 -0
  58. package/dist/tests/coValueCore.newContentSince.test.js +808 -0
  59. package/dist/tests/coValueCore.newContentSince.test.js.map +1 -0
  60. package/dist/tests/coreWasm.test.js +2 -2
  61. package/dist/tests/coreWasm.test.js.map +1 -1
  62. package/dist/tests/group.childKeyRotation.test.d.ts +2 -0
  63. package/dist/tests/group.childKeyRotation.test.d.ts.map +1 -0
  64. package/dist/tests/group.childKeyRotation.test.js +261 -0
  65. package/dist/tests/group.childKeyRotation.test.js.map +1 -0
  66. package/dist/tests/group.removeMember.test.js +1 -114
  67. package/dist/tests/group.removeMember.test.js.map +1 -1
  68. package/dist/tests/knownState.test.js +11 -11
  69. package/dist/tests/knownState.test.js.map +1 -1
  70. package/dist/tests/sync.auth.test.js +6 -6
  71. package/dist/tests/sync.load.test.js +68 -5
  72. package/dist/tests/sync.load.test.js.map +1 -1
  73. package/dist/tests/sync.mesh.test.js +11 -17
  74. package/dist/tests/sync.mesh.test.js.map +1 -1
  75. package/dist/tests/sync.peerReconciliation.test.js +1 -1
  76. package/dist/tests/sync.storage.test.js +7 -7
  77. package/dist/tests/sync.storage.test.js.map +1 -1
  78. package/dist/tests/sync.storageAsync.test.js +4 -4
  79. package/dist/tests/sync.storageAsync.test.js.map +1 -1
  80. package/dist/tests/sync.upload.test.js +96 -40
  81. package/dist/tests/sync.upload.test.js.map +1 -1
  82. package/dist/tests/testUtils.d.ts +2 -0
  83. package/dist/tests/testUtils.d.ts.map +1 -1
  84. package/dist/tests/testUtils.js +22 -1
  85. package/dist/tests/testUtils.js.map +1 -1
  86. package/package.json +3 -3
  87. package/src/SyncStateManager.ts +2 -5
  88. package/src/coValueCore/SessionMap.ts +24 -0
  89. package/src/coValueCore/coValueCore.ts +77 -55
  90. package/src/coValueCore/verifiedState.ts +123 -108
  91. package/src/coValues/group.ts +27 -4
  92. package/src/knownState.ts +1 -1
  93. package/src/localNode.ts +1 -2
  94. package/src/queue/LocalTransactionsSyncQueue.ts +25 -0
  95. package/src/storage/knownState.ts +2 -2
  96. package/src/sync.ts +7 -2
  97. package/src/tests/PureJSCrypto.test.ts +1 -2
  98. package/src/tests/StorageApiAsync.test.ts +11 -11
  99. package/src/tests/StorageApiSync.test.ts +3 -3
  100. package/src/tests/WasmCrypto.test.ts +1 -2
  101. package/src/tests/coPlainText.test.ts +1 -1
  102. package/src/tests/coStream.test.ts +12 -12
  103. package/src/tests/coValueCore.isCompletelyDownloaded.test.ts +589 -0
  104. package/src/tests/coValueCore.isStreaming.test.ts +271 -0
  105. package/src/tests/coValueCore.newContentSince.test.ts +966 -0
  106. package/src/tests/coreWasm.test.ts +2 -2
  107. package/src/tests/group.childKeyRotation.test.ts +431 -0
  108. package/src/tests/group.removeMember.test.ts +1 -184
  109. package/src/tests/knownState.test.ts +11 -11
  110. package/src/tests/sync.auth.test.ts +6 -6
  111. package/src/tests/sync.load.test.ts +80 -5
  112. package/src/tests/sync.mesh.test.ts +11 -17
  113. package/src/tests/sync.peerReconciliation.test.ts +1 -1
  114. package/src/tests/sync.storage.test.ts +7 -7
  115. package/src/tests/sync.storageAsync.test.ts +4 -4
  116. package/src/tests/sync.upload.test.ts +106 -40
  117. package/src/tests/testUtils.ts +24 -2
@@ -0,0 +1,808 @@
1
+ import { assert, beforeEach, describe, expect, test } from "vitest";
2
+ import { loadCoValueOrFail, setupTestNode } from "./testUtils.js";
3
+ import { CO_VALUE_PRIORITY } from "../priority.js";
4
+ import { emptyKnownState } from "../exports.js";
5
+ import { addTransactionToContentMessage } from "../coValueContentMessage.js";
6
+ beforeEach(() => {
7
+ setupTestNode({ isSyncServer: true });
8
+ });
9
+ // Simplify the content message to a value that can be used for snapshots
10
+ function simplifyContentMessage(message, sessionMapping) {
11
+ const newContent = Object.entries(message.new).map(([sessionID, content]) => [
12
+ sessionMapping[sessionID],
13
+ {
14
+ lastSignature: content.lastSignature ? "signature" : undefined,
15
+ newTransactions: `${content.newTransactions.length} transactions after ${content.after}`,
16
+ },
17
+ ]);
18
+ return {
19
+ action: message.action,
20
+ id: message.id ? "id" : undefined,
21
+ header: message.header ? "header" : undefined,
22
+ priority: message.priority,
23
+ new: Object.fromEntries(newContent),
24
+ expectContentUntil: message.expectContentUntil
25
+ ? Object.fromEntries(Object.entries(message.expectContentUntil).map(([sessionID, after]) => [sessionMapping[sessionID], after]))
26
+ : undefined,
27
+ };
28
+ }
29
+ function simplifyContentMessages(messages, sessionMapping) {
30
+ if (!messages) {
31
+ return undefined;
32
+ }
33
+ return messages.map((message) => simplifyContentMessage(message, sessionMapping));
34
+ }
35
+ describe("newContentSince", () => {
36
+ test("should return an empty content with the header when both the coValue and knownState are empty", () => {
37
+ const client = setupTestNode();
38
+ const group = client.node.createGroup();
39
+ const map = group.createMap();
40
+ expect(map.core.newContentSince(emptyKnownState(map.core.id))).toEqual([
41
+ {
42
+ action: "content",
43
+ id: map.core.id,
44
+ header: map.core.verified.header,
45
+ priority: CO_VALUE_PRIORITY.MEDIUM,
46
+ new: {},
47
+ },
48
+ ]);
49
+ });
50
+ test("should return an empty content with the header when the coValue is empty and knownState is undefined", () => {
51
+ const client = setupTestNode();
52
+ const group = client.node.createGroup();
53
+ const map = group.createMap();
54
+ expect(map.core.newContentSince(emptyKnownState(map.core.id))).toEqual([
55
+ {
56
+ action: "content",
57
+ id: map.core.id,
58
+ header: map.core.verified.header,
59
+ priority: CO_VALUE_PRIORITY.MEDIUM,
60
+ new: {},
61
+ },
62
+ ]);
63
+ });
64
+ test("should return the content when the coValue has new content and knownState is undefined", () => {
65
+ const client = setupTestNode();
66
+ const group = client.node.createGroup();
67
+ const map = group.createMap();
68
+ map.set("hello", "world", "trusting");
69
+ const content = map.core.newContentSince(undefined);
70
+ const sessionMapping = {
71
+ [client.node.currentSessionID]: "alice",
72
+ };
73
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
74
+ [
75
+ {
76
+ "action": "content",
77
+ "expectContentUntil": undefined,
78
+ "header": "header",
79
+ "id": "id",
80
+ "new": {
81
+ "alice": {
82
+ "lastSignature": "signature",
83
+ "newTransactions": "1 transactions after 0",
84
+ },
85
+ },
86
+ "priority": 3,
87
+ },
88
+ ]
89
+ `);
90
+ });
91
+ test("should return the content when the coValue has new content from multiple sessions and knownState is undefined", async () => {
92
+ const client = setupTestNode({
93
+ connected: true,
94
+ });
95
+ const group = client.node.createGroup();
96
+ const map = group.createMap();
97
+ map.set("hello", "world", "trusting");
98
+ const newSession = client.spawnNewSession();
99
+ const mapInNewSession = await loadCoValueOrFail(newSession.node, map.id);
100
+ mapInNewSession.set("hello", "world2", "trusting");
101
+ const content = mapInNewSession.core.newContentSince(undefined);
102
+ const sessionMapping = {
103
+ [client.node.currentSessionID]: "alice",
104
+ [newSession.node.currentSessionID]: "bob",
105
+ };
106
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
107
+ [
108
+ {
109
+ "action": "content",
110
+ "expectContentUntil": undefined,
111
+ "header": "header",
112
+ "id": "id",
113
+ "new": {
114
+ "alice": {
115
+ "lastSignature": "signature",
116
+ "newTransactions": "1 transactions after 0",
117
+ },
118
+ "bob": {
119
+ "lastSignature": "signature",
120
+ "newTransactions": "1 transactions after 0",
121
+ },
122
+ },
123
+ "priority": 3,
124
+ },
125
+ ]
126
+ `);
127
+ });
128
+ describe("large session logs", () => {
129
+ test("one large session log that requires multiple content pieces", () => {
130
+ const client = setupTestNode();
131
+ const group = client.node.createGroup();
132
+ const map = group.createMap();
133
+ const dataSize = 1 * 1024 * 100;
134
+ const chunkSize = 1024; // 1KB chunks
135
+ const chunks = dataSize / chunkSize;
136
+ const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
137
+ for (let i = 0; i < chunks; i++) {
138
+ const key = `key${i}`;
139
+ map.set(key, value, "trusting");
140
+ }
141
+ const content = map.core.newContentSince(undefined);
142
+ const sessionMapping = {
143
+ [client.node.currentSessionID]: "alice",
144
+ };
145
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
146
+ [
147
+ {
148
+ "action": "content",
149
+ "expectContentUntil": {
150
+ "alice": 100,
151
+ },
152
+ "header": "header",
153
+ "id": "id",
154
+ "new": {
155
+ "alice": {
156
+ "lastSignature": "signature",
157
+ "newTransactions": "73 transactions after 0",
158
+ },
159
+ },
160
+ "priority": 3,
161
+ },
162
+ {
163
+ "action": "content",
164
+ "expectContentUntil": undefined,
165
+ "header": undefined,
166
+ "id": "id",
167
+ "new": {
168
+ "alice": {
169
+ "lastSignature": "signature",
170
+ "newTransactions": "27 transactions after 73",
171
+ },
172
+ },
173
+ "priority": 3,
174
+ },
175
+ ]
176
+ `);
177
+ });
178
+ test("one large session log that requires multiple content pieces and one small", async () => {
179
+ const client = setupTestNode({
180
+ connected: true,
181
+ });
182
+ const group = client.node.createGroup();
183
+ const map = group.createMap();
184
+ // Generate a large amount of data (about 1MB)
185
+ const dataSize = 1 * 1024 * 100;
186
+ const chunkSize = 1024; // 1KB chunks
187
+ const chunks = dataSize / chunkSize;
188
+ const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
189
+ for (let i = 0; i < chunks; i++) {
190
+ const key = `key${i}`;
191
+ map.set(key, value, "trusting");
192
+ }
193
+ // Add a small session
194
+ const newSession = client.spawnNewSession();
195
+ const mapInNewSession = await loadCoValueOrFail(newSession.node, map.id);
196
+ mapInNewSession.set("small", "value", "trusting");
197
+ const content = mapInNewSession.core.newContentSince(undefined);
198
+ const sessionMapping = {
199
+ [client.node.currentSessionID]: "alice",
200
+ [newSession.node.currentSessionID]: "bob",
201
+ };
202
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
203
+ [
204
+ {
205
+ "action": "content",
206
+ "expectContentUntil": {
207
+ "alice": 100,
208
+ "bob": 1,
209
+ },
210
+ "header": "header",
211
+ "id": "id",
212
+ "new": {
213
+ "alice": {
214
+ "lastSignature": "signature",
215
+ "newTransactions": "73 transactions after 0",
216
+ },
217
+ },
218
+ "priority": 3,
219
+ },
220
+ {
221
+ "action": "content",
222
+ "expectContentUntil": undefined,
223
+ "header": undefined,
224
+ "id": "id",
225
+ "new": {
226
+ "alice": {
227
+ "lastSignature": "signature",
228
+ "newTransactions": "27 transactions after 73",
229
+ },
230
+ "bob": {
231
+ "lastSignature": "signature",
232
+ "newTransactions": "1 transactions after 0",
233
+ },
234
+ },
235
+ "priority": 3,
236
+ },
237
+ ]
238
+ `);
239
+ });
240
+ test("two large session logs", async () => {
241
+ const client = setupTestNode({
242
+ connected: true,
243
+ });
244
+ const group = client.node.createGroup();
245
+ const map = group.createMap();
246
+ // Generate a large amount of data in first session (about 1MB)
247
+ const dataSize = 1 * 1024 * 100;
248
+ const chunkSize = 1024; // 1KB chunks
249
+ const chunks = dataSize / chunkSize;
250
+ const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
251
+ for (let i = 0; i < chunks; i++) {
252
+ const key = `key1_${i}`;
253
+ map.set(key, value, "trusting");
254
+ }
255
+ // Add second large session
256
+ const newSession = client.spawnNewSession();
257
+ const mapInNewSession = await loadCoValueOrFail(newSession.node, map.id);
258
+ for (let i = 0; i < chunks; i++) {
259
+ const key = `key2_${i}`;
260
+ mapInNewSession.set(key, value, "trusting");
261
+ }
262
+ const content = mapInNewSession.core.newContentSince(undefined);
263
+ const sessionMapping = {
264
+ [client.node.currentSessionID]: "alice",
265
+ [newSession.node.currentSessionID]: "bob",
266
+ };
267
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
268
+ [
269
+ {
270
+ "action": "content",
271
+ "expectContentUntil": {
272
+ "alice": 100,
273
+ "bob": 100,
274
+ },
275
+ "header": "header",
276
+ "id": "id",
277
+ "new": {
278
+ "alice": {
279
+ "lastSignature": "signature",
280
+ "newTransactions": "73 transactions after 0",
281
+ },
282
+ },
283
+ "priority": 3,
284
+ },
285
+ {
286
+ "action": "content",
287
+ "expectContentUntil": undefined,
288
+ "header": undefined,
289
+ "id": "id",
290
+ "new": {
291
+ "bob": {
292
+ "lastSignature": "signature",
293
+ "newTransactions": "73 transactions after 0",
294
+ },
295
+ },
296
+ "priority": 3,
297
+ },
298
+ {
299
+ "action": "content",
300
+ "expectContentUntil": undefined,
301
+ "header": undefined,
302
+ "id": "id",
303
+ "new": {
304
+ "alice": {
305
+ "lastSignature": "signature",
306
+ "newTransactions": "27 transactions after 73",
307
+ },
308
+ "bob": {
309
+ "lastSignature": "signature",
310
+ "newTransactions": "27 transactions after 73",
311
+ },
312
+ },
313
+ "priority": 3,
314
+ },
315
+ ]
316
+ `);
317
+ });
318
+ test("one large, one small, and one large session log", async () => {
319
+ const client = setupTestNode({
320
+ connected: true,
321
+ });
322
+ const group = client.node.createGroup();
323
+ const map = group.createMap();
324
+ // Generate first large session (about 1MB)
325
+ const dataSize = 1 * 1024 * 100;
326
+ const chunkSize = 1024; // 1KB chunks
327
+ const chunks = dataSize / chunkSize;
328
+ const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
329
+ for (let i = 0; i < chunks; i++) {
330
+ const key = `key1_${i}`;
331
+ map.set(key, value, "trusting");
332
+ }
333
+ // Add small session
334
+ const session2 = client.spawnNewSession();
335
+ const mapInSession2 = await loadCoValueOrFail(session2.node, map.id);
336
+ mapInSession2.set("small", "value", "trusting");
337
+ // Add third large session
338
+ const session3 = client.spawnNewSession();
339
+ const mapInSession3 = await loadCoValueOrFail(session3.node, map.id);
340
+ for (let i = 0; i < chunks; i++) {
341
+ const key = `key3_${i}`;
342
+ mapInSession3.set(key, value, "trusting");
343
+ }
344
+ const content = mapInSession3.core.newContentSince(undefined);
345
+ const sessionMapping = {
346
+ [client.node.currentSessionID]: "alice",
347
+ [session2.node.currentSessionID]: "bob",
348
+ [session3.node.currentSessionID]: "charlie",
349
+ };
350
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
351
+ [
352
+ {
353
+ "action": "content",
354
+ "expectContentUntil": {
355
+ "alice": 100,
356
+ "bob": 1,
357
+ "charlie": 100,
358
+ },
359
+ "header": "header",
360
+ "id": "id",
361
+ "new": {
362
+ "alice": {
363
+ "lastSignature": "signature",
364
+ "newTransactions": "73 transactions after 0",
365
+ },
366
+ },
367
+ "priority": 3,
368
+ },
369
+ {
370
+ "action": "content",
371
+ "expectContentUntil": undefined,
372
+ "header": undefined,
373
+ "id": "id",
374
+ "new": {
375
+ "charlie": {
376
+ "lastSignature": "signature",
377
+ "newTransactions": "73 transactions after 0",
378
+ },
379
+ },
380
+ "priority": 3,
381
+ },
382
+ {
383
+ "action": "content",
384
+ "expectContentUntil": undefined,
385
+ "header": undefined,
386
+ "id": "id",
387
+ "new": {
388
+ "alice": {
389
+ "lastSignature": "signature",
390
+ "newTransactions": "27 transactions after 73",
391
+ },
392
+ "bob": {
393
+ "lastSignature": "signature",
394
+ "newTransactions": "1 transactions after 0",
395
+ },
396
+ "charlie": {
397
+ "lastSignature": "signature",
398
+ "newTransactions": "27 transactions after 73",
399
+ },
400
+ },
401
+ "priority": 3,
402
+ },
403
+ ]
404
+ `);
405
+ });
406
+ test("one small session log and one large without inbetween signatures", async () => {
407
+ const client = setupTestNode({
408
+ connected: true,
409
+ });
410
+ const group = client.node.createGroup();
411
+ const map = group.createMap();
412
+ await map.core.waitForSync();
413
+ client.disconnect();
414
+ // Generate first large session (about 1MB)
415
+ const dataSize = 1 * 1024 * 100;
416
+ const chunkSize = 1024; // 1KB chunks
417
+ const chunks = dataSize / chunkSize;
418
+ const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
419
+ for (let i = 0; i < chunks; i++) {
420
+ const key = `key1_${i}`;
421
+ map.set(key, value, "trusting");
422
+ }
423
+ const largeContent = map.core.newContentSince(undefined);
424
+ assert(largeContent);
425
+ const singleLargeContentPiece = largeContent[0];
426
+ for (const chunk of largeContent.slice(1)) {
427
+ for (const [sessionID, content] of Object.entries(chunk.new)) {
428
+ for (const tx of content.newTransactions) {
429
+ addTransactionToContentMessage(singleLargeContentPiece, tx, sessionID, content.lastSignature, 1);
430
+ }
431
+ }
432
+ }
433
+ // Add small session
434
+ const session2 = client.spawnNewSession();
435
+ const mapInSession2 = await loadCoValueOrFail(session2.node, map.id);
436
+ mapInSession2.set("small", "value", "trusting");
437
+ session2.node.syncManager.handleNewContent(singleLargeContentPiece, "storage");
438
+ await mapInSession2.core.waitForSync();
439
+ // Add third large session
440
+ const session3 = client.spawnNewSession();
441
+ const mapInSession3 = await loadCoValueOrFail(session3.node, map.id);
442
+ for (let i = 0; i < chunks; i++) {
443
+ const key = `key3_${i}`;
444
+ mapInSession3.set(key, value, "trusting");
445
+ }
446
+ const content = mapInSession3.core.newContentSince(undefined);
447
+ const sessionMapping = {
448
+ [client.node.currentSessionID]: "alice",
449
+ [session2.node.currentSessionID]: "bob",
450
+ [session3.node.currentSessionID]: "charlie",
451
+ };
452
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
453
+ [
454
+ {
455
+ "action": "content",
456
+ "expectContentUntil": {
457
+ "alice": 100,
458
+ "bob": 1,
459
+ "charlie": 100,
460
+ },
461
+ "header": "header",
462
+ "id": "id",
463
+ "new": {
464
+ "alice": {
465
+ "lastSignature": "signature",
466
+ "newTransactions": "100 transactions after 0",
467
+ },
468
+ },
469
+ "priority": 3,
470
+ },
471
+ {
472
+ "action": "content",
473
+ "expectContentUntil": undefined,
474
+ "header": undefined,
475
+ "id": "id",
476
+ "new": {
477
+ "charlie": {
478
+ "lastSignature": "signature",
479
+ "newTransactions": "73 transactions after 0",
480
+ },
481
+ },
482
+ "priority": 3,
483
+ },
484
+ {
485
+ "action": "content",
486
+ "expectContentUntil": undefined,
487
+ "header": undefined,
488
+ "id": "id",
489
+ "new": {
490
+ "bob": {
491
+ "lastSignature": "signature",
492
+ "newTransactions": "1 transactions after 0",
493
+ },
494
+ "charlie": {
495
+ "lastSignature": "signature",
496
+ "newTransactions": "27 transactions after 73",
497
+ },
498
+ },
499
+ "priority": 3,
500
+ },
501
+ ]
502
+ `);
503
+ });
504
+ });
505
+ describe("large session logs with knownState", () => {
506
+ test("one large session log that requires multiple content pieces starting from knownState", () => {
507
+ const client = setupTestNode();
508
+ const group = client.node.createGroup();
509
+ const map = group.createMap();
510
+ // Generate a large amount of data (about 1MB)
511
+ const dataSize = 1 * 1024 * 100;
512
+ const chunkSize = 1024; // 1KB chunks
513
+ const chunks = dataSize / chunkSize;
514
+ const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
515
+ for (let i = 0; i < chunks; i++) {
516
+ const key = `key${i}`;
517
+ map.set(key, value, "trusting");
518
+ }
519
+ // Capture knownState partway through
520
+ const knownState = map.core.knownState();
521
+ // Add more data
522
+ for (let i = 0; i < chunks; i++) {
523
+ const key = `key_new_${i}`;
524
+ map.set(key, value, "trusting");
525
+ }
526
+ const content = map.core.newContentSince(knownState);
527
+ const sessionMapping = {
528
+ [client.node.currentSessionID]: "alice",
529
+ };
530
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
531
+ [
532
+ {
533
+ "action": "content",
534
+ "expectContentUntil": {
535
+ "alice": 200,
536
+ },
537
+ "header": undefined,
538
+ "id": "id",
539
+ "new": {
540
+ "alice": {
541
+ "lastSignature": "signature",
542
+ "newTransactions": "46 transactions after 100",
543
+ },
544
+ },
545
+ "priority": 3,
546
+ },
547
+ {
548
+ "action": "content",
549
+ "expectContentUntil": undefined,
550
+ "header": undefined,
551
+ "id": "id",
552
+ "new": {
553
+ "alice": {
554
+ "lastSignature": "signature",
555
+ "newTransactions": "54 transactions after 146",
556
+ },
557
+ },
558
+ "priority": 3,
559
+ },
560
+ ]
561
+ `);
562
+ });
563
+ test("one large session log that requires multiple content pieces and one small starting from knownState", async () => {
564
+ const client = setupTestNode({
565
+ connected: true,
566
+ });
567
+ const group = client.node.createGroup();
568
+ const map = group.createMap();
569
+ // Generate a large amount of data (about 1MB)
570
+ const dataSize = 1 * 1024 * 100;
571
+ const chunkSize = 1024; // 1KB chunks
572
+ const chunks = dataSize / chunkSize;
573
+ const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
574
+ for (let i = 0; i < chunks; i++) {
575
+ const key = `key${i}`;
576
+ map.set(key, value, "trusting");
577
+ }
578
+ // Capture knownState
579
+ const knownState = map.core.knownState();
580
+ // Add more data to first session
581
+ for (let i = 0; i < chunks; i++) {
582
+ const key = `key_new_${i}`;
583
+ map.set(key, value, "trusting");
584
+ }
585
+ // Add a small session
586
+ const newSession = client.spawnNewSession();
587
+ const mapInNewSession = await loadCoValueOrFail(newSession.node, map.id);
588
+ mapInNewSession.set("small", "value", "trusting");
589
+ const content = mapInNewSession.core.newContentSince(knownState);
590
+ const sessionMapping = {
591
+ [client.node.currentSessionID]: "alice",
592
+ [newSession.node.currentSessionID]: "bob",
593
+ };
594
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
595
+ [
596
+ {
597
+ "action": "content",
598
+ "expectContentUntil": {
599
+ "alice": 200,
600
+ "bob": 1,
601
+ },
602
+ "header": undefined,
603
+ "id": "id",
604
+ "new": {
605
+ "alice": {
606
+ "lastSignature": "signature",
607
+ "newTransactions": "46 transactions after 100",
608
+ },
609
+ },
610
+ "priority": 3,
611
+ },
612
+ {
613
+ "action": "content",
614
+ "expectContentUntil": undefined,
615
+ "header": undefined,
616
+ "id": "id",
617
+ "new": {
618
+ "alice": {
619
+ "lastSignature": "signature",
620
+ "newTransactions": "54 transactions after 146",
621
+ },
622
+ "bob": {
623
+ "lastSignature": "signature",
624
+ "newTransactions": "1 transactions after 0",
625
+ },
626
+ },
627
+ "priority": 3,
628
+ },
629
+ ]
630
+ `);
631
+ });
632
+ test("two large session logs starting from knownState", async () => {
633
+ const client = setupTestNode({
634
+ connected: true,
635
+ });
636
+ const group = client.node.createGroup();
637
+ const map = group.createMap();
638
+ // Generate initial data
639
+ map.set("initial", "value", "trusting");
640
+ // Capture knownState
641
+ const knownState = map.core.knownState();
642
+ // Generate a large amount of data in first session (about 1MB)
643
+ const dataSize = 1 * 1024 * 100;
644
+ const chunkSize = 1024; // 1KB chunks
645
+ const chunks = dataSize / chunkSize;
646
+ const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
647
+ for (let i = 0; i < chunks; i++) {
648
+ const key = `key1_${i}`;
649
+ map.set(key, value, "trusting");
650
+ }
651
+ // Add second large session
652
+ const newSession = client.spawnNewSession();
653
+ const mapInNewSession = await loadCoValueOrFail(newSession.node, map.id);
654
+ for (let i = 0; i < chunks; i++) {
655
+ const key = `key2_${i}`;
656
+ mapInNewSession.set(key, value, "trusting");
657
+ }
658
+ const content = mapInNewSession.core.newContentSince(knownState);
659
+ const sessionMapping = {
660
+ [client.node.currentSessionID]: "alice",
661
+ [newSession.node.currentSessionID]: "bob",
662
+ };
663
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
664
+ [
665
+ {
666
+ "action": "content",
667
+ "expectContentUntil": {
668
+ "alice": 101,
669
+ "bob": 100,
670
+ },
671
+ "header": undefined,
672
+ "id": "id",
673
+ "new": {
674
+ "alice": {
675
+ "lastSignature": "signature",
676
+ "newTransactions": "73 transactions after 1",
677
+ },
678
+ },
679
+ "priority": 3,
680
+ },
681
+ {
682
+ "action": "content",
683
+ "expectContentUntil": undefined,
684
+ "header": undefined,
685
+ "id": "id",
686
+ "new": {
687
+ "bob": {
688
+ "lastSignature": "signature",
689
+ "newTransactions": "73 transactions after 0",
690
+ },
691
+ },
692
+ "priority": 3,
693
+ },
694
+ {
695
+ "action": "content",
696
+ "expectContentUntil": undefined,
697
+ "header": undefined,
698
+ "id": "id",
699
+ "new": {
700
+ "alice": {
701
+ "lastSignature": "signature",
702
+ "newTransactions": "27 transactions after 74",
703
+ },
704
+ "bob": {
705
+ "lastSignature": "signature",
706
+ "newTransactions": "27 transactions after 73",
707
+ },
708
+ },
709
+ "priority": 3,
710
+ },
711
+ ]
712
+ `);
713
+ });
714
+ test("one large, one small, and one large session log starting from knownState", async () => {
715
+ const client = setupTestNode({
716
+ connected: true,
717
+ });
718
+ const group = client.node.createGroup();
719
+ const map = group.createMap();
720
+ // Generate initial data
721
+ map.set("initial", "value", "trusting");
722
+ // Capture knownState
723
+ const knownState = map.core.knownState();
724
+ // Generate first large session (about 1MB)
725
+ const dataSize = 1 * 1024 * 100;
726
+ const chunkSize = 1024; // 1KB chunks
727
+ const chunks = dataSize / chunkSize;
728
+ const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
729
+ for (let i = 0; i < chunks; i++) {
730
+ const key = `key1_${i}`;
731
+ map.set(key, value, "trusting");
732
+ }
733
+ // Add small session
734
+ const session2 = client.spawnNewSession();
735
+ const mapInSession2 = await loadCoValueOrFail(session2.node, map.id);
736
+ mapInSession2.set("small", "value", "trusting");
737
+ // Add third large session
738
+ const session3 = client.spawnNewSession();
739
+ const mapInSession3 = await loadCoValueOrFail(session3.node, map.id);
740
+ for (let i = 0; i < chunks; i++) {
741
+ const key = `key3_${i}`;
742
+ mapInSession3.set(key, value, "trusting");
743
+ }
744
+ const content = mapInSession3.core.newContentSince(knownState);
745
+ const sessionMapping = {
746
+ [client.node.currentSessionID]: "alice",
747
+ [session2.node.currentSessionID]: "bob",
748
+ [session3.node.currentSessionID]: "charlie",
749
+ };
750
+ expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
751
+ [
752
+ {
753
+ "action": "content",
754
+ "expectContentUntil": {
755
+ "alice": 101,
756
+ "bob": 1,
757
+ "charlie": 100,
758
+ },
759
+ "header": undefined,
760
+ "id": "id",
761
+ "new": {
762
+ "alice": {
763
+ "lastSignature": "signature",
764
+ "newTransactions": "73 transactions after 1",
765
+ },
766
+ },
767
+ "priority": 3,
768
+ },
769
+ {
770
+ "action": "content",
771
+ "expectContentUntil": undefined,
772
+ "header": undefined,
773
+ "id": "id",
774
+ "new": {
775
+ "charlie": {
776
+ "lastSignature": "signature",
777
+ "newTransactions": "73 transactions after 0",
778
+ },
779
+ },
780
+ "priority": 3,
781
+ },
782
+ {
783
+ "action": "content",
784
+ "expectContentUntil": undefined,
785
+ "header": undefined,
786
+ "id": "id",
787
+ "new": {
788
+ "alice": {
789
+ "lastSignature": "signature",
790
+ "newTransactions": "27 transactions after 74",
791
+ },
792
+ "bob": {
793
+ "lastSignature": "signature",
794
+ "newTransactions": "1 transactions after 0",
795
+ },
796
+ "charlie": {
797
+ "lastSignature": "signature",
798
+ "newTransactions": "27 transactions after 73",
799
+ },
800
+ },
801
+ "priority": 3,
802
+ },
803
+ ]
804
+ `);
805
+ });
806
+ });
807
+ });
808
+ //# sourceMappingURL=coValueCore.newContentSince.test.js.map