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
|
@@ -28,21 +28,33 @@ export interface ClusterChannel {
|
|
|
28
28
|
* Tests inject a fake environment to control timing, storage, and lifecycle.
|
|
29
29
|
*/
|
|
30
30
|
export interface ClusterEnvironment {
|
|
31
|
-
/** localStorage (or null if unavailable). */
|
|
31
|
+
/** localStorage (or null if unavailable). Wrapped by BatchingStorageWriter. */
|
|
32
32
|
storage: StorageLike | null;
|
|
33
33
|
/** sessionStorage (or null if unavailable). Used for stable tab IDs. */
|
|
34
34
|
sessionStorage: StorageLike | null;
|
|
35
|
+
/** Monotonic clock; injected so tests can control time. */
|
|
35
36
|
now: () => number;
|
|
37
|
+
/** Generates a random ID (UUID when crypto is available, else Math.random). */
|
|
36
38
|
randomId: () => string;
|
|
39
|
+
/** Creates a BroadcastChannel by name, or null if unsupported. */
|
|
37
40
|
createChannel: (name: string) => ClusterChannel | null;
|
|
41
|
+
/** Sets an interval; returns a handle for clearInterval. */
|
|
38
42
|
setInterval: (callback: () => void, intervalMs: number) => unknown;
|
|
43
|
+
/** Clears a handle from setInterval. */
|
|
39
44
|
clearInterval: (handle: unknown) => void;
|
|
45
|
+
/** Current tab visibility ('visible' or 'hidden'). */
|
|
40
46
|
getVisibilityState: () => TabVisibilityState;
|
|
47
|
+
/** Register a listener for visibilitychange events. */
|
|
41
48
|
addVisibilityChangeListener: (listener: () => void) => void;
|
|
49
|
+
/** Remove a previously-added visibilitychange listener. */
|
|
42
50
|
removeVisibilityChangeListener: (listener: () => void) => void;
|
|
51
|
+
/** Register a listener for pagehide (BFCache entry). */
|
|
43
52
|
addPageHideListener: (listener: () => void) => void;
|
|
53
|
+
/** Remove a previously-added pagehide listener. */
|
|
44
54
|
removePageHideListener: (listener: () => void) => void;
|
|
55
|
+
/** Register a listener for pageshow (BFCache exit / restore). */
|
|
45
56
|
addPageShowListener: (listener: () => void) => void;
|
|
57
|
+
/** Remove a previously-added pageshow listener. */
|
|
46
58
|
removePageShowListener: (listener: () => void) => void;
|
|
47
59
|
}
|
|
48
60
|
/**
|
|
@@ -54,7 +66,9 @@ export declare function createBrowserEnvironment(): ClusterEnvironment;
|
|
|
54
66
|
/**
|
|
55
67
|
* Probe a storage instance with a write-read-delete round-trip.
|
|
56
68
|
* Returns a type guard so the caller can narrow the type after a successful check.
|
|
57
|
-
* Catches quota errors, disabled-storage, or opaque
|
|
69
|
+
* Catches quota errors, disabled-storage (Safari private mode), or opaque
|
|
70
|
+
* exceptions — any of which means the storage is not usable for coordination
|
|
71
|
+
* and the Runtime must degrade to local mode.
|
|
58
72
|
*/
|
|
59
73
|
export declare function canUseStorage(storage: StorageLike | null, probeKey: string): storage is StorageLike;
|
|
60
74
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/core/environment.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAExE,qFAAqF;AACrF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,sGAAsG;AACtG,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,oBAAoB,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACvG,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,oBAAoB,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1G,WAAW,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACjD,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC
|
|
1
|
+
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/core/environment.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAExE,qFAAqF;AACrF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,sGAAsG;AACtG,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,oBAAoB,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACvG,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,oBAAoB,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1G,WAAW,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACjD,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,wEAAwE;IACxE,cAAc,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,2DAA2D;IAC3D,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,kEAAkE;IAClE,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,cAAc,GAAG,IAAI,CAAC;IACvD,4DAA4D;IAC5D,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IACnE,wCAAwC;IACxC,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,sDAAsD;IACtD,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;IAC7C,uDAAuD;IACvD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAC5D,2DAA2D;IAC3D,8BAA8B,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAC/D,wDAAwD;IACxD,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACpD,mDAAmD;IACnD,sBAAsB,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACvD,iEAAiE;IACjE,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACpD,mDAAmD;IACnD,sBAAsB,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;CACxD;AA2BD;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,kBAAkB,CAoC7D;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,IAAI,WAAW,CASnG;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,kBAAkB,EAC/B,GAAG,SAAoC,GACtC,MAAM,CAqBR"}
|
package/dist/core/hash.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/core/hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/core/hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA+BrD"}
|
package/dist/core/routing.d.ts
CHANGED
|
@@ -6,13 +6,16 @@
|
|
|
6
6
|
* them straightforward to test and reason about.
|
|
7
7
|
*/
|
|
8
8
|
import type { WorkerRecord, WorkerRoute } from './types';
|
|
9
|
-
/** Default cap on the number of Workers that can own topics concurrently.
|
|
9
|
+
/** Default cap on the number of Workers that can own topics concurrently.
|
|
10
|
+
* Limits fan-out breadth: only N workers are eligible to be new-route
|
|
11
|
+
* owners, so a cluster of 20 tabs still concentrates ownership on a few. */
|
|
10
12
|
export declare const DEFAULT_MAX_ACTIVE_WORKERS = 3;
|
|
11
13
|
/**
|
|
12
14
|
* Pick the Worker with the fewest owned topics, optionally preferring a
|
|
13
15
|
* specific sticky owner when it is still in the candidate set.
|
|
14
16
|
* Uses a single reduce pass instead of a full sort — O(n) — and breaks
|
|
15
|
-
* load ties by workerId for deterministic routing across tabs
|
|
17
|
+
* load ties by workerId for deterministic routing across tabs (the
|
|
18
|
+
* comparison is code-unit based, not locale-based, for cross-host stability).
|
|
16
19
|
*/
|
|
17
20
|
export declare function selectLeastLoadedWorker(workers: readonly WorkerRecord[], preferredWorkerId?: string): WorkerRecord | undefined;
|
|
18
21
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/core/routing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEzD
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/core/routing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEzD;;4EAE4E;AAC5E,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,iBAAiB,CAAC,EAAE,MAAM,GACzB,YAAY,GAAG,SAAS,CAY1B;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,gBAAgB,SAA6B,GAC5C,YAAY,EAAE,CAYhB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,eAAe,EAAE,MAAM,GACtB,YAAY,GAAG,IAAI,CAYrB;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,EAAE,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAEnG"}
|
|
@@ -10,6 +10,15 @@ import type { StorageLike } from './environment';
|
|
|
10
10
|
* Coalesces synchronous storage writes and applies them in one pass, with
|
|
11
11
|
* exponential backoff when the underlying storage rejects a write.
|
|
12
12
|
*/
|
|
13
|
+
/**
|
|
14
|
+
* Coalesces synchronous storage writes and applies them in one pass, with
|
|
15
|
+
* exponential backoff when the underlying storage rejects a write.
|
|
16
|
+
*
|
|
17
|
+
* Wraps a {@link StorageLike} so callers (WorkerClusterRuntime) see a normal
|
|
18
|
+
* storage interface; reads transparently see pending writes before they flush.
|
|
19
|
+
* The coalescing window is one microtask, so a burst of heartbeat + route +
|
|
20
|
+
* subscriber writes in the same task becomes a single localStorage flush.
|
|
21
|
+
*/
|
|
13
22
|
export declare class BatchingStorageWriter implements StorageLike {
|
|
14
23
|
private readonly storage;
|
|
15
24
|
/** Coalesced write set. A `null` value represents a pending delete. */
|
|
@@ -20,6 +29,9 @@ export declare class BatchingStorageWriter implements StorageLike {
|
|
|
20
29
|
private retryHandle;
|
|
21
30
|
private retryDelayMs;
|
|
22
31
|
constructor(storage: StorageLike);
|
|
32
|
+
/** Number of writes queued in memory but not yet flushed to storage.
|
|
33
|
+
* Used by tests to assert the coalescing window and by flush() to detect
|
|
34
|
+
* the all-drained state. */
|
|
23
35
|
get pendingSize(): number;
|
|
24
36
|
get length(): number;
|
|
25
37
|
clear(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-batch.d.ts","sourceRoot":"","sources":["../../src/core/storage-batch.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"storage-batch.d.ts","sourceRoot":"","sources":["../../src/core/storage-batch.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAYjD;;;GAGG;AACH;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,YAAW,WAAW;IAS3C,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,uEAAuE;IACvE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,0DAA0D;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,WAAW,CAA8C;IACjE,OAAO,CAAC,YAAY,CAA0B;gBAEjB,OAAO,EAAE,WAAW;IAEjD;;gCAE4B;IAC5B,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,KAAK,IAAI,IAAI;IAab,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKnC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAIjC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAK7B,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzC,KAAK,IAAI,IAAI;IA6Cb,yEAAyE;IACzE,OAAO,CAAC,IAAI;IAiBZ,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,WAAW;CAMpB"}
|
package/dist/core/trace.d.ts
CHANGED
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { WorkerStatus } from './types';
|
|
10
10
|
/** Trace reporting mode: record only events, only metrics, or both. */
|
|
11
|
+
/** Selects which trace categories the reporter emits.
|
|
12
|
+
* - `events` — lifecycle/status/subscription/coordination/error events only.
|
|
13
|
+
* - `metrics` — periodic `message_metrics` snapshots only.
|
|
14
|
+
* - `all` — both event streams and metrics snapshots. */
|
|
11
15
|
export type DataBusTraceMode = 'events' | 'metrics' | 'all';
|
|
12
16
|
/** Emitted when the DataBus starts, stops, suspends, or resumes. */
|
|
13
17
|
export interface DataBusLifecycleTraceEvent {
|
|
@@ -65,10 +69,16 @@ export interface DataBusMetricsTraceEvent {
|
|
|
65
69
|
export type DataBusTraceEvent = DataBusLifecycleTraceEvent | DataBusStatusTraceEvent | DataBusSubscriptionTraceEvent | DataBusCoordinationTraceEvent | DataBusErrorTraceEvent | DataBusMetricsTraceEvent;
|
|
66
70
|
/** Distributive-conditional type: given a trace event union, derive the same shape minus `timestamp`. */
|
|
67
71
|
type DataBusTraceEventInput = DataBusTraceEvent extends infer TEvent ? TEvent extends DataBusTraceEvent ? Omit<TEvent, 'timestamp'> : never : never;
|
|
72
|
+
/** Configuration for {@link DataBusTraceReporter}. `sink` receives every
|
|
73
|
+
* emitted event (filtered by `mode`); all other fields are optional. */
|
|
68
74
|
export interface DataBusTraceOptions {
|
|
75
|
+
/** When `false`, the reporter is inert (no events emitted). Default `true`. */
|
|
69
76
|
enabled?: boolean;
|
|
77
|
+
/** Which event categories to emit. Default `all`. */
|
|
70
78
|
mode?: DataBusTraceMode;
|
|
79
|
+
/** Aggregation window for `message_metrics` events. Default 5 s. */
|
|
71
80
|
metricsIntervalMs?: number;
|
|
81
|
+
/** Callback invoked for each emitted trace event. */
|
|
72
82
|
sink: (event: DataBusTraceEvent) => void;
|
|
73
83
|
}
|
|
74
84
|
/**
|
|
@@ -94,7 +104,8 @@ export declare class DataBusTraceReporter {
|
|
|
94
104
|
private readonly latencyBuckets;
|
|
95
105
|
private latencySumMs;
|
|
96
106
|
constructor(options?: DataBusTraceOptions, now?: () => number);
|
|
97
|
-
/** Start the periodic metrics flush interval. No-op when mode is 'events'
|
|
107
|
+
/** Start the periodic metrics flush interval. No-op when mode is 'events'
|
|
108
|
+
* (no metrics to emit), when disabled, or when already running. */
|
|
98
109
|
start(): void;
|
|
99
110
|
/** Pause the metrics interval and reset accumulated counters. */
|
|
100
111
|
pause(): void;
|
|
@@ -116,6 +127,10 @@ export declare class DataBusTraceReporter {
|
|
|
116
127
|
* as dispatched but do not produce a latency sample.
|
|
117
128
|
*/
|
|
118
129
|
recordDispatched(topic: string): void;
|
|
130
|
+
/** True when metrics recording is active: enabled and mode includes metrics.
|
|
131
|
+
* Extracted so the four record / flush methods share one guard expression
|
|
132
|
+
* instead of repeating `!this.enabled || this.mode === 'events'` at each. */
|
|
133
|
+
private get metricsActive();
|
|
119
134
|
/** Emit the accumulated metrics snapshot if the interval is active. */
|
|
120
135
|
flush(): void;
|
|
121
136
|
private flushNow;
|
package/dist/core/trace.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/core/trace.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,uEAAuE;AACvE,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAC;AAE5D,oEAAoE;AACpE,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IAChD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,4DAA4D;AAC5D,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,6DAA6D;AAC7D,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,WAAW,GAAG,aAAa,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,sFAAsF;AACtF,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,WAAW,GAAG,WAAW,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,iBAAiB,GACzB,0BAA0B,GAC1B,uBAAuB,GACvB,6BAA6B,GAC7B,6BAA6B,GAC7B,sBAAsB,GACtB,wBAAwB,CAAC;AAE7B,yGAAyG;AACzG,KAAK,sBAAsB,GAAG,iBAAiB,SAAS,MAAM,MAAM,GAChE,MAAM,SAAS,iBAAiB,GAC9B,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,GACzB,KAAK,GACP,KAAK,CAAC;AAEV,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC1C;
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/core/trace.ts"],"names":[],"mappings":"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"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -5,31 +5,40 @@
|
|
|
5
5
|
* transport interfaces, trace events, and all supporting types used across
|
|
6
6
|
* the cluster coordination, DataBus public API, and diagnostics layers.
|
|
7
7
|
*/
|
|
8
|
-
/** Convenience alias for values that may be synchronously returned or
|
|
8
|
+
/** Convenience alias for values that may be synchronously returned or as a
|
|
9
|
+
* Promise. Used by the DataBusTransport contract so implementations can be
|
|
10
|
+
* either sync or async without changing the call signature. */
|
|
9
11
|
export type MaybePromise<T> = T | Promise<T>;
|
|
10
|
-
/** Whether this Worker can act as a Topic owner.
|
|
12
|
+
/** Whether this Worker can act as a Topic owner. `active` workers are eligible
|
|
13
|
+
* for new topic assignments; `standby` workers hold existing assignments but
|
|
14
|
+
* are not selected for new ones (e.g. a hidden tab that already owns topics). */
|
|
11
15
|
export type WorkerRole = 'active' | 'standby';
|
|
12
|
-
/** Connection-level status of the transport.
|
|
16
|
+
/** Connection-level status of the transport. `error` triggers auto-recovery
|
|
17
|
+
* (subject to a cooldown); `disconnected` is a clean or suspend state. */
|
|
13
18
|
export type WorkerStatus = 'connecting' | 'connected' | 'disconnected' | 'error';
|
|
14
|
-
/** Control-plane actions routed between Workers via BroadcastChannel.
|
|
19
|
+
/** Control-plane actions routed between Workers via BroadcastChannel.
|
|
20
|
+
* These are the three operations a subscriber asks the owning worker to perform. */
|
|
15
21
|
export type WorkerControlAction = 'SUBSCRIBE' | 'UNSUBSCRIBE' | 'PUBLISH';
|
|
16
|
-
/** Whether the tab is currently visible to the user.
|
|
22
|
+
/** Whether the tab is currently visible to the user. Only influences placement
|
|
23
|
+
* of NEW topic routes; existing routes are sticky and never migrated on hide. */
|
|
17
24
|
export type TabVisibilityState = 'visible' | 'hidden';
|
|
18
25
|
/**
|
|
19
26
|
* A Worker's self-published registration record, written to localStorage
|
|
20
27
|
* so sibling tabs can discover and route to it.
|
|
21
28
|
*/
|
|
22
29
|
export interface WorkerRecord {
|
|
30
|
+
/** Stable identity of this runtime instance. Random-suffixed; survives refresh. */
|
|
23
31
|
workerId: string;
|
|
32
|
+
/** Identity of the browser tab hosting this worker. Survives refresh. */
|
|
24
33
|
tabId: string;
|
|
25
|
-
/** Number of topics this Worker owns.
|
|
34
|
+
/** Number of topics this Worker owns. NOT a CPU load metric. */
|
|
26
35
|
load: number;
|
|
27
36
|
role: WorkerRole;
|
|
28
37
|
status: WorkerStatus;
|
|
29
38
|
visibilityState: TabVisibilityState;
|
|
30
|
-
/** Last heartbeat write timestamp (ms). */
|
|
39
|
+
/** Last heartbeat write timestamp (ms). Workers past `workerTtlMs` are pruned. */
|
|
31
40
|
heartbeatAt: number;
|
|
32
|
-
/** First registration timestamp (ms). Used for deterministic ordering. */
|
|
41
|
+
/** First registration timestamp (ms). Used for deterministic ordering in owner selection. */
|
|
33
42
|
registeredAt: number;
|
|
34
43
|
}
|
|
35
44
|
/**
|
|
@@ -38,45 +47,71 @@ export interface WorkerRecord {
|
|
|
38
47
|
* the SUBSCRIBE control message.
|
|
39
48
|
*/
|
|
40
49
|
export interface WorkerRoute {
|
|
50
|
+
/** Opaque 128-bit hash of the topic name (never the plaintext). */
|
|
41
51
|
topicKey: string;
|
|
52
|
+
/** The workerId that owns this topic's transport subscription. */
|
|
42
53
|
workerId: string;
|
|
54
|
+
/** The tabId of the owning worker. */
|
|
43
55
|
tabId: string;
|
|
56
|
+
/** Timestamp (ms) of the last route write. Used for orphan-TTL cleanup. */
|
|
44
57
|
updatedAt: number;
|
|
45
|
-
/** Monotonic route generation; handoff acknowledgements must match it
|
|
58
|
+
/** Monotonic route generation; handoff acknowledgements must match it to
|
|
59
|
+
* prevent a stale ACK from authorizing a superseded owner. */
|
|
46
60
|
generation: number;
|
|
47
|
-
/** Previous owner must release its transport subscription before
|
|
61
|
+
/** Previous owner that must release its transport subscription before the
|
|
62
|
+
* new owner takes over (graceful handoff only). */
|
|
48
63
|
handoffFromWorkerId?: string;
|
|
49
|
-
/** Set by the owner when it has processed the SUBSCRIBE. Absent →
|
|
64
|
+
/** Set by the owner when it has processed the SUBSCRIBE. Absent → the
|
|
65
|
+
* subscriber will retry the control message to recover from channel loss. */
|
|
50
66
|
confirmedAt?: number;
|
|
51
67
|
}
|
|
52
|
-
/** Per-tab-per-topic marker stored in localStorage so the cluster knows which
|
|
68
|
+
/** Per-tab-per-topic marker stored in localStorage so the cluster knows which
|
|
69
|
+
* tabs still need a topic. Each tab writes its own record independently,
|
|
70
|
+
* avoiding read-modify-write contention on a shared array. */
|
|
53
71
|
export interface TopicSubscriberRecord {
|
|
72
|
+
/** The tab that holds this subscription. */
|
|
54
73
|
tabId: string;
|
|
74
|
+
/** Timestamp (ms) of the last subscriber write. */
|
|
55
75
|
updatedAt: number;
|
|
56
76
|
}
|
|
57
77
|
/**
|
|
58
|
-
* Messages exchanged over the BroadcastChannel.
|
|
59
|
-
* - CONTROL:
|
|
78
|
+
* Messages exchanged over the BroadcastChannel. Four types:
|
|
79
|
+
* - CONTROL: point-to-point action (SUBSCRIBE / UNSUBSCRIBE / PUBLISH)
|
|
60
80
|
* - EVENT: fan-out publications from the owning Worker to all tabs
|
|
61
|
-
* - REGISTRY:
|
|
81
|
+
* - REGISTRY: nudge every tab to reconcile immediately
|
|
82
|
+
* - ROUTE_RELEASED: ACK a graceful handoff (only matching generation acts)
|
|
62
83
|
*/
|
|
63
|
-
export type WorkerClusterMessage<TEvent = unknown> =
|
|
84
|
+
export type WorkerClusterMessage<TEvent = unknown> =
|
|
85
|
+
/** A subscriber asks the target worker to perform an action on a topic.
|
|
86
|
+
* Carries the plaintext topic (for transport calls) and the opaque key
|
|
87
|
+
* (for storage/route bookkeeping). */
|
|
88
|
+
{
|
|
64
89
|
type: 'CONTROL';
|
|
65
90
|
sourceWorkerId: string;
|
|
66
91
|
targetWorkerId: string;
|
|
67
92
|
action: WorkerControlAction;
|
|
68
93
|
topic: string;
|
|
69
94
|
topicKey: string;
|
|
95
|
+
/** Present only for PUBLISH actions; the publication payload. */
|
|
70
96
|
data?: unknown;
|
|
71
|
-
}
|
|
97
|
+
}
|
|
98
|
+
/** The owning worker fans out a publication to every tab. `eventType`
|
|
99
|
+
* distinguishes databus publications from future event types. */
|
|
100
|
+
| {
|
|
72
101
|
type: 'EVENT';
|
|
73
102
|
sourceWorkerId: string;
|
|
74
103
|
eventType: string;
|
|
75
104
|
payload: TEvent;
|
|
76
|
-
}
|
|
105
|
+
}
|
|
106
|
+
/** Nudge peers to reconcile immediately after a registry/route/subscriber
|
|
107
|
+
* write, instead of waiting for the next heartbeat (3 s default). */
|
|
108
|
+
| {
|
|
77
109
|
type: 'REGISTRY';
|
|
78
110
|
sourceWorkerId: string;
|
|
79
|
-
}
|
|
111
|
+
}
|
|
112
|
+
/** The old owner acknowledges it released the transport subscription.
|
|
113
|
+
* Only the new owner whose route `generation` matches may act on this. */
|
|
114
|
+
| {
|
|
80
115
|
type: 'ROUTE_RELEASED';
|
|
81
116
|
sourceWorkerId: string;
|
|
82
117
|
targetWorkerId: string;
|
|
@@ -84,29 +119,49 @@ export type WorkerClusterMessage<TEvent = unknown> = {
|
|
|
84
119
|
topicKey: string;
|
|
85
120
|
generation: number;
|
|
86
121
|
};
|
|
122
|
+
/** A publication delivered to a topic handler: the topic name and the
|
|
123
|
+
* structured-clone-safe payload. */
|
|
87
124
|
export interface DataBusMessage<TData = unknown> {
|
|
88
125
|
topic: string;
|
|
89
126
|
data: TData;
|
|
90
127
|
}
|
|
91
|
-
/** Callbacks the transport calls to notify the DataBus of events.
|
|
128
|
+
/** Callbacks the transport calls to notify the DataBus of events.
|
|
129
|
+
* The DataBus wires these once during `start()`; the transport must hold
|
|
130
|
+
* the reference and call them for the lifetime of the connection. */
|
|
92
131
|
export interface DataBusTransportHandlers<TData = unknown> {
|
|
132
|
+
/** A publication arrived from the server for a topic this worker owns. */
|
|
93
133
|
onMessage: (message: DataBusMessage<TData>) => void;
|
|
134
|
+
/** The connection status changed. `error` triggers auto-recovery. */
|
|
94
135
|
onStatus: (status: WorkerStatus) => void;
|
|
136
|
+
/** A non-fatal transport error occurred. Does not imply disconnection. */
|
|
95
137
|
onError: (error: unknown) => void;
|
|
96
138
|
}
|
|
97
139
|
/**
|
|
98
140
|
* Transport abstraction that the DataBus delegates to for real I/O.
|
|
99
141
|
* Implementations may wrap a WebSocket library, a Worker, or a mock.
|
|
100
|
-
*
|
|
142
|
+
*
|
|
143
|
+
* Contract requirements:
|
|
144
|
+
* - `subscribe` / `unsubscribe` MUST be idempotent (called on reconnect).
|
|
145
|
+
* - `start` is called once per lifecycle; `stop` is idempotent.
|
|
146
|
+
* - `publish` may be called before `start` settles (queued by the DataBus).
|
|
101
147
|
*/
|
|
102
148
|
export interface DataBusTransport<TConfig = unknown, TData = unknown> {
|
|
149
|
+
/** Open the connection with `config`. Report status changes via `handlers.onStatus`.
|
|
150
|
+
* May return a Promise that resolves on connect or rejects on failure. */
|
|
103
151
|
start(config: TConfig, handlers: DataBusTransportHandlers<TData>): MaybePromise<void>;
|
|
152
|
+
/** Subscribe to a topic. Idempotent: re-subscribing an active topic is a no-op. */
|
|
104
153
|
subscribe(topic: string): MaybePromise<void>;
|
|
154
|
+
/** Unsubscribe from a topic. Idempotent: unsubscribing a non-subscribed topic is a no-op. */
|
|
105
155
|
unsubscribe(topic: string): MaybePromise<void>;
|
|
156
|
+
/** Publish `data` to `topic` via the server. */
|
|
106
157
|
publish(topic: string, data: unknown): MaybePromise<void>;
|
|
158
|
+
/** Close the connection and release all resources. Safe to call multiple times. */
|
|
107
159
|
stop(): MaybePromise<void>;
|
|
108
160
|
}
|
|
161
|
+
/** Callback invoked for each publication delivered to a subscribed topic. */
|
|
109
162
|
export type DataBusMessageHandler<TData = unknown> = (message: DataBusMessage<TData>) => void;
|
|
163
|
+
/** Callback invoked on every transport status change. */
|
|
110
164
|
export type DataBusStatusHandler = (status: WorkerStatus) => void;
|
|
165
|
+
/** Callback invoked when the transport or an operation reports an error. */
|
|
111
166
|
export type DataBusErrorHandler = (error: unknown) => void;
|
|
112
167
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
package/dist/worker-mode.d.ts
CHANGED
|
@@ -5,13 +5,21 @@
|
|
|
5
5
|
* that resolves the preference against browser capability to pick the actual
|
|
6
6
|
* backend (dedicated, shared, or local fallback).
|
|
7
7
|
*/
|
|
8
|
-
/** Preferred Worker mode
|
|
8
|
+
/** Preferred Worker mode.
|
|
9
|
+
* - `dedicated` → try Dedicated Worker first (one WebSocket per tab).
|
|
10
|
+
* - `shared` → try SharedWorker first (one process, per-port connections).
|
|
11
|
+
* - `auto` → same as `shared` (alias for forward compatibility). */
|
|
9
12
|
export type WorkerMode = 'dedicated' | 'shared' | 'auto';
|
|
10
|
-
/** Resolved backend that was actually created.
|
|
13
|
+
/** Resolved backend that was actually created. `local` means the session
|
|
14
|
+
* runs on the main thread (fallback when no Worker API is available). */
|
|
11
15
|
export type WorkerBackend = 'dedicated' | 'shared' | 'local';
|
|
12
|
-
/** Override Worker availability for testing or environments where feature
|
|
16
|
+
/** Override Worker availability for testing or environments where feature
|
|
17
|
+
* detection is unreliable (e.g. sandboxed iframes). When a field is omitted,
|
|
18
|
+
* the global `typeof Worker` / `typeof SharedWorker` check is used. */
|
|
13
19
|
export interface WorkerAvailability {
|
|
20
|
+
/** When provided, overrides `typeof Worker !== 'undefined'`. */
|
|
14
21
|
worker?: boolean;
|
|
22
|
+
/** When provided, overrides `typeof SharedWorker !== 'undefined'`. */
|
|
15
23
|
sharedWorker?: boolean;
|
|
16
24
|
}
|
|
17
25
|
/**
|
|
@@ -20,6 +28,7 @@ export interface WorkerAvailability {
|
|
|
20
28
|
*
|
|
21
29
|
* - `dedicated` prefers Dedicated Worker, then SharedWorker, then local mode.
|
|
22
30
|
* - `shared` and `auto` prefer SharedWorker, then Dedicated Worker, then local.
|
|
31
|
+
* Returns `'local'` when neither Worker API is available (main-thread fallback).
|
|
23
32
|
*/
|
|
24
33
|
export declare function selectWorkerBackend(mode: WorkerMode, availability?: WorkerAvailability): WorkerBackend;
|
|
25
34
|
//# sourceMappingURL=worker-mode.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-mode.d.ts","sourceRoot":"","sources":["../src/worker-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH
|
|
1
|
+
{"version":3,"file":"worker-mode.d.ts","sourceRoot":"","sources":["../src/worker-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;oEAGoE;AACpE,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEzD;yEACyE;AACzE,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7D;;uEAEuE;AACvE,MAAM,WAAW,kBAAkB;IACjC,gEAAgE;IAChE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sEAAsE;IACtE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,YAAY,GAAE,kBAAuB,GACpC,aAAa,CAOf"}
|
|
@@ -32,23 +32,38 @@ export declare class PortReaper {
|
|
|
32
32
|
private readonly setTimer;
|
|
33
33
|
private readonly clearTimer;
|
|
34
34
|
/** Track a newly connected port and its session. The default timeout applies
|
|
35
|
-
* until the port sends an INIT with its own heartbeat config
|
|
35
|
+
* until the port sends an INIT with its own heartbeat config, at which point
|
|
36
|
+
* setTimeout() overrides it. register() always calls schedule() so the
|
|
37
|
+
* reaper interval starts as soon as the first port connects. */
|
|
36
38
|
register(port: MessagePort, target: ReapTarget): void;
|
|
37
|
-
/** Record activity on a port (any incoming message). No-op for untracked
|
|
39
|
+
/** Record activity on a port (any incoming message). No-op for untracked
|
|
40
|
+
* ports — a late PING from a port that was already removed/STOP'd must not
|
|
41
|
+
* resurrect it in the reaper's tracking maps. */
|
|
38
42
|
touch(port: MessagePort): void;
|
|
39
43
|
/** Override a port's session timeout from its INIT heartbeat config.
|
|
40
44
|
* A non-finite or non-positive value falls back to the default so a bad
|
|
41
|
-
* payload cannot degenerate the reaper into a busy loop or silence it.
|
|
45
|
+
* payload cannot degenerate the reaper into a busy loop or silence it.
|
|
46
|
+
* No-op for untracked ports (e.g. setTimeout arrives after remove/STOP). */
|
|
42
47
|
setTimeout(port: MessagePort, heartbeatIntervalMs: number): void;
|
|
43
48
|
/** Remove a port (STOP message). The caller is responsible for closing the
|
|
44
|
-
* port and stopping the session.
|
|
49
|
+
* port and stopping the session. No-op for untracked ports so a duplicate
|
|
50
|
+
* STOP or a STOP-after-reap cannot corrupt the reaper's bookkeeping. */
|
|
45
51
|
remove(port: MessagePort): void;
|
|
46
52
|
/** Clear all state and stop the reaper. Closes and stops every tracked
|
|
47
53
|
* session so the SharedWorker does not leak WebSockets on shutdown. */
|
|
48
54
|
dispose(): void;
|
|
49
|
-
/** Recompute the reaper cadence, or stop it entirely when no ports remain.
|
|
55
|
+
/** Recompute the reaper cadence, or stop it entirely when no ports remain.
|
|
56
|
+
* Idempotent: if the interval is already running at the correct cadence,
|
|
57
|
+
* no new timer is created. This guards against register/remove/setTimeout
|
|
58
|
+
* each spawning redundant timers when the cadence hasn't changed. */
|
|
50
59
|
private schedule;
|
|
51
|
-
/**
|
|
60
|
+
/** Smallest heartbeat interval among active ports, derived from each port's
|
|
61
|
+
* configured session timeout. Exposed as a method so the cadence logic can
|
|
62
|
+
* be unit-tested in isolation from the timer plumbing. */
|
|
63
|
+
private computeMinHeartbeat;
|
|
64
|
+
/** Close sessions whose port has been silent longer than its timeout.
|
|
65
|
+
* Iterates a snapshot so closing a target (which mutates `targets`) during
|
|
66
|
+
* the loop cannot skip a subsequent entry or visit one twice. */
|
|
52
67
|
private reap;
|
|
53
68
|
}
|
|
54
69
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port-reaper.d.ts","sourceRoot":"","sources":["../../src/workers/port-reaper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;
|
|
1
|
+
{"version":3,"file":"port-reaper.d.ts","sourceRoot":"","sources":["../../src/workers/port-reaper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAQH,4EAA4E;AAC5E,MAAM,WAAW,UAAU;IACzB,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;CACd;AAED,KAAK,QAAQ,GAAG,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;AAC7D,KAAK,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAE3C,qBAAa,UAAU;IAQnB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAPtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAC9D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkC;IACnE,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAAiC;gBAGhC,GAAG,GAAE,MAAM,MAAiB,EAC7C,QAAQ,GAAE,QAA2E,EACrF,UAAU,GAAE,UAA4C;IAM1D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IAExC;;;oEAGgE;IAChE,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAOrD;;qDAEiD;IACjD,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAK9B;;;gFAG4E;IAC5E,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,GAAG,IAAI;IAShE;;4EAEwE;IACxE,MAAM,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAQ/B;2EACuE;IACvE,OAAO,IAAI,IAAI;IAgBf;;;yEAGqE;IACrE,OAAO,CAAC,QAAQ;IAahB;;8DAE0D;IAC1D,OAAO,CAAC,mBAAmB;IAQ3B;;qEAEiE;IACjE,OAAO,CAAC,IAAI;CA0Bb"}
|
package/docs/architecture.md
CHANGED
|
@@ -10,23 +10,33 @@ graph TB
|
|
|
10
10
|
subgraph TabA["Tab A"]
|
|
11
11
|
AppA["Business Module"] --> 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["Business Module"] --> 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 Control Plane"]
|
|
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 Registration"]
|
|
29
|
+
BatchB <--> Registry
|
|
30
|
+
BatchA <--> Routes["localStorage Topic Routes"]
|
|
31
|
+
BatchB <--> Routes
|
|
32
|
+
WorkerA --> SessionA["CentrifugeSession"]
|
|
33
|
+
WorkerB --> SessionB["CentrifugeSession"]
|
|
34
|
+
SessionA --> Server["Centrifuge / realtime server"]
|
|
35
|
+
SessionB --> Server
|
|
36
|
+
subgraph SW["SharedWorker process (when backend = shared)"]
|
|
37
|
+
Reaper["PortReaper"] -.-> SessionA
|
|
38
|
+
Reaper -.-> SessionB
|
|
39
|
+
end
|
|
30
40
|
```
|
|
31
41
|
|
|
32
42
|
By default, when `workerMode: 'dedicated'`, each Tab has its own dedicated transport Worker. When configured as `shared` or `auto` and the browser supports SharedWorker, same-origin tabs share the same SharedWorker; each connection port within the SharedWorker creates its own independent `CentrifugeSession`, so one Tab refreshing or stopping does not affect other Tabs. The `auto` mode degrades in order of **SharedWorker → Dedicated Worker → Local mode**, while the `dedicated` mode degrades in order of **Dedicated Worker → SharedWorker → Local mode**. `BroadcastChannel` is only responsible for control messages and real-time publication forwarding; localStorage is only responsible for eventually-consistent coordination metadata.
|