cross-tab-worker-databus 0.8.0 → 0.11.0

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +2 -0
  3. package/README.zh.md +2 -0
  4. package/dist/centrifuge-protocol.d.ts +4 -0
  5. package/dist/centrifuge-protocol.d.ts.map +1 -1
  6. package/dist/centrifuge-session.d.ts.map +1 -1
  7. package/dist/centrifuge.js +29 -11
  8. package/dist/centrifuge.js.map +2 -2
  9. package/dist/centrifuge.shared.worker.js +37 -6
  10. package/dist/centrifuge.shared.worker.js.map +3 -3
  11. package/dist/centrifuge.worker.js +37 -6
  12. package/dist/centrifuge.worker.js.map +3 -3
  13. package/dist/{chunk-WWUY2FV2.js → chunk-NX76TAV3.js} +137 -26
  14. package/dist/chunk-NX76TAV3.js.map +7 -0
  15. package/dist/cjs/centrifuge.cjs +164 -35
  16. package/dist/cjs/centrifuge.cjs.map +4 -4
  17. package/dist/cjs/index.cjs +172 -38
  18. package/dist/cjs/index.cjs.map +3 -3
  19. package/dist/core/cluster.d.ts +3 -2
  20. package/dist/core/cluster.d.ts.map +1 -1
  21. package/dist/core/data-bus.d.ts +19 -0
  22. package/dist/core/data-bus.d.ts.map +1 -1
  23. package/dist/core/publication.d.ts +10 -0
  24. package/dist/core/publication.d.ts.map +1 -0
  25. package/dist/core/replay-persistence.d.ts +2 -0
  26. package/dist/core/replay-persistence.d.ts.map +1 -1
  27. package/dist/core/trace.d.ts +7 -0
  28. package/dist/core/trace.d.ts.map +1 -1
  29. package/dist/core/types.d.ts +19 -7
  30. package/dist/core/types.d.ts.map +1 -1
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +39 -14
  34. package/dist/index.js.map +2 -2
  35. package/dist/websocket.d.ts.map +1 -1
  36. package/docs/api.md +27 -6
  37. package/docs/architecture.md +7 -1
  38. package/docs/capabilities.md +2 -2
  39. package/docs/configuration.md +1 -1
  40. package/docs/roadmap.md +15 -1
  41. package/docs/transports.md +9 -5
  42. package/docs/zh/api.md +27 -6
  43. package/docs/zh/architecture.md +7 -1
  44. package/docs/zh/capabilities.md +2 -2
  45. package/docs/zh/configuration.md +1 -1
  46. package/docs/zh/transports.md +8 -4
  47. package/package.json +1 -1
  48. package/dist/chunk-WWUY2FV2.js.map +0 -7
@@ -314,6 +314,13 @@ function writeJson(storage, key, value) {
314
314
  } catch {
315
315
  }
316
316
  }
317
+ function publicationMetadata(messageId, timestamp) {
318
+ if (messageId === void 0 && timestamp === void 0) return void 0;
319
+ return {
320
+ ...messageId === void 0 ? {} : { messageId },
321
+ ...timestamp === void 0 ? {} : { timestamp }
322
+ };
323
+ }
317
324
  function listKeys(storage, prefix) {
318
325
  try {
319
326
  return Array.from({ length: storage.length }, (_, index) => storage.key(index)).filter(
@@ -543,26 +550,21 @@ var WorkerClusterRuntime = class {
543
550
  this.sendRouteReleased(owner.workerId, topic, topicKey, generation);
544
551
  }
545
552
  }
546
- /**
547
- * Publish a message to `topic`, routing through the owning Worker (or self if
548
- * no owner is found). Returns false when the control message could not be
549
- * posted to a remote owner, so the caller can surface the failure instead of
550
- * silently dropping the publication.
551
- */
552
- publish(topic, data, messageId) {
553
+ publish(topic, data, metadataOrMessageId) {
554
+ const metadata = typeof metadataOrMessageId === "string" ? { messageId: metadataOrMessageId } : metadataOrMessageId;
553
555
  const topicKey = this.rememberTopic(topic);
554
556
  if (this.assignedTopics.has(topicKey)) {
555
- return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data, messageId);
557
+ return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data, metadata);
556
558
  }
557
559
  for (const pattern of this.assignedTopics.values()) {
558
560
  if (pattern !== topic && topicMatchesPattern(pattern, topic)) {
559
- return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data, messageId);
561
+ return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data, metadata);
560
562
  }
561
563
  }
562
564
  const workers = this.readWorkers();
563
565
  const route = this.readRoute(topicKey);
564
566
  const target = this.routeOwnerIsLive(route, workers) ? route?.workerId ?? this.workerId : this.workerId;
565
- return this.sendControl(target, "PUBLISH", topic, topicKey, data, messageId);
567
+ return this.sendControl(target, "PUBLISH", topic, topicKey, data, metadata);
566
568
  }
567
569
  /** True when `route` exists and its owner worker is among `workers`.
568
570
  * Shared by subscribe (skip re-assignment) and publish (route to owner).
@@ -684,11 +686,15 @@ var WorkerClusterRuntime = class {
684
686
  default:
685
687
  break;
686
688
  }
687
- if (message.messageId === void 0) {
688
- this.handlers.onControl(message.action, message.topic, message.data);
689
- } else {
690
- this.handlers.onControl(message.action, message.topic, message.data, message.messageId);
691
- }
689
+ const metadata = publicationMetadata(message.messageId, message.timestamp);
690
+ if (metadata) this.handlers.onControl(
691
+ message.action,
692
+ message.topic,
693
+ message.data,
694
+ metadata.messageId,
695
+ metadata.timestamp
696
+ );
697
+ else this.handlers.onControl(message.action, message.topic, message.data);
692
698
  if (message.action !== "PUBLISH") this.updateLoad();
693
699
  }
694
700
  /**
@@ -805,7 +811,7 @@ var WorkerClusterRuntime = class {
805
811
  * Local execution updates the assignment map and route synchronously, bypassing
806
812
  * the BroadcastChannel latency.
807
813
  */
808
- sendControl(targetWorkerId, action, topic, topicKey, data, messageId) {
814
+ sendControl(targetWorkerId, action, topic, topicKey, data, metadata) {
809
815
  if (targetWorkerId === this.workerId) {
810
816
  switch (action) {
811
817
  case "SUBSCRIBE":
@@ -819,8 +825,14 @@ var WorkerClusterRuntime = class {
819
825
  default:
820
826
  break;
821
827
  }
822
- if (messageId === void 0) this.handlers.onControl(action, topic, data);
823
- else this.handlers.onControl(action, topic, data, messageId);
828
+ if (metadata) this.handlers.onControl(
829
+ action,
830
+ topic,
831
+ data,
832
+ metadata.messageId,
833
+ metadata.timestamp
834
+ );
835
+ else this.handlers.onControl(action, topic, data);
824
836
  if (action !== "PUBLISH") this.updateLoad();
825
837
  return true;
826
838
  }
@@ -832,7 +844,8 @@ var WorkerClusterRuntime = class {
832
844
  topic,
833
845
  topicKey,
834
846
  ...data === void 0 ? {} : { data },
835
- ...messageId === void 0 ? {} : { messageId }
847
+ ...metadata?.messageId === void 0 ? {} : { messageId: metadata.messageId },
848
+ ...metadata?.timestamp === void 0 ? {} : { timestamp: metadata.timestamp }
836
849
  });
837
850
  }
838
851
  /** Post a message on the BroadcastChannel. Returns false on postMessage failure. */
@@ -1053,6 +1066,8 @@ var DataBusTraceReporter = class {
1053
1066
  // Bucketed histogram: bucket index = floor(delayMs / 50), capped at 19.
1054
1067
  latencyBuckets = new Array(LATENCY_BUCKET_COUNT).fill(0);
1055
1068
  latencySumMs = 0;
1069
+ dedupAccepted = 0;
1070
+ dedupSuppressed = 0;
1056
1071
  constructor(options, now = Date.now) {
1057
1072
  this.enabled = options?.enabled ?? false;
1058
1073
  this.mode = options?.mode ?? "all";
@@ -1128,6 +1143,13 @@ var DataBusTraceReporter = class {
1128
1143
  this.latencyBuckets[bucketIndex] = (this.latencyBuckets[bucketIndex] ?? 0) + 1;
1129
1144
  this.latencySumMs += delayMs;
1130
1145
  }
1146
+ /** Record deduplication outcomes for the next metrics window. */
1147
+ recordDedupAccepted() {
1148
+ if (this.metricsActive) this.dedupAccepted += 1;
1149
+ }
1150
+ recordDedupSuppressed() {
1151
+ if (this.metricsActive) this.dedupSuppressed += 1;
1152
+ }
1131
1153
  /** True when metrics recording is active: enabled and mode includes metrics.
1132
1154
  * Extracted so the four record / flush methods share one guard expression
1133
1155
  * instead of repeating `!this.enabled || this.mode === 'events'` at each. */
@@ -1141,7 +1163,7 @@ var DataBusTraceReporter = class {
1141
1163
  }
1142
1164
  flushNow() {
1143
1165
  const timestamp = this.now();
1144
- if (this.received > 0 || this.dispatched > 0) {
1166
+ if (this.received > 0 || this.dispatched > 0 || this.dedupAccepted > 0 || this.dedupSuppressed > 0) {
1145
1167
  const samples = this.latencySamples;
1146
1168
  this.emit({
1147
1169
  type: "message_metrics",
@@ -1155,6 +1177,8 @@ var DataBusTraceReporter = class {
1155
1177
  dispatchP50Ms: roundMs(percentileMs(this.latencyBuckets, samples, 0.5)),
1156
1178
  dispatchP95Ms: roundMs(percentileMs(this.latencyBuckets, samples, 0.95)),
1157
1179
  dispatchMaxMs: roundMs(percentileMs(this.latencyBuckets, samples, 1)),
1180
+ dedupAccepted: this.dedupAccepted,
1181
+ dedupSuppressed: this.dedupSuppressed,
1158
1182
  timestamp
1159
1183
  });
1160
1184
  this.resetMetrics();
@@ -1169,6 +1193,8 @@ var DataBusTraceReporter = class {
1169
1193
  this.receivedAt.clear();
1170
1194
  this.latencyBuckets.fill(0);
1171
1195
  this.latencySumMs = 0;
1196
+ this.dedupAccepted = 0;
1197
+ this.dedupSuppressed = 0;
1172
1198
  }
1173
1199
  emit(event) {
1174
1200
  try {
@@ -1219,6 +1245,7 @@ var CrossTabDataBus = class _CrossTabDataBus {
1219
1245
  replayBuffers;
1220
1246
  replayMaxPerTopic;
1221
1247
  replayPersistence;
1248
+ replayRetentionMs;
1222
1249
  replayHydration;
1223
1250
  initialConfig;
1224
1251
  hasInitialConfig;
@@ -1227,6 +1254,8 @@ var CrossTabDataBus = class _CrossTabDataBus {
1227
1254
  dedupTtlMs;
1228
1255
  dedupEnabled;
1229
1256
  seenMessageIds = /* @__PURE__ */ new Map();
1257
+ dedupSuppressed = 0;
1258
+ dedupAccepted = 0;
1230
1259
  activeConfig;
1231
1260
  status = "disconnected";
1232
1261
  started = false;
@@ -1264,6 +1293,10 @@ var CrossTabDataBus = class _CrossTabDataBus {
1264
1293
  this.replayMaxPerTopic = replay?.maxPerTopic ?? DEFAULT_REPLAY_MAX_PER_TOPIC;
1265
1294
  this.replayBuffers = replay ? /* @__PURE__ */ new Map() : null;
1266
1295
  this.replayPersistence = replay?.persistence ?? null;
1296
+ this.replayRetentionMs = replay?.retentionMs;
1297
+ if (this.replayRetentionMs !== void 0 && (!Number.isFinite(this.replayRetentionMs) || this.replayRetentionMs <= 0)) {
1298
+ throw new TypeError("replay.retentionMs must be a positive finite number.");
1299
+ }
1267
1300
  this.replayHydration = this.hydrateReplay();
1268
1301
  const { autoStart, initialConfig, trace, transport, dedup, ...clusterOptions } = options;
1269
1302
  this.transport = transport;
@@ -1284,7 +1317,7 @@ var CrossTabDataBus = class _CrossTabDataBus {
1284
1317
  handlers: {
1285
1318
  // The cluster calls `onControl` when it receives a SUBSCRIBE/UNSUBSCRIBE/PUBLISH
1286
1319
  // control message — meaning the owning Worker has delegated the action to us.
1287
- onControl: (action, topic, data, messageId) => {
1320
+ onControl: (action, topic, data, messageId, timestamp) => {
1288
1321
  switch (action) {
1289
1322
  case "SUBSCRIBE":
1290
1323
  if (this.subscribeTransport(topic)) this.traceSubscription("subscribe", topic);
@@ -1293,7 +1326,14 @@ var CrossTabDataBus = class _CrossTabDataBus {
1293
1326
  if (this.unsubscribeTransport(topic)) this.traceSubscription("unsubscribe", topic);
1294
1327
  break;
1295
1328
  case "PUBLISH":
1296
- this.runTransport(() => this.transport.publish(topic, data, messageId ? { messageId } : void 0));
1329
+ this.runTransport(() => this.transport.publish(
1330
+ topic,
1331
+ data,
1332
+ messageId === void 0 && timestamp === void 0 ? void 0 : {
1333
+ ...messageId === void 0 ? {} : { messageId },
1334
+ ...timestamp === void 0 ? {} : { timestamp }
1335
+ }
1336
+ ));
1297
1337
  break;
1298
1338
  default:
1299
1339
  break;
@@ -1484,10 +1524,49 @@ var CrossTabDataBus = class _CrossTabDataBus {
1484
1524
  }
1485
1525
  }
1486
1526
  }
1527
+ /** Clear replay history for one exact topic, including durable storage. */
1528
+ async clearReplayTopic(topic) {
1529
+ this.replayBuffers?.delete(topic);
1530
+ if (this.replayPersistence?.clearTopic) {
1531
+ try {
1532
+ await this.replayPersistence.clearTopic(topic);
1533
+ } catch (error) {
1534
+ this.reportError(error);
1535
+ throw error;
1536
+ }
1537
+ }
1538
+ }
1539
+ /** Remove replay entries older than an epoch-millisecond cutoff. */
1540
+ async clearReplayBefore(timestamp) {
1541
+ if (!Number.isFinite(timestamp)) throw new TypeError("timestamp must be finite.");
1542
+ if (this.replayBuffers) {
1543
+ for (const [topic, messages] of this.replayBuffers) {
1544
+ const kept = messages.filter((message) => (message.timestamp ?? 0) >= timestamp);
1545
+ if (kept.length) this.replayBuffers.set(topic, kept);
1546
+ else this.replayBuffers.delete(topic);
1547
+ }
1548
+ }
1549
+ if (this.replayPersistence?.clearBefore) await this.replayPersistence.clearBefore(timestamp);
1550
+ }
1551
+ /** Return bounded deduplication counters for diagnostics and health checks. */
1552
+ getDedupStats() {
1553
+ return {
1554
+ enabled: this.dedupEnabled,
1555
+ tracked: this.seenMessageIds.size,
1556
+ suppressed: this.dedupSuppressed,
1557
+ accepted: this.dedupAccepted
1558
+ };
1559
+ }
1560
+ /** Drop all remembered IDs and reset dedup counters. */
1561
+ resetDedup() {
1562
+ this.seenMessageIds.clear();
1563
+ this.dedupSuppressed = 0;
1564
+ this.dedupAccepted = 0;
1565
+ }
1487
1566
  /** Publish a message to `topic`. The owning Worker delivers it to the transport. */
1488
1567
  publish(topic, data, options) {
1489
1568
  this.ensureStarted();
1490
- if (!this.cluster.publish(topic, data, options?.messageId)) {
1569
+ if (!this.cluster.publish(topic, data, options)) {
1491
1570
  this.reportError(
1492
1571
  new Error("Failed to send the publish control message to the owning worker.")
1493
1572
  );
@@ -1576,9 +1655,13 @@ var CrossTabDataBus = class _CrossTabDataBus {
1576
1655
  }
1577
1656
  if (this.seenMessageIds.has(message.messageId)) {
1578
1657
  this.trace.event({ type: "reliability", operation: "dedup_suppressed", topic: message.topic });
1658
+ this.dedupSuppressed += 1;
1659
+ this.trace.recordDedupSuppressed();
1579
1660
  return true;
1580
1661
  }
1581
1662
  this.seenMessageIds.set(message.messageId, now);
1663
+ this.dedupAccepted += 1;
1664
+ this.trace.recordDedupAccepted();
1582
1665
  while (this.seenMessageIds.size > this.dedupMaxEntries) {
1583
1666
  const oldest = this.seenMessageIds.keys().next().value;
1584
1667
  if (oldest === void 0) break;
@@ -1608,10 +1691,14 @@ var CrossTabDataBus = class _CrossTabDataBus {
1608
1691
  buffer = [];
1609
1692
  this.replayBuffers.set(message.topic, buffer);
1610
1693
  }
1611
- buffer.push(message);
1694
+ const storedMessage = message;
1695
+ buffer.push(storedMessage);
1612
1696
  if (buffer.length > this.replayMaxPerTopic) buffer.shift();
1613
1697
  if (this.replayPersistence) {
1614
- void this.replayPersistence.append(message).catch((error) => this.reportError(error));
1698
+ void this.replayPersistence.append(storedMessage).catch((error) => this.reportError(error));
1699
+ if (this.replayRetentionMs !== void 0 && this.replayPersistence.clearBefore) {
1700
+ void this.replayPersistence.clearBefore(Date.now() - this.replayRetentionMs).catch((error) => this.reportError(error));
1701
+ }
1615
1702
  }
1616
1703
  }
1617
1704
  async hydrateReplay() {
@@ -1619,6 +1706,9 @@ var CrossTabDataBus = class _CrossTabDataBus {
1619
1706
  return;
1620
1707
  }
1621
1708
  try {
1709
+ if (this.replayRetentionMs !== void 0 && this.replayPersistence.clearBefore) {
1710
+ await this.replayPersistence.clearBefore(Date.now() - this.replayRetentionMs);
1711
+ }
1622
1712
  for (const message of await this.replayPersistence.load()) {
1623
1713
  let buffer = this.replayBuffers.get(message.topic);
1624
1714
  if (!buffer) {
@@ -1828,6 +1918,28 @@ function formatRouteTrace(route) {
1828
1918
 
1829
1919
  // src/centrifuge-session.ts
1830
1920
  var import_centrifuge = require("centrifuge");
1921
+
1922
+ // src/core/publication.ts
1923
+ function parseDataBusPublication(value, fallbackTopic) {
1924
+ if (!value || typeof value !== "object") {
1925
+ return fallbackTopic ? { topic: fallbackTopic, data: value } : null;
1926
+ }
1927
+ const frame = value;
1928
+ const nested = frame.publication && typeof frame.publication === "object" ? frame.publication : null;
1929
+ const publication = nested ?? frame;
1930
+ const topic = typeof publication.topic === "string" ? publication.topic : fallbackTopic;
1931
+ if (!topic) return null;
1932
+ const hasMetadataEnvelope = fallbackTopic !== void 0 && Object.prototype.hasOwnProperty.call(publication, "data") && (typeof publication.messageId === "string" || typeof publication.timestamp === "number");
1933
+ const data = nested || fallbackTopic === void 0 || hasMetadataEnvelope ? publication.data : value;
1934
+ return {
1935
+ topic,
1936
+ data,
1937
+ ...typeof publication.messageId === "string" ? { messageId: publication.messageId } : {},
1938
+ ...typeof publication.timestamp === "number" ? { timestamp: publication.timestamp } : {}
1939
+ };
1940
+ }
1941
+
1942
+ // src/centrifuge-session.ts
1831
1943
  var CentrifugeSession = class {
1832
1944
  constructor(sink) {
1833
1945
  this.sink = sink;
@@ -1851,7 +1963,7 @@ var CentrifugeSession = class {
1851
1963
  return;
1852
1964
  case "PUBLISH":
1853
1965
  case "PUBLISH_BIN":
1854
- this.publish(message.topic, message.data, message.messageId);
1966
+ this.publish(message.topic, message.data, message.messageId, message.timestamp);
1855
1967
  return;
1856
1968
  case "STOP":
1857
1969
  this.stop();
@@ -1916,9 +2028,14 @@ var CentrifugeSession = class {
1916
2028
  subscription.unsubscribe();
1917
2029
  }
1918
2030
  /** Publish a message to the Centrifuge channel. */
1919
- publish(topic, data, messageId) {
2031
+ publish(topic, data, messageId, timestamp) {
1920
2032
  if (!this.client) return this.postError(new Error("Centrifuge client is not initialized."));
1921
- const payload = messageId ? { data, messageId } : data;
2033
+ const hasMetadata = messageId !== void 0 || timestamp !== void 0;
2034
+ const payload = hasMetadata ? {
2035
+ data,
2036
+ ...messageId === void 0 ? {} : { messageId },
2037
+ ...timestamp === void 0 ? {} : { timestamp }
2038
+ } : data;
1922
2039
  void this.client.publish(topic, payload).catch((error) => this.postError(error));
1923
2040
  }
1924
2041
  /** Forward a publication to the transport. Binary payloads take the
@@ -1931,9 +2048,15 @@ var CentrifugeSession = class {
1931
2048
  this.post({ type: "MESSAGE_BIN", topic, data }, [data]);
1932
2049
  return;
1933
2050
  }
1934
- const messageId = data && typeof data === "object" && typeof data.messageId === "string" ? data.messageId : void 0;
1935
- const payload = messageId && Object.prototype.hasOwnProperty.call(data, "data") ? data.data : data;
1936
- this.post({ type: "MESSAGE", topic, data: payload, ...messageId ? { messageId } : {} });
2051
+ const publication = parseDataBusPublication(data, topic);
2052
+ if (!publication) return;
2053
+ this.post({
2054
+ type: "MESSAGE",
2055
+ topic: publication.topic,
2056
+ data: publication.data,
2057
+ ...publication.messageId === void 0 ? {} : { messageId: publication.messageId },
2058
+ ...publication.timestamp === void 0 ? {} : { timestamp: publication.timestamp }
2059
+ });
1937
2060
  }
1938
2061
  /** Disconnect the client and clear all subscriptions. */
1939
2062
  stop() {
@@ -2065,10 +2188,10 @@ var CentrifugeWorkerTransport = class {
2065
2188
  */
2066
2189
  publish(topic, data, options) {
2067
2190
  if (this.transferable && data instanceof ArrayBuffer) {
2068
- this.post({ type: "PUBLISH_BIN", topic, data, ...options?.messageId ? { messageId: options.messageId } : {} }, [data]);
2191
+ this.post({ type: "PUBLISH_BIN", topic, data, ...publicationMetadata2(options) }, [data]);
2069
2192
  return;
2070
2193
  }
2071
- this.post({ type: "PUBLISH", topic, data, ...options?.messageId ? { messageId: options.messageId } : {} });
2194
+ this.post({ type: "PUBLISH", topic, data, ...publicationMetadata2(options) });
2072
2195
  }
2073
2196
  /**
2074
2197
  * Gracefully stop the transport: send STOP, clean up event listeners, and
@@ -2139,8 +2262,8 @@ var CentrifugeWorkerTransport = class {
2139
2262
  * and the local-session sink — all three feed into this single dispatcher. */
2140
2263
  handleOutput(message) {
2141
2264
  if (message.type === "STATUS") this.handlers?.onStatus(message.status);
2142
- if (message.type === "MESSAGE") this.handlers?.onMessage({ topic: message.topic, data: message.data, ...message.messageId ? { messageId: message.messageId } : {} });
2143
- if (message.type === "MESSAGE_BIN") this.handlers?.onMessage({ topic: message.topic, data: message.data, ...message.messageId ? { messageId: message.messageId } : {} });
2265
+ if (message.type === "MESSAGE") this.handlers?.onMessage({ topic: message.topic, data: message.data, ...publicationMetadata2(message) });
2266
+ if (message.type === "MESSAGE_BIN") this.handlers?.onMessage({ topic: message.topic, data: message.data, ...publicationMetadata2(message) });
2144
2267
  if (message.type === "ERROR") this.handlers?.onError(deserializeWorkerError(message.error));
2145
2268
  }
2146
2269
  /** Handle a Worker-level failure (crash, message decode error). Discards the
@@ -2305,4 +2428,10 @@ function deserializeWorkerError(error) {
2305
2428
  if (error.context !== void 0) Object.assign(result, { context: error.context });
2306
2429
  return result;
2307
2430
  }
2431
+ function publicationMetadata2(metadata) {
2432
+ return {
2433
+ ...metadata?.messageId === void 0 ? {} : { messageId: metadata.messageId },
2434
+ ...metadata?.timestamp === void 0 ? {} : { timestamp: metadata.timestamp }
2435
+ };
2436
+ }
2308
2437
  //# sourceMappingURL=centrifuge.cjs.map