cross-tab-worker-databus 0.1.2 → 0.2.1
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 +64 -0
- package/README.md +32 -0
- package/README.zh.md +30 -0
- package/dist/centrifuge-protocol.d.ts +51 -15
- package/dist/centrifuge-protocol.d.ts.map +1 -1
- package/dist/centrifuge-session.d.ts +11 -3
- package/dist/centrifuge-session.d.ts.map +1 -1
- package/dist/centrifuge.d.ts +10 -2
- package/dist/centrifuge.d.ts.map +1 -1
- package/dist/centrifuge.js +69 -26
- package/dist/centrifuge.js.map +2 -2
- package/dist/centrifuge.shared.worker.js +73 -25
- package/dist/centrifuge.shared.worker.js.map +2 -2
- package/dist/centrifuge.worker.js +41 -12
- package/dist/centrifuge.worker.js.map +2 -2
- package/dist/{chunk-53INHVYO.js → chunk-LBXREMZA.js} +263 -158
- package/dist/chunk-LBXREMZA.js.map +7 -0
- package/dist/core/cluster.d.ts +49 -4
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/data-bus.d.ts +19 -2
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/environment.d.ts +16 -2
- package/dist/core/environment.d.ts.map +1 -1
- package/dist/core/hash.d.ts.map +1 -1
- package/dist/core/routing.d.ts +5 -2
- package/dist/core/routing.d.ts.map +1 -1
- package/dist/core/storage-batch.d.ts +12 -0
- package/dist/core/storage-batch.d.ts.map +1 -1
- package/dist/core/trace.d.ts +16 -1
- package/dist/core/trace.d.ts.map +1 -1
- package/dist/core/types.d.ts +76 -21
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/worker-mode.d.ts +12 -3
- package/dist/worker-mode.d.ts.map +1 -1
- package/dist/workers/port-reaper.d.ts +21 -6
- package/dist/workers/port-reaper.d.ts.map +1 -1
- package/docs/README.md +1 -0
- package/docs/architecture.md +18 -8
- package/docs/getting-started.md +3 -0
- package/docs/transports.md +145 -0
- package/docs/zh/README.md +1 -0
- package/docs/zh/architecture.md +18 -8
- package/docs/zh/getting-started.md +3 -0
- package/docs/zh/transports.md +133 -0
- package/package.json +29 -6
- package/dist/chunk-53INHVYO.js.map +0 -7
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Transport Backends
|
|
2
|
+
|
|
3
|
+
> [中文](./zh/transports.md) | English
|
|
4
|
+
|
|
5
|
+
The core package (`cross-tab-worker-databus`) is transport-agnostic. It defines a
|
|
6
|
+
`DataBusTransport` contract; the built-in Centrifuge backend is one implementation
|
|
7
|
+
of that contract, exposed as the optional `./centrifuge` subpath. This document
|
|
8
|
+
describes the contract and how to wire up a third-party backend (native WebSocket,
|
|
9
|
+
socket.io, SSE, etc.).
|
|
10
|
+
|
|
11
|
+
## The `DataBusTransport` contract
|
|
12
|
+
|
|
13
|
+
Every backend implements five methods. `subscribe` / `unsubscribe` MUST be
|
|
14
|
+
idempotent — the DataBus may call them repeatedly and replays them on reconnect.
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
interface DataBusTransport<TConfig = unknown, TData = unknown> {
|
|
18
|
+
start(config: TConfig, handlers: DataBusTransportHandlers<TData>): MaybePromise<void>;
|
|
19
|
+
subscribe(topic: string): MaybePromise<void>;
|
|
20
|
+
unsubscribe(topic: string): MaybePromise<void>;
|
|
21
|
+
publish(topic: string, data: unknown): MaybePromise<void>;
|
|
22
|
+
stop(): MaybePromise<void>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface DataBusTransportHandlers<TData = unknown> {
|
|
26
|
+
onMessage: (message: DataBusMessage<TData>) => void;
|
|
27
|
+
onStatus: (status: WorkerStatus) => void; // 'connecting' | 'connected' | 'disconnected' | 'error'
|
|
28
|
+
onError: (error: unknown) => void;
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`start()` receives the user-supplied connection config (untyped `TConfig` — the
|
|
33
|
+
backend owns its shape) and the three callbacks. Call `onStatus` whenever the
|
|
34
|
+
connection state changes; call `onMessage` for each inbound publication; call
|
|
35
|
+
`onError` for non-fatal errors (the DataBus applies a recovery cooldown so a
|
|
36
|
+
flapping connection does not retry-loop).
|
|
37
|
+
|
|
38
|
+
## Architectural layers
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
CrossTabDataBus ──► DataBusTransport (your backend)
|
|
42
|
+
│
|
|
43
|
+
┌───────┴────────┐
|
|
44
|
+
│ Worker protocol │ (your backend's main-thread ↔ worker messages)
|
|
45
|
+
└───────┬────────┘
|
|
46
|
+
│
|
|
47
|
+
Session layer (the actual client: WebSocket / centrifuge / …)
|
|
48
|
+
│
|
|
49
|
+
Server
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The DataBus layer handles cross-tab coordination (BroadcastChannel control
|
|
53
|
+
plane, localStorage routes, owner selection, failover, page lifecycle). Your
|
|
54
|
+
transport only owns the I/O path: connect, subscribe, publish, disconnect.
|
|
55
|
+
|
|
56
|
+
## Implementing a backend
|
|
57
|
+
|
|
58
|
+
### 1. Define your Worker protocol
|
|
59
|
+
|
|
60
|
+
Mirror the Centrifuge backend's `centrifuge-protocol.ts`: a discriminated union
|
|
61
|
+
of messages the main thread sends to the Worker (`INIT` / `SUBSCRIBE` /
|
|
62
|
+
`UNSUBSCRIBE` / `PUBLISH` / `PUBLISH_BIN` / `PING` / `STOP`) and a union the
|
|
63
|
+
Worker posts back (`STATUS` / `MESSAGE` / `MESSAGE_BIN` / `ERROR`). Keep it
|
|
64
|
+
structured-cloneable (no functions,
|
|
65
|
+
no class instances — `Error` must be serialised).
|
|
66
|
+
|
|
67
|
+
### 2. Implement the session
|
|
68
|
+
|
|
69
|
+
A session class owns one connection and lives inside the Worker (or, as a
|
|
70
|
+
fallback, on the main thread). It receives protocol messages via a `handle()`
|
|
71
|
+
method and posts outputs back through a sink. See
|
|
72
|
+
[`centrifuge-session.ts`](../src/centrifuge-session.ts) for the reference shape:
|
|
73
|
+
|
|
74
|
+
- `handle(message)` dispatches by `message.type`.
|
|
75
|
+
- `subscribe(topic)` is idempotent — re-subscribing an existing topic is a no-op.
|
|
76
|
+
- `unsubscribe(topic)` removes listeners before disconnecting, to avoid a late
|
|
77
|
+
event resurrecting a re-subscribed topic.
|
|
78
|
+
- `stop()` disconnects, clears all subscriptions, and emits `disconnected`.
|
|
79
|
+
|
|
80
|
+
### 3. Implement the transport
|
|
81
|
+
|
|
82
|
+
The transport selects a backend (SharedWorker / Dedicated Worker / local),
|
|
83
|
+
posts protocol messages to it, and routes Worker outputs back to the
|
|
84
|
+
`DataBusTransportHandlers`. See [`centrifuge.ts`](../src/centrifuge.ts) for the
|
|
85
|
+
reference shape, including:
|
|
86
|
+
|
|
87
|
+
- **Backend selection**: reuse `selectWorkerBackend` from `worker-mode.ts` so
|
|
88
|
+
your backend degrades consistently with the rest of the SDK.
|
|
89
|
+
- **Generation guard**: bump a monotonic counter when a backend is created;
|
|
90
|
+
error handlers check it so late errors from a superseded Worker cannot
|
|
91
|
+
corrupt the fresh session.
|
|
92
|
+
- **SharedWorker heartbeat**: if you use a SharedWorker, send periodic PINGs
|
|
93
|
+
so a `PortReaper` can reclaim dead-tab sessions.
|
|
94
|
+
|
|
95
|
+
### 4. Expose as a subpath
|
|
96
|
+
|
|
97
|
+
Add `exports` entries in `package.json` (one per entry point — the main bundle,
|
|
98
|
+
the dedicated worker, the shared worker):
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"exports": {
|
|
103
|
+
"./your-backend": {
|
|
104
|
+
"types": "./dist/your-backend.d.ts",
|
|
105
|
+
"import": "./dist/your-backend.js"
|
|
106
|
+
},
|
|
107
|
+
"./your-backend.worker": "./dist/your-backend.worker.js",
|
|
108
|
+
"./your-backend.shared.worker": "./dist/your-backend.shared.worker.js"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
This keeps the core package zero-dependency: users who do not import
|
|
114
|
+
`./your-backend` never pull your client library into their bundle.
|
|
115
|
+
|
|
116
|
+
### 5. Register the peer dependency
|
|
117
|
+
|
|
118
|
+
Declare your client library as an optional peer dependency so consumers
|
|
119
|
+
opt in:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"peerDependencies": { "your-client-lib": "^x.y.z" },
|
|
124
|
+
"peerDependenciesMeta": { "your-client-lib": { "optional": true } }
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Factory entry point
|
|
129
|
+
|
|
130
|
+
Provide a `create<Backend>DataBus(options)` factory that wires the transport
|
|
131
|
+
into a `CrossTabDataBus`, mirroring `createCentrifugeDataBus`. This is the
|
|
132
|
+
surface most consumers use; it should accept the connection config, cluster
|
|
133
|
+
key (defaulting to the connection URL), and forward trace / worker-mode
|
|
134
|
+
options to the DataBus.
|
|
135
|
+
|
|
136
|
+
## What the transport does NOT own
|
|
137
|
+
|
|
138
|
+
- **Cross-tab routing**: the `WorkerClusterRuntime` decides which tab owns a
|
|
139
|
+
topic. Your transport just subscribes when told.
|
|
140
|
+
- **Reconnect replay**: the DataBus replays the current owner's topics on
|
|
141
|
+
reconnect; your transport's `subscribe` must be safe to call again.
|
|
142
|
+
- **Publication fan-out**: the owner broadcasts publications over
|
|
143
|
+
BroadcastChannel; your transport only receives and reports them.
|
|
144
|
+
- **Page lifecycle**: the DataBus suspends/resumes the transport on
|
|
145
|
+
`pagehide` / `pageshow`; your transport's `stop()` must be clean.
|
package/docs/zh/README.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|---|---|
|
|
9
9
|
| [快速接入](./getting-started.md) | 安装、创建实例、订阅、发布和销毁 |
|
|
10
10
|
| [配置说明](./configuration.md) | 核心配置、Centrifuge 配置、默认值和约束 |
|
|
11
|
+
| [Transport 后端](./transports.md) | `DataBusTransport` 契约、Worker 协议与第三方后端接入指南 |
|
|
11
12
|
| [API 参考](./api.md) | 公共入口、类型、方法、返回值和行为 |
|
|
12
13
|
| [架构说明](./architecture.md) | Worker 集群、路由、存储、迁移和降级设计 |
|
|
13
14
|
| [能力矩阵](./capabilities.md) | 已实现、未实现和计划待实现的能力矩阵 |
|
package/docs/zh/architecture.md
CHANGED
|
@@ -10,23 +10,33 @@ graph TB
|
|
|
10
10
|
subgraph TabA["Tab A"]
|
|
11
11
|
AppA["业务模块"] --> BusA["CrossTabDataBus"]
|
|
12
12
|
BusA --> RuntimeA["WorkerClusterRuntime"]
|
|
13
|
-
BusA -->
|
|
13
|
+
BusA --> TransportA["CentrifugeWorkerTransport"]
|
|
14
|
+
TransportA --> WorkerA["Dedicated / Shared Worker A"]
|
|
14
15
|
end
|
|
15
16
|
subgraph TabB["Tab B"]
|
|
16
17
|
AppB["业务模块"] --> BusB["CrossTabDataBus"]
|
|
17
18
|
BusB --> RuntimeB["WorkerClusterRuntime"]
|
|
18
|
-
BusB -->
|
|
19
|
+
BusB --> TransportB["CentrifugeWorkerTransport"]
|
|
20
|
+
TransportB --> WorkerB["Dedicated / Shared Worker B"]
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
RuntimeA <--> Channel["BroadcastChannel 控制面"]
|
|
23
25
|
RuntimeB <--> Channel
|
|
24
|
-
RuntimeA
|
|
25
|
-
RuntimeB
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
RuntimeA --> BatchA["BatchingStorageWriter"]
|
|
27
|
+
RuntimeB --> BatchB["BatchingStorageWriter"]
|
|
28
|
+
BatchA <--> Registry["localStorage Worker 注册表"]
|
|
29
|
+
BatchB <--> Registry
|
|
30
|
+
BatchA <--> Routes["localStorage Topic 路由表"]
|
|
31
|
+
BatchB <--> Routes
|
|
32
|
+
WorkerA --> SessionA["CentrifugeSession"]
|
|
33
|
+
WorkerB --> SessionB["CentrifugeSession"]
|
|
34
|
+
SessionA --> Server["Centrifuge / 实时服务器"]
|
|
35
|
+
SessionB --> Server
|
|
36
|
+
subgraph SW["SharedWorker 进程(backend = shared 时)"]
|
|
37
|
+
Reaper["PortReaper"] -.-> SessionA
|
|
38
|
+
Reaper -.-> SessionB
|
|
39
|
+
end
|
|
30
40
|
```
|
|
31
41
|
|
|
32
42
|
默认 `workerMode: 'dedicated'` 时,每个 Tab 使用独立的 transport Worker。配置为 `shared` 或 `auto` 且浏览器支持 SharedWorker 时,同源 Tab 复用同一个 SharedWorker;SharedWorker 内每个连接 port 各自维护独立的 `CentrifugeSession`,一个 Tab 刷新或停止不会影响其他 Tab。`auto` 模式按 **SharedWorker → Dedicated Worker → 主线程 WebSocket** 降级,`dedicated` 模式按 **Dedicated Worker → SharedWorker → 主线程 WebSocket** 降级。`BroadcastChannel` 只负责控制消息和实时 publication 转发;localStorage 只负责最终一致的协调元数据。
|
|
@@ -12,8 +12,11 @@ pnpm add cross-tab-worker-databus
|
|
|
12
12
|
|
|
13
13
|
- `cross-tab-worker-databus`:核心 DataBus 和 transport 接口
|
|
14
14
|
- `cross-tab-worker-databus/centrifuge`:内置 Centrifuge Worker transport
|
|
15
|
+
- `cross-tab-worker-databus/centrifuge.worker`:Dedicated Worker 构建产物,默认由内置 factory 加载,通常无需直接引用
|
|
15
16
|
- `cross-tab-worker-databus/centrifuge.shared.worker`:SharedWorker 构建产物,默认由内置 factory 加载,通常无需直接引用
|
|
16
17
|
|
|
18
|
+
`cross-tab-worker-databus/centrifuge` 入口依赖可选 peer dependency `centrifuge`(^5.5.3)。使用内置 Centrifuge transport 时请一并安装:`pnpm add centrifuge`。
|
|
19
|
+
|
|
17
20
|
## 2. 创建实例
|
|
18
21
|
|
|
19
22
|
建议在应用基础设施层创建一个实例,其他模块直接导入。这样同一 Tab 内的业务模块会共享 Worker、连接和 Topic 引用。
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Transport 后端
|
|
2
|
+
|
|
3
|
+
> 中文 | [English](../transports.md)
|
|
4
|
+
|
|
5
|
+
核心包(`cross-tab-worker-databus`)与 transport 无关。它定义了一个
|
|
6
|
+
`DataBusTransport` 契约;内置的 Centrifuge 后端是该契约的一个实现,作为可选的
|
|
7
|
+
`./centrifuge` subpath 暴露。本文档描述该契约以及如何接入第三方后端(原生
|
|
8
|
+
WebSocket、socket.io、SSE 等)。
|
|
9
|
+
|
|
10
|
+
## `DataBusTransport` 契约
|
|
11
|
+
|
|
12
|
+
每个后端实现 5 个方法。`subscribe` / `unsubscribe` 必须幂等——DataBus 可能重复
|
|
13
|
+
调用,并在重连时回放。
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
interface DataBusTransport<TConfig = unknown, TData = unknown> {
|
|
17
|
+
start(config: TConfig, handlers: DataBusTransportHandlers<TData>): MaybePromise<void>;
|
|
18
|
+
subscribe(topic: string): MaybePromise<void>;
|
|
19
|
+
unsubscribe(topic: string): MaybePromise<void>;
|
|
20
|
+
publish(topic: string, data: unknown): MaybePromise<void>;
|
|
21
|
+
stop(): MaybePromise<void>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface DataBusTransportHandlers<TData = unknown> {
|
|
25
|
+
onMessage: (message: DataBusMessage<TData>) => void;
|
|
26
|
+
onStatus: (status: WorkerStatus) => void; // 'connecting' | 'connected' | 'disconnected' | 'error'
|
|
27
|
+
onError: (error: unknown) => void;
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`start()` 接收用户提供的连接配置(无类型 `TConfig`——后端自行定义其形状)和
|
|
32
|
+
三个回调。连接状态变化时调 `onStatus`;收到 publication 时调 `onMessage`;
|
|
33
|
+
非致命错误调 `onError`(DataBus 有恢复冷却窗口,避免抖动连接死循环重试)。
|
|
34
|
+
|
|
35
|
+
## 架构分层
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
CrossTabDataBus ──► DataBusTransport(你的后端)
|
|
39
|
+
│
|
|
40
|
+
┌───────┴────────┐
|
|
41
|
+
│ Worker 协议 │ (你的后端的主线程 ↔ worker 消息)
|
|
42
|
+
└───────┬────────┘
|
|
43
|
+
│
|
|
44
|
+
Session 层 (真正的客户端:WebSocket / centrifuge / …)
|
|
45
|
+
│
|
|
46
|
+
服务端
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
DataBus 层负责跨 Tab 协调(BroadcastChannel 控制面、localStorage 路由、owner 选举、
|
|
50
|
+
故障转移、页面生命周期)。你的 transport 只负责 I/O 路径:连接、订阅、发布、断开。
|
|
51
|
+
|
|
52
|
+
## 实现一个后端
|
|
53
|
+
|
|
54
|
+
### 1. 定义你的 Worker 协议
|
|
55
|
+
|
|
56
|
+
参照 Centrifuge 后端的 `centrifuge-protocol.ts`:一个主线程发给 Worker 的
|
|
57
|
+
判别联合(`INIT` / `SUBSCRIBE` / `UNSUBSCRIBE` / `PUBLISH` / `PUBLISH_BIN` /
|
|
58
|
+
`PING` / `STOP`)和一个 Worker 回传的联合(`STATUS` / `MESSAGE` / `MESSAGE_BIN` /
|
|
59
|
+
`ERROR`)。保持结构化克隆安全
|
|
60
|
+
(无函数、无类实例——`Error` 必须序列化)。
|
|
61
|
+
|
|
62
|
+
### 2. 实现 session
|
|
63
|
+
|
|
64
|
+
一个 session 类持有一个连接,运行在 Worker 内(或作为降级运行在主线程)。
|
|
65
|
+
它通过 `handle()` 方法接收协议消息,通过 sink 回传输出。参见
|
|
66
|
+
[`centrifuge-session.ts`](../../src/centrifuge-session.ts) 的参考形状:
|
|
67
|
+
|
|
68
|
+
- `handle(message)` 按 `message.type` 分派。
|
|
69
|
+
- `subscribe(topic)` 幂等——对已存在 topic 重复订阅是 no-op。
|
|
70
|
+
- `unsubscribe(topic)` 先移除监听器再断开,避免迟到事件复活已重订阅的 topic。
|
|
71
|
+
- `stop()` 断开、清理所有订阅、emit `disconnected`。
|
|
72
|
+
|
|
73
|
+
### 3. 实现 transport
|
|
74
|
+
|
|
75
|
+
transport 选择后端(SharedWorker / Dedicated Worker / 本地),向它发送协议
|
|
76
|
+
消息,并把 Worker 输出路由回 `DataBusTransportHandlers`。参见
|
|
77
|
+
[`centrifuge.ts`](../../src/centrifuge.ts) 的参考形状,包括:
|
|
78
|
+
|
|
79
|
+
- **后端选举**:复用 `worker-mode.ts` 的 `selectWorkerBackend`,使你的后端与
|
|
80
|
+
SDK 其余部分降级行为一致。
|
|
81
|
+
- **generation 守卫**:创建后端时递增单调计数器;错误处理检查它,使被取代的
|
|
82
|
+
Worker 的迟到错误不会污染新 session。
|
|
83
|
+
- **SharedWorker 心跳**:若用 SharedWorker,定期发 PING,让 `PortReaper` 能
|
|
84
|
+
回收死 tab 的 session。
|
|
85
|
+
|
|
86
|
+
### 4. 作为 subpath 暴露
|
|
87
|
+
|
|
88
|
+
在 `package.json` 加 `exports` 条目(每个入口一个——主 bundle、dedicated worker、
|
|
89
|
+
shared worker):
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"exports": {
|
|
94
|
+
"./your-backend": {
|
|
95
|
+
"types": "./dist/your-backend.d.ts",
|
|
96
|
+
"import": "./dist/your-backend.js"
|
|
97
|
+
},
|
|
98
|
+
"./your-backend.worker": "./dist/your-backend.worker.js",
|
|
99
|
+
"./your-backend.shared.worker": "./dist/your-backend.shared.worker.js"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
这保持核心包零依赖:不导入 `./your-backend` 的用户不会把你的客户端库打进 bundle。
|
|
105
|
+
|
|
106
|
+
### 5. 声明 peer 依赖
|
|
107
|
+
|
|
108
|
+
将你的客户端库声明为可选 peer 依赖,让消费者自行选择:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"peerDependencies": { "your-client-lib": "^x.y.z" },
|
|
113
|
+
"peerDependenciesMeta": { "your-client-lib": { "optional": true } }
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 工厂入口
|
|
118
|
+
|
|
119
|
+
提供一个 `create<Backend>DataBus(options)` 工厂,把 transport 接入
|
|
120
|
+
`CrossTabDataBus`,与 `createCentrifugeDataBus` 对称。这是大多数消费者使用的
|
|
121
|
+
界面;它应接受连接配置、cluster key(默认为连接 URL),并把 trace /
|
|
122
|
+
worker-mode 选项转发给 DataBus。
|
|
123
|
+
|
|
124
|
+
## transport 不负责的事
|
|
125
|
+
|
|
126
|
+
- **跨 Tab 路由**:`WorkerClusterRuntime` 决定哪个 tab 拥有 topic。你的 transport
|
|
127
|
+
只在被通知时订阅。
|
|
128
|
+
- **重连回放**:DataBus 在重连时回放当前 owner 的 topic;你的 transport 的
|
|
129
|
+
`subscribe` 必须可安全重复调用。
|
|
130
|
+
- **publication 扇出**:owner 通过 BroadcastChannel 广播 publication;你的
|
|
131
|
+
transport 只接收并上报。
|
|
132
|
+
- **页面生命周期**:DataBus 在 `pagehide` / `pageshow` 时挂起/恢复 transport;
|
|
133
|
+
你的 transport 的 `stop()` 必须干净。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cross-tab-worker-databus",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
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",
|
|
@@ -41,31 +41,54 @@
|
|
|
41
41
|
"types": "./dist/centrifuge.d.ts",
|
|
42
42
|
"import": "./dist/centrifuge.js"
|
|
43
43
|
},
|
|
44
|
-
"./centrifuge.worker":
|
|
45
|
-
|
|
44
|
+
"./centrifuge.worker": {
|
|
45
|
+
"types": "./dist/workers/centrifuge.worker.d.ts",
|
|
46
|
+
"default": "./dist/centrifuge.worker.js"
|
|
47
|
+
},
|
|
48
|
+
"./centrifuge.shared.worker": {
|
|
49
|
+
"types": "./dist/workers/centrifuge.shared.worker.d.ts",
|
|
50
|
+
"default": "./dist/centrifuge.shared.worker.js"
|
|
51
|
+
},
|
|
46
52
|
"./package.json": "./package.json"
|
|
47
53
|
},
|
|
54
|
+
"sideEffects": [
|
|
55
|
+
"./dist/centrifuge.worker.js",
|
|
56
|
+
"./dist/centrifuge.shared.worker.js"
|
|
57
|
+
],
|
|
48
58
|
"scripts": {
|
|
49
59
|
"build": "node scripts/build.mjs",
|
|
50
60
|
"check": "pnpm typecheck && pnpm test && pnpm build",
|
|
51
61
|
"examples": "node scripts/serve-examples.mjs",
|
|
62
|
+
"lint": "eslint .",
|
|
52
63
|
"test": "vitest run",
|
|
53
64
|
"test:watch": "vitest",
|
|
65
|
+
"test:coverage": "vitest run --coverage",
|
|
54
66
|
"test:e2e": "pnpm build && playwright test",
|
|
55
|
-
"typecheck": "tsc --noEmit"
|
|
67
|
+
"typecheck": "tsc --noEmit",
|
|
68
|
+
"prepublishOnly": "pnpm check"
|
|
56
69
|
},
|
|
57
|
-
"
|
|
70
|
+
"peerDependencies": {
|
|
58
71
|
"centrifuge": "^5.5.3"
|
|
59
72
|
},
|
|
73
|
+
"peerDependenciesMeta": {
|
|
74
|
+
"centrifuge": {
|
|
75
|
+
"optional": true
|
|
76
|
+
}
|
|
77
|
+
},
|
|
60
78
|
"devDependencies": {
|
|
79
|
+
"@eslint/js": "^9.39.5",
|
|
61
80
|
"@playwright/test": "^1.62.1",
|
|
62
81
|
"@types/node": "^24.0.0",
|
|
82
|
+
"@vitest/coverage-v8": "^3.2.7",
|
|
63
83
|
"esbuild": "^0.25.0",
|
|
84
|
+
"eslint": "^9.39.4",
|
|
85
|
+
"globals": "^17.11.0",
|
|
64
86
|
"typescript": "^5.9.0",
|
|
87
|
+
"typescript-eslint": "^8.68.0",
|
|
65
88
|
"vitest": "^3.2.0"
|
|
66
89
|
},
|
|
67
90
|
"engines": {
|
|
68
91
|
"node": ">=18.0.0"
|
|
69
92
|
},
|
|
70
93
|
"packageManager": "pnpm@10.14.0"
|
|
71
|
-
}
|
|
94
|
+
}
|