cojson 0.17.9 → 0.17.11

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 (86) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dist/coValueCore/SessionMap.d.ts +45 -0
  4. package/dist/coValueCore/SessionMap.d.ts.map +1 -0
  5. package/dist/coValueCore/SessionMap.js +118 -0
  6. package/dist/coValueCore/SessionMap.js.map +1 -0
  7. package/dist/coValueCore/coValueCore.d.ts +10 -4
  8. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  9. package/dist/coValueCore/coValueCore.js +55 -68
  10. package/dist/coValueCore/coValueCore.js.map +1 -1
  11. package/dist/coValueCore/verifiedState.d.ts +15 -19
  12. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  13. package/dist/coValueCore/verifiedState.js +24 -87
  14. package/dist/coValueCore/verifiedState.js.map +1 -1
  15. package/dist/coValues/account.d.ts +4 -0
  16. package/dist/coValues/account.d.ts.map +1 -1
  17. package/dist/coValues/account.js +24 -4
  18. package/dist/coValues/account.js.map +1 -1
  19. package/dist/coValues/group.d.ts.map +1 -1
  20. package/dist/coValues/group.js +6 -2
  21. package/dist/coValues/group.js.map +1 -1
  22. package/dist/crypto/PureJSCrypto.d.ts +31 -3
  23. package/dist/crypto/PureJSCrypto.d.ts.map +1 -1
  24. package/dist/crypto/PureJSCrypto.js +115 -0
  25. package/dist/crypto/PureJSCrypto.js.map +1 -1
  26. package/dist/crypto/WasmCrypto.d.ts +23 -4
  27. package/dist/crypto/WasmCrypto.d.ts.map +1 -1
  28. package/dist/crypto/WasmCrypto.js +44 -2
  29. package/dist/crypto/WasmCrypto.js.map +1 -1
  30. package/dist/crypto/crypto.d.ts +17 -1
  31. package/dist/crypto/crypto.d.ts.map +1 -1
  32. package/dist/crypto/crypto.js.map +1 -1
  33. package/dist/localNode.d.ts +1 -0
  34. package/dist/localNode.d.ts.map +1 -1
  35. package/dist/localNode.js +10 -5
  36. package/dist/localNode.js.map +1 -1
  37. package/dist/permissions.d.ts +17 -1
  38. package/dist/permissions.d.ts.map +1 -1
  39. package/dist/permissions.js.map +1 -1
  40. package/dist/sync.d.ts.map +1 -1
  41. package/dist/sync.js +55 -49
  42. package/dist/sync.js.map +1 -1
  43. package/dist/tests/PureJSCrypto.test.d.ts +2 -0
  44. package/dist/tests/PureJSCrypto.test.d.ts.map +1 -0
  45. package/dist/tests/PureJSCrypto.test.js +102 -0
  46. package/dist/tests/PureJSCrypto.test.js.map +1 -0
  47. package/dist/tests/WasmCrypto.test.d.ts +2 -0
  48. package/dist/tests/WasmCrypto.test.d.ts.map +1 -0
  49. package/dist/tests/WasmCrypto.test.js +88 -0
  50. package/dist/tests/WasmCrypto.test.js.map +1 -0
  51. package/dist/tests/coValueCore.test.js +62 -187
  52. package/dist/tests/coValueCore.test.js.map +1 -1
  53. package/dist/tests/coreWasm.test.d.ts +2 -0
  54. package/dist/tests/coreWasm.test.d.ts.map +1 -0
  55. package/dist/tests/coreWasm.test.js +80 -0
  56. package/dist/tests/coreWasm.test.js.map +1 -0
  57. package/dist/tests/group.addMember.test.js +6 -11
  58. package/dist/tests/group.addMember.test.js.map +1 -1
  59. package/dist/tests/sync.load.test.js +40 -1
  60. package/dist/tests/sync.load.test.js.map +1 -1
  61. package/dist/tests/sync.test.js +1 -1
  62. package/dist/tests/sync.test.js.map +1 -1
  63. package/dist/tests/testUtils.d.ts +3 -0
  64. package/dist/tests/testUtils.d.ts.map +1 -1
  65. package/dist/tests/testUtils.js +4 -1
  66. package/dist/tests/testUtils.js.map +1 -1
  67. package/package.json +3 -3
  68. package/src/coValueCore/SessionMap.ts +229 -0
  69. package/src/coValueCore/coValueCore.ts +106 -121
  70. package/src/coValueCore/verifiedState.ts +61 -132
  71. package/src/coValues/account.ts +28 -4
  72. package/src/coValues/group.ts +10 -2
  73. package/src/crypto/PureJSCrypto.ts +206 -2
  74. package/src/crypto/WasmCrypto.ts +95 -4
  75. package/src/crypto/crypto.ts +38 -1
  76. package/src/localNode.ts +18 -10
  77. package/src/permissions.ts +17 -1
  78. package/src/sync.ts +63 -59
  79. package/src/tests/PureJSCrypto.test.ts +153 -0
  80. package/src/tests/WasmCrypto.test.ts +128 -0
  81. package/src/tests/coValueCore.test.ts +81 -293
  82. package/src/tests/coreWasm.test.ts +142 -0
  83. package/src/tests/group.addMember.test.ts +69 -63
  84. package/src/tests/sync.load.test.ts +52 -0
  85. package/src/tests/sync.test.ts +0 -2
  86. package/src/tests/testUtils.ts +9 -1
@@ -0,0 +1,128 @@
1
+ import { assert, beforeEach, describe, expect, it } from "vitest";
2
+ import {
3
+ loadCoValueOrFail,
4
+ setCurrentTestCryptoProvider,
5
+ setupTestNode,
6
+ setupTestAccount,
7
+ } from "./testUtils";
8
+ import { stableStringify } from "../jsonStringify";
9
+ import { WasmCrypto } from "../crypto/WasmCrypto";
10
+
11
+ const wasmCrypto = await WasmCrypto.create();
12
+ setCurrentTestCryptoProvider(wasmCrypto);
13
+
14
+ let syncServer: ReturnType<typeof setupTestNode>;
15
+
16
+ beforeEach(() => {
17
+ syncServer = setupTestNode({ isSyncServer: true });
18
+ });
19
+
20
+ // A suite of tests focused on high-level tests that verify:
21
+ // - Keys creation and unsealing
22
+ // - Signature creation and verification
23
+ // - Encryption and decryption of values
24
+ describe("WasmCrypto", () => {
25
+ it("successfully creates a private CoValue and reads it in another session", async () => {
26
+ const client = setupTestNode({
27
+ connected: true,
28
+ });
29
+
30
+ const group = client.node.createGroup();
31
+ const map = group.createMap();
32
+ map.set("count", 0, "private");
33
+ map.set("count", 1, "private");
34
+ map.set("count", 2, "private");
35
+
36
+ const client2 = client.spawnNewSession();
37
+
38
+ const mapInTheOtherSession = await loadCoValueOrFail(client2.node, map.id);
39
+
40
+ expect(mapInTheOtherSession.get("count")).toEqual(2);
41
+ });
42
+
43
+ it("successfully updates a private CoValue and reads it in another session", async () => {
44
+ const client = setupTestNode({
45
+ connected: true,
46
+ });
47
+
48
+ const group = client.node.createGroup();
49
+ const map = group.createMap();
50
+ map.set("count", 0, "private");
51
+ map.set("count", 1, "private");
52
+ map.set("count", 2, "private");
53
+
54
+ const client2 = client.spawnNewSession();
55
+
56
+ const mapInTheOtherSession = await loadCoValueOrFail(client2.node, map.id);
57
+ mapInTheOtherSession.set("count", 3, "private");
58
+
59
+ await mapInTheOtherSession.core.waitForSync();
60
+
61
+ expect(mapInTheOtherSession.get("count")).toEqual(3);
62
+ });
63
+
64
+ it("can invite another account to a group and share a private CoValue", async () => {
65
+ const client = setupTestNode({
66
+ connected: true,
67
+ });
68
+ const account = await setupTestAccount({
69
+ connected: true,
70
+ });
71
+
72
+ const group = client.node.createGroup();
73
+ const invite = group.createInvite("admin");
74
+
75
+ await account.node.acceptInvite(group.id, invite);
76
+
77
+ const map = group.createMap();
78
+ map.set("secret", "private-data", "private");
79
+
80
+ // The other account should be able to read the private value
81
+ const mapInOtherSession = await loadCoValueOrFail(account.node, map.id);
82
+ expect(mapInOtherSession.get("secret")).toEqual("private-data");
83
+
84
+ mapInOtherSession.set("secret", "modified", "private");
85
+
86
+ await mapInOtherSession.core.waitForSync();
87
+
88
+ expect(map.get("secret")).toEqual("modified");
89
+ });
90
+
91
+ it("rejects sessions with invalid signatures", async () => {
92
+ const client = setupTestNode({
93
+ connected: true,
94
+ });
95
+
96
+ const group = client.node.createGroup();
97
+ const map = group.createMap();
98
+ map.set("count", 0, "trusting");
99
+
100
+ // Create a new session with the same agent
101
+ const client2 = client.spawnNewSession();
102
+
103
+ // This should work normally
104
+ const mapInOtherSession = await loadCoValueOrFail(client2.node, map.id);
105
+ expect(mapInOtherSession.get("count")).toEqual(0);
106
+
107
+ mapInOtherSession.core.tryAddTransactions(
108
+ client2.node.currentSessionID,
109
+ [
110
+ {
111
+ privacy: "trusting",
112
+ changes: stableStringify([{ op: "set", key: "count", value: 1 }]),
113
+ madeAt: Date.now(),
114
+ },
115
+ ],
116
+ "signature_z12345678",
117
+ true,
118
+ );
119
+
120
+ const content =
121
+ mapInOtherSession.core.verified.newContentSince(undefined)?.[0];
122
+ assert(content);
123
+
124
+ client.node.syncManager.handleNewContent(content, "storage");
125
+
126
+ expect(map.get("count")).toEqual(0);
127
+ });
128
+ });
@@ -1,4 +1,3 @@
1
- import { encrypt } from "jazz-crypto-rs";
2
1
  import {
3
2
  assert,
4
3
  afterEach,
@@ -8,15 +7,13 @@ import {
8
7
  test,
9
8
  vi,
10
9
  } from "vitest";
11
- import { bytesToBase64url } from "../base64url.js";
12
10
  import { CoValueCore } from "../coValueCore/coValueCore.js";
13
11
  import { Transaction } from "../coValueCore/verifiedState.js";
14
- import { MapOpPayload } from "../coValues/coMap.js";
15
12
  import { WasmCrypto } from "../crypto/WasmCrypto.js";
16
13
  import { stableStringify } from "../jsonStringify.js";
17
14
  import { LocalNode } from "../localNode.js";
18
- import { Role } from "../permissions.js";
19
15
  import {
16
+ agentAndSessionIDFromSecret,
20
17
  createTestMetricReader,
21
18
  createTestNode,
22
19
  createTwoConnectedNodes,
@@ -25,10 +22,13 @@ import {
25
22
  randomAgentAndSessionID,
26
23
  tearDownTestMetricReader,
27
24
  } from "./testUtils.js";
25
+ import { CO_VALUE_PRIORITY } from "../priority.js";
28
26
 
29
27
  const Crypto = await WasmCrypto.create();
30
28
 
31
29
  let metricReader: ReturnType<typeof createTestMetricReader>;
30
+ const agentSecret =
31
+ "sealerSecret_zE3Nr7YFr1KkVbJSx4JDCzYn4ApYdm8kJ5ghNBxREHQya/signerSecret_z9fEu4eNG1eXHMak3YSzY7uLdoG8HESSJ8YW4xWdNNDSP";
32
32
 
33
33
  beforeEach(() => {
34
34
  metricReader = createTestMetricReader();
@@ -38,47 +38,7 @@ afterEach(() => {
38
38
  tearDownTestMetricReader();
39
39
  });
40
40
 
41
- test("Can create coValue with new agent credentials and add transaction to it", () => {
42
- const [agent, sessionID] = randomAgentAndSessionID();
43
- const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
44
-
45
- const coValue = node.createCoValue({
46
- type: "costream",
47
- ruleset: { type: "unsafeAllowAll" },
48
- meta: null,
49
- ...Crypto.createdNowUnique(),
50
- });
51
-
52
- const transaction: Transaction = {
53
- privacy: "trusting",
54
- madeAt: Date.now(),
55
- changes: stableStringify([
56
- {
57
- hello: "world",
58
- },
59
- ]),
60
- };
61
-
62
- const { expectedNewHash } = coValue.verified.expectedNewHashAfter(
63
- node.currentSessionID,
64
- [transaction],
65
- );
66
-
67
- expect(
68
- coValue
69
- .tryAddTransactions(
70
- node.currentSessionID,
71
- [transaction],
72
- expectedNewHash,
73
- Crypto.sign(agent.currentSignerSecret(), expectedNewHash),
74
- "immediate",
75
- )
76
- ._unsafeUnwrap(),
77
- ).toBe(true);
78
- });
79
-
80
41
  test("transactions with wrong signature are rejected", () => {
81
- const wrongAgent = Crypto.newRandomAgentSecret();
82
42
  const node = nodeWithRandomAgentAndSessionID();
83
43
 
84
44
  const coValue = node.createCoValue({
@@ -88,88 +48,51 @@ test("transactions with wrong signature are rejected", () => {
88
48
  ...Crypto.createdNowUnique(),
89
49
  });
90
50
 
91
- const transaction: Transaction = {
92
- privacy: "trusting",
93
- madeAt: Date.now(),
94
- changes: stableStringify([
95
- {
96
- hello: "world",
97
- },
98
- ]),
99
- };
100
-
101
- const { expectedNewHash } = coValue.verified.expectedNewHashAfter(
102
- node.currentSessionID,
103
- [transaction],
104
- );
105
-
106
- // eslint-disable-next-line neverthrow/must-use-result
107
- coValue
108
- .tryAddTransactions(
51
+ const { transaction, signature } =
52
+ coValue.verified.makeNewTrustingTransaction(
109
53
  node.currentSessionID,
110
- [transaction],
111
- expectedNewHash,
112
- Crypto.sign(Crypto.getAgentSignerSecret(wrongAgent), expectedNewHash),
113
- "immediate",
114
- )
115
- ._unsafeUnwrapErr({ withStackTrace: true });
116
- });
54
+ node.getCurrentAgent(),
55
+ [{ hello: "world" }],
56
+ );
117
57
 
118
- test("transactions with correctly signed, but wrong hash are rejected", () => {
119
- const [agent, sessionID] = randomAgentAndSessionID();
120
- const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
58
+ transaction.madeAt = Date.now() + 1000;
121
59
 
122
- const coValue = node.createCoValue({
123
- type: "costream",
124
- ruleset: { type: "unsafeAllowAll" },
125
- meta: null,
126
- ...Crypto.createdNowUnique(),
127
- });
60
+ // Delete the transaction from the coValue
61
+ node.internalDeleteCoValue(coValue.id);
62
+ node.syncManager.handleNewContent(
63
+ {
64
+ action: "content",
65
+ id: coValue.id,
66
+ header: coValue.verified.header,
67
+ priority: CO_VALUE_PRIORITY.LOW,
68
+ new: {},
69
+ },
70
+ "import",
71
+ );
128
72
 
129
- const transaction: Transaction = {
130
- privacy: "trusting",
131
- madeAt: Date.now(),
132
- changes: stableStringify([
133
- {
134
- hello: "world",
135
- },
136
- ]),
137
- };
73
+ const newEntry = node.getCoValue(coValue.id);
138
74
 
139
- const { expectedNewHash } = coValue.verified.expectedNewHashAfter(
75
+ // eslint-disable-next-line neverthrow/must-use-result
76
+ const result = newEntry.tryAddTransactions(
140
77
  node.currentSessionID,
141
- [
142
- {
143
- privacy: "trusting",
144
- madeAt: Date.now(),
145
- changes: stableStringify([
146
- {
147
- hello: "wrong",
148
- },
149
- ]),
150
- },
151
- ],
78
+ [transaction],
79
+ signature,
152
80
  );
153
81
 
154
- // eslint-disable-next-line neverthrow/must-use-result
155
- coValue
156
- .tryAddTransactions(
157
- node.currentSessionID,
158
- [transaction],
159
- expectedNewHash,
160
- Crypto.sign(agent.currentSignerSecret(), expectedNewHash),
161
- "immediate",
162
- )
163
- ._unsafeUnwrapErr({ withStackTrace: true });
82
+ expect(result.isErr()).toBe(true);
83
+ expect(newEntry.getValidSortedTransactions().length).toBe(0);
164
84
  });
165
85
 
166
86
  test("New transactions in a group correctly update owned values, including subscriptions", async () => {
167
87
  const [agent, sessionID] = randomAgentAndSessionID();
168
88
  const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
169
89
 
170
- const group = node.createGroup();
90
+ const timeBeforeEdit = Date.now() - 1000;
91
+ const dateNowMock = vi
92
+ .spyOn(Date, "now")
93
+ .mockImplementation(() => timeBeforeEdit);
171
94
 
172
- const timeBeforeEdit = Date.now();
95
+ const group = node.createGroup();
173
96
 
174
97
  await new Promise((resolve) => setTimeout(resolve, 10));
175
98
 
@@ -179,49 +102,31 @@ test("New transactions in a group correctly update owned values, including subsc
179
102
 
180
103
  const listener = vi.fn();
181
104
 
182
- map.subscribe(listener);
105
+ map.subscribe((map) => {
106
+ listener(map.get("hello"));
107
+ });
108
+
109
+ expect(listener).toHaveBeenLastCalledWith("world");
183
110
 
184
- expect(listener.mock.calls[0]?.[0].get("hello")).toBe("world");
111
+ expect(map.core.getValidSortedTransactions().length).toBe(1);
112
+ expect(group.get(agent.id)).toBe("admin");
185
113
 
186
- const resignationThatWeJustLearnedAbout = {
187
- privacy: "trusting",
188
- madeAt: timeBeforeEdit,
189
- changes: stableStringify([
114
+ group.core.makeTransaction(
115
+ [
190
116
  {
191
117
  op: "set",
192
118
  key: agent.id,
193
119
  value: "revoked",
194
- } satisfies MapOpPayload<typeof agent.id, Role>,
195
- ]),
196
- } satisfies Transaction;
197
-
198
- const { expectedNewHash } = group.core.verified.expectedNewHashAfter(
199
- sessionID,
200
- [resignationThatWeJustLearnedAbout],
201
- );
202
-
203
- const signature = Crypto.sign(
204
- node.getCurrentAgent().currentSignerSecret(),
205
- expectedNewHash,
120
+ },
121
+ ],
122
+ "trusting",
206
123
  );
207
124
 
208
- expect(map.core.getValidSortedTransactions().length).toBe(1);
209
-
210
- const manuallyAdddedTxSuccess = group.core
211
- .tryAddTransactions(
212
- node.currentSessionID,
213
- [resignationThatWeJustLearnedAbout],
214
- expectedNewHash,
215
- signature,
216
- "immediate",
217
- )
218
- ._unsafeUnwrap({ withStackTrace: true });
219
-
220
- expect(manuallyAdddedTxSuccess).toBe(true);
221
-
222
- expect(listener.mock.calls.length).toBe(2);
223
- expect(listener.mock.calls[1]?.[0].get("hello")).toBe(undefined);
125
+ expect(group.get(agent.id)).toBe("revoked");
126
+ dateNowMock.mockReset();
224
127
 
128
+ expect(listener).toHaveBeenCalledTimes(2);
129
+ expect(listener).toHaveBeenLastCalledWith(undefined);
225
130
  expect(map.core.getValidSortedTransactions().length).toBe(0);
226
131
  });
227
132
 
@@ -359,166 +264,49 @@ test("listeners are notified even if the previous listener threw an error", asyn
359
264
  errorLog.mockRestore();
360
265
  });
361
266
 
362
- test("getValidTransactions should skip trusting transactions with invalid JSON", () => {
363
- const [agent, sessionID] = randomAgentAndSessionID();
364
- const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
365
-
366
- const coValue = node.createCoValue({
367
- type: "costream",
368
- ruleset: { type: "unsafeAllowAll" },
369
- meta: null,
370
- ...Crypto.createdNowUnique(),
371
- });
372
-
373
- // Create a valid transaction first
374
- const validTransaction: Transaction = {
375
- privacy: "trusting",
376
- madeAt: Date.now(),
377
- changes: stableStringify([{ hello: "world" }]),
378
- };
379
-
380
- const { expectedNewHash: expectedNewHash1 } =
381
- coValue.verified.expectedNewHashAfter(node.currentSessionID, [
382
- validTransaction,
383
- ]);
384
-
385
- coValue
386
- .tryAddTransactions(
387
- node.currentSessionID,
388
- [validTransaction],
389
- expectedNewHash1,
390
- Crypto.sign(agent.currentSignerSecret(), expectedNewHash1),
391
- "immediate",
392
- )
393
- ._unsafeUnwrap();
394
-
395
- // Create an invalid transaction with malformed JSON
396
- const invalidTransaction: Transaction = {
397
- privacy: "trusting",
398
- madeAt: Date.now() + 1,
399
- changes: '{"invalid": json}' as any, // Invalid JSON string
400
- };
401
-
402
- const { expectedNewHash: expectedNewHash2 } =
403
- coValue.verified.expectedNewHashAfter(node.currentSessionID, [
404
- invalidTransaction,
405
- ]);
406
-
407
- coValue
408
- .tryAddTransactions(
409
- node.currentSessionID,
410
- [invalidTransaction],
411
- expectedNewHash2,
412
- Crypto.sign(agent.currentSignerSecret(), expectedNewHash2),
413
- "immediate",
414
- )
415
- ._unsafeUnwrap();
416
-
417
- // Get valid transactions - should only include the valid one
418
- const validTransactions = coValue.getValidTransactions();
419
-
420
- expect(validTransactions).toHaveLength(1);
421
- expect(validTransactions[0]?.changes).toEqual([{ hello: "world" }]);
422
- });
423
-
424
267
  test("getValidTransactions should skip private transactions with invalid JSON", () => {
425
- const [agent, sessionID] = randomAgentAndSessionID();
268
+ const [agent, sessionID] = agentAndSessionIDFromSecret(agentSecret);
426
269
  const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
427
270
 
428
- const group = node.createGroup();
429
- group.addMember("everyone", "writer");
430
-
431
- const coValue = node.createCoValue({
432
- type: "costream",
433
- ruleset: { type: "ownedByGroup", group: group.id },
434
- meta: null,
435
- ...Crypto.createdNowUnique(),
436
- });
437
-
438
- const { secret: keySecret, id: keyID } = coValue.getCurrentReadKey();
439
-
440
- assert(keySecret);
441
-
442
- const encrypted = Crypto.encryptForTransaction(
443
- [{ hello: "world" }],
444
- keySecret,
445
- {
446
- in: coValue.id,
447
- tx: coValue.nextTransactionID(),
271
+ const fixtures = {
272
+ id: "co_zWwrEiushQLvbkWd6Z3L8WxTU1r",
273
+ signature:
274
+ "signature_z3ktW7wxMnW7VYExCGZv4Ug2UJSW3ag6zLDiP8GpZThzif6veJt7JipYpUgshhuGbgHtLcWywWSWysV7hChxFypDt",
275
+ decrypted:
276
+ '[{"after":"start","op":"app","value":"co_zMphsnYN6GU8nn2HDY5suvyGufY"}]',
277
+ key: {
278
+ secret: "keySecret_z3dU66SsyQkkGKpNCJW6NX74MnfVGHUyY7r85b4M8X88L",
279
+ id: "key_z5XUAHyoqUV9zXWvMK",
448
280
  },
449
- );
450
-
451
- // Create a valid private transaction first
452
- const validTransaction: Transaction = {
453
- privacy: "private",
454
- madeAt: Date.now(),
455
- keyUsed: keyID,
456
- encryptedChanges: encrypted as any,
457
- };
281
+ transaction: {
282
+ privacy: "private",
283
+ madeAt: 0,
284
+ encryptedChanges:
285
+ "encrypted_UNAxqdUSGRZ2rzuLU99AFPKCe2C0HwsTzMWQreXZqLr6RpWrSMa-5lwgwIev7xPHTgZFq5UyUgMFrO9zlHJHJGgjJcDzFihY=" as any,
286
+ keyUsed: "key_z5XUAHyoqUV9zXWvMK",
287
+ },
288
+ session:
289
+ "sealer_z5yhsCCe2XwLTZC4254mUoMASshm3Diq49JrefPpjTktp/signer_z7gVGDpNz9qUtsRxAkHMuu4DYdtVVCG4XELTKPYdoYLPr_session_z9mDP8FoonSA",
290
+ } as const;
458
291
 
459
- const { expectedNewHash: expectedNewHash1 } =
460
- coValue.verified.expectedNewHashAfter(node.currentSessionID, [
461
- validTransaction,
462
- ]);
292
+ const group = node.createGroup();
293
+ const map = group.createMap();
463
294
 
464
- coValue
465
- .tryAddTransactions(
466
- node.currentSessionID,
467
- [validTransaction],
468
- expectedNewHash1,
469
- Crypto.sign(agent.currentSignerSecret(), expectedNewHash1),
470
- "immediate",
471
- )
472
- ._unsafeUnwrap();
295
+ map.set("hello", "world");
473
296
 
474
- const textEncoder = new TextEncoder();
475
- const brokenChange = `encrypted_U${bytesToBase64url(
476
- encrypt(
477
- textEncoder.encode('{"invalid": json}'),
478
- keySecret,
479
- textEncoder.encode(
480
- stableStringify({
481
- in: coValue.id,
482
- tx: coValue.nextTransactionID(),
483
- }),
484
- ),
485
- ),
486
- )}`;
487
-
488
- // Create an invalid private transaction with malformed JSON after decryption
489
- const invalidTransaction: Transaction = {
490
- privacy: "private",
491
- madeAt: Date.now() + 1,
492
- keyUsed: keyID,
493
- encryptedChanges: brokenChange as any,
494
- };
495
-
496
- const { expectedNewHash: expectedNewHash2 } =
497
- coValue.verified.expectedNewHashAfter(node.currentSessionID, [
498
- invalidTransaction,
499
- ]);
500
-
501
- coValue
297
+ // This should fail silently, because the encryptedChanges will be outputted as gibberish
298
+ map.core
502
299
  .tryAddTransactions(
503
- node.currentSessionID,
504
- [invalidTransaction],
505
- expectedNewHash2,
506
- Crypto.sign(agent.currentSignerSecret(), expectedNewHash2),
507
- "immediate",
300
+ fixtures.session,
301
+ [fixtures.transaction],
302
+ fixtures.signature,
508
303
  )
509
304
  ._unsafeUnwrap();
510
305
 
511
- // Get valid transactions - should skip the invalid one
512
- const validTransactions = coValue.getValidTransactions({
513
- ignorePrivateTransactions: false,
514
- });
306
+ // Get valid transactions - should only include the valid one
307
+ const validTransactions = map.core.getValidTransactions();
515
308
 
516
- // Since we can't easily create valid private transactions in this test setup,
517
- // we just verify that the method doesn't crash and handles the invalid JSON gracefully
518
- expect(validTransactions).toBeDefined();
519
- expect(Array.isArray(validTransactions)).toBe(true);
520
- expect(validTransactions.length).toBe(1);
521
- expect(validTransactions[0]?.changes).toEqual([{ hello: "world" }]);
309
+ expect(validTransactions).toHaveLength(1);
522
310
  });
523
311
 
524
312
  describe("markErrored and isErroredInPeer", () => {