cojson 0.19.22 → 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 (194) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +54 -0
  3. package/dist/coValueContentMessage.d.ts +0 -2
  4. package/dist/coValueContentMessage.d.ts.map +1 -1
  5. package/dist/coValueContentMessage.js +0 -8
  6. package/dist/coValueContentMessage.js.map +1 -1
  7. package/dist/coValueCore/SessionMap.d.ts +4 -2
  8. package/dist/coValueCore/SessionMap.d.ts.map +1 -1
  9. package/dist/coValueCore/SessionMap.js +30 -0
  10. package/dist/coValueCore/SessionMap.js.map +1 -1
  11. package/dist/coValueCore/coValueCore.d.ts +67 -3
  12. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  13. package/dist/coValueCore/coValueCore.js +289 -12
  14. package/dist/coValueCore/coValueCore.js.map +1 -1
  15. package/dist/coValueCore/verifiedState.d.ts +6 -1
  16. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  17. package/dist/coValueCore/verifiedState.js +9 -0
  18. package/dist/coValueCore/verifiedState.js.map +1 -1
  19. package/dist/coValues/coList.d.ts +3 -2
  20. package/dist/coValues/coList.d.ts.map +1 -1
  21. package/dist/coValues/coList.js.map +1 -1
  22. package/dist/coValues/group.d.ts.map +1 -1
  23. package/dist/coValues/group.js +3 -6
  24. package/dist/coValues/group.js.map +1 -1
  25. package/dist/config.d.ts +0 -6
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +0 -8
  28. package/dist/config.js.map +1 -1
  29. package/dist/crypto/NapiCrypto.d.ts +1 -2
  30. package/dist/crypto/NapiCrypto.d.ts.map +1 -1
  31. package/dist/crypto/NapiCrypto.js +19 -4
  32. package/dist/crypto/NapiCrypto.js.map +1 -1
  33. package/dist/crypto/RNCrypto.d.ts.map +1 -1
  34. package/dist/crypto/RNCrypto.js +19 -4
  35. package/dist/crypto/RNCrypto.js.map +1 -1
  36. package/dist/crypto/WasmCrypto.d.ts +11 -4
  37. package/dist/crypto/WasmCrypto.d.ts.map +1 -1
  38. package/dist/crypto/WasmCrypto.js +52 -10
  39. package/dist/crypto/WasmCrypto.js.map +1 -1
  40. package/dist/crypto/WasmCryptoEdge.d.ts +1 -0
  41. package/dist/crypto/WasmCryptoEdge.d.ts.map +1 -1
  42. package/dist/crypto/WasmCryptoEdge.js +4 -1
  43. package/dist/crypto/WasmCryptoEdge.js.map +1 -1
  44. package/dist/crypto/crypto.d.ts +3 -3
  45. package/dist/crypto/crypto.d.ts.map +1 -1
  46. package/dist/crypto/crypto.js +6 -1
  47. package/dist/crypto/crypto.js.map +1 -1
  48. package/dist/exports.d.ts +2 -2
  49. package/dist/exports.d.ts.map +1 -1
  50. package/dist/exports.js +2 -1
  51. package/dist/exports.js.map +1 -1
  52. package/dist/ids.d.ts +4 -1
  53. package/dist/ids.d.ts.map +1 -1
  54. package/dist/ids.js +4 -0
  55. package/dist/ids.js.map +1 -1
  56. package/dist/knownState.d.ts +2 -0
  57. package/dist/knownState.d.ts.map +1 -1
  58. package/dist/localNode.d.ts +12 -0
  59. package/dist/localNode.d.ts.map +1 -1
  60. package/dist/localNode.js +14 -0
  61. package/dist/localNode.js.map +1 -1
  62. package/dist/platformUtils.d.ts +3 -0
  63. package/dist/platformUtils.d.ts.map +1 -0
  64. package/dist/platformUtils.js +24 -0
  65. package/dist/platformUtils.js.map +1 -0
  66. package/dist/storage/DeletedCoValuesEraserScheduler.d.ts +30 -0
  67. package/dist/storage/DeletedCoValuesEraserScheduler.d.ts.map +1 -0
  68. package/dist/storage/DeletedCoValuesEraserScheduler.js +84 -0
  69. package/dist/storage/DeletedCoValuesEraserScheduler.js.map +1 -0
  70. package/dist/storage/sqlite/client.d.ts +3 -0
  71. package/dist/storage/sqlite/client.d.ts.map +1 -1
  72. package/dist/storage/sqlite/client.js +44 -0
  73. package/dist/storage/sqlite/client.js.map +1 -1
  74. package/dist/storage/sqlite/sqliteMigrations.d.ts.map +1 -1
  75. package/dist/storage/sqlite/sqliteMigrations.js +7 -0
  76. package/dist/storage/sqlite/sqliteMigrations.js.map +1 -1
  77. package/dist/storage/sqliteAsync/client.d.ts +3 -0
  78. package/dist/storage/sqliteAsync/client.d.ts.map +1 -1
  79. package/dist/storage/sqliteAsync/client.js +42 -0
  80. package/dist/storage/sqliteAsync/client.js.map +1 -1
  81. package/dist/storage/storageAsync.d.ts +7 -0
  82. package/dist/storage/storageAsync.d.ts.map +1 -1
  83. package/dist/storage/storageAsync.js +48 -0
  84. package/dist/storage/storageAsync.js.map +1 -1
  85. package/dist/storage/storageSync.d.ts +6 -0
  86. package/dist/storage/storageSync.d.ts.map +1 -1
  87. package/dist/storage/storageSync.js +42 -0
  88. package/dist/storage/storageSync.js.map +1 -1
  89. package/dist/storage/types.d.ts +59 -0
  90. package/dist/storage/types.d.ts.map +1 -1
  91. package/dist/storage/types.js +12 -1
  92. package/dist/storage/types.js.map +1 -1
  93. package/dist/sync.d.ts.map +1 -1
  94. package/dist/sync.js +44 -11
  95. package/dist/sync.js.map +1 -1
  96. package/dist/tests/DeletedCoValuesEraserScheduler.test.d.ts +2 -0
  97. package/dist/tests/DeletedCoValuesEraserScheduler.test.d.ts.map +1 -0
  98. package/dist/tests/DeletedCoValuesEraserScheduler.test.js +149 -0
  99. package/dist/tests/DeletedCoValuesEraserScheduler.test.js.map +1 -0
  100. package/dist/tests/GarbageCollector.test.js +5 -6
  101. package/dist/tests/GarbageCollector.test.js.map +1 -1
  102. package/dist/tests/StorageApiAsync.test.js +484 -152
  103. package/dist/tests/StorageApiAsync.test.js.map +1 -1
  104. package/dist/tests/StorageApiSync.test.js +505 -136
  105. package/dist/tests/StorageApiSync.test.js.map +1 -1
  106. package/dist/tests/WasmCrypto.test.js +6 -3
  107. package/dist/tests/WasmCrypto.test.js.map +1 -1
  108. package/dist/tests/coValueCore.loadFromStorage.test.js +3 -0
  109. package/dist/tests/coValueCore.loadFromStorage.test.js.map +1 -1
  110. package/dist/tests/coValueCore.test.js +34 -13
  111. package/dist/tests/coValueCore.test.js.map +1 -1
  112. package/dist/tests/coreWasm.test.js +127 -4
  113. package/dist/tests/coreWasm.test.js.map +1 -1
  114. package/dist/tests/crypto.test.js +89 -93
  115. package/dist/tests/crypto.test.js.map +1 -1
  116. package/dist/tests/deleteCoValue.test.d.ts +2 -0
  117. package/dist/tests/deleteCoValue.test.d.ts.map +1 -0
  118. package/dist/tests/deleteCoValue.test.js +313 -0
  119. package/dist/tests/deleteCoValue.test.js.map +1 -0
  120. package/dist/tests/group.removeMember.test.js +18 -30
  121. package/dist/tests/group.removeMember.test.js.map +1 -1
  122. package/dist/tests/knownState.lazyLoading.test.js +3 -0
  123. package/dist/tests/knownState.lazyLoading.test.js.map +1 -1
  124. package/dist/tests/sync.deleted.test.d.ts +2 -0
  125. package/dist/tests/sync.deleted.test.d.ts.map +1 -0
  126. package/dist/tests/sync.deleted.test.js +214 -0
  127. package/dist/tests/sync.deleted.test.js.map +1 -0
  128. package/dist/tests/sync.mesh.test.js +3 -2
  129. package/dist/tests/sync.mesh.test.js.map +1 -1
  130. package/dist/tests/sync.storage.test.js +3 -2
  131. package/dist/tests/sync.storage.test.js.map +1 -1
  132. package/dist/tests/sync.test.js +3 -2
  133. package/dist/tests/sync.test.js.map +1 -1
  134. package/dist/tests/testStorage.d.ts +3 -0
  135. package/dist/tests/testStorage.d.ts.map +1 -1
  136. package/dist/tests/testStorage.js +14 -0
  137. package/dist/tests/testStorage.js.map +1 -1
  138. package/dist/tests/testUtils.d.ts +6 -3
  139. package/dist/tests/testUtils.d.ts.map +1 -1
  140. package/dist/tests/testUtils.js +17 -3
  141. package/dist/tests/testUtils.js.map +1 -1
  142. package/package.json +6 -16
  143. package/src/coValueContentMessage.ts +0 -14
  144. package/src/coValueCore/SessionMap.ts +43 -1
  145. package/src/coValueCore/coValueCore.ts +400 -8
  146. package/src/coValueCore/verifiedState.ts +26 -3
  147. package/src/coValues/coList.ts +5 -3
  148. package/src/coValues/group.ts +5 -6
  149. package/src/config.ts +0 -9
  150. package/src/crypto/NapiCrypto.ts +29 -13
  151. package/src/crypto/RNCrypto.ts +29 -11
  152. package/src/crypto/WasmCrypto.ts +67 -20
  153. package/src/crypto/WasmCryptoEdge.ts +5 -1
  154. package/src/crypto/crypto.ts +16 -4
  155. package/src/exports.ts +2 -0
  156. package/src/ids.ts +11 -1
  157. package/src/localNode.ts +15 -0
  158. package/src/platformUtils.ts +26 -0
  159. package/src/storage/DeletedCoValuesEraserScheduler.ts +124 -0
  160. package/src/storage/sqlite/client.ts +77 -0
  161. package/src/storage/sqlite/sqliteMigrations.ts +7 -0
  162. package/src/storage/sqliteAsync/client.ts +75 -0
  163. package/src/storage/storageAsync.ts +62 -0
  164. package/src/storage/storageSync.ts +58 -0
  165. package/src/storage/types.ts +69 -0
  166. package/src/sync.ts +51 -11
  167. package/src/tests/DeletedCoValuesEraserScheduler.test.ts +185 -0
  168. package/src/tests/GarbageCollector.test.ts +6 -10
  169. package/src/tests/StorageApiAsync.test.ts +572 -162
  170. package/src/tests/StorageApiSync.test.ts +580 -143
  171. package/src/tests/WasmCrypto.test.ts +8 -3
  172. package/src/tests/coValueCore.loadFromStorage.test.ts +6 -0
  173. package/src/tests/coValueCore.test.ts +49 -14
  174. package/src/tests/coreWasm.test.ts +319 -10
  175. package/src/tests/crypto.test.ts +141 -150
  176. package/src/tests/deleteCoValue.test.ts +528 -0
  177. package/src/tests/group.removeMember.test.ts +35 -35
  178. package/src/tests/knownState.lazyLoading.test.ts +6 -0
  179. package/src/tests/sync.deleted.test.ts +294 -0
  180. package/src/tests/sync.mesh.test.ts +5 -2
  181. package/src/tests/sync.storage.test.ts +5 -2
  182. package/src/tests/sync.test.ts +5 -2
  183. package/src/tests/testStorage.ts +28 -1
  184. package/src/tests/testUtils.ts +28 -9
  185. package/dist/crypto/PureJSCrypto.d.ts +0 -77
  186. package/dist/crypto/PureJSCrypto.d.ts.map +0 -1
  187. package/dist/crypto/PureJSCrypto.js +0 -236
  188. package/dist/crypto/PureJSCrypto.js.map +0 -1
  189. package/dist/tests/PureJSCrypto.test.d.ts +0 -2
  190. package/dist/tests/PureJSCrypto.test.d.ts.map +0 -1
  191. package/dist/tests/PureJSCrypto.test.js +0 -145
  192. package/dist/tests/PureJSCrypto.test.js.map +0 -1
  193. package/src/crypto/PureJSCrypto.ts +0 -429
  194. package/src/tests/PureJSCrypto.test.ts +0 -217
@@ -0,0 +1,185 @@
1
+ import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
2
+ import { logger } from "../logger.js";
3
+ import { DeletedCoValuesEraserScheduler } from "../storage/DeletedCoValuesEraserScheduler.js";
4
+
5
+ describe("DeletedCoValuesEraserScheduler", () => {
6
+ beforeEach(() => {
7
+ vi.useFakeTimers();
8
+ });
9
+
10
+ afterEach(() => {
11
+ vi.clearAllTimers();
12
+ vi.useRealTimers();
13
+ });
14
+
15
+ test("scheduleStartupDrain runs once after startupDelayMs (when idle)", async () => {
16
+ let runs = 0;
17
+ const scheduler = new DeletedCoValuesEraserScheduler({
18
+ run: async () => {
19
+ runs += 1;
20
+ return { hasMore: false };
21
+ },
22
+ opts: { throttleMs: 50, startupDelayMs: 10, followUpDelayMs: 10 },
23
+ });
24
+
25
+ scheduler.scheduleStartupDrain();
26
+
27
+ expect(runs).toBe(0);
28
+ await vi.advanceTimersByTimeAsync(10);
29
+ expect(runs).toBe(1);
30
+ scheduler.dispose();
31
+ });
32
+
33
+ test("onEnqueueDeletedCoValue is throttled (multiple enqueues -> one run)", async () => {
34
+ let runs = 0;
35
+ const scheduler = new DeletedCoValuesEraserScheduler({
36
+ run: async () => {
37
+ runs += 1;
38
+ return { hasMore: false };
39
+ },
40
+ opts: { throttleMs: 30, startupDelayMs: 10, followUpDelayMs: 10 },
41
+ });
42
+
43
+ scheduler.onEnqueueDeletedCoValue();
44
+ scheduler.onEnqueueDeletedCoValue();
45
+ scheduler.onEnqueueDeletedCoValue();
46
+
47
+ expect(runs).toBe(0);
48
+ await vi.advanceTimersByTimeAsync(29);
49
+ expect(runs).toBe(0);
50
+ await vi.advanceTimersByTimeAsync(1);
51
+ expect(runs).toBe(1);
52
+
53
+ // Ensure no second run was scheduled by repeated enqueues in the same throttle window.
54
+ await vi.advanceTimersByTimeAsync(100);
55
+ expect(runs).toBe(1);
56
+
57
+ scheduler.dispose();
58
+ });
59
+
60
+ test("schedules follow-up phases while run reports hasMore=true", async () => {
61
+ let remaining = 3;
62
+ let runs = 0;
63
+ const scheduler = new DeletedCoValuesEraserScheduler({
64
+ run: async () => {
65
+ runs += 1;
66
+ remaining -= 1;
67
+ return { hasMore: remaining > 0 };
68
+ },
69
+ opts: { throttleMs: 10, startupDelayMs: 10, followUpDelayMs: 10 },
70
+ });
71
+
72
+ scheduler.onEnqueueDeletedCoValue();
73
+
74
+ await vi.runAllTimersAsync();
75
+ expect(runs).toBe(3);
76
+ scheduler.dispose();
77
+ });
78
+
79
+ test("never runs run concurrently (re-entrancy guard via internal state machine)", async () => {
80
+ let concurrent = 0;
81
+ let maxConcurrent = 0;
82
+ let remaining = 2;
83
+
84
+ const scheduler = new DeletedCoValuesEraserScheduler({
85
+ run: async () => {
86
+ concurrent += 1;
87
+ maxConcurrent = Math.max(maxConcurrent, concurrent);
88
+
89
+ await new Promise<void>((resolve) => setTimeout(resolve, 30));
90
+ remaining -= 1;
91
+
92
+ concurrent -= 1;
93
+ return { hasMore: remaining > 0 };
94
+ },
95
+ opts: { throttleMs: 10, startupDelayMs: 10, followUpDelayMs: 10 },
96
+ });
97
+
98
+ scheduler.onEnqueueDeletedCoValue();
99
+ await vi.advanceTimersByTimeAsync(10); // start first run
100
+
101
+ // Even if we spam enqueues while active, they should be ignored.
102
+ scheduler.onEnqueueDeletedCoValue();
103
+ scheduler.onEnqueueDeletedCoValue();
104
+
105
+ await vi.runAllTimersAsync();
106
+ expect(remaining).toBe(0);
107
+ expect(maxConcurrent).toBe(1);
108
+
109
+ scheduler.dispose();
110
+ });
111
+
112
+ test("ignores enqueues while not idle, but schedules again once idle", async () => {
113
+ let runs = 0;
114
+ const scheduler = new DeletedCoValuesEraserScheduler({
115
+ run: async () => {
116
+ runs += 1;
117
+ return { hasMore: false };
118
+ },
119
+ opts: { throttleMs: 30, startupDelayMs: 10, followUpDelayMs: 10 },
120
+ });
121
+
122
+ scheduler.onEnqueueDeletedCoValue(); // schedules first run
123
+ await vi.advanceTimersByTimeAsync(5);
124
+ scheduler.onEnqueueDeletedCoValue(); // should be ignored (not idle)
125
+
126
+ await vi.advanceTimersByTimeAsync(25);
127
+ expect(runs).toBe(1);
128
+
129
+ // Now idle again; next enqueue should schedule another run.
130
+ scheduler.onEnqueueDeletedCoValue();
131
+ await vi.advanceTimersByTimeAsync(30);
132
+ expect(runs).toBe(2);
133
+
134
+ scheduler.dispose();
135
+ });
136
+
137
+ test("dispose cancels any scheduled run", async () => {
138
+ let runs = 0;
139
+ const scheduler = new DeletedCoValuesEraserScheduler({
140
+ run: async () => {
141
+ runs += 1;
142
+ return { hasMore: false };
143
+ },
144
+ opts: { throttleMs: 30, startupDelayMs: 10, followUpDelayMs: 10 },
145
+ });
146
+
147
+ scheduler.onEnqueueDeletedCoValue();
148
+ scheduler.dispose();
149
+
150
+ await vi.advanceTimersByTimeAsync(60);
151
+ expect(runs).toBe(0);
152
+ });
153
+
154
+ test("recovers when run throws (logs error and returns to idle so it can run again)", async () => {
155
+ const err = new Error("boom");
156
+ const errorSpy = vi.spyOn(logger, "error").mockImplementation(() => {});
157
+
158
+ let runs = 0;
159
+ const scheduler = new DeletedCoValuesEraserScheduler({
160
+ run: async () => {
161
+ runs += 1;
162
+ if (runs === 1) throw err;
163
+ return { hasMore: false };
164
+ },
165
+ opts: { throttleMs: 10, startupDelayMs: 10, followUpDelayMs: 10 },
166
+ });
167
+
168
+ scheduler.onEnqueueDeletedCoValue();
169
+ await vi.advanceTimersByTimeAsync(10);
170
+ expect(runs).toBe(1);
171
+
172
+ expect(errorSpy).toHaveBeenCalledWith(
173
+ "Error running deleted co values eraser scheduler",
174
+ expect.objectContaining({ err }),
175
+ );
176
+
177
+ // If the scheduler didn't reset back to idle after the error, this enqueue would be ignored.
178
+ scheduler.onEnqueueDeletedCoValue();
179
+ await vi.advanceTimersByTimeAsync(10);
180
+ expect(runs).toBe(2);
181
+
182
+ scheduler.dispose();
183
+ errorSpy.mockRestore();
184
+ });
185
+ });
@@ -205,6 +205,8 @@ describe("garbage collector", () => {
205
205
  });
206
206
 
207
207
  test("coValues are not garbage collected if the maxAge is not reached", async () => {
208
+ vi.useFakeTimers();
209
+
208
210
  setGarbageCollectorMaxAge(1000);
209
211
 
210
212
  const client = setupTestNode();
@@ -212,37 +214,31 @@ describe("garbage collector", () => {
212
214
  client.addStorage({
213
215
  ourName: "client",
214
216
  });
215
- client.connectToSyncServer();
216
217
  client.node.enableGarbageCollector();
217
218
 
218
219
  const garbageCollector = client.node.garbageCollector;
219
220
 
220
221
  assert(garbageCollector);
221
222
 
222
- const getCurrentTime = vi.spyOn(garbageCollector, "getCurrentTime");
223
-
224
- getCurrentTime.mockReturnValue(1);
223
+ await vi.advanceTimersByTimeAsync(100);
225
224
 
226
225
  const group = client.node.createGroup();
227
226
  const map1 = group.createMap();
228
227
  const map2 = group.createMap();
229
228
 
230
- await new Promise((resolve) => setTimeout(resolve, 10));
229
+ await vi.advanceTimersByTimeAsync(800);
231
230
 
231
+ // Access map1 again, to prevent it from being garbage collected
232
232
  map1.set("hello", "world", "trusting");
233
233
 
234
- getCurrentTime.mockReturnValue(2000);
235
-
236
- await new Promise((resolve) => setTimeout(resolve, 10));
234
+ await vi.advanceTimersByTimeAsync(300);
237
235
 
238
236
  garbageCollector.collect();
239
237
 
240
238
  const coValue = client.node.getCoValue(map1.id);
241
-
242
239
  expect(coValue.isAvailable()).toBe(true);
243
240
 
244
241
  const coValue2 = client.node.getCoValue(map2.id);
245
-
246
242
  expect(coValue2.isAvailable()).toBe(false);
247
243
  });
248
244
  });