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
|
@@ -113,6 +113,8 @@ const tryCatch = async (action, onError) => {
|
|
|
113
113
|
onError?.(error);
|
|
114
114
|
}
|
|
115
115
|
};
|
|
116
|
+
const tryCatchIgnore = (action, onIgnoredError) =>
|
|
117
|
+
tryCatch(action, (error) => void tryCatch(() => onIgnoredError?.(error)));
|
|
116
118
|
const tryCatchSync = (action, onError) => {
|
|
117
119
|
try {
|
|
118
120
|
return action();
|
|
@@ -434,6 +436,9 @@ const FRAGMENT_PAYLOAD = /^[^\n]*\n[-0-9A-Z_a-z]{16}\n\d+\n\d+\n/;
|
|
|
434
436
|
const INVALID_CHANNEL_ID_CHARACTERS = /[\n\r?#]/;
|
|
435
437
|
const MAX_FRAGMENT_BUFFERS = 100;
|
|
436
438
|
const MAX_FRAGMENT_COUNT = 1e3;
|
|
439
|
+
const MAX_MULTIPLE_CHANNELS = 100;
|
|
440
|
+
const MAX_MULTIPLE_CHANNEL_RESOURCES = MAX_MULTIPLE_CHANNELS * 2;
|
|
441
|
+
const MAX_MULTIPLE_CHANNEL_ID_SIZE = 1024;
|
|
437
442
|
const MAX_PENDING_REQUESTS = 100;
|
|
438
443
|
const MAX_WEBSOCKET_BUFFER_SIZE = 16777216;
|
|
439
444
|
const MAX_WEBSOCKET_QUEUE_SIZE = 1e3;
|
|
@@ -566,21 +571,30 @@ const createPayloadDecoder = (
|
|
|
566
571
|
receive,
|
|
567
572
|
fragmentTimeoutSeconds = 1,
|
|
568
573
|
onInvalid,
|
|
574
|
+
sharedBuffer,
|
|
569
575
|
) => {
|
|
570
576
|
const buffer = mapNew();
|
|
577
|
+
const payloadBuffer = sharedBuffer ?? [0, 0];
|
|
571
578
|
let bufferedSize = 0;
|
|
572
579
|
let valid = true;
|
|
573
580
|
const delPending = (bufferKey, pending) => {
|
|
574
581
|
stopTimeout(pending[4]);
|
|
575
582
|
bufferedSize -= pending[5];
|
|
583
|
+
payloadBuffer[0]--;
|
|
584
|
+
payloadBuffer[1] -= pending[5];
|
|
576
585
|
collDel(buffer, bufferKey);
|
|
577
586
|
};
|
|
587
|
+
const clear = () => {
|
|
588
|
+
mapForEach(buffer, (_bufferKey, pending) => stopTimeout(pending[4]));
|
|
589
|
+
payloadBuffer[0] -= collSize(buffer);
|
|
590
|
+
payloadBuffer[1] -= bufferedSize;
|
|
591
|
+
collClear(buffer);
|
|
592
|
+
bufferedSize = 0;
|
|
593
|
+
};
|
|
578
594
|
const invalid = (error = errorNew(ERROR_SYNC_MESSAGE)) => {
|
|
579
595
|
if (valid) {
|
|
580
596
|
valid = false;
|
|
581
|
-
|
|
582
|
-
collClear(buffer);
|
|
583
|
-
bufferedSize = 0;
|
|
597
|
+
clear();
|
|
584
598
|
onInvalid?.(error);
|
|
585
599
|
}
|
|
586
600
|
};
|
|
@@ -592,7 +606,7 @@ const createPayloadDecoder = (
|
|
|
592
606
|
invalid();
|
|
593
607
|
}
|
|
594
608
|
};
|
|
595
|
-
|
|
609
|
+
const decode = (payload) => {
|
|
596
610
|
if (!valid) {
|
|
597
611
|
return;
|
|
598
612
|
}
|
|
@@ -625,42 +639,52 @@ const createPayloadDecoder = (
|
|
|
625
639
|
const bufferKey = clientId + MESSAGE_SEPARATOR + messageId;
|
|
626
640
|
let pending = mapGet(buffer, bufferKey);
|
|
627
641
|
if (!pending) {
|
|
628
|
-
if (
|
|
642
|
+
if (payloadBuffer[0] >= MAX_FRAGMENT_BUFFERS) {
|
|
629
643
|
invalid(errorNew(ERROR_SYNC_OVERFLOW, 'fragments'));
|
|
630
644
|
return;
|
|
631
645
|
}
|
|
632
|
-
pending = [
|
|
633
|
-
[],
|
|
634
|
-
[],
|
|
635
|
-
total,
|
|
636
|
-
total,
|
|
637
|
-
startTimeout(() => {
|
|
638
|
-
const timedOut = mapGet(buffer, bufferKey);
|
|
639
|
-
if (timedOut) {
|
|
640
|
-
delPending(bufferKey, timedOut);
|
|
641
|
-
}
|
|
642
|
-
}, fragmentTimeoutSeconds),
|
|
643
|
-
0,
|
|
644
|
-
];
|
|
645
|
-
mapSet(buffer, bufferKey, pending);
|
|
646
646
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
647
|
+
if (
|
|
648
|
+
(isUndefined(pending) || total == pending[3]) &&
|
|
649
|
+
isUndefined(pending?.[0][index])
|
|
650
|
+
) {
|
|
651
|
+
const retainedSize =
|
|
652
|
+
getWebSocketPayloadSize(remainder) +
|
|
653
|
+
(pending ? 0 : getWebSocketPayloadSize(bufferKey));
|
|
654
|
+
if (payloadBuffer[1] + retainedSize > MAX_WEBSOCKET_BUFFER_SIZE) {
|
|
651
655
|
invalid(errorNew(ERROR_SYNC_OVERFLOW, 'fragments'));
|
|
652
656
|
return;
|
|
653
657
|
}
|
|
658
|
+
if (!pending) {
|
|
659
|
+
pending = [
|
|
660
|
+
[],
|
|
661
|
+
[],
|
|
662
|
+
total,
|
|
663
|
+
total,
|
|
664
|
+
startTimeout(() => {
|
|
665
|
+
const timedOut = mapGet(buffer, bufferKey);
|
|
666
|
+
if (timedOut) {
|
|
667
|
+
delPending(bufferKey, timedOut);
|
|
668
|
+
}
|
|
669
|
+
}, fragmentTimeoutSeconds),
|
|
670
|
+
0,
|
|
671
|
+
];
|
|
672
|
+
mapSet(buffer, bufferKey, pending);
|
|
673
|
+
payloadBuffer[0]++;
|
|
674
|
+
}
|
|
675
|
+
const [fragments, remainders] = pending;
|
|
654
676
|
fragments[index] = fragment;
|
|
655
677
|
remainders[index] = remainder;
|
|
656
678
|
pending[2]--;
|
|
657
|
-
pending[5] +=
|
|
658
|
-
bufferedSize +=
|
|
679
|
+
pending[5] += retainedSize;
|
|
680
|
+
bufferedSize += retainedSize;
|
|
681
|
+
payloadBuffer[1] += retainedSize;
|
|
659
682
|
} else {
|
|
660
683
|
invalid();
|
|
661
684
|
return;
|
|
662
685
|
}
|
|
663
686
|
if (pending[2] == 0) {
|
|
687
|
+
const [fragments, remainders] = pending;
|
|
664
688
|
delPending(bufferKey, pending);
|
|
665
689
|
receiveRemainder(clientId, remainders, arrayJoin(fragments));
|
|
666
690
|
}
|
|
@@ -673,6 +697,7 @@ const createPayloadDecoder = (
|
|
|
673
697
|
invalid();
|
|
674
698
|
}
|
|
675
699
|
};
|
|
700
|
+
return [decode, clear];
|
|
676
701
|
};
|
|
677
702
|
const getPayloadCoalesceKey = (clientId, payload) => {
|
|
678
703
|
let key;
|
|
@@ -689,12 +714,14 @@ const createPayloadReceiver = (
|
|
|
689
714
|
receive,
|
|
690
715
|
fragmentTimeoutSeconds = 1,
|
|
691
716
|
onInvalid,
|
|
717
|
+
sharedBuffer,
|
|
692
718
|
) =>
|
|
693
719
|
createPayloadDecoder(
|
|
694
720
|
(fromClientId, _remainders, requestId, message, body) =>
|
|
695
721
|
receive(fromClientId, requestId, message, body),
|
|
696
722
|
fragmentTimeoutSeconds,
|
|
697
723
|
onInvalid,
|
|
724
|
+
sharedBuffer,
|
|
698
725
|
);
|
|
699
726
|
const createRawPayload = (clientId, remainder) =>
|
|
700
727
|
clientId + MESSAGE_SEPARATOR + remainder;
|
|
@@ -727,12 +754,15 @@ const getFragments = (remainder, maxFragmentSize) => {
|
|
|
727
754
|
};
|
|
728
755
|
const createMultiplePayload = (channelId, payload) =>
|
|
729
756
|
createRawPayload(MULTIPLE_CLIENT_ID, createRawPayload(channelId, payload));
|
|
730
|
-
const ifMultiplePayloadValid = (payload, then) => {
|
|
757
|
+
const ifMultiplePayloadValid = (payload, then, onOversized) => {
|
|
731
758
|
let valid = false;
|
|
732
759
|
ifPayloadValid(payload, (multipleClientId, remainder) => {
|
|
733
760
|
if (multipleClientId == MULTIPLE_CLIENT_ID) {
|
|
734
761
|
ifPayloadValid(remainder, (channelId, channelPayload) => {
|
|
735
|
-
if (
|
|
762
|
+
if (isMultipleChannelIdTooLarge(channelId)) {
|
|
763
|
+
valid = true;
|
|
764
|
+
onOversized?.();
|
|
765
|
+
} else if (isMultipleChannelIdStructureValid(channelId)) {
|
|
736
766
|
valid = true;
|
|
737
767
|
then(channelId, channelPayload);
|
|
738
768
|
}
|
|
@@ -746,6 +776,15 @@ const createMultipleControlPayload = (requestId, control, body) =>
|
|
|
746
776
|
SERVER_CLIENT_ID,
|
|
747
777
|
jsonStringWithUndefined([requestId, MULTIPLE_MESSAGE, [control, body]]),
|
|
748
778
|
);
|
|
779
|
+
const isMultipleChannelIdTooLarge = (channelId) =>
|
|
780
|
+
getWebSocketPayloadSize(channelId) > MAX_MULTIPLE_CHANNEL_ID_SIZE;
|
|
781
|
+
const isMultipleChannelIdStructureValid = (channelId) =>
|
|
782
|
+
!isEmpty(channelId) &&
|
|
783
|
+
!INVALID_CHANNEL_ID_CHARACTERS.test(channelId) &&
|
|
784
|
+
arrayEvery(
|
|
785
|
+
strSplit(channelId, '/'),
|
|
786
|
+
(part) => !isEmpty(part) && part != '.' && part != '..',
|
|
787
|
+
);
|
|
749
788
|
const ifMultipleControlPayloadValid = (payload, then) => {
|
|
750
789
|
let valid = false;
|
|
751
790
|
ifPayloadValid(payload, (serverClientId, remainder) => {
|
|
@@ -763,11 +802,13 @@ const ifMultipleControlPayloadValid = (payload, then) => {
|
|
|
763
802
|
: control == 1 /* Subscribe */
|
|
764
803
|
? isString(requestId) &&
|
|
765
804
|
isString(body) &&
|
|
766
|
-
|
|
805
|
+
(isMultipleChannelIdTooLarge(body) ||
|
|
806
|
+
isMultipleChannelIdStructureValid(body))
|
|
767
807
|
: control == 2 /* Unsubscribe */ &&
|
|
768
808
|
isNull(requestId) &&
|
|
769
809
|
isString(body) &&
|
|
770
|
-
|
|
810
|
+
(isMultipleChannelIdTooLarge(body) ||
|
|
811
|
+
isMultipleChannelIdStructureValid(body)))
|
|
771
812
|
) {
|
|
772
813
|
valid = true;
|
|
773
814
|
then(requestId, control, body);
|
|
@@ -776,13 +817,6 @@ const ifMultipleControlPayloadValid = (payload, then) => {
|
|
|
776
817
|
});
|
|
777
818
|
return valid;
|
|
778
819
|
};
|
|
779
|
-
const isMultipleChannelIdValid = (channelId) =>
|
|
780
|
-
!isEmpty(channelId) &&
|
|
781
|
-
!INVALID_CHANNEL_ID_CHARACTERS.test(channelId) &&
|
|
782
|
-
arrayEvery(
|
|
783
|
-
strSplit(channelId, '/'),
|
|
784
|
-
(part) => !isEmpty(part) && part != '.' && part != '..',
|
|
785
|
-
);
|
|
786
820
|
const createMultipleServerClient = (
|
|
787
821
|
basePathId,
|
|
788
822
|
addChannel,
|
|
@@ -795,26 +829,87 @@ const createMultipleServerClient = (
|
|
|
795
829
|
) => {
|
|
796
830
|
const channels = mapNew();
|
|
797
831
|
const decoders = mapNew();
|
|
832
|
+
const payloadBuffer = [0, 0];
|
|
833
|
+
const resources = setNew();
|
|
834
|
+
let resourceCount = 0;
|
|
798
835
|
let negotiated = false;
|
|
836
|
+
let valid = true;
|
|
799
837
|
const sendControl = (requestId, control, body) =>
|
|
800
838
|
send(createMultipleControlPayload(requestId, control, body));
|
|
801
839
|
const delChannelAndDecoder = (channelId) => {
|
|
802
840
|
collDel(channels, channelId);
|
|
841
|
+
mapGet(decoders, channelId)?.[1]();
|
|
803
842
|
collDel(decoders, channelId);
|
|
804
843
|
};
|
|
844
|
+
const clearDecoders = () => {
|
|
845
|
+
mapForEach(decoders, (_channelId, decoder) => decoder[1]());
|
|
846
|
+
collClear(decoders);
|
|
847
|
+
};
|
|
848
|
+
const invalidate = (error) => {
|
|
849
|
+
if (valid) {
|
|
850
|
+
valid = false;
|
|
851
|
+
clearDecoders();
|
|
852
|
+
invalid(error);
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
const releaseChannel = (channel) => {
|
|
856
|
+
if (!channel[2 /* Released */]) {
|
|
857
|
+
channel[2 /* Released */] = 1;
|
|
858
|
+
resourceCount--;
|
|
859
|
+
collDel(resources, channel);
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
const teardownChannel = (channel) =>
|
|
863
|
+
(channel[1 /* Teardown */] ??= (async () => {
|
|
864
|
+
try {
|
|
865
|
+
const teardown = delChannel(channel[0 /* Channel */]);
|
|
866
|
+
if (isUndefined(teardown)) {
|
|
867
|
+
releaseChannel(channel);
|
|
868
|
+
} else {
|
|
869
|
+
await teardown;
|
|
870
|
+
}
|
|
871
|
+
} finally {
|
|
872
|
+
releaseChannel(channel);
|
|
873
|
+
}
|
|
874
|
+
})());
|
|
805
875
|
const handleControl = (requestId, control, body) => {
|
|
806
876
|
if (control == 0 /* Hello */) {
|
|
807
877
|
negotiated = true;
|
|
808
878
|
sendControl(requestId, control, body);
|
|
809
879
|
} else if (negotiated && control == 1 /* Subscribe */) {
|
|
810
|
-
|
|
880
|
+
const subscribed = collHas(channels, body);
|
|
881
|
+
if (
|
|
882
|
+
isMultipleChannelIdTooLarge(body) ||
|
|
883
|
+
(!subscribed &&
|
|
884
|
+
(collSize(channels) >= MAX_MULTIPLE_CHANNELS ||
|
|
885
|
+
resourceCount >= MAX_MULTIPLE_CHANNEL_RESOURCES))
|
|
886
|
+
) {
|
|
887
|
+
invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'channels'));
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
if (!subscribed) {
|
|
811
891
|
const pathId = basePathId + (basePathId ? '/' : EMPTY_STRING) + body;
|
|
812
|
-
|
|
892
|
+
resourceCount++;
|
|
893
|
+
let channelAndReady;
|
|
894
|
+
try {
|
|
895
|
+
channelAndReady = addChannel(pathId, body);
|
|
896
|
+
} catch (error) {
|
|
897
|
+
resourceCount--;
|
|
898
|
+
throw error;
|
|
899
|
+
}
|
|
900
|
+
const [addedChannel, ready] = channelAndReady;
|
|
901
|
+
const channel = [addedChannel];
|
|
902
|
+
setAdd(resources, channel);
|
|
813
903
|
mapSet(channels, body, channel);
|
|
814
904
|
sendControl(requestId, control, body);
|
|
815
905
|
if (ready) {
|
|
816
906
|
return ready.catch((error) => {
|
|
817
|
-
|
|
907
|
+
if (mapGet(channels, body) === channel) {
|
|
908
|
+
delChannelAndDecoder(body);
|
|
909
|
+
}
|
|
910
|
+
if (!channel[1 /* Teardown */]) {
|
|
911
|
+
releaseChannel(channel);
|
|
912
|
+
}
|
|
818
913
|
throw error;
|
|
819
914
|
});
|
|
820
915
|
}
|
|
@@ -822,16 +917,21 @@ const createMultipleServerClient = (
|
|
|
822
917
|
}
|
|
823
918
|
sendControl(requestId, control, body);
|
|
824
919
|
} else if (negotiated && control == 2 /* Unsubscribe */) {
|
|
920
|
+
if (isMultipleChannelIdTooLarge(body)) {
|
|
921
|
+
invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'channels'));
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
825
924
|
const channel = mapGet(channels, body);
|
|
826
925
|
delChannelAndDecoder(body);
|
|
827
|
-
|
|
828
|
-
return (async () => delChannel(channel))();
|
|
829
|
-
}
|
|
926
|
+
return isUndefined(channel) ? void 0 : teardownChannel(channel);
|
|
830
927
|
}
|
|
831
928
|
};
|
|
832
929
|
const handlePayload = (payload) => {
|
|
930
|
+
if (!valid) {
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
833
933
|
if (isWebSocketPayloadTooLarge(getWebSocketPayloadSize(payload))) {
|
|
834
|
-
|
|
934
|
+
invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'socket'));
|
|
835
935
|
return;
|
|
836
936
|
}
|
|
837
937
|
const control = ifMultipleControlPayloadValid(
|
|
@@ -846,32 +946,54 @@ const createMultipleServerClient = (
|
|
|
846
946
|
(channelId, channelPayload) => {
|
|
847
947
|
const channel2 = negotiated ? mapGet(channels, channelId) : void 0;
|
|
848
948
|
if (isUndefined(channel2)) {
|
|
849
|
-
|
|
949
|
+
invalidate(errorNew(ERROR_SYNC_MESSAGE));
|
|
850
950
|
} else {
|
|
851
951
|
mapEnsure(decoders, channelId, () =>
|
|
852
952
|
createPayloadDecoder(
|
|
853
953
|
(toClientId, remainders) =>
|
|
854
|
-
receive(channel2, toClientId, remainders),
|
|
954
|
+
receive(channel2[0 /* Channel */], toClientId, remainders),
|
|
855
955
|
fragmentTimeoutSeconds,
|
|
856
|
-
|
|
956
|
+
invalidate,
|
|
957
|
+
payloadBuffer,
|
|
857
958
|
),
|
|
858
|
-
)(channelPayload);
|
|
959
|
+
)[0](channelPayload);
|
|
859
960
|
}
|
|
860
961
|
},
|
|
962
|
+
() => invalidate(errorNew(ERROR_SYNC_OVERFLOW, 'channels')),
|
|
861
963
|
);
|
|
862
964
|
if (!control && !channel) {
|
|
863
|
-
|
|
965
|
+
invalidate(errorNew(ERROR_SYNC_MESSAGE));
|
|
864
966
|
}
|
|
865
967
|
};
|
|
866
|
-
const destroy = () =>
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
968
|
+
const destroy = () => {
|
|
969
|
+
valid = false;
|
|
970
|
+
clearDecoders();
|
|
971
|
+
return tryFinallyAsync(
|
|
972
|
+
async () => {
|
|
973
|
+
let errorToThrow;
|
|
974
|
+
let failed = false;
|
|
975
|
+
await promiseAll(
|
|
976
|
+
arrayMap(collValues(resources), async (channel) => {
|
|
977
|
+
try {
|
|
978
|
+
await teardownChannel(channel);
|
|
979
|
+
} catch (error) {
|
|
980
|
+
if (!failed) {
|
|
981
|
+
errorToThrow = error;
|
|
982
|
+
failed = true;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}),
|
|
986
|
+
);
|
|
987
|
+
if (failed) {
|
|
988
|
+
throw errorToThrow;
|
|
989
|
+
}
|
|
990
|
+
},
|
|
870
991
|
() => {
|
|
871
992
|
collClear(channels);
|
|
872
|
-
|
|
993
|
+
clearDecoders();
|
|
873
994
|
},
|
|
874
995
|
);
|
|
996
|
+
};
|
|
875
997
|
return [handlePayload, destroy];
|
|
876
998
|
};
|
|
877
999
|
const createPayloads = (toClientId, requestId, message, body, fragmentSize) => {
|
|
@@ -1233,11 +1355,35 @@ const createCustomPersister = (
|
|
|
1233
1355
|
initialContent,
|
|
1234
1356
|
startSaveFirst = false,
|
|
1235
1357
|
) => {
|
|
1236
|
-
const [call1, call2] = startSaveFirst
|
|
1237
|
-
? [startAutoSave, startAutoLoad]
|
|
1238
|
-
: [startAutoLoad, startAutoSave];
|
|
1239
|
-
|
|
1240
|
-
|
|
1358
|
+
const [call1, call2, stop1, stop2] = startSaveFirst
|
|
1359
|
+
? [startAutoSave, startAutoLoad, stopAutoSave, stopAutoLoad]
|
|
1360
|
+
: [startAutoLoad, startAutoSave, stopAutoLoad, stopAutoSave];
|
|
1361
|
+
const start1 = call1(initialContent);
|
|
1362
|
+
const generation1 = startSaveFirst
|
|
1363
|
+
? autoSaveGeneration
|
|
1364
|
+
: autoLoadGeneration;
|
|
1365
|
+
await start1;
|
|
1366
|
+
const start2 = call2(initialContent);
|
|
1367
|
+
const generation2 = startSaveFirst
|
|
1368
|
+
? autoLoadGeneration
|
|
1369
|
+
: autoSaveGeneration;
|
|
1370
|
+
try {
|
|
1371
|
+
await start2;
|
|
1372
|
+
} catch (error) {
|
|
1373
|
+
if (
|
|
1374
|
+
generation2 ==
|
|
1375
|
+
(startSaveFirst ? autoLoadGeneration : autoSaveGeneration)
|
|
1376
|
+
) {
|
|
1377
|
+
await tryCatchIgnore(stop2);
|
|
1378
|
+
}
|
|
1379
|
+
if (
|
|
1380
|
+
generation1 ==
|
|
1381
|
+
(startSaveFirst ? autoSaveGeneration : autoLoadGeneration)
|
|
1382
|
+
) {
|
|
1383
|
+
await tryCatchIgnore(stop1);
|
|
1384
|
+
}
|
|
1385
|
+
throw error;
|
|
1386
|
+
}
|
|
1241
1387
|
return persister;
|
|
1242
1388
|
};
|
|
1243
1389
|
const stopAutoPersisting = async (stopSaveFirst = false) => {
|
|
@@ -1630,6 +1776,7 @@ const createWsServer = (
|
|
|
1630
1776
|
const clientIdListeners = mapNew();
|
|
1631
1777
|
const paths = mapNew();
|
|
1632
1778
|
const webSockets = setNew();
|
|
1779
|
+
const buffersByWebSocket = mapNew();
|
|
1633
1780
|
const removeServerListeners = [];
|
|
1634
1781
|
const removeListenersByWebSocket = mapNew();
|
|
1635
1782
|
let destroying;
|
|
@@ -1679,7 +1826,7 @@ const createWsServer = (
|
|
|
1679
1826
|
serverClient[3 /* Send */] = createPayloadReceiver(
|
|
1680
1827
|
receive,
|
|
1681
1828
|
requestTimeoutSeconds,
|
|
1682
|
-
);
|
|
1829
|
+
)[0];
|
|
1683
1830
|
},
|
|
1684
1831
|
noop,
|
|
1685
1832
|
requestTimeoutSeconds,
|
|
@@ -1743,18 +1890,37 @@ const createWsServer = (
|
|
|
1743
1890
|
client.send(outgoingPayload);
|
|
1744
1891
|
}
|
|
1745
1892
|
};
|
|
1893
|
+
const updateWebSocketBuffer = (webSocket, count, size2) => {
|
|
1894
|
+
const webSocketBuffer = mapEnsure(buffersByWebSocket, webSocket, () => [
|
|
1895
|
+
0, 0,
|
|
1896
|
+
]);
|
|
1897
|
+
webSocketBuffer[0] += count;
|
|
1898
|
+
webSocketBuffer[1] += size2;
|
|
1899
|
+
if (!webSocketBuffer[0]) {
|
|
1900
|
+
mapSet(buffersByWebSocket, webSocket);
|
|
1901
|
+
}
|
|
1902
|
+
};
|
|
1903
|
+
const delBufferedFromWebSocket = ([, payload, , webSocket]) =>
|
|
1904
|
+
updateWebSocketBuffer(webSocket, -1, -getWebSocketPayloadSize(payload));
|
|
1746
1905
|
const clearServerBuffer = (serverClient) => {
|
|
1747
1906
|
if (serverClient[7 /* BufferTimeout */]) {
|
|
1748
1907
|
stopTimeout(serverClient[7 /* BufferTimeout */]);
|
|
1749
1908
|
serverClient[7 /* BufferTimeout */] = void 0;
|
|
1750
1909
|
}
|
|
1910
|
+
arrayForEach(serverClient[4 /* Buffer */], delBufferedFromWebSocket);
|
|
1751
1911
|
serverClient[4 /* Buffer */] = [];
|
|
1752
1912
|
serverClient[6 /* BufferSize */] = 0;
|
|
1753
1913
|
};
|
|
1754
1914
|
const delBufferedClient = (serverClient, clientId) => {
|
|
1755
1915
|
serverClient[4 /* Buffer */] = arrayFilter(
|
|
1756
1916
|
serverClient[4 /* Buffer */],
|
|
1757
|
-
(
|
|
1917
|
+
(buffered) => {
|
|
1918
|
+
if (buffered[0] == clientId) {
|
|
1919
|
+
delBufferedFromWebSocket(buffered);
|
|
1920
|
+
return false;
|
|
1921
|
+
}
|
|
1922
|
+
return true;
|
|
1923
|
+
},
|
|
1758
1924
|
);
|
|
1759
1925
|
serverClient[6 /* BufferSize */] = arrayReduce(
|
|
1760
1926
|
serverClient[4 /* Buffer */],
|
|
@@ -1768,10 +1934,8 @@ const createWsServer = (
|
|
|
1768
1934
|
const expireServerBuffer = (path) => {
|
|
1769
1935
|
const serverClient = path[1 /* ServerClient */];
|
|
1770
1936
|
const clients = setNew();
|
|
1771
|
-
arrayForEach(serverClient[4 /* Buffer */], ([
|
|
1772
|
-
|
|
1773
|
-
setAdd(clients, client),
|
|
1774
|
-
),
|
|
1937
|
+
arrayForEach(serverClient[4 /* Buffer */], ([, , , client]) =>
|
|
1938
|
+
setAdd(clients, client),
|
|
1775
1939
|
);
|
|
1776
1940
|
clearServerBuffer(serverClient);
|
|
1777
1941
|
arrayForEach(collValues(clients), (client) =>
|
|
@@ -1781,6 +1945,10 @@ const createWsServer = (
|
|
|
1781
1945
|
const bufferMessage = (path, clientId, payload) => {
|
|
1782
1946
|
const serverClient = path[1 /* ServerClient */];
|
|
1783
1947
|
const buffer = serverClient[4 /* Buffer */];
|
|
1948
|
+
const webSocket = mapGet(path[0 /* Clients */], clientId)?.[0];
|
|
1949
|
+
if (isUndefined(webSocket)) {
|
|
1950
|
+
return;
|
|
1951
|
+
}
|
|
1784
1952
|
const coalesceKey = getPayloadCoalesceKey(clientId, payload);
|
|
1785
1953
|
const coalesceIndex = coalesceKey
|
|
1786
1954
|
? arrayFindIndex(
|
|
@@ -1788,14 +1956,22 @@ const createWsServer = (
|
|
|
1788
1956
|
([, , bufferedKey]) => bufferedKey == coalesceKey,
|
|
1789
1957
|
)
|
|
1790
1958
|
: -1;
|
|
1791
|
-
const
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1959
|
+
const replaced = coalesceIndex > -1 ? buffer[coalesceIndex] : void 0;
|
|
1960
|
+
const replacedSize = isUndefined(replaced)
|
|
1961
|
+
? 0
|
|
1962
|
+
: getWebSocketPayloadSize(replaced[1]);
|
|
1795
1963
|
const payloadSize = getWebSocketPayloadSize(payload);
|
|
1964
|
+
const webSocketBuffer = mapGet(buffersByWebSocket, webSocket);
|
|
1965
|
+
const sameWebSocket = replaced?.[3] === webSocket;
|
|
1796
1966
|
if (
|
|
1797
1967
|
(coalesceIndex < 0 && size(buffer) >= MAX_WEBSOCKET_QUEUE_SIZE) ||
|
|
1798
1968
|
serverClient[6 /* BufferSize */] + payloadSize - replacedSize >
|
|
1969
|
+
MAX_WEBSOCKET_BUFFER_SIZE ||
|
|
1970
|
+
(!sameWebSocket &&
|
|
1971
|
+
(webSocketBuffer?.[0] ?? 0) >= MAX_WEBSOCKET_QUEUE_SIZE) ||
|
|
1972
|
+
(webSocketBuffer?.[1] ?? 0) +
|
|
1973
|
+
payloadSize -
|
|
1974
|
+
(sameWebSocket ? replacedSize : 0) >
|
|
1799
1975
|
MAX_WEBSOCKET_BUFFER_SIZE
|
|
1800
1976
|
) {
|
|
1801
1977
|
delBufferedClient(serverClient, clientId);
|
|
@@ -1804,12 +1980,14 @@ const createWsServer = (
|
|
|
1804
1980
|
);
|
|
1805
1981
|
return;
|
|
1806
1982
|
}
|
|
1807
|
-
const buffered = [clientId, payload, coalesceKey];
|
|
1983
|
+
const buffered = [clientId, payload, coalesceKey, webSocket];
|
|
1808
1984
|
if (coalesceIndex > -1) {
|
|
1985
|
+
delBufferedFromWebSocket(buffer[coalesceIndex]);
|
|
1809
1986
|
buffer[coalesceIndex] = buffered;
|
|
1810
1987
|
} else {
|
|
1811
1988
|
arrayPush(buffer, buffered);
|
|
1812
1989
|
}
|
|
1990
|
+
updateWebSocketBuffer(webSocket, 1, payloadSize);
|
|
1813
1991
|
serverClient[6 /* BufferSize */] += payloadSize - replacedSize;
|
|
1814
1992
|
serverClient[7 /* BufferTimeout */] ??= startTimeout(
|
|
1815
1993
|
() => expireServerBuffer(path),
|
|
@@ -1968,7 +2146,7 @@ const createWsServer = (
|
|
|
1968
2146
|
};
|
|
1969
2147
|
const addLegacyClient = async (client, clientId, pathId) => {
|
|
1970
2148
|
const [path, ready] = addClientToPath(pathId, clientId, [client]);
|
|
1971
|
-
const decode = createPayloadDecoder(
|
|
2149
|
+
const [decode, clearDecoder] = createPayloadDecoder(
|
|
1972
2150
|
(toClientId, remainders) =>
|
|
1973
2151
|
handleDecodedMessage(path, clientId, toClientId, remainders),
|
|
1974
2152
|
requestTimeoutSeconds,
|
|
@@ -1977,9 +2155,10 @@ const createWsServer = (
|
|
|
1977
2155
|
addWebSocketListener(client, MESSAGE, (data) =>
|
|
1978
2156
|
decode(data.toString(UTF8)),
|
|
1979
2157
|
);
|
|
1980
|
-
addWebSocketListener(client, CLOSE, () =>
|
|
1981
|
-
|
|
1982
|
-
|
|
2158
|
+
addWebSocketListener(client, CLOSE, () => {
|
|
2159
|
+
clearDecoder();
|
|
2160
|
+
delClientFromPath(pathId, path, clientId).catch(handleError);
|
|
2161
|
+
});
|
|
1983
2162
|
await ready;
|
|
1984
2163
|
};
|
|
1985
2164
|
const addMultipleClient = (client, clientId, basePathId) => {
|
|
@@ -2124,6 +2303,7 @@ const createWsServer = (
|
|
|
2124
2303
|
arrayForEach(removers, (remove) => tryReturn(remove)),
|
|
2125
2304
|
);
|
|
2126
2305
|
collClear(removeListenersByWebSocket);
|
|
2306
|
+
collClear(buffersByWebSocket);
|
|
2127
2307
|
collClear(paths);
|
|
2128
2308
|
collClear(webSockets);
|
|
2129
2309
|
const failure = serverFailure[0]
|