tinybase 9.4.0-beta.1 → 9.4.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 (239) hide show
  1. package/@types/persisters/index.d.ts +4 -0
  2. package/@types/persisters/persister-durable-object-sql-storage/index.d.ts +9 -2
  3. package/@types/persisters/persister-durable-object-sql-storage/with-schemas/index.d.ts +9 -2
  4. package/@types/persisters/with-schemas/index.d.ts +4 -0
  5. package/@types/queries/index.d.ts +4 -0
  6. package/@types/queries/with-schemas/index.d.ts +4 -0
  7. package/@types/synchronizers/synchronizer-ws-client/index.d.ts +7 -3
  8. package/@types/synchronizers/synchronizer-ws-client/with-schemas/index.d.ts +7 -3
  9. package/@types/synchronizers/synchronizer-ws-server/index.d.ts +9 -3
  10. package/@types/synchronizers/synchronizer-ws-server/with-schemas/index.d.ts +9 -3
  11. package/@types/synchronizers/synchronizer-ws-server-simple/index.d.ts +6 -3
  12. package/@types/synchronizers/synchronizer-ws-server-simple/with-schemas/index.d.ts +6 -3
  13. package/@types/ui-react-dom/index.d.ts +10 -10
  14. package/@types/ui-react-dom/with-schemas/index.d.ts +10 -10
  15. package/@types/ui-react-dom-charts/index.d.ts +7 -7
  16. package/@types/ui-react-dom-charts/with-schemas/index.d.ts +7 -7
  17. package/@types/ui-react-inspector/index.d.ts +1 -1
  18. package/@types/ui-react-inspector/with-schemas/index.d.ts +1 -1
  19. package/@types/ui-solid-dom/index.d.ts +10 -10
  20. package/@types/ui-solid-dom/with-schemas/index.d.ts +10 -10
  21. package/@types/ui-solid-inspector/index.d.ts +1 -1
  22. package/@types/ui-solid-inspector/with-schemas/index.d.ts +1 -1
  23. package/@types/ui-svelte-dom/index.d.ts +10 -10
  24. package/@types/ui-svelte-dom/with-schemas/index.d.ts +10 -10
  25. package/@types/ui-svelte-inspector/index.d.ts +1 -1
  26. package/@types/ui-svelte-inspector/with-schemas/index.d.ts +1 -1
  27. package/index.js +191 -74
  28. package/min/index.js +1 -1
  29. package/min/index.js.gz +0 -0
  30. package/min/omni/index.js +1 -1
  31. package/min/omni/index.js.gz +0 -0
  32. package/min/omni/with-schemas/index.js +1 -1
  33. package/min/omni/with-schemas/index.js.gz +0 -0
  34. package/min/persisters/index.js +1 -1
  35. package/min/persisters/index.js.gz +0 -0
  36. package/min/persisters/persister-automerge/index.js +1 -1
  37. package/min/persisters/persister-automerge/index.js.gz +0 -0
  38. package/min/persisters/persister-automerge/with-schemas/index.js +1 -1
  39. package/min/persisters/persister-automerge/with-schemas/index.js.gz +0 -0
  40. package/min/persisters/persister-browser/index.js +1 -1
  41. package/min/persisters/persister-browser/index.js.gz +0 -0
  42. package/min/persisters/persister-browser/with-schemas/index.js +1 -1
  43. package/min/persisters/persister-browser/with-schemas/index.js.gz +0 -0
  44. package/min/persisters/persister-cr-sqlite-wasm/index.js +1 -1
  45. package/min/persisters/persister-cr-sqlite-wasm/index.js.gz +0 -0
  46. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +1 -1
  47. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js.gz +0 -0
  48. package/min/persisters/persister-durable-object-sql-storage/index.js +1 -1
  49. package/min/persisters/persister-durable-object-sql-storage/index.js.gz +0 -0
  50. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js +1 -1
  51. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js.gz +0 -0
  52. package/min/persisters/persister-durable-object-storage/index.js +1 -1
  53. package/min/persisters/persister-durable-object-storage/index.js.gz +0 -0
  54. package/min/persisters/persister-durable-object-storage/with-schemas/index.js +1 -1
  55. package/min/persisters/persister-durable-object-storage/with-schemas/index.js.gz +0 -0
  56. package/min/persisters/persister-electric-sql/index.js +1 -1
  57. package/min/persisters/persister-electric-sql/index.js.gz +0 -0
  58. package/min/persisters/persister-electric-sql/with-schemas/index.js +1 -1
  59. package/min/persisters/persister-electric-sql/with-schemas/index.js.gz +0 -0
  60. package/min/persisters/persister-expo-sqlite/index.js +1 -1
  61. package/min/persisters/persister-expo-sqlite/index.js.gz +0 -0
  62. package/min/persisters/persister-expo-sqlite/with-schemas/index.js +1 -1
  63. package/min/persisters/persister-expo-sqlite/with-schemas/index.js.gz +0 -0
  64. package/min/persisters/persister-file/index.js +1 -1
  65. package/min/persisters/persister-file/index.js.gz +0 -0
  66. package/min/persisters/persister-file/with-schemas/index.js +1 -1
  67. package/min/persisters/persister-file/with-schemas/index.js.gz +0 -0
  68. package/min/persisters/persister-indexed-db/index.js +1 -1
  69. package/min/persisters/persister-indexed-db/index.js.gz +0 -0
  70. package/min/persisters/persister-indexed-db/with-schemas/index.js +1 -1
  71. package/min/persisters/persister-indexed-db/with-schemas/index.js.gz +0 -0
  72. package/min/persisters/persister-libsql/index.js +1 -1
  73. package/min/persisters/persister-libsql/index.js.gz +0 -0
  74. package/min/persisters/persister-libsql/with-schemas/index.js +1 -1
  75. package/min/persisters/persister-libsql/with-schemas/index.js.gz +0 -0
  76. package/min/persisters/persister-partykit-client/index.js +1 -1
  77. package/min/persisters/persister-partykit-client/index.js.gz +0 -0
  78. package/min/persisters/persister-partykit-client/with-schemas/index.js +1 -1
  79. package/min/persisters/persister-partykit-client/with-schemas/index.js.gz +0 -0
  80. package/min/persisters/persister-pglite/index.js +1 -1
  81. package/min/persisters/persister-pglite/index.js.gz +0 -0
  82. package/min/persisters/persister-pglite/with-schemas/index.js +1 -1
  83. package/min/persisters/persister-pglite/with-schemas/index.js.gz +0 -0
  84. package/min/persisters/persister-postgres/index.js +1 -1
  85. package/min/persisters/persister-postgres/index.js.gz +0 -0
  86. package/min/persisters/persister-postgres/with-schemas/index.js +1 -1
  87. package/min/persisters/persister-postgres/with-schemas/index.js.gz +0 -0
  88. package/min/persisters/persister-powersync/index.js +1 -1
  89. package/min/persisters/persister-powersync/index.js.gz +0 -0
  90. package/min/persisters/persister-powersync/with-schemas/index.js +1 -1
  91. package/min/persisters/persister-powersync/with-schemas/index.js.gz +0 -0
  92. package/min/persisters/persister-react-native-mmkv/index.js +1 -1
  93. package/min/persisters/persister-react-native-mmkv/index.js.gz +0 -0
  94. package/min/persisters/persister-react-native-mmkv/with-schemas/index.js +1 -1
  95. package/min/persisters/persister-react-native-mmkv/with-schemas/index.js.gz +0 -0
  96. package/min/persisters/persister-react-native-sqlite/index.js +1 -1
  97. package/min/persisters/persister-react-native-sqlite/index.js.gz +0 -0
  98. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js +1 -1
  99. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js.gz +0 -0
  100. package/min/persisters/persister-remote/index.js +1 -1
  101. package/min/persisters/persister-remote/index.js.gz +0 -0
  102. package/min/persisters/persister-remote/with-schemas/index.js +1 -1
  103. package/min/persisters/persister-remote/with-schemas/index.js.gz +0 -0
  104. package/min/persisters/persister-sqlite-bun/index.js +1 -1
  105. package/min/persisters/persister-sqlite-bun/index.js.gz +0 -0
  106. package/min/persisters/persister-sqlite-bun/with-schemas/index.js +1 -1
  107. package/min/persisters/persister-sqlite-bun/with-schemas/index.js.gz +0 -0
  108. package/min/persisters/persister-sqlite-wasm/index.js +1 -1
  109. package/min/persisters/persister-sqlite-wasm/index.js.gz +0 -0
  110. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js +1 -1
  111. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js.gz +0 -0
  112. package/min/persisters/persister-sqlite3/index.js +1 -1
  113. package/min/persisters/persister-sqlite3/index.js.gz +0 -0
  114. package/min/persisters/persister-sqlite3/with-schemas/index.js +1 -1
  115. package/min/persisters/persister-sqlite3/with-schemas/index.js.gz +0 -0
  116. package/min/persisters/persister-yjs/index.js +1 -1
  117. package/min/persisters/persister-yjs/index.js.gz +0 -0
  118. package/min/persisters/persister-yjs/with-schemas/index.js +1 -1
  119. package/min/persisters/persister-yjs/with-schemas/index.js.gz +0 -0
  120. package/min/persisters/with-schemas/index.js +1 -1
  121. package/min/persisters/with-schemas/index.js.gz +0 -0
  122. package/min/queries/index.js +1 -1
  123. package/min/queries/index.js.gz +0 -0
  124. package/min/queries/with-schemas/index.js +1 -1
  125. package/min/queries/with-schemas/index.js.gz +0 -0
  126. package/min/synchronizers/index.js +1 -1
  127. package/min/synchronizers/index.js.gz +0 -0
  128. package/min/synchronizers/synchronizer-broadcast-channel/index.js +1 -1
  129. package/min/synchronizers/synchronizer-broadcast-channel/index.js.gz +0 -0
  130. package/min/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js +1 -1
  131. package/min/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js.gz +0 -0
  132. package/min/synchronizers/synchronizer-local/index.js +1 -1
  133. package/min/synchronizers/synchronizer-local/index.js.gz +0 -0
  134. package/min/synchronizers/synchronizer-local/with-schemas/index.js +1 -1
  135. package/min/synchronizers/synchronizer-local/with-schemas/index.js.gz +0 -0
  136. package/min/synchronizers/synchronizer-ws-client/index.js +1 -1
  137. package/min/synchronizers/synchronizer-ws-client/index.js.gz +0 -0
  138. package/min/synchronizers/synchronizer-ws-client/with-schemas/index.js +1 -1
  139. package/min/synchronizers/synchronizer-ws-client/with-schemas/index.js.gz +0 -0
  140. package/min/synchronizers/synchronizer-ws-server/index.js +1 -1
  141. package/min/synchronizers/synchronizer-ws-server/index.js.gz +0 -0
  142. package/min/synchronizers/synchronizer-ws-server/with-schemas/index.js +1 -1
  143. package/min/synchronizers/synchronizer-ws-server/with-schemas/index.js.gz +0 -0
  144. package/min/synchronizers/synchronizer-ws-server-durable-object/index.js +1 -1
  145. package/min/synchronizers/synchronizer-ws-server-durable-object/index.js.gz +0 -0
  146. package/min/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +1 -1
  147. package/min/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js.gz +0 -0
  148. package/min/synchronizers/synchronizer-ws-server-simple/index.js +1 -1
  149. package/min/synchronizers/synchronizer-ws-server-simple/index.js.gz +0 -0
  150. package/min/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js +1 -1
  151. package/min/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js.gz +0 -0
  152. package/min/synchronizers/with-schemas/index.js +1 -1
  153. package/min/synchronizers/with-schemas/index.js.gz +0 -0
  154. package/min/ui-react-inspector/index.js +1 -1
  155. package/min/ui-react-inspector/index.js.gz +0 -0
  156. package/min/ui-react-inspector/with-schemas/index.js +1 -1
  157. package/min/ui-react-inspector/with-schemas/index.js.gz +0 -0
  158. package/min/ui-solid-inspector/index.js +1 -1
  159. package/min/ui-solid-inspector/index.js.gz +0 -0
  160. package/min/ui-solid-inspector/with-schemas/index.js +1 -1
  161. package/min/ui-solid-inspector/with-schemas/index.js.gz +0 -0
  162. package/min/ui-svelte-inspector/index.js +1 -1
  163. package/min/ui-svelte-inspector/index.js.gz +0 -0
  164. package/min/ui-svelte-inspector/with-schemas/index.js +1 -1
  165. package/min/ui-svelte-inspector/with-schemas/index.js.gz +0 -0
  166. package/min/with-schemas/index.js +1 -1
  167. package/min/with-schemas/index.js.gz +0 -0
  168. package/omni/index.js +606 -179
  169. package/omni/with-schemas/index.js +606 -179
  170. package/package.json +12 -8
  171. package/persisters/index.js +49 -10
  172. package/persisters/persister-automerge/index.js +29 -5
  173. package/persisters/persister-automerge/with-schemas/index.js +29 -5
  174. package/persisters/persister-browser/index.js +29 -5
  175. package/persisters/persister-browser/with-schemas/index.js +29 -5
  176. package/persisters/persister-cr-sqlite-wasm/index.js +29 -5
  177. package/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +29 -5
  178. package/persisters/persister-durable-object-sql-storage/index.js +44 -8
  179. package/persisters/persister-durable-object-sql-storage/with-schemas/index.js +44 -8
  180. package/persisters/persister-durable-object-storage/index.js +31 -5
  181. package/persisters/persister-durable-object-storage/with-schemas/index.js +31 -5
  182. package/persisters/persister-electric-sql/index.js +29 -5
  183. package/persisters/persister-electric-sql/with-schemas/index.js +29 -5
  184. package/persisters/persister-expo-sqlite/index.js +29 -5
  185. package/persisters/persister-expo-sqlite/with-schemas/index.js +29 -5
  186. package/persisters/persister-file/index.js +31 -5
  187. package/persisters/persister-file/with-schemas/index.js +31 -5
  188. package/persisters/persister-indexed-db/index.js +29 -5
  189. package/persisters/persister-indexed-db/with-schemas/index.js +29 -5
  190. package/persisters/persister-libsql/index.js +29 -5
  191. package/persisters/persister-libsql/with-schemas/index.js +29 -5
  192. package/persisters/persister-partykit-client/index.js +31 -5
  193. package/persisters/persister-partykit-client/with-schemas/index.js +31 -5
  194. package/persisters/persister-pglite/index.js +49 -10
  195. package/persisters/persister-pglite/with-schemas/index.js +49 -10
  196. package/persisters/persister-postgres/index.js +49 -10
  197. package/persisters/persister-postgres/with-schemas/index.js +49 -10
  198. package/persisters/persister-powersync/index.js +29 -5
  199. package/persisters/persister-powersync/with-schemas/index.js +29 -5
  200. package/persisters/persister-react-native-mmkv/index.js +31 -5
  201. package/persisters/persister-react-native-mmkv/with-schemas/index.js +31 -5
  202. package/persisters/persister-react-native-sqlite/index.js +29 -5
  203. package/persisters/persister-react-native-sqlite/with-schemas/index.js +29 -5
  204. package/persisters/persister-remote/index.js +31 -5
  205. package/persisters/persister-remote/with-schemas/index.js +31 -5
  206. package/persisters/persister-sqlite-bun/index.js +29 -5
  207. package/persisters/persister-sqlite-bun/with-schemas/index.js +29 -5
  208. package/persisters/persister-sqlite-wasm/index.js +29 -5
  209. package/persisters/persister-sqlite-wasm/with-schemas/index.js +29 -5
  210. package/persisters/persister-sqlite3/index.js +29 -5
  211. package/persisters/persister-sqlite3/with-schemas/index.js +29 -5
  212. package/persisters/persister-yjs/index.js +29 -5
  213. package/persisters/persister-yjs/with-schemas/index.js +29 -5
  214. package/persisters/with-schemas/index.js +49 -10
  215. package/queries/index.js +205 -74
  216. package/queries/with-schemas/index.js +205 -74
  217. package/readme.md +14 -14
  218. package/releases.md +84 -67
  219. package/synchronizers/index.js +31 -5
  220. package/synchronizers/synchronizer-broadcast-channel/index.js +39 -13
  221. package/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js +39 -13
  222. package/synchronizers/synchronizer-local/index.js +31 -5
  223. package/synchronizers/synchronizer-local/with-schemas/index.js +31 -5
  224. package/synchronizers/synchronizer-ws-client/index.js +220 -61
  225. package/synchronizers/synchronizer-ws-client/with-schemas/index.js +220 -61
  226. package/synchronizers/synchronizer-ws-server/index.js +253 -73
  227. package/synchronizers/synchronizer-ws-server/with-schemas/index.js +253 -73
  228. package/synchronizers/synchronizer-ws-server-durable-object/index.js +88 -40
  229. package/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +88 -40
  230. package/synchronizers/synchronizer-ws-server-simple/index.js +184 -60
  231. package/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js +184 -60
  232. package/synchronizers/with-schemas/index.js +31 -5
  233. package/ui-react-inspector/index.js +29 -5
  234. package/ui-react-inspector/with-schemas/index.js +29 -5
  235. package/ui-solid-inspector/index.js +29 -5
  236. package/ui-solid-inspector/with-schemas/index.js +29 -5
  237. package/ui-svelte-inspector/index.js +29 -5
  238. package/ui-svelte-inspector/with-schemas/index.js +29 -5
  239. package/with-schemas/index.js +191 -74
@@ -248,6 +248,8 @@ const tryCatch = async (action, onError) => {
248
248
  onError?.(error);
249
249
  }
250
250
  };
251
+ const tryCatchIgnore = (action, onIgnoredError) =>
252
+ tryCatch(action, (error) => void tryCatch(() => onIgnoredError?.(error)));
251
253
  const tryCatchSync = (action, onError) => {
252
254
  try {
253
255
  return action();
@@ -291,6 +293,14 @@ const isHlc = (hlc, maxLogicalTime) =>
291
293
  hlc == EMPTY_STRING ||
292
294
  (isString(hlc) && test(HLC, hlc) && decodeHlcTime(hlc) <= maxLogicalTime);
293
295
 
296
+ const setNew = (entryOrEntries) =>
297
+ new Set(
298
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
299
+ ? entryOrEntries
300
+ : [entryOrEntries],
301
+ );
302
+ const setAdd = (set, value) => set?.add(value);
303
+
294
304
  const MESSAGE_SEPARATOR = '\n';
295
305
  const FRAGMENT = /^([-0-9A-Z_a-z]{16})\n(\d+)\n(\d+)\n([\s\S]*)$/;
296
306
  const FRAGMENT_PAYLOAD = /^[^\n]*\n[-0-9A-Z_a-z]{16}\n\d+\n\d+\n/;
@@ -423,21 +433,30 @@ const createPayloadDecoder = (
423
433
  receive,
424
434
  fragmentTimeoutSeconds = 1,
425
435
  onInvalid,
436
+ sharedBuffer,
426
437
  ) => {
427
438
  const buffer = mapNew();
439
+ const payloadBuffer = [0, 0];
428
440
  let bufferedSize = 0;
429
441
  let valid = true;
430
442
  const delPending = (bufferKey, pending) => {
431
443
  stopTimeout(pending[4]);
432
444
  bufferedSize -= pending[5];
445
+ payloadBuffer[0]--;
446
+ payloadBuffer[1] -= pending[5];
433
447
  collDel(buffer, bufferKey);
434
448
  };
449
+ const clear = () => {
450
+ mapForEach(buffer, (_bufferKey, pending) => stopTimeout(pending[4]));
451
+ payloadBuffer[0] -= collSize(buffer);
452
+ payloadBuffer[1] -= bufferedSize;
453
+ collClear(buffer);
454
+ bufferedSize = 0;
455
+ };
435
456
  const invalid = (error = errorNew(ERROR_SYNC_MESSAGE)) => {
436
457
  if (valid) {
437
458
  valid = false;
438
- mapForEach(buffer, (_bufferKey, pending) => stopTimeout(pending[4]));
439
- collClear(buffer);
440
- bufferedSize = 0;
459
+ clear();
441
460
  onInvalid?.(error);
442
461
  }
443
462
  };
@@ -449,7 +468,7 @@ const createPayloadDecoder = (
449
468
  invalid();
450
469
  }
451
470
  };
452
- return (payload) => {
471
+ const decode = (payload) => {
453
472
  if (!valid) {
454
473
  return;
455
474
  }
@@ -482,42 +501,52 @@ const createPayloadDecoder = (
482
501
  const bufferKey = clientId + MESSAGE_SEPARATOR + messageId;
483
502
  let pending = mapGet(buffer, bufferKey);
484
503
  if (!pending) {
485
- if (collSize(buffer) >= MAX_FRAGMENT_BUFFERS) {
504
+ if (payloadBuffer[0] >= MAX_FRAGMENT_BUFFERS) {
486
505
  invalid(errorNew(ERROR_SYNC_OVERFLOW, 'fragments'));
487
506
  return;
488
507
  }
489
- pending = [
490
- [],
491
- [],
492
- total,
493
- total,
494
- startTimeout(() => {
495
- const timedOut = mapGet(buffer, bufferKey);
496
- if (timedOut) {
497
- delPending(bufferKey, timedOut);
498
- }
499
- }, fragmentTimeoutSeconds),
500
- 0,
501
- ];
502
- mapSet(buffer, bufferKey, pending);
503
508
  }
504
- const [fragments, remainders] = pending;
505
- if (total == pending[3] && isUndefined(fragments[index])) {
506
- const fragmentLength = getWebSocketPayloadSize(fragment);
507
- if (bufferedSize + fragmentLength > MAX_WEBSOCKET_BUFFER_SIZE) {
509
+ if (
510
+ (isUndefined(pending) || total == pending[3]) &&
511
+ isUndefined(pending?.[0][index])
512
+ ) {
513
+ const retainedSize =
514
+ getWebSocketPayloadSize(remainder) +
515
+ (pending ? 0 : getWebSocketPayloadSize(bufferKey));
516
+ if (payloadBuffer[1] + retainedSize > MAX_WEBSOCKET_BUFFER_SIZE) {
508
517
  invalid(errorNew(ERROR_SYNC_OVERFLOW, 'fragments'));
509
518
  return;
510
519
  }
520
+ if (!pending) {
521
+ pending = [
522
+ [],
523
+ [],
524
+ total,
525
+ total,
526
+ startTimeout(() => {
527
+ const timedOut = mapGet(buffer, bufferKey);
528
+ if (timedOut) {
529
+ delPending(bufferKey, timedOut);
530
+ }
531
+ }, fragmentTimeoutSeconds),
532
+ 0,
533
+ ];
534
+ mapSet(buffer, bufferKey, pending);
535
+ payloadBuffer[0]++;
536
+ }
537
+ const [fragments, remainders] = pending;
511
538
  fragments[index] = fragment;
512
539
  remainders[index] = remainder;
513
540
  pending[2]--;
514
- pending[5] += fragmentLength;
515
- bufferedSize += fragmentLength;
541
+ pending[5] += retainedSize;
542
+ bufferedSize += retainedSize;
543
+ payloadBuffer[1] += retainedSize;
516
544
  } else {
517
545
  invalid();
518
546
  return;
519
547
  }
520
548
  if (pending[2] == 0) {
549
+ const [fragments, remainders] = pending;
521
550
  delPending(bufferKey, pending);
522
551
  receiveRemainder(clientId, remainders, arrayJoin(fragments));
523
552
  }
@@ -530,11 +559,13 @@ const createPayloadDecoder = (
530
559
  invalid();
531
560
  }
532
561
  };
562
+ return [decode, clear];
533
563
  };
534
564
  const createPayloadReceiver = (
535
565
  receive,
536
566
  fragmentTimeoutSeconds = 1,
537
567
  onInvalid,
568
+ sharedBuffer,
538
569
  ) =>
539
570
  createPayloadDecoder(
540
571
  (fromClientId, _remainders, requestId, message, body) =>
@@ -621,14 +652,6 @@ const getPoolFunctions = () => {
621
652
  ];
622
653
  };
623
654
 
624
- const setNew = (entryOrEntries) =>
625
- new Set(
626
- isArray(entryOrEntries) || isUndefined(entryOrEntries)
627
- ? entryOrEntries
628
- : [entryOrEntries],
629
- );
630
- const setAdd = (set, value) => set?.add(value);
631
-
632
655
  const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
633
656
  const leaves = [];
634
657
  const deep = (node, p) =>
@@ -1053,11 +1076,35 @@ const createCustomPersister = (
1053
1076
  initialContent,
1054
1077
  startSaveFirst = false,
1055
1078
  ) => {
1056
- const [call1, call2] = startSaveFirst
1057
- ? [startAutoSave, startAutoLoad]
1058
- : [startAutoLoad, startAutoSave];
1059
- await call1(initialContent);
1060
- await call2(initialContent);
1079
+ const [call1, call2, stop1, stop2] = startSaveFirst
1080
+ ? [startAutoSave, startAutoLoad, stopAutoSave, stopAutoLoad]
1081
+ : [startAutoLoad, startAutoSave, stopAutoLoad, stopAutoSave];
1082
+ const start1 = call1(initialContent);
1083
+ const generation1 = startSaveFirst
1084
+ ? autoSaveGeneration
1085
+ : autoLoadGeneration;
1086
+ await start1;
1087
+ const start2 = call2(initialContent);
1088
+ const generation2 = startSaveFirst
1089
+ ? autoLoadGeneration
1090
+ : autoSaveGeneration;
1091
+ try {
1092
+ await start2;
1093
+ } catch (error) {
1094
+ if (
1095
+ generation2 ==
1096
+ (startSaveFirst ? autoLoadGeneration : autoSaveGeneration)
1097
+ ) {
1098
+ await tryCatchIgnore(stop2);
1099
+ }
1100
+ if (
1101
+ generation1 ==
1102
+ (startSaveFirst ? autoSaveGeneration : autoLoadGeneration)
1103
+ ) {
1104
+ await tryCatchIgnore(stop1);
1105
+ }
1106
+ throw error;
1107
+ }
1061
1108
  return persister;
1062
1109
  };
1063
1110
  const stopAutoPersisting = async (stopSaveFirst = false) => {
@@ -1478,7 +1525,7 @@ class WsServerDurableObject extends DurableObject {
1478
1525
  (this.#serverClientSend = createPayloadReceiver(
1479
1526
  receive,
1480
1527
  requestTimeoutSeconds,
1481
- )),
1528
+ )[0]),
1482
1529
  noop,
1483
1530
  requestTimeoutSeconds,
1484
1531
  );
@@ -1526,10 +1573,11 @@ class WsServerDurableObject extends DurableObject {
1526
1573
  );
1527
1574
  this.#payloadDecoders.set(client, decode);
1528
1575
  }
1529
- decode(message.toString());
1576
+ decode[0](message.toString());
1530
1577
  });
1531
1578
  }
1532
1579
  webSocketClose(client) {
1580
+ this.#payloadDecoders.get(client)?.[1]();
1533
1581
  this.#payloadDecoders.delete(client);
1534
1582
  const [clientId, pathId] = this.ctx.getTags(client);
1535
1583
  this.onClientId(pathId, clientId, -1);
@@ -248,6 +248,8 @@ const tryCatch = async (action, onError) => {
248
248
  onError?.(error);
249
249
  }
250
250
  };
251
+ const tryCatchIgnore = (action, onIgnoredError) =>
252
+ tryCatch(action, (error) => void tryCatch(() => onIgnoredError?.(error)));
251
253
  const tryCatchSync = (action, onError) => {
252
254
  try {
253
255
  return action();
@@ -291,6 +293,14 @@ const isHlc = (hlc, maxLogicalTime) =>
291
293
  hlc == EMPTY_STRING ||
292
294
  (isString(hlc) && test(HLC, hlc) && decodeHlcTime(hlc) <= maxLogicalTime);
293
295
 
296
+ const setNew = (entryOrEntries) =>
297
+ new Set(
298
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
299
+ ? entryOrEntries
300
+ : [entryOrEntries],
301
+ );
302
+ const setAdd = (set, value) => set?.add(value);
303
+
294
304
  const MESSAGE_SEPARATOR = '\n';
295
305
  const FRAGMENT = /^([-0-9A-Z_a-z]{16})\n(\d+)\n(\d+)\n([\s\S]*)$/;
296
306
  const FRAGMENT_PAYLOAD = /^[^\n]*\n[-0-9A-Z_a-z]{16}\n\d+\n\d+\n/;
@@ -423,21 +433,30 @@ const createPayloadDecoder = (
423
433
  receive,
424
434
  fragmentTimeoutSeconds = 1,
425
435
  onInvalid,
436
+ sharedBuffer,
426
437
  ) => {
427
438
  const buffer = mapNew();
439
+ const payloadBuffer = [0, 0];
428
440
  let bufferedSize = 0;
429
441
  let valid = true;
430
442
  const delPending = (bufferKey, pending) => {
431
443
  stopTimeout(pending[4]);
432
444
  bufferedSize -= pending[5];
445
+ payloadBuffer[0]--;
446
+ payloadBuffer[1] -= pending[5];
433
447
  collDel(buffer, bufferKey);
434
448
  };
449
+ const clear = () => {
450
+ mapForEach(buffer, (_bufferKey, pending) => stopTimeout(pending[4]));
451
+ payloadBuffer[0] -= collSize(buffer);
452
+ payloadBuffer[1] -= bufferedSize;
453
+ collClear(buffer);
454
+ bufferedSize = 0;
455
+ };
435
456
  const invalid = (error = errorNew(ERROR_SYNC_MESSAGE)) => {
436
457
  if (valid) {
437
458
  valid = false;
438
- mapForEach(buffer, (_bufferKey, pending) => stopTimeout(pending[4]));
439
- collClear(buffer);
440
- bufferedSize = 0;
459
+ clear();
441
460
  onInvalid?.(error);
442
461
  }
443
462
  };
@@ -449,7 +468,7 @@ const createPayloadDecoder = (
449
468
  invalid();
450
469
  }
451
470
  };
452
- return (payload) => {
471
+ const decode = (payload) => {
453
472
  if (!valid) {
454
473
  return;
455
474
  }
@@ -482,42 +501,52 @@ const createPayloadDecoder = (
482
501
  const bufferKey = clientId + MESSAGE_SEPARATOR + messageId;
483
502
  let pending = mapGet(buffer, bufferKey);
484
503
  if (!pending) {
485
- if (collSize(buffer) >= MAX_FRAGMENT_BUFFERS) {
504
+ if (payloadBuffer[0] >= MAX_FRAGMENT_BUFFERS) {
486
505
  invalid(errorNew(ERROR_SYNC_OVERFLOW, 'fragments'));
487
506
  return;
488
507
  }
489
- pending = [
490
- [],
491
- [],
492
- total,
493
- total,
494
- startTimeout(() => {
495
- const timedOut = mapGet(buffer, bufferKey);
496
- if (timedOut) {
497
- delPending(bufferKey, timedOut);
498
- }
499
- }, fragmentTimeoutSeconds),
500
- 0,
501
- ];
502
- mapSet(buffer, bufferKey, pending);
503
508
  }
504
- const [fragments, remainders] = pending;
505
- if (total == pending[3] && isUndefined(fragments[index])) {
506
- const fragmentLength = getWebSocketPayloadSize(fragment);
507
- if (bufferedSize + fragmentLength > MAX_WEBSOCKET_BUFFER_SIZE) {
509
+ if (
510
+ (isUndefined(pending) || total == pending[3]) &&
511
+ isUndefined(pending?.[0][index])
512
+ ) {
513
+ const retainedSize =
514
+ getWebSocketPayloadSize(remainder) +
515
+ (pending ? 0 : getWebSocketPayloadSize(bufferKey));
516
+ if (payloadBuffer[1] + retainedSize > MAX_WEBSOCKET_BUFFER_SIZE) {
508
517
  invalid(errorNew(ERROR_SYNC_OVERFLOW, 'fragments'));
509
518
  return;
510
519
  }
520
+ if (!pending) {
521
+ pending = [
522
+ [],
523
+ [],
524
+ total,
525
+ total,
526
+ startTimeout(() => {
527
+ const timedOut = mapGet(buffer, bufferKey);
528
+ if (timedOut) {
529
+ delPending(bufferKey, timedOut);
530
+ }
531
+ }, fragmentTimeoutSeconds),
532
+ 0,
533
+ ];
534
+ mapSet(buffer, bufferKey, pending);
535
+ payloadBuffer[0]++;
536
+ }
537
+ const [fragments, remainders] = pending;
511
538
  fragments[index] = fragment;
512
539
  remainders[index] = remainder;
513
540
  pending[2]--;
514
- pending[5] += fragmentLength;
515
- bufferedSize += fragmentLength;
541
+ pending[5] += retainedSize;
542
+ bufferedSize += retainedSize;
543
+ payloadBuffer[1] += retainedSize;
516
544
  } else {
517
545
  invalid();
518
546
  return;
519
547
  }
520
548
  if (pending[2] == 0) {
549
+ const [fragments, remainders] = pending;
521
550
  delPending(bufferKey, pending);
522
551
  receiveRemainder(clientId, remainders, arrayJoin(fragments));
523
552
  }
@@ -530,11 +559,13 @@ const createPayloadDecoder = (
530
559
  invalid();
531
560
  }
532
561
  };
562
+ return [decode, clear];
533
563
  };
534
564
  const createPayloadReceiver = (
535
565
  receive,
536
566
  fragmentTimeoutSeconds = 1,
537
567
  onInvalid,
568
+ sharedBuffer,
538
569
  ) =>
539
570
  createPayloadDecoder(
540
571
  (fromClientId, _remainders, requestId, message, body) =>
@@ -621,14 +652,6 @@ const getPoolFunctions = () => {
621
652
  ];
622
653
  };
623
654
 
624
- const setNew = (entryOrEntries) =>
625
- new Set(
626
- isArray(entryOrEntries) || isUndefined(entryOrEntries)
627
- ? entryOrEntries
628
- : [entryOrEntries],
629
- );
630
- const setAdd = (set, value) => set?.add(value);
631
-
632
655
  const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
633
656
  const leaves = [];
634
657
  const deep = (node, p) =>
@@ -1053,11 +1076,35 @@ const createCustomPersister = (
1053
1076
  initialContent,
1054
1077
  startSaveFirst = false,
1055
1078
  ) => {
1056
- const [call1, call2] = startSaveFirst
1057
- ? [startAutoSave, startAutoLoad]
1058
- : [startAutoLoad, startAutoSave];
1059
- await call1(initialContent);
1060
- await call2(initialContent);
1079
+ const [call1, call2, stop1, stop2] = startSaveFirst
1080
+ ? [startAutoSave, startAutoLoad, stopAutoSave, stopAutoLoad]
1081
+ : [startAutoLoad, startAutoSave, stopAutoLoad, stopAutoSave];
1082
+ const start1 = call1(initialContent);
1083
+ const generation1 = startSaveFirst
1084
+ ? autoSaveGeneration
1085
+ : autoLoadGeneration;
1086
+ await start1;
1087
+ const start2 = call2(initialContent);
1088
+ const generation2 = startSaveFirst
1089
+ ? autoLoadGeneration
1090
+ : autoSaveGeneration;
1091
+ try {
1092
+ await start2;
1093
+ } catch (error) {
1094
+ if (
1095
+ generation2 ==
1096
+ (startSaveFirst ? autoLoadGeneration : autoSaveGeneration)
1097
+ ) {
1098
+ await tryCatchIgnore(stop2);
1099
+ }
1100
+ if (
1101
+ generation1 ==
1102
+ (startSaveFirst ? autoSaveGeneration : autoLoadGeneration)
1103
+ ) {
1104
+ await tryCatchIgnore(stop1);
1105
+ }
1106
+ throw error;
1107
+ }
1061
1108
  return persister;
1062
1109
  };
1063
1110
  const stopAutoPersisting = async (stopSaveFirst = false) => {
@@ -1478,7 +1525,7 @@ class WsServerDurableObject extends DurableObject {
1478
1525
  (this.#serverClientSend = createPayloadReceiver(
1479
1526
  receive,
1480
1527
  requestTimeoutSeconds,
1481
- )),
1528
+ )[0]),
1482
1529
  noop,
1483
1530
  requestTimeoutSeconds,
1484
1531
  );
@@ -1526,10 +1573,11 @@ class WsServerDurableObject extends DurableObject {
1526
1573
  );
1527
1574
  this.#payloadDecoders.set(client, decode);
1528
1575
  }
1529
- decode(message.toString());
1576
+ decode[0](message.toString());
1530
1577
  });
1531
1578
  }
1532
1579
  webSocketClose(client) {
1580
+ this.#payloadDecoders.get(client)?.[1]();
1533
1581
  this.#payloadDecoders.delete(client);
1534
1582
  const [clientId, pathId] = this.ctx.getTags(client);
1535
1583
  this.onClientId(pathId, clientId, -1);