@electric-sql/client 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +65 -14
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.legacy-esm.js +65 -14
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +65 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +97 -17
package/dist/index.legacy-esm.js
CHANGED
|
@@ -716,8 +716,9 @@ function canonicalShapeKey(url) {
|
|
|
716
716
|
cleanUrl.searchParams.sort();
|
|
717
717
|
return cleanUrl.toString();
|
|
718
718
|
}
|
|
719
|
-
var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started, _state, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _isMidStream, _connected, _shapeHandle, _mode, _schema, _onError, _requestAbortController, _isRefreshing, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _messageChain, _snapshotTracker, _activeSnapshotRequests, _midStreamPromise, _midStreamPromiseResolver, _ShapeStream_instances, start_fn, requestShape_fn, constructUrl_fn, createAbortListener_fn, onInitialResponse_fn, onMessages_fn, fetchShape_fn, requestShapeLongPoll_fn, requestShapeSSE_fn, pause_fn, resume_fn, nextTick_fn, waitForStreamEnd_fn, publish_fn, sendErrorToSubscribers_fn, subscribeToVisibilityChanges_fn, reset_fn, fetchSnapshot_fn;
|
|
719
|
+
var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started, _state, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _isMidStream, _connected, _shapeHandle, _mode, _schema, _onError, _requestAbortController, _isRefreshing, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _messageChain, _snapshotTracker, _activeSnapshotRequests, _midStreamPromise, _midStreamPromiseResolver, _lastSseConnectionStartTime, _minSseConnectionDuration, _consecutiveShortSseConnections, _maxShortSseConnections, _sseFallbackToLongPolling, _sseBackoffBaseDelay, _sseBackoffMaxDelay, _ShapeStream_instances, start_fn, requestShape_fn, constructUrl_fn, createAbortListener_fn, onInitialResponse_fn, onMessages_fn, fetchShape_fn, requestShapeLongPoll_fn, requestShapeSSE_fn, pause_fn, resume_fn, nextTick_fn, waitForStreamEnd_fn, publish_fn, sendErrorToSubscribers_fn, subscribeToVisibilityChanges_fn, reset_fn, fetchSnapshot_fn;
|
|
720
720
|
var ShapeStream = class {
|
|
721
|
+
// Maximum delay cap (ms)
|
|
721
722
|
constructor(options) {
|
|
722
723
|
__privateAdd(this, _ShapeStream_instances);
|
|
723
724
|
__privateAdd(this, _error, null);
|
|
@@ -751,6 +752,16 @@ var ShapeStream = class {
|
|
|
751
752
|
// counter for concurrent snapshot requests
|
|
752
753
|
__privateAdd(this, _midStreamPromise);
|
|
753
754
|
__privateAdd(this, _midStreamPromiseResolver);
|
|
755
|
+
__privateAdd(this, _lastSseConnectionStartTime);
|
|
756
|
+
__privateAdd(this, _minSseConnectionDuration, 1e3);
|
|
757
|
+
// Minimum expected SSE connection duration (1 second)
|
|
758
|
+
__privateAdd(this, _consecutiveShortSseConnections, 0);
|
|
759
|
+
__privateAdd(this, _maxShortSseConnections, 3);
|
|
760
|
+
// Fall back to long polling after this many short connections
|
|
761
|
+
__privateAdd(this, _sseFallbackToLongPolling, false);
|
|
762
|
+
__privateAdd(this, _sseBackoffBaseDelay, 100);
|
|
763
|
+
// Base delay for exponential backoff (ms)
|
|
764
|
+
__privateAdd(this, _sseBackoffMaxDelay, 5e3);
|
|
754
765
|
var _a, _b, _c, _d;
|
|
755
766
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
756
767
|
validateOptions(this.options);
|
|
@@ -922,9 +933,16 @@ _snapshotTracker = new WeakMap();
|
|
|
922
933
|
_activeSnapshotRequests = new WeakMap();
|
|
923
934
|
_midStreamPromise = new WeakMap();
|
|
924
935
|
_midStreamPromiseResolver = new WeakMap();
|
|
936
|
+
_lastSseConnectionStartTime = new WeakMap();
|
|
937
|
+
_minSseConnectionDuration = new WeakMap();
|
|
938
|
+
_consecutiveShortSseConnections = new WeakMap();
|
|
939
|
+
_maxShortSseConnections = new WeakMap();
|
|
940
|
+
_sseFallbackToLongPolling = new WeakMap();
|
|
941
|
+
_sseBackoffBaseDelay = new WeakMap();
|
|
942
|
+
_sseBackoffMaxDelay = new WeakMap();
|
|
925
943
|
_ShapeStream_instances = new WeakSet();
|
|
926
944
|
start_fn = async function() {
|
|
927
|
-
var _a;
|
|
945
|
+
var _a, _b, _c, _d, _e;
|
|
928
946
|
__privateSet(this, _started, true);
|
|
929
947
|
try {
|
|
930
948
|
await __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
@@ -932,24 +950,34 @@ start_fn = async function() {
|
|
|
932
950
|
__privateSet(this, _error, err);
|
|
933
951
|
if (__privateGet(this, _onError)) {
|
|
934
952
|
const retryOpts = await __privateGet(this, _onError).call(this, err);
|
|
935
|
-
if (typeof retryOpts === `object`) {
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
this.options.params = retryOpts.params;
|
|
953
|
+
if (retryOpts && typeof retryOpts === `object`) {
|
|
954
|
+
if (retryOpts.params) {
|
|
955
|
+
this.options.params = __spreadValues(__spreadValues({}, (_a = this.options.params) != null ? _a : {}), retryOpts.params);
|
|
939
956
|
}
|
|
940
|
-
if (
|
|
941
|
-
this.options.headers = retryOpts.headers;
|
|
957
|
+
if (retryOpts.headers) {
|
|
958
|
+
this.options.headers = __spreadValues(__spreadValues({}, (_b = this.options.headers) != null ? _b : {}), retryOpts.headers);
|
|
942
959
|
}
|
|
960
|
+
__privateSet(this, _error, null);
|
|
943
961
|
__privateSet(this, _started, false);
|
|
944
|
-
__privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
962
|
+
await __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
if (err instanceof Error) {
|
|
966
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
|
|
945
967
|
}
|
|
968
|
+
__privateSet(this, _connected, false);
|
|
969
|
+
(_c = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _c.call(this);
|
|
946
970
|
return;
|
|
947
971
|
}
|
|
948
|
-
|
|
949
|
-
|
|
972
|
+
if (err instanceof Error) {
|
|
973
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
|
|
974
|
+
}
|
|
950
975
|
__privateSet(this, _connected, false);
|
|
951
|
-
(
|
|
976
|
+
(_d = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _d.call(this);
|
|
977
|
+
throw err;
|
|
952
978
|
}
|
|
979
|
+
__privateSet(this, _connected, false);
|
|
980
|
+
(_e = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _e.call(this);
|
|
953
981
|
};
|
|
954
982
|
requestShape_fn = async function() {
|
|
955
983
|
var _a, _b;
|
|
@@ -994,7 +1022,6 @@ requestShape_fn = async function() {
|
|
|
994
1022
|
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, Array.isArray(e.json) ? e.json : [e.json]);
|
|
995
1023
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
996
1024
|
} else {
|
|
997
|
-
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
|
|
998
1025
|
throw e;
|
|
999
1026
|
}
|
|
1000
1027
|
} finally {
|
|
@@ -1136,7 +1163,7 @@ onMessages_fn = async function(batch, isSseMessage = false) {
|
|
|
1136
1163
|
fetchShape_fn = async function(opts) {
|
|
1137
1164
|
var _a;
|
|
1138
1165
|
const useSse = (_a = this.options.liveSse) != null ? _a : this.options.experimentalLiveSse;
|
|
1139
|
-
if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause) {
|
|
1166
|
+
if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause && !__privateGet(this, _sseFallbackToLongPolling)) {
|
|
1140
1167
|
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
1141
1168
|
opts.fetchUrl.searchParams.set(LIVE_SSE_QUERY_PARAM, `true`);
|
|
1142
1169
|
return __privateMethod(this, _ShapeStream_instances, requestShapeSSE_fn).call(this, opts);
|
|
@@ -1160,6 +1187,7 @@ requestShapeLongPoll_fn = async function(opts) {
|
|
|
1160
1187
|
requestShapeSSE_fn = async function(opts) {
|
|
1161
1188
|
const { fetchUrl, requestAbortController, headers } = opts;
|
|
1162
1189
|
const fetch2 = __privateGet(this, _sseFetchClient);
|
|
1190
|
+
__privateSet(this, _lastSseConnectionStartTime, Date.now());
|
|
1163
1191
|
try {
|
|
1164
1192
|
let buffer = [];
|
|
1165
1193
|
await fetchEventSource(fetchUrl.toString(), {
|
|
@@ -1193,6 +1221,27 @@ requestShapeSSE_fn = async function(opts) {
|
|
|
1193
1221
|
throw new FetchBackoffAbortError();
|
|
1194
1222
|
}
|
|
1195
1223
|
throw error;
|
|
1224
|
+
} finally {
|
|
1225
|
+
const connectionDuration = Date.now() - __privateGet(this, _lastSseConnectionStartTime);
|
|
1226
|
+
const wasAborted = requestAbortController.signal.aborted;
|
|
1227
|
+
if (connectionDuration < __privateGet(this, _minSseConnectionDuration) && !wasAborted) {
|
|
1228
|
+
__privateWrapper(this, _consecutiveShortSseConnections)._++;
|
|
1229
|
+
if (__privateGet(this, _consecutiveShortSseConnections) >= __privateGet(this, _maxShortSseConnections)) {
|
|
1230
|
+
__privateSet(this, _sseFallbackToLongPolling, true);
|
|
1231
|
+
console.warn(
|
|
1232
|
+
`[Electric] SSE connections are closing immediately (possibly due to proxy buffering or misconfiguration). Falling back to long polling. Your proxy must support streaming SSE responses (not buffer the complete response). Configuration: Nginx add 'X-Accel-Buffering: no', Caddy add 'flush_interval -1' to reverse_proxy. Note: Do NOT disable caching entirely - Electric uses cache headers to enable request collapsing for efficiency.`
|
|
1233
|
+
);
|
|
1234
|
+
} else {
|
|
1235
|
+
const maxDelay = Math.min(
|
|
1236
|
+
__privateGet(this, _sseBackoffMaxDelay),
|
|
1237
|
+
__privateGet(this, _sseBackoffBaseDelay) * Math.pow(2, __privateGet(this, _consecutiveShortSseConnections))
|
|
1238
|
+
);
|
|
1239
|
+
const delayMs = Math.floor(Math.random() * maxDelay);
|
|
1240
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1241
|
+
}
|
|
1242
|
+
} else if (connectionDuration >= __privateGet(this, _minSseConnectionDuration)) {
|
|
1243
|
+
__privateSet(this, _consecutiveShortSseConnections, 0);
|
|
1244
|
+
}
|
|
1196
1245
|
}
|
|
1197
1246
|
};
|
|
1198
1247
|
pause_fn = function() {
|
|
@@ -1284,6 +1333,8 @@ reset_fn = function(handle) {
|
|
|
1284
1333
|
__privateSet(this, _connected, false);
|
|
1285
1334
|
__privateSet(this, _schema, void 0);
|
|
1286
1335
|
__privateSet(this, _activeSnapshotRequests, 0);
|
|
1336
|
+
__privateSet(this, _consecutiveShortSseConnections, 0);
|
|
1337
|
+
__privateSet(this, _sseFallbackToLongPolling, false);
|
|
1287
1338
|
};
|
|
1288
1339
|
fetchSnapshot_fn = async function(url, headers) {
|
|
1289
1340
|
const response = await __privateGet(this, _fetchClient2).call(this, url.toString(), { headers });
|