clone

a deno framework for local-first web apps that open instantly, work offline and sync when users choose

feat/fix-sync-enrollment-startup
lofi / package / tooling / process.ts
process.ts 1.6K
1export type DenoRunStatus = Deno.CommandStatus & {2 forwardedSignal: Deno.Signal | null;3};45export async function runDenoStatus(6 args: readonly string[],7 environment: Readonly<Record<string, string>>,8 cwd = Deno.cwd(),9): Promise<DenoRunStatus> {10 const child = new Deno.Command(Deno.execPath(), {11 args: [...args],12 cwd,13 clearEnv: true,14 env: { ...environment },15 stdin: "inherit",16 stdout: "piped",17 stderr: "piped",18 }).spawn();19 let forwardedSignal: Deno.Signal | null = null;20 const forward = (21 stream: ReadableStream<Uint8Array>,22 target: WritableStream<Uint8Array>,23 ) => stream.pipeTo(target, { preventClose: true });24 const forwardSignal = (signal: Deno.Signal) => {25 try {26 child.kill(signal);27 forwardedSignal ??= signal;28 } catch (error) {29 if (!(error instanceof Deno.errors.NotFound)) throw error;30 }31 };32 const onInterrupt = () => forwardSignal("SIGINT");33 const onTerminate = () => forwardSignal("SIGTERM");34 Deno.addSignalListener("SIGINT", onInterrupt);35 Deno.addSignalListener("SIGTERM", onTerminate);36 try {37 const [status] = await Promise.all([38 child.status,39 forward(child.stdout, Deno.stdout.writable),40 forward(child.stderr, Deno.stderr.writable),41 ]);42 return { ...status, forwardedSignal };43 } finally {44 Deno.removeSignalListener("SIGINT", onInterrupt);45 Deno.removeSignalListener("SIGTERM", onTerminate);46 }47}4849export async function runDeno(50 args: readonly string[],51 environment: Readonly<Record<string, string>>,52 cwd = Deno.cwd(),53): Promise<number> {54 return (await runDenoStatus(args, environment, cwd)).code;55}