|
| 1 | +import { Command, Options } from "@effect/cli"; |
| 2 | +import { NodeContext, NodeRuntime } from "@effect/platform-node"; |
| 3 | +import * as Path from "@effect/platform/Path"; |
| 4 | +import { Data, Effect, Option } from "effect"; |
| 5 | +import { NodeServer } from "effect-http-node"; |
| 6 | +import * as PrettyLogger from "effect-log/PrettyLogger"; |
| 7 | +import * as importx from "importx"; |
| 8 | +import pkg from "../package.json"; |
| 9 | +import * as CliConfig from "./CliConfig.js"; |
| 10 | +import * as ExampleServer from "./ExampleServer.js"; |
| 11 | +import * as RouterBuilder from "./RouterBuilder.js"; |
| 12 | + |
| 13 | + |
| 14 | +/** |
| 15 | + * An error that occurs when loading the config file. |
| 16 | + */ |
| 17 | +class ConfigError extends Data.TaggedError("ConfigError")<{ |
| 18 | + message: string; |
| 19 | +}> {} |
| 20 | + |
| 21 | +const configArg = Options.file("config").pipe( |
| 22 | + Options.withAlias("c"), |
| 23 | + Options.withDescription("Path to the config file"), |
| 24 | + Options.withDefault("./effect-http.config.ts"), |
| 25 | +); |
| 26 | + |
| 27 | +const portArg = Options.integer("port").pipe( |
| 28 | + Options.withAlias("p"), |
| 29 | + Options.withDescription("Port to run the server on"), |
| 30 | + Options.optional |
| 31 | +); |
| 32 | + |
| 33 | +const loadConfig = (relativePath: string) => |
| 34 | + Effect.flatMap(Path.Path, (path) => |
| 35 | + Effect.tryPromise(() => |
| 36 | + importx.import(path.join(process.cwd(), relativePath), import.meta.url), |
| 37 | + ).pipe( |
| 38 | + Effect.mapError( |
| 39 | + () => new ConfigError({ message: `Failed to find config at ${path}` }), |
| 40 | + ), |
| 41 | + Effect.flatMap((module) => |
| 42 | + module?.default |
| 43 | + ? Effect.succeed(module.default) |
| 44 | + : new ConfigError({ message: `No default export found in ${path}` }), |
| 45 | + ), |
| 46 | + Effect.flatMap((defaultExport) => |
| 47 | + defaultExport instanceof CliConfig.CliConfig |
| 48 | + ? Effect.succeed(defaultExport) |
| 49 | + : new ConfigError({ message: `Invalid config found in ${path}` }), |
| 50 | + ), |
| 51 | + Effect.withSpan("loadConfig", { attributes: { path } }) |
| 52 | + ), |
| 53 | + ); |
| 54 | + |
| 55 | +const command = Command.make("serve", { config: configArg, port: portArg }, (args) => |
| 56 | + Effect.gen(function* () { |
| 57 | + const config = yield* loadConfig(args.config); |
| 58 | + const port = Option.getOrUndefined(args.port) ?? config.server?.port ?? 11779; |
| 59 | + yield* ExampleServer.make(config.api).pipe(RouterBuilder.buildPartial, NodeServer.listen({ port })) |
| 60 | + }), |
| 61 | +); |
| 62 | + |
| 63 | +const cli = Command.run(command, { |
| 64 | + name: "Effect Http Cli", |
| 65 | + version: `v${pkg.version}`, |
| 66 | +}); |
| 67 | + |
| 68 | +cli(process.argv).pipe( |
| 69 | + Effect.provide(NodeContext.layer), |
| 70 | + Effect.provide(PrettyLogger.layer({ showFiberId: false })), |
| 71 | + NodeRuntime.runMain, |
| 72 | +); |
0 commit comments