import type { SpawnSyncOptionsWithStringEncoding } from "node:child_process"; export const PNPM_SCRIPT_TIMEOUT_MS = 60_000; export const PNPM_SCRIPT_MAX_OUTPUT_BYTES = 16 * 1024 * 1024; type BoundedChildInvocation = Readonly<{ command: string; arguments: readonly string[]; options: SpawnSyncOptionsWithStringEncoding; }>; type PnpmScriptResult = Readonly<{ status: number | null; signal: NodeJS.Signals | null; error?: Error; }>; export function createBoundedPnpmScriptInvocation(input: Readonly<{ nodePath: string; pnpmCli: string; script: string; environment: NodeJS.ProcessEnv; }>): BoundedChildInvocation { return createBoundedChildInvocation({ command: input.nodePath, arguments: [input.pnpmCli, "run", input.script], environment: input.environment, }); } export function createBoundedChildInvocation(input: Readonly<{ command: string; arguments: readonly string[]; environment: NodeJS.ProcessEnv; cwd?: string; }>): BoundedChildInvocation { return Object.freeze({ command: input.command, arguments: Object.freeze([...input.arguments]), options: Object.freeze({ ...(input.cwd === undefined ? {} : { cwd: input.cwd }), encoding: "utf8", env: input.environment, killSignal: "SIGTERM", maxBuffer: PNPM_SCRIPT_MAX_OUTPUT_BYTES, timeout: PNPM_SCRIPT_TIMEOUT_MS, }), }); } export function formatPnpmScriptFailure( script: string, result: PnpmScriptResult, ): string { const code = result.error && "code" in result.error && typeof result.error.code === "string" ? result.error.code : null; const message = result.error?.message.trim().replace(/\s+/g, " ") ?? null; const error = result.error === undefined ? "none" : `${code ?? result.error.name}: ${message || "no message"}`; return `${script} failed: exit=${String(result.status)}, signal=${result.signal ?? "none"}, error=${error}`; }