cross-tab-worker-databus 0.21.12 → 0.21.13
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 +16 -0
- package/dist/centrifuge-protocol.d.ts.map +1 -1
- package/dist/centrifuge-session.d.ts +10 -3
- package/dist/centrifuge-session.d.ts.map +1 -1
- package/dist/centrifuge.d.ts +10 -4
- package/dist/centrifuge.d.ts.map +1 -1
- package/dist/centrifuge.js +23 -11
- package/dist/centrifuge.js.map +2 -2
- package/dist/centrifuge.shared.worker.js +28 -11
- package/dist/centrifuge.shared.worker.js.map +2 -2
- package/dist/centrifuge.worker.js +10 -3
- package/dist/centrifuge.worker.js.map +2 -2
- package/dist/{chunk-TSTV3SDC.js → chunk-4HW6PYIR.js} +67 -33
- package/dist/chunk-4HW6PYIR.js.map +7 -0
- package/dist/{chunk-2TTJ7LGZ.js → chunk-NPFTD7YE.js} +1 -1
- package/dist/chunk-NPFTD7YE.js.map +7 -0
- package/dist/cjs/centrifuge.cjs +86 -40
- package/dist/cjs/centrifuge.cjs.map +2 -2
- package/dist/cjs/hooks.cjs.map +2 -2
- package/dist/cjs/index.cjs +80 -36
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/cjs/vue.cjs.map +2 -2
- package/dist/core/cluster.d.ts +33 -16
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/data-bus.d.ts +19 -5
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/dedup-manager.d.ts +6 -3
- package/dist/core/dedup-manager.d.ts.map +1 -1
- package/dist/core/environment.d.ts +14 -5
- package/dist/core/environment.d.ts.map +1 -1
- package/dist/core/hash.d.ts +10 -4
- package/dist/core/hash.d.ts.map +1 -1
- package/dist/core/replay-manager.d.ts +2 -1
- package/dist/core/replay-manager.d.ts.map +1 -1
- package/dist/core/routing.d.ts +18 -9
- package/dist/core/routing.d.ts.map +1 -1
- package/dist/core/storage-batch.d.ts +2 -2
- package/dist/core/storage-batch.d.ts.map +1 -1
- package/dist/core/trace.d.ts +21 -9
- package/dist/core/trace.d.ts.map +1 -1
- package/dist/core/types.d.ts +13 -5
- package/dist/core/types.d.ts.map +1 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +1 -1
- package/dist/hooks.js.map +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -7
- package/dist/index.js.map +2 -2
- package/dist/utils/constants.d.ts +7 -4
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/validation.d.ts +12 -4
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/vue.js +1 -1
- package/dist/websocket.d.ts +24 -6
- package/dist/websocket.d.ts.map +1 -1
- package/dist/workers/port-reaper.d.ts +18 -8
- package/dist/workers/port-reaper.d.ts.map +1 -1
- package/docs/api.md +6 -5
- package/docs/benchmarks.md +9 -9
- package/docs/release-checklist.md +3 -3
- package/docs/roadmap.md +31 -1
- package/docs/transports.md +3 -2
- package/docs/zh/api.md +6 -5
- package/docs/zh/benchmarks.md +9 -9
- package/docs/zh/release-checklist.md +3 -3
- package/docs/zh/roadmap.md +22 -1
- package/docs/zh/transports.md +2 -1
- package/package.json +2 -1
- package/dist/chunk-2TTJ7LGZ.js.map +0 -7
- package/dist/chunk-TSTV3SDC.js.map +0 -7
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/utils/constants.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * \u516C\u5171\u5B57\u7B26\u4E32\u5E38\u91CF \u2014\u2014 \u751F\u547D\u5468\u671F\u72B6\u6001\u3001\u89D2\u8272\u3001\u63A7\u5236\u52A8\u4F5C\u3001\u534F\u8BAE\u6D88\u606F\u7C7B\u578B\u3001\u679A\u4E3E\u4E0E\n * \u547D\u540D\u7A7A\u95F4\u524D\u7F00\u3002\n *\n * \u6240\u6709\u8FD0\u884C\u65F6\u4F7F\u7528\u7684\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u96C6\u4E2D\u5728\u6B64\u4E00\u4EFD\u503C\uFF0C\u7C7B\u578B\u5B9A\u4E49\uFF08src/core/types.ts\n * \u7B49\uFF09\u901A\u8FC7 `(typeof X)[keyof typeof X]` \u4ECE\u8FD9\u4E9B\u5E38\u91CF\u6D3E\u751F\uFF0C\u6BD4\u8F83/switch \u5904\u5F15\u7528\n * \u540C\u4E00\u5BF9\u8C61\u6210\u5458\u3002\u8FD9\u6837\u65E2\u80FD\u6D88\u9664\u6563\u843D\u5728\u5404\u6587\u4EF6\u91CC\u7684\u91CD\u590D\u5B57\u7B26\u4E32\uFF08\u907F\u514D\u5927\u5C0F\u5199\u4E0D\u7EDF\u4E00\n * \u6216\u7B14\u8BEF\uFF09\uFF0C\u53C8\u4FDD\u8BC1\u7C7B\u578B\u4E0E\u503C\u6C38\u4E0D\u9519\u4F4D\u3002\n *\n * ## \u4F7F\u7528\u7EA6\u5B9A\n *\n * - **\u65B0\u589E\u6216\u4FEE\u6539\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u65F6\uFF0C\u5148\u5230\u8FD9\u91CC\u67E5\u627E/\u589E\u8865\uFF0C\u4E0D\u8981\u5728\u4E1A\u52A1\u6587\u4EF6\u91CC\u76F4\u63A5\u5199\n * \u9B54\u6CD5\u5B57\u7B26\u4E32\u3002** \u626B\u63CF\u6B8B\u7559\u5B57\u9762\u91CF\uFF1A`rg \"'(['a-z]+)'\" src/`\u3002\n * - **\u53EA\u7528\u4E8E\u7C7B\u578B\u4F4D\u7F6E\u7684\u5E38\u91CF**\uFF08\u5373\u53EA\u51FA\u73B0\u5728 `typeof X[keyof typeof X]` \u8FD9\u7C7B\u6D3E\u751F\u91CC\u3001\n * \u4ECE\u4E0D\u53C2\u4E0E\u8FD0\u884C\u65F6\u6BD4\u8F83\u7684\uFF09\u5728\u8C03\u7528\u65B9\u7528 `import type`\uFF1B**\u5728\u8FD0\u884C\u65F6\u6BD4\u8F83/\u6784\u9020\u4E2D\u4F7F\u7528\u7684**\n * \uFF08\u5982 `WORKER_STATUS.ERROR`\u3001`TRACE_EVENT_TYPE.LIFECYCLE`\u3001\n * `PERSISTENCE_OPERATION.APPEND`\uFF09\u5FC5\u987B\u7528\u503C\u5BFC\u5165\uFF0C\u5426\u5219\u4F1A\u62A5 \"cannot be used as\n * a value because it was imported using 'import type'\"\u3002`PERSISTENCE_OPERATION`\n * \u5C5E\u4E8E\u540E\u8005\u800C\u4E0D\u662F\u7C7B\u578B\u4FA7\u7684\u4F8B\u5B50\uFF1A`replay-manager.ts` \u4EE5\u503C\u5BFC\u5165\u5B83\uFF0C\u5E76\u628A\u5B83\u7684\u6210\u5458\u4F5C\u4E3A\n * `withPersistenceRetry` \u7684\u7B2C\u4E00\u4E2A\u5B9E\u53C2\u4F20\u8FDB\u53BB\u3002\n * - **\u503C\u6D3E\u751F\u7C7B\u578B**\uFF1A`export type WorkerStatus = (typeof WORKER_STATUS)[keyof\n * typeof WORKER_STATUS]`\u3002\u8FD9\u6837\u65B0\u589E\u679A\u4E3E\u5206\u652F\u65F6\u7C7B\u578B\u81EA\u52A8\u6536\u7A84\uFF0C\u7F16\u8BD1\u5668\u4F1A\u6307\u51FA\n * \u6BCF\u4E2A\u9057\u6F0F\u7684 switch \u5206\u652F\u3002\n * - \u5206\u7EC4\u7684\u987A\u5E8F\uFF08\u72B6\u6001 / \u89D2\u8272 / \u540E\u7AEF / \u6D88\u606F\u7C7B\u578B / \u679A\u4E3E / \u524D\u7F00\uFF09\u4FDD\u6301\u7A33\u5B9A\uFF0C\u65B9\u4FBF\n * \u7EF4\u62A4\u8005\u4E00\u773C\u5B9A\u4F4D\u3002\n */\n\n// ---- \u751F\u547D\u5468\u671F\u72B6\u6001 / \u89D2\u8272 / \u53EF\u89C1\u6027 ----\nexport const WORKER_STATUS = {\n CONNECTING: 'connecting',\n CONNECTED: 'connected',\n DISCONNECTED: 'disconnected',\n ERROR: 'error',\n} as const;\n\nexport const WORKER_ROLE = {\n ACTIVE: 'active',\n STANDBY: 'standby',\n} as const;\n\nexport const TAB_VISIBILITY = {\n VISIBLE: 'visible',\n HIDDEN: 'hidden',\n} as const;\n\n// ---- Worker \u540E\u7AEF\u6A21\u5F0F\u4E0E\u89E3\u6790\u7ED3\u679C\uFF08WorkerMode / WorkerBackend\uFF09----\nexport const WORKER_MODE = {\n DEDICATED: 'dedicated',\n SHARED: 'shared',\n AUTO: 'auto',\n} as const;\n\nexport const WORKER_BACKEND = {\n DEDICATED: 'dedicated',\n SHARED: 'shared',\n LOCAL: 'local',\n} as const;\n\n// ---- \u5B58\u50A8\u4E8B\u4EF6\u901A\u9053\u56DE\u9000 ----\nexport const CHANNEL_FALLBACK = {\n NONE: 'none',\n STORAGE_EVENT: 'storage-event',\n} as const;\n\n// ---- Worker / MessagePort / BroadcastChannel \u7684 EventTarget \u4E8B\u4EF6\u540D\u5224\u522B ----\n// MessageEvent.type\uFF08'message' / 'messageerror'\uFF09\u4E0E Worker \u4E0A\u7684 'error' \u4E8B\u4EF6\u540D\uFF0C\n// \u7528\u4E8E\u73AF\u5883\u9002\u914D\u5668\u63A5\u53E3\u7B7E\u540D\u4E0E\u6D4B\u8BD5\u66FF\u8EAB\u7684 addEventListener \u771F\u5047\u5206\u652F\u3002\nexport const EVENT_TYPE = {\n MESSAGE: 'message',\n MESSAGEERROR: 'messageerror',\n ERROR: 'error',\n} as const;\n\n// ---- \u63A7\u5236\u5E73\u9762\u52A8\u4F5C\uFF08WorkerControlAction\uFF09----\nexport const CONTROL_ACTION = {\n SUBSCRIBE: 'SUBSCRIBE',\n UNSUBSCRIBE: 'UNSUBSCRIBE',\n PUBLISH: 'PUBLISH',\n} as const;\n\n// ---- BroadcastChannel \u96C6\u7FA4\u6D88\u606F\u7C7B\u578B ----\nexport const CLUSTER_MESSAGE_TYPE = {\n CONTROL: 'CONTROL',\n EVENT: 'EVENT',\n REGISTRY: 'REGISTRY',\n ROUTE_RELEASED: 'ROUTE_RELEASED',\n} as const;\n\n// ---- \u547D\u540D\u7A7A\u95F4\u524D\u7F00\u4E0E\u4E8B\u4EF6\u540D ----\nexport const DEFAULT_STORAGE_PREFIX = 'cross-tab-worker-databus';\nexport const STORAGE_CHANNEL_PREFIX = `${DEFAULT_STORAGE_PREFIX}:channel:`;\nexport const TAB_ID_STORAGE_KEY = `${DEFAULT_STORAGE_PREFIX}:tab-id`;\nexport const PUBLICATION_EVENT = 'DATABUS_PUBLICATION';\n\n// ---- \u89C4\u8303 JSON \u4FE1\u5C01\u64CD\u4F5C\u7801 ----\nexport const PUBLICATION_ENVELOPE_OP = 'publication';\n\n// ---- trace \u4E8B\u4EF6\u7C7B\u578B ----\nexport const TRACE_EVENT_TYPE = {\n LIFECYCLE: 'lifecycle',\n STATUS: 'status',\n SUBSCRIPTION: 'subscription',\n COORDINATION: 'coordination',\n ERROR: 'error',\n RELIABILITY: 'reliability',\n MESSAGE_METRICS: 'message_metrics',\n} as const;\n\n// ---- trace \u751F\u547D\u5468\u671F\u52A8\u4F5C ----\nexport const TRACE_LIFECYCLE_ACTION = {\n START: 'start',\n STOP: 'stop',\n SUSPEND: 'suspend',\n RESUME: 'resume',\n} as const;\n\n// ---- \u5185\u90E8 handler \u8C03\u7528\u6807\u7B7E\uFF08\u9694\u79BB\u5F02\u5E38\u65F6\u7684\u5206\u7C7B\u6765\u6E90\uFF09----\nexport const INVOKE_LABEL = {\n DISPATCH: 'dispatch',\n STATUS: 'status',\n ERROR_HANDLER: 'error handler',\n} as const;\n\n// ---- trace \u6A21\u5F0F\uFF08DataBusTraceMode\uFF09----\nexport const TRACE_MODE = {\n EVENTS: 'events',\n METRICS: 'metrics',\n ALL: 'all',\n} as const;\n\n// ---- trace \u9519\u8BEF\u6765\u6E90 ----\nexport const TRACE_ERROR_SOURCE = {\n TRANSPORT: 'transport',\n OPERATION: 'operation',\n} as const;\n\n// ---- reliability \u8BCA\u65AD\u64CD\u4F5C ----\nexport const RELIABILITY_OPERATION = {\n TRANSPORT_RECOVERY: 'transport_recovery',\n ROUTE_ACK: 'route_ack',\n ROUTE_MIGRATION: 'route_migration',\n // A re-election that recovered a stranded unconfirmed handoff (previous\n // owner gone, ACK never arrived). Distinct from ROUTE_MIGRATION so trace\n // consumers can tell recoveries apart from routine graceful handoffs.\n ROUTE_MIGRATION_RECOVERY: 'route_migration_recovery',\n PERSISTENCE_CLEANUP: 'persistence_cleanup',\n PERSISTENCE_RETRY: 'persistence_retry',\n DEDUP_SUPPRESSED: 'dedup_suppressed',\n} as const;\n\n// ---- \u81EA\u52A8\u6062\u590D\u5C1D\u8BD5\u7ED3\u679C ----\nexport const RECOVERY_OUTCOME = {\n SCHEDULED: 'scheduled',\n SUCCEEDED: 'succeeded',\n FAILED: 'failed',\n EXHAUSTED: 'exhausted',\n} as const;\n\n// ---- \u8BA2\u9605\u52A8\u4F5C ----\nexport const SUBSCRIPTION_ACTION = {\n SUBSCRIBE: 'subscribe',\n UNSUBSCRIBE: 'unsubscribe',\n} as const;\n\n// ---- \u56DE\u653E\u4FEE\u526A\u7B56\u7565 ----\nexport const PRUNE_STRATEGY = {\n COUNT: 'count',\n AGE: 'age',\n BOTH: 'both',\n} as const;\n\n// ---- \u6301\u4E45\u5316\u64CD\u4F5C ----\nexport const PERSISTENCE_OPERATION = {\n LOAD: 'load',\n APPEND: 'append',\n CLEAR: 'clear',\n CLEAR_TOPIC: 'clearTopic',\n CLEAR_BEFORE: 'clearBefore',\n} as const;\n\n// ---- \u6545\u969C\u6765\u6E90\uFF08DataBusFailureSource\uFF09----\nexport const FAILURE_SOURCE = {\n TRANSPORT: 'transport',\n PERSISTENCE: 'persistence',\n DISPATCH: 'dispatch',\n} as const;\n\n// ---- \u5065\u5EB7\u5224\u5B9A\u72B6\u6001\uFF08DataBusHealthSummary['state']\uFF09----\nexport const HEALTH_STATE = {\n STOPPED: 'stopped',\n STARTING: 'starting',\n HEALTHY: 'healthy',\n RECOVERING: 'recovering',\n SUSPENDED: 'suspended',\n DEGRADED: 'degraded',\n} as const;\n\n// ---- WebSocket wire \u534F\u8BAE\u64CD\u4F5C\u7801 ----\nexport const WS_OP = {\n SUBSCRIBE: 'subscribe',\n UNSUBSCRIBE: 'unsubscribe',\n PUBLISH: 'publish',\n PUBLISH_BATCH: 'publishBatch',\n} as const;\n\n// ---- Centrifuge Worker \u8F93\u5165\u6D88\u606F\u7C7B\u578B ----\nexport const CENTRIFUGE_INPUT_TYPE = {\n INIT: 'INIT',\n SUBSCRIBE: 'SUBSCRIBE',\n UNSUBSCRIBE: 'UNSUBSCRIBE',\n PUBLISH: 'PUBLISH',\n PUBLISH_BIN: 'PUBLISH_BIN',\n PING: 'PING',\n STOP: 'STOP',\n TOKEN_RESPONSE: 'TOKEN_RESPONSE',\n TOKEN_ERROR: 'TOKEN_ERROR',\n} as const;\n\n// ---- Centrifuge Worker \u8F93\u51FA\u6D88\u606F\u7C7B\u578B ----\nexport const CENTRIFUGE_OUTPUT_TYPE = {\n STATUS: 'STATUS',\n MESSAGE: 'MESSAGE',\n MESSAGE_BIN: 'MESSAGE_BIN',\n ERROR: 'ERROR',\n TOKEN_REQUEST: 'TOKEN_REQUEST',\n SESSION_REAPED: 'SESSION_REAPED',\n} as const;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/cjs/centrifuge.cjs
CHANGED
|
@@ -444,8 +444,8 @@ var BatchingStorageWriter = class {
|
|
|
444
444
|
retryHandle = null;
|
|
445
445
|
retryDelayMs = INITIAL_RETRY_DELAY_MS;
|
|
446
446
|
/** Number of writes queued in memory but not yet flushed to storage.
|
|
447
|
-
*
|
|
448
|
-
* the
|
|
447
|
+
* Test-only as a reader: `flush()` tests `pending.size` directly rather than
|
|
448
|
+
* going through this getter, so it is not part of the drain decision. */
|
|
449
449
|
get pendingSize() {
|
|
450
450
|
return this.pending.size;
|
|
451
451
|
}
|
|
@@ -783,8 +783,9 @@ var WorkerClusterRuntime = class {
|
|
|
783
783
|
// Topics this tab has subscribed to (local interest, plaintext).
|
|
784
784
|
subscribedTopics = /* @__PURE__ */ new Set();
|
|
785
785
|
// Topics assigned to this Worker as owner (topicKey → topic). Authoritative:
|
|
786
|
-
// membership drives isAssigned() and load.
|
|
787
|
-
//
|
|
786
|
+
// membership drives isAssigned() and load. Grown by exactly three writers —
|
|
787
|
+
// CONTROL/SUBSCRIBE, ROUTE_RELEASED (completing a handoff this worker accepted),
|
|
788
|
+
// and local self-subscribe — and never by the reverse cache.
|
|
788
789
|
assignedTopics = /* @__PURE__ */ new Map();
|
|
789
790
|
routeOwnerCache = /* @__PURE__ */ new Map();
|
|
790
791
|
routeOwnerCacheMax;
|
|
@@ -1178,9 +1179,12 @@ var WorkerClusterRuntime = class {
|
|
|
1178
1179
|
windowMs,
|
|
1179
1180
|
messageCount: this.throughputWindow.messageCount,
|
|
1180
1181
|
byteCount: this.throughputWindow.byteCount,
|
|
1181
|
-
// How much later the
|
|
1182
|
-
// window is anchored at the previous writeRecord
|
|
1183
|
-
//
|
|
1182
|
+
// How much later the last record write landed relative to a nominal
|
|
1183
|
+
// heartbeat interval. The window is anchored at the previous writeRecord,
|
|
1184
|
+
// which the heartbeat tick causes but activation, a status change, a
|
|
1185
|
+
// visibility change and a load update also cause — so a worker writing on
|
|
1186
|
+
// any of those shorter paths yields a small window and a clamped zero.
|
|
1187
|
+
// A starved event loop stretches the window past the interval, and the
|
|
1184
1188
|
// positive excess is the scheduling-overrun signal.
|
|
1185
1189
|
overrunMs: Math.max(0, windowMs - this.heartbeatIntervalMs),
|
|
1186
1190
|
sampledAt: now
|
|
@@ -1345,11 +1349,13 @@ var WorkerClusterRuntime = class {
|
|
|
1345
1349
|
else this.handlers.onControl(message.action, message.topic, message.data);
|
|
1346
1350
|
if (message.action !== CONTROL_ACTION.PUBLISH) this.updateLoad();
|
|
1347
1351
|
}
|
|
1348
|
-
/**
|
|
1349
|
-
*
|
|
1350
|
-
*
|
|
1351
|
-
*
|
|
1352
|
-
* handoff
|
|
1352
|
+
/** Drop this worker's ownership of the topic, then — only when this worker is
|
|
1353
|
+
* the previous owner in a graceful handoff and the new owner is asking us to
|
|
1354
|
+
* unsubscribe — release the old transport subscription and ACK the handoff with
|
|
1355
|
+
* ROUTE_RELEASED. The ownership delete runs for *every* CONTROL/UNSUBSCRIBE,
|
|
1356
|
+
* before the handoff test; the handoff legs below do not gate it. Returns true
|
|
1357
|
+
* when the message was a handoff release (the generic CONTROL dispatch must not
|
|
1358
|
+
* run as well).
|
|
1353
1359
|
*/
|
|
1354
1360
|
releaseHandoffOnUnsubscribe(message) {
|
|
1355
1361
|
this.assignedTopics.delete(message.topicKey);
|
|
@@ -1571,7 +1577,10 @@ var WorkerClusterRuntime = class {
|
|
|
1571
1577
|
}
|
|
1572
1578
|
return Array.from(subscribers);
|
|
1573
1579
|
}
|
|
1574
|
-
/** Read the current route for `topicKey
|
|
1580
|
+
/** Read the current route for `topicKey`. With a storage layer this returns
|
|
1581
|
+
* the durable route, or null when none is recorded. Without one (degraded
|
|
1582
|
+
* mode) it returns the synthesized local route from `buildLocalRoute`, which
|
|
1583
|
+
* is itself null unless this worker actually holds the topic. */
|
|
1575
1584
|
readRoute(topicKey) {
|
|
1576
1585
|
if (!this.storage) return this.buildLocalRoute(topicKey);
|
|
1577
1586
|
return readJson(this.storage, this.routeStorageKey(topicKey));
|
|
@@ -1652,8 +1661,9 @@ var WorkerClusterRuntime = class {
|
|
|
1652
1661
|
* @param notify — when true, broadcast a REGISTRY nudge so peers reconcile
|
|
1653
1662
|
* immediately instead of waiting for the next heartbeat. False on the
|
|
1654
1663
|
* periodic heartbeat tick (peers will notice on their own heartbeat) to
|
|
1655
|
-
* avoid a REGISTRY storm every 3 s
|
|
1656
|
-
*
|
|
1664
|
+
* avoid a REGISTRY storm every 3 s. Which sites pass what: activation,
|
|
1665
|
+
* status, visibility and load changes pass true; the heartbeat tick and a
|
|
1666
|
+
* role change pass false. */
|
|
1657
1667
|
writeRecord(notify) {
|
|
1658
1668
|
const now = this.environment.now();
|
|
1659
1669
|
const sample = this.loadWeighting !== void 0 ? this.sampleThroughput(now) : void 0;
|
|
@@ -1689,10 +1699,15 @@ var WorkerClusterRuntime = class {
|
|
|
1689
1699
|
* Despite the name, this is NOT a cache lookup — it unconditionally writes
|
|
1690
1700
|
* the `topicKey → topic` pair. Hashing is cheap enough that a caller needing
|
|
1691
1701
|
* the key should always call this rather than check `knownTopics` first;
|
|
1692
|
-
* the cache's FIFO eviction below keeps it bounded.
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
1695
|
-
*
|
|
1702
|
+
* the cache's FIFO eviction below keeps it bounded. Two sites deliberately
|
|
1703
|
+
* bypass it, and for the same kind of reason — neither may write a plaintext
|
|
1704
|
+
* into the reverse cache before it is authorized: `isAssigned` re-derives the
|
|
1705
|
+
* key as a read-only query, and the `ROUTE_RELEASED` handler hashes the
|
|
1706
|
+
* frame's own `topic` only to compare it against `topicKey`, on a channel
|
|
1707
|
+
* where that field is attacker-controlled until the comparison passes. (The
|
|
1708
|
+
* `CONTROL` handler performs the same re-derivation but then *does* call this
|
|
1709
|
+
* method, so it is not a bypass.) If you add a new call site, prefer
|
|
1710
|
+
* `rememberTopic` unless you have one of those reasons.
|
|
1696
1711
|
*/
|
|
1697
1712
|
rememberTopic(topic) {
|
|
1698
1713
|
const topicKey = createOpaqueKey(topic);
|
|
@@ -1766,8 +1781,10 @@ var DataBusTraceReporter = class {
|
|
|
1766
1781
|
this.asyncSink = options?.asyncSink ?? false;
|
|
1767
1782
|
this.now = now;
|
|
1768
1783
|
}
|
|
1769
|
-
/** Start the periodic metrics flush interval.
|
|
1770
|
-
*
|
|
1784
|
+
/** Start the periodic metrics flush interval. Only the `!enabled` return is a
|
|
1785
|
+
* true no-op: in 'events' mode, or with an interval already armed, it returns
|
|
1786
|
+
* without arming anything but has already cleared `stopped` one statement
|
|
1787
|
+
* earlier — which is what re-opens the event stream after a `stop()`. */
|
|
1771
1788
|
start() {
|
|
1772
1789
|
if (!this.enabled) return;
|
|
1773
1790
|
this.stopped = false;
|
|
@@ -1874,9 +1891,11 @@ var DataBusTraceReporter = class {
|
|
|
1874
1891
|
recordDedupSuppressed() {
|
|
1875
1892
|
if (this.metricsActive) this.dedupSuppressed += 1;
|
|
1876
1893
|
}
|
|
1877
|
-
/** True when metrics recording is active: enabled and mode
|
|
1878
|
-
* Extracted so the
|
|
1879
|
-
*
|
|
1894
|
+
/** True when metrics recording is active: enabled, not stopped, and the mode
|
|
1895
|
+
* includes metrics. Extracted so the seven readers — `getMetrics`, the five
|
|
1896
|
+
* `record*` methods and `flush` — share one guard instead of repeating it.
|
|
1897
|
+
* The `!stopped` term is part of the contract, not a bonus: `event()` does not
|
|
1898
|
+
* go through this getter and gates on `stopped` itself. */
|
|
1880
1899
|
get metricsActive() {
|
|
1881
1900
|
return this.enabled && !this.stopped && this.mode !== TRACE_MODE.EVENTS;
|
|
1882
1901
|
}
|
|
@@ -2140,7 +2159,8 @@ var ReplayManager = class {
|
|
|
2140
2159
|
}
|
|
2141
2160
|
}
|
|
2142
2161
|
}
|
|
2143
|
-
/** Clear replay history for one exact topic,
|
|
2162
|
+
/** Clear replay history for one exact topic, and for its durable history when
|
|
2163
|
+
* the injected adapter provides the optional `clearTopic`. */
|
|
2144
2164
|
async clearTopic(topic) {
|
|
2145
2165
|
if (!this.buffers) return;
|
|
2146
2166
|
const clearing = this.persistence?.clearTopic ? this.withPersistenceRetry(PERSISTENCE_OPERATION.CLEAR_TOPIC, () => this.persistence.clearTopic(topic)) : null;
|
|
@@ -2519,7 +2539,7 @@ var DedupManager = class {
|
|
|
2519
2539
|
};
|
|
2520
2540
|
|
|
2521
2541
|
// src/core/version.ts
|
|
2522
|
-
var SDK_VERSION = true ? "0.21.
|
|
2542
|
+
var SDK_VERSION = true ? "0.21.13" : "";
|
|
2523
2543
|
|
|
2524
2544
|
// src/core/data-bus.ts
|
|
2525
2545
|
var DEFAULT_REPLAY_MAX_PER_TOPIC = 100;
|
|
@@ -3050,7 +3070,10 @@ var CrossTabDataBus = class {
|
|
|
3050
3070
|
async clearReplay() {
|
|
3051
3071
|
await this.replayManager.clearAll();
|
|
3052
3072
|
}
|
|
3053
|
-
/** Clear replay history for one exact topic,
|
|
3073
|
+
/** Clear replay history for one exact topic and, when the persistence adapter
|
|
3074
|
+
* implements `clearTopic`, its durable history too — an adapter without that
|
|
3075
|
+
* optional method leaves the persisted rows in place, exactly as `clearReplay`
|
|
3076
|
+
* does. */
|
|
3054
3077
|
async clearReplayTopic(topic) {
|
|
3055
3078
|
await this.replayManager.clearTopic(topic);
|
|
3056
3079
|
}
|
|
@@ -3445,9 +3468,14 @@ var CrossTabDataBus = class {
|
|
|
3445
3468
|
});
|
|
3446
3469
|
}
|
|
3447
3470
|
/** Emit the coordination trace snapshot from the current cluster state.
|
|
3448
|
-
* Called
|
|
3449
|
-
*
|
|
3450
|
-
*
|
|
3471
|
+
* Called once per successful `start()`: `reopenTransport()`'s settle arms do not
|
|
3472
|
+
* emit, so a recovery produces no second snapshot. It runs after the opening
|
|
3473
|
+
* resolves — and not because a pre-open read would see no routes, which is the
|
|
3474
|
+
* wrong mechanism and was the shipped claim until it was measured: a snapshot
|
|
3475
|
+
* taken with the opening still unresolved already listed the route, its
|
|
3476
|
+
* confirmation and both tabs' worker records, because
|
|
3477
|
+
* `BatchingStorageWriter` serves pending writes on read (`storage-batch.ts:79-82`
|
|
3478
|
+
* for `getItem`, `:143-155` for the `keys()` union that `readAllByPrefix` uses). */
|
|
3451
3479
|
emitCoordinationTrace() {
|
|
3452
3480
|
const snapshot = this.cluster.getSnapshot();
|
|
3453
3481
|
this.trace.event({
|
|
@@ -3641,7 +3669,13 @@ var CrossTabDataBus = class {
|
|
|
3641
3669
|
}
|
|
3642
3670
|
/**
|
|
3643
3671
|
* Ensure the DataBus is started, throwing if no initialConfig was provided.
|
|
3644
|
-
*
|
|
3672
|
+
* subscribe/publish/ready call this *unconditionally*: the gate is the
|
|
3673
|
+
* `hasInitialConfig` check below, not the `autoStart` option. `autoStart`
|
|
3674
|
+
* participates in exactly one place, the constructor's
|
|
3675
|
+
* `if (autoStart ?? this.hasInitialConfig)`, where it overrides the default rather
|
|
3676
|
+
* than enabling a later path — so `autoStart: true` with no `initialConfig` throws
|
|
3677
|
+
* from the constructor. `docs/configuration.md`'s "`true` when `initialConfig` is
|
|
3678
|
+
* provided" row describes that single site.
|
|
3645
3679
|
*/
|
|
3646
3680
|
ensureStarted() {
|
|
3647
3681
|
if (this.started) return;
|
|
@@ -3839,9 +3873,16 @@ var CentrifugeSession = class {
|
|
|
3839
3873
|
* same emptiness before calling, and the subscription-level caller reads the
|
|
3840
3874
|
* topic out of a key this session only ever populates from a SUBSCRIBE frame.
|
|
3841
3875
|
* Measured — deleting this line leaves all 37 test files green, and the frame
|
|
3842
|
-
* it withholds
|
|
3843
|
-
*
|
|
3844
|
-
*
|
|
3876
|
+
* it withholds has nowhere to land anyway: the only handler registry is the
|
|
3877
|
+
* DataBus's `topicHandlers`, and every write to it sits behind
|
|
3878
|
+
* `assertPublicTopic` (`data-bus.ts:929`, `:1009`, `:1033`), so no `''` key can
|
|
3879
|
+
* exist — while `topicMatchesPattern` answers false for an empty topic against
|
|
3880
|
+
* both `*` and `prefix.*`, so a wildcard handler cannot see it either. Neither
|
|
3881
|
+
* of those is a reason to delete this guard: it is the only one *at this layer*,
|
|
3882
|
+
* because neither the session nor the transport calls `assertPublicTopic` — a
|
|
3883
|
+
* SUBSCRIBE frame naming `''` creates a real Centrifuge subscription
|
|
3884
|
+
* (`newSubscription` does not validate a channel), so the undeliverable
|
|
3885
|
+
* publication would otherwise be posted back to the main thread. Kept as the
|
|
3845
3886
|
* boundary statement, not counted as a closed leg. */
|
|
3846
3887
|
postPublication(topic, data) {
|
|
3847
3888
|
if (!topic) return;
|
|
@@ -3959,12 +4000,17 @@ var CentrifugeWorkerTransport = class {
|
|
|
3959
4000
|
heartbeatHandle = null;
|
|
3960
4001
|
localSession = null;
|
|
3961
4002
|
handlers = null;
|
|
3962
|
-
// Monotonically increasing counter, bumped
|
|
3963
|
-
//
|
|
3964
|
-
//
|
|
3965
|
-
//
|
|
3966
|
-
//
|
|
3967
|
-
//
|
|
4003
|
+
// Monotonically increasing counter, bumped when a *Worker* backend is created
|
|
4004
|
+
// (`startDedicatedWorker`, `startSharedWorker`) and when the transport stops.
|
|
4005
|
+
// The in-process `localSession` creation does not bump it, which is why
|
|
4006
|
+
// `isCurrentBackend()` compares worker/port/localSession identity as well.
|
|
4007
|
+
// Only the asynchronous credential bridge reads the counter: a provider may
|
|
4008
|
+
// settle after the backend it was answering is gone. Worker error events need
|
|
4009
|
+
// no such check, but not for the reason this note used to give — `stop()`
|
|
4010
|
+
// bumps at `:189` and removes the listeners at `:193-194`, so the generation
|
|
4011
|
+
// moves on *before* the removal, not after. The containment is that both
|
|
4012
|
+
// happen in one synchronous task, together with `handlers = null`, and no
|
|
4013
|
+
// message or error event can be delivered to this object mid-task.
|
|
3968
4014
|
generation = 0;
|
|
3969
4015
|
get diagnosticsBackend() {
|
|
3970
4016
|
return this.backend ?? "uninitialized";
|