| 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 | |
| 14 | export const process: Process | undefined = |
| 15 | (globalThis as { process?: Process }).process && |
| 16 | (globalThis as { process?: Process }).process?.versions?.node |
| 17 | ? (globalThis as { process?: Process }).process |
| 18 | : undefined; |
| 19 | |
| 20 | export const isServer: boolean = !!process; |
| 21 | |
| 22 | /** partial types for Node.js `globalThis.process` */ |
| 23 | interface Process { |
| 24 | getBuiltinModule<K extends keyof Builtins>(name: K): Builtins[K] | null; |
| 25 | binding?<K extends keyof Bindings>(name: K): Bindings[K] | null; |
| 26 | addListener(event: string, callback: () => void): this; |
| 27 | prependListener(event: string, callback: () => void): this; |
| 28 | removeListener(event: string, callback: () => void): this; |
| 29 | listenerCount(event: string): number; |
| 30 | kill(pid: number, signal: string): boolean; |
| 31 | env: Partial<Record<string, string>>; |
| 32 | pid: number; |
| 33 | ppid: number; |
| 34 | platform: string; |
| 35 | versions: { node?: string; bun?: string; deno?: string }; |
| 36 | stdin: TtyInput; |
| 37 | stdout: Tty; |
| 38 | stderr: Tty; |
| 39 | } |
| 40 | |
| 41 | /** the raw mode members are only present when the stream is a tty */ |
| 42 | interface TtyInput { |
| 43 | isRaw: boolean; |
| 44 | setRawMode(mode: boolean): this; |
| 45 | addListener(event: "data", callback: (chunk: Uint8Array | string) => void): this; |
| 46 | removeListener(event: "data", callback: (chunk: Uint8Array | string) => void): this; |
| 47 | listenerCount(event: string): number; |
| 48 | pause(): this; |
| 49 | resume(): this; |
| 50 | } |
| 51 | |
| 52 | interface Tty { |
| 53 | isTTY: boolean; |
| 54 | /** only present when the stream is a tty */ |
| 55 | columns: number | undefined; |
| 56 | /** only present when the stream is a tty */ |
| 57 | rows: number | undefined; |
| 58 | addListener(event: string, callback: () => void): this; |
| 59 | removeListener(event: string, callback: () => void): this; |
| 60 | end(text?: string | Uint8Array): this; |
| 61 | write(text: string | Uint8Array): boolean; |
| 62 | } |
| 63 | |
| 64 | /** |
| 65 | * Subset of Node.js builtin types needed to not depend on the problematic |
| 66 | * "@types/node" package. |
| 67 | */ |
| 68 | interface Builtins { |
| 69 | child_process: { |
| 70 | spawnSync(command: string, args: string[], options: { stdio: "ignore" }): unknown; |
| 71 | }; |
| 72 | fs: { |
| 73 | existsSync(file: string): boolean; |
| 74 | readFileSync(file: string, encoding: "utf-8"): string; |
| 75 | readFileSync(file: string): Uint8Array; |
| 76 | writeFileSync(file: string, data: string, options?: { mode?: number }): void; |
| 77 | appendFileSync(file: string, data: string, options?: { mode?: number }): void; |
| 78 | writeSync(fd: number, data: string): number; |
| 79 | mkdirSync(dir: string, options: { recursive: true }): void; |
| 80 | }; |
| 81 | inspector: { |
| 82 | Session: new () => { |
| 83 | connect(): void; |
| 84 | post( |
| 85 | method: string, |
| 86 | params: object, |
| 87 | // the result is whatever the Chrome DevTools Protocol method returns |
| 88 | callback: (error: Error | null, result: any) => void, |
| 89 | ): void; |
| 90 | }; |
| 91 | }; |
| 92 | path: { |
| 93 | isAbsolute(file: string): boolean; |
| 94 | dirname(file: string): string; |
| 95 | basename(file: string): string; |
| 96 | join(...parts: string[]): string; |
| 97 | resolve(...parts: string[]): string; |
| 98 | sep: string; |
| 99 | }; |
| 100 | tty: { |
| 101 | isatty(fd: number): boolean; |
| 102 | }; |
| 103 | url: { |
| 104 | pathToFileURL(file: string): URL; |
| 105 | }; |
| 106 | util: { |
| 107 | inspect(object: unknown, options?: { colors?: boolean }): string; |
| 108 | formatWithOptions(options: { colors?: boolean }, ...args: unknown[]): string; |
| 109 | }; |
| 110 | stream: { |
| 111 | Readable: { |
| 112 | toWeb(nodeStream: unknown): ReadableStream; |
| 113 | fromWeb(webStream: ReadableStream): { pipe: (other: unknown) => void }; |
| 114 | }; |
| 115 | Writable: { |
| 116 | prototype: { |
| 117 | write: (value: string) => boolean; |
| 118 | }; |
| 119 | }; |
| 120 | }; |
| 121 | } |
| 122 | |
| 123 | /** subset of Node.js binding types */ |
| 124 | interface Bindings { |
| 125 | /** |
| 126 | * key value mapping of internal module id to its source code. |
| 127 | * ``` |
| 128 | * { "fs": "// Copyright Joyent, Inc. and other Node contributors.\n... |
| 129 | * ``` |
| 130 | */ |
| 131 | natives: Partial<Record<string, string>>; |
| 132 | } |
| 133 | |
| 134 | /** return a built-in module */ |
| 135 | export function builtin<K extends keyof Builtins>(name: K): Builtins[K] | undefined { |
| 136 | return process?.getBuiltinModule(name) ?? undefined; |
| 137 | } |
| 138 | |
| 139 | /** return a built-in semi-private binding */ |
| 140 | export function binding<K extends keyof Bindings>(name: K): Bindings[K] | undefined { |
| 141 | if (!process) return undefined; |
| 142 | try { |
| 143 | return process.binding?.(name) ?? undefined; |
| 144 | } catch { |
| 145 | return undefined; |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | /** copy of `keyof typeof import('node:os').constants.errno` */ |
| 150 | // deno-fmt-ignore-next |
| 151 | export type ErrorCode = |
| 152 | | (string & {}) |
| 153 | | "E2BIG" |
| 154 | | "EACCES" |
| 155 | | "EADDRINUSE" |
| 156 | | "EADDRNOTAVAIL" |
| 157 | | "EAFNOSUPPORT" |
| 158 | | "EAGAIN" |
| 159 | | "EALREADY" |
| 160 | | "EBADF" |
| 161 | | "EBADMSG" |
| 162 | | "EBUSY" |
| 163 | | "ECANCELED" |
| 164 | | "ECHILD" |
| 165 | | "ECONNABORTED" |
| 166 | | "ECONNREFUSED" |
| 167 | | "ECONNRESET" |
| 168 | | "EDEADLK" |
| 169 | | "EDESTADDRREQ" |
| 170 | | "EDOM" |
| 171 | | "EDQUOT" |
| 172 | | "EEXIST" |
| 173 | | "EFAULT" |
| 174 | | "EFBIG" |
| 175 | | "EHOSTUNREACH" |
| 176 | | "EIDRM" |
| 177 | | "EILSEQ" |
| 178 | | "EINPROGRESS" |
| 179 | | "EINTR" |
| 180 | | "EINVAL" |
| 181 | | "EIO" |
| 182 | | "EISCONN" |
| 183 | | "EISDIR" |
| 184 | | "ELOOP" |
| 185 | | "EMFILE" |
| 186 | | "EMLINK" |
| 187 | | "EMSGSIZE" |
| 188 | | "EMULTIHOP" |
| 189 | | "ENAMETOOLONG" |
| 190 | | "ENETDOWN" |
| 191 | | "ENETRESET" |
| 192 | | "ENETUNREACH" |
| 193 | | "ENFILE" |
| 194 | | "ENOBUFS" |
| 195 | | "ENODATA" |
| 196 | | "ENODEV" |
| 197 | | "ENOENT" |
| 198 | | "ENOEXEC" |
| 199 | | "ENOLCK" |
| 200 | | "ENOLINK" |
| 201 | | "ENOMEM" |
| 202 | | "ENOMSG" |
| 203 | | "ENOPROTOOPT" |
| 204 | | "ENOSPC" |
| 205 | | "ENOSR" |
| 206 | | "ENOSTR" |
| 207 | | "ENOSYS" |
| 208 | | "ENOTCONN" |
| 209 | | "ENOTDIR" |
| 210 | | "ENOTEMPTY" |
| 211 | | "ENOTSOCK" |
| 212 | | "ENOTSUP" |
| 213 | | "ENOTTY" |
| 214 | | "ENXIO" |
| 215 | | "EOPNOTSUPP" |
| 216 | | "EOVERFLOW" |
| 217 | | "EPERM" |
| 218 | | "EPIPE" |
| 219 | | "EPROTO" |
| 220 | | "EPROTONOSUPPORT" |
| 221 | | "EPROTOTYPE" |
| 222 | | "ERANGE" |
| 223 | | "EROFS" |
| 224 | | "ESPIPE" |
| 225 | | "ESRCH" |
| 226 | | "ESTALE" |
| 227 | | "ETIME" |
| 228 | | "ETIMEDOUT" |
| 229 | | "ETXTBSY" |
| 230 | | "EWOULDBLOCK" |
| 231 | | "EXDEV" |
| 232 | | "WSAEINTR" |
| 233 | | "WSAEBADF" |
| 234 | | "WSAEACCES" |
| 235 | | "WSAEFAULT" |
| 236 | | "WSAEINVAL" |
| 237 | | "WSAEMFILE" |
| 238 | | "WSAEWOULDBLOCK" |
| 239 | | "WSAEINPROGRESS" |
| 240 | | "WSAEALREADY" |
| 241 | | "WSAENOTSOCK" |
| 242 | | "WSAEDESTADDRREQ" |
| 243 | | "WSAEMSGSIZE" |
| 244 | | "WSAEPROTOTYPE" |
| 245 | | "WSAENOPROTOOPT" |
| 246 | | "WSAEPROTONOSUPPORT" |
| 247 | | "WSAESOCKTNOSUPPORT" |
| 248 | | "WSAEOPNOTSUPP" |
| 249 | | "WSAEPFNOSUPPORT" |
| 250 | | "WSAEAFNOSUPPORT" |
| 251 | | "WSAEADDRINUSE" |
| 252 | | "WSAEADDRNOTAVAIL" |
| 253 | | "WSAENETDOWN" |
| 254 | | "WSAENETUNREACH" |
| 255 | | "WSAENETRESET" |
| 256 | | "WSAECONNABORTED" |
| 257 | | "WSAECONNRESET" |
| 258 | | "WSAENOBUFS" |
| 259 | | "WSAEISCONN" |
| 260 | | "WSAENOTCONN" |
| 261 | | "WSAESHUTDOWN" |
| 262 | | "WSAETOOMANYREFS" |
| 263 | | "WSAETIMEDOUT" |
| 264 | | "WSAECONNREFUSED" |
| 265 | | "WSAELOOP" |
| 266 | | "WSAENAMETOOLONG" |
| 267 | | "WSAEHOSTDOWN" |
| 268 | | "WSAEHOSTUNREACH" |
| 269 | | "WSAENOTEMPTY" |
| 270 | | "WSAEPROCLIM" |
| 271 | | "WSAEUSERS" |
| 272 | | "WSAEDQUOT" |
| 273 | | "WSAESTALE" |
| 274 | | "WSAEREMOTE" |
| 275 | | "WSASYSNOTREADY" |
| 276 | | "WSAVERNOTSUPPORTED" |
| 277 | | "WSANOTINITIALISED" |
| 278 | | "WSAEDISCON" |
| 279 | | "WSAENOMORE" |
| 280 | | "WSAECANCELLED" |
| 281 | | "WSAEINVALIDPROCTABLE" |
| 282 | | "WSAEINVALIDPROVIDER" |
| 283 | | "WSAEPROVIDERFAILEDINIT" |
| 284 | | "WSASYSCALLFAILURE" |
| 285 | | "WSASERVICE_NOT_FOUND" |
| 286 | | "WSATYPE_NOT_FOUND" |
| 287 | | "WSA_E_NO_MORE" |
| 288 | | "WSA_E_CANCELLED" |
| 289 | | "WSAEREFUSED"; |