@rebasepro/client 0.9.1-canary.97e305f → 0.9.1-canary.a57c262

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -1397,11 +1397,9 @@ var ClientStorageSourceRegistry = class ClientStorageSourceRegistry {
1397
1397
  function extractMessageError(message) {
1398
1398
  const payload = message.payload;
1399
1399
  const errPayload = payload?.error;
1400
- const errorMessage = typeof errPayload === "object" ? errPayload.message : payload?.message || (typeof errPayload === "string" ? errPayload : void 0) || message.error || "Unknown error";
1401
- const errorCode = typeof errPayload === "object" ? errPayload.code : payload?.code;
1402
1400
  return {
1403
- errorMessage: typeof errorMessage === "string" ? errorMessage : errorMessage == null ? "Unknown error" : JSON.stringify(errorMessage),
1404
- errorCode
1401
+ errorMessage: typeof errPayload === "object" ? errPayload.message : payload?.message || (typeof errPayload === "string" ? errPayload : void 0) || message.error || "Unknown error",
1402
+ errorCode: typeof errPayload === "object" ? errPayload.code : payload?.code
1405
1403
  };
1406
1404
  }
1407
1405
  /**
@@ -1437,7 +1435,6 @@ var RebaseWebSocketClient = class {
1437
1435
  isConnected = false;
1438
1436
  messageQueue = [];
1439
1437
  requestTimeoutMs = 3e4;
1440
- subscriptionTimeoutMs = 3e4;
1441
1438
  reconnectTimeout = null;
1442
1439
  isAuthenticated = false;
1443
1440
  authPromise = null;
@@ -1543,7 +1540,6 @@ var RebaseWebSocketClient = class {
1543
1540
  this.emit(wasReconnect ? "reconnect" : "connect");
1544
1541
  this.processMessageQueue();
1545
1542
  if (wasReconnect) this.resubscribeAll();
1546
- this.armPendingSubscribeWatchdogs();
1547
1543
  };
1548
1544
  this.ws.onmessage = (event) => {
1549
1545
  try {
@@ -1558,7 +1554,6 @@ var RebaseWebSocketClient = class {
1558
1554
  this.isConnected = false;
1559
1555
  this.isAuthenticated = false;
1560
1556
  this.authPromise = null;
1561
- this.suspendSubscribeWatchdogs();
1562
1557
  this.emit("disconnect");
1563
1558
  for (const [reqId, request] of this.pendingRequests.entries()) {
1564
1559
  if (reqId.startsWith("auth_")) request.reject(/* @__PURE__ */ new Error("Connection closed during authentication"));
@@ -1590,7 +1585,6 @@ var RebaseWebSocketClient = class {
1590
1585
  attemptReconnect() {
1591
1586
  if (this.reconnectAttempts >= this.maxReconnectAttempts) {
1592
1587
  console.error("Max reconnection attempts reached");
1593
- this.failAllPendingSubscriptions(new RebaseApiError$1("Connection lost", { code: "CONNECTION_LOST" }));
1594
1588
  return;
1595
1589
  }
1596
1590
  this.reconnectAttempts++;
@@ -1645,18 +1639,29 @@ var RebaseWebSocketClient = class {
1645
1639
  subscription.backendSubscriptionId = newBackendId;
1646
1640
  backendKeyMap.delete(oldBackendId);
1647
1641
  backendKeyMap.set(newBackendId, subscriptionKey);
1648
- if (messageType === "subscribe_collection") this.sendCollectionSubscribe(subscriptionKey);
1649
- else this.sendEntitySubscribe(subscriptionKey);
1650
- return;
1642
+ this.sendMessage({
1643
+ type: messageType,
1644
+ payload: {
1645
+ ...subscription.props,
1646
+ subscriptionId: newBackendId
1647
+ }
1648
+ }).catch((error) => {
1649
+ console.error(`[WS] Failed to re-subscribe ${idPrefix} after auth refresh:`, subscriptionKey, error);
1650
+ subscription.callbacks.forEach((callback) => {
1651
+ if (callback.onError) callback.onError(error);
1652
+ });
1653
+ });
1654
+ } else {
1655
+ const { errorMessage, errorCode } = extractMessageError(message);
1656
+ const error = new RebaseApiError$1(errorMessage, { code: errorCode });
1657
+ subscription.callbacks.forEach((callback) => {
1658
+ if (callback.onError) callback.onError(error);
1659
+ });
1651
1660
  }
1652
- const { errorMessage, errorCode } = extractMessageError(message);
1653
- const error = new RebaseApiError$1(errorMessage, { code: errorCode });
1654
- if (messageType === "subscribe_collection") this.failCollectionSubscription(subscriptionKey, error);
1655
- else this.failEntitySubscription(subscriptionKey, error);
1656
1661
  }).catch((err) => {
1657
- const error = err instanceof Error ? err : new Error(String(err));
1658
- if (messageType === "subscribe_collection") this.failCollectionSubscription(subscriptionKey, error);
1659
- else this.failEntitySubscription(subscriptionKey, error);
1662
+ subscription.callbacks.forEach((callback) => {
1663
+ if (callback.onError) callback.onError(err);
1664
+ });
1660
1665
  });
1661
1666
  }
1662
1667
  handleWebSocketMessage(message) {
@@ -1697,9 +1702,6 @@ var RebaseWebSocketClient = class {
1697
1702
  collectionSub.latestData = rows;
1698
1703
  collectionSub.lastUpdated = Date.now();
1699
1704
  collectionSub.isInitialDataReceived = true;
1700
- if (collectionSub.subscribeTimeout) clearTimeout(collectionSub.subscribeTimeout);
1701
- collectionSub.subscribeTimeout = void 0;
1702
- collectionSub.subscribeInFlight = false;
1703
1705
  collectionSub.callbacks.forEach((callback) => {
1704
1706
  try {
1705
1707
  callback.onUpdate(rows);
@@ -1755,9 +1757,6 @@ var RebaseWebSocketClient = class {
1755
1757
  entitySub.latestData = row;
1756
1758
  entitySub.lastUpdated = Date.now();
1757
1759
  entitySub.isInitialDataReceived = true;
1758
- if (entitySub.subscribeTimeout) clearTimeout(entitySub.subscribeTimeout);
1759
- entitySub.subscribeTimeout = void 0;
1760
- entitySub.subscribeInFlight = false;
1761
1760
  entitySub.callbacks.forEach((callback) => {
1762
1761
  try {
1763
1762
  callback.onUpdate(row);
@@ -1779,9 +1778,6 @@ var RebaseWebSocketClient = class {
1779
1778
  this.resubscribeAfterAuthRefresh(message, collectionSub, collectionKey, "collection", this.backendToCollectionKey, "subscribe_collection");
1780
1779
  return;
1781
1780
  }
1782
- if (collectionSub.subscribeTimeout) clearTimeout(collectionSub.subscribeTimeout);
1783
- collectionSub.subscribeTimeout = void 0;
1784
- collectionSub.subscribeInFlight = false;
1785
1781
  const { errorMessage, errorCode } = extractMessageError(message);
1786
1782
  const error = new RebaseApiError$1(errorMessage, { code: errorCode });
1787
1783
  collectionSub.callbacks.forEach((callback) => {
@@ -1798,9 +1794,6 @@ var RebaseWebSocketClient = class {
1798
1794
  this.resubscribeAfterAuthRefresh(message, entitySub, entityKey, "row", this.backendToEntityKey, "subscribe_one");
1799
1795
  return;
1800
1796
  }
1801
- if (entitySub.subscribeTimeout) clearTimeout(entitySub.subscribeTimeout);
1802
- entitySub.subscribeTimeout = void 0;
1803
- entitySub.subscribeInFlight = false;
1804
1797
  const { errorMessage, errorCode } = extractMessageError(message);
1805
1798
  const error = new RebaseApiError$1(errorMessage, { code: errorCode });
1806
1799
  entitySub.callbacks.forEach((callback) => {
@@ -2149,12 +2142,9 @@ var RebaseWebSocketClient = class {
2149
2142
  console.error("Error in collection subscription callback:", error);
2150
2143
  if (onError) onError(error instanceof Error ? error : new Error(String(error)));
2151
2144
  }
2152
- else if (!existingSubscription.subscribeInFlight) this.sendCollectionSubscribe(subscriptionKey);
2153
2145
  return () => {
2154
2146
  callbackMap.delete(callbackId);
2155
2147
  if (callbackMap.size === 0) {
2156
- if (this.collectionSubscriptions.get(subscriptionKey) !== existingSubscription) return;
2157
- if (existingSubscription.subscribeTimeout) clearTimeout(existingSubscription.subscribeTimeout);
2158
2148
  this.collectionSubscriptions.delete(subscriptionKey);
2159
2149
  this.backendToCollectionKey.delete(existingSubscription.backendSubscriptionId);
2160
2150
  if (this.isConnected && this.ws) this.sendMessage({
@@ -2176,14 +2166,21 @@ var RebaseWebSocketClient = class {
2176
2166
  props
2177
2167
  });
2178
2168
  this.backendToCollectionKey.set(backendSubscriptionId, subscriptionKey);
2179
- this.sendCollectionSubscribe(subscriptionKey);
2169
+ this.sendMessage({
2170
+ type: "subscribe_collection",
2171
+ payload: {
2172
+ ...props,
2173
+ subscriptionId: backendSubscriptionId
2174
+ }
2175
+ }).catch((error) => {
2176
+ if (onError) onError(error);
2177
+ });
2180
2178
  return () => {
2181
2179
  const subscription = this.collectionSubscriptions.get(subscriptionKey);
2182
2180
  if (subscription) {
2183
2181
  const callbacks = subscription.callbacks;
2184
2182
  callbacks.delete(callbackId);
2185
2183
  if (callbacks.size === 0) {
2186
- if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);
2187
2184
  this.collectionSubscriptions.delete(subscriptionKey);
2188
2185
  this.backendToCollectionKey.delete(subscription.backendSubscriptionId);
2189
2186
  if (this.isConnected && this.ws) this.sendMessage({
@@ -2210,12 +2207,9 @@ var RebaseWebSocketClient = class {
2210
2207
  console.error("Error in row subscription callback:", error);
2211
2208
  if (onError) onError(error instanceof Error ? error : new Error(String(error)));
2212
2209
  }
2213
- else if (!existingSubscription.subscribeInFlight) this.sendEntitySubscribe(subscriptionKey);
2214
2210
  return () => {
2215
2211
  callbackMap.delete(callbackId);
2216
2212
  if (callbackMap.size === 0) {
2217
- if (this.singleSubscriptions.get(subscriptionKey) !== existingSubscription) return;
2218
- if (existingSubscription.subscribeTimeout) clearTimeout(existingSubscription.subscribeTimeout);
2219
2213
  this.singleSubscriptions.delete(subscriptionKey);
2220
2214
  this.backendToEntityKey.delete(existingSubscription.backendSubscriptionId);
2221
2215
  if (this.isConnected && this.ws) this.sendMessage({
@@ -2237,7 +2231,15 @@ var RebaseWebSocketClient = class {
2237
2231
  props
2238
2232
  });
2239
2233
  this.backendToEntityKey.set(backendSubscriptionId, subscriptionKey);
2240
- this.sendEntitySubscribe(subscriptionKey);
2234
+ this.sendMessage({
2235
+ type: "subscribe_one",
2236
+ payload: {
2237
+ ...props,
2238
+ subscriptionId: backendSubscriptionId
2239
+ }
2240
+ }).catch((error) => {
2241
+ if (onError) onError(error);
2242
+ });
2241
2243
  return () => {
2242
2244
  const subscription = this.singleSubscriptions.get(subscriptionKey);
2243
2245
  if (subscription) {
@@ -2255,157 +2257,6 @@ var RebaseWebSocketClient = class {
2255
2257
  };
2256
2258
  }
2257
2259
  /**
2258
- * Send a `subscribe_collection` for an already-registered subscription and
2259
- * arm its watchdog.
2260
- *
2261
- * Every path that registers a collection subscription goes through here, so
2262
- * that a subscribe which never lands — a rejected send, or a server that
2263
- * never answers — always ends up in `failCollectionSubscription` rather than
2264
- * leaving the entry parked with `isInitialDataReceived === false` forever.
2265
- */
2266
- sendCollectionSubscribe(subscriptionKey) {
2267
- const subscription = this.collectionSubscriptions.get(subscriptionKey);
2268
- if (!subscription) return;
2269
- const backendSubscriptionId = subscription.backendSubscriptionId;
2270
- subscription.subscribeInFlight = true;
2271
- if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);
2272
- subscription.subscribeTimeout = void 0;
2273
- if (this.isConnected) this.sendCollectionSubscribeWatchdog(subscriptionKey);
2274
- this.sendMessage({
2275
- type: "subscribe_collection",
2276
- payload: {
2277
- ...subscription.props,
2278
- subscriptionId: backendSubscriptionId
2279
- }
2280
- }).catch((error) => {
2281
- const current = this.collectionSubscriptions.get(subscriptionKey);
2282
- if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;
2283
- this.failCollectionSubscription(subscriptionKey, error instanceof Error ? error : new Error(String(error)));
2284
- });
2285
- }
2286
- /** The `listenOne` counterpart of {@link sendCollectionSubscribe}. */
2287
- sendEntitySubscribe(subscriptionKey) {
2288
- const subscription = this.singleSubscriptions.get(subscriptionKey);
2289
- if (!subscription) return;
2290
- const backendSubscriptionId = subscription.backendSubscriptionId;
2291
- subscription.subscribeInFlight = true;
2292
- if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);
2293
- subscription.subscribeTimeout = void 0;
2294
- if (this.isConnected) this.sendEntitySubscribeWatchdog(subscriptionKey);
2295
- this.sendMessage({
2296
- type: "subscribe_one",
2297
- payload: {
2298
- ...subscription.props,
2299
- subscriptionId: backendSubscriptionId
2300
- }
2301
- }).catch((error) => {
2302
- const current = this.singleSubscriptions.get(subscriptionKey);
2303
- if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;
2304
- this.failEntitySubscription(subscriptionKey, error instanceof Error ? error : new Error(String(error)));
2305
- });
2306
- }
2307
- /**
2308
- * Report a subscribe failure to every listener and drop the registration.
2309
- *
2310
- * Dropping it is the point: the callbacks stay live (their components are
2311
- * still mounted and have been told), but the next `listenCollection` for
2312
- * these params finds no entry and issues a fresh subscribe instead of
2313
- * silently attaching to a dead one.
2314
- */
2315
- failCollectionSubscription(subscriptionKey, error) {
2316
- const subscription = this.collectionSubscriptions.get(subscriptionKey);
2317
- if (!subscription) return;
2318
- if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);
2319
- subscription.subscribeInFlight = false;
2320
- this.collectionSubscriptions.delete(subscriptionKey);
2321
- this.backendToCollectionKey.delete(subscription.backendSubscriptionId);
2322
- subscription.callbacks.forEach((callback) => {
2323
- if (callback.onError) try {
2324
- callback.onError(error);
2325
- } catch (callbackError) {
2326
- console.error("Error in collection subscription error callback:", callbackError);
2327
- }
2328
- });
2329
- }
2330
- /** The `listenOne` counterpart of {@link failCollectionSubscription}. */
2331
- failEntitySubscription(subscriptionKey, error) {
2332
- const subscription = this.singleSubscriptions.get(subscriptionKey);
2333
- if (!subscription) return;
2334
- if (subscription.subscribeTimeout) clearTimeout(subscription.subscribeTimeout);
2335
- subscription.subscribeInFlight = false;
2336
- this.singleSubscriptions.delete(subscriptionKey);
2337
- this.backendToEntityKey.delete(subscription.backendSubscriptionId);
2338
- subscription.callbacks.forEach((callback) => {
2339
- if (callback.onError) try {
2340
- callback.onError(error);
2341
- } catch (callbackError) {
2342
- console.error("Error in row subscription error callback:", callbackError);
2343
- }
2344
- });
2345
- }
2346
- /**
2347
- * Stop the watchdogs without failing anything — used when the socket drops,
2348
- * since the reconnect path re-subscribes everything anyway and a watchdog
2349
- * firing mid-reconnect would tear down healthy subscriptions.
2350
- */
2351
- suspendSubscribeWatchdogs() {
2352
- for (const sub of this.collectionSubscriptions.values()) {
2353
- if (sub.subscribeTimeout) clearTimeout(sub.subscribeTimeout);
2354
- sub.subscribeTimeout = void 0;
2355
- sub.subscribeInFlight = false;
2356
- }
2357
- for (const sub of this.singleSubscriptions.values()) {
2358
- if (sub.subscribeTimeout) clearTimeout(sub.subscribeTimeout);
2359
- sub.subscribeTimeout = void 0;
2360
- sub.subscribeInFlight = false;
2361
- }
2362
- }
2363
- /**
2364
- * Arm watchdogs for subscribes that were requested while offline and have
2365
- * just been flushed to the socket. Their timers were deliberately not set at
2366
- * request time, so without this they would have no timeout at all.
2367
- */
2368
- armPendingSubscribeWatchdogs() {
2369
- for (const [key, sub] of this.collectionSubscriptions.entries()) if (sub.subscribeInFlight && !sub.subscribeTimeout) this.sendCollectionSubscribeWatchdog(key);
2370
- for (const [key, sub] of this.singleSubscriptions.entries()) if (sub.subscribeInFlight && !sub.subscribeTimeout) this.sendEntitySubscribeWatchdog(key);
2371
- }
2372
- sendCollectionSubscribeWatchdog(subscriptionKey) {
2373
- const subscription = this.collectionSubscriptions.get(subscriptionKey);
2374
- if (!subscription) return;
2375
- const backendSubscriptionId = subscription.backendSubscriptionId;
2376
- subscription.subscribeTimeout = setTimeout(() => {
2377
- const current = this.collectionSubscriptions.get(subscriptionKey);
2378
- if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;
2379
- if (!current.subscribeInFlight) return;
2380
- this.failCollectionSubscription(subscriptionKey, new RebaseApiError$1("Subscription timed out", { code: "SUBSCRIPTION_TIMEOUT" }));
2381
- }, this.subscriptionTimeoutMs);
2382
- }
2383
- sendEntitySubscribeWatchdog(subscriptionKey) {
2384
- const subscription = this.singleSubscriptions.get(subscriptionKey);
2385
- if (!subscription) return;
2386
- const backendSubscriptionId = subscription.backendSubscriptionId;
2387
- subscription.subscribeTimeout = setTimeout(() => {
2388
- const current = this.singleSubscriptions.get(subscriptionKey);
2389
- if (!current || current.backendSubscriptionId !== backendSubscriptionId) return;
2390
- if (!current.subscribeInFlight) return;
2391
- this.failEntitySubscription(subscriptionKey, new RebaseApiError$1("Subscription timed out", { code: "SUBSCRIPTION_TIMEOUT" }));
2392
- }, this.subscriptionTimeoutMs);
2393
- }
2394
- /**
2395
- * Fail every subscription that never received data. Called when reconnection
2396
- * is given up on, so views surface an error instead of spinning forever.
2397
- */
2398
- failAllPendingSubscriptions(error) {
2399
- for (const key of [...this.collectionSubscriptions.keys()]) {
2400
- const sub = this.collectionSubscriptions.get(key);
2401
- if (sub && !sub.isInitialDataReceived) this.failCollectionSubscription(key, error);
2402
- }
2403
- for (const key of [...this.singleSubscriptions.keys()]) {
2404
- const sub = this.singleSubscriptions.get(key);
2405
- if (sub && !sub.isInitialDataReceived) this.failEntitySubscription(key, error);
2406
- }
2407
- }
2408
- /**
2409
2260
  * Re-send all active subscriptions to the backend after a reconnect.
2410
2261
  * The server wipes subscription state when a client disconnects, so
2411
2262
  * we need to re-register everything to resume receiving updates.
@@ -2418,7 +2269,15 @@ var RebaseWebSocketClient = class {
2418
2269
  sub.backendSubscriptionId = newBackendId;
2419
2270
  this.backendToCollectionKey.delete(oldBackendId);
2420
2271
  this.backendToCollectionKey.set(newBackendId, key);
2421
- this.sendCollectionSubscribe(key);
2272
+ this.sendMessage({
2273
+ type: "subscribe_collection",
2274
+ payload: {
2275
+ ...sub.props,
2276
+ subscriptionId: newBackendId
2277
+ }
2278
+ }).catch((error) => {
2279
+ console.error("[WS] Failed to re-subscribe collection:", key, error);
2280
+ });
2422
2281
  }
2423
2282
  for (const [key, sub] of this.singleSubscriptions.entries()) {
2424
2283
  const oldBackendId = sub.backendSubscriptionId;
@@ -2426,7 +2285,15 @@ var RebaseWebSocketClient = class {
2426
2285
  sub.backendSubscriptionId = newBackendId;
2427
2286
  this.backendToEntityKey.delete(oldBackendId);
2428
2287
  this.backendToEntityKey.set(newBackendId, key);
2429
- this.sendEntitySubscribe(key);
2288
+ this.sendMessage({
2289
+ type: "subscribe_one",
2290
+ payload: {
2291
+ ...sub.props,
2292
+ subscriptionId: newBackendId
2293
+ }
2294
+ }).catch((error) => {
2295
+ console.error("[WS] Failed to re-subscribe row:", key, error);
2296
+ });
2430
2297
  }
2431
2298
  }
2432
2299
  createCollectionSubscriptionKey(props) {