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.
- package/CHANGELOG.md +34 -0
- package/README.md +2 -0
- package/README.zh.md +2 -0
- package/dist/centrifuge-protocol.d.ts +4 -0
- package/dist/centrifuge-protocol.d.ts.map +1 -1
- package/dist/centrifuge-session.d.ts.map +1 -1
- package/dist/centrifuge.js +29 -11
- package/dist/centrifuge.js.map +2 -2
- package/dist/centrifuge.shared.worker.js +37 -6
- package/dist/centrifuge.shared.worker.js.map +3 -3
- package/dist/centrifuge.worker.js +37 -6
- package/dist/centrifuge.worker.js.map +3 -3
- package/dist/{chunk-WWUY2FV2.js → chunk-NX76TAV3.js} +137 -26
- package/dist/chunk-NX76TAV3.js.map +7 -0
- package/dist/cjs/centrifuge.cjs +164 -35
- package/dist/cjs/centrifuge.cjs.map +4 -4
- package/dist/cjs/index.cjs +172 -38
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/core/cluster.d.ts +3 -2
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/data-bus.d.ts +19 -0
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/publication.d.ts +10 -0
- package/dist/core/publication.d.ts.map +1 -0
- package/dist/core/replay-persistence.d.ts +2 -0
- package/dist/core/replay-persistence.d.ts.map +1 -1
- package/dist/core/trace.d.ts +7 -0
- package/dist/core/trace.d.ts.map +1 -1
- package/dist/core/types.d.ts +19 -7
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -14
- package/dist/index.js.map +2 -2
- package/dist/websocket.d.ts.map +1 -1
- package/docs/api.md +27 -6
- package/docs/architecture.md +7 -1
- package/docs/capabilities.md +2 -2
- package/docs/configuration.md +1 -1
- package/docs/roadmap.md +15 -1
- package/docs/transports.md +9 -5
- package/docs/zh/api.md +27 -6
- package/docs/zh/architecture.md +7 -1
- package/docs/zh/capabilities.md +2 -2
- package/docs/zh/configuration.md +1 -1
- package/docs/zh/transports.md +8 -4
- package/package.json +1 -1
- package/dist/chunk-WWUY2FV2.js.map +0 -7
package/dist/cjs/centrifuge.cjs
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
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,
|
|
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 (
|
|
823
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
|
1935
|
-
|
|
1936
|
-
this.post({
|
|
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
|
|
2191
|
+
this.post({ type: "PUBLISH_BIN", topic, data, ...publicationMetadata2(options) }, [data]);
|
|
2069
2192
|
return;
|
|
2070
2193
|
}
|
|
2071
|
-
this.post({ type: "PUBLISH", topic, data, ...options
|
|
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
|
|
2143
|
-
if (message.type === "MESSAGE_BIN") this.handlers?.onMessage({ topic: message.topic, data: message.data, ...message
|
|
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
|