cojson 0.16.3 → 0.16.5
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 +20 -0
- package/dist/coValue.d.ts +1 -1
- package/dist/coValue.d.ts.map +1 -1
- package/dist/coValue.js.map +1 -1
- package/dist/coValueContentMessage.d.ts +10 -0
- package/dist/coValueContentMessage.d.ts.map +1 -0
- package/dist/coValueContentMessage.js +46 -0
- package/dist/coValueContentMessage.js.map +1 -0
- package/dist/coValueCore/coValueCore.d.ts +6 -10
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +20 -125
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +1 -0
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +14 -27
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/group.d.ts +18 -10
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +237 -67
- package/dist/coValues/group.js.map +1 -1
- package/dist/ids.d.ts +3 -3
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js.map +1 -1
- package/dist/localNode.d.ts +11 -6
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +7 -2
- package/dist/localNode.js.map +1 -1
- package/dist/queue/LocalTransactionsSyncQueue.d.ts +24 -0
- package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -0
- package/dist/queue/LocalTransactionsSyncQueue.js +55 -0
- package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -0
- package/dist/queue/StoreQueue.d.ts +9 -6
- package/dist/queue/StoreQueue.d.ts.map +1 -1
- package/dist/queue/StoreQueue.js +10 -2
- package/dist/queue/StoreQueue.js.map +1 -1
- package/dist/storage/storageAsync.d.ts +11 -3
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js +59 -46
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/storage/storageSync.d.ts +9 -3
- package/dist/storage/storageSync.d.ts.map +1 -1
- package/dist/storage/storageSync.js +48 -35
- package/dist/storage/storageSync.js.map +1 -1
- package/dist/storage/syncUtils.d.ts +2 -1
- package/dist/storage/syncUtils.d.ts.map +1 -1
- package/dist/storage/syncUtils.js +4 -0
- package/dist/storage/syncUtils.js.map +1 -1
- package/dist/storage/types.d.ts +3 -2
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/sync.d.ts +6 -6
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +33 -56
- package/dist/sync.js.map +1 -1
- package/dist/tests/StorageApiAsync.test.d.ts +2 -0
- package/dist/tests/StorageApiAsync.test.d.ts.map +1 -0
- package/dist/tests/StorageApiAsync.test.js +574 -0
- package/dist/tests/StorageApiAsync.test.js.map +1 -0
- package/dist/tests/StorageApiSync.test.d.ts +2 -0
- package/dist/tests/StorageApiSync.test.d.ts.map +1 -0
- package/dist/tests/StorageApiSync.test.js +426 -0
- package/dist/tests/StorageApiSync.test.js.map +1 -0
- package/dist/tests/StoreQueue.test.js +9 -21
- package/dist/tests/StoreQueue.test.js.map +1 -1
- package/dist/tests/SyncStateManager.test.js +18 -8
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/group.inheritance.test.js +274 -2
- package/dist/tests/group.inheritance.test.js.map +1 -1
- package/dist/tests/group.removeMember.test.js +152 -1
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/group.roleOf.test.js +2 -2
- package/dist/tests/group.roleOf.test.js.map +1 -1
- package/dist/tests/group.test.js +81 -3
- package/dist/tests/group.test.js.map +1 -1
- package/dist/tests/sync.auth.test.js +22 -10
- package/dist/tests/sync.auth.test.js.map +1 -1
- package/dist/tests/sync.load.test.js +30 -25
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +12 -6
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.peerReconciliation.test.js +6 -4
- package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +8 -14
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.js +31 -14
- package/dist/tests/sync.storageAsync.test.js.map +1 -1
- package/dist/tests/sync.test.js +5 -9
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js +31 -1
- package/dist/tests/sync.upload.test.js.map +1 -1
- package/dist/tests/testStorage.d.ts +2 -3
- package/dist/tests/testStorage.d.ts.map +1 -1
- package/dist/tests/testStorage.js +16 -8
- package/dist/tests/testStorage.js.map +1 -1
- package/dist/tests/testUtils.d.ts +4 -0
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +22 -4
- package/dist/tests/testUtils.js.map +1 -1
- package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts +2 -2
- package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts.map +1 -1
- package/dist/typeUtils/expectGroup.d.ts.map +1 -1
- package/dist/typeUtils/expectGroup.js +6 -5
- package/dist/typeUtils/expectGroup.js.map +1 -1
- package/package.json +1 -1
- package/src/coValue.ts +1 -4
- package/src/coValueContentMessage.ts +73 -0
- package/src/coValueCore/coValueCore.ts +36 -192
- package/src/coValueCore/verifiedState.ts +28 -35
- package/src/coValues/group.ts +329 -99
- package/src/ids.ts +3 -3
- package/src/localNode.ts +15 -10
- package/src/queue/LocalTransactionsSyncQueue.ts +96 -0
- package/src/queue/StoreQueue.ts +22 -12
- package/src/storage/storageAsync.ts +78 -56
- package/src/storage/storageSync.ts +66 -45
- package/src/storage/syncUtils.ts +9 -1
- package/src/storage/types.ts +6 -5
- package/src/sync.ts +47 -67
- package/src/tests/StorageApiAsync.test.ts +829 -0
- package/src/tests/StorageApiSync.test.ts +628 -0
- package/src/tests/StoreQueue.test.ts +10 -24
- package/src/tests/SyncStateManager.test.ts +22 -21
- package/src/tests/group.inheritance.test.ts +415 -1
- package/src/tests/group.removeMember.test.ts +244 -1
- package/src/tests/group.roleOf.test.ts +2 -2
- package/src/tests/group.test.ts +105 -5
- package/src/tests/sync.auth.test.ts +22 -10
- package/src/tests/sync.load.test.ts +32 -26
- package/src/tests/sync.mesh.test.ts +12 -6
- package/src/tests/sync.peerReconciliation.test.ts +6 -4
- package/src/tests/sync.storage.test.ts +8 -14
- package/src/tests/sync.storageAsync.test.ts +39 -14
- package/src/tests/sync.test.ts +6 -14
- package/src/tests/sync.upload.test.ts +38 -1
- package/src/tests/testStorage.ts +19 -13
- package/src/tests/testUtils.ts +29 -5
- package/src/typeUtils/accountOrAgentIDfromSessionID.ts +2 -2
- package/src/typeUtils/expectGroup.ts +8 -5
|
@@ -142,19 +142,26 @@ describe("multiple clients syncing with the a cloud-like server mesh", () => {
|
|
|
142
142
|
}),
|
|
143
143
|
).toMatchInlineSnapshot(`
|
|
144
144
|
[
|
|
145
|
-
"edge-france -> storage | CONTENT Group header: true new: After: 0 New:
|
|
146
|
-
"edge-france -> core | CONTENT
|
|
147
|
-
"edge-france -> core | CONTENT Group header: true new: After: 0 New: 5",
|
|
145
|
+
"edge-france -> storage | CONTENT Group header: true new: After: 0 New: 3",
|
|
146
|
+
"edge-france -> core | CONTENT Group header: true new: After: 0 New: 3",
|
|
148
147
|
"edge-france -> storage | CONTENT ParentGroup header: true new: After: 0 New: 6",
|
|
148
|
+
"edge-france -> core | CONTENT ParentGroup header: true new: After: 0 New: 6",
|
|
149
|
+
"edge-france -> storage | CONTENT Group header: false new: After: 3 New: 2",
|
|
150
|
+
"edge-france -> core | CONTENT Group header: false new: After: 3 New: 2",
|
|
149
151
|
"edge-france -> storage | CONTENT Map header: true new: After: 0 New: 1",
|
|
150
152
|
"edge-france -> core | CONTENT Map header: true new: After: 0 New: 1",
|
|
153
|
+
"core -> edge-france | KNOWN Group sessions: header/3",
|
|
154
|
+
"core -> storage | CONTENT Group header: true new: After: 0 New: 3",
|
|
151
155
|
"core -> edge-france | KNOWN ParentGroup sessions: header/6",
|
|
152
156
|
"core -> storage | CONTENT ParentGroup header: true new: After: 0 New: 6",
|
|
153
157
|
"core -> edge-france | KNOWN Group sessions: header/5",
|
|
154
|
-
"core -> storage | CONTENT Group header:
|
|
158
|
+
"core -> storage | CONTENT Group header: false new: After: 3 New: 2",
|
|
155
159
|
"core -> edge-france | KNOWN Map sessions: header/1",
|
|
156
160
|
"core -> storage | CONTENT Map header: true new: After: 0 New: 1",
|
|
161
|
+
"edge-france -> core | CONTENT ParentGroup header: true new: ",
|
|
157
162
|
"client -> edge-italy | LOAD Map sessions: empty",
|
|
163
|
+
"core -> edge-france | KNOWN ParentGroup sessions: header/6",
|
|
164
|
+
"core -> storage | CONTENT ParentGroup header: true new: ",
|
|
158
165
|
"edge-italy -> storage | LOAD Map sessions: empty",
|
|
159
166
|
"storage -> edge-italy | KNOWN Map sessions: empty",
|
|
160
167
|
"edge-italy -> core | LOAD Map sessions: empty",
|
|
@@ -509,8 +516,7 @@ describe("multiple clients syncing with the a cloud-like server mesh", () => {
|
|
|
509
516
|
).toMatchInlineSnapshot(`
|
|
510
517
|
[
|
|
511
518
|
"edge -> storage | CONTENT Group header: true new: After: 0 New: 5",
|
|
512
|
-
"edge -> storage | CONTENT Map header: true new:
|
|
513
|
-
"edge -> storage | CONTENT Map header: false new: After: 0 New: 73",
|
|
519
|
+
"edge -> storage | CONTENT Map header: true new: After: 0 New: 73",
|
|
514
520
|
"edge -> storage | CONTENT Map header: false new: After: 73 New: 73",
|
|
515
521
|
"edge -> storage | CONTENT Map header: false new: After: 146 New: 54",
|
|
516
522
|
]
|
|
@@ -47,6 +47,8 @@ describe("peer reconciliation", () => {
|
|
|
47
47
|
"server -> client | KNOWN Map sessions: empty",
|
|
48
48
|
"server -> client | KNOWN Group sessions: header/3",
|
|
49
49
|
"server -> client | KNOWN Map sessions: header/1",
|
|
50
|
+
"client -> server | CONTENT Group header: true new: ",
|
|
51
|
+
"client -> server | CONTENT Map header: true new: ",
|
|
50
52
|
]
|
|
51
53
|
`);
|
|
52
54
|
});
|
|
@@ -203,7 +205,7 @@ describe("peer reconciliation", () => {
|
|
|
203
205
|
"server -> client | KNOWN CORRECTION Map sessions: empty",
|
|
204
206
|
"client -> server | CONTENT Map header: true new: After: 0 New: 2",
|
|
205
207
|
"server -> client | LOAD Group sessions: empty",
|
|
206
|
-
"server -> client | KNOWN Map sessions:
|
|
208
|
+
"server -> client | KNOWN Map sessions: header/2",
|
|
207
209
|
"client -> server | CONTENT Group header: true new: After: 0 New: 3",
|
|
208
210
|
"server -> client | KNOWN Group sessions: header/3",
|
|
209
211
|
]
|
|
@@ -276,8 +278,8 @@ describe("peer reconciliation", () => {
|
|
|
276
278
|
"client -> server | CONTENT Profile header: true new: After: 0 New: 1",
|
|
277
279
|
"client -> server | CONTENT Map header: false new: After: 1 New: 1",
|
|
278
280
|
"server -> client | LOAD Account sessions: empty",
|
|
279
|
-
"server -> client | KNOWN ProfileGroup sessions:
|
|
280
|
-
"server -> client | KNOWN Profile sessions:
|
|
281
|
+
"server -> client | KNOWN ProfileGroup sessions: header/0",
|
|
282
|
+
"server -> client | KNOWN Profile sessions: header/0",
|
|
281
283
|
"server -> client | KNOWN CORRECTION Map sessions: empty",
|
|
282
284
|
"client -> server | CONTENT Account header: true new: After: 0 New: 4",
|
|
283
285
|
"client -> server | CONTENT Map header: true new: After: 0 New: 2",
|
|
@@ -285,7 +287,7 @@ describe("peer reconciliation", () => {
|
|
|
285
287
|
"server -> client | KNOWN ProfileGroup sessions: header/5",
|
|
286
288
|
"server -> client | KNOWN Profile sessions: header/1",
|
|
287
289
|
"server -> client | LOAD Group sessions: empty",
|
|
288
|
-
"server -> client | KNOWN Map sessions:
|
|
290
|
+
"server -> client | KNOWN Map sessions: header/2",
|
|
289
291
|
"client -> server | CONTENT Group header: true new: After: 0 New: 3",
|
|
290
292
|
"server -> client | KNOWN Group sessions: header/3",
|
|
291
293
|
]
|
|
@@ -181,13 +181,11 @@ describe("client with storage syncs with server", () => {
|
|
|
181
181
|
[
|
|
182
182
|
"client -> server | LOAD Group sessions: header/3",
|
|
183
183
|
"client -> server | LOAD Map sessions: header/1",
|
|
184
|
-
"server -> client | CONTENT Group header: true new: After: 0 New: 3",
|
|
185
|
-
"server -> client | CONTENT Map header: true new: After: 0 New: 2",
|
|
186
184
|
"server -> client | CONTENT Map header: false new: After: 1 New: 1",
|
|
187
|
-
"
|
|
188
|
-
"
|
|
185
|
+
"server -> client | KNOWN Group sessions: header/3",
|
|
186
|
+
"server -> client | CONTENT Map header: false new: After: 1 New: 1",
|
|
189
187
|
"client -> server | KNOWN Map sessions: header/2",
|
|
190
|
-
"client -> storage | CONTENT Map header:
|
|
188
|
+
"client -> storage | CONTENT Map header: false new: After: 1 New: 1",
|
|
191
189
|
"client -> server | KNOWN Map sessions: header/2",
|
|
192
190
|
"client -> storage | CONTENT Map header: false new: After: 1 New: 1",
|
|
193
191
|
]
|
|
@@ -291,20 +289,16 @@ describe("client syncs with a server with storage", () => {
|
|
|
291
289
|
[
|
|
292
290
|
"client -> storage | CONTENT Group header: true new: After: 0 New: 5",
|
|
293
291
|
"client -> server | CONTENT Group header: true new: After: 0 New: 5",
|
|
294
|
-
"client -> storage | CONTENT Map header: true new:
|
|
295
|
-
"client ->
|
|
292
|
+
"client -> storage | CONTENT Map header: true new: After: 0 New: 73",
|
|
293
|
+
"client -> server | CONTENT Map header: true new: After: 0 New: 73",
|
|
296
294
|
"client -> storage | CONTENT Map header: false new: After: 73 New: 73",
|
|
297
|
-
"client -> storage | CONTENT Map header: false new: After: 146 New: 54",
|
|
298
|
-
"client -> server | CONTENT Map header: true new: expectContentUntil: header/200",
|
|
299
|
-
"client -> server | CONTENT Map header: false new: After: 0 New: 73",
|
|
300
295
|
"client -> server | CONTENT Map header: false new: After: 73 New: 73",
|
|
296
|
+
"client -> storage | CONTENT Map header: false new: After: 146 New: 54",
|
|
301
297
|
"client -> server | CONTENT Map header: false new: After: 146 New: 54",
|
|
302
298
|
"server -> client | KNOWN Group sessions: header/5",
|
|
303
299
|
"server -> storage | CONTENT Group header: true new: After: 0 New: 5",
|
|
304
|
-
"server -> client | KNOWN Map sessions: header/0",
|
|
305
|
-
"server -> storage | CONTENT Map header: true new: expectContentUntil: header/200",
|
|
306
300
|
"server -> client | KNOWN Map sessions: header/73",
|
|
307
|
-
"server -> storage | CONTENT Map header:
|
|
301
|
+
"server -> storage | CONTENT Map header: true new: After: 0 New: 73",
|
|
308
302
|
"server -> client | KNOWN Map sessions: header/146",
|
|
309
303
|
"server -> storage | CONTENT Map header: false new: After: 73 New: 73",
|
|
310
304
|
"server -> client | KNOWN Map sessions: header/200",
|
|
@@ -410,7 +404,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
410
404
|
|
|
411
405
|
const correctionSpy = vi.fn();
|
|
412
406
|
|
|
413
|
-
client.node.storage?.store(newContentChunks
|
|
407
|
+
client.node.storage?.store(newContentChunks[1]!, correctionSpy);
|
|
414
408
|
|
|
415
409
|
expect(correctionSpy).not.toHaveBeenCalled();
|
|
416
410
|
|
|
@@ -16,6 +16,7 @@ describe("client with storage syncs with server", () => {
|
|
|
16
16
|
let jazzCloud: ReturnType<typeof setupTestNode>;
|
|
17
17
|
|
|
18
18
|
beforeEach(async () => {
|
|
19
|
+
vi.resetAllMocks();
|
|
19
20
|
SyncMessagesLog.clear();
|
|
20
21
|
jazzCloud = setupTestNode({
|
|
21
22
|
isSyncServer: true,
|
|
@@ -174,18 +175,46 @@ describe("client with storage syncs with server", () => {
|
|
|
174
175
|
[
|
|
175
176
|
"client -> server | LOAD Group sessions: header/3",
|
|
176
177
|
"client -> server | LOAD Map sessions: header/1",
|
|
177
|
-
"server -> client | CONTENT Group header: true new: After: 0 New: 3",
|
|
178
|
-
"server -> client | CONTENT Map header: true new: After: 0 New: 2",
|
|
179
178
|
"server -> client | CONTENT Map header: false new: After: 1 New: 1",
|
|
180
|
-
"
|
|
181
|
-
"
|
|
179
|
+
"server -> client | KNOWN Group sessions: header/3",
|
|
180
|
+
"server -> client | CONTENT Map header: false new: After: 1 New: 1",
|
|
182
181
|
"client -> server | KNOWN Map sessions: header/2",
|
|
183
|
-
"client -> storage | CONTENT Map header:
|
|
182
|
+
"client -> storage | CONTENT Map header: false new: After: 1 New: 1",
|
|
184
183
|
"client -> server | KNOWN Map sessions: header/2",
|
|
185
184
|
"client -> storage | CONTENT Map header: false new: After: 1 New: 1",
|
|
186
185
|
]
|
|
187
186
|
`);
|
|
188
187
|
});
|
|
188
|
+
|
|
189
|
+
test("the order of updates between CoValues should be preserved to ensure consistency in case of shutdown in the middle of sync", async () => {
|
|
190
|
+
const client = setupTestNode();
|
|
191
|
+
|
|
192
|
+
await client.addAsyncStorage();
|
|
193
|
+
|
|
194
|
+
const group = client.node.createGroup();
|
|
195
|
+
const initialMap = group.createMap();
|
|
196
|
+
|
|
197
|
+
const child = group.createMap();
|
|
198
|
+
child.set("parent", initialMap.id);
|
|
199
|
+
initialMap.set("child", child.id);
|
|
200
|
+
|
|
201
|
+
await initialMap.core.waitForSync();
|
|
202
|
+
|
|
203
|
+
expect(
|
|
204
|
+
SyncMessagesLog.getMessages({
|
|
205
|
+
Group: group.core,
|
|
206
|
+
InitialMap: initialMap.core,
|
|
207
|
+
ChildMap: child.core,
|
|
208
|
+
}),
|
|
209
|
+
).toMatchInlineSnapshot(`
|
|
210
|
+
[
|
|
211
|
+
"client -> storage | CONTENT Group header: true new: After: 0 New: 3",
|
|
212
|
+
"client -> storage | CONTENT InitialMap header: true new: ",
|
|
213
|
+
"client -> storage | CONTENT ChildMap header: true new: After: 0 New: 1",
|
|
214
|
+
"client -> storage | CONTENT InitialMap header: false new: After: 0 New: 1",
|
|
215
|
+
]
|
|
216
|
+
`);
|
|
217
|
+
});
|
|
189
218
|
});
|
|
190
219
|
|
|
191
220
|
describe("client syncs with a server with storage", () => {
|
|
@@ -271,20 +300,16 @@ describe("client syncs with a server with storage", () => {
|
|
|
271
300
|
[
|
|
272
301
|
"client -> storage | CONTENT Group header: true new: After: 0 New: 5",
|
|
273
302
|
"client -> server | CONTENT Group header: true new: After: 0 New: 5",
|
|
274
|
-
"client -> storage | CONTENT Map header: true new:
|
|
275
|
-
"client ->
|
|
303
|
+
"client -> storage | CONTENT Map header: true new: After: 0 New: 73",
|
|
304
|
+
"client -> server | CONTENT Map header: true new: After: 0 New: 73",
|
|
276
305
|
"client -> storage | CONTENT Map header: false new: After: 73 New: 73",
|
|
277
|
-
"client -> storage | CONTENT Map header: false new: After: 146 New: 54",
|
|
278
|
-
"client -> server | CONTENT Map header: true new: expectContentUntil: header/200",
|
|
279
|
-
"client -> server | CONTENT Map header: false new: After: 0 New: 73",
|
|
280
306
|
"client -> server | CONTENT Map header: false new: After: 73 New: 73",
|
|
307
|
+
"client -> storage | CONTENT Map header: false new: After: 146 New: 54",
|
|
281
308
|
"client -> server | CONTENT Map header: false new: After: 146 New: 54",
|
|
282
309
|
"server -> client | KNOWN Group sessions: header/5",
|
|
283
310
|
"server -> storage | CONTENT Group header: true new: After: 0 New: 5",
|
|
284
|
-
"server -> client | KNOWN Map sessions: header/0",
|
|
285
|
-
"server -> storage | CONTENT Map header: true new: expectContentUntil: header/200",
|
|
286
311
|
"server -> client | KNOWN Map sessions: header/73",
|
|
287
|
-
"server -> storage | CONTENT Map header:
|
|
312
|
+
"server -> storage | CONTENT Map header: true new: After: 0 New: 73",
|
|
288
313
|
"server -> client | KNOWN Map sessions: header/146",
|
|
289
314
|
"server -> storage | CONTENT Map header: false new: After: 73 New: 73",
|
|
290
315
|
"server -> client | KNOWN Map sessions: header/200",
|
|
@@ -369,7 +394,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
369
394
|
|
|
370
395
|
const correctionSpy = vi.fn();
|
|
371
396
|
|
|
372
|
-
client.node.storage?.store(newContentChunks
|
|
397
|
+
client.node.storage?.store(newContentChunks[1]!, correctionSpy);
|
|
373
398
|
|
|
374
399
|
// Wait for the content to be stored in the storage
|
|
375
400
|
// We can't use waitForSync because we are trying to store stale data
|
package/src/tests/sync.test.ts
CHANGED
|
@@ -100,15 +100,18 @@ test("Can sync a coValue with private transactions through a server to another c
|
|
|
100
100
|
|
|
101
101
|
const map = group.createMap();
|
|
102
102
|
map.set("hello", "world", "private");
|
|
103
|
+
|
|
103
104
|
group.addMember("everyone", "reader");
|
|
104
105
|
|
|
105
106
|
const { node: client2 } = await setupTestAccount({
|
|
106
107
|
connected: true,
|
|
107
108
|
});
|
|
108
109
|
|
|
109
|
-
|
|
110
|
+
await waitFor(async () => {
|
|
111
|
+
const loadedMap = await loadCoValueOrFail(client2, map.id);
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
expect(loadedMap.get("hello")).toEqual("world");
|
|
114
|
+
});
|
|
112
115
|
});
|
|
113
116
|
|
|
114
117
|
test("should keep the peer state when the peer closes if persistent is true", async () => {
|
|
@@ -563,8 +566,6 @@ describe("SyncManager - knownStates vs optimisticKnownStates", () => {
|
|
|
563
566
|
const mapOnClient = group.createMap();
|
|
564
567
|
mapOnClient.set("key1", "value1", "trusting");
|
|
565
568
|
|
|
566
|
-
await client.syncManager.syncCoValue(mapOnClient.core);
|
|
567
|
-
|
|
568
569
|
// Wait for the full sync to complete
|
|
569
570
|
await mapOnClient.core.waitForSync();
|
|
570
571
|
|
|
@@ -594,7 +595,6 @@ describe("SyncManager - knownStates vs optimisticKnownStates", () => {
|
|
|
594
595
|
const map = group.createMap();
|
|
595
596
|
map.set("key1", "value1", "trusting");
|
|
596
597
|
|
|
597
|
-
await client.node.syncManager.syncCoValue(map.core);
|
|
598
598
|
await map.core.waitForSync();
|
|
599
599
|
|
|
600
600
|
// Block the content messages
|
|
@@ -606,7 +606,7 @@ describe("SyncManager - knownStates vs optimisticKnownStates", () => {
|
|
|
606
606
|
|
|
607
607
|
map.set("key2", "value2", "trusting");
|
|
608
608
|
|
|
609
|
-
await
|
|
609
|
+
await new Promise<void>(queueMicrotask);
|
|
610
610
|
|
|
611
611
|
expect(peerState.optimisticKnownStates.get(map.core.id)).not.toEqual(
|
|
612
612
|
peerState.knownStates.get(map.core.id),
|
|
@@ -638,8 +638,6 @@ describe("SyncManager.addPeer", () => {
|
|
|
638
638
|
const map = group.createMap();
|
|
639
639
|
map.set("key1", "value1", "trusting");
|
|
640
640
|
|
|
641
|
-
await client.node.syncManager.syncCoValue(map.core);
|
|
642
|
-
|
|
643
641
|
// Wait for initial sync
|
|
644
642
|
await map.core.waitForSync();
|
|
645
643
|
|
|
@@ -671,8 +669,6 @@ describe("SyncManager.addPeer", () => {
|
|
|
671
669
|
const map = group.createMap();
|
|
672
670
|
map.set("key1", "value1", "trusting");
|
|
673
671
|
|
|
674
|
-
await client.node.syncManager.syncCoValue(map.core);
|
|
675
|
-
|
|
676
672
|
// Wait for initial sync
|
|
677
673
|
await map.core.waitForSync();
|
|
678
674
|
|
|
@@ -843,8 +839,6 @@ describe("waitForSyncWithPeer", () => {
|
|
|
843
839
|
const map = group.createMap();
|
|
844
840
|
map.set("key1", "value1", "trusting");
|
|
845
841
|
|
|
846
|
-
await client.node.syncManager.syncCoValue(map.core);
|
|
847
|
-
|
|
848
842
|
await expect(
|
|
849
843
|
client.node.syncManager.waitForSyncWithPeer(
|
|
850
844
|
peerState.id,
|
|
@@ -868,8 +862,6 @@ describe("waitForSyncWithPeer", () => {
|
|
|
868
862
|
return Promise.resolve();
|
|
869
863
|
});
|
|
870
864
|
|
|
871
|
-
await client.node.syncManager.syncCoValue(map.core);
|
|
872
|
-
|
|
873
865
|
await expect(
|
|
874
866
|
client.node.syncManager.waitForSyncWithPeer(
|
|
875
867
|
peerState.id,
|
|
@@ -78,12 +78,15 @@ describe("client to server upload", () => {
|
|
|
78
78
|
}),
|
|
79
79
|
).toMatchInlineSnapshot(`
|
|
80
80
|
[
|
|
81
|
+
"client -> server | CONTENT Group header: true new: After: 0 New: 3",
|
|
81
82
|
"client -> server | CONTENT ParentGroup header: true new: After: 0 New: 6",
|
|
82
|
-
"client -> server | CONTENT Group header:
|
|
83
|
+
"client -> server | CONTENT Group header: false new: After: 3 New: 2",
|
|
83
84
|
"client -> server | CONTENT Map header: true new: After: 0 New: 1",
|
|
85
|
+
"server -> client | KNOWN Group sessions: header/3",
|
|
84
86
|
"server -> client | KNOWN ParentGroup sessions: header/6",
|
|
85
87
|
"server -> client | KNOWN Group sessions: header/5",
|
|
86
88
|
"server -> client | KNOWN Map sessions: header/1",
|
|
89
|
+
"client -> server | CONTENT ParentGroup header: true new: ",
|
|
87
90
|
]
|
|
88
91
|
`);
|
|
89
92
|
});
|
|
@@ -253,6 +256,40 @@ describe("client to server upload", () => {
|
|
|
253
256
|
`);
|
|
254
257
|
});
|
|
255
258
|
|
|
259
|
+
test("local updates batching", async () => {
|
|
260
|
+
const client = setupTestNode({
|
|
261
|
+
connected: true,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const group = client.node.createGroup();
|
|
265
|
+
const initialMap = group.createMap();
|
|
266
|
+
|
|
267
|
+
const child = group.createMap();
|
|
268
|
+
child.set("parent", initialMap.id);
|
|
269
|
+
initialMap.set("child", child.id);
|
|
270
|
+
|
|
271
|
+
await initialMap.core.waitForSync();
|
|
272
|
+
|
|
273
|
+
expect(
|
|
274
|
+
SyncMessagesLog.getMessages({
|
|
275
|
+
Group: group.core,
|
|
276
|
+
InitialMap: initialMap.core,
|
|
277
|
+
ChildMap: child.core,
|
|
278
|
+
}),
|
|
279
|
+
).toMatchInlineSnapshot(`
|
|
280
|
+
[
|
|
281
|
+
"client -> server | CONTENT Group header: true new: After: 0 New: 3",
|
|
282
|
+
"client -> server | CONTENT InitialMap header: true new: ",
|
|
283
|
+
"client -> server | CONTENT ChildMap header: true new: After: 0 New: 1",
|
|
284
|
+
"client -> server | CONTENT InitialMap header: false new: After: 0 New: 1",
|
|
285
|
+
"server -> client | KNOWN Group sessions: header/3",
|
|
286
|
+
"server -> client | KNOWN InitialMap sessions: header/0",
|
|
287
|
+
"server -> client | KNOWN ChildMap sessions: header/1",
|
|
288
|
+
"server -> client | KNOWN InitialMap sessions: header/1",
|
|
289
|
+
]
|
|
290
|
+
`);
|
|
291
|
+
});
|
|
292
|
+
|
|
256
293
|
test("large coValue upload streaming", async () => {
|
|
257
294
|
const client = setupTestNode({
|
|
258
295
|
connected: true,
|
package/src/tests/testStorage.ts
CHANGED
|
@@ -5,11 +5,7 @@ import { join } from "node:path";
|
|
|
5
5
|
import Database, { type Database as DatabaseT } from "libsql";
|
|
6
6
|
import { onTestFinished } from "vitest";
|
|
7
7
|
import { RawCoID, StorageAPI } from "../exports";
|
|
8
|
-
import {
|
|
9
|
-
SQLiteDatabaseDriver,
|
|
10
|
-
StorageApiAsync,
|
|
11
|
-
StorageApiSync,
|
|
12
|
-
} from "../storage";
|
|
8
|
+
import { SQLiteDatabaseDriver } from "../storage";
|
|
13
9
|
import { getSqliteStorage } from "../storage/sqlite";
|
|
14
10
|
import {
|
|
15
11
|
SQLiteDatabaseDriverAsync,
|
|
@@ -148,13 +144,11 @@ function trackStorageMessages(
|
|
|
148
144
|
const originalLoad = storage.load;
|
|
149
145
|
|
|
150
146
|
storage.store = function (data, correctionCallback) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
});
|
|
157
|
-
}
|
|
147
|
+
SyncMessagesLog.add({
|
|
148
|
+
from: nodeName,
|
|
149
|
+
to: storageName,
|
|
150
|
+
msg: data,
|
|
151
|
+
});
|
|
158
152
|
|
|
159
153
|
return originalStore.call(storage, data, (correction) => {
|
|
160
154
|
SyncMessagesLog.add({
|
|
@@ -167,7 +161,19 @@ function trackStorageMessages(
|
|
|
167
161
|
},
|
|
168
162
|
});
|
|
169
163
|
|
|
170
|
-
|
|
164
|
+
const correctionMessages = correctionCallback(correction);
|
|
165
|
+
|
|
166
|
+
if (correctionMessages) {
|
|
167
|
+
for (const msg of correctionMessages) {
|
|
168
|
+
SyncMessagesLog.add({
|
|
169
|
+
from: nodeName,
|
|
170
|
+
to: storageName,
|
|
171
|
+
msg,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return correctionMessages;
|
|
171
177
|
});
|
|
172
178
|
};
|
|
173
179
|
|
package/src/tests/testUtils.ts
CHANGED
|
@@ -40,6 +40,14 @@ export function randomAgentAndSessionID(): [ControlledAgent, SessionID] {
|
|
|
40
40
|
return [new ControlledAgent(agentSecret, Crypto), sessionID];
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export function agentAndSessionIDFromSecret(
|
|
44
|
+
secret: AgentSecret,
|
|
45
|
+
): [ControlledAgent, SessionID] {
|
|
46
|
+
const sessionID = Crypto.newRandomSessionID(Crypto.getAgentID(secret));
|
|
47
|
+
|
|
48
|
+
return [new ControlledAgent(secret, Crypto), sessionID];
|
|
49
|
+
}
|
|
50
|
+
|
|
43
51
|
export function nodeWithRandomAgentAndSessionID() {
|
|
44
52
|
const [agent, session] = randomAgentAndSessionID();
|
|
45
53
|
return new LocalNode(agent.agentSecret, session, Crypto);
|
|
@@ -154,8 +162,8 @@ export function connectTwoPeers(
|
|
|
154
162
|
bRole: "client" | "server",
|
|
155
163
|
) {
|
|
156
164
|
const [aAsPeer, bAsPeer] = connectedPeers(
|
|
157
|
-
"peer:" + a.
|
|
158
|
-
"peer:" + b.
|
|
165
|
+
"peer:" + a.currentSessionID,
|
|
166
|
+
"peer:" + b.currentSessionID,
|
|
159
167
|
{
|
|
160
168
|
peer1role: aRole,
|
|
161
169
|
peer2role: bRole,
|
|
@@ -443,7 +451,7 @@ export function getSyncServerConnectedPeer(opts: {
|
|
|
443
451
|
|
|
444
452
|
const { peer1, peer2 } = connectedPeersWithMessagesTracking({
|
|
445
453
|
peer1: {
|
|
446
|
-
id: currentSyncServer.
|
|
454
|
+
id: currentSyncServer.currentSessionID,
|
|
447
455
|
role: "server",
|
|
448
456
|
name: opts.syncServerName,
|
|
449
457
|
},
|
|
@@ -472,9 +480,13 @@ export function setupTestNode(
|
|
|
472
480
|
opts: {
|
|
473
481
|
isSyncServer?: boolean;
|
|
474
482
|
connected?: boolean;
|
|
483
|
+
secret?: AgentSecret;
|
|
475
484
|
} = {},
|
|
476
485
|
) {
|
|
477
|
-
const [admin, session] =
|
|
486
|
+
const [admin, session] = opts.secret
|
|
487
|
+
? agentAndSessionIDFromSecret(opts.secret)
|
|
488
|
+
: randomAgentAndSessionID();
|
|
489
|
+
|
|
478
490
|
let node = new LocalNode(admin.agentSecret, session, Crypto);
|
|
479
491
|
|
|
480
492
|
if (opts.isSyncServer) {
|
|
@@ -489,7 +501,7 @@ export function setupTestNode(
|
|
|
489
501
|
}) {
|
|
490
502
|
const { peer, peerStateOnServer, peerOnServer } =
|
|
491
503
|
getSyncServerConnectedPeer({
|
|
492
|
-
peerId:
|
|
504
|
+
peerId: session,
|
|
493
505
|
syncServerName: opts?.syncServerName,
|
|
494
506
|
ourName: opts?.ourName,
|
|
495
507
|
syncServer: opts?.syncServer,
|
|
@@ -551,6 +563,13 @@ export function setupTestNode(
|
|
|
551
563
|
|
|
552
564
|
return node;
|
|
553
565
|
},
|
|
566
|
+
spawnNewSession: () => {
|
|
567
|
+
return setupTestNode({
|
|
568
|
+
secret: node.agentSecret,
|
|
569
|
+
connected: opts.connected,
|
|
570
|
+
isSyncServer: opts.isSyncServer,
|
|
571
|
+
});
|
|
572
|
+
},
|
|
554
573
|
};
|
|
555
574
|
|
|
556
575
|
return ctx;
|
|
@@ -638,6 +657,11 @@ export async function setupTestAccount(
|
|
|
638
657
|
connectToSyncServer,
|
|
639
658
|
addStorage,
|
|
640
659
|
addAsyncStorage,
|
|
660
|
+
disconnect: () => {
|
|
661
|
+
ctx.node.syncManager.getPeers().forEach((peer) => {
|
|
662
|
+
peer.gracefulShutdown();
|
|
663
|
+
});
|
|
664
|
+
},
|
|
641
665
|
};
|
|
642
666
|
}
|
|
643
667
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RawAccountID } from "../coValues/account.js";
|
|
2
|
-
import { AgentID, SessionID } from "../ids.js";
|
|
1
|
+
import type { RawAccountID } from "../coValues/account.js";
|
|
2
|
+
import type { AgentID, SessionID } from "../ids.js";
|
|
3
3
|
|
|
4
4
|
export function accountOrAgentIDfromSessionID(
|
|
5
5
|
sessionID: SessionID,
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { type RawCoValue
|
|
1
|
+
import { type RawCoValue } from "../coValue.js";
|
|
2
2
|
import { RawGroup } from "../coValues/group.js";
|
|
3
3
|
|
|
4
4
|
export function expectGroup(content: RawCoValue): RawGroup {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
if (content.type !== "comap") {
|
|
6
|
+
throw new Error("Expected group");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (content.core.verified.header.ruleset.type !== "group") {
|
|
7
10
|
throw new Error("Expected group ruleset in group");
|
|
8
11
|
}
|
|
9
12
|
|
|
10
|
-
if (!(
|
|
13
|
+
if (!(content instanceof RawGroup)) {
|
|
11
14
|
throw new Error("Expected group");
|
|
12
15
|
}
|
|
13
16
|
|
|
14
|
-
return
|
|
17
|
+
return content;
|
|
15
18
|
}
|