1/**
2 * functions to load Node.js apis via `globalThis.process`. trivially bundlable
3 * for the browser. does not depend on `@types/node` and does not intend to
4 * define types for the entire api. instead, this file's types are used for
5 * other library modules like `lib/log.ts` to bind to the system.
6 *
7 * if you are using a competent bundler, you can define `globalThis.process` as
8 * a bundling constant (esbuild: `--define`) to enable tree shaking across the
9 * library to only include browser code paths.
10 *
11 * @module
12 */
13
14export const process: Process | undefined = (globalThis as { process?: Process }).process
15 && (globalThis as { process?: Process }).process?.versions?.node
16 ? (globalThis as { process?: Process }).process
17 : undefined;
18
19export const isServer: boolean = !!process;
20
21/** partial types for Node.js `globalThis.process` */
22interface Process {
23 getBuiltinModule<K extends keyof Builtins>(name: K): Builtins[K] | null;
24 binding?<K extends keyof Bindings>(name: K): Bindings[K] | null;
25 addListener(event: string, callback: () => void): this;
26 versions: { node?: string; bun?: string; deno?: string };
27 stdout: Tty;
28 stderr: Tty;
29}
30
31interface Tty {
32 isTTY: boolean;
33 /** only present when the stream is a tty */
34 columns: number | undefined;
35 /** only present when the stream is a tty */
36 rows: number | undefined;
37 addListener(event: string, callback: () => void): this;
38 removeListener(event: string, callback: () => void): this;
39 end(text?: string | Uint8Array): this;
40 write(text: string | Uint8Array): boolean;
41}
42
43/**
44 * Subset of Node.js builtin types needed to not depend on the problematic
45 * "@types/node" package.
46 */
47interface Builtins {
48 "fs": {
49 existsSync(file: string): boolean;
50 readFileSync(file: string, encoding: "utf-8"): string;
51 readFileSync(file: string): Uint8Array;
52 };
53 "path": {
54 isAbsolute(file: string): boolean;
55 dirname(file: string): string;
56 basename(file: string): string;
57 join(...parts: string[]): string;
58 sep: string;
59 };
60 "util": {
61 inspect(object: unknown): string;
62 formatWithOptions(
63 options: { colors?: boolean },
64 ...args: unknown[]
65 ): string;
66 };
67 "stream": {
68 Readable: {
69 toWeb(nodeStream: unknown): ReadableStream;
70 fromWeb(webStream: ReadableStream): { pipe: (other: unknown) => void };
71 };
72 Writable: {
73 prototype: {
74 write: (value: string) => boolean;
75 };
76 };
77 };
78}
79
80/** subset of Node.js binding types */
81interface Bindings {
82 /**
83 * key value mapping of internal module id to its source code.
84 * ```
85 * { "fs": "// Copyright Joyent, Inc. and other Node contributors.\n...
86 * ```
87 */
88 "natives": Partial<Record<string, string>>;
89}
90
91/** return a built-in module */
92export function builtin<K extends keyof Builtins>(
93 name: K,
94): Builtins[K] | undefined {
95 return process?.getBuiltinModule(name) ?? undefined;
96}
97
98/** return a built-in semi-private binding */
99export function binding<K extends keyof Bindings>(
100 name: K,
101): Bindings[K] | undefined {
102 if (!process) return undefined;
103 try {
104 return process.binding?.(name) ?? undefined;
105 } catch {
106 return undefined;
107 }
108}
109
110/** copy of `keyof typeof import('node:os').constants.errno` */
111// deno-fmt-ignore-next
112export type ErrorCode =
113 | (string & {})
114 | "E2BIG"
115 | "EACCES"
116 | "EADDRINUSE"
117 | "EADDRNOTAVAIL"
118 | "EAFNOSUPPORT"
119 | "EAGAIN"
120 | "EALREADY"
121 | "EBADF"
122 | "EBADMSG"
123 | "EBUSY"
124 | "ECANCELED"
125 | "ECHILD"
126 | "ECONNABORTED"
127 | "ECONNREFUSED"
128 | "ECONNRESET"
129 | "EDEADLK"
130 | "EDESTADDRREQ"
131 | "EDOM"
132 | "EDQUOT"
133 | "EEXIST"
134 | "EFAULT"
135 | "EFBIG"
136 | "EHOSTUNREACH"
137 | "EIDRM"
138 | "EILSEQ"
139 | "EINPROGRESS"
140 | "EINTR"
141 | "EINVAL"
142 | "EIO"
143 | "EISCONN"
144 | "EISDIR"
145 | "ELOOP"
146 | "EMFILE"
147 | "EMLINK"
148 | "EMSGSIZE"
149 | "EMULTIHOP"
150 | "ENAMETOOLONG"
151 | "ENETDOWN"
152 | "ENETRESET"
153 | "ENETUNREACH"
154 | "ENFILE"
155 | "ENOBUFS"
156 | "ENODATA"
157 | "ENODEV"
158 | "ENOENT"
159 | "ENOEXEC"
160 | "ENOLCK"
161 | "ENOLINK"
162 | "ENOMEM"
163 | "ENOMSG"
164 | "ENOPROTOOPT"
165 | "ENOSPC"
166 | "ENOSR"
167 | "ENOSTR"
168 | "ENOSYS"
169 | "ENOTCONN"
170 | "ENOTDIR"
171 | "ENOTEMPTY"
172 | "ENOTSOCK"
173 | "ENOTSUP"
174 | "ENOTTY"
175 | "ENXIO"
176 | "EOPNOTSUPP"
177 | "EOVERFLOW"
178 | "EPERM"
179 | "EPIPE"
180 | "EPROTO"
181 | "EPROTONOSUPPORT"
182 | "EPROTOTYPE"
183 | "ERANGE"
184 | "EROFS"
185 | "ESPIPE"
186 | "ESRCH"
187 | "ESTALE"
188 | "ETIME"
189 | "ETIMEDOUT"
190 | "ETXTBSY"
191 | "EWOULDBLOCK"
192 | "EXDEV"
193 | "WSAEINTR"
194 | "WSAEBADF"
195 | "WSAEACCES"
196 | "WSAEFAULT"
197 | "WSAEINVAL"
198 | "WSAEMFILE"
199 | "WSAEWOULDBLOCK"
200 | "WSAEINPROGRESS"
201 | "WSAEALREADY"
202 | "WSAENOTSOCK"
203 | "WSAEDESTADDRREQ"
204 | "WSAEMSGSIZE"
205 | "WSAEPROTOTYPE"
206 | "WSAENOPROTOOPT"
207 | "WSAEPROTONOSUPPORT"
208 | "WSAESOCKTNOSUPPORT"
209 | "WSAEOPNOTSUPP"
210 | "WSAEPFNOSUPPORT"
211 | "WSAEAFNOSUPPORT"
212 | "WSAEADDRINUSE"
213 | "WSAEADDRNOTAVAIL"
214 | "WSAENETDOWN"
215 | "WSAENETUNREACH"
216 | "WSAENETRESET"
217 | "WSAECONNABORTED"
218 | "WSAECONNRESET"
219 | "WSAENOBUFS"
220 | "WSAEISCONN"
221 | "WSAENOTCONN"
222 | "WSAESHUTDOWN"
223 | "WSAETOOMANYREFS"
224 | "WSAETIMEDOUT"
225 | "WSAECONNREFUSED"
226 | "WSAELOOP"
227 | "WSAENAMETOOLONG"
228 | "WSAEHOSTDOWN"
229 | "WSAEHOSTUNREACH"
230 | "WSAENOTEMPTY"
231 | "WSAEPROCLIM"
232 | "WSAEUSERS"
233 | "WSAEDQUOT"
234 | "WSAESTALE"
235 | "WSAEREMOTE"
236 | "WSASYSNOTREADY"
237 | "WSAVERNOTSUPPORTED"
238 | "WSANOTINITIALISED"
239 | "WSAEDISCON"
240 | "WSAENOMORE"
241 | "WSAECANCELLED"
242 | "WSAEINVALIDPROCTABLE"
243 | "WSAEINVALIDPROVIDER"
244 | "WSAEPROVIDERFAILEDINIT"
245 | "WSASYSCALLFAILURE"
246 | "WSASERVICE_NOT_FOUND"
247 | "WSATYPE_NOT_FOUND"
248 | "WSA_E_NO_MORE"
249 | "WSA_E_CANCELLED"
250 | "WSAEREFUSED";