cross-tab-worker-databus 0.20.65 → 0.20.67

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.
@@ -381,6 +381,8 @@ var WorkerClusterRuntime = class {
381
381
  routeOwnerCacheMax;
382
382
  routeOwnerCacheHits = 0;
383
383
  routeOwnerCacheMisses = 0;
384
+ unknownMessageCount = 0;
385
+ lastUnknownMessageType = null;
384
386
  touchRouteOwnerCache(topicKey, value) {
385
387
  if (this.routeOwnerCache.has(topicKey)) this.routeOwnerCache.delete(topicKey);
386
388
  this.routeOwnerCache.set(topicKey, value);
@@ -737,6 +739,10 @@ var WorkerClusterRuntime = class {
737
739
  }
738
740
  return false;
739
741
  }
742
+ /** Count and last type of unknown protocol messages observed. */
743
+ getUnknownMessageStats() {
744
+ return { count: this.unknownMessageCount, lastType: this.lastUnknownMessageType };
745
+ }
740
746
  /** Read-only snapshot of the cluster state (workers, routes, assignments). */
741
747
  getSnapshot() {
742
748
  const routes = this.storage ? readAllByPrefix(this.storage, this.routePrefix).map(({ value }) => ({
@@ -800,9 +806,13 @@ var WorkerClusterRuntime = class {
800
806
  case "REGISTRY":
801
807
  this.reconcile();
802
808
  return;
803
- default:
809
+ default: {
810
+ this.unknownMessageCount += 1;
811
+ const unknown = message;
812
+ this.lastUnknownMessageType = typeof unknown.type === "string" ? unknown.type : null;
804
813
  this.handlers.onUnknownMessage?.(message);
805
814
  return;
815
+ }
806
816
  }
807
817
  };
808
818
  /** Handle a point-to-point CONTROL message (SUBSCRIBE / UNSUBSCRIBE / PUBLISH). */
@@ -1908,6 +1918,7 @@ var CrossTabDataBus = class {
1908
1918
  recovery: this.getRecoveryStats(),
1909
1919
  dedup: this.getDedupStats(),
1910
1920
  replay: { enabled: Boolean(this.replayBuffers), topics: this.replayBuffers?.size ?? 0, messages },
1921
+ protocol: { unknownMessages: this.cluster.getUnknownMessageStats().count, lastUnknownMessageType: this.cluster.getUnknownMessageStats().lastType },
1911
1922
  cluster: this.cluster.getSnapshot()
1912
1923
  };
1913
1924
  }
@@ -2364,6 +2375,10 @@ function createIndexedDbReplayPersistence(options) {
2364
2375
  const dbName = options.dbName ?? "cross-tab-worker-databus";
2365
2376
  const storeName = "replay";
2366
2377
  const maxPerTopic = options.maxPerTopic;
2378
+ const pruneStrategy = options.pruneStrategy ?? "count";
2379
+ const retentionMs = options.retentionMs;
2380
+ if (!["count", "age", "both"].includes(pruneStrategy)) throw new TypeError("pruneStrategy must be count, age, or both.");
2381
+ if (retentionMs !== void 0 && (!Number.isFinite(retentionMs) || retentionMs <= 0)) throw new TypeError("retentionMs must be a positive finite number.");
2367
2382
  if (!Number.isSafeInteger(maxPerTopic) || maxPerTopic <= 0) {
2368
2383
  throw new TypeError(`maxPerTopic must be a positive safe integer, got ${String(maxPerTopic)}.`);
2369
2384
  }
@@ -2439,7 +2454,12 @@ function createIndexedDbReplayPersistence(options) {
2439
2454
  const store = transaction.objectStore(storeName);
2440
2455
  const request = store.get(message.topic);
2441
2456
  request.onsuccess = () => {
2442
- const messages = (request.result?.messages ?? []).concat(message).slice(-maxPerTopic);
2457
+ let messages = (request.result?.messages ?? []).concat(message);
2458
+ if (pruneStrategy !== "count" && retentionMs !== void 0) {
2459
+ const cutoff = Date.now() - retentionMs;
2460
+ messages = messages.filter((item) => item.timestamp === void 0 || item.timestamp >= cutoff);
2461
+ }
2462
+ if (pruneStrategy !== "age") messages = messages.slice(-maxPerTopic);
2443
2463
  store.put({ topic: message.topic, messages });
2444
2464
  };
2445
2465
  request.onerror = () => {