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