@volter/world-runtime 3.0.38 → 3.0.39
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/dist/known-external-services.json +3 -10
- package/dist/src/actions-runner-cli.js +3 -3
- package/dist/src/actions-runner.js +2 -1
- package/dist/src/app-url.js +2 -1
- package/dist/src/backings.d.ts +10 -1
- package/dist/src/backings.js +66 -7
- package/dist/src/branch.js +85 -52
- package/dist/src/browser-routes.cjs +59 -0
- package/dist/src/ca-trust.js +4 -3
- package/dist/src/changeset.js +4 -3
- package/dist/src/cli-commands.js +25 -9
- package/dist/src/cli.js +2 -1
- package/dist/src/command-lifetime.d.mts +12 -0
- package/dist/src/command-lifetime.d.ts +1 -15
- package/dist/src/command-lifetime.js +1 -98
- package/dist/src/command-lifetime.mjs +90 -0
- package/dist/src/configs.js +1 -1
- package/dist/src/console-apart.js +3 -2
- package/dist/src/covers.d.ts +3 -2
- package/dist/src/covers.js +95 -18
- package/dist/src/error-message.d.mts +1 -0
- package/dist/src/error-message.d.ts +1 -0
- package/dist/src/error-message.js +2 -0
- package/dist/src/error-message.mjs +10 -0
- package/dist/src/guest-command.d.mts +4 -0
- package/dist/src/guest-command.mjs +26 -0
- package/dist/src/guest-control.d.mts +1 -0
- package/dist/src/guest-control.mjs +17 -0
- package/dist/src/guest-entry.mjs +146 -0
- package/dist/src/guest-processes.d.mts +9 -0
- package/dist/src/guest-processes.mjs +47 -0
- package/dist/src/guest-runner.d.ts +6 -0
- package/dist/src/guest-runner.js +567 -0
- package/dist/src/host.js +5 -4
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/infra-cli.js +4 -0
- package/dist/src/infra.js +133 -23
- package/dist/src/init.js +60 -23
- package/dist/src/lifecycle-record.d.ts +3 -1
- package/dist/src/lifecycle-record.js +29 -6
- package/dist/src/livekit-backing.mjs +37 -0
- package/dist/src/local-branches.js +11 -3
- package/dist/src/mongodb-backing.d.ts +7 -0
- package/dist/src/mongodb-backing.js +58 -0
- package/dist/src/native-postgres-backing.d.ts +4 -0
- package/dist/src/native-postgres-backing.js +404 -0
- package/dist/src/origin.js +2 -1
- package/dist/src/owned-path.d.ts +4 -0
- package/dist/src/owned-path.js +37 -0
- package/dist/src/pack-facts.d.ts +1 -0
- package/dist/src/pglite-backing.d.ts +4 -13
- package/dist/src/pglite-backing.js +198 -106
- package/dist/src/pglite-host.mjs +47 -17
- package/dist/src/placeholder.d.ts +3 -2
- package/dist/src/placeholder.js +9 -4
- package/dist/src/process-groups.d.mts +2 -0
- package/dist/src/process-groups.d.ts +1 -4
- package/dist/src/process-groups.js +1 -49
- package/dist/src/process-groups.mjs +59 -0
- package/dist/src/process-receipt.d.mts +6 -0
- package/dist/src/process-receipt.d.ts +11 -0
- package/dist/src/process-receipt.js +3 -0
- package/dist/src/process-receipt.mjs +45 -0
- package/dist/src/process-signal.d.mts +9 -0
- package/dist/src/process-signal.mjs +92 -0
- package/dist/src/project-inspect.d.ts +1 -1
- package/dist/src/project-inspect.js +4 -2
- package/dist/src/proxy-daemon.js +2 -1
- package/dist/src/redirect-proxy.js +186 -19
- package/dist/src/redis-backing.js +99 -35
- package/dist/src/reflect.js +2 -1
- package/dist/src/root.js +7 -6
- package/dist/src/run-task-worker.js +2 -1
- package/dist/src/runtime.d.ts +24 -7
- package/dist/src/runtime.js +703 -286
- package/dist/src/schema.d.ts +12 -1
- package/dist/src/schema.js +20 -5
- package/dist/src/served-world.d.ts +1 -0
- package/dist/src/served-world.js +26 -14
- package/dist/src/service-recorder.js +8 -3
- package/dist/src/signals.d.mts +1 -0
- package/dist/src/signals.d.ts +1 -1
- package/dist/src/signals.js +1 -11
- package/dist/src/signals.mjs +10 -0
- package/dist/src/tail.d.ts +2 -0
- package/dist/src/tail.js +9 -2
- package/dist/src/tcp-port.js +27 -13
- package/dist/src/temporal-backing.mjs +28 -0
- package/dist/src/up-cli.js +8 -3
- package/dist/src/up-task-worker.js +2 -1
- package/dist/src/websocket-relay.d.ts +1 -1
- package/dist/src/websocket-relay.js +23 -10
- package/dist/src/world-view.js +2 -2
- package/known-external-services.json +3 -10
- package/package.json +12 -7
- package/src/actions-runner-cli.ts +3 -3
- package/src/actions-runner.ts +2 -1
- package/src/app-url.ts +2 -1
- package/src/backings.ts +65 -7
- package/src/branch.ts +73 -34
- package/src/browser-routes.cjs +59 -0
- package/src/ca-trust.ts +4 -3
- package/src/changeset.ts +4 -3
- package/src/cli-commands.ts +21 -9
- package/src/cli.ts +2 -1
- package/src/command-lifetime.d.mts +12 -0
- package/src/command-lifetime.mjs +90 -0
- package/src/command-lifetime.ts +1 -79
- package/src/configs.ts +1 -1
- package/src/console-apart.ts +2 -1
- package/src/covers.ts +97 -19
- package/src/error-message.d.mts +1 -0
- package/src/error-message.mjs +10 -0
- package/src/error-message.ts +2 -0
- package/src/guest-command.d.mts +4 -0
- package/src/guest-command.mjs +26 -0
- package/src/guest-control.d.mts +1 -0
- package/src/guest-control.mjs +17 -0
- package/src/guest-entry.mjs +146 -0
- package/src/guest-processes.d.mts +9 -0
- package/src/guest-processes.mjs +47 -0
- package/src/guest-runner.ts +414 -0
- package/src/host.ts +5 -4
- package/src/index.ts +1 -0
- package/src/infra-cli.ts +4 -0
- package/src/infra.ts +103 -22
- package/src/init.ts +55 -22
- package/src/lifecycle-record.ts +21 -6
- package/src/livekit-backing.mjs +37 -0
- package/src/local-branches.ts +6 -3
- package/src/mongodb-backing.ts +55 -0
- package/src/native-postgres-backing.ts +329 -0
- package/src/origin.ts +2 -1
- package/src/owned-path.ts +32 -0
- package/src/pack-facts.ts +1 -0
- package/src/pglite-backing.ts +155 -79
- package/src/pglite-host.mjs +47 -17
- package/src/placeholder.ts +10 -5
- package/src/process-groups.d.mts +2 -0
- package/src/process-groups.mjs +59 -0
- package/src/process-groups.ts +1 -33
- package/src/process-receipt.d.mts +6 -0
- package/src/process-receipt.mjs +45 -0
- package/src/process-receipt.ts +5 -0
- package/src/process-signal.d.mts +9 -0
- package/src/process-signal.mjs +92 -0
- package/src/project-inspect.ts +4 -2
- package/src/proxy-daemon.ts +2 -1
- package/src/redirect-proxy.ts +153 -18
- package/src/redis-backing.ts +74 -25
- package/src/reflect.ts +2 -1
- package/src/root.ts +7 -6
- package/src/run-task-worker.ts +2 -1
- package/src/runtime.ts +596 -265
- package/src/schema.ts +30 -6
- package/src/served-world.ts +21 -15
- package/src/service-recorder.ts +4 -2
- package/src/signals.d.mts +1 -0
- package/src/signals.mjs +10 -0
- package/src/signals.ts +1 -10
- package/src/tail.ts +10 -3
- package/src/tcp-port.ts +24 -13
- package/src/temporal-backing.mjs +28 -0
- package/src/up-cli.ts +6 -3
- package/src/up-task-worker.ts +2 -1
- package/src/websocket-relay.ts +18 -11
- package/src/world-view.ts +2 -2
package/src/redis-backing.ts
CHANGED
|
@@ -8,14 +8,20 @@
|
|
|
8
8
|
// in a container is state outside it (a branch of the World would share the container's queue and cache). The
|
|
9
9
|
// twin keeps each key a subject of the World (the Redis pack's storage module). It needs nothing
|
|
10
10
|
// installed: no container runtime, no redis-server binary.
|
|
11
|
-
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, rmSync
|
|
11
|
+
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, rmSync } from 'node:fs';
|
|
12
12
|
import { connect } from 'node:net';
|
|
13
13
|
import { dirname, join } from 'node:path';
|
|
14
|
-
import {
|
|
14
|
+
import { commandLifetime, COMMAND_GRACE_MS, COMMAND_CONFIRM_MS } from './command-lifetime.ts';
|
|
15
|
+
import { publishProcessReceipt, readProcessReceipt, readSpawnReceipt, spawnReceiptPath, signalOwnedProcess } from './process-receipt.ts';
|
|
16
|
+
import { spawn, type ChildProcess } from 'node:child_process';
|
|
17
|
+
import { survivingOwnedGroups } from './process-groups.ts';
|
|
18
|
+
import { errorMessage } from './error-message.ts';
|
|
15
19
|
import { findInstalledPackage, packCli } from './catalog.ts';
|
|
16
20
|
import { vendorPackageDir } from '@volter/world-core/runtime';
|
|
17
21
|
import type { HostLaunch, InfraService } from './pglite-backing.ts';
|
|
18
22
|
|
|
23
|
+
interface RedisHost { child: ChildProcess; lifetime: ReturnType<typeof commandLifetime>; closed: boolean }
|
|
24
|
+
const hosts = new Map<string, RedisHost>();
|
|
19
25
|
const PACKAGE = '@volter/twin-redis';
|
|
20
26
|
const READY_TIMEOUT_MS = 60_000;
|
|
21
27
|
|
|
@@ -34,7 +40,7 @@ const pidPath = (dataDir: string, service: InfraService): string => join(dataDir
|
|
|
34
40
|
export const redisTwinRoot = (dataDir: string): string => join(dataDir, 'redis-twin');
|
|
35
41
|
|
|
36
42
|
function alive(pid: number): boolean {
|
|
37
|
-
try { process.kill(pid, 0); return true; } catch { return false; }
|
|
43
|
+
try { process.kill(pid, 0); return true; } catch (error) { if ((error as NodeJS.ErrnoException).code === 'ESRCH') return false; throw error; }
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
function listening(port: number): Promise<boolean> {
|
|
@@ -53,7 +59,9 @@ const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
53
59
|
export async function redisTwinUp(services: InfraService[], dataDir: string, cli: string, launch: HostLaunch = {}): Promise<void> {
|
|
54
60
|
for (const service of services) {
|
|
55
61
|
const pidFile = pidPath(dataDir, service);
|
|
56
|
-
if (
|
|
62
|
+
if (hosts.has(pidFile) || existsSync(pidFile) || existsSync(spawnReceiptPath(pidFile))) {
|
|
63
|
+
await redisTwinDown([service], dataDir);
|
|
64
|
+
}
|
|
57
65
|
// a port that already answers is another process's (another World's twin, a redis-server): serving there would
|
|
58
66
|
// hand this World's app someone else's keys, so it is refused, never taken as ready
|
|
59
67
|
if (await listening(service.hostPort)) throw new Error(`port ${service.hostPort} already serves Redis for another process`);
|
|
@@ -66,21 +74,39 @@ export async function redisTwinUp(services: InfraService[], dataDir: string, cli
|
|
|
66
74
|
// the runtime this runs on: Bun runs the pack's TypeScript as it is; Node (volter-world-infra's shebang) needs
|
|
67
75
|
// type transformation, not only stripping (the kernel declares constructor parameter properties)
|
|
68
76
|
const runtime = typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined' || !cli.endsWith('.ts') ? [] : ['--experimental-transform-types', '--no-warnings'];
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
let held: RedisHost | undefined;
|
|
78
|
+
try {
|
|
79
|
+
try {
|
|
80
|
+
const child = spawn(process.execPath, [...runtime, cli, 'serve', '--port', String(service.hostPort), '--root', root], {
|
|
81
|
+
env: launch.env ?? process.env, detached: true, windowsHide: true, stdio: ['ignore', logFd, logFd],
|
|
82
|
+
});
|
|
83
|
+
// Retain BEFORE descriptor close, birth capture or either publication can fail.
|
|
84
|
+
held = { child, lifetime: commandLifetime(child, launch.signal), closed: false };
|
|
85
|
+
const observed = held;
|
|
86
|
+
child.once('close', () => { observed.closed = true; });
|
|
87
|
+
child.on('error', () => {}); // lifetime joins spawn failure and close
|
|
88
|
+
hosts.set(pidFile, held);
|
|
89
|
+
} finally { closeSync(logFd); }
|
|
90
|
+
if (!held.child.pid) throw new Error('Redis child did not start');
|
|
91
|
+
const identity = await held.lifetime.identity;
|
|
92
|
+
if (!identity?.start) throw new Error('Redis birth capture failed; retiring held child');
|
|
93
|
+
publishProcessReceipt(spawnReceiptPath(pidFile), JSON.stringify(identity) + '\n');
|
|
94
|
+
publishProcessReceipt(pidFile, `${held.child.pid}\n`);
|
|
95
|
+
const deadline = Date.now() + READY_TIMEOUT_MS;
|
|
96
|
+
while (!(await listening(service.hostPort)) || !alive(held.child.pid)) {
|
|
97
|
+
if (!alive(held.child.pid)) throw new Error(`redis exited before serving — see ${log}`);
|
|
98
|
+
launch.signal?.throwIfAborted();
|
|
99
|
+
if (Date.now() > deadline) throw new Error(`redis did not serve port ${service.hostPort} within ${READY_TIMEOUT_MS / 1000}s — see ${log}`);
|
|
100
|
+
await sleep(200);
|
|
101
|
+
}
|
|
81
102
|
launch.signal?.throwIfAborted();
|
|
82
|
-
|
|
83
|
-
|
|
103
|
+
held.child.unref();
|
|
104
|
+
} catch (error) {
|
|
105
|
+
if (held) {
|
|
106
|
+
try { await redisTwinDown([service], dataDir); }
|
|
107
|
+
catch (cleanup) { throw new AggregateError([error, cleanup], 'Redis startup and retirement failed; ownership retained'); }
|
|
108
|
+
}
|
|
109
|
+
throw error;
|
|
84
110
|
}
|
|
85
111
|
}
|
|
86
112
|
}
|
|
@@ -98,14 +124,37 @@ export async function redisTwinStatus(services: InfraService[], dataDir: string)
|
|
|
98
124
|
export async function redisTwinDown(services: InfraService[], dataDir: string): Promise<void> {
|
|
99
125
|
for (const service of services) {
|
|
100
126
|
const pidFile = pidPath(dataDir, service);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
127
|
+
const recorded = readProcessReceipt(pidFile, text => {
|
|
128
|
+
const pid = Number(text.trim());
|
|
129
|
+
if (!Number.isInteger(pid) || pid <= 0) throw new Error('Invalid Redis ownership PID');
|
|
130
|
+
return pid;
|
|
131
|
+
});
|
|
132
|
+
const identity = readSpawnReceipt(pidFile);
|
|
133
|
+
const held = hosts.get(pidFile);
|
|
134
|
+
if (recorded.error || identity.error) process.stderr.write(`${errorMessage(new AggregateError([recorded.error, identity.error].filter(Boolean), 'Redis ownership uncertain; retrying established ownership'))}\n`);
|
|
135
|
+
if (held) {
|
|
136
|
+
const retired = () => held!.closed && (!held!.child.pid || !survivingOwnedGroups([held!.child.pid]).length);
|
|
137
|
+
if (!retired()) {
|
|
138
|
+
held.child.ref(); held.lifetime.cancel('SIGTERM');
|
|
139
|
+
try { await held.lifetime.finish(); }
|
|
140
|
+
catch (error) { if (!retired()) throw error; }
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
if (!recorded.present && !identity.present) continue;
|
|
144
|
+
const pid = identity.value?.pid ?? recorded.value;
|
|
145
|
+
if (!pid) throw new AggregateError([recorded.error, identity.error].filter(Boolean), 'Redis ownership uncertain; receipts retained');
|
|
146
|
+
if (recorded.value && identity.value && recorded.value !== identity.value.pid) throw new Error('Redis ownership receipts disagree; retirement refused; receipts retained');
|
|
147
|
+
const live = () => survivingOwnedGroups([pid]).length > 0;
|
|
148
|
+
for (const [signal, limit] of [['SIGTERM', COMMAND_GRACE_MS], ['SIGKILL', COMMAND_CONFIRM_MS]] as const) {
|
|
149
|
+
if (!live()) break;
|
|
150
|
+
await signalOwnedProcess(identity.value, signal, true);
|
|
151
|
+
const deadline = Date.now() + limit;
|
|
152
|
+
while (live() && Date.now() < deadline) await sleep(20);
|
|
153
|
+
}
|
|
154
|
+
if (live()) throw new Error('Redis retirement unconfirmed; receipts retained');
|
|
108
155
|
}
|
|
109
156
|
rmSync(pidFile, { force: true });
|
|
157
|
+
rmSync(spawnReceiptPath(pidFile), { force: true });
|
|
158
|
+
hosts.delete(pidFile);
|
|
110
159
|
}
|
|
111
160
|
}
|
package/src/reflect.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorMessage } from './error-message.ts';
|
|
1
2
|
import { serveHttp, type HttpServer } from '@volter/world-core/runtime';
|
|
2
3
|
import { websocketRelay } from './websocket-relay.ts';
|
|
3
4
|
import { sessionTrustEnv } from './ca-trust.ts';
|
|
@@ -178,7 +179,7 @@ export async function startReflectFront(options: ReflectFrontOptions): Promise<R
|
|
|
178
179
|
} catch (error) {
|
|
179
180
|
let world: string | undefined;
|
|
180
181
|
try { world = options.envLoader().VOLTER_WORLD; } catch { /* the answer still goes out */ }
|
|
181
|
-
return new Response(twinUnreachableMessage(target.vendor, origin.origin, error instanceof Error ? error : new Error(
|
|
182
|
+
return new Response(twinUnreachableMessage(target.vendor, origin.origin, error instanceof Error ? error : new Error(errorMessage(error)), world), { status: 502 });
|
|
182
183
|
}
|
|
183
184
|
},
|
|
184
185
|
upgrade: websocketRelay(req => {
|
package/src/root.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// never in a pack, never an env var). `volter world deploy` performs landed entries against each
|
|
8
8
|
// root through the pack's adapters over the kernel executor, with the world's checks in front;
|
|
9
9
|
// `deploy: auto` does the same the moment an entry is appended (the host installs the hook).
|
|
10
|
+
import { errorMessage } from './error-message.ts';
|
|
10
11
|
import { randomBytes } from 'node:crypto';
|
|
11
12
|
import { packEntry } from './catalog.ts';
|
|
12
13
|
import { existsSync, readFileSync } from 'node:fs';
|
|
@@ -111,7 +112,7 @@ export async function bindLegacyCredentials(worldRoot: string, current: () => Re
|
|
|
111
112
|
// admits nothing until it opens again, and is never taken again from roots a request may have changed
|
|
112
113
|
try { inventory = (await currentSealer().open(JSON.parse(heldInventory) as SealedCredential, INVENTORY_SLOT)) as unknown as Inventory; }
|
|
113
114
|
catch (error) {
|
|
114
|
-
console.error(`[credential] the inventory beside the World does not open (${(error
|
|
115
|
+
console.error(`[credential] the inventory beside the World does not open (${errorMessage(error)}): nothing is admitted until it does`);
|
|
115
116
|
return { bound: [], failed: [], refused: [], ready: false };
|
|
116
117
|
}
|
|
117
118
|
}
|
|
@@ -121,7 +122,7 @@ export async function bindLegacyCredentials(worldRoot: string, current: () => Re
|
|
|
121
122
|
store.write(inventoryPath, `${JSON.stringify(sealed, null, 2)}\n`, { secret: true });
|
|
122
123
|
return true;
|
|
123
124
|
} catch (error) {
|
|
124
|
-
console.error(`[credential] the inventory could not be kept (${(error
|
|
125
|
+
console.error(`[credential] the inventory could not be kept (${errorMessage(error)})`);
|
|
125
126
|
return false;
|
|
126
127
|
}
|
|
127
128
|
};
|
|
@@ -149,7 +150,7 @@ export async function bindLegacyCredentials(worldRoot: string, current: () => Re
|
|
|
149
150
|
delete inventory.pending[name]; changed = true;
|
|
150
151
|
bound.push(name);
|
|
151
152
|
} catch (error) {
|
|
152
|
-
console.warn(`[credential] ${name}: not bound to its destination (${(error
|
|
153
|
+
console.warn(`[credential] ${name}: not bound to its destination (${errorMessage(error)})`);
|
|
153
154
|
failed.push(name);
|
|
154
155
|
}
|
|
155
156
|
}
|
|
@@ -170,7 +171,7 @@ export async function bindLegacyCredentials(worldRoot: string, current: () => Re
|
|
|
170
171
|
store.write(path, `${JSON.stringify({ ...moved, fingerprint: sealed.fingerprint, ...(sealed.rotatedAt ? { rotatedAt: sealed.rotatedAt } : {}) }, null, 2)}\n`, { secret: true });
|
|
171
172
|
bound.push(name);
|
|
172
173
|
} catch (error) {
|
|
173
|
-
console.warn(`[credential] ${name}: not moved to the vault (${(error
|
|
174
|
+
console.warn(`[credential] ${name}: not moved to the vault (${errorMessage(error)})`);
|
|
174
175
|
failed.push(name);
|
|
175
176
|
}
|
|
176
177
|
}
|
|
@@ -246,7 +247,7 @@ export async function rootCredentialInput(worldRoot: string, vendor: string, env
|
|
|
246
247
|
try {
|
|
247
248
|
response = await fetch(at, { headers: { 'x-vault-token': vault.token, ...(vault.namespace ? { 'x-vault-namespace': vault.namespace } : {}) }, signal: AbortSignal.timeout(10_000) });
|
|
248
249
|
} catch (error) {
|
|
249
|
-
notes.push(`the vault at ${vault.addr} did not answer (${(error
|
|
250
|
+
notes.push(`the vault at ${vault.addr} did not answer (${errorMessage(error)}; a private CA is not read from BAO_CACERT/VAULT_CACERT here)`);
|
|
250
251
|
}
|
|
251
252
|
if (response) {
|
|
252
253
|
if (response.status === 403) throw new Error(`the vault at ${vault.addr} refused kv/vendors/${vendor} (403): sign in again, or with a token that may read it`);
|
|
@@ -448,7 +449,7 @@ export async function refreshTwin(opts: { worldRoot: string; vendor: string; con
|
|
|
448
449
|
// failure — its reason and how many in a row — so the status door and the twin's status say so
|
|
449
450
|
const held = store.read(marker);
|
|
450
451
|
const previous = held !== null ? (JSON.parse(held) as { failed?: { count?: number } }) : {};
|
|
451
|
-
const reason =
|
|
452
|
+
const reason = errorMessage(error);
|
|
452
453
|
store.write(marker, `${JSON.stringify({ ...previous, at: new Date().toISOString(), failed: { at, reason, count: (previous.failed?.count ?? 0) + 1 } })}\n`);
|
|
453
454
|
throw error;
|
|
454
455
|
}
|
package/src/run-task-worker.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { runWorldOwned } from './runtime.ts';
|
|
2
|
+
import { errorMessage } from './error-message.ts';
|
|
2
3
|
import type { RunTaskReply, RunTaskRequest } from './run-task.ts';
|
|
3
4
|
|
|
4
5
|
// Only this process owns the IPC endpoint; child stdio explicitly excludes fd 3. A lost
|
|
@@ -20,7 +21,7 @@ process.on('message', async message => {
|
|
|
20
21
|
started = true;
|
|
21
22
|
let reply: RunTaskReply;
|
|
22
23
|
try { reply = { result: await runWorldOwned(request.configId, request.command, request.options, abort.signal) }; }
|
|
23
|
-
catch (error) { reply = { error:
|
|
24
|
+
catch (error) { reply = { error: errorMessage(error) }; }
|
|
24
25
|
if ('error' in reply) process.stderr.write(`${reply.error}\n`);
|
|
25
26
|
if (process.connected) process.send!(reply, () => process.exit('error' in reply ? 1 : 0));
|
|
26
27
|
else process.exit('error' in reply ? 1 : 0);
|