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