| 1 | import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; |
| 2 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 3 | import * as ConfigProvider from "effect/ConfigProvider"; |
| 4 | import * as Effect from "effect/Effect"; |
| 5 | import * as Layer from "effect/Layer"; |
| 6 | import * as Scope from "effect/Scope"; |
| 7 | import * as Framework from "./Framework.ts"; |
| 8 | import * as Server from "./Server.ts"; |
| 9 | |
| 10 | export { Cwd } from "./Cwd.ts"; |
| 11 | |
| 12 | export const layer = Server.layer.pipe( |
| 13 | Layer.provideMerge(Framework.layer), |
| 14 | Layer.provideMerge( |
| 15 | ConfigProvider.layer( |
| 16 | ConfigProvider.fromDotEnv().pipe( |
| 17 | Effect.orElseSucceed(() => ConfigProvider.fromEnv()), |
| 18 | ), |
| 19 | ), |
| 20 | ), |
| 21 | Layer.provideMerge(NodeServices.layer), |
| 22 | ); |
| 23 | |
| 24 | export const runMain = <A, E>(effect: Effect.Effect<A, E, Scope.Scope>) => { |
| 25 | const scope = Scope.makeUnsafe(); |
| 26 | return NodeRuntime.runMain(effect.pipe(Scope.provide(scope)), { |
| 27 | teardown: (exit, onExit) => { |
| 28 | Effect.runPromise(Scope.close(scope, exit)).then(() => { |
| 29 | const code = exit._tag === "Success" ? 0 : 1; |
| 30 | onExit(code); |
| 31 | // `NodeRuntime.runMain` only force-exits on failure/signal; on success |
| 32 | // it waits for the event loop to drain. The runtime layers can leave |
| 33 | // lingering handles behind (e.g. `cloudflare-runtime`'s docker proxy |
| 34 | // listener is started on a detached fiber with no finalizer, keeping |
| 35 | // the loop alive forever after a successful `e2e build`). A CLI must |
| 36 | // exit deterministically once its teardown has run. |
| 37 | process.exit(code); |
| 38 | }); |
| 39 | }, |
| 40 | }); |
| 41 | }; |