@electron-stagewright/host-supervisor 0.0.0-stage → 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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +253 -2
  3. package/dist/contract.d.ts +52 -0
  4. package/dist/contract.d.ts.map +1 -0
  5. package/dist/contract.js +2 -0
  6. package/dist/contract.js.map +1 -0
  7. package/dist/env.d.ts +9 -0
  8. package/dist/env.d.ts.map +1 -0
  9. package/dist/env.js +30 -0
  10. package/dist/env.js.map +1 -0
  11. package/dist/errors.d.ts +11 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +38 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/host.d.ts +129 -0
  16. package/dist/host.d.ts.map +1 -0
  17. package/dist/host.js +907 -0
  18. package/dist/host.js.map +1 -0
  19. package/dist/in-process.d.ts +8 -0
  20. package/dist/in-process.d.ts.map +1 -0
  21. package/dist/in-process.js +60 -0
  22. package/dist/in-process.js.map +1 -0
  23. package/dist/index.d.ts +15 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +14 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/policy.d.ts +34 -0
  28. package/dist/policy.d.ts.map +1 -0
  29. package/dist/policy.js +46 -0
  30. package/dist/policy.js.map +1 -0
  31. package/dist/protocol.d.ts +94 -0
  32. package/dist/protocol.d.ts.map +1 -0
  33. package/dist/protocol.js +111 -0
  34. package/dist/protocol.js.map +1 -0
  35. package/dist/serve.d.ts +42 -0
  36. package/dist/serve.d.ts.map +1 -0
  37. package/dist/serve.js +287 -0
  38. package/dist/serve.js.map +1 -0
  39. package/dist/utility.d.ts +46 -0
  40. package/dist/utility.d.ts.map +1 -0
  41. package/dist/utility.js +50 -0
  42. package/dist/utility.js.map +1 -0
  43. package/dist/worker.d.ts +31 -0
  44. package/dist/worker.d.ts.map +1 -0
  45. package/dist/worker.js +50 -0
  46. package/dist/worker.js.map +1 -0
  47. package/package.json +56 -3
package/dist/serve.js ADDED
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Host side: answers the supervisor from a worker thread or a utility process. Never imports
3
+ * Electron, so the same entry runs under Node.
4
+ */
5
+ import { performance } from 'node:perf_hooks';
6
+ import { getHeapStatistics } from 'node:v8';
7
+ import { parentPort } from 'node:worker_threads';
8
+ import { PROTOCOL_VERSION, parseSupervisorMessage, serializeError, } from './protocol.js';
9
+ /** The port this host was started with, or null outside a worker or utility process. */
10
+ export function defaultHostPort() {
11
+ const electronPort = process.parentPort;
12
+ if (electronPort) {
13
+ return {
14
+ post: (message) => electronPort.postMessage(message),
15
+ onMessage: (listener) => void electronPort.on('message', (event) => listener(event.data)),
16
+ // A utility process stays alive while its parent port listens. The delay lets the stop
17
+ // reply leave first; the supervisor terminates a host that lingers after it.
18
+ close: () => void setTimeout(() => process.exit(0), 50),
19
+ };
20
+ }
21
+ const port = parentPort;
22
+ if (port) {
23
+ return {
24
+ post: (message) => port.postMessage(message),
25
+ onMessage: (listener) => void port.on('message', listener),
26
+ close: () => port.close(),
27
+ };
28
+ }
29
+ return null;
30
+ }
31
+ const toMb = (bytes) => Math.round((bytes / 1_048_576) * 10) / 10;
32
+ function rejected(message, code) {
33
+ return { name: 'HostError', message, code };
34
+ }
35
+ /** A handler's error never crosses as `HostError`, so it cannot pass for the supervisor's own. */
36
+ function handlerError(error, options) {
37
+ const serialized = serializeError(error, options);
38
+ return serialized.name === 'HostError' ? { ...serialized, name: 'Error' } : serialized;
39
+ }
40
+ function withoutData(message) {
41
+ if (!('error' in message) || message.error?.data === undefined)
42
+ return null;
43
+ const { name, message: text, code } = message.error;
44
+ return { ...message, error: { name, message: text, ...(code ? { code } : {}) } };
45
+ }
46
+ /** Serves one host until the supervisor sends `stop`. */
47
+ export function serveHost(options) {
48
+ const found = options.port ?? defaultHostPort();
49
+ if (!found)
50
+ throw new Error('serveHost must run in a worker thread or a utility process');
51
+ const port = found;
52
+ const callOps = new Set(options.operations);
53
+ const streamOps = new Set(options.streams ?? []);
54
+ let handlers = null;
55
+ let starting = null;
56
+ let accepting = true;
57
+ let statsTimer = null;
58
+ const inflight = new Set();
59
+ const controllers = new Map();
60
+ const streams = new Map();
61
+ /** An error whose detail cannot be cloned still crosses, without the detail. */
62
+ const post = (message) => {
63
+ try {
64
+ port.post(message);
65
+ }
66
+ catch (error) {
67
+ const fallback = withoutData(message);
68
+ if (!fallback)
69
+ throw error;
70
+ port.post(fallback);
71
+ }
72
+ };
73
+ const failure = (error) => handlerError(error, options.errors);
74
+ function track(work) {
75
+ inflight.add(work);
76
+ void work.finally(() => inflight.delete(work));
77
+ }
78
+ /** A value that cannot be cloned still answers its call. */
79
+ function answer(id, message) {
80
+ try {
81
+ post(message);
82
+ }
83
+ catch (error) {
84
+ post({ type: 'result', id, ok: false, error: failure(error) });
85
+ }
86
+ }
87
+ let lastElu = performance.eventLoopUtilization();
88
+ const heapLimitMb = toMb(getHeapStatistics().heap_size_limit);
89
+ function postStats() {
90
+ const memory = process.memoryUsage();
91
+ const elu = performance.eventLoopUtilization(lastElu);
92
+ lastElu = performance.eventLoopUtilization();
93
+ post({
94
+ type: 'stats',
95
+ stats: {
96
+ rssMb: toMb(memory.rss),
97
+ heapUsedMb: toMb(memory.heapUsed),
98
+ heapLimitMb,
99
+ externalMb: toMb(memory.external + memory.arrayBuffers),
100
+ eventLoopUtilization: Math.round(elu.utilization * 1000) / 1000,
101
+ },
102
+ });
103
+ }
104
+ async function start(version, payload) {
105
+ try {
106
+ if (version !== PROTOCOL_VERSION) {
107
+ throw new Error(`The host speaks protocol ${PROTOCOL_VERSION}, not ${version}`);
108
+ }
109
+ let info;
110
+ let hasInfo = false;
111
+ let settled = false;
112
+ const context = {
113
+ setInfo: (value) => {
114
+ if (settled)
115
+ throw new Error('setInfo must be called before start resolves');
116
+ info = value;
117
+ hasInfo = true;
118
+ },
119
+ };
120
+ const served = (await options.start(payload, context));
121
+ for (const op of [...callOps, ...streamOps]) {
122
+ if (typeof served[op] !== 'function')
123
+ throw new Error(`No handler for ${op}`);
124
+ }
125
+ settled = true;
126
+ try {
127
+ post(hasInfo ? { type: 'started', info } : { type: 'started' });
128
+ }
129
+ catch (error) {
130
+ throw new Error('setInfo received a value that cannot be cloned', { cause: error });
131
+ }
132
+ handlers = served;
133
+ if (options.statsIntervalMs !== undefined) {
134
+ postStats();
135
+ statsTimer = setInterval(postStats, options.statsIntervalMs);
136
+ statsTimer.unref();
137
+ }
138
+ }
139
+ catch (error) {
140
+ post({ type: 'start-failed', error: failure(error) });
141
+ }
142
+ }
143
+ function call(id, op, args, stream) {
144
+ const served = handlers;
145
+ if (!served || !accepting) {
146
+ post({
147
+ type: 'result',
148
+ id,
149
+ ok: false,
150
+ error: rejected('The host is not serving', 'HOST_STOPPED'),
151
+ });
152
+ return;
153
+ }
154
+ if (!(stream ? streamOps : callOps).has(op)) {
155
+ post({
156
+ type: 'result',
157
+ id,
158
+ ok: false,
159
+ error: rejected(`${op} is not an operation of this host`, 'HOST_OPERATION_REJECTED'),
160
+ });
161
+ return;
162
+ }
163
+ const controller = new AbortController();
164
+ const context = { signal: controller.signal };
165
+ const handler = served[op];
166
+ if (stream) {
167
+ try {
168
+ const iterable = handler.apply(served, [...args, context]);
169
+ const iterator = Symbol.asyncIterator in iterable
170
+ ? iterable[Symbol.asyncIterator]()
171
+ : iterable[Symbol.iterator]();
172
+ streams.set(id, { iterator, controller });
173
+ }
174
+ catch (error) {
175
+ post({ type: 'result', id, ok: false, error: failure(error) });
176
+ }
177
+ return;
178
+ }
179
+ controllers.set(id, controller);
180
+ track(Promise.resolve()
181
+ .then(() => handler.apply(served, [...args, context]))
182
+ .then((value) => answer(id, { type: 'result', id, ok: true, value }), (error) => post({ type: 'result', id, ok: false, error: failure(error) }))
183
+ .finally(() => controllers.delete(id)));
184
+ }
185
+ function next(id) {
186
+ const open = streams.get(id);
187
+ if (!open) {
188
+ post({
189
+ type: 'result',
190
+ id,
191
+ ok: false,
192
+ error: rejected('The stream is not open', 'HOST_STOPPED'),
193
+ });
194
+ return;
195
+ }
196
+ track(Promise.resolve()
197
+ .then(() => open.iterator.next())
198
+ .then((result) => {
199
+ if (result.done) {
200
+ streams.delete(id);
201
+ post({ type: 'item', id, done: true });
202
+ }
203
+ else {
204
+ try {
205
+ post({ type: 'item', id, done: false, value: result.value });
206
+ }
207
+ catch (error) {
208
+ // An item that cannot be cloned ends the stream and frees its producer.
209
+ cancel(id);
210
+ post({ type: 'result', id, ok: false, error: failure(error) });
211
+ }
212
+ }
213
+ }, (error) => {
214
+ streams.delete(id);
215
+ post({ type: 'result', id, ok: false, error: failure(error) });
216
+ }));
217
+ }
218
+ function cancel(id) {
219
+ controllers.get(id)?.abort();
220
+ const open = streams.get(id);
221
+ if (!open)
222
+ return;
223
+ streams.delete(id);
224
+ open.controller.abort();
225
+ track(Promise.resolve()
226
+ .then(() => open.iterator.return?.())
227
+ .then(() => undefined, () => undefined));
228
+ }
229
+ async function stop() {
230
+ // Close admission before yielding, so a later message cannot reach a closing resource.
231
+ accepting = false;
232
+ let stopFailure = null;
233
+ try {
234
+ await starting;
235
+ for (const id of [...streams.keys()])
236
+ cancel(id);
237
+ while (inflight.size > 0)
238
+ await Promise.allSettled([...inflight]);
239
+ await options.stop?.();
240
+ }
241
+ catch (error) {
242
+ stopFailure = error;
243
+ }
244
+ handlers = null;
245
+ if (statsTimer)
246
+ clearInterval(statsTimer);
247
+ post(stopFailure ? { type: 'stopped', error: failure(stopFailure) } : { type: 'stopped' });
248
+ port.close();
249
+ }
250
+ if (options.reportCrashes !== false) {
251
+ process.on('uncaughtExceptionMonitor', (error) => {
252
+ try {
253
+ post({ type: 'crashed', error: failure(error) });
254
+ }
255
+ catch {
256
+ // The host is ending either way.
257
+ }
258
+ });
259
+ }
260
+ let stopped = false;
261
+ port.onMessage((raw) => {
262
+ const message = parseSupervisorMessage(raw);
263
+ if (!message)
264
+ return;
265
+ switch (message.type) {
266
+ case 'start':
267
+ starting ??= start(message.version, message.payload);
268
+ return;
269
+ case 'call':
270
+ call(message.id, message.op, message.args, message.stream === true);
271
+ return;
272
+ case 'next':
273
+ next(message.id);
274
+ return;
275
+ case 'cancel':
276
+ cancel(message.id);
277
+ return;
278
+ case 'stop':
279
+ if (stopped)
280
+ return;
281
+ stopped = true;
282
+ void stop();
283
+ return;
284
+ }
285
+ });
286
+ }
287
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Electron `utilityProcess` transport. The host gets its own process: a native crash ends only the
3
+ * host, at the cost of a slower start and more memory than a worker.
4
+ */
5
+ import type { HostTransport } from './contract.js';
6
+ /** The part of Electron's `UtilityProcess` the transport relies on. */
7
+ export interface UtilityProcessLike {
8
+ readonly pid?: number | undefined;
9
+ postMessage(message: unknown): void;
10
+ on(event: 'spawn', listener: () => void): unknown;
11
+ on(event: 'message', listener: (message: unknown) => void): unknown;
12
+ on(event: 'exit', listener: (code: number) => void): unknown;
13
+ on(event: 'error', listener: (type: string, location: string, report: string) => void): unknown;
14
+ kill(): boolean;
15
+ }
16
+ /** The `utilityProcess.fork` options the transport passes through. */
17
+ export interface UtilityForkOptions {
18
+ readonly env?: Record<string, string>;
19
+ readonly execArgv?: string[];
20
+ readonly cwd?: string;
21
+ readonly stdio?: 'pipe' | 'ignore' | 'inherit';
22
+ readonly serviceName?: string;
23
+ readonly allowLoadingUnsignedLibraries?: boolean;
24
+ }
25
+ export interface UtilityProcessTransportOptions {
26
+ /** The host entry: a file that calls `serveHost`. */
27
+ readonly entry: string;
28
+ readonly args?: readonly string[];
29
+ /** Shown in the OS task manager and in `app.getAppMetrics()`. */
30
+ readonly serviceName?: string;
31
+ /** Defaults to `minimalEnvironment(process.env)`, not the whole parent environment. */
32
+ readonly env?: Record<string, string>;
33
+ readonly execArgv?: readonly string[];
34
+ readonly cwd?: string;
35
+ readonly stdio?: 'pipe' | 'ignore' | 'inherit';
36
+ /** macOS: lets the hardened runtime load unsigned `.node` and `.dylib` files. Avoid in release builds. */
37
+ readonly allowLoadingUnsignedLibraries?: boolean;
38
+ /**
39
+ * Electron's `utilityProcess.fork`. Pass it when the main process is bundled (CommonJS, or any
40
+ * build where this package cannot `require('electron')` itself); tests pass a fake.
41
+ */
42
+ readonly fork?: (entry: string, args: string[], options: UtilityForkOptions) => UtilityProcessLike;
43
+ }
44
+ export declare function utilityProcessTransport(options: UtilityProcessTransportOptions): HostTransport;
45
+ export { minimalEnvironment } from './env.js';
46
+ //# sourceMappingURL=utility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utility.d.ts","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAA4B,aAAa,EAAE,MAAM,eAAe,CAAA;AAG5E,uEAAuE;AACvE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACnC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAA;IACjD,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAA;IACnE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAA;IAC5D,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAA;IAC/F,IAAI,IAAI,OAAO,CAAA;CAChB;AAED,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAA;IAC9C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,6BAA6B,CAAC,EAAE,OAAO,CAAA;CACjD;AAED,MAAM,WAAW,8BAA8B;IAC7C,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,iEAAiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,uFAAuF;IACvF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAA;IAC9C,0GAA0G;IAC1G,QAAQ,CAAC,6BAA6B,CAAC,EAAE,OAAO,CAAA;IAChD;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,kBAAkB,KAAK,kBAAkB,CAAA;CACnG;AAmBD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,8BAA8B,GAAG,aAAa,CAiC9F;AAED,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Electron `utilityProcess` transport. The host gets its own process: a native crash ends only the
3
+ * host, at the cost of a slower start and more memory than a worker.
4
+ */
5
+ import { createRequire } from 'node:module';
6
+ import { minimalEnvironment } from './env.js';
7
+ function electronFork(entry, args, options) {
8
+ // Loaded on first launch, so importing this module never needs Electron.
9
+ const electron = createRequire(import.meta.url)('electron');
10
+ if (!electron.utilityProcess) {
11
+ throw new Error('utilityProcessTransport must run in the Electron main process');
12
+ }
13
+ return electron.utilityProcess.fork(entry, args, options);
14
+ }
15
+ export function utilityProcessTransport(options) {
16
+ const fork = options.fork ?? electronFork;
17
+ return {
18
+ launch() {
19
+ const env = options.env ?? minimalEnvironment(process.env);
20
+ const child = fork(options.entry, [...(options.args ?? [])], {
21
+ // Electron reads an empty env as unset and passes the whole parent environment.
22
+ env: Object.keys(env).length > 0 ? env : { HOST_SUPERVISOR_EMPTY_ENV: '1' },
23
+ ...(options.execArgv ? { execArgv: [...options.execArgv] } : {}),
24
+ ...(options.cwd ? { cwd: options.cwd } : {}),
25
+ ...(options.stdio ? { stdio: options.stdio } : {}),
26
+ ...(options.serviceName ? { serviceName: options.serviceName } : {}),
27
+ ...(options.allowLoadingUnsignedLibraries ? { allowLoadingUnsignedLibraries: true } : {}),
28
+ });
29
+ let error = null;
30
+ child.on('error', (type, location) => {
31
+ error = new Error(`The host process hit a fatal ${type} at ${location}`);
32
+ });
33
+ return {
34
+ send: (message) => child.postMessage(message),
35
+ onMessage: (listener) => void child.on('message', listener),
36
+ onExit: (listener) => void child.on('exit', (code) => {
37
+ const exit = error ? { code, error, runtimeFatal: true } : { code };
38
+ listener(exit);
39
+ }),
40
+ kill: () => {
41
+ // Before 'spawn' Electron's kill() is a no-op that returns false.
42
+ if (!child.kill())
43
+ child.on('spawn', () => void child.kill());
44
+ },
45
+ };
46
+ },
47
+ };
48
+ }
49
+ export { minimalEnvironment } from './env.js';
50
+ //# sourceMappingURL=utility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utility.js","sourceRoot":"","sources":["../src/utility.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `worker_threads` transport. Cheap to start and close to the caller, but the host shares the
3
+ * process: a native crash in it ends the whole app.
4
+ */
5
+ import { type ResourceLimits, type WorkerOptions } from 'node:worker_threads';
6
+ import type { HostTransport } from './contract.js';
7
+ /** The part of `Worker` the transport relies on. */
8
+ export interface WorkerLike {
9
+ postMessage(message: unknown): void;
10
+ on(event: 'message', listener: (message: unknown) => void): unknown;
11
+ on(event: 'error', listener: (error: unknown) => void): unknown;
12
+ on(event: 'exit', listener: (code: number) => void): unknown;
13
+ terminate(): Promise<number>;
14
+ }
15
+ export interface WorkerThreadTransportOptions {
16
+ /** The host entry: a file that calls `serveHost`. */
17
+ readonly entry: string | URL;
18
+ /**
19
+ * V8 heap caps; past them Node usually ends only the worker, reported as `out-of-memory`. One
20
+ * allocation far past the cap can still abort the whole process.
21
+ */
22
+ readonly resourceLimits?: ResourceLimits;
23
+ readonly env?: WorkerOptions['env'];
24
+ readonly execArgv?: readonly string[];
25
+ readonly argv?: readonly unknown[];
26
+ readonly name?: string;
27
+ /** Replaces `new Worker`, for tests. */
28
+ readonly createWorker?: (entry: string | URL, options: WorkerOptions) => WorkerLike;
29
+ }
30
+ export declare function workerThreadTransport(options: WorkerThreadTransportOptions): HostTransport;
31
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAU,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAErF,OAAO,KAAK,EAA4B,aAAa,EAAE,MAAM,eAAe,CAAA;AAE5E,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IACnC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAA;IACnE,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAA;IAC/D,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAA;IAC5D,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;CAC7B;AAED,MAAM,WAAW,4BAA4B;IAC3C,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAA;IAC5B;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;IACxC,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,wCAAwC;IACxC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,OAAO,EAAE,aAAa,KAAK,UAAU,CAAA;CACpF;AAKD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,aAAa,CA4C1F"}
package/dist/worker.js ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * `worker_threads` transport. Cheap to start and close to the caller, but the host shares the
3
+ * process: a native crash in it ends the whole app.
4
+ */
5
+ import { Worker } from 'node:worker_threads';
6
+ const createNodeWorker = (entry, options) => new Worker(entry, options);
7
+ export function workerThreadTransport(options) {
8
+ const create = options.createWorker ?? createNodeWorker;
9
+ return {
10
+ launch() {
11
+ const worker = create(options.entry, {
12
+ ...(options.resourceLimits ? { resourceLimits: options.resourceLimits } : {}),
13
+ ...(options.env === undefined ? {} : { env: options.env }),
14
+ ...(options.execArgv ? { execArgv: [...options.execArgv] } : {}),
15
+ ...(options.argv ? { argv: [...options.argv] } : {}),
16
+ ...(options.name ? { name: options.name } : {}),
17
+ });
18
+ let error = null;
19
+ // Node emits its own heap-limit error in the same tick as 'exit'; an uncaught error that
20
+ // merely carries that code (from an inner worker, say) arrives earlier.
21
+ let errorThisTick = false;
22
+ // A worker can throw any value, falsy ones included.
23
+ worker.on('error', (cause) => {
24
+ error =
25
+ cause instanceof Error
26
+ ? cause
27
+ : new Error(`The host threw a non-error value: ${String(cause)}`);
28
+ errorThisTick = true;
29
+ queueMicrotask(() => (errorThisTick = false));
30
+ });
31
+ return {
32
+ send: (message) => worker.postMessage(message),
33
+ onMessage: (listener) => void worker.on('message', listener),
34
+ onExit: (listener) => void worker.on('exit', (code) => {
35
+ const exit = error
36
+ ? {
37
+ code,
38
+ error,
39
+ outOfMemory: errorThisTick &&
40
+ error.code === 'ERR_WORKER_OUT_OF_MEMORY',
41
+ }
42
+ : { code };
43
+ listener(exit);
44
+ }),
45
+ kill: () => void worker.terminate().catch(() => undefined),
46
+ };
47
+ },
48
+ };
49
+ }
50
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAA2C,MAAM,qBAAqB,CAAA;AA6BrF,MAAM,gBAAgB,GAAG,CAAC,KAAmB,EAAE,OAAsB,EAAc,EAAE,CACnF,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;AAE5B,MAAM,UAAU,qBAAqB,CAAC,OAAqC;IACzE,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,IAAI,gBAAgB,CAAA;IACvD,OAAO;QACL,MAAM;YACJ,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE;gBACnC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7E,GAAG,CAAC,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;gBAC1D,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpD,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChD,CAAC,CAAA;YACF,IAAI,KAAK,GAAiB,IAAI,CAAA;YAC9B,yFAAyF;YACzF,wEAAwE;YACxE,IAAI,aAAa,GAAG,KAAK,CAAA;YACzB,qDAAqD;YACrD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAc,EAAE,EAAE;gBACpC,KAAK;oBACH,KAAK,YAAY,KAAK;wBACpB,CAAC,CAAC,KAAK;wBACP,CAAC,CAAC,IAAI,KAAK,CAAC,qCAAqC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;gBACrE,aAAa,GAAG,IAAI,CAAA;gBACpB,cAAc,CAAC,GAAG,EAAE,CAAC,CAAC,aAAa,GAAG,KAAK,CAAC,CAAC,CAAA;YAC/C,CAAC,CAAC,CAAA;YACF,OAAO;gBACL,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC;gBAC9C,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;gBAC5D,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CACnB,KAAK,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;oBAC9B,MAAM,IAAI,GAAgB,KAAK;wBAC7B,CAAC,CAAC;4BACE,IAAI;4BACJ,KAAK;4BACL,WAAW,EACT,aAAa;gCACZ,KAA4B,CAAC,IAAI,KAAK,0BAA0B;yBACpE;wBACH,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;oBACZ,QAAQ,CAAC,IAAI,CAAC,CAAA;gBAChB,CAAC,CAAC;gBACJ,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;aAC3D,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,59 @@
1
1
  {
2
2
  "name": "@electron-stagewright/host-supervisor",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "Supervisor for one stateful host off the Electron main thread: a closed operation list, lazy start, drain on stop, per-call timeout and AbortSignal, a pending limit, and bounded restart, over worker_threads or utilityProcess.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "johnny4young <johnny.iv.young@gmail.com>",
8
+ "homepage": "https://electron-stagewright.github.io/electron-stagewright/",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/electron-stagewright/electron-stagewright.git",
12
+ "directory": "packages/host-supervisor"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/electron-stagewright/electron-stagewright/issues"
16
+ },
17
+ "keywords": [
18
+ "electron",
19
+ "utility-process",
20
+ "worker-threads",
21
+ "supervisor",
22
+ "rpc",
23
+ "performance"
24
+ ],
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "files": [
28
+ "dist/",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js"
36
+ },
37
+ "./worker": {
38
+ "types": "./dist/worker.d.ts",
39
+ "import": "./dist/worker.js"
40
+ },
41
+ "./utility": {
42
+ "types": "./dist/utility.d.ts",
43
+ "import": "./dist/utility.js"
44
+ }
45
+ },
46
+ "engines": {
47
+ "node": ">=26.13.1"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "devDependencies": {
53
+ "electron": "^42.11.10"
54
+ },
55
+ "scripts": {
56
+ "build": "tsc -p tsconfig.json",
57
+ "typecheck": "tsc -p tsconfig.json --noEmit"
58
+ }
6
59
  }