cross-tab-worker-databus 0.20.91 → 0.20.93

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.
@@ -22,7 +22,7 @@
22
22
  3. 依赖安全门禁:`pnpm audit --registry=https://registry.npmjs.org`(配置的镜像 registry 缺少 audit 端点;CI 在 verify job 中于公共 registry 运行)。任一已知漏洞公告即视为发布失败;`pnpm-workspace.yaml` overrides 钉住补丁版本。
23
23
  4. 浏览器基准回归门禁:运行两次 `pnpm bench:browser` 后执行 `pnpm bench:compare --fail-above-pct 50`(50% 上限用于吸收共享 runner 的无关噪声,参见已知的共享 runner 抖动说明);基线迁移(例如某指标从空操作变为真实路径)属预期内的一次性失败。用 `pnpm bench:trend` 刷新长期趋势文档,表格变化时一并提交。
24
24
  5. 用 `npm pack --dry-run --json` 确认发布包只包含预期文件。
25
- 6. 提交、给精确版本打 tag,并推送 `main --tags`。
25
+ 6. 在功能分支提交并推送该分支,PR 验证通过后使用 squash 或 fast-forward 合入(不创建 merge commit)。获取合入后的精确提交并打 tag,只推送该版本 tag;禁止直接推送 `main`/`master` 或 force-push。工作流运行 `node scripts/verify-release-version.mjs`,要求 `RELEASE_TAG` 等于 `v` 加 package 版本,且 CHANGELOG 中恰好有一个非空的对应版本章节。
26
26
 
27
27
  ## 安全与依赖扫描
28
28
 
@@ -30,7 +30,7 @@
30
30
 
31
31
  ## 打 tag 的发布工作流
32
32
 
33
- 推送版本 tag 会触发 `Release` GitHub Action:先跑 `pnpm check` 与 `pnpm lint`(tag 可能指向从未通过 CI lint 步骤的提交),再跑 `verify:compat` 与 `verify:pack`,从 `CHANGELOG` 对应章节生成 GitHub release,配置了 `NPM_TOKEN` 时自动发布到 npm,然后运行与手动执行相同预算的**阻塞式**消费者验证(`PUBLISHED_VERIFY_ATTEMPTS=48`、`PUBLISHED_VERIFY_DELAY_MS=7500`,即 6 分钟上限)。已发布包若无法被干净消费者导入,工作流即失败——任何 `verify:published` 失败都应视为发布失败,修复后重新发布该 tag。未配置 token 时跳过发布步骤,但验证仍会针对 npm 上已有的版本(例如手动发布的)通过。
33
+ 推送版本 tag 会触发 `Release` GitHub Action:先跑 `pnpm check` 与 `pnpm lint`(tag 可能指向从未通过 CI lint 步骤的提交),再跑 `verify:compat` 与 `verify:pack`,从 `CHANGELOG` 对应章节生成 GitHub release,配置了 `NPM_TOKEN` 时自动发布到 npm,然后运行与手动执行相同预算的**阻塞式**消费者验证(`PUBLISHED_VERIFY_ATTEMPTS=48`、`PUBLISHED_VERIFY_DELAY_MS=7500`,即 6 分钟上限)。已发布包若无法被干净消费者导入,工作流即失败——任何 `verify:published` 失败都应视为发布失败。若为 registry 传播延迟或基础设施故障,针对不变的 tag 重跑工作流;若为产物缺陷,发布新的 patch 版本。禁止移动或重用已发布 tag。未配置 token 时跳过发布步骤,但验证仍会针对 npm 上已有的版本(例如手动发布的)通过。
34
34
 
35
35
  ## 发布(手动场景)
36
36
 
@@ -1,6 +1,22 @@
1
1
  # 路线图
2
2
 
3
- 0.20.91 已发布。项目会先持续完成可靠性发布,再进入 1.0.0 稳定性冻结。
3
+ 0.20.93 已于 2026 年 9 月 19 日进入发布冻结。项目会先持续完成可靠性发布,再进入 1.0.0 稳定性冻结。
4
+
5
+ ## 0.20.93 冻结范围
6
+
7
+ - 强化 package 元数据、无条件与 fallback array target、递归嵌套及自定义 export condition 的兼容性门禁。
8
+ - storage 能力探测必须完成可读的写入-读取-删除往返;channel 构造失败时安全降级;sessionStorage 不可用时保持稳定的内存 tab identity。
9
+ - 在 clear 与 cluster teardown 时取消失败的 storage retry,并用 cluster 级 restart 回归覆盖收敛行为。
10
+ - 更新 patch 级开发依赖,完成发布、浏览器、打包、兼容性与安全全量门禁。
11
+
12
+ ## 0.20.92 冻结范围
13
+
14
+ 当前开发线继续验证 predecessor reopen 结算、排队启动就绪与 stop promise 清理等生命周期错误路径。该开发线现已落地十六处修复。第一处让共享 stop gate 先于同步 teardown 前奏安装:从同步 STOP lifecycle trace 事件重入的 `stop()` 会共享同一次 teardown,而不是再调用一次 `transport.stop()`。第二处在 START trace 发出前安装 lifecycle epoch 与 `startPromise`:若同步 trace/status 回调重入 `stop()`,外层 `start()` 会立即停止后续 timer、cluster 与 topic 启动,旧 opening 由 epoch guard 放弃,transport 不会被重新打开。第三处把相同的「先安装 lifecycle、再发同步回调」顺序应用到 `reopenTransport()` 的 CONNECTING 状态通知,使恢复期间重入的 stop 能取消本次 reopen,而不是在 teardown 后重新打开 transport。第四处让同步 RESUME trace 回调内的 stop 同时取消显式 `start()` 与原生 `pageshow` 恢复;`WorkerClusterRuntime` 通过 lifecycle generation 阻止外层 pageshow 在 `onResume` 已停止或暂停 cluster 后再次 `activate()`。此前这些场景都可能留下 `state: stopped` 但 transport 或 cluster 仍活跃的半停止状态。第五处让已经停靠在 recovery gate 上的 transport 操作不再因等待中的自动恢复尝试失败而滞留:`runTransport()` 现在统计停靠操作数,自动尝试失败时若仍有 waiter 会立即发起一次 on-demand reopen,使在 cooldown 期间发出的 `publish()` / `subscribe()` 自身即可驱动恢复,而不必等待之后某个无关操作。demand reopen 自身失败时仍会重新武装 flag 留待后续操作重试,而不会在自身失败上自循环;一旦 reopen 成功,全部 waiter 会按序 flush。cluster-key 隔离保证现在由双 runtime 回归固定:不同租户可独立拥有同一 topic、publication 不会跨命名空间边界、持久化 key 使用不同 opaque hash 且不暴露明文 key。第六处 replay retention 修复会在 suspend/resume 期间旧 cleanup 事务仍在收尾时,把新排队的最新 cutoff 交给新一轮 cleanup,避免它一直滞留到未来某个无关 publication 才被处理。第七处在 `reopenTransport()` 发出同步 CONNECTING 通知前清空 `transportReady`,避免同一 tick 内第二个操作把仍在关闭的旧 transport 误判为可用连接;所有操作都会继续停靠在 opening 上,并在 replacement 打开后按序 flush。第八处让 pagehide suspension 续体具备 epoch 感知:若同步 DISCONNECTED status 回调按公开恢复路径调用 `start()`,旧 hide 续体会被放弃,不会在 replacement 打开后再次停止 transport 并留下错误的 healthy 状态。第九处修复保留 durable hydration 与实时流量的回放顺序:若 `load()` 尚未完成时已有 publication 写入,加载快照会排在实时消息之前,数量裁剪因此保留最新的实时消息,而不会把旧历史误认为更新内容。第十处让 replay hydration 能跨 lifecycle 替换:清除全部、清除单 topic、退订与 cutoff 裁剪会应用到仍在进行的加载快照,避免已清除历史复活;suspend/restart 会取消被取代的 load 并启动新一代 hydration;显式 stop/start 后也会重新加载 durable history,而不是留下空 ring。第十一处补上严格交接的 generation 缺口:`ROUTE_RELEASED` 必须与存储 route 的 generation 精确相等,其他交接轮次的 ACK 不能确认当前 route,也不能提前释放其 `SUBSCRIBE`。第十二处修复排队重启与 BFCache 的竞态:`WorkerClusterRuntime.start()` 会先安装 lifecycle listener 再检查可见性,因此排队在异步 stop 之后的重启能观察到清理期间到达的 `pagehide`,保持挂起并等待 `pageshow`,而不会重新连接隐藏页面。
15
+ 第十三处把每个入站 `CONTROL/SUBSCRIBE` 绑定到持久化 route:较早分配轮的迟到帧不能再让非 owner 订阅 transport,也不能在匹配的 `ROUTE_RELEASED` 之前确认悬挂交接;同一 route 的合法订阅与正常交接 ACK 保持不变。
16
+ 第十四处修复 recovery gate 取消竞态:当 pagehide/stop 取代恢复周期时,已停靠在门上的操作会失效;紧随其后的显式 `start()` 可以在 replacement transport 上重建订阅,而旧 waiter 不能再于重启后重放并与该过程竞争出重复订阅。
17
+ 第十五处修复显式 `start()` 取代自动恢复 timer 时停靠操作被静默丢弃的问题:取消 timer 不再释放 recovery gate;若该显式重开也失败,停靠操作会保留到下一次自动或按需恢复成功后再回放。
18
+ 第十六处修复让被拒绝的 teardown 同时保留在两个失败账本中:`stop()` 仍会 resolve 并通过 `onError` 上报,但 recovery 账本会与统一的 `lastFailure` 记录保持同一次 stop 失败,直到显式 `start()` 同时重置两者。
19
+
4
20
 
5
21
  ## 0.20.91 已完成范围
6
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cross-tab-worker-databus",
3
- "version": "0.20.91",
3
+ "version": "0.20.93",
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",
@@ -126,20 +126,20 @@
126
126
  "@eslint/js": "^10.0.1",
127
127
  "@playwright/test": "^1.63.0",
128
128
  "@testing-library/react": "^16.3.3",
129
- "@types/node": "^26.5.1",
129
+ "@types/node": "^26.6.1",
130
130
  "@types/react": "^19.3.0",
131
131
  "@vitest/coverage-v8": "^5.0.1",
132
132
  "esbuild": "^0.28.2",
133
- "eslint": "^10.10.0",
133
+ "eslint": "^10.11.0",
134
134
  "fake-indexeddb": "^6.2.5",
135
135
  "globals": "^17.12.0",
136
- "jsdom": "^30.0.1",
136
+ "jsdom": "^30.1.0",
137
137
  "react": "^19.3.0",
138
138
  "react-dom": "^19.3.0",
139
139
  "typescript": "^6.0.3",
140
140
  "typescript-eslint": "^8.70.0",
141
141
  "vitest": "^5.0.1",
142
- "vue": "^3.5.42"
142
+ "vue": "^3.5.43"
143
143
  },
144
144
  "engines": {
145
145
  "node": ">=18.0.0"