@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.mjs
CHANGED
|
@@ -746,8 +746,9 @@ function canonicalShapeKey(url) {
|
|
|
746
746
|
cleanUrl.searchParams.sort();
|
|
747
747
|
return cleanUrl.toString();
|
|
748
748
|
}
|
|
749
|
-
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;
|
|
749
|
+
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;
|
|
750
750
|
var ShapeStream = class {
|
|
751
|
+
// Maximum delay cap (ms)
|
|
751
752
|
constructor(options) {
|
|
752
753
|
__privateAdd(this, _ShapeStream_instances);
|
|
753
754
|
__privateAdd(this, _error, null);
|
|
@@ -781,6 +782,16 @@ var ShapeStream = class {
|
|
|
781
782
|
// counter for concurrent snapshot requests
|
|
782
783
|
__privateAdd(this, _midStreamPromise);
|
|
783
784
|
__privateAdd(this, _midStreamPromiseResolver);
|
|
785
|
+
__privateAdd(this, _lastSseConnectionStartTime);
|
|
786
|
+
__privateAdd(this, _minSseConnectionDuration, 1e3);
|
|
787
|
+
// Minimum expected SSE connection duration (1 second)
|
|
788
|
+
__privateAdd(this, _consecutiveShortSseConnections, 0);
|
|
789
|
+
__privateAdd(this, _maxShortSseConnections, 3);
|
|
790
|
+
// Fall back to long polling after this many short connections
|
|
791
|
+
__privateAdd(this, _sseFallbackToLongPolling, false);
|
|
792
|
+
__privateAdd(this, _sseBackoffBaseDelay, 100);
|
|
793
|
+
// Base delay for exponential backoff (ms)
|
|
794
|
+
__privateAdd(this, _sseBackoffMaxDelay, 5e3);
|
|
784
795
|
var _a, _b, _c, _d;
|
|
785
796
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
786
797
|
validateOptions(this.options);
|
|
@@ -956,10 +967,17 @@ _snapshotTracker = new WeakMap();
|
|
|
956
967
|
_activeSnapshotRequests = new WeakMap();
|
|
957
968
|
_midStreamPromise = new WeakMap();
|
|
958
969
|
_midStreamPromiseResolver = new WeakMap();
|
|
970
|
+
_lastSseConnectionStartTime = new WeakMap();
|
|
971
|
+
_minSseConnectionDuration = new WeakMap();
|
|
972
|
+
_consecutiveShortSseConnections = new WeakMap();
|
|
973
|
+
_maxShortSseConnections = new WeakMap();
|
|
974
|
+
_sseFallbackToLongPolling = new WeakMap();
|
|
975
|
+
_sseBackoffBaseDelay = new WeakMap();
|
|
976
|
+
_sseBackoffMaxDelay = new WeakMap();
|
|
959
977
|
_ShapeStream_instances = new WeakSet();
|
|
960
978
|
start_fn = function() {
|
|
961
979
|
return __async(this, null, function* () {
|
|
962
|
-
var _a;
|
|
980
|
+
var _a, _b, _c, _d, _e;
|
|
963
981
|
__privateSet(this, _started, true);
|
|
964
982
|
try {
|
|
965
983
|
yield __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
@@ -967,24 +985,34 @@ start_fn = function() {
|
|
|
967
985
|
__privateSet(this, _error, err);
|
|
968
986
|
if (__privateGet(this, _onError)) {
|
|
969
987
|
const retryOpts = yield __privateGet(this, _onError).call(this, err);
|
|
970
|
-
if (typeof retryOpts === `object`) {
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
this.options.params = retryOpts.params;
|
|
988
|
+
if (retryOpts && typeof retryOpts === `object`) {
|
|
989
|
+
if (retryOpts.params) {
|
|
990
|
+
this.options.params = __spreadValues(__spreadValues({}, (_a = this.options.params) != null ? _a : {}), retryOpts.params);
|
|
974
991
|
}
|
|
975
|
-
if (
|
|
976
|
-
this.options.headers = retryOpts.headers;
|
|
992
|
+
if (retryOpts.headers) {
|
|
993
|
+
this.options.headers = __spreadValues(__spreadValues({}, (_b = this.options.headers) != null ? _b : {}), retryOpts.headers);
|
|
977
994
|
}
|
|
995
|
+
__privateSet(this, _error, null);
|
|
978
996
|
__privateSet(this, _started, false);
|
|
979
|
-
__privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
997
|
+
yield __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
if (err instanceof Error) {
|
|
1001
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
|
|
980
1002
|
}
|
|
1003
|
+
__privateSet(this, _connected, false);
|
|
1004
|
+
(_c = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _c.call(this);
|
|
981
1005
|
return;
|
|
982
1006
|
}
|
|
983
|
-
|
|
984
|
-
|
|
1007
|
+
if (err instanceof Error) {
|
|
1008
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
|
|
1009
|
+
}
|
|
985
1010
|
__privateSet(this, _connected, false);
|
|
986
|
-
(
|
|
1011
|
+
(_d = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _d.call(this);
|
|
1012
|
+
throw err;
|
|
987
1013
|
}
|
|
1014
|
+
__privateSet(this, _connected, false);
|
|
1015
|
+
(_e = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _e.call(this);
|
|
988
1016
|
});
|
|
989
1017
|
};
|
|
990
1018
|
requestShape_fn = function() {
|
|
@@ -1031,7 +1059,6 @@ requestShape_fn = function() {
|
|
|
1031
1059
|
yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, Array.isArray(e.json) ? e.json : [e.json]);
|
|
1032
1060
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
1033
1061
|
} else {
|
|
1034
|
-
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
|
|
1035
1062
|
throw e;
|
|
1036
1063
|
}
|
|
1037
1064
|
} finally {
|
|
@@ -1183,7 +1210,7 @@ fetchShape_fn = function(opts) {
|
|
|
1183
1210
|
return __async(this, null, function* () {
|
|
1184
1211
|
var _a;
|
|
1185
1212
|
const useSse = (_a = this.options.liveSse) != null ? _a : this.options.experimentalLiveSse;
|
|
1186
|
-
if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause) {
|
|
1213
|
+
if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause && !__privateGet(this, _sseFallbackToLongPolling)) {
|
|
1187
1214
|
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
1188
1215
|
opts.fetchUrl.searchParams.set(LIVE_SSE_QUERY_PARAM, `true`);
|
|
1189
1216
|
return __privateMethod(this, _ShapeStream_instances, requestShapeSSE_fn).call(this, opts);
|
|
@@ -1211,6 +1238,7 @@ requestShapeSSE_fn = function(opts) {
|
|
|
1211
1238
|
return __async(this, null, function* () {
|
|
1212
1239
|
const { fetchUrl, requestAbortController, headers } = opts;
|
|
1213
1240
|
const fetch2 = __privateGet(this, _sseFetchClient);
|
|
1241
|
+
__privateSet(this, _lastSseConnectionStartTime, Date.now());
|
|
1214
1242
|
try {
|
|
1215
1243
|
let buffer = [];
|
|
1216
1244
|
yield fetchEventSource(fetchUrl.toString(), {
|
|
@@ -1244,6 +1272,27 @@ requestShapeSSE_fn = function(opts) {
|
|
|
1244
1272
|
throw new FetchBackoffAbortError();
|
|
1245
1273
|
}
|
|
1246
1274
|
throw error;
|
|
1275
|
+
} finally {
|
|
1276
|
+
const connectionDuration = Date.now() - __privateGet(this, _lastSseConnectionStartTime);
|
|
1277
|
+
const wasAborted = requestAbortController.signal.aborted;
|
|
1278
|
+
if (connectionDuration < __privateGet(this, _minSseConnectionDuration) && !wasAborted) {
|
|
1279
|
+
__privateWrapper(this, _consecutiveShortSseConnections)._++;
|
|
1280
|
+
if (__privateGet(this, _consecutiveShortSseConnections) >= __privateGet(this, _maxShortSseConnections)) {
|
|
1281
|
+
__privateSet(this, _sseFallbackToLongPolling, true);
|
|
1282
|
+
console.warn(
|
|
1283
|
+
`[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.`
|
|
1284
|
+
);
|
|
1285
|
+
} else {
|
|
1286
|
+
const maxDelay = Math.min(
|
|
1287
|
+
__privateGet(this, _sseBackoffMaxDelay),
|
|
1288
|
+
__privateGet(this, _sseBackoffBaseDelay) * Math.pow(2, __privateGet(this, _consecutiveShortSseConnections))
|
|
1289
|
+
);
|
|
1290
|
+
const delayMs = Math.floor(Math.random() * maxDelay);
|
|
1291
|
+
yield new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1292
|
+
}
|
|
1293
|
+
} else if (connectionDuration >= __privateGet(this, _minSseConnectionDuration)) {
|
|
1294
|
+
__privateSet(this, _consecutiveShortSseConnections, 0);
|
|
1295
|
+
}
|
|
1247
1296
|
}
|
|
1248
1297
|
});
|
|
1249
1298
|
};
|
|
@@ -1342,6 +1391,8 @@ reset_fn = function(handle) {
|
|
|
1342
1391
|
__privateSet(this, _connected, false);
|
|
1343
1392
|
__privateSet(this, _schema, void 0);
|
|
1344
1393
|
__privateSet(this, _activeSnapshotRequests, 0);
|
|
1394
|
+
__privateSet(this, _consecutiveShortSseConnections, 0);
|
|
1395
|
+
__privateSet(this, _sseFallbackToLongPolling, false);
|
|
1345
1396
|
};
|
|
1346
1397
|
fetchSnapshot_fn = function(url, headers) {
|
|
1347
1398
|
return __async(this, null, function* () {
|