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