cross-tab-worker-databus 0.21.15 → 0.21.16

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.
@@ -444,6 +444,13 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
444
444
  * Run a transport operation now if the transport is ready, otherwise queue
445
445
  * it behind the start promise. This ensures subscribe/unsubscribe calls made
446
446
  * during startup are not lost.
447
+ *
448
+ * `stillWanted` expresses the deferred work as the *current* desired state
449
+ * rather than a captured call, and is checked at each place that resumes on a
450
+ * later task — the recovery gate and the opening flush. The immediate branch
451
+ * carries no check because every path into it evaluates the desired state in
452
+ * the same task: a caller that just mutated `transportSubscribedTopics`, or
453
+ * the gate re-entry one line above.
447
454
  */
448
455
  private runTransport;
449
456
  /**
@@ -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
@@ -20,7 +20,7 @@ import {
20
20
  selectRebalanceTarget,
21
21
  selectWorkerBackend,
22
22
  topicMatchesPattern
23
- } from "./chunk-VQJIMGJN.js";
23
+ } from "./chunk-GQ6NYWQL.js";
24
24
  import {
25
25
  DEFAULT_STORAGE_PREFIX,
26
26
  PRUNE_STRATEGY,
package/docs/api.md CHANGED
@@ -92,7 +92,7 @@ Registers a local subscription and returns a cleanup function.
92
92
  - Multiple handlers for the same topic use reference counting.
93
93
  - The first handler in the current tab registers a cluster subscription.
94
94
  - The current tab only leaves the topic after the last handler is released.
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`.
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`. What is issued is the subscription **still wanted** at that moment: a `subscribe()` released before its queued call ran is not sent, and a release whose topic was re-subscribed in the meantime is not sent either.
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
98
  - Topics must be non-empty: `subscribe()`, `publish()` and `publishBatch()` throw a `TypeError` when passed `''`, before any other effect (no start is requested and no handler is registered). No transport can address an empty channel, so a subscription to it could never receive anything, and a publication to it was dropped without a trace. `''` warned once per instance from 0.20.96 and became a rejection in 0.21.0, following the pre-1.0 deprecation policy; the guard sits with the option-validation asserts, so an empty topic fails the same way a bad `replay.maxPerTopic` does. `publishBatch('', [])` throws too — the invalid argument is checked ahead of the empty-array no-op.
@@ -472,7 +472,7 @@ Application: subscribe(topic, handler)
472
472
  → if no route: selectLeastLoadedWorker, writeRoute, sendControl(SUBSCRIBE)
473
473
  → owner receives CONTROL/SUBSCRIBE
474
474
  → assignedTopics.set(topicKey, topic)
475
- → transport.subscribe(topic) → transportSubscribedTopics.add(topic)
475
+ → transportSubscribedTopics.add(topic) → transport.subscribe(topic)
476
476
  ```
477
477
 
478
478
  **Unsubscribe propagation chain:**
@@ -485,13 +485,14 @@ Application: unsubscribe(topic, handler) (last handler)
485
485
  → if no subscribers left: delete route, sendControl(UNSUBSCRIBE)
486
486
  → owner receives CONTROL/UNSUBSCRIBE
487
487
  → assignedTopics.delete(topicKey)
488
- → transport.unsubscribe(topic) → transportSubscribedTopics.delete(topic)
488
+ → transportSubscribedTopics.delete(topic) → transport.unsubscribe(topic)
489
489
  ```
490
490
 
491
491
  **Disconnect / reconnect behavior:**
492
492
 
493
493
  - On transport disconnect: `transportSubscribedTopics` is **cleared** immediately. The other three sets (`topicHandlers`, `subscribedTopics`, `assignedTopics`) survive unchanged.
494
494
  - On transport reconnect: `CrossTabDataBus` iterates `assignedTopics` and re-calls `transport.subscribe(topic)` for each one, repopulating `transportSubscribedTopics`.
495
+ - Either transport call can be **deferred**: when the transport is not ready, the operation waits behind the opening (or behind a pending recovery attempt) instead of being written to a closed connection. Because `transportSubscribedTopics` is updated at the moment of the call rather than when it lands, a deferred operation is re-checked against that set before it runs — a subscribe whose topic was released in the meantime is dropped, and so is a release whose topic was re-subscribed in the meantime. Without the re-check, a parked subscribe can flush after its own unsubscribe and leave the transport holding a topic that none of the four sets above owns.
495
496
  - This is how business subscription intent survives transport failures: the application never needs to re-subscribe after a reconnect.
496
497
 
497
498
  ## Message Flow
@@ -604,7 +605,7 @@ These invariants are pinned by regression tests (see `tests/stability.test.ts` a
604
605
  - **Storage write recovery.** Coalesced writes retry with exponential backoff (50 ms → 1.6 s cap). A structurally failing key is dropped after 5 attempts (with a `console.warn`) without permanently blocking other queued keys, and the backoff delay resets once the queue fully drains or `clear()` cancels the retries.
605
606
  - **Transport recovery budget.** Automatic recovery is paced by a cooldown, bounded by `recovery.maxAttempts`, and reports `exhausted` when the budget is spent. A successful reopen resets the attempt counter and the exhausted flag; explicit `subscribe` on a down transport can still recover manually. Scheduling alone does not reopen a connection: the backend must release the invalid connection before a retry can create or re-open one. `WebSocketTransport` resolves `start()` only after the socket opens, rejects a pre-open `error`/`close` or a `connectTimeoutMs` expiry, marks the socket active only until error/close, and drops the stale reference before the next `start()` invokes the factory, so late callbacks from the superseded socket are ignored.
606
607
  - **BFCache suspension.** Hiding the tab stops the transport, bumps the persistence-retry generation (cancelling in-flight persistence retries without surfacing errors), pauses trace metrics and periodic dedup/replay cleanup, and gates dispatch; `pageshow` or an explicit `start()` reopens the transport, resumes those periodic resources, and re-establishes subscriptions exactly once per cycle.
607
- - **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.
608
+ - **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. A parked transport subscription call is additionally re-tested against the desired-subscription set it was issued from (`transportSubscribedTopics`), which is what cancels a subscribe released — or a release re-subscribed — while it waited; the generation check alone cannot, because nothing about the recovery cycle changed in that window.
608
609
  - **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`.
609
610
  - **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.
610
611
  - **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).
@@ -682,7 +683,7 @@ A runtime `error` intentionally keeps `transportReady` true: the flag records th
682
683
  - **Readiness during suspend**: A suspended bus sets `suspended = true` and reuses `startPromise`/`pendingStop` for the chained `transport.stop()`, so that promise proves cleanup completed rather than readiness. `ready()` checks `suspended` after the `stopping` gate and rejects with a suspended-state error instead of returning the stop gate. `pageshow`/`reopenTransport()` and an explicit `start()` clear the flag and install a real reopen promise, so `ready()` follows the newest lifecycle intent. Because `pagehide` pauses the *cluster* independently of the transport, an explicit `start()` that leaves suspension resumes the cluster too; without that, the bus would report a healthy transport while its channel listener, heartbeat, and route assignments stayed dormant until the next `pageshow`, and every incoming publication would be discarded by `isAssigned()` against the cleared assignment map. `getHealthSummary()` already reported `{ healthy: false, state: 'suspended' }`; rejection keeps that verdict consistent with `ready()`.
683
684
  - **Superseded open invalidation**: Every fresh start, reopen, suspend, and stop advances `lifecycleEpoch`. An open captures its epoch, ignores stale status/message/error callbacks, and neither marks the transport ready nor performs failure cleanup after a newer transition owns the lifecycle. `stop()` therefore waits for pending opens/reopens and prevents a superseded open from becoming ready after the stop completes.
684
685
  - **Recovery cooldown**: When the transport reports `error` while `started` is true and `stopping` is false, `updateStatus` schedules an automatic `reopenTransport()` after `RECOVERY_COOLDOWN_MS` (1000 ms). A second error within the cooldown window is suppressed to prevent a tight retry loop.
685
- - **Transport recovery gate**: Scheduling a reopen also arms a recovery gate, so `subscribe` / `publish` issued during the cooldown cannot reach the failed connection; they are released after the reopen succeeds. The gate deliberately survives a failed automatic attempt: the next explicit operation starts an immediate on-demand reopen instead of waiting for the next paced attempt, and parked operations flush behind that success. An explicit `start()` that supersedes the automatic timer cancels that attempt and resets the failure ledger but leaves the gate closed; if the manual open also fails, its parked operations remain queued for a later automatic or demand-driven reopen instead of being discarded with the superseded opening. Exhausting `recovery.maxAttempts` releases the gate so the explicit-retry path remains reachable. Superseding the wait with `stop()` / `suspendTransport()` also invalidates every parked waiter before releasing the gate, so the explicit restart and its cluster resubscription cannot be followed by a duplicate stale operation. A runtime `error` does not clear `transportReady`, because clearing it would let caller traffic reopen the transport outside the cooldown and report readiness against a connection that is not carrying data.
686
+ - **Transport recovery gate**: Scheduling a reopen also arms a recovery gate, so `subscribe` / `publish` issued during the cooldown cannot reach the failed connection; they are released after the reopen succeeds. The gate deliberately survives a failed automatic attempt: the next explicit operation starts an immediate on-demand reopen instead of waiting for the next paced attempt, and parked operations flush behind that success (a parked transport subscription first re-checks that its topic is still wanted — see **Recovery waiter invalidation**). An explicit `start()` that supersedes the automatic timer cancels that attempt and resets the failure ledger but leaves the gate closed; if the manual open also fails, its parked operations remain queued for a later automatic or demand-driven reopen instead of being discarded with the superseded opening. Exhausting `recovery.maxAttempts` releases the gate so the explicit-retry path remains reachable. Superseding the wait with `stop()` / `suspendTransport()` also invalidates every parked waiter before releasing the gate, so the explicit restart and its cluster resubscription cannot be followed by a duplicate stale operation. A runtime `error` does not clear `transportReady`, because clearing it would let caller traffic reopen the transport outside the cooldown and report readiness against a connection that is not carrying data.
686
687
  - **Stop during suspend**: `stop()` sets `stopping = true`, which prevents `suspendTransport()` from running. The cleanup awaits `startPromise` and `pendingStop` to ensure any in-flight open or stop completes before the final `transport.stop()`.
687
688
 
688
689
  ## Degradation
package/docs/roadmap.md CHANGED
@@ -1,6 +1,29 @@
1
1
  # Roadmap
2
2
 
3
- 0.21.15 was released on September 24, 2026. The project is intentionally continuing through reliability-focused releases before a 1.0.0 stability freeze.
3
+ 0.21.16 was released on September 24, 2026. The project is intentionally continuing through reliability-focused releases before a 1.0.0 stability freeze.
4
+
5
+ ## 0.21.16 delivered scope
6
+
7
+ - **A deferred transport operation is cancelable by its own release.** `subscribeTransport()` and
8
+ `unsubscribeTransport()` recorded intent in `transportSubscribedTopics` and then handed `runTransport()` a
9
+ captured call, so a subscribe parked behind a pending opening could flush *after* the unsubscribe that cancelled
10
+ it. The connection then held a channel that no local handler, cluster assignment, or route record owns — and
11
+ nothing recovers, because the dedupe that prevents double-subscribes reads the same stale set. `runTransport()`
12
+ now also takes the desired state as a predicate and re-reads it at each place that resumes on a later task. Three
13
+ regression cases, with per-leg mutation attribution: the two resume points have disjoint kill sets (1 test versus
14
+ 2), and inverting the guard fails 20 cases including the pre-existing startup-queueing test.
15
+ - **The coordination fuzz now delivers frames the way a browser does.** `ChannelHub.setAsyncDelivery(true)` defers
16
+ each post by one microtask; it is opt-in because 15 tests post a frame and assert without awaiting. Enabling it
17
+ on the sweep's hub is what turned the previous release's unresolved observation into the defect above — measured
18
+ as a control in both directions, six seeds failing before the fix and zero after, with the synchronous hub
19
+ passing on the broken code.
20
+ - **What the raised fidelity did *not* claim is recorded at the sites.** The async hub adds no standing mutant kill
21
+ on the fixed code, the member-set re-read inside the deferred pump is defensive rather than observable through
22
+ this fake, and the unsubscribe direction's measured cost is a redundant wire frame rather than a stranded
23
+ channel.
24
+ - **Shipped prose the fix invalidated**, corrected in English and Chinese: both subscription propagation chains
25
+ wrote the set *after* the transport call (the code does it before), the recovery-gate paragraph credited only the
26
+ cancellation-generation guard, and `api.md`'s `subscribe()` row promised queueing without cancellation.
4
27
 
5
28
  ## 0.21.15 delivered scope
6
29
 
package/docs/zh/api.md CHANGED
@@ -92,7 +92,7 @@ subscribe(
92
92
  - 同一 Topic 的多个 handler 使用引用计数。
93
93
  - 当前 Tab 第一个 handler 会登记集群订阅。
94
94
  - 最后一个 handler 释放后,当前 Tab 才退出该 Topic。
95
- - transport 尚未 ready 时订阅自动排队;transport 恢复待定时同样如此:订阅会挂在恢复门之后,等重开成功才下发,而不会写入刚刚上报 `error` 的连接。
95
+ - transport 尚未 ready 时订阅自动排队;transport 恢复待定时同样如此:订阅会挂在恢复门之后,等重开成功才下发,而不会写入刚刚上报 `error` 的连接。下发的是那一刻**仍然被需要**的订阅:排队期间已被释放的 subscribe 不会发出,排队期间又被重新订阅的释放同样不会发出。
96
96
  - 显式 `stop()` 尚未 settle 时发起的订阅不会登记:`subscribe()` 通过 `onError` 上报并返回 no-op 释放函数。调用方应等待 `stop()` settle,再调用 `start()` 后重新订阅。
97
97
  - 通配符订阅:以 `.*` 结尾的 Topic(如 `chat.*`)匹配任意后缀,`*` 匹配全部。pattern 以字面量参与路由、归属与传输订阅;携带匹配的具体 topic(或 pattern 本身)的发布都会投递给通配 handler。匹配规则见下方 `topicMatchesPattern`。
98
98
  - Topic 必须非空:`subscribe()`、`publish()`、`publishBatch()` 传入 `''` 时会抛出 `TypeError`,且在任何其他副作用之前(不会请求 start,也不会登记 handler)。没有任何 transport 能寻址空 channel,因此对它的订阅永远收不到消息,向它的发布也会被无声丢弃。`''` 自 0.20.96 起每个实例告警一次,自 0.21.0 起直接拒绝——遵循 1.0 前的弃用策略;该守卫与选项校验断言放在一起,空 topic 与非法 `replay.maxPerTopic` 以同样方式失败。`publishBatch('', [])` 同样抛错:非法参数先于空数组 no-op 检查。
@@ -416,7 +416,7 @@ sequenceDiagram
416
416
  → 无 route: 选择最低负载 Worker,写 route,sendControl(SUBSCRIBE)
417
417
  → owner 收到 CONTROL/SUBSCRIBE
418
418
  → assignedTopics.set(topicKey, topic)
419
- → transport.subscribe(topic) → transportSubscribedTopics.add(topic)
419
+ → transportSubscribedTopics.add(topic) → transport.subscribe(topic)
420
420
  ```
421
421
 
422
422
  **退订传递链:**
@@ -429,13 +429,14 @@ sequenceDiagram
429
429
  → 无其他 subscriber: 删除 route,sendControl(UNSUBSCRIBE)
430
430
  → owner 收到 CONTROL/UNSUBSCRIBE
431
431
  → assignedTopics.delete(topicKey)
432
- → transport.unsubscribe(topic) → transportSubscribedTopics.delete(topic)
432
+ → transportSubscribedTopics.delete(topic) → transport.unsubscribe(topic)
433
433
  ```
434
434
 
435
435
  **断开/重连行为:**
436
436
 
437
437
  - transport 断开时:`transportSubscribedTopics` **立即清空**。其他三个集合(`topicHandlers`、`subscribedTopics`、`assignedTopics`)保持不变。
438
438
  - transport 重连时:`CrossTabDataBus` 遍历 `assignedTopics`,对每个 topic 重新调用 `transport.subscribe(topic)`,重新填充 `transportSubscribedTopics`。
439
+ - 这两个 transport 调用都可能**被延后**:transport 未就绪时,操作会排在 opening(或进行中的恢复尝试)之后,而不是写到已关闭的连接上。由于 `transportSubscribedTopics` 是在发起调用时更新、而非在调用真正落地时更新,延后的操作在执行前会先依据该集合重新核对——期间 topic 已被释放的订阅会被丢弃,期间又被重新订阅的释放同样会被丢弃。缺少这层核对时,一个停靠的 subscribe 可能在其自身的 unsubscribe 之后才 flush,使 transport 持有一个上面四个集合都不再拥有的 topic。
439
440
  - 这就是业务订阅意图在 transport 故障后仍能保持的原因:应用层无需在重连后重新订阅。
440
441
 
441
442
  ## 消息流程
@@ -541,7 +542,7 @@ Transport 消息 → isAssigned(topic)? → 是 → broadcastEvent(EVENT)
541
542
  - **存储写失败恢复。** 合并写入按指数退避重试(50 ms → 1.6 s 封顶)。结构性失败的关键在 5 次尝试后被丢弃(伴随 `console.warn`),且不会永久阻塞其他排队 key;队列完全清空或 `clear()` 取消重试后,退避延迟重置。
542
543
  - **Transport 恢复预算。** 自动恢复由冷却时间限速、由 `recovery.maxAttempts` 限量,预算耗尽后标记 `exhausted`。成功的重开会重置尝试计数与 exhausted 标记;transport 宕机时显式 `subscribe` 仍可手动恢复。自动调度本身不会重开连接:后端必须先释放失效连接,重试才能创建或重开 socket。`WebSocketTransport` 只在 socket `open` 后 resolve `start()`;握手前的 `error`/`close` 或 `connectTimeoutMs` 超时都会 reject。它仅在 socket 有效期间将其标记为 active;`error`/`close` 会立即失效,下一次 `start()` 在调用工厂前清除旧引用,因此被取代 socket 的迟到回调会被忽略。
543
544
  - **BFCache 挂起。** Tab 隐藏时停止 transport、递增持久化重试 generation(取消在途重试且不对外报错),同时暂停 trace metrics 与 dedup/replay 周期清理并门控分发;`pageshow` 或显式 `start()` 会重开 transport、恢复这些周期资源,并且每轮循环只重建一次订阅。
544
- - **恢复 waiter 失效。** 每个停靠在 recovery gate 上的操作都会捕获当前恢复取消 generation;`stop()` 与 `suspendTransport()` 取代恢复周期时会递增该 generation,因此即使 waiter 的微任务在紧随其后的显式 `start()` 之后才运行,也不能把操作重放到替换 transport。重建后的 cluster 对每个已分配 topic 只负责一次重新订阅,旧操作不能再发出重复订阅。
545
+ - **恢复 waiter 失效。** 每个停靠在 recovery gate 上的操作都会捕获当前恢复取消 generation;`stop()` 与 `suspendTransport()` 取代恢复周期时会递增该 generation,因此即使 waiter 的微任务在紧随其后的显式 `start()` 之后才运行,也不能把操作重放到替换 transport。重建后的 cluster 对每个已分配 topic 只负责一次重新订阅,旧操作不能再发出重复订阅。停靠的 transport 订阅调用还会额外依据发起它的那份期望集合(`transportSubscribedTopics`)重新核对——这正是排队期间被释放的 subscribe(以及排队期间又被重新订阅的 release)会被取消的原因;单靠 generation 检查做不到,因为那段窗口里恢复周期本身没有任何变化。
545
546
  - **隐藏文档的激活守卫。** `WorkerClusterRuntime.start()` 会先安装 lifecycle listener 再检查可见性。若启动时文档已隐藏,则只记录挂起状态,不注册 worker、不打开 channel,也不启动 heartbeat;因此排队在异步 stop 之后的重启不会漏掉清理期间的 `pagehide` 并在后台重连,后续 `pageshow` 会由已安装的 listener 恢复。
546
547
  - **挂起态就绪判定。** 挂起中的 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()` 对照已清空的分配表而被丢弃。
547
548
  - **交接通道关闭顺序。** `pause()` 将物理 `channel.close()` 推迟一个任务。同步关闭会丢弃仍在排队等待投递的消息(包括交接的 `ROUTE_RELEASED`),使交接目标持有未确认路由。
@@ -619,7 +620,7 @@ DataBus 将"业务订阅意图"与"transport 当前订阅状态"分离。transpo
619
620
  - **启动期间隐藏**:`pagehide` 在 `openTransport` 飞行中触发时,`suspendTransport()` 设置 `suspended = true`,并在飞行中的 start 之后链式执行 `transport.stop()`。`openTransport` 的 catch 路径检测到 `suspended` 后放弃本次 open,不视为失败。当重复的 hide/show 让排队的 resume opening 与更早的 stop gate 交错时,挂起会安装新的串行 stop gate 并恢复 `startPromise === pendingStop` 不变量,使下一次 `pageshow` 真正重开,而不是复用已被淘汰的 opening 并永久停留在挂起状态。
620
621
  - **被取代 open 失效**:每次全新 start、reopen、suspend 和 stop 都会推进 `lifecycleEpoch`。open 会捕获自己的 epoch;一旦更新的转换接管生命周期,旧 open 的 status/message/error 回调会被忽略,也不会再把 transport 标记为 ready 或执行失败清理。因此 `stop()` 会等待未完成的 open/reopen,并阻止被取代的 open 在 stop 完成后变为 ready。
621
622
  - **恢复冷却**:transport 上报 `error` 且 `started` 为 true、`stopping` 为 false 时,`updateStatus` 在 `RECOVERY_COOLDOWN_MS`(1000 ms)后调度自动 `reopenTransport()`。冷却窗口内的第二次错误被抑制,防止紧循环重试。
622
- - **传输恢复门**:调度重开的同时会抬起恢复门,使冷却期间发起的 `subscribe` / `publish` 无法到达失效连接,等重开成功后才释放。自动尝试失败后门刻意保持关闭:下一次显式操作会立即触发按需重开,而不是等待下一个限速尝试,挂起的操作则在该次成功后一并 flush。显式 `start()` 取代自动 timer 时会取消该次尝试并重置失败账本,但保持门关闭;若手动重开也失败,停靠操作会继续等待后续自动或按需重开,而不会随被取代的 opening 一起静默丢弃。`recovery.maxAttempts` 耗尽时会释放门,以保留显式重试路径;若被 `stop()` / `suspendTransport()` 取代,则在释放门前使全部停靠 waiter 失效,因此显式重启及其 cluster 重新订阅之后不会再多执行一次过期操作。运行期 `error` 不会清除 `transportReady`——清除它会让调用方流量绕过冷却重开,并在连接尚未承载数据时报告 ready。
623
+ - **传输恢复门**:调度重开的同时会抬起恢复门,使冷却期间发起的 `subscribe` / `publish` 无法到达失效连接,等重开成功后才释放。自动尝试失败后门刻意保持关闭:下一次显式操作会立即触发按需重开,而不是等待下一个限速尝试,挂起的操作则在该次成功后一并 flush(停靠的 transport 订阅会先核对该 topic 是否仍被需要,见「恢复 waiter 失效」)。显式 `start()` 取代自动 timer 时会取消该次尝试并重置失败账本,但保持门关闭;若手动重开也失败,停靠操作会继续等待后续自动或按需重开,而不会随被取代的 opening 一起静默丢弃。`recovery.maxAttempts` 耗尽时会释放门,以保留显式重试路径;若被 `stop()` / `suspendTransport()` 取代,则在释放门前使全部停靠 waiter 失效,因此显式重启及其 cluster 重新订阅之后不会再多执行一次过期操作。运行期 `error` 不会清除 `transportReady`——清除它会让调用方流量绕过冷却重开,并在连接尚未承载数据时报告 ready。
623
624
  - **暂停期间停止**:`stop()` 设置 `stopping = true`,阻止 `suspendTransport()` 执行。清理过程会 await `startPromise` 和 `pendingStop`,确保任何飞行中的 open 或 stop 完成后才执行最终的 `transport.stop()`。
624
625
 
625
626
  ## 降级
@@ -1,6 +1,26 @@
1
1
  # 路线图
2
2
 
3
- 0.21.15 已于 2026 年 9 月 24 日发布。项目会先持续完成可靠性发布,再进入 1.0.0 稳定性冻结。
3
+ 0.21.16 已于 2026 年 9 月 24 日发布。项目会先持续完成可靠性发布,再进入 1.0.0 稳定性冻结。
4
+
5
+ ## 0.21.16 已完成范围
6
+
7
+ - **延后的 transport 操作现在可以被它自己的释放取消。** `subscribeTransport()` 与 `unsubscribeTransport()`
8
+ 先把意图写进 `transportSubscribedTopics`,再把一次*固化的调用*交给 `runTransport()`;因此停在 pending opening
9
+ 后面的 subscribe,可能在已经取消它的那个 unsubscribe 之后才 flush。连接于是持有一条不属于任何本地 handler、
10
+ 集群分配或路由记录的 channel,而且没有任何路径能恢复——因为防止重复订阅的去重判断读的就是这份过期集合。
11
+ `runTransport()` 现在额外接收“当前期望状态”的谓词,并在每个于后续任务中恢复的位置重新读取。三个回归用例,
12
+ 并按腿归属变异结果:两个恢复点各有不相交的击杀集(1 个用例与 2 个用例),而把守卫反向后会有 20 个用例失败,
13
+ 其中包括原有的“启动期间排队订阅”测试。
14
+ - **协同模糊测试的频道投递现在与浏览器一致。** `ChannelHub.setAsyncDelivery(true)` 把每次 post 延后一个
15
+ microtask;它是可选开启的,因为有 15 个测试发完帧就直接同步断言。在 sweep 的 hub 上启用它,正是把上一个版本
16
+ 未解决的那个观察变成上面这个缺陷的原因——两个方向都做了对照测量:修复前六个 seed 失败,修复后为零,而同步
17
+ hub 在坏代码上是通过的。
18
+ - **提高保真度所*没有*主张的东西,同样写在原位。** 在已修复的代码上,异步 hub 不新增任何常驻变异击杀;延后
19
+ pump 内部重新读取成员集合属于防御性写法,在当前 fake 下不可观察;退订方向的实测代价是多一帧冗余线上消息,
20
+ 而不是被搁置的 channel。
21
+ - **本次修复使其失效的随包文档**,中英两侧一并订正:两条订阅传递链都把集合写入画在 transport 调用*之后*(代码
22
+ 是先写集合),恢复门段落只归功于取消 generation 守卫,而 `api.md` 的 `subscribe()` 一行只承诺了排队、没有承诺
23
+ 取消。
4
24
 
5
25
  ## 0.21.15 已完成范围
6
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cross-tab-worker-databus",
3
- "version": "0.21.15",
3
+ "version": "0.21.16",
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",