1/**
2 * Process bootstrap for `Hetzner.Service` (a Node process serving the
3 * bundled program). The generated entry imports this module and the user's
4 * `main`, nothing else — see {@link ./Process.ts} for why.
5 */
6import { NodeServices } from "@effect/platform-node";
7import * as ConfigProvider from "effect/ConfigProvider";
8import * as Effect from "effect/Effect";
9import * as Layer from "effect/Layer";
10import * as Logger from "effect/Logger";
11import * as FetchHttpClient from "effect/http/FetchHttpClient";
12import { NodeHttpServer } from "../../Http.ts";
13import { reifyBoundConfigProvider } from "../../Runtime.ts";
14import {
15 entrypointLayer,
16 resolveProgram,
17 runProcess,
18 stackFromEnv,
19} from "./Process.ts";
20
21/**
22 * Resolve the bundled program (the runners registered via `host.run` /
23 * serve) and run it with a Node HTTP server bound to `PORT`, so the
24 * returned `{ fetch }` handler is actually served and `host.run` loops
25 * stay alive.
26 */
27export const bootstrap = (entrypoint: unknown): Promise<void> => {
28 const platform = Layer.mergeAll(
29 NodeServices.layer,
30 FetchHttpClient.layer,
31 Logger.layer([Logger.consolePretty()]),
32 );
33
34 const program = resolveProgram("program").pipe(
35 Effect.provide(
36 entrypointLayer(entrypoint).pipe(
37 Layer.provideMerge(stackFromEnv),
38 Layer.provideMerge(NodeHttpServer({ hostname: "0.0.0.0" })),
39 Layer.provideMerge(platform),
40 Layer.provideMerge(
41 Layer.succeed(
42 ConfigProvider.ConfigProvider,
43 reifyBoundConfigProvider(ConfigProvider.fromEnv(), process.env),
44 ),
45 ),
46 ),
47 ),
48 Effect.scoped,
49 );
50
51 return runProcess("Hetzner service", program);
52};