cross-tab-worker-databus 0.1.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -0
  3. package/README.md +185 -0
  4. package/README.zh.md +98 -0
  5. package/dist/centrifuge-protocol.d.ts +77 -0
  6. package/dist/centrifuge-protocol.d.ts.map +1 -0
  7. package/dist/centrifuge-session.d.ts +39 -0
  8. package/dist/centrifuge-session.d.ts.map +1 -0
  9. package/dist/centrifuge.d.ts +135 -0
  10. package/dist/centrifuge.d.ts.map +1 -0
  11. package/dist/centrifuge.js +407 -0
  12. package/dist/centrifuge.js.map +7 -0
  13. package/dist/centrifuge.shared.worker.js +5220 -0
  14. package/dist/centrifuge.shared.worker.js.map +7 -0
  15. package/dist/centrifuge.worker.js +5109 -0
  16. package/dist/centrifuge.worker.js.map +7 -0
  17. package/dist/chunk-GABYBK7I.js +1527 -0
  18. package/dist/chunk-GABYBK7I.js.map +7 -0
  19. package/dist/core/cluster.d.ts +219 -0
  20. package/dist/core/cluster.d.ts.map +1 -0
  21. package/dist/core/data-bus.d.ts +133 -0
  22. package/dist/core/data-bus.d.ts.map +1 -0
  23. package/dist/core/environment.d.ts +67 -0
  24. package/dist/core/environment.d.ts.map +1 -0
  25. package/dist/core/hash.d.ts +11 -0
  26. package/dist/core/hash.d.ts.map +1 -0
  27. package/dist/core/routing.d.ts +42 -0
  28. package/dist/core/routing.d.ts.map +1 -0
  29. package/dist/core/storage-batch.d.ts +35 -0
  30. package/dist/core/storage-batch.d.ts.map +1 -0
  31. package/dist/core/trace.d.ts +126 -0
  32. package/dist/core/trace.d.ts.map +1 -0
  33. package/dist/core/types.d.ts +112 -0
  34. package/dist/core/types.d.ts.map +1 -0
  35. package/dist/index.d.ts +23 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +27 -0
  38. package/dist/index.js.map +7 -0
  39. package/dist/worker-mode.d.ts +25 -0
  40. package/dist/worker-mode.d.ts.map +1 -0
  41. package/dist/workers/centrifuge.shared.worker.d.ts +2 -0
  42. package/dist/workers/centrifuge.shared.worker.d.ts.map +1 -0
  43. package/dist/workers/centrifuge.worker.d.ts +2 -0
  44. package/dist/workers/centrifuge.worker.d.ts.map +1 -0
  45. package/dist/workers/port-reaper.d.ts +52 -0
  46. package/dist/workers/port-reaper.d.ts.map +1 -0
  47. package/docs/README.md +21 -0
  48. package/docs/api.md +261 -0
  49. package/docs/architecture.md +514 -0
  50. package/docs/capabilities.md +41 -0
  51. package/docs/configuration.md +211 -0
  52. package/docs/getting-started.md +161 -0
  53. package/docs/zh/README.md +23 -0
  54. package/docs/zh/api.md +261 -0
  55. package/docs/zh/architecture.md +515 -0
  56. package/docs/zh/capabilities.md +41 -0
  57. package/docs/zh/configuration.md +211 -0
  58. package/docs/zh/getting-started.md +161 -0
  59. package/package.json +71 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ 本项目遵循 [Semantic Versioning](https://semver.org/);变更记录格式参考 [Keep a Changelog](https://keepachangelog.com/)。
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.0] - 2026-08-24
8
+
9
+ 首次公开发布。
10
+
11
+ ### Added
12
+
13
+ - 框架无关的跨标签页发布/订阅数据总线,通过 BroadcastChannel 在同源标签页间分发消息
14
+ - Dedicated Worker / Shared Worker / 本地线程三档 transport 后端,`auto` 模式自动降级
15
+ - 基于 localStorage + BroadcastChannel 的 Worker 集群协调:粘性 Topic owner 路由、新 Topic 负载均衡、owner 崩溃 failover、`pagehide` 优雅交接
16
+ - 内置 Centrifuge WebSocket transport,连接、订阅、token 刷新、二进制数据均在 Worker 内处理,不阻塞主线程
17
+ - ArrayBuffer Transferable 支持,零拷贝传输二进制 publication
18
+ - 本地 handler 引用计数与订阅排队:连接期间订阅不丢失,去重 transport subscribe 调用
19
+ - 可选结构化 trace:生命周期、连接状态、协调快照、订阅事件,以及分桶延迟直方图(P50/P95/Max)与吞吐聚合指标
20
+ - localStorage 写入合并与指数退避重试,协调元数据写入移出热路径
21
+ - 连接 URL 与 Topic 通过 128 位非加密哈希转为不透明 key,明文不落入 localStorage 键名
22
+ - SharedWorker 端口回收器:主线程 PING 心跳 + 静默超时回收,崩溃 Tab 未发 STOP 也不泄漏 session
23
+ - 优雅降级:localStorage/BroadcastChannel 不可用时退化为本地单 Tab 模式
24
+
25
+ ### Documentation
26
+
27
+ - 英文与中文文档:架构、API 参考、配置、快速上手、能力矩阵
28
+ - 多标签页浏览器演示页,可视化数据流、延迟指标与集群路由状态
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sun1090
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,185 @@
1
+ # cross-tab-worker-databus
2
+
3
+ > [中文](./README.zh.md) | English
4
+
5
+ Framework-agnostic browser cross-tab data bus.
6
+
7
+ By default each tab holds its own Dedicated Worker; when configured with `workerMode: 'shared'` or `'auto'`, same-origin tabs can reuse a single SharedWorker. In `auto` mode it degrades automatically through SharedWorker → Dedicated Worker → main-thread WebSocket. Same-origin tabs form a logical Worker cluster over BroadcastChannel; the SDK automatically coordinates sticky Topic owners, subscription reuse, new-Topic load distribution, failover, and page lifecycle, so the application only needs to subscribe to Topics and process data.
8
+
9
+ ## Features
10
+
11
+ - Subscribable immediately after creation; subscriptions auto-queue while the connection is pending
12
+ - Subscriptions within the same tab are deduplicated by handler reference counting
13
+ - Topic owners are reused across same-origin tabs, reducing duplicate real-time subscriptions
14
+ - In SharedWorker mode, same-origin tabs reuse a single SharedWorker; each tab's port maintains its own independent connection, so refreshing or stopping one tab does not affect others
15
+ - `workerMode` supports `dedicated` / `shared` / `auto`; `auto` degrades via SharedWorker → Dedicated Worker → main-thread WebSocket, while explicit `dedicated` degrades via Dedicated Worker → SharedWorker → main-thread WebSocket
16
+ - With `transferable: true`, ArrayBuffer messages are transmitted via Transferable while the object-message API stays unchanged
17
+ - localStorage coordination writes are merged and flushed in batches; heartbeat and route confirmation use exponential backoff
18
+ - Existing Topic owners remain stable while alive; visibility changes do not move established subscriptions
19
+ - New Topics are assigned to the least-loaded eligible Worker
20
+ - `pagehide` releases resources automatically; `pageshow` rebuilds the Worker and connection automatically
21
+ - Transport reconnect automatically restores the current owner's Topics
22
+ - After a tab exits abnormally, automatic migration happens via heartbeat TTL
23
+ - Automatically degrades to local mode when BroadcastChannel or localStorage is unavailable
24
+ - The persistence layer does not store connection addresses, raw Topic text, or message content
25
+
26
+ See the [Capabilities Matrix](./docs/capabilities.md) for the full list of implemented, unimplemented, and planned capabilities.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ pnpm add cross-tab-worker-databus
32
+ ```
33
+
34
+ ## Getting Started
35
+
36
+ ```ts
37
+ import { createCentrifugeDataBus } from 'cross-tab-worker-databus/centrifuge';
38
+
39
+ interface ResourceEvent {
40
+ id: string;
41
+ version: number;
42
+ content: unknown;
43
+ }
44
+
45
+ const bus = createCentrifugeDataBus<ResourceEvent>({
46
+ connection: {
47
+ url: getConnectionUrl(),
48
+ options: getConnectionOptions()
49
+ }
50
+ });
51
+
52
+ const unsubscribe = bus.subscribe('resource.changed', ({ data }) => {
53
+ applyResourceEvent(data);
54
+ });
55
+
56
+ await bus.ready();
57
+
58
+ unsubscribe();
59
+ await bus.stop();
60
+ ```
61
+
62
+ The application does not need to handle Tab owner, Worker migration, page recovery, or re-subscription after reconnection.
63
+
64
+ ## Browser Demo
65
+
66
+ The repository includes runnable multi-tab demo pages that showcase real-time data flow between publishing, receiving, cluster routing, Worker sessions, and the server:
67
+
68
+ ```bash
69
+ pnpm install
70
+ pnpm build
71
+ pnpm examples
72
+ ```
73
+
74
+ Then open `http://localhost:4173/examples/demo/` in multiple tabs at the same time to see cross-tab data flowing. The demo page uses the public Centrifugo demo endpoint `wss://faye.centrifugal.dev/connection/websocket` by default; the address, Worker mode, and Topics can all be modified in-page. You can also switch to "local broadcast" mode, which does not depend on an external server and demonstrates multi-tab coordination purely through BroadcastChannel.
75
+
76
+ The demo page includes data-flow animations, an event stream, receive/dispatch latency metrics, and cluster Worker routing status.
77
+
78
+ ## Docs
79
+
80
+ - [Docs Index](./docs/README.md)
81
+ - [Getting Started](./docs/getting-started.md)
82
+ - [Configuration](./docs/configuration.md)
83
+ - [API Reference](./docs/api.md)
84
+ - [Architecture](./docs/architecture.md)
85
+ - [Capabilities Matrix](./docs/capabilities.md)
86
+ - [Changelog](./CHANGELOG.md)
87
+
88
+ ## API Examples
89
+
90
+ ### Subscribe with lifecycle handling
91
+
92
+ ```ts
93
+ const bus = createCentrifugeDataBus<ResourceEvent>({
94
+ connection: { url: 'wss://example.com/ws', options: {} }
95
+ });
96
+
97
+ // Subscribe before connection — queued until ready
98
+ const unsub = bus.subscribe('events.created', ({ data }) => {
99
+ console.log('event received:', data);
100
+ });
101
+
102
+ // Monitor connection status
103
+ const unsubStatus = bus.onStatus(status => {
104
+ console.log('transport status:', status);
105
+ });
106
+
107
+ // Handle errors
108
+ const unsubError = bus.onError(error => {
109
+ console.error('transport error:', error);
110
+ });
111
+
112
+ await bus.ready();
113
+
114
+ // Later: clean up
115
+ unsub();
116
+ unsubStatus();
117
+ unsubError();
118
+ await bus.stop();
119
+ ```
120
+
121
+ ### Multi-tab cluster with SharedWorker
122
+
123
+ ```ts
124
+ import { createCentrifugeDataBus } from 'cross-tab-worker-databus/centrifuge';
125
+
126
+ const bus = createCentrifugeDataBus<ResourceEvent>({
127
+ connection: {
128
+ url: 'wss://example.com/connection/websocket',
129
+ options: {}
130
+ },
131
+ workerMode: 'auto' // SharedWorker → Dedicated Worker → local fallback
132
+ });
133
+
134
+ bus.subscribe('resource.changed', ({ data }) => {
135
+ // Data arrives from any tab's owner Worker
136
+ apply(data);
137
+ });
138
+ ```
139
+
140
+ ### Publish and receive
141
+
142
+ ```ts
143
+ const publisher = createCentrifugeDataBus<ResourceEvent>({
144
+ connection: { url: getUrl(), options: {} }
145
+ });
146
+ const receiver = createCentrifugeDataBus<ResourceEvent>({
147
+ connection: { url: getUrl(), options: {} }
148
+ });
149
+
150
+ receiver.subscribe('resource.updated', ({ data }) => {
151
+ console.log('got update:', data);
152
+ });
153
+
154
+ await publisher.ready();
155
+ publisher.publish('resource.updated', { id: 'abc', version: 2, content: { title: 'hello' } });
156
+ ```
157
+
158
+ ### Diagnostics
159
+
160
+ ```ts
161
+ const bus = createCentrifugeDataBus<ResourceEvent>({
162
+ connection: { url: getUrl(), options: {} },
163
+ trace: {
164
+ enabled: true,
165
+ sink: event => console.log('trace:', event.type, event)
166
+ }
167
+ });
168
+
169
+ // Snapshot
170
+ const snapshot = bus.getClusterSnapshot();
171
+ console.log(snapshot.workers, snapshot.routes, snapshot.assignedTopics);
172
+ ```
173
+
174
+ ## Development
175
+
176
+ ```bash
177
+ pnpm install
178
+ pnpm check # typecheck + unit tests + build
179
+ pnpm test:e2e # Playwright multi-tab browser tests (requires Google Chrome)
180
+ pnpm pack --pack-destination /tmp
181
+ ```
182
+
183
+ ## License
184
+
185
+ [MIT](./LICENSE)
package/README.zh.md ADDED
@@ -0,0 +1,98 @@
1
+ # cross-tab-worker-databus
2
+
3
+ > 中文 | [English](./README.md)
4
+
5
+ 框架无关的浏览器跨 Tab 数据总线。
6
+
7
+ 默认每个 Tab 使用独立的 Dedicated Worker;配置 `workerMode: 'shared'` 或 `'auto'` 后,同源 Tab 可复用同一个 SharedWorker。`auto` 模式自动从 SharedWorker → Dedicated Worker → 主线程 WebSocket 降级。同源 Tab 通过 BroadcastChannel 形成逻辑 Worker 集群;SDK 自动协调粘性 Topic owner、订阅复用、新 Topic 负载分配、故障转移和页面生命周期,业务只需订阅 Topic 和处理数据。
8
+
9
+ ## 特性
10
+
11
+ - 创建后可立即订阅;连接未就绪时订阅自动排队
12
+ - 同一 Tab 内同 Topic 多 handler 通过引用计数去重
13
+ - 同源 Tab 复用 Topic owner,减少重复实时订阅
14
+ - SharedWorker 模式同源 Tab 复用同一个 SharedWorker;每个 Tab 的 port 各自维护独立的连接,单个 Tab 刷新或停止不影响其他 Tab
15
+ - `workerMode` 支持 `dedicated` / `shared` / `auto`;`auto` 按 SharedWorker → Dedicated Worker → 主线程 WebSocket 降级,`dedicated` 按 Dedicated Worker → SharedWorker → 主线程 WebSocket 降级
16
+ - 开启 `transferable: true` 后,ArrayBuffer 消息通过 Transferable 传输,对象消息 API 不变
17
+ - localStorage 协调写入合并批量 flush;心跳和路由确认使用指数退避
18
+ - 已有 Topic 的 owner 存活时保持稳定,前后台切换不迁移已有订阅
19
+ - 新 Topic 分配给负载最低的候选 Worker
20
+ - `pagehide` 自动释放资源;`pageshow` 自动重建 Worker 和连接
21
+ - Transport 重连自动恢复当前 owner 的 Topic
22
+ - Tab 异常退出后通过心跳 TTL 自动迁移
23
+ - BroadcastChannel 或 localStorage 不可用时自动降级为本地模式
24
+ - 持久层不存储连接地址、原始 Topic 文本和消息内容
25
+
26
+ 完整能力清单见 [能力矩阵](./docs/zh/capabilities.md)。
27
+
28
+ ## 安装
29
+
30
+ ```bash
31
+ pnpm add cross-tab-worker-databus
32
+ ```
33
+
34
+ ## 快速接入
35
+
36
+ ```ts
37
+ import { createCentrifugeDataBus } from 'cross-tab-worker-databus/centrifuge';
38
+
39
+ interface ResourceEvent {
40
+ id: string;
41
+ version: number;
42
+ content: unknown;
43
+ }
44
+
45
+ const bus = createCentrifugeDataBus<ResourceEvent>({
46
+ connection: {
47
+ url: getConnectionUrl(),
48
+ options: getConnectionOptions()
49
+ }
50
+ });
51
+
52
+ const unsubscribe = bus.subscribe('resource.changed', ({ data }) => {
53
+ applyResourceEvent(data);
54
+ });
55
+
56
+ await bus.ready();
57
+
58
+ unsubscribe();
59
+ await bus.stop();
60
+ ```
61
+
62
+ 业务无需处理 Tab owner、Worker 迁移、页面恢复或重连后的重新订阅。
63
+
64
+ ## 浏览器演示
65
+
66
+ 仓库包含可运行的多标签演示页面,展示发布、接收、集群路由、Worker 会话和服务器之间的实时数据流:
67
+
68
+ ```bash
69
+ pnpm install
70
+ pnpm build
71
+ pnpm examples
72
+ ```
73
+
74
+ 然后在多个浏览器标签页中同时打开 `http://localhost:4173/examples/demo/` 即可观察跨 Tab 数据流转。演示页默认使用公共 Centrifugo 演示地址 `wss://faye.centrifugal.dev/connection/websocket`;地址、Worker 模式和 Topic 都可在页面内修改。也可以切换到"本地广播"模式,不依赖外部服务器,仅通过 BroadcastChannel 演示多标签协同。
75
+
76
+ 演示页包含数据流动画、事件流、接收/分发延迟指标和集群 Worker 路由状态。
77
+
78
+ ## 文档
79
+
80
+ - [文档索引](./docs/zh/README.md)
81
+ - [快速接入](./docs/zh/getting-started.md)
82
+ - [配置说明](./docs/zh/configuration.md)
83
+ - [API 参考](./docs/zh/api.md)
84
+ - [架构说明](./docs/zh/architecture.md)
85
+ - [能力矩阵](./docs/zh/capabilities.md)
86
+ - [变更日志](./CHANGELOG.md)
87
+
88
+ ## 开发
89
+
90
+ ```bash
91
+ pnpm install
92
+ pnpm check
93
+ pnpm pack --pack-destination /tmp
94
+ ```
95
+
96
+ ## 许可证
97
+
98
+ [MIT](./LICENSE)
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Worker-thread protocol for Centrifuge WebSocket transport.
3
+ *
4
+ * Defines the message types exchanged between the main thread and a Web Worker
5
+ * (dedicated or shared) that runs a centrifuge client. The worker is isolated
6
+ * from the main thread so that WebSocket lifecycle, token refresh, and binary
7
+ * data handling never block the UI.
8
+ */
9
+ import type { Options } from 'centrifuge';
10
+ import type { WorkerStatus } from './core/types';
11
+ /**
12
+ * Default interval between main-thread PING heartbeats to a SharedWorker. The
13
+ * SharedWorker reaps a silent port after `SESSION_TIMEOUT_MULTIPLIER` intervals.
14
+ * Shared here so the main thread (heartbeat sender) and the SharedWorker (reaper)
15
+ * always agree on the cadence.
16
+ */
17
+ export declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 10000;
18
+ /** SharedWorker per-port session timeout, expressed as a multiple of that port's
19
+ * heartbeat interval. A live port PINGs every heartbeat interval, so a timeout of
20
+ * several intervals tolerates throttled tabs without reaping healthy sessions. */
21
+ export declare const DEFAULT_SESSION_TIMEOUT_MULTIPLIER = 3;
22
+ type WorkerUnsafeOption = 'eventsource' | 'fetch' | 'getData' | 'getToken' | 'networkEventTarget' | 'readableStream' | 'sockjs' | 'websocket';
23
+ /** Centrifuge options safe to pass into a Worker; unsafe options are explicitly excluded. */
24
+ export type CentrifugeWorkerConfig = Omit<Partial<Options>, WorkerUnsafeOption> & {
25
+ [Key in WorkerUnsafeOption]?: never;
26
+ };
27
+ /** Messages sent from the main thread to the Worker. */
28
+ export type CentrifugeWorkerInput = {
29
+ type: 'INIT';
30
+ url: string;
31
+ config: CentrifugeWorkerConfig;
32
+ transferable?: boolean;
33
+ heartbeatIntervalMs?: number;
34
+ } | {
35
+ type: 'SUBSCRIBE';
36
+ topic: string;
37
+ } | {
38
+ type: 'UNSUBSCRIBE';
39
+ topic: string;
40
+ } | {
41
+ type: 'PUBLISH';
42
+ topic: string;
43
+ data: unknown;
44
+ } | {
45
+ type: 'PUBLISH_BIN';
46
+ topic: string;
47
+ data: ArrayBuffer;
48
+ } | {
49
+ type: 'PING';
50
+ } | {
51
+ type: 'STOP';
52
+ };
53
+ /** Messages sent from the Worker back to the main thread. */
54
+ export type CentrifugeWorkerOutput<TData = unknown> = {
55
+ type: 'STATUS';
56
+ status: WorkerStatus;
57
+ } | {
58
+ type: 'MESSAGE';
59
+ topic: string;
60
+ data: TData;
61
+ } | {
62
+ type: 'MESSAGE_BIN';
63
+ topic: string;
64
+ data: ArrayBuffer;
65
+ } | {
66
+ type: 'ERROR';
67
+ error: SerializedWorkerError;
68
+ };
69
+ /** Error object serialized for cross-thread transfer (Error instances cannot be cloned via postMessage). */
70
+ export interface SerializedWorkerError {
71
+ name: string;
72
+ message: string;
73
+ stack?: string;
74
+ context?: unknown;
75
+ }
76
+ export {};
77
+ //# sourceMappingURL=centrifuge-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"centrifuge-protocol.d.ts","sourceRoot":"","sources":["../src/centrifuge-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,QAAS,CAAC;AACpD;;kFAEkF;AAClF,eAAO,MAAM,kCAAkC,IAAI,CAAC;AAIpD,KAAK,kBAAkB,GACnB,aAAa,GACb,OAAO,GACP,SAAS,GACT,UAAU,GACV,oBAAoB,GACpB,gBAAgB,GAChB,QAAQ,GACR,WAAW,CAAC;AAEhB,6FAA6F;AAC7F,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC,GAAG;KAC/E,GAAG,IAAI,kBAAkB,CAAC,CAAC,EAAE,KAAK;CACpC,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,GACnH;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,6DAA6D;AAC7D,MAAM,MAAM,sBAAsB,CAAC,KAAK,GAAG,OAAO,IAC9C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAEpD,4GAA4G;AAC5G,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
@@ -0,0 +1,39 @@
1
+ import type { CentrifugeWorkerInput, CentrifugeWorkerOutput } from './centrifuge-protocol';
2
+ /** Callback interface for posting messages back to the transport layer. */
3
+ export interface CentrifugeSessionSink<TData = unknown> {
4
+ post(message: CentrifugeWorkerOutput<TData>, transfer?: ArrayBuffer[]): void;
5
+ }
6
+ /**
7
+ * Stateful Centrifuge client wrapper shared by Dedicated Worker, SharedWorker
8
+ * ports and the main-thread local fallback. Each session owns one connection.
9
+ */
10
+ export declare class CentrifugeSession<TData = unknown> {
11
+ private readonly sink;
12
+ private client;
13
+ private readonly subscriptions;
14
+ private transferable;
15
+ constructor(sink: CentrifugeSessionSink<TData>);
16
+ /** Dispatch an incoming Worker message to the matching operation. */
17
+ handle(message: CentrifugeWorkerInput): void;
18
+ /** Create the Centrifuge client, wire up lifecycle listeners, and connect. */
19
+ private initialize;
20
+ /** Subscribe to a Centrifuge channel. Reuses an existing subscription if one exists. */
21
+ private subscribe;
22
+ /** Unsubscribe from a Centrifuge channel and clean up the local reference. */
23
+ private unsubscribe;
24
+ /** Publish a message to the Centrifuge channel. */
25
+ private publish;
26
+ /** Forward a publication to the transport, using Transferable for binary data when enabled. */
27
+ private postPublication;
28
+ /** Disconnect the client and clear all subscriptions. */
29
+ private stop;
30
+ /** Forward a message to the sink (the transport layer). */
31
+ private post;
32
+ /** Serialise and report an error. The Centrifuge client handles reconnection
33
+ * internally, so a transient error should not trigger a `STATUS: error` that
34
+ * would cause `selectActiveWorkers()` to exclude this worker from routing.
35
+ * Fatal errors are distinguished by the client eventually emitting
36
+ * `disconnected` without a subsequent `connected`. */
37
+ private postError;
38
+ }
39
+ //# sourceMappingURL=centrifuge-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"centrifuge-session.d.ts","sourceRoot":"","sources":["../src/centrifuge-session.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAEV,qBAAqB,EACrB,sBAAsB,EAEvB,MAAM,uBAAuB,CAAC;AAE/B,2EAA2E;AAC3E,MAAM,WAAW,qBAAqB,CAAC,KAAK,GAAG,OAAO;IACpD,IAAI,CAAC,OAAO,EAAE,sBAAsB,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;CAC9E;AAED;;;GAGG;AACH,qBAAa,iBAAiB,CAAC,KAAK,GAAG,OAAO;IAKhC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJjC,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAmC;IACjE,OAAO,CAAC,YAAY,CAAS;gBAEA,IAAI,EAAE,qBAAqB,CAAC,KAAK,CAAC;IAE/D,qEAAqE;IACrE,MAAM,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAS5C,8EAA8E;IAC9E,OAAO,CAAC,UAAU;IAelB,wFAAwF;IACxF,OAAO,CAAC,SAAS;IAmBjB,8EAA8E;IAC9E,OAAO,CAAC,WAAW;IAOnB,mDAAmD;IACnD,OAAO,CAAC,OAAO;IAKf,+FAA+F;IAC/F,OAAO,CAAC,eAAe;IASvB,yDAAyD;IACzD,OAAO,CAAC,IAAI;IAOZ,2DAA2D;IAC3D,OAAO,CAAC,IAAI;IAIZ;;;;0DAIsD;IACtD,OAAO,CAAC,SAAS;CAGlB"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Centrifuge WebSocket transport that runs inside a Web Worker.
3
+ *
4
+ * Supports three backends, selected in order of preference:
5
+ * 1. SharedWorker — one WebSocket per tab session, hosted in a shared process
6
+ * 2. Dedicated Worker — one WebSocket per tab
7
+ * 3. In-process (local) — Centrifuge runs on the main thread (fallback when
8
+ * neither Worker type is available, e.g. in non-browser environments)
9
+ *
10
+ * Binary data (ArrayBuffer) can be transferred via Transferable when the
11
+ * `transferable` option is enabled, avoiding structured-clone overhead.
12
+ */
13
+ import { CrossTabDataBus } from './core/data-bus';
14
+ import type { CrossTabDataBusOptions } from './core/data-bus';
15
+ import type { DataBusTransport, DataBusTransportHandlers } from './core/types';
16
+ import type { WorkerMode } from './worker-mode';
17
+ import type { CentrifugeWorkerConfig } from './centrifuge-protocol';
18
+ export type { CentrifugeWorkerConfig, SerializedWorkerError } from './centrifuge-protocol';
19
+ export type { WorkerBackend, WorkerMode } from './worker-mode';
20
+ /** WebSocket connection parameters passed to the Centrifuge Worker. */
21
+ export interface CentrifugeDataBusConfig {
22
+ /** Centrifuge server WebSocket URL. */
23
+ url: string;
24
+ /** Centrifuge client options (token, channel params, etc.). */
25
+ options?: CentrifugeWorkerConfig;
26
+ }
27
+ /** Options for configuring the Worker backend (dedicated, shared, or local). */
28
+ export interface CentrifugeWorkerTransportOptions {
29
+ /** Custom dedicated Worker factory. Used for testing or bundler integration. */
30
+ workerFactory?: () => Worker;
31
+ /** Custom SharedWorker factory. */
32
+ sharedWorkerFactory?: () => SharedWorker;
33
+ /** Preferred Worker mode: 'dedicated', 'shared', or 'auto'. */
34
+ workerMode?: WorkerMode;
35
+ /** Enable transferable (ArrayBuffer) support for binary data. */
36
+ transferable?: boolean;
37
+ /** Interval (ms) between PING heartbeats sent to the SharedWorker. The
38
+ * SharedWorker reaps a silent port after `DEFAULT_SESSION_TIMEOUT_MULTIPLIER`
39
+ * × this interval. Pass `Infinity` to disable heartbeats entirely. Defaults
40
+ * to `DEFAULT_HEARTBEAT_INTERVAL_MS`. */
41
+ heartbeatIntervalMs?: number;
42
+ }
43
+ /** Options for creating a fully-configured CrossTabDataBus with a Centrifuge transport. */
44
+ export interface CreateCentrifugeDataBusOptions<TData = unknown> extends Omit<CrossTabDataBusOptions<CentrifugeDataBusConfig, TData>, 'autoStart' | 'clusterKey' | 'initialConfig' | 'transport'>, CentrifugeWorkerTransportOptions {
45
+ /** Centrifuge connection configuration. */
46
+ connection: CentrifugeDataBusConfig;
47
+ /** Cluster key for cross-tab coordination. Defaults to the connection URL. */
48
+ clusterKey?: string;
49
+ }
50
+ /**
51
+ * Transport layer that runs a Centrifuge WebSocket client inside a Web Worker.
52
+ *
53
+ * Delegates the actual WebSocket connection to a Worker (dedicated or shared)
54
+ * or falls back to an in-process CentrifugeSession. The Worker is isolated from
55
+ * the main thread so that WebSocket lifecycle, token refresh, and binary data
56
+ * handling never block the UI.
57
+ */
58
+ export declare class CentrifugeWorkerTransport<TData = unknown> implements DataBusTransport<CentrifugeDataBusConfig, TData> {
59
+ private readonly workerMode;
60
+ private readonly transferable;
61
+ private readonly heartbeatIntervalMs;
62
+ private readonly workerFactory;
63
+ private readonly sharedWorkerFactory;
64
+ private backend;
65
+ private worker;
66
+ private sharedWorker;
67
+ private port;
68
+ private heartbeatHandle;
69
+ private localSession;
70
+ private handlers;
71
+ private generation;
72
+ private backendGeneration;
73
+ constructor(options?: CentrifugeWorkerTransportOptions);
74
+ /**
75
+ * Start the transport: select a backend, initialise the Worker (or local
76
+ * session), and send the INIT message with connection parameters.
77
+ */
78
+ start(config: CentrifugeDataBusConfig, handlers: DataBusTransportHandlers<TData>): void;
79
+ subscribe(topic: string): void;
80
+ unsubscribe(topic: string): void;
81
+ /**
82
+ * Publish data to `topic`. Binary data (ArrayBuffer) is sent via Transferable
83
+ * when `transferable` is enabled, avoiding a structured-clone cycle.
84
+ */
85
+ publish(topic: string, data: unknown): void;
86
+ /**
87
+ * Gracefully stop the transport: send STOP, clean up event listeners, and
88
+ * terminate the Worker (or close the SharedWorker port).
89
+ */
90
+ stop(): void;
91
+ /** Create and initialise a dedicated Worker, then send the INIT message. */
92
+ private startDedicatedWorker;
93
+ /** Create and initialise a SharedWorker, open the MessagePort, and send the INIT message. */
94
+ private startSharedWorker;
95
+ /** Handle a message event from the Worker (dedicated or shared). */
96
+ private readonly handleMessage;
97
+ /** Handle a message from the in-process CentrifugeSession (local fallback). */
98
+ private readonly handleSessionOutput;
99
+ /** Route a Worker output message to the appropriate handler callback. */
100
+ private handleOutput;
101
+ /** Handle a Worker-level failure (crash, message decode error). Discards the
102
+ * dead backend so a later start()/reopen can rebuild from scratch, and
103
+ * signals an error status so the DataBus can trigger recovery. */
104
+ private onWorkerFailed;
105
+ /** Remove every listener attached to the current SharedWorker and its port. */
106
+ private detachSharedWorkerListeners;
107
+ /** Periodically ping the SharedWorker so its session reaper can detect a dead tab. */
108
+ private startHeartbeat;
109
+ private clearHeartbeat;
110
+ private readonly handleWorkerError;
111
+ private readonly handlePortError;
112
+ private readonly handleSharedWorkerError;
113
+ /** Clear the Worker/port/backend references after a failure or stop. */
114
+ private resetBackend;
115
+ /**
116
+ * Post a message to the active backend. Accepts optional Transferable buffers
117
+ * for zero-copy ArrayBuffer transfer.
118
+ */
119
+ private post;
120
+ }
121
+ /**
122
+ * Create a fully-configured CrossTabDataBus with a Centrifuge WebSocket transport.
123
+ *
124
+ * This is the primary entry point for consumers. It wires up the transport,
125
+ * cluster coordination, and lifecycle management:
126
+ *
127
+ * ```ts
128
+ * const bus = createCentrifugeDataBus({
129
+ * connection: { url: 'wss://example.com/connection/websocket', options: { token: '…' } },
130
+ * trace: { enabled: true, sink: event => console.log(event) },
131
+ * });
132
+ * ```
133
+ */
134
+ export declare function createCentrifugeDataBus<TData = unknown>(options: CreateCentrifugeDataBusOptions<TData>): CrossTabDataBus<CentrifugeDataBusConfig, TData>;
135
+ //# sourceMappingURL=centrifuge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"centrifuge.d.ts","sourceRoot":"","sources":["../src/centrifuge.ts"],"names":[],"mappings":"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"}