cross-tab-worker-databus 0.8.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +2 -0
- package/README.zh.md +2 -0
- package/dist/centrifuge-protocol.d.ts +4 -0
- package/dist/centrifuge-protocol.d.ts.map +1 -1
- package/dist/centrifuge-session.d.ts.map +1 -1
- package/dist/centrifuge.js +29 -11
- package/dist/centrifuge.js.map +2 -2
- package/dist/centrifuge.shared.worker.js +37 -6
- package/dist/centrifuge.shared.worker.js.map +3 -3
- package/dist/centrifuge.worker.js +37 -6
- package/dist/centrifuge.worker.js.map +3 -3
- package/dist/{chunk-WWUY2FV2.js → chunk-NX76TAV3.js} +137 -26
- package/dist/chunk-NX76TAV3.js.map +7 -0
- package/dist/cjs/centrifuge.cjs +164 -35
- package/dist/cjs/centrifuge.cjs.map +4 -4
- package/dist/cjs/index.cjs +172 -38
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/core/cluster.d.ts +3 -2
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/data-bus.d.ts +19 -0
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/publication.d.ts +10 -0
- package/dist/core/publication.d.ts.map +1 -0
- package/dist/core/replay-persistence.d.ts +2 -0
- package/dist/core/replay-persistence.d.ts.map +1 -1
- package/dist/core/trace.d.ts +7 -0
- package/dist/core/trace.d.ts.map +1 -1
- package/dist/core/types.d.ts +19 -7
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -14
- package/dist/index.js.map +2 -2
- package/dist/websocket.d.ts.map +1 -1
- package/docs/api.md +27 -6
- package/docs/architecture.md +7 -1
- package/docs/capabilities.md +2 -2
- package/docs/configuration.md +1 -1
- package/docs/roadmap.md +15 -1
- package/docs/transports.md +9 -5
- package/docs/zh/api.md +27 -6
- package/docs/zh/architecture.md +7 -1
- package/docs/zh/capabilities.md +2 -2
- package/docs/zh/configuration.md +1 -1
- package/docs/zh/transports.md +8 -4
- package/package.json +1 -1
- package/dist/chunk-WWUY2FV2.js.map +0 -7
package/docs/capabilities.md
CHANGED
|
@@ -22,7 +22,7 @@ Status Legend: `✅ Implemented` means the current version has code and test cov
|
|
|
22
22
|
| Degradation | Runs locally when localStorage or BroadcastChannel is unavailable | ✅ Implemented | Preserves the current Tab's connection and subscription capabilities |
|
|
23
23
|
| Centrifuge | Built-in Dedicated / Shared Worker transport | ✅ Implemented | Supports subscribe, unsubscribe, publish, connection status, and error reporting; `auto` degrades from SharedWorker → Dedicated Worker → main-thread WebSocket |
|
|
24
24
|
| Security Boundary | localStorage uses opaque keys derived from connection and Topic; BroadcastChannel coordination messages carry plaintext topic names | ✅ Implemented | Does not persist URLs, raw Topic names, credentials, or publication payloads. BroadcastChannel coordination messages are in-memory only and carry plaintext topic names — they are not persisted. |
|
|
25
|
-
| Diagnostics | Aggregates lifecycle events, throughput, delivery latency, recovery retries, route acknowledgments, and migrations | ✅ Implemented | Disabled by default; metrics are emitted every 5 seconds by default, with bounded reliability events for recovery and route coordination |
|
|
25
|
+
| Diagnostics | Aggregates lifecycle events, throughput, delivery latency, dedup outcomes, recovery retries, route acknowledgments, and migrations | ✅ Implemented | Disabled by default; metrics are emitted every 5 seconds by default, with bounded reliability events for recovery and route coordination |
|
|
26
26
|
| Performance | Batched writes of coordination metadata with backoff retry | ✅ Implemented | Heartbeat, route, and subscriber writes are merged and flushed in a microtask; failures use exponential backoff; `pagehide` / `stop()` flush synchronously |
|
|
27
27
|
| Performance | Optional ArrayBuffer Transferable transport | ✅ Implemented | With `transferable: true`, binary publish / receive bypasses structured clone copying; the object message API is unchanged |
|
|
28
28
|
| Message Semantics | exactly-once delivery | Not Implemented | Graceful handoff avoids overlap, but crash recovery and transport/server behavior still do not provide an exactly-once guarantee |
|
|
@@ -31,7 +31,7 @@ Status Legend: `✅ Implemented` means the current version has code and test cov
|
|
|
31
31
|
| Load Policy | Adaptive weighting by message rate, byte count, or CPU | Planned | Load is currently computed only from the number of owner Topics |
|
|
32
32
|
| Observability | Metrics/events for owner acknowledgments, migrations, and recovery attempts | ✅ Implemented | `DataBusReliabilityTraceEvent` reports bounded route ack/migration and transport recovery events; exact server-side ack remains transport-specific |
|
|
33
33
|
| Runtime Model | SharedWorker / Dedicated Worker transport | ✅ Implemented | `workerMode` supports `dedicated`, `shared`, and `auto`, defaulting to `dedicated` |
|
|
34
|
-
| Runtime Model | Service Worker transport | Not Implemented |
|
|
34
|
+
| Runtime Model | Service Worker transport | Not Implemented | Deliberately deferred; lifetime and long-lived connection constraints are documented in `docs/architecture.md` |
|
|
35
35
|
| Durable Messages | Persisting publications or publish commands across page close | Not Implemented | The SDK does not persist business payloads, nor does it replay publish commands after restoration |
|
|
36
36
|
|
|
37
37
|
## Acceptance Criteria
|
package/docs/configuration.md
CHANGED
|
@@ -46,7 +46,7 @@ const bus = new CrossTabDataBus({
|
|
|
46
46
|
| `metricsIntervalMs` | `number` | `5000` | Aggregation window; must be a finite value greater than 0 |
|
|
47
47
|
| `sink` | `(event) => void` | Required | Determined by the integrator: console, monitoring SDK, or other output |
|
|
48
48
|
|
|
49
|
-
`message_metrics` contains window duration, received count, dispatched count, active Topic count, and receive-to-dispatch latency sample count, average, P50, P95, and maximum. Latency is aggregated in 50ms buckets and never contains an individual message payload. Subscription events include their Topic so an integrator can correlate ownership changes. They are emitted only when the owner transport subscription set changes; idempotent `CONTROL` retries do not produce duplicate subscription events. Treat trace sinks as diagnostic surfaces: redact sensitive Topic conventions before writing to a console or external telemetry. Trace events do not include URLs, credentials, payloads, or error bodies. Errors thrown in the sink are isolated and will not interrupt message distribution, but will output to `console.warn` to help integrators discover diagnostic configuration issues.
|
|
49
|
+
`message_metrics` contains window duration, received count, dispatched count, active Topic count, and receive-to-dispatch latency sample count, average, P50, P95, and maximum, plus `dedupAccepted` and `dedupSuppressed` counters for the same window. Latency is aggregated in 50ms buckets and never contains an individual message payload. Subscription events include their Topic so an integrator can correlate ownership changes. They are emitted only when the owner transport subscription set changes; idempotent `CONTROL` retries do not produce duplicate subscription events. Treat trace sinks as diagnostic surfaces: redact sensitive Topic conventions before writing to a console or external telemetry. Trace events do not include URLs, credentials, payloads, or error bodies. Errors thrown in the sink are isolated and will not interrupt message distribution, but will output to `console.warn` to help integrators discover diagnostic configuration issues.
|
|
50
50
|
|
|
51
51
|
On `pagehide`, the aggregation timer stops and discards the incomplete window; on `pageshow`, it resumes with a new window. A permanent `stop()` clears the timer. Only diagnostics output is throttled; actual message reception and distribution are never rate-limited.
|
|
52
52
|
|
package/docs/roadmap.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# Roadmap
|
|
2
2
|
|
|
3
|
-
0.
|
|
3
|
+
0.11.0 is the current development line. The next work is organized as 1.0.0 candidates, with protocol stability and operational guarantees taking priority over adding another browser runtime.
|
|
4
|
+
|
|
5
|
+
## 0.11.0 delivered scope
|
|
6
|
+
|
|
7
|
+
- Automatic durable replay retention through `replay.retentionMs` when the persistence adapter supports `clearBefore`.
|
|
8
|
+
- Deduplication accepted/suppressed counters in periodic trace metrics.
|
|
9
|
+
- Publication metadata compatibility coverage across WebSocket, Centrifuge, Worker boundaries, and browser E2E.
|
|
10
|
+
- Service Worker transport decision: remain deliberately unimplemented until a stable connection-lifetime contract exists across target browsers.
|
|
11
|
+
|
|
12
|
+
## 1.0.0 candidates
|
|
13
|
+
|
|
14
|
+
1. Freeze the public export surface and transport-neutral publication envelope.
|
|
15
|
+
2. Document at-least-once delivery and deduplication guarantees precisely.
|
|
16
|
+
3. Add long-running browser soak coverage for replay retention, reconnect, BFCache, and owner migration.
|
|
17
|
+
4. Publish a migration guide and deprecation policy for any pre-1.0 protocol aliases.
|
|
4
18
|
|
|
5
19
|
## 0.7.0 candidates
|
|
6
20
|
|
package/docs/transports.md
CHANGED
|
@@ -141,14 +141,18 @@ const bus = createWebSocketDataBus({
|
|
|
141
141
|
|
|
142
142
|
Wire protocol (JSON text frames):
|
|
143
143
|
|
|
144
|
-
- client → server: `{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data"
|
|
145
|
-
- server → client:
|
|
146
|
-
without a string `topic` are ignored; malformed JSON is reported through
|
|
147
|
-
`handlers.onError` without throwing.
|
|
144
|
+
- client → server: `{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...,"messageId"?:"...","timestamp"?:123}`
|
|
145
|
+
- 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.
|
|
148
146
|
|
|
149
147
|
When `data` is an `ArrayBuffer`, publish uses a binary frame with a small
|
|
150
148
|
header (`0xc7`, UTF-8 topic length, topic, payload). Servers may echo the same
|
|
151
|
-
frame unchanged
|
|
149
|
+
frame unchanged. A binary publication carrying metadata uses the JSON-compatible
|
|
150
|
+
byte-array envelope so `messageId` and `timestamp` are not lost.
|
|
151
|
+
|
|
152
|
+
The Centrifuge session applies the same transport-neutral contract. Payloads
|
|
153
|
+
without metadata keep their original shape. Metadata-bearing publishes use
|
|
154
|
+
`{ data, messageId?, timestamp? }`, while inbound publications additionally
|
|
155
|
+
accept the canonical nested `DataBusPublicationEnvelope`.
|
|
152
156
|
|
|
153
157
|
Lifecycle mapping: `open` → `connected`, `close` → `disconnected`,
|
|
154
158
|
`error` → `error` (DataBus auto-recovery). Subscribe frames are re-sent when
|
package/docs/zh/api.md
CHANGED
|
@@ -86,7 +86,7 @@ subscribe(
|
|
|
86
86
|
- 最后一个 handler 释放后,当前 Tab 才退出该 Topic。
|
|
87
87
|
- transport 尚未 ready 时订阅自动排队。
|
|
88
88
|
- 通配符订阅:以 `.*` 结尾的 Topic(如 `chat.*`)匹配任意后缀,`*` 匹配全部。pattern 以字面量参与路由、归属与传输订阅;携带匹配的具体 topic(或 pattern 本身)的发布都会投递给通配 handler。匹配规则见下方 `topicMatchesPattern`。
|
|
89
|
-
- 重放(可选):构造 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`
|
|
89
|
+
- 重放(可选):构造 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` 后,如果 adapter 支持 `clearBefore`,会在 hydrate 和追加后自动清理过期历史。
|
|
90
90
|
- 持久化 replay store 还可实现 `clearTopic(topic)`;bus 会在最后一个 handler 退订时调用。应用可自行保留 `clear()` 做全量留存清理;`stop()` 会保留 durable history,以支持 reload/BFCache 恢复。
|
|
91
91
|
|
|
92
92
|
### `unsubscribe(topic, handler?)`
|
|
@@ -102,7 +102,11 @@ unsubscribe(topic: string, handler?: DataBusMessageHandler<TData>): void
|
|
|
102
102
|
### `publish(topic, data, options?)`
|
|
103
103
|
|
|
104
104
|
```ts
|
|
105
|
-
publish(
|
|
105
|
+
publish(
|
|
106
|
+
topic: string,
|
|
107
|
+
data: unknown,
|
|
108
|
+
options?: { messageId?: string; timestamp?: number }
|
|
109
|
+
): void
|
|
106
110
|
```
|
|
107
111
|
|
|
108
112
|
将发布操作路由到当前 Topic owner;没有有效路由时使用当前 Worker。
|
|
@@ -111,7 +115,17 @@ publish(topic: string, data: unknown, options?: { messageId?: string }): void
|
|
|
111
115
|
|
|
112
116
|
当 owner 是远端 Tab、且发布控制消息无法投递时(例如 BroadcastChannel 无法克隆 payload),`publish()` 会通过 `onError` 上报失败,而不是静默丢弃。
|
|
113
117
|
|
|
114
|
-
传入 `options.messageId`
|
|
118
|
+
传入 `options.messageId` 和 `options.timestamp` 后,元数据会穿过跨 Tab 路由、Worker 边界和支持的 transport。服务端必须回显或以其他方式保留它们,入站去重和 replay retention 才能使用。
|
|
119
|
+
|
|
120
|
+
`DataBusMessage` 与 `DataBusPublication` 暴露相同的可选元数据。
|
|
121
|
+
`DataBusPublicationEnvelope<TData>` 是标准 JSON envelope 类型:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
{
|
|
125
|
+
op: 'publication',
|
|
126
|
+
publication: { topic, data, messageId?, timestamp? }
|
|
127
|
+
}
|
|
128
|
+
```
|
|
115
129
|
|
|
116
130
|
### `clearReplay()`
|
|
117
131
|
|
|
@@ -121,6 +135,10 @@ clearReplay(): Promise<void>
|
|
|
121
135
|
|
|
122
136
|
清空内存 replay 缓冲,并调用持久化适配器可选的 `clear()`。适合留存策略、退出登录或租户切换;普通 `stop()` 仍会保留 durable history。
|
|
123
137
|
|
|
138
|
+
`clearReplayTopic(topic)` 只清理一个精确 topic。`getDedupStats()` 返回 `enabled`、`tracked`、`accepted`、`suppressed` 四项有界统计;`resetDedup()` 清除已记忆 ID 和计数,不改变 dedup 配置。
|
|
139
|
+
|
|
140
|
+
`clearReplayBefore(timestamp)` 按毫秒时间戳清理旧记录;实现可选 `clearBefore()` 的持久化适配器会同步执行该清理。
|
|
141
|
+
|
|
124
142
|
### `onStatus(handler)`
|
|
125
143
|
|
|
126
144
|
```ts
|
|
@@ -181,7 +199,7 @@ trace: {
|
|
|
181
199
|
}
|
|
182
200
|
```
|
|
183
201
|
|
|
184
|
-
低频事件类型包括 `lifecycle`、`status`、`subscription`、`coordination` 和 `error`;高频数据按窗口输出 `message_metrics`,包含接收/分发计数、活跃 Topic 数量和分发延迟聚合(`dispatchSamples`、`dispatchAvgMs`、`dispatchP50Ms`、`dispatchP95Ms`、`dispatchMaxMs`)。所有公开事件都使用固定结构,不包含原始 Topic、消息 payload、连接地址或错误正文。sink 抛错会被隔离,不会中断消息分发,但会向 `console.warn` 输出错误,便于定位诊断配置问题。sink 应尽量避免抛出异常——预期中的错误条件应通过事件数据表达,而不是通过异常上报。
|
|
202
|
+
低频事件类型包括 `lifecycle`、`status`、`subscription`、`coordination` 和 `error`;高频数据按窗口输出 `message_metrics`,包含接收/分发计数、活跃 Topic 数量和分发延迟聚合(`dispatchSamples`、`dispatchAvgMs`、`dispatchP50Ms`、`dispatchP95Ms`、`dispatchMaxMs`),以及去重结果(`dedupAccepted`、`dedupSuppressed`)。所有公开事件都使用固定结构,不包含原始 Topic、消息 payload、连接地址或错误正文。sink 抛错会被隔离,不会中断消息分发,但会向 `console.warn` 输出错误,便于定位诊断配置问题。sink 应尽量避免抛出异常——预期中的错误条件应通过事件数据表达,而不是通过异常上报。
|
|
185
203
|
|
|
186
204
|
### `stop()`
|
|
187
205
|
|
|
@@ -283,8 +301,11 @@ new WebSocketTransport<TData>(connection: WebSocketDataBusConfig)
|
|
|
283
301
|
|
|
284
302
|
JSON 文本帧:
|
|
285
303
|
|
|
286
|
-
- client → server:`{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data"
|
|
287
|
-
- server → client
|
|
304
|
+
- client → server:`{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...,"messageId"?:...,"timestamp"?:...}`
|
|
305
|
+
- server → client(标准):`{"op":"publication","publication":{"topic":"...","data":...,"messageId"?:...,"timestamp"?:...}}`
|
|
306
|
+
- server → client(旧格式,继续兼容):`{"topic":"...","data":...}`
|
|
307
|
+
|
|
308
|
+
没有字符串 publication `topic` 的帧会被忽略;非法 JSON 通过 `handlers.onError` 上报而不会抛出。
|
|
288
309
|
|
|
289
310
|
支持 pattern 的服务器建议以具体 topic 标注发布;以 pattern 本身标注的发布走精确匹配路径投递。
|
|
290
311
|
|
package/docs/zh/architecture.md
CHANGED
|
@@ -387,6 +387,8 @@ sequenceDiagram
|
|
|
387
387
|
4. owner 通过 BroadcastChannel 广播 `EVENT/DATABUS_PUBLICATION`;自身 Tab 也有本地订阅时直接分发一次。BroadcastChannel 从不把消息回传给发送者,因此不会重复分发。
|
|
388
388
|
5. 其余每个 Tab 收到 `EVENT` 后,仅当自己持有该 Topic 的 `subscriber:{topicKey}:{tabId}` 记录时才调用本地 handler;没有本地订阅的 Tab 直接丢弃。
|
|
389
389
|
|
|
390
|
+
可选的 publication 元数据(`messageId` 与 `timestamp`)与 payload 走同一条路径:`CONTROL/PUBLISH` → transport/服务器 → `DataBusMessage` → `EVENT` 扇出。它不会写入协调存储。各 transport 会在三处分发门之前,把旧 payload 格式与标准 `DataBusPublicationEnvelope` 统一规范化。
|
|
391
|
+
|
|
390
392
|
在 transport 层,Centrifuge 客户端可能同时在 `client` 对象和对应 `Subscription` 对象上触发同一 publication。为避免把同一条服务器 publication 分发两次,CentrifugeSession 的 client 级 `publication` 监听只处理**没有客户端订阅**的 topic(即服务端订阅);已有活跃订阅的 topic 仅由 subscription 级监听派发。
|
|
391
393
|
|
|
392
394
|
```mermaid
|
|
@@ -410,7 +412,11 @@ sequenceDiagram
|
|
|
410
412
|
|
|
411
413
|
BroadcastChannel 不会把消息回传给发送者,因此 owner 收不到自己广播的 `EVENT`——本地分发是唯一一次本地投递。
|
|
412
414
|
|
|
413
|
-
publication 不写入 localStorage
|
|
415
|
+
publication 不写入 localStorage。消息数据与 publication 元数据只存在于 BroadcastChannel 内存事件和 transport 内;批量写入只覆盖协调元数据。
|
|
416
|
+
|
|
417
|
+
### Service Worker 边界
|
|
418
|
+
|
|
419
|
+
SDK 当前刻意不在 Service Worker 中承载实时 transport。Service Worker 可能在事件之间被浏览器终止,不能提供持久的前台连接生命周期,而且各浏览器对长连接 WebSocket 的限制并不一致。未来若实现 adapter,必须先定义明确的连接 owner、客户端唤醒协议、重连策略和持久化交接语义;在这些条件标准化并有真实浏览器测试前,Dedicated/Shared Worker 仍是受支持的运行模型。
|
|
414
420
|
|
|
415
421
|
### 分发流程:三道关卡
|
|
416
422
|
|
package/docs/zh/capabilities.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
| 降级 | localStorage 或 BroadcastChannel 不可用时本地运行 | ✅ 已实现 | 保留当前 Tab 的连接和订阅能力 |
|
|
23
23
|
| Centrifuge | 内置 Dedicated / Shared Worker transport | ✅ 已实现 | 支持 subscribe、unsubscribe、publish、连接状态和错误上报;`auto` 从 SharedWorker → Dedicated Worker → 主线程 WebSocket 降级 |
|
|
24
24
|
| 安全边界 | localStorage 使用连接和 Topic 派生不透明 key;BroadcastChannel 协调消息以明文传输 Topic 名称 | ✅ 已实现 | 不持久化 URL、原始 Topic 名称、凭证或 publication payload。BroadcastChannel 协调消息仅存在于内存中,以明文传输 Topic 名称——不会被持久化。 |
|
|
25
|
-
| 诊断 |
|
|
25
|
+
| 诊断 | 聚合生命周期、吞吐量、分发延迟、去重结果、恢复重试、路由确认和迁移 | ✅ 已实现 | 默认关闭;默认每 5 秒输出指标,并以有界 reliability 事件记录恢复和路由协调 |
|
|
26
26
|
| 性能 | 协调元数据批量写入 + 退避重试 | ✅ 已实现 | 心跳、路由和 subscriber 写入合并后在微任务中 flush;失败时指数退避;`pagehide` / `stop()` 同步 flush |
|
|
27
27
|
| 性能 | 可选 ArrayBuffer Transferable 传输 | ✅ 已实现 | 开启 `transferable: true` 后,二进制 publish/receive 跳过 structured clone 复制;对象消息 API 不变 |
|
|
28
28
|
| 消息语义 | exactly-once 投递 | 未实现 | 正常交接会避免重叠,但异常恢复和 transport/服务端行为仍不提供 exactly-once 保证 |
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
| 负载策略 | 按消息速率、字节数或 CPU 自适应加权 | 规划中 | 当前负载仅按 owner Topic 数量计算 |
|
|
32
32
|
| 可观测性 | owner 确认、迁移和恢复尝试的指标/事件 | ✅ 已实现 | `DataBusReliabilityTraceEvent` 记录有界的 route ack/migration 与 transport recovery;服务端最终确认仍由 transport 决定 |
|
|
33
33
|
| 运行时模型 | SharedWorker / Dedicated Worker transport | ✅ 已实现 | `workerMode` 支持 `dedicated`、`shared` 和 `auto`,默认 `dedicated` |
|
|
34
|
-
| 运行时模型 | Service Worker transport | 未实现 |
|
|
34
|
+
| 运行时模型 | Service Worker transport | 未实现 | 刻意延后;生命周期与长连接约束见 `docs/zh/architecture.md` |
|
|
35
35
|
| 持久消息 | 跨页面关闭持久化 publication 或发布命令 | 未实现 | SDK 不持久化业务 payload,也不在恢复后重放发布命令 |
|
|
36
36
|
|
|
37
37
|
## 验收标准
|
package/docs/zh/configuration.md
CHANGED
|
@@ -46,7 +46,7 @@ const bus = new CrossTabDataBus({
|
|
|
46
46
|
| `metricsIntervalMs` | `number` | `5000` | 聚合窗口,必须是大于 0 的有限数值 |
|
|
47
47
|
| `sink` | `(event) => void` | 必填 | 由接入方决定 console、监控 SDK 或其他出口 |
|
|
48
48
|
|
|
49
|
-
`message_metrics` 包含窗口时长、接收数、分发数、活跃 Topic 数量,以及接收 → 分发延迟的样本数、平均值、P50、P95
|
|
49
|
+
`message_metrics` 包含窗口时长、接收数、分发数、活跃 Topic 数量,以及接收 → 分发延迟的样本数、平均值、P50、P95 和最大值,并包含同一窗口的 `dedupAccepted` 与 `dedupSuppressed` 计数。延迟按 50ms 桶聚合,不包含单条消息 payload。订阅事件会带 Topic,便于接入方关联 owner 变化;仅 owner transport 的订阅集合实际变化时才输出,幂等 `CONTROL` 重试不会产生重复订阅事件。将 trace 写入 console 或外部监控前,应按业务 Topic 约定进行脱敏。Trace 不包含 URL、凭证、payload 或错误正文。sink 抛错会被隔离,不会中断消息分发,但会向 `console.warn` 输出错误,方便接入方发现诊断配置问题。
|
|
50
50
|
|
|
51
51
|
`pagehide` 时聚合定时器会停止并丢弃未完成窗口,`pageshow` 后以新窗口恢复;永久 `stop()` 会清理定时器。这里节流的只是诊断输出,真实消息接收与分发不会被限速。
|
|
52
52
|
|
package/docs/zh/transports.md
CHANGED
|
@@ -129,13 +129,17 @@ const bus = createWebSocketDataBus({
|
|
|
129
129
|
|
|
130
130
|
线协议(JSON 文本帧):
|
|
131
131
|
|
|
132
|
-
- client → server:`{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data"
|
|
133
|
-
- server → client
|
|
134
|
-
会被忽略;非法 JSON 通过 `handlers.onError` 上报而不会抛出。
|
|
132
|
+
- client → server:`{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...,"messageId"?:"...","timestamp"?:123}`
|
|
133
|
+
- server → client:标准 publication 为 `{"op":"publication","publication":{"topic":"...","data":...,"messageId"?:"...","timestamp"?:123}}`;旧的扁平 `{"topic":"...","data":...}` 帧仍然兼容。没有字符串 topic 的帧会被忽略;非法 JSON 通过 `handlers.onError` 上报而不会抛出。
|
|
135
134
|
|
|
136
135
|
当 `data` 是 `ArrayBuffer` 时,publish 使用二进制帧:帧头为 `0xc7`,随后是
|
|
137
136
|
UTF-8 topic 长度、topic 和 payload。服务器可以原样回显该帧;其他 payload 仍走
|
|
138
|
-
JSON
|
|
137
|
+
JSON 兼容路径。带 metadata 的二进制 publication 使用 JSON 兼容的字节数组
|
|
138
|
+
envelope,避免丢失 `messageId` 与 `timestamp`。
|
|
139
|
+
|
|
140
|
+
Centrifuge session 遵循同一个传输无关契约:不带 metadata 的 payload 保持原始
|
|
141
|
+
形状;带 metadata 的 publish 使用 `{ data, messageId?, timestamp? }`,入站还接受
|
|
142
|
+
标准嵌套 `DataBusPublicationEnvelope`。
|
|
139
143
|
|
|
140
144
|
生命周期映射:`open` → `connected`,`close` → `disconnected`,`error` → `error`
|
|
141
145
|
(触发 DataBus 自动恢复)。socket 原地重连时自动重发订阅帧。支持 pattern 的
|
package/package.json
CHANGED