cross-tab-worker-databus 0.6.0 → 0.7.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 +15 -0
- package/dist/centrifuge.js +1 -1
- package/dist/{chunk-YUSQSNCX.js → chunk-SI7N5KNJ.js} +42 -2
- package/dist/chunk-SI7N5KNJ.js.map +7 -0
- package/dist/cjs/centrifuge.cjs +41 -1
- package/dist/cjs/centrifuge.cjs.map +2 -2
- package/dist/cjs/index.cjs +59 -1
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/core/cluster.d.ts +5 -0
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/data-bus.d.ts +12 -0
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/replay-persistence.d.ts +4 -0
- package/dist/core/replay-persistence.d.ts.map +1 -1
- package/dist/core/trace.d.ts +19 -1
- package/dist/core/trace.d.ts.map +1 -1
- package/dist/core/types.d.ts +2 -0
- 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 +19 -1
- package/dist/index.js.map +2 -2
- package/docs/api.md +3 -0
- package/docs/capabilities.md +3 -3
- package/docs/roadmap.md +7 -7
- package/docs/zh/api.md +1 -0
- package/docs/zh/capabilities.md +3 -3
- package/docs/zh/roadmap.md +7 -7
- package/package.json +1 -1
- package/dist/chunk-YUSQSNCX.js.map +0 -7
package/dist/cjs/centrifuge.cjs
CHANGED
|
@@ -537,6 +537,7 @@ var WorkerClusterRuntime = class {
|
|
|
537
537
|
projectedLoads.set(owner.workerId, (projectedLoads.get(owner.workerId) ?? owner.load) + 1);
|
|
538
538
|
const generation = (previous?.generation ?? 0) + 1;
|
|
539
539
|
this.writeRoute(topicKey, owner, previous?.workerId, generation);
|
|
540
|
+
this.handlers.onDiagnostic?.({ operation: "route_migration", topic });
|
|
540
541
|
this.flushStorage();
|
|
541
542
|
this.handlers.onControl("UNSUBSCRIBE", topic);
|
|
542
543
|
this.sendRouteReleased(owner.workerId, topic, topicKey, generation);
|
|
@@ -921,6 +922,8 @@ var WorkerClusterRuntime = class {
|
|
|
921
922
|
...route,
|
|
922
923
|
confirmedAt: this.environment.now()
|
|
923
924
|
});
|
|
925
|
+
const topic = this.knownTopics.get(topicKey);
|
|
926
|
+
if (topic) this.handlers.onDiagnostic?.({ operation: "route_ack", topic });
|
|
924
927
|
}
|
|
925
928
|
/** Remove routes whose topic has no subscribers and whose TTL has expired. */
|
|
926
929
|
cleanupOrphanedRoutes(workers) {
|
|
@@ -1214,6 +1217,10 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1214
1217
|
initialConfig;
|
|
1215
1218
|
hasInitialConfig;
|
|
1216
1219
|
trace;
|
|
1220
|
+
dedupMaxEntries;
|
|
1221
|
+
dedupTtlMs;
|
|
1222
|
+
dedupEnabled;
|
|
1223
|
+
seenMessageIds = /* @__PURE__ */ new Map();
|
|
1217
1224
|
activeConfig;
|
|
1218
1225
|
status = "disconnected";
|
|
1219
1226
|
started = false;
|
|
@@ -1252,11 +1259,20 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1252
1259
|
this.replayBuffers = replay ? /* @__PURE__ */ new Map() : null;
|
|
1253
1260
|
this.replayPersistence = replay?.persistence ?? null;
|
|
1254
1261
|
this.replayHydration = this.hydrateReplay();
|
|
1255
|
-
const { autoStart, initialConfig, trace, transport, ...clusterOptions } = options;
|
|
1262
|
+
const { autoStart, initialConfig, trace, transport, dedup, ...clusterOptions } = options;
|
|
1256
1263
|
this.transport = transport;
|
|
1257
1264
|
this.initialConfig = initialConfig;
|
|
1258
1265
|
this.hasInitialConfig = "initialConfig" in options;
|
|
1259
1266
|
this.trace = new DataBusTraceReporter(trace);
|
|
1267
|
+
this.dedupMaxEntries = dedup?.maxEntries ?? 1e3;
|
|
1268
|
+
this.dedupTtlMs = dedup?.ttlMs ?? 6e4;
|
|
1269
|
+
this.dedupEnabled = dedup !== void 0;
|
|
1270
|
+
if (!Number.isSafeInteger(this.dedupMaxEntries) || this.dedupMaxEntries <= 0) {
|
|
1271
|
+
throw new TypeError("dedup.maxEntries must be a positive safe integer.");
|
|
1272
|
+
}
|
|
1273
|
+
if (!Number.isFinite(this.dedupTtlMs) || this.dedupTtlMs <= 0) {
|
|
1274
|
+
throw new TypeError("dedup.ttlMs must be a positive finite number.");
|
|
1275
|
+
}
|
|
1260
1276
|
this.cluster = new WorkerClusterRuntime({
|
|
1261
1277
|
...clusterOptions,
|
|
1262
1278
|
handlers: {
|
|
@@ -1296,6 +1312,9 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1296
1312
|
this.trace.event({ type: "lifecycle", action: "resume" });
|
|
1297
1313
|
this.trace.start();
|
|
1298
1314
|
this.resumeTransport();
|
|
1315
|
+
},
|
|
1316
|
+
onDiagnostic: (event) => {
|
|
1317
|
+
this.trace.event({ type: "reliability", ...event });
|
|
1299
1318
|
}
|
|
1300
1319
|
}
|
|
1301
1320
|
});
|
|
@@ -1442,6 +1461,9 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1442
1461
|
if (handlers.size > 0) return;
|
|
1443
1462
|
this.topicHandlers.delete(topic);
|
|
1444
1463
|
this.replayBuffers?.delete(topic);
|
|
1464
|
+
if (this.replayPersistence?.clearTopic) {
|
|
1465
|
+
void this.replayPersistence.clearTopic(topic).catch((error) => this.reportError(error));
|
|
1466
|
+
}
|
|
1445
1467
|
this.cluster.unsubscribe(topic);
|
|
1446
1468
|
}
|
|
1447
1469
|
/** Publish a message to `topic`. The owning Worker delivers it to the transport. */
|
|
@@ -1497,6 +1519,7 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1497
1519
|
else await this.transport.stop();
|
|
1498
1520
|
} finally {
|
|
1499
1521
|
this.transportSubscribedTopics.clear();
|
|
1522
|
+
this.seenMessageIds.clear();
|
|
1500
1523
|
this.started = false;
|
|
1501
1524
|
this.stopping = false;
|
|
1502
1525
|
this.suspended = false;
|
|
@@ -1514,6 +1537,7 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1514
1537
|
* and dispatches locally.
|
|
1515
1538
|
*/
|
|
1516
1539
|
handleTransportMessage(message) {
|
|
1540
|
+
if (this.isDuplicate(message)) return;
|
|
1517
1541
|
this.trace.recordReceived(message.topic);
|
|
1518
1542
|
if (!this.cluster.isAssigned(message.topic)) {
|
|
1519
1543
|
this.trace.recordDiscarded(message.topic);
|
|
@@ -1526,6 +1550,21 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1526
1550
|
}
|
|
1527
1551
|
this.trace.recordDiscarded(message.topic);
|
|
1528
1552
|
}
|
|
1553
|
+
isDuplicate(message) {
|
|
1554
|
+
if (!this.dedupEnabled || !message.messageId) return false;
|
|
1555
|
+
const now = Date.now();
|
|
1556
|
+
for (const [id, timestamp] of this.seenMessageIds) {
|
|
1557
|
+
if (now - timestamp > this.dedupTtlMs) this.seenMessageIds.delete(id);
|
|
1558
|
+
}
|
|
1559
|
+
if (this.seenMessageIds.has(message.messageId)) return true;
|
|
1560
|
+
this.seenMessageIds.set(message.messageId, now);
|
|
1561
|
+
while (this.seenMessageIds.size > this.dedupMaxEntries) {
|
|
1562
|
+
const oldest = this.seenMessageIds.keys().next().value;
|
|
1563
|
+
if (oldest === void 0) break;
|
|
1564
|
+
this.seenMessageIds.delete(oldest);
|
|
1565
|
+
}
|
|
1566
|
+
return false;
|
|
1567
|
+
}
|
|
1529
1568
|
/** Deliver a message to every local handler registered for its topic,
|
|
1530
1569
|
* plus every handler registered with a wildcard subscription that matches
|
|
1531
1570
|
* (e.g. a handler subscribed to "chat.*" receives "chat.room.1"). */
|
|
@@ -1610,6 +1649,7 @@ var CrossTabDataBus = class _CrossTabDataBus {
|
|
|
1610
1649
|
const now = Date.now();
|
|
1611
1650
|
if (now - this.lastRecoveryAt >= _CrossTabDataBus.RECOVERY_COOLDOWN_MS) {
|
|
1612
1651
|
this.lastRecoveryAt = now;
|
|
1652
|
+
this.trace.event({ type: "reliability", operation: "transport_recovery", attempt: 1 });
|
|
1613
1653
|
setTimeout(() => {
|
|
1614
1654
|
if (this.stopping || !this.started || this.suspended) return;
|
|
1615
1655
|
if (this.status !== "error") return;
|