@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/cjs/index.cjs
CHANGED
|
@@ -775,8 +775,9 @@ function canonicalShapeKey(url) {
|
|
|
775
775
|
cleanUrl.searchParams.sort();
|
|
776
776
|
return cleanUrl.toString();
|
|
777
777
|
}
|
|
778
|
-
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;
|
|
778
|
+
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;
|
|
779
779
|
var ShapeStream = class {
|
|
780
|
+
// Maximum delay cap (ms)
|
|
780
781
|
constructor(options) {
|
|
781
782
|
__privateAdd(this, _ShapeStream_instances);
|
|
782
783
|
__privateAdd(this, _error, null);
|
|
@@ -810,6 +811,16 @@ var ShapeStream = class {
|
|
|
810
811
|
// counter for concurrent snapshot requests
|
|
811
812
|
__privateAdd(this, _midStreamPromise);
|
|
812
813
|
__privateAdd(this, _midStreamPromiseResolver);
|
|
814
|
+
__privateAdd(this, _lastSseConnectionStartTime);
|
|
815
|
+
__privateAdd(this, _minSseConnectionDuration, 1e3);
|
|
816
|
+
// Minimum expected SSE connection duration (1 second)
|
|
817
|
+
__privateAdd(this, _consecutiveShortSseConnections, 0);
|
|
818
|
+
__privateAdd(this, _maxShortSseConnections, 3);
|
|
819
|
+
// Fall back to long polling after this many short connections
|
|
820
|
+
__privateAdd(this, _sseFallbackToLongPolling, false);
|
|
821
|
+
__privateAdd(this, _sseBackoffBaseDelay, 100);
|
|
822
|
+
// Base delay for exponential backoff (ms)
|
|
823
|
+
__privateAdd(this, _sseBackoffMaxDelay, 5e3);
|
|
813
824
|
var _a, _b, _c, _d;
|
|
814
825
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
815
826
|
validateOptions(this.options);
|
|
@@ -985,10 +996,17 @@ _snapshotTracker = new WeakMap();
|
|
|
985
996
|
_activeSnapshotRequests = new WeakMap();
|
|
986
997
|
_midStreamPromise = new WeakMap();
|
|
987
998
|
_midStreamPromiseResolver = new WeakMap();
|
|
999
|
+
_lastSseConnectionStartTime = new WeakMap();
|
|
1000
|
+
_minSseConnectionDuration = new WeakMap();
|
|
1001
|
+
_consecutiveShortSseConnections = new WeakMap();
|
|
1002
|
+
_maxShortSseConnections = new WeakMap();
|
|
1003
|
+
_sseFallbackToLongPolling = new WeakMap();
|
|
1004
|
+
_sseBackoffBaseDelay = new WeakMap();
|
|
1005
|
+
_sseBackoffMaxDelay = new WeakMap();
|
|
988
1006
|
_ShapeStream_instances = new WeakSet();
|
|
989
1007
|
start_fn = function() {
|
|
990
1008
|
return __async(this, null, function* () {
|
|
991
|
-
var _a;
|
|
1009
|
+
var _a, _b, _c, _d, _e;
|
|
992
1010
|
__privateSet(this, _started, true);
|
|
993
1011
|
try {
|
|
994
1012
|
yield __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
@@ -996,24 +1014,34 @@ start_fn = function() {
|
|
|
996
1014
|
__privateSet(this, _error, err);
|
|
997
1015
|
if (__privateGet(this, _onError)) {
|
|
998
1016
|
const retryOpts = yield __privateGet(this, _onError).call(this, err);
|
|
999
|
-
if (typeof retryOpts === `object`) {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
this.options.params = retryOpts.params;
|
|
1017
|
+
if (retryOpts && typeof retryOpts === `object`) {
|
|
1018
|
+
if (retryOpts.params) {
|
|
1019
|
+
this.options.params = __spreadValues(__spreadValues({}, (_a = this.options.params) != null ? _a : {}), retryOpts.params);
|
|
1003
1020
|
}
|
|
1004
|
-
if (
|
|
1005
|
-
this.options.headers = retryOpts.headers;
|
|
1021
|
+
if (retryOpts.headers) {
|
|
1022
|
+
this.options.headers = __spreadValues(__spreadValues({}, (_b = this.options.headers) != null ? _b : {}), retryOpts.headers);
|
|
1006
1023
|
}
|
|
1024
|
+
__privateSet(this, _error, null);
|
|
1007
1025
|
__privateSet(this, _started, false);
|
|
1008
|
-
__privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
1026
|
+
yield __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
if (err instanceof Error) {
|
|
1030
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
|
|
1009
1031
|
}
|
|
1032
|
+
__privateSet(this, _connected, false);
|
|
1033
|
+
(_c = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _c.call(this);
|
|
1010
1034
|
return;
|
|
1011
1035
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1036
|
+
if (err instanceof Error) {
|
|
1037
|
+
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
|
|
1038
|
+
}
|
|
1014
1039
|
__privateSet(this, _connected, false);
|
|
1015
|
-
(
|
|
1040
|
+
(_d = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _d.call(this);
|
|
1041
|
+
throw err;
|
|
1016
1042
|
}
|
|
1043
|
+
__privateSet(this, _connected, false);
|
|
1044
|
+
(_e = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _e.call(this);
|
|
1017
1045
|
});
|
|
1018
1046
|
};
|
|
1019
1047
|
requestShape_fn = function() {
|
|
@@ -1060,7 +1088,6 @@ requestShape_fn = function() {
|
|
|
1060
1088
|
yield __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, Array.isArray(e.json) ? e.json : [e.json]);
|
|
1061
1089
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
1062
1090
|
} else {
|
|
1063
|
-
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, e);
|
|
1064
1091
|
throw e;
|
|
1065
1092
|
}
|
|
1066
1093
|
} finally {
|
|
@@ -1212,7 +1239,7 @@ fetchShape_fn = function(opts) {
|
|
|
1212
1239
|
return __async(this, null, function* () {
|
|
1213
1240
|
var _a;
|
|
1214
1241
|
const useSse = (_a = this.options.liveSse) != null ? _a : this.options.experimentalLiveSse;
|
|
1215
|
-
if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause) {
|
|
1242
|
+
if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause && !__privateGet(this, _sseFallbackToLongPolling)) {
|
|
1216
1243
|
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
1217
1244
|
opts.fetchUrl.searchParams.set(LIVE_SSE_QUERY_PARAM, `true`);
|
|
1218
1245
|
return __privateMethod(this, _ShapeStream_instances, requestShapeSSE_fn).call(this, opts);
|
|
@@ -1240,6 +1267,7 @@ requestShapeSSE_fn = function(opts) {
|
|
|
1240
1267
|
return __async(this, null, function* () {
|
|
1241
1268
|
const { fetchUrl, requestAbortController, headers } = opts;
|
|
1242
1269
|
const fetch2 = __privateGet(this, _sseFetchClient);
|
|
1270
|
+
__privateSet(this, _lastSseConnectionStartTime, Date.now());
|
|
1243
1271
|
try {
|
|
1244
1272
|
let buffer = [];
|
|
1245
1273
|
yield (0, import_fetch_event_source.fetchEventSource)(fetchUrl.toString(), {
|
|
@@ -1273,6 +1301,27 @@ requestShapeSSE_fn = function(opts) {
|
|
|
1273
1301
|
throw new FetchBackoffAbortError();
|
|
1274
1302
|
}
|
|
1275
1303
|
throw error;
|
|
1304
|
+
} finally {
|
|
1305
|
+
const connectionDuration = Date.now() - __privateGet(this, _lastSseConnectionStartTime);
|
|
1306
|
+
const wasAborted = requestAbortController.signal.aborted;
|
|
1307
|
+
if (connectionDuration < __privateGet(this, _minSseConnectionDuration) && !wasAborted) {
|
|
1308
|
+
__privateWrapper(this, _consecutiveShortSseConnections)._++;
|
|
1309
|
+
if (__privateGet(this, _consecutiveShortSseConnections) >= __privateGet(this, _maxShortSseConnections)) {
|
|
1310
|
+
__privateSet(this, _sseFallbackToLongPolling, true);
|
|
1311
|
+
console.warn(
|
|
1312
|
+
`[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.`
|
|
1313
|
+
);
|
|
1314
|
+
} else {
|
|
1315
|
+
const maxDelay = Math.min(
|
|
1316
|
+
__privateGet(this, _sseBackoffMaxDelay),
|
|
1317
|
+
__privateGet(this, _sseBackoffBaseDelay) * Math.pow(2, __privateGet(this, _consecutiveShortSseConnections))
|
|
1318
|
+
);
|
|
1319
|
+
const delayMs = Math.floor(Math.random() * maxDelay);
|
|
1320
|
+
yield new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1321
|
+
}
|
|
1322
|
+
} else if (connectionDuration >= __privateGet(this, _minSseConnectionDuration)) {
|
|
1323
|
+
__privateSet(this, _consecutiveShortSseConnections, 0);
|
|
1324
|
+
}
|
|
1276
1325
|
}
|
|
1277
1326
|
});
|
|
1278
1327
|
};
|
|
@@ -1371,6 +1420,8 @@ reset_fn = function(handle) {
|
|
|
1371
1420
|
__privateSet(this, _connected, false);
|
|
1372
1421
|
__privateSet(this, _schema, void 0);
|
|
1373
1422
|
__privateSet(this, _activeSnapshotRequests, 0);
|
|
1423
|
+
__privateSet(this, _consecutiveShortSseConnections, 0);
|
|
1424
|
+
__privateSet(this, _sseFallbackToLongPolling, false);
|
|
1374
1425
|
};
|
|
1375
1426
|
fetchSnapshot_fn = function(url, headers) {
|
|
1376
1427
|
return __async(this, null, function* () {
|