Files
hyperframes/packages/cli/src/renderSetupWorkerLifecycle.ts
T
Miguel Ángel 0241078560 fix(cli): name the unzip errors when every Windows unzip tool fails (#5355)
* fix(cli): name the unzip errors when every Windows unzip tool fails

* fix(cli): a cached empty or folder Chrome counts as missing, not found

* fix(engine): skip an empty cached Chrome the same way the CLI does

* fix(engine): keep scanning the Chrome cache past a build it cannot read

* test(engine): a folder at the cached Chrome path is skipped
2026-10-09 19:18:27 +00:00

77 lines
2.5 KiB
TypeScript

import { normalizeErrorMessage } from "./utils/errorMessage.js";
const RENDER_SETUP_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"] as const;
const RENDER_SETUP_RESULT_PREFIX = "HYPERFRAMES_RENDER_SETUP_RESULT:";
const RENDER_SETUP_ERROR_PREFIX = "HYPERFRAMES_RENDER_SETUP_ERROR:";
type RenderSetupSignal = (typeof RENDER_SETUP_SIGNALS)[number];
interface SignalTarget {
on(signal: RenderSetupSignal, handler: () => void): unknown;
off(signal: RenderSetupSignal, handler: () => void): unknown;
}
export function installRenderSetupSignalHandlers(
signalTarget: SignalTarget,
releaseLock: () => void,
resendSignal: (signal: RenderSetupSignal) => void,
handleHangup = true,
): () => void {
const handlers = new Map<RenderSetupSignal, () => void>();
const handledSignals = handleHangup
? RENDER_SETUP_SIGNALS
: RENDER_SETUP_SIGNALS.filter((signal) => signal !== "SIGHUP");
for (const signal of handledSignals) {
const handler = (): void => {
releaseLock();
signalTarget.off(signal, handler);
resendSignal(signal);
};
handlers.set(signal, handler);
signalTarget.on(signal, handler);
}
return () => {
for (const [signal, handler] of handlers) signalTarget.off(signal, handler);
};
}
function prefixedLine(prefix: string, value: unknown): string {
return prefix + JSON.stringify(value) + "\n";
}
function parseJson(text: string): unknown {
try {
return JSON.parse(text);
} catch {
return undefined;
}
}
function prefixedValue(output: string, prefix: string): unknown {
const line = output.split(/\r?\n/).find((text) => text.startsWith(prefix));
return line === undefined ? undefined : parseJson(line.slice(prefix.length));
}
export function renderSetupResultLine(result: unknown): string {
return prefixedLine(RENDER_SETUP_RESULT_PREFIX, result);
}
export function renderSetupResultFrom(stdout: string): unknown {
return prefixedValue(stdout, RENDER_SETUP_RESULT_PREFIX);
}
export function renderSetupErrorLine(error: unknown): string {
return "\n" + prefixedLine(RENDER_SETUP_ERROR_PREFIX, normalizeErrorMessage(error));
}
export function renderSetupFailureFrom(
stderr: string,
): { reason: string; earlierOutput: string } | undefined {
const lines = stderr.split(/\r?\n/);
const at = lines.findIndex((text) => text.startsWith(RENDER_SETUP_ERROR_PREFIX));
const reason =
at === -1 ? undefined : parseJson(lines[at]!.slice(RENDER_SETUP_ERROR_PREFIX.length));
if (typeof reason !== "string" || reason === "") return undefined;
return { reason, earlierOutput: lines.slice(0, at).join("\n") };
}