cross-tab-worker-databus 0.1.2 → 0.2.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 +44 -0
- package/README.md +11 -0
- package/README.zh.md +9 -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/architecture.md +18 -8
- package/docs/transports.md +144 -0
- package/docs/zh/architecture.md +18 -8
- package/docs/zh/transports.md +132 -0
- package/package.json +7 -2
- package/dist/chunk-53INHVYO.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,50 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.2.0] - 2026-08-27
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- `centrifuge` 从 `dependencies` 改为 optional `peerDependencies`:仅在使用内置 Centrifuge 后端时需要安装,核心包零运行时依赖。
|
|
12
|
+
- `CentrifugeSession.handle()` 由连续 `if` 改为 `switch` + `default`,未知消息类型静默忽略,为未来协议扩展留出兼容余地。
|
|
13
|
+
- `routing.ts` 的 workerId 平局处理由 `localeCompare` 改为数值比较,消除宿主 locale 对路由确定性的影响。
|
|
14
|
+
- `port-reaper.ts` 提取 `computeMinHeartbeat()` 方法,reap 迭代改用 `Array.from` 快照,reaper 节奏计算与计时器逻辑解耦。
|
|
15
|
+
- `centrifuge-protocol.ts` 新增 `DEFAULT_SESSION_TIMEOUT_MS` 派生常量,消除 `port-reaper` 中重复的字面量计算。
|
|
16
|
+
- `CentrifugeWorkerTransport` 提取 `buildInitInput()` 与 `postToPortLike()` helper,消除 `start()`/`post()` 中的重复构造逻辑。
|
|
17
|
+
- `cluster.ts` 提取 `readAllByPrefix()` helper,统一 `readWorkers`/`cleanupOrphanedRoutes`/`cleanupOrphanedSubscribers`/`getSnapshot` 的 listKeys+readJson 循环;删除无调用点的 `listKeysSafe`。
|
|
18
|
+
- `cluster.ts` 提取 `buildLocalRoute()`,将 `readRoute` 的无 storage 降级分支独立命名并补文档;`readSubscriberTabIds` 同类分支拆为多行可读形式。
|
|
19
|
+
- `cluster.ts` 提取 `sendRouteReleased()` helper,消除三处 `ROUTE_RELEASED` 消息构造的重复;`handoffAssignedTopics` 的 generation 计算复用单次求值;`reconcileAssignedTopics` 去除同一 topicKey 的二次 `readRoute` 调用。
|
|
20
|
+
- `cluster.ts` `releaseSubscription` 返回 topicKey,`unsubscribe` 复用而非重新哈希;`handleMessage`/`handleControlMessage`/`sendControl` 连续 `if` 改 `switch`;`getSnapshot` 的序列化改用 `Array.from`。
|
|
21
|
+
- `data-bus.ts` `onControl` 连续 `if` 改 `switch`;提取 `invokeHandlers()` 统一 dispatch/status/error 三处 handler 遍历的 try-catch 隔离;提取 `formatWorkerTrace`/`formatRouteTrace` 格式化函数。
|
|
22
|
+
- `trace.ts` 提取 `metricsActive` getter,统一四个 record/flush 方法的守卫表达式。
|
|
23
|
+
- `cluster.ts` 提取 `routeOwnerIsLive()` 与 `isActiveAmong()`,消除 subscribe/publish 和 isActiveWorker/refreshRole 中的重复 route+workers.some / selectActiveWorkers+some 模式。
|
|
24
|
+
- `cluster.ts` 提取 `isStaleRouteRelease()`,命名 handleRouteReleasedMessage 的守卫条件。
|
|
25
|
+
- `cluster.ts` `activate()` 合并两个分支的 rememberTopic 调用为单循环;`handoffAssignedTopics` 去掉同一 topicKey 的二次 readRoute。
|
|
26
|
+
- `cluster.ts` `readSubscriberTabIds` 改用 `readAllByPrefix` + `Array.from`;`getSnapshot` 序列化改用 `Array.from` + mapping callback。
|
|
27
|
+
- `data-bus.ts` 提取 `formatWorkerTrace`/`formatRouteTrace` 格式化函数;`invokeHandlers` 的 label 参数改为联合类型字面量而非自由字符串。
|
|
28
|
+
- 多处 JSDoc/注释补全:writeRecord notify 参数、activate channel 判空、reconcileWorkers cleanup 顺序、rememberTopic eviction break、suspendTransport pendingStop 守卫、reopenTransport startPromise 检查、trace flushNow 条件、storage-batch flush break / scheduleFlush 降级 / scheduleRetry、port-reaper 各方法守卫、centrifuge assertHeartbeatInterval/assertStructuredCloneable/deserializeWorkerError、environment canUseStorage。
|
|
29
|
+
|
|
30
|
+
### Documentation (JSDoc 全覆盖)
|
|
31
|
+
|
|
32
|
+
- `hash.ts` 提取 seed/prime/avalanche 常量与 `avalancheMix()` 函数,补非 ASCII 字符处理注释。
|
|
33
|
+
- `types.ts` 全部类型(WorkerRecord/WorkerRoute/WorkerClusterMessage/DataBusTransport/DataBusMessage/handler 别名)字段级 JSDoc 补全。
|
|
34
|
+
- `centrifuge-protocol.ts` 全部协议变体(WorkerUnsafeOption/CentrifugeWorkerConfig/CentrifugeWorkerInput 各变体/CentrifugeWorkerOutput 各变体/SerializedWorkerError)JSDoc 补全。
|
|
35
|
+
- `worker-mode.ts` WorkerMode/WorkerBackend/WorkerAvailability/selectWorkerBackend JSDoc 补全。
|
|
36
|
+
- `routing.ts` DEFAULT_MAX_ACTIVE_WORKERS/selectLeastLoadedWorker JSDoc 增强。
|
|
37
|
+
- `storage-batch.ts` INITIAL/MAX_RETRY 常量 + BatchingStorageWriter 类 + pendingSize getter JSDoc 补全。
|
|
38
|
+
- `trace.ts` normalizeInterval/roundMs JSDoc 补全。
|
|
39
|
+
- `environment.ts` ClusterEnvironment 各字段 + canUseStorage JSDoc 补全。
|
|
40
|
+
- `cluster.ts` readJson/writeJson/WorkerClusterOptions 各字段 JSDoc 补全。
|
|
41
|
+
- `data-bus.ts` PUBLICATION_EVENT/getStatus/getClusterSnapshot/CrossTabDataBusOptions JSDoc 补全。
|
|
42
|
+
- `centrifuge.ts` handleOutput/onWorkerFailed JSDoc 补全。
|
|
43
|
+
|
|
44
|
+
### Documentation
|
|
45
|
+
|
|
46
|
+
- 架构运行时图(中英)补全 `BatchingStorageWriter`、`PortReaper`、`CentrifugeSession`、`CentrifugeWorkerTransport` 节点,与代码结构对齐。
|
|
47
|
+
- `AGENTS.md` 目录注释明确列出每个测试文件职责。
|
|
48
|
+
- `README`(中英)补充 `centrifuge` 为可选 peer 依赖的安装说明。
|
|
49
|
+
- `trace.ts`、`environment.ts` 补充 JSDoc:trace 模式与选项字段含义、SSR 场景的 storage/ BroadcastChannel 检测说明。
|
|
50
|
+
|
|
7
51
|
## [0.1.2] - 2026-08-24
|
|
8
52
|
|
|
9
53
|
### Fixed
|
package/README.md
CHANGED
|
@@ -31,6 +31,17 @@ See the [Capabilities Matrix](./docs/capabilities.md) for the full list of imple
|
|
|
31
31
|
pnpm add cross-tab-worker-databus
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
The core package has zero runtime dependencies. The Centrifuge transport
|
|
35
|
+
(`cross-tab-worker-databus/centrifuge`) declares `centrifuge` as an optional
|
|
36
|
+
peer dependency — install it only when you use the built-in Centrifuge backend:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm add cross-tab-worker-databus centrifuge
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Tabs that only use the local BroadcastChannel data bus (no WebSocket server)
|
|
43
|
+
do not need to install `centrifuge` at all.
|
|
44
|
+
|
|
34
45
|
## Getting Started
|
|
35
46
|
|
|
36
47
|
```ts
|
package/README.zh.md
CHANGED
|
@@ -31,6 +31,15 @@
|
|
|
31
31
|
pnpm add cross-tab-worker-databus
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
核心包零运行时依赖。Centrifuge transport(`cross-tab-worker-databus/centrifuge`)
|
|
35
|
+
将 `centrifuge` 声明为可选 peer 依赖——仅在使用内置 Centrifuge 后端时安装:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pnpm add cross-tab-worker-databus centrifuge
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
仅使用本地 BroadcastChannel 数据总线(不连 WebSocket 服务)的 Tab 无需安装 `centrifuge`。
|
|
42
|
+
|
|
34
43
|
## 快速接入
|
|
35
44
|
|
|
36
45
|
```ts
|
|
@@ -19,58 +19,94 @@ export declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 10000;
|
|
|
19
19
|
* heartbeat interval. A live port PINGs every heartbeat interval, so a timeout of
|
|
20
20
|
* several intervals tolerates throttled tabs without reaping healthy sessions. */
|
|
21
21
|
export declare const DEFAULT_SESSION_TIMEOUT_MULTIPLIER = 3;
|
|
22
|
+
/** Default per-port session timeout in ms, derived from the heartbeat interval
|
|
23
|
+
* and the multiplier. Used as the fallback when a port sends no INIT config. */
|
|
24
|
+
export declare const DEFAULT_SESSION_TIMEOUT_MS: number;
|
|
22
25
|
type WorkerUnsafeOption = 'eventsource' | 'fetch' | 'getData' | 'getToken' | 'networkEventTarget' | 'readableStream' | 'sockjs' | 'websocket';
|
|
23
|
-
/** Centrifuge options safe to pass into a Worker; unsafe options are explicitly
|
|
26
|
+
/** Centrifuge options safe to pass into a Worker; unsafe options are explicitly
|
|
27
|
+
* excluded and set to `never` so the compiler rejects them at the call site. */
|
|
24
28
|
export type CentrifugeWorkerConfig = Omit<Partial<Options>, WorkerUnsafeOption> & {
|
|
25
29
|
[Key in WorkerUnsafeOption]?: never;
|
|
26
30
|
};
|
|
27
|
-
/** Messages sent from the main thread to the Worker.
|
|
28
|
-
|
|
31
|
+
/** Messages sent from the main thread to the Worker. All variants are
|
|
32
|
+
* structured-cloneable; `PUBLISH_BIN` carries an ArrayBuffer (transferable). */
|
|
33
|
+
export type CentrifugeWorkerInput =
|
|
34
|
+
/** Initial connection: URL + config. Sent once per backend creation.
|
|
35
|
+
* `transferable` enables ArrayBuffer zero-copy for subsequent PUBLISH_BIN.
|
|
36
|
+
* `heartbeatIntervalMs` overrides the SharedWorker PING cadence. */
|
|
37
|
+
{
|
|
29
38
|
type: 'INIT';
|
|
30
39
|
url: string;
|
|
31
40
|
config: CentrifugeWorkerConfig;
|
|
32
41
|
transferable?: boolean;
|
|
33
42
|
heartbeatIntervalMs?: number;
|
|
34
|
-
}
|
|
43
|
+
}
|
|
44
|
+
/** Subscribe to a channel. Idempotent — re-subscribing is a no-op. */
|
|
45
|
+
| {
|
|
35
46
|
type: 'SUBSCRIBE';
|
|
36
47
|
topic: string;
|
|
37
|
-
}
|
|
48
|
+
}
|
|
49
|
+
/** Unsubscribe from a channel. Idempotent. */
|
|
50
|
+
| {
|
|
38
51
|
type: 'UNSUBSCRIBE';
|
|
39
52
|
topic: string;
|
|
40
|
-
}
|
|
53
|
+
}
|
|
54
|
+
/** Publish a structured-cloneable payload to a channel. */
|
|
55
|
+
| {
|
|
41
56
|
type: 'PUBLISH';
|
|
42
57
|
topic: string;
|
|
43
58
|
data: unknown;
|
|
44
|
-
}
|
|
59
|
+
}
|
|
60
|
+
/** Publish an ArrayBuffer via Transferable (zero-copy when `transferable` is on). */
|
|
61
|
+
| {
|
|
45
62
|
type: 'PUBLISH_BIN';
|
|
46
63
|
topic: string;
|
|
47
64
|
data: ArrayBuffer;
|
|
48
|
-
}
|
|
65
|
+
}
|
|
66
|
+
/** Heartbeat from the main thread; the SharedWorker reaps silent ports. */
|
|
67
|
+
| {
|
|
49
68
|
type: 'PING';
|
|
50
|
-
}
|
|
69
|
+
}
|
|
70
|
+
/** Disconnect the client and clear all subscriptions. */
|
|
71
|
+
| {
|
|
51
72
|
type: 'STOP';
|
|
52
73
|
};
|
|
53
|
-
/** Messages sent from the Worker back to the main thread.
|
|
54
|
-
|
|
74
|
+
/** Messages sent from the Worker back to the main thread. The main thread
|
|
75
|
+
* routes these to the DataBusTransportHandlers via handleOutput(). */
|
|
76
|
+
export type CentrifugeWorkerOutput<TData = unknown> =
|
|
77
|
+
/** Connection status changed. Maps Centrifuge states to the DataBus vocabulary. */
|
|
78
|
+
{
|
|
55
79
|
type: 'STATUS';
|
|
56
80
|
status: WorkerStatus;
|
|
57
|
-
}
|
|
81
|
+
}
|
|
82
|
+
/** A JSON publication arrived. Routed to onMessage via handleOutput. */
|
|
83
|
+
| {
|
|
58
84
|
type: 'MESSAGE';
|
|
59
85
|
topic: string;
|
|
60
86
|
data: TData;
|
|
61
|
-
}
|
|
87
|
+
}
|
|
88
|
+
/** A binary publication arrived (Transferable). Routed to onMessage with the ArrayBuffer. */
|
|
89
|
+
| {
|
|
62
90
|
type: 'MESSAGE_BIN';
|
|
63
91
|
topic: string;
|
|
64
92
|
data: ArrayBuffer;
|
|
65
|
-
}
|
|
93
|
+
}
|
|
94
|
+
/** A non-fatal error occurred. Does not imply disconnection (the client retries internally). */
|
|
95
|
+
| {
|
|
66
96
|
type: 'ERROR';
|
|
67
97
|
error: SerializedWorkerError;
|
|
68
98
|
};
|
|
69
|
-
/** Error object serialized for cross-thread transfer
|
|
99
|
+
/** Error object serialized for cross-thread transfer. Error instances cannot
|
|
100
|
+
* be structured-cloned via postMessage, so the Worker converts them to this
|
|
101
|
+
* shape and the main thread rebuilds an Error via deserializeWorkerError(). */
|
|
70
102
|
export interface SerializedWorkerError {
|
|
103
|
+
/** The Error's `name` (e.g. 'TypeError', 'CentrifugeError'). */
|
|
71
104
|
name: string;
|
|
105
|
+
/** The Error's `message`. */
|
|
72
106
|
message: string;
|
|
107
|
+
/** The Error's `stack` if available (for debugging). */
|
|
73
108
|
stack?: string;
|
|
109
|
+
/** Arbitrary context attached by the Worker (e.g. the failing operation). */
|
|
74
110
|
context?: unknown;
|
|
75
111
|
}
|
|
76
112
|
export {};
|
|
@@ -1 +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;
|
|
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;AACpD;gFACgF;AAChF,eAAO,MAAM,0BAA0B,QAC6B,CAAC;AAOrE,KAAK,kBAAkB,GACnB,aAAa,GACb,OAAO,GACP,SAAS,GACT,UAAU,GACV,oBAAoB,GACpB,gBAAgB,GAChB,QAAQ,GACR,WAAW,CAAC;AAEhB;gFACgF;AAChF,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;gFACgF;AAChF,MAAM,MAAM,qBAAqB;AAC/B;;oEAEoE;AAClE;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;AACrH,sEAAsE;GACpE;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACtC,8CAA8C;GAC5C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACxC,2DAA2D;GACzD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE;AACnD,qFAAqF;GACnF;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE;AAC3D,2EAA2E;GACzE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;AAClB,yDAAyD;GACvD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB;sEACsE;AACtE,MAAM,MAAM,sBAAsB,CAAC,KAAK,GAAG,OAAO;AAChD,mFAAmF;AACjF;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE;AAC1C,wEAAwE;GACtE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE;AACjD,6FAA6F;GAC3F;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE;AAC3D,gGAAgG;GAC9F;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAEpD;;+EAE+E;AAC/E,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
|
|
@@ -13,11 +13,16 @@ export declare class CentrifugeSession<TData = unknown> {
|
|
|
13
13
|
private readonly subscriptions;
|
|
14
14
|
private transferable;
|
|
15
15
|
constructor(sink: CentrifugeSessionSink<TData>);
|
|
16
|
-
/** Dispatch an incoming Worker message to the matching operation.
|
|
16
|
+
/** Dispatch an incoming Worker message to the matching operation.
|
|
17
|
+
* Unknown message types are ignored rather than thrown, so a future protocol
|
|
18
|
+
* extension adding a new variant cannot crash an older session. */
|
|
17
19
|
handle(message: CentrifugeWorkerInput): void;
|
|
18
20
|
/** Create the Centrifuge client, wire up lifecycle listeners, and connect. */
|
|
19
21
|
private initialize;
|
|
20
|
-
/** Subscribe to a Centrifuge channel. Reuses an existing subscription if one exists.
|
|
22
|
+
/** Subscribe to a Centrifuge channel. Reuses an existing subscription if one exists.
|
|
23
|
+
* Listeners are only registered once per subscription object — a repeated
|
|
24
|
+
* SUBSCRIBE for an already-tracked topic skips the listener wiring entirely,
|
|
25
|
+
* avoiding the removeAllListeners + re-on churn on every duplicate message. */
|
|
21
26
|
private subscribe;
|
|
22
27
|
/** Unsubscribe from a Centrifuge channel and clean up the local reference.
|
|
23
28
|
* Listeners are removed before unsubscribing so a late `unsubscribed` event
|
|
@@ -25,7 +30,10 @@ export declare class CentrifugeSession<TData = unknown> {
|
|
|
25
30
|
private unsubscribe;
|
|
26
31
|
/** Publish a message to the Centrifuge channel. */
|
|
27
32
|
private publish;
|
|
28
|
-
/** Forward a publication to the transport
|
|
33
|
+
/** Forward a publication to the transport. Binary payloads take the
|
|
34
|
+
* zero-copy `MESSAGE_BIN` path when `transferable` is enabled; everything
|
|
35
|
+
* else is structured-cloned via `MESSAGE`. An empty topic means the
|
|
36
|
+
* publication carried no channel info and is silently dropped. */
|
|
29
37
|
private postPublication;
|
|
30
38
|
/** Disconnect the client and clear all subscriptions. */
|
|
31
39
|
private stop;
|
|
@@ -1 +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
|
|
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;;uEAEmE;IACnE,MAAM,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAyB5C,8EAA8E;IAC9E,OAAO,CAAC,UAAU;IAuBlB;;;mFAG+E;IAC/E,OAAO,CAAC,SAAS;IA2BjB;;gFAE4E;IAC5E,OAAO,CAAC,WAAW;IAUnB,mDAAmD;IACnD,OAAO,CAAC,OAAO;IAKf;;;sEAGkE;IAClE,OAAO,CAAC,eAAe;IASvB,yDAAyD;IACzD,OAAO,CAAC,IAAI;IAOZ,2DAA2D;IAC3D,OAAO,CAAC,IAAI;IAIZ;;;;0DAIsD;IACtD,OAAO,CAAC,SAAS;CAGlB"}
|
package/dist/centrifuge.d.ts
CHANGED
|
@@ -88,6 +88,10 @@ export declare class CentrifugeWorkerTransport<TData = unknown> implements DataB
|
|
|
88
88
|
* terminate the Worker (or close the SharedWorker port).
|
|
89
89
|
*/
|
|
90
90
|
stop(): void;
|
|
91
|
+
/** Build the INIT payload sent to the Worker / local session. Optional fields
|
|
92
|
+
* are only included when they deviate from the defaults, so the Worker's own
|
|
93
|
+
* default-resolution logic kicks in for the common case. */
|
|
94
|
+
private buildInitInput;
|
|
91
95
|
/** Create and initialise a dedicated Worker, then send the INIT message. */
|
|
92
96
|
private startDedicatedWorker;
|
|
93
97
|
/** Create and initialise a SharedWorker, open the MessagePort, and send the INIT message. */
|
|
@@ -96,11 +100,15 @@ export declare class CentrifugeWorkerTransport<TData = unknown> implements DataB
|
|
|
96
100
|
private readonly handleMessage;
|
|
97
101
|
/** Handle a message from the in-process CentrifugeSession (local fallback). */
|
|
98
102
|
private readonly handleSessionOutput;
|
|
99
|
-
/** Route a Worker output message to the appropriate handler callback.
|
|
103
|
+
/** Route a Worker output message to the appropriate handler callback.
|
|
104
|
+
* Shared by the Worker message listener, the SharedWorker port listener,
|
|
105
|
+
* and the local-session sink — all three feed into this single dispatcher. */
|
|
100
106
|
private handleOutput;
|
|
101
107
|
/** Handle a Worker-level failure (crash, message decode error). Discards the
|
|
102
108
|
* dead backend so a later start()/reopen can rebuild from scratch, and
|
|
103
|
-
* signals an error status so the DataBus can trigger recovery.
|
|
109
|
+
* signals an error status so the DataBus can trigger recovery.
|
|
110
|
+
* Only invoked when the generation guard confirms the failing backend is
|
|
111
|
+
* still current — late errors from a superseded Worker are silently dropped. */
|
|
104
112
|
private onWorkerFailed;
|
|
105
113
|
/** Remove every listener attached to the current SharedWorker and its port. */
|
|
106
114
|
private detachSharedWorkerListeners;
|
package/dist/centrifuge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"centrifuge.d.ts","sourceRoot":"","sources":["../src/centrifuge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAG/E,OAAO,KAAK,EAAiB,UAAU,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,KAAK,EACV,sBAAsB,EAIvB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE/D,uEAAuE;AACvE,MAAM,WAAW,uBAAuB;IACtC,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,OAAO,CAAC,EAAE,sBAAsB,CAAC;CAClC;AAED,gFAAgF;AAChF,MAAM,WAAW,gCAAgC;IAC/C,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;IAC7B,mCAAmC;IACnC,mBAAmB,CAAC,EAAE,MAAM,YAAY,CAAC;IACzC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,iEAAiE;IACjE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;6CAGyC;IACzC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,2FAA2F;AAC3F,MAAM,WAAW,8BAA8B,CAAC,KAAK,GAAG,OAAO,CAC7D,SAAQ,IAAI,CACR,sBAAsB,CAAC,uBAAuB,EAAE,KAAK,CAAC,EACtD,WAAW,GAAG,YAAY,GAAG,eAAe,GAAG,WAAW,CAC3D,EACD,gCAAgC;IAClC,2CAA2C;IAC3C,UAAU,EAAE,uBAAuB,CAAC;IACpC,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,qBAAa,yBAAyB,CAAC,KAAK,GAAG,OAAO,CACpD,YAAW,gBAAgB,CAAC,uBAAuB,EAAE,KAAK,CAAC;IAE3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAmC;IACvE,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,QAAQ,CAAgD;IAGhE,OAAO,CAAC,UAAU,CAAK;IAGvB,OAAO,CAAC,iBAAiB,CAAK;gBAElB,OAAO,GAAE,gCAAqC;IAS1D;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,uBAAuB,EAAE,QAAQ,EAAE,wBAAwB,CAAC,KAAK,CAAC,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"centrifuge.d.ts","sourceRoot":"","sources":["../src/centrifuge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAG/E,OAAO,KAAK,EAAiB,UAAU,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,KAAK,EACV,sBAAsB,EAIvB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE/D,uEAAuE;AACvE,MAAM,WAAW,uBAAuB;IACtC,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,OAAO,CAAC,EAAE,sBAAsB,CAAC;CAClC;AAED,gFAAgF;AAChF,MAAM,WAAW,gCAAgC;IAC/C,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;IAC7B,mCAAmC;IACnC,mBAAmB,CAAC,EAAE,MAAM,YAAY,CAAC;IACzC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,iEAAiE;IACjE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;6CAGyC;IACzC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,2FAA2F;AAC3F,MAAM,WAAW,8BAA8B,CAAC,KAAK,GAAG,OAAO,CAC7D,SAAQ,IAAI,CACR,sBAAsB,CAAC,uBAAuB,EAAE,KAAK,CAAC,EACtD,WAAW,GAAG,YAAY,GAAG,eAAe,GAAG,WAAW,CAC3D,EACD,gCAAgC;IAClC,2CAA2C;IAC3C,UAAU,EAAE,uBAAuB,CAAC;IACpC,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,qBAAa,yBAAyB,CAAC,KAAK,GAAG,OAAO,CACpD,YAAW,gBAAgB,CAAC,uBAAuB,EAAE,KAAK,CAAC;IAE3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAmC;IACvE,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,QAAQ,CAAgD;IAGhE,OAAO,CAAC,UAAU,CAAK;IAGvB,OAAO,CAAC,iBAAiB,CAAK;gBAElB,OAAO,GAAE,gCAAqC;IAS1D;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,uBAAuB,EAAE,QAAQ,EAAE,wBAAwB,CAAC,KAAK,CAAC,GAAG,IAAI;IAwBvF,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI9B,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIhC;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAQ3C;;;OAGG;IACH,IAAI,IAAI,IAAI;IAkBZ;;gEAE4D;IAC5D,OAAO,CAAC,cAAc;IAYtB,4EAA4E;IAC5E,OAAO,CAAC,oBAAoB;IAS5B,6FAA6F;IAC7F,OAAO,CAAC,iBAAiB;IAczB,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAE5B;IAEF,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAElC;IAEF;;kFAE8E;IAC9E,OAAO,CAAC,YAAY;IAOpB;;;;oFAIgF;IAChF,OAAO,CAAC,cAAc;IAetB,+EAA+E;IAC/E,OAAO,CAAC,2BAA2B;IAMnC,sFAAsF;IACtF,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAGhC;IAEF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAG9B;IAEF,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAGtC;IAEF,wEAAwE;IACxE,OAAO,CAAC,YAAY;IAQpB;;;OAGG;IACH,OAAO,CAAC,IAAI;CAeb;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,GAAG,OAAO,EACrD,OAAO,EAAE,8BAA8B,CAAC,KAAK,CAAC,GAC7C,eAAe,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAwBjD"}
|
package/dist/centrifuge.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CrossTabDataBus,
|
|
3
3
|
selectWorkerBackend
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-LBXREMZA.js";
|
|
5
5
|
|
|
6
6
|
// src/centrifuge-session.ts
|
|
7
7
|
import { Centrifuge } from "centrifuge";
|
|
@@ -12,14 +12,30 @@ var CentrifugeSession = class {
|
|
|
12
12
|
client = null;
|
|
13
13
|
subscriptions = /* @__PURE__ */ new Map();
|
|
14
14
|
transferable = false;
|
|
15
|
-
/** Dispatch an incoming Worker message to the matching operation.
|
|
15
|
+
/** Dispatch an incoming Worker message to the matching operation.
|
|
16
|
+
* Unknown message types are ignored rather than thrown, so a future protocol
|
|
17
|
+
* extension adding a new variant cannot crash an older session. */
|
|
16
18
|
handle(message) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
switch (message.type) {
|
|
20
|
+
case "INIT":
|
|
21
|
+
this.initialize(message.url, message.config, message.transferable === true);
|
|
22
|
+
return;
|
|
23
|
+
case "SUBSCRIBE":
|
|
24
|
+
this.subscribe(message.topic);
|
|
25
|
+
return;
|
|
26
|
+
case "UNSUBSCRIBE":
|
|
27
|
+
this.unsubscribe(message.topic);
|
|
28
|
+
return;
|
|
29
|
+
case "PUBLISH":
|
|
30
|
+
case "PUBLISH_BIN":
|
|
31
|
+
this.publish(message.topic, message.data);
|
|
32
|
+
return;
|
|
33
|
+
case "STOP":
|
|
34
|
+
this.stop();
|
|
35
|
+
return;
|
|
36
|
+
default:
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
23
39
|
}
|
|
24
40
|
/** Create the Centrifuge client, wire up lifecycle listeners, and connect. */
|
|
25
41
|
initialize(url, config, transferable) {
|
|
@@ -40,9 +56,17 @@ var CentrifugeSession = class {
|
|
|
40
56
|
});
|
|
41
57
|
client.connect();
|
|
42
58
|
}
|
|
43
|
-
/** Subscribe to a Centrifuge channel. Reuses an existing subscription if one exists.
|
|
59
|
+
/** Subscribe to a Centrifuge channel. Reuses an existing subscription if one exists.
|
|
60
|
+
* Listeners are only registered once per subscription object — a repeated
|
|
61
|
+
* SUBSCRIBE for an already-tracked topic skips the listener wiring entirely,
|
|
62
|
+
* avoiding the removeAllListeners + re-on churn on every duplicate message. */
|
|
44
63
|
subscribe(topic) {
|
|
45
64
|
if (!this.client) return this.postError(new Error("Centrifuge client is not initialized."));
|
|
65
|
+
const existing = this.subscriptions.get(topic);
|
|
66
|
+
if (existing) {
|
|
67
|
+
existing.subscribe();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
46
70
|
let subscription = this.client.getSubscription(topic);
|
|
47
71
|
if (!subscription) subscription = this.client.newSubscription(topic);
|
|
48
72
|
subscription.removeAllListeners("publication");
|
|
@@ -73,7 +97,10 @@ var CentrifugeSession = class {
|
|
|
73
97
|
if (!this.client) return this.postError(new Error("Centrifuge client is not initialized."));
|
|
74
98
|
void this.client.publish(topic, data).catch((error) => this.postError(error));
|
|
75
99
|
}
|
|
76
|
-
/** Forward a publication to the transport
|
|
100
|
+
/** Forward a publication to the transport. Binary payloads take the
|
|
101
|
+
* zero-copy `MESSAGE_BIN` path when `transferable` is enabled; everything
|
|
102
|
+
* else is structured-cloned via `MESSAGE`. An empty topic means the
|
|
103
|
+
* publication carried no channel info and is silently dropped. */
|
|
77
104
|
postPublication(topic, data) {
|
|
78
105
|
if (!topic) return;
|
|
79
106
|
if (this.transferable && data instanceof ArrayBuffer) {
|
|
@@ -105,12 +132,14 @@ var CentrifugeSession = class {
|
|
|
105
132
|
function getPayloadTopic(data) {
|
|
106
133
|
if (!data || typeof data !== "object") return "";
|
|
107
134
|
const payload = data;
|
|
108
|
-
const
|
|
135
|
+
const push = payload.push;
|
|
136
|
+
const nested = typeof push === "object" && push !== null ? push.channel : void 0;
|
|
137
|
+
const topic = nested ?? payload.channel;
|
|
109
138
|
return typeof topic === "string" ? topic : "";
|
|
110
139
|
}
|
|
140
|
+
var LIVE_STATES = /* @__PURE__ */ new Set(["connecting", "connected"]);
|
|
111
141
|
function normalizeStatus(status) {
|
|
112
|
-
|
|
113
|
-
return "disconnected";
|
|
142
|
+
return LIVE_STATES.has(status) ? status : "disconnected";
|
|
114
143
|
}
|
|
115
144
|
function serializeError(error) {
|
|
116
145
|
if (error instanceof Error) {
|
|
@@ -129,6 +158,8 @@ function serializeError(error) {
|
|
|
129
158
|
|
|
130
159
|
// src/centrifuge-protocol.ts
|
|
131
160
|
var DEFAULT_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
161
|
+
var DEFAULT_SESSION_TIMEOUT_MULTIPLIER = 3;
|
|
162
|
+
var DEFAULT_SESSION_TIMEOUT_MS = DEFAULT_HEARTBEAT_INTERVAL_MS * DEFAULT_SESSION_TIMEOUT_MULTIPLIER;
|
|
132
163
|
|
|
133
164
|
// src/centrifuge.ts
|
|
134
165
|
var CentrifugeWorkerTransport = class {
|
|
@@ -170,13 +201,7 @@ var CentrifugeWorkerTransport = class {
|
|
|
170
201
|
worker: this.workerFactory !== void 0,
|
|
171
202
|
sharedWorker: this.sharedWorkerFactory !== void 0
|
|
172
203
|
});
|
|
173
|
-
const input =
|
|
174
|
-
type: "INIT",
|
|
175
|
-
url: config.url,
|
|
176
|
-
config: config.options ?? {},
|
|
177
|
-
...this.transferable ? { transferable: true } : {},
|
|
178
|
-
...this.heartbeatIntervalMs !== DEFAULT_HEARTBEAT_INTERVAL_MS ? { heartbeatIntervalMs: this.heartbeatIntervalMs } : {}
|
|
179
|
-
};
|
|
204
|
+
const input = this.buildInitInput(config);
|
|
180
205
|
if (backend === "shared") {
|
|
181
206
|
this.startSharedWorker(input);
|
|
182
207
|
this.backend = "shared";
|
|
@@ -229,6 +254,18 @@ var CentrifugeWorkerTransport = class {
|
|
|
229
254
|
this.resetBackend();
|
|
230
255
|
this.handlers = null;
|
|
231
256
|
}
|
|
257
|
+
/** Build the INIT payload sent to the Worker / local session. Optional fields
|
|
258
|
+
* are only included when they deviate from the defaults, so the Worker's own
|
|
259
|
+
* default-resolution logic kicks in for the common case. */
|
|
260
|
+
buildInitInput(config) {
|
|
261
|
+
return {
|
|
262
|
+
type: "INIT",
|
|
263
|
+
url: config.url,
|
|
264
|
+
config: config.options ?? {},
|
|
265
|
+
...this.transferable ? { transferable: true } : {},
|
|
266
|
+
...this.heartbeatIntervalMs !== DEFAULT_HEARTBEAT_INTERVAL_MS ? { heartbeatIntervalMs: this.heartbeatIntervalMs } : {}
|
|
267
|
+
};
|
|
268
|
+
}
|
|
232
269
|
/** Create and initialise a dedicated Worker, then send the INIT message. */
|
|
233
270
|
startDedicatedWorker(input) {
|
|
234
271
|
this.backendGeneration = ++this.generation;
|
|
@@ -260,7 +297,9 @@ var CentrifugeWorkerTransport = class {
|
|
|
260
297
|
handleSessionOutput = (message) => {
|
|
261
298
|
this.handleOutput(message);
|
|
262
299
|
};
|
|
263
|
-
/** Route a Worker output message to the appropriate handler callback.
|
|
300
|
+
/** Route a Worker output message to the appropriate handler callback.
|
|
301
|
+
* Shared by the Worker message listener, the SharedWorker port listener,
|
|
302
|
+
* and the local-session sink — all three feed into this single dispatcher. */
|
|
264
303
|
handleOutput(message) {
|
|
265
304
|
if (message.type === "STATUS") this.handlers?.onStatus(message.status);
|
|
266
305
|
if (message.type === "MESSAGE") this.handlers?.onMessage({ topic: message.topic, data: message.data });
|
|
@@ -269,7 +308,9 @@ var CentrifugeWorkerTransport = class {
|
|
|
269
308
|
}
|
|
270
309
|
/** Handle a Worker-level failure (crash, message decode error). Discards the
|
|
271
310
|
* dead backend so a later start()/reopen can rebuild from scratch, and
|
|
272
|
-
* signals an error status so the DataBus can trigger recovery.
|
|
311
|
+
* signals an error status so the DataBus can trigger recovery.
|
|
312
|
+
* Only invoked when the generation guard confirms the failing backend is
|
|
313
|
+
* still current — late errors from a superseded Worker are silently dropped. */
|
|
273
314
|
onWorkerFailed(message) {
|
|
274
315
|
this.worker?.removeEventListener("message", this.handleMessage);
|
|
275
316
|
this.worker?.removeEventListener("error", this.handleWorkerError);
|
|
@@ -325,13 +366,11 @@ var CentrifugeWorkerTransport = class {
|
|
|
325
366
|
*/
|
|
326
367
|
post(message, transfer) {
|
|
327
368
|
if (this.worker) {
|
|
328
|
-
|
|
329
|
-
else this.worker.postMessage(message);
|
|
369
|
+
postToPortLike(this.worker, message, transfer);
|
|
330
370
|
return;
|
|
331
371
|
}
|
|
332
372
|
if (this.port) {
|
|
333
|
-
|
|
334
|
-
else this.port.postMessage(message);
|
|
373
|
+
postToPortLike(this.port, message, transfer);
|
|
335
374
|
return;
|
|
336
375
|
}
|
|
337
376
|
if (this.localSession) {
|
|
@@ -402,6 +441,10 @@ function assertStructuredCloneable(value) {
|
|
|
402
441
|
);
|
|
403
442
|
}
|
|
404
443
|
}
|
|
444
|
+
function postToPortLike(target, message, transfer) {
|
|
445
|
+
if (transfer) target.postMessage(message, transfer);
|
|
446
|
+
else target.postMessage(message);
|
|
447
|
+
}
|
|
405
448
|
function deserializeWorkerError(error) {
|
|
406
449
|
const result = new Error(error.message);
|
|
407
450
|
result.name = error.name;
|