cojson 0.19.21 → 0.20.0

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