cross-tab-worker-databus 0.20.93 → 0.20.95

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.
@@ -184,6 +184,7 @@ function createStorageEventChannel(options) {
184
184
  if (!storage || !win) return null;
185
185
  const key = `${STORAGE_CHANNEL_PREFIX}${name}`;
186
186
  const listeners = /* @__PURE__ */ new Set();
187
+ const senderId = randomId();
187
188
  let sequence = 0;
188
189
  const onStorage = (event) => {
189
190
  if (event.key !== key || event.newValue === null) return;
@@ -196,7 +197,12 @@ function createStorageEventChannel(options) {
196
197
  return;
197
198
  }
198
199
  const event_ = { data: message };
199
- for (const listener of [...listeners]) listener(event_);
200
+ for (const listener of [...listeners]) {
201
+ try {
202
+ listener(event_);
203
+ } catch {
204
+ }
205
+ }
200
206
  };
201
207
  win.addEventListener("storage", onStorage);
202
208
  let closed = false;
@@ -210,7 +216,7 @@ function createStorageEventChannel(options) {
210
216
  postMessage(message) {
211
217
  if (closed) return;
212
218
  sequence += 1;
213
- storage.setItem(key, JSON.stringify({ seq: sequence, message }));
219
+ storage.setItem(key, JSON.stringify({ senderId, seq: sequence, message }));
214
220
  },
215
221
  close() {
216
222
  closed = true;
@@ -536,11 +542,11 @@ var BatchingStorageWriter = class {
536
542
  if (typeof queueMicrotask === "function") queueMicrotask(flush);
537
543
  else setTimeout(flush, 0);
538
544
  }
539
- // Schedule a single retry timer. The guard ensures only one retry is in
540
- // flight at a time; subsequent scheduleRetry calls during the wait are
541
- // no-ops because the first retry will re-flush all pending keys together.
545
+ // Arm the single backoff timer for the pass that just failed. Exactly one
546
+ // retry can be in flight because flush() the only caller — cancels any
547
+ // armed retry on entry and stops at the first failing key, so this always
548
+ // runs with `retryHandle` cleared.
542
549
  scheduleRetry() {
543
- if (this.retryHandle !== null) return;
544
550
  this.retryHandle = setTimeout(() => {
545
551
  this.retryHandle = null;
546
552
  this.flush();
@@ -741,9 +747,8 @@ var WorkerClusterRuntime = class {
741
747
  touchRouteOwnerCache(topicKey, value) {
742
748
  if (this.routeOwnerCache.has(topicKey)) this.routeOwnerCache.delete(topicKey);
743
749
  this.routeOwnerCache.set(topicKey, value);
744
- while (this.routeOwnerCache.size > this.routeOwnerCacheMax) {
745
- const oldest = this.routeOwnerCache.keys().next().value;
746
- if (oldest === void 0) break;
750
+ for (const oldest of this.routeOwnerCache.keys()) {
751
+ if (this.routeOwnerCache.size <= this.routeOwnerCacheMax) break;
747
752
  this.routeOwnerCache.delete(oldest);
748
753
  }
749
754
  }
@@ -2401,9 +2406,8 @@ var DedupManager = class {
2401
2406
  this.accepted += 1;
2402
2407
  this.windowAccepted += 1;
2403
2408
  this.trace.recordDedupAccepted();
2404
- while (this.seenMessageIds.size > this.maxEntries) {
2405
- const oldest = this.seenMessageIds.keys().next().value;
2406
- if (oldest === void 0) break;
2409
+ for (const oldest of this.seenMessageIds.keys()) {
2410
+ if (this.seenMessageIds.size <= this.maxEntries) break;
2407
2411
  this.seenMessageIds.delete(oldest);
2408
2412
  }
2409
2413
  return false;
@@ -2464,7 +2468,7 @@ var DedupManager = class {
2464
2468
  };
2465
2469
 
2466
2470
  // src/core/version.ts
2467
- var SDK_VERSION = true ? "0.20.93" : "";
2471
+ var SDK_VERSION = true ? "0.20.95" : "";
2468
2472
 
2469
2473
  // src/core/data-bus.ts
2470
2474
  var DEFAULT_REPLAY_MAX_PER_TOPIC = 100;
@@ -3920,12 +3924,13 @@ var CentrifugeWorkerTransport = class {
3920
3924
  heartbeatHandle = null;
3921
3925
  localSession = null;
3922
3926
  handlers = null;
3923
- // Monotonically increasing counter, bumped each time a backend is created.
3924
- // Used to ignore late error events from a superseded Worker.
3927
+ // Monotonically increasing counter, bumped each time a backend is created or
3928
+ // the transport stops. Only the asynchronous credential bridge compares it:
3929
+ // a provider may settle after the Worker it was answering is gone. Worker
3930
+ // error events need no such check — stop() and onWorkerFailed() remove those
3931
+ // listeners before the generation moves on, so a superseded backend can no
3932
+ // longer reach this object at all.
3925
3933
  generation = 0;
3926
- // Generation captured when the current backend was created. Error handlers
3927
- // only act when the backend that registered them is still current.
3928
- backendGeneration = 0;
3929
3934
  get diagnosticsBackend() {
3930
3935
  return this.backend ?? "uninitialized";
3931
3936
  }
@@ -4018,7 +4023,7 @@ var CentrifugeWorkerTransport = class {
4018
4023
  }
4019
4024
  /** Create and initialise a dedicated Worker, then send the INIT message. */
4020
4025
  startDedicatedWorker(input) {
4021
- this.backendGeneration = ++this.generation;
4026
+ this.generation += 1;
4022
4027
  const worker = (this.workerFactory ?? createDefaultWorker)();
4023
4028
  this.worker = worker;
4024
4029
  worker.addEventListener("message", this.handleMessage);
@@ -4027,7 +4032,7 @@ var CentrifugeWorkerTransport = class {
4027
4032
  }
4028
4033
  /** Create and initialise a SharedWorker, open the MessagePort, and send the INIT message. */
4029
4034
  startSharedWorker(input) {
4030
- this.backendGeneration = ++this.generation;
4035
+ this.generation += 1;
4031
4036
  const shared = (this.sharedWorkerFactory ?? createDefaultSharedWorker)();
4032
4037
  this.sharedWorker = shared;
4033
4038
  const port = shared.port;
@@ -4097,9 +4102,10 @@ var CentrifugeWorkerTransport = class {
4097
4102
  }
4098
4103
  /** Handle a Worker-level failure (crash, message decode error). Discards the
4099
4104
  * dead backend so a later start()/reopen can rebuild from scratch, and
4100
- * signals an error status so the DataBus can trigger recovery.
4101
- * Only invoked when the generation guard confirms the failing backend is
4102
- * still current late errors from a superseded Worker are silently dropped. */
4105
+ * signals an error status so the DataBus can trigger recovery. A superseded
4106
+ * backend cannot reach this: its listeners are removed before the transport
4107
+ * moves on, which is what keeps late Worker errors from tearing down a fresh
4108
+ * session (pinned by 'ignores error events from a superseded worker'). */
4103
4109
  onWorkerFailed(message) {
4104
4110
  this.worker?.removeEventListener("message", this.handleMessage);
4105
4111
  this.worker?.removeEventListener("error", this.handleWorkerError);
@@ -4130,15 +4136,12 @@ var CentrifugeWorkerTransport = class {
4130
4136
  this.heartbeatHandle = null;
4131
4137
  }
4132
4138
  handleWorkerError = () => {
4133
- if (this.generation !== this.backendGeneration) return;
4134
4139
  this.onWorkerFailed("Centrifuge worker failed.");
4135
4140
  };
4136
4141
  handlePortError = () => {
4137
- if (this.generation !== this.backendGeneration) return;
4138
4142
  this.onWorkerFailed("Centrifuge shared worker message decoding failed.");
4139
4143
  };
4140
4144
  handleSharedWorkerError = () => {
4141
- if (this.generation !== this.backendGeneration) return;
4142
4145
  this.onWorkerFailed("Centrifuge shared worker failed.");
4143
4146
  };
4144
4147
  /** Clear the Worker/port/backend references after a failure or stop. */