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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +16 -0
- package/dist/coValueContentMessage.d.ts +5 -2
- package/dist/coValueContentMessage.d.ts.map +1 -1
- package/dist/coValueContentMessage.js +15 -0
- package/dist/coValueContentMessage.js.map +1 -1
- package/dist/coValueCore/SessionMap.d.ts +4 -3
- package/dist/coValueCore/SessionMap.d.ts.map +1 -1
- package/dist/coValueCore/SessionMap.js +12 -15
- package/dist/coValueCore/SessionMap.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +14 -6
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +29 -48
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +3 -3
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +18 -10
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +21 -16
- package/dist/coValues/group.js.map +1 -1
- package/dist/knownState.d.ts.map +1 -1
- package/dist/knownState.js.map +1 -1
- package/dist/localNode.d.ts +7 -2
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +8 -14
- package/dist/localNode.js.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +15 -18
- package/dist/sync.js.map +1 -1
- package/dist/tests/coValueContentMessage.test.js +130 -1
- package/dist/tests/coValueContentMessage.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +3 -6
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/group.childKeyRotation.test.js +6 -6
- package/dist/tests/group.childKeyRotation.test.js.map +1 -1
- package/package.json +3 -4
- package/src/coValueContentMessage.ts +29 -2
- package/src/coValueCore/SessionMap.ts +23 -16
- package/src/coValueCore/coValueCore.ts +37 -63
- package/src/coValueCore/verifiedState.ts +25 -15
- package/src/coValues/group.ts +41 -28
- package/src/knownState.ts +3 -12
- package/src/localNode.ts +10 -18
- package/src/sync.ts +24 -25
- package/src/tests/coValueContentMessage.test.ts +197 -2
- package/src/tests/coValueCore.test.ts +7 -10
- package/src/tests/group.childKeyRotation.test.ts +6 -6
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { describe, expect, test } from "vitest";
|
|
2
|
-
import {
|
|
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
|
-
|
|
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(
|
|
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
|
-
.
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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
|
|