cross-tab-worker-databus 0.20.87 → 0.20.88

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.
@@ -2331,7 +2331,7 @@ var DedupManager = class {
2331
2331
  };
2332
2332
 
2333
2333
  // src/core/version.ts
2334
- var SDK_VERSION = true ? "0.20.87" : "";
2334
+ var SDK_VERSION = true ? "0.20.88" : "";
2335
2335
 
2336
2336
  // src/core/data-bus.ts
2337
2337
  var DEFAULT_REPLAY_MAX_PER_TOPIC = 100;
@@ -2525,10 +2525,7 @@ var CrossTabDataBus = class {
2525
2525
  this.suspendTransport();
2526
2526
  },
2527
2527
  onResume: () => {
2528
- this.trace.event({ type: TRACE_EVENT_TYPE.LIFECYCLE, action: TRACE_LIFECYCLE_ACTION.RESUME });
2529
- this.trace.start();
2530
- this.startDedupSweep();
2531
- this.replayManager.start();
2528
+ this.resumeSuspendedResources();
2532
2529
  this.resumeTransport();
2533
2530
  },
2534
2531
  onDiagnostic: (event) => {
@@ -2558,7 +2555,11 @@ var CrossTabDataBus = class {
2558
2555
  if (!transportDown) return Promise.resolve();
2559
2556
  this.activeConfig = config;
2560
2557
  this.resetFailureState();
2561
- return this.reopenTransport();
2558
+ const resumingFromSuspend = this.suspended;
2559
+ if (resumingFromSuspend) this.resumeSuspendedResources();
2560
+ const opening2 = this.reopenTransport();
2561
+ if (resumingFromSuspend) this.cluster.start();
2562
+ return opening2;
2562
2563
  }
2563
2564
  this.started = true;
2564
2565
  this.stopping = false;
@@ -2681,6 +2682,7 @@ var CrossTabDataBus = class {
2681
2682
  this.transportReady = false;
2682
2683
  const chainedPendingStop = this.pendingStop;
2683
2684
  const isCurrentLifecycle = () => lifecycleEpoch === this.lifecycleEpoch;
2685
+ let startupInProgress = true;
2684
2686
  return before.catch(() => void 0).then(() => {
2685
2687
  if (!isCurrentLifecycle() || this.stopping || this.suspended) return;
2686
2688
  if (this.pendingStop === chainedPendingStop) this.pendingStop = null;
@@ -2691,13 +2693,16 @@ var CrossTabDataBus = class {
2691
2693
  if (isCurrentLifecycle()) this.handleTransportMessage(message);
2692
2694
  },
2693
2695
  onStatus: (status) => {
2694
- if (isCurrentLifecycle()) this.updateStatus(status);
2696
+ if (isCurrentLifecycle()) {
2697
+ this.updateStatus(status, status !== WORKER_STATUS.ERROR || !startupInProgress);
2698
+ }
2695
2699
  },
2696
2700
  onError: (error) => {
2697
2701
  if (isCurrentLifecycle()) this.reportError(error);
2698
2702
  }
2699
2703
  })
2700
2704
  ).then(() => {
2705
+ startupInProgress = false;
2701
2706
  if (!isCurrentLifecycle()) return;
2702
2707
  if (this.status === WORKER_STATUS.ERROR) {
2703
2708
  throw new Error("Transport failed during startup.");
@@ -2711,18 +2716,21 @@ var CrossTabDataBus = class {
2711
2716
  });
2712
2717
  }).catch((error) => {
2713
2718
  if (!isCurrentLifecycle()) throw error;
2719
+ startupInProgress = false;
2714
2720
  if (stopClusterOnFailure) this.started = false;
2715
2721
  if (!this.pendingStop) {
2716
2722
  this.pendingStop = this.createStopPromise();
2717
2723
  }
2718
2724
  this.transportReady = false;
2719
- this.updateStatus(WORKER_STATUS.ERROR);
2720
- this.reportError(error);
2721
2725
  if (stopClusterOnFailure) {
2722
2726
  this.stopping = true;
2723
2727
  this.cluster.stop();
2724
2728
  this.stopping = false;
2725
2729
  }
2730
+ this.recordError(error);
2731
+ this.startPromise = null;
2732
+ this.updateStatus(WORKER_STATUS.ERROR);
2733
+ this.notifyError(error);
2726
2734
  throw error;
2727
2735
  });
2728
2736
  }
@@ -3086,7 +3094,7 @@ var CrossTabDataBus = class {
3086
3094
  * Propagate a status change to the cluster, trace, and all registered
3087
3095
  * status handlers. On reconnect, re-subscribe any topics assigned to us.
3088
3096
  */
3089
- updateStatus(status) {
3097
+ updateStatus(status, notifyHandlers = true) {
3090
3098
  const previousStatus = this.status;
3091
3099
  this.status = status;
3092
3100
  if (status === WORKER_STATUS.CONNECTED) this.transportHasConnected = true;
@@ -3138,9 +3146,9 @@ var CrossTabDataBus = class {
3138
3146
  } else if (status === WORKER_STATUS.ERROR) {
3139
3147
  this.releaseRecoveryGate();
3140
3148
  }
3141
- this.invokeHandlers(this.statusHandlers, (handler) => handler(status));
3149
+ if (notifyHandlers) this.invokeHandlers(this.statusHandlers, (handler) => handler(status));
3142
3150
  }
3143
- reportError(error, source = FAILURE_SOURCE.TRANSPORT) {
3151
+ recordError(error, source = FAILURE_SOURCE.TRANSPORT) {
3144
3152
  const at = this.now();
3145
3153
  if (source === FAILURE_SOURCE.TRANSPORT) {
3146
3154
  this.lastError = error;
@@ -3160,8 +3168,14 @@ var CrossTabDataBus = class {
3160
3168
  type: TRACE_EVENT_TYPE.ERROR,
3161
3169
  source: source === FAILURE_SOURCE.TRANSPORT ? TRACE_ERROR_SOURCE.TRANSPORT : TRACE_ERROR_SOURCE.OPERATION
3162
3170
  });
3171
+ }
3172
+ notifyError(error) {
3163
3173
  this.invokeHandlers(this.errorHandlers, (handler) => handler(error), INVOKE_LABEL.ERROR_HANDLER);
3164
3174
  }
3175
+ reportError(error, source = FAILURE_SOURCE.TRANSPORT) {
3176
+ this.recordError(error, source);
3177
+ this.notifyError(error);
3178
+ }
3165
3179
  /** Report a persistence failure to the trace and the unified failure ledger,
3166
3180
  * unless it is a {@link PersistenceRetryCancelledError} cancellation from a
3167
3181
  * lifecycle transition (teardown should stay quiet). */
@@ -3224,6 +3238,15 @@ var CrossTabDataBus = class {
3224
3238
  }
3225
3239
  }
3226
3240
  }
3241
+ /** Resume the resources paused by a pagehide suspension. Both the native
3242
+ * pageshow path and explicit start() must run this so an explicit resume
3243
+ * cannot leave trace metrics and periodic cleanup timers permanently off. */
3244
+ resumeSuspendedResources() {
3245
+ this.trace.event({ type: TRACE_EVENT_TYPE.LIFECYCLE, action: TRACE_LIFECYCLE_ACTION.RESUME });
3246
+ this.trace.start();
3247
+ this.startDedupSweep();
3248
+ this.replayManager.start();
3249
+ }
3227
3250
  /**
3228
3251
  * Suspend the transport when the tab goes hidden. Stops the transport and
3229
3252
  * clears subscription state so it will be re-established on resume.
@@ -3236,8 +3259,11 @@ var CrossTabDataBus = class {
3236
3259
  this.transportReady = false;
3237
3260
  this.transportSubscribedTopics.clear();
3238
3261
  this.updateStatus(WORKER_STATUS.DISCONNECTED);
3239
- if (this.pendingStop) return;
3240
- const pending = this.startPromise ?? Promise.resolve();
3262
+ if (this.pendingStop && (this.startPromise === null || this.startPromise === this.pendingStop)) {
3263
+ this.startPromise = this.pendingStop;
3264
+ return;
3265
+ }
3266
+ const pending = this.startPromise ?? this.pendingStop ?? Promise.resolve();
3241
3267
  const stopping = pending.catch(() => void 0).then(() => this.transport.stop()).catch((error) => this.reportError(error));
3242
3268
  this.startPromise = stopping;
3243
3269
  this.pendingStop = stopping;
@@ -3332,10 +3358,17 @@ var CrossTabDataBus = class {
3332
3358
  ready = this.reopenTransport();
3333
3359
  }
3334
3360
  if (!ready || this.stopping) return;
3335
- void ready.then(() => {
3336
- if (!this.started || this.stopping || this.suspended) return;
3337
- return operation();
3338
- }).catch((error) => this.reportError(error));
3361
+ void ready.then(
3362
+ () => {
3363
+ if (!this.started || this.stopping || this.suspended) return;
3364
+ return operation();
3365
+ },
3366
+ // The opening promise reports its own lifecycle failure through
3367
+ // openTransport(). Swallowing it here prevents a stale startup
3368
+ // rejection from being recorded again after an onStatus/onError
3369
+ // callback has already started and reset the ledger for a retry.
3370
+ () => void 0
3371
+ ).catch((error) => this.reportError(error));
3339
3372
  }
3340
3373
  /**
3341
3374
  * Publications started after teardown begins cannot reach any transport.