cojson 0.18.34 → 0.18.36

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 (48) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +16 -0
  3. package/dist/coValueContentMessage.d.ts +5 -2
  4. package/dist/coValueContentMessage.d.ts.map +1 -1
  5. package/dist/coValueContentMessage.js +15 -0
  6. package/dist/coValueContentMessage.js.map +1 -1
  7. package/dist/coValueCore/SessionMap.d.ts +4 -3
  8. package/dist/coValueCore/SessionMap.d.ts.map +1 -1
  9. package/dist/coValueCore/SessionMap.js +12 -15
  10. package/dist/coValueCore/SessionMap.js.map +1 -1
  11. package/dist/coValueCore/coValueCore.d.ts +14 -6
  12. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  13. package/dist/coValueCore/coValueCore.js +29 -48
  14. package/dist/coValueCore/coValueCore.js.map +1 -1
  15. package/dist/coValueCore/verifiedState.d.ts +3 -3
  16. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  17. package/dist/coValueCore/verifiedState.js +18 -10
  18. package/dist/coValueCore/verifiedState.js.map +1 -1
  19. package/dist/coValues/group.d.ts.map +1 -1
  20. package/dist/coValues/group.js +21 -16
  21. package/dist/coValues/group.js.map +1 -1
  22. package/dist/knownState.d.ts.map +1 -1
  23. package/dist/knownState.js.map +1 -1
  24. package/dist/localNode.d.ts +7 -2
  25. package/dist/localNode.d.ts.map +1 -1
  26. package/dist/localNode.js +8 -14
  27. package/dist/localNode.js.map +1 -1
  28. package/dist/sync.d.ts.map +1 -1
  29. package/dist/sync.js +15 -18
  30. package/dist/sync.js.map +1 -1
  31. package/dist/tests/coValueContentMessage.test.js +130 -1
  32. package/dist/tests/coValueContentMessage.test.js.map +1 -1
  33. package/dist/tests/coValueCore.test.js +3 -6
  34. package/dist/tests/coValueCore.test.js.map +1 -1
  35. package/dist/tests/group.childKeyRotation.test.js +6 -6
  36. package/dist/tests/group.childKeyRotation.test.js.map +1 -1
  37. package/package.json +3 -4
  38. package/src/coValueContentMessage.ts +29 -2
  39. package/src/coValueCore/SessionMap.ts +23 -16
  40. package/src/coValueCore/coValueCore.ts +37 -63
  41. package/src/coValueCore/verifiedState.ts +25 -15
  42. package/src/coValues/group.ts +41 -28
  43. package/src/knownState.ts +3 -12
  44. package/src/localNode.ts +10 -18
  45. package/src/sync.ts +24 -25
  46. package/src/tests/coValueContentMessage.test.ts +197 -2
  47. package/src/tests/coValueCore.test.ts +7 -10
  48. package/src/tests/group.childKeyRotation.test.ts +6 -6
@@ -1,10 +1,15 @@
1
1
  import { describe, expect, test } from "vitest";
2
- import { knownStateFromContent } from "../coValueContentMessage.js";
2
+ import {
3
+ getNewTransactionsFromContentMessage,
4
+ knownStateFromContent,
5
+ } from "../coValueContentMessage.js";
3
6
  import { emptyKnownState } from "../knownState.js";
4
- import { NewContentMessage } from "../sync.js";
7
+ import { NewContentMessage, SessionNewContent } from "../sync.js";
5
8
  import type { RawCoID, SessionID } from "../ids.js";
6
9
  import { stableStringify } from "../jsonStringify.js";
7
10
  import { CO_VALUE_PRIORITY } from "../priority.js";
11
+ import { CoValueKnownState } from "../knownState.js";
12
+ import { Transaction } from "../coValueCore/verifiedState.js";
8
13
 
9
14
  describe("knownStateFromContent", () => {
10
15
  const mockCoID: RawCoID = "co_z1234567890abcdef";
@@ -213,3 +218,193 @@ describe("knownStateFromContent", () => {
213
218
  expect(result.sessions[mockSessionID1]).toBe(1); // 0 + 1
214
219
  });
215
220
  });
221
+
222
+ describe("getNewTransactionsFromContentMessage", () => {
223
+ const mockCoID: RawCoID = "co_z1234567890abcdef";
224
+ const mockSessionID: SessionID = "sealer_z123/signer_z456_session_z789";
225
+
226
+ function createTransaction(): Transaction {
227
+ return {
228
+ privacy: "trusting",
229
+ madeAt: Date.now(),
230
+ changes: stableStringify([{ op: "set", key: "test", value: "value" }]),
231
+ };
232
+ }
233
+
234
+ function createKnownState(
235
+ sessionTxIdx: number | undefined,
236
+ ): CoValueKnownState {
237
+ const knownState = emptyKnownState(mockCoID);
238
+ knownState.header = true;
239
+ if (sessionTxIdx !== undefined) {
240
+ knownState.sessions[mockSessionID] = sessionTxIdx;
241
+ }
242
+ return knownState;
243
+ }
244
+
245
+ test("returns all transactions when we know none (ourKnownTxIdx = 0, theirFirstNewTxIdx = 0)", () => {
246
+ const transactions = [createTransaction(), createTransaction()];
247
+ const content: SessionNewContent = {
248
+ after: 0,
249
+ newTransactions: transactions,
250
+ lastSignature: "signature_z1234",
251
+ };
252
+ const knownState = createKnownState(undefined); // defaults to 0
253
+
254
+ const result = getNewTransactionsFromContentMessage(
255
+ content,
256
+ knownState,
257
+ mockSessionID,
258
+ );
259
+
260
+ expect(result).toEqual(transactions);
261
+ expect(result).toHaveLength(2);
262
+ });
263
+
264
+ test("returns subset of transactions when we know some (ourKnownTxIdx = 3, theirFirstNewTxIdx = 0)", () => {
265
+ const transactions = [
266
+ createTransaction(),
267
+ createTransaction(),
268
+ createTransaction(),
269
+ createTransaction(),
270
+ createTransaction(),
271
+ ];
272
+ const content: SessionNewContent = {
273
+ after: 0,
274
+ newTransactions: transactions,
275
+ lastSignature: "signature_z1234",
276
+ };
277
+ const knownState = createKnownState(3); // we already know txs 0, 1, 2
278
+
279
+ const result = getNewTransactionsFromContentMessage(
280
+ content,
281
+ knownState,
282
+ mockSessionID,
283
+ );
284
+
285
+ expect(result).toEqual(transactions.slice(3));
286
+ expect(result).toHaveLength(2);
287
+ });
288
+
289
+ test("returns undefined when we're missing transactions (ourKnownTxIdx = 2, theirFirstNewTxIdx = 5)", () => {
290
+ const transactions = [createTransaction(), createTransaction()];
291
+ const content: SessionNewContent = {
292
+ after: 5, // they're sending txs starting from idx 5
293
+ newTransactions: transactions,
294
+ lastSignature: "signature_z1234",
295
+ };
296
+ const knownState = createKnownState(2); // but we only know up to idx 2
297
+
298
+ const result = getNewTransactionsFromContentMessage(
299
+ content,
300
+ knownState,
301
+ mockSessionID,
302
+ );
303
+
304
+ expect(result).toBeUndefined();
305
+ });
306
+
307
+ test("returns empty array when we know all transactions (ourKnownTxIdx = 5, theirFirstNewTxIdx = 2)", () => {
308
+ const transactions = [
309
+ createTransaction(),
310
+ createTransaction(),
311
+ createTransaction(),
312
+ ];
313
+ const content: SessionNewContent = {
314
+ after: 2, // they're sending txs 2, 3, 4
315
+ newTransactions: transactions,
316
+ lastSignature: "signature_z1234",
317
+ };
318
+ const knownState = createKnownState(5); // we already know txs up to idx 5
319
+
320
+ const result = getNewTransactionsFromContentMessage(
321
+ content,
322
+ knownState,
323
+ mockSessionID,
324
+ );
325
+
326
+ expect(result).toEqual([]);
327
+ expect(result).toHaveLength(0);
328
+ });
329
+
330
+ test("returns all transactions when ourKnownTxIdx equals theirFirstNewTxIdx", () => {
331
+ const transactions = [createTransaction(), createTransaction()];
332
+ const content: SessionNewContent = {
333
+ after: 3,
334
+ newTransactions: transactions,
335
+ lastSignature: "signature_z1234",
336
+ };
337
+ const knownState = createKnownState(3); // we know up to idx 3
338
+
339
+ const result = getNewTransactionsFromContentMessage(
340
+ content,
341
+ knownState,
342
+ mockSessionID,
343
+ );
344
+
345
+ expect(result).toEqual(transactions);
346
+ expect(result).toHaveLength(2);
347
+ });
348
+
349
+ test("handles session not in knownState (defaults to 0)", () => {
350
+ const transactions = [createTransaction()];
351
+ const content: SessionNewContent = {
352
+ after: 1,
353
+ newTransactions: transactions,
354
+ lastSignature: "signature_z1234",
355
+ };
356
+ const knownState = emptyKnownState(mockCoID);
357
+ knownState.header = true;
358
+ // no sessions defined, so mockSessionID defaults to 0
359
+
360
+ const result = getNewTransactionsFromContentMessage(
361
+ content,
362
+ knownState,
363
+ mockSessionID,
364
+ );
365
+
366
+ // ourKnownTxIdx = 0, theirFirstNewTxIdx = 1, so 0 < 1 -> undefined
367
+ expect(result).toBeUndefined();
368
+ });
369
+
370
+ test("returns single transaction when offset is length - 1", () => {
371
+ const transactions = [
372
+ createTransaction(),
373
+ createTransaction(),
374
+ createTransaction(),
375
+ ];
376
+ const content: SessionNewContent = {
377
+ after: 5,
378
+ newTransactions: transactions,
379
+ lastSignature: "signature_z1234",
380
+ };
381
+ const knownState = createKnownState(7); // we know up to idx 7 (5 + 2 transactions)
382
+
383
+ const result = getNewTransactionsFromContentMessage(
384
+ content,
385
+ knownState,
386
+ mockSessionID,
387
+ );
388
+
389
+ expect(result).toEqual([transactions[2]]);
390
+ expect(result).toHaveLength(1);
391
+ });
392
+
393
+ test("handles empty newTransactions array", () => {
394
+ const content: SessionNewContent = {
395
+ after: 5,
396
+ newTransactions: [],
397
+ lastSignature: "signature_z1234",
398
+ };
399
+ const knownState = createKnownState(5);
400
+
401
+ const result = getNewTransactionsFromContentMessage(
402
+ content,
403
+ knownState,
404
+ mockSessionID,
405
+ );
406
+
407
+ expect(result).toEqual([]);
408
+ expect(result).toHaveLength(0);
409
+ });
410
+ });
@@ -78,14 +78,13 @@ test("transactions with wrong signature are rejected", () => {
78
78
 
79
79
  const newEntry = node.getCoValue(coValue.id);
80
80
 
81
- // eslint-disable-next-line neverthrow/must-use-result
82
- const result = newEntry.tryAddTransactions(
81
+ const error = newEntry.tryAddTransactions(
83
82
  node.currentSessionID,
84
83
  [transaction],
85
84
  signature,
86
85
  );
87
86
 
88
- expect(result.isErr()).toBe(true);
87
+ expect(Boolean(error)).toBe(true);
89
88
  expect(newEntry.getValidSortedTransactions().length).toBe(0);
90
89
  });
91
90
 
@@ -448,13 +447,11 @@ test("getValidTransactions should skip private transactions with invalid JSON",
448
447
  map.set("hello", "world");
449
448
 
450
449
  // This should fail silently, because the encryptedChanges will be outputted as gibberish
451
- map.core
452
- .tryAddTransactions(
453
- fixtures.session,
454
- [fixtures.transaction],
455
- fixtures.signature,
456
- )
457
- ._unsafeUnwrap();
450
+ map.core.tryAddTransactions(
451
+ fixtures.session,
452
+ [fixtures.transaction],
453
+ fixtures.signature,
454
+ );
458
455
 
459
456
  // Get valid transactions - should only include the valid one
460
457
  const validTransactions = map.core.getValidTransactions();
@@ -69,7 +69,7 @@ describe("Group.childKeyRotation", () => {
69
69
  expect(mapOnAliceNode.get("test")).toBeUndefined();
70
70
  });
71
71
 
72
- test("removing a member should rotate the readKey on unloaded child groups", async () => {
72
+ test.skip("removing a member should rotate the readKey on unloaded child groups", async () => {
73
73
  const group = admin.node.createGroup();
74
74
 
75
75
  let childGroup = bob.node.createGroup();
@@ -103,7 +103,7 @@ describe("Group.childKeyRotation", () => {
103
103
  expect(mapOnAliceNode.get("test")).toBeUndefined();
104
104
  });
105
105
 
106
- test("removing a member on a large group should rotate the readKey on unloaded child group", async () => {
106
+ test.skip("removing a member on a large group should rotate the readKey on unloaded child group", async () => {
107
107
  const group = admin.node.createGroup();
108
108
 
109
109
  const childGroup = bob.node.createGroup();
@@ -163,7 +163,7 @@ describe("Group.childKeyRotation", () => {
163
163
  expect(mapOnAliceNode.get("test")).toBeUndefined();
164
164
  });
165
165
 
166
- test("removing a member on a large parent group should rotate the readKey on unloaded grandChild group", async () => {
166
+ test.skip("removing a member on a large parent group should rotate the readKey on unloaded grandChild group", async () => {
167
167
  const parentGroup = admin.node.createGroup();
168
168
 
169
169
  const group = bob.node.createGroup();
@@ -230,7 +230,7 @@ describe("Group.childKeyRotation", () => {
230
230
  expect(mapOnAliceNode.get("test")).toBeUndefined();
231
231
  });
232
232
 
233
- test("non-admin accounts can't trigger the unloaded child group key rotation", async () => {
233
+ test.skip("non-admin accounts can't trigger the unloaded child group key rotation", async () => {
234
234
  const group = admin.node.createGroup();
235
235
  const childGroup = bob.node.createGroup();
236
236
 
@@ -290,7 +290,7 @@ describe("Group.childKeyRotation", () => {
290
290
  expect(updatedMapOnCharlieNode.get("test")).toBe("Readable by charlie");
291
291
  });
292
292
 
293
- test("direct manager account can trigger the unloaded child group key rotation", async () => {
293
+ test.skip("direct manager account can trigger the unloaded child group key rotation", async () => {
294
294
  const group = admin.node.createGroup();
295
295
  const childGroup = bob.node.createGroup();
296
296
 
@@ -338,7 +338,7 @@ describe("Group.childKeyRotation", () => {
338
338
  expect(mapOnAliceNode.get("test")).toBeUndefined();
339
339
  });
340
340
 
341
- test("inherited admin account triggers the unloaded child group key rotation", async () => {
341
+ test.skip("inherited admin account triggers the unloaded child group key rotation", async () => {
342
342
  const group = admin.node.createGroup();
343
343
  const childGroup = bob.node.createGroup();
344
344