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
@@ -1,17 +1,19 @@
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 { describe, expect, onTestFinished, test, vi } from "vitest";
6
- import { WasmCrypto } from "../crypto/WasmCrypto.js";
7
- import { CoID, LocalNode, RawCoID, RawCoMap, logger } from "../exports.js";
1
+ import { describe, expect, test, vi, afterEach } from "vitest";
2
+ import { CoID, RawCoID, RawCoMap, logger } from "../exports.js";
8
3
  import { CoValueCore } from "../exports.js";
9
4
  import { NewContentMessage } from "../sync.js";
10
5
  import { CoValueKnownState, emptyKnownState } from "../knownState.js";
11
- import { createSyncStorage } from "./testStorage.js";
12
- import { loadCoValueOrFail, randomAgentAndSessionID } from "./testUtils.js";
13
-
14
- const crypto = await WasmCrypto.create();
6
+ import {
7
+ createSyncStorage,
8
+ getAllCoValuesWaitingForDelete,
9
+ getCoValueStoredSessions,
10
+ getDbPath,
11
+ } from "./testStorage.js";
12
+ import {
13
+ fillCoMapWithLargeData,
14
+ loadCoValueOrFail,
15
+ setupTestNode,
16
+ } from "./testUtils.js";
15
17
 
16
18
  /**
17
19
  * Helper function that gets new content since a known state, throwing if:
@@ -35,55 +37,23 @@ function getNewContentSince(
35
37
  return contentMessage;
36
38
  }
37
39
 
38
- async function createFixturesNode(customDbPath?: string) {
39
- const [admin, session] = randomAgentAndSessionID();
40
- const node = new LocalNode(admin.agentSecret, session, crypto);
41
-
42
- // Create a unique database file for each test
43
- const dbPath = customDbPath ?? join(tmpdir(), `test-${randomUUID()}.db`);
44
- const storage = createSyncStorage({
45
- filename: dbPath,
46
- nodeName: "test",
47
- storageName: "test-storage",
48
- });
49
-
50
- onTestFinished(() => {
51
- try {
52
- unlinkSync(dbPath);
53
- } catch {}
54
- });
55
-
56
- node.setStorage(storage);
57
-
58
- return {
59
- fixturesNode: node,
60
- dbPath,
61
- };
62
- }
63
-
64
- async function createTestNode(dbPath?: string) {
65
- const [admin, session] = randomAgentAndSessionID();
66
- const node = new LocalNode(admin.agentSecret, session, crypto);
67
-
68
- const storage = createSyncStorage({
69
- filename: dbPath,
70
- nodeName: "test",
71
- storageName: "test-storage",
72
- });
73
-
74
- return {
75
- node,
76
- storage,
77
- };
78
- }
40
+ afterEach(() => {
41
+ vi.useRealTimers();
42
+ });
79
43
 
80
44
  describe("StorageApiSync", () => {
81
45
  describe("getKnownState", () => {
82
46
  test("should return empty known state for new coValue ID and cache the result", async () => {
83
- const { fixturesNode } = await createFixturesNode();
84
- const { storage } = await createTestNode();
47
+ const fixtures = setupTestNode();
48
+ const client = setupTestNode();
49
+ const { storage } = client.addStorage({
50
+ storage: createSyncStorage({
51
+ nodeName: "test",
52
+ storageName: "test-storage",
53
+ }),
54
+ });
85
55
 
86
- const id = fixturesNode.createGroup().id;
56
+ const id = fixtures.node.createGroup().id;
87
57
  const knownState = storage.getKnownState(id);
88
58
 
89
59
  expect(knownState).toEqual(emptyKnownState(id));
@@ -91,7 +61,13 @@ describe("StorageApiSync", () => {
91
61
  });
92
62
 
93
63
  test("should return separate known state instances for different coValue IDs", async () => {
94
- const { storage } = await createTestNode();
64
+ const client = setupTestNode();
65
+ const { storage } = client.addStorage({
66
+ storage: createSyncStorage({
67
+ nodeName: "test",
68
+ storageName: "test-storage",
69
+ }),
70
+ });
95
71
  const id1 = "test-id-1";
96
72
  const id2 = "test-id-2";
97
73
 
@@ -104,7 +80,13 @@ describe("StorageApiSync", () => {
104
80
 
105
81
  describe("load", () => {
106
82
  test("should fail gracefully when loading non-existent coValue and preserve known state", async () => {
107
- const { storage } = await createTestNode();
83
+ const client = setupTestNode();
84
+ const { storage } = client.addStorage({
85
+ storage: createSyncStorage({
86
+ nodeName: "test",
87
+ storageName: "test-storage",
88
+ }),
89
+ });
108
90
  const id = "non-existent-id";
109
91
  const callback = vi.fn();
110
92
  const done = vi.fn();
@@ -124,15 +106,31 @@ describe("StorageApiSync", () => {
124
106
  });
125
107
 
126
108
  test("should successfully load coValue with header and update known state", async () => {
127
- const { fixturesNode, dbPath } = await createFixturesNode();
128
- const { node, storage } = await createTestNode(dbPath);
109
+ const dbPath = getDbPath();
110
+ const fixtures = setupTestNode();
111
+ fixtures.addStorage({
112
+ storage: createSyncStorage({
113
+ filename: dbPath,
114
+ nodeName: "test",
115
+ storageName: "test-storage",
116
+ }),
117
+ });
118
+
119
+ const client = setupTestNode();
120
+ const { storage } = client.addStorage({
121
+ storage: createSyncStorage({
122
+ filename: dbPath,
123
+ nodeName: "test",
124
+ storageName: "test-storage",
125
+ }),
126
+ });
129
127
  const callback = vi.fn((content) =>
130
- node.syncManager.handleNewContent(content, "storage"),
128
+ client.node.syncManager.handleNewContent(content, "storage"),
131
129
  );
132
130
  const done = vi.fn();
133
131
 
134
132
  // Create a real group and get its content message
135
- const group = fixturesNode.createGroup();
133
+ const group = fixtures.node.createGroup();
136
134
  await group.core.waitForSync();
137
135
 
138
136
  // Get initial known state
@@ -154,7 +152,7 @@ describe("StorageApiSync", () => {
154
152
  const updatedKnownState = storage.getKnownState(group.id);
155
153
  expect(updatedKnownState).toEqual(group.core.knownState());
156
154
 
157
- const groupOnNode = await loadCoValueOrFail(node, group.id);
155
+ const groupOnNode = await loadCoValueOrFail(client.node, group.id);
158
156
 
159
157
  expect(groupOnNode.core.verified.header).toEqual(
160
158
  group.core.verified.header,
@@ -162,15 +160,31 @@ describe("StorageApiSync", () => {
162
160
  });
163
161
 
164
162
  test("should successfully load coValue with transactions and update known state", async () => {
165
- const { fixturesNode, dbPath } = await createFixturesNode();
166
- const { node, storage } = await createTestNode(dbPath);
163
+ const dbPath = getDbPath();
164
+ const fixtures = setupTestNode();
165
+ fixtures.addStorage({
166
+ storage: createSyncStorage({
167
+ filename: dbPath,
168
+ nodeName: "test",
169
+ storageName: "test-storage",
170
+ }),
171
+ });
172
+
173
+ const client = setupTestNode();
174
+ const { storage } = client.addStorage({
175
+ storage: createSyncStorage({
176
+ filename: dbPath,
177
+ nodeName: "test",
178
+ storageName: "test-storage",
179
+ }),
180
+ });
167
181
  const callback = vi.fn((content) =>
168
- node.syncManager.handleNewContent(content, "storage"),
182
+ client.node.syncManager.handleNewContent(content, "storage"),
169
183
  );
170
184
  const done = vi.fn();
171
185
 
172
186
  // Create a real group and add a member to create transactions
173
- const group = fixturesNode.createGroup();
187
+ const group = fixtures.node.createGroup();
174
188
  group.addMember("everyone", "reader");
175
189
  await group.core.waitForSync();
176
190
 
@@ -185,7 +199,7 @@ describe("StorageApiSync", () => {
185
199
  id: group.id,
186
200
  header: group.core.verified.header,
187
201
  new: expect.objectContaining({
188
- [fixturesNode.currentSessionID]: expect.any(Object),
202
+ [fixtures.node.currentSessionID]: expect.any(Object),
189
203
  }),
190
204
  }),
191
205
  );
@@ -195,17 +209,30 @@ describe("StorageApiSync", () => {
195
209
  const updatedKnownState = storage.getKnownState(group.id);
196
210
  expect(updatedKnownState).toEqual(group.core.knownState());
197
211
 
198
- const groupOnNode = await loadCoValueOrFail(node, group.id);
212
+ const groupOnNode = await loadCoValueOrFail(client.node, group.id);
199
213
  expect(groupOnNode.get("everyone")).toEqual("reader");
200
214
  });
201
215
  });
202
216
 
203
217
  describe("store", () => {
204
218
  test("should successfully store new coValue with header and update known state", async () => {
205
- const { fixturesNode } = await createFixturesNode();
206
- const { node, storage } = await createTestNode();
219
+ const fixtures = setupTestNode();
220
+ fixtures.addStorage({
221
+ storage: createSyncStorage({
222
+ nodeName: "test",
223
+ storageName: "test-storage",
224
+ }),
225
+ });
226
+
227
+ const client = setupTestNode();
228
+ const { storage } = client.addStorage({
229
+ storage: createSyncStorage({
230
+ nodeName: "test",
231
+ storageName: "test-storage",
232
+ }),
233
+ });
207
234
  // Create a real group and get its content message
208
- const group = fixturesNode.createGroup();
235
+ const group = fixtures.node.createGroup();
209
236
  const contentMessage = getNewContentSince(
210
237
  group.core,
211
238
  emptyKnownState(group.id),
@@ -222,9 +249,9 @@ describe("StorageApiSync", () => {
222
249
  const updatedKnownState = storage.getKnownState(group.id);
223
250
  expect(updatedKnownState).toEqual(group.core.knownState());
224
251
 
225
- node.setStorage(storage);
252
+ client.addStorage({ storage });
226
253
 
227
- const groupOnNode = await loadCoValueOrFail(node, group.id);
254
+ const groupOnNode = await loadCoValueOrFail(client.node, group.id);
228
255
 
229
256
  expect(groupOnNode.core.verified.header).toEqual(
230
257
  group.core.verified.header,
@@ -232,11 +259,24 @@ describe("StorageApiSync", () => {
232
259
  });
233
260
 
234
261
  test("should successfully store coValue with transactions and update known state", async () => {
235
- const { fixturesNode } = await createFixturesNode();
236
- const { node, storage } = await createTestNode();
262
+ const fixtures = setupTestNode();
263
+ fixtures.addStorage({
264
+ storage: createSyncStorage({
265
+ nodeName: "test",
266
+ storageName: "test-storage",
267
+ }),
268
+ });
269
+
270
+ const client = setupTestNode();
271
+ const { storage } = client.addStorage({
272
+ storage: createSyncStorage({
273
+ nodeName: "test",
274
+ storageName: "test-storage",
275
+ }),
276
+ });
237
277
 
238
278
  // Create a real group and add a member to create transactions
239
- const group = fixturesNode.createGroup();
279
+ const group = fixtures.node.createGroup();
240
280
 
241
281
  group.addMember("everyone", "reader");
242
282
 
@@ -256,17 +296,30 @@ describe("StorageApiSync", () => {
256
296
  const updatedKnownState = storage.getKnownState(group.id);
257
297
  expect(updatedKnownState).toEqual(group.core.knownState());
258
298
 
259
- node.setStorage(storage);
299
+ client.addStorage({ storage });
260
300
 
261
- const groupOnNode = await loadCoValueOrFail(node, group.id);
301
+ const groupOnNode = await loadCoValueOrFail(client.node, group.id);
262
302
  expect(groupOnNode.get("everyone")).toEqual("reader");
263
303
  });
264
304
 
265
305
  test("should handle correction when header assumption is invalid", async () => {
266
- const { fixturesNode } = await createFixturesNode();
267
- const { node, storage } = await createTestNode();
306
+ const fixtures = setupTestNode();
307
+ fixtures.addStorage({
308
+ storage: createSyncStorage({
309
+ nodeName: "test",
310
+ storageName: "test-storage",
311
+ }),
312
+ });
268
313
 
269
- const group = fixturesNode.createGroup();
314
+ const client = setupTestNode();
315
+ const { storage } = client.addStorage({
316
+ storage: createSyncStorage({
317
+ nodeName: "test",
318
+ storageName: "test-storage",
319
+ }),
320
+ });
321
+
322
+ const group = fixtures.node.createGroup();
270
323
  const knownState = group.core.knownState();
271
324
 
272
325
  group.addMember("everyone", "reader");
@@ -290,17 +343,30 @@ describe("StorageApiSync", () => {
290
343
  const updatedKnownState = storage.getKnownState(group.id);
291
344
  expect(updatedKnownState).toEqual(group.core.knownState());
292
345
 
293
- node.setStorage(storage);
294
- const groupOnNode = await loadCoValueOrFail(node, group.id);
346
+ client.addStorage({ storage });
347
+ const groupOnNode = await loadCoValueOrFail(client.node, group.id);
295
348
 
296
349
  expect(groupOnNode.get("everyone")).toEqual("reader");
297
350
  });
298
351
 
299
352
  test("should handle correction when new content assumption is invalid", async () => {
300
- const { fixturesNode } = await createFixturesNode();
301
- const { node, storage } = await createTestNode();
353
+ const fixtures = setupTestNode();
354
+ fixtures.addStorage({
355
+ storage: createSyncStorage({
356
+ nodeName: "test",
357
+ storageName: "test-storage",
358
+ }),
359
+ });
360
+
361
+ const client = setupTestNode();
362
+ const { storage } = client.addStorage({
363
+ storage: createSyncStorage({
364
+ nodeName: "test",
365
+ storageName: "test-storage",
366
+ }),
367
+ });
302
368
 
303
- const group = fixturesNode.createGroup();
369
+ const group = fixtures.node.createGroup();
304
370
 
305
371
  const initialContent = getNewContentSince(
306
372
  group.core,
@@ -340,17 +406,30 @@ describe("StorageApiSync", () => {
340
406
  const finalKnownState = storage.getKnownState(group.id);
341
407
  expect(finalKnownState).toEqual(group.core.knownState());
342
408
 
343
- node.setStorage(storage);
344
- const groupOnNode = await loadCoValueOrFail(node, group.id);
409
+ client.addStorage({ storage });
410
+ const groupOnNode = await loadCoValueOrFail(client.node, group.id);
345
411
 
346
412
  expect(groupOnNode.get("everyone")).toEqual("writer");
347
413
  });
348
414
 
349
415
  test("should log error and fail when correction callback returns undefined", async () => {
350
- const { fixturesNode } = await createFixturesNode();
351
- const { storage } = await createTestNode();
416
+ const fixtures = setupTestNode();
417
+ fixtures.addStorage({
418
+ storage: createSyncStorage({
419
+ nodeName: "test",
420
+ storageName: "test-storage",
421
+ }),
422
+ });
352
423
 
353
- const group = fixturesNode.createGroup();
424
+ const client = setupTestNode();
425
+ const { storage } = client.addStorage({
426
+ storage: createSyncStorage({
427
+ nodeName: "test",
428
+ storageName: "test-storage",
429
+ }),
430
+ });
431
+
432
+ const group = fixtures.node.createGroup();
354
433
 
355
434
  const knownState = group.core.knownState();
356
435
  group.addMember("everyone", "writer");
@@ -385,10 +464,23 @@ describe("StorageApiSync", () => {
385
464
  });
386
465
 
387
466
  test("should log error and fail when correction callback returns invalid content message", async () => {
388
- const { fixturesNode } = await createFixturesNode();
389
- const { storage } = await createTestNode();
467
+ const fixtures = setupTestNode();
468
+ fixtures.addStorage({
469
+ storage: createSyncStorage({
470
+ nodeName: "test",
471
+ storageName: "test-storage",
472
+ }),
473
+ });
474
+
475
+ const client = setupTestNode();
476
+ const { storage } = client.addStorage({
477
+ storage: createSyncStorage({
478
+ nodeName: "test",
479
+ storageName: "test-storage",
480
+ }),
481
+ });
390
482
 
391
- const group = fixturesNode.createGroup();
483
+ const group = fixtures.node.createGroup();
392
484
 
393
485
  const knownState = group.core.knownState();
394
486
  group.addMember("everyone", "writer");
@@ -420,15 +512,39 @@ describe("StorageApiSync", () => {
420
512
  });
421
513
 
422
514
  test("should successfully store coValue with multiple sessions", async () => {
423
- const { fixturesNode, dbPath } = await createFixturesNode();
424
- const { fixturesNode: fixtureNode2 } = await createFixturesNode(dbPath);
425
- const { node, storage } = await createTestNode();
515
+ const dbPath = getDbPath();
516
+
517
+ const fixtures = setupTestNode();
518
+ fixtures.addStorage({
519
+ storage: createSyncStorage({
520
+ filename: dbPath,
521
+ nodeName: "test",
522
+ storageName: "test-storage",
523
+ }),
524
+ });
525
+
526
+ const fixture2 = setupTestNode();
527
+ fixture2.addStorage({
528
+ storage: createSyncStorage({
529
+ filename: dbPath,
530
+ nodeName: "test",
531
+ storageName: "test-storage",
532
+ }),
533
+ });
426
534
 
427
- const coValue = fixturesNode.createCoValue({
535
+ const client = setupTestNode();
536
+ const { storage } = client.addStorage({
537
+ storage: createSyncStorage({
538
+ nodeName: "test",
539
+ storageName: "test-storage",
540
+ }),
541
+ });
542
+
543
+ const coValue = fixtures.node.createCoValue({
428
544
  type: "comap",
429
545
  ruleset: { type: "unsafeAllowAll" },
430
546
  meta: null,
431
- ...crypto.createdNowUnique(),
547
+ ...fixtures.node.crypto.createdNowUnique(),
432
548
  });
433
549
 
434
550
  coValue.makeTransaction(
@@ -443,7 +559,7 @@ describe("StorageApiSync", () => {
443
559
  await coValue.waitForSync();
444
560
 
445
561
  const mapOnNode2 = await loadCoValueOrFail(
446
- fixtureNode2,
562
+ fixture2.node,
447
563
  coValue.id as CoID<RawCoMap>,
448
564
  );
449
565
 
@@ -466,27 +582,216 @@ describe("StorageApiSync", () => {
466
582
 
467
583
  storage.store(contentMessage, correctionCallback);
468
584
 
469
- node.setStorage(storage);
585
+ client.addStorage({ storage });
470
586
 
471
- const finalMap = await loadCoValueOrFail(node, mapOnNode2.id);
587
+ const finalMap = await loadCoValueOrFail(client.node, mapOnNode2.id);
472
588
  expect(finalMap.core.knownState()).toEqual(knownState);
473
589
  });
474
590
  });
475
591
 
592
+ describe("delete flow", () => {
593
+ test("deleteCoValue enqueues the coValue for erasure", async () => {
594
+ const client = setupTestNode();
595
+ const { storage } = client.addStorage({
596
+ storage: createSyncStorage({
597
+ nodeName: "test",
598
+ storageName: "test-storage",
599
+ }),
600
+ });
601
+
602
+ const group = client.node.createGroup();
603
+ const map = group.createMap();
604
+ map.core.deleteCoValue();
605
+ await map.core.waitForSync();
606
+
607
+ const queued = await getAllCoValuesWaitingForDelete(storage);
608
+ expect(queued).toContain(map.id);
609
+ });
610
+
611
+ test("background erasure doesn't run if not enabled", async () => {
612
+ const dbPath = getDbPath();
613
+ const node = setupTestNode();
614
+ const { storage } = node.addStorage({
615
+ storage: createSyncStorage({
616
+ filename: dbPath,
617
+ nodeName: "test",
618
+ storageName: "test-storage",
619
+ }),
620
+ });
621
+
622
+ const group = node.node.createGroup();
623
+ const map = group.createMap();
624
+ map.set("k", "v");
625
+ await map.core.waitForSync();
626
+
627
+ vi.useFakeTimers();
628
+
629
+ map.core.deleteCoValue();
630
+ await map.core.waitForSync();
631
+
632
+ await vi.advanceTimersByTimeAsync(70_000);
633
+
634
+ // Queue drained
635
+ expect(await getAllCoValuesWaitingForDelete(storage)).toContain(map.id);
636
+ });
637
+
638
+ test("background erasure run if enabled", async () => {
639
+ const dbPath = getDbPath();
640
+ const node = setupTestNode();
641
+ const { storage } = node.addStorage({
642
+ storage: createSyncStorage({
643
+ filename: dbPath,
644
+ nodeName: "test",
645
+ storageName: "test-storage",
646
+ }),
647
+ });
648
+
649
+ vi.useFakeTimers();
650
+
651
+ node.node.enableDeletedCoValuesErasure();
652
+
653
+ const group = node.node.createGroup();
654
+ const map = group.createMap();
655
+ map.set("k", "v");
656
+ await map.core.waitForSync();
657
+
658
+ map.core.deleteCoValue();
659
+ await map.core.waitForSync();
660
+
661
+ await vi.advanceTimersByTimeAsync(70_000);
662
+
663
+ // Queue drained
664
+ expect(await getAllCoValuesWaitingForDelete(storage)).not.toContain(
665
+ map.id,
666
+ );
667
+
668
+ const sessionIDs = await getCoValueStoredSessions(storage, map.id);
669
+
670
+ expect(sessionIDs).toHaveLength(1);
671
+ expect(sessionIDs[0]).toMatch(/_session_d[1-9A-HJ-NP-Za-km-z]+\$$/); // Delete session format
672
+ });
673
+
674
+ test("eraseAllDeletedCoValues deletes history but preserves tombstone", async () => {
675
+ const dbPath = getDbPath();
676
+
677
+ const node = setupTestNode();
678
+ const { storage } = node.addStorage({
679
+ storage: createSyncStorage({
680
+ filename: dbPath,
681
+ nodeName: "test",
682
+ storageName: "test-storage",
683
+ }),
684
+ });
685
+
686
+ const group = node.node.createGroup();
687
+ const map = group.createMap();
688
+ map.set("k", "v");
689
+ await map.core.waitForSync();
690
+
691
+ map.core.deleteCoValue();
692
+ await map.core.waitForSync();
693
+
694
+ expect(await getAllCoValuesWaitingForDelete(storage)).toContain(map.id);
695
+
696
+ await storage.eraseAllDeletedCoValues();
697
+
698
+ // Queue drained
699
+ expect(await getAllCoValuesWaitingForDelete(storage)).not.toContain(
700
+ map.id,
701
+ );
702
+
703
+ // Tombstone preserved + history erased when loaded from storage
704
+ const client = setupTestNode();
705
+ const { storage: clientStorage } = client.addStorage({
706
+ storage: createSyncStorage({
707
+ filename: dbPath,
708
+ nodeName: "test",
709
+ storageName: "test-storage",
710
+ }),
711
+ });
712
+
713
+ const loaded = await loadCoValueOrFail(
714
+ client.node,
715
+ map.id as CoID<RawCoMap>,
716
+ );
717
+
718
+ expect(loaded.core.isDeleted).toBe(true);
719
+ expect(loaded.get("k")).toBeUndefined();
720
+
721
+ const sessionIDs = await getCoValueStoredSessions(clientStorage, map.id);
722
+
723
+ expect(sessionIDs).toHaveLength(1);
724
+ expect(sessionIDs[0]).toMatch(/_session_d[1-9A-HJ-NP-Za-km-z]+\$$/); // Delete session format
725
+ });
726
+
727
+ test("eraseAllDeletedCoValues does not break when called while a coValue is streaming from storage", async () => {
728
+ const dbPath = getDbPath();
729
+
730
+ const node = setupTestNode();
731
+
732
+ const storage = createSyncStorage({
733
+ filename: dbPath,
734
+ nodeName: "test",
735
+ storageName: "test-storage",
736
+ });
737
+ node.addStorage({ storage });
738
+
739
+ const group = node.node.createGroup();
740
+ const map = group.createMap();
741
+ fillCoMapWithLargeData(map);
742
+ await map.core.waitForSync();
743
+ map.core.deleteCoValue();
744
+ await map.core.waitForSync();
745
+
746
+ storage.close();
747
+
748
+ const newStorage = createSyncStorage({
749
+ filename: dbPath,
750
+ nodeName: "test",
751
+ storageName: "test-storage",
752
+ });
753
+
754
+ const callback = vi.fn();
755
+
756
+ const loadPromise = new Promise((resolve) => {
757
+ newStorage.load(map.id, callback, resolve);
758
+ });
759
+ await newStorage.eraseAllDeletedCoValues();
760
+
761
+ expect(await loadPromise).toBe(true);
762
+ });
763
+ });
764
+
476
765
  describe("dependencies", () => {
477
766
  test("should load dependencies before dependent coValues and update all known states", async () => {
478
- const { fixturesNode, dbPath } = await createFixturesNode();
479
- const { node, storage } = await createTestNode(dbPath);
767
+ const dbPath = getDbPath();
768
+ const fixtures = setupTestNode();
769
+ fixtures.addStorage({
770
+ storage: createSyncStorage({
771
+ filename: dbPath,
772
+ nodeName: "test",
773
+ storageName: "test-storage",
774
+ }),
775
+ });
776
+
777
+ const client = setupTestNode();
778
+ const { storage } = client.addStorage({
779
+ storage: createSyncStorage({
780
+ filename: dbPath,
781
+ nodeName: "test",
782
+ storageName: "test-storage",
783
+ }),
784
+ });
480
785
 
481
786
  // Create a group and a map owned by that group to create dependencies
482
- const group = fixturesNode.createGroup();
787
+ const group = fixtures.node.createGroup();
483
788
  group.addMember("everyone", "reader");
484
789
  const map = group.createMap({ test: "value" });
485
790
  await group.core.waitForSync();
486
791
  await map.core.waitForSync();
487
792
 
488
793
  const callback = vi.fn((content) =>
489
- node.syncManager.handleNewContent(content, "storage"),
794
+ client.node.syncManager.handleNewContent(content, "storage"),
490
795
  );
491
796
  const done = vi.fn();
492
797
 
@@ -521,24 +826,40 @@ describe("StorageApiSync", () => {
521
826
  expect(updatedGroupKnownState).toEqual(group.core.knownState());
522
827
  expect(updatedMapKnownState).toEqual(map.core.knownState());
523
828
 
524
- node.setStorage(storage);
525
- const mapOnNode = await loadCoValueOrFail(node, map.id);
829
+ client.addStorage({ storage });
830
+ const mapOnNode = await loadCoValueOrFail(client.node, map.id);
526
831
  expect(mapOnNode.get("test")).toEqual("value");
527
832
  });
528
833
 
529
834
  test("should skip loading already loaded dependencies", async () => {
530
- const { fixturesNode, dbPath } = await createFixturesNode();
531
- const { node, storage } = await createTestNode(dbPath);
835
+ const dbPath = getDbPath();
836
+ const fixtures = setupTestNode();
837
+ fixtures.addStorage({
838
+ storage: createSyncStorage({
839
+ filename: dbPath,
840
+ nodeName: "test",
841
+ storageName: "test-storage",
842
+ }),
843
+ });
844
+
845
+ const client = setupTestNode();
846
+ const { storage } = client.addStorage({
847
+ storage: createSyncStorage({
848
+ filename: dbPath,
849
+ nodeName: "test",
850
+ storageName: "test-storage",
851
+ }),
852
+ });
532
853
 
533
854
  // Create a group and a map owned by that group
534
- const group = fixturesNode.createGroup();
855
+ const group = fixtures.node.createGroup();
535
856
  group.addMember("everyone", "reader");
536
857
  const map = group.createMap({ test: "value" });
537
858
  await group.core.waitForSync();
538
859
  await map.core.waitForSync();
539
860
 
540
861
  const callback = vi.fn((content) =>
541
- node.syncManager.handleNewContent(content, "storage"),
862
+ client.node.syncManager.handleNewContent(content, "storage"),
542
863
  );
543
864
  const done = vi.fn();
544
865
 
@@ -574,19 +895,100 @@ describe("StorageApiSync", () => {
574
895
  const finalMapKnownState = storage.getKnownState(map.id);
575
896
  expect(finalMapKnownState).toEqual(map.core.knownState());
576
897
 
577
- node.setStorage(storage);
578
- const mapOnNode = await loadCoValueOrFail(node, map.id);
898
+ client.addStorage({ storage });
899
+ const mapOnNode = await loadCoValueOrFail(client.node, map.id);
900
+ expect(mapOnNode.get("test")).toEqual("value");
901
+ });
902
+
903
+ test("should load dependencies again if they were unmounted", async () => {
904
+ const dbPath = getDbPath();
905
+ const fixtures = setupTestNode();
906
+ fixtures.addStorage({
907
+ storage: createSyncStorage({
908
+ filename: dbPath,
909
+ nodeName: "test",
910
+ storageName: "test-storage",
911
+ }),
912
+ });
913
+
914
+ const client = setupTestNode();
915
+ const { storage } = client.addStorage({
916
+ storage: createSyncStorage({
917
+ filename: dbPath,
918
+ nodeName: "test",
919
+ storageName: "test-storage",
920
+ }),
921
+ });
922
+
923
+ // Create a group and a map owned by that group
924
+ const group = fixtures.node.createGroup();
925
+ group.addMember("everyone", "reader");
926
+ const map = group.createMap({ test: "value" });
927
+ await group.core.waitForSync();
928
+ await map.core.waitForSync();
929
+
930
+ const callback = vi.fn((content) =>
931
+ client.node.syncManager.handleNewContent(content, "storage"),
932
+ );
933
+ const done = vi.fn();
934
+
935
+ // Load the map (and its group)
936
+ await storage.load(map.id, callback, done);
937
+ callback.mockClear();
938
+ done.mockClear();
939
+
940
+ // Unmount the map and its group
941
+ storage.onCoValueUnmounted(map.id);
942
+ storage.onCoValueUnmounted(group.id);
943
+
944
+ // Load the map. The group dependency should be loaded again
945
+ await storage.load(map.id, callback, done);
946
+
947
+ expect(callback).toHaveBeenCalledTimes(2);
948
+ expect(callback).toHaveBeenNthCalledWith(
949
+ 1,
950
+ expect.objectContaining({
951
+ id: group.id,
952
+ }),
953
+ );
954
+ expect(callback).toHaveBeenNthCalledWith(
955
+ 2,
956
+ expect.objectContaining({
957
+ id: map.id,
958
+ }),
959
+ );
960
+
961
+ expect(done).toHaveBeenCalledWith(true);
962
+
963
+ client.addStorage({ storage });
964
+ const mapOnNode = await loadCoValueOrFail(client.node, map.id);
579
965
  expect(mapOnNode.get("test")).toEqual("value");
580
966
  });
581
967
  });
582
968
 
583
969
  describe("waitForSync", () => {
584
970
  test("should resolve immediately when coValue is already synced", async () => {
585
- const { fixturesNode, dbPath } = await createFixturesNode();
586
- const { node, storage } = await createTestNode(dbPath);
971
+ const dbPath = getDbPath();
972
+ const fixtures = setupTestNode();
973
+ fixtures.addStorage({
974
+ storage: createSyncStorage({
975
+ filename: dbPath,
976
+ nodeName: "test",
977
+ storageName: "test-storage",
978
+ }),
979
+ });
980
+
981
+ const client = setupTestNode();
982
+ const { storage } = client.addStorage({
983
+ storage: createSyncStorage({
984
+ filename: dbPath,
985
+ nodeName: "test",
986
+ storageName: "test-storage",
987
+ }),
988
+ });
587
989
 
588
990
  // Create a group and add a member
589
- const group = fixturesNode.createGroup();
991
+ const group = fixtures.node.createGroup();
590
992
  group.addMember("everyone", "reader");
591
993
  await group.core.waitForSync();
592
994
 
@@ -598,10 +1000,10 @@ describe("StorageApiSync", () => {
598
1000
  const correctionCallback = vi.fn();
599
1001
  storage.store(contentMessage, correctionCallback);
600
1002
 
601
- node.setStorage(storage);
1003
+ client.addStorage({ storage });
602
1004
 
603
1005
  // Load the group on the new node
604
- const groupOnNode = await loadCoValueOrFail(node, group.id);
1006
+ const groupOnNode = await loadCoValueOrFail(client.node, group.id);
605
1007
 
606
1008
  // Wait for sync should resolve immediately since the coValue is already synced
607
1009
  await expect(
@@ -614,7 +1016,13 @@ describe("StorageApiSync", () => {
614
1016
 
615
1017
  describe("close", () => {
616
1018
  test("should close storage without throwing errors", async () => {
617
- const { storage } = await createTestNode();
1019
+ const client = setupTestNode();
1020
+ const { storage } = client.addStorage({
1021
+ storage: createSyncStorage({
1022
+ nodeName: "test",
1023
+ storageName: "test-storage",
1024
+ }),
1025
+ });
618
1026
 
619
1027
  expect(() => storage.close()).not.toThrow();
620
1028
  });
@@ -622,11 +1030,27 @@ describe("StorageApiSync", () => {
622
1030
 
623
1031
  describe("loadKnownState", () => {
624
1032
  test("should return correct knownState structure for existing CoValue", async () => {
625
- const { fixturesNode, dbPath } = await createFixturesNode();
626
- const { storage } = await createTestNode(dbPath);
1033
+ const dbPath = getDbPath();
1034
+ const fixtures = setupTestNode();
1035
+ fixtures.addStorage({
1036
+ storage: createSyncStorage({
1037
+ filename: dbPath,
1038
+ nodeName: "test",
1039
+ storageName: "test-storage",
1040
+ }),
1041
+ });
1042
+
1043
+ const client = setupTestNode();
1044
+ const { storage } = client.addStorage({
1045
+ storage: createSyncStorage({
1046
+ filename: dbPath,
1047
+ nodeName: "test",
1048
+ storageName: "test-storage",
1049
+ }),
1050
+ });
627
1051
 
628
1052
  // Create a group to have data in the database
629
- const group = fixturesNode.createGroup();
1053
+ const group = fixtures.node.createGroup();
630
1054
  group.addMember("everyone", "reader");
631
1055
  await group.core.waitForSync();
632
1056
 
@@ -643,7 +1067,13 @@ describe("StorageApiSync", () => {
643
1067
  });
644
1068
 
645
1069
  test("should return undefined for non-existent CoValue", async () => {
646
- const { storage } = await createTestNode();
1070
+ const client = setupTestNode();
1071
+ const { storage } = client.addStorage({
1072
+ storage: createSyncStorage({
1073
+ nodeName: "test",
1074
+ storageName: "test-storage",
1075
+ }),
1076
+ });
647
1077
 
648
1078
  const result = await new Promise<CoValueKnownState | undefined>(
649
1079
  (resolve) => {
@@ -655,15 +1085,31 @@ describe("StorageApiSync", () => {
655
1085
  });
656
1086
 
657
1087
  test("should handle CoValue with no sessions (header only)", async () => {
658
- const { fixturesNode, dbPath } = await createFixturesNode();
659
- const { storage } = await createTestNode(dbPath);
1088
+ const dbPath = getDbPath();
1089
+ const fixtures = setupTestNode();
1090
+ fixtures.addStorage({
1091
+ storage: createSyncStorage({
1092
+ filename: dbPath,
1093
+ nodeName: "test",
1094
+ storageName: "test-storage",
1095
+ }),
1096
+ });
1097
+
1098
+ const client = setupTestNode();
1099
+ const { storage } = client.addStorage({
1100
+ storage: createSyncStorage({
1101
+ filename: dbPath,
1102
+ nodeName: "test",
1103
+ storageName: "test-storage",
1104
+ }),
1105
+ });
660
1106
 
661
1107
  // Create a CoValue with just a header (no transactions yet)
662
- const coValue = fixturesNode.createCoValue({
1108
+ const coValue = fixtures.node.createCoValue({
663
1109
  type: "comap",
664
1110
  ruleset: { type: "unsafeAllowAll" },
665
1111
  meta: null,
666
- ...crypto.createdNowUnique(),
1112
+ ...fixtures.node.crypto.createdNowUnique(),
667
1113
  });
668
1114
  await coValue.waitForSync();
669
1115
 
@@ -681,23 +1127,47 @@ describe("StorageApiSync", () => {
681
1127
  });
682
1128
 
683
1129
  test("should handle CoValue with multiple sessions", async () => {
684
- const { fixturesNode, dbPath } = await createFixturesNode();
685
- const { fixturesNode: fixturesNode2 } = await createFixturesNode(dbPath);
686
- const { storage } = await createTestNode(dbPath);
1130
+ const dbPath = getDbPath();
1131
+ const fixtures = setupTestNode();
1132
+ fixtures.addStorage({
1133
+ storage: createSyncStorage({
1134
+ filename: dbPath,
1135
+ nodeName: "test",
1136
+ storageName: "test-storage",
1137
+ }),
1138
+ });
1139
+
1140
+ const fixtures2 = setupTestNode();
1141
+ fixtures2.addStorage({
1142
+ storage: createSyncStorage({
1143
+ filename: dbPath,
1144
+ nodeName: "test",
1145
+ storageName: "test-storage",
1146
+ }),
1147
+ });
1148
+
1149
+ const client = setupTestNode();
1150
+ const { storage } = client.addStorage({
1151
+ storage: createSyncStorage({
1152
+ filename: dbPath,
1153
+ nodeName: "test",
1154
+ storageName: "test-storage",
1155
+ }),
1156
+ });
687
1157
 
688
1158
  // Create a CoValue and have two nodes make transactions
689
- const coValue = fixturesNode.createCoValue({
1159
+ const coValue = fixtures.node.createCoValue({
690
1160
  type: "comap",
691
1161
  ruleset: { type: "unsafeAllowAll" },
692
1162
  meta: null,
693
- ...crypto.createdNowUnique(),
1163
+ ...fixtures.node.crypto.createdNowUnique(),
694
1164
  });
695
1165
 
696
1166
  coValue.makeTransaction([{ key1: "value1" }], "trusting");
697
1167
  await coValue.waitForSync();
698
1168
 
699
1169
  const coValueOnNode2 = await loadCoValueOrFail(
700
- fixturesNode2,
1170
+ fixtures2.node,
701
1171
  coValue.id as CoID<RawCoMap>,
702
1172
  );
703
1173
 
@@ -722,11 +1192,27 @@ describe("StorageApiSync", () => {
722
1192
  });
723
1193
 
724
1194
  test("should use cache when knownState is cached", async () => {
725
- const { fixturesNode, dbPath } = await createFixturesNode();
726
- const { storage } = await createTestNode(dbPath);
1195
+ const dbPath = getDbPath();
1196
+ const fixtures = setupTestNode();
1197
+ fixtures.addStorage({
1198
+ storage: createSyncStorage({
1199
+ filename: dbPath,
1200
+ nodeName: "test",
1201
+ storageName: "test-storage",
1202
+ }),
1203
+ });
1204
+
1205
+ const client = setupTestNode();
1206
+ const { storage } = client.addStorage({
1207
+ storage: createSyncStorage({
1208
+ filename: dbPath,
1209
+ nodeName: "test",
1210
+ storageName: "test-storage",
1211
+ }),
1212
+ });
727
1213
 
728
1214
  // Create a group to have data in the database
729
- const group = fixturesNode.createGroup();
1215
+ const group = fixtures.node.createGroup();
730
1216
  group.addMember("everyone", "reader");
731
1217
  await group.core.waitForSync();
732
1218