@electric-sql/client 1.5.2 → 1.5.4
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 +957 -274
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +2 -2
- package/dist/index.browser.mjs +4 -3
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.legacy-esm.js +956 -275
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +956 -275
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +304 -375
- package/src/pause-lock.ts +112 -0
- package/src/shape-stream-state.ts +781 -0
package/dist/index.mjs
CHANGED
|
@@ -854,10 +854,202 @@ function compileOrderBy(clauses, columnMapper) {
|
|
|
854
854
|
}).join(`, `);
|
|
855
855
|
}
|
|
856
856
|
|
|
857
|
-
//
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
857
|
+
// ../../node_modules/.pnpm/@microsoft+fetch-event-source@2.0.1_patch_hash=46f4e76dd960e002a542732bb4323817a24fce1673cb71e2f458fe09776fa188/node_modules/@microsoft/fetch-event-source/lib/esm/parse.js
|
|
858
|
+
async function getBytes(stream, onChunk) {
|
|
859
|
+
const reader = stream.getReader();
|
|
860
|
+
let result;
|
|
861
|
+
while (!(result = await reader.read()).done) {
|
|
862
|
+
onChunk(result.value);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
function getLines(onLine) {
|
|
866
|
+
let buffer;
|
|
867
|
+
let position;
|
|
868
|
+
let fieldLength;
|
|
869
|
+
let discardTrailingNewline = false;
|
|
870
|
+
return function onChunk(arr) {
|
|
871
|
+
if (buffer === void 0) {
|
|
872
|
+
buffer = arr;
|
|
873
|
+
position = 0;
|
|
874
|
+
fieldLength = -1;
|
|
875
|
+
} else {
|
|
876
|
+
buffer = concat(buffer, arr);
|
|
877
|
+
}
|
|
878
|
+
const bufLength = buffer.length;
|
|
879
|
+
let lineStart = 0;
|
|
880
|
+
while (position < bufLength) {
|
|
881
|
+
if (discardTrailingNewline) {
|
|
882
|
+
if (buffer[position] === 10) {
|
|
883
|
+
lineStart = ++position;
|
|
884
|
+
}
|
|
885
|
+
discardTrailingNewline = false;
|
|
886
|
+
}
|
|
887
|
+
let lineEnd = -1;
|
|
888
|
+
for (; position < bufLength && lineEnd === -1; ++position) {
|
|
889
|
+
switch (buffer[position]) {
|
|
890
|
+
case 58:
|
|
891
|
+
if (fieldLength === -1) {
|
|
892
|
+
fieldLength = position - lineStart;
|
|
893
|
+
}
|
|
894
|
+
break;
|
|
895
|
+
case 13:
|
|
896
|
+
discardTrailingNewline = true;
|
|
897
|
+
case 10:
|
|
898
|
+
lineEnd = position;
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
if (lineEnd === -1) {
|
|
903
|
+
break;
|
|
904
|
+
}
|
|
905
|
+
onLine(buffer.subarray(lineStart, lineEnd), fieldLength);
|
|
906
|
+
lineStart = position;
|
|
907
|
+
fieldLength = -1;
|
|
908
|
+
}
|
|
909
|
+
if (lineStart === bufLength) {
|
|
910
|
+
buffer = void 0;
|
|
911
|
+
} else if (lineStart !== 0) {
|
|
912
|
+
buffer = buffer.subarray(lineStart);
|
|
913
|
+
position -= lineStart;
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
function getMessages(onId, onRetry, onMessage) {
|
|
918
|
+
let message = newMessage();
|
|
919
|
+
const decoder = new TextDecoder();
|
|
920
|
+
return function onLine(line, fieldLength) {
|
|
921
|
+
if (line.length === 0) {
|
|
922
|
+
onMessage === null || onMessage === void 0 ? void 0 : onMessage(message);
|
|
923
|
+
message = newMessage();
|
|
924
|
+
} else if (fieldLength > 0) {
|
|
925
|
+
const field = decoder.decode(line.subarray(0, fieldLength));
|
|
926
|
+
const valueOffset = fieldLength + (line[fieldLength + 1] === 32 ? 2 : 1);
|
|
927
|
+
const value = decoder.decode(line.subarray(valueOffset));
|
|
928
|
+
switch (field) {
|
|
929
|
+
case "data":
|
|
930
|
+
message.data = message.data ? message.data + "\n" + value : value;
|
|
931
|
+
break;
|
|
932
|
+
case "event":
|
|
933
|
+
message.event = value;
|
|
934
|
+
break;
|
|
935
|
+
case "id":
|
|
936
|
+
onId(message.id = value);
|
|
937
|
+
break;
|
|
938
|
+
case "retry":
|
|
939
|
+
const retry = parseInt(value, 10);
|
|
940
|
+
if (!isNaN(retry)) {
|
|
941
|
+
onRetry(message.retry = retry);
|
|
942
|
+
}
|
|
943
|
+
break;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
function concat(a, b) {
|
|
949
|
+
const res = new Uint8Array(a.length + b.length);
|
|
950
|
+
res.set(a);
|
|
951
|
+
res.set(b, a.length);
|
|
952
|
+
return res;
|
|
953
|
+
}
|
|
954
|
+
function newMessage() {
|
|
955
|
+
return {
|
|
956
|
+
data: "",
|
|
957
|
+
event: "",
|
|
958
|
+
id: "",
|
|
959
|
+
retry: void 0
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// ../../node_modules/.pnpm/@microsoft+fetch-event-source@2.0.1_patch_hash=46f4e76dd960e002a542732bb4323817a24fce1673cb71e2f458fe09776fa188/node_modules/@microsoft/fetch-event-source/lib/esm/fetch.js
|
|
964
|
+
var __rest = function(s, e) {
|
|
965
|
+
var t = {};
|
|
966
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
967
|
+
t[p] = s[p];
|
|
968
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
969
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
970
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
971
|
+
t[p[i]] = s[p[i]];
|
|
972
|
+
}
|
|
973
|
+
return t;
|
|
974
|
+
};
|
|
975
|
+
var EventStreamContentType = "text/event-stream";
|
|
976
|
+
var DefaultRetryInterval = 1e3;
|
|
977
|
+
var LastEventId = "last-event-id";
|
|
978
|
+
function fetchEventSource(input, _a) {
|
|
979
|
+
var { signal: inputSignal, headers: inputHeaders, onopen: inputOnOpen, onmessage, onclose, onerror, openWhenHidden, fetch: inputFetch } = _a, rest = __rest(_a, ["signal", "headers", "onopen", "onmessage", "onclose", "onerror", "openWhenHidden", "fetch"]);
|
|
980
|
+
return new Promise((resolve, reject) => {
|
|
981
|
+
const headers = Object.assign({}, inputHeaders);
|
|
982
|
+
if (!headers.accept) {
|
|
983
|
+
headers.accept = EventStreamContentType;
|
|
984
|
+
}
|
|
985
|
+
let curRequestController;
|
|
986
|
+
function onVisibilityChange() {
|
|
987
|
+
curRequestController.abort();
|
|
988
|
+
if (typeof document !== "undefined" && !document.hidden) {
|
|
989
|
+
create();
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
if (typeof document !== "undefined" && !openWhenHidden) {
|
|
993
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
994
|
+
}
|
|
995
|
+
let retryInterval = DefaultRetryInterval;
|
|
996
|
+
let retryTimer = 0;
|
|
997
|
+
function dispose() {
|
|
998
|
+
if (typeof document !== "undefined") {
|
|
999
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
1000
|
+
}
|
|
1001
|
+
clearTimeout(retryTimer);
|
|
1002
|
+
curRequestController.abort();
|
|
1003
|
+
}
|
|
1004
|
+
inputSignal === null || inputSignal === void 0 ? void 0 : inputSignal.addEventListener("abort", () => {
|
|
1005
|
+
dispose();
|
|
1006
|
+
});
|
|
1007
|
+
const fetch2 = inputFetch !== null && inputFetch !== void 0 ? inputFetch : window.fetch;
|
|
1008
|
+
const onopen = inputOnOpen !== null && inputOnOpen !== void 0 ? inputOnOpen : defaultOnOpen;
|
|
1009
|
+
async function create() {
|
|
1010
|
+
var _a2;
|
|
1011
|
+
curRequestController = new AbortController();
|
|
1012
|
+
const sig = inputSignal.aborted ? inputSignal : curRequestController.signal;
|
|
1013
|
+
try {
|
|
1014
|
+
const response = await fetch2(input, Object.assign(Object.assign({}, rest), { headers, signal: sig }));
|
|
1015
|
+
await onopen(response);
|
|
1016
|
+
await getBytes(response.body, getLines(getMessages((id) => {
|
|
1017
|
+
if (id) {
|
|
1018
|
+
headers[LastEventId] = id;
|
|
1019
|
+
} else {
|
|
1020
|
+
delete headers[LastEventId];
|
|
1021
|
+
}
|
|
1022
|
+
}, (retry) => {
|
|
1023
|
+
retryInterval = retry;
|
|
1024
|
+
}, onmessage)));
|
|
1025
|
+
onclose === null || onclose === void 0 ? void 0 : onclose();
|
|
1026
|
+
dispose();
|
|
1027
|
+
resolve();
|
|
1028
|
+
} catch (err) {
|
|
1029
|
+
if (sig.aborted) {
|
|
1030
|
+
dispose();
|
|
1031
|
+
reject(err);
|
|
1032
|
+
} else if (!curRequestController.signal.aborted) {
|
|
1033
|
+
try {
|
|
1034
|
+
const interval = (_a2 = onerror === null || onerror === void 0 ? void 0 : onerror(err)) !== null && _a2 !== void 0 ? _a2 : retryInterval;
|
|
1035
|
+
clearTimeout(retryTimer);
|
|
1036
|
+
retryTimer = setTimeout(create, interval);
|
|
1037
|
+
} catch (innerErr) {
|
|
1038
|
+
dispose();
|
|
1039
|
+
reject(innerErr);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
create();
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
function defaultOnOpen(response) {
|
|
1048
|
+
const contentType = response.headers.get("content-type");
|
|
1049
|
+
if (!(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith(EventStreamContentType))) {
|
|
1050
|
+
throw new Error(`Expected content-type to be ${EventStreamContentType}, Actual: ${contentType}`);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
861
1053
|
|
|
862
1054
|
// src/expired-shapes-cache.ts
|
|
863
1055
|
var ExpiredShapesCache = class {
|
|
@@ -1095,6 +1287,544 @@ var SnapshotTracker = class {
|
|
|
1095
1287
|
}
|
|
1096
1288
|
};
|
|
1097
1289
|
|
|
1290
|
+
// src/shape-stream-state.ts
|
|
1291
|
+
var ShapeStreamState = class {
|
|
1292
|
+
// --- Derived booleans ---
|
|
1293
|
+
get isUpToDate() {
|
|
1294
|
+
return false;
|
|
1295
|
+
}
|
|
1296
|
+
// --- Per-state field defaults ---
|
|
1297
|
+
get staleCacheBuster() {
|
|
1298
|
+
return void 0;
|
|
1299
|
+
}
|
|
1300
|
+
get staleCacheRetryCount() {
|
|
1301
|
+
return 0;
|
|
1302
|
+
}
|
|
1303
|
+
get sseFallbackToLongPolling() {
|
|
1304
|
+
return false;
|
|
1305
|
+
}
|
|
1306
|
+
get consecutiveShortSseConnections() {
|
|
1307
|
+
return 0;
|
|
1308
|
+
}
|
|
1309
|
+
get replayCursor() {
|
|
1310
|
+
return void 0;
|
|
1311
|
+
}
|
|
1312
|
+
// --- Default no-op methods ---
|
|
1313
|
+
canEnterReplayMode() {
|
|
1314
|
+
return false;
|
|
1315
|
+
}
|
|
1316
|
+
enterReplayMode(_cursor) {
|
|
1317
|
+
return this;
|
|
1318
|
+
}
|
|
1319
|
+
shouldUseSse(_opts) {
|
|
1320
|
+
return false;
|
|
1321
|
+
}
|
|
1322
|
+
handleSseConnectionClosed(_input) {
|
|
1323
|
+
return {
|
|
1324
|
+
state: this,
|
|
1325
|
+
fellBackToLongPolling: false,
|
|
1326
|
+
wasShortConnection: false
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
// --- URL param application ---
|
|
1330
|
+
/** Adds state-specific query parameters to the fetch URL. */
|
|
1331
|
+
applyUrlParams(_url, _context) {
|
|
1332
|
+
}
|
|
1333
|
+
// --- Default response/message handlers (Paused/Error never receive these) ---
|
|
1334
|
+
handleResponseMetadata(_input) {
|
|
1335
|
+
return { action: `ignored`, state: this };
|
|
1336
|
+
}
|
|
1337
|
+
handleMessageBatch(_input) {
|
|
1338
|
+
return { state: this, suppressBatch: false, becameUpToDate: false };
|
|
1339
|
+
}
|
|
1340
|
+
pause() {
|
|
1341
|
+
return new PausedState(this);
|
|
1342
|
+
}
|
|
1343
|
+
toErrorState(error) {
|
|
1344
|
+
return new ErrorState(this, error);
|
|
1345
|
+
}
|
|
1346
|
+
markMustRefetch(handle) {
|
|
1347
|
+
return new InitialState({
|
|
1348
|
+
handle,
|
|
1349
|
+
offset: `-1`,
|
|
1350
|
+
liveCacheBuster: ``,
|
|
1351
|
+
lastSyncedAt: this.lastSyncedAt,
|
|
1352
|
+
schema: void 0
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
var _shared;
|
|
1357
|
+
var ActiveState = class extends ShapeStreamState {
|
|
1358
|
+
constructor(shared) {
|
|
1359
|
+
super();
|
|
1360
|
+
__privateAdd(this, _shared);
|
|
1361
|
+
__privateSet(this, _shared, shared);
|
|
1362
|
+
}
|
|
1363
|
+
get handle() {
|
|
1364
|
+
return __privateGet(this, _shared).handle;
|
|
1365
|
+
}
|
|
1366
|
+
get offset() {
|
|
1367
|
+
return __privateGet(this, _shared).offset;
|
|
1368
|
+
}
|
|
1369
|
+
get schema() {
|
|
1370
|
+
return __privateGet(this, _shared).schema;
|
|
1371
|
+
}
|
|
1372
|
+
get liveCacheBuster() {
|
|
1373
|
+
return __privateGet(this, _shared).liveCacheBuster;
|
|
1374
|
+
}
|
|
1375
|
+
get lastSyncedAt() {
|
|
1376
|
+
return __privateGet(this, _shared).lastSyncedAt;
|
|
1377
|
+
}
|
|
1378
|
+
/** Expose shared fields to subclasses for spreading into new instances. */
|
|
1379
|
+
get currentFields() {
|
|
1380
|
+
return __privateGet(this, _shared);
|
|
1381
|
+
}
|
|
1382
|
+
// --- URL param application ---
|
|
1383
|
+
applyUrlParams(url, _context) {
|
|
1384
|
+
url.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _shared).offset);
|
|
1385
|
+
if (__privateGet(this, _shared).handle) {
|
|
1386
|
+
url.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shared).handle);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
// --- Helpers for subclass handleResponseMetadata implementations ---
|
|
1390
|
+
/** Extracts updated SharedStateFields from response headers. */
|
|
1391
|
+
parseResponseFields(input) {
|
|
1392
|
+
var _a, _b, _c;
|
|
1393
|
+
const responseHandle = input.responseHandle;
|
|
1394
|
+
const handle = responseHandle && responseHandle !== input.expiredHandle ? responseHandle : __privateGet(this, _shared).handle;
|
|
1395
|
+
const offset = (_a = input.responseOffset) != null ? _a : __privateGet(this, _shared).offset;
|
|
1396
|
+
const liveCacheBuster = (_b = input.responseCursor) != null ? _b : __privateGet(this, _shared).liveCacheBuster;
|
|
1397
|
+
const schema = (_c = __privateGet(this, _shared).schema) != null ? _c : input.responseSchema;
|
|
1398
|
+
const lastSyncedAt = input.status === 204 ? input.now : __privateGet(this, _shared).lastSyncedAt;
|
|
1399
|
+
return { handle, offset, schema, liveCacheBuster, lastSyncedAt };
|
|
1400
|
+
}
|
|
1401
|
+
/**
|
|
1402
|
+
* Stale detection. Returns a transition if the response is stale,
|
|
1403
|
+
* or null if it is not stale and the caller should proceed normally.
|
|
1404
|
+
*/
|
|
1405
|
+
checkStaleResponse(input) {
|
|
1406
|
+
const responseHandle = input.responseHandle;
|
|
1407
|
+
const expiredHandle = input.expiredHandle;
|
|
1408
|
+
if (!responseHandle || responseHandle !== expiredHandle) {
|
|
1409
|
+
return null;
|
|
1410
|
+
}
|
|
1411
|
+
if (__privateGet(this, _shared).handle === void 0 || __privateGet(this, _shared).handle === expiredHandle) {
|
|
1412
|
+
const retryCount = this.staleCacheRetryCount + 1;
|
|
1413
|
+
return {
|
|
1414
|
+
action: `stale-retry`,
|
|
1415
|
+
state: new StaleRetryState(__spreadProps(__spreadValues({}, this.currentFields), {
|
|
1416
|
+
staleCacheBuster: input.createCacheBuster(),
|
|
1417
|
+
staleCacheRetryCount: retryCount
|
|
1418
|
+
})),
|
|
1419
|
+
exceededMaxRetries: retryCount > input.maxStaleCacheRetries
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
return { action: `ignored`, state: this };
|
|
1423
|
+
}
|
|
1424
|
+
// --- handleMessageBatch: template method with onUpToDate override point ---
|
|
1425
|
+
handleMessageBatch(input) {
|
|
1426
|
+
if (!input.hasMessages || !input.hasUpToDateMessage) {
|
|
1427
|
+
return { state: this, suppressBatch: false, becameUpToDate: false };
|
|
1428
|
+
}
|
|
1429
|
+
let offset = __privateGet(this, _shared).offset;
|
|
1430
|
+
if (input.isSse && input.upToDateOffset) {
|
|
1431
|
+
offset = input.upToDateOffset;
|
|
1432
|
+
}
|
|
1433
|
+
const shared = {
|
|
1434
|
+
handle: __privateGet(this, _shared).handle,
|
|
1435
|
+
offset,
|
|
1436
|
+
schema: __privateGet(this, _shared).schema,
|
|
1437
|
+
liveCacheBuster: __privateGet(this, _shared).liveCacheBuster,
|
|
1438
|
+
lastSyncedAt: input.now
|
|
1439
|
+
};
|
|
1440
|
+
return this.onUpToDate(shared, input);
|
|
1441
|
+
}
|
|
1442
|
+
/** Override point for up-to-date handling. Default → LiveState. */
|
|
1443
|
+
onUpToDate(shared, _input) {
|
|
1444
|
+
return {
|
|
1445
|
+
state: new LiveState(shared),
|
|
1446
|
+
suppressBatch: false,
|
|
1447
|
+
becameUpToDate: true
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
_shared = new WeakMap();
|
|
1452
|
+
var FetchingState = class extends ActiveState {
|
|
1453
|
+
handleResponseMetadata(input) {
|
|
1454
|
+
const staleResult = this.checkStaleResponse(input);
|
|
1455
|
+
if (staleResult) return staleResult;
|
|
1456
|
+
const shared = this.parseResponseFields(input);
|
|
1457
|
+
return { action: `accepted`, state: new SyncingState(shared) };
|
|
1458
|
+
}
|
|
1459
|
+
canEnterReplayMode() {
|
|
1460
|
+
return true;
|
|
1461
|
+
}
|
|
1462
|
+
enterReplayMode(cursor) {
|
|
1463
|
+
return new ReplayingState(__spreadProps(__spreadValues({}, this.currentFields), {
|
|
1464
|
+
replayCursor: cursor
|
|
1465
|
+
}));
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
var InitialState = class _InitialState extends FetchingState {
|
|
1469
|
+
constructor(shared) {
|
|
1470
|
+
super(shared);
|
|
1471
|
+
this.kind = `initial`;
|
|
1472
|
+
}
|
|
1473
|
+
withHandle(handle) {
|
|
1474
|
+
return new _InitialState(__spreadProps(__spreadValues({}, this.currentFields), { handle }));
|
|
1475
|
+
}
|
|
1476
|
+
};
|
|
1477
|
+
var SyncingState = class _SyncingState extends FetchingState {
|
|
1478
|
+
constructor(shared) {
|
|
1479
|
+
super(shared);
|
|
1480
|
+
this.kind = `syncing`;
|
|
1481
|
+
}
|
|
1482
|
+
withHandle(handle) {
|
|
1483
|
+
return new _SyncingState(__spreadProps(__spreadValues({}, this.currentFields), { handle }));
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
var _staleCacheBuster, _staleCacheRetryCount;
|
|
1487
|
+
var _StaleRetryState = class _StaleRetryState extends FetchingState {
|
|
1488
|
+
constructor(fields) {
|
|
1489
|
+
const _a = fields, { staleCacheBuster, staleCacheRetryCount } = _a, shared = __objRest(_a, ["staleCacheBuster", "staleCacheRetryCount"]);
|
|
1490
|
+
super(shared);
|
|
1491
|
+
this.kind = `stale-retry`;
|
|
1492
|
+
__privateAdd(this, _staleCacheBuster);
|
|
1493
|
+
__privateAdd(this, _staleCacheRetryCount);
|
|
1494
|
+
__privateSet(this, _staleCacheBuster, staleCacheBuster);
|
|
1495
|
+
__privateSet(this, _staleCacheRetryCount, staleCacheRetryCount);
|
|
1496
|
+
}
|
|
1497
|
+
get staleCacheBuster() {
|
|
1498
|
+
return __privateGet(this, _staleCacheBuster);
|
|
1499
|
+
}
|
|
1500
|
+
get staleCacheRetryCount() {
|
|
1501
|
+
return __privateGet(this, _staleCacheRetryCount);
|
|
1502
|
+
}
|
|
1503
|
+
// StaleRetryState must not enter replay mode — it would lose the retry count
|
|
1504
|
+
canEnterReplayMode() {
|
|
1505
|
+
return false;
|
|
1506
|
+
}
|
|
1507
|
+
withHandle(handle) {
|
|
1508
|
+
return new _StaleRetryState(__spreadProps(__spreadValues({}, this.currentFields), {
|
|
1509
|
+
handle,
|
|
1510
|
+
staleCacheBuster: __privateGet(this, _staleCacheBuster),
|
|
1511
|
+
staleCacheRetryCount: __privateGet(this, _staleCacheRetryCount)
|
|
1512
|
+
}));
|
|
1513
|
+
}
|
|
1514
|
+
applyUrlParams(url, context) {
|
|
1515
|
+
super.applyUrlParams(url, context);
|
|
1516
|
+
url.searchParams.set(CACHE_BUSTER_QUERY_PARAM, __privateGet(this, _staleCacheBuster));
|
|
1517
|
+
}
|
|
1518
|
+
};
|
|
1519
|
+
_staleCacheBuster = new WeakMap();
|
|
1520
|
+
_staleCacheRetryCount = new WeakMap();
|
|
1521
|
+
var StaleRetryState = _StaleRetryState;
|
|
1522
|
+
var _consecutiveShortSseConnections, _sseFallbackToLongPolling;
|
|
1523
|
+
var _LiveState = class _LiveState extends ActiveState {
|
|
1524
|
+
constructor(shared, sseState) {
|
|
1525
|
+
var _a, _b;
|
|
1526
|
+
super(shared);
|
|
1527
|
+
this.kind = `live`;
|
|
1528
|
+
__privateAdd(this, _consecutiveShortSseConnections);
|
|
1529
|
+
__privateAdd(this, _sseFallbackToLongPolling);
|
|
1530
|
+
__privateSet(this, _consecutiveShortSseConnections, (_a = sseState == null ? void 0 : sseState.consecutiveShortSseConnections) != null ? _a : 0);
|
|
1531
|
+
__privateSet(this, _sseFallbackToLongPolling, (_b = sseState == null ? void 0 : sseState.sseFallbackToLongPolling) != null ? _b : false);
|
|
1532
|
+
}
|
|
1533
|
+
get isUpToDate() {
|
|
1534
|
+
return true;
|
|
1535
|
+
}
|
|
1536
|
+
get consecutiveShortSseConnections() {
|
|
1537
|
+
return __privateGet(this, _consecutiveShortSseConnections);
|
|
1538
|
+
}
|
|
1539
|
+
get sseFallbackToLongPolling() {
|
|
1540
|
+
return __privateGet(this, _sseFallbackToLongPolling);
|
|
1541
|
+
}
|
|
1542
|
+
withHandle(handle) {
|
|
1543
|
+
return new _LiveState(__spreadProps(__spreadValues({}, this.currentFields), { handle }), this.sseState);
|
|
1544
|
+
}
|
|
1545
|
+
applyUrlParams(url, context) {
|
|
1546
|
+
super.applyUrlParams(url, context);
|
|
1547
|
+
if (!context.isSnapshotRequest) {
|
|
1548
|
+
url.searchParams.set(LIVE_CACHE_BUSTER_QUERY_PARAM, this.liveCacheBuster);
|
|
1549
|
+
if (context.canLongPoll) {
|
|
1550
|
+
url.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
get sseState() {
|
|
1555
|
+
return {
|
|
1556
|
+
consecutiveShortSseConnections: __privateGet(this, _consecutiveShortSseConnections),
|
|
1557
|
+
sseFallbackToLongPolling: __privateGet(this, _sseFallbackToLongPolling)
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
handleResponseMetadata(input) {
|
|
1561
|
+
const staleResult = this.checkStaleResponse(input);
|
|
1562
|
+
if (staleResult) return staleResult;
|
|
1563
|
+
const shared = this.parseResponseFields(input);
|
|
1564
|
+
return {
|
|
1565
|
+
action: `accepted`,
|
|
1566
|
+
state: new _LiveState(shared, this.sseState)
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
onUpToDate(shared, _input) {
|
|
1570
|
+
return {
|
|
1571
|
+
state: new _LiveState(shared, this.sseState),
|
|
1572
|
+
suppressBatch: false,
|
|
1573
|
+
becameUpToDate: true
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
shouldUseSse(opts) {
|
|
1577
|
+
return opts.liveSseEnabled && !opts.isRefreshing && !opts.resumingFromPause && !__privateGet(this, _sseFallbackToLongPolling);
|
|
1578
|
+
}
|
|
1579
|
+
handleSseConnectionClosed(input) {
|
|
1580
|
+
let nextConsecutiveShort = __privateGet(this, _consecutiveShortSseConnections);
|
|
1581
|
+
let nextFallback = __privateGet(this, _sseFallbackToLongPolling);
|
|
1582
|
+
let fellBackToLongPolling = false;
|
|
1583
|
+
let wasShortConnection = false;
|
|
1584
|
+
if (input.connectionDuration < input.minConnectionDuration && !input.wasAborted) {
|
|
1585
|
+
wasShortConnection = true;
|
|
1586
|
+
nextConsecutiveShort = nextConsecutiveShort + 1;
|
|
1587
|
+
if (nextConsecutiveShort >= input.maxShortConnections) {
|
|
1588
|
+
nextFallback = true;
|
|
1589
|
+
fellBackToLongPolling = true;
|
|
1590
|
+
}
|
|
1591
|
+
} else if (input.connectionDuration >= input.minConnectionDuration) {
|
|
1592
|
+
nextConsecutiveShort = 0;
|
|
1593
|
+
}
|
|
1594
|
+
return {
|
|
1595
|
+
state: new _LiveState(this.currentFields, {
|
|
1596
|
+
consecutiveShortSseConnections: nextConsecutiveShort,
|
|
1597
|
+
sseFallbackToLongPolling: nextFallback
|
|
1598
|
+
}),
|
|
1599
|
+
fellBackToLongPolling,
|
|
1600
|
+
wasShortConnection
|
|
1601
|
+
};
|
|
1602
|
+
}
|
|
1603
|
+
};
|
|
1604
|
+
_consecutiveShortSseConnections = new WeakMap();
|
|
1605
|
+
_sseFallbackToLongPolling = new WeakMap();
|
|
1606
|
+
var LiveState = _LiveState;
|
|
1607
|
+
var _replayCursor;
|
|
1608
|
+
var _ReplayingState = class _ReplayingState extends ActiveState {
|
|
1609
|
+
constructor(fields) {
|
|
1610
|
+
const _a = fields, { replayCursor } = _a, shared = __objRest(_a, ["replayCursor"]);
|
|
1611
|
+
super(shared);
|
|
1612
|
+
this.kind = `replaying`;
|
|
1613
|
+
__privateAdd(this, _replayCursor);
|
|
1614
|
+
__privateSet(this, _replayCursor, replayCursor);
|
|
1615
|
+
}
|
|
1616
|
+
get replayCursor() {
|
|
1617
|
+
return __privateGet(this, _replayCursor);
|
|
1618
|
+
}
|
|
1619
|
+
withHandle(handle) {
|
|
1620
|
+
return new _ReplayingState(__spreadProps(__spreadValues({}, this.currentFields), {
|
|
1621
|
+
handle,
|
|
1622
|
+
replayCursor: __privateGet(this, _replayCursor)
|
|
1623
|
+
}));
|
|
1624
|
+
}
|
|
1625
|
+
handleResponseMetadata(input) {
|
|
1626
|
+
const staleResult = this.checkStaleResponse(input);
|
|
1627
|
+
if (staleResult) return staleResult;
|
|
1628
|
+
const shared = this.parseResponseFields(input);
|
|
1629
|
+
return {
|
|
1630
|
+
action: `accepted`,
|
|
1631
|
+
state: new _ReplayingState(__spreadProps(__spreadValues({}, shared), {
|
|
1632
|
+
replayCursor: __privateGet(this, _replayCursor)
|
|
1633
|
+
}))
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1636
|
+
onUpToDate(shared, input) {
|
|
1637
|
+
const suppressBatch = !input.isSse && __privateGet(this, _replayCursor) === input.currentCursor;
|
|
1638
|
+
return {
|
|
1639
|
+
state: new LiveState(shared),
|
|
1640
|
+
suppressBatch,
|
|
1641
|
+
becameUpToDate: true
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
_replayCursor = new WeakMap();
|
|
1646
|
+
var ReplayingState = _ReplayingState;
|
|
1647
|
+
var PausedState = class _PausedState extends ShapeStreamState {
|
|
1648
|
+
constructor(previousState) {
|
|
1649
|
+
super();
|
|
1650
|
+
this.kind = `paused`;
|
|
1651
|
+
this.previousState = previousState;
|
|
1652
|
+
}
|
|
1653
|
+
get handle() {
|
|
1654
|
+
return this.previousState.handle;
|
|
1655
|
+
}
|
|
1656
|
+
get offset() {
|
|
1657
|
+
return this.previousState.offset;
|
|
1658
|
+
}
|
|
1659
|
+
get schema() {
|
|
1660
|
+
return this.previousState.schema;
|
|
1661
|
+
}
|
|
1662
|
+
get liveCacheBuster() {
|
|
1663
|
+
return this.previousState.liveCacheBuster;
|
|
1664
|
+
}
|
|
1665
|
+
get lastSyncedAt() {
|
|
1666
|
+
return this.previousState.lastSyncedAt;
|
|
1667
|
+
}
|
|
1668
|
+
get isUpToDate() {
|
|
1669
|
+
return this.previousState.isUpToDate;
|
|
1670
|
+
}
|
|
1671
|
+
get staleCacheBuster() {
|
|
1672
|
+
return this.previousState.staleCacheBuster;
|
|
1673
|
+
}
|
|
1674
|
+
get staleCacheRetryCount() {
|
|
1675
|
+
return this.previousState.staleCacheRetryCount;
|
|
1676
|
+
}
|
|
1677
|
+
get sseFallbackToLongPolling() {
|
|
1678
|
+
return this.previousState.sseFallbackToLongPolling;
|
|
1679
|
+
}
|
|
1680
|
+
get consecutiveShortSseConnections() {
|
|
1681
|
+
return this.previousState.consecutiveShortSseConnections;
|
|
1682
|
+
}
|
|
1683
|
+
get replayCursor() {
|
|
1684
|
+
return this.previousState.replayCursor;
|
|
1685
|
+
}
|
|
1686
|
+
withHandle(handle) {
|
|
1687
|
+
return new _PausedState(this.previousState.withHandle(handle));
|
|
1688
|
+
}
|
|
1689
|
+
applyUrlParams(url, context) {
|
|
1690
|
+
this.previousState.applyUrlParams(url, context);
|
|
1691
|
+
}
|
|
1692
|
+
pause() {
|
|
1693
|
+
return this;
|
|
1694
|
+
}
|
|
1695
|
+
resume() {
|
|
1696
|
+
return this.previousState;
|
|
1697
|
+
}
|
|
1698
|
+
};
|
|
1699
|
+
var ErrorState = class _ErrorState extends ShapeStreamState {
|
|
1700
|
+
constructor(previousState, error) {
|
|
1701
|
+
super();
|
|
1702
|
+
this.kind = `error`;
|
|
1703
|
+
this.previousState = previousState;
|
|
1704
|
+
this.error = error;
|
|
1705
|
+
}
|
|
1706
|
+
get handle() {
|
|
1707
|
+
return this.previousState.handle;
|
|
1708
|
+
}
|
|
1709
|
+
get offset() {
|
|
1710
|
+
return this.previousState.offset;
|
|
1711
|
+
}
|
|
1712
|
+
get schema() {
|
|
1713
|
+
return this.previousState.schema;
|
|
1714
|
+
}
|
|
1715
|
+
get liveCacheBuster() {
|
|
1716
|
+
return this.previousState.liveCacheBuster;
|
|
1717
|
+
}
|
|
1718
|
+
get lastSyncedAt() {
|
|
1719
|
+
return this.previousState.lastSyncedAt;
|
|
1720
|
+
}
|
|
1721
|
+
get isUpToDate() {
|
|
1722
|
+
return this.previousState.isUpToDate;
|
|
1723
|
+
}
|
|
1724
|
+
withHandle(handle) {
|
|
1725
|
+
return new _ErrorState(this.previousState.withHandle(handle), this.error);
|
|
1726
|
+
}
|
|
1727
|
+
applyUrlParams(url, context) {
|
|
1728
|
+
this.previousState.applyUrlParams(url, context);
|
|
1729
|
+
}
|
|
1730
|
+
retry() {
|
|
1731
|
+
return this.previousState;
|
|
1732
|
+
}
|
|
1733
|
+
reset(handle) {
|
|
1734
|
+
return this.previousState.markMustRefetch(handle);
|
|
1735
|
+
}
|
|
1736
|
+
};
|
|
1737
|
+
function createInitialState(opts) {
|
|
1738
|
+
return new InitialState({
|
|
1739
|
+
handle: opts.handle,
|
|
1740
|
+
offset: opts.offset,
|
|
1741
|
+
liveCacheBuster: ``,
|
|
1742
|
+
lastSyncedAt: void 0,
|
|
1743
|
+
schema: void 0
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
// src/pause-lock.ts
|
|
1748
|
+
var _holders, _onAcquired, _onReleased;
|
|
1749
|
+
var PauseLock = class {
|
|
1750
|
+
constructor(callbacks) {
|
|
1751
|
+
__privateAdd(this, _holders, /* @__PURE__ */ new Set());
|
|
1752
|
+
__privateAdd(this, _onAcquired);
|
|
1753
|
+
__privateAdd(this, _onReleased);
|
|
1754
|
+
__privateSet(this, _onAcquired, callbacks.onAcquired);
|
|
1755
|
+
__privateSet(this, _onReleased, callbacks.onReleased);
|
|
1756
|
+
}
|
|
1757
|
+
/**
|
|
1758
|
+
* Acquire the lock for a given reason. Idempotent — acquiring the same
|
|
1759
|
+
* reason twice is a no-op (but logs a warning since it likely indicates
|
|
1760
|
+
* a caller bug).
|
|
1761
|
+
*
|
|
1762
|
+
* Fires `onAcquired` when the first reason is acquired (transition from
|
|
1763
|
+
* unlocked to locked).
|
|
1764
|
+
*/
|
|
1765
|
+
acquire(reason) {
|
|
1766
|
+
if (__privateGet(this, _holders).has(reason)) {
|
|
1767
|
+
console.warn(
|
|
1768
|
+
`[Electric] PauseLock: "${reason}" already held \u2014 ignoring duplicate acquire`
|
|
1769
|
+
);
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
const wasUnlocked = __privateGet(this, _holders).size === 0;
|
|
1773
|
+
__privateGet(this, _holders).add(reason);
|
|
1774
|
+
if (wasUnlocked) {
|
|
1775
|
+
__privateGet(this, _onAcquired).call(this);
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Release the lock for a given reason. Releasing a reason that isn't
|
|
1780
|
+
* held logs a warning (likely indicates an acquire/release mismatch).
|
|
1781
|
+
*
|
|
1782
|
+
* Fires `onReleased` when the last reason is released (transition from
|
|
1783
|
+
* locked to unlocked).
|
|
1784
|
+
*/
|
|
1785
|
+
release(reason) {
|
|
1786
|
+
if (!__privateGet(this, _holders).delete(reason)) {
|
|
1787
|
+
console.warn(
|
|
1788
|
+
`[Electric] PauseLock: "${reason}" not held \u2014 ignoring release (possible acquire/release mismatch)`
|
|
1789
|
+
);
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
if (__privateGet(this, _holders).size === 0) {
|
|
1793
|
+
__privateGet(this, _onReleased).call(this);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
/**
|
|
1797
|
+
* Whether the lock is currently held by any reason.
|
|
1798
|
+
*/
|
|
1799
|
+
get isPaused() {
|
|
1800
|
+
return __privateGet(this, _holders).size > 0;
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Check if a specific reason is holding the lock.
|
|
1804
|
+
*/
|
|
1805
|
+
isHeldBy(reason) {
|
|
1806
|
+
return __privateGet(this, _holders).has(reason);
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1809
|
+
* Release all reasons matching a prefix. Does NOT fire `onReleased` —
|
|
1810
|
+
* this is for cleanup/reset paths where the stream state is being
|
|
1811
|
+
* managed separately.
|
|
1812
|
+
*
|
|
1813
|
+
* This preserves reasons with different prefixes (e.g., 'visibility'
|
|
1814
|
+
* is preserved when clearing 'snapshot-*' reasons).
|
|
1815
|
+
*/
|
|
1816
|
+
releaseAllMatching(prefix) {
|
|
1817
|
+
for (const reason of __privateGet(this, _holders)) {
|
|
1818
|
+
if (reason.startsWith(prefix)) {
|
|
1819
|
+
__privateGet(this, _holders).delete(reason);
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
};
|
|
1824
|
+
_holders = new WeakMap();
|
|
1825
|
+
_onAcquired = new WeakMap();
|
|
1826
|
+
_onReleased = new WeakMap();
|
|
1827
|
+
|
|
1098
1828
|
// src/client.ts
|
|
1099
1829
|
var RESERVED_PARAMS = /* @__PURE__ */ new Set([
|
|
1100
1830
|
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
@@ -1143,7 +1873,7 @@ function canonicalShapeKey(url) {
|
|
|
1143
1873
|
cleanUrl.searchParams.sort();
|
|
1144
1874
|
return cleanUrl.toString();
|
|
1145
1875
|
}
|
|
1146
|
-
var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started,
|
|
1876
|
+
var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started, _syncState, _connected, _mode, _onError, _requestAbortController, _refreshCount, _snapshotCounter, _ShapeStream_instances, isRefreshing_get, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _messageChain, _snapshotTracker, _pauseLock, _currentFetchUrl, _lastSseConnectionStartTime, _minSseConnectionDuration, _maxShortSseConnections, _sseBackoffBaseDelay, _sseBackoffMaxDelay, _unsubscribeFromVisibilityChanges, _unsubscribeFromWakeDetection, _maxStaleCacheRetries, start_fn, teardown_fn, requestShape_fn, constructUrl_fn, createAbortListener_fn, onInitialResponse_fn, onMessages_fn, fetchShape_fn, requestShapeLongPoll_fn, requestShapeSSE_fn, nextTick_fn, publish_fn, sendErrorToSubscribers_fn, hasBrowserVisibilityAPI_fn, subscribeToVisibilityChanges_fn, subscribeToWakeDetection_fn, reset_fn, buildSubsetBody_fn;
|
|
1147
1877
|
var ShapeStream = class {
|
|
1148
1878
|
constructor(options) {
|
|
1149
1879
|
__privateAdd(this, _ShapeStream_instances);
|
|
@@ -1153,58 +1883,57 @@ var ShapeStream = class {
|
|
|
1153
1883
|
__privateAdd(this, _messageParser);
|
|
1154
1884
|
__privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
|
|
1155
1885
|
__privateAdd(this, _started, false);
|
|
1156
|
-
__privateAdd(this,
|
|
1157
|
-
__privateAdd(this, _lastOffset);
|
|
1158
|
-
__privateAdd(this, _liveCacheBuster);
|
|
1159
|
-
// Seconds since our Electric Epoch 😎
|
|
1160
|
-
__privateAdd(this, _lastSyncedAt);
|
|
1161
|
-
// unix time
|
|
1162
|
-
__privateAdd(this, _isUpToDate, false);
|
|
1163
|
-
__privateAdd(this, _isMidStream, true);
|
|
1886
|
+
__privateAdd(this, _syncState);
|
|
1164
1887
|
__privateAdd(this, _connected, false);
|
|
1165
|
-
__privateAdd(this, _shapeHandle);
|
|
1166
1888
|
__privateAdd(this, _mode);
|
|
1167
|
-
__privateAdd(this, _schema);
|
|
1168
1889
|
__privateAdd(this, _onError);
|
|
1169
1890
|
__privateAdd(this, _requestAbortController);
|
|
1170
|
-
__privateAdd(this,
|
|
1891
|
+
__privateAdd(this, _refreshCount, 0);
|
|
1892
|
+
__privateAdd(this, _snapshotCounter, 0);
|
|
1171
1893
|
__privateAdd(this, _tickPromise);
|
|
1172
1894
|
__privateAdd(this, _tickPromiseResolver);
|
|
1173
1895
|
__privateAdd(this, _tickPromiseRejecter);
|
|
1174
1896
|
__privateAdd(this, _messageChain, Promise.resolve([]));
|
|
1175
1897
|
// promise chain for incoming messages
|
|
1176
1898
|
__privateAdd(this, _snapshotTracker, new SnapshotTracker());
|
|
1177
|
-
__privateAdd(this,
|
|
1178
|
-
// counter for concurrent snapshot requests
|
|
1179
|
-
__privateAdd(this, _midStreamPromise);
|
|
1180
|
-
__privateAdd(this, _midStreamPromiseResolver);
|
|
1181
|
-
__privateAdd(this, _lastSeenCursor);
|
|
1182
|
-
// Last seen cursor from previous session (used to detect cached responses)
|
|
1899
|
+
__privateAdd(this, _pauseLock);
|
|
1183
1900
|
__privateAdd(this, _currentFetchUrl);
|
|
1184
1901
|
// Current fetch URL for computing shape key
|
|
1185
1902
|
__privateAdd(this, _lastSseConnectionStartTime);
|
|
1186
1903
|
__privateAdd(this, _minSseConnectionDuration, 1e3);
|
|
1187
1904
|
// Minimum expected SSE connection duration (1 second)
|
|
1188
|
-
__privateAdd(this, _consecutiveShortSseConnections, 0);
|
|
1189
1905
|
__privateAdd(this, _maxShortSseConnections, 3);
|
|
1190
1906
|
// Fall back to long polling after this many short connections
|
|
1191
|
-
__privateAdd(this, _sseFallbackToLongPolling, false);
|
|
1192
1907
|
__privateAdd(this, _sseBackoffBaseDelay, 100);
|
|
1193
1908
|
// Base delay for exponential backoff (ms)
|
|
1194
1909
|
__privateAdd(this, _sseBackoffMaxDelay, 5e3);
|
|
1195
1910
|
// Maximum delay cap (ms)
|
|
1196
1911
|
__privateAdd(this, _unsubscribeFromVisibilityChanges);
|
|
1197
1912
|
__privateAdd(this, _unsubscribeFromWakeDetection);
|
|
1198
|
-
__privateAdd(this, _staleCacheBuster);
|
|
1199
|
-
// Cache buster set when stale CDN response detected, used on retry requests to bypass cache
|
|
1200
|
-
__privateAdd(this, _staleCacheRetryCount, 0);
|
|
1201
1913
|
__privateAdd(this, _maxStaleCacheRetries, 3);
|
|
1202
1914
|
var _a, _b, _c, _d;
|
|
1203
1915
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
1204
1916
|
validateOptions(this.options);
|
|
1205
|
-
__privateSet(this,
|
|
1206
|
-
|
|
1207
|
-
|
|
1917
|
+
__privateSet(this, _syncState, createInitialState({
|
|
1918
|
+
offset: (_a = this.options.offset) != null ? _a : `-1`,
|
|
1919
|
+
handle: this.options.handle
|
|
1920
|
+
}));
|
|
1921
|
+
__privateSet(this, _pauseLock, new PauseLock({
|
|
1922
|
+
onAcquired: () => {
|
|
1923
|
+
var _a2;
|
|
1924
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).pause());
|
|
1925
|
+
if (__privateGet(this, _started)) {
|
|
1926
|
+
(_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(PAUSE_STREAM);
|
|
1927
|
+
}
|
|
1928
|
+
},
|
|
1929
|
+
onReleased: () => {
|
|
1930
|
+
var _a2;
|
|
1931
|
+
if (!__privateGet(this, _started)) return;
|
|
1932
|
+
if ((_a2 = this.options.signal) == null ? void 0 : _a2.aborted) return;
|
|
1933
|
+
__privateMethod(this, _ShapeStream_instances, start_fn).call(this).catch(() => {
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
}));
|
|
1208
1937
|
let transformer;
|
|
1209
1938
|
if (options.columnMapper) {
|
|
1210
1939
|
const applyColumnMapper = (row) => {
|
|
@@ -1242,16 +1971,16 @@ var ShapeStream = class {
|
|
|
1242
1971
|
__privateMethod(this, _ShapeStream_instances, subscribeToWakeDetection_fn).call(this);
|
|
1243
1972
|
}
|
|
1244
1973
|
get shapeHandle() {
|
|
1245
|
-
return __privateGet(this,
|
|
1974
|
+
return __privateGet(this, _syncState).handle;
|
|
1246
1975
|
}
|
|
1247
1976
|
get error() {
|
|
1248
1977
|
return __privateGet(this, _error);
|
|
1249
1978
|
}
|
|
1250
1979
|
get isUpToDate() {
|
|
1251
|
-
return __privateGet(this,
|
|
1980
|
+
return __privateGet(this, _syncState).isUpToDate;
|
|
1252
1981
|
}
|
|
1253
1982
|
get lastOffset() {
|
|
1254
|
-
return __privateGet(this,
|
|
1983
|
+
return __privateGet(this, _syncState).offset;
|
|
1255
1984
|
}
|
|
1256
1985
|
get mode() {
|
|
1257
1986
|
return __privateGet(this, _mode);
|
|
@@ -1271,28 +2000,28 @@ var ShapeStream = class {
|
|
|
1271
2000
|
(_a = __privateGet(this, _unsubscribeFromVisibilityChanges)) == null ? void 0 : _a.call(this);
|
|
1272
2001
|
(_b = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _b.call(this);
|
|
1273
2002
|
}
|
|
1274
|
-
/** Unix time at which we last synced. Undefined
|
|
2003
|
+
/** Unix time at which we last synced. Undefined until first successful up-to-date. */
|
|
1275
2004
|
lastSyncedAt() {
|
|
1276
|
-
return __privateGet(this,
|
|
2005
|
+
return __privateGet(this, _syncState).lastSyncedAt;
|
|
1277
2006
|
}
|
|
1278
2007
|
/** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */
|
|
1279
2008
|
lastSynced() {
|
|
1280
|
-
if (__privateGet(this,
|
|
1281
|
-
return Date.now() - __privateGet(this,
|
|
2009
|
+
if (__privateGet(this, _syncState).lastSyncedAt === void 0) return Infinity;
|
|
2010
|
+
return Date.now() - __privateGet(this, _syncState).lastSyncedAt;
|
|
1282
2011
|
}
|
|
1283
2012
|
/** Indicates if we are connected to the Electric sync service. */
|
|
1284
2013
|
isConnected() {
|
|
1285
2014
|
return __privateGet(this, _connected);
|
|
1286
2015
|
}
|
|
1287
|
-
/** True during initial fetch. False
|
|
2016
|
+
/** True during initial fetch. False afterwards. */
|
|
1288
2017
|
isLoading() {
|
|
1289
|
-
return !__privateGet(this,
|
|
2018
|
+
return !__privateGet(this, _syncState).isUpToDate;
|
|
1290
2019
|
}
|
|
1291
2020
|
hasStarted() {
|
|
1292
2021
|
return __privateGet(this, _started);
|
|
1293
2022
|
}
|
|
1294
2023
|
isPaused() {
|
|
1295
|
-
return __privateGet(this,
|
|
2024
|
+
return __privateGet(this, _pauseLock).isPaused;
|
|
1296
2025
|
}
|
|
1297
2026
|
/**
|
|
1298
2027
|
* Refreshes the shape stream.
|
|
@@ -1302,12 +2031,15 @@ var ShapeStream = class {
|
|
|
1302
2031
|
*/
|
|
1303
2032
|
async forceDisconnectAndRefresh() {
|
|
1304
2033
|
var _a, _b;
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
(
|
|
2034
|
+
__privateWrapper(this, _refreshCount)._++;
|
|
2035
|
+
try {
|
|
2036
|
+
if (__privateGet(this, _syncState).isUpToDate && !((_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.signal.aborted)) {
|
|
2037
|
+
(_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(FORCE_DISCONNECT_AND_REFRESH);
|
|
2038
|
+
}
|
|
2039
|
+
await __privateMethod(this, _ShapeStream_instances, nextTick_fn).call(this);
|
|
2040
|
+
} finally {
|
|
2041
|
+
__privateWrapper(this, _refreshCount)._--;
|
|
1308
2042
|
}
|
|
1309
|
-
await __privateMethod(this, _ShapeStream_instances, nextTick_fn).call(this);
|
|
1310
|
-
__privateSet(this, _isRefreshing, false);
|
|
1311
2043
|
}
|
|
1312
2044
|
/**
|
|
1313
2045
|
* Request a snapshot for subset of data and inject it into the subscribed data stream.
|
|
@@ -1329,13 +2061,18 @@ var ShapeStream = class {
|
|
|
1329
2061
|
`Snapshot requests are not supported in ${__privateGet(this, _mode)} mode, as the consumer is guaranteed to observe all data`
|
|
1330
2062
|
);
|
|
1331
2063
|
}
|
|
1332
|
-
if (!__privateGet(this, _started))
|
|
1333
|
-
|
|
1334
|
-
|
|
2064
|
+
if (!__privateGet(this, _started)) {
|
|
2065
|
+
__privateMethod(this, _ShapeStream_instances, start_fn).call(this).catch(() => {
|
|
2066
|
+
});
|
|
2067
|
+
}
|
|
2068
|
+
const snapshotReason = `snapshot-${++__privateWrapper(this, _snapshotCounter)._}`;
|
|
2069
|
+
__privateGet(this, _pauseLock).acquire(snapshotReason);
|
|
2070
|
+
const snapshotWarnTimer = setTimeout(() => {
|
|
2071
|
+
console.warn(
|
|
2072
|
+
`[Electric] Snapshot "${snapshotReason}" has held the pause lock for 30s \u2014 possible hung request or leaked lock. Current holders: ${[.../* @__PURE__ */ new Set([snapshotReason])].join(`, `)}`
|
|
2073
|
+
);
|
|
2074
|
+
}, 3e4);
|
|
1335
2075
|
try {
|
|
1336
|
-
if (__privateGet(this, _activeSnapshotRequests) === 1) {
|
|
1337
|
-
__privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
|
|
1338
|
-
}
|
|
1339
2076
|
const { metadata, data } = await this.fetchSnapshot(opts);
|
|
1340
2077
|
const dataWithEndBoundary = data.concat([
|
|
1341
2078
|
{ headers: __spreadValues({ control: `snapshot-end` }, metadata) },
|
|
@@ -1351,10 +2088,8 @@ var ShapeStream = class {
|
|
|
1351
2088
|
data
|
|
1352
2089
|
};
|
|
1353
2090
|
} finally {
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
__privateMethod(this, _ShapeStream_instances, resume_fn).call(this);
|
|
1357
|
-
}
|
|
2091
|
+
clearTimeout(snapshotWarnTimer);
|
|
2092
|
+
__privateGet(this, _pauseLock).release(snapshotReason);
|
|
1358
2093
|
}
|
|
1359
2094
|
}
|
|
1360
2095
|
/**
|
|
@@ -1389,7 +2124,7 @@ var ShapeStream = class {
|
|
|
1389
2124
|
fetchUrl = result.fetchUrl;
|
|
1390
2125
|
fetchOptions = { headers: result.requestHeaders };
|
|
1391
2126
|
}
|
|
1392
|
-
const usedHandle = __privateGet(this,
|
|
2127
|
+
const usedHandle = __privateGet(this, _syncState).handle;
|
|
1393
2128
|
let response;
|
|
1394
2129
|
try {
|
|
1395
2130
|
response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), fetchOptions);
|
|
@@ -1399,7 +2134,8 @@ var ShapeStream = class {
|
|
|
1399
2134
|
const shapeKey = canonicalShapeKey(fetchUrl);
|
|
1400
2135
|
expiredShapesCache.markExpired(shapeKey, usedHandle);
|
|
1401
2136
|
}
|
|
1402
|
-
|
|
2137
|
+
const nextHandle = e.headers[SHAPE_HANDLE_HEADER] || `${usedHandle != null ? usedHandle : `handle`}-next`;
|
|
2138
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).withHandle(nextHandle));
|
|
1403
2139
|
return this.fetchSnapshot(opts);
|
|
1404
2140
|
}
|
|
1405
2141
|
throw e;
|
|
@@ -1407,7 +2143,7 @@ var ShapeStream = class {
|
|
|
1407
2143
|
if (!response.ok) {
|
|
1408
2144
|
throw await FetchError.fromResponse(response, fetchUrl.toString());
|
|
1409
2145
|
}
|
|
1410
|
-
const schema = (_c = __privateGet(this,
|
|
2146
|
+
const schema = (_c = __privateGet(this, _syncState).schema) != null ? _c : getSchemaFromHeaders(response.headers, {
|
|
1411
2147
|
required: true,
|
|
1412
2148
|
url: fetchUrl.toString()
|
|
1413
2149
|
});
|
|
@@ -1425,52 +2161,42 @@ _sseFetchClient = new WeakMap();
|
|
|
1425
2161
|
_messageParser = new WeakMap();
|
|
1426
2162
|
_subscribers = new WeakMap();
|
|
1427
2163
|
_started = new WeakMap();
|
|
1428
|
-
|
|
1429
|
-
_lastOffset = new WeakMap();
|
|
1430
|
-
_liveCacheBuster = new WeakMap();
|
|
1431
|
-
_lastSyncedAt = new WeakMap();
|
|
1432
|
-
_isUpToDate = new WeakMap();
|
|
1433
|
-
_isMidStream = new WeakMap();
|
|
2164
|
+
_syncState = new WeakMap();
|
|
1434
2165
|
_connected = new WeakMap();
|
|
1435
|
-
_shapeHandle = new WeakMap();
|
|
1436
2166
|
_mode = new WeakMap();
|
|
1437
|
-
_schema = new WeakMap();
|
|
1438
2167
|
_onError = new WeakMap();
|
|
1439
2168
|
_requestAbortController = new WeakMap();
|
|
1440
|
-
|
|
2169
|
+
_refreshCount = new WeakMap();
|
|
2170
|
+
_snapshotCounter = new WeakMap();
|
|
2171
|
+
_ShapeStream_instances = new WeakSet();
|
|
2172
|
+
isRefreshing_get = function() {
|
|
2173
|
+
return __privateGet(this, _refreshCount) > 0;
|
|
2174
|
+
};
|
|
1441
2175
|
_tickPromise = new WeakMap();
|
|
1442
2176
|
_tickPromiseResolver = new WeakMap();
|
|
1443
2177
|
_tickPromiseRejecter = new WeakMap();
|
|
1444
2178
|
_messageChain = new WeakMap();
|
|
1445
2179
|
_snapshotTracker = new WeakMap();
|
|
1446
|
-
|
|
1447
|
-
_midStreamPromise = new WeakMap();
|
|
1448
|
-
_midStreamPromiseResolver = new WeakMap();
|
|
1449
|
-
_lastSeenCursor = new WeakMap();
|
|
2180
|
+
_pauseLock = new WeakMap();
|
|
1450
2181
|
_currentFetchUrl = new WeakMap();
|
|
1451
2182
|
_lastSseConnectionStartTime = new WeakMap();
|
|
1452
2183
|
_minSseConnectionDuration = new WeakMap();
|
|
1453
|
-
_consecutiveShortSseConnections = new WeakMap();
|
|
1454
2184
|
_maxShortSseConnections = new WeakMap();
|
|
1455
|
-
_sseFallbackToLongPolling = new WeakMap();
|
|
1456
2185
|
_sseBackoffBaseDelay = new WeakMap();
|
|
1457
2186
|
_sseBackoffMaxDelay = new WeakMap();
|
|
1458
2187
|
_unsubscribeFromVisibilityChanges = new WeakMap();
|
|
1459
2188
|
_unsubscribeFromWakeDetection = new WeakMap();
|
|
1460
|
-
_staleCacheBuster = new WeakMap();
|
|
1461
|
-
_staleCacheRetryCount = new WeakMap();
|
|
1462
2189
|
_maxStaleCacheRetries = new WeakMap();
|
|
1463
|
-
_ShapeStream_instances = new WeakSet();
|
|
1464
|
-
replayMode_get = function() {
|
|
1465
|
-
return __privateGet(this, _lastSeenCursor) !== void 0;
|
|
1466
|
-
};
|
|
1467
2190
|
start_fn = async function() {
|
|
1468
|
-
var _a, _b
|
|
2191
|
+
var _a, _b;
|
|
1469
2192
|
__privateSet(this, _started, true);
|
|
1470
2193
|
try {
|
|
1471
2194
|
await __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
1472
2195
|
} catch (err) {
|
|
1473
2196
|
__privateSet(this, _error, err);
|
|
2197
|
+
if (err instanceof Error) {
|
|
2198
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).toErrorState(err));
|
|
2199
|
+
}
|
|
1474
2200
|
if (__privateGet(this, _onError)) {
|
|
1475
2201
|
const retryOpts = await __privateGet(this, _onError).call(this, err);
|
|
1476
2202
|
const isRetryable = !(err instanceof MissingHeadersError);
|
|
@@ -1482,6 +2208,9 @@ start_fn = async function() {
|
|
|
1482
2208
|
this.options.headers = __spreadValues(__spreadValues({}, (_b = this.options.headers) != null ? _b : {}), retryOpts.headers);
|
|
1483
2209
|
}
|
|
1484
2210
|
__privateSet(this, _error, null);
|
|
2211
|
+
if (__privateGet(this, _syncState) instanceof ErrorState) {
|
|
2212
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).retry());
|
|
2213
|
+
}
|
|
1485
2214
|
__privateSet(this, _started, false);
|
|
1486
2215
|
await __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
1487
2216
|
return;
|
|
@@ -1489,38 +2218,45 @@ start_fn = async function() {
|
|
|
1489
2218
|
if (err instanceof Error) {
|
|
1490
2219
|
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
|
|
1491
2220
|
}
|
|
1492
|
-
|
|
1493
|
-
(_c = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _c.call(this);
|
|
1494
|
-
(_d = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _d.call(this);
|
|
2221
|
+
__privateMethod(this, _ShapeStream_instances, teardown_fn).call(this);
|
|
1495
2222
|
return;
|
|
1496
2223
|
}
|
|
1497
2224
|
if (err instanceof Error) {
|
|
1498
2225
|
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
|
|
1499
2226
|
}
|
|
1500
|
-
|
|
1501
|
-
(_e = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _e.call(this);
|
|
1502
|
-
(_f = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _f.call(this);
|
|
2227
|
+
__privateMethod(this, _ShapeStream_instances, teardown_fn).call(this);
|
|
1503
2228
|
throw err;
|
|
1504
2229
|
}
|
|
2230
|
+
__privateMethod(this, _ShapeStream_instances, teardown_fn).call(this);
|
|
2231
|
+
};
|
|
2232
|
+
teardown_fn = function() {
|
|
2233
|
+
var _a, _b;
|
|
1505
2234
|
__privateSet(this, _connected, false);
|
|
1506
|
-
(
|
|
1507
|
-
(
|
|
2235
|
+
(_a = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _a.call(this);
|
|
2236
|
+
(_b = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _b.call(this);
|
|
1508
2237
|
};
|
|
1509
2238
|
requestShape_fn = async function() {
|
|
1510
2239
|
var _a, _b;
|
|
1511
|
-
if (__privateGet(this,
|
|
1512
|
-
|
|
2240
|
+
if (__privateGet(this, _pauseLock).isPaused) return;
|
|
2241
|
+
if (!this.options.subscribe && (((_a = this.options.signal) == null ? void 0 : _a.aborted) || __privateGet(this, _syncState).isUpToDate)) {
|
|
1513
2242
|
return;
|
|
1514
2243
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
2244
|
+
let resumingFromPause = false;
|
|
2245
|
+
if (__privateGet(this, _syncState) instanceof PausedState) {
|
|
2246
|
+
resumingFromPause = true;
|
|
2247
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).resume());
|
|
1517
2248
|
}
|
|
1518
|
-
const resumingFromPause = __privateGet(this, _state) === `paused`;
|
|
1519
|
-
__privateSet(this, _state, `active`);
|
|
1520
2249
|
const { url, signal } = this.options;
|
|
1521
2250
|
const { fetchUrl, requestHeaders } = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, url, resumingFromPause);
|
|
1522
2251
|
const abortListener = await __privateMethod(this, _ShapeStream_instances, createAbortListener_fn).call(this, signal);
|
|
1523
2252
|
const requestAbortController = __privateGet(this, _requestAbortController);
|
|
2253
|
+
if (__privateGet(this, _pauseLock).isPaused) {
|
|
2254
|
+
if (abortListener && signal) {
|
|
2255
|
+
signal.removeEventListener(`abort`, abortListener);
|
|
2256
|
+
}
|
|
2257
|
+
__privateSet(this, _requestAbortController, void 0);
|
|
2258
|
+
return;
|
|
2259
|
+
}
|
|
1524
2260
|
try {
|
|
1525
2261
|
await __privateMethod(this, _ShapeStream_instances, fetchShape_fn).call(this, {
|
|
1526
2262
|
fetchUrl,
|
|
@@ -1535,10 +2271,6 @@ requestShape_fn = async function() {
|
|
|
1535
2271
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
1536
2272
|
}
|
|
1537
2273
|
if (e instanceof FetchBackoffAbortError) {
|
|
1538
|
-
const currentState = __privateGet(this, _state);
|
|
1539
|
-
if (requestAbortController.signal.aborted && requestAbortController.signal.reason === PAUSE_STREAM && currentState === `pause-requested`) {
|
|
1540
|
-
__privateSet(this, _state, `paused`);
|
|
1541
|
-
}
|
|
1542
2274
|
return;
|
|
1543
2275
|
}
|
|
1544
2276
|
if (e instanceof StaleCacheError) {
|
|
@@ -1546,11 +2278,11 @@ requestShape_fn = async function() {
|
|
|
1546
2278
|
}
|
|
1547
2279
|
if (!(e instanceof FetchError)) throw e;
|
|
1548
2280
|
if (e.status == 409) {
|
|
1549
|
-
if (__privateGet(this,
|
|
2281
|
+
if (__privateGet(this, _syncState).handle) {
|
|
1550
2282
|
const shapeKey = canonicalShapeKey(fetchUrl);
|
|
1551
|
-
expiredShapesCache.markExpired(shapeKey, __privateGet(this,
|
|
2283
|
+
expiredShapesCache.markExpired(shapeKey, __privateGet(this, _syncState).handle);
|
|
1552
2284
|
}
|
|
1553
|
-
const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER] || `${__privateGet(this,
|
|
2285
|
+
const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER] || `${__privateGet(this, _syncState).handle}-next`;
|
|
1554
2286
|
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
|
|
1555
2287
|
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, Array.isArray(e.json) ? e.json : [e.json]);
|
|
1556
2288
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
@@ -1656,32 +2388,18 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
|
|
|
1656
2388
|
setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, encodedOrderBy);
|
|
1657
2389
|
}
|
|
1658
2390
|
}
|
|
1659
|
-
|
|
2391
|
+
__privateGet(this, _syncState).applyUrlParams(fetchUrl, {
|
|
2392
|
+
isSnapshotRequest: subsetParams !== void 0,
|
|
2393
|
+
// Don't long-poll when resuming from pause or refreshing — avoids
|
|
2394
|
+
// a 20s hold during which `isConnected` would be false
|
|
2395
|
+
canLongPoll: !__privateGet(this, _ShapeStream_instances, isRefreshing_get) && !resumingFromPause
|
|
2396
|
+
});
|
|
1660
2397
|
fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
|
|
1661
|
-
const isSnapshotRequest = subsetParams !== void 0;
|
|
1662
|
-
if (__privateGet(this, _isUpToDate) && !isSnapshotRequest) {
|
|
1663
|
-
if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
|
|
1664
|
-
fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
1665
|
-
}
|
|
1666
|
-
fetchUrl.searchParams.set(
|
|
1667
|
-
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
1668
|
-
__privateGet(this, _liveCacheBuster)
|
|
1669
|
-
);
|
|
1670
|
-
}
|
|
1671
|
-
if (__privateGet(this, _shapeHandle)) {
|
|
1672
|
-
fetchUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shapeHandle));
|
|
1673
|
-
}
|
|
1674
2398
|
const shapeKey = canonicalShapeKey(fetchUrl);
|
|
1675
2399
|
const expiredHandle = expiredShapesCache.getExpiredHandle(shapeKey);
|
|
1676
2400
|
if (expiredHandle) {
|
|
1677
2401
|
fetchUrl.searchParams.set(EXPIRED_HANDLE_QUERY_PARAM, expiredHandle);
|
|
1678
2402
|
}
|
|
1679
|
-
if (__privateGet(this, _staleCacheBuster)) {
|
|
1680
|
-
fetchUrl.searchParams.set(
|
|
1681
|
-
CACHE_BUSTER_QUERY_PARAM,
|
|
1682
|
-
__privateGet(this, _staleCacheBuster)
|
|
1683
|
-
);
|
|
1684
|
-
}
|
|
1685
2403
|
fetchUrl.searchParams.sort();
|
|
1686
2404
|
return {
|
|
1687
2405
|
fetchUrl,
|
|
@@ -1704,108 +2422,100 @@ createAbortListener_fn = async function(signal) {
|
|
|
1704
2422
|
}
|
|
1705
2423
|
};
|
|
1706
2424
|
onInitialResponse_fn = async function(response) {
|
|
1707
|
-
var _a, _b, _c
|
|
2425
|
+
var _a, _b, _c;
|
|
1708
2426
|
const { headers, status } = response;
|
|
1709
2427
|
const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
`
|
|
1734
|
-
);
|
|
1735
|
-
__privateSet(this, _staleCacheBuster, `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`);
|
|
1736
|
-
throw new StaleCacheError(
|
|
1737
|
-
`Received stale cached response with expired handle "${shapeHandle}". This indicates a proxy/CDN caching misconfiguration. Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key.`
|
|
1738
|
-
);
|
|
1739
|
-
} else {
|
|
1740
|
-
console.warn(
|
|
1741
|
-
`[Electric] Received stale cached response with expired shape handle. This should not happen and indicates a proxy/CDN caching misconfiguration. The response contained handle "${shapeHandle}" which was previously marked as expired. Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key. Ignoring the stale response and continuing with handle "${__privateGet(this, _shapeHandle)}".`
|
|
2428
|
+
const shapeKey = __privateGet(this, _currentFetchUrl) ? canonicalShapeKey(__privateGet(this, _currentFetchUrl)) : null;
|
|
2429
|
+
const expiredHandle = shapeKey ? expiredShapesCache.getExpiredHandle(shapeKey) : null;
|
|
2430
|
+
const transition = __privateGet(this, _syncState).handleResponseMetadata({
|
|
2431
|
+
status,
|
|
2432
|
+
responseHandle: shapeHandle,
|
|
2433
|
+
responseOffset: headers.get(CHUNK_LAST_OFFSET_HEADER),
|
|
2434
|
+
responseCursor: headers.get(LIVE_CACHE_BUSTER_HEADER),
|
|
2435
|
+
responseSchema: getSchemaFromHeaders(headers),
|
|
2436
|
+
expiredHandle,
|
|
2437
|
+
now: Date.now(),
|
|
2438
|
+
maxStaleCacheRetries: __privateGet(this, _maxStaleCacheRetries),
|
|
2439
|
+
createCacheBuster: () => `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
|
|
2440
|
+
});
|
|
2441
|
+
__privateSet(this, _syncState, transition.state);
|
|
2442
|
+
if (transition.action === `stale-retry`) {
|
|
2443
|
+
await ((_a = response.body) == null ? void 0 : _a.cancel());
|
|
2444
|
+
if (transition.exceededMaxRetries) {
|
|
2445
|
+
throw new FetchError(
|
|
2446
|
+
502,
|
|
2447
|
+
void 0,
|
|
2448
|
+
void 0,
|
|
2449
|
+
{},
|
|
2450
|
+
(_c = (_b = __privateGet(this, _currentFetchUrl)) == null ? void 0 : _b.toString()) != null ? _c : ``,
|
|
2451
|
+
`CDN continues serving stale cached responses after ${__privateGet(this, _maxStaleCacheRetries)} retry attempts. This indicates a severe proxy/CDN misconfiguration. Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key. For more information visit the troubleshooting guide: https://electric-sql.com/docs/guides/troubleshooting`
|
|
1742
2452
|
);
|
|
1743
|
-
return;
|
|
1744
2453
|
}
|
|
2454
|
+
console.warn(
|
|
2455
|
+
`[Electric] Received stale cached response with expired shape handle. This should not happen and indicates a proxy/CDN caching misconfiguration. The response contained handle "${shapeHandle}" which was previously marked as expired. Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key. For more information visit the troubleshooting guide: https://electric-sql.com/docs/guides/troubleshooting Retrying with a random cache buster to bypass the stale cache (attempt ${__privateGet(this, _syncState).staleCacheRetryCount}/${__privateGet(this, _maxStaleCacheRetries)}).`
|
|
2456
|
+
);
|
|
2457
|
+
throw new StaleCacheError(
|
|
2458
|
+
`Received stale cached response with expired handle "${shapeHandle}". This indicates a proxy/CDN caching misconfiguration. Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key.`
|
|
2459
|
+
);
|
|
1745
2460
|
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
if (liveCacheBuster) {
|
|
1752
|
-
__privateSet(this, _liveCacheBuster, liveCacheBuster);
|
|
1753
|
-
}
|
|
1754
|
-
__privateSet(this, _schema, (_d = __privateGet(this, _schema)) != null ? _d : getSchemaFromHeaders(headers));
|
|
1755
|
-
if (status === 204) {
|
|
1756
|
-
__privateSet(this, _lastSyncedAt, Date.now());
|
|
2461
|
+
if (transition.action === `ignored`) {
|
|
2462
|
+
console.warn(
|
|
2463
|
+
`[Electric] Received stale cached response with expired shape handle. This should not happen and indicates a proxy/CDN caching misconfiguration. The response contained handle "${shapeHandle}" which was previously marked as expired. Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key. Ignoring the stale response and continuing with handle "${__privateGet(this, _syncState).handle}".`
|
|
2464
|
+
);
|
|
2465
|
+
return false;
|
|
1757
2466
|
}
|
|
2467
|
+
return true;
|
|
1758
2468
|
};
|
|
1759
2469
|
onMessages_fn = async function(batch, isSseMessage = false) {
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
if (__privateGet(this, _currentFetchUrl)) {
|
|
1784
|
-
const shapeKey = canonicalShapeKey(__privateGet(this, _currentFetchUrl));
|
|
1785
|
-
upToDateTracker.recordUpToDate(shapeKey, __privateGet(this, _liveCacheBuster));
|
|
1786
|
-
}
|
|
2470
|
+
if (batch.length === 0) return;
|
|
2471
|
+
const lastMessage = batch[batch.length - 1];
|
|
2472
|
+
const hasUpToDateMessage = isUpToDateMessage(lastMessage);
|
|
2473
|
+
const upToDateOffset = hasUpToDateMessage ? getOffset(lastMessage) : void 0;
|
|
2474
|
+
const transition = __privateGet(this, _syncState).handleMessageBatch({
|
|
2475
|
+
hasMessages: true,
|
|
2476
|
+
hasUpToDateMessage,
|
|
2477
|
+
isSse: isSseMessage,
|
|
2478
|
+
upToDateOffset,
|
|
2479
|
+
now: Date.now(),
|
|
2480
|
+
currentCursor: __privateGet(this, _syncState).liveCacheBuster
|
|
2481
|
+
});
|
|
2482
|
+
__privateSet(this, _syncState, transition.state);
|
|
2483
|
+
if (hasUpToDateMessage) {
|
|
2484
|
+
if (transition.suppressBatch) {
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
if (__privateGet(this, _currentFetchUrl)) {
|
|
2488
|
+
const shapeKey = canonicalShapeKey(__privateGet(this, _currentFetchUrl));
|
|
2489
|
+
upToDateTracker.recordUpToDate(
|
|
2490
|
+
shapeKey,
|
|
2491
|
+
__privateGet(this, _syncState).liveCacheBuster
|
|
2492
|
+
);
|
|
1787
2493
|
}
|
|
1788
|
-
const messagesToProcess = batch.filter((message) => {
|
|
1789
|
-
if (isChangeMessage(message)) {
|
|
1790
|
-
return !__privateGet(this, _snapshotTracker).shouldRejectMessage(message);
|
|
1791
|
-
}
|
|
1792
|
-
return true;
|
|
1793
|
-
});
|
|
1794
|
-
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, messagesToProcess);
|
|
1795
2494
|
}
|
|
2495
|
+
const messagesToProcess = batch.filter((message) => {
|
|
2496
|
+
if (isChangeMessage(message)) {
|
|
2497
|
+
return !__privateGet(this, _snapshotTracker).shouldRejectMessage(message);
|
|
2498
|
+
}
|
|
2499
|
+
return true;
|
|
2500
|
+
});
|
|
2501
|
+
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, messagesToProcess);
|
|
1796
2502
|
};
|
|
1797
2503
|
fetchShape_fn = async function(opts) {
|
|
1798
2504
|
var _a;
|
|
1799
2505
|
__privateSet(this, _currentFetchUrl, opts.fetchUrl);
|
|
1800
|
-
if (!__privateGet(this,
|
|
2506
|
+
if (!__privateGet(this, _syncState).isUpToDate && __privateGet(this, _syncState).canEnterReplayMode()) {
|
|
1801
2507
|
const shapeKey = canonicalShapeKey(opts.fetchUrl);
|
|
1802
2508
|
const lastSeenCursor = upToDateTracker.shouldEnterReplayMode(shapeKey);
|
|
1803
2509
|
if (lastSeenCursor) {
|
|
1804
|
-
__privateSet(this,
|
|
2510
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).enterReplayMode(lastSeenCursor));
|
|
1805
2511
|
}
|
|
1806
2512
|
}
|
|
1807
2513
|
const useSse = (_a = this.options.liveSse) != null ? _a : this.options.experimentalLiveSse;
|
|
1808
|
-
if (__privateGet(this,
|
|
2514
|
+
if (__privateGet(this, _syncState).shouldUseSse({
|
|
2515
|
+
liveSseEnabled: !!useSse,
|
|
2516
|
+
isRefreshing: __privateGet(this, _ShapeStream_instances, isRefreshing_get),
|
|
2517
|
+
resumingFromPause: !!opts.resumingFromPause
|
|
2518
|
+
})) {
|
|
1809
2519
|
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
1810
2520
|
opts.fetchUrl.searchParams.set(LIVE_SSE_QUERY_PARAM, `true`);
|
|
1811
2521
|
return __privateMethod(this, _ShapeStream_instances, requestShapeSSE_fn).call(this, opts);
|
|
@@ -1819,8 +2529,9 @@ requestShapeLongPoll_fn = async function(opts) {
|
|
|
1819
2529
|
headers
|
|
1820
2530
|
});
|
|
1821
2531
|
__privateSet(this, _connected, true);
|
|
1822
|
-
await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
1823
|
-
|
|
2532
|
+
const shouldProcessBody = await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
2533
|
+
if (!shouldProcessBody) return;
|
|
2534
|
+
const schema = __privateGet(this, _syncState).schema;
|
|
1824
2535
|
const res = await response.text();
|
|
1825
2536
|
const messages = res || `[]`;
|
|
1826
2537
|
const batch = __privateGet(this, _messageParser).parse(messages, schema);
|
|
@@ -1833,6 +2544,7 @@ requestShapeSSE_fn = async function(opts) {
|
|
|
1833
2544
|
const sseHeaders = __spreadProps(__spreadValues({}, headers), {
|
|
1834
2545
|
Accept: `text/event-stream`
|
|
1835
2546
|
});
|
|
2547
|
+
let ignoredStaleResponse = false;
|
|
1836
2548
|
try {
|
|
1837
2549
|
let buffer = [];
|
|
1838
2550
|
await fetchEventSource(fetchUrl.toString(), {
|
|
@@ -1840,11 +2552,15 @@ requestShapeSSE_fn = async function(opts) {
|
|
|
1840
2552
|
fetch: fetch2,
|
|
1841
2553
|
onopen: async (response) => {
|
|
1842
2554
|
__privateSet(this, _connected, true);
|
|
1843
|
-
await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
2555
|
+
const shouldProcessBody = await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
2556
|
+
if (!shouldProcessBody) {
|
|
2557
|
+
ignoredStaleResponse = true;
|
|
2558
|
+
throw new Error(`stale response ignored`);
|
|
2559
|
+
}
|
|
1844
2560
|
},
|
|
1845
2561
|
onmessage: (event) => {
|
|
1846
2562
|
if (event.data) {
|
|
1847
|
-
const schema = __privateGet(this,
|
|
2563
|
+
const schema = __privateGet(this, _syncState).schema;
|
|
1848
2564
|
const message = __privateGet(this, _messageParser).parse(
|
|
1849
2565
|
event.data,
|
|
1850
2566
|
schema
|
|
@@ -1862,6 +2578,9 @@ requestShapeSSE_fn = async function(opts) {
|
|
|
1862
2578
|
signal: requestAbortController.signal
|
|
1863
2579
|
});
|
|
1864
2580
|
} catch (error) {
|
|
2581
|
+
if (ignoredStaleResponse) {
|
|
2582
|
+
return;
|
|
2583
|
+
}
|
|
1865
2584
|
if (requestAbortController.signal.aborted) {
|
|
1866
2585
|
throw new FetchBackoffAbortError();
|
|
1867
2586
|
}
|
|
@@ -1869,46 +2588,33 @@ requestShapeSSE_fn = async function(opts) {
|
|
|
1869
2588
|
} finally {
|
|
1870
2589
|
const connectionDuration = Date.now() - __privateGet(this, _lastSseConnectionStartTime);
|
|
1871
2590
|
const wasAborted = requestAbortController.signal.aborted;
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
}
|
|
1891
|
-
};
|
|
1892
|
-
pause_fn = function() {
|
|
1893
|
-
var _a;
|
|
1894
|
-
if (__privateGet(this, _started) && __privateGet(this, _state) === `active`) {
|
|
1895
|
-
__privateSet(this, _state, `pause-requested`);
|
|
1896
|
-
(_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.abort(PAUSE_STREAM);
|
|
1897
|
-
}
|
|
1898
|
-
};
|
|
1899
|
-
resume_fn = function() {
|
|
1900
|
-
var _a;
|
|
1901
|
-
if (__privateGet(this, _started) && (__privateGet(this, _state) === `paused` || __privateGet(this, _state) === `pause-requested`)) {
|
|
1902
|
-
if ((_a = this.options.signal) == null ? void 0 : _a.aborted) {
|
|
1903
|
-
return;
|
|
1904
|
-
}
|
|
1905
|
-
if (__privateGet(this, _state) === `pause-requested`) {
|
|
1906
|
-
__privateSet(this, _state, `active`);
|
|
2591
|
+
const transition = __privateGet(this, _syncState).handleSseConnectionClosed({
|
|
2592
|
+
connectionDuration,
|
|
2593
|
+
wasAborted,
|
|
2594
|
+
minConnectionDuration: __privateGet(this, _minSseConnectionDuration),
|
|
2595
|
+
maxShortConnections: __privateGet(this, _maxShortSseConnections)
|
|
2596
|
+
});
|
|
2597
|
+
__privateSet(this, _syncState, transition.state);
|
|
2598
|
+
if (transition.fellBackToLongPolling) {
|
|
2599
|
+
console.warn(
|
|
2600
|
+
`[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.`
|
|
2601
|
+
);
|
|
2602
|
+
} else if (transition.wasShortConnection) {
|
|
2603
|
+
const maxDelay = Math.min(
|
|
2604
|
+
__privateGet(this, _sseBackoffMaxDelay),
|
|
2605
|
+
__privateGet(this, _sseBackoffBaseDelay) * Math.pow(2, __privateGet(this, _syncState).consecutiveShortSseConnections)
|
|
2606
|
+
);
|
|
2607
|
+
const delayMs = Math.floor(Math.random() * maxDelay);
|
|
2608
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1907
2609
|
}
|
|
1908
|
-
__privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
1909
2610
|
}
|
|
1910
2611
|
};
|
|
1911
2612
|
nextTick_fn = async function() {
|
|
2613
|
+
if (__privateGet(this, _pauseLock).isPaused) {
|
|
2614
|
+
throw new Error(
|
|
2615
|
+
`Cannot wait for next tick while PauseLock is held \u2014 this would deadlock because the request loop is paused`
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
1912
2618
|
if (__privateGet(this, _tickPromise)) {
|
|
1913
2619
|
return __privateGet(this, _tickPromise);
|
|
1914
2620
|
}
|
|
@@ -1923,22 +2629,6 @@ nextTick_fn = async function() {
|
|
|
1923
2629
|
});
|
|
1924
2630
|
return __privateGet(this, _tickPromise);
|
|
1925
2631
|
};
|
|
1926
|
-
waitForStreamEnd_fn = async function() {
|
|
1927
|
-
if (!__privateGet(this, _isMidStream)) {
|
|
1928
|
-
return;
|
|
1929
|
-
}
|
|
1930
|
-
if (__privateGet(this, _midStreamPromise)) {
|
|
1931
|
-
return __privateGet(this, _midStreamPromise);
|
|
1932
|
-
}
|
|
1933
|
-
__privateSet(this, _midStreamPromise, new Promise((resolve) => {
|
|
1934
|
-
__privateSet(this, _midStreamPromiseResolver, resolve);
|
|
1935
|
-
}));
|
|
1936
|
-
__privateGet(this, _midStreamPromise).finally(() => {
|
|
1937
|
-
__privateSet(this, _midStreamPromise, void 0);
|
|
1938
|
-
__privateSet(this, _midStreamPromiseResolver, void 0);
|
|
1939
|
-
});
|
|
1940
|
-
return __privateGet(this, _midStreamPromise);
|
|
1941
|
-
};
|
|
1942
2632
|
publish_fn = async function(messages) {
|
|
1943
2633
|
__privateSet(this, _messageChain, __privateGet(this, _messageChain).then(
|
|
1944
2634
|
() => Promise.all(
|
|
@@ -1967,9 +2657,9 @@ subscribeToVisibilityChanges_fn = function() {
|
|
|
1967
2657
|
if (__privateMethod(this, _ShapeStream_instances, hasBrowserVisibilityAPI_fn).call(this)) {
|
|
1968
2658
|
const visibilityHandler = () => {
|
|
1969
2659
|
if (document.hidden) {
|
|
1970
|
-
|
|
2660
|
+
__privateGet(this, _pauseLock).acquire(`visibility`);
|
|
1971
2661
|
} else {
|
|
1972
|
-
|
|
2662
|
+
__privateGet(this, _pauseLock).release(`visibility`);
|
|
1973
2663
|
}
|
|
1974
2664
|
};
|
|
1975
2665
|
document.addEventListener(`visibilitychange`, visibilityHandler);
|
|
@@ -2000,11 +2690,11 @@ subscribeToWakeDetection_fn = function() {
|
|
|
2000
2690
|
const elapsed = now - lastTickTime;
|
|
2001
2691
|
lastTickTime = now;
|
|
2002
2692
|
if (elapsed > INTERVAL_MS + WAKE_THRESHOLD_MS) {
|
|
2003
|
-
if (__privateGet(this,
|
|
2004
|
-
|
|
2693
|
+
if (!__privateGet(this, _pauseLock).isPaused && __privateGet(this, _requestAbortController)) {
|
|
2694
|
+
__privateWrapper(this, _refreshCount)._++;
|
|
2005
2695
|
__privateGet(this, _requestAbortController).abort(SYSTEM_WAKE);
|
|
2006
2696
|
queueMicrotask(() => {
|
|
2007
|
-
|
|
2697
|
+
__privateWrapper(this, _refreshCount)._--;
|
|
2008
2698
|
});
|
|
2009
2699
|
}
|
|
2010
2700
|
}
|
|
@@ -2021,18 +2711,9 @@ subscribeToWakeDetection_fn = function() {
|
|
|
2021
2711
|
* shape handle
|
|
2022
2712
|
*/
|
|
2023
2713
|
reset_fn = function(handle) {
|
|
2024
|
-
__privateSet(this,
|
|
2025
|
-
__privateSet(this, _liveCacheBuster, ``);
|
|
2026
|
-
__privateSet(this, _shapeHandle, handle);
|
|
2027
|
-
__privateSet(this, _isUpToDate, false);
|
|
2028
|
-
__privateSet(this, _isMidStream, true);
|
|
2714
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).markMustRefetch(handle));
|
|
2029
2715
|
__privateSet(this, _connected, false);
|
|
2030
|
-
|
|
2031
|
-
__privateSet(this, _activeSnapshotRequests, 0);
|
|
2032
|
-
__privateSet(this, _consecutiveShortSseConnections, 0);
|
|
2033
|
-
__privateSet(this, _sseFallbackToLongPolling, false);
|
|
2034
|
-
__privateSet(this, _staleCacheBuster, void 0);
|
|
2035
|
-
__privateSet(this, _staleCacheRetryCount, 0);
|
|
2716
|
+
__privateGet(this, _pauseLock).releaseAllMatching(`snapshot`);
|
|
2036
2717
|
};
|
|
2037
2718
|
buildSubsetBody_fn = function(opts) {
|
|
2038
2719
|
var _a, _b, _c, _d;
|