@electron-stagewright/host-supervisor 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +143 -2
- package/dist/contract.d.ts +50 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +2 -0
- package/dist/contract.js.map +1 -0
- package/dist/env.d.ts +9 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +30 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +33 -0
- package/dist/errors.js.map +1 -0
- package/dist/host.d.ts +79 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +712 -0
- package/dist/host.js.map +1 -0
- package/dist/in-process.d.ts +8 -0
- package/dist/in-process.d.ts.map +1 -0
- package/dist/in-process.js +60 -0
- package/dist/in-process.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/policy.d.ts +34 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +46 -0
- package/dist/policy.js.map +1 -0
- package/dist/protocol.d.ts +81 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +94 -0
- package/dist/protocol.js.map +1 -0
- package/dist/serve.d.ts +32 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +252 -0
- package/dist/serve.js.map +1 -0
- package/dist/utility.d.ts +43 -0
- package/dist/utility.d.ts.map +1 -0
- package/dist/utility.js +50 -0
- package/dist/utility.js.map +1 -0
- package/dist/worker.d.ts +31 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +50 -0
- package/dist/worker.js.map +1 -0
- package/package.json +64 -3
package/dist/serve.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
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) {
|
|
37
|
+
const serialized = serializeError(error);
|
|
38
|
+
return serialized.name === 'HostError' ? { ...serialized, name: 'Error' } : serialized;
|
|
39
|
+
}
|
|
40
|
+
/** Serves one host until the supervisor sends `stop`. */
|
|
41
|
+
export function serveHost(options) {
|
|
42
|
+
const found = options.port ?? defaultHostPort();
|
|
43
|
+
if (!found)
|
|
44
|
+
throw new Error('serveHost must run in a worker thread or a utility process');
|
|
45
|
+
const port = found;
|
|
46
|
+
const callOps = new Set(options.operations);
|
|
47
|
+
const streamOps = new Set(options.streams ?? []);
|
|
48
|
+
let handlers = null;
|
|
49
|
+
let starting = null;
|
|
50
|
+
let accepting = true;
|
|
51
|
+
let statsTimer = null;
|
|
52
|
+
const inflight = new Set();
|
|
53
|
+
const controllers = new Map();
|
|
54
|
+
const streams = new Map();
|
|
55
|
+
const post = (message) => port.post(message);
|
|
56
|
+
function track(work) {
|
|
57
|
+
inflight.add(work);
|
|
58
|
+
void work.finally(() => inflight.delete(work));
|
|
59
|
+
}
|
|
60
|
+
/** A value that cannot be cloned still answers its call. */
|
|
61
|
+
function answer(id, message) {
|
|
62
|
+
try {
|
|
63
|
+
post(message);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
post({ type: 'result', id, ok: false, error: handlerError(error) });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
let lastElu = performance.eventLoopUtilization();
|
|
70
|
+
const heapLimitMb = toMb(getHeapStatistics().heap_size_limit);
|
|
71
|
+
function postStats() {
|
|
72
|
+
const memory = process.memoryUsage();
|
|
73
|
+
const elu = performance.eventLoopUtilization(lastElu);
|
|
74
|
+
lastElu = performance.eventLoopUtilization();
|
|
75
|
+
post({
|
|
76
|
+
type: 'stats',
|
|
77
|
+
stats: {
|
|
78
|
+
rssMb: toMb(memory.rss),
|
|
79
|
+
heapUsedMb: toMb(memory.heapUsed),
|
|
80
|
+
heapLimitMb,
|
|
81
|
+
externalMb: toMb(memory.external + memory.arrayBuffers),
|
|
82
|
+
eventLoopUtilization: Math.round(elu.utilization * 1000) / 1000,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
async function start(version, payload) {
|
|
87
|
+
try {
|
|
88
|
+
if (version !== PROTOCOL_VERSION) {
|
|
89
|
+
throw new Error(`The host speaks protocol ${PROTOCOL_VERSION}, not ${version}`);
|
|
90
|
+
}
|
|
91
|
+
const served = (await options.start(payload));
|
|
92
|
+
for (const op of [...callOps, ...streamOps]) {
|
|
93
|
+
if (typeof served[op] !== 'function')
|
|
94
|
+
throw new Error(`No handler for ${op}`);
|
|
95
|
+
}
|
|
96
|
+
handlers = served;
|
|
97
|
+
post({ type: 'started' });
|
|
98
|
+
if (options.statsIntervalMs !== undefined) {
|
|
99
|
+
postStats();
|
|
100
|
+
statsTimer = setInterval(postStats, options.statsIntervalMs);
|
|
101
|
+
statsTimer.unref();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
post({ type: 'start-failed', error: handlerError(error) });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function call(id, op, args, stream) {
|
|
109
|
+
const served = handlers;
|
|
110
|
+
if (!served || !accepting) {
|
|
111
|
+
post({
|
|
112
|
+
type: 'result',
|
|
113
|
+
id,
|
|
114
|
+
ok: false,
|
|
115
|
+
error: rejected('The host is not serving', 'HOST_STOPPED'),
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (!(stream ? streamOps : callOps).has(op)) {
|
|
120
|
+
post({
|
|
121
|
+
type: 'result',
|
|
122
|
+
id,
|
|
123
|
+
ok: false,
|
|
124
|
+
error: rejected(`${op} is not an operation of this host`, 'HOST_OPERATION_REJECTED'),
|
|
125
|
+
});
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const controller = new AbortController();
|
|
129
|
+
const context = { signal: controller.signal };
|
|
130
|
+
const handler = served[op];
|
|
131
|
+
if (stream) {
|
|
132
|
+
try {
|
|
133
|
+
const iterable = handler.apply(served, [...args, context]);
|
|
134
|
+
const iterator = Symbol.asyncIterator in iterable
|
|
135
|
+
? iterable[Symbol.asyncIterator]()
|
|
136
|
+
: iterable[Symbol.iterator]();
|
|
137
|
+
streams.set(id, { iterator, controller });
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
post({ type: 'result', id, ok: false, error: handlerError(error) });
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
controllers.set(id, controller);
|
|
145
|
+
track(Promise.resolve()
|
|
146
|
+
.then(() => handler.apply(served, [...args, context]))
|
|
147
|
+
.then((value) => answer(id, { type: 'result', id, ok: true, value }), (error) => post({ type: 'result', id, ok: false, error: handlerError(error) }))
|
|
148
|
+
.finally(() => controllers.delete(id)));
|
|
149
|
+
}
|
|
150
|
+
function next(id) {
|
|
151
|
+
const open = streams.get(id);
|
|
152
|
+
if (!open) {
|
|
153
|
+
post({
|
|
154
|
+
type: 'result',
|
|
155
|
+
id,
|
|
156
|
+
ok: false,
|
|
157
|
+
error: rejected('The stream is not open', 'HOST_STOPPED'),
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
track(Promise.resolve()
|
|
162
|
+
.then(() => open.iterator.next())
|
|
163
|
+
.then((result) => {
|
|
164
|
+
if (result.done) {
|
|
165
|
+
streams.delete(id);
|
|
166
|
+
post({ type: 'item', id, done: true });
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
try {
|
|
170
|
+
post({ type: 'item', id, done: false, value: result.value });
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
// An item that cannot be cloned ends the stream and frees its producer.
|
|
174
|
+
cancel(id);
|
|
175
|
+
post({ type: 'result', id, ok: false, error: handlerError(error) });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}, (error) => {
|
|
179
|
+
streams.delete(id);
|
|
180
|
+
post({ type: 'result', id, ok: false, error: handlerError(error) });
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
function cancel(id) {
|
|
184
|
+
controllers.get(id)?.abort();
|
|
185
|
+
const open = streams.get(id);
|
|
186
|
+
if (!open)
|
|
187
|
+
return;
|
|
188
|
+
streams.delete(id);
|
|
189
|
+
open.controller.abort();
|
|
190
|
+
track(Promise.resolve()
|
|
191
|
+
.then(() => open.iterator.return?.())
|
|
192
|
+
.then(() => undefined, () => undefined));
|
|
193
|
+
}
|
|
194
|
+
async function stop() {
|
|
195
|
+
// Close admission before yielding, so a later message cannot reach a closing resource.
|
|
196
|
+
accepting = false;
|
|
197
|
+
let failure = null;
|
|
198
|
+
try {
|
|
199
|
+
await starting;
|
|
200
|
+
for (const id of [...streams.keys()])
|
|
201
|
+
cancel(id);
|
|
202
|
+
while (inflight.size > 0)
|
|
203
|
+
await Promise.allSettled([...inflight]);
|
|
204
|
+
await options.stop?.();
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
failure = error;
|
|
208
|
+
}
|
|
209
|
+
handlers = null;
|
|
210
|
+
if (statsTimer)
|
|
211
|
+
clearInterval(statsTimer);
|
|
212
|
+
post(failure ? { type: 'stopped', error: handlerError(failure) } : { type: 'stopped' });
|
|
213
|
+
port.close();
|
|
214
|
+
}
|
|
215
|
+
if (options.reportCrashes !== false) {
|
|
216
|
+
process.on('uncaughtExceptionMonitor', (error) => {
|
|
217
|
+
try {
|
|
218
|
+
post({ type: 'crashed', error: handlerError(error) });
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
// The host is ending either way.
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
let stopped = false;
|
|
226
|
+
port.onMessage((raw) => {
|
|
227
|
+
const message = parseSupervisorMessage(raw);
|
|
228
|
+
if (!message)
|
|
229
|
+
return;
|
|
230
|
+
switch (message.type) {
|
|
231
|
+
case 'start':
|
|
232
|
+
starting ??= start(message.version, message.payload);
|
|
233
|
+
return;
|
|
234
|
+
case 'call':
|
|
235
|
+
call(message.id, message.op, message.args, message.stream === true);
|
|
236
|
+
return;
|
|
237
|
+
case 'next':
|
|
238
|
+
next(message.id);
|
|
239
|
+
return;
|
|
240
|
+
case 'cancel':
|
|
241
|
+
cancel(message.id);
|
|
242
|
+
return;
|
|
243
|
+
case 'stop':
|
|
244
|
+
if (stopped)
|
|
245
|
+
return;
|
|
246
|
+
stopped = true;
|
|
247
|
+
void stop();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
//# 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,43 @@
|
|
|
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
|
+
/** Replaces `utilityProcess.fork`, for tests. */
|
|
39
|
+
readonly fork?: (entry: string, args: string[], options: UtilityForkOptions) => UtilityProcessLike;
|
|
40
|
+
}
|
|
41
|
+
export declare function utilityProcessTransport(options: UtilityProcessTransportOptions): HostTransport;
|
|
42
|
+
export { minimalEnvironment } from './env.js';
|
|
43
|
+
//# 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,iDAAiD;IACjD,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"}
|
package/dist/utility.js
ADDED
|
@@ -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 } : { 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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"}
|
package/dist/worker.d.ts
ADDED
|
@@ -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,67 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@electron-stagewright/host-supervisor",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.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": ">=24.0.0"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"electron": ">=42.0.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependenciesMeta": {
|
|
56
|
+
"electron": {
|
|
57
|
+
"optional": true
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"electron": "^42.11.10"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsc -p tsconfig.json",
|
|
65
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
66
|
+
}
|
|
6
67
|
}
|