cojson 0.19.21 → 0.20.0
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 +67 -0
- package/dist/CojsonMessageChannel/CojsonMessageChannel.d.ts +42 -0
- package/dist/CojsonMessageChannel/CojsonMessageChannel.d.ts.map +1 -0
- package/dist/CojsonMessageChannel/CojsonMessageChannel.js +261 -0
- package/dist/CojsonMessageChannel/CojsonMessageChannel.js.map +1 -0
- package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.d.ts +18 -0
- package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.d.ts.map +1 -0
- package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.js +37 -0
- package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.js.map +1 -0
- package/dist/CojsonMessageChannel/index.d.ts +3 -0
- package/dist/CojsonMessageChannel/index.d.ts.map +1 -0
- package/dist/CojsonMessageChannel/index.js +2 -0
- package/dist/CojsonMessageChannel/index.js.map +1 -0
- package/dist/CojsonMessageChannel/types.d.ts +149 -0
- package/dist/CojsonMessageChannel/types.d.ts.map +1 -0
- package/dist/CojsonMessageChannel/types.js +36 -0
- package/dist/CojsonMessageChannel/types.js.map +1 -0
- package/dist/GarbageCollector.d.ts +4 -2
- package/dist/GarbageCollector.d.ts.map +1 -1
- package/dist/GarbageCollector.js +5 -3
- package/dist/GarbageCollector.js.map +1 -1
- package/dist/SyncStateManager.d.ts +3 -3
- package/dist/SyncStateManager.d.ts.map +1 -1
- package/dist/SyncStateManager.js +4 -4
- package/dist/SyncStateManager.js.map +1 -1
- package/dist/coValueContentMessage.d.ts +0 -2
- package/dist/coValueContentMessage.d.ts.map +1 -1
- package/dist/coValueContentMessage.js +0 -8
- package/dist/coValueContentMessage.js.map +1 -1
- package/dist/coValueCore/SessionMap.d.ts +4 -2
- package/dist/coValueCore/SessionMap.d.ts.map +1 -1
- package/dist/coValueCore/SessionMap.js +30 -0
- package/dist/coValueCore/SessionMap.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +86 -4
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +318 -17
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +6 -1
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +9 -0
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/coList.d.ts +3 -2
- package/dist/coValues/coList.d.ts.map +1 -1
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +3 -6
- package/dist/coValues/group.js.map +1 -1
- package/dist/config.d.ts +0 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -8
- package/dist/config.js.map +1 -1
- package/dist/crypto/NapiCrypto.d.ts +1 -2
- package/dist/crypto/NapiCrypto.d.ts.map +1 -1
- package/dist/crypto/NapiCrypto.js +19 -4
- package/dist/crypto/NapiCrypto.js.map +1 -1
- package/dist/crypto/RNCrypto.d.ts.map +1 -1
- package/dist/crypto/RNCrypto.js +19 -4
- package/dist/crypto/RNCrypto.js.map +1 -1
- package/dist/crypto/WasmCrypto.d.ts +11 -4
- package/dist/crypto/WasmCrypto.d.ts.map +1 -1
- package/dist/crypto/WasmCrypto.js +52 -10
- package/dist/crypto/WasmCrypto.js.map +1 -1
- package/dist/crypto/WasmCryptoEdge.d.ts +1 -0
- package/dist/crypto/WasmCryptoEdge.d.ts.map +1 -1
- package/dist/crypto/WasmCryptoEdge.js +4 -1
- package/dist/crypto/WasmCryptoEdge.js.map +1 -1
- package/dist/crypto/crypto.d.ts +3 -3
- package/dist/crypto/crypto.d.ts.map +1 -1
- package/dist/crypto/crypto.js +6 -1
- package/dist/crypto/crypto.js.map +1 -1
- package/dist/exports.d.ts +3 -2
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +3 -1
- package/dist/exports.js.map +1 -1
- package/dist/ids.d.ts +4 -1
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +4 -0
- package/dist/ids.js.map +1 -1
- package/dist/knownState.d.ts +2 -0
- package/dist/knownState.d.ts.map +1 -1
- package/dist/localNode.d.ts +13 -3
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +17 -2
- package/dist/localNode.js.map +1 -1
- package/dist/platformUtils.d.ts +3 -0
- package/dist/platformUtils.d.ts.map +1 -0
- package/dist/platformUtils.js +24 -0
- package/dist/platformUtils.js.map +1 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.d.ts +30 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.d.ts.map +1 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.js +84 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.js.map +1 -0
- package/dist/storage/sqlite/client.d.ts +3 -0
- package/dist/storage/sqlite/client.d.ts.map +1 -1
- package/dist/storage/sqlite/client.js +44 -0
- package/dist/storage/sqlite/client.js.map +1 -1
- package/dist/storage/sqlite/sqliteMigrations.d.ts.map +1 -1
- package/dist/storage/sqlite/sqliteMigrations.js +7 -0
- package/dist/storage/sqlite/sqliteMigrations.js.map +1 -1
- package/dist/storage/sqliteAsync/client.d.ts +3 -0
- package/dist/storage/sqliteAsync/client.d.ts.map +1 -1
- package/dist/storage/sqliteAsync/client.js +42 -0
- package/dist/storage/sqliteAsync/client.js.map +1 -1
- package/dist/storage/storageAsync.d.ts +15 -3
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js +60 -3
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/storage/storageSync.d.ts +14 -3
- package/dist/storage/storageSync.d.ts.map +1 -1
- package/dist/storage/storageSync.js +54 -3
- package/dist/storage/storageSync.js.map +1 -1
- package/dist/storage/types.d.ts +64 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js +12 -1
- package/dist/storage/types.js.map +1 -1
- package/dist/sync.d.ts +6 -0
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +69 -15
- package/dist/sync.js.map +1 -1
- package/dist/tests/CojsonMessageChannel.test.d.ts +2 -0
- package/dist/tests/CojsonMessageChannel.test.d.ts.map +1 -0
- package/dist/tests/CojsonMessageChannel.test.js +236 -0
- package/dist/tests/CojsonMessageChannel.test.js.map +1 -0
- package/dist/tests/DeletedCoValuesEraserScheduler.test.d.ts +2 -0
- package/dist/tests/DeletedCoValuesEraserScheduler.test.d.ts.map +1 -0
- package/dist/tests/DeletedCoValuesEraserScheduler.test.js +149 -0
- package/dist/tests/DeletedCoValuesEraserScheduler.test.js.map +1 -0
- package/dist/tests/GarbageCollector.test.js +91 -18
- package/dist/tests/GarbageCollector.test.js.map +1 -1
- package/dist/tests/StorageApiAsync.test.js +510 -146
- package/dist/tests/StorageApiAsync.test.js.map +1 -1
- package/dist/tests/StorageApiSync.test.js +531 -130
- package/dist/tests/StorageApiSync.test.js.map +1 -1
- package/dist/tests/SyncManager.processQueues.test.js +1 -1
- package/dist/tests/SyncManager.processQueues.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/WasmCrypto.test.js +6 -3
- package/dist/tests/WasmCrypto.test.js.map +1 -1
- package/dist/tests/coPlainText.test.js +1 -1
- package/dist/tests/coPlainText.test.js.map +1 -1
- package/dist/tests/coValueCore.loadFromStorage.test.js +4 -0
- package/dist/tests/coValueCore.loadFromStorage.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +34 -13
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/coreWasm.test.js +127 -4
- package/dist/tests/coreWasm.test.js.map +1 -1
- package/dist/tests/crypto.test.js +89 -93
- package/dist/tests/crypto.test.js.map +1 -1
- package/dist/tests/deleteCoValue.test.d.ts +2 -0
- package/dist/tests/deleteCoValue.test.d.ts.map +1 -0
- package/dist/tests/deleteCoValue.test.js +313 -0
- package/dist/tests/deleteCoValue.test.js.map +1 -0
- package/dist/tests/group.removeMember.test.js +18 -30
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/knownState.lazyLoading.test.js +4 -0
- package/dist/tests/knownState.lazyLoading.test.js.map +1 -1
- package/dist/tests/sync.deleted.test.d.ts +2 -0
- package/dist/tests/sync.deleted.test.d.ts.map +1 -0
- package/dist/tests/sync.deleted.test.js +214 -0
- package/dist/tests/sync.deleted.test.js.map +1 -0
- package/dist/tests/sync.garbageCollection.test.js +56 -32
- package/dist/tests/sync.garbageCollection.test.js.map +1 -1
- package/dist/tests/sync.load.test.js +3 -5
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +4 -3
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.peerReconciliation.test.js +3 -3
- package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +12 -11
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.js +7 -7
- package/dist/tests/sync.storageAsync.test.js.map +1 -1
- package/dist/tests/sync.test.js +3 -2
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.tracking.test.js +35 -4
- package/dist/tests/sync.tracking.test.js.map +1 -1
- package/dist/tests/testStorage.d.ts +3 -0
- package/dist/tests/testStorage.d.ts.map +1 -1
- package/dist/tests/testStorage.js +16 -2
- package/dist/tests/testStorage.js.map +1 -1
- package/dist/tests/testUtils.d.ts +29 -4
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +84 -9
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +6 -16
- package/src/CojsonMessageChannel/CojsonMessageChannel.ts +332 -0
- package/src/CojsonMessageChannel/MessagePortOutgoingChannel.ts +52 -0
- package/src/CojsonMessageChannel/index.ts +9 -0
- package/src/CojsonMessageChannel/types.ts +200 -0
- package/src/GarbageCollector.ts +5 -5
- package/src/SyncStateManager.ts +6 -6
- package/src/coValueContentMessage.ts +0 -14
- package/src/coValueCore/SessionMap.ts +43 -1
- package/src/coValueCore/coValueCore.ts +430 -15
- package/src/coValueCore/verifiedState.ts +26 -3
- package/src/coValues/coList.ts +5 -3
- package/src/coValues/group.ts +5 -6
- package/src/config.ts +0 -9
- package/src/crypto/NapiCrypto.ts +29 -13
- package/src/crypto/RNCrypto.ts +29 -11
- package/src/crypto/WasmCrypto.ts +67 -20
- package/src/crypto/WasmCryptoEdge.ts +5 -1
- package/src/crypto/crypto.ts +16 -4
- package/src/exports.ts +3 -0
- package/src/ids.ts +11 -1
- package/src/localNode.ts +18 -5
- package/src/platformUtils.ts +26 -0
- package/src/storage/DeletedCoValuesEraserScheduler.ts +124 -0
- package/src/storage/sqlite/client.ts +77 -0
- package/src/storage/sqlite/sqliteMigrations.ts +7 -0
- package/src/storage/sqliteAsync/client.ts +75 -0
- package/src/storage/storageAsync.ts +77 -4
- package/src/storage/storageSync.ts +73 -4
- package/src/storage/types.ts +75 -0
- package/src/sync.ts +84 -15
- package/src/tests/CojsonMessageChannel.test.ts +306 -0
- package/src/tests/DeletedCoValuesEraserScheduler.test.ts +185 -0
- package/src/tests/GarbageCollector.test.ts +119 -22
- package/src/tests/StorageApiAsync.test.ts +615 -156
- package/src/tests/StorageApiSync.test.ts +623 -137
- package/src/tests/SyncManager.processQueues.test.ts +1 -1
- package/src/tests/SyncStateManager.test.ts +1 -1
- package/src/tests/WasmCrypto.test.ts +8 -3
- package/src/tests/coPlainText.test.ts +1 -1
- package/src/tests/coValueCore.loadFromStorage.test.ts +8 -0
- package/src/tests/coValueCore.test.ts +49 -14
- package/src/tests/coreWasm.test.ts +319 -10
- package/src/tests/crypto.test.ts +141 -150
- package/src/tests/deleteCoValue.test.ts +528 -0
- package/src/tests/group.removeMember.test.ts +35 -35
- package/src/tests/knownState.lazyLoading.test.ts +8 -0
- package/src/tests/sync.deleted.test.ts +294 -0
- package/src/tests/sync.garbageCollection.test.ts +69 -36
- package/src/tests/sync.load.test.ts +3 -5
- package/src/tests/sync.mesh.test.ts +6 -3
- package/src/tests/sync.peerReconciliation.test.ts +3 -3
- package/src/tests/sync.storage.test.ts +14 -11
- package/src/tests/sync.storageAsync.test.ts +7 -7
- package/src/tests/sync.test.ts +5 -2
- package/src/tests/sync.tracking.test.ts +54 -4
- package/src/tests/testStorage.ts +30 -3
- package/src/tests/testUtils.ts +113 -15
- package/dist/crypto/PureJSCrypto.d.ts +0 -77
- package/dist/crypto/PureJSCrypto.d.ts.map +0 -1
- package/dist/crypto/PureJSCrypto.js +0 -236
- package/dist/crypto/PureJSCrypto.js.map +0 -1
- package/dist/tests/PureJSCrypto.test.d.ts +0 -2
- package/dist/tests/PureJSCrypto.test.d.ts.map +0 -1
- package/dist/tests/PureJSCrypto.test.js +0 -145
- package/dist/tests/PureJSCrypto.test.js.map +0 -1
- package/src/crypto/PureJSCrypto.ts +0 -429
- package/src/tests/PureJSCrypto.test.ts +0 -217
|
@@ -72,7 +72,7 @@ describe("client with storage syncs with server", () => {
|
|
|
72
72
|
const firstLoad = await loadCoValueOrFail(client.node, map.id);
|
|
73
73
|
await firstLoad.core.waitForSync(); // Need to wait for sync with storage
|
|
74
74
|
|
|
75
|
-
client.restart();
|
|
75
|
+
await client.restart();
|
|
76
76
|
|
|
77
77
|
client.connectToSyncServer();
|
|
78
78
|
client.addStorage({
|
|
@@ -311,7 +311,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
311
311
|
|
|
312
312
|
SyncMessagesLog.clear();
|
|
313
313
|
|
|
314
|
-
client.restart();
|
|
314
|
+
await client.restart();
|
|
315
315
|
|
|
316
316
|
client.connectToSyncServer({
|
|
317
317
|
ourName: "client",
|
|
@@ -406,7 +406,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
406
406
|
const largeMapContent =
|
|
407
407
|
largeMap.core.newContentSince(undefined)?.slice(0, 4) ?? [];
|
|
408
408
|
|
|
409
|
-
client.restart();
|
|
409
|
+
await client.restart();
|
|
410
410
|
|
|
411
411
|
const newSyncServer = setupTestNode({
|
|
412
412
|
isSyncServer: true,
|
|
@@ -518,7 +518,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
518
518
|
|
|
519
519
|
expect(correctionSpy).not.toHaveBeenCalled();
|
|
520
520
|
|
|
521
|
-
client.restart();
|
|
521
|
+
await client.restart();
|
|
522
522
|
|
|
523
523
|
client.connectToSyncServer({
|
|
524
524
|
ourName: "client",
|
|
@@ -566,14 +566,14 @@ describe("client syncs with a server with storage", () => {
|
|
|
566
566
|
|
|
567
567
|
await largeMap.core.waitForSync();
|
|
568
568
|
|
|
569
|
-
server.restart();
|
|
569
|
+
await server.restart();
|
|
570
570
|
|
|
571
571
|
server.addStorage({
|
|
572
572
|
ourName: "server",
|
|
573
573
|
storage: serverStorage,
|
|
574
574
|
});
|
|
575
575
|
|
|
576
|
-
client.restart();
|
|
576
|
+
await client.restart();
|
|
577
577
|
|
|
578
578
|
client.connectToSyncServer({
|
|
579
579
|
ourName: "client",
|
|
@@ -703,7 +703,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
703
703
|
|
|
704
704
|
SyncMessagesLog.clear();
|
|
705
705
|
|
|
706
|
-
syncServer.restart();
|
|
706
|
+
await syncServer.restart();
|
|
707
707
|
syncServer.addStorage({
|
|
708
708
|
ourName: "syncServer",
|
|
709
709
|
storage,
|
package/src/tests/sync.test.ts
CHANGED
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
tearDownTestMetricReader,
|
|
19
19
|
waitFor,
|
|
20
20
|
} from "./testUtils.js";
|
|
21
|
-
import {
|
|
21
|
+
import { Stringified } from "../jsonStringify.js";
|
|
22
|
+
import { JsonValue } from "../jsonValue.js";
|
|
22
23
|
|
|
23
24
|
// We want to simulate a real world communication that happens asynchronously
|
|
24
25
|
TEST_NODE_CONFIG.withAsyncPeers = true;
|
|
@@ -168,7 +169,9 @@ test("should not verify transactions when SyncManager has verification disabled"
|
|
|
168
169
|
[
|
|
169
170
|
{
|
|
170
171
|
privacy: "trusting",
|
|
171
|
-
changes:
|
|
172
|
+
changes: JSON.stringify([
|
|
173
|
+
{ op: "set", key: "hello", value: "world" },
|
|
174
|
+
]) as Stringified<JsonValue[]>,
|
|
172
175
|
madeAt: Date.now(),
|
|
173
176
|
},
|
|
174
177
|
],
|
|
@@ -73,6 +73,56 @@ describe("coValue sync state tracking", () => {
|
|
|
73
73
|
expect(unsyncedTracker.has(map.id)).toBe(true);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
test("coValue is marked as synced after connecting to a server peer", async () => {
|
|
77
|
+
const client = setupTestNode({ connected: false });
|
|
78
|
+
|
|
79
|
+
const group = client.node.createGroup();
|
|
80
|
+
const map = group.createMap();
|
|
81
|
+
map.set("key", "value");
|
|
82
|
+
|
|
83
|
+
await new Promise<void>((resolve) => queueMicrotask(resolve));
|
|
84
|
+
|
|
85
|
+
const unsyncedTracker = client.node.syncManager.unsyncedTracker;
|
|
86
|
+
expect(unsyncedTracker.has(map.id)).toBe(true);
|
|
87
|
+
|
|
88
|
+
client.connectToSyncServer();
|
|
89
|
+
|
|
90
|
+
const serverPeer =
|
|
91
|
+
client.node.syncManager.peers[jazzCloud.node.currentSessionID]!;
|
|
92
|
+
await waitFor(() =>
|
|
93
|
+
client.node.syncManager.syncState.isSynced(serverPeer, map.id),
|
|
94
|
+
);
|
|
95
|
+
expect(unsyncedTracker.has(map.id)).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("coValue is NOT marked as synced after uploading it to a client peer", async () => {
|
|
99
|
+
const client = setupTestNode({ connected: false });
|
|
100
|
+
|
|
101
|
+
const group = client.node.createGroup();
|
|
102
|
+
const map = group.createMap();
|
|
103
|
+
map.set("key", "value");
|
|
104
|
+
|
|
105
|
+
await new Promise<void>((resolve) => queueMicrotask(resolve));
|
|
106
|
+
|
|
107
|
+
const unsyncedTracker = client.node.syncManager.unsyncedTracker;
|
|
108
|
+
expect(unsyncedTracker.has(map.id)).toBe(true);
|
|
109
|
+
|
|
110
|
+
const anotherClient = setupTestNode({ connected: false });
|
|
111
|
+
anotherClient.connectToSyncServer({
|
|
112
|
+
syncServer: client.node,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Load the coValue from the client to trigger sync between the server and the client
|
|
116
|
+
await anotherClient.node.loadCoValueCore(map.id);
|
|
117
|
+
|
|
118
|
+
const clientPeer =
|
|
119
|
+
client.node.syncManager.peers[anotherClient.node.currentSessionID]!;
|
|
120
|
+
await waitFor(() =>
|
|
121
|
+
client.node.syncManager.syncState.isSynced(clientPeer, map.id),
|
|
122
|
+
);
|
|
123
|
+
expect(unsyncedTracker.has(map.id)).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
|
|
76
126
|
test("only tracks sync state for persistent servers peers", async () => {
|
|
77
127
|
const { node: client, connectToSyncServer } = setupTestNode({
|
|
78
128
|
connected: true,
|
|
@@ -262,7 +312,7 @@ describe("sync resumption", () => {
|
|
|
262
312
|
expect(unsyncedTracker.has(map.id)).toBe(true);
|
|
263
313
|
expect(await getUnsyncedCoValueIDsFromStorage()).toHaveLength(2);
|
|
264
314
|
|
|
265
|
-
client.restart();
|
|
315
|
+
await client.restart();
|
|
266
316
|
client.addStorage({ storage });
|
|
267
317
|
const { peerState: serverPeerState } = client.connectToSyncServer();
|
|
268
318
|
|
|
@@ -300,7 +350,7 @@ describe("sync resumption", () => {
|
|
|
300
350
|
}
|
|
301
351
|
expect(await getUnsyncedCoValueIDsFromStorage()).toHaveLength(101);
|
|
302
352
|
|
|
303
|
-
client.restart();
|
|
353
|
+
await client.restart();
|
|
304
354
|
client.addStorage({ storage });
|
|
305
355
|
const { peerState: serverPeerState } = client.connectToSyncServer();
|
|
306
356
|
|
|
@@ -339,7 +389,7 @@ describe("sync resumption", () => {
|
|
|
339
389
|
|
|
340
390
|
expect(await getUnsyncedCoValueIDsFromStorage()).toHaveLength(2);
|
|
341
391
|
|
|
342
|
-
client.restart();
|
|
392
|
+
await client.restart();
|
|
343
393
|
client.addStorage({ storage });
|
|
344
394
|
const newSyncServer = setupTestNode({ isSyncServer: true });
|
|
345
395
|
const { peerState: newServerPeerState } = client.connectToSyncServer({
|
|
@@ -377,7 +427,7 @@ describe("sync resumption", () => {
|
|
|
377
427
|
expect(unsyncedCoValueIDs).toContain(map.id);
|
|
378
428
|
expect(unsyncedCoValueIDs).toContain(group.id);
|
|
379
429
|
|
|
380
|
-
client.restart();
|
|
430
|
+
await client.restart();
|
|
381
431
|
client.addStorage({ storage });
|
|
382
432
|
const newPeer = setupTestNode({ isSyncServer: true });
|
|
383
433
|
client.connectToSyncServer({
|
package/src/tests/testStorage.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { tmpdir } from "node:os";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import Database, { type Database as DatabaseT } from "libsql";
|
|
6
6
|
import { onTestFinished } from "vitest";
|
|
7
|
-
import { RawCoID, StorageAPI } from "../exports";
|
|
7
|
+
import { RawCoID, SessionID, StorageAPI } from "../exports";
|
|
8
8
|
import { SQLiteDatabaseDriver } from "../storage";
|
|
9
9
|
import { getSqliteStorage } from "../storage/sqlite";
|
|
10
10
|
import {
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
getSqliteStorageAsync,
|
|
13
13
|
} from "../storage/sqliteAsync";
|
|
14
14
|
import { SyncMessagesLog, SyncTestMessage } from "./testUtils";
|
|
15
|
+
import { knownStateFromContent } from "../coValueContentMessage";
|
|
15
16
|
|
|
16
17
|
class LibSQLSqliteAsyncDriver implements SQLiteDatabaseDriverAsync {
|
|
17
18
|
private readonly db: DatabaseT;
|
|
@@ -104,8 +105,8 @@ export async function createAsyncStorage({
|
|
|
104
105
|
new LibSQLSqliteAsyncDriver(getDbPath(filename)),
|
|
105
106
|
);
|
|
106
107
|
|
|
107
|
-
onTestFinished(() => {
|
|
108
|
-
storage.close();
|
|
108
|
+
onTestFinished(async () => {
|
|
109
|
+
await storage.close();
|
|
109
110
|
});
|
|
110
111
|
|
|
111
112
|
trackStorageMessages(storage, nodeName, storageName);
|
|
@@ -131,6 +132,32 @@ export function createSyncStorage({
|
|
|
131
132
|
return storage;
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
export async function getAllCoValuesWaitingForDelete(
|
|
136
|
+
storage: StorageAPI,
|
|
137
|
+
): Promise<RawCoID[]> {
|
|
138
|
+
// @ts-expect-error - dbClient is private
|
|
139
|
+
return storage.dbClient.getAllCoValuesWaitingForDelete();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function getCoValueStoredSessions(
|
|
143
|
+
storage: StorageAPI,
|
|
144
|
+
id: RawCoID,
|
|
145
|
+
): Promise<SessionID[]> {
|
|
146
|
+
return new Promise<SessionID[]>((resolve) => {
|
|
147
|
+
storage.load(
|
|
148
|
+
id,
|
|
149
|
+
(content) => {
|
|
150
|
+
if (content.id === id) {
|
|
151
|
+
resolve(
|
|
152
|
+
Object.keys(knownStateFromContent(content).sessions) as SessionID[],
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
() => {},
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
134
161
|
export function getDbPath(defaultDbPath?: string) {
|
|
135
162
|
const dbPath = defaultDbPath ?? join(tmpdir(), `test-${randomUUID()}.db`);
|
|
136
163
|
|
package/src/tests/testUtils.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
MeterProvider,
|
|
6
6
|
MetricReader,
|
|
7
7
|
} from "@opentelemetry/sdk-metrics";
|
|
8
|
-
import { expect, onTestFinished, vi } from "vitest";
|
|
8
|
+
import { assert, expect, onTestFinished, vi } from "vitest";
|
|
9
9
|
import { ControlledAccount, ControlledAgent } from "../coValues/account.js";
|
|
10
10
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
11
11
|
import {
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
AnyRawCoValue,
|
|
14
14
|
type CoID,
|
|
15
15
|
type CoValueCore,
|
|
16
|
+
MessageChannelLike,
|
|
17
|
+
MessagePortLike,
|
|
16
18
|
type RawAccount,
|
|
17
19
|
RawAccountID,
|
|
18
20
|
RawCoMap,
|
|
@@ -26,15 +28,12 @@ import type { Peer, SyncMessage, SyncWhen } from "../sync.js";
|
|
|
26
28
|
import { expectGroup } from "../typeUtils/expectGroup.js";
|
|
27
29
|
import { toSimplifiedMessages } from "./messagesTestUtils.js";
|
|
28
30
|
import { createAsyncStorage, createSyncStorage } from "./testStorage.js";
|
|
29
|
-
import { PureJSCrypto } from "../crypto/PureJSCrypto.js";
|
|
30
31
|
import { CoValueHeader } from "../coValueCore/verifiedState.js";
|
|
31
32
|
import { idforHeader } from "../coValueCore/coValueCore.js";
|
|
32
33
|
|
|
33
34
|
let Crypto = await WasmCrypto.create();
|
|
34
35
|
|
|
35
|
-
export function setCurrentTestCryptoProvider(
|
|
36
|
-
crypto: WasmCrypto | PureJSCrypto,
|
|
37
|
-
) {
|
|
36
|
+
export function setCurrentTestCryptoProvider(crypto: WasmCrypto) {
|
|
38
37
|
Crypto = crypto;
|
|
39
38
|
}
|
|
40
39
|
|
|
@@ -187,8 +186,8 @@ export function newGroupHighLevel() {
|
|
|
187
186
|
|
|
188
187
|
const group = node.createGroup();
|
|
189
188
|
|
|
190
|
-
onTestFinished(() => {
|
|
191
|
-
node.gracefulShutdown();
|
|
189
|
+
onTestFinished(async () => {
|
|
190
|
+
await node.gracefulShutdown();
|
|
192
191
|
});
|
|
193
192
|
return { admin, node, group };
|
|
194
193
|
}
|
|
@@ -501,11 +500,11 @@ export function setupTestNode(
|
|
|
501
500
|
}
|
|
502
501
|
|
|
503
502
|
async function addAsyncStorage(
|
|
504
|
-
opts: { ourName?: string; filename?: string } = {},
|
|
503
|
+
opts: { ourName?: string; filename?: string; storageName?: string } = {},
|
|
505
504
|
) {
|
|
506
505
|
const storage = await createAsyncStorage({
|
|
507
506
|
nodeName: opts.ourName ?? "client",
|
|
508
|
-
storageName: "storage",
|
|
507
|
+
storageName: opts.storageName ?? "storage",
|
|
509
508
|
filename: opts.filename,
|
|
510
509
|
});
|
|
511
510
|
node.setStorage(storage);
|
|
@@ -517,8 +516,8 @@ export function setupTestNode(
|
|
|
517
516
|
connectToSyncServer();
|
|
518
517
|
}
|
|
519
518
|
|
|
520
|
-
onTestFinished(() => {
|
|
521
|
-
node.gracefulShutdown();
|
|
519
|
+
onTestFinished(async () => {
|
|
520
|
+
await node.gracefulShutdown();
|
|
522
521
|
});
|
|
523
522
|
|
|
524
523
|
const ctx = {
|
|
@@ -526,8 +525,8 @@ export function setupTestNode(
|
|
|
526
525
|
connectToSyncServer,
|
|
527
526
|
addStorage,
|
|
528
527
|
addAsyncStorage,
|
|
529
|
-
restart: () => {
|
|
530
|
-
node.gracefulShutdown();
|
|
528
|
+
restart: async () => {
|
|
529
|
+
await node.gracefulShutdown();
|
|
531
530
|
ctx.node = node = new LocalNode(
|
|
532
531
|
admin.agentSecret,
|
|
533
532
|
session,
|
|
@@ -638,10 +637,12 @@ export async function setupTestAccount(
|
|
|
638
637
|
return { storage };
|
|
639
638
|
}
|
|
640
639
|
|
|
641
|
-
async function addAsyncStorage(
|
|
640
|
+
async function addAsyncStorage(
|
|
641
|
+
opts: { ourName?: string; storageName?: string } = {},
|
|
642
|
+
) {
|
|
642
643
|
const storage = await createAsyncStorage({
|
|
643
644
|
nodeName: opts.ourName ?? "client",
|
|
644
|
-
storageName: "storage",
|
|
645
|
+
storageName: opts.storageName ?? "storage",
|
|
645
646
|
});
|
|
646
647
|
ctx.node.setStorage(storage);
|
|
647
648
|
|
|
@@ -656,9 +657,14 @@ export async function setupTestAccount(
|
|
|
656
657
|
await ctx.node.gracefulShutdown();
|
|
657
658
|
});
|
|
658
659
|
|
|
660
|
+
const account = ctx.node
|
|
661
|
+
.getCoValue(ctx.accountID)
|
|
662
|
+
.getCurrentContent() as RawAccount;
|
|
663
|
+
|
|
659
664
|
return {
|
|
660
665
|
node: ctx.node,
|
|
661
666
|
accountID: ctx.accountID,
|
|
667
|
+
account,
|
|
662
668
|
connectToSyncServer,
|
|
663
669
|
addStorage,
|
|
664
670
|
addAsyncStorage,
|
|
@@ -811,3 +817,95 @@ export function fillCoMapWithLargeData(map: RawCoMap) {
|
|
|
811
817
|
|
|
812
818
|
return map;
|
|
813
819
|
}
|
|
820
|
+
|
|
821
|
+
export function importContentIntoNode(
|
|
822
|
+
coValue: CoValueCore,
|
|
823
|
+
node: LocalNode,
|
|
824
|
+
chunks?: number,
|
|
825
|
+
) {
|
|
826
|
+
const content = coValue.newContentSince(undefined);
|
|
827
|
+
assert(content);
|
|
828
|
+
for (const [i, chunk] of content.entries()) {
|
|
829
|
+
if (chunks && i >= chunks) {
|
|
830
|
+
break;
|
|
831
|
+
}
|
|
832
|
+
node.syncManager.handleNewContent(chunk, "import");
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// ============================================================================
|
|
837
|
+
// MessageChannel Test Helpers
|
|
838
|
+
// ============================================================================
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* Type guard to check if a message is a SyncMessage.
|
|
842
|
+
*/
|
|
843
|
+
export function isSyncMessage(msg: unknown): msg is SyncMessage {
|
|
844
|
+
return (
|
|
845
|
+
typeof msg === "object" &&
|
|
846
|
+
msg !== null &&
|
|
847
|
+
"action" in msg &&
|
|
848
|
+
typeof (msg as { action: unknown }).action === "string"
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* Creates a MessageChannel that logs all sync messages exchanged between ports.
|
|
854
|
+
* Similar to connectedPeersWithMessagesTracking but for MessageChannel.
|
|
855
|
+
*/
|
|
856
|
+
export function createTrackedMessageChannel(opts: {
|
|
857
|
+
port1Name?: string;
|
|
858
|
+
port2Name?: string;
|
|
859
|
+
}) {
|
|
860
|
+
const { port1, port2 } = new MessageChannel();
|
|
861
|
+
const port1Name = opts.port1Name ?? "port1";
|
|
862
|
+
const port2Name = opts.port2Name ?? "port2";
|
|
863
|
+
|
|
864
|
+
// Wrap port1.postMessage to log messages
|
|
865
|
+
const originalPort1PostMessage = port1.postMessage.bind(port1);
|
|
866
|
+
port1.postMessage = (message, transfer) => {
|
|
867
|
+
if (isSyncMessage(message)) {
|
|
868
|
+
SyncMessagesLog.add({
|
|
869
|
+
from: port1Name,
|
|
870
|
+
to: port2Name,
|
|
871
|
+
msg: message,
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
originalPort1PostMessage(message, transfer);
|
|
876
|
+
};
|
|
877
|
+
|
|
878
|
+
// Wrap port2.postMessage to log messages
|
|
879
|
+
const originalPort2PostMessage = port2.postMessage.bind(port2);
|
|
880
|
+
port2.postMessage = (message, transfer) => {
|
|
881
|
+
if (isSyncMessage(message)) {
|
|
882
|
+
SyncMessagesLog.add({
|
|
883
|
+
from: port2Name,
|
|
884
|
+
to: port1Name,
|
|
885
|
+
msg: message,
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
originalPort2PostMessage(message, transfer);
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
return { port1, port2 };
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/**
|
|
896
|
+
* Creates a mock worker target that simulates receiving a port
|
|
897
|
+
* and calling a callback with the received port (simulating a connection handshake).
|
|
898
|
+
*/
|
|
899
|
+
export function createMockWorkerWithAccept(
|
|
900
|
+
onPortReceived: (port: MessagePortLike) => Promise<void>,
|
|
901
|
+
) {
|
|
902
|
+
return {
|
|
903
|
+
postMessage: vi.fn().mockImplementation((data, transfer) => {
|
|
904
|
+
if (data?.type === "jazz:port" && transfer?.[0]) {
|
|
905
|
+
const port = transfer[0] as MessagePortLike;
|
|
906
|
+
// Simulate the worker receiving the port and calling accept
|
|
907
|
+
onPortReceived(port);
|
|
908
|
+
}
|
|
909
|
+
}),
|
|
910
|
+
};
|
|
911
|
+
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { PrivateTransaction, Transaction, TrustingTransaction } from "../coValueCore/verifiedState.js";
|
|
2
|
-
import { RawCoID, SessionID, TransactionID } from "../ids.js";
|
|
3
|
-
import { Stringified } from "../jsonStringify.js";
|
|
4
|
-
import { JsonObject, JsonValue } from "../jsonValue.js";
|
|
5
|
-
import { CryptoProvider, Encrypted, KeyID, KeySecret, Sealed, SealerID, SealerSecret, SessionLogImpl, Signature, SignerID, SignerSecret } from "./crypto.js";
|
|
6
|
-
import { ControlledAccountOrAgent } from "../coValues/account.js";
|
|
7
|
-
export type Blake3State = {
|
|
8
|
-
update: (buf: Uint8Array) => Blake3State;
|
|
9
|
-
digest: () => Uint8Array;
|
|
10
|
-
clone: () => Blake3State;
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Pure JavaScript implementation of the CryptoProvider interface using noble-curves and noble-ciphers libraries.
|
|
14
|
-
* This provides a fallback implementation that doesn't require WebAssembly, offering:
|
|
15
|
-
* - Signing/verifying (Ed25519)
|
|
16
|
-
* - Encryption/decryption (XSalsa20)
|
|
17
|
-
* - Sealing/unsealing (X25519 + XSalsa20-Poly1305)
|
|
18
|
-
* - Hashing (BLAKE3)
|
|
19
|
-
*/
|
|
20
|
-
export declare class PureJSCrypto extends CryptoProvider<Blake3State> {
|
|
21
|
-
static create(): Promise<PureJSCrypto>;
|
|
22
|
-
createStreamingHash(): Blake3State;
|
|
23
|
-
blake3HashOnce(data: Uint8Array): Uint8Array;
|
|
24
|
-
blake3HashOnceWithContext(data: Uint8Array, { context }: {
|
|
25
|
-
context: Uint8Array;
|
|
26
|
-
}): Uint8Array;
|
|
27
|
-
generateNonce(input: Uint8Array): Uint8Array;
|
|
28
|
-
generateJsonNonce(material: JsonValue): Uint8Array;
|
|
29
|
-
newEd25519SigningKey(): Uint8Array;
|
|
30
|
-
getSignerID(secret: SignerSecret): SignerID;
|
|
31
|
-
sign(secret: SignerSecret, message: JsonValue): Signature;
|
|
32
|
-
verify(signature: Signature, message: JsonValue, id: SignerID): boolean;
|
|
33
|
-
newX25519StaticSecret(): Uint8Array;
|
|
34
|
-
getSealerID(secret: SealerSecret): SealerID;
|
|
35
|
-
encrypt<T extends JsonValue, N extends JsonValue>(value: T, keySecret: KeySecret, nOnceMaterial: N): Encrypted<T, N>;
|
|
36
|
-
decryptRaw<T extends JsonValue, N extends JsonValue>(encrypted: Encrypted<T, N>, keySecret: KeySecret, nOnceMaterial: N): Stringified<T>;
|
|
37
|
-
seal<T extends JsonValue>({ message, from, to, nOnceMaterial, }: {
|
|
38
|
-
message: T;
|
|
39
|
-
from: SealerSecret;
|
|
40
|
-
to: SealerID;
|
|
41
|
-
nOnceMaterial: {
|
|
42
|
-
in: RawCoID;
|
|
43
|
-
tx: TransactionID;
|
|
44
|
-
};
|
|
45
|
-
}): Sealed<T>;
|
|
46
|
-
unseal<T extends JsonValue>(sealed: Sealed<T>, sealer: SealerSecret, from: SealerID, nOnceMaterial: {
|
|
47
|
-
in: RawCoID;
|
|
48
|
-
tx: TransactionID;
|
|
49
|
-
}): T | undefined;
|
|
50
|
-
createSessionLog(coID: RawCoID, sessionID: SessionID, signerID?: SignerID): SessionLogImpl;
|
|
51
|
-
}
|
|
52
|
-
export declare class PureJSSessionLog implements SessionLogImpl {
|
|
53
|
-
private readonly coID;
|
|
54
|
-
private readonly sessionID;
|
|
55
|
-
private readonly signerID;
|
|
56
|
-
private readonly crypto;
|
|
57
|
-
transactions: string[];
|
|
58
|
-
lastSignature: Signature | undefined;
|
|
59
|
-
streamingHash: Blake3State;
|
|
60
|
-
constructor(coID: RawCoID, sessionID: SessionID, signerID: SignerID | undefined, crypto: PureJSCrypto);
|
|
61
|
-
clone(): SessionLogImpl;
|
|
62
|
-
tryAdd(transactions: Transaction[], newSignature: Signature, skipVerify: boolean): void;
|
|
63
|
-
internalTryAdd(transactions: string[], newSignature: Signature, skipVerify: boolean): `signature_z${string}`;
|
|
64
|
-
internalAddNewTransaction(transaction: string, signerAgent: ControlledAccountOrAgent): `signature_z${string}`;
|
|
65
|
-
addNewPrivateTransaction(signerAgent: ControlledAccountOrAgent, changes: JsonValue[], keyID: KeyID, keySecret: KeySecret, madeAt: number, meta: JsonObject | undefined): {
|
|
66
|
-
signature: Signature;
|
|
67
|
-
transaction: PrivateTransaction;
|
|
68
|
-
};
|
|
69
|
-
addNewTrustingTransaction(signerAgent: ControlledAccountOrAgent, changes: JsonValue[], madeAt: number, meta: JsonObject | undefined): {
|
|
70
|
-
signature: Signature;
|
|
71
|
-
transaction: TrustingTransaction;
|
|
72
|
-
};
|
|
73
|
-
decryptNextTransactionChangesJson(txIndex: number, keySecret: KeySecret): string;
|
|
74
|
-
decryptNextTransactionMetaJson(txIndex: number, keySecret: KeySecret): string | undefined;
|
|
75
|
-
free(): void;
|
|
76
|
-
}
|
|
77
|
-
//# sourceMappingURL=PureJSCrypto.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PureJSCrypto.d.ts","sourceRoot":"","sources":["../../src/crypto/PureJSCrypto.ts"],"names":[],"mappings":"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"}
|