cojson-storage-indexeddb 0.13.28 → 0.13.29

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.
@@ -1,4 +1,4 @@
1
1
 
2
- > cojson-storage-indexeddb@0.13.28 build /home/runner/_work/jazz/jazz/packages/cojson-storage-indexeddb
2
+ > cojson-storage-indexeddb@0.13.29 build /home/runner/_work/jazz/jazz/packages/cojson-storage-indexeddb
3
3
  > rm -rf ./dist && tsc --sourceMap --outDir dist
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # cojson-storage-indexeddb
2
2
 
3
+ ## 0.13.29
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [e2d6ba3]
8
+ - Updated dependencies [eef1a5d]
9
+ - Updated dependencies [191ae38]
10
+ - Updated dependencies [daee7b9]
11
+ - cojson-storage@0.13.29
12
+ - cojson@0.13.29
13
+
3
14
  ## 0.13.28
4
15
 
5
16
  ### Patch Changes
@@ -1,7 +1,7 @@
1
1
  import type { CojsonInternalTypes, RawCoID, SessionID } from "cojson";
2
- import type { DBClientInterface, SessionRow, SignatureAfterRow, StoredCoValueRow, StoredSessionRow, TransactionRow } from "cojson-storage";
2
+ import type { DBClientInterfaceAsync, SessionRow, SignatureAfterRow, StoredCoValueRow, StoredSessionRow, TransactionRow } from "cojson-storage";
3
3
  import { CoJsonIDBTransaction } from "./CoJsonIDBTransaction.js";
4
- export declare class IDBClient implements DBClientInterface {
4
+ export declare class IDBClient implements DBClientInterfaceAsync {
5
5
  private db;
6
6
  activeTransaction: CoJsonIDBTransaction | undefined;
7
7
  autoBatchingTransaction: CoJsonIDBTransaction | undefined;
@@ -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,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,qBAAa,SAAU,YAAW,iBAAiB;IACjD,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,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,cAAc,EAAE,CAAC;IAatB,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"}
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,gBAAgB,CAAC;AACxB,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,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,cAAc,EAAE,CAAC;IAatB,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"}
@@ -1 +1 @@
1
- {"version":3,"file":"idbNode.d.ts","sourceRoot":"","sources":["../src/idbNode.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,IAAI,EAEV,MAAM,QAAQ,CAAC;AAMhB,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,QAEpD;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;gBAGxC,EAAE,EAAE,WAAW,EACf,aAAa,EAAE,kBAAkB,EACjC,WAAW,EAAE,iBAAiB;WAuBnB,MAAM,CACjB,EAAE,aAAuB,EAAE,GAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAEzD,GACA,OAAO,CAAC,IAAI,CAAC;WAgBH,IAAI,CACf,aAAa,EAAE,kBAAkB,EACjC,WAAW,EAAE,iBAAiB;CA8CjC"}
1
+ {"version":3,"file":"idbNode.d.ts","sourceRoot":"","sources":["../src/idbNode.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,IAAI,EAEV,MAAM,QAAQ,CAAC;AAMhB,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,QAEpD;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsB;gBAGhD,EAAE,EAAE,WAAW,EACf,aAAa,EAAE,kBAAkB,EACjC,WAAW,EAAE,iBAAiB;WAuBnB,MAAM,CACjB,EAAE,aAAuB,EAAE,GAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAEzD,GACA,OAAO,CAAC,IAAI,CAAC;WAgBH,IAAI,CACf,aAAa,EAAE,kBAAkB,EACjC,WAAW,EAAE,iBAAiB;CA8CjC"}
package/dist/idbNode.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { cojsonInternals, } from "cojson";
2
- import { SyncManager } from "cojson-storage";
2
+ import { StorageManagerAsync } from "cojson-storage";
3
3
  import { IDBClient } from "./idbClient.js";
4
4
  let DATABASE_NAME = "jazz-storage";
5
5
  export function internal_setDatabaseName(name) {
@@ -8,7 +8,7 @@ export function internal_setDatabaseName(name) {
8
8
  export class IDBNode {
9
9
  constructor(db, fromLocalNode, toLocalNode) {
10
10
  this.dbClient = new IDBClient(db);
11
- this.syncManager = new SyncManager(this.dbClient, toLocalNode);
11
+ this.syncManager = new StorageManagerAsync(this.dbClient, toLocalNode);
12
12
  const processMessages = async () => {
13
13
  for await (const msg of fromLocalNode) {
14
14
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"idbNode.js","sourceRoot":"","sources":["../src/idbNode.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"idbNode.js","sourceRoot":"","sources":["../src/idbNode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=indexeddb.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb.test.d.ts","sourceRoot":"","sources":["../../src/tests/indexeddb.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,227 @@
1
+ import { LocalNode } from "cojson";
2
+ import { StorageManagerAsync } from "cojson-storage";
3
+ import { WasmCrypto } from "cojson/crypto/WasmCrypto";
4
+ import { expect, test, vi } from "vitest";
5
+ import { IDBStorage } from "../index.js";
6
+ import { toSimplifiedMessages } from "./messagesTestUtils.js";
7
+ import { trackMessages } from "./testUtils.js";
8
+ const Crypto = await WasmCrypto.create();
9
+ test("Should be able to initialize and load from empty DB", async () => {
10
+ const agentSecret = Crypto.newRandomAgentSecret();
11
+ const node = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
12
+ node.syncManager.addPeer(await IDBStorage.asPeer());
13
+ await new Promise((resolve) => setTimeout(resolve, 200));
14
+ expect(node.syncManager.peers.indexedDB).toBeDefined();
15
+ });
16
+ test("should sync and load data from storage", async () => {
17
+ const agentSecret = Crypto.newRandomAgentSecret();
18
+ const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
19
+ const node1Sync = trackMessages(node1);
20
+ const peer = await IDBStorage.asPeer();
21
+ node1.syncManager.addPeer(peer);
22
+ const group = node1.createGroup();
23
+ const map = group.createMap();
24
+ map.set("hello", "world");
25
+ await new Promise((resolve) => setTimeout(resolve, 200));
26
+ expect(toSimplifiedMessages({
27
+ Map: map.core,
28
+ Group: group.core,
29
+ }, node1Sync.messages)).toMatchInlineSnapshot(`
30
+ [
31
+ "client -> CONTENT Group header: true new: After: 0 New: 3",
32
+ "storage -> KNOWN Group sessions: header/3",
33
+ "client -> CONTENT Map header: true new: After: 0 New: 1",
34
+ "storage -> KNOWN Map sessions: header/1",
35
+ ]
36
+ `);
37
+ node1Sync.restore();
38
+ const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
39
+ const node2Sync = trackMessages(node2);
40
+ const peer2 = await IDBStorage.asPeer();
41
+ node2.syncManager.addPeer(peer2);
42
+ const map2 = await node2.load(map.id);
43
+ if (map2 === "unavailable") {
44
+ throw new Error("Map is unavailable");
45
+ }
46
+ expect(map2.get("hello")).toBe("world");
47
+ expect(toSimplifiedMessages({
48
+ Map: map.core,
49
+ Group: group.core,
50
+ }, node2Sync.messages)).toMatchInlineSnapshot(`
51
+ [
52
+ "client -> LOAD Map sessions: empty",
53
+ "storage -> KNOWN Group sessions: header/3",
54
+ "storage -> CONTENT Group header: true new: After: 0 New: 3",
55
+ "storage -> KNOWN Map sessions: header/1",
56
+ "storage -> CONTENT Map header: true new: After: 0 New: 1",
57
+ "client -> KNOWN Group sessions: header/3",
58
+ ]
59
+ `);
60
+ node2Sync.restore();
61
+ });
62
+ test("should load dependencies correctly (group inheritance)", async () => {
63
+ const agentSecret = Crypto.newRandomAgentSecret();
64
+ const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
65
+ const node1Sync = trackMessages(node1);
66
+ const peer = await IDBStorage.asPeer();
67
+ node1.syncManager.addPeer(peer);
68
+ const group = node1.createGroup();
69
+ const parentGroup = node1.createGroup();
70
+ group.extend(parentGroup);
71
+ const map = group.createMap();
72
+ map.set("hello", "world");
73
+ await new Promise((resolve) => setTimeout(resolve, 200));
74
+ expect(toSimplifiedMessages({
75
+ Map: map.core,
76
+ Group: group.core,
77
+ ParentGroup: parentGroup.core,
78
+ }, node1Sync.messages)).toMatchInlineSnapshot(`
79
+ [
80
+ "client -> CONTENT ParentGroup header: true new: After: 0 New: 4",
81
+ "storage -> KNOWN ParentGroup sessions: header/4",
82
+ "client -> CONTENT Group header: true new: After: 0 New: 5",
83
+ "storage -> KNOWN Group sessions: header/5",
84
+ "client -> CONTENT Map header: true new: After: 0 New: 1",
85
+ "storage -> KNOWN Map sessions: header/1",
86
+ ]
87
+ `);
88
+ node1Sync.restore();
89
+ const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
90
+ const node2Sync = trackMessages(node2);
91
+ const peer2 = await IDBStorage.asPeer();
92
+ node2.syncManager.addPeer(peer2);
93
+ await node2.load(map.id);
94
+ expect(node2.expectCoValueLoaded(map.id)).toBeTruthy();
95
+ expect(node2.expectCoValueLoaded(group.id)).toBeTruthy();
96
+ expect(node2.expectCoValueLoaded(parentGroup.id)).toBeTruthy();
97
+ expect(toSimplifiedMessages({
98
+ Map: map.core,
99
+ Group: group.core,
100
+ ParentGroup: parentGroup.core,
101
+ }, node2Sync.messages)).toMatchInlineSnapshot(`
102
+ [
103
+ "client -> LOAD Map sessions: empty",
104
+ "storage -> KNOWN ParentGroup sessions: header/4",
105
+ "storage -> CONTENT ParentGroup header: true new: After: 0 New: 4",
106
+ "storage -> KNOWN Group sessions: header/5",
107
+ "storage -> CONTENT Group header: true new: After: 0 New: 5",
108
+ "client -> KNOWN ParentGroup sessions: header/4",
109
+ "storage -> KNOWN Map sessions: header/1",
110
+ "storage -> CONTENT Map header: true new: After: 0 New: 1",
111
+ "client -> KNOWN Group sessions: header/5",
112
+ ]
113
+ `);
114
+ });
115
+ test("should not send the same dependency value twice", async () => {
116
+ const agentSecret = Crypto.newRandomAgentSecret();
117
+ const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
118
+ const node1Sync = trackMessages(node1);
119
+ const peer = await IDBStorage.asPeer();
120
+ node1.syncManager.addPeer(peer);
121
+ const group = node1.createGroup();
122
+ const parentGroup = node1.createGroup();
123
+ group.extend(parentGroup);
124
+ const mapFromParent = parentGroup.createMap();
125
+ const map = group.createMap();
126
+ map.set("hello", "world");
127
+ mapFromParent.set("hello", "world");
128
+ await new Promise((resolve) => setTimeout(resolve, 200));
129
+ node1Sync.restore();
130
+ const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
131
+ const node2Sync = trackMessages(node2);
132
+ const peer2 = await IDBStorage.asPeer();
133
+ node2.syncManager.addPeer(peer2);
134
+ await node2.load(map.id);
135
+ await node2.load(mapFromParent.id);
136
+ expect(node2.expectCoValueLoaded(map.id)).toBeTruthy();
137
+ expect(node2.expectCoValueLoaded(mapFromParent.id)).toBeTruthy();
138
+ expect(node2.expectCoValueLoaded(group.id)).toBeTruthy();
139
+ expect(node2.expectCoValueLoaded(parentGroup.id)).toBeTruthy();
140
+ expect(toSimplifiedMessages({
141
+ Map: map.core,
142
+ Group: group.core,
143
+ ParentGroup: parentGroup.core,
144
+ MapFromParent: mapFromParent.core,
145
+ }, node2Sync.messages)).toMatchInlineSnapshot(`
146
+ [
147
+ "client -> LOAD Map sessions: empty",
148
+ "storage -> KNOWN ParentGroup sessions: header/4",
149
+ "storage -> CONTENT ParentGroup header: true new: After: 0 New: 4",
150
+ "storage -> KNOWN Group sessions: header/5",
151
+ "storage -> CONTENT Group header: true new: After: 0 New: 5",
152
+ "client -> KNOWN ParentGroup sessions: header/4",
153
+ "storage -> KNOWN Map sessions: header/1",
154
+ "storage -> CONTENT Map header: true new: After: 0 New: 1",
155
+ "client -> KNOWN Group sessions: header/5",
156
+ "client -> KNOWN Map sessions: header/1",
157
+ "client -> LOAD MapFromParent sessions: empty",
158
+ "storage -> KNOWN MapFromParent sessions: header/1",
159
+ "storage -> CONTENT MapFromParent header: true new: After: 0 New: 1",
160
+ "client -> KNOWN MapFromParent sessions: header/1",
161
+ ]
162
+ `);
163
+ });
164
+ test("should recover from data loss", async () => {
165
+ const agentSecret = Crypto.newRandomAgentSecret();
166
+ const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
167
+ const node1Sync = trackMessages(node1);
168
+ const peer = await IDBStorage.asPeer();
169
+ node1.syncManager.addPeer(peer);
170
+ const group = node1.createGroup();
171
+ const map = group.createMap();
172
+ map.set("0", 0);
173
+ await new Promise((resolve) => setTimeout(resolve, 200));
174
+ const mock = vi
175
+ .spyOn(StorageManagerAsync.prototype, "handleSyncMessage")
176
+ .mockImplementation(() => Promise.resolve());
177
+ map.set("1", 1);
178
+ map.set("2", 2);
179
+ await new Promise((resolve) => setTimeout(resolve, 200));
180
+ mock.mockReset();
181
+ map.set("3", 3);
182
+ await new Promise((resolve) => setTimeout(resolve, 200));
183
+ expect(toSimplifiedMessages({
184
+ Map: map.core,
185
+ Group: group.core,
186
+ }, node1Sync.messages)).toMatchInlineSnapshot(`
187
+ [
188
+ "client -> CONTENT Group header: true new: After: 0 New: 3",
189
+ "storage -> KNOWN Group sessions: header/3",
190
+ "client -> CONTENT Map header: true new: After: 0 New: 1",
191
+ "storage -> KNOWN Map sessions: header/1",
192
+ "client -> CONTENT Map header: false new: After: 3 New: 1",
193
+ "storage -> KNOWN CORRECTION Map sessions: header/1",
194
+ "client -> CONTENT Map header: false new: After: 1 New: 3",
195
+ "storage -> KNOWN Map sessions: header/4",
196
+ ]
197
+ `);
198
+ node1Sync.restore();
199
+ const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
200
+ const node2Sync = trackMessages(node2);
201
+ const peer2 = await IDBStorage.asPeer();
202
+ node2.syncManager.addPeer(peer2);
203
+ const map2 = await node2.load(map.id);
204
+ if (map2 === "unavailable") {
205
+ throw new Error("Map is unavailable");
206
+ }
207
+ expect(map2.toJSON()).toEqual({
208
+ "0": 0,
209
+ "1": 1,
210
+ "2": 2,
211
+ "3": 3,
212
+ });
213
+ expect(toSimplifiedMessages({
214
+ Map: map.core,
215
+ Group: group.core,
216
+ }, node2Sync.messages)).toMatchInlineSnapshot(`
217
+ [
218
+ "client -> LOAD Map sessions: empty",
219
+ "storage -> KNOWN Group sessions: header/3",
220
+ "storage -> CONTENT Group header: true new: After: 0 New: 3",
221
+ "storage -> KNOWN Map sessions: header/4",
222
+ "storage -> CONTENT Map header: true new: After: 0 New: 4",
223
+ "client -> KNOWN Group sessions: header/3",
224
+ ]
225
+ `);
226
+ });
227
+ //# sourceMappingURL=indexeddb.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb.test.js","sourceRoot":"","sources":["../../src/tests/indexeddb.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { CoValueCore, SyncMessage } from "cojson";
2
+ export declare function toSimplifiedMessages(coValues: Record<string, CoValueCore>, messages: {
3
+ from: "client" | "server" | "storage";
4
+ msg: SyncMessage;
5
+ }[]): string[];
6
+ export declare function debugMessages(coValues: Record<string, CoValueCore>, messages: {
7
+ from: "client" | "server" | "storage";
8
+ msg: SyncMessage;
9
+ }[]): void;
10
+ //# sourceMappingURL=messagesTestUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messagesTestUtils.d.ts","sourceRoot":"","sources":["../../src/tests/messagesTestUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAuB,WAAW,EAAE,MAAM,QAAQ,CAAC;AA2B5E,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,QAAQ,EAAE;IACR,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtC,GAAG,EAAE,WAAW,CAAC;CAClB,EAAE,YA6BJ;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,QAAQ,EAAE;IACR,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtC,GAAG,EAAE,WAAW,CAAC;CAClB,EAAE,QAGJ"}
@@ -0,0 +1,42 @@
1
+ function simplifySessions(msg) {
2
+ const count = Object.values(msg.sessions).reduce((acc, session) => acc + session, 0);
3
+ if (msg.header) {
4
+ return `header/${count}`;
5
+ }
6
+ return "empty";
7
+ }
8
+ function simplifyNewContent(content) {
9
+ if (!content) {
10
+ return undefined;
11
+ }
12
+ return Object.values(content)
13
+ .map((c) => `After: ${c.after} New: ${c.newTransactions.length}`)
14
+ .join(" | ");
15
+ }
16
+ export function toSimplifiedMessages(coValues, messages) {
17
+ function getCoValue(id) {
18
+ for (const [name, coValue] of Object.entries(coValues)) {
19
+ if (coValue.id === id) {
20
+ return name;
21
+ }
22
+ }
23
+ return `unknown/${id}`;
24
+ }
25
+ function toDebugString(from, msg) {
26
+ switch (msg.action) {
27
+ case "known":
28
+ return `${from} -> KNOWN ${msg.isCorrection ? "CORRECTION " : ""}${getCoValue(msg.id)} sessions: ${simplifySessions(msg)}`;
29
+ case "load":
30
+ return `${from} -> LOAD ${getCoValue(msg.id)} sessions: ${simplifySessions(msg)}`;
31
+ case "done":
32
+ return `${from} -> DONE ${getCoValue(msg.id)}`;
33
+ case "content":
34
+ return `${from} -> CONTENT ${getCoValue(msg.id)} header: ${Boolean(msg.header)} new: ${simplifyNewContent(msg.new)}`;
35
+ }
36
+ }
37
+ return messages.map((m) => toDebugString(m.from, m.msg));
38
+ }
39
+ export function debugMessages(coValues, messages) {
40
+ console.log(toSimplifiedMessages(coValues, messages));
41
+ }
42
+ //# sourceMappingURL=messagesTestUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messagesTestUtils.js","sourceRoot":"","sources":["../../src/tests/messagesTestUtils.ts"],"names":[],"mappings":"AAEA,SAAS,gBAAgB,CAAC,GAA0C;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,MAAM,CAC9C,CAAC,GAAW,EAAE,OAAe,EAAE,EAAE,CAAC,GAAG,GAAG,OAAO,EAC/C,CAAC,CACF,CAAC;IAEF,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACf,OAAO,UAAU,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,kBAAkB,CACzB,OAAqD;IAErD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;SAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC;SAChE,IAAI,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,QAAqC,EACrC,QAGG;IAEH,SAAS,UAAU,CAAC,EAAU;QAC5B,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvD,IAAI,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,WAAW,EAAE,EAAE,CAAC;IACzB,CAAC;IAED,SAAS,aAAa,CACpB,IAAqC,EACrC,GAAgB;QAEhB,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;YACnB,KAAK,OAAO;gBACV,OAAO,GAAG,IAAI,aAAa,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7H,KAAK,MAAM;gBACT,OAAO,GAAG,IAAI,YAAY,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;YACpF,KAAK,MAAM;gBACT,OAAO,GAAG,IAAI,YAAY,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACjD,KAAK,SAAS;gBACZ,OAAO,GAAG,IAAI,eAAe,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACzH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,QAAqC,EACrC,QAGG;IAEH,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { LocalNode, SyncMessage } from "cojson";
2
+ export declare function trackMessages(node: LocalNode): {
3
+ messages: {
4
+ from: "client" | "server" | "storage";
5
+ msg: SyncMessage;
6
+ }[];
7
+ restore: () => void;
8
+ };
9
+ //# sourceMappingURL=testUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../../src/tests/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAIrD,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS;;cAEnC,QAAQ,GAAG,QAAQ,GAAG,SAAS;aAChC,WAAW;;;EAoCnB"}
@@ -0,0 +1,33 @@
1
+ import { StorageManagerAsync } from "cojson-storage";
2
+ import { onTestFinished } from "vitest";
3
+ export function trackMessages(node) {
4
+ const messages = [];
5
+ const originalHandleSyncMessage = StorageManagerAsync.prototype.handleSyncMessage;
6
+ const originalNodeSyncMessage = node.syncManager.handleSyncMessage;
7
+ StorageManagerAsync.prototype.handleSyncMessage = async function (msg) {
8
+ messages.push({
9
+ from: "client",
10
+ msg,
11
+ });
12
+ return originalHandleSyncMessage.call(this, msg);
13
+ };
14
+ node.syncManager.handleSyncMessage = async function (msg, peer) {
15
+ messages.push({
16
+ from: "storage",
17
+ msg,
18
+ });
19
+ return originalNodeSyncMessage.call(this, msg, peer);
20
+ };
21
+ const restore = () => {
22
+ StorageManagerAsync.prototype.handleSyncMessage = originalHandleSyncMessage;
23
+ node.syncManager.handleSyncMessage = originalNodeSyncMessage;
24
+ };
25
+ onTestFinished(() => {
26
+ restore();
27
+ });
28
+ return {
29
+ messages,
30
+ restore,
31
+ };
32
+ }
33
+ //# sourceMappingURL=testUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testUtils.js","sourceRoot":"","sources":["../../src/tests/testUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAExC,MAAM,UAAU,aAAa,CAAC,IAAe;IAC3C,MAAM,QAAQ,GAGR,EAAE,CAAC;IAET,MAAM,yBAAyB,GAC7B,mBAAmB,CAAC,SAAS,CAAC,iBAAiB,CAAC;IAClD,MAAM,uBAAuB,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC;IAEnE,mBAAmB,CAAC,SAAS,CAAC,iBAAiB,GAAG,KAAK,WAAW,GAAG;QACnE,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,QAAQ;YACd,GAAG;SACJ,CAAC,CAAC;QACH,OAAO,yBAAyB,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC,CAAC;IAEF,IAAI,CAAC,WAAW,CAAC,iBAAiB,GAAG,KAAK,WAAW,GAAG,EAAE,IAAI;QAC5D,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,SAAS;YACf,GAAG;SACJ,CAAC,CAAC;QACH,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,mBAAmB,CAAC,SAAS,CAAC,iBAAiB,GAAG,yBAAyB,CAAC;QAC5E,IAAI,CAAC,WAAW,CAAC,iBAAiB,GAAG,uBAAuB,CAAC;IAC/D,CAAC,CAAC;IAEF,cAAc,CAAC,GAAG,EAAE;QAClB,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,QAAQ;QACR,OAAO;KACR,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "cojson-storage-indexeddb",
3
- "version": "0.13.28",
3
+ "version": "0.13.29",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "types": "dist/index.d.ts",
7
7
  "license": "MIT",
8
8
  "dependencies": {
9
- "cojson": "0.13.28",
10
- "cojson-storage": "0.13.28"
9
+ "cojson": "0.13.29",
10
+ "cojson-storage": "0.13.29"
11
11
  },
12
12
  "devDependencies": {
13
13
  "typescript": "5.6.2",
package/src/idbClient.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { CojsonInternalTypes, RawCoID, SessionID } from "cojson";
2
2
  import type {
3
3
  CoValueRow,
4
- DBClientInterface,
4
+ DBClientInterfaceAsync,
5
5
  SessionRow,
6
6
  SignatureAfterRow,
7
7
  StoredCoValueRow,
@@ -10,7 +10,7 @@ import type {
10
10
  } from "cojson-storage";
11
11
  import { CoJsonIDBTransaction } from "./CoJsonIDBTransaction.js";
12
12
 
13
- export class IDBClient implements DBClientInterface {
13
+ export class IDBClient implements DBClientInterfaceAsync {
14
14
  private db;
15
15
 
16
16
  activeTransaction: CoJsonIDBTransaction | undefined;
package/src/idbNode.ts CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  type Peer,
5
5
  cojsonInternals,
6
6
  } from "cojson";
7
- import { SyncManager } from "cojson-storage";
7
+ import { StorageManagerAsync } from "cojson-storage";
8
8
  import { IDBClient } from "./idbClient.js";
9
9
 
10
10
  let DATABASE_NAME = "jazz-storage";
@@ -15,7 +15,7 @@ export function internal_setDatabaseName(name: string) {
15
15
 
16
16
  export class IDBNode {
17
17
  private readonly dbClient: IDBClient;
18
- private readonly syncManager: SyncManager;
18
+ private readonly syncManager: StorageManagerAsync;
19
19
 
20
20
  constructor(
21
21
  db: IDBDatabase,
@@ -23,7 +23,7 @@ export class IDBNode {
23
23
  toLocalNode: OutgoingSyncQueue,
24
24
  ) {
25
25
  this.dbClient = new IDBClient(db);
26
- this.syncManager = new SyncManager(this.dbClient, toLocalNode);
26
+ this.syncManager = new StorageManagerAsync(this.dbClient, toLocalNode);
27
27
 
28
28
  const processMessages = async () => {
29
29
  for await (const msg of fromLocalNode) {
@@ -0,0 +1,384 @@
1
+ import { LocalNode } from "cojson";
2
+ import { StorageManagerAsync } from "cojson-storage";
3
+ import { WasmCrypto } from "cojson/crypto/WasmCrypto";
4
+ import { expect, test, vi } from "vitest";
5
+ import { IDBStorage } from "../index.js";
6
+ import { toSimplifiedMessages } from "./messagesTestUtils.js";
7
+ import { trackMessages } from "./testUtils.js";
8
+
9
+ const Crypto = await WasmCrypto.create();
10
+
11
+ test("Should be able to initialize and load from empty DB", async () => {
12
+ const agentSecret = Crypto.newRandomAgentSecret();
13
+
14
+ const node = new LocalNode(
15
+ agentSecret,
16
+ Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
17
+ Crypto,
18
+ );
19
+
20
+ node.syncManager.addPeer(await IDBStorage.asPeer());
21
+
22
+ await new Promise((resolve) => setTimeout(resolve, 200));
23
+
24
+ expect(node.syncManager.peers.indexedDB).toBeDefined();
25
+ });
26
+
27
+ test("should sync and load data from storage", async () => {
28
+ const agentSecret = Crypto.newRandomAgentSecret();
29
+
30
+ const node1 = new LocalNode(
31
+ agentSecret,
32
+ Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
33
+ Crypto,
34
+ );
35
+
36
+ const node1Sync = trackMessages(node1);
37
+
38
+ const peer = await IDBStorage.asPeer();
39
+
40
+ node1.syncManager.addPeer(peer);
41
+
42
+ const group = node1.createGroup();
43
+
44
+ const map = group.createMap();
45
+
46
+ map.set("hello", "world");
47
+
48
+ await new Promise((resolve) => setTimeout(resolve, 200));
49
+
50
+ expect(
51
+ toSimplifiedMessages(
52
+ {
53
+ Map: map.core,
54
+ Group: group.core,
55
+ },
56
+ node1Sync.messages,
57
+ ),
58
+ ).toMatchInlineSnapshot(`
59
+ [
60
+ "client -> CONTENT Group header: true new: After: 0 New: 3",
61
+ "storage -> KNOWN Group sessions: header/3",
62
+ "client -> CONTENT Map header: true new: After: 0 New: 1",
63
+ "storage -> KNOWN Map sessions: header/1",
64
+ ]
65
+ `);
66
+
67
+ node1Sync.restore();
68
+
69
+ const node2 = new LocalNode(
70
+ agentSecret,
71
+ Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
72
+ Crypto,
73
+ );
74
+
75
+ const node2Sync = trackMessages(node2);
76
+
77
+ const peer2 = await IDBStorage.asPeer();
78
+
79
+ node2.syncManager.addPeer(peer2);
80
+
81
+ const map2 = await node2.load(map.id);
82
+ if (map2 === "unavailable") {
83
+ throw new Error("Map is unavailable");
84
+ }
85
+
86
+ expect(map2.get("hello")).toBe("world");
87
+
88
+ expect(
89
+ toSimplifiedMessages(
90
+ {
91
+ Map: map.core,
92
+ Group: group.core,
93
+ },
94
+ node2Sync.messages,
95
+ ),
96
+ ).toMatchInlineSnapshot(`
97
+ [
98
+ "client -> LOAD Map sessions: empty",
99
+ "storage -> KNOWN Group sessions: header/3",
100
+ "storage -> CONTENT Group header: true new: After: 0 New: 3",
101
+ "storage -> KNOWN Map sessions: header/1",
102
+ "storage -> CONTENT Map header: true new: After: 0 New: 1",
103
+ "client -> KNOWN Group sessions: header/3",
104
+ ]
105
+ `);
106
+
107
+ node2Sync.restore();
108
+ });
109
+
110
+ test("should load dependencies correctly (group inheritance)", async () => {
111
+ const agentSecret = Crypto.newRandomAgentSecret();
112
+
113
+ const node1 = new LocalNode(
114
+ agentSecret,
115
+ Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
116
+ Crypto,
117
+ );
118
+
119
+ const node1Sync = trackMessages(node1);
120
+
121
+ const peer = await IDBStorage.asPeer();
122
+
123
+ node1.syncManager.addPeer(peer);
124
+
125
+ const group = node1.createGroup();
126
+ const parentGroup = node1.createGroup();
127
+
128
+ group.extend(parentGroup);
129
+
130
+ const map = group.createMap();
131
+
132
+ map.set("hello", "world");
133
+
134
+ await new Promise((resolve) => setTimeout(resolve, 200));
135
+
136
+ expect(
137
+ toSimplifiedMessages(
138
+ {
139
+ Map: map.core,
140
+ Group: group.core,
141
+ ParentGroup: parentGroup.core,
142
+ },
143
+ node1Sync.messages,
144
+ ),
145
+ ).toMatchInlineSnapshot(`
146
+ [
147
+ "client -> CONTENT ParentGroup header: true new: After: 0 New: 4",
148
+ "storage -> KNOWN ParentGroup sessions: header/4",
149
+ "client -> CONTENT Group header: true new: After: 0 New: 5",
150
+ "storage -> KNOWN Group sessions: header/5",
151
+ "client -> CONTENT Map header: true new: After: 0 New: 1",
152
+ "storage -> KNOWN Map sessions: header/1",
153
+ ]
154
+ `);
155
+
156
+ node1Sync.restore();
157
+
158
+ const node2 = new LocalNode(
159
+ agentSecret,
160
+ Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
161
+ Crypto,
162
+ );
163
+
164
+ const node2Sync = trackMessages(node2);
165
+
166
+ const peer2 = await IDBStorage.asPeer();
167
+
168
+ node2.syncManager.addPeer(peer2);
169
+
170
+ await node2.load(map.id);
171
+
172
+ expect(node2.expectCoValueLoaded(map.id)).toBeTruthy();
173
+ expect(node2.expectCoValueLoaded(group.id)).toBeTruthy();
174
+ expect(node2.expectCoValueLoaded(parentGroup.id)).toBeTruthy();
175
+
176
+ expect(
177
+ toSimplifiedMessages(
178
+ {
179
+ Map: map.core,
180
+ Group: group.core,
181
+ ParentGroup: parentGroup.core,
182
+ },
183
+ node2Sync.messages,
184
+ ),
185
+ ).toMatchInlineSnapshot(`
186
+ [
187
+ "client -> LOAD Map sessions: empty",
188
+ "storage -> KNOWN ParentGroup sessions: header/4",
189
+ "storage -> CONTENT ParentGroup header: true new: After: 0 New: 4",
190
+ "storage -> KNOWN Group sessions: header/5",
191
+ "storage -> CONTENT Group header: true new: After: 0 New: 5",
192
+ "client -> KNOWN ParentGroup sessions: header/4",
193
+ "storage -> KNOWN Map sessions: header/1",
194
+ "storage -> CONTENT Map header: true new: After: 0 New: 1",
195
+ "client -> KNOWN Group sessions: header/5",
196
+ ]
197
+ `);
198
+ });
199
+
200
+ test("should not send the same dependency value twice", async () => {
201
+ const agentSecret = Crypto.newRandomAgentSecret();
202
+
203
+ const node1 = new LocalNode(
204
+ agentSecret,
205
+ Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
206
+ Crypto,
207
+ );
208
+
209
+ const node1Sync = trackMessages(node1);
210
+
211
+ const peer = await IDBStorage.asPeer();
212
+
213
+ node1.syncManager.addPeer(peer);
214
+
215
+ const group = node1.createGroup();
216
+ const parentGroup = node1.createGroup();
217
+
218
+ group.extend(parentGroup);
219
+
220
+ const mapFromParent = parentGroup.createMap();
221
+ const map = group.createMap();
222
+
223
+ map.set("hello", "world");
224
+ mapFromParent.set("hello", "world");
225
+
226
+ await new Promise((resolve) => setTimeout(resolve, 200));
227
+
228
+ node1Sync.restore();
229
+
230
+ const node2 = new LocalNode(
231
+ agentSecret,
232
+ Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
233
+ Crypto,
234
+ );
235
+
236
+ const node2Sync = trackMessages(node2);
237
+
238
+ const peer2 = await IDBStorage.asPeer();
239
+
240
+ node2.syncManager.addPeer(peer2);
241
+
242
+ await node2.load(map.id);
243
+ await node2.load(mapFromParent.id);
244
+
245
+ expect(node2.expectCoValueLoaded(map.id)).toBeTruthy();
246
+ expect(node2.expectCoValueLoaded(mapFromParent.id)).toBeTruthy();
247
+ expect(node2.expectCoValueLoaded(group.id)).toBeTruthy();
248
+ expect(node2.expectCoValueLoaded(parentGroup.id)).toBeTruthy();
249
+
250
+ expect(
251
+ toSimplifiedMessages(
252
+ {
253
+ Map: map.core,
254
+ Group: group.core,
255
+ ParentGroup: parentGroup.core,
256
+ MapFromParent: mapFromParent.core,
257
+ },
258
+ node2Sync.messages,
259
+ ),
260
+ ).toMatchInlineSnapshot(`
261
+ [
262
+ "client -> LOAD Map sessions: empty",
263
+ "storage -> KNOWN ParentGroup sessions: header/4",
264
+ "storage -> CONTENT ParentGroup header: true new: After: 0 New: 4",
265
+ "storage -> KNOWN Group sessions: header/5",
266
+ "storage -> CONTENT Group header: true new: After: 0 New: 5",
267
+ "client -> KNOWN ParentGroup sessions: header/4",
268
+ "storage -> KNOWN Map sessions: header/1",
269
+ "storage -> CONTENT Map header: true new: After: 0 New: 1",
270
+ "client -> KNOWN Group sessions: header/5",
271
+ "client -> KNOWN Map sessions: header/1",
272
+ "client -> LOAD MapFromParent sessions: empty",
273
+ "storage -> KNOWN MapFromParent sessions: header/1",
274
+ "storage -> CONTENT MapFromParent header: true new: After: 0 New: 1",
275
+ "client -> KNOWN MapFromParent sessions: header/1",
276
+ ]
277
+ `);
278
+ });
279
+
280
+ test("should recover from data loss", async () => {
281
+ const agentSecret = Crypto.newRandomAgentSecret();
282
+
283
+ const node1 = new LocalNode(
284
+ agentSecret,
285
+ Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
286
+ Crypto,
287
+ );
288
+
289
+ const node1Sync = trackMessages(node1);
290
+
291
+ const peer = await IDBStorage.asPeer();
292
+
293
+ node1.syncManager.addPeer(peer);
294
+
295
+ const group = node1.createGroup();
296
+
297
+ const map = group.createMap();
298
+
299
+ map.set("0", 0);
300
+
301
+ await new Promise((resolve) => setTimeout(resolve, 200));
302
+
303
+ const mock = vi
304
+ .spyOn(StorageManagerAsync.prototype, "handleSyncMessage")
305
+ .mockImplementation(() => Promise.resolve());
306
+
307
+ map.set("1", 1);
308
+ map.set("2", 2);
309
+
310
+ await new Promise((resolve) => setTimeout(resolve, 200));
311
+
312
+ mock.mockReset();
313
+
314
+ map.set("3", 3);
315
+
316
+ await new Promise((resolve) => setTimeout(resolve, 200));
317
+
318
+ expect(
319
+ toSimplifiedMessages(
320
+ {
321
+ Map: map.core,
322
+ Group: group.core,
323
+ },
324
+ node1Sync.messages,
325
+ ),
326
+ ).toMatchInlineSnapshot(`
327
+ [
328
+ "client -> CONTENT Group header: true new: After: 0 New: 3",
329
+ "storage -> KNOWN Group sessions: header/3",
330
+ "client -> CONTENT Map header: true new: After: 0 New: 1",
331
+ "storage -> KNOWN Map sessions: header/1",
332
+ "client -> CONTENT Map header: false new: After: 3 New: 1",
333
+ "storage -> KNOWN CORRECTION Map sessions: header/1",
334
+ "client -> CONTENT Map header: false new: After: 1 New: 3",
335
+ "storage -> KNOWN Map sessions: header/4",
336
+ ]
337
+ `);
338
+
339
+ node1Sync.restore();
340
+
341
+ const node2 = new LocalNode(
342
+ agentSecret,
343
+ Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
344
+ Crypto,
345
+ );
346
+
347
+ const node2Sync = trackMessages(node2);
348
+
349
+ const peer2 = await IDBStorage.asPeer();
350
+
351
+ node2.syncManager.addPeer(peer2);
352
+
353
+ const map2 = await node2.load(map.id);
354
+
355
+ if (map2 === "unavailable") {
356
+ throw new Error("Map is unavailable");
357
+ }
358
+
359
+ expect(map2.toJSON()).toEqual({
360
+ "0": 0,
361
+ "1": 1,
362
+ "2": 2,
363
+ "3": 3,
364
+ });
365
+
366
+ expect(
367
+ toSimplifiedMessages(
368
+ {
369
+ Map: map.core,
370
+ Group: group.core,
371
+ },
372
+ node2Sync.messages,
373
+ ),
374
+ ).toMatchInlineSnapshot(`
375
+ [
376
+ "client -> LOAD Map sessions: empty",
377
+ "storage -> KNOWN Group sessions: header/3",
378
+ "storage -> CONTENT Group header: true new: After: 0 New: 3",
379
+ "storage -> KNOWN Map sessions: header/4",
380
+ "storage -> CONTENT Map header: true new: After: 0 New: 4",
381
+ "client -> KNOWN Group sessions: header/3",
382
+ ]
383
+ `);
384
+ });
@@ -0,0 +1,72 @@
1
+ import type { CoValueCore, CojsonInternalTypes, SyncMessage } from "cojson";
2
+
3
+ function simplifySessions(msg: CojsonInternalTypes.CoValueKnownState) {
4
+ const count = Object.values(msg.sessions).reduce(
5
+ (acc: number, session: number) => acc + session,
6
+ 0,
7
+ );
8
+
9
+ if (msg.header) {
10
+ return `header/${count}`;
11
+ }
12
+
13
+ return "empty";
14
+ }
15
+
16
+ function simplifyNewContent(
17
+ content: CojsonInternalTypes.NewContentMessage["new"],
18
+ ) {
19
+ if (!content) {
20
+ return undefined;
21
+ }
22
+
23
+ return Object.values(content)
24
+ .map((c) => `After: ${c.after} New: ${c.newTransactions.length}`)
25
+ .join(" | ");
26
+ }
27
+
28
+ export function toSimplifiedMessages(
29
+ coValues: Record<string, CoValueCore>,
30
+ messages: {
31
+ from: "client" | "server" | "storage";
32
+ msg: SyncMessage;
33
+ }[],
34
+ ) {
35
+ function getCoValue(id: string) {
36
+ for (const [name, coValue] of Object.entries(coValues)) {
37
+ if (coValue.id === id) {
38
+ return name;
39
+ }
40
+ }
41
+
42
+ return `unknown/${id}`;
43
+ }
44
+
45
+ function toDebugString(
46
+ from: "client" | "server" | "storage",
47
+ msg: SyncMessage,
48
+ ) {
49
+ switch (msg.action) {
50
+ case "known":
51
+ return `${from} -> KNOWN ${msg.isCorrection ? "CORRECTION " : ""}${getCoValue(msg.id)} sessions: ${simplifySessions(msg)}`;
52
+ case "load":
53
+ return `${from} -> LOAD ${getCoValue(msg.id)} sessions: ${simplifySessions(msg)}`;
54
+ case "done":
55
+ return `${from} -> DONE ${getCoValue(msg.id)}`;
56
+ case "content":
57
+ return `${from} -> CONTENT ${getCoValue(msg.id)} header: ${Boolean(msg.header)} new: ${simplifyNewContent(msg.new)}`;
58
+ }
59
+ }
60
+
61
+ return messages.map((m) => toDebugString(m.from, m.msg));
62
+ }
63
+
64
+ export function debugMessages(
65
+ coValues: Record<string, CoValueCore>,
66
+ messages: {
67
+ from: "client" | "server" | "storage";
68
+ msg: SyncMessage;
69
+ }[],
70
+ ) {
71
+ console.log(toSimplifiedMessages(coValues, messages));
72
+ }
@@ -0,0 +1,44 @@
1
+ import type { LocalNode, SyncMessage } from "cojson";
2
+ import { StorageManagerAsync } from "cojson-storage";
3
+ import { onTestFinished } from "vitest";
4
+
5
+ export function trackMessages(node: LocalNode) {
6
+ const messages: {
7
+ from: "client" | "server" | "storage";
8
+ msg: SyncMessage;
9
+ }[] = [];
10
+
11
+ const originalHandleSyncMessage =
12
+ StorageManagerAsync.prototype.handleSyncMessage;
13
+ const originalNodeSyncMessage = node.syncManager.handleSyncMessage;
14
+
15
+ StorageManagerAsync.prototype.handleSyncMessage = async function (msg) {
16
+ messages.push({
17
+ from: "client",
18
+ msg,
19
+ });
20
+ return originalHandleSyncMessage.call(this, msg);
21
+ };
22
+
23
+ node.syncManager.handleSyncMessage = async function (msg, peer) {
24
+ messages.push({
25
+ from: "storage",
26
+ msg,
27
+ });
28
+ return originalNodeSyncMessage.call(this, msg, peer);
29
+ };
30
+
31
+ const restore = () => {
32
+ StorageManagerAsync.prototype.handleSyncMessage = originalHandleSyncMessage;
33
+ node.syncManager.handleSyncMessage = originalNodeSyncMessage;
34
+ };
35
+
36
+ onTestFinished(() => {
37
+ restore();
38
+ });
39
+
40
+ return {
41
+ messages,
42
+ restore,
43
+ };
44
+ }