1// @effect-diagnostics nodeBuiltinImport:off
2// Entrypoint detection runs before any Effect runtime is built, so it stays on
3// Node built-ins.
4import * as NodeFS from "node:fs";
5import * as NodeURL from "node:url";
6
7/**
8 * Whether the module identified by `moduleUrl` is the process entrypoint.
9 *
10 * `import.meta.main` answers this directly, but it only exists on Node 22.18+
11 * and 24.2+. This package's `engines.node` range also accepts 22.16, 22.17 and
12 * 23.11, where it is `undefined`: an `if (import.meta.main)` guard never runs,
13 * so the process loads every module and exits 0 without output. Fall back to
14 * comparing the entrypoint path on those versions.
15 */
16export const isEntrypoint = (input: {
17 readonly moduleUrl: string;
18 readonly entryPath: string | undefined;
19 readonly runtimeMain: boolean | undefined;
20}): boolean => {
21 if (input.runtimeMain !== undefined) {
22 return input.runtimeMain;
23 }
24 if (input.entryPath === undefined || input.entryPath === "") {
25 return false;
26 }
27 if (input.moduleUrl === NodeURL.pathToFileURL(input.entryPath).href) {
28 return true;
29 }
30 // npm and npx install the CLI as a symlink. Without `--preserve-symlinks` the
31 // module URL is the resolved real path while `process.argv[1]` keeps the link
32 // path, so the comparison above misses.
33 try {
34 return input.moduleUrl === NodeURL.pathToFileURL(NodeFS.realpathSync(input.entryPath)).href;
35 } catch {
36 return false;
37 }
38};