1/**
2 * Shared child-process ENTRY for framework production builds.
3 *
4 * Executed only as a spawned process by `runBuildChild` (`BuildChild.ts`) —
5 * never imported. `argv[2]` carries the JSON {@link BuildChildPayload}: the
6 * framework source module to load (a file URL), the config for its exported
7 * `buildInChild`, and the path to persist the resulting `BuildOutput` to.
8 *
9 * This is deliberately the ONLY module in the package with top-level
10 * execution: every importable module (including the framework source
11 * modules) stays pure — their `buildInChild` exports are plain functions
12 * returning Effects, callable in-process by tests. Process concerns (argv
13 * parsing, platform services, exit codes) live here, at the process
14 * boundary where they belong.
15 */
16import * as NodeServices from "@effect/platform-node/NodeServices";
17import * as Effect from "effect/Effect";
18import * as FileSystem from "effect/FileSystem";
19import type { BuildChildModule, BuildChildPayload } from "./BuildChild.ts";
20import { writeBuildOutput } from "./BuildOutput.ts";
21
22const payload = JSON.parse(process.argv[2] ?? "{}") as BuildChildPayload;
23
24const program = Effect.gen(function* () {
25 const module = (yield* Effect.promise(
26 () => import(payload.module),
27 )) as Partial<BuildChildModule>;
28 if (typeof module.buildInChild !== "function") {
29 return yield* Effect.die(
30 new Error(
31 `Build child module ${payload.module} does not export a buildInChild function`,
32 ),
33 );
34 }
35 const output = yield* module.buildInChild(payload.config as never).pipe(
36 // Hand the failure message back to `runBuildChild` for its error.
37 Effect.tapError((error) =>
38 Effect.gen(function* () {
39 const fs = yield* FileSystem.FileSystem;
40 yield* fs
41 .writeFileString(
42 payload.errorPath,
43 error instanceof Error ? error.message : String(error),
44 )
45 .pipe(Effect.ignore);
46 }),
47 ),
48 );
49 yield* writeBuildOutput(payload.outputPath, output);
50}).pipe(Effect.provide(NodeServices.layer));
51
52void Effect.runPromise(program).then(
53 // The macrotask hop lets buffered stdout/stderr drain before exiting.
54 () => setTimeout(() => process.exit(0), 0),
55 (error) => {
56 console.error(error);
57 setTimeout(() => process.exit(1), 0);
58 },
59);