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.
- package/@types/persisters/index.d.ts +4 -0
- package/@types/persisters/persister-durable-object-sql-storage/index.d.ts +9 -2
- package/@types/persisters/persister-durable-object-sql-storage/with-schemas/index.d.ts +9 -2
- package/@types/persisters/with-schemas/index.d.ts +4 -0
- package/@types/queries/index.d.ts +145 -7
- package/@types/queries/with-schemas/index.d.ts +157 -7
- package/@types/synchronizers/synchronizer-ws-client/index.d.ts +7 -3
- package/@types/synchronizers/synchronizer-ws-client/with-schemas/index.d.ts +7 -3
- package/@types/synchronizers/synchronizer-ws-server/index.d.ts +9 -3
- package/@types/synchronizers/synchronizer-ws-server/with-schemas/index.d.ts +9 -3
- package/@types/synchronizers/synchronizer-ws-server-simple/index.d.ts +6 -3
- package/@types/synchronizers/synchronizer-ws-server-simple/with-schemas/index.d.ts +6 -3
- package/index.js +315 -22
- package/min/index.js +1 -1
- package/min/index.js.gz +0 -0
- package/min/omni/index.js +1 -1
- package/min/omni/index.js.gz +0 -0
- package/min/omni/with-schemas/index.js +1 -1
- package/min/omni/with-schemas/index.js.gz +0 -0
- package/min/persisters/index.js +1 -1
- package/min/persisters/index.js.gz +0 -0
- package/min/persisters/persister-automerge/index.js +1 -1
- package/min/persisters/persister-automerge/index.js.gz +0 -0
- package/min/persisters/persister-automerge/with-schemas/index.js +1 -1
- package/min/persisters/persister-automerge/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-browser/index.js +1 -1
- package/min/persisters/persister-browser/index.js.gz +0 -0
- package/min/persisters/persister-browser/with-schemas/index.js +1 -1
- package/min/persisters/persister-browser/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-cr-sqlite-wasm/index.js +1 -1
- package/min/persisters/persister-cr-sqlite-wasm/index.js.gz +0 -0
- package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +1 -1
- package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-durable-object-sql-storage/index.js +1 -1
- package/min/persisters/persister-durable-object-sql-storage/index.js.gz +0 -0
- package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js +1 -1
- package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-durable-object-storage/index.js +1 -1
- package/min/persisters/persister-durable-object-storage/index.js.gz +0 -0
- package/min/persisters/persister-durable-object-storage/with-schemas/index.js +1 -1
- package/min/persisters/persister-durable-object-storage/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-electric-sql/index.js +1 -1
- package/min/persisters/persister-electric-sql/index.js.gz +0 -0
- package/min/persisters/persister-electric-sql/with-schemas/index.js +1 -1
- package/min/persisters/persister-electric-sql/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-expo-sqlite/index.js +1 -1
- package/min/persisters/persister-expo-sqlite/index.js.gz +0 -0
- package/min/persisters/persister-expo-sqlite/with-schemas/index.js +1 -1
- package/min/persisters/persister-expo-sqlite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-file/index.js +1 -1
- package/min/persisters/persister-file/index.js.gz +0 -0
- package/min/persisters/persister-file/with-schemas/index.js +1 -1
- package/min/persisters/persister-file/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-indexed-db/index.js +1 -1
- package/min/persisters/persister-indexed-db/index.js.gz +0 -0
- package/min/persisters/persister-indexed-db/with-schemas/index.js +1 -1
- package/min/persisters/persister-indexed-db/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-libsql/index.js +1 -1
- package/min/persisters/persister-libsql/index.js.gz +0 -0
- package/min/persisters/persister-libsql/with-schemas/index.js +1 -1
- package/min/persisters/persister-libsql/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-partykit-client/index.js +1 -1
- package/min/persisters/persister-partykit-client/index.js.gz +0 -0
- package/min/persisters/persister-partykit-client/with-schemas/index.js +1 -1
- package/min/persisters/persister-partykit-client/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-pglite/index.js +1 -1
- package/min/persisters/persister-pglite/index.js.gz +0 -0
- package/min/persisters/persister-pglite/with-schemas/index.js +1 -1
- package/min/persisters/persister-pglite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-postgres/index.js +1 -1
- package/min/persisters/persister-postgres/index.js.gz +0 -0
- package/min/persisters/persister-postgres/with-schemas/index.js +1 -1
- package/min/persisters/persister-postgres/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-powersync/index.js +1 -1
- package/min/persisters/persister-powersync/index.js.gz +0 -0
- package/min/persisters/persister-powersync/with-schemas/index.js +1 -1
- package/min/persisters/persister-powersync/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-react-native-mmkv/index.js +1 -1
- package/min/persisters/persister-react-native-mmkv/index.js.gz +0 -0
- package/min/persisters/persister-react-native-mmkv/with-schemas/index.js +1 -1
- package/min/persisters/persister-react-native-mmkv/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-react-native-sqlite/index.js +1 -1
- package/min/persisters/persister-react-native-sqlite/index.js.gz +0 -0
- package/min/persisters/persister-react-native-sqlite/with-schemas/index.js +1 -1
- package/min/persisters/persister-react-native-sqlite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-remote/index.js +1 -1
- package/min/persisters/persister-remote/index.js.gz +0 -0
- package/min/persisters/persister-remote/with-schemas/index.js +1 -1
- package/min/persisters/persister-remote/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-bun/index.js +1 -1
- package/min/persisters/persister-sqlite-bun/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-bun/with-schemas/index.js +1 -1
- package/min/persisters/persister-sqlite-bun/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-wasm/index.js +1 -1
- package/min/persisters/persister-sqlite-wasm/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-wasm/with-schemas/index.js +1 -1
- package/min/persisters/persister-sqlite-wasm/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-sqlite3/index.js +1 -1
- package/min/persisters/persister-sqlite3/index.js.gz +0 -0
- package/min/persisters/persister-sqlite3/with-schemas/index.js +1 -1
- package/min/persisters/persister-sqlite3/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-yjs/index.js +1 -1
- package/min/persisters/persister-yjs/index.js.gz +0 -0
- package/min/persisters/persister-yjs/with-schemas/index.js +1 -1
- package/min/persisters/persister-yjs/with-schemas/index.js.gz +0 -0
- package/min/persisters/with-schemas/index.js +1 -1
- package/min/persisters/with-schemas/index.js.gz +0 -0
- package/min/queries/index.js +1 -1
- package/min/queries/index.js.gz +0 -0
- package/min/queries/with-schemas/index.js +1 -1
- package/min/queries/with-schemas/index.js.gz +0 -0
- package/min/synchronizers/index.js +1 -1
- package/min/synchronizers/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-broadcast-channel/index.js +1 -1
- package/min/synchronizers/synchronizer-broadcast-channel/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js +1 -1
- package/min/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-local/index.js +1 -1
- package/min/synchronizers/synchronizer-local/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-local/with-schemas/index.js +1 -1
- package/min/synchronizers/synchronizer-local/with-schemas/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-ws-client/index.js +1 -1
- package/min/synchronizers/synchronizer-ws-client/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-ws-client/with-schemas/index.js +1 -1
- package/min/synchronizers/synchronizer-ws-client/with-schemas/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-ws-server/index.js +1 -1
- package/min/synchronizers/synchronizer-ws-server/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-ws-server/with-schemas/index.js +1 -1
- package/min/synchronizers/synchronizer-ws-server/with-schemas/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-ws-server-durable-object/index.js +1 -1
- package/min/synchronizers/synchronizer-ws-server-durable-object/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +1 -1
- package/min/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-ws-server-simple/index.js +1 -1
- package/min/synchronizers/synchronizer-ws-server-simple/index.js.gz +0 -0
- package/min/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js +1 -1
- package/min/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js.gz +0 -0
- package/min/synchronizers/with-schemas/index.js +1 -1
- package/min/synchronizers/with-schemas/index.js.gz +0 -0
- package/min/ui-react-inspector/index.js +1 -1
- package/min/ui-react-inspector/index.js.gz +0 -0
- package/min/ui-react-inspector/with-schemas/index.js +1 -1
- package/min/ui-react-inspector/with-schemas/index.js.gz +0 -0
- package/min/ui-solid-inspector/index.js +1 -1
- package/min/ui-solid-inspector/index.js.gz +0 -0
- package/min/ui-solid-inspector/with-schemas/index.js +1 -1
- package/min/ui-solid-inspector/with-schemas/index.js.gz +0 -0
- package/min/ui-svelte-inspector/index.js +1 -1
- package/min/ui-svelte-inspector/index.js.gz +0 -0
- package/min/ui-svelte-inspector/with-schemas/index.js +1 -1
- package/min/ui-svelte-inspector/with-schemas/index.js.gz +0 -0
- package/min/with-schemas/index.js +1 -1
- package/min/with-schemas/index.js.gz +0 -0
- package/omni/index.js +730 -127
- package/omni/with-schemas/index.js +730 -127
- package/package.json +8 -4
- package/persisters/index.js +49 -10
- package/persisters/persister-automerge/index.js +29 -5
- package/persisters/persister-automerge/with-schemas/index.js +29 -5
- package/persisters/persister-browser/index.js +29 -5
- package/persisters/persister-browser/with-schemas/index.js +29 -5
- package/persisters/persister-cr-sqlite-wasm/index.js +29 -5
- package/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +29 -5
- package/persisters/persister-durable-object-sql-storage/index.js +44 -8
- package/persisters/persister-durable-object-sql-storage/with-schemas/index.js +44 -8
- package/persisters/persister-durable-object-storage/index.js +31 -5
- package/persisters/persister-durable-object-storage/with-schemas/index.js +31 -5
- package/persisters/persister-electric-sql/index.js +29 -5
- package/persisters/persister-electric-sql/with-schemas/index.js +29 -5
- package/persisters/persister-expo-sqlite/index.js +29 -5
- package/persisters/persister-expo-sqlite/with-schemas/index.js +29 -5
- package/persisters/persister-file/index.js +31 -5
- package/persisters/persister-file/with-schemas/index.js +31 -5
- package/persisters/persister-indexed-db/index.js +29 -5
- package/persisters/persister-indexed-db/with-schemas/index.js +29 -5
- package/persisters/persister-libsql/index.js +29 -5
- package/persisters/persister-libsql/with-schemas/index.js +29 -5
- package/persisters/persister-partykit-client/index.js +31 -5
- package/persisters/persister-partykit-client/with-schemas/index.js +31 -5
- package/persisters/persister-pglite/index.js +49 -10
- package/persisters/persister-pglite/with-schemas/index.js +49 -10
- package/persisters/persister-postgres/index.js +49 -10
- package/persisters/persister-postgres/with-schemas/index.js +49 -10
- package/persisters/persister-powersync/index.js +29 -5
- package/persisters/persister-powersync/with-schemas/index.js +29 -5
- package/persisters/persister-react-native-mmkv/index.js +31 -5
- package/persisters/persister-react-native-mmkv/with-schemas/index.js +31 -5
- package/persisters/persister-react-native-sqlite/index.js +29 -5
- package/persisters/persister-react-native-sqlite/with-schemas/index.js +29 -5
- package/persisters/persister-remote/index.js +31 -5
- package/persisters/persister-remote/with-schemas/index.js +31 -5
- package/persisters/persister-sqlite-bun/index.js +29 -5
- package/persisters/persister-sqlite-bun/with-schemas/index.js +29 -5
- package/persisters/persister-sqlite-wasm/index.js +29 -5
- package/persisters/persister-sqlite-wasm/with-schemas/index.js +29 -5
- package/persisters/persister-sqlite3/index.js +29 -5
- package/persisters/persister-sqlite3/with-schemas/index.js +29 -5
- package/persisters/persister-yjs/index.js +29 -5
- package/persisters/persister-yjs/with-schemas/index.js +29 -5
- package/persisters/with-schemas/index.js +49 -10
- package/queries/index.js +334 -22
- package/queries/with-schemas/index.js +334 -22
- package/readme.md +14 -14
- package/releases.md +84 -67
- package/synchronizers/index.js +31 -5
- package/synchronizers/synchronizer-broadcast-channel/index.js +39 -13
- package/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js +39 -13
- package/synchronizers/synchronizer-local/index.js +31 -5
- package/synchronizers/synchronizer-local/with-schemas/index.js +31 -5
- package/synchronizers/synchronizer-ws-client/index.js +220 -61
- package/synchronizers/synchronizer-ws-client/with-schemas/index.js +220 -61
- package/synchronizers/synchronizer-ws-server/index.js +253 -73
- package/synchronizers/synchronizer-ws-server/with-schemas/index.js +253 -73
- package/synchronizers/synchronizer-ws-server-durable-object/index.js +88 -40
- package/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +88 -40
- package/synchronizers/synchronizer-ws-server-simple/index.js +184 -60
- package/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js +184 -60
- package/synchronizers/with-schemas/index.js +31 -5
- package/ui-react-inspector/index.js +29 -5
- package/ui-react-inspector/with-schemas/index.js +29 -5
- package/ui-solid-inspector/index.js +29 -5
- package/ui-solid-inspector/with-schemas/index.js +29 -5
- package/ui-svelte-inspector/index.js +29 -5
- package/ui-svelte-inspector/with-schemas/index.js +29 -5
- package/with-schemas/index.js +315 -22
package/omni/index.js
CHANGED
|
@@ -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
|
-
|
|
4908
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
6500
|
-
|
|
6501
|
-
|
|
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
|
|
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
|
|
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
|
-
? [
|
|
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
|
-
|
|
8594
|
+
selectCount++;
|
|
8595
|
+
arrayPush(selectionEntries, selectEntry);
|
|
8430
8596
|
return {
|
|
8431
|
-
as: (selectedCellId) => (selectEntry[
|
|
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
|
-
|
|
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
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
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
|
-
|
|
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 = [
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
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] +=
|
|
9451
|
-
bufferedSize +=
|
|
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 (
|
|
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
|
-
|
|
9942
|
+
(isMultipleChannelIdTooLarge(body) ||
|
|
9943
|
+
isMultipleChannelIdStructureValid(body))
|
|
9562
9944
|
: control == 2 /* Unsubscribe */ &&
|
|
9563
9945
|
isNull(requestId) &&
|
|
9564
9946
|
isString(body) &&
|
|
9565
|
-
|
|
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
|
-
!
|
|
9576
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10105
|
+
invalidate(errorNew(ERROR_SYNC_MESSAGE));
|
|
9659
10106
|
}
|
|
9660
10107
|
};
|
|
9661
|
-
const destroy = () =>
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
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
|
-
|
|
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, [
|
|
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
|
-
|
|
10363
|
-
|
|
10364
|
-
|
|
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 (
|
|
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,
|
|
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[
|
|
11010
|
+
if (pendingControl?.[0] == control2 && pendingControl[1] === body) {
|
|
11011
|
+
stopTimeout(pendingControl[4]);
|
|
10468
11012
|
collDel(pendingControls, requestId);
|
|
10469
|
-
pendingControl[
|
|
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 (
|
|
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[
|
|
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(
|
|
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
|
-
(
|
|
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 */], ([
|
|
11386
|
-
|
|
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
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
|
|
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
|
-
|
|
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]
|