cojson 0.16.3 → 0.16.5

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 (138) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +20 -0
  3. package/dist/coValue.d.ts +1 -1
  4. package/dist/coValue.d.ts.map +1 -1
  5. package/dist/coValue.js.map +1 -1
  6. package/dist/coValueContentMessage.d.ts +10 -0
  7. package/dist/coValueContentMessage.d.ts.map +1 -0
  8. package/dist/coValueContentMessage.js +46 -0
  9. package/dist/coValueContentMessage.js.map +1 -0
  10. package/dist/coValueCore/coValueCore.d.ts +6 -10
  11. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  12. package/dist/coValueCore/coValueCore.js +20 -125
  13. package/dist/coValueCore/coValueCore.js.map +1 -1
  14. package/dist/coValueCore/verifiedState.d.ts +1 -0
  15. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  16. package/dist/coValueCore/verifiedState.js +14 -27
  17. package/dist/coValueCore/verifiedState.js.map +1 -1
  18. package/dist/coValues/group.d.ts +18 -10
  19. package/dist/coValues/group.d.ts.map +1 -1
  20. package/dist/coValues/group.js +237 -67
  21. package/dist/coValues/group.js.map +1 -1
  22. package/dist/ids.d.ts +3 -3
  23. package/dist/ids.d.ts.map +1 -1
  24. package/dist/ids.js.map +1 -1
  25. package/dist/localNode.d.ts +11 -6
  26. package/dist/localNode.d.ts.map +1 -1
  27. package/dist/localNode.js +7 -2
  28. package/dist/localNode.js.map +1 -1
  29. package/dist/queue/LocalTransactionsSyncQueue.d.ts +24 -0
  30. package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -0
  31. package/dist/queue/LocalTransactionsSyncQueue.js +55 -0
  32. package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -0
  33. package/dist/queue/StoreQueue.d.ts +9 -6
  34. package/dist/queue/StoreQueue.d.ts.map +1 -1
  35. package/dist/queue/StoreQueue.js +10 -2
  36. package/dist/queue/StoreQueue.js.map +1 -1
  37. package/dist/storage/storageAsync.d.ts +11 -3
  38. package/dist/storage/storageAsync.d.ts.map +1 -1
  39. package/dist/storage/storageAsync.js +59 -46
  40. package/dist/storage/storageAsync.js.map +1 -1
  41. package/dist/storage/storageSync.d.ts +9 -3
  42. package/dist/storage/storageSync.d.ts.map +1 -1
  43. package/dist/storage/storageSync.js +48 -35
  44. package/dist/storage/storageSync.js.map +1 -1
  45. package/dist/storage/syncUtils.d.ts +2 -1
  46. package/dist/storage/syncUtils.d.ts.map +1 -1
  47. package/dist/storage/syncUtils.js +4 -0
  48. package/dist/storage/syncUtils.js.map +1 -1
  49. package/dist/storage/types.d.ts +3 -2
  50. package/dist/storage/types.d.ts.map +1 -1
  51. package/dist/sync.d.ts +6 -6
  52. package/dist/sync.d.ts.map +1 -1
  53. package/dist/sync.js +33 -56
  54. package/dist/sync.js.map +1 -1
  55. package/dist/tests/StorageApiAsync.test.d.ts +2 -0
  56. package/dist/tests/StorageApiAsync.test.d.ts.map +1 -0
  57. package/dist/tests/StorageApiAsync.test.js +574 -0
  58. package/dist/tests/StorageApiAsync.test.js.map +1 -0
  59. package/dist/tests/StorageApiSync.test.d.ts +2 -0
  60. package/dist/tests/StorageApiSync.test.d.ts.map +1 -0
  61. package/dist/tests/StorageApiSync.test.js +426 -0
  62. package/dist/tests/StorageApiSync.test.js.map +1 -0
  63. package/dist/tests/StoreQueue.test.js +9 -21
  64. package/dist/tests/StoreQueue.test.js.map +1 -1
  65. package/dist/tests/SyncStateManager.test.js +18 -8
  66. package/dist/tests/SyncStateManager.test.js.map +1 -1
  67. package/dist/tests/group.inheritance.test.js +274 -2
  68. package/dist/tests/group.inheritance.test.js.map +1 -1
  69. package/dist/tests/group.removeMember.test.js +152 -1
  70. package/dist/tests/group.removeMember.test.js.map +1 -1
  71. package/dist/tests/group.roleOf.test.js +2 -2
  72. package/dist/tests/group.roleOf.test.js.map +1 -1
  73. package/dist/tests/group.test.js +81 -3
  74. package/dist/tests/group.test.js.map +1 -1
  75. package/dist/tests/sync.auth.test.js +22 -10
  76. package/dist/tests/sync.auth.test.js.map +1 -1
  77. package/dist/tests/sync.load.test.js +30 -25
  78. package/dist/tests/sync.load.test.js.map +1 -1
  79. package/dist/tests/sync.mesh.test.js +12 -6
  80. package/dist/tests/sync.mesh.test.js.map +1 -1
  81. package/dist/tests/sync.peerReconciliation.test.js +6 -4
  82. package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
  83. package/dist/tests/sync.storage.test.js +8 -14
  84. package/dist/tests/sync.storage.test.js.map +1 -1
  85. package/dist/tests/sync.storageAsync.test.js +31 -14
  86. package/dist/tests/sync.storageAsync.test.js.map +1 -1
  87. package/dist/tests/sync.test.js +5 -9
  88. package/dist/tests/sync.test.js.map +1 -1
  89. package/dist/tests/sync.upload.test.js +31 -1
  90. package/dist/tests/sync.upload.test.js.map +1 -1
  91. package/dist/tests/testStorage.d.ts +2 -3
  92. package/dist/tests/testStorage.d.ts.map +1 -1
  93. package/dist/tests/testStorage.js +16 -8
  94. package/dist/tests/testStorage.js.map +1 -1
  95. package/dist/tests/testUtils.d.ts +4 -0
  96. package/dist/tests/testUtils.d.ts.map +1 -1
  97. package/dist/tests/testUtils.js +22 -4
  98. package/dist/tests/testUtils.js.map +1 -1
  99. package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts +2 -2
  100. package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts.map +1 -1
  101. package/dist/typeUtils/expectGroup.d.ts.map +1 -1
  102. package/dist/typeUtils/expectGroup.js +6 -5
  103. package/dist/typeUtils/expectGroup.js.map +1 -1
  104. package/package.json +1 -1
  105. package/src/coValue.ts +1 -4
  106. package/src/coValueContentMessage.ts +73 -0
  107. package/src/coValueCore/coValueCore.ts +36 -192
  108. package/src/coValueCore/verifiedState.ts +28 -35
  109. package/src/coValues/group.ts +329 -99
  110. package/src/ids.ts +3 -3
  111. package/src/localNode.ts +15 -10
  112. package/src/queue/LocalTransactionsSyncQueue.ts +96 -0
  113. package/src/queue/StoreQueue.ts +22 -12
  114. package/src/storage/storageAsync.ts +78 -56
  115. package/src/storage/storageSync.ts +66 -45
  116. package/src/storage/syncUtils.ts +9 -1
  117. package/src/storage/types.ts +6 -5
  118. package/src/sync.ts +47 -67
  119. package/src/tests/StorageApiAsync.test.ts +829 -0
  120. package/src/tests/StorageApiSync.test.ts +628 -0
  121. package/src/tests/StoreQueue.test.ts +10 -24
  122. package/src/tests/SyncStateManager.test.ts +22 -21
  123. package/src/tests/group.inheritance.test.ts +415 -1
  124. package/src/tests/group.removeMember.test.ts +244 -1
  125. package/src/tests/group.roleOf.test.ts +2 -2
  126. package/src/tests/group.test.ts +105 -5
  127. package/src/tests/sync.auth.test.ts +22 -10
  128. package/src/tests/sync.load.test.ts +32 -26
  129. package/src/tests/sync.mesh.test.ts +12 -6
  130. package/src/tests/sync.peerReconciliation.test.ts +6 -4
  131. package/src/tests/sync.storage.test.ts +8 -14
  132. package/src/tests/sync.storageAsync.test.ts +39 -14
  133. package/src/tests/sync.test.ts +6 -14
  134. package/src/tests/sync.upload.test.ts +38 -1
  135. package/src/tests/testStorage.ts +19 -13
  136. package/src/tests/testUtils.ts +29 -5
  137. package/src/typeUtils/accountOrAgentIDfromSessionID.ts +2 -2
  138. package/src/typeUtils/expectGroup.ts +8 -5
@@ -1,12 +1,15 @@
1
1
  import { beforeEach, describe, expect, test } from "vitest";
2
+ import { setCoValueLoadingRetryDelay } from "../config.js";
2
3
  import {
3
4
  SyncMessagesLog,
4
- TEST_NODE_CONFIG,
5
+ blockMessageTypeOnOutgoingPeer,
5
6
  loadCoValueOrFail,
6
7
  setupTestAccount,
7
8
  setupTestNode,
8
9
  } from "./testUtils.js";
9
10
 
11
+ setCoValueLoadingRetryDelay(10);
12
+
10
13
  let jazzCloud: ReturnType<typeof setupTestNode>;
11
14
 
12
15
  beforeEach(async () => {
@@ -15,6 +18,65 @@ beforeEach(async () => {
15
18
  });
16
19
 
17
20
  describe("Group.removeMember", () => {
21
+ test("revoking a member access should not affect everyone access", async () => {
22
+ const admin = await setupTestAccount({
23
+ connected: true,
24
+ });
25
+
26
+ const alice = await setupTestAccount({
27
+ connected: true,
28
+ });
29
+
30
+ const group = admin.node.createGroup();
31
+ group.addMember("everyone", "writer");
32
+
33
+ const aliceOnAdminNode = await loadCoValueOrFail(
34
+ admin.node,
35
+ alice.accountID,
36
+ );
37
+ group.addMember(aliceOnAdminNode, "writer");
38
+ group.removeMember(aliceOnAdminNode);
39
+
40
+ const groupOnAliceNode = await loadCoValueOrFail(alice.node, group.id);
41
+ expect(groupOnAliceNode.myRole()).toEqual("writer");
42
+
43
+ const map = groupOnAliceNode.createMap();
44
+
45
+ map.set("test", "test");
46
+ expect(map.get("test")).toEqual("test");
47
+ });
48
+
49
+ test("revoking a member access should not affect everyone access when everyone access is gained through a group extension", async () => {
50
+ const admin = await setupTestAccount({
51
+ connected: true,
52
+ });
53
+
54
+ const alice = await setupTestAccount({
55
+ connected: true,
56
+ });
57
+
58
+ const parentGroup = admin.node.createGroup();
59
+ const group = admin.node.createGroup();
60
+ parentGroup.addMember("everyone", "reader");
61
+ group.extend(parentGroup);
62
+
63
+ const aliceOnAdminNode = await loadCoValueOrFail(
64
+ admin.node,
65
+ alice.accountID,
66
+ );
67
+ group.addMember(aliceOnAdminNode, "writer");
68
+ group.removeMember(aliceOnAdminNode);
69
+
70
+ const map = group.createMap();
71
+ map.set("test", "test");
72
+
73
+ const groupOnAliceNode = await loadCoValueOrFail(alice.node, group.id);
74
+ expect(groupOnAliceNode.myRole()).toEqual("reader");
75
+
76
+ const mapOnAliceNode = await loadCoValueOrFail(alice.node, map.id);
77
+ expect(mapOnAliceNode.get("test")).toEqual("test");
78
+ });
79
+
18
80
  test("a reader member should be able to revoke themselves", async () => {
19
81
  const admin = await setupTestAccount({
20
82
  connected: true,
@@ -294,4 +356,185 @@ describe("Group.removeMember", () => {
294
356
  undefined,
295
357
  );
296
358
  });
359
+
360
+ test("removing a member should rotate the readKey on available child groups", async () => {
361
+ const admin = await setupTestAccount({
362
+ connected: true,
363
+ });
364
+
365
+ const alice = await setupTestAccount({
366
+ connected: true,
367
+ });
368
+
369
+ const aliceOnAdminNode = await loadCoValueOrFail(
370
+ admin.node,
371
+ alice.accountID,
372
+ );
373
+
374
+ const group = admin.node.createGroup();
375
+ const childGroup = admin.node.createGroup();
376
+ group.addMember(aliceOnAdminNode, "reader");
377
+
378
+ childGroup.extend(group);
379
+
380
+ group.removeMember(aliceOnAdminNode);
381
+
382
+ const map = childGroup.createMap();
383
+ map.set("test", "Not readable by alice");
384
+
385
+ await map.core.waitForSync();
386
+
387
+ const mapOnAliceNode = await loadCoValueOrFail(alice.node, map.id);
388
+ expect(mapOnAliceNode.get("test")).toBeUndefined();
389
+ });
390
+
391
+ test("removing a member should rotate the readKey on unloaded child groups", async () => {
392
+ const admin = await setupTestAccount({
393
+ connected: true,
394
+ });
395
+
396
+ const bob = await setupTestAccount({
397
+ connected: true,
398
+ });
399
+
400
+ const alice = await setupTestAccount({
401
+ connected: true,
402
+ });
403
+
404
+ const bobOnAdminNode = await loadCoValueOrFail(admin.node, bob.accountID);
405
+
406
+ const aliceOnAdminNode = await loadCoValueOrFail(
407
+ admin.node,
408
+ alice.accountID,
409
+ );
410
+
411
+ const group = admin.node.createGroup();
412
+
413
+ const childGroup = bob.node.createGroup();
414
+ group.addMember(bobOnAdminNode, "reader");
415
+ group.addMember(aliceOnAdminNode, "reader");
416
+
417
+ const groupOnBobNode = await loadCoValueOrFail(bob.node, group.id);
418
+
419
+ childGroup.extend(groupOnBobNode);
420
+
421
+ await childGroup.core.waitForSync();
422
+
423
+ group.removeMember(aliceOnAdminNode);
424
+
425
+ // Rotating the child group keys is async when the child group is not loaded
426
+ await admin.node.getCoValue(childGroup.id).waitForAvailableOrUnavailable();
427
+ await admin.node.syncManager.waitForAllCoValuesSync();
428
+
429
+ const map = childGroup.createMap();
430
+ map.set("test", "Not readable by alice");
431
+
432
+ await map.core.waitForSync();
433
+
434
+ const mapOnAliceNode = await loadCoValueOrFail(alice.node, map.id);
435
+ expect(mapOnAliceNode.get("test")).toBeUndefined();
436
+ });
437
+
438
+ test("removing a member should work even if there are partially available child groups", async () => {
439
+ const admin = await setupTestAccount({
440
+ connected: true,
441
+ });
442
+
443
+ const bob = await setupTestAccount();
444
+ const { peer } = bob.connectToSyncServer();
445
+
446
+ const alice = await setupTestAccount({
447
+ connected: true,
448
+ });
449
+
450
+ const bobOnAdminNode = await loadCoValueOrFail(admin.node, bob.accountID);
451
+
452
+ const aliceOnAdminNode = await loadCoValueOrFail(
453
+ admin.node,
454
+ alice.accountID,
455
+ );
456
+
457
+ const group = admin.node.createGroup();
458
+ const childGroup = bob.node.createGroup();
459
+
460
+ group.addMember(bobOnAdminNode, "reader");
461
+ group.addMember(aliceOnAdminNode, "reader");
462
+
463
+ await group.core.waitForSync();
464
+
465
+ blockMessageTypeOnOutgoingPeer(peer, "content", {
466
+ id: childGroup.id,
467
+ });
468
+
469
+ const groupOnBobNode = await loadCoValueOrFail(bob.node, group.id);
470
+
471
+ childGroup.extend(groupOnBobNode);
472
+
473
+ await groupOnBobNode.core.waitForSync();
474
+
475
+ group.removeMember(aliceOnAdminNode);
476
+
477
+ await admin.node.syncManager.waitForAllCoValuesSync();
478
+
479
+ const map = group.createMap();
480
+ map.set("test", "Not readable by alice");
481
+
482
+ await map.core.waitForSync();
483
+
484
+ const mapOnAliceNode = await loadCoValueOrFail(alice.node, map.id);
485
+ expect(mapOnAliceNode.get("test")).toBeUndefined();
486
+ });
487
+
488
+ test("removing a member should work even if there are unavailable child groups", async () => {
489
+ const admin = await setupTestAccount({
490
+ connected: true,
491
+ });
492
+
493
+ const { peerOnServer } = admin.connectToSyncServer();
494
+
495
+ const bob = await setupTestAccount({
496
+ connected: true,
497
+ });
498
+
499
+ const alice = await setupTestAccount({
500
+ connected: true,
501
+ });
502
+
503
+ const bobOnAdminNode = await loadCoValueOrFail(admin.node, bob.accountID);
504
+
505
+ const aliceOnAdminNode = await loadCoValueOrFail(
506
+ admin.node,
507
+ alice.accountID,
508
+ );
509
+
510
+ const group = admin.node.createGroup();
511
+ const childGroup = bob.node.createGroup();
512
+
513
+ blockMessageTypeOnOutgoingPeer(peerOnServer, "content", {
514
+ id: childGroup.id,
515
+ });
516
+
517
+ group.addMember(bobOnAdminNode, "reader");
518
+ group.addMember(aliceOnAdminNode, "reader");
519
+
520
+ await group.core.waitForSync();
521
+
522
+ const groupOnBobNode = await loadCoValueOrFail(bob.node, group.id);
523
+
524
+ childGroup.extend(groupOnBobNode);
525
+
526
+ await groupOnBobNode.core.waitForSync();
527
+
528
+ group.removeMember(aliceOnAdminNode);
529
+
530
+ await group.core.waitForSync();
531
+
532
+ const map = group.createMap();
533
+ map.set("test", "Not readable by alice");
534
+
535
+ await map.core.waitForSync();
536
+
537
+ const mapOnAliceNode = await loadCoValueOrFail(alice.node, map.id);
538
+ expect(mapOnAliceNode.get("test")).toBeUndefined();
539
+ });
297
540
  });
@@ -33,7 +33,7 @@ describe("roleOf", () => {
33
33
  const [agent2] = randomAgentAndSessionID();
34
34
 
35
35
  group.addMember(agent2, "writer");
36
- group.removeMemberInternal(agent2);
36
+ group.removeMember(agent2);
37
37
  expect(group.roleOfInternal(agent2.id)).toEqual(undefined);
38
38
  });
39
39
 
@@ -63,7 +63,7 @@ describe("roleOf", () => {
63
63
 
64
64
  group.addMemberInternal("everyone", "reader");
65
65
  group.addMember(agent2, "writer");
66
- group.removeMemberInternal("everyone");
66
+ group.removeMember("everyone");
67
67
  expect(group.roleOfInternal(agent2.id)).toEqual("writer");
68
68
  expect(group.roleOfInternal("123" as RawAccountID)).toEqual(undefined);
69
69
  });
@@ -3,18 +3,27 @@ import { RawCoList } from "../coValues/coList.js";
3
3
  import { RawCoMap } from "../coValues/coMap.js";
4
4
  import { RawCoStream } from "../coValues/coStream.js";
5
5
  import { RawBinaryCoStream } from "../coValues/coStream.js";
6
- import { WasmCrypto } from "../crypto/WasmCrypto.js";
7
- import { RawAccountID } from "../exports.js";
6
+ import type { RawCoValue, RawGroup } from "../exports.js";
7
+ import type { NewContentMessage } from "../sync.js";
8
8
  import {
9
9
  createThreeConnectedNodes,
10
10
  createTwoConnectedNodes,
11
11
  loadCoValueOrFail,
12
12
  nodeWithRandomAgentAndSessionID,
13
- randomAgentAndSessionID,
14
- waitFor,
13
+ setupTestNode,
15
14
  } from "./testUtils.js";
16
15
 
17
- const Crypto = await WasmCrypto.create();
16
+ function expectGroup(content: RawCoValue): RawGroup {
17
+ if (content.type !== "comap") {
18
+ throw new Error("Expected group");
19
+ }
20
+
21
+ if (content.core.verified.header.ruleset.type !== "group") {
22
+ throw new Error("Expected group ruleset in group");
23
+ }
24
+
25
+ return content as RawGroup;
26
+ }
18
27
 
19
28
  test("Can create a RawCoMap in a group", () => {
20
29
  const node = nodeWithRandomAgentAndSessionID();
@@ -307,6 +316,97 @@ test("Invites should have access to the new keys", async () => {
307
316
  expect(mapOnNode2.get("test")).toEqual("Written from node1");
308
317
  });
309
318
 
319
+ test("Should heal the missing key_for_everyone", async () => {
320
+ const client = setupTestNode({
321
+ secret:
322
+ "sealerSecret_zBTPp7U58Fzq9o7EvJpu4KEziepi8QVf2Xaxuy5xmmXFx/signerSecret_z62DuviZdXCjz4EZWofvr9vaLYFXDeTaC9KWhoQiQjzKk",
323
+ });
324
+
325
+ const brokenGroupContent = {
326
+ action: "content",
327
+ id: "co_zW7F36Nnop9A7Er4gUzBcUXnZCK",
328
+ header: {
329
+ type: "comap",
330
+ ruleset: {
331
+ type: "group",
332
+ initialAdmin:
333
+ "sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv",
334
+ },
335
+ meta: null,
336
+ createdAt: "2025-08-06T10:14:39.617Z",
337
+ uniqueness: "z3LJjnuPiPJaf5Qb9A",
338
+ },
339
+ priority: 0,
340
+ new: {
341
+ "sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv_session_zYLsz2CiW9pW":
342
+ {
343
+ after: 0,
344
+ newTransactions: [
345
+ {
346
+ privacy: "trusting",
347
+ madeAt: 1754475279619,
348
+ changes:
349
+ '[{"key":"sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"admin"}]',
350
+ },
351
+ {
352
+ privacy: "trusting",
353
+ madeAt: 1754475279621,
354
+ changes:
355
+ '[{"key":"key_z5CVahfMkEWPj1B3zH_for_sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"sealed_UCg4UkytXF-W8PaIvaDffO3pZ3d9hdXUuNkQQEikPTAuOD9us92Pqb5Vgu7lx1Fpb0X8V5BJ2yxz6_D5WOzK3qjWBSsc7J1xDJA=="}]',
356
+ },
357
+ {
358
+ privacy: "trusting",
359
+ madeAt: 1754475279621,
360
+ changes:
361
+ '[{"key":"readKey","op":"set","value":"key_z5CVahfMkEWPj1B3zH"}]',
362
+ },
363
+ {
364
+ privacy: "trusting",
365
+ madeAt: 1754475279622,
366
+ changes: '[{"key":"everyone","op":"set","value":"reader"}]',
367
+ },
368
+ {
369
+ privacy: "trusting",
370
+ madeAt: 1754475279623,
371
+ changes:
372
+ '[{"key":"key_z5CVahfMkEWPj1B3zH_for_everyone","op":"set","value":"keySecret_z9U9gzkahQXCxDoSw7isiUnbobXwuLdcSkL9Ci6ZEEkaL"}]',
373
+ },
374
+ {
375
+ privacy: "trusting",
376
+ madeAt: 1754475279623,
377
+ changes:
378
+ '[{"key":"key_z4Fi7hZNBx7XoVAKkP_for_sealer_z12QDazYB3ygPZtBV7sMm7iYKMRnNZ6Aaj1dfLXR7LSBm/signer_z2AskZQbc82qxo7iA3oiXoNExHLsAEXC2pHbwJzRnATWv","op":"set","value":"sealed_UuCBBfZkTnRTrGraqWWlzm9JE-VFduhsfu7WaZjpCbJYOTXpPhSNOnzGeS8qVuIsG6dORbME22lc5ltLxPjRqofQdDCNGQehCeQ=="}]',
379
+ },
380
+ {
381
+ privacy: "trusting",
382
+ madeAt: 1754475279624,
383
+ changes:
384
+ '[{"key":"key_z5CVahfMkEWPj1B3zH_for_key_z4Fi7hZNBx7XoVAKkP","op":"set","value":"encrypted_USTrBuobwTCORwy5yHxy4sFZ7swfrafP6k5ZwcTf76f0MBu9Ie-JmsX3mNXad4mluI47gvGXzi8I_"}]',
385
+ },
386
+ {
387
+ privacy: "trusting",
388
+ madeAt: 1754475279624,
389
+ changes:
390
+ '[{"key":"readKey","op":"set","value":"key_z4Fi7hZNBx7XoVAKkP"}]',
391
+ },
392
+ ],
393
+ lastSignature:
394
+ "signature_z3tsE7U1JaeNeUmZ4EY3Xq5uQ9jq9jDi6Rkhdt7T7b7z4NCnpMgB4bo8TwLXYVCrRdBm6PoyyPdK8fYFzHJUh5EzA",
395
+ },
396
+ },
397
+ } as unknown as NewContentMessage;
398
+
399
+ client.node.syncManager.handleNewContent(brokenGroupContent, "import");
400
+
401
+ const group = expectGroup(
402
+ client.node.getCoValue(brokenGroupContent.id).getCurrentContent(),
403
+ );
404
+
405
+ expect(group.get(`${group.get("readKey")!}_for_everyone`)).toBe(
406
+ group.core.getCurrentReadKey()?.secret,
407
+ );
408
+ });
409
+
310
410
  describe("writeOnly", () => {
311
411
  test("Admins can invite writeOnly members", async () => {
312
412
  const { node1, node2 } = await createTwoConnectedNodes("server", "server");
@@ -53,12 +53,14 @@ describe("LocalNode auth sync", () => {
53
53
  }),
54
54
  ).toMatchInlineSnapshot(`
55
55
  [
56
- "client -> server | CONTENT Account header: true new: After: 0 New: 4",
56
+ "client -> server | CONTENT Account header: true new: After: 0 New: 3",
57
57
  "client -> server | CONTENT ProfileGroup header: true new: After: 0 New: 5",
58
58
  "client -> server | CONTENT Profile header: true new: After: 0 New: 1",
59
- "server -> client | KNOWN Account sessions: header/4",
59
+ "client -> server | CONTENT Account header: false new: After: 3 New: 1",
60
+ "server -> client | KNOWN Account sessions: header/3",
60
61
  "server -> client | KNOWN ProfileGroup sessions: header/5",
61
62
  "server -> client | KNOWN Profile sessions: header/1",
63
+ "server -> client | KNOWN Account sessions: header/4",
62
64
  ]
63
65
  `);
64
66
  });
@@ -114,12 +116,18 @@ describe("LocalNode auth sync", () => {
114
116
  }),
115
117
  ).toMatchInlineSnapshot(`
116
118
  [
117
- "client -> server | CONTENT Account header: true new: After: 0 New: 5",
118
- "client -> server | CONTENT Root header: true new: After: 0 New: 1",
119
- "client -> server | CONTENT Profile header: true new: After: 0 New: 1",
120
- "server -> client | KNOWN Account sessions: header/5",
119
+ "client -> server | CONTENT Account header: true new: After: 0 New: 3",
120
+ "client -> server | CONTENT Root header: true new: ",
121
+ "client -> server | CONTENT Profile header: true new: ",
122
+ "client -> server | CONTENT Root header: false new: After: 0 New: 1",
123
+ "client -> server | CONTENT Profile header: false new: After: 0 New: 1",
124
+ "client -> server | CONTENT Account header: false new: After: 3 New: 2",
125
+ "server -> client | KNOWN Account sessions: header/3",
126
+ "server -> client | KNOWN Root sessions: header/0",
127
+ "server -> client | KNOWN Profile sessions: header/0",
121
128
  "server -> client | KNOWN Root sessions: header/1",
122
129
  "server -> client | KNOWN Profile sessions: header/1",
130
+ "server -> client | KNOWN Account sessions: header/5",
123
131
  ]
124
132
  `);
125
133
  });
@@ -168,13 +176,15 @@ describe("LocalNode auth sync", () => {
168
176
  }),
169
177
  ).toMatchInlineSnapshot(`
170
178
  [
171
- "creation-node -> server | CONTENT Account header: true new: After: 0 New: 4",
179
+ "creation-node -> server | CONTENT Account header: true new: After: 0 New: 3",
172
180
  "creation-node -> server | CONTENT ProfileGroup header: true new: After: 0 New: 5",
173
181
  "creation-node -> server | CONTENT Profile header: true new: After: 0 New: 1",
182
+ "creation-node -> server | CONTENT Account header: false new: After: 3 New: 1",
174
183
  "auth-node -> server | LOAD Account sessions: empty",
175
- "server -> creation-node | KNOWN Account sessions: header/4",
184
+ "server -> creation-node | KNOWN Account sessions: header/3",
176
185
  "server -> creation-node | KNOWN ProfileGroup sessions: header/5",
177
186
  "server -> creation-node | KNOWN Profile sessions: header/1",
187
+ "server -> creation-node | KNOWN Account sessions: header/4",
178
188
  "server -> auth-node | CONTENT Account header: true new: After: 0 New: 4",
179
189
  "auth-node -> server | KNOWN Account sessions: header/4",
180
190
  "auth-node -> server | LOAD Profile sessions: empty",
@@ -236,12 +246,14 @@ describe("LocalNode auth sync", () => {
236
246
  }),
237
247
  ).toMatchInlineSnapshot(`
238
248
  [
239
- "creation-node -> server | CONTENT Account header: true new: After: 0 New: 4",
249
+ "creation-node -> server | CONTENT Account header: true new: After: 0 New: 3",
240
250
  "creation-node -> server | CONTENT ProfileGroup header: true new: After: 0 New: 5",
241
251
  "creation-node -> server | CONTENT Profile header: true new: After: 0 New: 1",
242
- "server -> creation-node | KNOWN Account sessions: header/4",
252
+ "creation-node -> server | CONTENT Account header: false new: After: 3 New: 1",
253
+ "server -> creation-node | KNOWN Account sessions: header/3",
243
254
  "server -> creation-node | KNOWN ProfileGroup sessions: header/5",
244
255
  "server -> creation-node | KNOWN Profile sessions: header/1",
256
+ "server -> creation-node | KNOWN Account sessions: header/4",
245
257
  "auth-node -> server | LOAD Account sessions: empty",
246
258
  "server -> auth-node | CONTENT Account header: true new: After: 0 New: 4",
247
259
  "auth-node -> server | KNOWN Account sessions: header/4",
@@ -15,15 +15,15 @@ import {
15
15
  waitFor,
16
16
  } from "./testUtils";
17
17
 
18
- // We want to simulate a real world communication that happens asynchronously
19
- TEST_NODE_CONFIG.withAsyncPeers = true;
20
-
21
18
  let jazzCloud: ReturnType<typeof setupTestNode>;
22
19
 
23
20
  // Set a short timeout to make the tests on unavailable complete faster
24
21
  setCoValueLoadingRetryDelay(100);
25
22
 
26
23
  beforeEach(async () => {
24
+ // We want to simulate a real world communication that happens asynchronously
25
+ TEST_NODE_CONFIG.withAsyncPeers = true;
26
+
27
27
  SyncMessagesLog.clear();
28
28
  jazzCloud = setupTestNode({ isSyncServer: true });
29
29
  });
@@ -295,10 +295,9 @@ describe("loading coValues from server", () => {
295
295
  [
296
296
  "client -> server | LOAD Group sessions: header/3",
297
297
  "client -> server | LOAD Map sessions: header/1",
298
- "server -> client | CONTENT Group header: true new: After: 0 New: 3",
299
- "server -> client | CONTENT Map header: true new: After: 0 New: 2",
300
298
  "server -> client | CONTENT Map header: false new: After: 1 New: 1",
301
- "client -> server | KNOWN Group sessions: header/3",
299
+ "server -> client | KNOWN Group sessions: header/3",
300
+ "server -> client | CONTENT Map header: false new: After: 1 New: 1",
302
301
  "client -> server | KNOWN Map sessions: header/2",
303
302
  "client -> server | KNOWN Map sessions: header/2",
304
303
  ]
@@ -340,11 +339,10 @@ describe("loading coValues from server", () => {
340
339
  [
341
340
  "client -> server | LOAD Group sessions: header/5",
342
341
  "client -> server | LOAD Map sessions: header/2",
343
- "server -> client | CONTENT Group header: true new: After: 0 New: 5",
344
- "server -> client | CONTENT Map header: true new: After: 0 New: 2",
342
+ "server -> client | CONTENT Map header: false new: After: 1 New: 1",
345
343
  "client -> server | CONTENT Map header: false new: After: 0 New: 1",
344
+ "server -> client | KNOWN Group sessions: header/5",
346
345
  "server -> client | CONTENT Map header: false new: After: 1 New: 1",
347
- "client -> server | KNOWN Group sessions: header/5",
348
346
  "client -> server | KNOWN Map sessions: header/3",
349
347
  "server -> client | KNOWN Map sessions: header/3",
350
348
  "client -> server | KNOWN Map sessions: header/3",
@@ -550,6 +548,8 @@ describe("loading coValues from server", () => {
550
548
  });
551
549
 
552
550
  test("should handle reconnections in the middle of a load with a persistent peer", async () => {
551
+ TEST_NODE_CONFIG.withAsyncPeers = false; // To avoid flakiness
552
+
553
553
  const client = setupTestNode();
554
554
  const connection1 = client.connectToSyncServer({
555
555
  persistent: true,
@@ -590,11 +590,14 @@ describe("loading coValues from server", () => {
590
590
  "client -> server | LOAD Map sessions: empty",
591
591
  "server -> client | CONTENT Group header: true new: After: 0 New: 5",
592
592
  "client -> server | KNOWN Group sessions: header/5",
593
- "client -> server | LOAD Map sessions: empty",
594
- "client -> server | LOAD Group sessions: header/5",
595
- "server -> client | KNOWN Group sessions: header/5",
593
+ "server -> client | CONTENT Group header: true new: After: 0 New: 5",
594
+ "client -> server | KNOWN Group sessions: header/5",
596
595
  "server -> client | CONTENT Map header: true new: After: 0 New: 1",
597
596
  "client -> server | KNOWN Map sessions: header/1",
597
+ "client -> server | LOAD Group sessions: header/5",
598
+ "server -> client | KNOWN Group sessions: header/5",
599
+ "client -> server | LOAD Map sessions: header/1",
600
+ "server -> client | KNOWN Map sessions: header/1",
598
601
  ]
599
602
  `);
600
603
  });
@@ -634,7 +637,7 @@ describe("loading coValues from server", () => {
634
637
  "server -> client | CONTENT Map header: true new: After: 0 New: 1",
635
638
  "client -> server | KNOWN ParentGroup sessions: header/6",
636
639
  "client -> server | LOAD Group sessions: empty",
637
- "client -> server | KNOWN Map sessions: empty",
640
+ "client -> server | KNOWN Map sessions: header/1",
638
641
  "server -> client | CONTENT Group header: true new: After: 0 New: 5",
639
642
  "client -> server | KNOWN Group sessions: header/5",
640
643
  ]
@@ -677,8 +680,8 @@ describe("loading coValues from server", () => {
677
680
  "server -> client | CONTENT Group header: true new: After: 0 New: 5",
678
681
  "server -> client | CONTENT Map header: true new: After: 0 New: 1",
679
682
  "client -> server | LOAD ParentGroup sessions: empty",
680
- "client -> server | KNOWN Group sessions: empty",
681
- "client -> server | KNOWN Map sessions: empty",
683
+ "client -> server | KNOWN Group sessions: header/5",
684
+ "client -> server | KNOWN Map sessions: header/1",
682
685
  "server -> client | CONTENT ParentGroup header: true new: After: 0 New: 6",
683
686
  "client -> server | KNOWN ParentGroup sessions: header/6",
684
687
  ]
@@ -723,8 +726,8 @@ describe("loading coValues from server", () => {
723
726
  "server -> client | CONTENT Group header: true new: After: 0 New: 5",
724
727
  "server -> client | CONTENT Map header: true new: After: 0 New: 1",
725
728
  "client -> server | LOAD Account sessions: empty",
726
- "client -> server | KNOWN Group sessions: empty",
727
- "client -> server | KNOWN Map sessions: empty",
729
+ "client -> server | KNOWN Group sessions: header/0",
730
+ "client -> server | KNOWN Map sessions: header/0",
728
731
  "server -> client | CONTENT Account header: true new: After: 0 New: 4",
729
732
  "client -> server | KNOWN Account sessions: header/4",
730
733
  "client -> server | KNOWN Group sessions: header/5",
@@ -787,7 +790,7 @@ describe("loading coValues from server", () => {
787
790
  "server -> client | CONTENT Map header: true new: After: 0 New: 1 | After: 0 New: 1",
788
791
  "client -> server | KNOWN Group sessions: header/5",
789
792
  "client -> server | LOAD Account sessions: empty",
790
- "client -> server | KNOWN Map sessions: empty",
793
+ "client -> server | KNOWN Map sessions: header/1",
791
794
  "server -> client | CONTENT Account header: true new: After: 0 New: 4",
792
795
  "client -> server | KNOWN Account sessions: header/4",
793
796
  "client -> server | KNOWN Map sessions: header/2",
@@ -851,8 +854,8 @@ describe("loading coValues from server", () => {
851
854
  "server -> client | CONTENT Group header: true new: After: 0 New: 5",
852
855
  "server -> client | CONTENT Map header: true new: After: 0 New: 1",
853
856
  "client -> server | LOAD Account sessions: empty",
854
- "client -> server | KNOWN Group sessions: empty",
855
- "client -> server | KNOWN Map sessions: empty",
857
+ "client -> server | KNOWN Group sessions: header/0",
858
+ "client -> server | KNOWN Map sessions: header/0",
856
859
  "server -> client | CONTENT Account header: true new: After: 0 New: 4",
857
860
  "server -> client | CONTENT Account header: true new: After: 0 New: 4",
858
861
  "client -> server | KNOWN Account sessions: header/4",
@@ -922,7 +925,7 @@ describe("loading coValues from server", () => {
922
925
  "client -> server | LOAD Map sessions: empty",
923
926
  "server -> client | CONTENT Map header: true new: After: 0 New: 1",
924
927
  "client -> server | LOAD Account sessions: empty",
925
- "client -> server | KNOWN Map sessions: empty",
928
+ "client -> server | KNOWN Map sessions: header/0",
926
929
  "server -> client | CONTENT Account header: true new: After: 0 New: 4",
927
930
  "server -> client | CONTENT Account header: true new: After: 0 New: 4",
928
931
  "client -> server | KNOWN Account sessions: header/4",
@@ -960,14 +963,17 @@ describe("loading coValues from server", () => {
960
963
  }),
961
964
  ).toMatchInlineSnapshot(`
962
965
  [
963
- "client -> server | CONTENT ParentGroup header: true new: After: 0 New: 8",
964
- "client -> server | CONTENT Group header: true new: After: 0 New: 6",
966
+ "client -> server | CONTENT Group header: true new: After: 0 New: 3",
967
+ "client -> server | CONTENT ParentGroup header: true new: After: 0 New: 6",
968
+ "client -> server | CONTENT Group header: false new: After: 3 New: 3",
969
+ "client -> server | CONTENT ParentGroup header: false new: After: 6 New: 2",
965
970
  "client -> server | CONTENT Map header: true new: After: 0 New: 1",
966
- "server -> client | LOAD Group sessions: empty",
967
- "server -> client | KNOWN ParentGroup sessions: empty",
971
+ "server -> client | KNOWN Group sessions: header/3",
972
+ "server -> client | KNOWN ParentGroup sessions: header/6",
968
973
  "server -> client | KNOWN Group sessions: header/6",
974
+ "server -> client | KNOWN ParentGroup sessions: header/8",
969
975
  "server -> client | KNOWN Map sessions: header/1",
970
- "client -> server | CONTENT Group header: true new: After: 0 New: 6",
976
+ "client -> server | CONTENT ParentGroup header: true new: ",
971
977
  ]
972
978
  `);
973
979
  });