cojson 0.18.32 → 0.18.34
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 +18 -0
- package/dist/SyncStateManager.d.ts.map +1 -1
- package/dist/SyncStateManager.js +2 -2
- package/dist/SyncStateManager.js.map +1 -1
- package/dist/coValueCore/SessionMap.d.ts +1 -0
- package/dist/coValueCore/SessionMap.d.ts.map +1 -1
- package/dist/coValueCore/SessionMap.js +22 -12
- package/dist/coValueCore/SessionMap.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +14 -9
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +65 -51
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +5 -3
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +93 -76
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/group.d.ts +1 -0
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +24 -4
- package/dist/coValues/group.js.map +1 -1
- package/dist/knownState.d.ts +9 -1
- package/dist/knownState.d.ts.map +1 -1
- package/dist/knownState.js +29 -3
- package/dist/knownState.js.map +1 -1
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +3 -3
- package/dist/localNode.js.map +1 -1
- package/dist/queue/LocalTransactionsSyncQueue.d.ts +10 -9
- package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -1
- package/dist/queue/LocalTransactionsSyncQueue.js +53 -32
- package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -1
- package/dist/storage/knownState.js +2 -2
- package/dist/storage/knownState.js.map +1 -1
- package/dist/sync.d.ts +1 -2
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +8 -3
- package/dist/sync.js.map +1 -1
- package/dist/tests/PureJSCrypto.test.js +1 -1
- package/dist/tests/PureJSCrypto.test.js.map +1 -1
- package/dist/tests/StorageApiAsync.test.js +11 -11
- package/dist/tests/StorageApiAsync.test.js.map +1 -1
- package/dist/tests/StorageApiSync.test.js +3 -3
- package/dist/tests/StorageApiSync.test.js.map +1 -1
- package/dist/tests/WasmCrypto.test.js +1 -1
- package/dist/tests/WasmCrypto.test.js.map +1 -1
- package/dist/tests/coPlainText.test.js +13 -14
- package/dist/tests/coPlainText.test.js.map +1 -1
- package/dist/tests/coStream.test.js +12 -12
- package/dist/tests/coStream.test.js.map +1 -1
- package/dist/tests/coValueCore.isCompletelyDownloaded.test.d.ts +2 -0
- package/dist/tests/coValueCore.isCompletelyDownloaded.test.d.ts.map +1 -0
- package/dist/tests/coValueCore.isCompletelyDownloaded.test.js +422 -0
- package/dist/tests/coValueCore.isCompletelyDownloaded.test.js.map +1 -0
- package/dist/tests/coValueCore.isStreaming.test.d.ts +2 -0
- package/dist/tests/coValueCore.isStreaming.test.d.ts.map +1 -0
- package/dist/tests/coValueCore.isStreaming.test.js +232 -0
- package/dist/tests/coValueCore.isStreaming.test.js.map +1 -0
- package/dist/tests/coValueCore.newContentSince.test.d.ts +2 -0
- package/dist/tests/coValueCore.newContentSince.test.d.ts.map +1 -0
- package/dist/tests/coValueCore.newContentSince.test.js +808 -0
- package/dist/tests/coValueCore.newContentSince.test.js.map +1 -0
- package/dist/tests/coreWasm.test.js +2 -2
- package/dist/tests/coreWasm.test.js.map +1 -1
- package/dist/tests/group.childKeyRotation.test.d.ts +2 -0
- package/dist/tests/group.childKeyRotation.test.d.ts.map +1 -0
- package/dist/tests/group.childKeyRotation.test.js +261 -0
- package/dist/tests/group.childKeyRotation.test.js.map +1 -0
- package/dist/tests/group.removeMember.test.js +1 -114
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/knownState.test.js +83 -11
- package/dist/tests/knownState.test.js.map +1 -1
- package/dist/tests/sync.auth.test.js +6 -6
- package/dist/tests/sync.load.test.js +67 -4
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +41 -40
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.peerReconciliation.test.js +1 -1
- package/dist/tests/sync.storage.test.js +29 -28
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.js +26 -25
- package/dist/tests/sync.storageAsync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js +96 -40
- package/dist/tests/sync.upload.test.js.map +1 -1
- package/dist/tests/testUtils.d.ts +12 -8
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +39 -8
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +3 -3
- package/src/SyncStateManager.ts +5 -2
- package/src/coValueCore/SessionMap.ts +39 -12
- package/src/coValueCore/coValueCore.ts +81 -66
- package/src/coValueCore/verifiedState.ts +139 -109
- package/src/coValues/group.ts +27 -4
- package/src/knownState.ts +49 -5
- package/src/localNode.ts +7 -5
- package/src/queue/LocalTransactionsSyncQueue.ts +77 -68
- package/src/storage/knownState.ts +2 -2
- package/src/sync.ts +7 -3
- package/src/tests/PureJSCrypto.test.ts +1 -2
- package/src/tests/StorageApiAsync.test.ts +11 -11
- package/src/tests/StorageApiSync.test.ts +3 -3
- package/src/tests/WasmCrypto.test.ts +1 -2
- package/src/tests/coPlainText.test.ts +13 -14
- package/src/tests/coStream.test.ts +12 -12
- package/src/tests/coValueCore.isCompletelyDownloaded.test.ts +590 -0
- package/src/tests/coValueCore.isStreaming.test.ts +353 -0
- package/src/tests/coValueCore.newContentSince.test.ts +966 -0
- package/src/tests/coreWasm.test.ts +2 -2
- package/src/tests/group.childKeyRotation.test.ts +431 -0
- package/src/tests/group.removeMember.test.ts +1 -184
- package/src/tests/knownState.test.ts +108 -11
- package/src/tests/sync.auth.test.ts +6 -6
- package/src/tests/sync.load.test.ts +79 -4
- package/src/tests/sync.mesh.test.ts +41 -40
- package/src/tests/sync.peerReconciliation.test.ts +1 -1
- package/src/tests/sync.storage.test.ts +29 -28
- package/src/tests/sync.storageAsync.test.ts +26 -25
- package/src/tests/sync.upload.test.ts +106 -40
- package/src/tests/testUtils.ts +43 -9
|
@@ -0,0 +1,808 @@
|
|
|
1
|
+
import { assert, beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
import { loadCoValueOrFail, setupTestNode } from "./testUtils.js";
|
|
3
|
+
import { CO_VALUE_PRIORITY } from "../priority.js";
|
|
4
|
+
import { emptyKnownState } from "../exports.js";
|
|
5
|
+
import { addTransactionToContentMessage } from "../coValueContentMessage.js";
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
setupTestNode({ isSyncServer: true });
|
|
8
|
+
});
|
|
9
|
+
// Simplify the content message to a value that can be used for snapshots
|
|
10
|
+
function simplifyContentMessage(message, sessionMapping) {
|
|
11
|
+
const newContent = Object.entries(message.new).map(([sessionID, content]) => [
|
|
12
|
+
sessionMapping[sessionID],
|
|
13
|
+
{
|
|
14
|
+
lastSignature: content.lastSignature ? "signature" : undefined,
|
|
15
|
+
newTransactions: `${content.newTransactions.length} transactions after ${content.after}`,
|
|
16
|
+
},
|
|
17
|
+
]);
|
|
18
|
+
return {
|
|
19
|
+
action: message.action,
|
|
20
|
+
id: message.id ? "id" : undefined,
|
|
21
|
+
header: message.header ? "header" : undefined,
|
|
22
|
+
priority: message.priority,
|
|
23
|
+
new: Object.fromEntries(newContent),
|
|
24
|
+
expectContentUntil: message.expectContentUntil
|
|
25
|
+
? Object.fromEntries(Object.entries(message.expectContentUntil).map(([sessionID, after]) => [sessionMapping[sessionID], after]))
|
|
26
|
+
: undefined,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function simplifyContentMessages(messages, sessionMapping) {
|
|
30
|
+
if (!messages) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return messages.map((message) => simplifyContentMessage(message, sessionMapping));
|
|
34
|
+
}
|
|
35
|
+
describe("newContentSince", () => {
|
|
36
|
+
test("should return an empty content with the header when both the coValue and knownState are empty", () => {
|
|
37
|
+
const client = setupTestNode();
|
|
38
|
+
const group = client.node.createGroup();
|
|
39
|
+
const map = group.createMap();
|
|
40
|
+
expect(map.core.newContentSince(emptyKnownState(map.core.id))).toEqual([
|
|
41
|
+
{
|
|
42
|
+
action: "content",
|
|
43
|
+
id: map.core.id,
|
|
44
|
+
header: map.core.verified.header,
|
|
45
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
46
|
+
new: {},
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
});
|
|
50
|
+
test("should return an empty content with the header when the coValue is empty and knownState is undefined", () => {
|
|
51
|
+
const client = setupTestNode();
|
|
52
|
+
const group = client.node.createGroup();
|
|
53
|
+
const map = group.createMap();
|
|
54
|
+
expect(map.core.newContentSince(emptyKnownState(map.core.id))).toEqual([
|
|
55
|
+
{
|
|
56
|
+
action: "content",
|
|
57
|
+
id: map.core.id,
|
|
58
|
+
header: map.core.verified.header,
|
|
59
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
60
|
+
new: {},
|
|
61
|
+
},
|
|
62
|
+
]);
|
|
63
|
+
});
|
|
64
|
+
test("should return the content when the coValue has new content and knownState is undefined", () => {
|
|
65
|
+
const client = setupTestNode();
|
|
66
|
+
const group = client.node.createGroup();
|
|
67
|
+
const map = group.createMap();
|
|
68
|
+
map.set("hello", "world", "trusting");
|
|
69
|
+
const content = map.core.newContentSince(undefined);
|
|
70
|
+
const sessionMapping = {
|
|
71
|
+
[client.node.currentSessionID]: "alice",
|
|
72
|
+
};
|
|
73
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
74
|
+
[
|
|
75
|
+
{
|
|
76
|
+
"action": "content",
|
|
77
|
+
"expectContentUntil": undefined,
|
|
78
|
+
"header": "header",
|
|
79
|
+
"id": "id",
|
|
80
|
+
"new": {
|
|
81
|
+
"alice": {
|
|
82
|
+
"lastSignature": "signature",
|
|
83
|
+
"newTransactions": "1 transactions after 0",
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
"priority": 3,
|
|
87
|
+
},
|
|
88
|
+
]
|
|
89
|
+
`);
|
|
90
|
+
});
|
|
91
|
+
test("should return the content when the coValue has new content from multiple sessions and knownState is undefined", async () => {
|
|
92
|
+
const client = setupTestNode({
|
|
93
|
+
connected: true,
|
|
94
|
+
});
|
|
95
|
+
const group = client.node.createGroup();
|
|
96
|
+
const map = group.createMap();
|
|
97
|
+
map.set("hello", "world", "trusting");
|
|
98
|
+
const newSession = client.spawnNewSession();
|
|
99
|
+
const mapInNewSession = await loadCoValueOrFail(newSession.node, map.id);
|
|
100
|
+
mapInNewSession.set("hello", "world2", "trusting");
|
|
101
|
+
const content = mapInNewSession.core.newContentSince(undefined);
|
|
102
|
+
const sessionMapping = {
|
|
103
|
+
[client.node.currentSessionID]: "alice",
|
|
104
|
+
[newSession.node.currentSessionID]: "bob",
|
|
105
|
+
};
|
|
106
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
107
|
+
[
|
|
108
|
+
{
|
|
109
|
+
"action": "content",
|
|
110
|
+
"expectContentUntil": undefined,
|
|
111
|
+
"header": "header",
|
|
112
|
+
"id": "id",
|
|
113
|
+
"new": {
|
|
114
|
+
"alice": {
|
|
115
|
+
"lastSignature": "signature",
|
|
116
|
+
"newTransactions": "1 transactions after 0",
|
|
117
|
+
},
|
|
118
|
+
"bob": {
|
|
119
|
+
"lastSignature": "signature",
|
|
120
|
+
"newTransactions": "1 transactions after 0",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
"priority": 3,
|
|
124
|
+
},
|
|
125
|
+
]
|
|
126
|
+
`);
|
|
127
|
+
});
|
|
128
|
+
describe("large session logs", () => {
|
|
129
|
+
test("one large session log that requires multiple content pieces", () => {
|
|
130
|
+
const client = setupTestNode();
|
|
131
|
+
const group = client.node.createGroup();
|
|
132
|
+
const map = group.createMap();
|
|
133
|
+
const dataSize = 1 * 1024 * 100;
|
|
134
|
+
const chunkSize = 1024; // 1KB chunks
|
|
135
|
+
const chunks = dataSize / chunkSize;
|
|
136
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
137
|
+
for (let i = 0; i < chunks; i++) {
|
|
138
|
+
const key = `key${i}`;
|
|
139
|
+
map.set(key, value, "trusting");
|
|
140
|
+
}
|
|
141
|
+
const content = map.core.newContentSince(undefined);
|
|
142
|
+
const sessionMapping = {
|
|
143
|
+
[client.node.currentSessionID]: "alice",
|
|
144
|
+
};
|
|
145
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
146
|
+
[
|
|
147
|
+
{
|
|
148
|
+
"action": "content",
|
|
149
|
+
"expectContentUntil": {
|
|
150
|
+
"alice": 100,
|
|
151
|
+
},
|
|
152
|
+
"header": "header",
|
|
153
|
+
"id": "id",
|
|
154
|
+
"new": {
|
|
155
|
+
"alice": {
|
|
156
|
+
"lastSignature": "signature",
|
|
157
|
+
"newTransactions": "73 transactions after 0",
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
"priority": 3,
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"action": "content",
|
|
164
|
+
"expectContentUntil": undefined,
|
|
165
|
+
"header": undefined,
|
|
166
|
+
"id": "id",
|
|
167
|
+
"new": {
|
|
168
|
+
"alice": {
|
|
169
|
+
"lastSignature": "signature",
|
|
170
|
+
"newTransactions": "27 transactions after 73",
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
"priority": 3,
|
|
174
|
+
},
|
|
175
|
+
]
|
|
176
|
+
`);
|
|
177
|
+
});
|
|
178
|
+
test("one large session log that requires multiple content pieces and one small", async () => {
|
|
179
|
+
const client = setupTestNode({
|
|
180
|
+
connected: true,
|
|
181
|
+
});
|
|
182
|
+
const group = client.node.createGroup();
|
|
183
|
+
const map = group.createMap();
|
|
184
|
+
// Generate a large amount of data (about 1MB)
|
|
185
|
+
const dataSize = 1 * 1024 * 100;
|
|
186
|
+
const chunkSize = 1024; // 1KB chunks
|
|
187
|
+
const chunks = dataSize / chunkSize;
|
|
188
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
189
|
+
for (let i = 0; i < chunks; i++) {
|
|
190
|
+
const key = `key${i}`;
|
|
191
|
+
map.set(key, value, "trusting");
|
|
192
|
+
}
|
|
193
|
+
// Add a small session
|
|
194
|
+
const newSession = client.spawnNewSession();
|
|
195
|
+
const mapInNewSession = await loadCoValueOrFail(newSession.node, map.id);
|
|
196
|
+
mapInNewSession.set("small", "value", "trusting");
|
|
197
|
+
const content = mapInNewSession.core.newContentSince(undefined);
|
|
198
|
+
const sessionMapping = {
|
|
199
|
+
[client.node.currentSessionID]: "alice",
|
|
200
|
+
[newSession.node.currentSessionID]: "bob",
|
|
201
|
+
};
|
|
202
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
203
|
+
[
|
|
204
|
+
{
|
|
205
|
+
"action": "content",
|
|
206
|
+
"expectContentUntil": {
|
|
207
|
+
"alice": 100,
|
|
208
|
+
"bob": 1,
|
|
209
|
+
},
|
|
210
|
+
"header": "header",
|
|
211
|
+
"id": "id",
|
|
212
|
+
"new": {
|
|
213
|
+
"alice": {
|
|
214
|
+
"lastSignature": "signature",
|
|
215
|
+
"newTransactions": "73 transactions after 0",
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
"priority": 3,
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"action": "content",
|
|
222
|
+
"expectContentUntil": undefined,
|
|
223
|
+
"header": undefined,
|
|
224
|
+
"id": "id",
|
|
225
|
+
"new": {
|
|
226
|
+
"alice": {
|
|
227
|
+
"lastSignature": "signature",
|
|
228
|
+
"newTransactions": "27 transactions after 73",
|
|
229
|
+
},
|
|
230
|
+
"bob": {
|
|
231
|
+
"lastSignature": "signature",
|
|
232
|
+
"newTransactions": "1 transactions after 0",
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
"priority": 3,
|
|
236
|
+
},
|
|
237
|
+
]
|
|
238
|
+
`);
|
|
239
|
+
});
|
|
240
|
+
test("two large session logs", async () => {
|
|
241
|
+
const client = setupTestNode({
|
|
242
|
+
connected: true,
|
|
243
|
+
});
|
|
244
|
+
const group = client.node.createGroup();
|
|
245
|
+
const map = group.createMap();
|
|
246
|
+
// Generate a large amount of data in first session (about 1MB)
|
|
247
|
+
const dataSize = 1 * 1024 * 100;
|
|
248
|
+
const chunkSize = 1024; // 1KB chunks
|
|
249
|
+
const chunks = dataSize / chunkSize;
|
|
250
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
251
|
+
for (let i = 0; i < chunks; i++) {
|
|
252
|
+
const key = `key1_${i}`;
|
|
253
|
+
map.set(key, value, "trusting");
|
|
254
|
+
}
|
|
255
|
+
// Add second large session
|
|
256
|
+
const newSession = client.spawnNewSession();
|
|
257
|
+
const mapInNewSession = await loadCoValueOrFail(newSession.node, map.id);
|
|
258
|
+
for (let i = 0; i < chunks; i++) {
|
|
259
|
+
const key = `key2_${i}`;
|
|
260
|
+
mapInNewSession.set(key, value, "trusting");
|
|
261
|
+
}
|
|
262
|
+
const content = mapInNewSession.core.newContentSince(undefined);
|
|
263
|
+
const sessionMapping = {
|
|
264
|
+
[client.node.currentSessionID]: "alice",
|
|
265
|
+
[newSession.node.currentSessionID]: "bob",
|
|
266
|
+
};
|
|
267
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
268
|
+
[
|
|
269
|
+
{
|
|
270
|
+
"action": "content",
|
|
271
|
+
"expectContentUntil": {
|
|
272
|
+
"alice": 100,
|
|
273
|
+
"bob": 100,
|
|
274
|
+
},
|
|
275
|
+
"header": "header",
|
|
276
|
+
"id": "id",
|
|
277
|
+
"new": {
|
|
278
|
+
"alice": {
|
|
279
|
+
"lastSignature": "signature",
|
|
280
|
+
"newTransactions": "73 transactions after 0",
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
"priority": 3,
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"action": "content",
|
|
287
|
+
"expectContentUntil": undefined,
|
|
288
|
+
"header": undefined,
|
|
289
|
+
"id": "id",
|
|
290
|
+
"new": {
|
|
291
|
+
"bob": {
|
|
292
|
+
"lastSignature": "signature",
|
|
293
|
+
"newTransactions": "73 transactions after 0",
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
"priority": 3,
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"action": "content",
|
|
300
|
+
"expectContentUntil": undefined,
|
|
301
|
+
"header": undefined,
|
|
302
|
+
"id": "id",
|
|
303
|
+
"new": {
|
|
304
|
+
"alice": {
|
|
305
|
+
"lastSignature": "signature",
|
|
306
|
+
"newTransactions": "27 transactions after 73",
|
|
307
|
+
},
|
|
308
|
+
"bob": {
|
|
309
|
+
"lastSignature": "signature",
|
|
310
|
+
"newTransactions": "27 transactions after 73",
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
"priority": 3,
|
|
314
|
+
},
|
|
315
|
+
]
|
|
316
|
+
`);
|
|
317
|
+
});
|
|
318
|
+
test("one large, one small, and one large session log", async () => {
|
|
319
|
+
const client = setupTestNode({
|
|
320
|
+
connected: true,
|
|
321
|
+
});
|
|
322
|
+
const group = client.node.createGroup();
|
|
323
|
+
const map = group.createMap();
|
|
324
|
+
// Generate first large session (about 1MB)
|
|
325
|
+
const dataSize = 1 * 1024 * 100;
|
|
326
|
+
const chunkSize = 1024; // 1KB chunks
|
|
327
|
+
const chunks = dataSize / chunkSize;
|
|
328
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
329
|
+
for (let i = 0; i < chunks; i++) {
|
|
330
|
+
const key = `key1_${i}`;
|
|
331
|
+
map.set(key, value, "trusting");
|
|
332
|
+
}
|
|
333
|
+
// Add small session
|
|
334
|
+
const session2 = client.spawnNewSession();
|
|
335
|
+
const mapInSession2 = await loadCoValueOrFail(session2.node, map.id);
|
|
336
|
+
mapInSession2.set("small", "value", "trusting");
|
|
337
|
+
// Add third large session
|
|
338
|
+
const session3 = client.spawnNewSession();
|
|
339
|
+
const mapInSession3 = await loadCoValueOrFail(session3.node, map.id);
|
|
340
|
+
for (let i = 0; i < chunks; i++) {
|
|
341
|
+
const key = `key3_${i}`;
|
|
342
|
+
mapInSession3.set(key, value, "trusting");
|
|
343
|
+
}
|
|
344
|
+
const content = mapInSession3.core.newContentSince(undefined);
|
|
345
|
+
const sessionMapping = {
|
|
346
|
+
[client.node.currentSessionID]: "alice",
|
|
347
|
+
[session2.node.currentSessionID]: "bob",
|
|
348
|
+
[session3.node.currentSessionID]: "charlie",
|
|
349
|
+
};
|
|
350
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
351
|
+
[
|
|
352
|
+
{
|
|
353
|
+
"action": "content",
|
|
354
|
+
"expectContentUntil": {
|
|
355
|
+
"alice": 100,
|
|
356
|
+
"bob": 1,
|
|
357
|
+
"charlie": 100,
|
|
358
|
+
},
|
|
359
|
+
"header": "header",
|
|
360
|
+
"id": "id",
|
|
361
|
+
"new": {
|
|
362
|
+
"alice": {
|
|
363
|
+
"lastSignature": "signature",
|
|
364
|
+
"newTransactions": "73 transactions after 0",
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
"priority": 3,
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
"action": "content",
|
|
371
|
+
"expectContentUntil": undefined,
|
|
372
|
+
"header": undefined,
|
|
373
|
+
"id": "id",
|
|
374
|
+
"new": {
|
|
375
|
+
"charlie": {
|
|
376
|
+
"lastSignature": "signature",
|
|
377
|
+
"newTransactions": "73 transactions after 0",
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
"priority": 3,
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"action": "content",
|
|
384
|
+
"expectContentUntil": undefined,
|
|
385
|
+
"header": undefined,
|
|
386
|
+
"id": "id",
|
|
387
|
+
"new": {
|
|
388
|
+
"alice": {
|
|
389
|
+
"lastSignature": "signature",
|
|
390
|
+
"newTransactions": "27 transactions after 73",
|
|
391
|
+
},
|
|
392
|
+
"bob": {
|
|
393
|
+
"lastSignature": "signature",
|
|
394
|
+
"newTransactions": "1 transactions after 0",
|
|
395
|
+
},
|
|
396
|
+
"charlie": {
|
|
397
|
+
"lastSignature": "signature",
|
|
398
|
+
"newTransactions": "27 transactions after 73",
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
"priority": 3,
|
|
402
|
+
},
|
|
403
|
+
]
|
|
404
|
+
`);
|
|
405
|
+
});
|
|
406
|
+
test("one small session log and one large without inbetween signatures", async () => {
|
|
407
|
+
const client = setupTestNode({
|
|
408
|
+
connected: true,
|
|
409
|
+
});
|
|
410
|
+
const group = client.node.createGroup();
|
|
411
|
+
const map = group.createMap();
|
|
412
|
+
await map.core.waitForSync();
|
|
413
|
+
client.disconnect();
|
|
414
|
+
// Generate first large session (about 1MB)
|
|
415
|
+
const dataSize = 1 * 1024 * 100;
|
|
416
|
+
const chunkSize = 1024; // 1KB chunks
|
|
417
|
+
const chunks = dataSize / chunkSize;
|
|
418
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
419
|
+
for (let i = 0; i < chunks; i++) {
|
|
420
|
+
const key = `key1_${i}`;
|
|
421
|
+
map.set(key, value, "trusting");
|
|
422
|
+
}
|
|
423
|
+
const largeContent = map.core.newContentSince(undefined);
|
|
424
|
+
assert(largeContent);
|
|
425
|
+
const singleLargeContentPiece = largeContent[0];
|
|
426
|
+
for (const chunk of largeContent.slice(1)) {
|
|
427
|
+
for (const [sessionID, content] of Object.entries(chunk.new)) {
|
|
428
|
+
for (const tx of content.newTransactions) {
|
|
429
|
+
addTransactionToContentMessage(singleLargeContentPiece, tx, sessionID, content.lastSignature, 1);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
// Add small session
|
|
434
|
+
const session2 = client.spawnNewSession();
|
|
435
|
+
const mapInSession2 = await loadCoValueOrFail(session2.node, map.id);
|
|
436
|
+
mapInSession2.set("small", "value", "trusting");
|
|
437
|
+
session2.node.syncManager.handleNewContent(singleLargeContentPiece, "storage");
|
|
438
|
+
await mapInSession2.core.waitForSync();
|
|
439
|
+
// Add third large session
|
|
440
|
+
const session3 = client.spawnNewSession();
|
|
441
|
+
const mapInSession3 = await loadCoValueOrFail(session3.node, map.id);
|
|
442
|
+
for (let i = 0; i < chunks; i++) {
|
|
443
|
+
const key = `key3_${i}`;
|
|
444
|
+
mapInSession3.set(key, value, "trusting");
|
|
445
|
+
}
|
|
446
|
+
const content = mapInSession3.core.newContentSince(undefined);
|
|
447
|
+
const sessionMapping = {
|
|
448
|
+
[client.node.currentSessionID]: "alice",
|
|
449
|
+
[session2.node.currentSessionID]: "bob",
|
|
450
|
+
[session3.node.currentSessionID]: "charlie",
|
|
451
|
+
};
|
|
452
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
453
|
+
[
|
|
454
|
+
{
|
|
455
|
+
"action": "content",
|
|
456
|
+
"expectContentUntil": {
|
|
457
|
+
"alice": 100,
|
|
458
|
+
"bob": 1,
|
|
459
|
+
"charlie": 100,
|
|
460
|
+
},
|
|
461
|
+
"header": "header",
|
|
462
|
+
"id": "id",
|
|
463
|
+
"new": {
|
|
464
|
+
"alice": {
|
|
465
|
+
"lastSignature": "signature",
|
|
466
|
+
"newTransactions": "100 transactions after 0",
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
"priority": 3,
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
"action": "content",
|
|
473
|
+
"expectContentUntil": undefined,
|
|
474
|
+
"header": undefined,
|
|
475
|
+
"id": "id",
|
|
476
|
+
"new": {
|
|
477
|
+
"charlie": {
|
|
478
|
+
"lastSignature": "signature",
|
|
479
|
+
"newTransactions": "73 transactions after 0",
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
"priority": 3,
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
"action": "content",
|
|
486
|
+
"expectContentUntil": undefined,
|
|
487
|
+
"header": undefined,
|
|
488
|
+
"id": "id",
|
|
489
|
+
"new": {
|
|
490
|
+
"bob": {
|
|
491
|
+
"lastSignature": "signature",
|
|
492
|
+
"newTransactions": "1 transactions after 0",
|
|
493
|
+
},
|
|
494
|
+
"charlie": {
|
|
495
|
+
"lastSignature": "signature",
|
|
496
|
+
"newTransactions": "27 transactions after 73",
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
"priority": 3,
|
|
500
|
+
},
|
|
501
|
+
]
|
|
502
|
+
`);
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
describe("large session logs with knownState", () => {
|
|
506
|
+
test("one large session log that requires multiple content pieces starting from knownState", () => {
|
|
507
|
+
const client = setupTestNode();
|
|
508
|
+
const group = client.node.createGroup();
|
|
509
|
+
const map = group.createMap();
|
|
510
|
+
// Generate a large amount of data (about 1MB)
|
|
511
|
+
const dataSize = 1 * 1024 * 100;
|
|
512
|
+
const chunkSize = 1024; // 1KB chunks
|
|
513
|
+
const chunks = dataSize / chunkSize;
|
|
514
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
515
|
+
for (let i = 0; i < chunks; i++) {
|
|
516
|
+
const key = `key${i}`;
|
|
517
|
+
map.set(key, value, "trusting");
|
|
518
|
+
}
|
|
519
|
+
// Capture knownState partway through
|
|
520
|
+
const knownState = map.core.knownState();
|
|
521
|
+
// Add more data
|
|
522
|
+
for (let i = 0; i < chunks; i++) {
|
|
523
|
+
const key = `key_new_${i}`;
|
|
524
|
+
map.set(key, value, "trusting");
|
|
525
|
+
}
|
|
526
|
+
const content = map.core.newContentSince(knownState);
|
|
527
|
+
const sessionMapping = {
|
|
528
|
+
[client.node.currentSessionID]: "alice",
|
|
529
|
+
};
|
|
530
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
531
|
+
[
|
|
532
|
+
{
|
|
533
|
+
"action": "content",
|
|
534
|
+
"expectContentUntil": {
|
|
535
|
+
"alice": 200,
|
|
536
|
+
},
|
|
537
|
+
"header": undefined,
|
|
538
|
+
"id": "id",
|
|
539
|
+
"new": {
|
|
540
|
+
"alice": {
|
|
541
|
+
"lastSignature": "signature",
|
|
542
|
+
"newTransactions": "46 transactions after 100",
|
|
543
|
+
},
|
|
544
|
+
},
|
|
545
|
+
"priority": 3,
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"action": "content",
|
|
549
|
+
"expectContentUntil": undefined,
|
|
550
|
+
"header": undefined,
|
|
551
|
+
"id": "id",
|
|
552
|
+
"new": {
|
|
553
|
+
"alice": {
|
|
554
|
+
"lastSignature": "signature",
|
|
555
|
+
"newTransactions": "54 transactions after 146",
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
"priority": 3,
|
|
559
|
+
},
|
|
560
|
+
]
|
|
561
|
+
`);
|
|
562
|
+
});
|
|
563
|
+
test("one large session log that requires multiple content pieces and one small starting from knownState", async () => {
|
|
564
|
+
const client = setupTestNode({
|
|
565
|
+
connected: true,
|
|
566
|
+
});
|
|
567
|
+
const group = client.node.createGroup();
|
|
568
|
+
const map = group.createMap();
|
|
569
|
+
// Generate a large amount of data (about 1MB)
|
|
570
|
+
const dataSize = 1 * 1024 * 100;
|
|
571
|
+
const chunkSize = 1024; // 1KB chunks
|
|
572
|
+
const chunks = dataSize / chunkSize;
|
|
573
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
574
|
+
for (let i = 0; i < chunks; i++) {
|
|
575
|
+
const key = `key${i}`;
|
|
576
|
+
map.set(key, value, "trusting");
|
|
577
|
+
}
|
|
578
|
+
// Capture knownState
|
|
579
|
+
const knownState = map.core.knownState();
|
|
580
|
+
// Add more data to first session
|
|
581
|
+
for (let i = 0; i < chunks; i++) {
|
|
582
|
+
const key = `key_new_${i}`;
|
|
583
|
+
map.set(key, value, "trusting");
|
|
584
|
+
}
|
|
585
|
+
// Add a small session
|
|
586
|
+
const newSession = client.spawnNewSession();
|
|
587
|
+
const mapInNewSession = await loadCoValueOrFail(newSession.node, map.id);
|
|
588
|
+
mapInNewSession.set("small", "value", "trusting");
|
|
589
|
+
const content = mapInNewSession.core.newContentSince(knownState);
|
|
590
|
+
const sessionMapping = {
|
|
591
|
+
[client.node.currentSessionID]: "alice",
|
|
592
|
+
[newSession.node.currentSessionID]: "bob",
|
|
593
|
+
};
|
|
594
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
595
|
+
[
|
|
596
|
+
{
|
|
597
|
+
"action": "content",
|
|
598
|
+
"expectContentUntil": {
|
|
599
|
+
"alice": 200,
|
|
600
|
+
"bob": 1,
|
|
601
|
+
},
|
|
602
|
+
"header": undefined,
|
|
603
|
+
"id": "id",
|
|
604
|
+
"new": {
|
|
605
|
+
"alice": {
|
|
606
|
+
"lastSignature": "signature",
|
|
607
|
+
"newTransactions": "46 transactions after 100",
|
|
608
|
+
},
|
|
609
|
+
},
|
|
610
|
+
"priority": 3,
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
"action": "content",
|
|
614
|
+
"expectContentUntil": undefined,
|
|
615
|
+
"header": undefined,
|
|
616
|
+
"id": "id",
|
|
617
|
+
"new": {
|
|
618
|
+
"alice": {
|
|
619
|
+
"lastSignature": "signature",
|
|
620
|
+
"newTransactions": "54 transactions after 146",
|
|
621
|
+
},
|
|
622
|
+
"bob": {
|
|
623
|
+
"lastSignature": "signature",
|
|
624
|
+
"newTransactions": "1 transactions after 0",
|
|
625
|
+
},
|
|
626
|
+
},
|
|
627
|
+
"priority": 3,
|
|
628
|
+
},
|
|
629
|
+
]
|
|
630
|
+
`);
|
|
631
|
+
});
|
|
632
|
+
test("two large session logs starting from knownState", async () => {
|
|
633
|
+
const client = setupTestNode({
|
|
634
|
+
connected: true,
|
|
635
|
+
});
|
|
636
|
+
const group = client.node.createGroup();
|
|
637
|
+
const map = group.createMap();
|
|
638
|
+
// Generate initial data
|
|
639
|
+
map.set("initial", "value", "trusting");
|
|
640
|
+
// Capture knownState
|
|
641
|
+
const knownState = map.core.knownState();
|
|
642
|
+
// Generate a large amount of data in first session (about 1MB)
|
|
643
|
+
const dataSize = 1 * 1024 * 100;
|
|
644
|
+
const chunkSize = 1024; // 1KB chunks
|
|
645
|
+
const chunks = dataSize / chunkSize;
|
|
646
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
647
|
+
for (let i = 0; i < chunks; i++) {
|
|
648
|
+
const key = `key1_${i}`;
|
|
649
|
+
map.set(key, value, "trusting");
|
|
650
|
+
}
|
|
651
|
+
// Add second large session
|
|
652
|
+
const newSession = client.spawnNewSession();
|
|
653
|
+
const mapInNewSession = await loadCoValueOrFail(newSession.node, map.id);
|
|
654
|
+
for (let i = 0; i < chunks; i++) {
|
|
655
|
+
const key = `key2_${i}`;
|
|
656
|
+
mapInNewSession.set(key, value, "trusting");
|
|
657
|
+
}
|
|
658
|
+
const content = mapInNewSession.core.newContentSince(knownState);
|
|
659
|
+
const sessionMapping = {
|
|
660
|
+
[client.node.currentSessionID]: "alice",
|
|
661
|
+
[newSession.node.currentSessionID]: "bob",
|
|
662
|
+
};
|
|
663
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
664
|
+
[
|
|
665
|
+
{
|
|
666
|
+
"action": "content",
|
|
667
|
+
"expectContentUntil": {
|
|
668
|
+
"alice": 101,
|
|
669
|
+
"bob": 100,
|
|
670
|
+
},
|
|
671
|
+
"header": undefined,
|
|
672
|
+
"id": "id",
|
|
673
|
+
"new": {
|
|
674
|
+
"alice": {
|
|
675
|
+
"lastSignature": "signature",
|
|
676
|
+
"newTransactions": "73 transactions after 1",
|
|
677
|
+
},
|
|
678
|
+
},
|
|
679
|
+
"priority": 3,
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
"action": "content",
|
|
683
|
+
"expectContentUntil": undefined,
|
|
684
|
+
"header": undefined,
|
|
685
|
+
"id": "id",
|
|
686
|
+
"new": {
|
|
687
|
+
"bob": {
|
|
688
|
+
"lastSignature": "signature",
|
|
689
|
+
"newTransactions": "73 transactions after 0",
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
"priority": 3,
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
"action": "content",
|
|
696
|
+
"expectContentUntil": undefined,
|
|
697
|
+
"header": undefined,
|
|
698
|
+
"id": "id",
|
|
699
|
+
"new": {
|
|
700
|
+
"alice": {
|
|
701
|
+
"lastSignature": "signature",
|
|
702
|
+
"newTransactions": "27 transactions after 74",
|
|
703
|
+
},
|
|
704
|
+
"bob": {
|
|
705
|
+
"lastSignature": "signature",
|
|
706
|
+
"newTransactions": "27 transactions after 73",
|
|
707
|
+
},
|
|
708
|
+
},
|
|
709
|
+
"priority": 3,
|
|
710
|
+
},
|
|
711
|
+
]
|
|
712
|
+
`);
|
|
713
|
+
});
|
|
714
|
+
test("one large, one small, and one large session log starting from knownState", async () => {
|
|
715
|
+
const client = setupTestNode({
|
|
716
|
+
connected: true,
|
|
717
|
+
});
|
|
718
|
+
const group = client.node.createGroup();
|
|
719
|
+
const map = group.createMap();
|
|
720
|
+
// Generate initial data
|
|
721
|
+
map.set("initial", "value", "trusting");
|
|
722
|
+
// Capture knownState
|
|
723
|
+
const knownState = map.core.knownState();
|
|
724
|
+
// Generate first large session (about 1MB)
|
|
725
|
+
const dataSize = 1 * 1024 * 100;
|
|
726
|
+
const chunkSize = 1024; // 1KB chunks
|
|
727
|
+
const chunks = dataSize / chunkSize;
|
|
728
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
729
|
+
for (let i = 0; i < chunks; i++) {
|
|
730
|
+
const key = `key1_${i}`;
|
|
731
|
+
map.set(key, value, "trusting");
|
|
732
|
+
}
|
|
733
|
+
// Add small session
|
|
734
|
+
const session2 = client.spawnNewSession();
|
|
735
|
+
const mapInSession2 = await loadCoValueOrFail(session2.node, map.id);
|
|
736
|
+
mapInSession2.set("small", "value", "trusting");
|
|
737
|
+
// Add third large session
|
|
738
|
+
const session3 = client.spawnNewSession();
|
|
739
|
+
const mapInSession3 = await loadCoValueOrFail(session3.node, map.id);
|
|
740
|
+
for (let i = 0; i < chunks; i++) {
|
|
741
|
+
const key = `key3_${i}`;
|
|
742
|
+
mapInSession3.set(key, value, "trusting");
|
|
743
|
+
}
|
|
744
|
+
const content = mapInSession3.core.newContentSince(knownState);
|
|
745
|
+
const sessionMapping = {
|
|
746
|
+
[client.node.currentSessionID]: "alice",
|
|
747
|
+
[session2.node.currentSessionID]: "bob",
|
|
748
|
+
[session3.node.currentSessionID]: "charlie",
|
|
749
|
+
};
|
|
750
|
+
expect(simplifyContentMessages(content, sessionMapping)).toMatchInlineSnapshot(`
|
|
751
|
+
[
|
|
752
|
+
{
|
|
753
|
+
"action": "content",
|
|
754
|
+
"expectContentUntil": {
|
|
755
|
+
"alice": 101,
|
|
756
|
+
"bob": 1,
|
|
757
|
+
"charlie": 100,
|
|
758
|
+
},
|
|
759
|
+
"header": undefined,
|
|
760
|
+
"id": "id",
|
|
761
|
+
"new": {
|
|
762
|
+
"alice": {
|
|
763
|
+
"lastSignature": "signature",
|
|
764
|
+
"newTransactions": "73 transactions after 1",
|
|
765
|
+
},
|
|
766
|
+
},
|
|
767
|
+
"priority": 3,
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
"action": "content",
|
|
771
|
+
"expectContentUntil": undefined,
|
|
772
|
+
"header": undefined,
|
|
773
|
+
"id": "id",
|
|
774
|
+
"new": {
|
|
775
|
+
"charlie": {
|
|
776
|
+
"lastSignature": "signature",
|
|
777
|
+
"newTransactions": "73 transactions after 0",
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
"priority": 3,
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
"action": "content",
|
|
784
|
+
"expectContentUntil": undefined,
|
|
785
|
+
"header": undefined,
|
|
786
|
+
"id": "id",
|
|
787
|
+
"new": {
|
|
788
|
+
"alice": {
|
|
789
|
+
"lastSignature": "signature",
|
|
790
|
+
"newTransactions": "27 transactions after 74",
|
|
791
|
+
},
|
|
792
|
+
"bob": {
|
|
793
|
+
"lastSignature": "signature",
|
|
794
|
+
"newTransactions": "1 transactions after 0",
|
|
795
|
+
},
|
|
796
|
+
"charlie": {
|
|
797
|
+
"lastSignature": "signature",
|
|
798
|
+
"newTransactions": "27 transactions after 73",
|
|
799
|
+
},
|
|
800
|
+
},
|
|
801
|
+
"priority": 3,
|
|
802
|
+
},
|
|
803
|
+
]
|
|
804
|
+
`);
|
|
805
|
+
});
|
|
806
|
+
});
|
|
807
|
+
});
|
|
808
|
+
//# sourceMappingURL=coValueCore.newContentSince.test.js.map
|