cojson 0.18.6 → 0.18.7
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 +11 -0
- package/dist/coValueContentMessage.d.ts +2 -0
- package/dist/coValueContentMessage.d.ts.map +1 -1
- package/dist/coValueContentMessage.js +7 -0
- package/dist/coValueContentMessage.js.map +1 -1
- package/dist/coValueCore/SessionMap.d.ts +2 -2
- package/dist/coValueCore/SessionMap.d.ts.map +1 -1
- package/dist/coValueCore/SessionMap.js +2 -4
- package/dist/coValueCore/SessionMap.js.map +1 -1
- package/dist/coValueCore/branching.d.ts +31 -9
- package/dist/coValueCore/branching.d.ts.map +1 -1
- package/dist/coValueCore/branching.js +50 -100
- package/dist/coValueCore/branching.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +12 -8
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +93 -23
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +4 -2
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +6 -4
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/coList.d.ts.map +1 -1
- package/dist/coValues/coList.js +10 -1
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.d.ts +2 -2
- package/dist/coValues/coMap.d.ts.map +1 -1
- package/dist/coValues/coMap.js +8 -8
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +14 -1
- package/dist/coValues/group.js.map +1 -1
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/crypto/PureJSCrypto.d.ts.map +1 -1
- package/dist/crypto/PureJSCrypto.js +14 -6
- package/dist/crypto/PureJSCrypto.js.map +1 -1
- package/dist/exports.d.ts +3 -2
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +2 -2
- package/dist/exports.js.map +1 -1
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +7 -2
- package/dist/localNode.js.map +1 -1
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/sync.d.ts +1 -3
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +8 -18
- package/dist/sync.js.map +1 -1
- package/dist/tests/branching.test.js +107 -9
- package/dist/tests/branching.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +45 -1
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/sync.content.test.d.ts +2 -0
- package/dist/tests/sync.content.test.d.ts.map +1 -0
- package/dist/tests/sync.content.test.js +120 -0
- package/dist/tests/sync.content.test.js.map +1 -0
- package/dist/tests/sync.load.test.js +2 -2
- package/dist/tests/sync.storage.test.js +1 -1
- package/dist/tests/sync.upload.test.js +2 -2
- package/package.json +2 -2
- package/src/coValueContentMessage.ts +13 -0
- package/src/coValueCore/SessionMap.ts +2 -2
- package/src/coValueCore/branching.ts +94 -149
- package/src/coValueCore/coValueCore.ts +121 -27
- package/src/coValueCore/verifiedState.ts +8 -0
- package/src/coValues/coList.ts +12 -1
- package/src/coValues/coMap.ts +10 -12
- package/src/coValues/group.ts +14 -1
- package/src/config.ts +9 -0
- package/src/crypto/PureJSCrypto.ts +25 -13
- package/src/exports.ts +7 -1
- package/src/localNode.ts +8 -2
- package/src/storage/storageAsync.ts +0 -1
- package/src/sync.ts +8 -32
- package/src/tests/branching.test.ts +158 -9
- package/src/tests/coValueCore.test.ts +62 -2
- package/src/tests/sync.content.test.ts +153 -0
- package/src/tests/sync.load.test.ts +2 -2
- package/src/tests/sync.storage.test.ts +1 -1
- package/src/tests/sync.upload.test.ts +2 -2
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, test } from "vitest";
|
|
1
|
+
import { assert, beforeEach, describe, expect, test } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
createTestNode,
|
|
4
4
|
setupTestNode,
|
|
5
5
|
loadCoValueOrFail,
|
|
6
6
|
} from "./testUtils.js";
|
|
7
7
|
import { expectList, expectMap, expectPlainText } from "../coValue.js";
|
|
8
|
+
import { RawCoMap } from "../exports.js";
|
|
8
9
|
|
|
9
10
|
let jazzCloud: ReturnType<typeof setupTestNode>;
|
|
10
11
|
|
|
@@ -94,7 +95,7 @@ describe("Branching Logic", () => {
|
|
|
94
95
|
const result = expectMap(branch.core.mergeBranch().getCurrentContent());
|
|
95
96
|
|
|
96
97
|
// Verify only one merge commit was created
|
|
97
|
-
expect(
|
|
98
|
+
expect(branch.core.mergeCommits.length).toBe(1);
|
|
98
99
|
|
|
99
100
|
// Verify source contains branch transactions
|
|
100
101
|
expect(result.get("key1")).toBe("branchValue1");
|
|
@@ -154,7 +155,7 @@ describe("Branching Logic", () => {
|
|
|
154
155
|
branch.core.mergeBranch();
|
|
155
156
|
|
|
156
157
|
// Verify two merge commits exist
|
|
157
|
-
expect(
|
|
158
|
+
expect(branch.core.mergeCommits.length).toBe(2);
|
|
158
159
|
|
|
159
160
|
// Verify both changes are now in original map
|
|
160
161
|
expect(originalMap.get("key1")).toBe("branchValue1");
|
|
@@ -210,6 +211,8 @@ describe("Branching Logic", () => {
|
|
|
210
211
|
.getCurrentContent(),
|
|
211
212
|
);
|
|
212
213
|
|
|
214
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
215
|
+
|
|
213
216
|
// Add different items to second branch
|
|
214
217
|
branch2.appendItems(["apples", "oranges", "carrots"]);
|
|
215
218
|
|
|
@@ -233,18 +236,20 @@ describe("Branching Logic", () => {
|
|
|
233
236
|
|
|
234
237
|
expect(list.toJSON()).toEqual([
|
|
235
238
|
"bread",
|
|
236
|
-
"cheese",
|
|
237
239
|
"apples",
|
|
238
240
|
"oranges",
|
|
239
241
|
"carrots",
|
|
240
242
|
"tomatoes",
|
|
241
243
|
"cucumber",
|
|
244
|
+
"cheese",
|
|
242
245
|
]);
|
|
243
246
|
});
|
|
244
247
|
|
|
245
|
-
test("should work with co.plainText when
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
+
test("should work with co.plainText when merging the same branch twice on different sessions", async () => {
|
|
249
|
+
const client = setupTestNode({
|
|
250
|
+
connected: true,
|
|
251
|
+
});
|
|
252
|
+
const group = client.node.createGroup();
|
|
248
253
|
const plainText = group.createPlainText();
|
|
249
254
|
|
|
250
255
|
plainText.insertAfter(0, "hello");
|
|
@@ -255,12 +260,28 @@ describe("Branching Logic", () => {
|
|
|
255
260
|
.getCurrentContent(),
|
|
256
261
|
);
|
|
257
262
|
|
|
263
|
+
branch.insertAfter("hello".length, " world");
|
|
264
|
+
|
|
265
|
+
const anotherSession = client.spawnNewSession();
|
|
266
|
+
|
|
267
|
+
const loadedBranch = await loadCoValueOrFail(
|
|
268
|
+
anotherSession.node,
|
|
269
|
+
branch.id,
|
|
270
|
+
);
|
|
271
|
+
assert(loadedBranch);
|
|
272
|
+
|
|
273
|
+
anotherSession.connectToSyncServer().peerState.gracefulShutdown();
|
|
274
|
+
|
|
258
275
|
// Add more items to the branch
|
|
259
|
-
|
|
276
|
+
loadedBranch.insertAfter("hello world".length, " people");
|
|
260
277
|
|
|
261
278
|
branch.core.mergeBranch();
|
|
279
|
+
const loadedBranchMergeResult = loadedBranch.core.mergeBranch();
|
|
262
280
|
|
|
263
|
-
|
|
281
|
+
anotherSession.connectToSyncServer();
|
|
282
|
+
await loadedBranchMergeResult.waitForSync();
|
|
283
|
+
|
|
284
|
+
expect(plainText.toString()).toEqual("hello world people");
|
|
264
285
|
});
|
|
265
286
|
});
|
|
266
287
|
|
|
@@ -527,4 +548,132 @@ describe("Branching Logic", () => {
|
|
|
527
548
|
expect(aliceBranch.get("bob")).toBe(true);
|
|
528
549
|
});
|
|
529
550
|
});
|
|
551
|
+
|
|
552
|
+
test("should alias the txID when a transaction comes from a merge", async () => {
|
|
553
|
+
const client = setupTestNode({
|
|
554
|
+
connected: true,
|
|
555
|
+
});
|
|
556
|
+
const group = client.node.createGroup();
|
|
557
|
+
const map = group.createMap();
|
|
558
|
+
|
|
559
|
+
map.set("key", "value");
|
|
560
|
+
|
|
561
|
+
const branch = map.core
|
|
562
|
+
.createBranch("feature-branch", group.id)
|
|
563
|
+
.getCurrentContent() as RawCoMap;
|
|
564
|
+
branch.set("branchKey", "branchValue");
|
|
565
|
+
|
|
566
|
+
const originalTxID = branch.core
|
|
567
|
+
.getValidTransactions({
|
|
568
|
+
skipBranchSource: true,
|
|
569
|
+
ignorePrivateTransactions: false,
|
|
570
|
+
})
|
|
571
|
+
.at(-1)?.txID;
|
|
572
|
+
|
|
573
|
+
branch.core.mergeBranch();
|
|
574
|
+
|
|
575
|
+
map.set("key2", "value2");
|
|
576
|
+
|
|
577
|
+
const validSortedTransactions = map.core.getValidSortedTransactions();
|
|
578
|
+
|
|
579
|
+
// Only the merged transaction should have the txId changed
|
|
580
|
+
const mergedTransactionIdx = validSortedTransactions.findIndex(
|
|
581
|
+
(tx) => tx.txID.branch,
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
expect(validSortedTransactions[mergedTransactionIdx - 1]?.txID.branch).toBe(
|
|
585
|
+
undefined,
|
|
586
|
+
);
|
|
587
|
+
expect(validSortedTransactions[mergedTransactionIdx]?.txID).toEqual(
|
|
588
|
+
originalTxID,
|
|
589
|
+
);
|
|
590
|
+
expect(validSortedTransactions[mergedTransactionIdx + 1]?.txID.branch).toBe(
|
|
591
|
+
undefined,
|
|
592
|
+
);
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
describe("hasBranch", () => {
|
|
596
|
+
test("should work when the branch owner is the source owner", () => {
|
|
597
|
+
const client = setupTestNode({
|
|
598
|
+
connected: true,
|
|
599
|
+
});
|
|
600
|
+
const group = client.node.createGroup();
|
|
601
|
+
const map = group.createMap();
|
|
602
|
+
|
|
603
|
+
map.set("key", "value");
|
|
604
|
+
|
|
605
|
+
const branch = map.core.createBranch("feature-branch", group.id);
|
|
606
|
+
|
|
607
|
+
expect(map.core.hasBranch("feature-branch")).toBe(true);
|
|
608
|
+
expect(map.core.hasBranch("feature-branch", group.id)).toBe(true);
|
|
609
|
+
expect(branch.hasBranch("feature-branch")).toBe(false);
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
test("should work when the branch onwer is implicit", () => {
|
|
613
|
+
const client = setupTestNode({
|
|
614
|
+
connected: true,
|
|
615
|
+
});
|
|
616
|
+
const group = client.node.createGroup();
|
|
617
|
+
const map = group.createMap();
|
|
618
|
+
|
|
619
|
+
map.set("key", "value");
|
|
620
|
+
|
|
621
|
+
const branch = map.core.createBranch("feature-branch");
|
|
622
|
+
|
|
623
|
+
expect(map.core.hasBranch("feature-branch")).toBe(true);
|
|
624
|
+
expect(map.core.hasBranch("feature-branch", group.id)).toBe(true);
|
|
625
|
+
expect(branch.hasBranch("feature-branch")).toBe(false);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
test("should return false for non-existent branch name", () => {
|
|
629
|
+
const client = setupTestNode({
|
|
630
|
+
connected: true,
|
|
631
|
+
});
|
|
632
|
+
const group = client.node.createGroup();
|
|
633
|
+
const map = group.createMap();
|
|
634
|
+
|
|
635
|
+
map.set("key", "value");
|
|
636
|
+
|
|
637
|
+
expect(map.core.hasBranch("non-existent-branch")).toBe(false);
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
test("should work with explicit ownerId parameter", () => {
|
|
641
|
+
const client = setupTestNode({
|
|
642
|
+
connected: true,
|
|
643
|
+
});
|
|
644
|
+
const group = client.node.createGroup();
|
|
645
|
+
const map = group.createMap();
|
|
646
|
+
|
|
647
|
+
map.set("key", "value");
|
|
648
|
+
|
|
649
|
+
const differentGroup = client.node.createGroup();
|
|
650
|
+
|
|
651
|
+
map.core.createBranch("feature-branch", differentGroup.id);
|
|
652
|
+
|
|
653
|
+
// Test with explicit ownerId
|
|
654
|
+
expect(map.core.hasBranch("feature-branch", differentGroup.id)).toBe(
|
|
655
|
+
true,
|
|
656
|
+
);
|
|
657
|
+
expect(map.core.hasBranch("feature-branch")).toBe(false);
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
test("should work when the transactions have not been parsed yet", async () => {
|
|
661
|
+
const client = setupTestNode({
|
|
662
|
+
connected: true,
|
|
663
|
+
});
|
|
664
|
+
const group = client.node.createGroup();
|
|
665
|
+
const map = group.createMap();
|
|
666
|
+
|
|
667
|
+
map.set("key", "value");
|
|
668
|
+
|
|
669
|
+
map.core.createBranch("feature-branch", group.id);
|
|
670
|
+
|
|
671
|
+
await map.core.waitForSync();
|
|
672
|
+
|
|
673
|
+
const newSession = client.spawnNewSession();
|
|
674
|
+
const loadedMapCore = await newSession.node.loadCoValueCore(map.core.id);
|
|
675
|
+
|
|
676
|
+
expect(loadedMapCore.hasBranch("feature-branch", group.id)).toBe(true);
|
|
677
|
+
});
|
|
678
|
+
});
|
|
530
679
|
});
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
vi,
|
|
9
9
|
} from "vitest";
|
|
10
10
|
import { CoValueCore } from "../coValueCore/coValueCore.js";
|
|
11
|
-
import { Transaction } from "../coValueCore/verifiedState.js";
|
|
12
11
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
13
12
|
import { stableStringify } from "../jsonStringify.js";
|
|
14
13
|
import { LocalNode } from "../localNode.js";
|
|
@@ -24,7 +23,7 @@ import {
|
|
|
24
23
|
tearDownTestMetricReader,
|
|
25
24
|
} from "./testUtils.js";
|
|
26
25
|
import { CO_VALUE_PRIORITY } from "../priority.js";
|
|
27
|
-
import {
|
|
26
|
+
import { setMaxTxSizeBytes } from "../config.js";
|
|
28
27
|
|
|
29
28
|
const Crypto = await WasmCrypto.create();
|
|
30
29
|
|
|
@@ -57,6 +56,7 @@ test("transactions with wrong signature are rejected", () => {
|
|
|
57
56
|
node.getCurrentAgent(),
|
|
58
57
|
[{ hello: "world" }],
|
|
59
58
|
undefined,
|
|
59
|
+
Date.now(),
|
|
60
60
|
);
|
|
61
61
|
|
|
62
62
|
transaction.madeAt = Date.now() + 1000;
|
|
@@ -87,6 +87,66 @@ test("transactions with wrong signature are rejected", () => {
|
|
|
87
87
|
expect(newEntry.getValidSortedTransactions().length).toBe(0);
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
+
describe("transactions that exceed the byte size limit are rejected", () => {
|
|
91
|
+
beforeEach(() => {
|
|
92
|
+
setMaxTxSizeBytes(1 * 1024);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
afterEach(() => {
|
|
96
|
+
setMaxTxSizeBytes(1 * 1024 * 1024);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("makeTransaction should throw error when transaction exceeds byte size limit", () => {
|
|
100
|
+
const [agent, sessionID] = randomAgentAndSessionID();
|
|
101
|
+
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
|
|
102
|
+
|
|
103
|
+
const coValue = node.createCoValue({
|
|
104
|
+
type: "costream",
|
|
105
|
+
ruleset: { type: "unsafeAllowAll" },
|
|
106
|
+
meta: null,
|
|
107
|
+
...Crypto.createdNowUnique(),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const largeBinaryData = "x".repeat(1024 + 100);
|
|
111
|
+
|
|
112
|
+
expect(() => {
|
|
113
|
+
coValue.makeTransaction(
|
|
114
|
+
[
|
|
115
|
+
{
|
|
116
|
+
data: largeBinaryData,
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
"trusting",
|
|
120
|
+
);
|
|
121
|
+
}).toThrow(/Transaction is too large to be synced/);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("makeTransaction should work for transactions under byte size limit", () => {
|
|
125
|
+
const [agent, sessionID] = randomAgentAndSessionID();
|
|
126
|
+
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
|
|
127
|
+
|
|
128
|
+
const coValue = node.createCoValue({
|
|
129
|
+
type: "costream",
|
|
130
|
+
ruleset: { type: "unsafeAllowAll" },
|
|
131
|
+
meta: null,
|
|
132
|
+
...Crypto.createdNowUnique(),
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const smallData = "Hello, world!";
|
|
136
|
+
|
|
137
|
+
const success = coValue.makeTransaction(
|
|
138
|
+
[
|
|
139
|
+
{
|
|
140
|
+
data: smallData,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
"trusting",
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
expect(success).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
90
150
|
test("New transactions in a group correctly update owned values, including subscriptions", async () => {
|
|
91
151
|
const [agent, sessionID] = randomAgentAndSessionID();
|
|
92
152
|
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { SyncMessagesLog, TEST_NODE_CONFIG, setupTestNode } from "./testUtils";
|
|
4
|
+
|
|
5
|
+
// We want to simulate a real world communication that happens asynchronously
|
|
6
|
+
TEST_NODE_CONFIG.withAsyncPeers = true;
|
|
7
|
+
|
|
8
|
+
describe("handling content messages", () => {
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
SyncMessagesLog.clear();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("dependencies are included when syncing new content to clients", async () => {
|
|
14
|
+
/*
|
|
15
|
+
* Initial Setup:
|
|
16
|
+
* core <-- edge <-- client1
|
|
17
|
+
*/
|
|
18
|
+
const core = setupTestNode();
|
|
19
|
+
|
|
20
|
+
const edge = setupTestNode();
|
|
21
|
+
edge.connectToSyncServer({
|
|
22
|
+
ourName: "edge",
|
|
23
|
+
syncServerName: "core",
|
|
24
|
+
syncServer: core.node,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const client1 = setupTestNode();
|
|
28
|
+
client1.connectToSyncServer({
|
|
29
|
+
ourName: "client1",
|
|
30
|
+
syncServerName: "edge",
|
|
31
|
+
syncServer: edge.node,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Create a map with a dependency on the client.
|
|
35
|
+
// Everythig will sync all the way back to core.
|
|
36
|
+
const group = client1.node.createGroup();
|
|
37
|
+
const map = group.createMap();
|
|
38
|
+
map.set("hello", "world", "trusting");
|
|
39
|
+
await map.core.waitForSync();
|
|
40
|
+
|
|
41
|
+
/*
|
|
42
|
+
* Add another client:
|
|
43
|
+
*
|
|
44
|
+
* |-- client1
|
|
45
|
+
* core <-- edge <--|
|
|
46
|
+
* |-- client2
|
|
47
|
+
*
|
|
48
|
+
*/
|
|
49
|
+
const client2 = setupTestNode();
|
|
50
|
+
const { peerStateOnServer: client2PeerStateOnEdge } =
|
|
51
|
+
client2.connectToSyncServer({
|
|
52
|
+
ourName: "client2",
|
|
53
|
+
syncServerName: "edge",
|
|
54
|
+
syncServer: edge.node,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
client2PeerStateOnEdge.setOptimisticKnownState(map.core.id, {
|
|
58
|
+
id: map.core.id,
|
|
59
|
+
header: false,
|
|
60
|
+
sessions: {},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Update the map on client1.
|
|
64
|
+
// This should sync the map AND its dependencies to the new client.
|
|
65
|
+
map.set("hello2", "world2", "trusting");
|
|
66
|
+
await map.core.waitForSync();
|
|
67
|
+
|
|
68
|
+
const syncMessages = SyncMessagesLog.getMessages({
|
|
69
|
+
Group: group.core,
|
|
70
|
+
Map: map.core,
|
|
71
|
+
});
|
|
72
|
+
expect(
|
|
73
|
+
syncMessages.some((msg) =>
|
|
74
|
+
msg.startsWith("edge -> client2 | CONTENT Map"),
|
|
75
|
+
),
|
|
76
|
+
).toBe(true);
|
|
77
|
+
expect(
|
|
78
|
+
syncMessages.some((msg) =>
|
|
79
|
+
msg.startsWith("edge -> client2 | CONTENT Group"),
|
|
80
|
+
),
|
|
81
|
+
).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("dependencies are excluded when syncing new content to servers", async () => {
|
|
85
|
+
/*
|
|
86
|
+
* Initial Setup:
|
|
87
|
+
* core1 <-- edge <-- client
|
|
88
|
+
*/
|
|
89
|
+
const core1 = setupTestNode();
|
|
90
|
+
|
|
91
|
+
const edge = setupTestNode();
|
|
92
|
+
edge.connectToSyncServer({
|
|
93
|
+
ourName: "edge",
|
|
94
|
+
syncServerName: "core1",
|
|
95
|
+
syncServer: core1.node,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const client = setupTestNode();
|
|
99
|
+
client.connectToSyncServer({
|
|
100
|
+
ourName: "client",
|
|
101
|
+
syncServerName: "edge",
|
|
102
|
+
syncServer: edge.node,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Create a map with a dependency on the client.
|
|
106
|
+
// Everythig will sync all the way back to core1.
|
|
107
|
+
const group = client.node.createGroup();
|
|
108
|
+
const map = group.createMap();
|
|
109
|
+
map.set("hello", "world", "trusting");
|
|
110
|
+
await map.core.waitForSync();
|
|
111
|
+
|
|
112
|
+
/*
|
|
113
|
+
* Add another core:
|
|
114
|
+
*
|
|
115
|
+
* core1 <--
|
|
116
|
+
* |
|
|
117
|
+
* |-- edge <-- client
|
|
118
|
+
* |
|
|
119
|
+
* core2 <--
|
|
120
|
+
*/
|
|
121
|
+
const core2 = setupTestNode();
|
|
122
|
+
const { peerState: core2PeerStateOnEdge } = edge.connectToSyncServer({
|
|
123
|
+
ourName: "edge",
|
|
124
|
+
syncServerName: "core2",
|
|
125
|
+
syncServer: core2.node,
|
|
126
|
+
skipReconciliation: true,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
core2PeerStateOnEdge.setOptimisticKnownState(map.core.id, {
|
|
130
|
+
id: map.core.id,
|
|
131
|
+
header: false,
|
|
132
|
+
sessions: {},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Update the map on the client.
|
|
136
|
+
// This should sync ONLY the map back to both cores.
|
|
137
|
+
map.set("hello2", "world2", "trusting");
|
|
138
|
+
await map.core.waitForSync();
|
|
139
|
+
|
|
140
|
+
const syncMessages = SyncMessagesLog.getMessages({
|
|
141
|
+
Group: group.core,
|
|
142
|
+
Map: map.core,
|
|
143
|
+
});
|
|
144
|
+
expect(
|
|
145
|
+
syncMessages.some((msg) => msg.startsWith("edge -> core2 | CONTENT Map")),
|
|
146
|
+
).toBe(true);
|
|
147
|
+
expect(
|
|
148
|
+
syncMessages.some((msg) =>
|
|
149
|
+
msg.startsWith("edge -> core2 | CONTENT Group"),
|
|
150
|
+
),
|
|
151
|
+
).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -171,10 +171,10 @@ describe("loading coValues from server", () => {
|
|
|
171
171
|
[
|
|
172
172
|
"client -> server | LOAD Branch sessions: empty",
|
|
173
173
|
"server -> client | CONTENT Group header: true new: After: 0 New: 5",
|
|
174
|
-
"server -> client | CONTENT Map header: true new: After: 0 New:
|
|
174
|
+
"server -> client | CONTENT Map header: true new: After: 0 New: 3",
|
|
175
175
|
"server -> client | CONTENT Branch header: true new: After: 0 New: 2",
|
|
176
176
|
"client -> server | KNOWN Group sessions: header/5",
|
|
177
|
-
"client -> server | KNOWN Map sessions: header/
|
|
177
|
+
"client -> server | KNOWN Map sessions: header/3",
|
|
178
178
|
"client -> server | KNOWN Branch sessions: header/2",
|
|
179
179
|
]
|
|
180
180
|
`);
|
|
@@ -238,7 +238,7 @@ describe("client with storage syncs with server", () => {
|
|
|
238
238
|
[
|
|
239
239
|
"client -> storage | LOAD Branch sessions: empty",
|
|
240
240
|
"storage -> client | CONTENT Group header: true new: After: 0 New: 3",
|
|
241
|
-
"storage -> client | CONTENT Map header: true new: After: 0 New:
|
|
241
|
+
"storage -> client | CONTENT Map header: true new: After: 0 New: 3",
|
|
242
242
|
"storage -> client | CONTENT Branch header: true new: After: 0 New: 2",
|
|
243
243
|
]
|
|
244
244
|
`);
|
|
@@ -92,11 +92,11 @@ describe("client to server upload", () => {
|
|
|
92
92
|
"server -> client | CONTENT Map header: true new: After: 0 New: 2",
|
|
93
93
|
"client -> server | KNOWN Group sessions: header/5",
|
|
94
94
|
"client -> server | KNOWN Map sessions: header/2",
|
|
95
|
-
"client -> server | LOAD Branch sessions: empty",
|
|
96
|
-
"server -> client | KNOWN Branch sessions: empty",
|
|
97
95
|
"client -> server | CONTENT Branch header: true new: After: 0 New: 1",
|
|
96
|
+
"client -> server | CONTENT Map header: false new: After: 0 New: 1",
|
|
98
97
|
"client -> server | CONTENT Branch header: false new: After: 1 New: 1",
|
|
99
98
|
"server -> client | KNOWN Branch sessions: header/1",
|
|
99
|
+
"server -> client | KNOWN Map sessions: header/3",
|
|
100
100
|
"server -> client | KNOWN Branch sessions: header/2",
|
|
101
101
|
]
|
|
102
102
|
`);
|