cross-tab-worker-databus 0.21.42 → 0.21.43

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.
@@ -2495,6 +2495,8 @@ var DedupManager = class {
2495
2495
  seenMessageIds = /* @__PURE__ */ new Map();
2496
2496
  sweepTimer = null;
2497
2497
  windowStartedAt = 0;
2498
+ /** The most recent finite reading of `now`, and the fallback for a broken one. */
2499
+ lastFiniteNow = 0;
2498
2500
  windowAccepted = 0;
2499
2501
  suppressed = 0;
2500
2502
  accepted = 0;
@@ -2506,14 +2508,46 @@ var DedupManager = class {
2506
2508
  this.sweepMs = options.sweepMs;
2507
2509
  this.now = options.now;
2508
2510
  this.trace = options.trace;
2509
- this.windowStartedAt = this.now();
2511
+ this.lastFiniteNow = Number.isFinite(this.now()) ? this.now() : 0;
2512
+ this.windowStartedAt = this.lastFiniteNow;
2513
+ }
2514
+ /**
2515
+ * The injected clock, normalized.
2516
+ *
2517
+ * `dedup.now` is a public option and a non-wall-clock host is exactly the case it
2518
+ * exists for — one whose reading can be *missing* rather than merely unusual. Every
2519
+ * comparison this class makes is arithmetic on a timestamp, so a single non-finite
2520
+ * reading does not degrade one field: `now - timestamp > ttlMs` becomes
2521
+ * `NaN > ttlMs` (false, so nothing expires), the adaptive window's
2522
+ * `elapsed >= ADAPTIVE_WINDOW_MS` never fires, and `getStats().ttlMs` reports
2523
+ * `NaN` — which `JSON.stringify` turns into `null`, so a health summary or a
2524
+ * diagnostics log would carry a null where a duration belongs. Measured on the
2525
+ * pre-fix class: `getStats().ttlMs` → `NaN`, serialized → `null`, and an id
2526
+ * stayed suppressed for as long as it stayed in the map.
2527
+ *
2528
+ * Holding the last finite reading is the degradation that changes least: time
2529
+ * stands still, expiry pauses, and the adaptive window keeps the value it last
2530
+ * computed. Substituting `Date.now()` would be worse — it silently mixes two
2531
+ * clocks — and zeroing would expire the whole map on the next call. This is the
2532
+ * same class of guard `trace.ts` carries on its own public clock, and that
2533
+ * `websocket.ts` and `replay-manager.ts` apply to their numeric options; it is one
2534
+ * helper rather than a condition per site because the broken input is the *clock*,
2535
+ * not any particular comparison.
2536
+ */
2537
+ nowMs() {
2538
+ const reading = this.now();
2539
+ if (Number.isFinite(reading)) {
2540
+ this.lastFiniteNow = reading;
2541
+ return reading;
2542
+ }
2543
+ return this.lastFiniteNow;
2510
2544
  }
2511
2545
  /** True when a publication carrying `messageId` was already seen. Records the
2512
2546
  * ID and updates counters/trace on acceptance. Disabled or ID-less messages
2513
2547
  * always pass through. */
2514
2548
  isDuplicate(messageId, topic) {
2515
2549
  if (!this.enabled || !messageId) return false;
2516
- const now = this.now();
2550
+ const now = this.nowMs();
2517
2551
  const ttlMs = this.currentTtl();
2518
2552
  for (const [id, timestamp] of this.seenMessageIds) {
2519
2553
  if (now - timestamp > ttlMs) this.seenMessageIds.delete(id);
@@ -2564,12 +2598,12 @@ var DedupManager = class {
2564
2598
  this.seenMessageIds.clear();
2565
2599
  this.suppressed = 0;
2566
2600
  this.accepted = 0;
2567
- this.windowStartedAt = this.now();
2601
+ this.windowStartedAt = this.nowMs();
2568
2602
  this.windowAccepted = 0;
2569
2603
  }
2570
2604
  /** Remove IDs whose timestamp predates the effective TTL cutoff. */
2571
2605
  pruneExpired() {
2572
- const cutoff = this.now() - this.currentTtl();
2606
+ const cutoff = this.nowMs() - this.currentTtl();
2573
2607
  for (const [id, timestamp] of this.seenMessageIds) {
2574
2608
  if (timestamp < cutoff) this.seenMessageIds.delete(id);
2575
2609
  }
@@ -2580,7 +2614,7 @@ var DedupManager = class {
2580
2614
  * every ADAPTIVE_WINDOW_MS. */
2581
2615
  currentTtl() {
2582
2616
  if (!this.adaptiveBounds) return this.ttlMs;
2583
- const now = this.now();
2617
+ const now = this.nowMs();
2584
2618
  const elapsed = now - this.windowStartedAt;
2585
2619
  if (elapsed >= ADAPTIVE_WINDOW_MS) {
2586
2620
  this.windowStartedAt = now;
@@ -2604,7 +2638,7 @@ var SDK_VERSION = (
2604
2638
  // declaration's type is `string | undefined` and the export's is `string`
2605
2639
  // (dropping the conditional is TS2322, measured). Recorded here so the leg reads
2606
2640
  // as a shape the harness cannot reach rather than as a case nobody exercised.
2607
- true ? "0.21.42" : ""
2641
+ true ? "0.21.43" : ""
2608
2642
  );
2609
2643
 
2610
2644
  // src/core/data-bus.ts