cojson 0.19.22 → 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 +54 -0
- 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 +67 -3
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +289 -12
- 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 +2 -2
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +2 -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 +12 -0
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +14 -0
- 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 +7 -0
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js +48 -0
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/storage/storageSync.d.ts +6 -0
- package/dist/storage/storageSync.d.ts.map +1 -1
- package/dist/storage/storageSync.js +42 -0
- package/dist/storage/storageSync.js.map +1 -1
- package/dist/storage/types.d.ts +59 -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.map +1 -1
- package/dist/sync.js +44 -11
- package/dist/sync.js.map +1 -1
- 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 +5 -6
- package/dist/tests/GarbageCollector.test.js.map +1 -1
- package/dist/tests/StorageApiAsync.test.js +484 -152
- package/dist/tests/StorageApiAsync.test.js.map +1 -1
- package/dist/tests/StorageApiSync.test.js +505 -136
- package/dist/tests/StorageApiSync.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/coValueCore.loadFromStorage.test.js +3 -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 +3 -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.mesh.test.js +3 -2
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +3 -2
- package/dist/tests/sync.storage.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/testStorage.d.ts +3 -0
- package/dist/tests/testStorage.d.ts.map +1 -1
- package/dist/tests/testStorage.js +14 -0
- package/dist/tests/testStorage.js.map +1 -1
- package/dist/tests/testUtils.d.ts +6 -3
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +17 -3
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +6 -16
- package/src/coValueContentMessage.ts +0 -14
- package/src/coValueCore/SessionMap.ts +43 -1
- package/src/coValueCore/coValueCore.ts +400 -8
- 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 +2 -0
- package/src/ids.ts +11 -1
- package/src/localNode.ts +15 -0
- 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 +62 -0
- package/src/storage/storageSync.ts +58 -0
- package/src/storage/types.ts +69 -0
- package/src/sync.ts +51 -11
- package/src/tests/DeletedCoValuesEraserScheduler.test.ts +185 -0
- package/src/tests/GarbageCollector.test.ts +6 -10
- package/src/tests/StorageApiAsync.test.ts +572 -162
- package/src/tests/StorageApiSync.test.ts +580 -143
- package/src/tests/WasmCrypto.test.ts +8 -3
- package/src/tests/coValueCore.loadFromStorage.test.ts +6 -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 +6 -0
- package/src/tests/sync.deleted.test.ts +294 -0
- package/src/tests/sync.mesh.test.ts +5 -2
- package/src/tests/sync.storage.test.ts +5 -2
- package/src/tests/sync.test.ts +5 -2
- package/src/tests/testStorage.ts +28 -1
- package/src/tests/testUtils.ts +28 -9
- 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
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import { describe, expect, onTestFinished, test, vi } from "vitest";
|
|
6
|
-
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
7
|
-
import { LocalNode, logger } from "../exports.js";
|
|
1
|
+
import { describe, expect, test, vi, afterEach } from "vitest";
|
|
2
|
+
import { logger } from "../exports.js";
|
|
8
3
|
import { emptyKnownState } from "../knownState.js";
|
|
9
|
-
import { createSyncStorage } from "./testStorage.js";
|
|
10
|
-
import { loadCoValueOrFail,
|
|
11
|
-
const crypto = await WasmCrypto.create();
|
|
4
|
+
import { createSyncStorage, getAllCoValuesWaitingForDelete, getCoValueStoredSessions, getDbPath, } from "./testStorage.js";
|
|
5
|
+
import { fillCoMapWithLargeData, loadCoValueOrFail, setupTestNode, } from "./testUtils.js";
|
|
12
6
|
/**
|
|
13
7
|
* Helper function that gets new content since a known state, throwing if:
|
|
14
8
|
* - The coValue is not verified
|
|
@@ -24,53 +18,33 @@ function getNewContentSince(coValue, knownState) {
|
|
|
24
18
|
}
|
|
25
19
|
return contentMessage;
|
|
26
20
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// Create a unique database file for each test
|
|
31
|
-
const dbPath = customDbPath ?? join(tmpdir(), `test-${randomUUID()}.db`);
|
|
32
|
-
const storage = createSyncStorage({
|
|
33
|
-
filename: dbPath,
|
|
34
|
-
nodeName: "test",
|
|
35
|
-
storageName: "test-storage",
|
|
36
|
-
});
|
|
37
|
-
onTestFinished(() => {
|
|
38
|
-
try {
|
|
39
|
-
unlinkSync(dbPath);
|
|
40
|
-
}
|
|
41
|
-
catch { }
|
|
42
|
-
});
|
|
43
|
-
node.setStorage(storage);
|
|
44
|
-
return {
|
|
45
|
-
fixturesNode: node,
|
|
46
|
-
dbPath,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
async function createTestNode(dbPath) {
|
|
50
|
-
const [admin, session] = randomAgentAndSessionID();
|
|
51
|
-
const node = new LocalNode(admin.agentSecret, session, crypto);
|
|
52
|
-
const storage = createSyncStorage({
|
|
53
|
-
filename: dbPath,
|
|
54
|
-
nodeName: "test",
|
|
55
|
-
storageName: "test-storage",
|
|
56
|
-
});
|
|
57
|
-
return {
|
|
58
|
-
node,
|
|
59
|
-
storage,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
vi.useRealTimers();
|
|
23
|
+
});
|
|
62
24
|
describe("StorageApiSync", () => {
|
|
63
25
|
describe("getKnownState", () => {
|
|
64
26
|
test("should return empty known state for new coValue ID and cache the result", async () => {
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
const
|
|
27
|
+
const fixtures = setupTestNode();
|
|
28
|
+
const client = setupTestNode();
|
|
29
|
+
const { storage } = client.addStorage({
|
|
30
|
+
storage: createSyncStorage({
|
|
31
|
+
nodeName: "test",
|
|
32
|
+
storageName: "test-storage",
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
const id = fixtures.node.createGroup().id;
|
|
68
36
|
const knownState = storage.getKnownState(id);
|
|
69
37
|
expect(knownState).toEqual(emptyKnownState(id));
|
|
70
38
|
expect(storage.getKnownState(id)).toBe(knownState); // Should return same instance
|
|
71
39
|
});
|
|
72
40
|
test("should return separate known state instances for different coValue IDs", async () => {
|
|
73
|
-
const
|
|
41
|
+
const client = setupTestNode();
|
|
42
|
+
const { storage } = client.addStorage({
|
|
43
|
+
storage: createSyncStorage({
|
|
44
|
+
nodeName: "test",
|
|
45
|
+
storageName: "test-storage",
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
74
48
|
const id1 = "test-id-1";
|
|
75
49
|
const id2 = "test-id-2";
|
|
76
50
|
const knownState1 = storage.getKnownState(id1);
|
|
@@ -80,7 +54,13 @@ describe("StorageApiSync", () => {
|
|
|
80
54
|
});
|
|
81
55
|
describe("load", () => {
|
|
82
56
|
test("should fail gracefully when loading non-existent coValue and preserve known state", async () => {
|
|
83
|
-
const
|
|
57
|
+
const client = setupTestNode();
|
|
58
|
+
const { storage } = client.addStorage({
|
|
59
|
+
storage: createSyncStorage({
|
|
60
|
+
nodeName: "test",
|
|
61
|
+
storageName: "test-storage",
|
|
62
|
+
}),
|
|
63
|
+
});
|
|
84
64
|
const id = "non-existent-id";
|
|
85
65
|
const callback = vi.fn();
|
|
86
66
|
const done = vi.fn();
|
|
@@ -95,12 +75,27 @@ describe("StorageApiSync", () => {
|
|
|
95
75
|
expect(afterLoadKnownState).toEqual(initialKnownState);
|
|
96
76
|
});
|
|
97
77
|
test("should successfully load coValue with header and update known state", async () => {
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
78
|
+
const dbPath = getDbPath();
|
|
79
|
+
const fixtures = setupTestNode();
|
|
80
|
+
fixtures.addStorage({
|
|
81
|
+
storage: createSyncStorage({
|
|
82
|
+
filename: dbPath,
|
|
83
|
+
nodeName: "test",
|
|
84
|
+
storageName: "test-storage",
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
const client = setupTestNode();
|
|
88
|
+
const { storage } = client.addStorage({
|
|
89
|
+
storage: createSyncStorage({
|
|
90
|
+
filename: dbPath,
|
|
91
|
+
nodeName: "test",
|
|
92
|
+
storageName: "test-storage",
|
|
93
|
+
}),
|
|
94
|
+
});
|
|
95
|
+
const callback = vi.fn((content) => client.node.syncManager.handleNewContent(content, "storage"));
|
|
101
96
|
const done = vi.fn();
|
|
102
97
|
// Create a real group and get its content message
|
|
103
|
-
const group =
|
|
98
|
+
const group = fixtures.node.createGroup();
|
|
104
99
|
await group.core.waitForSync();
|
|
105
100
|
// Get initial known state
|
|
106
101
|
const initialKnownState = storage.getKnownState(group.id);
|
|
@@ -115,16 +110,31 @@ describe("StorageApiSync", () => {
|
|
|
115
110
|
// Verify that storage known state is updated after load
|
|
116
111
|
const updatedKnownState = storage.getKnownState(group.id);
|
|
117
112
|
expect(updatedKnownState).toEqual(group.core.knownState());
|
|
118
|
-
const groupOnNode = await loadCoValueOrFail(node, group.id);
|
|
113
|
+
const groupOnNode = await loadCoValueOrFail(client.node, group.id);
|
|
119
114
|
expect(groupOnNode.core.verified.header).toEqual(group.core.verified.header);
|
|
120
115
|
});
|
|
121
116
|
test("should successfully load coValue with transactions and update known state", async () => {
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
|
|
117
|
+
const dbPath = getDbPath();
|
|
118
|
+
const fixtures = setupTestNode();
|
|
119
|
+
fixtures.addStorage({
|
|
120
|
+
storage: createSyncStorage({
|
|
121
|
+
filename: dbPath,
|
|
122
|
+
nodeName: "test",
|
|
123
|
+
storageName: "test-storage",
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
126
|
+
const client = setupTestNode();
|
|
127
|
+
const { storage } = client.addStorage({
|
|
128
|
+
storage: createSyncStorage({
|
|
129
|
+
filename: dbPath,
|
|
130
|
+
nodeName: "test",
|
|
131
|
+
storageName: "test-storage",
|
|
132
|
+
}),
|
|
133
|
+
});
|
|
134
|
+
const callback = vi.fn((content) => client.node.syncManager.handleNewContent(content, "storage"));
|
|
125
135
|
const done = vi.fn();
|
|
126
136
|
// Create a real group and add a member to create transactions
|
|
127
|
-
const group =
|
|
137
|
+
const group = fixtures.node.createGroup();
|
|
128
138
|
group.addMember("everyone", "reader");
|
|
129
139
|
await group.core.waitForSync();
|
|
130
140
|
// Get initial known state
|
|
@@ -135,23 +145,35 @@ describe("StorageApiSync", () => {
|
|
|
135
145
|
id: group.id,
|
|
136
146
|
header: group.core.verified.header,
|
|
137
147
|
new: expect.objectContaining({
|
|
138
|
-
[
|
|
148
|
+
[fixtures.node.currentSessionID]: expect.any(Object),
|
|
139
149
|
}),
|
|
140
150
|
}));
|
|
141
151
|
expect(done).toHaveBeenCalledWith(true);
|
|
142
152
|
// Verify that storage known state is updated after load
|
|
143
153
|
const updatedKnownState = storage.getKnownState(group.id);
|
|
144
154
|
expect(updatedKnownState).toEqual(group.core.knownState());
|
|
145
|
-
const groupOnNode = await loadCoValueOrFail(node, group.id);
|
|
155
|
+
const groupOnNode = await loadCoValueOrFail(client.node, group.id);
|
|
146
156
|
expect(groupOnNode.get("everyone")).toEqual("reader");
|
|
147
157
|
});
|
|
148
158
|
});
|
|
149
159
|
describe("store", () => {
|
|
150
160
|
test("should successfully store new coValue with header and update known state", async () => {
|
|
151
|
-
const
|
|
152
|
-
|
|
161
|
+
const fixtures = setupTestNode();
|
|
162
|
+
fixtures.addStorage({
|
|
163
|
+
storage: createSyncStorage({
|
|
164
|
+
nodeName: "test",
|
|
165
|
+
storageName: "test-storage",
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
const client = setupTestNode();
|
|
169
|
+
const { storage } = client.addStorage({
|
|
170
|
+
storage: createSyncStorage({
|
|
171
|
+
nodeName: "test",
|
|
172
|
+
storageName: "test-storage",
|
|
173
|
+
}),
|
|
174
|
+
});
|
|
153
175
|
// Create a real group and get its content message
|
|
154
|
-
const group =
|
|
176
|
+
const group = fixtures.node.createGroup();
|
|
155
177
|
const contentMessage = getNewContentSince(group.core, emptyKnownState(group.id));
|
|
156
178
|
const correctionCallback = vi.fn();
|
|
157
179
|
// Get initial known state
|
|
@@ -161,15 +183,27 @@ describe("StorageApiSync", () => {
|
|
|
161
183
|
// Verify that storage known state is updated after store
|
|
162
184
|
const updatedKnownState = storage.getKnownState(group.id);
|
|
163
185
|
expect(updatedKnownState).toEqual(group.core.knownState());
|
|
164
|
-
|
|
165
|
-
const groupOnNode = await loadCoValueOrFail(node, group.id);
|
|
186
|
+
client.addStorage({ storage });
|
|
187
|
+
const groupOnNode = await loadCoValueOrFail(client.node, group.id);
|
|
166
188
|
expect(groupOnNode.core.verified.header).toEqual(group.core.verified.header);
|
|
167
189
|
});
|
|
168
190
|
test("should successfully store coValue with transactions and update known state", async () => {
|
|
169
|
-
const
|
|
170
|
-
|
|
191
|
+
const fixtures = setupTestNode();
|
|
192
|
+
fixtures.addStorage({
|
|
193
|
+
storage: createSyncStorage({
|
|
194
|
+
nodeName: "test",
|
|
195
|
+
storageName: "test-storage",
|
|
196
|
+
}),
|
|
197
|
+
});
|
|
198
|
+
const client = setupTestNode();
|
|
199
|
+
const { storage } = client.addStorage({
|
|
200
|
+
storage: createSyncStorage({
|
|
201
|
+
nodeName: "test",
|
|
202
|
+
storageName: "test-storage",
|
|
203
|
+
}),
|
|
204
|
+
});
|
|
171
205
|
// Create a real group and add a member to create transactions
|
|
172
|
-
const group =
|
|
206
|
+
const group = fixtures.node.createGroup();
|
|
173
207
|
group.addMember("everyone", "reader");
|
|
174
208
|
const contentMessage = getNewContentSince(group.core, emptyKnownState(group.id));
|
|
175
209
|
const correctionCallback = vi.fn();
|
|
@@ -180,14 +214,26 @@ describe("StorageApiSync", () => {
|
|
|
180
214
|
// Verify that storage known state is updated after store
|
|
181
215
|
const updatedKnownState = storage.getKnownState(group.id);
|
|
182
216
|
expect(updatedKnownState).toEqual(group.core.knownState());
|
|
183
|
-
|
|
184
|
-
const groupOnNode = await loadCoValueOrFail(node, group.id);
|
|
217
|
+
client.addStorage({ storage });
|
|
218
|
+
const groupOnNode = await loadCoValueOrFail(client.node, group.id);
|
|
185
219
|
expect(groupOnNode.get("everyone")).toEqual("reader");
|
|
186
220
|
});
|
|
187
221
|
test("should handle correction when header assumption is invalid", async () => {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
222
|
+
const fixtures = setupTestNode();
|
|
223
|
+
fixtures.addStorage({
|
|
224
|
+
storage: createSyncStorage({
|
|
225
|
+
nodeName: "test",
|
|
226
|
+
storageName: "test-storage",
|
|
227
|
+
}),
|
|
228
|
+
});
|
|
229
|
+
const client = setupTestNode();
|
|
230
|
+
const { storage } = client.addStorage({
|
|
231
|
+
storage: createSyncStorage({
|
|
232
|
+
nodeName: "test",
|
|
233
|
+
storageName: "test-storage",
|
|
234
|
+
}),
|
|
235
|
+
});
|
|
236
|
+
const group = fixtures.node.createGroup();
|
|
191
237
|
const knownState = group.core.knownState();
|
|
192
238
|
group.addMember("everyone", "reader");
|
|
193
239
|
const contentMessage = getNewContentSince(group.core, knownState);
|
|
@@ -204,14 +250,26 @@ describe("StorageApiSync", () => {
|
|
|
204
250
|
// Verify that storage known state is updated after store with correction
|
|
205
251
|
const updatedKnownState = storage.getKnownState(group.id);
|
|
206
252
|
expect(updatedKnownState).toEqual(group.core.knownState());
|
|
207
|
-
|
|
208
|
-
const groupOnNode = await loadCoValueOrFail(node, group.id);
|
|
253
|
+
client.addStorage({ storage });
|
|
254
|
+
const groupOnNode = await loadCoValueOrFail(client.node, group.id);
|
|
209
255
|
expect(groupOnNode.get("everyone")).toEqual("reader");
|
|
210
256
|
});
|
|
211
257
|
test("should handle correction when new content assumption is invalid", async () => {
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
258
|
+
const fixtures = setupTestNode();
|
|
259
|
+
fixtures.addStorage({
|
|
260
|
+
storage: createSyncStorage({
|
|
261
|
+
nodeName: "test",
|
|
262
|
+
storageName: "test-storage",
|
|
263
|
+
}),
|
|
264
|
+
});
|
|
265
|
+
const client = setupTestNode();
|
|
266
|
+
const { storage } = client.addStorage({
|
|
267
|
+
storage: createSyncStorage({
|
|
268
|
+
nodeName: "test",
|
|
269
|
+
storageName: "test-storage",
|
|
270
|
+
}),
|
|
271
|
+
});
|
|
272
|
+
const group = fixtures.node.createGroup();
|
|
215
273
|
const initialContent = getNewContentSince(group.core, emptyKnownState(group.id));
|
|
216
274
|
const initialKnownState = group.core.knownState();
|
|
217
275
|
group.addMember("everyone", "reader");
|
|
@@ -235,14 +293,26 @@ describe("StorageApiSync", () => {
|
|
|
235
293
|
// Verify that storage known state is updated after store with correction
|
|
236
294
|
const finalKnownState = storage.getKnownState(group.id);
|
|
237
295
|
expect(finalKnownState).toEqual(group.core.knownState());
|
|
238
|
-
|
|
239
|
-
const groupOnNode = await loadCoValueOrFail(node, group.id);
|
|
296
|
+
client.addStorage({ storage });
|
|
297
|
+
const groupOnNode = await loadCoValueOrFail(client.node, group.id);
|
|
240
298
|
expect(groupOnNode.get("everyone")).toEqual("writer");
|
|
241
299
|
});
|
|
242
300
|
test("should log error and fail when correction callback returns undefined", async () => {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
301
|
+
const fixtures = setupTestNode();
|
|
302
|
+
fixtures.addStorage({
|
|
303
|
+
storage: createSyncStorage({
|
|
304
|
+
nodeName: "test",
|
|
305
|
+
storageName: "test-storage",
|
|
306
|
+
}),
|
|
307
|
+
});
|
|
308
|
+
const client = setupTestNode();
|
|
309
|
+
const { storage } = client.addStorage({
|
|
310
|
+
storage: createSyncStorage({
|
|
311
|
+
nodeName: "test",
|
|
312
|
+
storageName: "test-storage",
|
|
313
|
+
}),
|
|
314
|
+
});
|
|
315
|
+
const group = fixtures.node.createGroup();
|
|
246
316
|
const knownState = group.core.knownState();
|
|
247
317
|
group.addMember("everyone", "writer");
|
|
248
318
|
const contentMessage = getNewContentSince(group.core, knownState);
|
|
@@ -265,9 +335,21 @@ describe("StorageApiSync", () => {
|
|
|
265
335
|
errorSpy.mockClear();
|
|
266
336
|
});
|
|
267
337
|
test("should log error and fail when correction callback returns invalid content message", async () => {
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
338
|
+
const fixtures = setupTestNode();
|
|
339
|
+
fixtures.addStorage({
|
|
340
|
+
storage: createSyncStorage({
|
|
341
|
+
nodeName: "test",
|
|
342
|
+
storageName: "test-storage",
|
|
343
|
+
}),
|
|
344
|
+
});
|
|
345
|
+
const client = setupTestNode();
|
|
346
|
+
const { storage } = client.addStorage({
|
|
347
|
+
storage: createSyncStorage({
|
|
348
|
+
nodeName: "test",
|
|
349
|
+
storageName: "test-storage",
|
|
350
|
+
}),
|
|
351
|
+
});
|
|
352
|
+
const group = fixtures.node.createGroup();
|
|
271
353
|
const knownState = group.core.knownState();
|
|
272
354
|
group.addMember("everyone", "writer");
|
|
273
355
|
const contentMessage = getNewContentSince(group.core, knownState);
|
|
@@ -288,14 +370,35 @@ describe("StorageApiSync", () => {
|
|
|
288
370
|
errorSpy.mockClear();
|
|
289
371
|
});
|
|
290
372
|
test("should successfully store coValue with multiple sessions", async () => {
|
|
291
|
-
const
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
373
|
+
const dbPath = getDbPath();
|
|
374
|
+
const fixtures = setupTestNode();
|
|
375
|
+
fixtures.addStorage({
|
|
376
|
+
storage: createSyncStorage({
|
|
377
|
+
filename: dbPath,
|
|
378
|
+
nodeName: "test",
|
|
379
|
+
storageName: "test-storage",
|
|
380
|
+
}),
|
|
381
|
+
});
|
|
382
|
+
const fixture2 = setupTestNode();
|
|
383
|
+
fixture2.addStorage({
|
|
384
|
+
storage: createSyncStorage({
|
|
385
|
+
filename: dbPath,
|
|
386
|
+
nodeName: "test",
|
|
387
|
+
storageName: "test-storage",
|
|
388
|
+
}),
|
|
389
|
+
});
|
|
390
|
+
const client = setupTestNode();
|
|
391
|
+
const { storage } = client.addStorage({
|
|
392
|
+
storage: createSyncStorage({
|
|
393
|
+
nodeName: "test",
|
|
394
|
+
storageName: "test-storage",
|
|
395
|
+
}),
|
|
396
|
+
});
|
|
397
|
+
const coValue = fixtures.node.createCoValue({
|
|
295
398
|
type: "comap",
|
|
296
399
|
ruleset: { type: "unsafeAllowAll" },
|
|
297
400
|
meta: null,
|
|
298
|
-
...crypto.createdNowUnique(),
|
|
401
|
+
...fixtures.node.crypto.createdNowUnique(),
|
|
299
402
|
});
|
|
300
403
|
coValue.makeTransaction([
|
|
301
404
|
{
|
|
@@ -303,7 +406,7 @@ describe("StorageApiSync", () => {
|
|
|
303
406
|
},
|
|
304
407
|
], "trusting");
|
|
305
408
|
await coValue.waitForSync();
|
|
306
|
-
const mapOnNode2 = await loadCoValueOrFail(
|
|
409
|
+
const mapOnNode2 = await loadCoValueOrFail(fixture2.node, coValue.id);
|
|
307
410
|
coValue.makeTransaction([
|
|
308
411
|
{
|
|
309
412
|
count: 2,
|
|
@@ -313,22 +416,164 @@ describe("StorageApiSync", () => {
|
|
|
313
416
|
const contentMessage = getNewContentSince(mapOnNode2.core, emptyKnownState(mapOnNode2.id));
|
|
314
417
|
const correctionCallback = vi.fn();
|
|
315
418
|
storage.store(contentMessage, correctionCallback);
|
|
316
|
-
|
|
317
|
-
const finalMap = await loadCoValueOrFail(node, mapOnNode2.id);
|
|
419
|
+
client.addStorage({ storage });
|
|
420
|
+
const finalMap = await loadCoValueOrFail(client.node, mapOnNode2.id);
|
|
318
421
|
expect(finalMap.core.knownState()).toEqual(knownState);
|
|
319
422
|
});
|
|
320
423
|
});
|
|
424
|
+
describe("delete flow", () => {
|
|
425
|
+
test("deleteCoValue enqueues the coValue for erasure", async () => {
|
|
426
|
+
const client = setupTestNode();
|
|
427
|
+
const { storage } = client.addStorage({
|
|
428
|
+
storage: createSyncStorage({
|
|
429
|
+
nodeName: "test",
|
|
430
|
+
storageName: "test-storage",
|
|
431
|
+
}),
|
|
432
|
+
});
|
|
433
|
+
const group = client.node.createGroup();
|
|
434
|
+
const map = group.createMap();
|
|
435
|
+
map.core.deleteCoValue();
|
|
436
|
+
await map.core.waitForSync();
|
|
437
|
+
const queued = await getAllCoValuesWaitingForDelete(storage);
|
|
438
|
+
expect(queued).toContain(map.id);
|
|
439
|
+
});
|
|
440
|
+
test("background erasure doesn't run if not enabled", async () => {
|
|
441
|
+
const dbPath = getDbPath();
|
|
442
|
+
const node = setupTestNode();
|
|
443
|
+
const { storage } = node.addStorage({
|
|
444
|
+
storage: createSyncStorage({
|
|
445
|
+
filename: dbPath,
|
|
446
|
+
nodeName: "test",
|
|
447
|
+
storageName: "test-storage",
|
|
448
|
+
}),
|
|
449
|
+
});
|
|
450
|
+
const group = node.node.createGroup();
|
|
451
|
+
const map = group.createMap();
|
|
452
|
+
map.set("k", "v");
|
|
453
|
+
await map.core.waitForSync();
|
|
454
|
+
vi.useFakeTimers();
|
|
455
|
+
map.core.deleteCoValue();
|
|
456
|
+
await map.core.waitForSync();
|
|
457
|
+
await vi.advanceTimersByTimeAsync(70000);
|
|
458
|
+
// Queue drained
|
|
459
|
+
expect(await getAllCoValuesWaitingForDelete(storage)).toContain(map.id);
|
|
460
|
+
});
|
|
461
|
+
test("background erasure run if enabled", async () => {
|
|
462
|
+
const dbPath = getDbPath();
|
|
463
|
+
const node = setupTestNode();
|
|
464
|
+
const { storage } = node.addStorage({
|
|
465
|
+
storage: createSyncStorage({
|
|
466
|
+
filename: dbPath,
|
|
467
|
+
nodeName: "test",
|
|
468
|
+
storageName: "test-storage",
|
|
469
|
+
}),
|
|
470
|
+
});
|
|
471
|
+
vi.useFakeTimers();
|
|
472
|
+
node.node.enableDeletedCoValuesErasure();
|
|
473
|
+
const group = node.node.createGroup();
|
|
474
|
+
const map = group.createMap();
|
|
475
|
+
map.set("k", "v");
|
|
476
|
+
await map.core.waitForSync();
|
|
477
|
+
map.core.deleteCoValue();
|
|
478
|
+
await map.core.waitForSync();
|
|
479
|
+
await vi.advanceTimersByTimeAsync(70000);
|
|
480
|
+
// Queue drained
|
|
481
|
+
expect(await getAllCoValuesWaitingForDelete(storage)).not.toContain(map.id);
|
|
482
|
+
const sessionIDs = await getCoValueStoredSessions(storage, map.id);
|
|
483
|
+
expect(sessionIDs).toHaveLength(1);
|
|
484
|
+
expect(sessionIDs[0]).toMatch(/_session_d[1-9A-HJ-NP-Za-km-z]+\$$/); // Delete session format
|
|
485
|
+
});
|
|
486
|
+
test("eraseAllDeletedCoValues deletes history but preserves tombstone", async () => {
|
|
487
|
+
const dbPath = getDbPath();
|
|
488
|
+
const node = setupTestNode();
|
|
489
|
+
const { storage } = node.addStorage({
|
|
490
|
+
storage: createSyncStorage({
|
|
491
|
+
filename: dbPath,
|
|
492
|
+
nodeName: "test",
|
|
493
|
+
storageName: "test-storage",
|
|
494
|
+
}),
|
|
495
|
+
});
|
|
496
|
+
const group = node.node.createGroup();
|
|
497
|
+
const map = group.createMap();
|
|
498
|
+
map.set("k", "v");
|
|
499
|
+
await map.core.waitForSync();
|
|
500
|
+
map.core.deleteCoValue();
|
|
501
|
+
await map.core.waitForSync();
|
|
502
|
+
expect(await getAllCoValuesWaitingForDelete(storage)).toContain(map.id);
|
|
503
|
+
await storage.eraseAllDeletedCoValues();
|
|
504
|
+
// Queue drained
|
|
505
|
+
expect(await getAllCoValuesWaitingForDelete(storage)).not.toContain(map.id);
|
|
506
|
+
// Tombstone preserved + history erased when loaded from storage
|
|
507
|
+
const client = setupTestNode();
|
|
508
|
+
const { storage: clientStorage } = client.addStorage({
|
|
509
|
+
storage: createSyncStorage({
|
|
510
|
+
filename: dbPath,
|
|
511
|
+
nodeName: "test",
|
|
512
|
+
storageName: "test-storage",
|
|
513
|
+
}),
|
|
514
|
+
});
|
|
515
|
+
const loaded = await loadCoValueOrFail(client.node, map.id);
|
|
516
|
+
expect(loaded.core.isDeleted).toBe(true);
|
|
517
|
+
expect(loaded.get("k")).toBeUndefined();
|
|
518
|
+
const sessionIDs = await getCoValueStoredSessions(clientStorage, map.id);
|
|
519
|
+
expect(sessionIDs).toHaveLength(1);
|
|
520
|
+
expect(sessionIDs[0]).toMatch(/_session_d[1-9A-HJ-NP-Za-km-z]+\$$/); // Delete session format
|
|
521
|
+
});
|
|
522
|
+
test("eraseAllDeletedCoValues does not break when called while a coValue is streaming from storage", async () => {
|
|
523
|
+
const dbPath = getDbPath();
|
|
524
|
+
const node = setupTestNode();
|
|
525
|
+
const storage = createSyncStorage({
|
|
526
|
+
filename: dbPath,
|
|
527
|
+
nodeName: "test",
|
|
528
|
+
storageName: "test-storage",
|
|
529
|
+
});
|
|
530
|
+
node.addStorage({ storage });
|
|
531
|
+
const group = node.node.createGroup();
|
|
532
|
+
const map = group.createMap();
|
|
533
|
+
fillCoMapWithLargeData(map);
|
|
534
|
+
await map.core.waitForSync();
|
|
535
|
+
map.core.deleteCoValue();
|
|
536
|
+
await map.core.waitForSync();
|
|
537
|
+
storage.close();
|
|
538
|
+
const newStorage = createSyncStorage({
|
|
539
|
+
filename: dbPath,
|
|
540
|
+
nodeName: "test",
|
|
541
|
+
storageName: "test-storage",
|
|
542
|
+
});
|
|
543
|
+
const callback = vi.fn();
|
|
544
|
+
const loadPromise = new Promise((resolve) => {
|
|
545
|
+
newStorage.load(map.id, callback, resolve);
|
|
546
|
+
});
|
|
547
|
+
await newStorage.eraseAllDeletedCoValues();
|
|
548
|
+
expect(await loadPromise).toBe(true);
|
|
549
|
+
});
|
|
550
|
+
});
|
|
321
551
|
describe("dependencies", () => {
|
|
322
552
|
test("should load dependencies before dependent coValues and update all known states", async () => {
|
|
323
|
-
const
|
|
324
|
-
const
|
|
553
|
+
const dbPath = getDbPath();
|
|
554
|
+
const fixtures = setupTestNode();
|
|
555
|
+
fixtures.addStorage({
|
|
556
|
+
storage: createSyncStorage({
|
|
557
|
+
filename: dbPath,
|
|
558
|
+
nodeName: "test",
|
|
559
|
+
storageName: "test-storage",
|
|
560
|
+
}),
|
|
561
|
+
});
|
|
562
|
+
const client = setupTestNode();
|
|
563
|
+
const { storage } = client.addStorage({
|
|
564
|
+
storage: createSyncStorage({
|
|
565
|
+
filename: dbPath,
|
|
566
|
+
nodeName: "test",
|
|
567
|
+
storageName: "test-storage",
|
|
568
|
+
}),
|
|
569
|
+
});
|
|
325
570
|
// Create a group and a map owned by that group to create dependencies
|
|
326
|
-
const group =
|
|
571
|
+
const group = fixtures.node.createGroup();
|
|
327
572
|
group.addMember("everyone", "reader");
|
|
328
573
|
const map = group.createMap({ test: "value" });
|
|
329
574
|
await group.core.waitForSync();
|
|
330
575
|
await map.core.waitForSync();
|
|
331
|
-
const callback = vi.fn((content) => node.syncManager.handleNewContent(content, "storage"));
|
|
576
|
+
const callback = vi.fn((content) => client.node.syncManager.handleNewContent(content, "storage"));
|
|
332
577
|
const done = vi.fn();
|
|
333
578
|
// Get initial known states
|
|
334
579
|
const initialGroupKnownState = storage.getKnownState(group.id);
|
|
@@ -350,20 +595,35 @@ describe("StorageApiSync", () => {
|
|
|
350
595
|
const updatedMapKnownState = storage.getKnownState(map.id);
|
|
351
596
|
expect(updatedGroupKnownState).toEqual(group.core.knownState());
|
|
352
597
|
expect(updatedMapKnownState).toEqual(map.core.knownState());
|
|
353
|
-
|
|
354
|
-
const mapOnNode = await loadCoValueOrFail(node, map.id);
|
|
598
|
+
client.addStorage({ storage });
|
|
599
|
+
const mapOnNode = await loadCoValueOrFail(client.node, map.id);
|
|
355
600
|
expect(mapOnNode.get("test")).toEqual("value");
|
|
356
601
|
});
|
|
357
602
|
test("should skip loading already loaded dependencies", async () => {
|
|
358
|
-
const
|
|
359
|
-
const
|
|
603
|
+
const dbPath = getDbPath();
|
|
604
|
+
const fixtures = setupTestNode();
|
|
605
|
+
fixtures.addStorage({
|
|
606
|
+
storage: createSyncStorage({
|
|
607
|
+
filename: dbPath,
|
|
608
|
+
nodeName: "test",
|
|
609
|
+
storageName: "test-storage",
|
|
610
|
+
}),
|
|
611
|
+
});
|
|
612
|
+
const client = setupTestNode();
|
|
613
|
+
const { storage } = client.addStorage({
|
|
614
|
+
storage: createSyncStorage({
|
|
615
|
+
filename: dbPath,
|
|
616
|
+
nodeName: "test",
|
|
617
|
+
storageName: "test-storage",
|
|
618
|
+
}),
|
|
619
|
+
});
|
|
360
620
|
// Create a group and a map owned by that group
|
|
361
|
-
const group =
|
|
621
|
+
const group = fixtures.node.createGroup();
|
|
362
622
|
group.addMember("everyone", "reader");
|
|
363
623
|
const map = group.createMap({ test: "value" });
|
|
364
624
|
await group.core.waitForSync();
|
|
365
625
|
await map.core.waitForSync();
|
|
366
|
-
const callback = vi.fn((content) => node.syncManager.handleNewContent(content, "storage"));
|
|
626
|
+
const callback = vi.fn((content) => client.node.syncManager.handleNewContent(content, "storage"));
|
|
367
627
|
const done = vi.fn();
|
|
368
628
|
// Get initial known states
|
|
369
629
|
const initialGroupKnownState = storage.getKnownState(group.id);
|
|
@@ -388,20 +648,35 @@ describe("StorageApiSync", () => {
|
|
|
388
648
|
// Verify map known state is updated after second load
|
|
389
649
|
const finalMapKnownState = storage.getKnownState(map.id);
|
|
390
650
|
expect(finalMapKnownState).toEqual(map.core.knownState());
|
|
391
|
-
|
|
392
|
-
const mapOnNode = await loadCoValueOrFail(node, map.id);
|
|
651
|
+
client.addStorage({ storage });
|
|
652
|
+
const mapOnNode = await loadCoValueOrFail(client.node, map.id);
|
|
393
653
|
expect(mapOnNode.get("test")).toEqual("value");
|
|
394
654
|
});
|
|
395
655
|
test("should load dependencies again if they were unmounted", async () => {
|
|
396
|
-
const
|
|
397
|
-
const
|
|
656
|
+
const dbPath = getDbPath();
|
|
657
|
+
const fixtures = setupTestNode();
|
|
658
|
+
fixtures.addStorage({
|
|
659
|
+
storage: createSyncStorage({
|
|
660
|
+
filename: dbPath,
|
|
661
|
+
nodeName: "test",
|
|
662
|
+
storageName: "test-storage",
|
|
663
|
+
}),
|
|
664
|
+
});
|
|
665
|
+
const client = setupTestNode();
|
|
666
|
+
const { storage } = client.addStorage({
|
|
667
|
+
storage: createSyncStorage({
|
|
668
|
+
filename: dbPath,
|
|
669
|
+
nodeName: "test",
|
|
670
|
+
storageName: "test-storage",
|
|
671
|
+
}),
|
|
672
|
+
});
|
|
398
673
|
// Create a group and a map owned by that group
|
|
399
|
-
const group =
|
|
674
|
+
const group = fixtures.node.createGroup();
|
|
400
675
|
group.addMember("everyone", "reader");
|
|
401
676
|
const map = group.createMap({ test: "value" });
|
|
402
677
|
await group.core.waitForSync();
|
|
403
678
|
await map.core.waitForSync();
|
|
404
|
-
const callback = vi.fn((content) => node.syncManager.handleNewContent(content, "storage"));
|
|
679
|
+
const callback = vi.fn((content) => client.node.syncManager.handleNewContent(content, "storage"));
|
|
405
680
|
const done = vi.fn();
|
|
406
681
|
// Load the map (and its group)
|
|
407
682
|
await storage.load(map.id, callback, done);
|
|
@@ -420,26 +695,41 @@ describe("StorageApiSync", () => {
|
|
|
420
695
|
id: map.id,
|
|
421
696
|
}));
|
|
422
697
|
expect(done).toHaveBeenCalledWith(true);
|
|
423
|
-
|
|
424
|
-
const mapOnNode = await loadCoValueOrFail(node, map.id);
|
|
698
|
+
client.addStorage({ storage });
|
|
699
|
+
const mapOnNode = await loadCoValueOrFail(client.node, map.id);
|
|
425
700
|
expect(mapOnNode.get("test")).toEqual("value");
|
|
426
701
|
});
|
|
427
702
|
});
|
|
428
703
|
describe("waitForSync", () => {
|
|
429
704
|
test("should resolve immediately when coValue is already synced", async () => {
|
|
430
|
-
const
|
|
431
|
-
const
|
|
705
|
+
const dbPath = getDbPath();
|
|
706
|
+
const fixtures = setupTestNode();
|
|
707
|
+
fixtures.addStorage({
|
|
708
|
+
storage: createSyncStorage({
|
|
709
|
+
filename: dbPath,
|
|
710
|
+
nodeName: "test",
|
|
711
|
+
storageName: "test-storage",
|
|
712
|
+
}),
|
|
713
|
+
});
|
|
714
|
+
const client = setupTestNode();
|
|
715
|
+
const { storage } = client.addStorage({
|
|
716
|
+
storage: createSyncStorage({
|
|
717
|
+
filename: dbPath,
|
|
718
|
+
nodeName: "test",
|
|
719
|
+
storageName: "test-storage",
|
|
720
|
+
}),
|
|
721
|
+
});
|
|
432
722
|
// Create a group and add a member
|
|
433
|
-
const group =
|
|
723
|
+
const group = fixtures.node.createGroup();
|
|
434
724
|
group.addMember("everyone", "reader");
|
|
435
725
|
await group.core.waitForSync();
|
|
436
726
|
// Store the group in storage
|
|
437
727
|
const contentMessage = getNewContentSince(group.core, emptyKnownState(group.id));
|
|
438
728
|
const correctionCallback = vi.fn();
|
|
439
729
|
storage.store(contentMessage, correctionCallback);
|
|
440
|
-
|
|
730
|
+
client.addStorage({ storage });
|
|
441
731
|
// Load the group on the new node
|
|
442
|
-
const groupOnNode = await loadCoValueOrFail(node, group.id);
|
|
732
|
+
const groupOnNode = await loadCoValueOrFail(client.node, group.id);
|
|
443
733
|
// Wait for sync should resolve immediately since the coValue is already synced
|
|
444
734
|
await expect(storage.waitForSync(group.id, groupOnNode.core)).resolves.toBeUndefined();
|
|
445
735
|
expect(groupOnNode.get("everyone")).toEqual("reader");
|
|
@@ -447,16 +737,37 @@ describe("StorageApiSync", () => {
|
|
|
447
737
|
});
|
|
448
738
|
describe("close", () => {
|
|
449
739
|
test("should close storage without throwing errors", async () => {
|
|
450
|
-
const
|
|
740
|
+
const client = setupTestNode();
|
|
741
|
+
const { storage } = client.addStorage({
|
|
742
|
+
storage: createSyncStorage({
|
|
743
|
+
nodeName: "test",
|
|
744
|
+
storageName: "test-storage",
|
|
745
|
+
}),
|
|
746
|
+
});
|
|
451
747
|
expect(() => storage.close()).not.toThrow();
|
|
452
748
|
});
|
|
453
749
|
});
|
|
454
750
|
describe("loadKnownState", () => {
|
|
455
751
|
test("should return correct knownState structure for existing CoValue", async () => {
|
|
456
|
-
const
|
|
457
|
-
const
|
|
752
|
+
const dbPath = getDbPath();
|
|
753
|
+
const fixtures = setupTestNode();
|
|
754
|
+
fixtures.addStorage({
|
|
755
|
+
storage: createSyncStorage({
|
|
756
|
+
filename: dbPath,
|
|
757
|
+
nodeName: "test",
|
|
758
|
+
storageName: "test-storage",
|
|
759
|
+
}),
|
|
760
|
+
});
|
|
761
|
+
const client = setupTestNode();
|
|
762
|
+
const { storage } = client.addStorage({
|
|
763
|
+
storage: createSyncStorage({
|
|
764
|
+
filename: dbPath,
|
|
765
|
+
nodeName: "test",
|
|
766
|
+
storageName: "test-storage",
|
|
767
|
+
}),
|
|
768
|
+
});
|
|
458
769
|
// Create a group to have data in the database
|
|
459
|
-
const group =
|
|
770
|
+
const group = fixtures.node.createGroup();
|
|
460
771
|
group.addMember("everyone", "reader");
|
|
461
772
|
await group.core.waitForSync();
|
|
462
773
|
const result = await new Promise((resolve) => {
|
|
@@ -468,21 +779,42 @@ describe("StorageApiSync", () => {
|
|
|
468
779
|
expect(result?.sessions).toEqual(group.core.knownState().sessions);
|
|
469
780
|
});
|
|
470
781
|
test("should return undefined for non-existent CoValue", async () => {
|
|
471
|
-
const
|
|
782
|
+
const client = setupTestNode();
|
|
783
|
+
const { storage } = client.addStorage({
|
|
784
|
+
storage: createSyncStorage({
|
|
785
|
+
nodeName: "test",
|
|
786
|
+
storageName: "test-storage",
|
|
787
|
+
}),
|
|
788
|
+
});
|
|
472
789
|
const result = await new Promise((resolve) => {
|
|
473
790
|
storage.loadKnownState("co_nonexistent", resolve);
|
|
474
791
|
});
|
|
475
792
|
expect(result).toBeUndefined();
|
|
476
793
|
});
|
|
477
794
|
test("should handle CoValue with no sessions (header only)", async () => {
|
|
478
|
-
const
|
|
479
|
-
const
|
|
795
|
+
const dbPath = getDbPath();
|
|
796
|
+
const fixtures = setupTestNode();
|
|
797
|
+
fixtures.addStorage({
|
|
798
|
+
storage: createSyncStorage({
|
|
799
|
+
filename: dbPath,
|
|
800
|
+
nodeName: "test",
|
|
801
|
+
storageName: "test-storage",
|
|
802
|
+
}),
|
|
803
|
+
});
|
|
804
|
+
const client = setupTestNode();
|
|
805
|
+
const { storage } = client.addStorage({
|
|
806
|
+
storage: createSyncStorage({
|
|
807
|
+
filename: dbPath,
|
|
808
|
+
nodeName: "test",
|
|
809
|
+
storageName: "test-storage",
|
|
810
|
+
}),
|
|
811
|
+
});
|
|
480
812
|
// Create a CoValue with just a header (no transactions yet)
|
|
481
|
-
const coValue =
|
|
813
|
+
const coValue = fixtures.node.createCoValue({
|
|
482
814
|
type: "comap",
|
|
483
815
|
ruleset: { type: "unsafeAllowAll" },
|
|
484
816
|
meta: null,
|
|
485
|
-
...crypto.createdNowUnique(),
|
|
817
|
+
...fixtures.node.crypto.createdNowUnique(),
|
|
486
818
|
});
|
|
487
819
|
await coValue.waitForSync();
|
|
488
820
|
const result = await new Promise((resolve) => {
|
|
@@ -495,19 +827,41 @@ describe("StorageApiSync", () => {
|
|
|
495
827
|
expect(Object.keys(result?.sessions || {}).length).toBe(0);
|
|
496
828
|
});
|
|
497
829
|
test("should handle CoValue with multiple sessions", async () => {
|
|
498
|
-
const
|
|
499
|
-
const
|
|
500
|
-
|
|
830
|
+
const dbPath = getDbPath();
|
|
831
|
+
const fixtures = setupTestNode();
|
|
832
|
+
fixtures.addStorage({
|
|
833
|
+
storage: createSyncStorage({
|
|
834
|
+
filename: dbPath,
|
|
835
|
+
nodeName: "test",
|
|
836
|
+
storageName: "test-storage",
|
|
837
|
+
}),
|
|
838
|
+
});
|
|
839
|
+
const fixtures2 = setupTestNode();
|
|
840
|
+
fixtures2.addStorage({
|
|
841
|
+
storage: createSyncStorage({
|
|
842
|
+
filename: dbPath,
|
|
843
|
+
nodeName: "test",
|
|
844
|
+
storageName: "test-storage",
|
|
845
|
+
}),
|
|
846
|
+
});
|
|
847
|
+
const client = setupTestNode();
|
|
848
|
+
const { storage } = client.addStorage({
|
|
849
|
+
storage: createSyncStorage({
|
|
850
|
+
filename: dbPath,
|
|
851
|
+
nodeName: "test",
|
|
852
|
+
storageName: "test-storage",
|
|
853
|
+
}),
|
|
854
|
+
});
|
|
501
855
|
// Create a CoValue and have two nodes make transactions
|
|
502
|
-
const coValue =
|
|
856
|
+
const coValue = fixtures.node.createCoValue({
|
|
503
857
|
type: "comap",
|
|
504
858
|
ruleset: { type: "unsafeAllowAll" },
|
|
505
859
|
meta: null,
|
|
506
|
-
...crypto.createdNowUnique(),
|
|
860
|
+
...fixtures.node.crypto.createdNowUnique(),
|
|
507
861
|
});
|
|
508
862
|
coValue.makeTransaction([{ key1: "value1" }], "trusting");
|
|
509
863
|
await coValue.waitForSync();
|
|
510
|
-
const coValueOnNode2 = await loadCoValueOrFail(
|
|
864
|
+
const coValueOnNode2 = await loadCoValueOrFail(fixtures2.node, coValue.id);
|
|
511
865
|
coValueOnNode2.set("key2", "value2", "trusting");
|
|
512
866
|
await coValueOnNode2.core.waitForSync();
|
|
513
867
|
const result = await new Promise((resolve) => {
|
|
@@ -522,10 +876,25 @@ describe("StorageApiSync", () => {
|
|
|
522
876
|
expect(result?.sessions).toEqual(coValueOnNode2.core.knownState().sessions);
|
|
523
877
|
});
|
|
524
878
|
test("should use cache when knownState is cached", async () => {
|
|
525
|
-
const
|
|
526
|
-
const
|
|
879
|
+
const dbPath = getDbPath();
|
|
880
|
+
const fixtures = setupTestNode();
|
|
881
|
+
fixtures.addStorage({
|
|
882
|
+
storage: createSyncStorage({
|
|
883
|
+
filename: dbPath,
|
|
884
|
+
nodeName: "test",
|
|
885
|
+
storageName: "test-storage",
|
|
886
|
+
}),
|
|
887
|
+
});
|
|
888
|
+
const client = setupTestNode();
|
|
889
|
+
const { storage } = client.addStorage({
|
|
890
|
+
storage: createSyncStorage({
|
|
891
|
+
filename: dbPath,
|
|
892
|
+
nodeName: "test",
|
|
893
|
+
storageName: "test-storage",
|
|
894
|
+
}),
|
|
895
|
+
});
|
|
527
896
|
// Create a group to have data in the database
|
|
528
|
-
const group =
|
|
897
|
+
const group = fixtures.node.createGroup();
|
|
529
898
|
group.addMember("everyone", "reader");
|
|
530
899
|
await group.core.waitForSync();
|
|
531
900
|
// First call should hit the database and cache the result
|