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
@@ -356,6 +356,7 @@ const ERROR_INDEXED_DB_OPEN = 12;
356
356
  const ERROR_HLC = 13;
357
357
  const ERROR_SYNC_MESSAGE = 14;
358
358
  const ERROR_SYNC_OVERFLOW = 15;
359
+ const ERROR_QUERY_SELECT_ALL_CYCLE = 16;
359
360
  const errorNew = (code, details) =>
360
361
  new Error(
361
362
  TINYBASE +
@@ -4901,11 +4902,35 @@ const createCustomPersister = (
4901
4902
  initialContent,
4902
4903
  startSaveFirst = false,
4903
4904
  ) => {
4904
- const [call1, call2] = startSaveFirst
4905
- ? [startAutoSave, startAutoLoad]
4906
- : [startAutoLoad, startAutoSave];
4907
- await call1(initialContent);
4908
- await call2(initialContent);
4905
+ const [call1, call2, stop1, stop2] = startSaveFirst
4906
+ ? [startAutoSave, startAutoLoad, stopAutoSave, stopAutoLoad]
4907
+ : [startAutoLoad, startAutoSave, stopAutoLoad, stopAutoSave];
4908
+ const start1 = call1(initialContent);
4909
+ const generation1 = startSaveFirst
4910
+ ? autoSaveGeneration
4911
+ : autoLoadGeneration;
4912
+ await start1;
4913
+ const start2 = call2(initialContent);
4914
+ const generation2 = startSaveFirst
4915
+ ? autoLoadGeneration
4916
+ : autoSaveGeneration;
4917
+ try {
4918
+ await start2;
4919
+ } catch (error) {
4920
+ if (
4921
+ generation2 ==
4922
+ (startSaveFirst ? autoLoadGeneration : autoSaveGeneration)
4923
+ ) {
4924
+ await tryCatchIgnore(stop2);
4925
+ }
4926
+ if (
4927
+ generation1 ==
4928
+ (startSaveFirst ? autoSaveGeneration : autoLoadGeneration)
4929
+ ) {
4930
+ await tryCatchIgnore(stop1);
4931
+ }
4932
+ throw error;
4933
+ }
4909
4934
  return persister;
4910
4935
  };
4911
4936
  const stopAutoPersisting = async (stopSaveFirst = false) => {
@@ -5787,6 +5812,8 @@ const createTabularPersister = (
5787
5812
  const TABLE_CREATED = 'c';
5788
5813
  const DATA_CHANGED = 'd';
5789
5814
  const EVENT_REGEX = /^([cd]:)(.+)/;
5815
+ const SIMPLE_TABLE_NAME = /^[A-Za-z0-9_]+$/;
5816
+ const POSTGRES_IDENTIFIER_SIZE = 63;
5790
5817
  const listenerResourcesByThing = mapNew();
5791
5818
  const createCustomPostgreSqlPersister = (
5792
5819
  store,
@@ -5859,17 +5886,30 @@ const createCustomPostgreSqlPersister = (
5859
5886
  );
5860
5887
  const addDataChangedTriggers = (tableName, dataChangedFunction) =>
5861
5888
  promiseAll(
5862
- arrayMap([INSERT, DELETE$1, UPDATE], (action, newOrOldOrBoth) =>
5863
- createTrigger(
5889
+ arrayMap([INSERT, DELETE$1, UPDATE], (action, newOrOldOrBoth) => {
5890
+ const legacyTriggerId = arrayJoin(
5891
+ [TINYBASE, DATA_CHANGED, configHash, tableName, action],
5892
+ '_',
5893
+ );
5894
+ return createTrigger(
5864
5895
  OR_REPLACE,
5865
- escapeIds(TINYBASE, DATA_CHANGED, configHash, tableName, action),
5896
+ test(SIMPLE_TABLE_NAME, tableName) &&
5897
+ size(legacyTriggerId) <= POSTGRES_IDENTIFIER_SIZE
5898
+ ? escapeId(legacyTriggerId)
5899
+ : escapeIds(
5900
+ TINYBASE,
5901
+ DATA_CHANGED,
5902
+ configHash,
5903
+ action,
5904
+ EMPTY_STRING + getHash(tableName),
5905
+ ),
5866
5906
  `AFTER ${action} ON${escapeId(tableName)}FOR EACH ROW WHEN(${when(
5867
5907
  tableName,
5868
5908
  newOrOldOrBoth,
5869
5909
  )})`,
5870
5910
  dataChangedFunction,
5871
- ),
5872
- ),
5911
+ );
5912
+ }),
5873
5913
  );
5874
5914
  const dropFunctions = async (functionNames) => {
5875
5915
  if (!isEmpty(functionNames)) {
@@ -6490,15 +6530,27 @@ const stampNewObjectWithHash$1 = () =>
6490
6530
  stampNewWithHash(objNew(), EMPTY_STRING, 0);
6491
6531
  const escapeGeneratedId = (id) =>
6492
6532
  test(/^[a-zA-Z_][a-zA-Z0-9_]*$/, id) ? id : escapeId(id);
6533
+ const encodeStoragePrefix = (storagePrefix) =>
6534
+ arrayJoin(
6535
+ arrayMap(
6536
+ strSplit(storagePrefix),
6537
+ (character) =>
6538
+ '$' + slice((65536 + character.charCodeAt(0)).toString(16), 1),
6539
+ ),
6540
+ );
6493
6541
  const createDurableObjectFragmentedSqlStoragePersister = (
6494
6542
  store,
6495
6543
  sqlStorage,
6496
6544
  storagePrefix = EMPTY_STRING,
6497
6545
  onIgnoredError,
6498
6546
  ) => {
6499
- const tablePrefix = strReplace(storagePrefix, /[^a-zA-Z0-9_]/g, '_');
6500
- const tablesTable = escapeGeneratedId(`${tablePrefix}tinybase_tables`);
6501
- const valuesTable = escapeGeneratedId(`${tablePrefix}tinybase_values`);
6547
+ const tablePrefix = test(/^[a-z0-9_]*$/, storagePrefix)
6548
+ ? storagePrefix
6549
+ : `$tinybase$${encodeStoragePrefix(storagePrefix)}$`;
6550
+ const tablesTableId = `${tablePrefix}tinybase_tables`;
6551
+ const valuesTableId = `${tablePrefix}tinybase_values`;
6552
+ const tablesTable = escapeGeneratedId(tablesTableId);
6553
+ const valuesTable = escapeGeneratedId(valuesTableId);
6502
6554
  const insertTableSql = `INSERT INTO ${tablesTable} (type, table_id, row_id, cell_id, value_data, timestamp, hash) VALUES (?, ?, ?, ?, ?, ?, ?)`;
6503
6555
  const insertValueSql = `INSERT INTO ${valuesTable} (value_id, value_data, timestamp, hash) VALUES (?, ?, ?, ?)`;
6504
6556
  const getRowKey = (tableId, rowId) => jsonString([tableId, rowId]);
@@ -8231,7 +8283,50 @@ const createQueries = getCreateFunction((store) => {
8231
8283
  const preStoreListenerIds = mapNew();
8232
8284
  const sourceStoreListenerIds = mapNew();
8233
8285
  const selectAllListenerIds = mapNew();
8286
+ const selectAllRetryListenerIds = mapNew();
8287
+ const selectAllQuerySources = mapNew();
8234
8288
  const referencedQueryIds = mapNew();
8289
+ const assertNoMappedSelectAllCycle = (queryId, nextQuerySources) => {
8290
+ const getQuerySources = (sourceQueryId) =>
8291
+ sourceQueryId === queryId
8292
+ ? nextQuerySources
8293
+ : mapGet(selectAllQuerySources, sourceQueryId);
8294
+ const reachesQuery = (
8295
+ sourceQueryId,
8296
+ targetQueryId,
8297
+ visitedQueryIds = setNew(),
8298
+ ) => {
8299
+ if (sourceQueryId === targetQueryId) {
8300
+ return true;
8301
+ }
8302
+ if (collHas(visitedQueryIds, sourceQueryId)) {
8303
+ return false;
8304
+ }
8305
+ setAdd(visitedQueryIds, sourceQueryId);
8306
+ return !collEvery(
8307
+ getQuerySources(sourceQueryId),
8308
+ (_changesCellId, nextQueryId) =>
8309
+ !reachesQuery(nextQueryId, targetQueryId, visitedQueryIds),
8310
+ );
8311
+ };
8312
+ const hasMappedCycle = (sourceQueryId, querySources) =>
8313
+ !collEvery(
8314
+ querySources,
8315
+ (changesCellId, nextQueryId) =>
8316
+ !changesCellId || !reachesQuery(nextQueryId, sourceQueryId),
8317
+ );
8318
+ if (
8319
+ hasMappedCycle(queryId, nextQuerySources) ||
8320
+ !collEvery(
8321
+ selectAllQuerySources,
8322
+ (querySources, sourceQueryId) =>
8323
+ sourceQueryId === queryId ||
8324
+ !hasMappedCycle(sourceQueryId, querySources),
8325
+ )
8326
+ ) {
8327
+ errorThrow(ERROR_QUERY_SELECT_ALL_CYCLE);
8328
+ }
8329
+ };
8235
8330
  const {
8236
8331
  _: [, addListener, callListeners],
8237
8332
  delListener: delListenerImpl,
@@ -8305,6 +8400,30 @@ const createQueries = getCreateFunction((store) => {
8305
8400
  resetStoreListeners(mapGet(sourceStoreListenerIds, queryId));
8306
8401
  mapSet(sourceStoreListenerIds, queryId);
8307
8402
  };
8403
+ const clearSelectAllRetryListeners = (queryId) =>
8404
+ ifNotUndefined(
8405
+ mapGet(selectAllRetryListenerIds, queryId),
8406
+ (listenerIds) => {
8407
+ mapForEach(listenerIds, (sourceStore, listenerIdsByTableId) =>
8408
+ mapForEach(listenerIdsByTableId, (_sourceTableId, listenerId) =>
8409
+ sourceStore.delListener(listenerId),
8410
+ ),
8411
+ );
8412
+ mapSet(selectAllRetryListenerIds, queryId);
8413
+ },
8414
+ );
8415
+ const addSelectAllRetryListener = (queryId, sourceStore, sourceTableId) => {
8416
+ const listenerIdsByTableId = mapEnsure(
8417
+ mapEnsure(selectAllRetryListenerIds, queryId, mapNew),
8418
+ sourceStore,
8419
+ mapNew,
8420
+ );
8421
+ mapEnsure(listenerIdsByTableId, sourceTableId, () =>
8422
+ sourceStore.addTableListener(sourceTableId, () =>
8423
+ setQueryDefinitionImpl(queryId),
8424
+ ),
8425
+ );
8426
+ };
8308
8427
  const syncSelectAllListeners = (queryId, nextSources = mapNew()) => {
8309
8428
  const listenerIds = mapEnsure(selectAllListenerIds, queryId, mapNew);
8310
8429
  mapForEach(listenerIds, (sourceStore, listenerIdsByTableId) => {
@@ -8323,7 +8442,13 @@ const createQueries = getCreateFunction((store) => {
8323
8442
  collForEach(tableIds, (sourceTableId) =>
8324
8443
  mapEnsure(listenerIdsByTableId, sourceTableId, () =>
8325
8444
  sourceStore.addTableCellIdsListener(sourceTableId, () =>
8326
- setQueryDefinitionImpl(queryId),
8445
+ tryCatchSync(
8446
+ () => setQueryDefinitionImpl(queryId),
8447
+ (error) => {
8448
+ addSelectAllRetryListener(queryId, sourceStore, sourceTableId);
8449
+ throw error;
8450
+ },
8451
+ ),
8327
8452
  ),
8328
8453
  ),
8329
8454
  );
@@ -8482,6 +8607,10 @@ const createQueries = getCreateFunction((store) => {
8482
8607
  isFunction(prefixOrMapper)
8483
8608
  ? prefixOrMapper
8484
8609
  : (cellId) => (prefixOrMapper ?? EMPTY_STRING) + cellId,
8610
+ isFunction(prefixOrMapper) ||
8611
+ (!isUndefined(prefixOrMapper) && prefixOrMapper !== EMPTY_STRING)
8612
+ ? 1
8613
+ : 0,
8485
8614
  ]);
8486
8615
  };
8487
8616
  const join = (arg1, arg2, arg3, arg4) => {
@@ -8555,28 +8684,49 @@ const createQueries = getCreateFunction((store) => {
8555
8684
  getSelectedOrGroupedCell(arg1) === arg2,
8556
8685
  );
8557
8686
  build({select, selectAll, join, where, group, having, param});
8558
- resultStore2.delTable(queryId);
8559
- if (isEmpty(selectionEntries)) {
8560
- commit?.();
8561
- return queries;
8562
- }
8563
8687
  const joins = mapNew(joinEntries);
8564
8688
  mapForEach(joins, (joinAlias, [, fromJoinAlias]) =>
8565
8689
  ifNotUndefined(mapGet(joins, fromJoinAlias), ({3: toJoinAliases2}) =>
8566
8690
  isUndefined(joinAlias) ? 0 : arrayPush(toJoinAliases2, joinAlias),
8567
8691
  ),
8568
8692
  );
8569
- const groups = mapNew(groupEntries);
8570
- const hasGroupsOrHavings = !collIsEmpty(groups) || !isEmpty(havings);
8571
- const selectEntries = [];
8572
- const selectAllSources = stagedDefinition[3];
8693
+ const isRootSelectAll = (joinedTableId) => isUndefined(joinedTableId);
8573
8694
  const getSelectAllJoin = (joinedTableId) =>
8574
8695
  mapGet(
8575
8696
  joins,
8576
- isUndefined(joinedTableId) || joinedTableId === tableId
8577
- ? void 0
8578
- : joinedTableId,
8697
+ isRootSelectAll(joinedTableId) ? void 0 : joinedTableId,
8579
8698
  );
8699
+ const nextSelectAllQuerySources = stagedDefinition[5];
8700
+ arrayForEach(
8701
+ selectionEntries,
8702
+ ([selectAll2, selectedOrJoinedTableId, , changesCellId = 0]) =>
8703
+ selectAll2
8704
+ ? ifNotUndefined(
8705
+ getSelectAllJoin(selectedOrJoinedTableId),
8706
+ ([sourceQueryId, , , , , sourceStore]) =>
8707
+ sourceStore === store
8708
+ ? 0
8709
+ : mapSet(
8710
+ nextSelectAllQuerySources,
8711
+ sourceQueryId,
8712
+ mapGet(nextSelectAllQuerySources, sourceQueryId) ||
8713
+ changesCellId
8714
+ ? 1
8715
+ : 0,
8716
+ ),
8717
+ )
8718
+ : 0,
8719
+ );
8720
+ assertNoMappedSelectAllCycle(queryId, nextSelectAllQuerySources);
8721
+ resultStore2.delTable(queryId);
8722
+ if (isEmpty(selectionEntries)) {
8723
+ commit?.();
8724
+ return queries;
8725
+ }
8726
+ const groups = mapNew(groupEntries);
8727
+ const hasGroupsOrHavings = !collIsEmpty(groups) || !isEmpty(havings);
8728
+ const selectEntries = [];
8729
+ const selectAllSources = stagedDefinition[3];
8580
8730
  arrayForEach(
8581
8731
  selectionEntries,
8582
8732
  ([selectAll2, selectedOrJoinedTableId, clauseOrMapper]) => {
@@ -8594,11 +8744,7 @@ const createQueries = getCreateFunction((store) => {
8594
8744
  (cellId) =>
8595
8745
  arrayPush(selectEntries, [
8596
8746
  clauseOrMapper(cellId),
8597
- (getTableCell) =>
8598
- isUndefined(selectedOrJoinedTableId) ||
8599
- selectedOrJoinedTableId === tableId
8600
- ? getTableCell(cellId)
8601
- : getTableCell(selectedOrJoinedTableId, cellId),
8747
+ getUndefined,
8602
8748
  ]),
8603
8749
  );
8604
8750
  },
@@ -8795,67 +8941,74 @@ const createQueries = getCreateFunction((store) => {
8795
8941
  joinedCellId,
8796
8942
  );
8797
8943
  };
8944
+ const writeSelectAllRow = () => {
8945
+ const resultRow = objNew();
8946
+ arrayForEach(
8947
+ selectionEntries,
8948
+ ([selectAll2, selectedOrJoinedTableId, clauseOrMapper]) => {
8949
+ if (selectAll2) {
8950
+ ifNotUndefined(
8951
+ getSelectAllJoin(selectedOrJoinedTableId),
8952
+ ([realTableId, , , , remoteIdPairs, sourceStore]) => {
8953
+ const sourceRowId = isRootSelectAll(
8954
+ selectedOrJoinedTableId,
8955
+ )
8956
+ ? rootRowId
8957
+ : mapGet(remoteIdPairs, rootRowId)?.[0];
8958
+ ifNotUndefined(sourceRowId, (sourceRowId2) =>
8959
+ arrayForEach(
8960
+ arraySort(
8961
+ sourceStore.getCellIds(realTableId, sourceRowId2),
8962
+ ),
8963
+ (cellId) =>
8964
+ objSet(
8965
+ resultRow,
8966
+ clauseOrMapper(cellId),
8967
+ sourceStore.getCell(
8968
+ realTableId,
8969
+ sourceRowId2,
8970
+ cellId,
8971
+ ),
8972
+ ),
8973
+ ),
8974
+ );
8975
+ },
8976
+ );
8977
+ } else {
8978
+ const selectedCell = clauseOrMapper(getJoinCell, rootRowId);
8979
+ const selectedCellId = selectedOrJoinedTableId;
8980
+ if (isUndefined(selectedCell)) {
8981
+ objDel(resultRow, selectedCellId);
8982
+ } else {
8983
+ objSet(resultRow, selectedCellId, selectedCell);
8984
+ }
8985
+ }
8986
+ },
8987
+ );
8988
+ if (objIsEmpty(resultRow)) {
8989
+ selectJoinWhereStore.delRow(queryId, rootRowId);
8990
+ } else {
8991
+ selectJoinWhereStore.setRow(queryId, rootRowId, resultRow);
8992
+ }
8993
+ };
8798
8994
  selectJoinWhereStore.transaction(() => {
8799
8995
  if (!arrayEvery(wheres, (where2) => where2(getJoinCell))) {
8800
8996
  selectJoinWhereStore.delRow(queryId, rootRowId);
8801
8997
  } else if (hasGroupsOrHavings) {
8802
- mapForEach(selects, (asCellId, tableCellGetter) =>
8803
- selectJoinWhereStore._[5](
8804
- queryId,
8805
- rootRowId,
8806
- asCellId,
8807
- tableCellGetter(getJoinCell, rootRowId),
8808
- ),
8809
- );
8810
- } else if (hasSelectAll) {
8811
- const resultRow = objNew();
8812
- arrayForEach(
8813
- selectionEntries,
8814
- ([selectAll2, selectedOrJoinedTableId, clauseOrMapper]) => {
8815
- if (selectAll2) {
8816
- ifNotUndefined(
8817
- getSelectAllJoin(selectedOrJoinedTableId),
8818
- ([realTableId, , , , remoteIdPairs, sourceStore]) => {
8819
- const sourceRowId =
8820
- isUndefined(selectedOrJoinedTableId) ||
8821
- selectedOrJoinedTableId === tableId
8822
- ? rootRowId
8823
- : mapGet(remoteIdPairs, rootRowId)?.[0];
8824
- ifNotUndefined(sourceRowId, (sourceRowId2) =>
8825
- arrayForEach(
8826
- arraySort(
8827
- sourceStore.getCellIds(realTableId, sourceRowId2),
8828
- ),
8829
- (cellId) =>
8830
- objSet(
8831
- resultRow,
8832
- clauseOrMapper(cellId),
8833
- sourceStore.getCell(
8834
- realTableId,
8835
- sourceRowId2,
8836
- cellId,
8837
- ),
8838
- ),
8839
- ),
8840
- );
8841
- },
8842
- );
8843
- } else {
8844
- const selectedCell = clauseOrMapper(getJoinCell, rootRowId);
8845
- const selectedCellId = selectedOrJoinedTableId;
8846
- if (isUndefined(selectedCell)) {
8847
- objDel(resultRow, selectedCellId);
8848
- } else {
8849
- objSet(resultRow, selectedCellId, selectedCell);
8850
- }
8851
- }
8852
- },
8853
- );
8854
- if (objIsEmpty(resultRow)) {
8855
- selectJoinWhereStore.delRow(queryId, rootRowId);
8998
+ if (hasSelectAll) {
8999
+ writeSelectAllRow();
8856
9000
  } else {
8857
- selectJoinWhereStore.setRow(queryId, rootRowId, resultRow);
9001
+ mapForEach(selects, (asCellId, tableCellGetter) =>
9002
+ selectJoinWhereStore._[5](
9003
+ queryId,
9004
+ rootRowId,
9005
+ asCellId,
9006
+ tableCellGetter(getJoinCell, rootRowId),
9007
+ ),
9008
+ );
8858
9009
  }
9010
+ } else if (hasSelectAll) {
9011
+ writeSelectAllRow();
8859
9012
  } else {
8860
9013
  mapForEach(selects, (asCellId, tableCellGetter) =>
8861
9014
  selectJoinWhereStore._[5](
@@ -8985,7 +9138,14 @@ const createQueries = getCreateFunction((store) => {
8985
9138
  }),
8986
9139
  );
8987
9140
  const setQueryDefinitionImpl = (queryId, definition) => {
8988
- const stagedDefinition = [mapNew(), mapNew(), void 0, mapNew(), setNew()];
9141
+ const stagedDefinition = [
9142
+ mapNew(),
9143
+ mapNew(),
9144
+ void 0,
9145
+ mapNew(),
9146
+ setNew(),
9147
+ mapNew(),
9148
+ ];
8989
9149
  let committed = false;
8990
9150
  tryCatchSync(
8991
9151
  () =>
@@ -9007,11 +9167,17 @@ const createQueries = getCreateFunction((store) => {
9007
9167
  );
9008
9168
  mapSet(preStores, queryId, stagedDefinition[2]);
9009
9169
  syncSelectAllListeners(queryId, stagedDefinition[3]);
9170
+ clearSelectAllRetryListeners(queryId);
9010
9171
  mapSet(
9011
9172
  referencedQueryIds,
9012
9173
  queryId,
9013
9174
  collIsEmpty(stagedDefinition[4]) ? void 0 : stagedDefinition[4],
9014
9175
  );
9176
+ mapSet(
9177
+ selectAllQuerySources,
9178
+ queryId,
9179
+ collIsEmpty(stagedDefinition[5]) ? void 0 : stagedDefinition[5],
9180
+ );
9015
9181
  committed = true;
9016
9182
  }),
9017
9183
  (error) => {
@@ -9062,7 +9228,9 @@ const createQueries = getCreateFunction((store) => {
9062
9228
  resetPreStores(queryId);
9063
9229
  resetSourceStores(queryId);
9064
9230
  syncSelectAllListeners(queryId);
9231
+ clearSelectAllRetryListeners(queryId);
9065
9232
  mapSet(referencedQueryIds, queryId);
9233
+ mapSet(selectAllQuerySources, queryId);
9066
9234
  delDefinition(queryId);
9067
9235
  cleanStores();
9068
9236
  return queries;
@@ -9397,6 +9565,9 @@ const FRAGMENT_PAYLOAD = /^[^\n]*\n[-0-9A-Z_a-z]{16}\n\d+\n\d+\n/;
9397
9565
  const INVALID_CHANNEL_ID_CHARACTERS = /[\n\r?#]/;
9398
9566
  const MAX_FRAGMENT_BUFFERS = 100;
9399
9567
  const MAX_FRAGMENT_COUNT = 1e3;
9568
+ const MAX_MULTIPLE_CHANNELS = 100;
9569
+ const MAX_MULTIPLE_CHANNEL_RESOURCES = MAX_MULTIPLE_CHANNELS * 2;
9570
+ const MAX_MULTIPLE_CHANNEL_ID_SIZE = 1024;
9400
9571
  const MAX_PENDING_REQUESTS = 100;
9401
9572
  const MAX_WEBSOCKET_BUFFER_SIZE = 16777216;
9402
9573
  const MAX_WEBSOCKET_QUEUE_SIZE = 1e3;
@@ -9535,21 +9706,30 @@ const createPayloadDecoder = (
9535
9706
  receive,
9536
9707
  fragmentTimeoutSeconds = 1,
9537
9708
  onInvalid,
9709
+ sharedBuffer,
9538
9710
  ) => {
9539
9711
  const buffer = mapNew();
9712
+ const payloadBuffer = sharedBuffer ?? [0, 0];
9540
9713
  let bufferedSize = 0;
9541
9714
  let valid = true;
9542
9715
  const delPending = (bufferKey, pending) => {
9543
9716
  stopTimeout(pending[4]);
9544
9717
  bufferedSize -= pending[5];
9718
+ payloadBuffer[0]--;
9719
+ payloadBuffer[1] -= pending[5];
9545
9720
  collDel(buffer, bufferKey);
9546
9721
  };
9722
+ const clear = () => {
9723
+ mapForEach(buffer, (_bufferKey, pending) => stopTimeout(pending[4]));
9724
+ payloadBuffer[0] -= collSize(buffer);
9725
+ payloadBuffer[1] -= bufferedSize;
9726
+ collClear(buffer);
9727
+ bufferedSize = 0;
9728
+ };
9547
9729
  const invalid = (error = errorNew(ERROR_SYNC_MESSAGE)) => {
9548
9730
  if (valid) {
9549
9731
  valid = false;
9550
- mapForEach(buffer, (_bufferKey, pending) => stopTimeout(pending[4]));
9551
- collClear(buffer);
9552
- bufferedSize = 0;
9732
+ clear();
9553
9733
  onInvalid?.(error);
9554
9734
  }
9555
9735
  };
@@ -9561,7 +9741,7 @@ const createPayloadDecoder = (
9561
9741
  invalid();
9562
9742
  }
9563
9743
  };
9564
- return (payload) => {
9744
+ const decode = (payload) => {
9565
9745
  if (!valid) {
9566
9746
  return;
9567
9747
  }
@@ -9594,42 +9774,52 @@ const createPayloadDecoder = (
9594
9774
  const bufferKey = clientId + MESSAGE_SEPARATOR + messageId;
9595
9775
  let pending = mapGet(buffer, bufferKey);
9596
9776
  if (!pending) {
9597
- if (collSize(buffer) >= MAX_FRAGMENT_BUFFERS) {
9777
+ if (payloadBuffer[0] >= MAX_FRAGMENT_BUFFERS) {
9598
9778
  invalid(errorNew(ERROR_SYNC_OVERFLOW, 'fragments'));
9599
9779
  return;
9600
9780
  }
9601
- pending = [
9602
- [],
9603
- [],
9604
- total,
9605
- total,
9606
- startTimeout(() => {
9607
- const timedOut = mapGet(buffer, bufferKey);
9608
- if (timedOut) {
9609
- delPending(bufferKey, timedOut);
9610
- }
9611
- }, fragmentTimeoutSeconds),
9612
- 0,
9613
- ];
9614
- mapSet(buffer, bufferKey, pending);
9615
9781
  }
9616
- const [fragments, remainders] = pending;
9617
- if (total == pending[3] && isUndefined(fragments[index])) {
9618
- const fragmentLength = getWebSocketPayloadSize(fragment);
9619
- if (bufferedSize + fragmentLength > MAX_WEBSOCKET_BUFFER_SIZE) {
9782
+ if (
9783
+ (isUndefined(pending) || total == pending[3]) &&
9784
+ isUndefined(pending?.[0][index])
9785
+ ) {
9786
+ const retainedSize =
9787
+ getWebSocketPayloadSize(remainder) +
9788
+ (pending ? 0 : getWebSocketPayloadSize(bufferKey));
9789
+ if (payloadBuffer[1] + retainedSize > MAX_WEBSOCKET_BUFFER_SIZE) {
9620
9790
  invalid(errorNew(ERROR_SYNC_OVERFLOW, 'fragments'));
9621
9791
  return;
9622
9792
  }
9793
+ if (!pending) {
9794
+ pending = [
9795
+ [],
9796
+ [],
9797
+ total,
9798
+ total,
9799
+ startTimeout(() => {
9800
+ const timedOut = mapGet(buffer, bufferKey);
9801
+ if (timedOut) {
9802
+ delPending(bufferKey, timedOut);
9803
+ }
9804
+ }, fragmentTimeoutSeconds),
9805
+ 0,
9806
+ ];
9807
+ mapSet(buffer, bufferKey, pending);
9808
+ payloadBuffer[0]++;
9809
+ }
9810
+ const [fragments, remainders] = pending;
9623
9811
  fragments[index] = fragment;
9624
9812
  remainders[index] = remainder;
9625
9813
  pending[2]--;
9626
- pending[5] += fragmentLength;
9627
- bufferedSize += fragmentLength;
9814
+ pending[5] += retainedSize;
9815
+ bufferedSize += retainedSize;
9816
+ payloadBuffer[1] += retainedSize;
9628
9817
  } else {
9629
9818
  invalid();
9630
9819
  return;
9631
9820
  }
9632
9821
  if (pending[2] == 0) {
9822
+ const [fragments, remainders] = pending;
9633
9823
  delPending(bufferKey, pending);
9634
9824
  receiveRemainder(clientId, remainders, arrayJoin(fragments));
9635
9825
  }
@@ -9642,6 +9832,7 @@ const createPayloadDecoder = (
9642
9832
  invalid();
9643
9833
  }
9644
9834
  };
9835
+ return [decode, clear];
9645
9836
  };
9646
9837
  const getPayloadCoalesceKey = (clientId, payload) => {
9647
9838
  let key;
@@ -9658,12 +9849,14 @@ const createPayloadReceiver = (
9658
9849
  receive,
9659
9850
  fragmentTimeoutSeconds = 1,
9660
9851
  onInvalid,
9852
+ sharedBuffer,
9661
9853
  ) =>
9662
9854
  createPayloadDecoder(
9663
9855
  (fromClientId, _remainders, requestId, message, body) =>
9664
9856
  receive(fromClientId, requestId, message, body),
9665
9857
  fragmentTimeoutSeconds,
9666
9858
  onInvalid,
9859
+ sharedBuffer,
9667
9860
  );
9668
9861
  const createPayload = (toClientId, ...args) =>
9669
9862
  createRawPayload(toClientId, jsonStringWithUndefined(args));
@@ -9698,12 +9891,15 @@ const getFragments = (remainder, maxFragmentSize) => {
9698
9891
  };
9699
9892
  const createMultiplePayload = (channelId, payload) =>
9700
9893
  createRawPayload(MULTIPLE_CLIENT_ID, createRawPayload(channelId, payload));
9701
- const ifMultiplePayloadValid = (payload, then) => {
9894
+ const ifMultiplePayloadValid = (payload, then, onOversized) => {
9702
9895
  let valid = false;
9703
9896
  ifPayloadValid(payload, (multipleClientId, remainder) => {
9704
9897
  if (multipleClientId == MULTIPLE_CLIENT_ID) {
9705
9898
  ifPayloadValid(remainder, (channelId, channelPayload) => {
9706
- if (isMultipleChannelIdValid(channelId)) {
9899
+ if (isMultipleChannelIdTooLarge(channelId)) {
9900
+ valid = true;
9901
+ onOversized?.();
9902
+ } else if (isMultipleChannelIdStructureValid(channelId)) {
9707
9903
  valid = true;
9708
9904
  then(channelId, channelPayload);
9709
9905
  }
@@ -9717,6 +9913,15 @@ const createMultipleControlPayload = (requestId, control, body) =>
9717
9913
  SERVER_CLIENT_ID$1,
9718
9914
  jsonStringWithUndefined([requestId, MULTIPLE_MESSAGE, [control, body]]),
9719
9915
  );
9916
+ const isMultipleChannelIdTooLarge = (channelId) =>
9917
+ getWebSocketPayloadSize(channelId) > MAX_MULTIPLE_CHANNEL_ID_SIZE;
9918
+ const isMultipleChannelIdStructureValid = (channelId) =>
9919
+ !isEmpty(channelId) &&
9920
+ !INVALID_CHANNEL_ID_CHARACTERS.test(channelId) &&
9921
+ arrayEvery(
9922
+ strSplit(channelId, '/'),
9923
+ (part) => !isEmpty(part) && part != '.' && part != '..',
9924
+ );
9720
9925
  const ifMultipleControlPayloadValid = (payload, then) => {
9721
9926
  let valid = false;
9722
9927
  ifPayloadValid(payload, (serverClientId, remainder) => {
@@ -9734,11 +9939,13 @@ const ifMultipleControlPayloadValid = (payload, then) => {
9734
9939
  : control == 1 /* Subscribe */
9735
9940
  ? isString(requestId) &&
9736
9941
  isString(body) &&
9737
- isMultipleChannelIdValid(body)
9942
+ (isMultipleChannelIdTooLarge(body) ||
9943
+ isMultipleChannelIdStructureValid(body))
9738
9944
  : control == 2 /* Unsubscribe */ &&
9739
9945
  isNull(requestId) &&
9740
9946
  isString(body) &&
9741
- isMultipleChannelIdValid(body))
9947
+ (isMultipleChannelIdTooLarge(body) ||
9948
+ isMultipleChannelIdStructureValid(body)))
9742
9949
  ) {
9743
9950
  valid = true;
9744
9951
  then(requestId, control, body);
@@ -9748,12 +9955,8 @@ const ifMultipleControlPayloadValid = (payload, then) => {
9748
9955
  return valid;
9749
9956
  };
9750
9957
  const isMultipleChannelIdValid = (channelId) =>
9751
- !isEmpty(channelId) &&
9752
- !INVALID_CHANNEL_ID_CHARACTERS.test(channelId) &&
9753
- arrayEvery(
9754
- strSplit(channelId, '/'),
9755
- (part) => !isEmpty(part) && part != '.' && part != '..',
9756
- );
9958
+ !isMultipleChannelIdTooLarge(channelId) &&
9959
+ isMultipleChannelIdStructureValid(channelId);
9757
9960
  const createMultipleServerClient = (
9758
9961
  basePathId,
9759
9962
  addChannel,
@@ -9766,26 +9969,87 @@ const createMultipleServerClient = (
9766
9969
  ) => {
9767
9970
  const channels = mapNew();
9768
9971
  const decoders = mapNew();
9972
+ const payloadBuffer = [0, 0];
9973
+ const resources = setNew();
9974
+ let resourceCount = 0;
9769
9975
  let negotiated = false;
9976
+ let valid = true;
9770
9977
  const sendControl = (requestId, control, body) =>
9771
9978
  send(createMultipleControlPayload(requestId, control, body));
9772
9979
  const delChannelAndDecoder = (channelId) => {
9773
9980
  collDel(channels, channelId);
9981
+ mapGet(decoders, channelId)?.[1]();
9774
9982
  collDel(decoders, channelId);
9775
9983
  };
9984
+ const clearDecoders = () => {
9985
+ mapForEach(decoders, (_channelId, decoder) => decoder[1]());
9986
+ collClear(decoders);
9987
+ };
9988
+ const invalidate = (error) => {
9989
+ if (valid) {
9990
+ valid = false;
9991
+ clearDecoders();
9992
+ invalid(error);
9993
+ }
9994
+ };
9995
+ const releaseChannel = (channel) => {
9996
+ if (!channel[2 /* Released */]) {
9997
+ channel[2 /* Released */] = 1;
9998
+ resourceCount--;
9999
+ collDel(resources, channel);
10000
+ }
10001
+ };
10002
+ const teardownChannel = (channel) =>
10003
+ (channel[1 /* Teardown */] ??= (async () => {
10004
+ try {
10005
+ const teardown = delChannel(channel[0 /* Channel */]);
10006
+ if (isUndefined(teardown)) {
10007
+ releaseChannel(channel);
10008
+ } else {
10009
+ await teardown;
10010
+ }
10011
+ } finally {
10012
+ releaseChannel(channel);
10013
+ }
10014
+ })());
9776
10015
  const handleControl = (requestId, control, body) => {
9777
10016
  if (control == 0 /* Hello */) {
9778
10017
  negotiated = true;
9779
10018
  sendControl(requestId, control, body);
9780
10019
  } else if (negotiated && control == 1 /* Subscribe */) {
9781
- if (!collHas(channels, body)) {
10020
+ const subscribed = collHas(channels, body);
10021
+ if (
10022
+ isMultipleChannelIdTooLarge(body) ||
10023
+ (!subscribed &&
10024
+ (collSize(channels) >= MAX_MULTIPLE_CHANNELS ||
10025
+ resourceCount >= MAX_MULTIPLE_CHANNEL_RESOURCES))
10026
+ ) {
10027
+ invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'channels'));
10028
+ return;
10029
+ }
10030
+ if (!subscribed) {
9782
10031
  const pathId = basePathId + (basePathId ? '/' : EMPTY_STRING) + body;
9783
- const [channel, ready] = addChannel(pathId, body);
10032
+ resourceCount++;
10033
+ let channelAndReady;
10034
+ try {
10035
+ channelAndReady = addChannel(pathId, body);
10036
+ } catch (error) {
10037
+ resourceCount--;
10038
+ throw error;
10039
+ }
10040
+ const [addedChannel, ready] = channelAndReady;
10041
+ const channel = [addedChannel];
10042
+ setAdd(resources, channel);
9784
10043
  mapSet(channels, body, channel);
9785
10044
  sendControl(requestId, control, body);
9786
10045
  if (ready) {
9787
10046
  return ready.catch((error) => {
9788
- delChannelAndDecoder(body);
10047
+ if (mapGet(channels, body) === channel) {
10048
+ delChannelAndDecoder(body);
10049
+ }
10050
+ if (!channel[1 /* Teardown */]) {
10051
+ releaseChannel(channel);
10052
+ }
9789
10053
  throw error;
9790
10054
  });
9791
10055
  }
@@ -9793,16 +10057,21 @@ const createMultipleServerClient = (
9793
10057
  }
9794
10058
  sendControl(requestId, control, body);
9795
10059
  } else if (negotiated && control == 2 /* Unsubscribe */) {
10060
+ if (isMultipleChannelIdTooLarge(body)) {
10061
+ invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'channels'));
10062
+ return;
10063
+ }
9796
10064
  const channel = mapGet(channels, body);
9797
10065
  delChannelAndDecoder(body);
9798
- if (!isUndefined(channel)) {
9799
- return (async () => delChannel(channel))();
9800
- }
10066
+ return isUndefined(channel) ? void 0 : teardownChannel(channel);
9801
10067
  }
9802
10068
  };
9803
10069
  const handlePayload = (payload) => {
10070
+ if (!valid) {
10071
+ return;
10072
+ }
9804
10073
  if (isWebSocketPayloadTooLarge(getWebSocketPayloadSize(payload))) {
9805
- invalid(errorNew(ERROR_SYNC_OVERFLOW, 'socket'));
10074
+ invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'socket'));
9806
10075
  return;
9807
10076
  }
9808
10077
  const control = ifMultipleControlPayloadValid(
@@ -9817,32 +10086,54 @@ const createMultipleServerClient = (
9817
10086
  (channelId, channelPayload) => {
9818
10087
  const channel2 = negotiated ? mapGet(channels, channelId) : void 0;
9819
10088
  if (isUndefined(channel2)) {
9820
- invalid(errorNew(ERROR_SYNC_MESSAGE));
10089
+ invalidate(errorNew(ERROR_SYNC_MESSAGE));
9821
10090
  } else {
9822
10091
  mapEnsure(decoders, channelId, () =>
9823
10092
  createPayloadDecoder(
9824
10093
  (toClientId, remainders) =>
9825
- receive(channel2, toClientId, remainders),
10094
+ receive(channel2[0 /* Channel */], toClientId, remainders),
9826
10095
  fragmentTimeoutSeconds,
9827
- invalid,
10096
+ invalidate,
10097
+ payloadBuffer,
9828
10098
  ),
9829
- )(channelPayload);
10099
+ )[0](channelPayload);
9830
10100
  }
9831
10101
  },
10102
+ () => invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'channels')),
9832
10103
  );
9833
10104
  if (!control && !channel) {
9834
- invalid(errorNew(ERROR_SYNC_MESSAGE));
10105
+ invalidate(errorNew(ERROR_SYNC_MESSAGE));
9835
10106
  }
9836
10107
  };
9837
- const destroy = () =>
9838
- tryFinallyAsync(
9839
- () =>
9840
- promiseAll(mapMap(channels, async (channel) => delChannel(channel))),
10108
+ const destroy = () => {
10109
+ valid = false;
10110
+ clearDecoders();
10111
+ return tryFinallyAsync(
10112
+ async () => {
10113
+ let errorToThrow;
10114
+ let failed = false;
10115
+ await promiseAll(
10116
+ arrayMap(collValues(resources), async (channel) => {
10117
+ try {
10118
+ await teardownChannel(channel);
10119
+ } catch (error) {
10120
+ if (!failed) {
10121
+ errorToThrow = error;
10122
+ failed = true;
10123
+ }
10124
+ }
10125
+ }),
10126
+ );
10127
+ if (failed) {
10128
+ throw errorToThrow;
10129
+ }
10130
+ },
9841
10131
  () => {
9842
10132
  collClear(channels);
9843
- collClear(decoders);
10133
+ clearDecoders();
9844
10134
  },
9845
10135
  );
10136
+ };
9846
10137
  return [handlePayload, destroy];
9847
10138
  };
9848
10139
  const createPayloads = (toClientId, requestId, message, body, fragmentSize) => {
@@ -10239,6 +10530,7 @@ const createConnection = () => {
10239
10530
  const createMultipleState = (webSocket) => {
10240
10531
  const channels = mapNew();
10241
10532
  const pendingControls = mapNew();
10533
+ const payloadBuffer = [0, 0];
10242
10534
  const removeListeners = [];
10243
10535
  let connection = createConnection();
10244
10536
  let connected = false;
@@ -10250,6 +10542,7 @@ const createMultipleState = (webSocket) => {
10250
10542
  let overflowing = false;
10251
10543
  let queuedCount = 0;
10252
10544
  let queuedSize = 0;
10545
+ let receiving = true;
10253
10546
  const notifyChannelIgnoredError = (channel, error) =>
10254
10547
  tryReturn(() => channel[6 /* OnIgnoredError */]?.(error));
10255
10548
  const notifyIgnoredError = (error) =>
@@ -10261,11 +10554,10 @@ const createMultipleState = (webSocket) => {
10261
10554
  disconnect();
10262
10555
  tryReturn(() => webSocket.close());
10263
10556
  };
10264
- const invalid = createInvalidPayloadHandler(webSocket, notifyIgnoredError);
10265
10557
  const addWebSocketListener = (event, handler) =>
10266
10558
  arrayPush(removeListeners, addEventListener(webSocket, event, handler));
10267
10559
  const rejectPendingControls = (error) =>
10268
- mapForEach(pendingControls, (requestId, [, , reject, timeout]) => {
10560
+ mapForEach(pendingControls, (requestId, [, , , reject, timeout]) => {
10269
10561
  stopTimeout(timeout);
10270
10562
  collDel(pendingControls, requestId);
10271
10563
  reject(error);
@@ -10296,11 +10588,43 @@ const createMultipleState = (webSocket) => {
10296
10588
  channel[7 /* Dirty */] = void 0;
10297
10589
  }
10298
10590
  };
10591
+ const clearReceive = (channel) => channel[0 /* Receive */]?.[1]();
10592
+ const clearReceives = () =>
10593
+ mapForEach(channels, (_channelId, channel) => clearReceive(channel));
10594
+ const handleInvalid = createInvalidPayloadHandler(
10595
+ webSocket,
10596
+ notifyIgnoredError,
10597
+ );
10598
+ const invalid = (error) => {
10599
+ if (receiving) {
10600
+ receiving = false;
10601
+ disconnected = true;
10602
+ connected = false;
10603
+ clearReceives();
10604
+ connection[2](error);
10605
+ rejectPendingControls(error);
10606
+ failChannels(error);
10607
+ mapForEach(channels, (_channelId, channel) => {
10608
+ clearIncoming(channel);
10609
+ clearOutgoing(channel, true);
10610
+ channel[3 /* Subscribed */] = false;
10611
+ channel[4 /* Subscribing */] = void 0;
10612
+ channel[12 /* SubscribeConnection */] = void 0;
10613
+ });
10614
+ if (flushTimeout) {
10615
+ stopTimeout(flushTimeout);
10616
+ flushTimeout = void 0;
10617
+ }
10618
+ handleInvalid(error);
10619
+ }
10620
+ };
10299
10621
  const overflow = (details) => {
10300
10622
  const error = errorNew(ERROR_SYNC_OVERFLOW, details);
10301
10623
  if (!overflowing && !destroyed) {
10302
10624
  overflowing = true;
10625
+ receiving = false;
10303
10626
  connected = false;
10627
+ clearReceives();
10304
10628
  notifyIgnoredError(error);
10305
10629
  rejectPendingControls(error);
10306
10630
  failChannels(error);
@@ -10309,6 +10633,7 @@ const createMultipleState = (webSocket) => {
10309
10633
  clearOutgoing(channel, true);
10310
10634
  channel[3 /* Subscribed */] = false;
10311
10635
  channel[4 /* Subscribing */] = void 0;
10636
+ channel[12 /* SubscribeConnection */] = void 0;
10312
10637
  });
10313
10638
  if (flushTimeout) {
10314
10639
  stopTimeout(flushTimeout);
@@ -10330,7 +10655,7 @@ const createMultipleState = (webSocket) => {
10330
10655
  });
10331
10656
  return timeoutSeconds;
10332
10657
  };
10333
- const sendControl = (control, body, timeoutSeconds) => {
10658
+ const sendControl = (control, body, timeoutSeconds, onSent) => {
10334
10659
  const requestId = getUniqueId();
10335
10660
  return promiseNew((resolve, reject) => {
10336
10661
  if (collSize(pendingControls) >= MAX_PENDING_REQUESTS) {
@@ -10350,9 +10675,16 @@ const createMultipleState = (webSocket) => {
10350
10675
  collDel(pendingControls, requestId);
10351
10676
  reject(errorNew(ERROR_MULTIPLEX_RESPONSE, control));
10352
10677
  }, timeoutSeconds);
10353
- mapSet(pendingControls, requestId, [control, resolve, reject, timeout]);
10678
+ mapSet(pendingControls, requestId, [
10679
+ control,
10680
+ body,
10681
+ resolve,
10682
+ reject,
10683
+ timeout,
10684
+ ]);
10354
10685
  try {
10355
10686
  webSocket.send(payload);
10687
+ onSent?.();
10356
10688
  } catch (error) {
10357
10689
  stopTimeout(timeout);
10358
10690
  collDel(pendingControls, requestId);
@@ -10535,23 +10867,45 @@ const createMultipleState = (webSocket) => {
10535
10867
  const subscribe = async (channelId, channel, timeoutSeconds) => {
10536
10868
  if (!channel[3 /* Subscribed */]) {
10537
10869
  let subscribing = channel[4 /* Subscribing */];
10538
- if (!subscribing) {
10539
- subscribing = (async () => {
10540
- await connection[0];
10870
+ const subscribingConnection = connection;
10871
+ if (subscribing?.[0] !== subscribingConnection) {
10872
+ const subscribingPromise = (async () => {
10873
+ await subscribingConnection[0];
10874
+ if (
10875
+ mapGet(channels, channelId) !== channel ||
10876
+ connection !== subscribingConnection ||
10877
+ !connected
10878
+ ) {
10879
+ return;
10880
+ }
10541
10881
  await sendControl(
10542
10882
  MultipleControl.Subscribe,
10543
10883
  channelId,
10544
10884
  timeoutSeconds,
10885
+ () => {
10886
+ if (
10887
+ mapGet(channels, channelId) === channel &&
10888
+ connection === subscribingConnection &&
10889
+ connected
10890
+ ) {
10891
+ channel[12 /* SubscribeConnection */] = subscribingConnection;
10892
+ }
10893
+ },
10545
10894
  );
10546
- if (mapGet(channels, channelId) === channel && connected) {
10895
+ if (
10896
+ mapGet(channels, channelId) === channel &&
10897
+ connection === subscribingConnection &&
10898
+ connected
10899
+ ) {
10547
10900
  channel[3 /* Subscribed */] = true;
10548
10901
  flushOutgoing(channelId, channel);
10549
10902
  }
10550
10903
  })();
10904
+ subscribing = [subscribingConnection, subscribingPromise];
10551
10905
  channel[4 /* Subscribing */] = subscribing;
10552
10906
  }
10553
10907
  try {
10554
- await subscribing;
10908
+ await subscribing[1];
10555
10909
  } finally {
10556
10910
  if (channel[4 /* Subscribing */] === subscribing) {
10557
10911
  channel[4 /* Subscribing */] = void 0;
@@ -10560,7 +10914,7 @@ const createMultipleState = (webSocket) => {
10560
10914
  }
10561
10915
  };
10562
10916
  const onOpen = () => {
10563
- if (destroyed || opening?.[0] === connection) {
10917
+ if (destroyed || !receiving || connected || opening?.[0] === connection) {
10564
10918
  return;
10565
10919
  }
10566
10920
  disconnected = false;
@@ -10573,7 +10927,7 @@ const createMultipleState = (webSocket) => {
10573
10927
  MULTIPLE_VERSION,
10574
10928
  getConnectionTimeoutSeconds(),
10575
10929
  );
10576
- if (connection === openingConnection) {
10930
+ if (connection === openingConnection && receiving && !destroyed) {
10577
10931
  connected = true;
10578
10932
  openingConnection[1]();
10579
10933
  mapForEach(channels, (channelId, channel) =>
@@ -10621,13 +10975,18 @@ const createMultipleState = (webSocket) => {
10621
10975
  }
10622
10976
  connection = createConnection();
10623
10977
  mapForEach(channels, (_channelId, channel) => {
10978
+ clearReceive(channel);
10624
10979
  channel[3 /* Subscribed */] = false;
10625
10980
  channel[4 /* Subscribing */] = void 0;
10981
+ channel[12 /* SubscribeConnection */] = void 0;
10626
10982
  });
10627
10983
  }
10628
10984
  };
10629
10985
  const onClose = disconnect;
10630
10986
  addWebSocketListener(MESSAGE, ({data}) => {
10987
+ if (!receiving) {
10988
+ return;
10989
+ }
10631
10990
  const payload = data.toString(UTF8);
10632
10991
  if (isWebSocketPayloadTooLarge(getWebSocketPayloadSize(payload))) {
10633
10992
  invalid(errorNew(ERROR_SYNC_OVERFLOW, 'socket'));
@@ -10635,14 +10994,23 @@ const createMultipleState = (webSocket) => {
10635
10994
  }
10636
10995
  const control = ifMultipleControlPayloadValid(
10637
10996
  payload,
10638
- (requestId, control2, _body) => {
10997
+ (requestId, control2, body) => {
10998
+ if (
10999
+ (control2 == MultipleControl.Subscribe ||
11000
+ control2 == MultipleControl.Unsubscribe) &&
11001
+ isString(body) &&
11002
+ !isMultipleChannelIdValid(body)
11003
+ ) {
11004
+ overflow('channels');
11005
+ return;
11006
+ }
10639
11007
  const pendingControl = requestId
10640
11008
  ? mapGet(pendingControls, requestId)
10641
11009
  : void 0;
10642
- if (pendingControl?.[0] == control2) {
10643
- stopTimeout(pendingControl[3]);
11010
+ if (pendingControl?.[0] == control2 && pendingControl[1] === body) {
11011
+ stopTimeout(pendingControl[4]);
10644
11012
  collDel(pendingControls, requestId);
10645
- pendingControl[1]();
11013
+ pendingControl[2]();
10646
11014
  }
10647
11015
  },
10648
11016
  );
@@ -10652,7 +11020,7 @@ const createMultipleState = (webSocket) => {
10652
11020
  const channel2 = mapGet(channels, channelId);
10653
11021
  if (channel2) {
10654
11022
  if (channel2[0 /* Receive */]) {
10655
- channel2[0 /* Receive */](channelPayload);
11023
+ channel2[0 /* Receive */][0](channelPayload);
10656
11024
  } else {
10657
11025
  queueIncoming(channel2, channelPayload);
10658
11026
  }
@@ -10660,6 +11028,7 @@ const createMultipleState = (webSocket) => {
10660
11028
  invalid(errorNew(ERROR_SYNC_MESSAGE));
10661
11029
  }
10662
11030
  },
11031
+ () => overflow('channels'),
10663
11032
  );
10664
11033
  if (!control && !channel) {
10665
11034
  invalid(errorNew(ERROR_SYNC_MESSAGE));
@@ -10672,12 +11041,18 @@ const createMultipleState = (webSocket) => {
10672
11041
  failChannels(errorNew(ERROR_MULTIPLEX_SOCKET));
10673
11042
  });
10674
11043
  const addChannel = async (channelId, timeoutSeconds, onIgnoredError) => {
11044
+ if (!receiving || destroyed) {
11045
+ errorThrow(ERROR_MULTIPLEX_SOCKET);
11046
+ }
10675
11047
  if (!isMultipleChannelIdValid(channelId)) {
10676
11048
  errorThrow(ERROR_MULTIPLEX_CHANNEL, channelId);
10677
11049
  }
10678
11050
  if (collHas(channels, channelId)) {
10679
11051
  errorThrow(ERROR_MULTIPLEX_CHANNEL_DUPLICATE, channelId);
10680
11052
  }
11053
+ if (collSize(channels) >= MAX_MULTIPLE_CHANNELS) {
11054
+ errorThrow(ERROR_SYNC_OVERFLOW, 'channels');
11055
+ }
10681
11056
  const channel = [
10682
11057
  void 0,
10683
11058
  [],
@@ -10691,6 +11066,7 @@ const createMultipleState = (webSocket) => {
10691
11066
  0,
10692
11067
  0,
10693
11068
  void 0,
11069
+ void 0,
10694
11070
  ];
10695
11071
  mapSet(channels, channelId, channel);
10696
11072
  if (webSocket.readyState == webSocket.OPEN) {
@@ -10724,7 +11100,7 @@ const createMultipleState = (webSocket) => {
10724
11100
  queuedCount--;
10725
11101
  queuedSize -= payloadSize;
10726
11102
  incomingIndex++;
10727
- receive(payload);
11103
+ receive[0](payload);
10728
11104
  }
10729
11105
  },
10730
11106
  () => arrayClear(incoming, incomingIndex),
@@ -10732,6 +11108,9 @@ const createMultipleState = (webSocket) => {
10732
11108
  }
10733
11109
  };
10734
11110
  const send = (channelId, payloads, coalesce) => {
11111
+ if (!receiving) {
11112
+ return;
11113
+ }
10735
11114
  const channel = mapGet(channels, channelId);
10736
11115
  if (channel) {
10737
11116
  if (
@@ -10752,6 +11131,9 @@ const createMultipleState = (webSocket) => {
10752
11131
  const destroyIfEmpty = () => {
10753
11132
  if (collIsEmpty(channels) && !destroyed) {
10754
11133
  destroyed = true;
11134
+ const closeWebSocket = receiving && !overflowing;
11135
+ receiving = false;
11136
+ clearReceives();
10755
11137
  const error = errorNew(ERROR_MULTIPLEX_DESTROYED);
10756
11138
  rejectPendingControls(error);
10757
11139
  if (flushTimeout) {
@@ -10763,7 +11145,7 @@ const createMultipleState = (webSocket) => {
10763
11145
  );
10764
11146
  arrayClear(removeListeners);
10765
11147
  multipleStates.delete(webSocket);
10766
- if (!overflowing) {
11148
+ if (closeWebSocket) {
10767
11149
  tryReturn(() => webSocket.close());
10768
11150
  }
10769
11151
  }
@@ -10772,9 +11154,10 @@ const createMultipleState = (webSocket) => {
10772
11154
  const channel = mapGet(channels, channelId);
10773
11155
  if (channel) {
10774
11156
  try {
11157
+ clearReceive(channel);
10775
11158
  clearIncoming(channel);
10776
11159
  clearOutgoing(channel, true);
10777
- if (connected && channel[3 /* Subscribed */]) {
11160
+ if (connected && channel[12 /* SubscribeConnection */] === connection) {
10778
11161
  const payload = createMultipleControlPayload(
10779
11162
  null,
10780
11163
  MultipleControl.Unsubscribe,
@@ -10803,6 +11186,7 @@ const createMultipleState = (webSocket) => {
10803
11186
  delChannel,
10804
11187
  destroyIfEmpty,
10805
11188
  invalid,
11189
+ payloadBuffer,
10806
11190
  registerReceive,
10807
11191
  send,
10808
11192
  };
@@ -10858,7 +11242,12 @@ const createMultipleWsSynchronizer = async (
10858
11242
  (receive, fail) =>
10859
11243
  state.registerReceive(
10860
11244
  channelId,
10861
- createPayloadReceiver(receive, requestTimeoutSeconds, state.invalid),
11245
+ createPayloadReceiver(
11246
+ receive,
11247
+ requestTimeoutSeconds,
11248
+ state.invalid,
11249
+ state.payloadBuffer,
11250
+ ),
10862
11251
  fail,
10863
11252
  ),
10864
11253
  () => state.delChannel(channelId),
@@ -10900,13 +11289,14 @@ const createLegacyWsSynchronizer = async (
10900
11289
  };
10901
11290
  const registerReceive = (receive, fail) => {
10902
11291
  const invalid = createInvalidPayloadHandler(webSocket, notifyIgnoredError);
10903
- const receivePayload = createPayloadReceiver(
11292
+ const [receivePayload, clearReceivePayload] = createPayloadReceiver(
10904
11293
  receive,
10905
11294
  requestTimeoutSeconds,
10906
11295
  invalid,
10907
11296
  );
10908
11297
  let removeListeners = [];
10909
11298
  removeTransportListeners = () => {
11299
+ clearReceivePayload();
10910
11300
  arrayForEach(removeListeners, (removeListener) =>
10911
11301
  tryReturn(removeListener),
10912
11302
  );
@@ -11076,7 +11466,7 @@ class WsServerDurableObject extends DurableObject {
11076
11466
  (this.#serverClientSend = createPayloadReceiver(
11077
11467
  receive,
11078
11468
  requestTimeoutSeconds,
11079
- )),
11469
+ )[0]),
11080
11470
  noop,
11081
11471
  requestTimeoutSeconds,
11082
11472
  );
@@ -11124,10 +11514,11 @@ class WsServerDurableObject extends DurableObject {
11124
11514
  );
11125
11515
  this.#payloadDecoders.set(client, decode);
11126
11516
  }
11127
- decode(message.toString());
11517
+ decode[0](message.toString());
11128
11518
  });
11129
11519
  }
11130
11520
  webSocketClose(client) {
11521
+ this.#payloadDecoders.get(client)?.[1]();
11131
11522
  this.#payloadDecoders.delete(client);
11132
11523
  const [clientId, pathId] = this.ctx.getTags(client);
11133
11524
  this.onClientId(pathId, clientId, -1);
@@ -11280,7 +11671,7 @@ const createWsServerSimple = (webSocketServer) => {
11280
11671
  };
11281
11672
  const addLegacyClient = (client, clientId, pathId) => {
11282
11673
  addClientToPath(pathId, clientId, [client]);
11283
- const decode = createPayloadDecoder(
11674
+ const [decode, clearDecoder] = createPayloadDecoder(
11284
11675
  (toClientId, remainders) =>
11285
11676
  handleDecodedMessage(pathId, clientId, toClientId, remainders),
11286
11677
  1,
@@ -11289,8 +11680,10 @@ const createWsServerSimple = (webSocketServer) => {
11289
11680
  addWebSocketListener(client, MESSAGE, (data) =>
11290
11681
  decode(data.toString(UTF8)),
11291
11682
  );
11292
- mapGet(webSocketStates, client)[1] = () =>
11683
+ mapGet(webSocketStates, client)[1] = () => {
11684
+ clearDecoder();
11293
11685
  delClientFromPath(pathId, clientId);
11686
+ };
11294
11687
  };
11295
11688
  const addMultipleClient = (client, clientId, basePathId) => {
11296
11689
  const invalid = createInvalidPayloadHandler(client);
@@ -11420,6 +11813,7 @@ const createWsServer = (
11420
11813
  const clientIdListeners = mapNew();
11421
11814
  const paths = mapNew();
11422
11815
  const webSockets = setNew();
11816
+ const buffersByWebSocket = mapNew();
11423
11817
  const removeServerListeners = [];
11424
11818
  const removeListenersByWebSocket = mapNew();
11425
11819
  let destroying;
@@ -11469,7 +11863,7 @@ const createWsServer = (
11469
11863
  serverClient[3 /* Send */] = createPayloadReceiver(
11470
11864
  receive,
11471
11865
  requestTimeoutSeconds,
11472
- );
11866
+ )[0];
11473
11867
  },
11474
11868
  noop,
11475
11869
  requestTimeoutSeconds,
@@ -11533,18 +11927,37 @@ const createWsServer = (
11533
11927
  client.send(outgoingPayload);
11534
11928
  }
11535
11929
  };
11930
+ const updateWebSocketBuffer = (webSocket, count, size2) => {
11931
+ const webSocketBuffer = mapEnsure(buffersByWebSocket, webSocket, () => [
11932
+ 0, 0,
11933
+ ]);
11934
+ webSocketBuffer[0] += count;
11935
+ webSocketBuffer[1] += size2;
11936
+ if (!webSocketBuffer[0]) {
11937
+ mapSet(buffersByWebSocket, webSocket);
11938
+ }
11939
+ };
11940
+ const delBufferedFromWebSocket = ([, payload, , webSocket]) =>
11941
+ updateWebSocketBuffer(webSocket, -1, -getWebSocketPayloadSize(payload));
11536
11942
  const clearServerBuffer = (serverClient) => {
11537
11943
  if (serverClient[7 /* BufferTimeout */]) {
11538
11944
  stopTimeout(serverClient[7 /* BufferTimeout */]);
11539
11945
  serverClient[7 /* BufferTimeout */] = void 0;
11540
11946
  }
11947
+ arrayForEach(serverClient[4 /* Buffer */], delBufferedFromWebSocket);
11541
11948
  serverClient[4 /* Buffer */] = [];
11542
11949
  serverClient[6 /* BufferSize */] = 0;
11543
11950
  };
11544
11951
  const delBufferedClient = (serverClient, clientId) => {
11545
11952
  serverClient[4 /* Buffer */] = arrayFilter(
11546
11953
  serverClient[4 /* Buffer */],
11547
- ([bufferedClientId]) => bufferedClientId != clientId,
11954
+ (buffered) => {
11955
+ if (buffered[0] == clientId) {
11956
+ delBufferedFromWebSocket(buffered);
11957
+ return false;
11958
+ }
11959
+ return true;
11960
+ },
11548
11961
  );
11549
11962
  serverClient[6 /* BufferSize */] = arrayReduce(
11550
11963
  serverClient[4 /* Buffer */],
@@ -11558,10 +11971,8 @@ const createWsServer = (
11558
11971
  const expireServerBuffer = (path) => {
11559
11972
  const serverClient = path[1 /* ServerClient */];
11560
11973
  const clients = setNew();
11561
- arrayForEach(serverClient[4 /* Buffer */], ([clientId]) =>
11562
- ifNotUndefined(mapGet(path[0 /* Clients */], clientId), ([client]) =>
11563
- setAdd(clients, client),
11564
- ),
11974
+ arrayForEach(serverClient[4 /* Buffer */], ([, , , client]) =>
11975
+ setAdd(clients, client),
11565
11976
  );
11566
11977
  clearServerBuffer(serverClient);
11567
11978
  arrayForEach(collValues(clients), (client) =>
@@ -11571,6 +11982,10 @@ const createWsServer = (
11571
11982
  const bufferMessage = (path, clientId, payload) => {
11572
11983
  const serverClient = path[1 /* ServerClient */];
11573
11984
  const buffer = serverClient[4 /* Buffer */];
11985
+ const webSocket = mapGet(path[0 /* Clients */], clientId)?.[0];
11986
+ if (isUndefined(webSocket)) {
11987
+ return;
11988
+ }
11574
11989
  const coalesceKey = getPayloadCoalesceKey(clientId, payload);
11575
11990
  const coalesceIndex = coalesceKey
11576
11991
  ? arrayFindIndex(
@@ -11578,14 +11993,22 @@ const createWsServer = (
11578
11993
  ([, , bufferedKey]) => bufferedKey == coalesceKey,
11579
11994
  )
11580
11995
  : -1;
11581
- const replacedSize =
11582
- coalesceIndex > -1
11583
- ? getWebSocketPayloadSize(buffer[coalesceIndex][1])
11584
- : 0;
11996
+ const replaced = coalesceIndex > -1 ? buffer[coalesceIndex] : void 0;
11997
+ const replacedSize = isUndefined(replaced)
11998
+ ? 0
11999
+ : getWebSocketPayloadSize(replaced[1]);
11585
12000
  const payloadSize = getWebSocketPayloadSize(payload);
12001
+ const webSocketBuffer = mapGet(buffersByWebSocket, webSocket);
12002
+ const sameWebSocket = replaced?.[3] === webSocket;
11586
12003
  if (
11587
12004
  (coalesceIndex < 0 && size(buffer) >= MAX_WEBSOCKET_QUEUE_SIZE) ||
11588
12005
  serverClient[6 /* BufferSize */] + payloadSize - replacedSize >
12006
+ MAX_WEBSOCKET_BUFFER_SIZE ||
12007
+ (!sameWebSocket &&
12008
+ (webSocketBuffer?.[0] ?? 0) >= MAX_WEBSOCKET_QUEUE_SIZE) ||
12009
+ (webSocketBuffer?.[1] ?? 0) +
12010
+ payloadSize -
12011
+ (sameWebSocket ? replacedSize : 0) >
11589
12012
  MAX_WEBSOCKET_BUFFER_SIZE
11590
12013
  ) {
11591
12014
  delBufferedClient(serverClient, clientId);
@@ -11594,12 +12017,14 @@ const createWsServer = (
11594
12017
  );
11595
12018
  return;
11596
12019
  }
11597
- const buffered = [clientId, payload, coalesceKey];
12020
+ const buffered = [clientId, payload, coalesceKey, webSocket];
11598
12021
  if (coalesceIndex > -1) {
12022
+ delBufferedFromWebSocket(buffer[coalesceIndex]);
11599
12023
  buffer[coalesceIndex] = buffered;
11600
12024
  } else {
11601
12025
  arrayPush(buffer, buffered);
11602
12026
  }
12027
+ updateWebSocketBuffer(webSocket, 1, payloadSize);
11603
12028
  serverClient[6 /* BufferSize */] += payloadSize - replacedSize;
11604
12029
  serverClient[7 /* BufferTimeout */] ??= startTimeout(
11605
12030
  () => expireServerBuffer(path),
@@ -11758,7 +12183,7 @@ const createWsServer = (
11758
12183
  };
11759
12184
  const addLegacyClient = async (client, clientId, pathId) => {
11760
12185
  const [path, ready] = addClientToPath(pathId, clientId, [client]);
11761
- const decode = createPayloadDecoder(
12186
+ const [decode, clearDecoder] = createPayloadDecoder(
11762
12187
  (toClientId, remainders) =>
11763
12188
  handleDecodedMessage(path, clientId, toClientId, remainders),
11764
12189
  requestTimeoutSeconds,
@@ -11767,9 +12192,10 @@ const createWsServer = (
11767
12192
  addWebSocketListener(client, MESSAGE, (data) =>
11768
12193
  decode(data.toString(UTF8)),
11769
12194
  );
11770
- addWebSocketListener(client, CLOSE, () =>
11771
- delClientFromPath(pathId, path, clientId).catch(handleError),
11772
- );
12195
+ addWebSocketListener(client, CLOSE, () => {
12196
+ clearDecoder();
12197
+ delClientFromPath(pathId, path, clientId).catch(handleError);
12198
+ });
11773
12199
  await ready;
11774
12200
  };
11775
12201
  const addMultipleClient = (client, clientId, basePathId) => {
@@ -11914,6 +12340,7 @@ const createWsServer = (
11914
12340
  arrayForEach(removers, (remove) => tryReturn(remove)),
11915
12341
  );
11916
12342
  collClear(removeListenersByWebSocket);
12343
+ collClear(buffersByWebSocket);
11917
12344
  collClear(paths);
11918
12345
  collClear(webSockets);
11919
12346
  const failure = serverFailure[0]