@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/cjs/index.cjs
CHANGED
|
@@ -891,8 +891,202 @@ function compileOrderBy(clauses, columnMapper) {
|
|
|
891
891
|
}).join(`, `);
|
|
892
892
|
}
|
|
893
893
|
|
|
894
|
-
//
|
|
895
|
-
|
|
894
|
+
// ../../node_modules/.pnpm/@microsoft+fetch-event-source@2.0.1_patch_hash=46f4e76dd960e002a542732bb4323817a24fce1673cb71e2f458fe09776fa188/node_modules/@microsoft/fetch-event-source/lib/esm/parse.js
|
|
895
|
+
async function getBytes(stream, onChunk) {
|
|
896
|
+
const reader = stream.getReader();
|
|
897
|
+
let result;
|
|
898
|
+
while (!(result = await reader.read()).done) {
|
|
899
|
+
onChunk(result.value);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
function getLines(onLine) {
|
|
903
|
+
let buffer;
|
|
904
|
+
let position;
|
|
905
|
+
let fieldLength;
|
|
906
|
+
let discardTrailingNewline = false;
|
|
907
|
+
return function onChunk(arr) {
|
|
908
|
+
if (buffer === void 0) {
|
|
909
|
+
buffer = arr;
|
|
910
|
+
position = 0;
|
|
911
|
+
fieldLength = -1;
|
|
912
|
+
} else {
|
|
913
|
+
buffer = concat(buffer, arr);
|
|
914
|
+
}
|
|
915
|
+
const bufLength = buffer.length;
|
|
916
|
+
let lineStart = 0;
|
|
917
|
+
while (position < bufLength) {
|
|
918
|
+
if (discardTrailingNewline) {
|
|
919
|
+
if (buffer[position] === 10) {
|
|
920
|
+
lineStart = ++position;
|
|
921
|
+
}
|
|
922
|
+
discardTrailingNewline = false;
|
|
923
|
+
}
|
|
924
|
+
let lineEnd = -1;
|
|
925
|
+
for (; position < bufLength && lineEnd === -1; ++position) {
|
|
926
|
+
switch (buffer[position]) {
|
|
927
|
+
case 58:
|
|
928
|
+
if (fieldLength === -1) {
|
|
929
|
+
fieldLength = position - lineStart;
|
|
930
|
+
}
|
|
931
|
+
break;
|
|
932
|
+
case 13:
|
|
933
|
+
discardTrailingNewline = true;
|
|
934
|
+
case 10:
|
|
935
|
+
lineEnd = position;
|
|
936
|
+
break;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if (lineEnd === -1) {
|
|
940
|
+
break;
|
|
941
|
+
}
|
|
942
|
+
onLine(buffer.subarray(lineStart, lineEnd), fieldLength);
|
|
943
|
+
lineStart = position;
|
|
944
|
+
fieldLength = -1;
|
|
945
|
+
}
|
|
946
|
+
if (lineStart === bufLength) {
|
|
947
|
+
buffer = void 0;
|
|
948
|
+
} else if (lineStart !== 0) {
|
|
949
|
+
buffer = buffer.subarray(lineStart);
|
|
950
|
+
position -= lineStart;
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
function getMessages(onId, onRetry, onMessage) {
|
|
955
|
+
let message = newMessage();
|
|
956
|
+
const decoder = new TextDecoder();
|
|
957
|
+
return function onLine(line, fieldLength) {
|
|
958
|
+
if (line.length === 0) {
|
|
959
|
+
onMessage === null || onMessage === void 0 ? void 0 : onMessage(message);
|
|
960
|
+
message = newMessage();
|
|
961
|
+
} else if (fieldLength > 0) {
|
|
962
|
+
const field = decoder.decode(line.subarray(0, fieldLength));
|
|
963
|
+
const valueOffset = fieldLength + (line[fieldLength + 1] === 32 ? 2 : 1);
|
|
964
|
+
const value = decoder.decode(line.subarray(valueOffset));
|
|
965
|
+
switch (field) {
|
|
966
|
+
case "data":
|
|
967
|
+
message.data = message.data ? message.data + "\n" + value : value;
|
|
968
|
+
break;
|
|
969
|
+
case "event":
|
|
970
|
+
message.event = value;
|
|
971
|
+
break;
|
|
972
|
+
case "id":
|
|
973
|
+
onId(message.id = value);
|
|
974
|
+
break;
|
|
975
|
+
case "retry":
|
|
976
|
+
const retry = parseInt(value, 10);
|
|
977
|
+
if (!isNaN(retry)) {
|
|
978
|
+
onRetry(message.retry = retry);
|
|
979
|
+
}
|
|
980
|
+
break;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
function concat(a, b) {
|
|
986
|
+
const res = new Uint8Array(a.length + b.length);
|
|
987
|
+
res.set(a);
|
|
988
|
+
res.set(b, a.length);
|
|
989
|
+
return res;
|
|
990
|
+
}
|
|
991
|
+
function newMessage() {
|
|
992
|
+
return {
|
|
993
|
+
data: "",
|
|
994
|
+
event: "",
|
|
995
|
+
id: "",
|
|
996
|
+
retry: void 0
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// ../../node_modules/.pnpm/@microsoft+fetch-event-source@2.0.1_patch_hash=46f4e76dd960e002a542732bb4323817a24fce1673cb71e2f458fe09776fa188/node_modules/@microsoft/fetch-event-source/lib/esm/fetch.js
|
|
1001
|
+
var __rest = function(s, e) {
|
|
1002
|
+
var t = {};
|
|
1003
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
1004
|
+
t[p] = s[p];
|
|
1005
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
1006
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
1007
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
1008
|
+
t[p[i]] = s[p[i]];
|
|
1009
|
+
}
|
|
1010
|
+
return t;
|
|
1011
|
+
};
|
|
1012
|
+
var EventStreamContentType = "text/event-stream";
|
|
1013
|
+
var DefaultRetryInterval = 1e3;
|
|
1014
|
+
var LastEventId = "last-event-id";
|
|
1015
|
+
function fetchEventSource(input, _a) {
|
|
1016
|
+
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"]);
|
|
1017
|
+
return new Promise((resolve, reject) => {
|
|
1018
|
+
const headers = Object.assign({}, inputHeaders);
|
|
1019
|
+
if (!headers.accept) {
|
|
1020
|
+
headers.accept = EventStreamContentType;
|
|
1021
|
+
}
|
|
1022
|
+
let curRequestController;
|
|
1023
|
+
function onVisibilityChange() {
|
|
1024
|
+
curRequestController.abort();
|
|
1025
|
+
if (typeof document !== "undefined" && !document.hidden) {
|
|
1026
|
+
create();
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
if (typeof document !== "undefined" && !openWhenHidden) {
|
|
1030
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
1031
|
+
}
|
|
1032
|
+
let retryInterval = DefaultRetryInterval;
|
|
1033
|
+
let retryTimer = 0;
|
|
1034
|
+
function dispose() {
|
|
1035
|
+
if (typeof document !== "undefined") {
|
|
1036
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
1037
|
+
}
|
|
1038
|
+
clearTimeout(retryTimer);
|
|
1039
|
+
curRequestController.abort();
|
|
1040
|
+
}
|
|
1041
|
+
inputSignal === null || inputSignal === void 0 ? void 0 : inputSignal.addEventListener("abort", () => {
|
|
1042
|
+
dispose();
|
|
1043
|
+
});
|
|
1044
|
+
const fetch2 = inputFetch !== null && inputFetch !== void 0 ? inputFetch : window.fetch;
|
|
1045
|
+
const onopen = inputOnOpen !== null && inputOnOpen !== void 0 ? inputOnOpen : defaultOnOpen;
|
|
1046
|
+
async function create() {
|
|
1047
|
+
var _a2;
|
|
1048
|
+
curRequestController = new AbortController();
|
|
1049
|
+
const sig = inputSignal.aborted ? inputSignal : curRequestController.signal;
|
|
1050
|
+
try {
|
|
1051
|
+
const response = await fetch2(input, Object.assign(Object.assign({}, rest), { headers, signal: sig }));
|
|
1052
|
+
await onopen(response);
|
|
1053
|
+
await getBytes(response.body, getLines(getMessages((id) => {
|
|
1054
|
+
if (id) {
|
|
1055
|
+
headers[LastEventId] = id;
|
|
1056
|
+
} else {
|
|
1057
|
+
delete headers[LastEventId];
|
|
1058
|
+
}
|
|
1059
|
+
}, (retry) => {
|
|
1060
|
+
retryInterval = retry;
|
|
1061
|
+
}, onmessage)));
|
|
1062
|
+
onclose === null || onclose === void 0 ? void 0 : onclose();
|
|
1063
|
+
dispose();
|
|
1064
|
+
resolve();
|
|
1065
|
+
} catch (err) {
|
|
1066
|
+
if (sig.aborted) {
|
|
1067
|
+
dispose();
|
|
1068
|
+
reject(err);
|
|
1069
|
+
} else if (!curRequestController.signal.aborted) {
|
|
1070
|
+
try {
|
|
1071
|
+
const interval = (_a2 = onerror === null || onerror === void 0 ? void 0 : onerror(err)) !== null && _a2 !== void 0 ? _a2 : retryInterval;
|
|
1072
|
+
clearTimeout(retryTimer);
|
|
1073
|
+
retryTimer = setTimeout(create, interval);
|
|
1074
|
+
} catch (innerErr) {
|
|
1075
|
+
dispose();
|
|
1076
|
+
reject(innerErr);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
create();
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
function defaultOnOpen(response) {
|
|
1085
|
+
const contentType = response.headers.get("content-type");
|
|
1086
|
+
if (!(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith(EventStreamContentType))) {
|
|
1087
|
+
throw new Error(`Expected content-type to be ${EventStreamContentType}, Actual: ${contentType}`);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
896
1090
|
|
|
897
1091
|
// src/expired-shapes-cache.ts
|
|
898
1092
|
var ExpiredShapesCache = class {
|
|
@@ -1130,6 +1324,544 @@ var SnapshotTracker = class {
|
|
|
1130
1324
|
}
|
|
1131
1325
|
};
|
|
1132
1326
|
|
|
1327
|
+
// src/shape-stream-state.ts
|
|
1328
|
+
var ShapeStreamState = class {
|
|
1329
|
+
// --- Derived booleans ---
|
|
1330
|
+
get isUpToDate() {
|
|
1331
|
+
return false;
|
|
1332
|
+
}
|
|
1333
|
+
// --- Per-state field defaults ---
|
|
1334
|
+
get staleCacheBuster() {
|
|
1335
|
+
return void 0;
|
|
1336
|
+
}
|
|
1337
|
+
get staleCacheRetryCount() {
|
|
1338
|
+
return 0;
|
|
1339
|
+
}
|
|
1340
|
+
get sseFallbackToLongPolling() {
|
|
1341
|
+
return false;
|
|
1342
|
+
}
|
|
1343
|
+
get consecutiveShortSseConnections() {
|
|
1344
|
+
return 0;
|
|
1345
|
+
}
|
|
1346
|
+
get replayCursor() {
|
|
1347
|
+
return void 0;
|
|
1348
|
+
}
|
|
1349
|
+
// --- Default no-op methods ---
|
|
1350
|
+
canEnterReplayMode() {
|
|
1351
|
+
return false;
|
|
1352
|
+
}
|
|
1353
|
+
enterReplayMode(_cursor) {
|
|
1354
|
+
return this;
|
|
1355
|
+
}
|
|
1356
|
+
shouldUseSse(_opts) {
|
|
1357
|
+
return false;
|
|
1358
|
+
}
|
|
1359
|
+
handleSseConnectionClosed(_input) {
|
|
1360
|
+
return {
|
|
1361
|
+
state: this,
|
|
1362
|
+
fellBackToLongPolling: false,
|
|
1363
|
+
wasShortConnection: false
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
// --- URL param application ---
|
|
1367
|
+
/** Adds state-specific query parameters to the fetch URL. */
|
|
1368
|
+
applyUrlParams(_url, _context) {
|
|
1369
|
+
}
|
|
1370
|
+
// --- Default response/message handlers (Paused/Error never receive these) ---
|
|
1371
|
+
handleResponseMetadata(_input) {
|
|
1372
|
+
return { action: `ignored`, state: this };
|
|
1373
|
+
}
|
|
1374
|
+
handleMessageBatch(_input) {
|
|
1375
|
+
return { state: this, suppressBatch: false, becameUpToDate: false };
|
|
1376
|
+
}
|
|
1377
|
+
pause() {
|
|
1378
|
+
return new PausedState(this);
|
|
1379
|
+
}
|
|
1380
|
+
toErrorState(error) {
|
|
1381
|
+
return new ErrorState(this, error);
|
|
1382
|
+
}
|
|
1383
|
+
markMustRefetch(handle) {
|
|
1384
|
+
return new InitialState({
|
|
1385
|
+
handle,
|
|
1386
|
+
offset: `-1`,
|
|
1387
|
+
liveCacheBuster: ``,
|
|
1388
|
+
lastSyncedAt: this.lastSyncedAt,
|
|
1389
|
+
schema: void 0
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
var _shared;
|
|
1394
|
+
var ActiveState = class extends ShapeStreamState {
|
|
1395
|
+
constructor(shared) {
|
|
1396
|
+
super();
|
|
1397
|
+
__privateAdd(this, _shared);
|
|
1398
|
+
__privateSet(this, _shared, shared);
|
|
1399
|
+
}
|
|
1400
|
+
get handle() {
|
|
1401
|
+
return __privateGet(this, _shared).handle;
|
|
1402
|
+
}
|
|
1403
|
+
get offset() {
|
|
1404
|
+
return __privateGet(this, _shared).offset;
|
|
1405
|
+
}
|
|
1406
|
+
get schema() {
|
|
1407
|
+
return __privateGet(this, _shared).schema;
|
|
1408
|
+
}
|
|
1409
|
+
get liveCacheBuster() {
|
|
1410
|
+
return __privateGet(this, _shared).liveCacheBuster;
|
|
1411
|
+
}
|
|
1412
|
+
get lastSyncedAt() {
|
|
1413
|
+
return __privateGet(this, _shared).lastSyncedAt;
|
|
1414
|
+
}
|
|
1415
|
+
/** Expose shared fields to subclasses for spreading into new instances. */
|
|
1416
|
+
get currentFields() {
|
|
1417
|
+
return __privateGet(this, _shared);
|
|
1418
|
+
}
|
|
1419
|
+
// --- URL param application ---
|
|
1420
|
+
applyUrlParams(url, _context) {
|
|
1421
|
+
url.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _shared).offset);
|
|
1422
|
+
if (__privateGet(this, _shared).handle) {
|
|
1423
|
+
url.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shared).handle);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
// --- Helpers for subclass handleResponseMetadata implementations ---
|
|
1427
|
+
/** Extracts updated SharedStateFields from response headers. */
|
|
1428
|
+
parseResponseFields(input) {
|
|
1429
|
+
var _a, _b, _c;
|
|
1430
|
+
const responseHandle = input.responseHandle;
|
|
1431
|
+
const handle = responseHandle && responseHandle !== input.expiredHandle ? responseHandle : __privateGet(this, _shared).handle;
|
|
1432
|
+
const offset = (_a = input.responseOffset) != null ? _a : __privateGet(this, _shared).offset;
|
|
1433
|
+
const liveCacheBuster = (_b = input.responseCursor) != null ? _b : __privateGet(this, _shared).liveCacheBuster;
|
|
1434
|
+
const schema = (_c = __privateGet(this, _shared).schema) != null ? _c : input.responseSchema;
|
|
1435
|
+
const lastSyncedAt = input.status === 204 ? input.now : __privateGet(this, _shared).lastSyncedAt;
|
|
1436
|
+
return { handle, offset, schema, liveCacheBuster, lastSyncedAt };
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* Stale detection. Returns a transition if the response is stale,
|
|
1440
|
+
* or null if it is not stale and the caller should proceed normally.
|
|
1441
|
+
*/
|
|
1442
|
+
checkStaleResponse(input) {
|
|
1443
|
+
const responseHandle = input.responseHandle;
|
|
1444
|
+
const expiredHandle = input.expiredHandle;
|
|
1445
|
+
if (!responseHandle || responseHandle !== expiredHandle) {
|
|
1446
|
+
return null;
|
|
1447
|
+
}
|
|
1448
|
+
if (__privateGet(this, _shared).handle === void 0 || __privateGet(this, _shared).handle === expiredHandle) {
|
|
1449
|
+
const retryCount = this.staleCacheRetryCount + 1;
|
|
1450
|
+
return {
|
|
1451
|
+
action: `stale-retry`,
|
|
1452
|
+
state: new StaleRetryState(__spreadProps(__spreadValues({}, this.currentFields), {
|
|
1453
|
+
staleCacheBuster: input.createCacheBuster(),
|
|
1454
|
+
staleCacheRetryCount: retryCount
|
|
1455
|
+
})),
|
|
1456
|
+
exceededMaxRetries: retryCount > input.maxStaleCacheRetries
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
return { action: `ignored`, state: this };
|
|
1460
|
+
}
|
|
1461
|
+
// --- handleMessageBatch: template method with onUpToDate override point ---
|
|
1462
|
+
handleMessageBatch(input) {
|
|
1463
|
+
if (!input.hasMessages || !input.hasUpToDateMessage) {
|
|
1464
|
+
return { state: this, suppressBatch: false, becameUpToDate: false };
|
|
1465
|
+
}
|
|
1466
|
+
let offset = __privateGet(this, _shared).offset;
|
|
1467
|
+
if (input.isSse && input.upToDateOffset) {
|
|
1468
|
+
offset = input.upToDateOffset;
|
|
1469
|
+
}
|
|
1470
|
+
const shared = {
|
|
1471
|
+
handle: __privateGet(this, _shared).handle,
|
|
1472
|
+
offset,
|
|
1473
|
+
schema: __privateGet(this, _shared).schema,
|
|
1474
|
+
liveCacheBuster: __privateGet(this, _shared).liveCacheBuster,
|
|
1475
|
+
lastSyncedAt: input.now
|
|
1476
|
+
};
|
|
1477
|
+
return this.onUpToDate(shared, input);
|
|
1478
|
+
}
|
|
1479
|
+
/** Override point for up-to-date handling. Default → LiveState. */
|
|
1480
|
+
onUpToDate(shared, _input) {
|
|
1481
|
+
return {
|
|
1482
|
+
state: new LiveState(shared),
|
|
1483
|
+
suppressBatch: false,
|
|
1484
|
+
becameUpToDate: true
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
_shared = new WeakMap();
|
|
1489
|
+
var FetchingState = class extends ActiveState {
|
|
1490
|
+
handleResponseMetadata(input) {
|
|
1491
|
+
const staleResult = this.checkStaleResponse(input);
|
|
1492
|
+
if (staleResult) return staleResult;
|
|
1493
|
+
const shared = this.parseResponseFields(input);
|
|
1494
|
+
return { action: `accepted`, state: new SyncingState(shared) };
|
|
1495
|
+
}
|
|
1496
|
+
canEnterReplayMode() {
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
enterReplayMode(cursor) {
|
|
1500
|
+
return new ReplayingState(__spreadProps(__spreadValues({}, this.currentFields), {
|
|
1501
|
+
replayCursor: cursor
|
|
1502
|
+
}));
|
|
1503
|
+
}
|
|
1504
|
+
};
|
|
1505
|
+
var InitialState = class _InitialState extends FetchingState {
|
|
1506
|
+
constructor(shared) {
|
|
1507
|
+
super(shared);
|
|
1508
|
+
this.kind = `initial`;
|
|
1509
|
+
}
|
|
1510
|
+
withHandle(handle) {
|
|
1511
|
+
return new _InitialState(__spreadProps(__spreadValues({}, this.currentFields), { handle }));
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1514
|
+
var SyncingState = class _SyncingState extends FetchingState {
|
|
1515
|
+
constructor(shared) {
|
|
1516
|
+
super(shared);
|
|
1517
|
+
this.kind = `syncing`;
|
|
1518
|
+
}
|
|
1519
|
+
withHandle(handle) {
|
|
1520
|
+
return new _SyncingState(__spreadProps(__spreadValues({}, this.currentFields), { handle }));
|
|
1521
|
+
}
|
|
1522
|
+
};
|
|
1523
|
+
var _staleCacheBuster, _staleCacheRetryCount;
|
|
1524
|
+
var _StaleRetryState = class _StaleRetryState extends FetchingState {
|
|
1525
|
+
constructor(fields) {
|
|
1526
|
+
const _a = fields, { staleCacheBuster, staleCacheRetryCount } = _a, shared = __objRest(_a, ["staleCacheBuster", "staleCacheRetryCount"]);
|
|
1527
|
+
super(shared);
|
|
1528
|
+
this.kind = `stale-retry`;
|
|
1529
|
+
__privateAdd(this, _staleCacheBuster);
|
|
1530
|
+
__privateAdd(this, _staleCacheRetryCount);
|
|
1531
|
+
__privateSet(this, _staleCacheBuster, staleCacheBuster);
|
|
1532
|
+
__privateSet(this, _staleCacheRetryCount, staleCacheRetryCount);
|
|
1533
|
+
}
|
|
1534
|
+
get staleCacheBuster() {
|
|
1535
|
+
return __privateGet(this, _staleCacheBuster);
|
|
1536
|
+
}
|
|
1537
|
+
get staleCacheRetryCount() {
|
|
1538
|
+
return __privateGet(this, _staleCacheRetryCount);
|
|
1539
|
+
}
|
|
1540
|
+
// StaleRetryState must not enter replay mode — it would lose the retry count
|
|
1541
|
+
canEnterReplayMode() {
|
|
1542
|
+
return false;
|
|
1543
|
+
}
|
|
1544
|
+
withHandle(handle) {
|
|
1545
|
+
return new _StaleRetryState(__spreadProps(__spreadValues({}, this.currentFields), {
|
|
1546
|
+
handle,
|
|
1547
|
+
staleCacheBuster: __privateGet(this, _staleCacheBuster),
|
|
1548
|
+
staleCacheRetryCount: __privateGet(this, _staleCacheRetryCount)
|
|
1549
|
+
}));
|
|
1550
|
+
}
|
|
1551
|
+
applyUrlParams(url, context) {
|
|
1552
|
+
super.applyUrlParams(url, context);
|
|
1553
|
+
url.searchParams.set(CACHE_BUSTER_QUERY_PARAM, __privateGet(this, _staleCacheBuster));
|
|
1554
|
+
}
|
|
1555
|
+
};
|
|
1556
|
+
_staleCacheBuster = new WeakMap();
|
|
1557
|
+
_staleCacheRetryCount = new WeakMap();
|
|
1558
|
+
var StaleRetryState = _StaleRetryState;
|
|
1559
|
+
var _consecutiveShortSseConnections, _sseFallbackToLongPolling;
|
|
1560
|
+
var _LiveState = class _LiveState extends ActiveState {
|
|
1561
|
+
constructor(shared, sseState) {
|
|
1562
|
+
var _a, _b;
|
|
1563
|
+
super(shared);
|
|
1564
|
+
this.kind = `live`;
|
|
1565
|
+
__privateAdd(this, _consecutiveShortSseConnections);
|
|
1566
|
+
__privateAdd(this, _sseFallbackToLongPolling);
|
|
1567
|
+
__privateSet(this, _consecutiveShortSseConnections, (_a = sseState == null ? void 0 : sseState.consecutiveShortSseConnections) != null ? _a : 0);
|
|
1568
|
+
__privateSet(this, _sseFallbackToLongPolling, (_b = sseState == null ? void 0 : sseState.sseFallbackToLongPolling) != null ? _b : false);
|
|
1569
|
+
}
|
|
1570
|
+
get isUpToDate() {
|
|
1571
|
+
return true;
|
|
1572
|
+
}
|
|
1573
|
+
get consecutiveShortSseConnections() {
|
|
1574
|
+
return __privateGet(this, _consecutiveShortSseConnections);
|
|
1575
|
+
}
|
|
1576
|
+
get sseFallbackToLongPolling() {
|
|
1577
|
+
return __privateGet(this, _sseFallbackToLongPolling);
|
|
1578
|
+
}
|
|
1579
|
+
withHandle(handle) {
|
|
1580
|
+
return new _LiveState(__spreadProps(__spreadValues({}, this.currentFields), { handle }), this.sseState);
|
|
1581
|
+
}
|
|
1582
|
+
applyUrlParams(url, context) {
|
|
1583
|
+
super.applyUrlParams(url, context);
|
|
1584
|
+
if (!context.isSnapshotRequest) {
|
|
1585
|
+
url.searchParams.set(LIVE_CACHE_BUSTER_QUERY_PARAM, this.liveCacheBuster);
|
|
1586
|
+
if (context.canLongPoll) {
|
|
1587
|
+
url.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
get sseState() {
|
|
1592
|
+
return {
|
|
1593
|
+
consecutiveShortSseConnections: __privateGet(this, _consecutiveShortSseConnections),
|
|
1594
|
+
sseFallbackToLongPolling: __privateGet(this, _sseFallbackToLongPolling)
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
handleResponseMetadata(input) {
|
|
1598
|
+
const staleResult = this.checkStaleResponse(input);
|
|
1599
|
+
if (staleResult) return staleResult;
|
|
1600
|
+
const shared = this.parseResponseFields(input);
|
|
1601
|
+
return {
|
|
1602
|
+
action: `accepted`,
|
|
1603
|
+
state: new _LiveState(shared, this.sseState)
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
onUpToDate(shared, _input) {
|
|
1607
|
+
return {
|
|
1608
|
+
state: new _LiveState(shared, this.sseState),
|
|
1609
|
+
suppressBatch: false,
|
|
1610
|
+
becameUpToDate: true
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
shouldUseSse(opts) {
|
|
1614
|
+
return opts.liveSseEnabled && !opts.isRefreshing && !opts.resumingFromPause && !__privateGet(this, _sseFallbackToLongPolling);
|
|
1615
|
+
}
|
|
1616
|
+
handleSseConnectionClosed(input) {
|
|
1617
|
+
let nextConsecutiveShort = __privateGet(this, _consecutiveShortSseConnections);
|
|
1618
|
+
let nextFallback = __privateGet(this, _sseFallbackToLongPolling);
|
|
1619
|
+
let fellBackToLongPolling = false;
|
|
1620
|
+
let wasShortConnection = false;
|
|
1621
|
+
if (input.connectionDuration < input.minConnectionDuration && !input.wasAborted) {
|
|
1622
|
+
wasShortConnection = true;
|
|
1623
|
+
nextConsecutiveShort = nextConsecutiveShort + 1;
|
|
1624
|
+
if (nextConsecutiveShort >= input.maxShortConnections) {
|
|
1625
|
+
nextFallback = true;
|
|
1626
|
+
fellBackToLongPolling = true;
|
|
1627
|
+
}
|
|
1628
|
+
} else if (input.connectionDuration >= input.minConnectionDuration) {
|
|
1629
|
+
nextConsecutiveShort = 0;
|
|
1630
|
+
}
|
|
1631
|
+
return {
|
|
1632
|
+
state: new _LiveState(this.currentFields, {
|
|
1633
|
+
consecutiveShortSseConnections: nextConsecutiveShort,
|
|
1634
|
+
sseFallbackToLongPolling: nextFallback
|
|
1635
|
+
}),
|
|
1636
|
+
fellBackToLongPolling,
|
|
1637
|
+
wasShortConnection
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
};
|
|
1641
|
+
_consecutiveShortSseConnections = new WeakMap();
|
|
1642
|
+
_sseFallbackToLongPolling = new WeakMap();
|
|
1643
|
+
var LiveState = _LiveState;
|
|
1644
|
+
var _replayCursor;
|
|
1645
|
+
var _ReplayingState = class _ReplayingState extends ActiveState {
|
|
1646
|
+
constructor(fields) {
|
|
1647
|
+
const _a = fields, { replayCursor } = _a, shared = __objRest(_a, ["replayCursor"]);
|
|
1648
|
+
super(shared);
|
|
1649
|
+
this.kind = `replaying`;
|
|
1650
|
+
__privateAdd(this, _replayCursor);
|
|
1651
|
+
__privateSet(this, _replayCursor, replayCursor);
|
|
1652
|
+
}
|
|
1653
|
+
get replayCursor() {
|
|
1654
|
+
return __privateGet(this, _replayCursor);
|
|
1655
|
+
}
|
|
1656
|
+
withHandle(handle) {
|
|
1657
|
+
return new _ReplayingState(__spreadProps(__spreadValues({}, this.currentFields), {
|
|
1658
|
+
handle,
|
|
1659
|
+
replayCursor: __privateGet(this, _replayCursor)
|
|
1660
|
+
}));
|
|
1661
|
+
}
|
|
1662
|
+
handleResponseMetadata(input) {
|
|
1663
|
+
const staleResult = this.checkStaleResponse(input);
|
|
1664
|
+
if (staleResult) return staleResult;
|
|
1665
|
+
const shared = this.parseResponseFields(input);
|
|
1666
|
+
return {
|
|
1667
|
+
action: `accepted`,
|
|
1668
|
+
state: new _ReplayingState(__spreadProps(__spreadValues({}, shared), {
|
|
1669
|
+
replayCursor: __privateGet(this, _replayCursor)
|
|
1670
|
+
}))
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
onUpToDate(shared, input) {
|
|
1674
|
+
const suppressBatch = !input.isSse && __privateGet(this, _replayCursor) === input.currentCursor;
|
|
1675
|
+
return {
|
|
1676
|
+
state: new LiveState(shared),
|
|
1677
|
+
suppressBatch,
|
|
1678
|
+
becameUpToDate: true
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
_replayCursor = new WeakMap();
|
|
1683
|
+
var ReplayingState = _ReplayingState;
|
|
1684
|
+
var PausedState = class _PausedState extends ShapeStreamState {
|
|
1685
|
+
constructor(previousState) {
|
|
1686
|
+
super();
|
|
1687
|
+
this.kind = `paused`;
|
|
1688
|
+
this.previousState = previousState;
|
|
1689
|
+
}
|
|
1690
|
+
get handle() {
|
|
1691
|
+
return this.previousState.handle;
|
|
1692
|
+
}
|
|
1693
|
+
get offset() {
|
|
1694
|
+
return this.previousState.offset;
|
|
1695
|
+
}
|
|
1696
|
+
get schema() {
|
|
1697
|
+
return this.previousState.schema;
|
|
1698
|
+
}
|
|
1699
|
+
get liveCacheBuster() {
|
|
1700
|
+
return this.previousState.liveCacheBuster;
|
|
1701
|
+
}
|
|
1702
|
+
get lastSyncedAt() {
|
|
1703
|
+
return this.previousState.lastSyncedAt;
|
|
1704
|
+
}
|
|
1705
|
+
get isUpToDate() {
|
|
1706
|
+
return this.previousState.isUpToDate;
|
|
1707
|
+
}
|
|
1708
|
+
get staleCacheBuster() {
|
|
1709
|
+
return this.previousState.staleCacheBuster;
|
|
1710
|
+
}
|
|
1711
|
+
get staleCacheRetryCount() {
|
|
1712
|
+
return this.previousState.staleCacheRetryCount;
|
|
1713
|
+
}
|
|
1714
|
+
get sseFallbackToLongPolling() {
|
|
1715
|
+
return this.previousState.sseFallbackToLongPolling;
|
|
1716
|
+
}
|
|
1717
|
+
get consecutiveShortSseConnections() {
|
|
1718
|
+
return this.previousState.consecutiveShortSseConnections;
|
|
1719
|
+
}
|
|
1720
|
+
get replayCursor() {
|
|
1721
|
+
return this.previousState.replayCursor;
|
|
1722
|
+
}
|
|
1723
|
+
withHandle(handle) {
|
|
1724
|
+
return new _PausedState(this.previousState.withHandle(handle));
|
|
1725
|
+
}
|
|
1726
|
+
applyUrlParams(url, context) {
|
|
1727
|
+
this.previousState.applyUrlParams(url, context);
|
|
1728
|
+
}
|
|
1729
|
+
pause() {
|
|
1730
|
+
return this;
|
|
1731
|
+
}
|
|
1732
|
+
resume() {
|
|
1733
|
+
return this.previousState;
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
var ErrorState = class _ErrorState extends ShapeStreamState {
|
|
1737
|
+
constructor(previousState, error) {
|
|
1738
|
+
super();
|
|
1739
|
+
this.kind = `error`;
|
|
1740
|
+
this.previousState = previousState;
|
|
1741
|
+
this.error = error;
|
|
1742
|
+
}
|
|
1743
|
+
get handle() {
|
|
1744
|
+
return this.previousState.handle;
|
|
1745
|
+
}
|
|
1746
|
+
get offset() {
|
|
1747
|
+
return this.previousState.offset;
|
|
1748
|
+
}
|
|
1749
|
+
get schema() {
|
|
1750
|
+
return this.previousState.schema;
|
|
1751
|
+
}
|
|
1752
|
+
get liveCacheBuster() {
|
|
1753
|
+
return this.previousState.liveCacheBuster;
|
|
1754
|
+
}
|
|
1755
|
+
get lastSyncedAt() {
|
|
1756
|
+
return this.previousState.lastSyncedAt;
|
|
1757
|
+
}
|
|
1758
|
+
get isUpToDate() {
|
|
1759
|
+
return this.previousState.isUpToDate;
|
|
1760
|
+
}
|
|
1761
|
+
withHandle(handle) {
|
|
1762
|
+
return new _ErrorState(this.previousState.withHandle(handle), this.error);
|
|
1763
|
+
}
|
|
1764
|
+
applyUrlParams(url, context) {
|
|
1765
|
+
this.previousState.applyUrlParams(url, context);
|
|
1766
|
+
}
|
|
1767
|
+
retry() {
|
|
1768
|
+
return this.previousState;
|
|
1769
|
+
}
|
|
1770
|
+
reset(handle) {
|
|
1771
|
+
return this.previousState.markMustRefetch(handle);
|
|
1772
|
+
}
|
|
1773
|
+
};
|
|
1774
|
+
function createInitialState(opts) {
|
|
1775
|
+
return new InitialState({
|
|
1776
|
+
handle: opts.handle,
|
|
1777
|
+
offset: opts.offset,
|
|
1778
|
+
liveCacheBuster: ``,
|
|
1779
|
+
lastSyncedAt: void 0,
|
|
1780
|
+
schema: void 0
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
// src/pause-lock.ts
|
|
1785
|
+
var _holders, _onAcquired, _onReleased;
|
|
1786
|
+
var PauseLock = class {
|
|
1787
|
+
constructor(callbacks) {
|
|
1788
|
+
__privateAdd(this, _holders, /* @__PURE__ */ new Set());
|
|
1789
|
+
__privateAdd(this, _onAcquired);
|
|
1790
|
+
__privateAdd(this, _onReleased);
|
|
1791
|
+
__privateSet(this, _onAcquired, callbacks.onAcquired);
|
|
1792
|
+
__privateSet(this, _onReleased, callbacks.onReleased);
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* Acquire the lock for a given reason. Idempotent — acquiring the same
|
|
1796
|
+
* reason twice is a no-op (but logs a warning since it likely indicates
|
|
1797
|
+
* a caller bug).
|
|
1798
|
+
*
|
|
1799
|
+
* Fires `onAcquired` when the first reason is acquired (transition from
|
|
1800
|
+
* unlocked to locked).
|
|
1801
|
+
*/
|
|
1802
|
+
acquire(reason) {
|
|
1803
|
+
if (__privateGet(this, _holders).has(reason)) {
|
|
1804
|
+
console.warn(
|
|
1805
|
+
`[Electric] PauseLock: "${reason}" already held \u2014 ignoring duplicate acquire`
|
|
1806
|
+
);
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
const wasUnlocked = __privateGet(this, _holders).size === 0;
|
|
1810
|
+
__privateGet(this, _holders).add(reason);
|
|
1811
|
+
if (wasUnlocked) {
|
|
1812
|
+
__privateGet(this, _onAcquired).call(this);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
/**
|
|
1816
|
+
* Release the lock for a given reason. Releasing a reason that isn't
|
|
1817
|
+
* held logs a warning (likely indicates an acquire/release mismatch).
|
|
1818
|
+
*
|
|
1819
|
+
* Fires `onReleased` when the last reason is released (transition from
|
|
1820
|
+
* locked to unlocked).
|
|
1821
|
+
*/
|
|
1822
|
+
release(reason) {
|
|
1823
|
+
if (!__privateGet(this, _holders).delete(reason)) {
|
|
1824
|
+
console.warn(
|
|
1825
|
+
`[Electric] PauseLock: "${reason}" not held \u2014 ignoring release (possible acquire/release mismatch)`
|
|
1826
|
+
);
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
if (__privateGet(this, _holders).size === 0) {
|
|
1830
|
+
__privateGet(this, _onReleased).call(this);
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Whether the lock is currently held by any reason.
|
|
1835
|
+
*/
|
|
1836
|
+
get isPaused() {
|
|
1837
|
+
return __privateGet(this, _holders).size > 0;
|
|
1838
|
+
}
|
|
1839
|
+
/**
|
|
1840
|
+
* Check if a specific reason is holding the lock.
|
|
1841
|
+
*/
|
|
1842
|
+
isHeldBy(reason) {
|
|
1843
|
+
return __privateGet(this, _holders).has(reason);
|
|
1844
|
+
}
|
|
1845
|
+
/**
|
|
1846
|
+
* Release all reasons matching a prefix. Does NOT fire `onReleased` —
|
|
1847
|
+
* this is for cleanup/reset paths where the stream state is being
|
|
1848
|
+
* managed separately.
|
|
1849
|
+
*
|
|
1850
|
+
* This preserves reasons with different prefixes (e.g., 'visibility'
|
|
1851
|
+
* is preserved when clearing 'snapshot-*' reasons).
|
|
1852
|
+
*/
|
|
1853
|
+
releaseAllMatching(prefix) {
|
|
1854
|
+
for (const reason of __privateGet(this, _holders)) {
|
|
1855
|
+
if (reason.startsWith(prefix)) {
|
|
1856
|
+
__privateGet(this, _holders).delete(reason);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
};
|
|
1861
|
+
_holders = new WeakMap();
|
|
1862
|
+
_onAcquired = new WeakMap();
|
|
1863
|
+
_onReleased = new WeakMap();
|
|
1864
|
+
|
|
1133
1865
|
// src/client.ts
|
|
1134
1866
|
var RESERVED_PARAMS = /* @__PURE__ */ new Set([
|
|
1135
1867
|
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
@@ -1178,7 +1910,7 @@ function canonicalShapeKey(url) {
|
|
|
1178
1910
|
cleanUrl.searchParams.sort();
|
|
1179
1911
|
return cleanUrl.toString();
|
|
1180
1912
|
}
|
|
1181
|
-
var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started,
|
|
1913
|
+
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;
|
|
1182
1914
|
var ShapeStream = class {
|
|
1183
1915
|
constructor(options) {
|
|
1184
1916
|
__privateAdd(this, _ShapeStream_instances);
|
|
@@ -1188,58 +1920,57 @@ var ShapeStream = class {
|
|
|
1188
1920
|
__privateAdd(this, _messageParser);
|
|
1189
1921
|
__privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
|
|
1190
1922
|
__privateAdd(this, _started, false);
|
|
1191
|
-
__privateAdd(this,
|
|
1192
|
-
__privateAdd(this, _lastOffset);
|
|
1193
|
-
__privateAdd(this, _liveCacheBuster);
|
|
1194
|
-
// Seconds since our Electric Epoch 😎
|
|
1195
|
-
__privateAdd(this, _lastSyncedAt);
|
|
1196
|
-
// unix time
|
|
1197
|
-
__privateAdd(this, _isUpToDate, false);
|
|
1198
|
-
__privateAdd(this, _isMidStream, true);
|
|
1923
|
+
__privateAdd(this, _syncState);
|
|
1199
1924
|
__privateAdd(this, _connected, false);
|
|
1200
|
-
__privateAdd(this, _shapeHandle);
|
|
1201
1925
|
__privateAdd(this, _mode);
|
|
1202
|
-
__privateAdd(this, _schema);
|
|
1203
1926
|
__privateAdd(this, _onError);
|
|
1204
1927
|
__privateAdd(this, _requestAbortController);
|
|
1205
|
-
__privateAdd(this,
|
|
1928
|
+
__privateAdd(this, _refreshCount, 0);
|
|
1929
|
+
__privateAdd(this, _snapshotCounter, 0);
|
|
1206
1930
|
__privateAdd(this, _tickPromise);
|
|
1207
1931
|
__privateAdd(this, _tickPromiseResolver);
|
|
1208
1932
|
__privateAdd(this, _tickPromiseRejecter);
|
|
1209
1933
|
__privateAdd(this, _messageChain, Promise.resolve([]));
|
|
1210
1934
|
// promise chain for incoming messages
|
|
1211
1935
|
__privateAdd(this, _snapshotTracker, new SnapshotTracker());
|
|
1212
|
-
__privateAdd(this,
|
|
1213
|
-
// counter for concurrent snapshot requests
|
|
1214
|
-
__privateAdd(this, _midStreamPromise);
|
|
1215
|
-
__privateAdd(this, _midStreamPromiseResolver);
|
|
1216
|
-
__privateAdd(this, _lastSeenCursor);
|
|
1217
|
-
// Last seen cursor from previous session (used to detect cached responses)
|
|
1936
|
+
__privateAdd(this, _pauseLock);
|
|
1218
1937
|
__privateAdd(this, _currentFetchUrl);
|
|
1219
1938
|
// Current fetch URL for computing shape key
|
|
1220
1939
|
__privateAdd(this, _lastSseConnectionStartTime);
|
|
1221
1940
|
__privateAdd(this, _minSseConnectionDuration, 1e3);
|
|
1222
1941
|
// Minimum expected SSE connection duration (1 second)
|
|
1223
|
-
__privateAdd(this, _consecutiveShortSseConnections, 0);
|
|
1224
1942
|
__privateAdd(this, _maxShortSseConnections, 3);
|
|
1225
1943
|
// Fall back to long polling after this many short connections
|
|
1226
|
-
__privateAdd(this, _sseFallbackToLongPolling, false);
|
|
1227
1944
|
__privateAdd(this, _sseBackoffBaseDelay, 100);
|
|
1228
1945
|
// Base delay for exponential backoff (ms)
|
|
1229
1946
|
__privateAdd(this, _sseBackoffMaxDelay, 5e3);
|
|
1230
1947
|
// Maximum delay cap (ms)
|
|
1231
1948
|
__privateAdd(this, _unsubscribeFromVisibilityChanges);
|
|
1232
1949
|
__privateAdd(this, _unsubscribeFromWakeDetection);
|
|
1233
|
-
__privateAdd(this, _staleCacheBuster);
|
|
1234
|
-
// Cache buster set when stale CDN response detected, used on retry requests to bypass cache
|
|
1235
|
-
__privateAdd(this, _staleCacheRetryCount, 0);
|
|
1236
1950
|
__privateAdd(this, _maxStaleCacheRetries, 3);
|
|
1237
1951
|
var _a, _b, _c, _d;
|
|
1238
1952
|
this.options = __spreadValues({ subscribe: true }, options);
|
|
1239
1953
|
validateOptions(this.options);
|
|
1240
|
-
__privateSet(this,
|
|
1241
|
-
|
|
1242
|
-
|
|
1954
|
+
__privateSet(this, _syncState, createInitialState({
|
|
1955
|
+
offset: (_a = this.options.offset) != null ? _a : `-1`,
|
|
1956
|
+
handle: this.options.handle
|
|
1957
|
+
}));
|
|
1958
|
+
__privateSet(this, _pauseLock, new PauseLock({
|
|
1959
|
+
onAcquired: () => {
|
|
1960
|
+
var _a2;
|
|
1961
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).pause());
|
|
1962
|
+
if (__privateGet(this, _started)) {
|
|
1963
|
+
(_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(PAUSE_STREAM);
|
|
1964
|
+
}
|
|
1965
|
+
},
|
|
1966
|
+
onReleased: () => {
|
|
1967
|
+
var _a2;
|
|
1968
|
+
if (!__privateGet(this, _started)) return;
|
|
1969
|
+
if ((_a2 = this.options.signal) == null ? void 0 : _a2.aborted) return;
|
|
1970
|
+
__privateMethod(this, _ShapeStream_instances, start_fn).call(this).catch(() => {
|
|
1971
|
+
});
|
|
1972
|
+
}
|
|
1973
|
+
}));
|
|
1243
1974
|
let transformer;
|
|
1244
1975
|
if (options.columnMapper) {
|
|
1245
1976
|
const applyColumnMapper = (row) => {
|
|
@@ -1277,16 +2008,16 @@ var ShapeStream = class {
|
|
|
1277
2008
|
__privateMethod(this, _ShapeStream_instances, subscribeToWakeDetection_fn).call(this);
|
|
1278
2009
|
}
|
|
1279
2010
|
get shapeHandle() {
|
|
1280
|
-
return __privateGet(this,
|
|
2011
|
+
return __privateGet(this, _syncState).handle;
|
|
1281
2012
|
}
|
|
1282
2013
|
get error() {
|
|
1283
2014
|
return __privateGet(this, _error);
|
|
1284
2015
|
}
|
|
1285
2016
|
get isUpToDate() {
|
|
1286
|
-
return __privateGet(this,
|
|
2017
|
+
return __privateGet(this, _syncState).isUpToDate;
|
|
1287
2018
|
}
|
|
1288
2019
|
get lastOffset() {
|
|
1289
|
-
return __privateGet(this,
|
|
2020
|
+
return __privateGet(this, _syncState).offset;
|
|
1290
2021
|
}
|
|
1291
2022
|
get mode() {
|
|
1292
2023
|
return __privateGet(this, _mode);
|
|
@@ -1306,28 +2037,28 @@ var ShapeStream = class {
|
|
|
1306
2037
|
(_a = __privateGet(this, _unsubscribeFromVisibilityChanges)) == null ? void 0 : _a.call(this);
|
|
1307
2038
|
(_b = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _b.call(this);
|
|
1308
2039
|
}
|
|
1309
|
-
/** Unix time at which we last synced. Undefined
|
|
2040
|
+
/** Unix time at which we last synced. Undefined until first successful up-to-date. */
|
|
1310
2041
|
lastSyncedAt() {
|
|
1311
|
-
return __privateGet(this,
|
|
2042
|
+
return __privateGet(this, _syncState).lastSyncedAt;
|
|
1312
2043
|
}
|
|
1313
2044
|
/** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */
|
|
1314
2045
|
lastSynced() {
|
|
1315
|
-
if (__privateGet(this,
|
|
1316
|
-
return Date.now() - __privateGet(this,
|
|
2046
|
+
if (__privateGet(this, _syncState).lastSyncedAt === void 0) return Infinity;
|
|
2047
|
+
return Date.now() - __privateGet(this, _syncState).lastSyncedAt;
|
|
1317
2048
|
}
|
|
1318
2049
|
/** Indicates if we are connected to the Electric sync service. */
|
|
1319
2050
|
isConnected() {
|
|
1320
2051
|
return __privateGet(this, _connected);
|
|
1321
2052
|
}
|
|
1322
|
-
/** True during initial fetch. False
|
|
2053
|
+
/** True during initial fetch. False afterwards. */
|
|
1323
2054
|
isLoading() {
|
|
1324
|
-
return !__privateGet(this,
|
|
2055
|
+
return !__privateGet(this, _syncState).isUpToDate;
|
|
1325
2056
|
}
|
|
1326
2057
|
hasStarted() {
|
|
1327
2058
|
return __privateGet(this, _started);
|
|
1328
2059
|
}
|
|
1329
2060
|
isPaused() {
|
|
1330
|
-
return __privateGet(this,
|
|
2061
|
+
return __privateGet(this, _pauseLock).isPaused;
|
|
1331
2062
|
}
|
|
1332
2063
|
/**
|
|
1333
2064
|
* Refreshes the shape stream.
|
|
@@ -1337,12 +2068,15 @@ var ShapeStream = class {
|
|
|
1337
2068
|
*/
|
|
1338
2069
|
async forceDisconnectAndRefresh() {
|
|
1339
2070
|
var _a, _b;
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
(
|
|
2071
|
+
__privateWrapper(this, _refreshCount)._++;
|
|
2072
|
+
try {
|
|
2073
|
+
if (__privateGet(this, _syncState).isUpToDate && !((_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.signal.aborted)) {
|
|
2074
|
+
(_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(FORCE_DISCONNECT_AND_REFRESH);
|
|
2075
|
+
}
|
|
2076
|
+
await __privateMethod(this, _ShapeStream_instances, nextTick_fn).call(this);
|
|
2077
|
+
} finally {
|
|
2078
|
+
__privateWrapper(this, _refreshCount)._--;
|
|
1343
2079
|
}
|
|
1344
|
-
await __privateMethod(this, _ShapeStream_instances, nextTick_fn).call(this);
|
|
1345
|
-
__privateSet(this, _isRefreshing, false);
|
|
1346
2080
|
}
|
|
1347
2081
|
/**
|
|
1348
2082
|
* Request a snapshot for subset of data and inject it into the subscribed data stream.
|
|
@@ -1364,13 +2098,18 @@ var ShapeStream = class {
|
|
|
1364
2098
|
`Snapshot requests are not supported in ${__privateGet(this, _mode)} mode, as the consumer is guaranteed to observe all data`
|
|
1365
2099
|
);
|
|
1366
2100
|
}
|
|
1367
|
-
if (!__privateGet(this, _started))
|
|
1368
|
-
|
|
1369
|
-
|
|
2101
|
+
if (!__privateGet(this, _started)) {
|
|
2102
|
+
__privateMethod(this, _ShapeStream_instances, start_fn).call(this).catch(() => {
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
const snapshotReason = `snapshot-${++__privateWrapper(this, _snapshotCounter)._}`;
|
|
2106
|
+
__privateGet(this, _pauseLock).acquire(snapshotReason);
|
|
2107
|
+
const snapshotWarnTimer = setTimeout(() => {
|
|
2108
|
+
console.warn(
|
|
2109
|
+
`[Electric] Snapshot "${snapshotReason}" has held the pause lock for 30s \u2014 possible hung request or leaked lock. Current holders: ${[.../* @__PURE__ */ new Set([snapshotReason])].join(`, `)}`
|
|
2110
|
+
);
|
|
2111
|
+
}, 3e4);
|
|
1370
2112
|
try {
|
|
1371
|
-
if (__privateGet(this, _activeSnapshotRequests) === 1) {
|
|
1372
|
-
__privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
|
|
1373
|
-
}
|
|
1374
2113
|
const { metadata, data } = await this.fetchSnapshot(opts);
|
|
1375
2114
|
const dataWithEndBoundary = data.concat([
|
|
1376
2115
|
{ headers: __spreadValues({ control: `snapshot-end` }, metadata) },
|
|
@@ -1386,10 +2125,8 @@ var ShapeStream = class {
|
|
|
1386
2125
|
data
|
|
1387
2126
|
};
|
|
1388
2127
|
} finally {
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
__privateMethod(this, _ShapeStream_instances, resume_fn).call(this);
|
|
1392
|
-
}
|
|
2128
|
+
clearTimeout(snapshotWarnTimer);
|
|
2129
|
+
__privateGet(this, _pauseLock).release(snapshotReason);
|
|
1393
2130
|
}
|
|
1394
2131
|
}
|
|
1395
2132
|
/**
|
|
@@ -1424,7 +2161,7 @@ var ShapeStream = class {
|
|
|
1424
2161
|
fetchUrl = result.fetchUrl;
|
|
1425
2162
|
fetchOptions = { headers: result.requestHeaders };
|
|
1426
2163
|
}
|
|
1427
|
-
const usedHandle = __privateGet(this,
|
|
2164
|
+
const usedHandle = __privateGet(this, _syncState).handle;
|
|
1428
2165
|
let response;
|
|
1429
2166
|
try {
|
|
1430
2167
|
response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), fetchOptions);
|
|
@@ -1434,7 +2171,8 @@ var ShapeStream = class {
|
|
|
1434
2171
|
const shapeKey = canonicalShapeKey(fetchUrl);
|
|
1435
2172
|
expiredShapesCache.markExpired(shapeKey, usedHandle);
|
|
1436
2173
|
}
|
|
1437
|
-
|
|
2174
|
+
const nextHandle = e.headers[SHAPE_HANDLE_HEADER] || `${usedHandle != null ? usedHandle : `handle`}-next`;
|
|
2175
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).withHandle(nextHandle));
|
|
1438
2176
|
return this.fetchSnapshot(opts);
|
|
1439
2177
|
}
|
|
1440
2178
|
throw e;
|
|
@@ -1442,7 +2180,7 @@ var ShapeStream = class {
|
|
|
1442
2180
|
if (!response.ok) {
|
|
1443
2181
|
throw await FetchError.fromResponse(response, fetchUrl.toString());
|
|
1444
2182
|
}
|
|
1445
|
-
const schema = (_c = __privateGet(this,
|
|
2183
|
+
const schema = (_c = __privateGet(this, _syncState).schema) != null ? _c : getSchemaFromHeaders(response.headers, {
|
|
1446
2184
|
required: true,
|
|
1447
2185
|
url: fetchUrl.toString()
|
|
1448
2186
|
});
|
|
@@ -1460,52 +2198,42 @@ _sseFetchClient = new WeakMap();
|
|
|
1460
2198
|
_messageParser = new WeakMap();
|
|
1461
2199
|
_subscribers = new WeakMap();
|
|
1462
2200
|
_started = new WeakMap();
|
|
1463
|
-
|
|
1464
|
-
_lastOffset = new WeakMap();
|
|
1465
|
-
_liveCacheBuster = new WeakMap();
|
|
1466
|
-
_lastSyncedAt = new WeakMap();
|
|
1467
|
-
_isUpToDate = new WeakMap();
|
|
1468
|
-
_isMidStream = new WeakMap();
|
|
2201
|
+
_syncState = new WeakMap();
|
|
1469
2202
|
_connected = new WeakMap();
|
|
1470
|
-
_shapeHandle = new WeakMap();
|
|
1471
2203
|
_mode = new WeakMap();
|
|
1472
|
-
_schema = new WeakMap();
|
|
1473
2204
|
_onError = new WeakMap();
|
|
1474
2205
|
_requestAbortController = new WeakMap();
|
|
1475
|
-
|
|
2206
|
+
_refreshCount = new WeakMap();
|
|
2207
|
+
_snapshotCounter = new WeakMap();
|
|
2208
|
+
_ShapeStream_instances = new WeakSet();
|
|
2209
|
+
isRefreshing_get = function() {
|
|
2210
|
+
return __privateGet(this, _refreshCount) > 0;
|
|
2211
|
+
};
|
|
1476
2212
|
_tickPromise = new WeakMap();
|
|
1477
2213
|
_tickPromiseResolver = new WeakMap();
|
|
1478
2214
|
_tickPromiseRejecter = new WeakMap();
|
|
1479
2215
|
_messageChain = new WeakMap();
|
|
1480
2216
|
_snapshotTracker = new WeakMap();
|
|
1481
|
-
|
|
1482
|
-
_midStreamPromise = new WeakMap();
|
|
1483
|
-
_midStreamPromiseResolver = new WeakMap();
|
|
1484
|
-
_lastSeenCursor = new WeakMap();
|
|
2217
|
+
_pauseLock = new WeakMap();
|
|
1485
2218
|
_currentFetchUrl = new WeakMap();
|
|
1486
2219
|
_lastSseConnectionStartTime = new WeakMap();
|
|
1487
2220
|
_minSseConnectionDuration = new WeakMap();
|
|
1488
|
-
_consecutiveShortSseConnections = new WeakMap();
|
|
1489
2221
|
_maxShortSseConnections = new WeakMap();
|
|
1490
|
-
_sseFallbackToLongPolling = new WeakMap();
|
|
1491
2222
|
_sseBackoffBaseDelay = new WeakMap();
|
|
1492
2223
|
_sseBackoffMaxDelay = new WeakMap();
|
|
1493
2224
|
_unsubscribeFromVisibilityChanges = new WeakMap();
|
|
1494
2225
|
_unsubscribeFromWakeDetection = new WeakMap();
|
|
1495
|
-
_staleCacheBuster = new WeakMap();
|
|
1496
|
-
_staleCacheRetryCount = new WeakMap();
|
|
1497
2226
|
_maxStaleCacheRetries = new WeakMap();
|
|
1498
|
-
_ShapeStream_instances = new WeakSet();
|
|
1499
|
-
replayMode_get = function() {
|
|
1500
|
-
return __privateGet(this, _lastSeenCursor) !== void 0;
|
|
1501
|
-
};
|
|
1502
2227
|
start_fn = async function() {
|
|
1503
|
-
var _a, _b
|
|
2228
|
+
var _a, _b;
|
|
1504
2229
|
__privateSet(this, _started, true);
|
|
1505
2230
|
try {
|
|
1506
2231
|
await __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
1507
2232
|
} catch (err) {
|
|
1508
2233
|
__privateSet(this, _error, err);
|
|
2234
|
+
if (err instanceof Error) {
|
|
2235
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).toErrorState(err));
|
|
2236
|
+
}
|
|
1509
2237
|
if (__privateGet(this, _onError)) {
|
|
1510
2238
|
const retryOpts = await __privateGet(this, _onError).call(this, err);
|
|
1511
2239
|
const isRetryable = !(err instanceof MissingHeadersError);
|
|
@@ -1517,6 +2245,9 @@ start_fn = async function() {
|
|
|
1517
2245
|
this.options.headers = __spreadValues(__spreadValues({}, (_b = this.options.headers) != null ? _b : {}), retryOpts.headers);
|
|
1518
2246
|
}
|
|
1519
2247
|
__privateSet(this, _error, null);
|
|
2248
|
+
if (__privateGet(this, _syncState) instanceof ErrorState) {
|
|
2249
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).retry());
|
|
2250
|
+
}
|
|
1520
2251
|
__privateSet(this, _started, false);
|
|
1521
2252
|
await __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
1522
2253
|
return;
|
|
@@ -1524,38 +2255,45 @@ start_fn = async function() {
|
|
|
1524
2255
|
if (err instanceof Error) {
|
|
1525
2256
|
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
|
|
1526
2257
|
}
|
|
1527
|
-
|
|
1528
|
-
(_c = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _c.call(this);
|
|
1529
|
-
(_d = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _d.call(this);
|
|
2258
|
+
__privateMethod(this, _ShapeStream_instances, teardown_fn).call(this);
|
|
1530
2259
|
return;
|
|
1531
2260
|
}
|
|
1532
2261
|
if (err instanceof Error) {
|
|
1533
2262
|
__privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
|
|
1534
2263
|
}
|
|
1535
|
-
|
|
1536
|
-
(_e = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _e.call(this);
|
|
1537
|
-
(_f = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _f.call(this);
|
|
2264
|
+
__privateMethod(this, _ShapeStream_instances, teardown_fn).call(this);
|
|
1538
2265
|
throw err;
|
|
1539
2266
|
}
|
|
2267
|
+
__privateMethod(this, _ShapeStream_instances, teardown_fn).call(this);
|
|
2268
|
+
};
|
|
2269
|
+
teardown_fn = function() {
|
|
2270
|
+
var _a, _b;
|
|
1540
2271
|
__privateSet(this, _connected, false);
|
|
1541
|
-
(
|
|
1542
|
-
(
|
|
2272
|
+
(_a = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _a.call(this);
|
|
2273
|
+
(_b = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _b.call(this);
|
|
1543
2274
|
};
|
|
1544
2275
|
requestShape_fn = async function() {
|
|
1545
2276
|
var _a, _b;
|
|
1546
|
-
if (__privateGet(this,
|
|
1547
|
-
|
|
2277
|
+
if (__privateGet(this, _pauseLock).isPaused) return;
|
|
2278
|
+
if (!this.options.subscribe && (((_a = this.options.signal) == null ? void 0 : _a.aborted) || __privateGet(this, _syncState).isUpToDate)) {
|
|
1548
2279
|
return;
|
|
1549
2280
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
2281
|
+
let resumingFromPause = false;
|
|
2282
|
+
if (__privateGet(this, _syncState) instanceof PausedState) {
|
|
2283
|
+
resumingFromPause = true;
|
|
2284
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).resume());
|
|
1552
2285
|
}
|
|
1553
|
-
const resumingFromPause = __privateGet(this, _state) === `paused`;
|
|
1554
|
-
__privateSet(this, _state, `active`);
|
|
1555
2286
|
const { url, signal } = this.options;
|
|
1556
2287
|
const { fetchUrl, requestHeaders } = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, url, resumingFromPause);
|
|
1557
2288
|
const abortListener = await __privateMethod(this, _ShapeStream_instances, createAbortListener_fn).call(this, signal);
|
|
1558
2289
|
const requestAbortController = __privateGet(this, _requestAbortController);
|
|
2290
|
+
if (__privateGet(this, _pauseLock).isPaused) {
|
|
2291
|
+
if (abortListener && signal) {
|
|
2292
|
+
signal.removeEventListener(`abort`, abortListener);
|
|
2293
|
+
}
|
|
2294
|
+
__privateSet(this, _requestAbortController, void 0);
|
|
2295
|
+
return;
|
|
2296
|
+
}
|
|
1559
2297
|
try {
|
|
1560
2298
|
await __privateMethod(this, _ShapeStream_instances, fetchShape_fn).call(this, {
|
|
1561
2299
|
fetchUrl,
|
|
@@ -1570,10 +2308,6 @@ requestShape_fn = async function() {
|
|
|
1570
2308
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
1571
2309
|
}
|
|
1572
2310
|
if (e instanceof FetchBackoffAbortError) {
|
|
1573
|
-
const currentState = __privateGet(this, _state);
|
|
1574
|
-
if (requestAbortController.signal.aborted && requestAbortController.signal.reason === PAUSE_STREAM && currentState === `pause-requested`) {
|
|
1575
|
-
__privateSet(this, _state, `paused`);
|
|
1576
|
-
}
|
|
1577
2311
|
return;
|
|
1578
2312
|
}
|
|
1579
2313
|
if (e instanceof StaleCacheError) {
|
|
@@ -1581,11 +2315,11 @@ requestShape_fn = async function() {
|
|
|
1581
2315
|
}
|
|
1582
2316
|
if (!(e instanceof FetchError)) throw e;
|
|
1583
2317
|
if (e.status == 409) {
|
|
1584
|
-
if (__privateGet(this,
|
|
2318
|
+
if (__privateGet(this, _syncState).handle) {
|
|
1585
2319
|
const shapeKey = canonicalShapeKey(fetchUrl);
|
|
1586
|
-
expiredShapesCache.markExpired(shapeKey, __privateGet(this,
|
|
2320
|
+
expiredShapesCache.markExpired(shapeKey, __privateGet(this, _syncState).handle);
|
|
1587
2321
|
}
|
|
1588
|
-
const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER] || `${__privateGet(this,
|
|
2322
|
+
const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER] || `${__privateGet(this, _syncState).handle}-next`;
|
|
1589
2323
|
__privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
|
|
1590
2324
|
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, Array.isArray(e.json) ? e.json : [e.json]);
|
|
1591
2325
|
return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
|
|
@@ -1691,32 +2425,18 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
|
|
|
1691
2425
|
setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, encodedOrderBy);
|
|
1692
2426
|
}
|
|
1693
2427
|
}
|
|
1694
|
-
|
|
2428
|
+
__privateGet(this, _syncState).applyUrlParams(fetchUrl, {
|
|
2429
|
+
isSnapshotRequest: subsetParams !== void 0,
|
|
2430
|
+
// Don't long-poll when resuming from pause or refreshing — avoids
|
|
2431
|
+
// a 20s hold during which `isConnected` would be false
|
|
2432
|
+
canLongPoll: !__privateGet(this, _ShapeStream_instances, isRefreshing_get) && !resumingFromPause
|
|
2433
|
+
});
|
|
1695
2434
|
fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, __privateGet(this, _mode));
|
|
1696
|
-
const isSnapshotRequest = subsetParams !== void 0;
|
|
1697
|
-
if (__privateGet(this, _isUpToDate) && !isSnapshotRequest) {
|
|
1698
|
-
if (!__privateGet(this, _isRefreshing) && !resumingFromPause) {
|
|
1699
|
-
fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`);
|
|
1700
|
-
}
|
|
1701
|
-
fetchUrl.searchParams.set(
|
|
1702
|
-
LIVE_CACHE_BUSTER_QUERY_PARAM,
|
|
1703
|
-
__privateGet(this, _liveCacheBuster)
|
|
1704
|
-
);
|
|
1705
|
-
}
|
|
1706
|
-
if (__privateGet(this, _shapeHandle)) {
|
|
1707
|
-
fetchUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shapeHandle));
|
|
1708
|
-
}
|
|
1709
2435
|
const shapeKey = canonicalShapeKey(fetchUrl);
|
|
1710
2436
|
const expiredHandle = expiredShapesCache.getExpiredHandle(shapeKey);
|
|
1711
2437
|
if (expiredHandle) {
|
|
1712
2438
|
fetchUrl.searchParams.set(EXPIRED_HANDLE_QUERY_PARAM, expiredHandle);
|
|
1713
2439
|
}
|
|
1714
|
-
if (__privateGet(this, _staleCacheBuster)) {
|
|
1715
|
-
fetchUrl.searchParams.set(
|
|
1716
|
-
CACHE_BUSTER_QUERY_PARAM,
|
|
1717
|
-
__privateGet(this, _staleCacheBuster)
|
|
1718
|
-
);
|
|
1719
|
-
}
|
|
1720
2440
|
fetchUrl.searchParams.sort();
|
|
1721
2441
|
return {
|
|
1722
2442
|
fetchUrl,
|
|
@@ -1739,108 +2459,100 @@ createAbortListener_fn = async function(signal) {
|
|
|
1739
2459
|
}
|
|
1740
2460
|
};
|
|
1741
2461
|
onInitialResponse_fn = async function(response) {
|
|
1742
|
-
var _a, _b, _c
|
|
2462
|
+
var _a, _b, _c;
|
|
1743
2463
|
const { headers, status } = response;
|
|
1744
2464
|
const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
`
|
|
1769
|
-
);
|
|
1770
|
-
__privateSet(this, _staleCacheBuster, `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`);
|
|
1771
|
-
throw new StaleCacheError(
|
|
1772
|
-
`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.`
|
|
1773
|
-
);
|
|
1774
|
-
} else {
|
|
1775
|
-
console.warn(
|
|
1776
|
-
`[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)}".`
|
|
2465
|
+
const shapeKey = __privateGet(this, _currentFetchUrl) ? canonicalShapeKey(__privateGet(this, _currentFetchUrl)) : null;
|
|
2466
|
+
const expiredHandle = shapeKey ? expiredShapesCache.getExpiredHandle(shapeKey) : null;
|
|
2467
|
+
const transition = __privateGet(this, _syncState).handleResponseMetadata({
|
|
2468
|
+
status,
|
|
2469
|
+
responseHandle: shapeHandle,
|
|
2470
|
+
responseOffset: headers.get(CHUNK_LAST_OFFSET_HEADER),
|
|
2471
|
+
responseCursor: headers.get(LIVE_CACHE_BUSTER_HEADER),
|
|
2472
|
+
responseSchema: getSchemaFromHeaders(headers),
|
|
2473
|
+
expiredHandle,
|
|
2474
|
+
now: Date.now(),
|
|
2475
|
+
maxStaleCacheRetries: __privateGet(this, _maxStaleCacheRetries),
|
|
2476
|
+
createCacheBuster: () => `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
|
|
2477
|
+
});
|
|
2478
|
+
__privateSet(this, _syncState, transition.state);
|
|
2479
|
+
if (transition.action === `stale-retry`) {
|
|
2480
|
+
await ((_a = response.body) == null ? void 0 : _a.cancel());
|
|
2481
|
+
if (transition.exceededMaxRetries) {
|
|
2482
|
+
throw new FetchError(
|
|
2483
|
+
502,
|
|
2484
|
+
void 0,
|
|
2485
|
+
void 0,
|
|
2486
|
+
{},
|
|
2487
|
+
(_c = (_b = __privateGet(this, _currentFetchUrl)) == null ? void 0 : _b.toString()) != null ? _c : ``,
|
|
2488
|
+
`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`
|
|
1777
2489
|
);
|
|
1778
|
-
return;
|
|
1779
2490
|
}
|
|
2491
|
+
console.warn(
|
|
2492
|
+
`[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)}).`
|
|
2493
|
+
);
|
|
2494
|
+
throw new StaleCacheError(
|
|
2495
|
+
`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.`
|
|
2496
|
+
);
|
|
1780
2497
|
}
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
if (liveCacheBuster) {
|
|
1787
|
-
__privateSet(this, _liveCacheBuster, liveCacheBuster);
|
|
1788
|
-
}
|
|
1789
|
-
__privateSet(this, _schema, (_d = __privateGet(this, _schema)) != null ? _d : getSchemaFromHeaders(headers));
|
|
1790
|
-
if (status === 204) {
|
|
1791
|
-
__privateSet(this, _lastSyncedAt, Date.now());
|
|
2498
|
+
if (transition.action === `ignored`) {
|
|
2499
|
+
console.warn(
|
|
2500
|
+
`[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}".`
|
|
2501
|
+
);
|
|
2502
|
+
return false;
|
|
1792
2503
|
}
|
|
2504
|
+
return true;
|
|
1793
2505
|
};
|
|
1794
2506
|
onMessages_fn = async function(batch, isSseMessage = false) {
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
if (__privateGet(this, _currentFetchUrl)) {
|
|
1819
|
-
const shapeKey = canonicalShapeKey(__privateGet(this, _currentFetchUrl));
|
|
1820
|
-
upToDateTracker.recordUpToDate(shapeKey, __privateGet(this, _liveCacheBuster));
|
|
1821
|
-
}
|
|
2507
|
+
if (batch.length === 0) return;
|
|
2508
|
+
const lastMessage = batch[batch.length - 1];
|
|
2509
|
+
const hasUpToDateMessage = isUpToDateMessage(lastMessage);
|
|
2510
|
+
const upToDateOffset = hasUpToDateMessage ? getOffset(lastMessage) : void 0;
|
|
2511
|
+
const transition = __privateGet(this, _syncState).handleMessageBatch({
|
|
2512
|
+
hasMessages: true,
|
|
2513
|
+
hasUpToDateMessage,
|
|
2514
|
+
isSse: isSseMessage,
|
|
2515
|
+
upToDateOffset,
|
|
2516
|
+
now: Date.now(),
|
|
2517
|
+
currentCursor: __privateGet(this, _syncState).liveCacheBuster
|
|
2518
|
+
});
|
|
2519
|
+
__privateSet(this, _syncState, transition.state);
|
|
2520
|
+
if (hasUpToDateMessage) {
|
|
2521
|
+
if (transition.suppressBatch) {
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
if (__privateGet(this, _currentFetchUrl)) {
|
|
2525
|
+
const shapeKey = canonicalShapeKey(__privateGet(this, _currentFetchUrl));
|
|
2526
|
+
upToDateTracker.recordUpToDate(
|
|
2527
|
+
shapeKey,
|
|
2528
|
+
__privateGet(this, _syncState).liveCacheBuster
|
|
2529
|
+
);
|
|
1822
2530
|
}
|
|
1823
|
-
const messagesToProcess = batch.filter((message) => {
|
|
1824
|
-
if (isChangeMessage(message)) {
|
|
1825
|
-
return !__privateGet(this, _snapshotTracker).shouldRejectMessage(message);
|
|
1826
|
-
}
|
|
1827
|
-
return true;
|
|
1828
|
-
});
|
|
1829
|
-
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, messagesToProcess);
|
|
1830
2531
|
}
|
|
2532
|
+
const messagesToProcess = batch.filter((message) => {
|
|
2533
|
+
if (isChangeMessage(message)) {
|
|
2534
|
+
return !__privateGet(this, _snapshotTracker).shouldRejectMessage(message);
|
|
2535
|
+
}
|
|
2536
|
+
return true;
|
|
2537
|
+
});
|
|
2538
|
+
await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, messagesToProcess);
|
|
1831
2539
|
};
|
|
1832
2540
|
fetchShape_fn = async function(opts) {
|
|
1833
2541
|
var _a;
|
|
1834
2542
|
__privateSet(this, _currentFetchUrl, opts.fetchUrl);
|
|
1835
|
-
if (!__privateGet(this,
|
|
2543
|
+
if (!__privateGet(this, _syncState).isUpToDate && __privateGet(this, _syncState).canEnterReplayMode()) {
|
|
1836
2544
|
const shapeKey = canonicalShapeKey(opts.fetchUrl);
|
|
1837
2545
|
const lastSeenCursor = upToDateTracker.shouldEnterReplayMode(shapeKey);
|
|
1838
2546
|
if (lastSeenCursor) {
|
|
1839
|
-
__privateSet(this,
|
|
2547
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).enterReplayMode(lastSeenCursor));
|
|
1840
2548
|
}
|
|
1841
2549
|
}
|
|
1842
2550
|
const useSse = (_a = this.options.liveSse) != null ? _a : this.options.experimentalLiveSse;
|
|
1843
|
-
if (__privateGet(this,
|
|
2551
|
+
if (__privateGet(this, _syncState).shouldUseSse({
|
|
2552
|
+
liveSseEnabled: !!useSse,
|
|
2553
|
+
isRefreshing: __privateGet(this, _ShapeStream_instances, isRefreshing_get),
|
|
2554
|
+
resumingFromPause: !!opts.resumingFromPause
|
|
2555
|
+
})) {
|
|
1844
2556
|
opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
|
|
1845
2557
|
opts.fetchUrl.searchParams.set(LIVE_SSE_QUERY_PARAM, `true`);
|
|
1846
2558
|
return __privateMethod(this, _ShapeStream_instances, requestShapeSSE_fn).call(this, opts);
|
|
@@ -1854,8 +2566,9 @@ requestShapeLongPoll_fn = async function(opts) {
|
|
|
1854
2566
|
headers
|
|
1855
2567
|
});
|
|
1856
2568
|
__privateSet(this, _connected, true);
|
|
1857
|
-
await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
1858
|
-
|
|
2569
|
+
const shouldProcessBody = await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
2570
|
+
if (!shouldProcessBody) return;
|
|
2571
|
+
const schema = __privateGet(this, _syncState).schema;
|
|
1859
2572
|
const res = await response.text();
|
|
1860
2573
|
const messages = res || `[]`;
|
|
1861
2574
|
const batch = __privateGet(this, _messageParser).parse(messages, schema);
|
|
@@ -1868,18 +2581,23 @@ requestShapeSSE_fn = async function(opts) {
|
|
|
1868
2581
|
const sseHeaders = __spreadProps(__spreadValues({}, headers), {
|
|
1869
2582
|
Accept: `text/event-stream`
|
|
1870
2583
|
});
|
|
2584
|
+
let ignoredStaleResponse = false;
|
|
1871
2585
|
try {
|
|
1872
2586
|
let buffer = [];
|
|
1873
|
-
await
|
|
2587
|
+
await fetchEventSource(fetchUrl.toString(), {
|
|
1874
2588
|
headers: sseHeaders,
|
|
1875
2589
|
fetch: fetch2,
|
|
1876
2590
|
onopen: async (response) => {
|
|
1877
2591
|
__privateSet(this, _connected, true);
|
|
1878
|
-
await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
2592
|
+
const shouldProcessBody = await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
|
|
2593
|
+
if (!shouldProcessBody) {
|
|
2594
|
+
ignoredStaleResponse = true;
|
|
2595
|
+
throw new Error(`stale response ignored`);
|
|
2596
|
+
}
|
|
1879
2597
|
},
|
|
1880
2598
|
onmessage: (event) => {
|
|
1881
2599
|
if (event.data) {
|
|
1882
|
-
const schema = __privateGet(this,
|
|
2600
|
+
const schema = __privateGet(this, _syncState).schema;
|
|
1883
2601
|
const message = __privateGet(this, _messageParser).parse(
|
|
1884
2602
|
event.data,
|
|
1885
2603
|
schema
|
|
@@ -1897,6 +2615,9 @@ requestShapeSSE_fn = async function(opts) {
|
|
|
1897
2615
|
signal: requestAbortController.signal
|
|
1898
2616
|
});
|
|
1899
2617
|
} catch (error) {
|
|
2618
|
+
if (ignoredStaleResponse) {
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
1900
2621
|
if (requestAbortController.signal.aborted) {
|
|
1901
2622
|
throw new FetchBackoffAbortError();
|
|
1902
2623
|
}
|
|
@@ -1904,46 +2625,33 @@ requestShapeSSE_fn = async function(opts) {
|
|
|
1904
2625
|
} finally {
|
|
1905
2626
|
const connectionDuration = Date.now() - __privateGet(this, _lastSseConnectionStartTime);
|
|
1906
2627
|
const wasAborted = requestAbortController.signal.aborted;
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
}
|
|
1926
|
-
};
|
|
1927
|
-
pause_fn = function() {
|
|
1928
|
-
var _a;
|
|
1929
|
-
if (__privateGet(this, _started) && __privateGet(this, _state) === `active`) {
|
|
1930
|
-
__privateSet(this, _state, `pause-requested`);
|
|
1931
|
-
(_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.abort(PAUSE_STREAM);
|
|
1932
|
-
}
|
|
1933
|
-
};
|
|
1934
|
-
resume_fn = function() {
|
|
1935
|
-
var _a;
|
|
1936
|
-
if (__privateGet(this, _started) && (__privateGet(this, _state) === `paused` || __privateGet(this, _state) === `pause-requested`)) {
|
|
1937
|
-
if ((_a = this.options.signal) == null ? void 0 : _a.aborted) {
|
|
1938
|
-
return;
|
|
1939
|
-
}
|
|
1940
|
-
if (__privateGet(this, _state) === `pause-requested`) {
|
|
1941
|
-
__privateSet(this, _state, `active`);
|
|
2628
|
+
const transition = __privateGet(this, _syncState).handleSseConnectionClosed({
|
|
2629
|
+
connectionDuration,
|
|
2630
|
+
wasAborted,
|
|
2631
|
+
minConnectionDuration: __privateGet(this, _minSseConnectionDuration),
|
|
2632
|
+
maxShortConnections: __privateGet(this, _maxShortSseConnections)
|
|
2633
|
+
});
|
|
2634
|
+
__privateSet(this, _syncState, transition.state);
|
|
2635
|
+
if (transition.fellBackToLongPolling) {
|
|
2636
|
+
console.warn(
|
|
2637
|
+
`[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.`
|
|
2638
|
+
);
|
|
2639
|
+
} else if (transition.wasShortConnection) {
|
|
2640
|
+
const maxDelay = Math.min(
|
|
2641
|
+
__privateGet(this, _sseBackoffMaxDelay),
|
|
2642
|
+
__privateGet(this, _sseBackoffBaseDelay) * Math.pow(2, __privateGet(this, _syncState).consecutiveShortSseConnections)
|
|
2643
|
+
);
|
|
2644
|
+
const delayMs = Math.floor(Math.random() * maxDelay);
|
|
2645
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1942
2646
|
}
|
|
1943
|
-
__privateMethod(this, _ShapeStream_instances, start_fn).call(this);
|
|
1944
2647
|
}
|
|
1945
2648
|
};
|
|
1946
2649
|
nextTick_fn = async function() {
|
|
2650
|
+
if (__privateGet(this, _pauseLock).isPaused) {
|
|
2651
|
+
throw new Error(
|
|
2652
|
+
`Cannot wait for next tick while PauseLock is held \u2014 this would deadlock because the request loop is paused`
|
|
2653
|
+
);
|
|
2654
|
+
}
|
|
1947
2655
|
if (__privateGet(this, _tickPromise)) {
|
|
1948
2656
|
return __privateGet(this, _tickPromise);
|
|
1949
2657
|
}
|
|
@@ -1958,22 +2666,6 @@ nextTick_fn = async function() {
|
|
|
1958
2666
|
});
|
|
1959
2667
|
return __privateGet(this, _tickPromise);
|
|
1960
2668
|
};
|
|
1961
|
-
waitForStreamEnd_fn = async function() {
|
|
1962
|
-
if (!__privateGet(this, _isMidStream)) {
|
|
1963
|
-
return;
|
|
1964
|
-
}
|
|
1965
|
-
if (__privateGet(this, _midStreamPromise)) {
|
|
1966
|
-
return __privateGet(this, _midStreamPromise);
|
|
1967
|
-
}
|
|
1968
|
-
__privateSet(this, _midStreamPromise, new Promise((resolve) => {
|
|
1969
|
-
__privateSet(this, _midStreamPromiseResolver, resolve);
|
|
1970
|
-
}));
|
|
1971
|
-
__privateGet(this, _midStreamPromise).finally(() => {
|
|
1972
|
-
__privateSet(this, _midStreamPromise, void 0);
|
|
1973
|
-
__privateSet(this, _midStreamPromiseResolver, void 0);
|
|
1974
|
-
});
|
|
1975
|
-
return __privateGet(this, _midStreamPromise);
|
|
1976
|
-
};
|
|
1977
2669
|
publish_fn = async function(messages) {
|
|
1978
2670
|
__privateSet(this, _messageChain, __privateGet(this, _messageChain).then(
|
|
1979
2671
|
() => Promise.all(
|
|
@@ -2002,9 +2694,9 @@ subscribeToVisibilityChanges_fn = function() {
|
|
|
2002
2694
|
if (__privateMethod(this, _ShapeStream_instances, hasBrowserVisibilityAPI_fn).call(this)) {
|
|
2003
2695
|
const visibilityHandler = () => {
|
|
2004
2696
|
if (document.hidden) {
|
|
2005
|
-
|
|
2697
|
+
__privateGet(this, _pauseLock).acquire(`visibility`);
|
|
2006
2698
|
} else {
|
|
2007
|
-
|
|
2699
|
+
__privateGet(this, _pauseLock).release(`visibility`);
|
|
2008
2700
|
}
|
|
2009
2701
|
};
|
|
2010
2702
|
document.addEventListener(`visibilitychange`, visibilityHandler);
|
|
@@ -2035,11 +2727,11 @@ subscribeToWakeDetection_fn = function() {
|
|
|
2035
2727
|
const elapsed = now - lastTickTime;
|
|
2036
2728
|
lastTickTime = now;
|
|
2037
2729
|
if (elapsed > INTERVAL_MS + WAKE_THRESHOLD_MS) {
|
|
2038
|
-
if (__privateGet(this,
|
|
2039
|
-
|
|
2730
|
+
if (!__privateGet(this, _pauseLock).isPaused && __privateGet(this, _requestAbortController)) {
|
|
2731
|
+
__privateWrapper(this, _refreshCount)._++;
|
|
2040
2732
|
__privateGet(this, _requestAbortController).abort(SYSTEM_WAKE);
|
|
2041
2733
|
queueMicrotask(() => {
|
|
2042
|
-
|
|
2734
|
+
__privateWrapper(this, _refreshCount)._--;
|
|
2043
2735
|
});
|
|
2044
2736
|
}
|
|
2045
2737
|
}
|
|
@@ -2056,18 +2748,9 @@ subscribeToWakeDetection_fn = function() {
|
|
|
2056
2748
|
* shape handle
|
|
2057
2749
|
*/
|
|
2058
2750
|
reset_fn = function(handle) {
|
|
2059
|
-
__privateSet(this,
|
|
2060
|
-
__privateSet(this, _liveCacheBuster, ``);
|
|
2061
|
-
__privateSet(this, _shapeHandle, handle);
|
|
2062
|
-
__privateSet(this, _isUpToDate, false);
|
|
2063
|
-
__privateSet(this, _isMidStream, true);
|
|
2751
|
+
__privateSet(this, _syncState, __privateGet(this, _syncState).markMustRefetch(handle));
|
|
2064
2752
|
__privateSet(this, _connected, false);
|
|
2065
|
-
|
|
2066
|
-
__privateSet(this, _activeSnapshotRequests, 0);
|
|
2067
|
-
__privateSet(this, _consecutiveShortSseConnections, 0);
|
|
2068
|
-
__privateSet(this, _sseFallbackToLongPolling, false);
|
|
2069
|
-
__privateSet(this, _staleCacheBuster, void 0);
|
|
2070
|
-
__privateSet(this, _staleCacheRetryCount, 0);
|
|
2753
|
+
__privateGet(this, _pauseLock).releaseAllMatching(`snapshot`);
|
|
2071
2754
|
};
|
|
2072
2755
|
buildSubsetBody_fn = function(opts) {
|
|
2073
2756
|
var _a, _b, _c, _d;
|