cross-tab-worker-databus 0.20.71 → 0.20.85
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 +204 -2
- package/README.md +8 -0
- package/README.zh.md +4 -0
- package/dist/centrifuge-protocol.d.ts +59 -26
- package/dist/centrifuge-protocol.d.ts.map +1 -1
- package/dist/centrifuge-session.d.ts +9 -0
- package/dist/centrifuge-session.d.ts.map +1 -1
- package/dist/centrifuge.d.ts +12 -2
- package/dist/centrifuge.d.ts.map +1 -1
- package/dist/centrifuge.js +168 -88
- package/dist/centrifuge.js.map +3 -3
- package/dist/centrifuge.shared.worker.js +146 -38
- package/dist/centrifuge.shared.worker.js.map +3 -3
- package/dist/centrifuge.worker.js +140 -33
- package/dist/centrifuge.worker.js.map +3 -3
- package/dist/{chunk-D2SIT473.js → chunk-PW63EWIK.js} +1090 -494
- package/dist/chunk-PW63EWIK.js.map +7 -0
- package/dist/chunk-TZ7ZP7YD.js +175 -0
- package/dist/chunk-TZ7ZP7YD.js.map +7 -0
- package/dist/cjs/centrifuge.cjs +1403 -637
- package/dist/cjs/centrifuge.cjs.map +4 -4
- package/dist/cjs/hooks.cjs +37 -2
- package/dist/cjs/hooks.cjs.map +3 -3
- package/dist/cjs/index.cjs +1453 -730
- package/dist/cjs/index.cjs.map +4 -4
- package/dist/cjs/vue.cjs +45 -2
- package/dist/cjs/vue.cjs.map +3 -3
- package/dist/core/cluster.d.ts +40 -4
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/data-bus.d.ts +93 -69
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/dedup-manager.d.ts +98 -0
- package/dist/core/dedup-manager.d.ts.map +1 -0
- package/dist/core/environment.d.ts +43 -3
- package/dist/core/environment.d.ts.map +1 -1
- package/dist/core/replay-manager.d.ts +128 -0
- package/dist/core/replay-manager.d.ts.map +1 -0
- package/dist/core/replay-persistence.d.ts +2 -1
- package/dist/core/replay-persistence.d.ts.map +1 -1
- package/dist/core/routing.d.ts +22 -3
- package/dist/core/routing.d.ts.map +1 -1
- package/dist/core/storage-batch.d.ts +0 -4
- package/dist/core/storage-batch.d.ts.map +1 -1
- package/dist/core/trace.d.ts +55 -15
- package/dist/core/trace.d.ts.map +1 -1
- package/dist/core/types.d.ts +58 -9
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/version.d.ts +2 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/hooks.d.ts +12 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +28 -2
- package/dist/hooks.js.map +2 -2
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +228 -162
- package/dist/index.js.map +3 -3
- package/dist/utils/constants.d.ts +170 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/error-utils.d.ts +28 -0
- package/dist/utils/error-utils.d.ts.map +1 -0
- package/dist/utils/metadata.d.ts +16 -0
- package/dist/utils/metadata.d.ts.map +1 -0
- package/dist/utils/storage-utils.d.ts +24 -0
- package/dist/utils/storage-utils.d.ts.map +1 -0
- package/dist/utils/validation.d.ts +76 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/vue.d.ts +13 -1
- package/dist/vue.d.ts.map +1 -1
- package/dist/vue.js +36 -2
- package/dist/vue.js.map +2 -2
- package/dist/websocket.d.ts +6 -1
- package/dist/websocket.d.ts.map +1 -1
- package/dist/worker-mode.d.ts +6 -2
- package/dist/worker-mode.d.ts.map +1 -1
- package/docs/README.md +1 -0
- package/docs/api.md +122 -2
- package/docs/architecture.md +80 -0
- package/docs/benchmarks.md +24 -0
- package/docs/capabilities.md +24 -3
- package/docs/configuration.md +58 -0
- package/docs/getting-started.md +35 -0
- package/docs/release-checklist.md +28 -5
- package/docs/roadmap.md +74 -5
- package/docs/zh/README.md +2 -1
- package/docs/zh/api.md +121 -2
- package/docs/zh/architecture.md +49 -0
- package/docs/zh/benchmarks.md +24 -0
- package/docs/zh/capabilities.md +21 -3
- package/docs/zh/configuration.md +53 -0
- package/docs/zh/getting-started.md +35 -0
- package/docs/zh/release-checklist.md +29 -6
- package/docs/zh/roadmap.md +86 -5
- package/package.json +39 -16
- package/dist/chunk-D2SIT473.js.map +0 -7
package/dist/centrifuge.js
CHANGED
|
@@ -1,54 +1,119 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CrossTabDataBus,
|
|
3
|
+
assertHeartbeatInterval,
|
|
4
|
+
assertStructuredCloneable,
|
|
3
5
|
parseDataBusPublication,
|
|
6
|
+
publicationMetadata,
|
|
4
7
|
selectWorkerBackend
|
|
5
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-PW63EWIK.js";
|
|
9
|
+
import {
|
|
10
|
+
CENTRIFUGE_INPUT_TYPE,
|
|
11
|
+
CENTRIFUGE_OUTPUT_TYPE,
|
|
12
|
+
DEFAULT_STORAGE_PREFIX,
|
|
13
|
+
WORKER_BACKEND,
|
|
14
|
+
WORKER_MODE,
|
|
15
|
+
WORKER_STATUS
|
|
16
|
+
} from "./chunk-TZ7ZP7YD.js";
|
|
6
17
|
|
|
7
18
|
// src/centrifuge-session.ts
|
|
8
19
|
import { Centrifuge } from "centrifuge";
|
|
20
|
+
|
|
21
|
+
// src/utils/error-utils.ts
|
|
22
|
+
function serializeError(error) {
|
|
23
|
+
if (error instanceof Error) {
|
|
24
|
+
return {
|
|
25
|
+
name: error.name,
|
|
26
|
+
message: error.message,
|
|
27
|
+
...error.stack ? { stack: error.stack } : {}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const context = error === void 0 ? void 0 : error;
|
|
31
|
+
return {
|
|
32
|
+
name: "CentrifugeError",
|
|
33
|
+
message: typeof error === "string" ? error : "Centrifuge worker operation failed.",
|
|
34
|
+
...context === void 0 || !isStructuredCloneable(context) ? {} : { context }
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function isStructuredCloneable(value) {
|
|
38
|
+
if (typeof structuredClone !== "function") return true;
|
|
39
|
+
try {
|
|
40
|
+
structuredClone(value);
|
|
41
|
+
return true;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function deserializeWorkerError(error) {
|
|
47
|
+
const result = new Error(error.message);
|
|
48
|
+
result.name = error.name;
|
|
49
|
+
if (error.stack) result.stack = error.stack;
|
|
50
|
+
if (error.context !== void 0) Object.assign(result, { context: error.context });
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/centrifuge-session.ts
|
|
9
55
|
var CentrifugeSession = class {
|
|
10
56
|
constructor(sink) {
|
|
11
57
|
this.sink = sink;
|
|
12
58
|
}
|
|
59
|
+
sink;
|
|
13
60
|
client = null;
|
|
14
61
|
subscriptions = /* @__PURE__ */ new Map();
|
|
15
62
|
transferable = false;
|
|
63
|
+
tokenBridge = false;
|
|
64
|
+
nextRequestId = 1;
|
|
65
|
+
pendingTokenRequests = /* @__PURE__ */ new Map();
|
|
16
66
|
/** Dispatch an incoming Worker message to the matching operation.
|
|
17
67
|
* Unknown message types are ignored rather than thrown, so a future protocol
|
|
18
68
|
* extension adding a new variant cannot crash an older session. */
|
|
19
69
|
handle(message) {
|
|
20
70
|
switch (message.type) {
|
|
21
|
-
case
|
|
22
|
-
this.initialize(message.url, message.config, message.transferable === true);
|
|
71
|
+
case CENTRIFUGE_INPUT_TYPE.INIT:
|
|
72
|
+
this.initialize(message.url, message.config, message.transferable === true, message.tokenBridge === true);
|
|
23
73
|
return;
|
|
24
|
-
case
|
|
74
|
+
case CENTRIFUGE_INPUT_TYPE.SUBSCRIBE:
|
|
25
75
|
this.subscribe(message.topic);
|
|
26
76
|
return;
|
|
27
|
-
case
|
|
77
|
+
case CENTRIFUGE_INPUT_TYPE.UNSUBSCRIBE:
|
|
28
78
|
this.unsubscribe(message.topic);
|
|
29
79
|
return;
|
|
30
|
-
case
|
|
31
|
-
case
|
|
80
|
+
case CENTRIFUGE_INPUT_TYPE.PUBLISH:
|
|
81
|
+
case CENTRIFUGE_INPUT_TYPE.PUBLISH_BIN:
|
|
32
82
|
this.publish(message.topic, message.data, message.messageId, message.timestamp);
|
|
33
83
|
return;
|
|
34
|
-
case
|
|
84
|
+
case CENTRIFUGE_INPUT_TYPE.STOP:
|
|
35
85
|
this.stop();
|
|
36
86
|
return;
|
|
87
|
+
case CENTRIFUGE_INPUT_TYPE.TOKEN_RESPONSE:
|
|
88
|
+
this.resolveToken(message.requestId, message.token);
|
|
89
|
+
return;
|
|
90
|
+
case CENTRIFUGE_INPUT_TYPE.TOKEN_ERROR:
|
|
91
|
+
this.rejectToken(message.requestId, deserializeWorkerError(message.error));
|
|
92
|
+
return;
|
|
37
93
|
default:
|
|
38
94
|
return;
|
|
39
95
|
}
|
|
40
96
|
}
|
|
41
97
|
/** Create the Centrifuge client, wire up lifecycle listeners, and connect. */
|
|
42
|
-
initialize(url, config, transferable) {
|
|
98
|
+
initialize(url, config, transferable, tokenBridge) {
|
|
43
99
|
if (this.client) return;
|
|
44
100
|
this.transferable = transferable;
|
|
45
|
-
|
|
101
|
+
this.tokenBridge = tokenBridge;
|
|
102
|
+
const clientOptions = tokenBridge ? {
|
|
103
|
+
...config,
|
|
104
|
+
// Route credential fetches back to the main thread, where the
|
|
105
|
+
// application's credentialProvider lives (config must stay
|
|
106
|
+
// structured-cloneable, so functions cannot cross the boundary).
|
|
107
|
+
getToken: () => this.requestToken("token"),
|
|
108
|
+
getChannelToken: (channel) => this.requestToken("channelToken", channel)
|
|
109
|
+
} : config;
|
|
110
|
+
const client = new Centrifuge(url, clientOptions);
|
|
46
111
|
this.client = client;
|
|
47
112
|
client.on("state", (context) => {
|
|
48
|
-
this.post({ type:
|
|
113
|
+
this.post({ type: CENTRIFUGE_OUTPUT_TYPE.STATUS, status: normalizeStatus(context.newState) });
|
|
49
114
|
});
|
|
50
|
-
client.on("connected", () => this.post({ type:
|
|
51
|
-
client.on("disconnected", () => this.post({ type:
|
|
115
|
+
client.on("connected", () => this.post({ type: CENTRIFUGE_OUTPUT_TYPE.STATUS, status: WORKER_STATUS.CONNECTED }));
|
|
116
|
+
client.on("disconnected", () => this.post({ type: CENTRIFUGE_OUTPUT_TYPE.STATUS, status: WORKER_STATUS.DISCONNECTED }));
|
|
52
117
|
client.on("error", (context) => this.postError(context));
|
|
53
118
|
client.on("publication", (context) => {
|
|
54
119
|
const topic = context.channel || getPayloadTopic(context.data);
|
|
@@ -111,25 +176,56 @@ var CentrifugeSession = class {
|
|
|
111
176
|
postPublication(topic, data) {
|
|
112
177
|
if (!topic) return;
|
|
113
178
|
if (this.transferable && data instanceof ArrayBuffer) {
|
|
114
|
-
this.post({ type:
|
|
179
|
+
this.post({ type: CENTRIFUGE_OUTPUT_TYPE.MESSAGE_BIN, topic, data }, [data]);
|
|
115
180
|
return;
|
|
116
181
|
}
|
|
117
182
|
const publication = parseDataBusPublication(data, topic);
|
|
118
183
|
if (!publication) return;
|
|
119
184
|
this.post({
|
|
120
|
-
type:
|
|
185
|
+
type: CENTRIFUGE_OUTPUT_TYPE.MESSAGE,
|
|
121
186
|
topic: publication.topic,
|
|
122
187
|
data: publication.data,
|
|
123
|
-
...publication.messageId
|
|
124
|
-
...publication.timestamp === void 0 ? {} : { timestamp: publication.timestamp }
|
|
188
|
+
...publicationMetadata(publication.messageId, publication.timestamp)
|
|
125
189
|
});
|
|
126
190
|
}
|
|
127
191
|
/** Disconnect the client and clear all subscriptions. */
|
|
128
192
|
stop() {
|
|
193
|
+
for (const [, pending] of this.pendingTokenRequests) {
|
|
194
|
+
pending.reject(new Error("Centrifuge session stopped before the credential was resolved."));
|
|
195
|
+
}
|
|
196
|
+
this.pendingTokenRequests.clear();
|
|
129
197
|
this.client?.disconnect();
|
|
130
198
|
this.subscriptions.clear();
|
|
131
199
|
this.client = null;
|
|
132
|
-
this.post({ type:
|
|
200
|
+
this.post({ type: CENTRIFUGE_OUTPUT_TYPE.STATUS, status: WORKER_STATUS.DISCONNECTED });
|
|
201
|
+
}
|
|
202
|
+
/** Issue a credential request to the main thread and await the response.
|
|
203
|
+
* Used as Centrifuge's `getToken` / `getChannelToken` when token bridging is
|
|
204
|
+
* enabled; resolved or rejected by a matching TOKEN_RESPONSE / TOKEN_ERROR. */
|
|
205
|
+
requestToken(kind, channel) {
|
|
206
|
+
const requestId = this.nextRequestId;
|
|
207
|
+
this.nextRequestId += 1;
|
|
208
|
+
return new Promise((resolve, reject) => {
|
|
209
|
+
this.pendingTokenRequests.set(requestId, { resolve, reject });
|
|
210
|
+
this.post({
|
|
211
|
+
type: CENTRIFUGE_OUTPUT_TYPE.TOKEN_REQUEST,
|
|
212
|
+
requestId,
|
|
213
|
+
kind,
|
|
214
|
+
...channel === void 0 ? {} : { channel }
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
resolveToken(requestId, token) {
|
|
219
|
+
const pending = this.pendingTokenRequests.get(requestId);
|
|
220
|
+
if (!pending) return;
|
|
221
|
+
this.pendingTokenRequests.delete(requestId);
|
|
222
|
+
pending.resolve(token);
|
|
223
|
+
}
|
|
224
|
+
rejectToken(requestId, error) {
|
|
225
|
+
const pending = this.pendingTokenRequests.get(requestId);
|
|
226
|
+
if (!pending) return;
|
|
227
|
+
this.pendingTokenRequests.delete(requestId);
|
|
228
|
+
pending.reject(error);
|
|
133
229
|
}
|
|
134
230
|
/** Forward a message to the sink (the transport layer). */
|
|
135
231
|
post(message, transfer) {
|
|
@@ -141,7 +237,7 @@ var CentrifugeSession = class {
|
|
|
141
237
|
* Fatal errors are distinguished by the client eventually emitting
|
|
142
238
|
* `disconnected` without a subsequent `connected`. */
|
|
143
239
|
postError(error) {
|
|
144
|
-
this.post({ type:
|
|
240
|
+
this.post({ type: CENTRIFUGE_OUTPUT_TYPE.ERROR, error: serializeError(error) });
|
|
145
241
|
}
|
|
146
242
|
};
|
|
147
243
|
function getPayloadTopic(data) {
|
|
@@ -152,24 +248,10 @@ function getPayloadTopic(data) {
|
|
|
152
248
|
const topic = nested ?? payload.channel;
|
|
153
249
|
return typeof topic === "string" ? topic : "";
|
|
154
250
|
}
|
|
155
|
-
var LIVE_STATES = /* @__PURE__ */ new Set([
|
|
251
|
+
var LIVE_STATES = /* @__PURE__ */ new Set([WORKER_STATUS.CONNECTING, WORKER_STATUS.CONNECTED]);
|
|
156
252
|
function normalizeStatus(status) {
|
|
157
253
|
return LIVE_STATES.has(status) ? status : "disconnected";
|
|
158
254
|
}
|
|
159
|
-
function serializeError(error) {
|
|
160
|
-
if (error instanceof Error) {
|
|
161
|
-
return {
|
|
162
|
-
name: error.name,
|
|
163
|
-
message: error.message,
|
|
164
|
-
...error.stack ? { stack: error.stack } : {}
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
return {
|
|
168
|
-
name: "CentrifugeError",
|
|
169
|
-
message: typeof error === "string" ? error : "Centrifuge worker operation failed.",
|
|
170
|
-
...error === void 0 ? {} : { context: error }
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
255
|
|
|
174
256
|
// src/centrifuge-protocol.ts
|
|
175
257
|
var DEFAULT_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
@@ -184,6 +266,7 @@ var CentrifugeWorkerTransport = class {
|
|
|
184
266
|
heartbeatIntervalMs;
|
|
185
267
|
workerFactory;
|
|
186
268
|
sharedWorkerFactory;
|
|
269
|
+
credentialProvider;
|
|
187
270
|
backend = null;
|
|
188
271
|
worker = null;
|
|
189
272
|
sharedWorker = null;
|
|
@@ -201,12 +284,13 @@ var CentrifugeWorkerTransport = class {
|
|
|
201
284
|
return this.backend ?? "uninitialized";
|
|
202
285
|
}
|
|
203
286
|
constructor(options = {}) {
|
|
204
|
-
this.workerMode = options.workerMode ??
|
|
287
|
+
this.workerMode = options.workerMode ?? WORKER_MODE.DEDICATED;
|
|
205
288
|
this.transferable = options.transferable ?? false;
|
|
206
289
|
this.heartbeatIntervalMs = options.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
|
|
207
290
|
assertHeartbeatInterval(this.heartbeatIntervalMs);
|
|
208
291
|
this.workerFactory = options.workerFactory;
|
|
209
292
|
this.sharedWorkerFactory = options.sharedWorkerFactory;
|
|
293
|
+
this.credentialProvider = options.credentialProvider;
|
|
210
294
|
}
|
|
211
295
|
/**
|
|
212
296
|
* Start the transport: select a backend, initialise the Worker (or local
|
|
@@ -217,29 +301,29 @@ var CentrifugeWorkerTransport = class {
|
|
|
217
301
|
assertStructuredCloneable(config.options ?? {});
|
|
218
302
|
this.handlers = handlers;
|
|
219
303
|
const backend = selectWorkerBackend(this.workerMode, {
|
|
220
|
-
worker: this.workerFactory !== void 0,
|
|
221
|
-
sharedWorker: this.sharedWorkerFactory !== void 0
|
|
304
|
+
worker: this.workerFactory !== void 0 || typeof Worker !== "undefined",
|
|
305
|
+
sharedWorker: this.sharedWorkerFactory !== void 0 || typeof SharedWorker !== "undefined"
|
|
222
306
|
});
|
|
223
307
|
const input = this.buildInitInput(config);
|
|
224
|
-
if (backend ===
|
|
308
|
+
if (backend === WORKER_BACKEND.SHARED) {
|
|
225
309
|
this.startSharedWorker(input);
|
|
226
|
-
this.backend =
|
|
310
|
+
this.backend = WORKER_BACKEND.SHARED;
|
|
227
311
|
return;
|
|
228
312
|
}
|
|
229
|
-
if (backend ===
|
|
313
|
+
if (backend === WORKER_BACKEND.DEDICATED) {
|
|
230
314
|
this.startDedicatedWorker(input);
|
|
231
|
-
this.backend =
|
|
315
|
+
this.backend = WORKER_BACKEND.DEDICATED;
|
|
232
316
|
return;
|
|
233
317
|
}
|
|
234
318
|
this.localSession = new CentrifugeSession({ post: this.handleSessionOutput });
|
|
235
319
|
this.localSession.handle(input);
|
|
236
|
-
this.backend =
|
|
320
|
+
this.backend = WORKER_BACKEND.LOCAL;
|
|
237
321
|
}
|
|
238
322
|
subscribe(topic) {
|
|
239
|
-
this.post({ type:
|
|
323
|
+
this.post({ type: CENTRIFUGE_INPUT_TYPE.SUBSCRIBE, topic });
|
|
240
324
|
}
|
|
241
325
|
unsubscribe(topic) {
|
|
242
|
-
this.post({ type:
|
|
326
|
+
this.post({ type: CENTRIFUGE_INPUT_TYPE.UNSUBSCRIBE, topic });
|
|
243
327
|
}
|
|
244
328
|
/**
|
|
245
329
|
* Publish data to `topic`. Binary data (ArrayBuffer) is sent via Transferable
|
|
@@ -247,10 +331,10 @@ var CentrifugeWorkerTransport = class {
|
|
|
247
331
|
*/
|
|
248
332
|
publish(topic, data, options) {
|
|
249
333
|
if (this.transferable && data instanceof ArrayBuffer) {
|
|
250
|
-
this.post({ type:
|
|
334
|
+
this.post({ type: CENTRIFUGE_INPUT_TYPE.PUBLISH_BIN, topic, data, ...publicationMetadata(options?.messageId, options?.timestamp) }, [data]);
|
|
251
335
|
return;
|
|
252
336
|
}
|
|
253
|
-
this.post({ type:
|
|
337
|
+
this.post({ type: CENTRIFUGE_INPUT_TYPE.PUBLISH, topic, data, ...publicationMetadata(options?.messageId, options?.timestamp) });
|
|
254
338
|
}
|
|
255
339
|
/**
|
|
256
340
|
* Gracefully stop the transport: send STOP, clean up event listeners, and
|
|
@@ -259,7 +343,7 @@ var CentrifugeWorkerTransport = class {
|
|
|
259
343
|
stop() {
|
|
260
344
|
if (!this.backend) return;
|
|
261
345
|
this.generation++;
|
|
262
|
-
this.post({ type:
|
|
346
|
+
this.post({ type: CENTRIFUGE_INPUT_TYPE.STOP });
|
|
263
347
|
this.clearHeartbeat();
|
|
264
348
|
if (this.worker) {
|
|
265
349
|
this.worker.removeEventListener("message", this.handleMessage);
|
|
@@ -278,10 +362,11 @@ var CentrifugeWorkerTransport = class {
|
|
|
278
362
|
* default-resolution logic kicks in for the common case. */
|
|
279
363
|
buildInitInput(config) {
|
|
280
364
|
return {
|
|
281
|
-
type:
|
|
365
|
+
type: CENTRIFUGE_INPUT_TYPE.INIT,
|
|
282
366
|
url: config.url,
|
|
283
367
|
config: config.options ?? {},
|
|
284
368
|
...this.transferable ? { transferable: true } : {},
|
|
369
|
+
...this.credentialProvider ? { tokenBridge: true } : {},
|
|
285
370
|
...this.heartbeatIntervalMs !== DEFAULT_HEARTBEAT_INTERVAL_MS ? { heartbeatIntervalMs: this.heartbeatIntervalMs } : {}
|
|
286
371
|
};
|
|
287
372
|
}
|
|
@@ -320,10 +405,34 @@ var CentrifugeWorkerTransport = class {
|
|
|
320
405
|
* Shared by the Worker message listener, the SharedWorker port listener,
|
|
321
406
|
* and the local-session sink — all three feed into this single dispatcher. */
|
|
322
407
|
handleOutput(message) {
|
|
323
|
-
if (message.type ===
|
|
324
|
-
if (message.type ===
|
|
325
|
-
if (message.type ===
|
|
326
|
-
if (message.type ===
|
|
408
|
+
if (message.type === CENTRIFUGE_OUTPUT_TYPE.STATUS) this.handlers?.onStatus(message.status);
|
|
409
|
+
if (message.type === CENTRIFUGE_OUTPUT_TYPE.MESSAGE) this.handlers?.onMessage({ topic: message.topic, data: message.data, ...publicationMetadata(message.messageId, message.timestamp) });
|
|
410
|
+
if (message.type === CENTRIFUGE_OUTPUT_TYPE.MESSAGE_BIN) this.handlers?.onMessage({ topic: message.topic, data: message.data, ...publicationMetadata(message.messageId, message.timestamp) });
|
|
411
|
+
if (message.type === CENTRIFUGE_OUTPUT_TYPE.ERROR) this.handlers?.onError(deserializeWorkerError(message.error));
|
|
412
|
+
if (message.type === CENTRIFUGE_OUTPUT_TYPE.TOKEN_REQUEST) this.resolveTokenRequest(message.requestId, message.kind, message.channel);
|
|
413
|
+
}
|
|
414
|
+
/** Resolve a Worker credential request from the main thread: call the
|
|
415
|
+
* credentialProvider, then post the fresh token (or a serialized failure)
|
|
416
|
+
* back to the session that issued the request. */
|
|
417
|
+
resolveTokenRequest(requestId, kind, channel) {
|
|
418
|
+
const provider = this.credentialProvider;
|
|
419
|
+
const value = kind === "channelToken" && provider?.getChannelToken ? provider.getChannelToken(channel ?? "") : provider?.getToken?.();
|
|
420
|
+
Promise.resolve(value).then(
|
|
421
|
+
(token) => {
|
|
422
|
+
if (typeof token !== "string" || token.length === 0) {
|
|
423
|
+
this.post({
|
|
424
|
+
type: CENTRIFUGE_INPUT_TYPE.TOKEN_ERROR,
|
|
425
|
+
requestId,
|
|
426
|
+
error: serializeError(new Error(`The credential provider returned no ${kind}.`))
|
|
427
|
+
});
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
this.post({ type: CENTRIFUGE_INPUT_TYPE.TOKEN_RESPONSE, requestId, token });
|
|
431
|
+
},
|
|
432
|
+
(error) => {
|
|
433
|
+
this.post({ type: CENTRIFUGE_INPUT_TYPE.TOKEN_ERROR, requestId, error: serializeError(error) });
|
|
434
|
+
}
|
|
435
|
+
);
|
|
327
436
|
}
|
|
328
437
|
/** Handle a Worker-level failure (crash, message decode error). Discards the
|
|
329
438
|
* dead backend so a later start()/reopen can rebuild from scratch, and
|
|
@@ -339,7 +448,7 @@ var CentrifugeWorkerTransport = class {
|
|
|
339
448
|
this.clearHeartbeat();
|
|
340
449
|
this.resetBackend();
|
|
341
450
|
this.handlers?.onError(new Error(message));
|
|
342
|
-
this.handlers?.onStatus(
|
|
451
|
+
this.handlers?.onStatus(WORKER_STATUS.ERROR);
|
|
343
452
|
}
|
|
344
453
|
/** Remove every listener attached to the current SharedWorker and its port. */
|
|
345
454
|
detachSharedWorkerListeners() {
|
|
@@ -352,7 +461,7 @@ var CentrifugeWorkerTransport = class {
|
|
|
352
461
|
if (this.heartbeatHandle !== null) return;
|
|
353
462
|
if (this.heartbeatIntervalMs === Infinity) return;
|
|
354
463
|
this.heartbeatHandle = setInterval(() => {
|
|
355
|
-
this.post({ type:
|
|
464
|
+
this.post({ type: CENTRIFUGE_INPUT_TYPE.PING });
|
|
356
465
|
}, this.heartbeatIntervalMs);
|
|
357
466
|
}
|
|
358
467
|
clearHeartbeat() {
|
|
@@ -403,6 +512,7 @@ function createCentrifugeDataBus(options) {
|
|
|
403
512
|
const {
|
|
404
513
|
clusterKey,
|
|
405
514
|
connection,
|
|
515
|
+
credentialProvider,
|
|
406
516
|
heartbeatIntervalMs,
|
|
407
517
|
sharedWorkerFactory,
|
|
408
518
|
transferable,
|
|
@@ -420,7 +530,8 @@ function createCentrifugeDataBus(options) {
|
|
|
420
530
|
...sharedWorkerFactory ? { sharedWorkerFactory } : {},
|
|
421
531
|
...transferable === void 0 ? {} : { transferable },
|
|
422
532
|
...workerMode ? { workerMode } : {},
|
|
423
|
-
...heartbeatIntervalMs === void 0 ? {} : { heartbeatIntervalMs }
|
|
533
|
+
...heartbeatIntervalMs === void 0 ? {} : { heartbeatIntervalMs },
|
|
534
|
+
...credentialProvider ? { credentialProvider } : {}
|
|
424
535
|
})
|
|
425
536
|
});
|
|
426
537
|
}
|
|
@@ -437,7 +548,7 @@ function createDefaultWorker() {
|
|
|
437
548
|
);
|
|
438
549
|
}
|
|
439
550
|
return new Worker(workerUrl, {
|
|
440
|
-
name:
|
|
551
|
+
name: DEFAULT_STORAGE_PREFIX,
|
|
441
552
|
type: "module"
|
|
442
553
|
});
|
|
443
554
|
}
|
|
@@ -454,45 +565,14 @@ function createDefaultSharedWorker() {
|
|
|
454
565
|
);
|
|
455
566
|
}
|
|
456
567
|
return new SharedWorker(workerUrl, {
|
|
457
|
-
name:
|
|
568
|
+
name: `${DEFAULT_STORAGE_PREFIX}-shared`,
|
|
458
569
|
type: "module"
|
|
459
570
|
});
|
|
460
571
|
}
|
|
461
|
-
function assertHeartbeatInterval(value) {
|
|
462
|
-
if (value === Infinity) return;
|
|
463
|
-
if (typeof value === "number" && Number.isFinite(value) && value > 0) return;
|
|
464
|
-
throw new TypeError(
|
|
465
|
-
`Centrifuge heartbeatIntervalMs must be a positive number or Infinity, got ${String(value)}.`
|
|
466
|
-
);
|
|
467
|
-
}
|
|
468
|
-
function assertStructuredCloneable(value) {
|
|
469
|
-
if (typeof structuredClone !== "function") return;
|
|
470
|
-
try {
|
|
471
|
-
structuredClone(value);
|
|
472
|
-
} catch (error) {
|
|
473
|
-
throw new TypeError(
|
|
474
|
-
"Centrifuge Worker configuration and published data must be structured-cloneable.",
|
|
475
|
-
{ cause: error }
|
|
476
|
-
);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
572
|
function postToPortLike(target, message, transfer) {
|
|
480
573
|
if (transfer) target.postMessage(message, transfer);
|
|
481
574
|
else target.postMessage(message);
|
|
482
575
|
}
|
|
483
|
-
function deserializeWorkerError(error) {
|
|
484
|
-
const result = new Error(error.message);
|
|
485
|
-
result.name = error.name;
|
|
486
|
-
if (error.stack) result.stack = error.stack;
|
|
487
|
-
if (error.context !== void 0) Object.assign(result, { context: error.context });
|
|
488
|
-
return result;
|
|
489
|
-
}
|
|
490
|
-
function publicationMetadata(metadata) {
|
|
491
|
-
return {
|
|
492
|
-
...metadata?.messageId === void 0 ? {} : { messageId: metadata.messageId },
|
|
493
|
-
...metadata?.timestamp === void 0 ? {} : { timestamp: metadata.timestamp }
|
|
494
|
-
};
|
|
495
|
-
}
|
|
496
576
|
export {
|
|
497
577
|
CentrifugeWorkerTransport,
|
|
498
578
|
createCentrifugeDataBus
|