cross-tab-worker-databus 0.20.95 → 0.20.97
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 +29 -0
- package/dist/centrifuge.d.ts.map +1 -1
- package/dist/centrifuge.js +1 -7
- package/dist/centrifuge.js.map +2 -2
- package/dist/{chunk-7BPB2Y4E.js → chunk-IVTDQ2KD.js} +20 -2
- package/dist/{chunk-7BPB2Y4E.js.map → chunk-IVTDQ2KD.js.map} +2 -2
- package/dist/cjs/centrifuge.cjs +19 -7
- package/dist/cjs/centrifuge.cjs.map +2 -2
- package/dist/cjs/index.cjs +19 -1
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/core/data-bus.d.ts +6 -0
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/docs/api.md +1 -0
- package/docs/architecture.md +3 -0
- package/docs/benchmarks.md +8 -8
- package/docs/getting-started.md +4 -0
- package/docs/roadmap.md +19 -1
- package/docs/transports.md +1 -0
- package/docs/zh/api.md +1 -0
- package/docs/zh/architecture.md +3 -0
- package/docs/zh/benchmarks.md +8 -8
- package/docs/zh/getting-started.md +4 -0
- package/docs/zh/roadmap.md +19 -1
- package/docs/zh/transports.md +1 -0
- package/package.json +4 -3
package/dist/core/data-bus.d.ts
CHANGED
|
@@ -196,6 +196,7 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
|
|
|
196
196
|
private recoveryCancellationToken;
|
|
197
197
|
private recoveryDemandAllowed;
|
|
198
198
|
private recoveryWaiters;
|
|
199
|
+
private emptyTopicWarned;
|
|
199
200
|
/** Monotonic generation incremented on every successful transport open.
|
|
200
201
|
* Stays in lockstep with `lastSuccessAt` so callers can detect that the
|
|
201
202
|
* transport has been reopened even if the timestamp window is short. */
|
|
@@ -289,6 +290,11 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
|
|
|
289
290
|
getDedupStats(): DataBusDedupStats;
|
|
290
291
|
/** Drop all remembered IDs and reset dedup counters. */
|
|
291
292
|
resetDedup(): void;
|
|
293
|
+
/** Warn (once per bus) that an empty topic is deprecated, without changing
|
|
294
|
+
* behavior yet. `''` flows through routing as a literal channel, so the
|
|
295
|
+
* subscription it creates can never be addressed by a transport: the message
|
|
296
|
+
* silently goes nowhere. A future minor rejects it at this boundary. */
|
|
297
|
+
private warnEmptyTopic;
|
|
292
298
|
/** Publish a message to `topic`. The owning Worker delivers it to the transport. */
|
|
293
299
|
publish(topic: string, data: unknown, options?: DataBusPublishOptions): void;
|
|
294
300
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-bus.d.ts","sourceRoot":"","sources":["../../src/core/data-bus.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"data-bus.d.ts","sourceRoot":"","sources":["../../src/core/data-bus.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
package/docs/api.md
CHANGED
|
@@ -95,6 +95,7 @@ Registers a local subscription and returns a cleanup function.
|
|
|
95
95
|
- Subscriptions are automatically queued when the transport is not yet ready, including while a transport recovery is pending: they are held behind the recovery gate and issued once the reopen succeeds instead of being written to the connection that just reported `error`.
|
|
96
96
|
- A subscription requested while an explicit `stop()` is settling is not registered: `subscribe()` reports the rejection through `onError` and returns a no-op cleanup function. Wait for `stop()` to settle, then call `start()` before subscribing again.
|
|
97
97
|
- Wildcard subscriptions: a topic ending in `.*` (`chat.*`) matches any remainder, and `*` matches everything. The pattern is routed, owned, and transport-subscribed as a literal channel; publications tagged with a matching concrete topic (or with the pattern itself) are delivered to wildcard handlers. See `topicMatchesPattern` below.
|
|
98
|
+
- Topics must be non-empty. `''` is still accepted and routed as a literal channel, but no transport can address it, so nothing is ever delivered; the bus logs one `console.warn` per instance the first time `subscribe`/`publish`/`publishBatch` is called with it. A future minor rejects an empty topic at this boundary, consistent with the option-validation guards.
|
|
98
99
|
- Replay (opt-in): construct the bus with `replay: { maxPerTopic }` and pass `{ replay: true | n }` as the third `subscribe()` argument. `maxPerTopic` must be a positive safe integer. The new handler immediately receives the buffered history (up to `n`, capped by `maxPerTopic`, default 100) with `message.replayed: true`, so late joiners do not miss earlier publications. Only dispatched publications are buffered (a topic with no local subscriber drops them as unowned); buffers are in-memory and cleared when the last handler for the topic unsubscribes. Wildcard subscriptions replay across every buffered topic matching the pattern. For reload/BFCache persistence, pass an optional `persistence` created by `createIndexedDbReplayPersistence({ maxPerTopic })`; persistence is asynchronous and failures are reported through `onError` without breaking live delivery. Set `retentionMs` to prune expired producer-timestamped history in memory and to sweep adapters that implement `clearBefore` during hydration and after appends. Set `persistenceRetry: { maxAttempts, backoffMs }` to retry transient persistence failures; defaults preserve one-attempt behavior. Set `pruneStrategy` to `'count'` (default), `'age'`, or `'both'` to cap by `maxPerTopic`, prune timestamped history by `retentionMs`, or apply both. Under `age`, timestamp-less legacy entries are retained but capped by `maxPerTopic`; timestamped entries are bounded by the retention window.
|
|
99
100
|
When tracing is enabled, retries emit `reliability` events with `operation: 'persistence_retry'`, a bounded `persistenceOperation`, and `attempt`.
|
|
100
101
|
|
package/docs/architecture.md
CHANGED
|
@@ -548,6 +548,9 @@ These invariants are pinned by regression tests (see `tests/stability.test.ts` a
|
|
|
548
548
|
- **Recovery waiter invalidation.** Each operation parked behind the recovery gate captures the recovery cancellation generation. `stop()` and `suspendTransport()` invalidate that generation when they supersede the recovery cycle, so a waiter whose microtask runs after an immediate explicit `start()` cannot replay into the replacement transport. The restarted cluster owns exactly one resubscription per assigned topic, and the stale operation cannot issue a duplicate subscription.
|
|
549
549
|
- **Hidden-document activation guard.** `WorkerClusterRuntime.start()` installs lifecycle listeners before it checks visibility. A start that reaches a hidden document records suspension without registering a worker, opening a channel, or starting heartbeats, so a restart queued behind an asynchronous stop cannot miss a `pagehide` during cleanup and reconnect in the background; the installed listener handles the later `pageshow`.
|
|
550
550
|
- **Handoff channel close ordering.** `pause()` defers the physical `channel.close()` by one task. Closing synchronously would discard messages still queued for delivery — including the handoff's `ROUTE_RELEASED` — stranding the handoff target with an unconfirmed route.
|
|
551
|
+
- **Unserved route drop.** A departing owner migrates only the routes that still have subscribers. When every remaining subscriber record of a route it owns has gone — a peer tab that died without releasing — the route is deleted instead of handed to a live peer, which would otherwise carry a transport subscription no Tab listens to. `pause()` runs no orphan-route cleanup (that lives in `reconcile`), so this is the only synchronous release of that record (pinned by regression).
|
|
552
|
+
- **Last-subscriber release.** An owning Worker learns a topic is unserved from the last subscriber's `CONTROL/UNSUBSCRIBE`: it drops the assignment *and* dispatches the release to its transport. Consuming the message inside the handoff short-circuit alone would leave the server subscription — and its inbound fan-out — alive after every tab has left.
|
|
553
|
+
- **Assignment drift repair.** Every reconcile tick drops any topic this Worker holds in `assignedTopics` once the durable route no longer names it, releasing the transport subscription as it goes. Ownership thus follows the storage record rather than whichever message arrived last: a stale `CONTROL/SUBSCRIBE`, a lost route write, or a tab that claimed a route it does not own all converge back to exactly one owner within a heartbeat. `tests/coordination-invariants.test.ts` fuzzes three tabs through those corruptions and asserts the quiescent result (pinned by regression: emptying this sweep makes the fuzzed end state fail).
|
|
551
554
|
- **Stranded-handoff recovery.** If the previous owner is gone and its `ROUTE_RELEASED` never arrives (dropped channel message under load, or a crash between the route write and the ACK), the reconcile loop re-elects a live owner once the unconfirmed handoff has been stuck longer than a worker TTL (10 s default): the route is rewritten with a fresh generation and the handoff marker cleared, so the normal confirmation path completes (pinned by regression). The age gate matters — a fresh unconfirmed route may simply be waiting out its confirmation flush — and while the previous owner is still alive the new owner keeps waiting, so the strict handoff keeps its no-overlap guarantee.
|
|
552
555
|
- **Loss and recovery matrix.** Each coordination message has a bounded recovery path: a lost `CONTROL/SUBSCRIBE` is re-sent by the heartbeat reconcile for any route still lacking `confirmedAt`; a lost `REGISTRY` nudge costs at most one heartbeat interval (3 s default) because every tick reconciles anyway; a lost `ROUTE_RELEASED` is recovered by reconcile re-election once the previous owner is gone and the handoff has been stuck longer than a worker TTL (see the stranded-handoff invariant above, pinned by regression); publications dropped during a transport disconnect window are the one documented unrecoverable loss (transport contract). The storage-event fallback channel guarantees value-change delivery via a monotonic sequence in the envelope, and a dropped dispatch recovers through the same reconcile loop.
|
|
553
556
|
- **Recovery diagnostics.** `getHealthSummary()` derives a single readiness verdict from the lifecycle flags (`stopped` / `starting` / `healthy` / `recovering` / `suspended` / `degraded`); the unified `lastFailure` ledger and persistence counters reset on every explicit `start()`.
|
package/docs/benchmarks.md
CHANGED
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
# Browser Benchmark Trend
|
|
4
4
|
|
|
5
|
-
> Data through 2026-09-
|
|
5
|
+
> Data through 2026-09-22, from the 44 archived `bench-results/browser-*.json` reports (run `pnpm bench:browser` to add one; regenerate this doc with `node scripts/bench-trend.mjs`).
|
|
6
6
|
|
|
7
7
|
The comparison baseline for release gating is `pnpm bench:compare --fail-above-pct 50`, which compares the newest report against the median of the same metric in the preceding reports (50% ceiling absorbs shared-runner noise; a single previous report was a fragile baseline because the in-page hot-path metrics alternate between a fast and a slow mode on identical code). This doc records the long-run picture: values are per-metric latencies where lower is better, and the last column is the best run inside the most recent 5 reports — not an all-time record, because the in-page matrix changed measurement semantics in early September 2026 and older reports are not comparable.
|
|
8
8
|
|
|
9
9
|
<!-- BENCH-TREND:BEGIN (machine-generated table) -->
|
|
10
10
|
| Metric | Previous (ms) | Latest (ms) | Δ | Best of last 5 runs (ms) |
|
|
11
11
|
|---|---|---|---|---|
|
|
12
|
-
| publish per-message (ms, lower is better) — dedicated |
|
|
13
|
-
| publish per-message (ms, lower is better) — shared | 34.
|
|
14
|
-
| wildcard dispatch ×1000 (ms, lower is better) |
|
|
15
|
-
| publishBatch ×1000 (ms, lower is better) | 4.
|
|
16
|
-
| dedup ×1000 (ms, lower is better) |
|
|
17
|
-
| trace + publish ×1000 (ms, lower is better) |
|
|
18
|
-
| first-packet cold dispatch (ms, lower is better) | 0
|
|
12
|
+
| publish per-message (ms, lower is better) — dedicated | 50.6466 | 51.8687 | +1.22 | 38.6243 |
|
|
13
|
+
| publish per-message (ms, lower is better) — shared | 34.0188 | 33.7528 | -0.27 | 33.7123 |
|
|
14
|
+
| wildcard dispatch ×1000 (ms, lower is better) | 7.2 | 8.1 | +0.90 | 5.8 |
|
|
15
|
+
| publishBatch ×1000 (ms, lower is better) | 4.7 | 4.7 | +0.00 | 3.5 |
|
|
16
|
+
| dedup ×1000 (ms, lower is better) | 14.8 | 16.1 | +1.30 | 10.6 |
|
|
17
|
+
| trace + publish ×1000 (ms, lower is better) | 6.3 | 5.7 | -0.60 | 4.6 |
|
|
18
|
+
| first-packet cold dispatch (ms, lower is better) | 0 | 0 | +0.00 | 0 |
|
|
19
19
|
<!-- BENCH-TREND:END -->
|
|
20
20
|
|
|
21
21
|
Notes:
|
package/docs/getting-started.md
CHANGED
|
@@ -150,6 +150,8 @@ Open `http://localhost:4173/examples/demo/` and open it in multiple browser Tabs
|
|
|
150
150
|
- Data flow animations, event stream, distribution latency metrics, and cluster Worker routing status
|
|
151
151
|
- SDK capability, transport configuration, active/standby Worker, and visible/hidden Tab state
|
|
152
152
|
|
|
153
|
+
Two more pages are served next to the demo. `http://localhost:4173/examples/react/` wires the framework-agnostic core by hand (effect, `subscribe`, status), while `http://localhost:4173/examples/vue/` uses nothing but the shipped `cross-tab-worker-databus/vue` composables. Both point at the same local demo endpoint, so a publication from one is received by a tab on any of the three pages that uses the same Topic — which is also how the adapter pages are covered by the browser suite (`e2e/adapters.spec.ts`).
|
|
154
|
+
|
|
153
155
|
When consuming the repository directly through a Git dependency, use a pinned commit. The repository ships `dist` so consumers do not need to build the SDK during installation.
|
|
154
156
|
|
|
155
157
|
## 9. Explicit Start
|
|
@@ -197,6 +199,8 @@ The fallback is opt-in because coordination payloads (plaintext topic names) the
|
|
|
197
199
|
|
|
198
200
|
Before `1.0.0` the SDK is allowed to grow additively and, behind an explicit deprecation cycle, remove APIs. The root export surface is pinned by the regression suite and a tag-to-tag compatibility gate, so an unintended removal fails CI rather than silently breaking consumers.
|
|
199
201
|
|
|
202
|
+
Currently deprecated: an empty topic string in `subscribe()`, `publish()` and `publishBatch()`. Calls with `""` still work and the bus warns once per instance, but no transport can address an empty channel, so nothing is ever delivered through it — the warning is about a subscription that cannot function, and a future minor will reject it outright.
|
|
203
|
+
|
|
200
204
|
When you upgrade:
|
|
201
205
|
|
|
202
206
|
- Read the CHANGELOG for each version between your current and target version. Every removal is called out there, and the deprecation cycle itself only forwards through minor versions.
|
package/docs/roadmap.md
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
# Roadmap
|
|
2
2
|
|
|
3
|
-
0.20.
|
|
3
|
+
0.20.97 was released on September 22, 2026. The project is intentionally continuing through reliability-focused releases before a 1.0.0 stability freeze.
|
|
4
|
+
|
|
5
|
+
## 0.20.97 delivered scope
|
|
6
|
+
|
|
7
|
+
- No public surface and no observable runtime behavior changed. The shipped `src/` delta is `centrifuge.ts` only: two unreachable `typeof Worker` / `typeof SharedWorker` throws removed, and comments recording why one guard survives while another does not. Everything else is example, test, CI and documentation work.
|
|
8
|
+
- The Vue adapter finally runs where it ships: `examples/vue/` mounts the real `cross-tab-worker-databus/vue` composables against the local demo endpoint from the installed `vue` package (no CDN), and `e2e/adapters.spec.ts` drives it in real Chromium tabs — publish/receive across two tabs, a reactive topic change releasing the old channel server-side, and delivery surviving the owning tab's close. Before this the Vue entry had never executed outside jsdom.
|
|
9
|
+
- The cluster's promise *between* tabs is now fuzzed rather than hand-ordered: three buses over one storage registry and BroadcastChannel through randomized subscribe/unsubscribe/publish/hide/show/stop/start/heartbeat/dropped-frame/forged-`SUBSCRIBE` interleavings, asserting at quiescence one owner and one transport holder per live topic, no residue for a departed topic, and exactly-once fan-out. Five mutations kill those arms; three guards survive because `reconcileAssignedTopics()` repairs them, which is recorded as the reason those belong to frame-level regressions.
|
|
10
|
+
- Two release-gate timing failures were traced to their causes instead of retried. The coordination fuzzer's `Date.now()` budget was reading a clock the suite fakes — a leaked fake `Date` in a reused worker made the same file stop at its floor after 16.4s and burn 539s on CI — so `tests/setup.ts` now restores real timers after every test and the fuzzers budget on `performance.now()`. The hot-path performance gates moved to their own sequential step, because an absolute-millisecond ceiling only measures code on an unscheduled core.
|
|
11
|
+
- The credential-guard investigation ended with the guard kept: a PR proposing its deletion as unreachable was shown to be reachable through application code (`getToken()` may `stop()` the transport before throwing), so it gained a mutation-proved regression test, and the rule distinguishing that from a genuinely dominated branch is now written into `AGENTS.md` and the source.
|
|
12
|
+
- The CommonJS-only default-Worker failure is pinned from the built artifacts: `dist/cjs` cannot resolve a Worker URL through esbuild's `import.meta` shim, so `start()` must report the actionable "provide workerFactory explicitly" rather than `TypeError: Invalid URL` — asserted on both factories, with the ESM artifact checked in the same case to tie the failure to the module format.
|
|
13
|
+
- Whole-suite coverage moved from 98.62 / 96.02 / 98.54 / 99.38 to 98.68 / 96.17 / 98.54 / 99.46 without lowering any ceiling; `docs/transports.md` (en + zh) documents that a publication carrying its own string `topic` is re-addressed to it, which is how wildcard delivery names a concrete topic and why `{ "topic": … }` payloads can go nowhere.
|
|
14
|
+
|
|
15
|
+
## 0.20.96 delivered scope
|
|
16
|
+
|
|
17
|
+
- Opened the project's first deprecation cycle: an empty topic (`""`) now warns once per bus in `subscribe()`, `publish()` and `publishBatch()` instead of silently registering a channel no transport can address. Behaviour is unchanged; a future minor rejects it at that boundary, following the pre-1.0 policy. The contract is documented in the API reference and in the upgrading guide, in both languages.
|
|
18
|
+
- Closed the coverage-leg ledger with proof instead of assumption: eleven behaviors that could not fail their tests are now mutation-verified — the departing-owner handoff that deletes an unserved route rather than migrating it onto a live peer, the owner releasing its transport subscription when the last remote subscriber leaves, a cancelled durable-retention sweep staying silent, a superseded hydration snapshot being dropped instead of merged, the default platform `WebSocket` construction including subprotocols, `ready()` surfacing the recorded transport error after the recovery budget is spent, the Vue adapter containing a rejected `ready()`, a `connectTimeoutMs` of `0` or `Infinity` genuinely waiting forever, a private topic leaving no route record when its only holder hides, the trace reporter containing a throwing sink on a runtime with no `console.warn`, and an unrelated owned wildcard pattern failing to capture a batch bound for a remote topic.
|
|
19
|
+
- Every remaining zero-count branch in `src` is now classified as dominated, unreachable by construction, or a missing boundary check (which is what produced the deprecation above). `vue.ts` and `hooks.ts` reach 100% on all four metrics and `cluster.ts` is down to a single uncovered line.
|
|
20
|
+
- `AGENTS.md` records the traps that made early drafts decorative: a `ChannelHub`-sharing peer heals the state under observation, a peer started without a microtask flush is invisible, and textually duplicated guards let a non-global mutation edit the wrong copy.
|
|
21
|
+
- `typescript-eslint` refreshed to `8.70.1`; TypeScript stays at `6.0.3` while the lint toolchain's peer range excludes 7.x.
|
|
4
22
|
|
|
5
23
|
## 0.20.95 delivered scope
|
|
6
24
|
|
package/docs/transports.md
CHANGED
|
@@ -149,6 +149,7 @@ Wire protocol (JSON text frames):
|
|
|
149
149
|
|
|
150
150
|
- client → server: `{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...,"messageId"?:"...","timestamp"?:123}`
|
|
151
151
|
- server → client: the canonical publication is `{"op":"publication","publication":{"topic":"...","data":...,"messageId"?:"...","timestamp"?:123}}`. The legacy flat `{"topic":"...","data":...}` frame remains accepted. Frames without a string topic are ignored; malformed JSON is reported through `handlers.onError` without throwing.
|
|
152
|
+
- A publication that carries its own string `topic` is addressed by **that** value rather than by the channel it arrived on — that is how a server delivering through a wildcard channel (`chat.*`) names the concrete topic. A payload whose top level happens to contain a `topic` string is therefore re-addressed, and dropped when no tab owns the resulting topic. On Centrifuge the channel normally arrives out of band, which is why the rule needs stating here: it is the one transport where "the topic was already in the frame" is not otherwise visible.
|
|
152
153
|
|
|
153
154
|
When `data` is an `ArrayBuffer`, publish uses a binary frame with a small
|
|
154
155
|
header (`0xc7`, UTF-8 topic length, topic, payload). Servers may echo the same
|
package/docs/zh/api.md
CHANGED
|
@@ -95,6 +95,7 @@ subscribe(
|
|
|
95
95
|
- transport 尚未 ready 时订阅自动排队;transport 恢复待定时同样如此:订阅会挂在恢复门之后,等重开成功才下发,而不会写入刚刚上报 `error` 的连接。
|
|
96
96
|
- 显式 `stop()` 尚未 settle 时发起的订阅不会登记:`subscribe()` 通过 `onError` 上报并返回 no-op 释放函数。调用方应等待 `stop()` settle,再调用 `start()` 后重新订阅。
|
|
97
97
|
- 通配符订阅:以 `.*` 结尾的 Topic(如 `chat.*`)匹配任意后缀,`*` 匹配全部。pattern 以字面量参与路由、归属与传输订阅;携带匹配的具体 topic(或 pattern 本身)的发布都会投递给通配 handler。匹配规则见下方 `topicMatchesPattern`。
|
|
98
|
+
- Topic 必须非空。`''` 目前仍以字面量 channel 参与路由,但没有任何 transport 能寻址它,因此永远不会投递消息;实例第一次以空 topic 调用 `subscribe`/`publish`/`publishBatch` 时会输出一条 `console.warn`。后续小版本会在该边界直接拒绝空 topic,与选项校验保持一致。
|
|
98
99
|
- 重放(可选):构造 bus 时传 `replay: { maxPerTopic }` 开启缓冲,`maxPerTopic` 必须是正安全整数;`subscribe()` 第三个参数传 `{ replay: true | n }` 后,新 handler 会立即收到缓冲历史(最多 `n` 条,受 `maxPerTopic` 上限约束,默认 100),消息带 `message.replayed: true` 标记——晚加入的 handler 不会错过更早的发布。只有被分发过的消息才入缓冲(无本地订阅者的 topic 会被 owner 丢弃);缓冲仅存内存,该 topic 最后一个 handler 退订时清空。通配订阅会对所有匹配 pattern 的已缓冲 topic 做回放。需要跨 reload/BFCache 持久化时,可传入 `createIndexedDbReplayPersistence({ maxPerTopic })` 创建的 `persistence`;持久化为异步操作,失败会通过 `onError` 报告,不影响实时投递。设置 `retentionMs` 后会清理内存中过期的 producer-timestamped 历史,并通过实现 `clearBefore` 的 adapter 在 hydrate 和追加后清理 durable 历史。设置 `persistenceRetry: { maxAttempts, backoffMs }` 可重试瞬时持久化失败;默认仍保持单次尝试。设置 `pruneStrategy` 为 `'count'`(默认)、`'age'` 或 `'both'`,分别表示按 `maxPerTopic` 截断、按 `retentionMs` 清理带时间戳历史,或两者都应用。`age` 下无时间戳的 legacy 条目会保留,但受 `maxPerTopic` 限制;带时间戳条目由 retention 窗口约束。
|
|
99
100
|
启用 trace 后,重试会发出 `reliability` 事件,包含 `operation: 'persistence_retry'`、有界的 `persistenceOperation` 和 `attempt`。
|
|
100
101
|
|
package/docs/zh/architecture.md
CHANGED
|
@@ -519,6 +519,9 @@ Transport 消息 → isAssigned(topic)? → 是 → broadcastEvent(EVENT)
|
|
|
519
519
|
- **隐藏文档的激活守卫。** `WorkerClusterRuntime.start()` 会先安装 lifecycle listener 再检查可见性。若启动时文档已隐藏,则只记录挂起状态,不注册 worker、不打开 channel,也不启动 heartbeat;因此排队在异步 stop 之后的重启不会漏掉清理期间的 `pagehide` 并在后台重连,后续 `pageshow` 会由已安装的 listener 恢复。
|
|
520
520
|
- **挂起态就绪判定。** 挂起中的 bus 会把 `startPromise` 复用为 `pendingStop`(即 chained `transport.stop()` 的 gate),该 Promise 只能证明清理完成,不能证明可以承载数据。`ready()` 在 `stopping` 门之后检查 `suspended`,以挂起态错误 reject,而不是返回 stop gate;`pageshow`/`reopenTransport()` 与显式 `start()` 会清除标记并安装真正的重开 Promise,使 `ready()` 跟随最新生命周期意图。`getHealthSummary()` 原本就报告 `{ healthy: false, state: 'suspended' }`,reject 让 `ready()` 与该判定保持一致。由于 `pagehide` 会独立于 transport 暂停 cluster,显式 `start()` 在解除挂起时也必须一并恢复 cluster;否则 bus 会报告 transport 健康,而 channel listener、heartbeat 与 route 分配仍保持休眠直到下一次 `pageshow`,所有入站 publication 都会因 `isAssigned()` 对照已清空的分配表而被丢弃。
|
|
521
521
|
- **交接通道关闭顺序。** `pause()` 将物理 `channel.close()` 推迟一个任务。同步关闭会丢弃仍在排队等待投递的消息(包括交接的 `ROUTE_RELEASED`),使交接目标持有未确认路由。
|
|
522
|
+
- **无人订阅路由的删除。** 离开的 owner 只交接仍有订阅者的路由。若它拥有的某条路由,其剩余订阅记录已全部消失(某个 peer Tab 未释放就死亡),则该路由被删除而不是交给仍然存活的 peer——否则那个 peer 会背负一个没有任何 Tab 监听的 transport 订阅。`pause()` 不执行孤儿路由清理(该逻辑在 `reconcile` 中),因此这是对该记录唯一的同步释放(由回归测试固定)。
|
|
523
|
+
- **最后一个订阅者的释放。** owner Worker 通过最后一个订阅者发来的 `CONTROL/UNSUBSCRIBE` 得知某 Topic 已无人订阅:它会同时丢弃本地 ownership 并把释放动作派发给自己的 transport。若只在交接短路里消费该消息,server 订阅(以及它的入站扇出)会在所有 Tab 离开后依然存活。
|
|
524
|
+
- **归属漂移的修复。** 每一轮 reconcile 都会丢弃那些 `assignedTopics` 里仍持有、但持久路由已不再指向本 Worker 的 Topic,并顺带释放对应的 transport 订阅。于是 ownership 跟随存储记录,而不是最后到达的那条消息:陈旧的 `CONTROL/SUBSCRIBE`、丢失的路由写入、或某个抢到了不属于自己的路由的 Tab,都会在一个 heartbeat 内收敛回“恰好一个 owner”。`tests/coordination-invariants.test.ts` 会针对三个 Tab 随机制造这些破坏并断言静默后的结果(由回归测试固定:把这一轮清扫掏空,模糊测试的终态就会失败)。
|
|
522
525
|
- **悬挂交接恢复。** 若前任 owner 已消失而其 `ROUTE_RELEASED` 始终未到达(高负载下通道消息丢失,或 route 写入与 ACK 发送之间崩溃),reconcile 循环会在该未确认交接悬挂超过一个 worker TTL(默认 10 秒)后重新选举存活 owner:路由以全新 generation 重写并清除交接标记,使常规确认路径得以完成(已有回归固化)。年龄门限很关键——刚写入的未确认路由可能只是在等确认落盘,不能误判为悬挂;而只要前任 owner 仍然存活,新 owner 会继续等待,因此严格交接的无重叠保证不受影响。
|
|
523
526
|
- **丢失与恢复矩阵。** 每类协调消息都有有界恢复路径:丢失的 `CONTROL/SUBSCRIBE` 由心跳 reconcile 对未确认路由重发;丢失的 `REGISTRY` 通知最多损失一个心跳间隔(默认 3 秒),因为每次 tick 都会 reconcile;丢失的 `ROUTE_RELEASED` 由 reconcile 在前任 owner 消失且交接悬挂超过一个 worker TTL 后重新选举恢复(见上文悬挂交接不变量,已有回归固化);transport 断连窗口内被丢弃的 publication 是唯一文档化的不可恢复丢失(transport 契约)。storage-event 降级通道通过信封内的单调序列号保证变值投递,丢失的派发由同一 reconcile 循环恢复。
|
|
524
527
|
- **恢复诊断。** `getHealthSummary()` 从生命周期标志推导单一就绪判定(`stopped` / `starting` / `healthy` / `recovering` / `suspended` / `degraded`);统一的 `lastFailure` 账本与持久化计数在每次显式 `start()` 后重置。
|
package/docs/zh/benchmarks.md
CHANGED
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
# 浏览器基准趋势
|
|
4
4
|
|
|
5
|
-
> 数据截至 2026-09-
|
|
5
|
+
> 数据截至 2026-09-22,基于 44 份归档的 `bench-results/browser-*.json` 报告(运行 `pnpm bench:browser` 追加一份;用 `node scripts/bench-trend.mjs` 重新生成本文档)。
|
|
6
6
|
|
|
7
7
|
发布门禁的对比基线是 `pnpm bench:compare --fail-above-pct 50`:将最新报告与其之前若干报告中同一指标的中位数比较(50% 上限用于吸收共享 runner 的噪声;此前只看"上一份报告"并不稳定,因为页内热路径指标在同一份代码上会在快/慢两档之间来回跳)。本文记录长期趋势:数值为逐指标延迟,越低越好;最后一列是最近 5 份报告内的最优值,而不是历史纪录——页内基准矩阵在 2026 年 9 月初变更过测量语义,更早的报告不可比。
|
|
8
8
|
|
|
9
9
|
<!-- BENCH-TREND:BEGIN (machine-generated table) -->
|
|
10
10
|
| 指标 | 上次 (ms) | 本次 (ms) | Δ | 近 5 次最优 (ms) |
|
|
11
11
|
|---|---|---|---|---|
|
|
12
|
-
| publish per-message (ms, lower is better) — dedicated |
|
|
13
|
-
| publish per-message (ms, lower is better) — shared | 34.
|
|
14
|
-
| wildcard dispatch ×1000 (ms, lower is better) |
|
|
15
|
-
| publishBatch ×1000 (ms, lower is better) | 4.
|
|
16
|
-
| dedup ×1000 (ms, lower is better) |
|
|
17
|
-
| trace + publish ×1000 (ms, lower is better) |
|
|
18
|
-
| first-packet cold dispatch (ms, lower is better) | 0
|
|
12
|
+
| publish per-message (ms, lower is better) — dedicated | 50.6466 | 51.8687 | +1.22 | 38.6243 |
|
|
13
|
+
| publish per-message (ms, lower is better) — shared | 34.0188 | 33.7528 | -0.27 | 33.7123 |
|
|
14
|
+
| wildcard dispatch ×1000 (ms, lower is better) | 7.2 | 8.1 | +0.90 | 5.8 |
|
|
15
|
+
| publishBatch ×1000 (ms, lower is better) | 4.7 | 4.7 | +0.00 | 3.5 |
|
|
16
|
+
| dedup ×1000 (ms, lower is better) | 14.8 | 16.1 | +1.30 | 10.6 |
|
|
17
|
+
| trace + publish ×1000 (ms, lower is better) | 6.3 | 5.7 | -0.60 | 4.6 |
|
|
18
|
+
| first-packet cold dispatch (ms, lower is better) | 0 | 0 | +0.00 | 0 |
|
|
19
19
|
<!-- BENCH-TREND:END -->
|
|
20
20
|
|
|
21
21
|
说明:
|
|
@@ -150,6 +150,8 @@ pnpm examples
|
|
|
150
150
|
- 数据流动画、事件流、分发延迟指标和集群 Worker 路由状态
|
|
151
151
|
- SDK 能力、transport 配置、活跃/等待 Worker 与可见/隐藏 Tab 状态
|
|
152
152
|
|
|
153
|
+
演示页之外还有两个页面:`http://localhost:4173/examples/react/` 手写接入与框架无关的核心 API(effect、`subscribe`、状态),`http://localhost:4173/examples/vue/` 则只使用已发布的 `cross-tab-worker-databus/vue` 组合式 API。二者都连到同一个本地 demo 端点,因此其中一个页面发布的数据会被三个页面里任何使用同一 Topic 的标签页收到——适配器页面也正是这样被浏览器测试覆盖的(`e2e/adapters.spec.ts`)。
|
|
154
|
+
|
|
153
155
|
通过 Git 依赖直接接入仓库时,应固定到具体 commit。仓库随代码提供 `dist`,消费方安装时无需构建 SDK。
|
|
154
156
|
|
|
155
157
|
## 9. 显式启动
|
|
@@ -197,6 +199,8 @@ const bus = new CrossTabDataBus({
|
|
|
197
199
|
|
|
198
200
|
在 `1.0.0` 之前,SDK 允许增量新增,并在明确的弃用周期后才移除 API。根导出面由回归套件与 tag 间兼容性门禁钉住,意外删除会令 CI 失败,而不是静默破坏既有消费者。
|
|
199
201
|
|
|
202
|
+
当前处于弃用中:`subscribe()`、`publish()`、`publishBatch()` 的空 topic 字符串。传入 `""` 的调用仍然可用,实例首次遇到时会输出一条 `console.warn`,但没有任何 transport 能寻址空 channel,因此经由它的订阅永远不会收到消息——警告针对的是一个无法工作的订阅,后续小版本会直接拒绝它。
|
|
203
|
+
|
|
200
204
|
升级时请注意:
|
|
201
205
|
|
|
202
206
|
- 逐版阅读当前版本到目标版本之间每个版本的 CHANGELOG。每次移除都会在其中明确指出,且弃用周期只在小版本间顺延。
|
package/docs/zh/roadmap.md
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
# 路线图
|
|
2
2
|
|
|
3
|
-
0.20.
|
|
3
|
+
0.20.97 已于 2026 年 9 月 22 日发布。项目会先持续完成可靠性发布,再进入 1.0.0 稳定性冻结。
|
|
4
|
+
|
|
5
|
+
## 0.20.97 已完成范围
|
|
6
|
+
|
|
7
|
+
- 公开接口与可观察的运行时行为均未改变。发布的 `src/` 变更只涉及 `centrifuge.ts`:删除两处不可达的 `typeof Worker` / `typeof SharedWorker` 抛错,并以注释记录为何一个守卫被保留、另一个被移除。其余全部是示例、测试、CI 与文档工作。
|
|
8
|
+
- Vue 适配层终于运行在它真正交付的环境里:`examples/vue/` 用本地安装的 `vue` 包(不依赖 CDN)挂载真实的 `cross-tab-worker-databus/vue` 组合式 API 并连上本地 demo 端点,`e2e/adapters.spec.ts` 在真实 Chromium 标签页中驱动它——两个标签互收消息、响应式切换 topic 后服务端释放旧 channel、owner 标签关闭后仍能送达。在此之前 Vue 入口从未在 jsdom 之外执行过。
|
|
9
|
+
- 跨 tab 之间的核心契约由手工排列变成随机模糊:三个 bus 共享一套存储注册表与 BroadcastChannel,随机交织订阅/退订/发布/隐藏/显示/停止/启动/心跳/丢弃帧/伪造 `SUBSCRIBE`,在静默态断言每个存活 topic 恰有一个 owner 与恰一个 transport 持有者、已离开的 topic 不留残留、一次发布对每个存活订阅者恰好扇出一次。五个变异体能杀死这些断言;三个守卫存活,因为 `reconcileAssignedTopics()` 会修复它们——这一点被记录下来,也正是它们属于帧级回归的原因。
|
|
10
|
+
- 两个发布门禁的计时失败被追到根因而非重试了事。协调模糊测试的 `Date.now()` 预算读的是本套件自己伪造的时钟——复用 worker 里残留的假 `Date` 让同一个文件一次在 16.4 秒停在下限、另一次在 CI 上烧掉 539 秒——因此 `tests/setup.ts` 现在在每个测试后恢复真实计时器,模糊测试改用 `performance.now()` 计预算。热路径性能门禁移入独立的顺序步骤,因为绝对毫秒上限只有在未被调度的核上才度量代码。
|
|
11
|
+
- 一次凭证守卫的调查结果恰是"守卫留下":一个以不可达为由删除它的 PR 被证明是可达的——入口代码(`getToken()`)可以在抛错前先 `stop()` 传输——于是它获得了经变异验证的回归用例,而区分"可达"与"确实被上层支配"的规则写进了 `AGENTS.md` 与源码。
|
|
12
|
+
- 仅 CommonJS 才有的默认 Worker 失败由构建产物钉住:`dist/cjs` 无法经 esbuild 的 `import.meta` 垫片解析 Worker URL,因此 `start()` 必须给出可操作的 "provide workerFactory explicitly" 而非 `TypeError: Invalid URL`;两个工厂函数都被断言,且同一用例同时检查 ESM 产物,从而把失败绑定到模块格式而不是文件名。
|
|
13
|
+
- 全量覆盖率从 98.62 / 96.02 / 98.54 / 99.38 提升到 98.68 / 96.17 / 98.54 / 99.46,且未下调任何阈值;`docs/transports.md`(中英)记录了"自带字符串 `topic` 的发布会被重新寻址到该 topic"这一规则——它既是通配符投递指明具体 topic 的方式,也是 `{ "topic": … }` 载荷可能无声丢失的原因。
|
|
14
|
+
|
|
15
|
+
## 0.20.96 已完成范围
|
|
16
|
+
|
|
17
|
+
- 开启项目第一个弃用周期:空 topic(`""`)现在会在 `subscribe()`、`publish()`、`publishBatch()` 中每个 bus 实例告警一次,而不再静默登记一个没有任何 transport 能寻址的 channel。行为保持不变;按 pre-1.0 策略,后续小版本会在该边界直接拒绝。契约已写入 API 参考与升级指南(中英双语)。
|
|
18
|
+
- 用证明取代假设,清空覆盖率分支台账:十一个"测试根本不可能失败"的行为获得经变异验证的回归用例——离开方 owner 删除无人订阅路由而非交接给存活 peer、最后一个远端订阅者离开时 owner 释放自身 transport 订阅、被取消的持久化清扫保持静默、被取代的水合快照被丢弃而非合并、默认平台 `WebSocket` 构造(含子协议)、恢复预算耗尽后 `ready()` 交出真实传输错误、Vue 适配层吞掉被拒绝的 `ready()`、把 `connectTimeoutMs` 设为 0 或 Infinity 时确实无限等待、私有 topic 在其唯一持有者隐藏时不留路由记录、在没有 `console.warn` 的运行时吞掉抛错的 trace sink,以及无关的已持有通配符 pattern 无法截获发往远端 topic 的批量消息。
|
|
19
|
+
- `src` 中其余零计数分支已全部归类:被支配、按构造不可达,或属于缺失的边界校验(正是它引出了上面的弃用项)。`vue.ts` 与 `hooks.ts` 四项指标均达 100%,`cluster.ts` 只剩一行未覆盖。
|
|
20
|
+
- `AGENTS.md` 记下让早期草稿变成装饰性测试的陷阱:共享 `ChannelHub` 的 peer 会自愈被观测的状态、缺少一次 microtask flush 的 peer 对其他 Tab 不可见、文本重复的守卫会让非全局替换改到错的那一份。
|
|
21
|
+
- `typescript-eslint` 升级到 `8.70.1`;在 lint 工具链的 peer 范围仍排除 7.x 期间,TypeScript 保持 `6.0.3`。
|
|
4
22
|
|
|
5
23
|
## 0.20.95 已完成范围
|
|
6
24
|
|
package/docs/zh/transports.md
CHANGED
|
@@ -135,6 +135,7 @@ const bus = createWebSocketDataBus({
|
|
|
135
135
|
|
|
136
136
|
- client → server:`{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...,"messageId"?:"...","timestamp"?:123}`
|
|
137
137
|
- server → client:标准 publication 为 `{"op":"publication","publication":{"topic":"...","data":...,"messageId"?:"...","timestamp"?:123}}`;旧的扁平 `{"topic":"...","data":...}` 帧仍然兼容。没有字符串 topic 的帧会被忽略;非法 JSON 通过 `handlers.onError` 上报而不会抛出。
|
|
138
|
+
- 自带字符串 `topic` 的 publication 会按**该值**寻址,而不是按它到达的 channel——这正是 server 通过通配 channel(`chat.*`)投递时指明具体 topic 的方式。因此顶层恰好含 `topic` 字段的负载会被重新寻址,若集群中没有任何 Tab 拥有重定向后的 topic,就会被丢弃。Centrifuge 的 channel 通常由客户端库在带外给出,这也是必须在此说明该规则的原因:只有在这条链路上,"topic 本来就写在帧里"这件事才可见。
|
|
138
139
|
|
|
139
140
|
当 `data` 是 `ArrayBuffer` 时,publish 使用二进制帧:帧头为 `0xc7`,随后是
|
|
140
141
|
UTF-8 topic 长度、topic 和 payload。服务器可以原样回显该帧;其他 payload 仍走
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cross-tab-worker-databus",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.97",
|
|
4
4
|
"description": "Framework-agnostic cross-tab data bus with Dedicated/Shared Worker clustering and Centrifuge support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -89,10 +89,11 @@
|
|
|
89
89
|
],
|
|
90
90
|
"scripts": {
|
|
91
91
|
"build": "node scripts/build.mjs",
|
|
92
|
-
"check": "pnpm typecheck && pnpm build && pnpm test",
|
|
92
|
+
"check": "pnpm typecheck && pnpm build && pnpm test && pnpm test:perf",
|
|
93
93
|
"examples": "node scripts/serve-examples.mjs",
|
|
94
94
|
"lint": "eslint .",
|
|
95
95
|
"test": "vitest run",
|
|
96
|
+
"test:perf": "DATABUS_PERF_GATES=1 vitest run tests/perf-gate.test.ts",
|
|
96
97
|
"test:watch": "vitest",
|
|
97
98
|
"test:coverage": "vitest run --coverage",
|
|
98
99
|
"bench": "vitest bench --run",
|
|
@@ -138,7 +139,7 @@
|
|
|
138
139
|
"react": "^19.3.0",
|
|
139
140
|
"react-dom": "^19.3.0",
|
|
140
141
|
"typescript": "^6.0.3",
|
|
141
|
-
"typescript-eslint": "^8.70.
|
|
142
|
+
"typescript-eslint": "^8.70.1",
|
|
142
143
|
"vitest": "^5.0.1",
|
|
143
144
|
"vue": "^3.5.43"
|
|
144
145
|
},
|