cojson 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.
Files changed (218) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +12 -0
  3. package/dist/IncomingMessagesQueue.d.ts +27 -0
  4. package/dist/IncomingMessagesQueue.d.ts.map +1 -0
  5. package/dist/IncomingMessagesQueue.js +114 -0
  6. package/dist/IncomingMessagesQueue.js.map +1 -0
  7. package/dist/PeerState.d.ts +2 -10
  8. package/dist/PeerState.d.ts.map +1 -1
  9. package/dist/PeerState.js +9 -90
  10. package/dist/PeerState.js.map +1 -1
  11. package/dist/PriorityBasedMessageQueue.d.ts +2 -1
  12. package/dist/PriorityBasedMessageQueue.d.ts.map +1 -1
  13. package/dist/PriorityBasedMessageQueue.js +9 -6
  14. package/dist/PriorityBasedMessageQueue.js.map +1 -1
  15. package/dist/SyncStateManager.d.ts +1 -0
  16. package/dist/SyncStateManager.d.ts.map +1 -1
  17. package/dist/SyncStateManager.js +1 -1
  18. package/dist/SyncStateManager.js.map +1 -1
  19. package/dist/coValue.d.ts +1 -1
  20. package/dist/coValueCore/coValueCore.d.ts +9 -17
  21. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  22. package/dist/coValueCore/coValueCore.js +75 -50
  23. package/dist/coValueCore/coValueCore.js.map +1 -1
  24. package/dist/coValueCore/verifiedState.d.ts +10 -3
  25. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  26. package/dist/coValueCore/verifiedState.js +73 -14
  27. package/dist/coValueCore/verifiedState.js.map +1 -1
  28. package/dist/coValues/coMap.d.ts +3 -3
  29. package/dist/coValues/coStream.d.ts +2 -2
  30. package/dist/coValues/group.d.ts +1 -1
  31. package/dist/coValues/group.d.ts.map +1 -1
  32. package/dist/coValues/group.js +2 -4
  33. package/dist/coValues/group.js.map +1 -1
  34. package/dist/config.d.ts +19 -0
  35. package/dist/config.d.ts.map +1 -0
  36. package/dist/config.js +23 -0
  37. package/dist/config.js.map +1 -0
  38. package/dist/crypto/WasmCrypto.d.ts.map +1 -1
  39. package/dist/crypto/WasmCrypto.js +2 -1
  40. package/dist/crypto/WasmCrypto.js.map +1 -1
  41. package/dist/exports.d.ts +18 -7
  42. package/dist/exports.d.ts.map +1 -1
  43. package/dist/exports.js +11 -8
  44. package/dist/exports.js.map +1 -1
  45. package/dist/localNode.d.ts +8 -2
  46. package/dist/localNode.d.ts.map +1 -1
  47. package/dist/localNode.js +19 -12
  48. package/dist/localNode.js.map +1 -1
  49. package/dist/storage/StoreQueue.d.ts +15 -0
  50. package/dist/storage/StoreQueue.d.ts.map +1 -0
  51. package/dist/storage/StoreQueue.js +35 -0
  52. package/dist/storage/StoreQueue.js.map +1 -0
  53. package/dist/storage/index.d.ts +6 -0
  54. package/dist/storage/index.d.ts.map +1 -0
  55. package/dist/storage/index.js +6 -0
  56. package/dist/storage/index.js.map +1 -0
  57. package/dist/storage/knownState.d.ts +18 -0
  58. package/dist/storage/knownState.d.ts.map +1 -0
  59. package/dist/storage/knownState.js +63 -0
  60. package/dist/storage/knownState.js.map +1 -0
  61. package/dist/storage/sqlite/client.d.ts +37 -0
  62. package/dist/storage/sqlite/client.d.ts.map +1 -0
  63. package/dist/storage/sqlite/client.js +89 -0
  64. package/dist/storage/sqlite/client.js.map +1 -0
  65. package/dist/storage/sqlite/index.d.ts +5 -0
  66. package/dist/storage/sqlite/index.d.ts.map +1 -0
  67. package/dist/storage/sqlite/index.js +13 -0
  68. package/dist/storage/sqlite/index.js.map +1 -0
  69. package/dist/storage/sqlite/sqliteMigrations.d.ts +3 -0
  70. package/dist/storage/sqlite/sqliteMigrations.d.ts.map +1 -0
  71. package/dist/storage/sqlite/sqliteMigrations.js +44 -0
  72. package/dist/storage/sqlite/sqliteMigrations.js.map +1 -0
  73. package/dist/storage/sqlite/types.d.ts +8 -0
  74. package/dist/storage/sqlite/types.d.ts.map +1 -0
  75. package/dist/storage/sqlite/types.js +2 -0
  76. package/dist/storage/sqlite/types.js.map +1 -0
  77. package/dist/storage/sqliteAsync/client.d.ts +37 -0
  78. package/dist/storage/sqliteAsync/client.d.ts.map +1 -0
  79. package/dist/storage/sqliteAsync/client.js +88 -0
  80. package/dist/storage/sqliteAsync/client.js.map +1 -0
  81. package/dist/storage/sqliteAsync/index.d.ts +6 -0
  82. package/dist/storage/sqliteAsync/index.d.ts.map +1 -0
  83. package/dist/storage/sqliteAsync/index.js +15 -0
  84. package/dist/storage/sqliteAsync/index.js.map +1 -0
  85. package/dist/storage/sqliteAsync/types.d.ts +9 -0
  86. package/dist/storage/sqliteAsync/types.d.ts.map +1 -0
  87. package/dist/storage/sqliteAsync/types.js +2 -0
  88. package/dist/storage/sqliteAsync/types.js.map +1 -0
  89. package/dist/storage/storageAsync.d.ts +22 -0
  90. package/dist/storage/storageAsync.d.ts.map +1 -0
  91. package/dist/storage/storageAsync.js +214 -0
  92. package/dist/storage/storageAsync.js.map +1 -0
  93. package/dist/storage/storageSync.d.ts +21 -0
  94. package/dist/storage/storageSync.d.ts.map +1 -0
  95. package/dist/storage/storageSync.js +206 -0
  96. package/dist/storage/storageSync.js.map +1 -0
  97. package/dist/storage/syncUtils.d.ts +13 -0
  98. package/dist/storage/syncUtils.d.ts.map +1 -0
  99. package/dist/storage/syncUtils.js +25 -0
  100. package/dist/storage/syncUtils.js.map +1 -0
  101. package/dist/storage/types.d.ts +82 -0
  102. package/dist/storage/types.d.ts.map +1 -0
  103. package/dist/storage/types.js +2 -0
  104. package/dist/storage/types.js.map +1 -0
  105. package/dist/streamUtils.d.ts +13 -9
  106. package/dist/streamUtils.d.ts.map +1 -1
  107. package/dist/streamUtils.js +46 -13
  108. package/dist/streamUtils.js.map +1 -1
  109. package/dist/sync.d.ts +22 -14
  110. package/dist/sync.d.ts.map +1 -1
  111. package/dist/sync.js +143 -125
  112. package/dist/sync.js.map +1 -1
  113. package/dist/tests/IncomingMessagesQueue.test.d.ts +2 -0
  114. package/dist/tests/IncomingMessagesQueue.test.d.ts.map +1 -0
  115. package/dist/tests/IncomingMessagesQueue.test.js +437 -0
  116. package/dist/tests/IncomingMessagesQueue.test.js.map +1 -0
  117. package/dist/tests/PeerState.test.js +6 -94
  118. package/dist/tests/PeerState.test.js.map +1 -1
  119. package/dist/tests/PriorityBasedMessageQueue.test.js +14 -14
  120. package/dist/tests/PriorityBasedMessageQueue.test.js.map +1 -1
  121. package/dist/tests/StoreQueue.test.d.ts +2 -0
  122. package/dist/tests/StoreQueue.test.d.ts.map +1 -0
  123. package/dist/tests/StoreQueue.test.js +208 -0
  124. package/dist/tests/StoreQueue.test.js.map +1 -0
  125. package/dist/tests/SyncStateManager.test.js +3 -1
  126. package/dist/tests/SyncStateManager.test.js.map +1 -1
  127. package/dist/tests/account.test.js +9 -9
  128. package/dist/tests/account.test.js.map +1 -1
  129. package/dist/tests/coStream.test.js +1 -1
  130. package/dist/tests/coStream.test.js.map +1 -1
  131. package/dist/tests/coValueCore.test.js +208 -1
  132. package/dist/tests/coValueCore.test.js.map +1 -1
  133. package/dist/tests/coValueCoreLoadingState.test.js +2 -2
  134. package/dist/tests/coValueCoreLoadingState.test.js.map +1 -1
  135. package/dist/tests/group.addMember.test.js.map +1 -1
  136. package/dist/tests/group.removeMember.test.js +1 -1
  137. package/dist/tests/group.removeMember.test.js.map +1 -1
  138. package/dist/tests/messagesTestUtils.js +1 -1
  139. package/dist/tests/messagesTestUtils.js.map +1 -1
  140. package/dist/tests/sync.auth.test.js +23 -15
  141. package/dist/tests/sync.auth.test.js.map +1 -1
  142. package/dist/tests/sync.invite.test.js +10 -16
  143. package/dist/tests/sync.invite.test.js.map +1 -1
  144. package/dist/tests/sync.load.test.js +52 -50
  145. package/dist/tests/sync.load.test.js.map +1 -1
  146. package/dist/tests/sync.mesh.test.js +173 -56
  147. package/dist/tests/sync.mesh.test.js.map +1 -1
  148. package/dist/tests/sync.peerReconciliation.test.js +42 -32
  149. package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
  150. package/dist/tests/sync.storage.test.js +162 -62
  151. package/dist/tests/sync.storage.test.js.map +1 -1
  152. package/dist/tests/sync.storageAsync.test.d.ts +2 -0
  153. package/dist/tests/sync.storageAsync.test.d.ts.map +1 -0
  154. package/dist/tests/sync.storageAsync.test.js +361 -0
  155. package/dist/tests/sync.storageAsync.test.js.map +1 -0
  156. package/dist/tests/sync.test.js +16 -21
  157. package/dist/tests/sync.test.js.map +1 -1
  158. package/dist/tests/sync.upload.test.js +28 -25
  159. package/dist/tests/sync.upload.test.js.map +1 -1
  160. package/dist/tests/testStorage.d.ts +12 -0
  161. package/dist/tests/testStorage.d.ts.map +1 -0
  162. package/dist/tests/testStorage.js +151 -0
  163. package/dist/tests/testStorage.js.map +1 -0
  164. package/dist/tests/testUtils.d.ts +20 -15
  165. package/dist/tests/testUtils.d.ts.map +1 -1
  166. package/dist/tests/testUtils.js +79 -45
  167. package/dist/tests/testUtils.js.map +1 -1
  168. package/package.json +2 -2
  169. package/src/IncomingMessagesQueue.ts +142 -0
  170. package/src/PeerState.ts +11 -110
  171. package/src/PriorityBasedMessageQueue.ts +13 -5
  172. package/src/SyncStateManager.ts +1 -1
  173. package/src/coValueCore/coValueCore.ts +100 -66
  174. package/src/coValueCore/verifiedState.ts +91 -21
  175. package/src/coValues/group.ts +2 -4
  176. package/src/config.ts +26 -0
  177. package/src/crypto/WasmCrypto.ts +3 -1
  178. package/src/exports.ts +20 -27
  179. package/src/localNode.ts +27 -12
  180. package/src/storage/StoreQueue.ts +56 -0
  181. package/src/storage/index.ts +5 -0
  182. package/src/storage/knownState.ts +88 -0
  183. package/src/storage/sqlite/client.ts +180 -0
  184. package/src/storage/sqlite/index.ts +19 -0
  185. package/src/storage/sqlite/sqliteMigrations.ts +44 -0
  186. package/src/storage/sqlite/types.ts +7 -0
  187. package/src/storage/sqliteAsync/client.ts +179 -0
  188. package/src/storage/sqliteAsync/index.ts +25 -0
  189. package/src/storage/sqliteAsync/types.ts +8 -0
  190. package/src/storage/storageAsync.ts +367 -0
  191. package/src/storage/storageSync.ts +343 -0
  192. package/src/storage/syncUtils.ts +50 -0
  193. package/src/storage/types.ts +162 -0
  194. package/src/streamUtils.ts +61 -19
  195. package/src/sync.ts +191 -160
  196. package/src/tests/IncomingMessagesQueue.test.ts +626 -0
  197. package/src/tests/PeerState.test.ts +6 -118
  198. package/src/tests/PriorityBasedMessageQueue.test.ts +18 -14
  199. package/src/tests/StoreQueue.test.ts +283 -0
  200. package/src/tests/SyncStateManager.test.ts +4 -1
  201. package/src/tests/account.test.ts +11 -12
  202. package/src/tests/coStream.test.ts +1 -3
  203. package/src/tests/coValueCore.test.ts +270 -1
  204. package/src/tests/coValueCoreLoadingState.test.ts +2 -2
  205. package/src/tests/group.addMember.test.ts +1 -0
  206. package/src/tests/group.removeMember.test.ts +2 -8
  207. package/src/tests/messagesTestUtils.ts +2 -2
  208. package/src/tests/sync.auth.test.ts +24 -14
  209. package/src/tests/sync.invite.test.ts +11 -17
  210. package/src/tests/sync.load.test.ts +53 -49
  211. package/src/tests/sync.mesh.test.ts +198 -56
  212. package/src/tests/sync.peerReconciliation.test.ts +44 -34
  213. package/src/tests/sync.storage.test.ts +231 -64
  214. package/src/tests/sync.storageAsync.test.ts +486 -0
  215. package/src/tests/sync.test.ts +17 -23
  216. package/src/tests/sync.upload.test.ts +29 -24
  217. package/src/tests/testStorage.ts +216 -0
  218. package/src/tests/testUtils.ts +89 -54
@@ -4,13 +4,17 @@ import { expectList, expectMap } from "../coValue";
4
4
  import { WasmCrypto } from "../crypto/WasmCrypto";
5
5
  import {
6
6
  SyncMessagesLog,
7
+ TEST_NODE_CONFIG,
7
8
  loadCoValueOrFail,
8
9
  setupTestNode,
9
10
  waitFor,
10
11
  } from "./testUtils";
11
12
 
13
+ // We want to simulate a real world communication that happens asynchronously
14
+ TEST_NODE_CONFIG.withAsyncPeers = true;
15
+
12
16
  const Crypto = await WasmCrypto.create();
13
- let jazzCloud = setupTestNode({ isSyncServer: true });
17
+ let jazzCloud: ReturnType<typeof setupTestNode>;
14
18
 
15
19
  beforeEach(async () => {
16
20
  SyncMessagesLog.clear();
@@ -40,8 +44,8 @@ describe("client to server upload", () => {
40
44
  ).toMatchInlineSnapshot(`
41
45
  [
42
46
  "client -> server | CONTENT Group header: true new: After: 0 New: 3",
43
- "server -> client | KNOWN Group sessions: header/3",
44
47
  "client -> server | CONTENT Map header: true new: After: 0 New: 1",
48
+ "server -> client | KNOWN Group sessions: header/3",
45
49
  "server -> client | KNOWN Map sessions: header/1",
46
50
  ]
47
51
  `);
@@ -75,10 +79,10 @@ describe("client to server upload", () => {
75
79
  ).toMatchInlineSnapshot(`
76
80
  [
77
81
  "client -> server | CONTENT ParentGroup header: true new: After: 0 New: 6",
78
- "server -> client | KNOWN ParentGroup sessions: header/6",
79
82
  "client -> server | CONTENT Group header: true new: After: 0 New: 5",
80
- "server -> client | KNOWN Group sessions: header/5",
81
83
  "client -> server | CONTENT Map header: true new: After: 0 New: 1",
84
+ "server -> client | KNOWN ParentGroup sessions: header/6",
85
+ "server -> client | KNOWN Group sessions: header/5",
82
86
  "server -> client | KNOWN Map sessions: header/1",
83
87
  ]
84
88
  `);
@@ -113,8 +117,8 @@ describe("client to server upload", () => {
113
117
  ).toMatchInlineSnapshot(`
114
118
  [
115
119
  "client -> server | CONTENT Group header: true new: After: 0 New: 3",
116
- "server -> client | KNOWN Group sessions: header/3",
117
120
  "client -> server | CONTENT Map header: true new: After: 0 New: 1",
121
+ "server -> client | KNOWN Group sessions: header/3",
118
122
  "server -> client | KNOWN Map sessions: header/1",
119
123
  "client -> server | CONTENT Map header: false new: After: 1 New: 1",
120
124
  "server -> client | KNOWN Map sessions: header/2",
@@ -158,8 +162,8 @@ describe("client to server upload", () => {
158
162
  ).toMatchInlineSnapshot(`
159
163
  [
160
164
  "client -> server | CONTENT Group header: true new: After: 0 New: 5",
161
- "server -> client | KNOWN Group sessions: header/5",
162
165
  "client -> server | CONTENT Map header: true new: After: 0 New: 1",
166
+ "server -> client | KNOWN Group sessions: header/5",
163
167
  "server -> client | KNOWN Map sessions: header/1",
164
168
  "client -> server | CONTENT Map header: false new: After: 1 New: 1",
165
169
  "server -> client | KNOWN CORRECTION Map sessions: empty",
@@ -233,16 +237,17 @@ describe("client to server upload", () => {
233
237
  "otherClient -> server | KNOWN Colist sessions: header/1",
234
238
  "client -> server | CONTENT Colist header: false new: After: 1 New: 1",
235
239
  "server -> client | KNOWN Colist sessions: header/2",
240
+ "server -> otherClient | CONTENT Colist header: false new: After: 1 New: 1",
236
241
  "otherClient -> server | LOAD Colist sessions: header/3",
237
242
  "client -> server | CONTENT Colist header: false new: After: 2 New: 1",
238
243
  "server -> otherClient | CONTENT Colist header: false new: After: 1 New: 1",
239
244
  "server -> client | KNOWN Colist sessions: header/3",
240
- "otherClient -> server | KNOWN Colist sessions: header/4",
241
245
  "server -> otherClient | CONTENT Colist header: false new: After: 2 New: 1",
246
+ "otherClient -> server | KNOWN Colist sessions: header/4",
242
247
  "otherClient -> server | CONTENT Colist header: false new: After: 0 New: 2",
248
+ "otherClient -> server | KNOWN Colist sessions: header/5",
243
249
  "server -> otherClient | KNOWN Colist sessions: header/5",
244
250
  "server -> client | CONTENT Colist header: false new: After: 0 New: 2",
245
- "otherClient -> server | KNOWN Colist sessions: header/5",
246
251
  "client -> server | KNOWN Colist sessions: header/5",
247
252
  ]
248
253
  `);
@@ -283,38 +288,38 @@ describe("client to server upload", () => {
283
288
  [
284
289
  "client -> server | LOAD Map sessions: empty",
285
290
  "server -> client | CONTENT Group header: true new: After: 0 New: 5",
291
+ "server -> client | CONTENT Map header: true new: expectContentUntil: header/1024",
292
+ "server -> client | CONTENT Map header: false new: After: 0 New: 73",
293
+ "server -> client | CONTENT Map header: false new: After: 73 New: 73",
294
+ "server -> client | CONTENT Map header: false new: After: 146 New: 73",
295
+ "server -> client | CONTENT Map header: false new: After: 219 New: 73",
296
+ "server -> client | CONTENT Map header: false new: After: 292 New: 73",
297
+ "server -> client | CONTENT Map header: false new: After: 365 New: 73",
298
+ "server -> client | CONTENT Map header: false new: After: 438 New: 73",
299
+ "server -> client | CONTENT Map header: false new: After: 511 New: 73",
300
+ "server -> client | CONTENT Map header: false new: After: 584 New: 73",
301
+ "server -> client | CONTENT Map header: false new: After: 657 New: 73",
302
+ "server -> client | CONTENT Map header: false new: After: 730 New: 73",
303
+ "server -> client | CONTENT Map header: false new: After: 803 New: 73",
304
+ "server -> client | CONTENT Map header: false new: After: 876 New: 73",
305
+ "server -> client | CONTENT Map header: false new: After: 949 New: 73",
306
+ "server -> client | CONTENT Map header: false new: After: 1022 New: 2",
286
307
  "client -> server | KNOWN Group sessions: header/5",
287
- "server -> client | CONTENT Map header: true new: ",
288
308
  "client -> server | KNOWN Map sessions: header/0",
289
- "server -> client | CONTENT Map header: false new: After: 0 New: 73",
290
309
  "client -> server | KNOWN Map sessions: header/73",
291
- "server -> client | CONTENT Map header: false new: After: 73 New: 73",
292
310
  "client -> server | KNOWN Map sessions: header/146",
293
- "server -> client | CONTENT Map header: false new: After: 146 New: 73",
294
311
  "client -> server | KNOWN Map sessions: header/219",
295
- "server -> client | CONTENT Map header: false new: After: 219 New: 73",
296
312
  "client -> server | KNOWN Map sessions: header/292",
297
- "server -> client | CONTENT Map header: false new: After: 292 New: 73",
298
313
  "client -> server | KNOWN Map sessions: header/365",
299
- "server -> client | CONTENT Map header: false new: After: 365 New: 73",
300
314
  "client -> server | KNOWN Map sessions: header/438",
301
- "server -> client | CONTENT Map header: false new: After: 438 New: 73",
302
315
  "client -> server | KNOWN Map sessions: header/511",
303
- "server -> client | CONTENT Map header: false new: After: 511 New: 73",
304
316
  "client -> server | KNOWN Map sessions: header/584",
305
- "server -> client | CONTENT Map header: false new: After: 584 New: 73",
306
317
  "client -> server | KNOWN Map sessions: header/657",
307
- "server -> client | CONTENT Map header: false new: After: 657 New: 73",
308
318
  "client -> server | KNOWN Map sessions: header/730",
309
- "server -> client | CONTENT Map header: false new: After: 730 New: 73",
310
319
  "client -> server | KNOWN Map sessions: header/803",
311
- "server -> client | CONTENT Map header: false new: After: 803 New: 73",
312
320
  "client -> server | KNOWN Map sessions: header/876",
313
- "server -> client | CONTENT Map header: false new: After: 876 New: 73",
314
321
  "client -> server | KNOWN Map sessions: header/949",
315
- "server -> client | CONTENT Map header: false new: After: 949 New: 73",
316
322
  "client -> server | KNOWN Map sessions: header/1022",
317
- "server -> client | CONTENT Map header: false new: After: 1022 New: 2",
318
323
  "client -> server | KNOWN Map sessions: header/1024",
319
324
  ]
320
325
  `);
@@ -0,0 +1,216 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { unlinkSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import Database, { type Database as DatabaseT } from "libsql";
6
+ import { onTestFinished } from "vitest";
7
+ import { RawCoID, StorageAPI } from "../exports";
8
+ import {
9
+ SQLiteDatabaseDriver,
10
+ StorageApiAsync,
11
+ StorageApiSync,
12
+ } from "../storage";
13
+ import { getSqliteStorage } from "../storage/sqlite";
14
+ import {
15
+ SQLiteDatabaseDriverAsync,
16
+ getSqliteStorageAsync,
17
+ } from "../storage/sqliteAsync";
18
+ import { SyncMessagesLog, SyncTestMessage } from "./testUtils";
19
+
20
+ class LibSQLSqliteAsyncDriver implements SQLiteDatabaseDriverAsync {
21
+ private readonly db: DatabaseT;
22
+
23
+ constructor(filename: string) {
24
+ this.db = new Database(filename, {});
25
+ }
26
+
27
+ async initialize() {
28
+ await this.db.pragma("journal_mode = WAL");
29
+ }
30
+
31
+ async run(sql: string, params: unknown[]) {
32
+ this.db.prepare(sql).run(params);
33
+ }
34
+
35
+ async query<T>(sql: string, params: unknown[]): Promise<T[]> {
36
+ return this.db.prepare(sql).all(params) as T[];
37
+ }
38
+
39
+ async get<T>(sql: string, params: unknown[]): Promise<T | undefined> {
40
+ return this.db.prepare(sql).get(params) as T | undefined;
41
+ }
42
+
43
+ async transaction(callback: () => unknown) {
44
+ await this.run("BEGIN TRANSACTION", []);
45
+
46
+ try {
47
+ await callback();
48
+ await this.run("COMMIT", []);
49
+ } catch (error) {
50
+ await this.run("ROLLBACK", []);
51
+ }
52
+ }
53
+
54
+ async closeDb() {
55
+ this.db.close();
56
+ }
57
+ }
58
+
59
+ class LibSQLSqliteSyncDriver implements SQLiteDatabaseDriver {
60
+ private readonly db: DatabaseT;
61
+
62
+ constructor(filename: string) {
63
+ this.db = new Database(filename, {});
64
+ }
65
+
66
+ initialize() {
67
+ this.db.pragma("journal_mode = WAL");
68
+ }
69
+
70
+ run(sql: string, params: unknown[]) {
71
+ this.db.prepare(sql).run(params);
72
+ }
73
+
74
+ query<T>(sql: string, params: unknown[]): T[] {
75
+ return this.db.prepare(sql).all(params) as T[];
76
+ }
77
+
78
+ get<T>(sql: string, params: unknown[]): T | undefined {
79
+ return this.db.prepare(sql).get(params) as T | undefined;
80
+ }
81
+
82
+ transaction(callback: () => unknown) {
83
+ this.run("BEGIN TRANSACTION", []);
84
+
85
+ try {
86
+ callback();
87
+ this.run("COMMIT", []);
88
+ } catch (error) {
89
+ this.run("ROLLBACK", []);
90
+ }
91
+ }
92
+
93
+ closeDb() {
94
+ this.db.close();
95
+ }
96
+ }
97
+
98
+ export async function createAsyncStorage({
99
+ filename,
100
+ nodeName = "client",
101
+ storageName = "storage",
102
+ }: { filename?: string; nodeName: string; storageName: string }) {
103
+ const storage = await getSqliteStorageAsync(
104
+ new LibSQLSqliteAsyncDriver(getDbPath(filename)),
105
+ );
106
+
107
+ onTestFinished(() => {
108
+ storage.close();
109
+ });
110
+
111
+ trackStorageMessages(storage, nodeName, storageName);
112
+
113
+ return storage;
114
+ }
115
+
116
+ export function createSyncStorage({
117
+ filename,
118
+ nodeName = "client",
119
+ storageName = "storage",
120
+ }: { filename?: string; nodeName: string; storageName: string }) {
121
+ const storage = getSqliteStorage(
122
+ new LibSQLSqliteSyncDriver(getDbPath(filename)),
123
+ );
124
+
125
+ trackStorageMessages(storage, nodeName, storageName);
126
+
127
+ return storage;
128
+ }
129
+
130
+ function getDbPath(defaultDbPath?: string) {
131
+ const dbPath = defaultDbPath ?? join(tmpdir(), `test-${randomUUID()}.db`);
132
+
133
+ if (!defaultDbPath) {
134
+ onTestFinished(() => {
135
+ unlinkSync(dbPath);
136
+ });
137
+ }
138
+
139
+ return dbPath;
140
+ }
141
+
142
+ function trackStorageMessages(
143
+ storage: StorageAPI,
144
+ nodeName: string,
145
+ storageName: string,
146
+ ) {
147
+ const originalStore = storage.store;
148
+ const originalLoad = storage.load;
149
+
150
+ storage.store = function (data, correctionCallback) {
151
+ for (const msg of data ?? []) {
152
+ SyncMessagesLog.add({
153
+ from: nodeName,
154
+ to: storageName,
155
+ msg,
156
+ });
157
+ }
158
+
159
+ return originalStore.call(storage, data, (correction) => {
160
+ SyncMessagesLog.add({
161
+ from: storageName,
162
+ to: nodeName,
163
+ msg: {
164
+ action: "known",
165
+ isCorrection: true,
166
+ ...correction,
167
+ },
168
+ });
169
+
170
+ return correctionCallback(correction);
171
+ });
172
+ };
173
+
174
+ storage.load = function (id, callback, done) {
175
+ SyncMessagesLog.add({
176
+ from: nodeName,
177
+ to: storageName,
178
+ msg: {
179
+ action: "load",
180
+ id: id as RawCoID,
181
+ sessions: {},
182
+ header: false,
183
+ },
184
+ });
185
+
186
+ return originalLoad.call(
187
+ storage,
188
+ id,
189
+ (msg) => {
190
+ SyncMessagesLog.add({
191
+ from: storageName,
192
+ to: nodeName,
193
+ msg,
194
+ });
195
+
196
+ return callback(msg);
197
+ },
198
+ (found) => {
199
+ if (!found) {
200
+ SyncMessagesLog.add({
201
+ from: storageName,
202
+ to: nodeName,
203
+ msg: {
204
+ action: "known",
205
+ id: id as RawCoID,
206
+ sessions: {},
207
+ header: false,
208
+ },
209
+ });
210
+ }
211
+
212
+ return done?.(found);
213
+ },
214
+ );
215
+ };
216
+ }
@@ -14,13 +14,15 @@ import {
14
14
  type CoValueCore,
15
15
  type RawAccount,
16
16
  type RawCoValue,
17
+ StorageAPI,
17
18
  } from "../exports.js";
18
- import type { SessionID } from "../ids.js";
19
+ import type { RawCoID, SessionID } from "../ids.js";
19
20
  import { LocalNode } from "../localNode.js";
20
21
  import { connectedPeers } from "../streamUtils.js";
21
22
  import type { Peer, SyncMessage } from "../sync.js";
22
23
  import { expectGroup } from "../typeUtils/expectGroup.js";
23
24
  import { toSimplifiedMessages } from "./messagesTestUtils.js";
25
+ import { createAsyncStorage, createSyncStorage } from "./testStorage.js";
24
26
 
25
27
  const Crypto = await WasmCrypto.create();
26
28
 
@@ -301,6 +303,7 @@ export function blockMessageTypeOnOutgoingPeer(
301
303
 
302
304
  pushSpy.mockImplementation(async (msg) => {
303
305
  if (
306
+ typeof msg === "object" &&
304
307
  msg.action === messageType &&
305
308
  (!opts.id || msg.id === opts.id) &&
306
309
  (!opts.once || !blockedIds.has(msg.id))
@@ -459,31 +462,9 @@ export function getSyncServerConnectedPeer(opts: {
459
462
  };
460
463
  }
461
464
 
462
- export function createMockStoragePeer(opts: {
463
- ourName?: string;
464
- peerId: string;
465
- }) {
466
- const storage = createTestNode();
467
-
468
- const { peer1, peer2 } = connectedPeersWithMessagesTracking({
469
- peer1: { id: storage.getCurrentAgent().id, role: "storage" },
470
- peer2: {
471
- id: opts.peerId,
472
- role: "client",
473
- name: opts.ourName,
474
- },
475
- });
476
-
477
- peer1.role = "storage";
478
- peer1.priority = 100;
479
-
480
- storage.syncManager.addPeer(peer2);
481
-
482
- return {
483
- storage,
484
- peer: peer1,
485
- };
486
- }
465
+ export const TEST_NODE_CONFIG = {
466
+ withAsyncPeers: false,
467
+ };
487
468
 
488
469
  export function setupTestNode(
489
470
  opts: {
@@ -521,25 +502,41 @@ export function setupTestNode(
521
502
  };
522
503
  }
523
504
 
524
- function addStoragePeer(opts: { ourName?: string } = {}) {
525
- const { peer, storage } = createMockStoragePeer({
526
- peerId: node.getCurrentAgent().id,
527
- ourName: opts.ourName,
528
- });
505
+ function addStorage(opts: { ourName?: string; storage?: StorageAPI } = {}) {
506
+ const storage =
507
+ opts.storage ??
508
+ createSyncStorage({
509
+ nodeName: opts.ourName ?? "client",
510
+ storageName: "storage",
511
+ });
512
+ node.setStorage(storage);
529
513
 
530
- node.syncManager.addPeer(peer);
514
+ return { storage };
515
+ }
516
+
517
+ async function addAsyncStorage(opts: { ourName?: string } = {}) {
518
+ const storage = await createAsyncStorage({
519
+ nodeName: opts.ourName ?? "client",
520
+ storageName: "storage",
521
+ });
522
+ node.setStorage(storage);
531
523
 
532
- return { peer, peerState: node.syncManager.peers[peer.id]!, storage };
524
+ return { storage };
533
525
  }
534
526
 
535
527
  if (opts.connected) {
536
528
  connectToSyncServer();
537
529
  }
538
530
 
531
+ onTestFinished(() => {
532
+ node.gracefulShutdown();
533
+ });
534
+
539
535
  const ctx = {
540
536
  node,
541
537
  connectToSyncServer,
542
- addStoragePeer,
538
+ addStorage,
539
+ addAsyncStorage,
543
540
  restart: () => {
544
541
  node.gracefulShutdown();
545
542
  ctx.node = node = new LocalNode(admin.agentSecret, session, Crypto);
@@ -559,12 +556,14 @@ export async function setupTestAccount(
559
556
  opts: {
560
557
  isSyncServer?: boolean;
561
558
  connected?: boolean;
559
+ storage?: StorageAPI;
562
560
  } = {},
563
561
  ) {
564
562
  const ctx = await LocalNode.withNewlyCreatedAccount({
565
563
  peersToLoadFrom: [],
566
564
  crypto: Crypto,
567
565
  creationProps: { name: "Client" },
566
+ storage: opts.storage,
568
567
  });
569
568
 
570
569
  if (opts.isSyncServer) {
@@ -599,26 +598,42 @@ export async function setupTestAccount(
599
598
  };
600
599
  }
601
600
 
602
- function addStoragePeer(opts: { ourName?: string } = {}) {
603
- const { peer, storage } = createMockStoragePeer({
604
- peerId: ctx.node.getCurrentAgent().id,
605
- ourName: opts.ourName,
606
- });
601
+ function addStorage(opts: { ourName?: string; storage?: StorageAPI } = {}) {
602
+ const storage =
603
+ opts.storage ??
604
+ createSyncStorage({
605
+ nodeName: opts.ourName ?? "client",
606
+ storageName: "storage",
607
+ });
608
+ ctx.node.setStorage(storage);
607
609
 
608
- ctx.node.syncManager.addPeer(peer);
610
+ return { storage };
611
+ }
609
612
 
610
- return { peer, peerState: ctx.node.syncManager.peers[peer.id]!, storage };
613
+ async function addAsyncStorage(opts: { ourName?: string } = {}) {
614
+ const storage = await createAsyncStorage({
615
+ nodeName: opts.ourName ?? "client",
616
+ storageName: "storage",
617
+ });
618
+ ctx.node.setStorage(storage);
619
+
620
+ return { storage };
611
621
  }
612
622
 
613
623
  if (opts.connected) {
614
624
  connectToSyncServer();
615
625
  }
616
626
 
627
+ onTestFinished(() => {
628
+ ctx.node.gracefulShutdown();
629
+ });
630
+
617
631
  return {
618
632
  node: ctx.node,
619
633
  accountID: ctx.accountID,
620
634
  connectToSyncServer,
621
- addStoragePeer,
635
+ addStorage,
636
+ addAsyncStorage,
622
637
  };
623
638
  }
624
639
 
@@ -639,22 +654,42 @@ export function connectedPeersWithMessagesTracking(opts: {
639
654
 
640
655
  const peer1Push = peer1.outgoing.push;
641
656
  peer1.outgoing.push = (msg) => {
642
- SyncMessagesLog.add({
643
- from: opts.peer2.name ?? opts.peer2.role,
644
- to: opts.peer1.name ?? opts.peer1.role,
645
- msg,
646
- });
647
- return peer1Push.call(peer1.outgoing, msg);
657
+ if (typeof msg !== "string") {
658
+ SyncMessagesLog.add({
659
+ from: opts.peer2.name ?? opts.peer2.role,
660
+ to: opts.peer1.name ?? opts.peer1.role,
661
+ msg,
662
+ });
663
+ }
664
+
665
+ if (!TEST_NODE_CONFIG.withAsyncPeers) {
666
+ peer1Push.call(peer1.outgoing, msg);
667
+ } else {
668
+ // Simulate the async nature of the real push
669
+ setTimeout(() => {
670
+ peer1Push.call(peer1.outgoing, msg);
671
+ }, 0);
672
+ }
648
673
  };
649
674
 
650
675
  const peer2Push = peer2.outgoing.push;
651
676
  peer2.outgoing.push = (msg) => {
652
- SyncMessagesLog.add({
653
- from: opts.peer1.name ?? opts.peer1.role,
654
- to: opts.peer2.name ?? opts.peer2.role,
655
- msg,
656
- });
657
- return peer2Push.call(peer2.outgoing, msg);
677
+ if (typeof msg !== "string") {
678
+ SyncMessagesLog.add({
679
+ from: opts.peer1.name ?? opts.peer1.role,
680
+ to: opts.peer2.name ?? opts.peer2.role,
681
+ msg,
682
+ });
683
+ }
684
+
685
+ if (!TEST_NODE_CONFIG.withAsyncPeers) {
686
+ peer2Push.call(peer2.outgoing, msg);
687
+ } else {
688
+ // Simulate the async nature of the real push
689
+ setTimeout(() => {
690
+ peer2Push.call(peer2.outgoing, msg);
691
+ }, 0);
692
+ }
658
693
  };
659
694
 
660
695
  return {