cojson 0.18.26 → 0.18.28
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 +17 -0
- package/dist/PeerKnownStates.d.ts +4 -3
- package/dist/PeerKnownStates.d.ts.map +1 -1
- package/dist/PeerKnownStates.js +27 -18
- package/dist/PeerKnownStates.js.map +1 -1
- package/dist/PeerState.d.ts +3 -2
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js.map +1 -1
- package/dist/SyncStateManager.d.ts +2 -2
- package/dist/SyncStateManager.d.ts.map +1 -1
- package/dist/SyncStateManager.js +2 -10
- package/dist/SyncStateManager.js.map +1 -1
- package/dist/coValueContentMessage.d.ts +1 -1
- package/dist/coValueContentMessage.d.ts.map +1 -1
- package/dist/coValueContentMessage.js +1 -1
- package/dist/coValueContentMessage.js.map +1 -1
- package/dist/coValueCore/SessionMap.d.ts +6 -3
- package/dist/coValueCore/SessionMap.d.ts.map +1 -1
- package/dist/coValueCore/SessionMap.js +41 -8
- package/dist/coValueCore/SessionMap.js.map +1 -1
- package/dist/coValueCore/branching.d.ts +5 -4
- package/dist/coValueCore/branching.d.ts.map +1 -1
- package/dist/coValueCore/branching.js +22 -4
- package/dist/coValueCore/branching.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +29 -25
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +163 -126
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/decryptTransactionChangesAndMeta.d.ts +3 -0
- package/dist/coValueCore/decryptTransactionChangesAndMeta.d.ts.map +1 -0
- package/dist/coValueCore/decryptTransactionChangesAndMeta.js +34 -0
- package/dist/coValueCore/decryptTransactionChangesAndMeta.js.map +1 -0
- package/dist/coValueCore/verifiedState.d.ts +12 -6
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +28 -56
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/coMap.d.ts.map +1 -1
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.d.ts.map +1 -1
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/exports.d.ts +3 -2
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +2 -1
- package/dist/exports.js.map +1 -1
- package/dist/knownState.d.ts +58 -2
- package/dist/knownState.d.ts.map +1 -1
- package/dist/knownState.js +79 -5
- package/dist/knownState.js.map +1 -1
- package/dist/localNode.js +1 -1
- package/dist/localNode.js.map +1 -1
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +18 -20
- package/dist/permissions.js.map +1 -1
- package/dist/storage/knownState.d.ts +1 -1
- package/dist/storage/knownState.d.ts.map +1 -1
- package/dist/storage/knownState.js +2 -3
- package/dist/storage/knownState.js.map +1 -1
- package/dist/storage/storageAsync.d.ts +2 -1
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js +5 -6
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/storage/storageSync.d.ts +2 -1
- package/dist/storage/storageSync.d.ts.map +1 -1
- package/dist/storage/storageSync.js +5 -5
- package/dist/storage/storageSync.js.map +1 -1
- package/dist/storage/types.d.ts +2 -1
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/sync.d.ts +2 -12
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +9 -38
- package/dist/sync.js.map +1 -1
- package/dist/tests/PeerKnownStates.test.js +1 -1
- package/dist/tests/PeerKnownStates.test.js.map +1 -1
- package/dist/tests/PeerState.test.js +19 -0
- package/dist/tests/PeerState.test.js.map +1 -1
- package/dist/tests/PureJSCrypto.test.js.map +1 -1
- package/dist/tests/StorageApiAsync.test.js +1 -1
- package/dist/tests/StorageApiAsync.test.js.map +1 -1
- package/dist/tests/StorageApiSync.test.js +1 -2
- package/dist/tests/StorageApiSync.test.js.map +1 -1
- package/dist/tests/StoreQueue.test.js.map +1 -1
- package/dist/tests/SyncStateManager.test.js +1 -1
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/branching.test.js +237 -28
- package/dist/tests/branching.test.js.map +1 -1
- package/dist/tests/coValueContentMessage.test.js +1 -1
- package/dist/tests/coValueContentMessage.test.js.map +1 -1
- package/dist/tests/coValueCore.loadFromStorage.test.d.ts +2 -0
- package/dist/tests/coValueCore.loadFromStorage.test.d.ts.map +1 -0
- package/dist/tests/coValueCore.loadFromStorage.test.js +395 -0
- package/dist/tests/coValueCore.loadFromStorage.test.js.map +1 -0
- package/dist/tests/coValueCore.loadingState.test.d.ts +2 -0
- package/dist/tests/coValueCore.loadingState.test.d.ts.map +1 -0
- package/dist/tests/{coValueCoreLoadingState.test.js → coValueCore.loadingState.test.js} +4 -12
- package/dist/tests/coValueCore.loadingState.test.js.map +1 -0
- package/dist/tests/coValueCore.test.js +30 -5
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/knownState.test.d.ts +2 -0
- package/dist/tests/knownState.test.d.ts.map +1 -0
- package/dist/tests/knownState.test.js +510 -0
- package/dist/tests/knownState.test.js.map +1 -0
- package/dist/tests/messagesTestUtils.d.ts.map +1 -1
- package/dist/tests/messagesTestUtils.js.map +1 -1
- package/dist/tests/priority.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +4 -34
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js.map +1 -1
- package/dist/tests/testUtils.d.ts +7 -1
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +12 -0
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +3 -3
- package/src/PeerKnownStates.ts +36 -22
- package/src/PeerState.ts +2 -1
- package/src/SyncStateManager.ts +4 -17
- package/src/coValueContentMessage.ts +2 -1
- package/src/coValueCore/SessionMap.ts +66 -11
- package/src/coValueCore/branching.ts +37 -13
- package/src/coValueCore/coValueCore.ts +224 -177
- package/src/coValueCore/decryptTransactionChangesAndMeta.ts +56 -0
- package/src/coValueCore/verifiedState.ts +32 -64
- package/src/coValues/coMap.ts +1 -5
- package/src/coValues/coStream.ts +1 -5
- package/src/exports.ts +2 -2
- package/src/knownState.ts +118 -12
- package/src/localNode.ts +1 -1
- package/src/permissions.ts +21 -22
- package/src/storage/knownState.ts +9 -3
- package/src/storage/storageAsync.ts +15 -7
- package/src/storage/storageSync.ts +16 -8
- package/src/storage/types.ts +2 -1
- package/src/sync.ts +14 -60
- package/src/tests/PeerKnownStates.test.ts +1 -1
- package/src/tests/PeerState.test.ts +29 -3
- package/src/tests/PureJSCrypto.test.ts +0 -1
- package/src/tests/StorageApiAsync.test.ts +3 -6
- package/src/tests/StorageApiSync.test.ts +2 -6
- package/src/tests/StoreQueue.test.ts +3 -2
- package/src/tests/SyncStateManager.test.ts +1 -1
- package/src/tests/branching.test.ts +392 -45
- package/src/tests/coValueContentMessage.test.ts +2 -2
- package/src/tests/coValueCore.loadFromStorage.test.ts +540 -0
- package/src/tests/{coValueCoreLoadingState.test.ts → coValueCore.loadingState.test.ts} +3 -16
- package/src/tests/coValueCore.test.ts +40 -5
- package/src/tests/knownState.test.ts +665 -0
- package/src/tests/messagesTestUtils.ts +2 -1
- package/src/tests/priority.test.ts +0 -2
- package/src/tests/sync.mesh.test.ts +11 -38
- package/src/tests/sync.storage.test.ts +0 -1
- package/src/tests/sync.upload.test.ts +0 -1
- package/src/tests/testUtils.ts +22 -2
- package/dist/coValueCore/decodeTransactionChangesAndMeta.d.ts +0 -3
- package/dist/coValueCore/decodeTransactionChangesAndMeta.d.ts.map +0 -1
- package/dist/coValueCore/decodeTransactionChangesAndMeta.js +0 -59
- package/dist/coValueCore/decodeTransactionChangesAndMeta.js.map +0 -1
- package/dist/tests/coValueCoreLoadingState.test.d.ts +0 -2
- package/dist/tests/coValueCoreLoadingState.test.d.ts.map +0 -1
- package/dist/tests/coValueCoreLoadingState.test.js.map +0 -1
- package/src/coValueCore/decodeTransactionChangesAndMeta.ts +0 -81
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
assert,
|
|
3
|
+
beforeEach,
|
|
4
|
+
describe,
|
|
5
|
+
expect,
|
|
6
|
+
onTestFinished,
|
|
7
|
+
test,
|
|
8
|
+
vi,
|
|
9
|
+
} from "vitest";
|
|
2
10
|
import {
|
|
3
11
|
createTestNode,
|
|
4
12
|
setupTestNode,
|
|
5
13
|
loadCoValueOrFail,
|
|
14
|
+
setupTestAccount,
|
|
15
|
+
waitFor,
|
|
6
16
|
} from "./testUtils.js";
|
|
7
17
|
import { expectList, expectMap, expectPlainText } from "../coValue.js";
|
|
8
|
-
import { RawCoMap } from "../exports.js";
|
|
18
|
+
import { RawAccount, RawCoMap } from "../exports.js";
|
|
9
19
|
|
|
10
20
|
let jazzCloud: ReturnType<typeof setupTestNode>;
|
|
11
21
|
|
|
@@ -237,6 +247,7 @@ describe("Branching Logic", () => {
|
|
|
237
247
|
loadedBranch2.core.mergeBranch();
|
|
238
248
|
|
|
239
249
|
await loadedBranch2.core.waitForSync();
|
|
250
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
240
251
|
|
|
241
252
|
branch1.core.mergeBranch();
|
|
242
253
|
|
|
@@ -289,6 +300,385 @@ describe("Branching Logic", () => {
|
|
|
289
300
|
|
|
290
301
|
expect(plainText.toString()).toEqual("hello world people");
|
|
291
302
|
});
|
|
303
|
+
|
|
304
|
+
test("should preserve the conflict resolution that was applied to the branch", async () => {
|
|
305
|
+
const dateNowMock = vi.spyOn(Date, "now");
|
|
306
|
+
|
|
307
|
+
dateNowMock.mockReturnValue(1);
|
|
308
|
+
|
|
309
|
+
const client = setupTestNode({
|
|
310
|
+
connected: true,
|
|
311
|
+
});
|
|
312
|
+
const group = client.node.createGroup();
|
|
313
|
+
const map = group.createMap();
|
|
314
|
+
const branchName = "feature-branch";
|
|
315
|
+
|
|
316
|
+
onTestFinished(() => {
|
|
317
|
+
dateNowMock.mockRestore();
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Add initial transactions to original map
|
|
321
|
+
map.set("value", 1, "trusting");
|
|
322
|
+
|
|
323
|
+
// Create branch from original map
|
|
324
|
+
const branch = expectMap(
|
|
325
|
+
map.core.createBranch(branchName, group.id).getCurrentContent(),
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
dateNowMock.mockReturnValue(2);
|
|
329
|
+
|
|
330
|
+
// Add new transaction to branch
|
|
331
|
+
branch.set("value", 2, "trusting");
|
|
332
|
+
|
|
333
|
+
const newSession = client.spawnNewSession();
|
|
334
|
+
|
|
335
|
+
const loadedBranch = await loadCoValueOrFail(newSession.node, branch.id);
|
|
336
|
+
|
|
337
|
+
dateNowMock.mockReturnValue(3);
|
|
338
|
+
|
|
339
|
+
loadedBranch.set("value", 3, "trusting");
|
|
340
|
+
|
|
341
|
+
expect(loadedBranch.get("value")).toBe(3);
|
|
342
|
+
|
|
343
|
+
await loadedBranch.core.waitForSync();
|
|
344
|
+
|
|
345
|
+
// Push back the change, so it doesn't win the conflict
|
|
346
|
+
dateNowMock.mockReturnValue(1);
|
|
347
|
+
|
|
348
|
+
branch.set("value", 4, "trusting");
|
|
349
|
+
|
|
350
|
+
expect(branch.get("value")).toBe(3);
|
|
351
|
+
|
|
352
|
+
dateNowMock.mockReturnValue(4);
|
|
353
|
+
branch.core.mergeBranch();
|
|
354
|
+
|
|
355
|
+
// The conflict resolution should be preserved, so we should have 3 and not 4
|
|
356
|
+
expect(map.get("value")).toBe(3);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
test("should preserve the original madeAt of the branch", async () => {
|
|
360
|
+
const client = setupTestNode();
|
|
361
|
+
const group = client.node.createGroup();
|
|
362
|
+
const map = group.createMap();
|
|
363
|
+
|
|
364
|
+
// Add initial transactions to original map
|
|
365
|
+
map.set("value", 1, "trusting");
|
|
366
|
+
|
|
367
|
+
// Create branch from original map
|
|
368
|
+
const branch = expectMap(
|
|
369
|
+
map.core.createBranch("feature-branch", group.id).getCurrentContent(),
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
// Add new transaction to branch
|
|
373
|
+
branch.set("value", 2, "trusting");
|
|
374
|
+
|
|
375
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
376
|
+
|
|
377
|
+
const result = branch.core.mergeBranch();
|
|
378
|
+
|
|
379
|
+
// The merge should be successful
|
|
380
|
+
expect(map.get("value")).toBe(2);
|
|
381
|
+
|
|
382
|
+
const lastBranchTransaction = branch.core
|
|
383
|
+
.getValidSortedTransactions()
|
|
384
|
+
.at(-1);
|
|
385
|
+
const lastMapTransaction = result
|
|
386
|
+
.getValidSortedTransactions()
|
|
387
|
+
.findLast((tx) => tx.txID.branch === branch.id);
|
|
388
|
+
|
|
389
|
+
expect(lastMapTransaction?.currentMadeAt).not.toBe(
|
|
390
|
+
lastMapTransaction?.madeAt,
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
expect(lastBranchTransaction?.madeAt).toBe(lastMapTransaction?.madeAt);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
test("should not load the merged transactions into the branch (regression test)", async () => {
|
|
397
|
+
const client = setupTestNode();
|
|
398
|
+
const group = client.node.createGroup();
|
|
399
|
+
const map = group.createMap();
|
|
400
|
+
|
|
401
|
+
// Add initial transactions to original map
|
|
402
|
+
map.set("value", 1, "trusting");
|
|
403
|
+
|
|
404
|
+
// Create branch from original map
|
|
405
|
+
const branch = expectMap(
|
|
406
|
+
map.core.createBranch("feature-branch", group.id).getCurrentContent(),
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
410
|
+
|
|
411
|
+
// Add new transaction to branch
|
|
412
|
+
branch.set("value", 2, "trusting");
|
|
413
|
+
|
|
414
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
415
|
+
|
|
416
|
+
const result = branch.core.mergeBranch();
|
|
417
|
+
|
|
418
|
+
// The merge should be successful
|
|
419
|
+
expect(map.get("value")).toBe(2);
|
|
420
|
+
|
|
421
|
+
const lastBranchTransaction = branch.core
|
|
422
|
+
.getValidSortedTransactions()
|
|
423
|
+
.at(-1);
|
|
424
|
+
expect(lastBranchTransaction?.madeAt).toBe(
|
|
425
|
+
lastBranchTransaction?.currentMadeAt,
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
const lastMapTransaction = result
|
|
429
|
+
.getValidSortedTransactions()
|
|
430
|
+
.findLast((tx) => tx.txID.branch === branch.id);
|
|
431
|
+
expect(lastMapTransaction?.madeAt).not.toBe(
|
|
432
|
+
lastMapTransaction?.currentMadeAt,
|
|
433
|
+
);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test("write permissions should be validated against the time of the merge and not the original madeAt", async () => {
|
|
437
|
+
const alice = setupTestNode({
|
|
438
|
+
connected: true,
|
|
439
|
+
});
|
|
440
|
+
const bob = await setupTestAccount({
|
|
441
|
+
connected: true,
|
|
442
|
+
});
|
|
443
|
+
const group = alice.node.createGroup();
|
|
444
|
+
const map = group.createMap();
|
|
445
|
+
const branchName = "feature-branch";
|
|
446
|
+
|
|
447
|
+
map.set("value", 1, "trusting");
|
|
448
|
+
|
|
449
|
+
const branch = expectMap(
|
|
450
|
+
map.core.createBranch(branchName, group.id).getCurrentContent(),
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
branch.set("value", 2, "trusting");
|
|
454
|
+
|
|
455
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
456
|
+
|
|
457
|
+
// Grant writer rights to bob after the changes inside the branche
|
|
458
|
+
group.addMember(
|
|
459
|
+
await loadCoValueOrFail(alice.node, bob.accountID),
|
|
460
|
+
"writer",
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
const loadedBranch = await loadCoValueOrFail(bob.node, branch.id);
|
|
464
|
+
|
|
465
|
+
// Bob merges the branch
|
|
466
|
+
const mergeResult = loadedBranch.core.mergeBranch();
|
|
467
|
+
|
|
468
|
+
// The merge should be successful
|
|
469
|
+
expect(expectMap(mergeResult.getCurrentContent()).get("value")).toBe(2);
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
test("should reject edits from kicked out member even with timestamp manipulation", async () => {
|
|
473
|
+
const alice = setupTestNode({
|
|
474
|
+
connected: true,
|
|
475
|
+
});
|
|
476
|
+
const bob = await setupTestAccount({
|
|
477
|
+
connected: true,
|
|
478
|
+
});
|
|
479
|
+
const group = alice.node.createGroup();
|
|
480
|
+
const map = group.createMap();
|
|
481
|
+
|
|
482
|
+
group.addMember(
|
|
483
|
+
await loadCoValueOrFail(alice.node, bob.accountID),
|
|
484
|
+
"writer",
|
|
485
|
+
);
|
|
486
|
+
const timeOnInvitation = Date.now();
|
|
487
|
+
|
|
488
|
+
const bobMap = await loadCoValueOrFail(bob.node, map.id);
|
|
489
|
+
|
|
490
|
+
bobMap.set("value", 1, "trusting");
|
|
491
|
+
|
|
492
|
+
await bobMap.core.waitForSync();
|
|
493
|
+
|
|
494
|
+
const bobGroup = bob.node.createGroup();
|
|
495
|
+
const branch = expectMap(
|
|
496
|
+
bobMap.core
|
|
497
|
+
.createBranch("feature-branch", bobGroup.id)
|
|
498
|
+
.getCurrentContent(),
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
502
|
+
|
|
503
|
+
// Alice sets value to 2 and downgrade bob to reader
|
|
504
|
+
map.set("value", 2, "trusting");
|
|
505
|
+
group.addMember(
|
|
506
|
+
await loadCoValueOrFail(alice.node, bob.accountID),
|
|
507
|
+
"reader",
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
511
|
+
|
|
512
|
+
branch.set("value", 3, "trusting");
|
|
513
|
+
|
|
514
|
+
// Bob attempts to make an edit after being kicked out by modifying the merge time
|
|
515
|
+
const dateNowMock = vi.spyOn(Date, "now");
|
|
516
|
+
dateNowMock.mockReturnValue(timeOnInvitation + 1);
|
|
517
|
+
|
|
518
|
+
const mergeResult = branch.core.mergeBranch();
|
|
519
|
+
|
|
520
|
+
dateNowMock.mockRestore();
|
|
521
|
+
|
|
522
|
+
// Wait for the full sync to complete
|
|
523
|
+
await waitFor(() => {
|
|
524
|
+
expect(mergeResult.knownState().sessions).toEqual(
|
|
525
|
+
map.core.knownState().sessions,
|
|
526
|
+
);
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
expect(expectMap(map.core.getCurrentContent()).get("value")).toBe(2);
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
test("should alias the txID when a transaction comes from a merge", async () => {
|
|
533
|
+
const client = setupTestNode({
|
|
534
|
+
connected: true,
|
|
535
|
+
});
|
|
536
|
+
const group = client.node.createGroup();
|
|
537
|
+
const map = group.createMap();
|
|
538
|
+
|
|
539
|
+
map.set("key", "value");
|
|
540
|
+
|
|
541
|
+
const branch = map.core
|
|
542
|
+
.createBranch("feature-branch", group.id)
|
|
543
|
+
.getCurrentContent() as RawCoMap;
|
|
544
|
+
branch.set("branchKey", "branchValue");
|
|
545
|
+
|
|
546
|
+
const originalTxID = branch.core
|
|
547
|
+
.getValidTransactions({
|
|
548
|
+
skipBranchSource: true,
|
|
549
|
+
ignorePrivateTransactions: false,
|
|
550
|
+
})
|
|
551
|
+
.at(-1)?.txID;
|
|
552
|
+
|
|
553
|
+
branch.core.mergeBranch();
|
|
554
|
+
|
|
555
|
+
map.set("key2", "value2");
|
|
556
|
+
|
|
557
|
+
const validSortedTransactions = map.core.getValidSortedTransactions();
|
|
558
|
+
|
|
559
|
+
// Only the merged transaction should have the txId changed
|
|
560
|
+
const mergedTransactionIdx = validSortedTransactions.findIndex(
|
|
561
|
+
(tx) => tx.txID.branch,
|
|
562
|
+
);
|
|
563
|
+
|
|
564
|
+
expect(
|
|
565
|
+
validSortedTransactions[mergedTransactionIdx - 1]?.txID.branch,
|
|
566
|
+
).toBe(undefined);
|
|
567
|
+
expect(validSortedTransactions[mergedTransactionIdx]?.txID).toEqual(
|
|
568
|
+
originalTxID,
|
|
569
|
+
);
|
|
570
|
+
expect(
|
|
571
|
+
validSortedTransactions[mergedTransactionIdx + 1]?.txID.branch,
|
|
572
|
+
).toBe(undefined);
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
describe("Branching permissions", () => {
|
|
577
|
+
test("should allow the creation of private branches to accounts with read access to the source group", async () => {
|
|
578
|
+
const alice = setupTestNode({
|
|
579
|
+
connected: true,
|
|
580
|
+
});
|
|
581
|
+
const bob = await setupTestAccount({
|
|
582
|
+
connected: true,
|
|
583
|
+
});
|
|
584
|
+
const group = alice.node.createGroup();
|
|
585
|
+
group.addMember(
|
|
586
|
+
await loadCoValueOrFail(alice.node, bob.accountID),
|
|
587
|
+
"reader",
|
|
588
|
+
);
|
|
589
|
+
const map = group.createMap();
|
|
590
|
+
map.set("key", "alice");
|
|
591
|
+
|
|
592
|
+
const bobGroup = bob.node.createGroup();
|
|
593
|
+
|
|
594
|
+
const mapOnBob = await loadCoValueOrFail(bob.node, map.id);
|
|
595
|
+
|
|
596
|
+
const branch = expectMap(
|
|
597
|
+
mapOnBob.core
|
|
598
|
+
.createBranch("feature-branch", bobGroup.id)
|
|
599
|
+
.getCurrentContent(),
|
|
600
|
+
);
|
|
601
|
+
|
|
602
|
+
expect(mapOnBob.core.branches).toEqual([
|
|
603
|
+
{
|
|
604
|
+
branch: "feature-branch",
|
|
605
|
+
ownerId: bobGroup.id,
|
|
606
|
+
},
|
|
607
|
+
]);
|
|
608
|
+
|
|
609
|
+
expect(branch.id).not.toBe(map.id);
|
|
610
|
+
expect(branch.get("key")).toBe("alice");
|
|
611
|
+
expect(branch.core.getGroup().id).toBe(bobGroup.id);
|
|
612
|
+
expect(branch.core.getGroup().myRole()).toBe("admin");
|
|
613
|
+
branch.set("key", "bob");
|
|
614
|
+
|
|
615
|
+
expect(branch.get("key")).toBe("bob");
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
test("an account with write access to the source and read access to the branch should be able to merge a branch created by a reader", async () => {
|
|
619
|
+
const alice = await setupTestAccount({
|
|
620
|
+
connected: true,
|
|
621
|
+
});
|
|
622
|
+
const bob = await setupTestAccount({
|
|
623
|
+
connected: true,
|
|
624
|
+
});
|
|
625
|
+
const group = alice.node.createGroup();
|
|
626
|
+
group.addMember(
|
|
627
|
+
await loadCoValueOrFail(alice.node, bob.accountID),
|
|
628
|
+
"reader",
|
|
629
|
+
);
|
|
630
|
+
const map = group.createMap();
|
|
631
|
+
map.set("key", "alice");
|
|
632
|
+
|
|
633
|
+
const bobGroup = bob.node.createGroup();
|
|
634
|
+
bobGroup.addMember(
|
|
635
|
+
await loadCoValueOrFail(bob.node, alice.accountID),
|
|
636
|
+
"reader",
|
|
637
|
+
);
|
|
638
|
+
|
|
639
|
+
const mapOnBob = await loadCoValueOrFail(bob.node, map.id);
|
|
640
|
+
|
|
641
|
+
const branch = expectMap(
|
|
642
|
+
mapOnBob.core
|
|
643
|
+
.createBranch("feature-branch", bobGroup.id)
|
|
644
|
+
.getCurrentContent(),
|
|
645
|
+
);
|
|
646
|
+
|
|
647
|
+
branch.set("key", "bob");
|
|
648
|
+
|
|
649
|
+
expect(branch.get("key")).toBe("bob");
|
|
650
|
+
|
|
651
|
+
const branchOnAlice = await loadCoValueOrFail(alice.node, branch.id);
|
|
652
|
+
branchOnAlice.core.mergeBranch();
|
|
653
|
+
|
|
654
|
+
expect(map.get("key")).toBe("bob");
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
test("should not allow the creation of public branches to accounts with read access", async () => {
|
|
658
|
+
const alice = setupTestNode({
|
|
659
|
+
connected: true,
|
|
660
|
+
});
|
|
661
|
+
const bob = await setupTestAccount({
|
|
662
|
+
connected: true,
|
|
663
|
+
});
|
|
664
|
+
const group = alice.node.createGroup();
|
|
665
|
+
group.addMember(
|
|
666
|
+
await loadCoValueOrFail(alice.node, bob.accountID),
|
|
667
|
+
"reader",
|
|
668
|
+
);
|
|
669
|
+
const map = group.createMap();
|
|
670
|
+
map.set("key", "alice");
|
|
671
|
+
|
|
672
|
+
const mapOnBob = await loadCoValueOrFail(bob.node, map.id);
|
|
673
|
+
|
|
674
|
+
const branch = expectMap(
|
|
675
|
+
mapOnBob.core.createBranch("feature-branch").getCurrentContent(),
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
expect(mapOnBob.core.branches).toEqual([]);
|
|
679
|
+
|
|
680
|
+
expect(branch.id).toBe(map.id);
|
|
681
|
+
});
|
|
292
682
|
});
|
|
293
683
|
|
|
294
684
|
describe("Branch Loading and Checkout", () => {
|
|
@@ -560,49 +950,6 @@ describe("Branching Logic", () => {
|
|
|
560
950
|
});
|
|
561
951
|
});
|
|
562
952
|
|
|
563
|
-
test("should alias the txID when a transaction comes from a merge", async () => {
|
|
564
|
-
const client = setupTestNode({
|
|
565
|
-
connected: true,
|
|
566
|
-
});
|
|
567
|
-
const group = client.node.createGroup();
|
|
568
|
-
const map = group.createMap();
|
|
569
|
-
|
|
570
|
-
map.set("key", "value");
|
|
571
|
-
|
|
572
|
-
const branch = map.core
|
|
573
|
-
.createBranch("feature-branch", group.id)
|
|
574
|
-
.getCurrentContent() as RawCoMap;
|
|
575
|
-
branch.set("branchKey", "branchValue");
|
|
576
|
-
|
|
577
|
-
const originalTxID = branch.core
|
|
578
|
-
.getValidTransactions({
|
|
579
|
-
skipBranchSource: true,
|
|
580
|
-
ignorePrivateTransactions: false,
|
|
581
|
-
})
|
|
582
|
-
.at(-1)?.txID;
|
|
583
|
-
|
|
584
|
-
branch.core.mergeBranch();
|
|
585
|
-
|
|
586
|
-
map.set("key2", "value2");
|
|
587
|
-
|
|
588
|
-
const validSortedTransactions = map.core.getValidSortedTransactions();
|
|
589
|
-
|
|
590
|
-
// Only the merged transaction should have the txId changed
|
|
591
|
-
const mergedTransactionIdx = validSortedTransactions.findIndex(
|
|
592
|
-
(tx) => tx.txID.branch,
|
|
593
|
-
);
|
|
594
|
-
|
|
595
|
-
expect(validSortedTransactions[mergedTransactionIdx - 1]?.txID.branch).toBe(
|
|
596
|
-
undefined,
|
|
597
|
-
);
|
|
598
|
-
expect(validSortedTransactions[mergedTransactionIdx]?.txID).toEqual(
|
|
599
|
-
originalTxID,
|
|
600
|
-
);
|
|
601
|
-
expect(validSortedTransactions[mergedTransactionIdx + 1]?.txID.branch).toBe(
|
|
602
|
-
undefined,
|
|
603
|
-
);
|
|
604
|
-
});
|
|
605
|
-
|
|
606
953
|
describe("hasBranch", () => {
|
|
607
954
|
test("should work when the branch owner is the source owner", () => {
|
|
608
955
|
const client = setupTestNode({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, test } from "vitest";
|
|
2
2
|
import { knownStateFromContent } from "../coValueContentMessage.js";
|
|
3
|
-
import { emptyKnownState } from "../
|
|
4
|
-
import
|
|
3
|
+
import { emptyKnownState } from "../knownState.js";
|
|
4
|
+
import { NewContentMessage } from "../sync.js";
|
|
5
5
|
import type { RawCoID, SessionID } from "../ids.js";
|
|
6
6
|
import { stableStringify } from "../jsonStringify.js";
|
|
7
7
|
import { CO_VALUE_PRIORITY } from "../priority.js";
|