cojson 0.17.12 → 0.17.14

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 (90) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +16 -0
  3. package/dist/coValueCore/SessionMap.d.ts +4 -3
  4. package/dist/coValueCore/SessionMap.d.ts.map +1 -1
  5. package/dist/coValueCore/SessionMap.js +15 -4
  6. package/dist/coValueCore/SessionMap.js.map +1 -1
  7. package/dist/coValueCore/coValueCore.d.ts +2 -2
  8. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  9. package/dist/coValueCore/coValueCore.js +33 -32
  10. package/dist/coValueCore/coValueCore.js.map +1 -1
  11. package/dist/coValueCore/utils.d.ts.map +1 -1
  12. package/dist/coValueCore/utils.js.map +1 -1
  13. package/dist/coValueCore/verifiedState.d.ts +8 -2
  14. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  15. package/dist/coValueCore/verifiedState.js +7 -4
  16. package/dist/coValueCore/verifiedState.js.map +1 -1
  17. package/dist/coValues/account.d.ts +6 -2
  18. package/dist/coValues/account.d.ts.map +1 -1
  19. package/dist/coValues/account.js +12 -0
  20. package/dist/coValues/account.js.map +1 -1
  21. package/dist/crypto/PureJSCrypto.d.ts +4 -3
  22. package/dist/crypto/PureJSCrypto.d.ts.map +1 -1
  23. package/dist/crypto/PureJSCrypto.js +34 -2
  24. package/dist/crypto/PureJSCrypto.js.map +1 -1
  25. package/dist/crypto/WasmCrypto.d.ts +4 -3
  26. package/dist/crypto/WasmCrypto.d.ts.map +1 -1
  27. package/dist/crypto/WasmCrypto.js +10 -4
  28. package/dist/crypto/WasmCrypto.js.map +1 -1
  29. package/dist/crypto/crypto.d.ts +4 -3
  30. package/dist/crypto/crypto.d.ts.map +1 -1
  31. package/dist/sync.d.ts +14 -5
  32. package/dist/sync.d.ts.map +1 -1
  33. package/dist/sync.js +44 -13
  34. package/dist/sync.js.map +1 -1
  35. package/dist/tests/PureJSCrypto.test.js +43 -0
  36. package/dist/tests/PureJSCrypto.test.js.map +1 -1
  37. package/dist/tests/WasmCrypto.test.js +55 -0
  38. package/dist/tests/WasmCrypto.test.js.map +1 -1
  39. package/dist/tests/account.test.js +40 -0
  40. package/dist/tests/account.test.js.map +1 -1
  41. package/dist/tests/coList.test.js +13 -0
  42. package/dist/tests/coList.test.js.map +1 -1
  43. package/dist/tests/coMap.test.js +14 -0
  44. package/dist/tests/coMap.test.js.map +1 -1
  45. package/dist/tests/coPlainText.test.js +13 -0
  46. package/dist/tests/coPlainText.test.js.map +1 -1
  47. package/dist/tests/coStream.test.js +25 -0
  48. package/dist/tests/coStream.test.js.map +1 -1
  49. package/dist/tests/coValueCore.test.js +28 -2
  50. package/dist/tests/coValueCore.test.js.map +1 -1
  51. package/dist/tests/coreWasm.test.js +1 -1
  52. package/dist/tests/coreWasm.test.js.map +1 -1
  53. package/dist/tests/sync.sharding.test.js +104 -1
  54. package/dist/tests/sync.sharding.test.js.map +1 -1
  55. package/dist/tests/sync.storage.test.js +31 -1
  56. package/dist/tests/sync.storage.test.js.map +1 -1
  57. package/dist/tests/sync.storageAsync.test.js +1 -1
  58. package/dist/tests/sync.storageAsync.test.js.map +1 -1
  59. package/dist/tests/sync.test.js +2 -2
  60. package/dist/tests/sync.test.js.map +1 -1
  61. package/dist/tests/sync.upload.test.js +26 -0
  62. package/dist/tests/sync.upload.test.js.map +1 -1
  63. package/dist/tests/testUtils.d.ts.map +1 -1
  64. package/dist/tests/testUtils.js +3 -1
  65. package/dist/tests/testUtils.js.map +1 -1
  66. package/package.json +2 -2
  67. package/src/coValueCore/SessionMap.ts +24 -1
  68. package/src/coValueCore/coValueCore.ts +46 -41
  69. package/src/coValueCore/utils.ts +0 -1
  70. package/src/coValueCore/verifiedState.ts +14 -3
  71. package/src/coValues/account.ts +27 -3
  72. package/src/crypto/PureJSCrypto.ts +49 -1
  73. package/src/crypto/WasmCrypto.ts +15 -1
  74. package/src/crypto/crypto.ts +7 -1
  75. package/src/sync.ts +53 -19
  76. package/src/tests/PureJSCrypto.test.ts +66 -0
  77. package/src/tests/WasmCrypto.test.ts +88 -0
  78. package/src/tests/account.test.ts +56 -0
  79. package/src/tests/coList.test.ts +19 -0
  80. package/src/tests/coMap.test.ts +21 -0
  81. package/src/tests/coPlainText.test.ts +18 -0
  82. package/src/tests/coStream.test.ts +36 -0
  83. package/src/tests/coValueCore.test.ts +49 -0
  84. package/src/tests/coreWasm.test.ts +1 -0
  85. package/src/tests/sync.sharding.test.ts +156 -6
  86. package/src/tests/sync.storage.test.ts +43 -1
  87. package/src/tests/sync.storageAsync.test.ts +1 -1
  88. package/src/tests/sync.test.ts +6 -2
  89. package/src/tests/sync.upload.test.ts +35 -0
  90. package/src/tests/testUtils.ts +3 -1
@@ -217,6 +217,27 @@ test("Can set items in bulk with assign", () => {
217
217
  });
218
218
  });
219
219
 
220
+ test("Should ignore unknown meta transactions", () => {
221
+ const node = nodeWithRandomAgentAndSessionID();
222
+
223
+ const coValue = node.createCoValue({
224
+ type: "comap",
225
+ ruleset: { type: "unsafeAllowAll" },
226
+ meta: null,
227
+ ...Crypto.createdNowUnique(),
228
+ });
229
+
230
+ coValue.makeTransaction([], "trusting", { unknownMeta: 1 });
231
+
232
+ const content = expectMap(coValue.getCurrentContent());
233
+
234
+ expect(content.type).toEqual("comap");
235
+
236
+ content.set("key1", "set1", "trusting");
237
+
238
+ expect(content.get("key1")).toEqual("set1");
239
+ });
240
+
220
241
  test("totalValidTransactions should return the number of valid transactions processed", async () => {
221
242
  const client = setupTestNode({
222
243
  connected: true,
@@ -298,6 +298,24 @@ test("Splits into and from grapheme string arrays", () => {
298
298
  expect(text).toEqual("👋 안녕!");
299
299
  });
300
300
 
301
+ test("Should ignore unknown meta transactions", () => {
302
+ const node = nodeWithRandomAgentAndSessionID();
303
+
304
+ const coValue = node.createCoValue({
305
+ type: "coplaintext",
306
+ ruleset: { type: "unsafeAllowAll" },
307
+ meta: null,
308
+ ...Crypto.createdNowUnique(),
309
+ });
310
+
311
+ coValue.makeTransaction([], "trusting", { unknownMeta: 1 });
312
+
313
+ const content = expectPlainText(coValue.getCurrentContent());
314
+
315
+ content.insertAfter(0, "hello", "trusting");
316
+ expect(content.toString()).toEqual("hello");
317
+ });
318
+
301
319
  test("chunks transactions when when the chars are longer than MAX_RECOMMENDED_TX_SIZE", async () => {
302
320
  setMaxRecommendedTxSize(5);
303
321
 
@@ -127,6 +127,42 @@ test("Can push into RawBinaryCoStream", () => {
127
127
  });
128
128
  });
129
129
 
130
+ test("Should ignore meta transactions on RawBinaryCoStream", () => {
131
+ const node = nodeWithRandomAgentAndSessionID();
132
+
133
+ const coValue = node.createCoValue({
134
+ type: "costream",
135
+ ruleset: { type: "unsafeAllowAll" },
136
+ meta: { type: "binary" },
137
+ ...Crypto.createdNowUnique(),
138
+ });
139
+
140
+ coValue.makeTransaction([], "trusting", { unknownMeta: 1 });
141
+
142
+ const content = coValue.getCurrentContent();
143
+
144
+ if (
145
+ content.type !== "costream" ||
146
+ content.headerMeta?.type !== "binary" ||
147
+ !(content instanceof RawBinaryCoStream)
148
+ ) {
149
+ throw new Error("Expected binary stream");
150
+ }
151
+
152
+ content.startBinaryStream(
153
+ { mimeType: "text/plain", fileName: "test.txt" },
154
+ "trusting",
155
+ );
156
+ content.pushBinaryStreamChunk(new Uint8Array([1, 2, 3]), "trusting");
157
+ content.endBinaryStream("trusting");
158
+ expect(content.getBinaryChunks()).toEqual({
159
+ mimeType: "text/plain",
160
+ fileName: "test.txt",
161
+ chunks: [new Uint8Array([1, 2, 3])],
162
+ finished: true,
163
+ });
164
+ });
165
+
130
166
  test("When adding large transactions (small fraction of MAX_RECOMMENDED_TX_SIZE), we store an inbetween signature every time we reach MAX_RECOMMENDED_TX_SIZE and split up newContentSince accordingly", () => {
131
167
  const node = nodeWithRandomAgentAndSessionID();
132
168
 
@@ -20,9 +20,11 @@ import {
20
20
  loadCoValueOrFail,
21
21
  nodeWithRandomAgentAndSessionID,
22
22
  randomAgentAndSessionID,
23
+ setupTestNode,
23
24
  tearDownTestMetricReader,
24
25
  } from "./testUtils.js";
25
26
  import { CO_VALUE_PRIORITY } from "../priority.js";
27
+ import { determineValidTransactions } from "../permissions.js";
26
28
 
27
29
  const Crypto = await WasmCrypto.create();
28
30
 
@@ -32,6 +34,7 @@ const agentSecret =
32
34
 
33
35
  beforeEach(() => {
34
36
  metricReader = createTestMetricReader();
37
+ setupTestNode({ isSyncServer: true });
35
38
  });
36
39
 
37
40
  afterEach(() => {
@@ -53,6 +56,7 @@ test("transactions with wrong signature are rejected", () => {
53
56
  node.currentSessionID,
54
57
  node.getCurrentAgent(),
55
58
  [{ hello: "world" }],
59
+ undefined,
56
60
  );
57
61
 
58
62
  transaction.madeAt = Date.now() + 1000;
@@ -264,6 +268,51 @@ test("listeners are notified even if the previous listener threw an error", asyn
264
268
  errorLog.mockRestore();
265
269
  });
266
270
 
271
+ test("creates a transaction with trusting meta information", async () => {
272
+ const client = setupTestNode();
273
+
274
+ const group = client.node.createGroup();
275
+ const map = group.createMap();
276
+ map.core.makeTransaction([], "trusting", {
277
+ meta: true,
278
+ });
279
+
280
+ const validTransactions = determineValidTransactions(map.core);
281
+
282
+ expect(validTransactions[0]?.tx.meta).toBe(`{"meta":true}`);
283
+ });
284
+
285
+ test("creates a transaction with private meta information", async () => {
286
+ const client = setupTestNode({ connected: true });
287
+
288
+ const group = client.node.createGroup();
289
+ const map = group.createMap();
290
+ map.core.makeTransaction([], "private", {
291
+ meta: true,
292
+ });
293
+
294
+ const localTransactionMeta = map.core.verified.decryptTransactionMeta(
295
+ client.node.currentSessionID,
296
+ 0,
297
+ map.core.getCurrentReadKey().secret!,
298
+ );
299
+
300
+ expect(localTransactionMeta).toEqual({ meta: true });
301
+
302
+ const newSession = client.spawnNewSession();
303
+
304
+ const mapOnNewSession = await loadCoValueOrFail(newSession.node, map.id);
305
+
306
+ const syncedTransactionMeta =
307
+ mapOnNewSession.core.verified.decryptTransactionMeta(
308
+ client.node.currentSessionID,
309
+ 0,
310
+ mapOnNewSession.core.getCurrentReadKey().secret!,
311
+ );
312
+
313
+ expect(syncedTransactionMeta).toEqual({ meta: true });
314
+ });
315
+
267
316
  test("getValidTransactions should skip private transactions with invalid JSON", () => {
268
317
  const [agent, sessionID] = agentAndSessionIDFromSecret(agentSecret);
269
318
  const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
@@ -85,6 +85,7 @@ describe("SessionLog WASM", () => {
85
85
  key.id,
86
86
  key.secret,
87
87
  0,
88
+ undefined,
88
89
  );
89
90
 
90
91
  expect(signature).toMatch(/^signature_z[a-zA-Z0-9]+$/);
@@ -1,16 +1,15 @@
1
1
  import { beforeEach, describe, expect, test } from "vitest";
2
- import { setCoValueLoadingRetryDelay } from "../config";
2
+ import { Peer } from "../exports";
3
+ import { hwrServerPeerSelector, ServerPeerSelector } from "../sync";
3
4
  import {
4
5
  SyncMessagesLog,
5
6
  TEST_NODE_CONFIG,
6
- blockMessageTypeOnOutgoingPeer,
7
+ connectedPeersWithMessagesTracking,
7
8
  getSyncServerConnectedPeer,
8
- loadCoValueOrFail,
9
9
  setupTestAccount,
10
10
  setupTestNode,
11
11
  } from "./testUtils";
12
- import { Peer } from "../exports";
13
- import { ServerPeerSelector } from "../sync";
12
+ import { PeerState } from "../PeerState";
14
13
 
15
14
  beforeEach(async () => {
16
15
  // We want to simulate a real world communication that happens asynchronously
@@ -47,7 +46,6 @@ describe("sharding", () => {
47
46
  const firstAlphabetical: ServerPeerSelector = (id, serverPeers) => {
48
47
  return serverPeers.sort((a, b) => a.id.localeCompare(b.id)).slice(0, 1);
49
48
  };
50
-
51
49
  const { node: client } = setupTestNode({
52
50
  connected: false,
53
51
  });
@@ -73,4 +71,156 @@ describe("sharding", () => {
73
71
  allPeers.sort((a, b) => a.id.localeCompare(b.id))[0]!.id,
74
72
  );
75
73
  });
74
+
75
+ test("getPeers respects the serverPeerSelector", async () => {
76
+ const firstPeer: ServerPeerSelector = (id, serverPeers) => {
77
+ return serverPeers.slice(0, 1);
78
+ };
79
+ const { node: edge } = setupTestNode({
80
+ connected: false,
81
+ });
82
+ edge.syncManager.serverPeerSelector = firstPeer;
83
+
84
+ // Connect 2 clients to edge
85
+ for (let i = 0; i < 2; i++) {
86
+ const client = await setupTestAccount({});
87
+ const { peer1, peer2 } = connectedPeersWithMessagesTracking({
88
+ peer1: {
89
+ id: client.node.getCurrentAgent().id,
90
+ role: "client",
91
+ },
92
+ peer2: {
93
+ id: edge.getCurrentAgent().id,
94
+ role: "server",
95
+ },
96
+ });
97
+
98
+ edge.syncManager.addPeer(peer1);
99
+ }
100
+
101
+ // Connect edge to 3 core nodes
102
+ for (let i = 0; i < 3; i++) {
103
+ const syncServer = await setupTestAccount({ isSyncServer: true });
104
+
105
+ const { peer } = getSyncServerConnectedPeer({
106
+ peerId: edge.getCurrentAgent().id,
107
+ syncServer: syncServer.node,
108
+ });
109
+
110
+ edge.syncManager.addPeer(peer);
111
+ }
112
+
113
+ expect(edge.syncManager.getPeers("co_z12345").length).toBe(
114
+ 2 + 1, // 2 clients + 1 selected core
115
+ );
116
+ });
117
+
118
+ describe("hwrServerPeerSelector", () => {
119
+ const createMockPeer = (
120
+ id: string,
121
+ role: "server" | "client" = "server",
122
+ ): Peer => ({
123
+ id,
124
+ role,
125
+ incoming: {
126
+ close: () => {},
127
+ onMessage: () => {},
128
+ onClose: () => {},
129
+ },
130
+ outgoing: {
131
+ push: () => {},
132
+ close: () => {},
133
+ onClose: () => {},
134
+ },
135
+ });
136
+
137
+ test("selects top n peers by hash weight", () => {
138
+ const allPeers = Array.from(
139
+ { length: 5 },
140
+ (_, i) => new PeerState(createMockPeer(`peer_${i + 1}`), undefined),
141
+ );
142
+
143
+ // Create selector that picks top 2 peers
144
+ const selector = hwrServerPeerSelector(2);
145
+ const selectedPeers = selector("co_ztest123", allPeers);
146
+
147
+ // Should return exactly 2 peers (n=2)
148
+ expect(selectedPeers.length).toBe(2);
149
+
150
+ // All returned peers should be from the original set
151
+ expect(allPeers).toContain(selectedPeers[0]);
152
+ expect(allPeers).toContain(selectedPeers[1]);
153
+
154
+ // The two peers should be different
155
+ expect(selectedPeers[0]).not.toBe(selectedPeers[1]);
156
+ });
157
+
158
+ test("returns all peers when n >= total peers", () => {
159
+ const allPeers = Array.from(
160
+ { length: 3 },
161
+ (_, i) => new PeerState(createMockPeer(`peer_${i + 1}`), undefined),
162
+ );
163
+
164
+ // Create a selector that picks top 10 peers (more than we'll have)
165
+ const selector = hwrServerPeerSelector(10);
166
+ const selectedPeers = selector("co_ztest123", allPeers);
167
+
168
+ // Should return all 3 peers since n=10 > 3
169
+ expect(selectedPeers.length).toBe(3);
170
+ expect(new Set(selectedPeers.map((p) => p.id))).toEqual(
171
+ new Set(allPeers.map((p) => p.id)),
172
+ );
173
+ });
174
+
175
+ test("returns consistent results for same CoValue ID", () => {
176
+ const allPeers = Array.from(
177
+ { length: 5 },
178
+ (_, i) => new PeerState(createMockPeer(`peer_${i + 1}`), undefined),
179
+ );
180
+
181
+ const selector = hwrServerPeerSelector(2);
182
+
183
+ // Call the selector multiple times with the same CoValue ID
184
+ const result1 = selector("co_ztest123", allPeers);
185
+ const result2 = selector("co_ztest123", allPeers);
186
+ const result3 = selector("co_ztest123", allPeers);
187
+
188
+ // Results should be consistent (same peers selected each time for the same CoValue ID)
189
+ expect(new Set(result1.map((p) => p.id))).toEqual(
190
+ new Set(result2.map((p) => p.id)),
191
+ );
192
+ expect(new Set(result2.map((p) => p.id))).toEqual(
193
+ new Set(result3.map((p) => p.id)),
194
+ );
195
+ });
196
+
197
+ test("returns different results for different CoValue IDs", () => {
198
+ const allPeers = Array.from(
199
+ { length: 6 },
200
+ (_, i) => new PeerState(createMockPeer(`peer_${i + 1}`), undefined),
201
+ );
202
+
203
+ const selector = hwrServerPeerSelector(5);
204
+
205
+ // Call the selector with different CoValue IDs
206
+ const result1 = selector("co_ztest123", allPeers);
207
+ const result2 = selector("co_ztest456", allPeers);
208
+ const result3 = selector("co_ztest789", allPeers);
209
+
210
+ expect(result1.length).toBe(5);
211
+ expect(result2.length).toBe(5);
212
+ expect(result3.length).toBe(5);
213
+
214
+ // Results should all be in different orders
215
+ expect(result1).not.toEqual(result2);
216
+ expect(result1).not.toEqual(result3);
217
+ expect(result2).not.toEqual(result3);
218
+ });
219
+
220
+ test("with n=0 throws an error", () => {
221
+ expect(() => hwrServerPeerSelector(0)).toThrow(
222
+ "n must be greater than 0",
223
+ );
224
+ });
225
+ });
76
226
  });
@@ -20,6 +20,7 @@ import {
20
20
  waitFor,
21
21
  } from "./testUtils";
22
22
  import { stableStringify } from "../jsonStringify";
23
+ import { determineValidTransactions } from "../permissions";
23
24
 
24
25
  // We want to simulate a real world communication that happens asynchronously
25
26
  TEST_NODE_CONFIG.withAsyncPeers = true;
@@ -151,6 +152,47 @@ describe("client with storage syncs with server", () => {
151
152
  `);
152
153
  });
153
154
 
155
+ test("persists meta information", async () => {
156
+ const client = setupTestNode();
157
+
158
+ const { storage } = client.addStorage();
159
+
160
+ const group = client.node.createGroup();
161
+ const map = group.createMap();
162
+ map.core.makeTransaction([], "trusting", {
163
+ meta: true,
164
+ });
165
+
166
+ await map.core.waitForSync();
167
+
168
+ client.restart();
169
+
170
+ client.addStorage({
171
+ storage,
172
+ });
173
+
174
+ const loadedValue = await loadCoValueOrFail(client.node, map.id);
175
+
176
+ const validTransactions = determineValidTransactions(loadedValue.core);
177
+
178
+ expect(validTransactions[0]?.tx.meta).toBe(`{"meta":true}`);
179
+
180
+ expect(
181
+ SyncMessagesLog.getMessages({
182
+ Group: group.core,
183
+ Map: map.core,
184
+ }),
185
+ ).toMatchInlineSnapshot(`
186
+ [
187
+ "client -> storage | CONTENT Group header: true new: After: 0 New: 3",
188
+ "client -> storage | CONTENT Map header: true new: After: 0 New: 1",
189
+ "client -> storage | LOAD Map sessions: empty",
190
+ "storage -> client | CONTENT Group header: true new: After: 0 New: 3",
191
+ "storage -> client | CONTENT Map header: true new: After: 0 New: 1",
192
+ ]
193
+ `);
194
+ });
195
+
154
196
  test("updating a coValue while offline", async () => {
155
197
  const client = setupTestNode();
156
198
 
@@ -164,7 +206,7 @@ describe("client with storage syncs with server", () => {
164
206
  const mapOnClient = await loadCoValueOrFail(client.node, map.id);
165
207
  expect(mapOnClient.get("hello")).toEqual("world");
166
208
 
167
- client.node.syncManager.getPeers()[0]?.gracefulShutdown();
209
+ client.node.syncManager.getPeers(map.id)[0]?.gracefulShutdown();
168
210
 
169
211
  SyncMessagesLog.clear();
170
212
  map.set("hello", "updated", "trusting");
@@ -156,7 +156,7 @@ describe("client with storage syncs with server", () => {
156
156
  const mapOnClient = await loadCoValueOrFail(client.node, map.id);
157
157
  expect(mapOnClient.get("hello")).toEqual("world");
158
158
 
159
- client.node.syncManager.getPeers()[0]?.gracefulShutdown();
159
+ client.node.syncManager.getPeers(map.id)[0]?.gracefulShutdown();
160
160
 
161
161
  SyncMessagesLog.clear();
162
162
  map.set("hello", "updated", "trusting");
@@ -599,8 +599,12 @@ describe("SyncManager - knownStates vs optimisticKnownStates", () => {
599
599
  // Wait for the full sync to complete
600
600
  await mapOnClient.core.waitForSync();
601
601
 
602
- const peerStateClient = client.syncManager.getPeers()[0]!;
603
- const peerStateJazzCloud = jazzCloud.node.syncManager.getPeers()[0]!;
602
+ const peerStateClient = client.syncManager.getPeers(
603
+ mapOnClient.core.id,
604
+ )[0]!;
605
+ const peerStateJazzCloud = jazzCloud.node.syncManager.getPeers(
606
+ mapOnClient.core.id,
607
+ )[0]!;
604
608
 
605
609
  // The optimisticKnownStates should be the same as the knownStates after the full sync is complete
606
610
  expect(
@@ -9,6 +9,7 @@ import {
9
9
  setupTestNode,
10
10
  waitFor,
11
11
  } from "./testUtils";
12
+ import { determineValidTransactions } from "../permissions";
12
13
 
13
14
  // We want to simulate a real world communication that happens asynchronously
14
15
  TEST_NODE_CONFIG.withAsyncPeers = true;
@@ -51,6 +52,40 @@ describe("client to server upload", () => {
51
52
  `);
52
53
  });
53
54
 
55
+ test("syncs meta information", async () => {
56
+ const client = setupTestNode({
57
+ connected: true,
58
+ });
59
+
60
+ const group = client.node.createGroup();
61
+ const map = group.createMap();
62
+ map.core.makeTransaction([], "trusting", {
63
+ meta: true,
64
+ });
65
+
66
+ await map.core.waitForSync();
67
+
68
+ const loadedValue = await loadCoValueOrFail(jazzCloud.node, map.id);
69
+
70
+ const validTransactions = determineValidTransactions(loadedValue.core);
71
+
72
+ expect(validTransactions[0]?.tx.meta).toBe(`{"meta":true}`);
73
+
74
+ expect(
75
+ SyncMessagesLog.getMessages({
76
+ Group: group.core,
77
+ Map: map.core,
78
+ }),
79
+ ).toMatchInlineSnapshot(`
80
+ [
81
+ "client -> server | CONTENT Group header: true new: After: 0 New: 3",
82
+ "client -> server | CONTENT Map header: true new: After: 0 New: 1",
83
+ "server -> client | KNOWN Group sessions: header/3",
84
+ "server -> client | KNOWN Map sessions: header/1",
85
+ ]
86
+ `);
87
+ });
88
+
54
89
  test("coValue with parent groups uploading", async () => {
55
90
  const client = setupTestNode({
56
91
  connected: true,
@@ -669,9 +669,11 @@ export async function setupTestAccount(
669
669
  addStorage,
670
670
  addAsyncStorage,
671
671
  disconnect: () => {
672
- ctx.node.syncManager.getPeers().forEach((peer) => {
672
+ const allPeers = ctx.node.syncManager.getPeers(ctx.accountID);
673
+ allPeers.forEach((peer) => {
673
674
  peer.gracefulShutdown();
674
675
  });
676
+ ctx.node.syncManager.peers = {};
675
677
  },
676
678
  };
677
679
  }