@electric-sql/client 1.5.2 → 1.5.3

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.
@@ -1095,6 +1095,544 @@ var SnapshotTracker = class {
1095
1095
  }
1096
1096
  };
1097
1097
 
1098
+ // src/shape-stream-state.ts
1099
+ var ShapeStreamState = class {
1100
+ // --- Derived booleans ---
1101
+ get isUpToDate() {
1102
+ return false;
1103
+ }
1104
+ // --- Per-state field defaults ---
1105
+ get staleCacheBuster() {
1106
+ return void 0;
1107
+ }
1108
+ get staleCacheRetryCount() {
1109
+ return 0;
1110
+ }
1111
+ get sseFallbackToLongPolling() {
1112
+ return false;
1113
+ }
1114
+ get consecutiveShortSseConnections() {
1115
+ return 0;
1116
+ }
1117
+ get replayCursor() {
1118
+ return void 0;
1119
+ }
1120
+ // --- Default no-op methods ---
1121
+ canEnterReplayMode() {
1122
+ return false;
1123
+ }
1124
+ enterReplayMode(_cursor) {
1125
+ return this;
1126
+ }
1127
+ shouldUseSse(_opts) {
1128
+ return false;
1129
+ }
1130
+ handleSseConnectionClosed(_input) {
1131
+ return {
1132
+ state: this,
1133
+ fellBackToLongPolling: false,
1134
+ wasShortConnection: false
1135
+ };
1136
+ }
1137
+ // --- URL param application ---
1138
+ /** Adds state-specific query parameters to the fetch URL. */
1139
+ applyUrlParams(_url, _context) {
1140
+ }
1141
+ // --- Default response/message handlers (Paused/Error never receive these) ---
1142
+ handleResponseMetadata(_input) {
1143
+ return { action: `ignored`, state: this };
1144
+ }
1145
+ handleMessageBatch(_input) {
1146
+ return { state: this, suppressBatch: false, becameUpToDate: false };
1147
+ }
1148
+ pause() {
1149
+ return new PausedState(this);
1150
+ }
1151
+ toErrorState(error) {
1152
+ return new ErrorState(this, error);
1153
+ }
1154
+ markMustRefetch(handle) {
1155
+ return new InitialState({
1156
+ handle,
1157
+ offset: `-1`,
1158
+ liveCacheBuster: ``,
1159
+ lastSyncedAt: this.lastSyncedAt,
1160
+ schema: void 0
1161
+ });
1162
+ }
1163
+ };
1164
+ var _shared;
1165
+ var ActiveState = class extends ShapeStreamState {
1166
+ constructor(shared) {
1167
+ super();
1168
+ __privateAdd(this, _shared);
1169
+ __privateSet(this, _shared, shared);
1170
+ }
1171
+ get handle() {
1172
+ return __privateGet(this, _shared).handle;
1173
+ }
1174
+ get offset() {
1175
+ return __privateGet(this, _shared).offset;
1176
+ }
1177
+ get schema() {
1178
+ return __privateGet(this, _shared).schema;
1179
+ }
1180
+ get liveCacheBuster() {
1181
+ return __privateGet(this, _shared).liveCacheBuster;
1182
+ }
1183
+ get lastSyncedAt() {
1184
+ return __privateGet(this, _shared).lastSyncedAt;
1185
+ }
1186
+ /** Expose shared fields to subclasses for spreading into new instances. */
1187
+ get currentFields() {
1188
+ return __privateGet(this, _shared);
1189
+ }
1190
+ // --- URL param application ---
1191
+ applyUrlParams(url, _context) {
1192
+ url.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _shared).offset);
1193
+ if (__privateGet(this, _shared).handle) {
1194
+ url.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, __privateGet(this, _shared).handle);
1195
+ }
1196
+ }
1197
+ // --- Helpers for subclass handleResponseMetadata implementations ---
1198
+ /** Extracts updated SharedStateFields from response headers. */
1199
+ parseResponseFields(input) {
1200
+ var _a, _b, _c;
1201
+ const responseHandle = input.responseHandle;
1202
+ const handle = responseHandle && responseHandle !== input.expiredHandle ? responseHandle : __privateGet(this, _shared).handle;
1203
+ const offset = (_a = input.responseOffset) != null ? _a : __privateGet(this, _shared).offset;
1204
+ const liveCacheBuster = (_b = input.responseCursor) != null ? _b : __privateGet(this, _shared).liveCacheBuster;
1205
+ const schema = (_c = __privateGet(this, _shared).schema) != null ? _c : input.responseSchema;
1206
+ const lastSyncedAt = input.status === 204 ? input.now : __privateGet(this, _shared).lastSyncedAt;
1207
+ return { handle, offset, schema, liveCacheBuster, lastSyncedAt };
1208
+ }
1209
+ /**
1210
+ * Stale detection. Returns a transition if the response is stale,
1211
+ * or null if it is not stale and the caller should proceed normally.
1212
+ */
1213
+ checkStaleResponse(input) {
1214
+ const responseHandle = input.responseHandle;
1215
+ const expiredHandle = input.expiredHandle;
1216
+ if (!responseHandle || responseHandle !== expiredHandle) {
1217
+ return null;
1218
+ }
1219
+ if (__privateGet(this, _shared).handle === void 0 || __privateGet(this, _shared).handle === expiredHandle) {
1220
+ const retryCount = this.staleCacheRetryCount + 1;
1221
+ return {
1222
+ action: `stale-retry`,
1223
+ state: new StaleRetryState(__spreadProps(__spreadValues({}, this.currentFields), {
1224
+ staleCacheBuster: input.createCacheBuster(),
1225
+ staleCacheRetryCount: retryCount
1226
+ })),
1227
+ exceededMaxRetries: retryCount > input.maxStaleCacheRetries
1228
+ };
1229
+ }
1230
+ return { action: `ignored`, state: this };
1231
+ }
1232
+ // --- handleMessageBatch: template method with onUpToDate override point ---
1233
+ handleMessageBatch(input) {
1234
+ if (!input.hasMessages || !input.hasUpToDateMessage) {
1235
+ return { state: this, suppressBatch: false, becameUpToDate: false };
1236
+ }
1237
+ let offset = __privateGet(this, _shared).offset;
1238
+ if (input.isSse && input.upToDateOffset) {
1239
+ offset = input.upToDateOffset;
1240
+ }
1241
+ const shared = {
1242
+ handle: __privateGet(this, _shared).handle,
1243
+ offset,
1244
+ schema: __privateGet(this, _shared).schema,
1245
+ liveCacheBuster: __privateGet(this, _shared).liveCacheBuster,
1246
+ lastSyncedAt: input.now
1247
+ };
1248
+ return this.onUpToDate(shared, input);
1249
+ }
1250
+ /** Override point for up-to-date handling. Default → LiveState. */
1251
+ onUpToDate(shared, _input) {
1252
+ return {
1253
+ state: new LiveState(shared),
1254
+ suppressBatch: false,
1255
+ becameUpToDate: true
1256
+ };
1257
+ }
1258
+ };
1259
+ _shared = new WeakMap();
1260
+ var FetchingState = class extends ActiveState {
1261
+ handleResponseMetadata(input) {
1262
+ const staleResult = this.checkStaleResponse(input);
1263
+ if (staleResult) return staleResult;
1264
+ const shared = this.parseResponseFields(input);
1265
+ return { action: `accepted`, state: new SyncingState(shared) };
1266
+ }
1267
+ canEnterReplayMode() {
1268
+ return true;
1269
+ }
1270
+ enterReplayMode(cursor) {
1271
+ return new ReplayingState(__spreadProps(__spreadValues({}, this.currentFields), {
1272
+ replayCursor: cursor
1273
+ }));
1274
+ }
1275
+ };
1276
+ var InitialState = class _InitialState extends FetchingState {
1277
+ constructor(shared) {
1278
+ super(shared);
1279
+ this.kind = `initial`;
1280
+ }
1281
+ withHandle(handle) {
1282
+ return new _InitialState(__spreadProps(__spreadValues({}, this.currentFields), { handle }));
1283
+ }
1284
+ };
1285
+ var SyncingState = class _SyncingState extends FetchingState {
1286
+ constructor(shared) {
1287
+ super(shared);
1288
+ this.kind = `syncing`;
1289
+ }
1290
+ withHandle(handle) {
1291
+ return new _SyncingState(__spreadProps(__spreadValues({}, this.currentFields), { handle }));
1292
+ }
1293
+ };
1294
+ var _staleCacheBuster, _staleCacheRetryCount;
1295
+ var _StaleRetryState = class _StaleRetryState extends FetchingState {
1296
+ constructor(fields) {
1297
+ const _a = fields, { staleCacheBuster, staleCacheRetryCount } = _a, shared = __objRest(_a, ["staleCacheBuster", "staleCacheRetryCount"]);
1298
+ super(shared);
1299
+ this.kind = `stale-retry`;
1300
+ __privateAdd(this, _staleCacheBuster);
1301
+ __privateAdd(this, _staleCacheRetryCount);
1302
+ __privateSet(this, _staleCacheBuster, staleCacheBuster);
1303
+ __privateSet(this, _staleCacheRetryCount, staleCacheRetryCount);
1304
+ }
1305
+ get staleCacheBuster() {
1306
+ return __privateGet(this, _staleCacheBuster);
1307
+ }
1308
+ get staleCacheRetryCount() {
1309
+ return __privateGet(this, _staleCacheRetryCount);
1310
+ }
1311
+ // StaleRetryState must not enter replay mode — it would lose the retry count
1312
+ canEnterReplayMode() {
1313
+ return false;
1314
+ }
1315
+ withHandle(handle) {
1316
+ return new _StaleRetryState(__spreadProps(__spreadValues({}, this.currentFields), {
1317
+ handle,
1318
+ staleCacheBuster: __privateGet(this, _staleCacheBuster),
1319
+ staleCacheRetryCount: __privateGet(this, _staleCacheRetryCount)
1320
+ }));
1321
+ }
1322
+ applyUrlParams(url, context) {
1323
+ super.applyUrlParams(url, context);
1324
+ url.searchParams.set(CACHE_BUSTER_QUERY_PARAM, __privateGet(this, _staleCacheBuster));
1325
+ }
1326
+ };
1327
+ _staleCacheBuster = new WeakMap();
1328
+ _staleCacheRetryCount = new WeakMap();
1329
+ var StaleRetryState = _StaleRetryState;
1330
+ var _consecutiveShortSseConnections, _sseFallbackToLongPolling;
1331
+ var _LiveState = class _LiveState extends ActiveState {
1332
+ constructor(shared, sseState) {
1333
+ var _a, _b;
1334
+ super(shared);
1335
+ this.kind = `live`;
1336
+ __privateAdd(this, _consecutiveShortSseConnections);
1337
+ __privateAdd(this, _sseFallbackToLongPolling);
1338
+ __privateSet(this, _consecutiveShortSseConnections, (_a = sseState == null ? void 0 : sseState.consecutiveShortSseConnections) != null ? _a : 0);
1339
+ __privateSet(this, _sseFallbackToLongPolling, (_b = sseState == null ? void 0 : sseState.sseFallbackToLongPolling) != null ? _b : false);
1340
+ }
1341
+ get isUpToDate() {
1342
+ return true;
1343
+ }
1344
+ get consecutiveShortSseConnections() {
1345
+ return __privateGet(this, _consecutiveShortSseConnections);
1346
+ }
1347
+ get sseFallbackToLongPolling() {
1348
+ return __privateGet(this, _sseFallbackToLongPolling);
1349
+ }
1350
+ withHandle(handle) {
1351
+ return new _LiveState(__spreadProps(__spreadValues({}, this.currentFields), { handle }), this.sseState);
1352
+ }
1353
+ applyUrlParams(url, context) {
1354
+ super.applyUrlParams(url, context);
1355
+ if (!context.isSnapshotRequest) {
1356
+ url.searchParams.set(LIVE_CACHE_BUSTER_QUERY_PARAM, this.liveCacheBuster);
1357
+ if (context.canLongPoll) {
1358
+ url.searchParams.set(LIVE_QUERY_PARAM, `true`);
1359
+ }
1360
+ }
1361
+ }
1362
+ get sseState() {
1363
+ return {
1364
+ consecutiveShortSseConnections: __privateGet(this, _consecutiveShortSseConnections),
1365
+ sseFallbackToLongPolling: __privateGet(this, _sseFallbackToLongPolling)
1366
+ };
1367
+ }
1368
+ handleResponseMetadata(input) {
1369
+ const staleResult = this.checkStaleResponse(input);
1370
+ if (staleResult) return staleResult;
1371
+ const shared = this.parseResponseFields(input);
1372
+ return {
1373
+ action: `accepted`,
1374
+ state: new _LiveState(shared, this.sseState)
1375
+ };
1376
+ }
1377
+ onUpToDate(shared, _input) {
1378
+ return {
1379
+ state: new _LiveState(shared, this.sseState),
1380
+ suppressBatch: false,
1381
+ becameUpToDate: true
1382
+ };
1383
+ }
1384
+ shouldUseSse(opts) {
1385
+ return opts.liveSseEnabled && !opts.isRefreshing && !opts.resumingFromPause && !__privateGet(this, _sseFallbackToLongPolling);
1386
+ }
1387
+ handleSseConnectionClosed(input) {
1388
+ let nextConsecutiveShort = __privateGet(this, _consecutiveShortSseConnections);
1389
+ let nextFallback = __privateGet(this, _sseFallbackToLongPolling);
1390
+ let fellBackToLongPolling = false;
1391
+ let wasShortConnection = false;
1392
+ if (input.connectionDuration < input.minConnectionDuration && !input.wasAborted) {
1393
+ wasShortConnection = true;
1394
+ nextConsecutiveShort = nextConsecutiveShort + 1;
1395
+ if (nextConsecutiveShort >= input.maxShortConnections) {
1396
+ nextFallback = true;
1397
+ fellBackToLongPolling = true;
1398
+ }
1399
+ } else if (input.connectionDuration >= input.minConnectionDuration) {
1400
+ nextConsecutiveShort = 0;
1401
+ }
1402
+ return {
1403
+ state: new _LiveState(this.currentFields, {
1404
+ consecutiveShortSseConnections: nextConsecutiveShort,
1405
+ sseFallbackToLongPolling: nextFallback
1406
+ }),
1407
+ fellBackToLongPolling,
1408
+ wasShortConnection
1409
+ };
1410
+ }
1411
+ };
1412
+ _consecutiveShortSseConnections = new WeakMap();
1413
+ _sseFallbackToLongPolling = new WeakMap();
1414
+ var LiveState = _LiveState;
1415
+ var _replayCursor;
1416
+ var _ReplayingState = class _ReplayingState extends ActiveState {
1417
+ constructor(fields) {
1418
+ const _a = fields, { replayCursor } = _a, shared = __objRest(_a, ["replayCursor"]);
1419
+ super(shared);
1420
+ this.kind = `replaying`;
1421
+ __privateAdd(this, _replayCursor);
1422
+ __privateSet(this, _replayCursor, replayCursor);
1423
+ }
1424
+ get replayCursor() {
1425
+ return __privateGet(this, _replayCursor);
1426
+ }
1427
+ withHandle(handle) {
1428
+ return new _ReplayingState(__spreadProps(__spreadValues({}, this.currentFields), {
1429
+ handle,
1430
+ replayCursor: __privateGet(this, _replayCursor)
1431
+ }));
1432
+ }
1433
+ handleResponseMetadata(input) {
1434
+ const staleResult = this.checkStaleResponse(input);
1435
+ if (staleResult) return staleResult;
1436
+ const shared = this.parseResponseFields(input);
1437
+ return {
1438
+ action: `accepted`,
1439
+ state: new _ReplayingState(__spreadProps(__spreadValues({}, shared), {
1440
+ replayCursor: __privateGet(this, _replayCursor)
1441
+ }))
1442
+ };
1443
+ }
1444
+ onUpToDate(shared, input) {
1445
+ const suppressBatch = !input.isSse && __privateGet(this, _replayCursor) === input.currentCursor;
1446
+ return {
1447
+ state: new LiveState(shared),
1448
+ suppressBatch,
1449
+ becameUpToDate: true
1450
+ };
1451
+ }
1452
+ };
1453
+ _replayCursor = new WeakMap();
1454
+ var ReplayingState = _ReplayingState;
1455
+ var PausedState = class _PausedState extends ShapeStreamState {
1456
+ constructor(previousState) {
1457
+ super();
1458
+ this.kind = `paused`;
1459
+ this.previousState = previousState;
1460
+ }
1461
+ get handle() {
1462
+ return this.previousState.handle;
1463
+ }
1464
+ get offset() {
1465
+ return this.previousState.offset;
1466
+ }
1467
+ get schema() {
1468
+ return this.previousState.schema;
1469
+ }
1470
+ get liveCacheBuster() {
1471
+ return this.previousState.liveCacheBuster;
1472
+ }
1473
+ get lastSyncedAt() {
1474
+ return this.previousState.lastSyncedAt;
1475
+ }
1476
+ get isUpToDate() {
1477
+ return this.previousState.isUpToDate;
1478
+ }
1479
+ get staleCacheBuster() {
1480
+ return this.previousState.staleCacheBuster;
1481
+ }
1482
+ get staleCacheRetryCount() {
1483
+ return this.previousState.staleCacheRetryCount;
1484
+ }
1485
+ get sseFallbackToLongPolling() {
1486
+ return this.previousState.sseFallbackToLongPolling;
1487
+ }
1488
+ get consecutiveShortSseConnections() {
1489
+ return this.previousState.consecutiveShortSseConnections;
1490
+ }
1491
+ get replayCursor() {
1492
+ return this.previousState.replayCursor;
1493
+ }
1494
+ withHandle(handle) {
1495
+ return new _PausedState(this.previousState.withHandle(handle));
1496
+ }
1497
+ applyUrlParams(url, context) {
1498
+ this.previousState.applyUrlParams(url, context);
1499
+ }
1500
+ pause() {
1501
+ return this;
1502
+ }
1503
+ resume() {
1504
+ return this.previousState;
1505
+ }
1506
+ };
1507
+ var ErrorState = class _ErrorState extends ShapeStreamState {
1508
+ constructor(previousState, error) {
1509
+ super();
1510
+ this.kind = `error`;
1511
+ this.previousState = previousState;
1512
+ this.error = error;
1513
+ }
1514
+ get handle() {
1515
+ return this.previousState.handle;
1516
+ }
1517
+ get offset() {
1518
+ return this.previousState.offset;
1519
+ }
1520
+ get schema() {
1521
+ return this.previousState.schema;
1522
+ }
1523
+ get liveCacheBuster() {
1524
+ return this.previousState.liveCacheBuster;
1525
+ }
1526
+ get lastSyncedAt() {
1527
+ return this.previousState.lastSyncedAt;
1528
+ }
1529
+ get isUpToDate() {
1530
+ return this.previousState.isUpToDate;
1531
+ }
1532
+ withHandle(handle) {
1533
+ return new _ErrorState(this.previousState.withHandle(handle), this.error);
1534
+ }
1535
+ applyUrlParams(url, context) {
1536
+ this.previousState.applyUrlParams(url, context);
1537
+ }
1538
+ retry() {
1539
+ return this.previousState;
1540
+ }
1541
+ reset(handle) {
1542
+ return this.previousState.markMustRefetch(handle);
1543
+ }
1544
+ };
1545
+ function createInitialState(opts) {
1546
+ return new InitialState({
1547
+ handle: opts.handle,
1548
+ offset: opts.offset,
1549
+ liveCacheBuster: ``,
1550
+ lastSyncedAt: void 0,
1551
+ schema: void 0
1552
+ });
1553
+ }
1554
+
1555
+ // src/pause-lock.ts
1556
+ var _holders, _onAcquired, _onReleased;
1557
+ var PauseLock = class {
1558
+ constructor(callbacks) {
1559
+ __privateAdd(this, _holders, /* @__PURE__ */ new Set());
1560
+ __privateAdd(this, _onAcquired);
1561
+ __privateAdd(this, _onReleased);
1562
+ __privateSet(this, _onAcquired, callbacks.onAcquired);
1563
+ __privateSet(this, _onReleased, callbacks.onReleased);
1564
+ }
1565
+ /**
1566
+ * Acquire the lock for a given reason. Idempotent — acquiring the same
1567
+ * reason twice is a no-op (but logs a warning since it likely indicates
1568
+ * a caller bug).
1569
+ *
1570
+ * Fires `onAcquired` when the first reason is acquired (transition from
1571
+ * unlocked to locked).
1572
+ */
1573
+ acquire(reason) {
1574
+ if (__privateGet(this, _holders).has(reason)) {
1575
+ console.warn(
1576
+ `[Electric] PauseLock: "${reason}" already held \u2014 ignoring duplicate acquire`
1577
+ );
1578
+ return;
1579
+ }
1580
+ const wasUnlocked = __privateGet(this, _holders).size === 0;
1581
+ __privateGet(this, _holders).add(reason);
1582
+ if (wasUnlocked) {
1583
+ __privateGet(this, _onAcquired).call(this);
1584
+ }
1585
+ }
1586
+ /**
1587
+ * Release the lock for a given reason. Releasing a reason that isn't
1588
+ * held logs a warning (likely indicates an acquire/release mismatch).
1589
+ *
1590
+ * Fires `onReleased` when the last reason is released (transition from
1591
+ * locked to unlocked).
1592
+ */
1593
+ release(reason) {
1594
+ if (!__privateGet(this, _holders).delete(reason)) {
1595
+ console.warn(
1596
+ `[Electric] PauseLock: "${reason}" not held \u2014 ignoring release (possible acquire/release mismatch)`
1597
+ );
1598
+ return;
1599
+ }
1600
+ if (__privateGet(this, _holders).size === 0) {
1601
+ __privateGet(this, _onReleased).call(this);
1602
+ }
1603
+ }
1604
+ /**
1605
+ * Whether the lock is currently held by any reason.
1606
+ */
1607
+ get isPaused() {
1608
+ return __privateGet(this, _holders).size > 0;
1609
+ }
1610
+ /**
1611
+ * Check if a specific reason is holding the lock.
1612
+ */
1613
+ isHeldBy(reason) {
1614
+ return __privateGet(this, _holders).has(reason);
1615
+ }
1616
+ /**
1617
+ * Release all reasons matching a prefix. Does NOT fire `onReleased` —
1618
+ * this is for cleanup/reset paths where the stream state is being
1619
+ * managed separately.
1620
+ *
1621
+ * This preserves reasons with different prefixes (e.g., 'visibility'
1622
+ * is preserved when clearing 'snapshot-*' reasons).
1623
+ */
1624
+ releaseAllMatching(prefix) {
1625
+ for (const reason of __privateGet(this, _holders)) {
1626
+ if (reason.startsWith(prefix)) {
1627
+ __privateGet(this, _holders).delete(reason);
1628
+ }
1629
+ }
1630
+ }
1631
+ };
1632
+ _holders = new WeakMap();
1633
+ _onAcquired = new WeakMap();
1634
+ _onReleased = new WeakMap();
1635
+
1098
1636
  // src/client.ts
1099
1637
  var RESERVED_PARAMS = /* @__PURE__ */ new Set([
1100
1638
  LIVE_CACHE_BUSTER_QUERY_PARAM,
@@ -1143,7 +1681,7 @@ function canonicalShapeKey(url) {
1143
1681
  cleanUrl.searchParams.sort();
1144
1682
  return cleanUrl.toString();
1145
1683
  }
1146
- var _error, _fetchClient2, _sseFetchClient, _messageParser, _subscribers, _started, _state, _lastOffset, _liveCacheBuster, _lastSyncedAt, _isUpToDate, _isMidStream, _connected, _shapeHandle, _mode, _schema, _onError, _requestAbortController, _isRefreshing, _tickPromise, _tickPromiseResolver, _tickPromiseRejecter, _messageChain, _snapshotTracker, _activeSnapshotRequests, _midStreamPromise, _midStreamPromiseResolver, _lastSeenCursor, _currentFetchUrl, _lastSseConnectionStartTime, _minSseConnectionDuration, _consecutiveShortSseConnections, _maxShortSseConnections, _sseFallbackToLongPolling, _sseBackoffBaseDelay, _sseBackoffMaxDelay, _unsubscribeFromVisibilityChanges, _unsubscribeFromWakeDetection, _staleCacheBuster, _staleCacheRetryCount, _maxStaleCacheRetries, _ShapeStream_instances, replayMode_get, start_fn, requestShape_fn, constructUrl_fn, createAbortListener_fn, onInitialResponse_fn, onMessages_fn, fetchShape_fn, requestShapeLongPoll_fn, requestShapeSSE_fn, pause_fn, resume_fn, nextTick_fn, waitForStreamEnd_fn, publish_fn, sendErrorToSubscribers_fn, hasBrowserVisibilityAPI_fn, subscribeToVisibilityChanges_fn, subscribeToWakeDetection_fn, reset_fn, buildSubsetBody_fn;
1684
+ 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
1685
  var ShapeStream = class {
1148
1686
  constructor(options) {
1149
1687
  __privateAdd(this, _ShapeStream_instances);
@@ -1153,58 +1691,57 @@ var ShapeStream = class {
1153
1691
  __privateAdd(this, _messageParser);
1154
1692
  __privateAdd(this, _subscribers, /* @__PURE__ */ new Map());
1155
1693
  __privateAdd(this, _started, false);
1156
- __privateAdd(this, _state, `active`);
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);
1694
+ __privateAdd(this, _syncState);
1164
1695
  __privateAdd(this, _connected, false);
1165
- __privateAdd(this, _shapeHandle);
1166
1696
  __privateAdd(this, _mode);
1167
- __privateAdd(this, _schema);
1168
1697
  __privateAdd(this, _onError);
1169
1698
  __privateAdd(this, _requestAbortController);
1170
- __privateAdd(this, _isRefreshing, false);
1699
+ __privateAdd(this, _refreshCount, 0);
1700
+ __privateAdd(this, _snapshotCounter, 0);
1171
1701
  __privateAdd(this, _tickPromise);
1172
1702
  __privateAdd(this, _tickPromiseResolver);
1173
1703
  __privateAdd(this, _tickPromiseRejecter);
1174
1704
  __privateAdd(this, _messageChain, Promise.resolve([]));
1175
1705
  // promise chain for incoming messages
1176
1706
  __privateAdd(this, _snapshotTracker, new SnapshotTracker());
1177
- __privateAdd(this, _activeSnapshotRequests, 0);
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)
1707
+ __privateAdd(this, _pauseLock);
1183
1708
  __privateAdd(this, _currentFetchUrl);
1184
1709
  // Current fetch URL for computing shape key
1185
1710
  __privateAdd(this, _lastSseConnectionStartTime);
1186
1711
  __privateAdd(this, _minSseConnectionDuration, 1e3);
1187
1712
  // Minimum expected SSE connection duration (1 second)
1188
- __privateAdd(this, _consecutiveShortSseConnections, 0);
1189
1713
  __privateAdd(this, _maxShortSseConnections, 3);
1190
1714
  // Fall back to long polling after this many short connections
1191
- __privateAdd(this, _sseFallbackToLongPolling, false);
1192
1715
  __privateAdd(this, _sseBackoffBaseDelay, 100);
1193
1716
  // Base delay for exponential backoff (ms)
1194
1717
  __privateAdd(this, _sseBackoffMaxDelay, 5e3);
1195
1718
  // Maximum delay cap (ms)
1196
1719
  __privateAdd(this, _unsubscribeFromVisibilityChanges);
1197
1720
  __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
1721
  __privateAdd(this, _maxStaleCacheRetries, 3);
1202
1722
  var _a, _b, _c, _d;
1203
1723
  this.options = __spreadValues({ subscribe: true }, options);
1204
1724
  validateOptions(this.options);
1205
- __privateSet(this, _lastOffset, (_a = this.options.offset) != null ? _a : `-1`);
1206
- __privateSet(this, _liveCacheBuster, ``);
1207
- __privateSet(this, _shapeHandle, this.options.handle);
1725
+ __privateSet(this, _syncState, createInitialState({
1726
+ offset: (_a = this.options.offset) != null ? _a : `-1`,
1727
+ handle: this.options.handle
1728
+ }));
1729
+ __privateSet(this, _pauseLock, new PauseLock({
1730
+ onAcquired: () => {
1731
+ var _a2;
1732
+ __privateSet(this, _syncState, __privateGet(this, _syncState).pause());
1733
+ if (__privateGet(this, _started)) {
1734
+ (_a2 = __privateGet(this, _requestAbortController)) == null ? void 0 : _a2.abort(PAUSE_STREAM);
1735
+ }
1736
+ },
1737
+ onReleased: () => {
1738
+ var _a2;
1739
+ if (!__privateGet(this, _started)) return;
1740
+ if ((_a2 = this.options.signal) == null ? void 0 : _a2.aborted) return;
1741
+ __privateMethod(this, _ShapeStream_instances, start_fn).call(this).catch(() => {
1742
+ });
1743
+ }
1744
+ }));
1208
1745
  let transformer;
1209
1746
  if (options.columnMapper) {
1210
1747
  const applyColumnMapper = (row) => {
@@ -1242,16 +1779,16 @@ var ShapeStream = class {
1242
1779
  __privateMethod(this, _ShapeStream_instances, subscribeToWakeDetection_fn).call(this);
1243
1780
  }
1244
1781
  get shapeHandle() {
1245
- return __privateGet(this, _shapeHandle);
1782
+ return __privateGet(this, _syncState).handle;
1246
1783
  }
1247
1784
  get error() {
1248
1785
  return __privateGet(this, _error);
1249
1786
  }
1250
1787
  get isUpToDate() {
1251
- return __privateGet(this, _isUpToDate);
1788
+ return __privateGet(this, _syncState).isUpToDate;
1252
1789
  }
1253
1790
  get lastOffset() {
1254
- return __privateGet(this, _lastOffset);
1791
+ return __privateGet(this, _syncState).offset;
1255
1792
  }
1256
1793
  get mode() {
1257
1794
  return __privateGet(this, _mode);
@@ -1271,28 +1808,28 @@ var ShapeStream = class {
1271
1808
  (_a = __privateGet(this, _unsubscribeFromVisibilityChanges)) == null ? void 0 : _a.call(this);
1272
1809
  (_b = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _b.call(this);
1273
1810
  }
1274
- /** Unix time at which we last synced. Undefined when `isLoading` is true. */
1811
+ /** Unix time at which we last synced. Undefined until first successful up-to-date. */
1275
1812
  lastSyncedAt() {
1276
- return __privateGet(this, _lastSyncedAt);
1813
+ return __privateGet(this, _syncState).lastSyncedAt;
1277
1814
  }
1278
1815
  /** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */
1279
1816
  lastSynced() {
1280
- if (__privateGet(this, _lastSyncedAt) === void 0) return Infinity;
1281
- return Date.now() - __privateGet(this, _lastSyncedAt);
1817
+ if (__privateGet(this, _syncState).lastSyncedAt === void 0) return Infinity;
1818
+ return Date.now() - __privateGet(this, _syncState).lastSyncedAt;
1282
1819
  }
1283
1820
  /** Indicates if we are connected to the Electric sync service. */
1284
1821
  isConnected() {
1285
1822
  return __privateGet(this, _connected);
1286
1823
  }
1287
- /** True during initial fetch. False afterwise. */
1824
+ /** True during initial fetch. False afterwards. */
1288
1825
  isLoading() {
1289
- return !__privateGet(this, _isUpToDate);
1826
+ return !__privateGet(this, _syncState).isUpToDate;
1290
1827
  }
1291
1828
  hasStarted() {
1292
1829
  return __privateGet(this, _started);
1293
1830
  }
1294
1831
  isPaused() {
1295
- return __privateGet(this, _state) === `paused`;
1832
+ return __privateGet(this, _pauseLock).isPaused;
1296
1833
  }
1297
1834
  /**
1298
1835
  * Refreshes the shape stream.
@@ -1302,12 +1839,15 @@ var ShapeStream = class {
1302
1839
  */
1303
1840
  async forceDisconnectAndRefresh() {
1304
1841
  var _a, _b;
1305
- __privateSet(this, _isRefreshing, true);
1306
- if (__privateGet(this, _isUpToDate) && !((_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.signal.aborted)) {
1307
- (_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(FORCE_DISCONNECT_AND_REFRESH);
1842
+ __privateWrapper(this, _refreshCount)._++;
1843
+ try {
1844
+ if (__privateGet(this, _syncState).isUpToDate && !((_a = __privateGet(this, _requestAbortController)) == null ? void 0 : _a.signal.aborted)) {
1845
+ (_b = __privateGet(this, _requestAbortController)) == null ? void 0 : _b.abort(FORCE_DISCONNECT_AND_REFRESH);
1846
+ }
1847
+ await __privateMethod(this, _ShapeStream_instances, nextTick_fn).call(this);
1848
+ } finally {
1849
+ __privateWrapper(this, _refreshCount)._--;
1308
1850
  }
1309
- await __privateMethod(this, _ShapeStream_instances, nextTick_fn).call(this);
1310
- __privateSet(this, _isRefreshing, false);
1311
1851
  }
1312
1852
  /**
1313
1853
  * Request a snapshot for subset of data and inject it into the subscribed data stream.
@@ -1329,13 +1869,18 @@ var ShapeStream = class {
1329
1869
  `Snapshot requests are not supported in ${__privateGet(this, _mode)} mode, as the consumer is guaranteed to observe all data`
1330
1870
  );
1331
1871
  }
1332
- if (!__privateGet(this, _started)) await __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
1333
- await __privateMethod(this, _ShapeStream_instances, waitForStreamEnd_fn).call(this);
1334
- __privateWrapper(this, _activeSnapshotRequests)._++;
1872
+ if (!__privateGet(this, _started)) {
1873
+ __privateMethod(this, _ShapeStream_instances, start_fn).call(this).catch(() => {
1874
+ });
1875
+ }
1876
+ const snapshotReason = `snapshot-${++__privateWrapper(this, _snapshotCounter)._}`;
1877
+ __privateGet(this, _pauseLock).acquire(snapshotReason);
1878
+ const snapshotWarnTimer = setTimeout(() => {
1879
+ console.warn(
1880
+ `[Electric] Snapshot "${snapshotReason}" has held the pause lock for 30s \u2014 possible hung request or leaked lock. Current holders: ${[.../* @__PURE__ */ new Set([snapshotReason])].join(`, `)}`
1881
+ );
1882
+ }, 3e4);
1335
1883
  try {
1336
- if (__privateGet(this, _activeSnapshotRequests) === 1) {
1337
- __privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
1338
- }
1339
1884
  const { metadata, data } = await this.fetchSnapshot(opts);
1340
1885
  const dataWithEndBoundary = data.concat([
1341
1886
  { headers: __spreadValues({ control: `snapshot-end` }, metadata) },
@@ -1351,10 +1896,8 @@ var ShapeStream = class {
1351
1896
  data
1352
1897
  };
1353
1898
  } finally {
1354
- __privateWrapper(this, _activeSnapshotRequests)._--;
1355
- if (__privateGet(this, _activeSnapshotRequests) === 0) {
1356
- __privateMethod(this, _ShapeStream_instances, resume_fn).call(this);
1357
- }
1899
+ clearTimeout(snapshotWarnTimer);
1900
+ __privateGet(this, _pauseLock).release(snapshotReason);
1358
1901
  }
1359
1902
  }
1360
1903
  /**
@@ -1389,7 +1932,7 @@ var ShapeStream = class {
1389
1932
  fetchUrl = result.fetchUrl;
1390
1933
  fetchOptions = { headers: result.requestHeaders };
1391
1934
  }
1392
- const usedHandle = __privateGet(this, _shapeHandle);
1935
+ const usedHandle = __privateGet(this, _syncState).handle;
1393
1936
  let response;
1394
1937
  try {
1395
1938
  response = await __privateGet(this, _fetchClient2).call(this, fetchUrl.toString(), fetchOptions);
@@ -1399,7 +1942,8 @@ var ShapeStream = class {
1399
1942
  const shapeKey = canonicalShapeKey(fetchUrl);
1400
1943
  expiredShapesCache.markExpired(shapeKey, usedHandle);
1401
1944
  }
1402
- __privateSet(this, _shapeHandle, e.headers[SHAPE_HANDLE_HEADER] || `${usedHandle != null ? usedHandle : `handle`}-next`);
1945
+ const nextHandle = e.headers[SHAPE_HANDLE_HEADER] || `${usedHandle != null ? usedHandle : `handle`}-next`;
1946
+ __privateSet(this, _syncState, __privateGet(this, _syncState).withHandle(nextHandle));
1403
1947
  return this.fetchSnapshot(opts);
1404
1948
  }
1405
1949
  throw e;
@@ -1407,7 +1951,7 @@ var ShapeStream = class {
1407
1951
  if (!response.ok) {
1408
1952
  throw await FetchError.fromResponse(response, fetchUrl.toString());
1409
1953
  }
1410
- const schema = (_c = __privateGet(this, _schema)) != null ? _c : getSchemaFromHeaders(response.headers, {
1954
+ const schema = (_c = __privateGet(this, _syncState).schema) != null ? _c : getSchemaFromHeaders(response.headers, {
1411
1955
  required: true,
1412
1956
  url: fetchUrl.toString()
1413
1957
  });
@@ -1425,52 +1969,42 @@ _sseFetchClient = new WeakMap();
1425
1969
  _messageParser = new WeakMap();
1426
1970
  _subscribers = new WeakMap();
1427
1971
  _started = new WeakMap();
1428
- _state = new WeakMap();
1429
- _lastOffset = new WeakMap();
1430
- _liveCacheBuster = new WeakMap();
1431
- _lastSyncedAt = new WeakMap();
1432
- _isUpToDate = new WeakMap();
1433
- _isMidStream = new WeakMap();
1972
+ _syncState = new WeakMap();
1434
1973
  _connected = new WeakMap();
1435
- _shapeHandle = new WeakMap();
1436
1974
  _mode = new WeakMap();
1437
- _schema = new WeakMap();
1438
1975
  _onError = new WeakMap();
1439
1976
  _requestAbortController = new WeakMap();
1440
- _isRefreshing = new WeakMap();
1977
+ _refreshCount = new WeakMap();
1978
+ _snapshotCounter = new WeakMap();
1979
+ _ShapeStream_instances = new WeakSet();
1980
+ isRefreshing_get = function() {
1981
+ return __privateGet(this, _refreshCount) > 0;
1982
+ };
1441
1983
  _tickPromise = new WeakMap();
1442
1984
  _tickPromiseResolver = new WeakMap();
1443
1985
  _tickPromiseRejecter = new WeakMap();
1444
1986
  _messageChain = new WeakMap();
1445
1987
  _snapshotTracker = new WeakMap();
1446
- _activeSnapshotRequests = new WeakMap();
1447
- _midStreamPromise = new WeakMap();
1448
- _midStreamPromiseResolver = new WeakMap();
1449
- _lastSeenCursor = new WeakMap();
1988
+ _pauseLock = new WeakMap();
1450
1989
  _currentFetchUrl = new WeakMap();
1451
1990
  _lastSseConnectionStartTime = new WeakMap();
1452
1991
  _minSseConnectionDuration = new WeakMap();
1453
- _consecutiveShortSseConnections = new WeakMap();
1454
1992
  _maxShortSseConnections = new WeakMap();
1455
- _sseFallbackToLongPolling = new WeakMap();
1456
1993
  _sseBackoffBaseDelay = new WeakMap();
1457
1994
  _sseBackoffMaxDelay = new WeakMap();
1458
1995
  _unsubscribeFromVisibilityChanges = new WeakMap();
1459
1996
  _unsubscribeFromWakeDetection = new WeakMap();
1460
- _staleCacheBuster = new WeakMap();
1461
- _staleCacheRetryCount = new WeakMap();
1462
1997
  _maxStaleCacheRetries = new WeakMap();
1463
- _ShapeStream_instances = new WeakSet();
1464
- replayMode_get = function() {
1465
- return __privateGet(this, _lastSeenCursor) !== void 0;
1466
- };
1467
1998
  start_fn = async function() {
1468
- var _a, _b, _c, _d, _e, _f, _g, _h;
1999
+ var _a, _b;
1469
2000
  __privateSet(this, _started, true);
1470
2001
  try {
1471
2002
  await __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
1472
2003
  } catch (err) {
1473
2004
  __privateSet(this, _error, err);
2005
+ if (err instanceof Error) {
2006
+ __privateSet(this, _syncState, __privateGet(this, _syncState).toErrorState(err));
2007
+ }
1474
2008
  if (__privateGet(this, _onError)) {
1475
2009
  const retryOpts = await __privateGet(this, _onError).call(this, err);
1476
2010
  const isRetryable = !(err instanceof MissingHeadersError);
@@ -1482,6 +2016,9 @@ start_fn = async function() {
1482
2016
  this.options.headers = __spreadValues(__spreadValues({}, (_b = this.options.headers) != null ? _b : {}), retryOpts.headers);
1483
2017
  }
1484
2018
  __privateSet(this, _error, null);
2019
+ if (__privateGet(this, _syncState) instanceof ErrorState) {
2020
+ __privateSet(this, _syncState, __privateGet(this, _syncState).retry());
2021
+ }
1485
2022
  __privateSet(this, _started, false);
1486
2023
  await __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
1487
2024
  return;
@@ -1489,38 +2026,45 @@ start_fn = async function() {
1489
2026
  if (err instanceof Error) {
1490
2027
  __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
1491
2028
  }
1492
- __privateSet(this, _connected, false);
1493
- (_c = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _c.call(this);
1494
- (_d = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _d.call(this);
2029
+ __privateMethod(this, _ShapeStream_instances, teardown_fn).call(this);
1495
2030
  return;
1496
2031
  }
1497
2032
  if (err instanceof Error) {
1498
2033
  __privateMethod(this, _ShapeStream_instances, sendErrorToSubscribers_fn).call(this, err);
1499
2034
  }
1500
- __privateSet(this, _connected, false);
1501
- (_e = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _e.call(this);
1502
- (_f = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _f.call(this);
2035
+ __privateMethod(this, _ShapeStream_instances, teardown_fn).call(this);
1503
2036
  throw err;
1504
2037
  }
2038
+ __privateMethod(this, _ShapeStream_instances, teardown_fn).call(this);
2039
+ };
2040
+ teardown_fn = function() {
2041
+ var _a, _b;
1505
2042
  __privateSet(this, _connected, false);
1506
- (_g = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _g.call(this);
1507
- (_h = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _h.call(this);
2043
+ (_a = __privateGet(this, _tickPromiseRejecter)) == null ? void 0 : _a.call(this);
2044
+ (_b = __privateGet(this, _unsubscribeFromWakeDetection)) == null ? void 0 : _b.call(this);
1508
2045
  };
1509
2046
  requestShape_fn = async function() {
1510
2047
  var _a, _b;
1511
- if (__privateGet(this, _state) === `pause-requested`) {
1512
- __privateSet(this, _state, `paused`);
2048
+ if (__privateGet(this, _pauseLock).isPaused) return;
2049
+ if (!this.options.subscribe && (((_a = this.options.signal) == null ? void 0 : _a.aborted) || __privateGet(this, _syncState).isUpToDate)) {
1513
2050
  return;
1514
2051
  }
1515
- if (!this.options.subscribe && (((_a = this.options.signal) == null ? void 0 : _a.aborted) || __privateGet(this, _isUpToDate))) {
1516
- return;
2052
+ let resumingFromPause = false;
2053
+ if (__privateGet(this, _syncState) instanceof PausedState) {
2054
+ resumingFromPause = true;
2055
+ __privateSet(this, _syncState, __privateGet(this, _syncState).resume());
1517
2056
  }
1518
- const resumingFromPause = __privateGet(this, _state) === `paused`;
1519
- __privateSet(this, _state, `active`);
1520
2057
  const { url, signal } = this.options;
1521
2058
  const { fetchUrl, requestHeaders } = await __privateMethod(this, _ShapeStream_instances, constructUrl_fn).call(this, url, resumingFromPause);
1522
2059
  const abortListener = await __privateMethod(this, _ShapeStream_instances, createAbortListener_fn).call(this, signal);
1523
2060
  const requestAbortController = __privateGet(this, _requestAbortController);
2061
+ if (__privateGet(this, _pauseLock).isPaused) {
2062
+ if (abortListener && signal) {
2063
+ signal.removeEventListener(`abort`, abortListener);
2064
+ }
2065
+ __privateSet(this, _requestAbortController, void 0);
2066
+ return;
2067
+ }
1524
2068
  try {
1525
2069
  await __privateMethod(this, _ShapeStream_instances, fetchShape_fn).call(this, {
1526
2070
  fetchUrl,
@@ -1535,10 +2079,6 @@ requestShape_fn = async function() {
1535
2079
  return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
1536
2080
  }
1537
2081
  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
2082
  return;
1543
2083
  }
1544
2084
  if (e instanceof StaleCacheError) {
@@ -1546,11 +2086,11 @@ requestShape_fn = async function() {
1546
2086
  }
1547
2087
  if (!(e instanceof FetchError)) throw e;
1548
2088
  if (e.status == 409) {
1549
- if (__privateGet(this, _shapeHandle)) {
2089
+ if (__privateGet(this, _syncState).handle) {
1550
2090
  const shapeKey = canonicalShapeKey(fetchUrl);
1551
- expiredShapesCache.markExpired(shapeKey, __privateGet(this, _shapeHandle));
2091
+ expiredShapesCache.markExpired(shapeKey, __privateGet(this, _syncState).handle);
1552
2092
  }
1553
- const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER] || `${__privateGet(this, _shapeHandle)}-next`;
2093
+ const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER] || `${__privateGet(this, _syncState).handle}-next`;
1554
2094
  __privateMethod(this, _ShapeStream_instances, reset_fn).call(this, newShapeHandle);
1555
2095
  await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, Array.isArray(e.json) ? e.json : [e.json]);
1556
2096
  return __privateMethod(this, _ShapeStream_instances, requestShape_fn).call(this);
@@ -1656,32 +2196,18 @@ constructUrl_fn = async function(url, resumingFromPause, subsetParams) {
1656
2196
  setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, encodedOrderBy);
1657
2197
  }
1658
2198
  }
1659
- fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, __privateGet(this, _lastOffset));
2199
+ __privateGet(this, _syncState).applyUrlParams(fetchUrl, {
2200
+ isSnapshotRequest: subsetParams !== void 0,
2201
+ // Don't long-poll when resuming from pause or refreshing — avoids
2202
+ // a 20s hold during which `isConnected` would be false
2203
+ canLongPoll: !__privateGet(this, _ShapeStream_instances, isRefreshing_get) && !resumingFromPause
2204
+ });
1660
2205
  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
2206
  const shapeKey = canonicalShapeKey(fetchUrl);
1675
2207
  const expiredHandle = expiredShapesCache.getExpiredHandle(shapeKey);
1676
2208
  if (expiredHandle) {
1677
2209
  fetchUrl.searchParams.set(EXPIRED_HANDLE_QUERY_PARAM, expiredHandle);
1678
2210
  }
1679
- if (__privateGet(this, _staleCacheBuster)) {
1680
- fetchUrl.searchParams.set(
1681
- CACHE_BUSTER_QUERY_PARAM,
1682
- __privateGet(this, _staleCacheBuster)
1683
- );
1684
- }
1685
2211
  fetchUrl.searchParams.sort();
1686
2212
  return {
1687
2213
  fetchUrl,
@@ -1704,108 +2230,100 @@ createAbortListener_fn = async function(signal) {
1704
2230
  }
1705
2231
  };
1706
2232
  onInitialResponse_fn = async function(response) {
1707
- var _a, _b, _c, _d;
2233
+ var _a, _b, _c;
1708
2234
  const { headers, status } = response;
1709
2235
  const shapeHandle = headers.get(SHAPE_HANDLE_HEADER);
1710
- if (shapeHandle) {
1711
- const shapeKey = __privateGet(this, _currentFetchUrl) ? canonicalShapeKey(__privateGet(this, _currentFetchUrl)) : null;
1712
- const expiredHandle = shapeKey ? expiredShapesCache.getExpiredHandle(shapeKey) : null;
1713
- if (shapeHandle !== expiredHandle) {
1714
- __privateSet(this, _shapeHandle, shapeHandle);
1715
- if (__privateGet(this, _staleCacheBuster)) {
1716
- __privateSet(this, _staleCacheBuster, void 0);
1717
- __privateSet(this, _staleCacheRetryCount, 0);
1718
- }
1719
- } else if (__privateGet(this, _shapeHandle) === void 0) {
1720
- __privateWrapper(this, _staleCacheRetryCount)._++;
1721
- await ((_a = response.body) == null ? void 0 : _a.cancel());
1722
- if (__privateGet(this, _staleCacheRetryCount) > __privateGet(this, _maxStaleCacheRetries)) {
1723
- throw new FetchError(
1724
- 502,
1725
- void 0,
1726
- void 0,
1727
- {},
1728
- (_c = (_b = __privateGet(this, _currentFetchUrl)) == null ? void 0 : _b.toString()) != null ? _c : ``,
1729
- `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`
1730
- );
1731
- }
1732
- console.warn(
1733
- `[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, _staleCacheRetryCount)}/${__privateGet(this, _maxStaleCacheRetries)}).`
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)}".`
2236
+ const shapeKey = __privateGet(this, _currentFetchUrl) ? canonicalShapeKey(__privateGet(this, _currentFetchUrl)) : null;
2237
+ const expiredHandle = shapeKey ? expiredShapesCache.getExpiredHandle(shapeKey) : null;
2238
+ const transition = __privateGet(this, _syncState).handleResponseMetadata({
2239
+ status,
2240
+ responseHandle: shapeHandle,
2241
+ responseOffset: headers.get(CHUNK_LAST_OFFSET_HEADER),
2242
+ responseCursor: headers.get(LIVE_CACHE_BUSTER_HEADER),
2243
+ responseSchema: getSchemaFromHeaders(headers),
2244
+ expiredHandle,
2245
+ now: Date.now(),
2246
+ maxStaleCacheRetries: __privateGet(this, _maxStaleCacheRetries),
2247
+ createCacheBuster: () => `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
2248
+ });
2249
+ __privateSet(this, _syncState, transition.state);
2250
+ if (transition.action === `stale-retry`) {
2251
+ await ((_a = response.body) == null ? void 0 : _a.cancel());
2252
+ if (transition.exceededMaxRetries) {
2253
+ throw new FetchError(
2254
+ 502,
2255
+ void 0,
2256
+ void 0,
2257
+ {},
2258
+ (_c = (_b = __privateGet(this, _currentFetchUrl)) == null ? void 0 : _b.toString()) != null ? _c : ``,
2259
+ `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
2260
  );
1743
- return;
1744
2261
  }
2262
+ console.warn(
2263
+ `[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)}).`
2264
+ );
2265
+ throw new StaleCacheError(
2266
+ `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.`
2267
+ );
1745
2268
  }
1746
- const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER);
1747
- if (lastOffset) {
1748
- __privateSet(this, _lastOffset, lastOffset);
1749
- }
1750
- const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER);
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());
2269
+ if (transition.action === `ignored`) {
2270
+ console.warn(
2271
+ `[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}".`
2272
+ );
2273
+ return false;
1757
2274
  }
2275
+ return true;
1758
2276
  };
1759
2277
  onMessages_fn = async function(batch, isSseMessage = false) {
1760
- var _a;
1761
- if (batch.length > 0) {
1762
- __privateSet(this, _isMidStream, true);
1763
- const lastMessage = batch[batch.length - 1];
1764
- if (isUpToDateMessage(lastMessage)) {
1765
- if (isSseMessage) {
1766
- const offset = getOffset(lastMessage);
1767
- if (offset) {
1768
- __privateSet(this, _lastOffset, offset);
1769
- }
1770
- }
1771
- __privateSet(this, _lastSyncedAt, Date.now());
1772
- __privateSet(this, _isUpToDate, true);
1773
- __privateSet(this, _isMidStream, false);
1774
- (_a = __privateGet(this, _midStreamPromiseResolver)) == null ? void 0 : _a.call(this);
1775
- if (__privateGet(this, _ShapeStream_instances, replayMode_get) && !isSseMessage) {
1776
- const currentCursor = __privateGet(this, _liveCacheBuster);
1777
- if (currentCursor === __privateGet(this, _lastSeenCursor)) {
1778
- __privateSet(this, _lastSeenCursor, void 0);
1779
- return;
1780
- }
1781
- }
1782
- __privateSet(this, _lastSeenCursor, void 0);
1783
- if (__privateGet(this, _currentFetchUrl)) {
1784
- const shapeKey = canonicalShapeKey(__privateGet(this, _currentFetchUrl));
1785
- upToDateTracker.recordUpToDate(shapeKey, __privateGet(this, _liveCacheBuster));
1786
- }
2278
+ if (batch.length === 0) return;
2279
+ const lastMessage = batch[batch.length - 1];
2280
+ const hasUpToDateMessage = isUpToDateMessage(lastMessage);
2281
+ const upToDateOffset = hasUpToDateMessage ? getOffset(lastMessage) : void 0;
2282
+ const transition = __privateGet(this, _syncState).handleMessageBatch({
2283
+ hasMessages: true,
2284
+ hasUpToDateMessage,
2285
+ isSse: isSseMessage,
2286
+ upToDateOffset,
2287
+ now: Date.now(),
2288
+ currentCursor: __privateGet(this, _syncState).liveCacheBuster
2289
+ });
2290
+ __privateSet(this, _syncState, transition.state);
2291
+ if (hasUpToDateMessage) {
2292
+ if (transition.suppressBatch) {
2293
+ return;
2294
+ }
2295
+ if (__privateGet(this, _currentFetchUrl)) {
2296
+ const shapeKey = canonicalShapeKey(__privateGet(this, _currentFetchUrl));
2297
+ upToDateTracker.recordUpToDate(
2298
+ shapeKey,
2299
+ __privateGet(this, _syncState).liveCacheBuster
2300
+ );
1787
2301
  }
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
2302
  }
2303
+ const messagesToProcess = batch.filter((message) => {
2304
+ if (isChangeMessage(message)) {
2305
+ return !__privateGet(this, _snapshotTracker).shouldRejectMessage(message);
2306
+ }
2307
+ return true;
2308
+ });
2309
+ await __privateMethod(this, _ShapeStream_instances, publish_fn).call(this, messagesToProcess);
1796
2310
  };
1797
2311
  fetchShape_fn = async function(opts) {
1798
2312
  var _a;
1799
2313
  __privateSet(this, _currentFetchUrl, opts.fetchUrl);
1800
- if (!__privateGet(this, _isUpToDate) && !__privateGet(this, _ShapeStream_instances, replayMode_get)) {
2314
+ if (!__privateGet(this, _syncState).isUpToDate && __privateGet(this, _syncState).canEnterReplayMode()) {
1801
2315
  const shapeKey = canonicalShapeKey(opts.fetchUrl);
1802
2316
  const lastSeenCursor = upToDateTracker.shouldEnterReplayMode(shapeKey);
1803
2317
  if (lastSeenCursor) {
1804
- __privateSet(this, _lastSeenCursor, lastSeenCursor);
2318
+ __privateSet(this, _syncState, __privateGet(this, _syncState).enterReplayMode(lastSeenCursor));
1805
2319
  }
1806
2320
  }
1807
2321
  const useSse = (_a = this.options.liveSse) != null ? _a : this.options.experimentalLiveSse;
1808
- if (__privateGet(this, _isUpToDate) && useSse && !__privateGet(this, _isRefreshing) && !opts.resumingFromPause && !__privateGet(this, _sseFallbackToLongPolling)) {
2322
+ if (__privateGet(this, _syncState).shouldUseSse({
2323
+ liveSseEnabled: !!useSse,
2324
+ isRefreshing: __privateGet(this, _ShapeStream_instances, isRefreshing_get),
2325
+ resumingFromPause: !!opts.resumingFromPause
2326
+ })) {
1809
2327
  opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`);
1810
2328
  opts.fetchUrl.searchParams.set(LIVE_SSE_QUERY_PARAM, `true`);
1811
2329
  return __privateMethod(this, _ShapeStream_instances, requestShapeSSE_fn).call(this, opts);
@@ -1819,8 +2337,9 @@ requestShapeLongPoll_fn = async function(opts) {
1819
2337
  headers
1820
2338
  });
1821
2339
  __privateSet(this, _connected, true);
1822
- await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
1823
- const schema = __privateGet(this, _schema);
2340
+ const shouldProcessBody = await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
2341
+ if (!shouldProcessBody) return;
2342
+ const schema = __privateGet(this, _syncState).schema;
1824
2343
  const res = await response.text();
1825
2344
  const messages = res || `[]`;
1826
2345
  const batch = __privateGet(this, _messageParser).parse(messages, schema);
@@ -1833,6 +2352,7 @@ requestShapeSSE_fn = async function(opts) {
1833
2352
  const sseHeaders = __spreadProps(__spreadValues({}, headers), {
1834
2353
  Accept: `text/event-stream`
1835
2354
  });
2355
+ let ignoredStaleResponse = false;
1836
2356
  try {
1837
2357
  let buffer = [];
1838
2358
  await fetchEventSource(fetchUrl.toString(), {
@@ -1840,11 +2360,15 @@ requestShapeSSE_fn = async function(opts) {
1840
2360
  fetch: fetch2,
1841
2361
  onopen: async (response) => {
1842
2362
  __privateSet(this, _connected, true);
1843
- await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
2363
+ const shouldProcessBody = await __privateMethod(this, _ShapeStream_instances, onInitialResponse_fn).call(this, response);
2364
+ if (!shouldProcessBody) {
2365
+ ignoredStaleResponse = true;
2366
+ throw new Error(`stale response ignored`);
2367
+ }
1844
2368
  },
1845
2369
  onmessage: (event) => {
1846
2370
  if (event.data) {
1847
- const schema = __privateGet(this, _schema);
2371
+ const schema = __privateGet(this, _syncState).schema;
1848
2372
  const message = __privateGet(this, _messageParser).parse(
1849
2373
  event.data,
1850
2374
  schema
@@ -1862,6 +2386,9 @@ requestShapeSSE_fn = async function(opts) {
1862
2386
  signal: requestAbortController.signal
1863
2387
  });
1864
2388
  } catch (error) {
2389
+ if (ignoredStaleResponse) {
2390
+ return;
2391
+ }
1865
2392
  if (requestAbortController.signal.aborted) {
1866
2393
  throw new FetchBackoffAbortError();
1867
2394
  }
@@ -1869,46 +2396,33 @@ requestShapeSSE_fn = async function(opts) {
1869
2396
  } finally {
1870
2397
  const connectionDuration = Date.now() - __privateGet(this, _lastSseConnectionStartTime);
1871
2398
  const wasAborted = requestAbortController.signal.aborted;
1872
- if (connectionDuration < __privateGet(this, _minSseConnectionDuration) && !wasAborted) {
1873
- __privateWrapper(this, _consecutiveShortSseConnections)._++;
1874
- if (__privateGet(this, _consecutiveShortSseConnections) >= __privateGet(this, _maxShortSseConnections)) {
1875
- __privateSet(this, _sseFallbackToLongPolling, true);
1876
- console.warn(
1877
- `[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.`
1878
- );
1879
- } else {
1880
- const maxDelay = Math.min(
1881
- __privateGet(this, _sseBackoffMaxDelay),
1882
- __privateGet(this, _sseBackoffBaseDelay) * Math.pow(2, __privateGet(this, _consecutiveShortSseConnections))
1883
- );
1884
- const delayMs = Math.floor(Math.random() * maxDelay);
1885
- await new Promise((resolve) => setTimeout(resolve, delayMs));
1886
- }
1887
- } else if (connectionDuration >= __privateGet(this, _minSseConnectionDuration)) {
1888
- __privateSet(this, _consecutiveShortSseConnections, 0);
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`);
2399
+ const transition = __privateGet(this, _syncState).handleSseConnectionClosed({
2400
+ connectionDuration,
2401
+ wasAborted,
2402
+ minConnectionDuration: __privateGet(this, _minSseConnectionDuration),
2403
+ maxShortConnections: __privateGet(this, _maxShortSseConnections)
2404
+ });
2405
+ __privateSet(this, _syncState, transition.state);
2406
+ if (transition.fellBackToLongPolling) {
2407
+ console.warn(
2408
+ `[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.`
2409
+ );
2410
+ } else if (transition.wasShortConnection) {
2411
+ const maxDelay = Math.min(
2412
+ __privateGet(this, _sseBackoffMaxDelay),
2413
+ __privateGet(this, _sseBackoffBaseDelay) * Math.pow(2, __privateGet(this, _syncState).consecutiveShortSseConnections)
2414
+ );
2415
+ const delayMs = Math.floor(Math.random() * maxDelay);
2416
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1907
2417
  }
1908
- __privateMethod(this, _ShapeStream_instances, start_fn).call(this);
1909
2418
  }
1910
2419
  };
1911
2420
  nextTick_fn = async function() {
2421
+ if (__privateGet(this, _pauseLock).isPaused) {
2422
+ throw new Error(
2423
+ `Cannot wait for next tick while PauseLock is held \u2014 this would deadlock because the request loop is paused`
2424
+ );
2425
+ }
1912
2426
  if (__privateGet(this, _tickPromise)) {
1913
2427
  return __privateGet(this, _tickPromise);
1914
2428
  }
@@ -1923,22 +2437,6 @@ nextTick_fn = async function() {
1923
2437
  });
1924
2438
  return __privateGet(this, _tickPromise);
1925
2439
  };
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
2440
  publish_fn = async function(messages) {
1943
2441
  __privateSet(this, _messageChain, __privateGet(this, _messageChain).then(
1944
2442
  () => Promise.all(
@@ -1967,9 +2465,9 @@ subscribeToVisibilityChanges_fn = function() {
1967
2465
  if (__privateMethod(this, _ShapeStream_instances, hasBrowserVisibilityAPI_fn).call(this)) {
1968
2466
  const visibilityHandler = () => {
1969
2467
  if (document.hidden) {
1970
- __privateMethod(this, _ShapeStream_instances, pause_fn).call(this);
2468
+ __privateGet(this, _pauseLock).acquire(`visibility`);
1971
2469
  } else {
1972
- __privateMethod(this, _ShapeStream_instances, resume_fn).call(this);
2470
+ __privateGet(this, _pauseLock).release(`visibility`);
1973
2471
  }
1974
2472
  };
1975
2473
  document.addEventListener(`visibilitychange`, visibilityHandler);
@@ -2000,11 +2498,11 @@ subscribeToWakeDetection_fn = function() {
2000
2498
  const elapsed = now - lastTickTime;
2001
2499
  lastTickTime = now;
2002
2500
  if (elapsed > INTERVAL_MS + WAKE_THRESHOLD_MS) {
2003
- if (__privateGet(this, _state) === `active` && __privateGet(this, _requestAbortController)) {
2004
- __privateSet(this, _isRefreshing, true);
2501
+ if (!__privateGet(this, _pauseLock).isPaused && __privateGet(this, _requestAbortController)) {
2502
+ __privateWrapper(this, _refreshCount)._++;
2005
2503
  __privateGet(this, _requestAbortController).abort(SYSTEM_WAKE);
2006
2504
  queueMicrotask(() => {
2007
- __privateSet(this, _isRefreshing, false);
2505
+ __privateWrapper(this, _refreshCount)._--;
2008
2506
  });
2009
2507
  }
2010
2508
  }
@@ -2021,18 +2519,9 @@ subscribeToWakeDetection_fn = function() {
2021
2519
  * shape handle
2022
2520
  */
2023
2521
  reset_fn = function(handle) {
2024
- __privateSet(this, _lastOffset, `-1`);
2025
- __privateSet(this, _liveCacheBuster, ``);
2026
- __privateSet(this, _shapeHandle, handle);
2027
- __privateSet(this, _isUpToDate, false);
2028
- __privateSet(this, _isMidStream, true);
2522
+ __privateSet(this, _syncState, __privateGet(this, _syncState).markMustRefetch(handle));
2029
2523
  __privateSet(this, _connected, false);
2030
- __privateSet(this, _schema, void 0);
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);
2524
+ __privateGet(this, _pauseLock).releaseAllMatching(`snapshot`);
2036
2525
  };
2037
2526
  buildSubsetBody_fn = function(opts) {
2038
2527
  var _a, _b, _c, _d;