tinybase 9.4.0-beta.0 → 9.4.0-beta.2

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 (225) 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 +145 -7
  6. package/@types/queries/with-schemas/index.d.ts +157 -7
  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/index.js +315 -22
  14. package/min/index.js +1 -1
  15. package/min/index.js.gz +0 -0
  16. package/min/omni/index.js +1 -1
  17. package/min/omni/index.js.gz +0 -0
  18. package/min/omni/with-schemas/index.js +1 -1
  19. package/min/omni/with-schemas/index.js.gz +0 -0
  20. package/min/persisters/index.js +1 -1
  21. package/min/persisters/index.js.gz +0 -0
  22. package/min/persisters/persister-automerge/index.js +1 -1
  23. package/min/persisters/persister-automerge/index.js.gz +0 -0
  24. package/min/persisters/persister-automerge/with-schemas/index.js +1 -1
  25. package/min/persisters/persister-automerge/with-schemas/index.js.gz +0 -0
  26. package/min/persisters/persister-browser/index.js +1 -1
  27. package/min/persisters/persister-browser/index.js.gz +0 -0
  28. package/min/persisters/persister-browser/with-schemas/index.js +1 -1
  29. package/min/persisters/persister-browser/with-schemas/index.js.gz +0 -0
  30. package/min/persisters/persister-cr-sqlite-wasm/index.js +1 -1
  31. package/min/persisters/persister-cr-sqlite-wasm/index.js.gz +0 -0
  32. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +1 -1
  33. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js.gz +0 -0
  34. package/min/persisters/persister-durable-object-sql-storage/index.js +1 -1
  35. package/min/persisters/persister-durable-object-sql-storage/index.js.gz +0 -0
  36. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js +1 -1
  37. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js.gz +0 -0
  38. package/min/persisters/persister-durable-object-storage/index.js +1 -1
  39. package/min/persisters/persister-durable-object-storage/index.js.gz +0 -0
  40. package/min/persisters/persister-durable-object-storage/with-schemas/index.js +1 -1
  41. package/min/persisters/persister-durable-object-storage/with-schemas/index.js.gz +0 -0
  42. package/min/persisters/persister-electric-sql/index.js +1 -1
  43. package/min/persisters/persister-electric-sql/index.js.gz +0 -0
  44. package/min/persisters/persister-electric-sql/with-schemas/index.js +1 -1
  45. package/min/persisters/persister-electric-sql/with-schemas/index.js.gz +0 -0
  46. package/min/persisters/persister-expo-sqlite/index.js +1 -1
  47. package/min/persisters/persister-expo-sqlite/index.js.gz +0 -0
  48. package/min/persisters/persister-expo-sqlite/with-schemas/index.js +1 -1
  49. package/min/persisters/persister-expo-sqlite/with-schemas/index.js.gz +0 -0
  50. package/min/persisters/persister-file/index.js +1 -1
  51. package/min/persisters/persister-file/index.js.gz +0 -0
  52. package/min/persisters/persister-file/with-schemas/index.js +1 -1
  53. package/min/persisters/persister-file/with-schemas/index.js.gz +0 -0
  54. package/min/persisters/persister-indexed-db/index.js +1 -1
  55. package/min/persisters/persister-indexed-db/index.js.gz +0 -0
  56. package/min/persisters/persister-indexed-db/with-schemas/index.js +1 -1
  57. package/min/persisters/persister-indexed-db/with-schemas/index.js.gz +0 -0
  58. package/min/persisters/persister-libsql/index.js +1 -1
  59. package/min/persisters/persister-libsql/index.js.gz +0 -0
  60. package/min/persisters/persister-libsql/with-schemas/index.js +1 -1
  61. package/min/persisters/persister-libsql/with-schemas/index.js.gz +0 -0
  62. package/min/persisters/persister-partykit-client/index.js +1 -1
  63. package/min/persisters/persister-partykit-client/index.js.gz +0 -0
  64. package/min/persisters/persister-partykit-client/with-schemas/index.js +1 -1
  65. package/min/persisters/persister-partykit-client/with-schemas/index.js.gz +0 -0
  66. package/min/persisters/persister-pglite/index.js +1 -1
  67. package/min/persisters/persister-pglite/index.js.gz +0 -0
  68. package/min/persisters/persister-pglite/with-schemas/index.js +1 -1
  69. package/min/persisters/persister-pglite/with-schemas/index.js.gz +0 -0
  70. package/min/persisters/persister-postgres/index.js +1 -1
  71. package/min/persisters/persister-postgres/index.js.gz +0 -0
  72. package/min/persisters/persister-postgres/with-schemas/index.js +1 -1
  73. package/min/persisters/persister-postgres/with-schemas/index.js.gz +0 -0
  74. package/min/persisters/persister-powersync/index.js +1 -1
  75. package/min/persisters/persister-powersync/index.js.gz +0 -0
  76. package/min/persisters/persister-powersync/with-schemas/index.js +1 -1
  77. package/min/persisters/persister-powersync/with-schemas/index.js.gz +0 -0
  78. package/min/persisters/persister-react-native-mmkv/index.js +1 -1
  79. package/min/persisters/persister-react-native-mmkv/index.js.gz +0 -0
  80. package/min/persisters/persister-react-native-mmkv/with-schemas/index.js +1 -1
  81. package/min/persisters/persister-react-native-mmkv/with-schemas/index.js.gz +0 -0
  82. package/min/persisters/persister-react-native-sqlite/index.js +1 -1
  83. package/min/persisters/persister-react-native-sqlite/index.js.gz +0 -0
  84. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js +1 -1
  85. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js.gz +0 -0
  86. package/min/persisters/persister-remote/index.js +1 -1
  87. package/min/persisters/persister-remote/index.js.gz +0 -0
  88. package/min/persisters/persister-remote/with-schemas/index.js +1 -1
  89. package/min/persisters/persister-remote/with-schemas/index.js.gz +0 -0
  90. package/min/persisters/persister-sqlite-bun/index.js +1 -1
  91. package/min/persisters/persister-sqlite-bun/index.js.gz +0 -0
  92. package/min/persisters/persister-sqlite-bun/with-schemas/index.js +1 -1
  93. package/min/persisters/persister-sqlite-bun/with-schemas/index.js.gz +0 -0
  94. package/min/persisters/persister-sqlite-wasm/index.js +1 -1
  95. package/min/persisters/persister-sqlite-wasm/index.js.gz +0 -0
  96. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js +1 -1
  97. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js.gz +0 -0
  98. package/min/persisters/persister-sqlite3/index.js +1 -1
  99. package/min/persisters/persister-sqlite3/index.js.gz +0 -0
  100. package/min/persisters/persister-sqlite3/with-schemas/index.js +1 -1
  101. package/min/persisters/persister-sqlite3/with-schemas/index.js.gz +0 -0
  102. package/min/persisters/persister-yjs/index.js +1 -1
  103. package/min/persisters/persister-yjs/index.js.gz +0 -0
  104. package/min/persisters/persister-yjs/with-schemas/index.js +1 -1
  105. package/min/persisters/persister-yjs/with-schemas/index.js.gz +0 -0
  106. package/min/persisters/with-schemas/index.js +1 -1
  107. package/min/persisters/with-schemas/index.js.gz +0 -0
  108. package/min/queries/index.js +1 -1
  109. package/min/queries/index.js.gz +0 -0
  110. package/min/queries/with-schemas/index.js +1 -1
  111. package/min/queries/with-schemas/index.js.gz +0 -0
  112. package/min/synchronizers/index.js +1 -1
  113. package/min/synchronizers/index.js.gz +0 -0
  114. package/min/synchronizers/synchronizer-broadcast-channel/index.js +1 -1
  115. package/min/synchronizers/synchronizer-broadcast-channel/index.js.gz +0 -0
  116. package/min/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js +1 -1
  117. package/min/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js.gz +0 -0
  118. package/min/synchronizers/synchronizer-local/index.js +1 -1
  119. package/min/synchronizers/synchronizer-local/index.js.gz +0 -0
  120. package/min/synchronizers/synchronizer-local/with-schemas/index.js +1 -1
  121. package/min/synchronizers/synchronizer-local/with-schemas/index.js.gz +0 -0
  122. package/min/synchronizers/synchronizer-ws-client/index.js +1 -1
  123. package/min/synchronizers/synchronizer-ws-client/index.js.gz +0 -0
  124. package/min/synchronizers/synchronizer-ws-client/with-schemas/index.js +1 -1
  125. package/min/synchronizers/synchronizer-ws-client/with-schemas/index.js.gz +0 -0
  126. package/min/synchronizers/synchronizer-ws-server/index.js +1 -1
  127. package/min/synchronizers/synchronizer-ws-server/index.js.gz +0 -0
  128. package/min/synchronizers/synchronizer-ws-server/with-schemas/index.js +1 -1
  129. package/min/synchronizers/synchronizer-ws-server/with-schemas/index.js.gz +0 -0
  130. package/min/synchronizers/synchronizer-ws-server-durable-object/index.js +1 -1
  131. package/min/synchronizers/synchronizer-ws-server-durable-object/index.js.gz +0 -0
  132. package/min/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +1 -1
  133. package/min/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js.gz +0 -0
  134. package/min/synchronizers/synchronizer-ws-server-simple/index.js +1 -1
  135. package/min/synchronizers/synchronizer-ws-server-simple/index.js.gz +0 -0
  136. package/min/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js +1 -1
  137. package/min/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js.gz +0 -0
  138. package/min/synchronizers/with-schemas/index.js +1 -1
  139. package/min/synchronizers/with-schemas/index.js.gz +0 -0
  140. package/min/ui-react-inspector/index.js +1 -1
  141. package/min/ui-react-inspector/index.js.gz +0 -0
  142. package/min/ui-react-inspector/with-schemas/index.js +1 -1
  143. package/min/ui-react-inspector/with-schemas/index.js.gz +0 -0
  144. package/min/ui-solid-inspector/index.js +1 -1
  145. package/min/ui-solid-inspector/index.js.gz +0 -0
  146. package/min/ui-solid-inspector/with-schemas/index.js +1 -1
  147. package/min/ui-solid-inspector/with-schemas/index.js.gz +0 -0
  148. package/min/ui-svelte-inspector/index.js +1 -1
  149. package/min/ui-svelte-inspector/index.js.gz +0 -0
  150. package/min/ui-svelte-inspector/with-schemas/index.js +1 -1
  151. package/min/ui-svelte-inspector/with-schemas/index.js.gz +0 -0
  152. package/min/with-schemas/index.js +1 -1
  153. package/min/with-schemas/index.js.gz +0 -0
  154. package/omni/index.js +730 -127
  155. package/omni/with-schemas/index.js +730 -127
  156. package/package.json +8 -4
  157. package/persisters/index.js +49 -10
  158. package/persisters/persister-automerge/index.js +29 -5
  159. package/persisters/persister-automerge/with-schemas/index.js +29 -5
  160. package/persisters/persister-browser/index.js +29 -5
  161. package/persisters/persister-browser/with-schemas/index.js +29 -5
  162. package/persisters/persister-cr-sqlite-wasm/index.js +29 -5
  163. package/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +29 -5
  164. package/persisters/persister-durable-object-sql-storage/index.js +44 -8
  165. package/persisters/persister-durable-object-sql-storage/with-schemas/index.js +44 -8
  166. package/persisters/persister-durable-object-storage/index.js +31 -5
  167. package/persisters/persister-durable-object-storage/with-schemas/index.js +31 -5
  168. package/persisters/persister-electric-sql/index.js +29 -5
  169. package/persisters/persister-electric-sql/with-schemas/index.js +29 -5
  170. package/persisters/persister-expo-sqlite/index.js +29 -5
  171. package/persisters/persister-expo-sqlite/with-schemas/index.js +29 -5
  172. package/persisters/persister-file/index.js +31 -5
  173. package/persisters/persister-file/with-schemas/index.js +31 -5
  174. package/persisters/persister-indexed-db/index.js +29 -5
  175. package/persisters/persister-indexed-db/with-schemas/index.js +29 -5
  176. package/persisters/persister-libsql/index.js +29 -5
  177. package/persisters/persister-libsql/with-schemas/index.js +29 -5
  178. package/persisters/persister-partykit-client/index.js +31 -5
  179. package/persisters/persister-partykit-client/with-schemas/index.js +31 -5
  180. package/persisters/persister-pglite/index.js +49 -10
  181. package/persisters/persister-pglite/with-schemas/index.js +49 -10
  182. package/persisters/persister-postgres/index.js +49 -10
  183. package/persisters/persister-postgres/with-schemas/index.js +49 -10
  184. package/persisters/persister-powersync/index.js +29 -5
  185. package/persisters/persister-powersync/with-schemas/index.js +29 -5
  186. package/persisters/persister-react-native-mmkv/index.js +31 -5
  187. package/persisters/persister-react-native-mmkv/with-schemas/index.js +31 -5
  188. package/persisters/persister-react-native-sqlite/index.js +29 -5
  189. package/persisters/persister-react-native-sqlite/with-schemas/index.js +29 -5
  190. package/persisters/persister-remote/index.js +31 -5
  191. package/persisters/persister-remote/with-schemas/index.js +31 -5
  192. package/persisters/persister-sqlite-bun/index.js +29 -5
  193. package/persisters/persister-sqlite-bun/with-schemas/index.js +29 -5
  194. package/persisters/persister-sqlite-wasm/index.js +29 -5
  195. package/persisters/persister-sqlite-wasm/with-schemas/index.js +29 -5
  196. package/persisters/persister-sqlite3/index.js +29 -5
  197. package/persisters/persister-sqlite3/with-schemas/index.js +29 -5
  198. package/persisters/persister-yjs/index.js +29 -5
  199. package/persisters/persister-yjs/with-schemas/index.js +29 -5
  200. package/persisters/with-schemas/index.js +49 -10
  201. package/queries/index.js +334 -22
  202. package/queries/with-schemas/index.js +334 -22
  203. package/readme.md +14 -14
  204. package/releases.md +84 -67
  205. package/synchronizers/index.js +31 -5
  206. package/synchronizers/synchronizer-broadcast-channel/index.js +39 -13
  207. package/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js +39 -13
  208. package/synchronizers/synchronizer-local/index.js +31 -5
  209. package/synchronizers/synchronizer-local/with-schemas/index.js +31 -5
  210. package/synchronizers/synchronizer-ws-client/index.js +220 -61
  211. package/synchronizers/synchronizer-ws-client/with-schemas/index.js +220 -61
  212. package/synchronizers/synchronizer-ws-server/index.js +253 -73
  213. package/synchronizers/synchronizer-ws-server/with-schemas/index.js +253 -73
  214. package/synchronizers/synchronizer-ws-server-durable-object/index.js +88 -40
  215. package/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +88 -40
  216. package/synchronizers/synchronizer-ws-server-simple/index.js +184 -60
  217. package/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js +184 -60
  218. package/synchronizers/with-schemas/index.js +31 -5
  219. package/ui-react-inspector/index.js +29 -5
  220. package/ui-react-inspector/with-schemas/index.js +29 -5
  221. package/ui-solid-inspector/index.js +29 -5
  222. package/ui-solid-inspector/with-schemas/index.js +29 -5
  223. package/ui-svelte-inspector/index.js +29 -5
  224. package/ui-svelte-inspector/with-schemas/index.js +29 -5
  225. package/with-schemas/index.js +315 -22
@@ -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]);
@@ -8230,6 +8282,51 @@ const createQueries = getCreateFunction((store) => {
8230
8282
  };
8231
8283
  const preStoreListenerIds = mapNew();
8232
8284
  const sourceStoreListenerIds = mapNew();
8285
+ const selectAllListenerIds = mapNew();
8286
+ const selectAllRetryListenerIds = mapNew();
8287
+ const selectAllQuerySources = mapNew();
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
+ };
8233
8330
  const {
8234
8331
  _: [, addListener, callListeners],
8235
8332
  delListener: delListenerImpl,
@@ -8303,11 +8400,72 @@ const createQueries = getCreateFunction((store) => {
8303
8400
  resetStoreListeners(mapGet(sourceStoreListenerIds, queryId));
8304
8401
  mapSet(sourceStoreListenerIds, queryId);
8305
8402
  };
8306
- const isResultStoreReferenced = (resultStore2) =>
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
+ };
8427
+ const syncSelectAllListeners = (queryId, nextSources = mapNew()) => {
8428
+ const listenerIds = mapEnsure(selectAllListenerIds, queryId, mapNew);
8429
+ mapForEach(listenerIds, (sourceStore, listenerIdsByTableId) => {
8430
+ mapForEach(listenerIdsByTableId, (sourceTableId, listenerId) =>
8431
+ collHas(mapGet(nextSources, sourceStore), sourceTableId)
8432
+ ? 0
8433
+ : (sourceStore.delListener(listenerId),
8434
+ mapSet(listenerIdsByTableId, sourceTableId)),
8435
+ );
8436
+ if (collIsEmpty(listenerIdsByTableId)) {
8437
+ mapSet(listenerIds, sourceStore);
8438
+ }
8439
+ });
8440
+ mapForEach(nextSources, (sourceStore, tableIds) => {
8441
+ const listenerIdsByTableId = mapEnsure(listenerIds, sourceStore, mapNew);
8442
+ collForEach(tableIds, (sourceTableId) =>
8443
+ mapEnsure(listenerIdsByTableId, sourceTableId, () =>
8444
+ sourceStore.addTableCellIdsListener(sourceTableId, () =>
8445
+ tryCatchSync(
8446
+ () => setQueryDefinitionImpl(queryId),
8447
+ (error) => {
8448
+ addSelectAllRetryListener(queryId, sourceStore, sourceTableId);
8449
+ throw error;
8450
+ },
8451
+ ),
8452
+ ),
8453
+ ),
8454
+ );
8455
+ });
8456
+ if (collIsEmpty(listenerIds)) {
8457
+ mapSet(selectAllListenerIds, queryId);
8458
+ }
8459
+ };
8460
+ const isResultStoreReferenced = (queryId, resultStore2) =>
8307
8461
  !(
8308
8462
  collEvery(routedResultListeners, ([, storeListenerIds]) =>
8309
8463
  collEvery(storeListenerIds, ([store2]) => store2 !== resultStore2),
8310
8464
  ) &&
8465
+ collEvery(
8466
+ referencedQueryIds,
8467
+ (queryIds) => !collHas(queryIds, queryId),
8468
+ ) &&
8311
8469
  arrayEvery(
8312
8470
  [preStoreListenerIds, sourceStoreListenerIds],
8313
8471
  (storeListenerIds) =>
@@ -8322,7 +8480,7 @@ const createQueries = getCreateFunction((store) => {
8322
8480
  hasQuery(queryId) ? 0 : mapSet(preStores, queryId),
8323
8481
  );
8324
8482
  mapForEach(resultStores, (queryId, resultStore2) =>
8325
- hasQuery(queryId) || isResultStoreReferenced(resultStore2)
8483
+ hasQuery(queryId) || isResultStoreReferenced(queryId, resultStore2)
8326
8484
  ? 0
8327
8485
  : mapSet(resultStores, queryId),
8328
8486
  );
@@ -8404,7 +8562,13 @@ const createQueries = getCreateFunction((store) => {
8404
8562
  const rootStore = asQuery ? getResultStore(tableId) : store;
8405
8563
  const resultStore2 = getResultStore(queryId);
8406
8564
  const paramValues = definition?.[3] ?? getParamValues(queryId);
8407
- const selectEntries = [];
8565
+ const nextReferencedQueryIds = stagedDefinition[4];
8566
+ if (asQuery) {
8567
+ setAdd(nextReferencedQueryIds, tableId);
8568
+ }
8569
+ const selectionEntries = [];
8570
+ let hasSelectAll = false;
8571
+ let selectCount = 0;
8408
8572
  const joinEntries = [
8409
8573
  [void 0, [tableId, void 0, void 0, [], mapNew(), rootStore]],
8410
8574
  ];
@@ -8416,21 +8580,39 @@ const createQueries = getCreateFunction((store) => {
8416
8580
  const joinedTableId = isTrue(arg1) ? arg2 : arg1;
8417
8581
  const joinedCellId = isTrue(arg1) ? arg3 : arg2;
8418
8582
  const selectEntry = isFunction(arg1)
8419
- ? [size(selectEntries) + EMPTY_STRING, arg1]
8583
+ ? [0, selectCount + EMPTY_STRING, arg1]
8420
8584
  : isUndefined(joinedCellId)
8421
- ? [arg1, (getTableCell) => getTableCell(arg1)]
8585
+ ? [0, arg1, (getTableCell) => getTableCell(arg1)]
8422
8586
  : [
8587
+ 0,
8423
8588
  joinedCellId,
8424
8589
  (getTableCell) =>
8425
8590
  isTrue(arg1)
8426
8591
  ? getTableCell(true, joinedTableId, joinedCellId)
8427
8592
  : getTableCell(joinedTableId, joinedCellId),
8428
8593
  ];
8429
- arrayPush(selectEntries, selectEntry);
8594
+ selectCount++;
8595
+ arrayPush(selectionEntries, selectEntry);
8430
8596
  return {
8431
- as: (selectedCellId) => (selectEntry[0] = selectedCellId),
8597
+ as: (selectedCellId) => (selectEntry[1] = selectedCellId),
8432
8598
  };
8433
8599
  };
8600
+ const selectAll = (arg1, arg2, arg3) => {
8601
+ hasSelectAll = true;
8602
+ const joinedTableId = isTrue(arg1) ? arg2 : arg1;
8603
+ const prefixOrMapper = isTrue(arg1) ? arg3 : arg2;
8604
+ arrayPush(selectionEntries, [
8605
+ 1,
8606
+ joinedTableId,
8607
+ isFunction(prefixOrMapper)
8608
+ ? prefixOrMapper
8609
+ : (cellId) => (prefixOrMapper ?? EMPTY_STRING) + cellId,
8610
+ isFunction(prefixOrMapper) ||
8611
+ (!isUndefined(prefixOrMapper) && prefixOrMapper !== EMPTY_STRING)
8612
+ ? 1
8613
+ : 0,
8614
+ ]);
8615
+ };
8434
8616
  const join = (arg1, arg2, arg3, arg4) => {
8435
8617
  const joinedTableId = isTrue(arg1) ? arg2 : arg1;
8436
8618
  const [fromJoinAlias, onArg] = isTrue(arg1)
@@ -8440,6 +8622,13 @@ const createQueries = getCreateFunction((store) => {
8440
8622
  : isUndefined(arg3) || isFunction(arg2)
8441
8623
  ? [void 0, arg2]
8442
8624
  : [arg2, arg3];
8625
+ const sourceIsQuery = isTrue(arg1);
8626
+ const sourceStore = sourceIsQuery
8627
+ ? getResultStore(joinedTableId)
8628
+ : store;
8629
+ if (sourceIsQuery) {
8630
+ setAdd(nextReferencedQueryIds, joinedTableId);
8631
+ }
8443
8632
  const joinEntry = [
8444
8633
  joinedTableId,
8445
8634
  [
@@ -8448,7 +8637,7 @@ const createQueries = getCreateFunction((store) => {
8448
8637
  isFunction(onArg) ? onArg : (getCell) => getCell(onArg),
8449
8638
  [],
8450
8639
  mapNew(),
8451
- isTrue(arg1) ? getResultStore(joinedTableId) : store,
8640
+ sourceStore,
8452
8641
  ],
8453
8642
  ];
8454
8643
  arrayPush(joinEntries, joinEntry);
@@ -8494,21 +8683,86 @@ const createQueries = getCreateFunction((store) => {
8494
8683
  : (getSelectedOrGroupedCell) =>
8495
8684
  getSelectedOrGroupedCell(arg1) === arg2,
8496
8685
  );
8497
- build({select, join, where, group, having, param});
8498
- resultStore2.delTable(queryId);
8499
- const selects = mapNew(selectEntries);
8500
- if (collIsEmpty(selects)) {
8501
- commit?.();
8502
- return queries;
8503
- }
8686
+ build({select, selectAll, join, where, group, having, param});
8504
8687
  const joins = mapNew(joinEntries);
8505
8688
  mapForEach(joins, (joinAlias, [, fromJoinAlias]) =>
8506
8689
  ifNotUndefined(mapGet(joins, fromJoinAlias), ({3: toJoinAliases2}) =>
8507
8690
  isUndefined(joinAlias) ? 0 : arrayPush(toJoinAliases2, joinAlias),
8508
8691
  ),
8509
8692
  );
8693
+ const isRootSelectAll = (joinedTableId) => isUndefined(joinedTableId);
8694
+ const getSelectAllJoin = (joinedTableId) =>
8695
+ mapGet(
8696
+ joins,
8697
+ isRootSelectAll(joinedTableId) ? void 0 : joinedTableId,
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
+ }
8510
8726
  const groups = mapNew(groupEntries);
8511
8727
  const hasGroupsOrHavings = !collIsEmpty(groups) || !isEmpty(havings);
8728
+ const selectEntries = [];
8729
+ const selectAllSources = stagedDefinition[3];
8730
+ arrayForEach(
8731
+ selectionEntries,
8732
+ ([selectAll2, selectedOrJoinedTableId, clauseOrMapper]) => {
8733
+ if (selectAll2) {
8734
+ if (hasGroupsOrHavings) {
8735
+ ifNotUndefined(
8736
+ getSelectAllJoin(selectedOrJoinedTableId),
8737
+ ([realTableId, , , , , sourceStore]) => {
8738
+ setAdd(
8739
+ mapEnsure(selectAllSources, sourceStore, setNew),
8740
+ realTableId,
8741
+ );
8742
+ arrayForEach(
8743
+ arraySort(sourceStore.getTableCellIds(realTableId)),
8744
+ (cellId) =>
8745
+ arrayPush(selectEntries, [
8746
+ clauseOrMapper(cellId),
8747
+ getUndefined,
8748
+ ]),
8749
+ );
8750
+ },
8751
+ );
8752
+ }
8753
+ } else {
8754
+ arrayPush(selectEntries, [
8755
+ selectedOrJoinedTableId,
8756
+ clauseOrMapper,
8757
+ ]);
8758
+ }
8759
+ },
8760
+ );
8761
+ const selects = mapNew(selectEntries);
8762
+ if (hasGroupsOrHavings && collIsEmpty(selects)) {
8763
+ commit?.();
8764
+ return queries;
8765
+ }
8512
8766
  const selectJoinWhereStore = hasGroupsOrHavings
8513
8767
  ? (stagedDefinition[2] = createStore())
8514
8768
  : resultStore2;
@@ -8687,18 +8941,85 @@ const createQueries = getCreateFunction((store) => {
8687
8941
  joinedCellId,
8688
8942
  );
8689
8943
  };
8690
- selectJoinWhereStore.transaction(() =>
8691
- arrayEvery(wheres, (where2) => where2(getJoinCell))
8692
- ? mapForEach(selects, (asCellId, tableCellGetter) =>
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
+ };
8994
+ selectJoinWhereStore.transaction(() => {
8995
+ if (!arrayEvery(wheres, (where2) => where2(getJoinCell))) {
8996
+ selectJoinWhereStore.delRow(queryId, rootRowId);
8997
+ } else if (hasGroupsOrHavings) {
8998
+ if (hasSelectAll) {
8999
+ writeSelectAllRow();
9000
+ } else {
9001
+ mapForEach(selects, (asCellId, tableCellGetter) =>
8693
9002
  selectJoinWhereStore._[5](
8694
9003
  queryId,
8695
9004
  rootRowId,
8696
9005
  asCellId,
8697
9006
  tableCellGetter(getJoinCell, rootRowId),
8698
9007
  ),
8699
- )
8700
- : selectJoinWhereStore.delRow(queryId, rootRowId),
8701
- );
9008
+ );
9009
+ }
9010
+ } else if (hasSelectAll) {
9011
+ writeSelectAllRow();
9012
+ } else {
9013
+ mapForEach(selects, (asCellId, tableCellGetter) =>
9014
+ selectJoinWhereStore._[5](
9015
+ queryId,
9016
+ rootRowId,
9017
+ asCellId,
9018
+ tableCellGetter(getJoinCell, rootRowId),
9019
+ ),
9020
+ );
9021
+ }
9022
+ });
8702
9023
  };
8703
9024
  const listenToTable = (
8704
9025
  rootRowId,
@@ -8817,7 +9138,14 @@ const createQueries = getCreateFunction((store) => {
8817
9138
  }),
8818
9139
  );
8819
9140
  const setQueryDefinitionImpl = (queryId, definition) => {
8820
- const stagedDefinition = [mapNew(), mapNew()];
9141
+ const stagedDefinition = [
9142
+ mapNew(),
9143
+ mapNew(),
9144
+ void 0,
9145
+ mapNew(),
9146
+ setNew(),
9147
+ mapNew(),
9148
+ ];
8821
9149
  let committed = false;
8822
9150
  tryCatchSync(
8823
9151
  () =>
@@ -8838,6 +9166,18 @@ const createQueries = getCreateFunction((store) => {
8838
9166
  collIsEmpty(stagedDefinition[1]) ? void 0 : stagedDefinition[1],
8839
9167
  );
8840
9168
  mapSet(preStores, queryId, stagedDefinition[2]);
9169
+ syncSelectAllListeners(queryId, stagedDefinition[3]);
9170
+ clearSelectAllRetryListeners(queryId);
9171
+ mapSet(
9172
+ referencedQueryIds,
9173
+ queryId,
9174
+ collIsEmpty(stagedDefinition[4]) ? void 0 : stagedDefinition[4],
9175
+ );
9176
+ mapSet(
9177
+ selectAllQuerySources,
9178
+ queryId,
9179
+ collIsEmpty(stagedDefinition[5]) ? void 0 : stagedDefinition[5],
9180
+ );
8841
9181
  committed = true;
8842
9182
  }),
8843
9183
  (error) => {
@@ -8887,6 +9227,10 @@ const createQueries = getCreateFunction((store) => {
8887
9227
  paramStore.delRow(PARAMS_TABLE, queryId);
8888
9228
  resetPreStores(queryId);
8889
9229
  resetSourceStores(queryId);
9230
+ syncSelectAllListeners(queryId);
9231
+ clearSelectAllRetryListeners(queryId);
9232
+ mapSet(referencedQueryIds, queryId);
9233
+ mapSet(selectAllQuerySources, queryId);
8890
9234
  delDefinition(queryId);
8891
9235
  cleanStores();
8892
9236
  return queries;
@@ -9221,6 +9565,9 @@ const FRAGMENT_PAYLOAD = /^[^\n]*\n[-0-9A-Z_a-z]{16}\n\d+\n\d+\n/;
9221
9565
  const INVALID_CHANNEL_ID_CHARACTERS = /[\n\r?#]/;
9222
9566
  const MAX_FRAGMENT_BUFFERS = 100;
9223
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;
9224
9571
  const MAX_PENDING_REQUESTS = 100;
9225
9572
  const MAX_WEBSOCKET_BUFFER_SIZE = 16777216;
9226
9573
  const MAX_WEBSOCKET_QUEUE_SIZE = 1e3;
@@ -9359,21 +9706,30 @@ const createPayloadDecoder = (
9359
9706
  receive,
9360
9707
  fragmentTimeoutSeconds = 1,
9361
9708
  onInvalid,
9709
+ sharedBuffer,
9362
9710
  ) => {
9363
9711
  const buffer = mapNew();
9712
+ const payloadBuffer = sharedBuffer ?? [0, 0];
9364
9713
  let bufferedSize = 0;
9365
9714
  let valid = true;
9366
9715
  const delPending = (bufferKey, pending) => {
9367
9716
  stopTimeout(pending[4]);
9368
9717
  bufferedSize -= pending[5];
9718
+ payloadBuffer[0]--;
9719
+ payloadBuffer[1] -= pending[5];
9369
9720
  collDel(buffer, bufferKey);
9370
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
+ };
9371
9729
  const invalid = (error = errorNew(ERROR_SYNC_MESSAGE)) => {
9372
9730
  if (valid) {
9373
9731
  valid = false;
9374
- mapForEach(buffer, (_bufferKey, pending) => stopTimeout(pending[4]));
9375
- collClear(buffer);
9376
- bufferedSize = 0;
9732
+ clear();
9377
9733
  onInvalid?.(error);
9378
9734
  }
9379
9735
  };
@@ -9385,7 +9741,7 @@ const createPayloadDecoder = (
9385
9741
  invalid();
9386
9742
  }
9387
9743
  };
9388
- return (payload) => {
9744
+ const decode = (payload) => {
9389
9745
  if (!valid) {
9390
9746
  return;
9391
9747
  }
@@ -9418,42 +9774,52 @@ const createPayloadDecoder = (
9418
9774
  const bufferKey = clientId + MESSAGE_SEPARATOR + messageId;
9419
9775
  let pending = mapGet(buffer, bufferKey);
9420
9776
  if (!pending) {
9421
- if (collSize(buffer) >= MAX_FRAGMENT_BUFFERS) {
9777
+ if (payloadBuffer[0] >= MAX_FRAGMENT_BUFFERS) {
9422
9778
  invalid(errorNew(ERROR_SYNC_OVERFLOW, 'fragments'));
9423
9779
  return;
9424
9780
  }
9425
- pending = [
9426
- [],
9427
- [],
9428
- total,
9429
- total,
9430
- startTimeout(() => {
9431
- const timedOut = mapGet(buffer, bufferKey);
9432
- if (timedOut) {
9433
- delPending(bufferKey, timedOut);
9434
- }
9435
- }, fragmentTimeoutSeconds),
9436
- 0,
9437
- ];
9438
- mapSet(buffer, bufferKey, pending);
9439
9781
  }
9440
- const [fragments, remainders] = pending;
9441
- if (total == pending[3] && isUndefined(fragments[index])) {
9442
- const fragmentLength = getWebSocketPayloadSize(fragment);
9443
- 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) {
9444
9790
  invalid(errorNew(ERROR_SYNC_OVERFLOW, 'fragments'));
9445
9791
  return;
9446
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;
9447
9811
  fragments[index] = fragment;
9448
9812
  remainders[index] = remainder;
9449
9813
  pending[2]--;
9450
- pending[5] += fragmentLength;
9451
- bufferedSize += fragmentLength;
9814
+ pending[5] += retainedSize;
9815
+ bufferedSize += retainedSize;
9816
+ payloadBuffer[1] += retainedSize;
9452
9817
  } else {
9453
9818
  invalid();
9454
9819
  return;
9455
9820
  }
9456
9821
  if (pending[2] == 0) {
9822
+ const [fragments, remainders] = pending;
9457
9823
  delPending(bufferKey, pending);
9458
9824
  receiveRemainder(clientId, remainders, arrayJoin(fragments));
9459
9825
  }
@@ -9466,6 +9832,7 @@ const createPayloadDecoder = (
9466
9832
  invalid();
9467
9833
  }
9468
9834
  };
9835
+ return [decode, clear];
9469
9836
  };
9470
9837
  const getPayloadCoalesceKey = (clientId, payload) => {
9471
9838
  let key;
@@ -9482,12 +9849,14 @@ const createPayloadReceiver = (
9482
9849
  receive,
9483
9850
  fragmentTimeoutSeconds = 1,
9484
9851
  onInvalid,
9852
+ sharedBuffer,
9485
9853
  ) =>
9486
9854
  createPayloadDecoder(
9487
9855
  (fromClientId, _remainders, requestId, message, body) =>
9488
9856
  receive(fromClientId, requestId, message, body),
9489
9857
  fragmentTimeoutSeconds,
9490
9858
  onInvalid,
9859
+ sharedBuffer,
9491
9860
  );
9492
9861
  const createPayload = (toClientId, ...args) =>
9493
9862
  createRawPayload(toClientId, jsonStringWithUndefined(args));
@@ -9522,12 +9891,15 @@ const getFragments = (remainder, maxFragmentSize) => {
9522
9891
  };
9523
9892
  const createMultiplePayload = (channelId, payload) =>
9524
9893
  createRawPayload(MULTIPLE_CLIENT_ID, createRawPayload(channelId, payload));
9525
- const ifMultiplePayloadValid = (payload, then) => {
9894
+ const ifMultiplePayloadValid = (payload, then, onOversized) => {
9526
9895
  let valid = false;
9527
9896
  ifPayloadValid(payload, (multipleClientId, remainder) => {
9528
9897
  if (multipleClientId == MULTIPLE_CLIENT_ID) {
9529
9898
  ifPayloadValid(remainder, (channelId, channelPayload) => {
9530
- if (isMultipleChannelIdValid(channelId)) {
9899
+ if (isMultipleChannelIdTooLarge(channelId)) {
9900
+ valid = true;
9901
+ onOversized?.();
9902
+ } else if (isMultipleChannelIdStructureValid(channelId)) {
9531
9903
  valid = true;
9532
9904
  then(channelId, channelPayload);
9533
9905
  }
@@ -9541,6 +9913,15 @@ const createMultipleControlPayload = (requestId, control, body) =>
9541
9913
  SERVER_CLIENT_ID$1,
9542
9914
  jsonStringWithUndefined([requestId, MULTIPLE_MESSAGE, [control, body]]),
9543
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
+ );
9544
9925
  const ifMultipleControlPayloadValid = (payload, then) => {
9545
9926
  let valid = false;
9546
9927
  ifPayloadValid(payload, (serverClientId, remainder) => {
@@ -9558,11 +9939,13 @@ const ifMultipleControlPayloadValid = (payload, then) => {
9558
9939
  : control == 1 /* Subscribe */
9559
9940
  ? isString(requestId) &&
9560
9941
  isString(body) &&
9561
- isMultipleChannelIdValid(body)
9942
+ (isMultipleChannelIdTooLarge(body) ||
9943
+ isMultipleChannelIdStructureValid(body))
9562
9944
  : control == 2 /* Unsubscribe */ &&
9563
9945
  isNull(requestId) &&
9564
9946
  isString(body) &&
9565
- isMultipleChannelIdValid(body))
9947
+ (isMultipleChannelIdTooLarge(body) ||
9948
+ isMultipleChannelIdStructureValid(body)))
9566
9949
  ) {
9567
9950
  valid = true;
9568
9951
  then(requestId, control, body);
@@ -9572,12 +9955,8 @@ const ifMultipleControlPayloadValid = (payload, then) => {
9572
9955
  return valid;
9573
9956
  };
9574
9957
  const isMultipleChannelIdValid = (channelId) =>
9575
- !isEmpty(channelId) &&
9576
- !INVALID_CHANNEL_ID_CHARACTERS.test(channelId) &&
9577
- arrayEvery(
9578
- strSplit(channelId, '/'),
9579
- (part) => !isEmpty(part) && part != '.' && part != '..',
9580
- );
9958
+ !isMultipleChannelIdTooLarge(channelId) &&
9959
+ isMultipleChannelIdStructureValid(channelId);
9581
9960
  const createMultipleServerClient = (
9582
9961
  basePathId,
9583
9962
  addChannel,
@@ -9590,26 +9969,87 @@ const createMultipleServerClient = (
9590
9969
  ) => {
9591
9970
  const channels = mapNew();
9592
9971
  const decoders = mapNew();
9972
+ const payloadBuffer = [0, 0];
9973
+ const resources = setNew();
9974
+ let resourceCount = 0;
9593
9975
  let negotiated = false;
9976
+ let valid = true;
9594
9977
  const sendControl = (requestId, control, body) =>
9595
9978
  send(createMultipleControlPayload(requestId, control, body));
9596
9979
  const delChannelAndDecoder = (channelId) => {
9597
9980
  collDel(channels, channelId);
9981
+ mapGet(decoders, channelId)?.[1]();
9598
9982
  collDel(decoders, channelId);
9599
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
+ })());
9600
10015
  const handleControl = (requestId, control, body) => {
9601
10016
  if (control == 0 /* Hello */) {
9602
10017
  negotiated = true;
9603
10018
  sendControl(requestId, control, body);
9604
10019
  } else if (negotiated && control == 1 /* Subscribe */) {
9605
- 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) {
9606
10031
  const pathId = basePathId + (basePathId ? '/' : EMPTY_STRING) + body;
9607
- 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);
9608
10043
  mapSet(channels, body, channel);
9609
10044
  sendControl(requestId, control, body);
9610
10045
  if (ready) {
9611
10046
  return ready.catch((error) => {
9612
- delChannelAndDecoder(body);
10047
+ if (mapGet(channels, body) === channel) {
10048
+ delChannelAndDecoder(body);
10049
+ }
10050
+ if (!channel[1 /* Teardown */]) {
10051
+ releaseChannel(channel);
10052
+ }
9613
10053
  throw error;
9614
10054
  });
9615
10055
  }
@@ -9617,16 +10057,21 @@ const createMultipleServerClient = (
9617
10057
  }
9618
10058
  sendControl(requestId, control, body);
9619
10059
  } else if (negotiated && control == 2 /* Unsubscribe */) {
10060
+ if (isMultipleChannelIdTooLarge(body)) {
10061
+ invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'channels'));
10062
+ return;
10063
+ }
9620
10064
  const channel = mapGet(channels, body);
9621
10065
  delChannelAndDecoder(body);
9622
- if (!isUndefined(channel)) {
9623
- return (async () => delChannel(channel))();
9624
- }
10066
+ return isUndefined(channel) ? void 0 : teardownChannel(channel);
9625
10067
  }
9626
10068
  };
9627
10069
  const handlePayload = (payload) => {
10070
+ if (!valid) {
10071
+ return;
10072
+ }
9628
10073
  if (isWebSocketPayloadTooLarge(getWebSocketPayloadSize(payload))) {
9629
- invalid(errorNew(ERROR_SYNC_OVERFLOW, 'socket'));
10074
+ invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'socket'));
9630
10075
  return;
9631
10076
  }
9632
10077
  const control = ifMultipleControlPayloadValid(
@@ -9641,32 +10086,54 @@ const createMultipleServerClient = (
9641
10086
  (channelId, channelPayload) => {
9642
10087
  const channel2 = negotiated ? mapGet(channels, channelId) : void 0;
9643
10088
  if (isUndefined(channel2)) {
9644
- invalid(errorNew(ERROR_SYNC_MESSAGE));
10089
+ invalidate(errorNew(ERROR_SYNC_MESSAGE));
9645
10090
  } else {
9646
10091
  mapEnsure(decoders, channelId, () =>
9647
10092
  createPayloadDecoder(
9648
10093
  (toClientId, remainders) =>
9649
- receive(channel2, toClientId, remainders),
10094
+ receive(channel2[0 /* Channel */], toClientId, remainders),
9650
10095
  fragmentTimeoutSeconds,
9651
- invalid,
10096
+ invalidate,
10097
+ payloadBuffer,
9652
10098
  ),
9653
- )(channelPayload);
10099
+ )[0](channelPayload);
9654
10100
  }
9655
10101
  },
10102
+ () => invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'channels')),
9656
10103
  );
9657
10104
  if (!control && !channel) {
9658
- invalid(errorNew(ERROR_SYNC_MESSAGE));
10105
+ invalidate(errorNew(ERROR_SYNC_MESSAGE));
9659
10106
  }
9660
10107
  };
9661
- const destroy = () =>
9662
- tryFinallyAsync(
9663
- () =>
9664
- 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
+ },
9665
10131
  () => {
9666
10132
  collClear(channels);
9667
- collClear(decoders);
10133
+ clearDecoders();
9668
10134
  },
9669
10135
  );
10136
+ };
9670
10137
  return [handlePayload, destroy];
9671
10138
  };
9672
10139
  const createPayloads = (toClientId, requestId, message, body, fragmentSize) => {
@@ -10063,6 +10530,7 @@ const createConnection = () => {
10063
10530
  const createMultipleState = (webSocket) => {
10064
10531
  const channels = mapNew();
10065
10532
  const pendingControls = mapNew();
10533
+ const payloadBuffer = [0, 0];
10066
10534
  const removeListeners = [];
10067
10535
  let connection = createConnection();
10068
10536
  let connected = false;
@@ -10074,6 +10542,7 @@ const createMultipleState = (webSocket) => {
10074
10542
  let overflowing = false;
10075
10543
  let queuedCount = 0;
10076
10544
  let queuedSize = 0;
10545
+ let receiving = true;
10077
10546
  const notifyChannelIgnoredError = (channel, error) =>
10078
10547
  tryReturn(() => channel[6 /* OnIgnoredError */]?.(error));
10079
10548
  const notifyIgnoredError = (error) =>
@@ -10085,11 +10554,10 @@ const createMultipleState = (webSocket) => {
10085
10554
  disconnect();
10086
10555
  tryReturn(() => webSocket.close());
10087
10556
  };
10088
- const invalid = createInvalidPayloadHandler(webSocket, notifyIgnoredError);
10089
10557
  const addWebSocketListener = (event, handler) =>
10090
10558
  arrayPush(removeListeners, addEventListener(webSocket, event, handler));
10091
10559
  const rejectPendingControls = (error) =>
10092
- mapForEach(pendingControls, (requestId, [, , reject, timeout]) => {
10560
+ mapForEach(pendingControls, (requestId, [, , , reject, timeout]) => {
10093
10561
  stopTimeout(timeout);
10094
10562
  collDel(pendingControls, requestId);
10095
10563
  reject(error);
@@ -10120,11 +10588,43 @@ const createMultipleState = (webSocket) => {
10120
10588
  channel[7 /* Dirty */] = void 0;
10121
10589
  }
10122
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
+ };
10123
10621
  const overflow = (details) => {
10124
10622
  const error = errorNew(ERROR_SYNC_OVERFLOW, details);
10125
10623
  if (!overflowing && !destroyed) {
10126
10624
  overflowing = true;
10625
+ receiving = false;
10127
10626
  connected = false;
10627
+ clearReceives();
10128
10628
  notifyIgnoredError(error);
10129
10629
  rejectPendingControls(error);
10130
10630
  failChannels(error);
@@ -10133,6 +10633,7 @@ const createMultipleState = (webSocket) => {
10133
10633
  clearOutgoing(channel, true);
10134
10634
  channel[3 /* Subscribed */] = false;
10135
10635
  channel[4 /* Subscribing */] = void 0;
10636
+ channel[12 /* SubscribeConnection */] = void 0;
10136
10637
  });
10137
10638
  if (flushTimeout) {
10138
10639
  stopTimeout(flushTimeout);
@@ -10154,7 +10655,7 @@ const createMultipleState = (webSocket) => {
10154
10655
  });
10155
10656
  return timeoutSeconds;
10156
10657
  };
10157
- const sendControl = (control, body, timeoutSeconds) => {
10658
+ const sendControl = (control, body, timeoutSeconds, onSent) => {
10158
10659
  const requestId = getUniqueId();
10159
10660
  return promiseNew((resolve, reject) => {
10160
10661
  if (collSize(pendingControls) >= MAX_PENDING_REQUESTS) {
@@ -10174,9 +10675,16 @@ const createMultipleState = (webSocket) => {
10174
10675
  collDel(pendingControls, requestId);
10175
10676
  reject(errorNew(ERROR_MULTIPLEX_RESPONSE, control));
10176
10677
  }, timeoutSeconds);
10177
- mapSet(pendingControls, requestId, [control, resolve, reject, timeout]);
10678
+ mapSet(pendingControls, requestId, [
10679
+ control,
10680
+ body,
10681
+ resolve,
10682
+ reject,
10683
+ timeout,
10684
+ ]);
10178
10685
  try {
10179
10686
  webSocket.send(payload);
10687
+ onSent?.();
10180
10688
  } catch (error) {
10181
10689
  stopTimeout(timeout);
10182
10690
  collDel(pendingControls, requestId);
@@ -10359,23 +10867,45 @@ const createMultipleState = (webSocket) => {
10359
10867
  const subscribe = async (channelId, channel, timeoutSeconds) => {
10360
10868
  if (!channel[3 /* Subscribed */]) {
10361
10869
  let subscribing = channel[4 /* Subscribing */];
10362
- if (!subscribing) {
10363
- subscribing = (async () => {
10364
- 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
+ }
10365
10881
  await sendControl(
10366
10882
  MultipleControl.Subscribe,
10367
10883
  channelId,
10368
10884
  timeoutSeconds,
10885
+ () => {
10886
+ if (
10887
+ mapGet(channels, channelId) === channel &&
10888
+ connection === subscribingConnection &&
10889
+ connected
10890
+ ) {
10891
+ channel[12 /* SubscribeConnection */] = subscribingConnection;
10892
+ }
10893
+ },
10369
10894
  );
10370
- if (mapGet(channels, channelId) === channel && connected) {
10895
+ if (
10896
+ mapGet(channels, channelId) === channel &&
10897
+ connection === subscribingConnection &&
10898
+ connected
10899
+ ) {
10371
10900
  channel[3 /* Subscribed */] = true;
10372
10901
  flushOutgoing(channelId, channel);
10373
10902
  }
10374
10903
  })();
10904
+ subscribing = [subscribingConnection, subscribingPromise];
10375
10905
  channel[4 /* Subscribing */] = subscribing;
10376
10906
  }
10377
10907
  try {
10378
- await subscribing;
10908
+ await subscribing[1];
10379
10909
  } finally {
10380
10910
  if (channel[4 /* Subscribing */] === subscribing) {
10381
10911
  channel[4 /* Subscribing */] = void 0;
@@ -10384,7 +10914,7 @@ const createMultipleState = (webSocket) => {
10384
10914
  }
10385
10915
  };
10386
10916
  const onOpen = () => {
10387
- if (destroyed || opening?.[0] === connection) {
10917
+ if (destroyed || !receiving || connected || opening?.[0] === connection) {
10388
10918
  return;
10389
10919
  }
10390
10920
  disconnected = false;
@@ -10397,7 +10927,7 @@ const createMultipleState = (webSocket) => {
10397
10927
  MULTIPLE_VERSION,
10398
10928
  getConnectionTimeoutSeconds(),
10399
10929
  );
10400
- if (connection === openingConnection) {
10930
+ if (connection === openingConnection && receiving && !destroyed) {
10401
10931
  connected = true;
10402
10932
  openingConnection[1]();
10403
10933
  mapForEach(channels, (channelId, channel) =>
@@ -10445,13 +10975,18 @@ const createMultipleState = (webSocket) => {
10445
10975
  }
10446
10976
  connection = createConnection();
10447
10977
  mapForEach(channels, (_channelId, channel) => {
10978
+ clearReceive(channel);
10448
10979
  channel[3 /* Subscribed */] = false;
10449
10980
  channel[4 /* Subscribing */] = void 0;
10981
+ channel[12 /* SubscribeConnection */] = void 0;
10450
10982
  });
10451
10983
  }
10452
10984
  };
10453
10985
  const onClose = disconnect;
10454
10986
  addWebSocketListener(MESSAGE, ({data}) => {
10987
+ if (!receiving) {
10988
+ return;
10989
+ }
10455
10990
  const payload = data.toString(UTF8);
10456
10991
  if (isWebSocketPayloadTooLarge(getWebSocketPayloadSize(payload))) {
10457
10992
  invalid(errorNew(ERROR_SYNC_OVERFLOW, 'socket'));
@@ -10459,14 +10994,23 @@ const createMultipleState = (webSocket) => {
10459
10994
  }
10460
10995
  const control = ifMultipleControlPayloadValid(
10461
10996
  payload,
10462
- (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
+ }
10463
11007
  const pendingControl = requestId
10464
11008
  ? mapGet(pendingControls, requestId)
10465
11009
  : void 0;
10466
- if (pendingControl?.[0] == control2) {
10467
- stopTimeout(pendingControl[3]);
11010
+ if (pendingControl?.[0] == control2 && pendingControl[1] === body) {
11011
+ stopTimeout(pendingControl[4]);
10468
11012
  collDel(pendingControls, requestId);
10469
- pendingControl[1]();
11013
+ pendingControl[2]();
10470
11014
  }
10471
11015
  },
10472
11016
  );
@@ -10476,7 +11020,7 @@ const createMultipleState = (webSocket) => {
10476
11020
  const channel2 = mapGet(channels, channelId);
10477
11021
  if (channel2) {
10478
11022
  if (channel2[0 /* Receive */]) {
10479
- channel2[0 /* Receive */](channelPayload);
11023
+ channel2[0 /* Receive */][0](channelPayload);
10480
11024
  } else {
10481
11025
  queueIncoming(channel2, channelPayload);
10482
11026
  }
@@ -10484,6 +11028,7 @@ const createMultipleState = (webSocket) => {
10484
11028
  invalid(errorNew(ERROR_SYNC_MESSAGE));
10485
11029
  }
10486
11030
  },
11031
+ () => overflow('channels'),
10487
11032
  );
10488
11033
  if (!control && !channel) {
10489
11034
  invalid(errorNew(ERROR_SYNC_MESSAGE));
@@ -10496,12 +11041,18 @@ const createMultipleState = (webSocket) => {
10496
11041
  failChannels(errorNew(ERROR_MULTIPLEX_SOCKET));
10497
11042
  });
10498
11043
  const addChannel = async (channelId, timeoutSeconds, onIgnoredError) => {
11044
+ if (!receiving || destroyed) {
11045
+ errorThrow(ERROR_MULTIPLEX_SOCKET);
11046
+ }
10499
11047
  if (!isMultipleChannelIdValid(channelId)) {
10500
11048
  errorThrow(ERROR_MULTIPLEX_CHANNEL, channelId);
10501
11049
  }
10502
11050
  if (collHas(channels, channelId)) {
10503
11051
  errorThrow(ERROR_MULTIPLEX_CHANNEL_DUPLICATE, channelId);
10504
11052
  }
11053
+ if (collSize(channels) >= MAX_MULTIPLE_CHANNELS) {
11054
+ errorThrow(ERROR_SYNC_OVERFLOW, 'channels');
11055
+ }
10505
11056
  const channel = [
10506
11057
  void 0,
10507
11058
  [],
@@ -10515,6 +11066,7 @@ const createMultipleState = (webSocket) => {
10515
11066
  0,
10516
11067
  0,
10517
11068
  void 0,
11069
+ void 0,
10518
11070
  ];
10519
11071
  mapSet(channels, channelId, channel);
10520
11072
  if (webSocket.readyState == webSocket.OPEN) {
@@ -10548,7 +11100,7 @@ const createMultipleState = (webSocket) => {
10548
11100
  queuedCount--;
10549
11101
  queuedSize -= payloadSize;
10550
11102
  incomingIndex++;
10551
- receive(payload);
11103
+ receive[0](payload);
10552
11104
  }
10553
11105
  },
10554
11106
  () => arrayClear(incoming, incomingIndex),
@@ -10556,6 +11108,9 @@ const createMultipleState = (webSocket) => {
10556
11108
  }
10557
11109
  };
10558
11110
  const send = (channelId, payloads, coalesce) => {
11111
+ if (!receiving) {
11112
+ return;
11113
+ }
10559
11114
  const channel = mapGet(channels, channelId);
10560
11115
  if (channel) {
10561
11116
  if (
@@ -10576,6 +11131,9 @@ const createMultipleState = (webSocket) => {
10576
11131
  const destroyIfEmpty = () => {
10577
11132
  if (collIsEmpty(channels) && !destroyed) {
10578
11133
  destroyed = true;
11134
+ const closeWebSocket = receiving && !overflowing;
11135
+ receiving = false;
11136
+ clearReceives();
10579
11137
  const error = errorNew(ERROR_MULTIPLEX_DESTROYED);
10580
11138
  rejectPendingControls(error);
10581
11139
  if (flushTimeout) {
@@ -10587,7 +11145,7 @@ const createMultipleState = (webSocket) => {
10587
11145
  );
10588
11146
  arrayClear(removeListeners);
10589
11147
  multipleStates.delete(webSocket);
10590
- if (!overflowing) {
11148
+ if (closeWebSocket) {
10591
11149
  tryReturn(() => webSocket.close());
10592
11150
  }
10593
11151
  }
@@ -10596,9 +11154,10 @@ const createMultipleState = (webSocket) => {
10596
11154
  const channel = mapGet(channels, channelId);
10597
11155
  if (channel) {
10598
11156
  try {
11157
+ clearReceive(channel);
10599
11158
  clearIncoming(channel);
10600
11159
  clearOutgoing(channel, true);
10601
- if (connected && channel[3 /* Subscribed */]) {
11160
+ if (connected && channel[12 /* SubscribeConnection */] === connection) {
10602
11161
  const payload = createMultipleControlPayload(
10603
11162
  null,
10604
11163
  MultipleControl.Unsubscribe,
@@ -10627,6 +11186,7 @@ const createMultipleState = (webSocket) => {
10627
11186
  delChannel,
10628
11187
  destroyIfEmpty,
10629
11188
  invalid,
11189
+ payloadBuffer,
10630
11190
  registerReceive,
10631
11191
  send,
10632
11192
  };
@@ -10682,7 +11242,12 @@ const createMultipleWsSynchronizer = async (
10682
11242
  (receive, fail) =>
10683
11243
  state.registerReceive(
10684
11244
  channelId,
10685
- createPayloadReceiver(receive, requestTimeoutSeconds, state.invalid),
11245
+ createPayloadReceiver(
11246
+ receive,
11247
+ requestTimeoutSeconds,
11248
+ state.invalid,
11249
+ state.payloadBuffer,
11250
+ ),
10686
11251
  fail,
10687
11252
  ),
10688
11253
  () => state.delChannel(channelId),
@@ -10724,13 +11289,14 @@ const createLegacyWsSynchronizer = async (
10724
11289
  };
10725
11290
  const registerReceive = (receive, fail) => {
10726
11291
  const invalid = createInvalidPayloadHandler(webSocket, notifyIgnoredError);
10727
- const receivePayload = createPayloadReceiver(
11292
+ const [receivePayload, clearReceivePayload] = createPayloadReceiver(
10728
11293
  receive,
10729
11294
  requestTimeoutSeconds,
10730
11295
  invalid,
10731
11296
  );
10732
11297
  let removeListeners = [];
10733
11298
  removeTransportListeners = () => {
11299
+ clearReceivePayload();
10734
11300
  arrayForEach(removeListeners, (removeListener) =>
10735
11301
  tryReturn(removeListener),
10736
11302
  );
@@ -10900,7 +11466,7 @@ class WsServerDurableObject extends DurableObject {
10900
11466
  (this.#serverClientSend = createPayloadReceiver(
10901
11467
  receive,
10902
11468
  requestTimeoutSeconds,
10903
- )),
11469
+ )[0]),
10904
11470
  noop,
10905
11471
  requestTimeoutSeconds,
10906
11472
  );
@@ -10948,10 +11514,11 @@ class WsServerDurableObject extends DurableObject {
10948
11514
  );
10949
11515
  this.#payloadDecoders.set(client, decode);
10950
11516
  }
10951
- decode(message.toString());
11517
+ decode[0](message.toString());
10952
11518
  });
10953
11519
  }
10954
11520
  webSocketClose(client) {
11521
+ this.#payloadDecoders.get(client)?.[1]();
10955
11522
  this.#payloadDecoders.delete(client);
10956
11523
  const [clientId, pathId] = this.ctx.getTags(client);
10957
11524
  this.onClientId(pathId, clientId, -1);
@@ -11104,7 +11671,7 @@ const createWsServerSimple = (webSocketServer) => {
11104
11671
  };
11105
11672
  const addLegacyClient = (client, clientId, pathId) => {
11106
11673
  addClientToPath(pathId, clientId, [client]);
11107
- const decode = createPayloadDecoder(
11674
+ const [decode, clearDecoder] = createPayloadDecoder(
11108
11675
  (toClientId, remainders) =>
11109
11676
  handleDecodedMessage(pathId, clientId, toClientId, remainders),
11110
11677
  1,
@@ -11113,8 +11680,10 @@ const createWsServerSimple = (webSocketServer) => {
11113
11680
  addWebSocketListener(client, MESSAGE, (data) =>
11114
11681
  decode(data.toString(UTF8)),
11115
11682
  );
11116
- mapGet(webSocketStates, client)[1] = () =>
11683
+ mapGet(webSocketStates, client)[1] = () => {
11684
+ clearDecoder();
11117
11685
  delClientFromPath(pathId, clientId);
11686
+ };
11118
11687
  };
11119
11688
  const addMultipleClient = (client, clientId, basePathId) => {
11120
11689
  const invalid = createInvalidPayloadHandler(client);
@@ -11244,6 +11813,7 @@ const createWsServer = (
11244
11813
  const clientIdListeners = mapNew();
11245
11814
  const paths = mapNew();
11246
11815
  const webSockets = setNew();
11816
+ const buffersByWebSocket = mapNew();
11247
11817
  const removeServerListeners = [];
11248
11818
  const removeListenersByWebSocket = mapNew();
11249
11819
  let destroying;
@@ -11293,7 +11863,7 @@ const createWsServer = (
11293
11863
  serverClient[3 /* Send */] = createPayloadReceiver(
11294
11864
  receive,
11295
11865
  requestTimeoutSeconds,
11296
- );
11866
+ )[0];
11297
11867
  },
11298
11868
  noop,
11299
11869
  requestTimeoutSeconds,
@@ -11357,18 +11927,37 @@ const createWsServer = (
11357
11927
  client.send(outgoingPayload);
11358
11928
  }
11359
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));
11360
11942
  const clearServerBuffer = (serverClient) => {
11361
11943
  if (serverClient[7 /* BufferTimeout */]) {
11362
11944
  stopTimeout(serverClient[7 /* BufferTimeout */]);
11363
11945
  serverClient[7 /* BufferTimeout */] = void 0;
11364
11946
  }
11947
+ arrayForEach(serverClient[4 /* Buffer */], delBufferedFromWebSocket);
11365
11948
  serverClient[4 /* Buffer */] = [];
11366
11949
  serverClient[6 /* BufferSize */] = 0;
11367
11950
  };
11368
11951
  const delBufferedClient = (serverClient, clientId) => {
11369
11952
  serverClient[4 /* Buffer */] = arrayFilter(
11370
11953
  serverClient[4 /* Buffer */],
11371
- ([bufferedClientId]) => bufferedClientId != clientId,
11954
+ (buffered) => {
11955
+ if (buffered[0] == clientId) {
11956
+ delBufferedFromWebSocket(buffered);
11957
+ return false;
11958
+ }
11959
+ return true;
11960
+ },
11372
11961
  );
11373
11962
  serverClient[6 /* BufferSize */] = arrayReduce(
11374
11963
  serverClient[4 /* Buffer */],
@@ -11382,10 +11971,8 @@ const createWsServer = (
11382
11971
  const expireServerBuffer = (path) => {
11383
11972
  const serverClient = path[1 /* ServerClient */];
11384
11973
  const clients = setNew();
11385
- arrayForEach(serverClient[4 /* Buffer */], ([clientId]) =>
11386
- ifNotUndefined(mapGet(path[0 /* Clients */], clientId), ([client]) =>
11387
- setAdd(clients, client),
11388
- ),
11974
+ arrayForEach(serverClient[4 /* Buffer */], ([, , , client]) =>
11975
+ setAdd(clients, client),
11389
11976
  );
11390
11977
  clearServerBuffer(serverClient);
11391
11978
  arrayForEach(collValues(clients), (client) =>
@@ -11395,6 +11982,10 @@ const createWsServer = (
11395
11982
  const bufferMessage = (path, clientId, payload) => {
11396
11983
  const serverClient = path[1 /* ServerClient */];
11397
11984
  const buffer = serverClient[4 /* Buffer */];
11985
+ const webSocket = mapGet(path[0 /* Clients */], clientId)?.[0];
11986
+ if (isUndefined(webSocket)) {
11987
+ return;
11988
+ }
11398
11989
  const coalesceKey = getPayloadCoalesceKey(clientId, payload);
11399
11990
  const coalesceIndex = coalesceKey
11400
11991
  ? arrayFindIndex(
@@ -11402,14 +11993,22 @@ const createWsServer = (
11402
11993
  ([, , bufferedKey]) => bufferedKey == coalesceKey,
11403
11994
  )
11404
11995
  : -1;
11405
- const replacedSize =
11406
- coalesceIndex > -1
11407
- ? getWebSocketPayloadSize(buffer[coalesceIndex][1])
11408
- : 0;
11996
+ const replaced = coalesceIndex > -1 ? buffer[coalesceIndex] : void 0;
11997
+ const replacedSize = isUndefined(replaced)
11998
+ ? 0
11999
+ : getWebSocketPayloadSize(replaced[1]);
11409
12000
  const payloadSize = getWebSocketPayloadSize(payload);
12001
+ const webSocketBuffer = mapGet(buffersByWebSocket, webSocket);
12002
+ const sameWebSocket = replaced?.[3] === webSocket;
11410
12003
  if (
11411
12004
  (coalesceIndex < 0 && size(buffer) >= MAX_WEBSOCKET_QUEUE_SIZE) ||
11412
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) >
11413
12012
  MAX_WEBSOCKET_BUFFER_SIZE
11414
12013
  ) {
11415
12014
  delBufferedClient(serverClient, clientId);
@@ -11418,12 +12017,14 @@ const createWsServer = (
11418
12017
  );
11419
12018
  return;
11420
12019
  }
11421
- const buffered = [clientId, payload, coalesceKey];
12020
+ const buffered = [clientId, payload, coalesceKey, webSocket];
11422
12021
  if (coalesceIndex > -1) {
12022
+ delBufferedFromWebSocket(buffer[coalesceIndex]);
11423
12023
  buffer[coalesceIndex] = buffered;
11424
12024
  } else {
11425
12025
  arrayPush(buffer, buffered);
11426
12026
  }
12027
+ updateWebSocketBuffer(webSocket, 1, payloadSize);
11427
12028
  serverClient[6 /* BufferSize */] += payloadSize - replacedSize;
11428
12029
  serverClient[7 /* BufferTimeout */] ??= startTimeout(
11429
12030
  () => expireServerBuffer(path),
@@ -11582,7 +12183,7 @@ const createWsServer = (
11582
12183
  };
11583
12184
  const addLegacyClient = async (client, clientId, pathId) => {
11584
12185
  const [path, ready] = addClientToPath(pathId, clientId, [client]);
11585
- const decode = createPayloadDecoder(
12186
+ const [decode, clearDecoder] = createPayloadDecoder(
11586
12187
  (toClientId, remainders) =>
11587
12188
  handleDecodedMessage(path, clientId, toClientId, remainders),
11588
12189
  requestTimeoutSeconds,
@@ -11591,9 +12192,10 @@ const createWsServer = (
11591
12192
  addWebSocketListener(client, MESSAGE, (data) =>
11592
12193
  decode(data.toString(UTF8)),
11593
12194
  );
11594
- addWebSocketListener(client, CLOSE, () =>
11595
- delClientFromPath(pathId, path, clientId).catch(handleError),
11596
- );
12195
+ addWebSocketListener(client, CLOSE, () => {
12196
+ clearDecoder();
12197
+ delClientFromPath(pathId, path, clientId).catch(handleError);
12198
+ });
11597
12199
  await ready;
11598
12200
  };
11599
12201
  const addMultipleClient = (client, clientId, basePathId) => {
@@ -11738,6 +12340,7 @@ const createWsServer = (
11738
12340
  arrayForEach(removers, (remove) => tryReturn(remove)),
11739
12341
  );
11740
12342
  collClear(removeListenersByWebSocket);
12343
+ collClear(buffersByWebSocket);
11741
12344
  collClear(paths);
11742
12345
  collClear(webSockets);
11743
12346
  const failure = serverFailure[0]