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/index.cjs
CHANGED
|
@@ -339,6 +339,13 @@ function writeJson(storage, key, value) {
|
|
|
339
339
|
} catch {
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
|
+
function publicationMetadata(messageId, timestamp) {
|
|
343
|
+
if (messageId === void 0 && timestamp === void 0) return void 0;
|
|
344
|
+
return {
|
|
345
|
+
...messageId === void 0 ? {} : { messageId },
|
|
346
|
+
...timestamp === void 0 ? {} : { timestamp }
|
|
347
|
+
};
|
|
348
|
+
}
|
|
342
349
|
function listKeys(storage, prefix) {
|
|
343
350
|
try {
|
|
344
351
|
return Array.from({ length: storage.length }, (_, index) => storage.key(index)).filter(
|
|
@@ -568,26 +575,21 @@ var WorkerClusterRuntime = class {
|
|
|
568
575
|
this.sendRouteReleased(owner.workerId, topic, topicKey, generation);
|
|
569
576
|
}
|
|
570
577
|
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
* no owner is found). Returns false when the control message could not be
|
|
574
|
-
* posted to a remote owner, so the caller can surface the failure instead of
|
|
575
|
-
* silently dropping the publication.
|
|
576
|
-
*/
|
|
577
|
-
publish(topic, data, messageId) {
|
|
578
|
+
publish(topic, data, metadataOrMessageId) {
|
|
579
|
+
const metadata = typeof metadataOrMessageId === "string" ? { messageId: metadataOrMessageId } : metadataOrMessageId;
|
|
578
580
|
const topicKey = this.rememberTopic(topic);
|
|
579
581
|
if (this.assignedTopics.has(topicKey)) {
|
|
580
|
-
return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data,
|
|
582
|
+
return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data, metadata);
|
|
581
583
|
}
|
|
582
584
|
for (const pattern of this.assignedTopics.values()) {
|
|
583
585
|
if (pattern !== topic && topicMatchesPattern(pattern, topic)) {
|
|
584
|
-
return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data,
|
|
586
|
+
return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data, metadata);
|
|
585
587
|
}
|
|
586
588
|
}
|
|
587
589
|
const workers = this.readWorkers();
|
|
588
590
|
const route = this.readRoute(topicKey);
|
|
589
591
|
const target = this.routeOwnerIsLive(route, workers) ? route?.workerId ?? this.workerId : this.workerId;
|
|
590
|
-
return this.sendControl(target, "PUBLISH", topic, topicKey, data,
|
|
592
|
+
return this.sendControl(target, "PUBLISH", topic, topicKey, data, metadata);
|
|
591
593
|
}
|
|
592
594
|
/** True when `route` exists and its owner worker is among `workers`.
|
|
593
595
|
* Shared by subscribe (skip re-assignment) and publish (route to owner).
|
|
@@ -709,11 +711,15 @@ var WorkerClusterRuntime = class {
|
|
|
709
711
|
default:
|
|
710
712
|
break;
|
|
711
713
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
714
|
+
const metadata = publicationMetadata(message.messageId, message.timestamp);
|
|
715
|
+
if (metadata) this.handlers.onControl(
|
|
716
|
+
message.action,
|
|
717
|
+
message.topic,
|
|
718
|
+
message.data,
|
|
719
|
+
metadata.messageId,
|
|
720
|
+
metadata.timestamp
|
|
721
|
+
);
|
|
722
|
+
else this.handlers.onControl(message.action, message.topic, message.data);
|
|
717
723
|
if (message.action !== "PUBLISH") this.updateLoad();
|
|
718
724
|
}
|
|
719
725
|
/**
|
|
@@ -830,7 +836,7 @@ var WorkerClusterRuntime = class {
|
|
|
830
836
|
* Local execution updates the assignment map and route synchronously, bypassing
|
|
831
837
|
* the BroadcastChannel latency.
|
|
832
838
|
*/
|
|
833
|
-
sendControl(targetWorkerId, action, topic, topicKey, data,
|
|
839
|
+
sendControl(targetWorkerId, action, topic, topicKey, data, metadata) {
|
|
834
840
|
if (targetWorkerId === this.workerId) {
|
|
835
841
|
switch (action) {
|
|
836
842
|
case "SUBSCRIBE":
|
|
@@ -844,8 +850,14 @@ var WorkerClusterRuntime = class {
|
|
|
844
850
|
default:
|
|
845
851
|
break;
|
|
846
852
|
}
|
|
847
|
-
if (
|
|
848
|
-
|
|
853
|
+
if (metadata) this.handlers.onControl(
|
|
854
|
+
action,
|
|
855
|
+
topic,
|
|
856
|
+
data,
|
|
857
|
+
metadata.messageId,
|
|
858
|
+
metadata.timestamp
|
|
859
|
+
);
|
|
860
|
+
else this.handlers.onControl(action, topic, data);
|
|
849
861
|
if (action !== "PUBLISH") this.updateLoad();
|
|
850
862
|
return true;
|
|
851
863
|
}
|
|
@@ -857,7 +869,8 @@ var WorkerClusterRuntime = class {
|
|
|
857
869
|
topic,
|
|
858
870
|
topicKey,
|
|
859
871
|
...data === void 0 ? {} : { data },
|
|
860
|
-
...messageId === void 0 ? {} : { messageId }
|
|
872
|
+
...metadata?.messageId === void 0 ? {} : { messageId: metadata.messageId },
|
|
873
|
+
...metadata?.timestamp === void 0 ? {} : { timestamp: metadata.timestamp }
|
|
861
874
|
});
|
|
862
875
|
}
|
|
863
876
|
/** Post a message on the BroadcastChannel. Returns false on postMessage failure. */
|
|
@@ -1078,6 +1091,8 @@ var DataBusTraceReporter = class {
|
|
|
1078
1091
|
// Bucketed histogram: bucket index = floor(delayMs / 50), capped at 19.
|
|
1079
1092
|
latencyBuckets = new Array(LATENCY_BUCKET_COUNT).fill(0);
|
|
1080
1093
|
latencySumMs = 0;
|
|
1094
|
+
dedupAccepted = 0;
|
|
1095
|
+
dedupSuppressed = 0;
|
|
1081
1096
|
constructor(options, now = Date.now) {
|
|
1082
1097
|
this.enabled = options?.enabled ?? false;
|
|
1083
1098
|
this.mode = options?.mode ?? "all";
|
|
@@ -1153,6 +1168,13 @@ var DataBusTraceReporter = class {
|
|
|
1153
1168
|
this.latencyBuckets[bucketIndex] = (this.latencyBuckets[bucketIndex] ?? 0) + 1;
|
|
1154
1169
|
this.latencySumMs += delayMs;
|
|
1155
1170
|
}
|
|
1171
|
+
/** Record deduplication outcomes for the next metrics window. */
|
|
1172
|
+
recordDedupAccepted() {
|
|
1173
|
+
if (this.metricsActive) this.dedupAccepted += 1;
|
|
1174
|
+
}
|
|
1175
|
+
recordDedupSuppressed() {
|
|
1176
|
+
if (this.metricsActive) this.dedupSuppressed += 1;
|
|
1177
|
+
}
|
|
1156
1178
|
/** True when metrics recording is active: enabled and mode includes metrics.
|
|
1157
1179
|
* Extracted so the four record / flush methods share one guard expression
|
|
1158
1180
|
* instead of repeating `!this.enabled || this.mode === 'events'` at each. */
|
|
@@ -1166,7 +1188,7 @@ var DataBusTraceReporter = class {
|
|
|
1166
1188
|
}
|
|
1167
1189
|
flushNow() {
|
|
1168
1190
|
const timestamp = this.now();
|
|
1169
|
-
if (this.received > 0 || this.dispatched > 0) {
|
|
1191
|
+
if (this.received > 0 || this.dispatched > 0 || this.dedupAccepted > 0 || this.dedupSuppressed > 0) {
|
|
1170
1192
|
const samples = this.latencySamples;
|
|
1171
1193
|
this.emit({
|
|
1172
1194
|
type: "message_metrics",
|
|
@@ -1180,6 +1202,8 @@ var DataBusTraceReporter = class {
|
|
|
1180
1202
|
dispatchP50Ms: roundMs(percentileMs(this.latencyBuckets, samples, 0.5)),
|
|
1181
1203
|
dispatchP95Ms: roundMs(percentileMs(this.latencyBuckets, samples, 0.95)),
|
|
1182
1204
|
dispatchMaxMs: roundMs(percentileMs(this.latencyBuckets, samples, 1)),
|
|
1205
|
+
dedupAccepted: this.dedupAccepted,
|
|
1206
|
+
dedupSuppressed: this.dedupSuppressed,
|
|
1183
1207
|
timestamp
|
|
1184
1208
|
});
|
|
1185
1209
|
this.resetMetrics();
|
|
@@ -1194,6 +1218,8 @@ var DataBusTraceReporter = class {
|
|
|
1194
1218
|
this.receivedAt.clear();
|
|
1195
1219
|
this.latencyBuckets.fill(0);
|
|
1196
1220
|
this.latencySumMs = 0;
|
|
1221
|
+
this.dedupAccepted = 0;
|
|
1222
|
+
this.dedupSuppressed = 0;
|
|
1197
1223
|
}
|
|
1198
1224
|
emit(event) {
|
|
1199
1225
|
try {
|
|
@@ -1244,6 +1270,7 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1244
1270
|
replayBuffers;
|
|
1245
1271
|
replayMaxPerTopic;
|
|
1246
1272
|
replayPersistence;
|
|
1273
|
+
replayRetentionMs;
|
|
1247
1274
|
replayHydration;
|
|
1248
1275
|
initialConfig;
|
|
1249
1276
|
hasInitialConfig;
|
|
@@ -1252,6 +1279,8 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1252
1279
|
dedupTtlMs;
|
|
1253
1280
|
dedupEnabled;
|
|
1254
1281
|
seenMessageIds = /* @__PURE__ */ new Map();
|
|
1282
|
+
dedupSuppressed = 0;
|
|
1283
|
+
dedupAccepted = 0;
|
|
1255
1284
|
activeConfig;
|
|
1256
1285
|
status = "disconnected";
|
|
1257
1286
|
started = false;
|
|
@@ -1289,6 +1318,10 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1289
1318
|
this.replayMaxPerTopic = replay?.maxPerTopic ?? DEFAULT_REPLAY_MAX_PER_TOPIC;
|
|
1290
1319
|
this.replayBuffers = replay ? /* @__PURE__ */ new Map() : null;
|
|
1291
1320
|
this.replayPersistence = replay?.persistence ?? null;
|
|
1321
|
+
this.replayRetentionMs = replay?.retentionMs;
|
|
1322
|
+
if (this.replayRetentionMs !== void 0 && (!Number.isFinite(this.replayRetentionMs) || this.replayRetentionMs <= 0)) {
|
|
1323
|
+
throw new TypeError("replay.retentionMs must be a positive finite number.");
|
|
1324
|
+
}
|
|
1292
1325
|
this.replayHydration = this.hydrateReplay();
|
|
1293
1326
|
const { autoStart, initialConfig, trace, transport, dedup, ...clusterOptions } = options;
|
|
1294
1327
|
this.transport = transport;
|
|
@@ -1309,7 +1342,7 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1309
1342
|
handlers: {
|
|
1310
1343
|
// The cluster calls `onControl` when it receives a SUBSCRIBE/UNSUBSCRIBE/PUBLISH
|
|
1311
1344
|
// control message — meaning the owning Worker has delegated the action to us.
|
|
1312
|
-
onControl: (action, topic, data, messageId) => {
|
|
1345
|
+
onControl: (action, topic, data, messageId, timestamp) => {
|
|
1313
1346
|
switch (action) {
|
|
1314
1347
|
case "SUBSCRIBE":
|
|
1315
1348
|
if (this.subscribeTransport(topic)) this.traceSubscription("subscribe", topic);
|
|
@@ -1318,7 +1351,14 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1318
1351
|
if (this.unsubscribeTransport(topic)) this.traceSubscription("unsubscribe", topic);
|
|
1319
1352
|
break;
|
|
1320
1353
|
case "PUBLISH":
|
|
1321
|
-
this.runTransport(() => this.transport.publish(
|
|
1354
|
+
this.runTransport(() => this.transport.publish(
|
|
1355
|
+
topic,
|
|
1356
|
+
data,
|
|
1357
|
+
messageId === void 0 && timestamp === void 0 ? void 0 : {
|
|
1358
|
+
...messageId === void 0 ? {} : { messageId },
|
|
1359
|
+
...timestamp === void 0 ? {} : { timestamp }
|
|
1360
|
+
}
|
|
1361
|
+
));
|
|
1322
1362
|
break;
|
|
1323
1363
|
default:
|
|
1324
1364
|
break;
|
|
@@ -1509,10 +1549,49 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1509
1549
|
}
|
|
1510
1550
|
}
|
|
1511
1551
|
}
|
|
1552
|
+
/** Clear replay history for one exact topic, including durable storage. */
|
|
1553
|
+
async clearReplayTopic(topic) {
|
|
1554
|
+
this.replayBuffers?.delete(topic);
|
|
1555
|
+
if (this.replayPersistence?.clearTopic) {
|
|
1556
|
+
try {
|
|
1557
|
+
await this.replayPersistence.clearTopic(topic);
|
|
1558
|
+
} catch (error) {
|
|
1559
|
+
this.reportError(error);
|
|
1560
|
+
throw error;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
/** Remove replay entries older than an epoch-millisecond cutoff. */
|
|
1565
|
+
async clearReplayBefore(timestamp) {
|
|
1566
|
+
if (!Number.isFinite(timestamp)) throw new TypeError("timestamp must be finite.");
|
|
1567
|
+
if (this.replayBuffers) {
|
|
1568
|
+
for (const [topic, messages] of this.replayBuffers) {
|
|
1569
|
+
const kept = messages.filter((message) => (message.timestamp ?? 0) >= timestamp);
|
|
1570
|
+
if (kept.length) this.replayBuffers.set(topic, kept);
|
|
1571
|
+
else this.replayBuffers.delete(topic);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
if (this.replayPersistence?.clearBefore) await this.replayPersistence.clearBefore(timestamp);
|
|
1575
|
+
}
|
|
1576
|
+
/** Return bounded deduplication counters for diagnostics and health checks. */
|
|
1577
|
+
getDedupStats() {
|
|
1578
|
+
return {
|
|
1579
|
+
enabled: this.dedupEnabled,
|
|
1580
|
+
tracked: this.seenMessageIds.size,
|
|
1581
|
+
suppressed: this.dedupSuppressed,
|
|
1582
|
+
accepted: this.dedupAccepted
|
|
1583
|
+
};
|
|
1584
|
+
}
|
|
1585
|
+
/** Drop all remembered IDs and reset dedup counters. */
|
|
1586
|
+
resetDedup() {
|
|
1587
|
+
this.seenMessageIds.clear();
|
|
1588
|
+
this.dedupSuppressed = 0;
|
|
1589
|
+
this.dedupAccepted = 0;
|
|
1590
|
+
}
|
|
1512
1591
|
/** Publish a message to `topic`. The owning Worker delivers it to the transport. */
|
|
1513
1592
|
publish(topic, data, options) {
|
|
1514
1593
|
this.ensureStarted();
|
|
1515
|
-
if (!this.cluster.publish(topic, data, options
|
|
1594
|
+
if (!this.cluster.publish(topic, data, options)) {
|
|
1516
1595
|
this.reportError(
|
|
1517
1596
|
new Error("Failed to send the publish control message to the owning worker.")
|
|
1518
1597
|
);
|
|
@@ -1601,9 +1680,13 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1601
1680
|
}
|
|
1602
1681
|
if (this.seenMessageIds.has(message.messageId)) {
|
|
1603
1682
|
this.trace.event({ type: "reliability", operation: "dedup_suppressed", topic: message.topic });
|
|
1683
|
+
this.dedupSuppressed += 1;
|
|
1684
|
+
this.trace.recordDedupSuppressed();
|
|
1604
1685
|
return true;
|
|
1605
1686
|
}
|
|
1606
1687
|
this.seenMessageIds.set(message.messageId, now);
|
|
1688
|
+
this.dedupAccepted += 1;
|
|
1689
|
+
this.trace.recordDedupAccepted();
|
|
1607
1690
|
while (this.seenMessageIds.size > this.dedupMaxEntries) {
|
|
1608
1691
|
const oldest = this.seenMessageIds.keys().next().value;
|
|
1609
1692
|
if (oldest === void 0) break;
|
|
@@ -1633,10 +1716,14 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1633
1716
|
buffer = [];
|
|
1634
1717
|
this.replayBuffers.set(message.topic, buffer);
|
|
1635
1718
|
}
|
|
1636
|
-
|
|
1719
|
+
const storedMessage = message;
|
|
1720
|
+
buffer.push(storedMessage);
|
|
1637
1721
|
if (buffer.length > this.replayMaxPerTopic) buffer.shift();
|
|
1638
1722
|
if (this.replayPersistence) {
|
|
1639
|
-
void this.replayPersistence.append(
|
|
1723
|
+
void this.replayPersistence.append(storedMessage).catch((error) => this.reportError(error));
|
|
1724
|
+
if (this.replayRetentionMs !== void 0 && this.replayPersistence.clearBefore) {
|
|
1725
|
+
void this.replayPersistence.clearBefore(Date.now() - this.replayRetentionMs).catch((error) => this.reportError(error));
|
|
1726
|
+
}
|
|
1640
1727
|
}
|
|
1641
1728
|
}
|
|
1642
1729
|
async hydrateReplay() {
|
|
@@ -1644,6 +1731,9 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1644
1731
|
return;
|
|
1645
1732
|
}
|
|
1646
1733
|
try {
|
|
1734
|
+
if (this.replayRetentionMs !== void 0 && this.replayPersistence.clearBefore) {
|
|
1735
|
+
await this.replayPersistence.clearBefore(Date.now() - this.replayRetentionMs);
|
|
1736
|
+
}
|
|
1647
1737
|
for (const message of await this.replayPersistence.load()) {
|
|
1648
1738
|
let buffer = this.replayBuffers.get(message.topic);
|
|
1649
1739
|
if (!buffer) {
|
|
@@ -1913,10 +2003,48 @@ function createIndexedDbReplayPersistence(options) {
|
|
|
1913
2003
|
transaction.oncomplete = () => resolve();
|
|
1914
2004
|
transaction.onerror = () => reject(transaction.error ?? new Error("Failed to clear topic replay history."));
|
|
1915
2005
|
});
|
|
2006
|
+
},
|
|
2007
|
+
async clearBefore(timestamp) {
|
|
2008
|
+
const db = await open();
|
|
2009
|
+
await new Promise((resolve, reject) => {
|
|
2010
|
+
const transaction = db.transaction(storeName, "readwrite");
|
|
2011
|
+
const store = transaction.objectStore(storeName);
|
|
2012
|
+
const request = store.getAll();
|
|
2013
|
+
request.onsuccess = () => {
|
|
2014
|
+
for (const record of request.result) {
|
|
2015
|
+
const messages = record.messages.filter((message) => (message.timestamp ?? 0) >= timestamp);
|
|
2016
|
+
if (messages.length === 0) store.delete(record.topic);
|
|
2017
|
+
else if (messages.length !== record.messages.length) store.put({ topic: record.topic, messages });
|
|
2018
|
+
}
|
|
2019
|
+
};
|
|
2020
|
+
request.onerror = () => reject(request.error ?? new Error("Failed to read replay history."));
|
|
2021
|
+
transaction.oncomplete = () => resolve();
|
|
2022
|
+
transaction.onerror = () => reject(transaction.error ?? new Error("Failed to prune replay history."));
|
|
2023
|
+
});
|
|
1916
2024
|
}
|
|
1917
2025
|
};
|
|
1918
2026
|
}
|
|
1919
2027
|
|
|
2028
|
+
// src/core/publication.ts
|
|
2029
|
+
function parseDataBusPublication(value, fallbackTopic) {
|
|
2030
|
+
if (!value || typeof value !== "object") {
|
|
2031
|
+
return fallbackTopic ? { topic: fallbackTopic, data: value } : null;
|
|
2032
|
+
}
|
|
2033
|
+
const frame = value;
|
|
2034
|
+
const nested = frame.publication && typeof frame.publication === "object" ? frame.publication : null;
|
|
2035
|
+
const publication = nested ?? frame;
|
|
2036
|
+
const topic = typeof publication.topic === "string" ? publication.topic : fallbackTopic;
|
|
2037
|
+
if (!topic) return null;
|
|
2038
|
+
const hasMetadataEnvelope = fallbackTopic !== void 0 && Object.prototype.hasOwnProperty.call(publication, "data") && (typeof publication.messageId === "string" || typeof publication.timestamp === "number");
|
|
2039
|
+
const data = nested || fallbackTopic === void 0 || hasMetadataEnvelope ? publication.data : value;
|
|
2040
|
+
return {
|
|
2041
|
+
topic,
|
|
2042
|
+
data,
|
|
2043
|
+
...typeof publication.messageId === "string" ? { messageId: publication.messageId } : {},
|
|
2044
|
+
...typeof publication.timestamp === "number" ? { timestamp: publication.timestamp } : {}
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
|
|
1920
2048
|
// src/websocket.ts
|
|
1921
2049
|
var WS_OPEN = 1;
|
|
1922
2050
|
var WebSocketTransport = class {
|
|
@@ -1966,10 +2094,16 @@ var WebSocketTransport = class {
|
|
|
1966
2094
|
/** Publish `data` to `topic` as a JSON frame. Requires an open socket. */
|
|
1967
2095
|
publish(topic, data, options) {
|
|
1968
2096
|
if (data instanceof ArrayBuffer) {
|
|
1969
|
-
this.sendBinaryFrame(topic, data, options?.messageId);
|
|
2097
|
+
this.sendBinaryFrame(topic, data, options?.messageId, options?.timestamp);
|
|
1970
2098
|
return;
|
|
1971
2099
|
}
|
|
1972
|
-
this.sendFrame({
|
|
2100
|
+
this.sendFrame({
|
|
2101
|
+
op: "publish",
|
|
2102
|
+
topic,
|
|
2103
|
+
data,
|
|
2104
|
+
...options?.messageId === void 0 ? {} : { messageId: options.messageId },
|
|
2105
|
+
...options?.timestamp === void 0 ? {} : { timestamp: options.timestamp }
|
|
2106
|
+
});
|
|
1973
2107
|
}
|
|
1974
2108
|
/** Close the socket and drop all state. Safe to call multiple times. */
|
|
1975
2109
|
stop() {
|
|
@@ -1989,9 +2123,15 @@ var WebSocketTransport = class {
|
|
|
1989
2123
|
}
|
|
1990
2124
|
this.socket.send(JSON.stringify(payload));
|
|
1991
2125
|
}
|
|
1992
|
-
sendBinaryFrame(topic, data, messageId) {
|
|
1993
|
-
if (messageId) {
|
|
1994
|
-
this.sendFrame({
|
|
2126
|
+
sendBinaryFrame(topic, data, messageId, timestamp) {
|
|
2127
|
+
if (messageId !== void 0 || timestamp !== void 0) {
|
|
2128
|
+
this.sendFrame({
|
|
2129
|
+
op: "publish",
|
|
2130
|
+
topic,
|
|
2131
|
+
data: Array.from(new Uint8Array(data)),
|
|
2132
|
+
...messageId === void 0 ? {} : { messageId },
|
|
2133
|
+
...timestamp === void 0 ? {} : { timestamp }
|
|
2134
|
+
});
|
|
1995
2135
|
return;
|
|
1996
2136
|
}
|
|
1997
2137
|
if (this.socket?.readyState !== WS_OPEN) {
|
|
@@ -2033,14 +2173,8 @@ var WebSocketTransport = class {
|
|
|
2033
2173
|
return;
|
|
2034
2174
|
}
|
|
2035
2175
|
if (!parsed || typeof parsed !== "object") return;
|
|
2036
|
-
const
|
|
2037
|
-
if (
|
|
2038
|
-
const message = {
|
|
2039
|
-
topic: frame.topic,
|
|
2040
|
-
data: frame.data,
|
|
2041
|
-
...typeof frame.messageId === "string" ? { messageId: frame.messageId } : {}
|
|
2042
|
-
};
|
|
2043
|
-
this.handlers?.onMessage(message);
|
|
2176
|
+
const publication = parseDataBusPublication(parsed);
|
|
2177
|
+
if (publication) this.handlers?.onMessage(publication);
|
|
2044
2178
|
}
|
|
2045
2179
|
};
|
|
2046
2180
|
function defaultWebSocketFactory(url, protocols) {
|