cojson-storage-indexeddb 0.15.8 → 0.15.10
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 +14 -0
- package/dist/idbClient.d.ts +1 -1
- package/dist/idbClient.d.ts.map +1 -1
- package/dist/idbNode.d.ts +2 -10
- package/dist/idbNode.d.ts.map +1 -1
- package/dist/idbNode.js +39 -96
- package/dist/idbNode.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/tests/storage.indexeddb.test.js +36 -86
- package/dist/tests/storage.indexeddb.test.js.map +1 -1
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +36 -15
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +2 -3
- package/src/idbClient.ts +1 -1
- package/src/idbNode.ts +43 -131
- package/src/index.ts +1 -2
- package/src/tests/storage.indexeddb.test.ts +37 -111
- package/src/tests/testUtils.ts +42 -18
- package/dist/tests/idbNode.test.d.ts +0 -2
- package/dist/tests/idbNode.test.d.ts.map +0 -1
- package/dist/tests/idbNode.test.js +0 -29
- package/dist/tests/idbNode.test.js.map +0 -1
- package/src/tests/idbNode.test.ts +0 -61
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# cojson-storage-indexeddb
|
|
2
2
|
|
|
3
|
+
## 0.15.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- cojson@0.15.10
|
|
8
|
+
|
|
9
|
+
## 0.15.9
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [27b4837]
|
|
14
|
+
- Updated dependencies [2776263]
|
|
15
|
+
- cojson@0.15.9
|
|
16
|
+
|
|
3
17
|
## 0.15.8
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/dist/idbClient.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CojsonInternalTypes, RawCoID, SessionID } from "cojson";
|
|
2
|
-
import type { DBClientInterfaceAsync, SessionRow, SignatureAfterRow, StoredCoValueRow, StoredSessionRow, TransactionRow } from "cojson
|
|
2
|
+
import type { DBClientInterfaceAsync, SessionRow, SignatureAfterRow, StoredCoValueRow, StoredSessionRow, TransactionRow } from "cojson";
|
|
3
3
|
import { CoJsonIDBTransaction } from "./CoJsonIDBTransaction.js";
|
|
4
4
|
export declare class IDBClient implements DBClientInterfaceAsync {
|
|
5
5
|
private db;
|
package/dist/idbClient.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idbClient.d.ts","sourceRoot":"","sources":["../src/idbClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACtE,OAAO,KAAK,EAEV,sBAAsB,EACtB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACf,MAAM,
|
|
1
|
+
{"version":3,"file":"idbClient.d.ts","sourceRoot":"","sources":["../src/idbClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACtE,OAAO,KAAK,EAEV,sBAAsB,EACtB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACf,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,qBAAa,SAAU,YAAW,sBAAsB;IACtD,OAAO,CAAC,EAAE,CAAC;IAEX,iBAAiB,EAAE,oBAAoB,GAAG,SAAS,CAAC;IACpD,uBAAuB,EAAE,oBAAoB,GAAG,SAAS,CAAC;gBAE9C,EAAE,EAAE,WAAW;IAI3B,WAAW,CAAC,CAAC,EACX,OAAO,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,UAAU,CAAC,CAAC,CAAC,GACxD,OAAO,CAAC,CAAC,CAAC;IAgBP,UAAU,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC;IAMrE,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IASrE,uBAAuB,CAC3B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC;IASlC,0BAA0B,CAC9B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,EAAE,CAAC;IAUtB,aAAa,CACjB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAazB,UAAU,CACd,GAAG,EAAE,mBAAmB,CAAC,iBAAiB,GACzC,OAAO,CAAC,MAAM,CAAC;IAcZ,gBAAgB,CAAC,EACrB,aAAa,EACb,UAAU,GACX,EAAE;QACD,aAAa,EAAE,UAAU,CAAC;QAC1B,UAAU,CAAC,EAAE,gBAAgB,CAAC;KAC/B,GAAG,OAAO,CAAC,MAAM,CAAC;IAcb,cAAc,CAClB,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,mBAAmB,CAAC,WAAW;IAW3C,iBAAiB,CAAC,EACtB,YAAY,EACZ,GAAG,EACH,SAAS,GACV,EAAE;QACD,YAAY,EAAE,MAAM,CAAC;QACrB,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,mBAAmB,CAAC,SAAS,CAAC;KAC1C;IAUD,gBAAgB,CAAC,EAAE,EAAE,oBAAoB;IAQnC,WAAW,CAAC,kBAAkB,EAAE,MAAM,OAAO;CAYpD"}
|
package/dist/idbNode.d.ts
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StorageApiAsync } from "cojson";
|
|
2
2
|
export declare function internal_setDatabaseName(name: string): void;
|
|
3
|
-
export declare
|
|
4
|
-
private readonly dbClient;
|
|
5
|
-
private readonly syncManager;
|
|
6
|
-
constructor(db: IDBDatabase, fromLocalNode: IncomingSyncStream, toLocalNode: OutgoingSyncQueue);
|
|
7
|
-
static asPeer({ localNodeName }?: {
|
|
8
|
-
localNodeName?: string;
|
|
9
|
-
} | undefined): Promise<Peer>;
|
|
10
|
-
static open(fromLocalNode: IncomingSyncStream, toLocalNode: OutgoingSyncQueue): Promise<IDBNode>;
|
|
11
|
-
}
|
|
3
|
+
export declare function getIndexedDBStorage(name?: string): Promise<StorageApiAsync>;
|
|
12
4
|
//# sourceMappingURL=idbNode.d.ts.map
|
package/dist/idbNode.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idbNode.d.ts","sourceRoot":"","sources":["../src/idbNode.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"idbNode.d.ts","sourceRoot":"","sources":["../src/idbNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAKzC,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,QAEpD;AAED,wBAAsB,mBAAmB,CAAC,IAAI,SAAgB,4BA8C7D"}
|
package/dist/idbNode.js
CHANGED
|
@@ -1,105 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { StorageManagerAsync } from "cojson-storage";
|
|
1
|
+
import { StorageApiAsync } from "cojson";
|
|
3
2
|
import { IDBClient } from "./idbClient.js";
|
|
4
3
|
let DATABASE_NAME = "jazz-storage";
|
|
5
4
|
export function internal_setDatabaseName(name) {
|
|
6
5
|
DATABASE_NAME = name;
|
|
7
6
|
}
|
|
8
|
-
function
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
await batch.wait();
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
catch (e) {
|
|
47
|
-
console.error(e);
|
|
48
|
-
}
|
|
7
|
+
export async function getIndexedDBStorage(name = DATABASE_NAME) {
|
|
8
|
+
const dbPromise = new Promise((resolve, reject) => {
|
|
9
|
+
const request = indexedDB.open(name, 4);
|
|
10
|
+
request.onerror = () => {
|
|
11
|
+
reject(request.error);
|
|
12
|
+
};
|
|
13
|
+
request.onsuccess = () => {
|
|
14
|
+
resolve(request.result);
|
|
15
|
+
};
|
|
16
|
+
request.onupgradeneeded = async (ev) => {
|
|
17
|
+
const db = request.result;
|
|
18
|
+
if (ev.oldVersion === 0) {
|
|
19
|
+
const coValues = db.createObjectStore("coValues", {
|
|
20
|
+
autoIncrement: true,
|
|
21
|
+
keyPath: "rowID",
|
|
22
|
+
});
|
|
23
|
+
coValues.createIndex("coValuesById", "id", {
|
|
24
|
+
unique: true,
|
|
25
|
+
});
|
|
26
|
+
const sessions = db.createObjectStore("sessions", {
|
|
27
|
+
autoIncrement: true,
|
|
28
|
+
keyPath: "rowID",
|
|
29
|
+
});
|
|
30
|
+
sessions.createIndex("sessionsByCoValue", "coValue");
|
|
31
|
+
sessions.createIndex("uniqueSessions", ["coValue", "sessionID"], {
|
|
32
|
+
unique: true,
|
|
33
|
+
});
|
|
34
|
+
db.createObjectStore("transactions", {
|
|
35
|
+
keyPath: ["ses", "idx"],
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (ev.oldVersion <= 1) {
|
|
39
|
+
db.createObjectStore("signatureAfter", {
|
|
40
|
+
keyPath: ["ses", "idx"],
|
|
41
|
+
});
|
|
49
42
|
}
|
|
50
43
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
localNodeName: "local",
|
|
55
|
-
}) {
|
|
56
|
-
const [localNodeAsPeer, storageAsPeer] = cojsonInternals.connectedPeers(localNodeName, "indexedDB", {
|
|
57
|
-
peer1role: "client",
|
|
58
|
-
peer2role: "storage",
|
|
59
|
-
crashOnClose: true,
|
|
60
|
-
});
|
|
61
|
-
await IDBNode.open(localNodeAsPeer.incoming, localNodeAsPeer.outgoing);
|
|
62
|
-
return { ...storageAsPeer, priority: 100 };
|
|
63
|
-
}
|
|
64
|
-
static async open(fromLocalNode, toLocalNode) {
|
|
65
|
-
const dbPromise = new Promise((resolve, reject) => {
|
|
66
|
-
const request = indexedDB.open(DATABASE_NAME, 4);
|
|
67
|
-
request.onerror = () => {
|
|
68
|
-
reject(request.error);
|
|
69
|
-
};
|
|
70
|
-
request.onsuccess = () => {
|
|
71
|
-
resolve(request.result);
|
|
72
|
-
};
|
|
73
|
-
request.onupgradeneeded = async (ev) => {
|
|
74
|
-
const db = request.result;
|
|
75
|
-
if (ev.oldVersion === 0) {
|
|
76
|
-
const coValues = db.createObjectStore("coValues", {
|
|
77
|
-
autoIncrement: true,
|
|
78
|
-
keyPath: "rowID",
|
|
79
|
-
});
|
|
80
|
-
coValues.createIndex("coValuesById", "id", {
|
|
81
|
-
unique: true,
|
|
82
|
-
});
|
|
83
|
-
const sessions = db.createObjectStore("sessions", {
|
|
84
|
-
autoIncrement: true,
|
|
85
|
-
keyPath: "rowID",
|
|
86
|
-
});
|
|
87
|
-
sessions.createIndex("sessionsByCoValue", "coValue");
|
|
88
|
-
sessions.createIndex("uniqueSessions", ["coValue", "sessionID"], {
|
|
89
|
-
unique: true,
|
|
90
|
-
});
|
|
91
|
-
db.createObjectStore("transactions", {
|
|
92
|
-
keyPath: ["ses", "idx"],
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
if (ev.oldVersion <= 1) {
|
|
96
|
-
db.createObjectStore("signatureAfter", {
|
|
97
|
-
keyPath: ["ses", "idx"],
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
});
|
|
102
|
-
return new IDBNode(await dbPromise, fromLocalNode, toLocalNode);
|
|
103
|
-
}
|
|
44
|
+
});
|
|
45
|
+
const db = await dbPromise;
|
|
46
|
+
return new StorageApiAsync(new IDBClient(db));
|
|
104
47
|
}
|
|
105
48
|
//# sourceMappingURL=idbNode.js.map
|
package/dist/idbNode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idbNode.js","sourceRoot":"","sources":["../src/idbNode.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"idbNode.js","sourceRoot":"","sources":["../src/idbNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,IAAI,aAAa,GAAG,cAAc,CAAC;AAEnC,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAI,GAAG,aAAa;IAC5D,MAAM,SAAS,GAAG,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7D,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE;YACrB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC,CAAC;QACF,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE;YACvB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC,CAAC;QACF,OAAO,CAAC,eAAe,GAAG,KAAK,EAAE,EAAE,EAAE,EAAE;YACrC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;YAC1B,IAAI,EAAE,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;gBACxB,MAAM,QAAQ,GAAG,EAAE,CAAC,iBAAiB,CAAC,UAAU,EAAE;oBAChD,aAAa,EAAE,IAAI;oBACnB,OAAO,EAAE,OAAO;iBACjB,CAAC,CAAC;gBAEH,QAAQ,CAAC,WAAW,CAAC,cAAc,EAAE,IAAI,EAAE;oBACzC,MAAM,EAAE,IAAI;iBACb,CAAC,CAAC;gBAEH,MAAM,QAAQ,GAAG,EAAE,CAAC,iBAAiB,CAAC,UAAU,EAAE;oBAChD,aAAa,EAAE,IAAI;oBACnB,OAAO,EAAE,OAAO;iBACjB,CAAC,CAAC;gBAEH,QAAQ,CAAC,WAAW,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAC;gBACrD,QAAQ,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE;oBAC/D,MAAM,EAAE,IAAI;iBACb,CAAC,CAAC;gBAEH,EAAE,CAAC,iBAAiB,CAAC,cAAc,EAAE;oBACnC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;iBACxB,CAAC,CAAC;YACL,CAAC;YACD,IAAI,EAAE,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;gBACvB,EAAE,CAAC,iBAAiB,CAAC,gBAAgB,EAAE;oBACrC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;iBACxB,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC;IAE3B,OAAO,IAAI,eAAe,CAAC,IAAI,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;AAChD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { internal_setDatabaseName, getIndexedDBStorage, } from "./idbNode.js";
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { internal_setDatabaseName, getIndexedDBStorage, } from "./idbNode.js";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,cAAc,CAAC"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { LocalNode } from "cojson";
|
|
2
|
-
import { StorageManagerAsync } from "cojson-storage";
|
|
1
|
+
import { LocalNode, StorageApiAsync } from "cojson";
|
|
3
2
|
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
|
|
4
3
|
import { afterEach, beforeEach, expect, test, vi } from "vitest";
|
|
5
|
-
import {
|
|
4
|
+
import { getIndexedDBStorage } from "../index.js";
|
|
6
5
|
import { toSimplifiedMessages } from "./messagesTestUtils.js";
|
|
7
6
|
import { trackMessages, waitFor } from "./testUtils.js";
|
|
8
7
|
const Crypto = await WasmCrypto.create();
|
|
@@ -13,38 +12,27 @@ beforeEach(() => {
|
|
|
13
12
|
afterEach(() => {
|
|
14
13
|
syncMessages.restore();
|
|
15
14
|
});
|
|
16
|
-
test("Should be able to initialize and load from empty DB", async () => {
|
|
17
|
-
const agentSecret = Crypto.newRandomAgentSecret();
|
|
18
|
-
const node = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
19
|
-
node.syncManager.addPeer(await IDBStorage.asPeer());
|
|
20
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
21
|
-
expect(node.syncManager.peers.indexedDB).toBeDefined();
|
|
22
|
-
});
|
|
23
15
|
test("should sync and load data from storage", async () => {
|
|
24
16
|
const agentSecret = Crypto.newRandomAgentSecret();
|
|
25
17
|
const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
26
|
-
|
|
27
|
-
node1.syncManager.addPeer(peer);
|
|
18
|
+
node1.setStorage(await getIndexedDBStorage());
|
|
28
19
|
const group = node1.createGroup();
|
|
29
20
|
const map = group.createMap();
|
|
30
21
|
map.set("hello", "world");
|
|
31
|
-
await
|
|
22
|
+
await map.core.waitForSync();
|
|
32
23
|
expect(toSimplifiedMessages({
|
|
33
24
|
Map: map.core,
|
|
34
25
|
Group: group.core,
|
|
35
26
|
}, syncMessages.messages)).toMatchInlineSnapshot(`
|
|
36
27
|
[
|
|
37
28
|
"client -> CONTENT Group header: true new: After: 0 New: 3",
|
|
38
|
-
"storage -> KNOWN Group sessions: header/3",
|
|
39
29
|
"client -> CONTENT Map header: true new: After: 0 New: 1",
|
|
40
|
-
"storage -> KNOWN Map sessions: header/1",
|
|
41
30
|
]
|
|
42
31
|
`);
|
|
43
32
|
node1.gracefulShutdown();
|
|
44
33
|
syncMessages.clear();
|
|
45
34
|
const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
46
|
-
|
|
47
|
-
node2.syncManager.addPeer(peer2);
|
|
35
|
+
node2.setStorage(await getIndexedDBStorage());
|
|
48
36
|
const map2 = await node2.load(map.id);
|
|
49
37
|
if (map2 === "unavailable") {
|
|
50
38
|
throw new Error("Map is unavailable");
|
|
@@ -57,36 +45,30 @@ test("should sync and load data from storage", async () => {
|
|
|
57
45
|
[
|
|
58
46
|
"client -> LOAD Map sessions: empty",
|
|
59
47
|
"storage -> CONTENT Group header: true new: After: 0 New: 3",
|
|
60
|
-
"client -> KNOWN Group sessions: header/3",
|
|
61
48
|
"storage -> CONTENT Map header: true new: After: 0 New: 1",
|
|
62
|
-
"client -> KNOWN Map sessions: header/1",
|
|
63
49
|
]
|
|
64
50
|
`);
|
|
65
51
|
});
|
|
66
52
|
test("should send an empty content message if there is no content", async () => {
|
|
67
53
|
const agentSecret = Crypto.newRandomAgentSecret();
|
|
68
54
|
const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
69
|
-
|
|
70
|
-
node1.syncManager.addPeer(peer);
|
|
55
|
+
node1.setStorage(await getIndexedDBStorage());
|
|
71
56
|
const group = node1.createGroup();
|
|
72
57
|
const map = group.createMap();
|
|
73
|
-
await
|
|
58
|
+
await map.core.waitForSync();
|
|
74
59
|
expect(toSimplifiedMessages({
|
|
75
60
|
Map: map.core,
|
|
76
61
|
Group: group.core,
|
|
77
62
|
}, syncMessages.messages)).toMatchInlineSnapshot(`
|
|
78
63
|
[
|
|
79
64
|
"client -> CONTENT Group header: true new: After: 0 New: 3",
|
|
80
|
-
"storage -> KNOWN Group sessions: header/3",
|
|
81
65
|
"client -> CONTENT Map header: true new: ",
|
|
82
|
-
"storage -> KNOWN Map sessions: header/0",
|
|
83
66
|
]
|
|
84
67
|
`);
|
|
85
68
|
syncMessages.clear();
|
|
86
69
|
node1.gracefulShutdown();
|
|
87
70
|
const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
88
|
-
|
|
89
|
-
node2.syncManager.addPeer(peer2);
|
|
71
|
+
node2.setStorage(await getIndexedDBStorage());
|
|
90
72
|
const map2 = await node2.load(map.id);
|
|
91
73
|
if (map2 === "unavailable") {
|
|
92
74
|
throw new Error("Map is unavailable");
|
|
@@ -98,42 +80,35 @@ test("should send an empty content message if there is no content", async () =>
|
|
|
98
80
|
[
|
|
99
81
|
"client -> LOAD Map sessions: empty",
|
|
100
82
|
"storage -> CONTENT Group header: true new: After: 0 New: 3",
|
|
101
|
-
"client -> KNOWN Group sessions: header/3",
|
|
102
83
|
"storage -> CONTENT Map header: true new: ",
|
|
103
|
-
"client -> KNOWN Map sessions: header/0",
|
|
104
84
|
]
|
|
105
85
|
`);
|
|
106
86
|
});
|
|
107
87
|
test("should load dependencies correctly (group inheritance)", async () => {
|
|
108
88
|
const agentSecret = Crypto.newRandomAgentSecret();
|
|
109
89
|
const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
110
|
-
|
|
111
|
-
node1.syncManager.addPeer(peer);
|
|
90
|
+
node1.setStorage(await getIndexedDBStorage());
|
|
112
91
|
const group = node1.createGroup();
|
|
113
92
|
const parentGroup = node1.createGroup();
|
|
114
93
|
group.extend(parentGroup);
|
|
115
94
|
const map = group.createMap();
|
|
116
95
|
map.set("hello", "world");
|
|
117
|
-
await
|
|
96
|
+
await map.core.waitForSync();
|
|
118
97
|
expect(toSimplifiedMessages({
|
|
119
98
|
Map: map.core,
|
|
120
99
|
Group: group.core,
|
|
121
100
|
ParentGroup: parentGroup.core,
|
|
122
101
|
}, syncMessages.messages)).toMatchInlineSnapshot(`
|
|
123
102
|
[
|
|
124
|
-
"client -> CONTENT ParentGroup header: true new: After: 0 New: 4",
|
|
125
|
-
"storage -> KNOWN ParentGroup sessions: header/4",
|
|
126
103
|
"client -> CONTENT Group header: true new: After: 0 New: 5",
|
|
127
|
-
"
|
|
104
|
+
"client -> CONTENT ParentGroup header: true new: After: 0 New: 4",
|
|
128
105
|
"client -> CONTENT Map header: true new: After: 0 New: 1",
|
|
129
|
-
"storage -> KNOWN Map sessions: header/1",
|
|
130
106
|
]
|
|
131
107
|
`);
|
|
132
108
|
syncMessages.clear();
|
|
133
109
|
node1.gracefulShutdown();
|
|
134
110
|
const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
135
|
-
|
|
136
|
-
node2.syncManager.addPeer(peer2);
|
|
111
|
+
node2.setStorage(await getIndexedDBStorage());
|
|
137
112
|
await node2.load(map.id);
|
|
138
113
|
expect(node2.expectCoValueLoaded(map.id)).toBeTruthy();
|
|
139
114
|
expect(node2.expectCoValueLoaded(group.id)).toBeTruthy();
|
|
@@ -146,19 +121,15 @@ test("should load dependencies correctly (group inheritance)", async () => {
|
|
|
146
121
|
[
|
|
147
122
|
"client -> LOAD Map sessions: empty",
|
|
148
123
|
"storage -> CONTENT ParentGroup header: true new: After: 0 New: 4",
|
|
149
|
-
"client -> KNOWN ParentGroup sessions: header/4",
|
|
150
124
|
"storage -> CONTENT Group header: true new: After: 0 New: 5",
|
|
151
|
-
"client -> KNOWN Group sessions: header/5",
|
|
152
125
|
"storage -> CONTENT Map header: true new: After: 0 New: 1",
|
|
153
|
-
"client -> KNOWN Map sessions: header/1",
|
|
154
126
|
]
|
|
155
127
|
`);
|
|
156
128
|
});
|
|
157
129
|
test("should not send the same dependency value twice", async () => {
|
|
158
130
|
const agentSecret = Crypto.newRandomAgentSecret();
|
|
159
131
|
const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
160
|
-
|
|
161
|
-
node1.syncManager.addPeer(peer);
|
|
132
|
+
node1.setStorage(await getIndexedDBStorage());
|
|
162
133
|
const group = node1.createGroup();
|
|
163
134
|
const parentGroup = node1.createGroup();
|
|
164
135
|
group.extend(parentGroup);
|
|
@@ -166,12 +137,12 @@ test("should not send the same dependency value twice", async () => {
|
|
|
166
137
|
const map = group.createMap();
|
|
167
138
|
map.set("hello", "world");
|
|
168
139
|
mapFromParent.set("hello", "world");
|
|
169
|
-
await
|
|
140
|
+
await map.core.waitForSync();
|
|
141
|
+
await mapFromParent.core.waitForSync();
|
|
170
142
|
syncMessages.clear();
|
|
171
143
|
node1.gracefulShutdown();
|
|
172
144
|
const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
173
|
-
|
|
174
|
-
node2.syncManager.addPeer(peer2);
|
|
145
|
+
node2.setStorage(await getIndexedDBStorage());
|
|
175
146
|
await node2.load(map.id);
|
|
176
147
|
await node2.load(mapFromParent.id);
|
|
177
148
|
expect(node2.expectCoValueLoaded(map.id)).toBeTruthy();
|
|
@@ -187,55 +158,49 @@ test("should not send the same dependency value twice", async () => {
|
|
|
187
158
|
[
|
|
188
159
|
"client -> LOAD Map sessions: empty",
|
|
189
160
|
"storage -> CONTENT ParentGroup header: true new: After: 0 New: 4",
|
|
190
|
-
"client -> KNOWN ParentGroup sessions: header/4",
|
|
191
161
|
"storage -> CONTENT Group header: true new: After: 0 New: 5",
|
|
192
|
-
"client -> KNOWN Group sessions: header/5",
|
|
193
162
|
"storage -> CONTENT Map header: true new: After: 0 New: 1",
|
|
194
|
-
"client -> KNOWN Map sessions: header/1",
|
|
195
163
|
"client -> LOAD MapFromParent sessions: empty",
|
|
196
164
|
"storage -> CONTENT MapFromParent header: true new: After: 0 New: 1",
|
|
197
|
-
"client -> KNOWN MapFromParent sessions: header/1",
|
|
198
165
|
]
|
|
199
166
|
`);
|
|
200
167
|
});
|
|
201
168
|
test("should recover from data loss", async () => {
|
|
202
169
|
const agentSecret = Crypto.newRandomAgentSecret();
|
|
203
170
|
const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
204
|
-
const
|
|
205
|
-
node1.
|
|
171
|
+
const storage = await getIndexedDBStorage();
|
|
172
|
+
node1.setStorage(storage);
|
|
206
173
|
const group = node1.createGroup();
|
|
207
174
|
const map = group.createMap();
|
|
208
175
|
map.set("0", 0);
|
|
209
|
-
await
|
|
176
|
+
await map.core.waitForSync();
|
|
210
177
|
const mock = vi
|
|
211
|
-
.spyOn(
|
|
212
|
-
.mockImplementation(() => Promise.resolve());
|
|
178
|
+
.spyOn(StorageApiAsync.prototype, "store")
|
|
179
|
+
.mockImplementation(() => Promise.resolve(undefined));
|
|
213
180
|
map.set("1", 1);
|
|
214
181
|
map.set("2", 2);
|
|
215
182
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
183
|
+
const knownState = storage.getKnownState(map.id);
|
|
184
|
+
Object.assign(knownState, map.core.knownState());
|
|
216
185
|
mock.mockReset();
|
|
217
186
|
map.set("3", 3);
|
|
218
|
-
await
|
|
187
|
+
await map.core.waitForSync();
|
|
219
188
|
expect(toSimplifiedMessages({
|
|
220
189
|
Map: map.core,
|
|
221
190
|
Group: group.core,
|
|
222
191
|
}, syncMessages.messages)).toMatchInlineSnapshot(`
|
|
223
192
|
[
|
|
224
193
|
"client -> CONTENT Group header: true new: After: 0 New: 3",
|
|
225
|
-
"storage -> KNOWN Group sessions: header/3",
|
|
226
194
|
"client -> CONTENT Map header: true new: After: 0 New: 1",
|
|
227
|
-
"storage -> KNOWN Map sessions: header/1",
|
|
228
195
|
"client -> CONTENT Map header: false new: After: 3 New: 1",
|
|
229
|
-
"storage -> KNOWN CORRECTION Map sessions: header/
|
|
196
|
+
"storage -> KNOWN CORRECTION Map sessions: header/4",
|
|
230
197
|
"client -> CONTENT Map header: false new: After: 1 New: 3",
|
|
231
|
-
"storage -> KNOWN Map sessions: header/4",
|
|
232
198
|
]
|
|
233
199
|
`);
|
|
234
200
|
syncMessages.clear();
|
|
235
201
|
node1.gracefulShutdown();
|
|
236
202
|
const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
237
|
-
|
|
238
|
-
node2.syncManager.addPeer(peer2);
|
|
203
|
+
node2.setStorage(await getIndexedDBStorage());
|
|
239
204
|
const map2 = await node2.load(map.id);
|
|
240
205
|
if (map2 === "unavailable") {
|
|
241
206
|
throw new Error("Map is unavailable");
|
|
@@ -253,23 +218,21 @@ test("should recover from data loss", async () => {
|
|
|
253
218
|
[
|
|
254
219
|
"client -> LOAD Map sessions: empty",
|
|
255
220
|
"storage -> CONTENT Group header: true new: After: 0 New: 3",
|
|
256
|
-
"client -> KNOWN Group sessions: header/3",
|
|
257
221
|
"storage -> CONTENT Map header: true new: After: 0 New: 4",
|
|
258
|
-
"client -> KNOWN Map sessions: header/4",
|
|
259
222
|
]
|
|
260
223
|
`);
|
|
261
224
|
});
|
|
262
225
|
test("should sync multiple sessions in a single content message", async () => {
|
|
263
226
|
const agentSecret = Crypto.newRandomAgentSecret();
|
|
264
227
|
const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
265
|
-
node1.
|
|
228
|
+
node1.setStorage(await getIndexedDBStorage());
|
|
266
229
|
const group = node1.createGroup();
|
|
267
230
|
const map = group.createMap();
|
|
268
231
|
map.set("hello", "world");
|
|
269
|
-
await
|
|
232
|
+
await map.core.waitForSync();
|
|
270
233
|
node1.gracefulShutdown();
|
|
271
234
|
const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
272
|
-
node2.
|
|
235
|
+
node2.setStorage(await getIndexedDBStorage());
|
|
273
236
|
const map2 = await node2.load(map.id);
|
|
274
237
|
if (map2 === "unavailable") {
|
|
275
238
|
throw new Error("Map is unavailable");
|
|
@@ -280,7 +243,7 @@ test("should sync multiple sessions in a single content message", async () => {
|
|
|
280
243
|
node2.gracefulShutdown();
|
|
281
244
|
const node3 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
282
245
|
syncMessages.clear();
|
|
283
|
-
node3.
|
|
246
|
+
node3.setStorage(await getIndexedDBStorage());
|
|
284
247
|
const map3 = await node3.load(map.id);
|
|
285
248
|
if (map3 === "unavailable") {
|
|
286
249
|
throw new Error("Map is unavailable");
|
|
@@ -293,16 +256,14 @@ test("should sync multiple sessions in a single content message", async () => {
|
|
|
293
256
|
[
|
|
294
257
|
"client -> LOAD Map sessions: empty",
|
|
295
258
|
"storage -> CONTENT Group header: true new: After: 0 New: 3",
|
|
296
|
-
"client -> KNOWN Group sessions: header/3",
|
|
297
259
|
"storage -> CONTENT Map header: true new: After: 0 New: 1 | After: 0 New: 1",
|
|
298
|
-
"client -> KNOWN Map sessions: header/2",
|
|
299
260
|
]
|
|
300
261
|
`);
|
|
301
262
|
});
|
|
302
263
|
test("large coValue upload streaming", async () => {
|
|
303
264
|
const agentSecret = Crypto.newRandomAgentSecret();
|
|
304
265
|
const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
305
|
-
node1.
|
|
266
|
+
node1.setStorage(await getIndexedDBStorage());
|
|
306
267
|
const group = node1.createGroup();
|
|
307
268
|
const largeMap = group.createMap();
|
|
308
269
|
// Generate a large amount of data (about 100MB)
|
|
@@ -314,12 +275,13 @@ test("large coValue upload streaming", async () => {
|
|
|
314
275
|
const key = `key${i}`;
|
|
315
276
|
largeMap.set(key, value, "trusting");
|
|
316
277
|
}
|
|
278
|
+
// TODO: Wait for storage to be updated
|
|
317
279
|
await largeMap.core.waitForSync();
|
|
318
280
|
const knownState = largeMap.core.knownState();
|
|
319
281
|
node1.gracefulShutdown();
|
|
320
282
|
const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
|
|
321
283
|
syncMessages.clear();
|
|
322
|
-
node2.
|
|
284
|
+
node2.setStorage(await getIndexedDBStorage());
|
|
323
285
|
const largeMapOnNode2 = await node2.load(largeMap.id);
|
|
324
286
|
if (largeMapOnNode2 === "unavailable") {
|
|
325
287
|
throw new Error("Map is unavailable");
|
|
@@ -334,15 +296,10 @@ test("large coValue upload streaming", async () => {
|
|
|
334
296
|
}, syncMessages.messages)).toMatchInlineSnapshot(`
|
|
335
297
|
[
|
|
336
298
|
"client -> LOAD Map sessions: empty",
|
|
337
|
-
"storage -> KNOWN Map sessions: header/200",
|
|
338
299
|
"storage -> CONTENT Group header: true new: After: 0 New: 3",
|
|
339
|
-
"client -> KNOWN Group sessions: header/3",
|
|
340
300
|
"storage -> CONTENT Map header: true new: After: 0 New: 97",
|
|
341
|
-
"client -> KNOWN Map sessions: header/97",
|
|
342
301
|
"storage -> CONTENT Map header: true new: After: 97 New: 97",
|
|
343
|
-
"client -> KNOWN Map sessions: header/194",
|
|
344
302
|
"storage -> CONTENT Map header: true new: After: 194 New: 6",
|
|
345
|
-
"client -> KNOWN Map sessions: header/200",
|
|
346
303
|
]
|
|
347
304
|
`);
|
|
348
305
|
});
|
|
@@ -351,7 +308,7 @@ test("should sync and load accounts from storage", async () => {
|
|
|
351
308
|
const { node: node1, accountID } = await LocalNode.withNewlyCreatedAccount({
|
|
352
309
|
crypto: Crypto,
|
|
353
310
|
initialAgentSecret: agentSecret,
|
|
354
|
-
|
|
311
|
+
storage: await getIndexedDBStorage(),
|
|
355
312
|
creationProps: {
|
|
356
313
|
name: "test",
|
|
357
314
|
},
|
|
@@ -359,7 +316,6 @@ test("should sync and load accounts from storage", async () => {
|
|
|
359
316
|
const account1 = node1.getCoValue(accountID);
|
|
360
317
|
const profile = node1.expectProfileLoaded(accountID);
|
|
361
318
|
const profileGroup = profile.group;
|
|
362
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
363
319
|
expect(toSimplifiedMessages({
|
|
364
320
|
Account: account1,
|
|
365
321
|
Profile: profile.core,
|
|
@@ -367,11 +323,8 @@ test("should sync and load accounts from storage", async () => {
|
|
|
367
323
|
}, syncMessages.messages)).toMatchInlineSnapshot(`
|
|
368
324
|
[
|
|
369
325
|
"client -> CONTENT Account header: true new: After: 0 New: 4",
|
|
370
|
-
"storage -> KNOWN Account sessions: header/4",
|
|
371
326
|
"client -> CONTENT ProfileGroup header: true new: After: 0 New: 5",
|
|
372
|
-
"storage -> KNOWN ProfileGroup sessions: header/5",
|
|
373
327
|
"client -> CONTENT Profile header: true new: After: 0 New: 1",
|
|
374
|
-
"storage -> KNOWN Profile sessions: header/1",
|
|
375
328
|
]
|
|
376
329
|
`);
|
|
377
330
|
node1.gracefulShutdown();
|
|
@@ -381,10 +334,10 @@ test("should sync and load accounts from storage", async () => {
|
|
|
381
334
|
crypto: Crypto,
|
|
382
335
|
accountSecret: agentSecret,
|
|
383
336
|
accountID,
|
|
384
|
-
peersToLoadFrom: [
|
|
337
|
+
peersToLoadFrom: [],
|
|
338
|
+
storage: await getIndexedDBStorage(),
|
|
385
339
|
sessionID: Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
|
|
386
340
|
});
|
|
387
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
388
341
|
expect(toSimplifiedMessages({
|
|
389
342
|
Account: account1,
|
|
390
343
|
Profile: profile.core,
|
|
@@ -393,12 +346,9 @@ test("should sync and load accounts from storage", async () => {
|
|
|
393
346
|
[
|
|
394
347
|
"client -> LOAD Account sessions: empty",
|
|
395
348
|
"storage -> CONTENT Account header: true new: After: 0 New: 4",
|
|
396
|
-
"client -> KNOWN Account sessions: header/4",
|
|
397
349
|
"client -> LOAD Profile sessions: empty",
|
|
398
350
|
"storage -> CONTENT ProfileGroup header: true new: After: 0 New: 5",
|
|
399
|
-
"client -> KNOWN ProfileGroup sessions: header/5",
|
|
400
351
|
"storage -> CONTENT Profile header: true new: After: 0 New: 1",
|
|
401
|
-
"client -> KNOWN Profile sessions: header/1",
|
|
402
352
|
]
|
|
403
353
|
`);
|
|
404
354
|
expect(node2.getCoValue(accountID).isAvailable()).toBeTruthy();
|