@thalesrc/hermes 7.4.7 → 7.5.2

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.
@@ -1,9 +1,12 @@
1
1
  import { uniqueId } from "@thalesrc/js-utils/unique-id";
2
2
  import { noop } from "@thalesrc/js-utils/function/noop";
3
- import { promisify } from '@thalesrc/js-utils/promise/promisify';
4
3
  import { Subject } from "rxjs";
5
4
  import { MessageClient } from "../message-client";
6
5
  import { GET_NEW_ID, RESPONSES$, SEND } from "../selectors";
6
+ import { initializer } from "./initializer";
7
+ const WORKER = Symbol('Client Worker');
8
+ const HANDLER = Symbol('Client Message Handler');
9
+ const INSTANCE_ID = Symbol('Client Instance ID');
7
10
  /**
8
11
  * WorkerMessageClient
9
12
  *
@@ -54,12 +57,12 @@ export class WorkerMessageClient extends MessageClient {
54
57
  * Promise resolving to the Worker instance or undefined if running in worker context
55
58
  * @private
56
59
  */
57
- #worker = Promise.resolve(undefined);
60
+ [WORKER] = Promise.resolve(undefined);
58
61
  /**
59
62
  * Unique identifier for this client instance to prevent ID collisions
60
63
  * @private
61
64
  */
62
- #instanceId = Date.now();
65
+ [INSTANCE_ID] = '' + Math.floor(Math.random() * 10000);
63
66
  /**
64
67
  * Observable stream of message responses from the worker or main thread
65
68
  */
@@ -107,30 +110,11 @@ export class WorkerMessageClient extends MessageClient {
107
110
  * };
108
111
  */
109
112
  initialize(worker) {
110
- // Deinitialize previous worker if any
111
- this.#worker.then(prevWorker => {
112
- if (prevWorker) {
113
- prevWorker.removeEventListener('message', this.#handler);
114
- }
115
- else {
116
- removeEventListener('message', this.#handler);
117
- }
118
- }).catch(noop);
119
- // Resolve worker parameter: execute function if provided, otherwise use value directly
120
- const _worker = typeof worker === 'function' ? worker() : worker;
121
- // Ensure worker is wrapped in a promise for consistent async handling
122
- this.#worker = promisify(_worker);
123
- // Set up message listener once worker is resolved
124
- this.#worker.then(worker => {
125
- if (worker) {
126
- // Main thread context: listen to specific worker
127
- worker.addEventListener('message', this.#handler);
128
- }
129
- else {
130
- // Worker thread context: listen to messages from main thread
131
- addEventListener('message', this.#handler);
132
- }
133
- }).catch(noop);
113
+ // Ensure WORKER is initialized if not already
114
+ if (!this[WORKER]) {
115
+ this[WORKER] = Promise.resolve(undefined);
116
+ }
117
+ this[WORKER] = initializer(this[WORKER], worker, this[HANDLER]);
134
118
  }
135
119
  /**
136
120
  * Sends a message to the worker or main thread
@@ -140,7 +124,7 @@ export class WorkerMessageClient extends MessageClient {
140
124
  * @internal Used by @Request decorator
141
125
  */
142
126
  [SEND](message) {
143
- this.#worker.then(worker => {
127
+ this[WORKER].then(worker => {
144
128
  if (worker) {
145
129
  // Main thread: send to worker
146
130
  worker.postMessage(message);
@@ -155,7 +139,7 @@ export class WorkerMessageClient extends MessageClient {
155
139
  * Handles incoming messages and forwards them to the responses stream
156
140
  * @private
157
141
  */
158
- #handler = (event) => {
142
+ [HANDLER] = (event) => {
159
143
  this[RESPONSES$].next(event.data);
160
144
  };
161
145
  /**
@@ -165,7 +149,7 @@ export class WorkerMessageClient extends MessageClient {
165
149
  * @internal Used by @Request decorator
166
150
  */
167
151
  [GET_NEW_ID]() {
168
- return uniqueId('hermes-worker-message-' + this.#instanceId);
152
+ return uniqueId('hermes-worker-message-' + this[INSTANCE_ID]);
169
153
  }
170
154
  }
171
155
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../libs/hermes/src/worker/message-client.ts"],"names":[],"mappings":"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","file":"message-client.js","sourcesContent":["import { uniqueId } from \"@thalesrc/js-utils/unique-id\";\nimport { noop } from \"@thalesrc/js-utils/function/noop\";\nimport { promisify } from '@thalesrc/js-utils/promise/promisify';\nimport { Subject } from \"rxjs\";\nimport { MessageClient } from \"../message-client\";\nimport { MessageResponse } from \"../message-response.type\";\nimport { Message } from \"../message.interface\";\nimport { GET_NEW_ID, RESPONSES$, SEND } from \"../selectors\";\n\ntype ClientWorkerType = Worker | undefined;\ntype ClientWorkerPromise = Promise<ClientWorkerType>;\ntype ClientWorkerFactory = () => ClientWorkerType | ClientWorkerPromise;\ntype ClientWorkerArg = ClientWorkerType | ClientWorkerPromise | ClientWorkerFactory;\n\n/**\n * WorkerMessageClient\n *\n * Client implementation for Web Worker communication. Sends messages to and receives\n * responses from Web Workers using the Worker postMessage API.\n *\n * This class can be used in two contexts:\n * - **Main thread**: Provide a Worker instance to communicate with that specific worker\n * - **Worker thread**: Omit the worker parameter to communicate with the main thread via self\n *\n * The worker parameter supports multiple types for flexibility:\n * - Direct Worker instance\n * - Promise that resolves to a Worker (for async worker initialization)\n * - Function that returns a Worker (for lazy initialization)\n * - Function that returns a Promise<Worker> (for async lazy initialization)\n *\n * The `initialize()` method allows dynamic worker management, enabling you to switch\n * workers at runtime or re-establish connections after errors.\n *\n * @example\n * // In main thread - communicate with a specific worker\n * const worker = new Worker('./worker.js');\n * const client = new WorkerMessageClient(worker);\n *\n * @example\n * // In worker thread - communicate with main thread\n * const client = new WorkerMessageClient();\n *\n * @example\n * // With async worker initialization\n * const workerPromise = import('./worker.js').then(m => new m.MyWorker());\n * const client = new WorkerMessageClient(workerPromise);\n *\n * @example\n * // With lazy initialization\n * const client = new WorkerMessageClient(() =>\n * document.querySelector('[data-worker]') ? new Worker('./worker.js') : undefined\n * );\n *\n * @example\n * // Re-initialize with a different worker\n * const client = new WorkerMessageClient();\n * // Later, switch to a different worker\n * client.initialize(new Worker('./different-worker.js'));\n */\nexport class WorkerMessageClient extends MessageClient {\n /**\n * Promise resolving to the Worker instance or undefined if running in worker context\n * @private\n */\n #worker: ClientWorkerPromise = Promise.resolve(undefined);\n\n /**\n * Unique identifier for this client instance to prevent ID collisions\n * @private\n */\n #instanceId = Date.now();\n\n /**\n * Observable stream of message responses from the worker or main thread\n */\n public [RESPONSES$] = new Subject<MessageResponse>();\n\n /**\n * Creates a new WorkerMessageClient instance\n *\n * @param worker - Optional worker configuration:\n * - Worker: Direct worker instance (main thread)\n * - Promise<Worker>: Promise resolving to worker (async initialization)\n * - () => Worker: Function returning worker (lazy initialization)\n * - () => Promise<Worker>: Function returning promise (async lazy initialization)\n * - undefined: Omit for worker thread context (uses self)\n */\n constructor(worker?: ClientWorkerArg) {\n super();\n\n this.initialize(worker);\n }\n\n /**\n * Initializes or re-initializes the worker connection.\n *\n * This method sets up message listeners for the provided worker. If a worker\n * was previously initialized, it cleans up the old connection before establishing\n * the new one. This allows for dynamic worker management, such as:\n * - Switching between different workers at runtime\n * - Re-establishing connections after worker errors\n * - Lazy initialization when the worker is conditionally needed\n *\n * @param worker - Optional worker configuration:\n * - Worker: Direct worker instance (main thread)\n * - Promise<Worker>: Promise resolving to worker (async initialization)\n * - () => Worker: Function returning worker (lazy initialization)\n * - () => Promise<Worker>: Function returning promise (async lazy initialization)\n * - undefined: Omit for worker thread context (uses self)\n *\n * @example\n * // Switch to a different worker dynamically\n * const client = new WorkerMessageClient(oldWorker);\n * client.initialize(newWorker); // Cleans up old listener, sets up new one\n *\n * @example\n * // Re-initialize after worker error\n * worker.onerror = () => {\n * client.initialize(new Worker('./worker.js'));\n * };\n */\n initialize(worker?: ClientWorkerArg) {\n // Deinitialize previous worker if any\n this.#worker.then(prevWorker => {\n if (prevWorker) {\n prevWorker.removeEventListener('message', this.#handler);\n } else {\n removeEventListener('message', this.#handler);\n }\n }).catch(noop);\n\n // Resolve worker parameter: execute function if provided, otherwise use value directly\n const _worker: ClientWorkerType | ClientWorkerPromise | undefined = typeof worker === 'function' ? worker() : worker;\n // Ensure worker is wrapped in a promise for consistent async handling\n this.#worker = promisify(_worker);\n\n // Set up message listener once worker is resolved\n this.#worker.then(worker => {\n if (worker) {\n // Main thread context: listen to specific worker\n worker.addEventListener('message', this.#handler);\n } else {\n // Worker thread context: listen to messages from main thread\n addEventListener('message', this.#handler);\n }\n }).catch(noop);\n }\n\n /**\n * Sends a message to the worker or main thread\n *\n * @param message - The message to send\n * @template T - Type of the message body\n * @internal Used by @Request decorator\n */\n public [SEND]<T>(message: Message<T>) {\n this.#worker.then(worker => {\n if (worker) {\n // Main thread: send to worker\n worker.postMessage(message);\n } else {\n // Worker thread: send to main thread\n (postMessage as any)(message);\n }\n }).catch(noop);\n }\n\n /**\n * Handles incoming messages and forwards them to the responses stream\n * @private\n */\n #handler = (event: MessageEvent<MessageResponse>) => {\n this[RESPONSES$].next(event.data);\n }\n\n /**\n * Generates a unique message ID for tracking request-response pairs\n *\n * @returns Unique message identifier\n * @internal Used by @Request decorator\n */\n protected [GET_NEW_ID](): string {\n return uniqueId('hermes-worker-message-' + this.#instanceId) as string;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../../../../libs/hermes/src/worker/message-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,kCAAkC,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAwC,WAAW,EAAE,MAAM,eAAe,CAAC;AAElF,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;AACvC,MAAM,OAAO,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AACjD,MAAM,WAAW,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,OAAO,mBAAoB,SAAQ,aAAa;IACpD;;;OAGG;IACK,CAAC,MAAM,CAAC,GAAwB,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEnE;;;OAGG;IACK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC;IAE/D;;OAEG;IACI,CAAC,UAAU,CAAC,GAAG,IAAI,OAAO,EAAmB,CAAC;IAErD;;;;;;;;;OASG;IACH,YAAY,MAAwB;QAClC,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,UAAU,CAAC,MAAwB;QACjC,8CAA8C;QAC9C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,GAAG,WAAW,CACxB,IAAI,CAAC,MAAM,CAAC,EACZ,MAAM,EACN,IAAI,CAAC,OAAO,CAAC,CACd,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,CAAC,IAAI,CAAC,CAAI,OAAmB;QAClC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YACzB,IAAI,MAAM,EAAE,CAAC;gBACX,8BAA8B;gBAC9B,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;iBAAM,CAAC;gBACN,qCAAqC;gBACpC,WAAmB,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;QACH,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IAED;;;OAGG;IACK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAoC,EAAE,EAAE;QAC3D,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC,CAAA;IAED;;;;;OAKG;IACO,CAAC,UAAU,CAAC;QACpB,OAAO,QAAQ,CAAC,wBAAwB,GAAG,IAAI,CAAC,WAAW,CAAC,CAAW,CAAC;IAC1E,CAAC;CACF","file":"message-client.js","sourcesContent":["import { uniqueId } from \"@thalesrc/js-utils/unique-id\";\nimport { noop } from \"@thalesrc/js-utils/function/noop\";\nimport { Subject } from \"rxjs\";\nimport { MessageClient } from \"../message-client\";\nimport { MessageResponse } from \"../message-response.type\";\nimport { Message } from \"../message.interface\";\nimport { GET_NEW_ID, RESPONSES$, SEND } from \"../selectors\";\nimport { ClientWorkerArg, ClientWorkerPromise, initializer } from \"./initializer\";\n\nconst WORKER = Symbol('Client Worker');\nconst HANDLER = Symbol('Client Message Handler');\nconst INSTANCE_ID = Symbol('Client Instance ID');\n\n/**\n * WorkerMessageClient\n *\n * Client implementation for Web Worker communication. Sends messages to and receives\n * responses from Web Workers using the Worker postMessage API.\n *\n * This class can be used in two contexts:\n * - **Main thread**: Provide a Worker instance to communicate with that specific worker\n * - **Worker thread**: Omit the worker parameter to communicate with the main thread via self\n *\n * The worker parameter supports multiple types for flexibility:\n * - Direct Worker instance\n * - Promise that resolves to a Worker (for async worker initialization)\n * - Function that returns a Worker (for lazy initialization)\n * - Function that returns a Promise<Worker> (for async lazy initialization)\n *\n * The `initialize()` method allows dynamic worker management, enabling you to switch\n * workers at runtime or re-establish connections after errors.\n *\n * @example\n * // In main thread - communicate with a specific worker\n * const worker = new Worker('./worker.js');\n * const client = new WorkerMessageClient(worker);\n *\n * @example\n * // In worker thread - communicate with main thread\n * const client = new WorkerMessageClient();\n *\n * @example\n * // With async worker initialization\n * const workerPromise = import('./worker.js').then(m => new m.MyWorker());\n * const client = new WorkerMessageClient(workerPromise);\n *\n * @example\n * // With lazy initialization\n * const client = new WorkerMessageClient(() =>\n * document.querySelector('[data-worker]') ? new Worker('./worker.js') : undefined\n * );\n *\n * @example\n * // Re-initialize with a different worker\n * const client = new WorkerMessageClient();\n * // Later, switch to a different worker\n * client.initialize(new Worker('./different-worker.js'));\n */\nexport class WorkerMessageClient extends MessageClient {\n /**\n * Promise resolving to the Worker instance or undefined if running in worker context\n * @private\n */\n private [WORKER]: ClientWorkerPromise = Promise.resolve(undefined);\n\n /**\n * Unique identifier for this client instance to prevent ID collisions\n * @private\n */\n private [INSTANCE_ID] = '' + Math.floor(Math.random() * 10000);\n\n /**\n * Observable stream of message responses from the worker or main thread\n */\n public [RESPONSES$] = new Subject<MessageResponse>();\n\n /**\n * Creates a new WorkerMessageClient instance\n *\n * @param worker - Optional worker configuration:\n * - Worker: Direct worker instance (main thread)\n * - Promise<Worker>: Promise resolving to worker (async initialization)\n * - () => Worker: Function returning worker (lazy initialization)\n * - () => Promise<Worker>: Function returning promise (async lazy initialization)\n * - undefined: Omit for worker thread context (uses self)\n */\n constructor(worker?: ClientWorkerArg) {\n super();\n\n this.initialize(worker);\n }\n\n /**\n * Initializes or re-initializes the worker connection.\n *\n * This method sets up message listeners for the provided worker. If a worker\n * was previously initialized, it cleans up the old connection before establishing\n * the new one. This allows for dynamic worker management, such as:\n * - Switching between different workers at runtime\n * - Re-establishing connections after worker errors\n * - Lazy initialization when the worker is conditionally needed\n *\n * @param worker - Optional worker configuration:\n * - Worker: Direct worker instance (main thread)\n * - Promise<Worker>: Promise resolving to worker (async initialization)\n * - () => Worker: Function returning worker (lazy initialization)\n * - () => Promise<Worker>: Function returning promise (async lazy initialization)\n * - undefined: Omit for worker thread context (uses self)\n *\n * @example\n * // Switch to a different worker dynamically\n * const client = new WorkerMessageClient(oldWorker);\n * client.initialize(newWorker); // Cleans up old listener, sets up new one\n *\n * @example\n * // Re-initialize after worker error\n * worker.onerror = () => {\n * client.initialize(new Worker('./worker.js'));\n * };\n */\n initialize(worker?: ClientWorkerArg) {\n // Ensure WORKER is initialized if not already\n if (!this[WORKER]) {\n this[WORKER] = Promise.resolve(undefined);\n }\n\n this[WORKER] = initializer(\n this[WORKER],\n worker,\n this[HANDLER]\n );\n }\n\n /**\n * Sends a message to the worker or main thread\n *\n * @param message - The message to send\n * @template T - Type of the message body\n * @internal Used by @Request decorator\n */\n public [SEND]<T>(message: Message<T>) {\n this[WORKER].then(worker => {\n if (worker) {\n // Main thread: send to worker\n worker.postMessage(message);\n } else {\n // Worker thread: send to main thread\n (postMessage as any)(message);\n }\n }).catch(noop);\n }\n\n /**\n * Handles incoming messages and forwards them to the responses stream\n * @private\n */\n private [HANDLER] = (event: MessageEvent<MessageResponse>) => {\n this[RESPONSES$].next(event.data);\n }\n\n /**\n * Generates a unique message ID for tracking request-response pairs\n *\n * @returns Unique message identifier\n * @internal Used by @Request decorator\n */\n protected [GET_NEW_ID](): string {\n return uniqueId('hermes-worker-message-' + this[INSTANCE_ID]) as string;\n }\n}\n"]}
@@ -4,38 +4,162 @@ exports.WorkerMessageHost = void 0;
4
4
  const rxjs_1 = require("rxjs");
5
5
  const message_host_1 = require("../message-host");
6
6
  const selectors_1 = require("../selectors");
7
+ const initializer_1 = require("./initializer");
8
+ const noop_1 = require("@thalesrc/js-utils/function/noop");
9
+ const WORKER = Symbol('Host Worker');
10
+ const HANDLER = Symbol('Host Message Handler');
11
+ const REQUESTS$ = Symbol('Host Requests Stream');
12
+ /**
13
+ * WorkerMessageHost
14
+ *
15
+ * Host implementation for Web Worker communication. Receives messages from and sends
16
+ * responses to Web Workers using the Worker postMessage API.
17
+ *
18
+ * This class can be used in two contexts:
19
+ * - **Main thread**: Provide a Worker instance to receive messages from that specific worker
20
+ * - **Worker thread**: Omit the worker parameter to receive messages from the main thread via self
21
+ *
22
+ * The worker parameter supports multiple types for flexibility:
23
+ * - Direct Worker instance
24
+ * - Promise that resolves to a Worker (for async worker initialization)
25
+ * - Function that returns a Worker (for lazy initialization)
26
+ * - Function that returns a Promise<Worker> (for async lazy initialization)
27
+ *
28
+ * The `initialize()` method allows dynamic worker management, enabling you to switch
29
+ * workers at runtime or re-establish connections after errors.
30
+ *
31
+ * @example
32
+ * // In main thread - receive messages from a specific worker
33
+ * const worker = new Worker('./worker.js');
34
+ * const host = new WorkerMessageHost(worker);
35
+ *
36
+ * @example
37
+ * // In worker thread - receive messages from main thread
38
+ * const host = new WorkerMessageHost();
39
+ *
40
+ * @example
41
+ * // With async worker initialization
42
+ * const workerPromise = import('./worker.js').then(m => new m.MyWorker());
43
+ * const host = new WorkerMessageHost(workerPromise);
44
+ *
45
+ * @example
46
+ * // With lazy initialization
47
+ * const host = new WorkerMessageHost(() =>
48
+ * document.querySelector('[data-worker]') ? new Worker('./worker.js') : undefined
49
+ * );
50
+ *
51
+ * @example
52
+ * // Re-initialize with a different worker
53
+ * const host = new WorkerMessageHost();
54
+ * // Later, switch to a different worker
55
+ * host.initialize(new Worker('./different-worker.js'));
56
+ */
7
57
  class WorkerMessageHost extends message_host_1.MessageHost {
8
- #requests$ = new rxjs_1.Subject();
9
- #worker;
58
+ /**
59
+ * Observable stream of incoming messages from the worker or main thread
60
+ * @private
61
+ */
62
+ [REQUESTS$] = new rxjs_1.Subject();
63
+ /**
64
+ * Promise resolving to the Worker instance or undefined if running in worker context
65
+ * @private
66
+ */
67
+ [WORKER] = Promise.resolve(undefined);
68
+ /**
69
+ * Creates a new WorkerMessageHost instance
70
+ *
71
+ * @param worker - Optional worker configuration:
72
+ * - Worker: Direct worker instance (main thread)
73
+ * - Promise<Worker>: Promise resolving to worker (async initialization)
74
+ * - () => Worker: Function returning worker (lazy initialization)
75
+ * - () => Promise<Worker>: Function returning promise (async lazy initialization)
76
+ * - undefined: Omit for worker thread context (uses self)
77
+ */
10
78
  constructor(worker) {
11
79
  super();
12
- if (worker) {
13
- this.#worker = worker;
14
- worker.addEventListener('message', this.#handler);
15
- }
16
- else {
17
- addEventListener('message', this.#handler);
80
+ this.initialize(worker);
81
+ this[selectors_1.LISTEN](this[REQUESTS$]);
82
+ }
83
+ /**
84
+ * Initializes or re-initializes the worker connection.
85
+ *
86
+ * This method sets up message listeners for the provided worker. If a worker
87
+ * was previously initialized, it cleans up the old connection before establishing
88
+ * the new one. This allows for dynamic worker management, such as:
89
+ * - Switching between different workers at runtime
90
+ * - Re-establishing connections after worker errors
91
+ * - Lazy initialization when the worker is conditionally needed
92
+ *
93
+ * @param worker - Optional worker configuration:
94
+ * - Worker: Direct worker instance (main thread)
95
+ * - Promise<Worker>: Promise resolving to worker (async initialization)
96
+ * - () => Worker: Function returning worker (lazy initialization)
97
+ * - () => Promise<Worker>: Function returning promise (async lazy initialization)
98
+ * - undefined: Omit for worker thread context (uses self)
99
+ *
100
+ * @example
101
+ * // Switch to a different worker dynamically
102
+ * const host = new WorkerMessageHost(oldWorker);
103
+ * host.initialize(newWorker); // Cleans up old listener, sets up new one
104
+ *
105
+ * @example
106
+ * // Re-initialize after worker error
107
+ * worker.onerror = () => {
108
+ * host.initialize(new Worker('./worker.js'));
109
+ * };
110
+ */
111
+ initialize(worker) {
112
+ // Ensure WORKER is initialized if not already
113
+ if (!this[WORKER]) {
114
+ this[WORKER] = Promise.resolve(undefined);
18
115
  }
19
- this[selectors_1.LISTEN](this.#requests$);
116
+ this[WORKER] = (0, initializer_1.initializer)(this[WORKER], worker, this[HANDLER]);
20
117
  }
118
+ /**
119
+ * Sends a response message back to the worker or main thread
120
+ *
121
+ * @param message - The response message to send
122
+ * @internal Used by the message handling system to send responses
123
+ */
21
124
  [selectors_1.RESPONSE](message) {
22
- if (this.#worker) {
23
- this.#worker.postMessage(message);
24
- }
25
- else {
26
- postMessage(message);
27
- }
125
+ this[WORKER].then(worker => {
126
+ if (worker) {
127
+ worker.postMessage(message);
128
+ }
129
+ else {
130
+ postMessage(message);
131
+ }
132
+ }).catch(noop_1.noop);
28
133
  }
134
+ /**
135
+ * Terminates the worker connection and cleans up message listeners.
136
+ *
137
+ * This method should be called when you're done with the host to prevent memory leaks.
138
+ * It removes the message event listener from either the Worker instance (main thread)
139
+ * or the global scope (worker thread).
140
+ *
141
+ * @example
142
+ * // Clean up when done
143
+ * const host = new WorkerMessageHost(worker);
144
+ * // ... use the host ...
145
+ * host.terminate(); // Clean up listeners
146
+ */
29
147
  terminate() {
30
- if (this.#worker) {
31
- this.#worker.removeEventListener('message', this.#handler);
32
- }
33
- else {
34
- removeEventListener('message', this.#handler);
35
- }
148
+ this[WORKER].then(worker => {
149
+ if (worker) {
150
+ worker.removeEventListener('message', this[HANDLER]);
151
+ }
152
+ else {
153
+ removeEventListener('message', this[HANDLER]);
154
+ }
155
+ }).catch(noop_1.noop);
36
156
  }
37
- #handler = (event) => {
38
- this.#requests$.next(event.data);
157
+ /**
158
+ * Handles incoming messages and forwards them to the requests stream
159
+ * @private
160
+ */
161
+ [HANDLER] = (event) => {
162
+ this[REQUESTS$].next(event.data);
39
163
  };
40
164
  }
41
165
  exports.WorkerMessageHost = WorkerMessageHost;
@@ -1,9 +1,131 @@
1
1
  import { MessageHost } from "../message-host";
2
2
  import { MessageResponse } from "../message-response.type";
3
3
  import { RESPONSE } from "../selectors";
4
+ import { ClientWorkerArg } from "./initializer";
5
+ declare const WORKER: unique symbol;
6
+ declare const HANDLER: unique symbol;
7
+ declare const REQUESTS$: unique symbol;
8
+ /**
9
+ * WorkerMessageHost
10
+ *
11
+ * Host implementation for Web Worker communication. Receives messages from and sends
12
+ * responses to Web Workers using the Worker postMessage API.
13
+ *
14
+ * This class can be used in two contexts:
15
+ * - **Main thread**: Provide a Worker instance to receive messages from that specific worker
16
+ * - **Worker thread**: Omit the worker parameter to receive messages from the main thread via self
17
+ *
18
+ * The worker parameter supports multiple types for flexibility:
19
+ * - Direct Worker instance
20
+ * - Promise that resolves to a Worker (for async worker initialization)
21
+ * - Function that returns a Worker (for lazy initialization)
22
+ * - Function that returns a Promise<Worker> (for async lazy initialization)
23
+ *
24
+ * The `initialize()` method allows dynamic worker management, enabling you to switch
25
+ * workers at runtime or re-establish connections after errors.
26
+ *
27
+ * @example
28
+ * // In main thread - receive messages from a specific worker
29
+ * const worker = new Worker('./worker.js');
30
+ * const host = new WorkerMessageHost(worker);
31
+ *
32
+ * @example
33
+ * // In worker thread - receive messages from main thread
34
+ * const host = new WorkerMessageHost();
35
+ *
36
+ * @example
37
+ * // With async worker initialization
38
+ * const workerPromise = import('./worker.js').then(m => new m.MyWorker());
39
+ * const host = new WorkerMessageHost(workerPromise);
40
+ *
41
+ * @example
42
+ * // With lazy initialization
43
+ * const host = new WorkerMessageHost(() =>
44
+ * document.querySelector('[data-worker]') ? new Worker('./worker.js') : undefined
45
+ * );
46
+ *
47
+ * @example
48
+ * // Re-initialize with a different worker
49
+ * const host = new WorkerMessageHost();
50
+ * // Later, switch to a different worker
51
+ * host.initialize(new Worker('./different-worker.js'));
52
+ */
4
53
  export declare class WorkerMessageHost extends MessageHost {
5
- #private;
54
+ /**
55
+ * Observable stream of incoming messages from the worker or main thread
56
+ * @private
57
+ */
58
+ private [REQUESTS$];
59
+ /**
60
+ * Promise resolving to the Worker instance or undefined if running in worker context
61
+ * @private
62
+ */
63
+ private [WORKER];
64
+ /**
65
+ * Creates a new WorkerMessageHost instance
66
+ *
67
+ * @param worker - Optional worker configuration:
68
+ * - Worker: Direct worker instance (main thread)
69
+ * - Promise<Worker>: Promise resolving to worker (async initialization)
70
+ * - () => Worker: Function returning worker (lazy initialization)
71
+ * - () => Promise<Worker>: Function returning promise (async lazy initialization)
72
+ * - undefined: Omit for worker thread context (uses self)
73
+ */
6
74
  constructor(worker?: Worker);
75
+ /**
76
+ * Initializes or re-initializes the worker connection.
77
+ *
78
+ * This method sets up message listeners for the provided worker. If a worker
79
+ * was previously initialized, it cleans up the old connection before establishing
80
+ * the new one. This allows for dynamic worker management, such as:
81
+ * - Switching between different workers at runtime
82
+ * - Re-establishing connections after worker errors
83
+ * - Lazy initialization when the worker is conditionally needed
84
+ *
85
+ * @param worker - Optional worker configuration:
86
+ * - Worker: Direct worker instance (main thread)
87
+ * - Promise<Worker>: Promise resolving to worker (async initialization)
88
+ * - () => Worker: Function returning worker (lazy initialization)
89
+ * - () => Promise<Worker>: Function returning promise (async lazy initialization)
90
+ * - undefined: Omit for worker thread context (uses self)
91
+ *
92
+ * @example
93
+ * // Switch to a different worker dynamically
94
+ * const host = new WorkerMessageHost(oldWorker);
95
+ * host.initialize(newWorker); // Cleans up old listener, sets up new one
96
+ *
97
+ * @example
98
+ * // Re-initialize after worker error
99
+ * worker.onerror = () => {
100
+ * host.initialize(new Worker('./worker.js'));
101
+ * };
102
+ */
103
+ initialize(worker: ClientWorkerArg): void;
104
+ /**
105
+ * Sends a response message back to the worker or main thread
106
+ *
107
+ * @param message - The response message to send
108
+ * @internal Used by the message handling system to send responses
109
+ */
7
110
  protected [RESPONSE](message: MessageResponse): void;
111
+ /**
112
+ * Terminates the worker connection and cleans up message listeners.
113
+ *
114
+ * This method should be called when you're done with the host to prevent memory leaks.
115
+ * It removes the message event listener from either the Worker instance (main thread)
116
+ * or the global scope (worker thread).
117
+ *
118
+ * @example
119
+ * // Clean up when done
120
+ * const host = new WorkerMessageHost(worker);
121
+ * // ... use the host ...
122
+ * host.terminate(); // Clean up listeners
123
+ */
8
124
  terminate(): void;
125
+ /**
126
+ * Handles incoming messages and forwards them to the requests stream
127
+ * @private
128
+ */
129
+ private [HANDLER];
9
130
  }
131
+ export {};
@@ -1,38 +1,162 @@
1
1
  import { Subject } from "rxjs";
2
2
  import { MessageHost } from "../message-host";
3
3
  import { LISTEN, RESPONSE } from "../selectors";
4
+ import { initializer } from "./initializer";
5
+ import { noop } from "@thalesrc/js-utils/function/noop";
6
+ const WORKER = Symbol('Host Worker');
7
+ const HANDLER = Symbol('Host Message Handler');
8
+ const REQUESTS$ = Symbol('Host Requests Stream');
9
+ /**
10
+ * WorkerMessageHost
11
+ *
12
+ * Host implementation for Web Worker communication. Receives messages from and sends
13
+ * responses to Web Workers using the Worker postMessage API.
14
+ *
15
+ * This class can be used in two contexts:
16
+ * - **Main thread**: Provide a Worker instance to receive messages from that specific worker
17
+ * - **Worker thread**: Omit the worker parameter to receive messages from the main thread via self
18
+ *
19
+ * The worker parameter supports multiple types for flexibility:
20
+ * - Direct Worker instance
21
+ * - Promise that resolves to a Worker (for async worker initialization)
22
+ * - Function that returns a Worker (for lazy initialization)
23
+ * - Function that returns a Promise<Worker> (for async lazy initialization)
24
+ *
25
+ * The `initialize()` method allows dynamic worker management, enabling you to switch
26
+ * workers at runtime or re-establish connections after errors.
27
+ *
28
+ * @example
29
+ * // In main thread - receive messages from a specific worker
30
+ * const worker = new Worker('./worker.js');
31
+ * const host = new WorkerMessageHost(worker);
32
+ *
33
+ * @example
34
+ * // In worker thread - receive messages from main thread
35
+ * const host = new WorkerMessageHost();
36
+ *
37
+ * @example
38
+ * // With async worker initialization
39
+ * const workerPromise = import('./worker.js').then(m => new m.MyWorker());
40
+ * const host = new WorkerMessageHost(workerPromise);
41
+ *
42
+ * @example
43
+ * // With lazy initialization
44
+ * const host = new WorkerMessageHost(() =>
45
+ * document.querySelector('[data-worker]') ? new Worker('./worker.js') : undefined
46
+ * );
47
+ *
48
+ * @example
49
+ * // Re-initialize with a different worker
50
+ * const host = new WorkerMessageHost();
51
+ * // Later, switch to a different worker
52
+ * host.initialize(new Worker('./different-worker.js'));
53
+ */
4
54
  export class WorkerMessageHost extends MessageHost {
5
- #requests$ = new Subject();
6
- #worker;
55
+ /**
56
+ * Observable stream of incoming messages from the worker or main thread
57
+ * @private
58
+ */
59
+ [REQUESTS$] = new Subject();
60
+ /**
61
+ * Promise resolving to the Worker instance or undefined if running in worker context
62
+ * @private
63
+ */
64
+ [WORKER] = Promise.resolve(undefined);
65
+ /**
66
+ * Creates a new WorkerMessageHost instance
67
+ *
68
+ * @param worker - Optional worker configuration:
69
+ * - Worker: Direct worker instance (main thread)
70
+ * - Promise<Worker>: Promise resolving to worker (async initialization)
71
+ * - () => Worker: Function returning worker (lazy initialization)
72
+ * - () => Promise<Worker>: Function returning promise (async lazy initialization)
73
+ * - undefined: Omit for worker thread context (uses self)
74
+ */
7
75
  constructor(worker) {
8
76
  super();
9
- if (worker) {
10
- this.#worker = worker;
11
- worker.addEventListener('message', this.#handler);
12
- }
13
- else {
14
- addEventListener('message', this.#handler);
77
+ this.initialize(worker);
78
+ this[LISTEN](this[REQUESTS$]);
79
+ }
80
+ /**
81
+ * Initializes or re-initializes the worker connection.
82
+ *
83
+ * This method sets up message listeners for the provided worker. If a worker
84
+ * was previously initialized, it cleans up the old connection before establishing
85
+ * the new one. This allows for dynamic worker management, such as:
86
+ * - Switching between different workers at runtime
87
+ * - Re-establishing connections after worker errors
88
+ * - Lazy initialization when the worker is conditionally needed
89
+ *
90
+ * @param worker - Optional worker configuration:
91
+ * - Worker: Direct worker instance (main thread)
92
+ * - Promise<Worker>: Promise resolving to worker (async initialization)
93
+ * - () => Worker: Function returning worker (lazy initialization)
94
+ * - () => Promise<Worker>: Function returning promise (async lazy initialization)
95
+ * - undefined: Omit for worker thread context (uses self)
96
+ *
97
+ * @example
98
+ * // Switch to a different worker dynamically
99
+ * const host = new WorkerMessageHost(oldWorker);
100
+ * host.initialize(newWorker); // Cleans up old listener, sets up new one
101
+ *
102
+ * @example
103
+ * // Re-initialize after worker error
104
+ * worker.onerror = () => {
105
+ * host.initialize(new Worker('./worker.js'));
106
+ * };
107
+ */
108
+ initialize(worker) {
109
+ // Ensure WORKER is initialized if not already
110
+ if (!this[WORKER]) {
111
+ this[WORKER] = Promise.resolve(undefined);
15
112
  }
16
- this[LISTEN](this.#requests$);
113
+ this[WORKER] = initializer(this[WORKER], worker, this[HANDLER]);
17
114
  }
115
+ /**
116
+ * Sends a response message back to the worker or main thread
117
+ *
118
+ * @param message - The response message to send
119
+ * @internal Used by the message handling system to send responses
120
+ */
18
121
  [RESPONSE](message) {
19
- if (this.#worker) {
20
- this.#worker.postMessage(message);
21
- }
22
- else {
23
- postMessage(message);
24
- }
122
+ this[WORKER].then(worker => {
123
+ if (worker) {
124
+ worker.postMessage(message);
125
+ }
126
+ else {
127
+ postMessage(message);
128
+ }
129
+ }).catch(noop);
25
130
  }
131
+ /**
132
+ * Terminates the worker connection and cleans up message listeners.
133
+ *
134
+ * This method should be called when you're done with the host to prevent memory leaks.
135
+ * It removes the message event listener from either the Worker instance (main thread)
136
+ * or the global scope (worker thread).
137
+ *
138
+ * @example
139
+ * // Clean up when done
140
+ * const host = new WorkerMessageHost(worker);
141
+ * // ... use the host ...
142
+ * host.terminate(); // Clean up listeners
143
+ */
26
144
  terminate() {
27
- if (this.#worker) {
28
- this.#worker.removeEventListener('message', this.#handler);
29
- }
30
- else {
31
- removeEventListener('message', this.#handler);
32
- }
145
+ this[WORKER].then(worker => {
146
+ if (worker) {
147
+ worker.removeEventListener('message', this[HANDLER]);
148
+ }
149
+ else {
150
+ removeEventListener('message', this[HANDLER]);
151
+ }
152
+ }).catch(noop);
33
153
  }
34
- #handler = (event) => {
35
- this.#requests$.next(event.data);
154
+ /**
155
+ * Handles incoming messages and forwards them to the requests stream
156
+ * @private
157
+ */
158
+ [HANDLER] = (event) => {
159
+ this[REQUESTS$].next(event.data);
36
160
  };
37
161
  }
38
162