Skip to content
Source
Sign inSign up

bin.ts

60 lines2.3 KB

1// @effect-diagnostics nodeBuiltinImport:off -- The service launcher starts before the CLI runtime.
2import * as NodeModule from "node:module";
3import * as NodeSea from "node:sea";
4import * as NodeURL from "node:url";
5​
6import { isEntrypoint } from "./entrypoint.ts";
7​
8// Loads the CLI outside the launcher's module graph. Packaged builds embed it as a raw asset.
9async function loadCliMain(): Promise<typeof import("./binMain.ts")> {
10 if (!NodeSea.isSea()) return import("./binMain.ts");
11​
12 // Keep the executable's module URL so the CLI finds the web client and native packages beside it.
13 const require = NodeModule.createRequire(import.meta.url);
14 // require() resolves links in the executable path, such as a Windows junction.
15 const cliUrl = NodeURL.pathToFileURL(require.resolve(process.execPath)).href;
16 const hook = NodeModule.registerHooks({
17 load(url, context, next) {
18 if (url !== cliUrl) return next(url, context);
19 return {
20 format: "module",
21 source: new Uint8Array(NodeSea.getRawAsset("binMain.mjs")),
22 shortCircuit: true,
23 };
24 },
25 });
26 try {
27 return require(process.execPath) as typeof import("./binMain.ts");
28 } finally {
29 hook.deregister();
30 }
32​
33function ignoreOutputError(): void {}
34​
35if (
36 isEntrypoint({
37 moduleUrl: import.meta.url,
38 entryPath: process.argv[1],
39 runtimeMain: import.meta.main,
40 })
41) {
42 // Logs go to stdout and stderr, which may be a closed desktop launcher pipe or a log file on
43 // a full disk. Node emits a failed write as an unhandled stream error that crashes the process
44 // and skips shutdown, so drop the line instead.
45 process.stdout.on("error", ignoreOutputError);
46 process.stderr.on("error", ignoreOutputError);
47​
48 // The launcher owns shutdown until its child exits, so it bypasses the Effect CLI runtime.
49 // A service unit passes nothing, or on Windows the launcher's own flags; help and anything
50 // else go through the full CLI.
51 const launcher =
52 process.argv[2] === "__service-launcher" ? await import("./cli/serviceLauncher.ts") : undefined;
53 const launcherOptions = launcher?.parseServiceLauncherArgs(process.argv.slice(3));
54 if (launcher !== undefined && launcherOptions !== undefined) {
55 await launcher.runServiceLauncherCli(launcherOptions);
56 } else {
57 const { runCliCommand } = await loadCliMain();
58 await runCliCommand();
59 }