├── .nvmrc ├── .prettierrc ├── .github ├── CODEOWNERS └── workflows │ ├── autofix.yml │ └── ci.yml ├── .prettierignore ├── lib ├── mock.d.cts └── mock.cjs ├── src ├── runtime │ ├── polyfill │ │ ├── package.json │ │ ├── globalthis.ts │ │ ├── buffer.ts │ │ ├── globalthis-global.ts │ │ ├── timers.ts │ │ ├── process.ts │ │ ├── source-maps.ts │ │ └── performance.ts │ ├── mock │ │ ├── noop.ts │ │ ├── empty.ts │ │ └── proxy.ts │ ├── node │ │ ├── sys.ts │ │ ├── path │ │ │ ├── posix.ts │ │ │ └── win32.ts │ │ ├── internal │ │ │ ├── process │ │ │ │ ├── node-version.ts │ │ │ │ ├── hrtime.ts │ │ │ │ ├── env.ts │ │ │ │ └── nexttick.ts │ │ │ ├── tls │ │ │ │ ├── secure-context.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── server.ts │ │ │ │ └── tls-socket.ts │ │ │ ├── vm │ │ │ │ ├── constants.ts │ │ │ │ └── script.ts │ │ │ ├── v8 │ │ │ │ ├── profiler.ts │ │ │ │ ├── serializer.ts │ │ │ │ └── deserializer.ts │ │ │ ├── worker_threads │ │ │ │ ├── message-channel.ts │ │ │ │ ├── broadcast-channel.ts │ │ │ │ ├── message-port.ts │ │ │ │ └── worker.ts │ │ │ ├── trace_events │ │ │ │ └── tracing.ts │ │ │ ├── util │ │ │ │ ├── inherits.ts │ │ │ │ ├── promisify.ts │ │ │ │ ├── mime.ts │ │ │ │ ├── log.ts │ │ │ │ └── legacy-types.ts │ │ │ ├── url │ │ │ │ ├── util.ts │ │ │ │ ├── constants.ts │ │ │ │ └── errors.ts │ │ │ ├── crypto │ │ │ │ ├── web.ts │ │ │ │ └── constants.ts │ │ │ ├── tty │ │ │ │ ├── read-stream.ts │ │ │ │ └── write-stream.ts │ │ │ ├── readline │ │ │ │ ├── promises │ │ │ │ │ ├── interface.ts │ │ │ │ │ └── readline.ts │ │ │ │ └── interface.ts │ │ │ ├── zlib │ │ │ │ ├── codes.ts │ │ │ │ └── formats │ │ │ │ │ ├── zip.ts │ │ │ │ │ ├── gzip.ts │ │ │ │ │ ├── brotli.ts │ │ │ │ │ ├── deflate.ts │ │ │ │ │ └── _shared.ts │ │ │ ├── http │ │ │ │ ├── agent.ts │ │ │ │ ├── request.ts │ │ │ │ └── constants.ts │ │ │ ├── timers │ │ │ │ ├── scheduler.ts │ │ │ │ ├── set-interval.ts │ │ │ │ ├── set-immediate.ts │ │ │ │ ├── set-timeout.ts │ │ │ │ ├── timeout.ts │ │ │ │ └── immediate.ts │ │ │ ├── domain │ │ │ │ └── domain.ts │ │ │ ├── stream │ │ │ │ ├── transform.ts │ │ │ │ └── duplex.ts │ │ │ ├── fs │ │ │ │ ├── classes.ts │ │ │ │ ├── constants.ts │ │ │ │ └── promises.ts │ │ │ ├── buffer │ │ │ │ ├── file.ts │ │ │ │ └── ieee754.ts │ │ │ ├── net │ │ │ │ ├── server.ts │ │ │ │ └── socket.ts │ │ │ ├── dns │ │ │ │ └── constants.ts │ │ │ ├── dgram │ │ │ │ └── socket.ts │ │ │ ├── async_hooks │ │ │ │ ├── async-local-storage.ts │ │ │ │ ├── async-resource.ts │ │ │ │ └── async-hook.ts │ │ │ ├── perf_hooks │ │ │ │ ├── constants.ts │ │ │ │ └── histogram.ts │ │ │ ├── diagnostics_channel │ │ │ │ ├── channel.ts │ │ │ │ └── tracing-channel.ts │ │ │ ├── os │ │ │ │ └── constants.ts │ │ │ └── querystring │ │ │ │ └── querystring.ts │ │ ├── util │ │ │ └── types.ts │ │ ├── punycode.ts │ │ ├── wasi.ts │ │ ├── stream │ │ │ ├── promises.ts │ │ │ ├── consumers.ts │ │ │ └── web.ts │ │ ├── string_decoder.ts │ │ ├── trace_events.ts │ │ ├── dgram.ts │ │ ├── sqlite.ts │ │ ├── domain.ts │ │ ├── tty.ts │ │ ├── readline │ │ │ └── promises.ts │ │ ├── async_hooks.ts │ │ ├── timers │ │ │ └── promises.ts │ │ ├── https.ts │ │ ├── readline.ts │ │ ├── events.ts │ │ ├── fs │ │ │ └── promises.ts │ │ ├── repl.ts │ │ ├── child_process.ts │ │ ├── path.ts │ │ ├── assert │ │ │ └── strict.ts │ │ ├── buffer.ts │ │ ├── inspector │ │ │ └── promises.ts │ │ ├── timers.ts │ │ ├── diagnostics_channel.ts │ │ ├── vm.ts │ │ ├── inspector.ts │ │ ├── tls.ts │ │ ├── process.ts │ │ ├── cluster.ts │ │ ├── http.ts │ │ ├── worker_threads.ts │ │ ├── net.ts │ │ ├── console.ts │ │ ├── perf_hooks.ts │ │ └── stream.ts │ ├── npm │ │ ├── inherits.ts │ │ ├── whatwg-url │ │ │ ├── webidl2js-wrapper.ts │ │ │ └── index.ts │ │ ├── cross-fetch.ts │ │ ├── fsevents.ts │ │ ├── node-fetch.ts │ │ └── debug.ts │ ├── _internal │ │ ├── types.ts │ │ └── utils.ts │ └── web │ │ └── performance │ │ └── index.ts ├── index.ts ├── types.ts └── preset.ts ├── .gitignore ├── renovate.json ├── test ├── workerd │ └── config.capnp ├── node.test.ts ├── node-env.test.ts ├── node │ ├── test-url-format-invalid-input.mjs │ ├── test-querystring-multichar-separator.mjs │ ├── test-url-domain-ascii-unicode.mjs │ ├── test-querystring-escape.mjs │ ├── test-url-urltooptions.mjs │ ├── test-querystring-maxKeys-non-finite.mjs │ ├── test-url-parse-invalid-input.mjs │ └── test-url-parse-query.mjs ├── node-coverage.test.ts ├── workerd.test.ts ├── mock.test.ts └── env.test.ts ├── tsconfig.json ├── LICENSE ├── eslint.config.mjs └── package.json /.nvmrc: -------------------------------------------------------------------------------- 1 | 22.14.0 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @pi0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .github/CODEOWNERS 2 | -------------------------------------------------------------------------------- /lib/mock.d.cts: -------------------------------------------------------------------------------- 1 | export = unknown; 2 | -------------------------------------------------------------------------------- /src/runtime/polyfill/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "sideEffects": true 3 | } 4 | -------------------------------------------------------------------------------- /src/runtime/mock/noop.ts: -------------------------------------------------------------------------------- 1 | export default Object.assign(() => {}, { __unenv__: true }); 2 | -------------------------------------------------------------------------------- /src/runtime/node/sys.ts: -------------------------------------------------------------------------------- 1 | export * from "./util.ts"; 2 | export { default } from "./util.ts"; 3 | -------------------------------------------------------------------------------- /src/runtime/npm/inherits.ts: -------------------------------------------------------------------------------- 1 | import { inherits } from "node:util"; 2 | 3 | export default inherits; 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | node_modules 3 | *.log* 4 | dist 5 | /runtime 6 | .tmp 7 | .wrangler 8 | coverage 9 | -------------------------------------------------------------------------------- /src/runtime/node/path/posix.ts: -------------------------------------------------------------------------------- 1 | export * from "../path.ts"; 2 | export { default } from "../path.ts"; 3 | -------------------------------------------------------------------------------- /src/runtime/node/path/win32.ts: -------------------------------------------------------------------------------- 1 | export * from "../path.ts"; 2 | export { default } from "../path.ts"; 3 | -------------------------------------------------------------------------------- /src/runtime/node/internal/process/node-version.ts: -------------------------------------------------------------------------------- 1 | // Extracted from .nvmrc 2 | export const NODE_VERSION = "22.14.0"; 3 | -------------------------------------------------------------------------------- /src/runtime/polyfill/globalthis.ts: -------------------------------------------------------------------------------- 1 | // Injectable version of `globalThis.global` (without side effects) 2 | export default globalThis; 3 | -------------------------------------------------------------------------------- /src/runtime/mock/empty.ts: -------------------------------------------------------------------------------- 1 | export default Object.freeze( 2 | Object.create(null, { 3 | __unenv__: { get: () => true }, 4 | }), 5 | ); 6 | -------------------------------------------------------------------------------- /src/runtime/polyfill/buffer.ts: -------------------------------------------------------------------------------- 1 | import { Buffer } from "node:buffer"; 2 | 3 | if (!globalThis.Buffer) { 4 | globalThis.Buffer = Buffer; 5 | } 6 | -------------------------------------------------------------------------------- /src/runtime/npm/whatwg-url/webidl2js-wrapper.ts: -------------------------------------------------------------------------------- 1 | export const URL = globalThis.URL; 2 | export const URLSearchParams = globalThis.URLSearchParams; 3 | -------------------------------------------------------------------------------- /src/runtime/node/internal/tls/secure-context.ts: -------------------------------------------------------------------------------- 1 | import type nodeTls from "node:tls"; 2 | 3 | export class SecureContext implements nodeTls.SecureContext { 4 | context = {}; 5 | } 6 | -------------------------------------------------------------------------------- /src/runtime/polyfill/globalthis-global.ts: -------------------------------------------------------------------------------- 1 | // Node.js compatibility 2 | if (!("global" in globalThis)) { 3 | globalThis.global = globalThis; 4 | } 5 | 6 | export default globalThis; 7 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["github>unjs/renovate-config"], 4 | "ignoreDeps": [ 5 | "@types/node" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { defineEnv } from "./env.ts"; 2 | 3 | export type { 4 | Preset, 5 | Environment, 6 | CreateEnvOptions, 7 | ResolvedEnvironment, 8 | EnvResolveOptions, 9 | } from "./types.ts"; 10 | -------------------------------------------------------------------------------- /src/runtime/_internal/types.ts: -------------------------------------------------------------------------------- 1 | export type Callback = (error?: E) => void; 2 | export type HeadersObject = { [key: string]: string | string[] | undefined }; 3 | export type BufferEncoding = any; // TODO 4 | -------------------------------------------------------------------------------- /src/runtime/node/internal/vm/constants.ts: -------------------------------------------------------------------------------- 1 | export const USE_MAIN_CONTEXT_DEFAULT_LOADER = /*@__PURE__*/ Symbol( 2 | "vm_dynamic_import_main_context_default", 3 | ); 4 | 5 | export const DONT_CONTEXTIFY = /*@__PURE__*/ Symbol("vm_context_no_contextify"); 6 | -------------------------------------------------------------------------------- /src/runtime/node/util/types.ts: -------------------------------------------------------------------------------- 1 | import type nodeUtilTypes from "node:util/types"; 2 | 3 | import * as types from "../internal/util/types.ts"; 4 | 5 | export * from "../internal/util/types.ts"; 6 | 7 | export default types satisfies typeof nodeUtilTypes; 8 | -------------------------------------------------------------------------------- /src/runtime/node/punycode.ts: -------------------------------------------------------------------------------- 1 | import type nodePunycode from "node:punycode"; 2 | 3 | import _punycode from "./internal/punycode/punycode.ts"; 4 | 5 | export * from "./internal/punycode/punycode.ts"; 6 | 7 | export default _punycode satisfies typeof nodePunycode; 8 | -------------------------------------------------------------------------------- /src/runtime/polyfill/timers.ts: -------------------------------------------------------------------------------- 1 | import { setImmediate, clearImmediate } from "node:timers"; 2 | 3 | if (!globalThis.setImmediate) { 4 | globalThis.setImmediate = setImmediate; 5 | } 6 | 7 | if (!globalThis.clearImmediate) { 8 | globalThis.clearImmediate = clearImmediate; 9 | } 10 | -------------------------------------------------------------------------------- /src/runtime/node/wasi.ts: -------------------------------------------------------------------------------- 1 | import type nodeWasi from "node:wasi"; 2 | import { notImplementedClass } from "../_internal/utils.ts"; 3 | 4 | export const WASI: typeof nodeWasi.WASI = 5 | /*@__PURE__*/ notImplementedClass("wasi.WASI"); 6 | 7 | export default { 8 | WASI, 9 | } satisfies typeof nodeWasi; 10 | -------------------------------------------------------------------------------- /src/runtime/node/internal/v8/profiler.ts: -------------------------------------------------------------------------------- 1 | import type nodeV8 from "node:v8"; 2 | 3 | export class GCProfiler implements nodeV8.GCProfiler { 4 | start() {} 5 | stop() { 6 | return { 7 | version: 1, 8 | startTime: 0, 9 | endTime: 0, 10 | statistics: [], 11 | }; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/runtime/node/internal/worker_threads/message-channel.ts: -------------------------------------------------------------------------------- 1 | import { MessagePort } from "./message-port.ts"; 2 | import type nodeWorkerThreads from "node:worker_threads"; 3 | 4 | export class MessageChannel implements nodeWorkerThreads.MessageChannel { 5 | port1 = new MessagePort(); 6 | port2 = new MessagePort(); 7 | } 8 | -------------------------------------------------------------------------------- /src/runtime/node/internal/trace_events/tracing.ts: -------------------------------------------------------------------------------- 1 | import type nodeTraceEvents from "node:trace_events"; 2 | 3 | export class Tracing implements nodeTraceEvents.Tracing { 4 | categories = ""; 5 | enabled = false; 6 | disable() { 7 | this.enabled = false; 8 | } 9 | enable() { 10 | this.enabled = true; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/runtime/npm/cross-fetch.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/lquixada/cross-fetch 2 | 3 | export const fetch = (...args: Parameters<(typeof globalThis)["fetch"]>) => 4 | globalThis.fetch(...args); 5 | export default fetch; 6 | 7 | export const Headers = globalThis.Headers; 8 | export const Request = globalThis.Request; 9 | export const Response = globalThis.Response; 10 | -------------------------------------------------------------------------------- /src/runtime/node/internal/util/inherits.ts: -------------------------------------------------------------------------------- 1 | export function inherits(ctor: any, superCtor: any) { 2 | if (!superCtor) { 3 | return; 4 | } 5 | ctor.super_ = superCtor; 6 | ctor.prototype = Object.create(superCtor.prototype, { 7 | constructor: { 8 | value: ctor, 9 | enumerable: false, 10 | writable: true, 11 | configurable: true, 12 | }, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /src/runtime/node/internal/url/util.ts: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob/v22.7.0/lib/internal/util.js 2 | 3 | // As of V8 6.6, depending on the size of the array, this is anywhere 4 | // between 1.5-10x faster than the two-arg version of Array#splice() 5 | export function spliceOne(list: unknown[], index: number) { 6 | for (; index + 1 < list.length; index++) list[index] = list[index + 1]; 7 | list.pop(); 8 | } 9 | -------------------------------------------------------------------------------- /src/runtime/node/internal/crypto/web.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/crypto.html 2 | // https://github.com/unjs/uncrypto 3 | 4 | export const subtle: SubtleCrypto = globalThis.crypto?.subtle; 5 | 6 | export const randomUUID: Crypto["randomUUID"] = () => { 7 | return globalThis.crypto?.randomUUID(); 8 | }; 9 | 10 | export const getRandomValues: Crypto["getRandomValues"] = (array: any) => { 11 | return globalThis.crypto?.getRandomValues(array); 12 | }; 13 | -------------------------------------------------------------------------------- /src/runtime/node/internal/tty/read-stream.ts: -------------------------------------------------------------------------------- 1 | import type nodeTty from "node:tty"; 2 | import { Socket } from "node:net"; 3 | 4 | export class ReadStream implements Partial { 5 | fd: number; 6 | isRaw = false; 7 | isTTY = false; 8 | 9 | constructor(fd: number) { 10 | this.fd = fd; 11 | } 12 | 13 | setRawMode(mode: boolean) { 14 | this.isRaw = mode; 15 | return this as unknown as nodeTty.ReadStream; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/runtime/node/stream/promises.ts: -------------------------------------------------------------------------------- 1 | import type nodeStreamPromises from "node:stream/promises"; 2 | import { notImplemented } from "../../_internal/utils.ts"; 3 | 4 | export const finished = /*@__PURE__*/ notImplemented( 5 | "stream.promises.finished", 6 | ); 7 | export const pipeline = /*@__PURE__*/ notImplemented( 8 | "stream.promises.pipeline", 9 | ); 10 | 11 | export default { 12 | finished, 13 | pipeline, 14 | } satisfies typeof nodeStreamPromises; 15 | -------------------------------------------------------------------------------- /src/runtime/node/internal/worker_threads/broadcast-channel.ts: -------------------------------------------------------------------------------- 1 | import type nodeWorkerThreads from "node:worker_threads"; 2 | 3 | export class BroadcastChannel implements nodeWorkerThreads.BroadcastChannel { 4 | name = ""; 5 | onmessage = (message: unknown) => {}; 6 | onmessageerror = (message: unknown) => {}; 7 | close() {} 8 | postMessage(message: unknown) {} 9 | ref() { 10 | return this; 11 | } 12 | unref() { 13 | return this; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/runtime/node/string_decoder.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/string_decoder.html 2 | import type nodeStringDecoder from "node:string_decoder"; 3 | import { notImplementedClass } from "../_internal/utils.ts"; 4 | 5 | export const StringDecoder: typeof nodeStringDecoder.StringDecoder = 6 | (globalThis as any).StringDecoder || 7 | /*@__PURE__*/ notImplementedClass("string_decoder.StringDecoder"); 8 | 9 | export default { 10 | StringDecoder, 11 | } satisfies typeof nodeStringDecoder; 12 | -------------------------------------------------------------------------------- /test/workerd/config.capnp: -------------------------------------------------------------------------------- 1 | using Workerd = import "../../node_modules/workerd/workerd.capnp"; 2 | 3 | const unitTests :Workerd.Config = ( 4 | services = [ 5 | (name = "tests", worker = .testsWorker), 6 | ], 7 | ); 8 | 9 | const testsWorker :Workerd.Worker = ( 10 | modules = [ 11 | (name = "tests", esModule = embed "./tests.mjs") 12 | ], 13 | compatibilityDate = "2024-10-04", 14 | compatibilityFlags = ["nodejs_compat"], 15 | moduleFallback = "localhost:8888", 16 | ); 17 | -------------------------------------------------------------------------------- /src/runtime/node/trace_events.ts: -------------------------------------------------------------------------------- 1 | import type nodeTraceEvents from "node:trace_events"; 2 | import { Tracing } from "./internal/trace_events/tracing.ts"; 3 | 4 | export const createTracing: typeof nodeTraceEvents.createTracing = function () { 5 | return new Tracing(); 6 | }; 7 | export const getEnabledCategories: typeof nodeTraceEvents.getEnabledCategories = 8 | () => ""; 9 | 10 | export default { 11 | createTracing, 12 | getEnabledCategories, 13 | } satisfies typeof nodeTraceEvents; 14 | -------------------------------------------------------------------------------- /src/runtime/node/internal/tls/constants.ts: -------------------------------------------------------------------------------- 1 | // npx -y node@22.14 -e 'const tls=require("tls");console.log(Object.entries(tls).filter(e => ["string", "number"].includes(typeof e[1])).map(([k,v]) => `export const ${k} = ${JSON.stringify(v)}`).join("\n"))' 2 | 3 | export const CLIENT_RENEG_LIMIT = 3; 4 | export const CLIENT_RENEG_WINDOW = 600; 5 | export const DEFAULT_CIPHERS = ""; 6 | export const DEFAULT_ECDH_CURVE = "auto"; 7 | export const DEFAULT_MIN_VERSION = "TLSv1.2"; 8 | export const DEFAULT_MAX_VERSION = "TLSv1.3"; 9 | -------------------------------------------------------------------------------- /src/runtime/node/dgram.ts: -------------------------------------------------------------------------------- 1 | import noop from "../mock/noop.ts"; 2 | import type nodeDgram from "node:dgram"; 3 | import { Socket } from "./internal/dgram/socket.ts"; 4 | 5 | export { Socket } from "./internal/dgram/socket.ts"; 6 | 7 | export const _createSocketHandle = noop; 8 | 9 | export const createSocket: typeof nodeDgram.createSocket = function () { 10 | return new Socket(); 11 | }; 12 | 13 | export default { 14 | Socket, 15 | _createSocketHandle, 16 | createSocket, 17 | } as /* TODO: use satisfies */ typeof nodeDgram; 18 | -------------------------------------------------------------------------------- /src/runtime/npm/fsevents.ts: -------------------------------------------------------------------------------- 1 | // https://www.npmjs.com/package/fsevents 2 | 3 | export default { 4 | watch(_dir: string, _cb: (...args: any[]) => any) { 5 | return Promise.resolve(); 6 | }, 7 | getInfo(path: string, _flags: number, _id: string) { 8 | return { 9 | event: "mock", 10 | path, 11 | type: "file", 12 | flags: 0x1_00_00_00_00, 13 | changes: { 14 | inode: false, 15 | finder: false, 16 | access: false, 17 | xattrs: false, 18 | }, 19 | }; 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /src/runtime/node/internal/readline/promises/interface.ts: -------------------------------------------------------------------------------- 1 | import type nodeReadlinePromises from "node:readline/promises"; 2 | import type { Abortable } from "node:events"; 3 | import { Interface as _Interface } from "../interface.ts"; 4 | 5 | export class Interface 6 | extends _Interface 7 | implements nodeReadlinePromises.Interface 8 | { 9 | question(query: string): Promise; 10 | question(query: string, options: Abortable): Promise; 11 | question(query: unknown, options?: unknown): Promise { 12 | return Promise.resolve(""); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/autofix.yml: -------------------------------------------------------------------------------- 1 | name: autofix.ci 2 | on: { push: {}, pull_request: {} } 3 | permissions: { contents: read } 4 | jobs: 5 | autofix: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v6 9 | - run: npm i -fg corepack && corepack enable 10 | - uses: actions/setup-node@v6 11 | with: { node-version-file: ".nvmrc", cache: pnpm } 12 | - run: pnpm install 13 | - run: pnpm lint:fix 14 | - uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27 15 | with: { commit-message: "chore: apply automated updates" } 16 | -------------------------------------------------------------------------------- /src/runtime/node/sqlite.ts: -------------------------------------------------------------------------------- 1 | import type * as nodeSqlite from "node:sqlite"; 2 | import { notImplementedClass } from "../_internal/utils.ts"; 3 | 4 | export const DatabaseSync: typeof nodeSqlite.DatabaseSync = 5 | /*@__PURE__*/ notImplementedClass("sqlite.DatabaseSync"); 6 | 7 | export const StatementSync: typeof nodeSqlite.StatementSync = 8 | /*@__PURE__*/ notImplementedClass("sqlite.StatementSync"); 9 | 10 | export const constants = {} as typeof nodeSqlite.constants; 11 | 12 | export default { 13 | DatabaseSync, 14 | StatementSync, 15 | constants, 16 | } satisfies typeof nodeSqlite; 17 | -------------------------------------------------------------------------------- /src/runtime/node/internal/v8/serializer.ts: -------------------------------------------------------------------------------- 1 | import type nodeV8 from "node:v8"; 2 | 3 | export class Serializer implements nodeV8.Serializer { 4 | writeHeader() {} 5 | writeValue(val: any) { 6 | return false; 7 | } 8 | releaseBuffer(): Buffer { 9 | return Buffer.from(""); 10 | } 11 | transferArrayBuffer(id: number, arrayBuffer: ArrayBuffer) {} 12 | writeDouble(value: number) {} 13 | writeUint32(value: number) {} 14 | writeUint64(hi: number, lo: number) {} 15 | writeRawBytes(buffer: NodeJS.TypedArray) {} 16 | } 17 | 18 | export class DefaultSerializer extends Serializer {} 19 | -------------------------------------------------------------------------------- /src/runtime/node/internal/zlib/codes.ts: -------------------------------------------------------------------------------- 1 | // import type nodeZlib from "node:zlib"; 2 | 3 | export const codes = { 4 | "0": "Z_OK", 5 | "1": "Z_STREAM_END", 6 | "2": "Z_NEED_DICT", 7 | Z_OK: 0, 8 | Z_STREAM_END: 1, 9 | Z_NEED_DICT: 2, 10 | Z_ERRNO: -1, 11 | Z_STREAM_ERROR: -2, 12 | Z_DATA_ERROR: -3, 13 | Z_MEM_ERROR: -4, 14 | Z_BUF_ERROR: -5, 15 | Z_VERSION_ERROR: -6, 16 | "-1": "Z_ERRNO", 17 | "-2": "Z_STREAM_ERROR", 18 | "-3": "Z_DATA_ERROR", 19 | "-4": "Z_MEM_ERROR", 20 | "-5": "Z_BUF_ERROR", 21 | "-6": "Z_VERSION_ERROR", 22 | }; // satisfies typeof nodeZlib.codes ; 23 | -------------------------------------------------------------------------------- /src/runtime/node/domain.ts: -------------------------------------------------------------------------------- 1 | import type nodeDomain from "node:domain"; 2 | import { Domain } from "./internal/domain/domain.ts"; 3 | 4 | export { Domain } from "./internal/domain/domain.ts"; 5 | 6 | export const create: typeof nodeDomain.create = function () { 7 | return new Domain(); 8 | }; 9 | export const createDomain: typeof nodeDomain.create = create; 10 | const _domain = create(); 11 | export const active = () => _domain; 12 | export const _stack = []; 13 | 14 | export default { 15 | Domain, 16 | _stack, 17 | active, 18 | create, 19 | createDomain, 20 | } as /* TODO: use satisfies */ typeof nodeDomain; 21 | -------------------------------------------------------------------------------- /src/runtime/node/internal/http/agent.ts: -------------------------------------------------------------------------------- 1 | import type nodeHttp from "node:http"; 2 | import { EventEmitter } from "node:events"; 3 | 4 | export class Agent extends EventEmitter implements nodeHttp.Agent { 5 | public __unenv__ = {}; 6 | maxFreeSockets = 256; 7 | maxSockets: number = Infinity; 8 | maxTotalSockets: number = Infinity; 9 | readonly freeSockets = {}; 10 | readonly sockets = {}; 11 | readonly requests = {}; 12 | readonly options: nodeHttp.AgentOptions; 13 | constructor(opts: nodeHttp.AgentOptions = {}) { 14 | super(); 15 | this.options = opts; 16 | } 17 | destroy(): void {} 18 | } 19 | -------------------------------------------------------------------------------- /src/runtime/node/internal/timers/scheduler.ts: -------------------------------------------------------------------------------- 1 | import timers from "node:timers/promises"; 2 | import type { TimerOptions } from "node:timers"; 3 | 4 | import { setTimeoutFallbackPromises as setTimeout } from "./set-timeout.ts"; 5 | import { setImmediateFallbackPromises as setImmediate } from "./set-immediate.ts"; 6 | 7 | export class Scheduler implements timers.Scheduler { 8 | wait( 9 | delay?: number | undefined, 10 | options?: Pick | undefined, 11 | ) { 12 | return setTimeout(delay, undefined, options); 13 | } 14 | yield() { 15 | return setImmediate(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/runtime/node/internal/zlib/formats/zip.ts: -------------------------------------------------------------------------------- 1 | import type nodeZlib from "node:zlib"; 2 | import { notImplemented } from "../../../../_internal/utils.ts"; 3 | import { ZlibCompress } from "./_shared.ts"; 4 | 5 | // Zip Decompression 6 | 7 | export class Unzip extends ZlibCompress { 8 | readonly _format = "zip"; 9 | } 10 | 11 | export const createUnzip: typeof nodeZlib.createUnzip = () => new Unzip(); 12 | 13 | export const unzip: typeof nodeZlib.unzip = 14 | /*@__PURE__*/ notImplemented("zlib.unzip"); 15 | 16 | export const unzipSync: typeof nodeZlib.unzipSync = 17 | /*@__PURE__*/ notImplemented("zlib.unzipSync"); 18 | -------------------------------------------------------------------------------- /src/runtime/node/tty.ts: -------------------------------------------------------------------------------- 1 | import type nodeTty from "node:tty"; 2 | import { ReadStream } from "./internal/tty/read-stream.ts"; 3 | import { WriteStream } from "./internal/tty/write-stream.ts"; 4 | 5 | export { ReadStream } from "./internal/tty/read-stream.ts"; 6 | export { WriteStream } from "./internal/tty/write-stream.ts"; 7 | 8 | export const isatty: typeof nodeTty.isatty = function () { 9 | return false; 10 | }; 11 | 12 | export default { 13 | ReadStream: ReadStream as unknown as typeof nodeTty.ReadStream, 14 | WriteStream: WriteStream as unknown as typeof nodeTty.WriteStream, 15 | isatty, 16 | } satisfies typeof nodeTty; 17 | -------------------------------------------------------------------------------- /src/runtime/node/readline/promises.ts: -------------------------------------------------------------------------------- 1 | import type nodeReadline from "node:readline/promises"; 2 | import { Interface } from "../internal/readline/promises/interface.ts"; 3 | import { Readline } from "../internal/readline/promises/readline.ts"; 4 | 5 | export { Interface } from "../internal/readline/promises/interface.ts"; 6 | export { Readline } from "../internal/readline/promises/readline.ts"; 7 | 8 | export const createInterface: typeof nodeReadline.createInterface = () => 9 | new Interface(); 10 | 11 | export default { 12 | Interface, 13 | Readline, 14 | createInterface, 15 | } as /* TODO: use satisfies */ typeof nodeReadline; 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "bundler", 6 | "esModuleInterop": true, 7 | "strict": true, 8 | "declaration": true, 9 | "resolveJsonModule": true, 10 | "allowImportingTsExtensions": true, 11 | "noEmit": true, 12 | "isolatedDeclarations": false, 13 | "types": [ 14 | "node" 15 | ], 16 | "paths": { 17 | "unenv": [ 18 | "./src/index.ts" 19 | ], 20 | "unenv/*": [ 21 | "./src/runtime/*" 22 | ] 23 | } 24 | }, 25 | "include": [ 26 | "src/**/*" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /src/runtime/node/internal/readline/promises/readline.ts: -------------------------------------------------------------------------------- 1 | import type nodeReadlinePromises from "node:readline/promises"; 2 | import type { Direction } from "node:readline"; 3 | 4 | export class Readline implements nodeReadlinePromises.Readline { 5 | clearLine(dir: Direction) { 6 | return this; 7 | } 8 | clearScreenDown() { 9 | return this; 10 | } 11 | commit(): Promise { 12 | return Promise.resolve(); 13 | } 14 | cursorTo(x: number, y?: number | undefined) { 15 | return this; 16 | } 17 | moveCursor(dx: number, dy: number) { 18 | return this; 19 | } 20 | rollback() { 21 | return this; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/runtime/polyfill/process.ts: -------------------------------------------------------------------------------- 1 | import processModule from "node:process"; 2 | 3 | // Keep a reference to the original process to avoid circular references after polyfilling 4 | const originalProcess = globalThis["process"]; 5 | 6 | globalThis.process = originalProcess 7 | ? new Proxy(originalProcess, { 8 | get(target, prop, receiver) { 9 | if (Reflect.has(target, prop)) { 10 | return Reflect.get(target, prop, receiver); 11 | } 12 | return Reflect.get(processModule, prop, receiver); 13 | }, 14 | }) 15 | : processModule; 16 | 17 | export default globalThis.process satisfies typeof processModule; 18 | -------------------------------------------------------------------------------- /test/node.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { x } from "tinyexec"; 3 | 4 | describe("tests in node", () => { 5 | it("run", async () => { 6 | const { exitCode, stderr, stdout } = await x( 7 | "node", 8 | [ 9 | "--disable-warning=ExperimentalWarning", 10 | "--experimental-strip-types", 11 | "--test", 12 | "./node/test-*", 13 | ], 14 | { 15 | nodeOptions: { 16 | cwd: __dirname, 17 | }, 18 | }, 19 | ); 20 | expect(exitCode).toBe(0); 21 | expect(stderr).toBe(""); 22 | expect(stdout).include("fail 0"); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/runtime/node/internal/timers/set-interval.ts: -------------------------------------------------------------------------------- 1 | import { Timeout } from "./timeout.ts"; 2 | 3 | export async function* setIntervalFallbackPromises( 4 | delay?: number, 5 | value?: T, 6 | ): NodeJS.AsyncIterator { 7 | yield value as T; 8 | } 9 | 10 | export function setIntervalFallback( 11 | callback: (args: void) => void, 12 | ms?: number, 13 | ): NodeJS.Timeout; 14 | export function setIntervalFallback( 15 | callback: (...args: TArgs) => void, 16 | ms?: number, 17 | ...args: TArgs 18 | ): NodeJS.Timeout { 19 | return new Timeout(callback, args); 20 | } 21 | setIntervalFallback.__promisify__ = setIntervalFallbackPromises; 22 | -------------------------------------------------------------------------------- /test/node-env.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { env } from "../src/runtime/node/internal/process/env"; 3 | 4 | describe("process.env polyfill", () => { 5 | it("env.TEST", () => { 6 | expect(env.TEST).toBe("true"); 7 | }); 8 | 9 | it("env.CUSTOM", () => { 10 | env.CUSTOM = "true"; 11 | expect(env.CUSTOM).toBe("true"); 12 | }); 13 | 14 | it("Object.keys(env)", () => { 15 | expect(Object.keys(env)).toContain("TEST"); 16 | expect(Object.keys(env)).toContain("CUSTOM"); 17 | }); 18 | 19 | it("Object.entries(env)", () => { 20 | expect(Object.entries(env)).toContainEqual(["TEST", "true"]); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/runtime/node/internal/v8/deserializer.ts: -------------------------------------------------------------------------------- 1 | import type nodeV8 from "node:v8"; 2 | 3 | export class Deserializer implements nodeV8.Deserializer { 4 | readHeader() { 5 | return false; 6 | } 7 | readValue() {} 8 | transferArrayBuffer(id: number, arrayBuffer: ArrayBuffer) {} 9 | getWireFormatVersion() { 10 | return 0; 11 | } 12 | readUint32(): number { 13 | return 0; 14 | } 15 | readUint64(): [number, number] { 16 | return [0, 0]; 17 | } 18 | readDouble(): number { 19 | return 0; 20 | } 21 | readRawBytes(length: number): Buffer { 22 | return Buffer.from(""); 23 | } 24 | } 25 | 26 | export class DefaultDeserializer extends Deserializer {} 27 | -------------------------------------------------------------------------------- /src/runtime/node/internal/timers/set-immediate.ts: -------------------------------------------------------------------------------- 1 | import { Immediate } from "./immediate.ts"; 2 | 3 | export function setImmediateFallbackPromises(value?: T): Promise { 4 | return new Promise((res) => { 5 | res(value as T | PromiseLike); 6 | }); 7 | } 8 | 9 | export function setImmediateFallback( 10 | callback: (...args: TArgs) => void, 11 | ...args: TArgs 12 | ): NodeJS.Immediate { 13 | return new Immediate(callback, args); 14 | } 15 | setImmediateFallback.__promisify__ = setImmediateFallbackPromises; 16 | 17 | export function clearImmediateFallback( 18 | immediate: NodeJS.Immediate | undefined, 19 | ) { 20 | immediate?.[Symbol.dispose](); 21 | } 22 | -------------------------------------------------------------------------------- /src/runtime/polyfill/source-maps.ts: -------------------------------------------------------------------------------- 1 | // This polyfill enables `node --enable-source-maps` effect in supported Node.js versions (22.14+, 23.7+) 2 | // Docs: https://nodejs.org/api/module.html#modulesetsourcemapssupportenabled-options 3 | 4 | try { 5 | const nodeModule = globalThis.process?.getBuiltinModule?.("node:module"); 6 | // @ts-expect-error TODO: update Node.js types 7 | if (nodeModule && !nodeModule.getSourceMapsSupport?.()?.enabled) { 8 | // @ts-expect-error 9 | nodeModule.setSourceMapsSupport?.(true, { 10 | generatedCode: true, 11 | nodeModules: true, 12 | }); 13 | } 14 | } catch (error) { 15 | console.warn("Failed to enable source maps support:", error); 16 | } 17 | -------------------------------------------------------------------------------- /src/runtime/node/stream/consumers.ts: -------------------------------------------------------------------------------- 1 | import type nodeStreamConsumers from "node:stream/consumers"; 2 | import { notImplemented } from "../../_internal/utils.ts"; 3 | 4 | export const arrayBuffer = /*@__PURE__*/ notImplemented( 5 | "stream.consumers.arrayBuffer", 6 | ); 7 | export const blob = /*@__PURE__*/ notImplemented("stream.consumers.blob"); 8 | export const buffer = /*@__PURE__*/ notImplemented("stream.consumers.buffer"); 9 | export const text = /*@__PURE__*/ notImplemented("stream.consumers.text"); 10 | export const json = /*@__PURE__*/ notImplemented("stream.consumers.json"); 11 | 12 | export default { 13 | arrayBuffer, 14 | blob, 15 | buffer, 16 | text, 17 | json, 18 | } satisfies typeof nodeStreamConsumers; 19 | -------------------------------------------------------------------------------- /src/runtime/node/internal/domain/domain.ts: -------------------------------------------------------------------------------- 1 | import { createNotImplementedError } from "../../../_internal/utils.ts"; 2 | import { EventEmitter } from "node:events"; 3 | import type nodeDomain from "node:domain"; 4 | 5 | export class Domain extends EventEmitter implements nodeDomain.Domain { 6 | readonly __unenv__ = true; 7 | 8 | members = []; 9 | add() {} 10 | enter() {} 11 | exit() {} 12 | remove() {} 13 | bind(callback: T): T { 14 | throw createNotImplementedError("Domain.bind"); 15 | } 16 | intercept(callback: T): T { 17 | throw createNotImplementedError("Domain.intercept"); 18 | } 19 | run(fn: (...args: any[]) => T, ...args: any[]): T { 20 | throw createNotImplementedError("Domain.run"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/runtime/node/internal/stream/transform.ts: -------------------------------------------------------------------------------- 1 | import type nodeStream from "node:stream"; 2 | import { Duplex } from "./duplex.ts"; 3 | 4 | // Docs: https://nodejs.org/api/stream.html#stream_duplex_and_transform_streams 5 | // Implementation: https://github.com/nodejs/node/blob/master/lib/internal/streams/transform.js 6 | 7 | export class _Transform extends Duplex implements nodeStream.Transform { 8 | readonly __unenv__ = true; 9 | 10 | _transform( 11 | chunk: any, 12 | encoding: globalThis.BufferEncoding, 13 | callback: nodeStream.TransformCallback, 14 | ): void {} 15 | 16 | _flush(callback: nodeStream.TransformCallback): void {} 17 | } 18 | 19 | export const Transform: typeof nodeStream.Transform = 20 | (globalThis as any).Transform || _Transform; 21 | -------------------------------------------------------------------------------- /src/runtime/node/internal/fs/classes.ts: -------------------------------------------------------------------------------- 1 | import type nodeFs from "node:fs"; 2 | import { notImplementedClass } from "../../../_internal/utils.ts"; 3 | 4 | export const Dir: typeof nodeFs.Dir = 5 | /*@__PURE__*/ notImplementedClass("fs.Dir"); 6 | 7 | export const Dirent: typeof nodeFs.Dirent = 8 | /*@__PURE__*/ notImplementedClass("fs.Dirent"); 9 | 10 | export const Stats: typeof nodeFs.Stats = 11 | /*@__PURE__*/ notImplementedClass("fs.Stats"); 12 | 13 | export const ReadStream: typeof nodeFs.ReadStream = 14 | /*@__PURE__*/ notImplementedClass("fs.ReadStream"); 15 | 16 | export const WriteStream: typeof nodeFs.WriteStream = 17 | /*@__PURE__*/ notImplementedClass("fs.WriteStream"); 18 | 19 | export const FileReadStream = ReadStream; 20 | 21 | export const FileWriteStream = WriteStream; 22 | -------------------------------------------------------------------------------- /src/runtime/polyfill/performance.ts: -------------------------------------------------------------------------------- 1 | import { 2 | performance, 3 | Performance, 4 | PerformanceEntry, 5 | PerformanceMark, 6 | PerformanceMeasure, 7 | PerformanceObserver, 8 | PerformanceObserverEntryList, 9 | PerformanceResourceTiming, 10 | } from "../web/performance/index.ts"; 11 | 12 | globalThis.performance ||= performance; 13 | globalThis.Performance ||= Performance; 14 | globalThis.PerformanceEntry ||= PerformanceEntry; 15 | globalThis.PerformanceMark ||= PerformanceMark; 16 | globalThis.PerformanceMeasure ||= PerformanceMeasure; 17 | globalThis.PerformanceObserver ||= PerformanceObserver; 18 | globalThis.PerformanceObserverEntryList ||= PerformanceObserverEntryList; 19 | globalThis.PerformanceResourceTiming ||= PerformanceResourceTiming; 20 | 21 | export default globalThis.performance; 22 | -------------------------------------------------------------------------------- /src/runtime/node/internal/worker_threads/message-port.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "node:events"; 2 | import type nodeWorkerThreads from "node:worker_threads"; 3 | 4 | export class MessagePort 5 | extends EventEmitter 6 | implements nodeWorkerThreads.MessagePort 7 | { 8 | close() {} 9 | postMessage( 10 | value: any, 11 | transferList?: readonly nodeWorkerThreads.TransferListItem[] | undefined, 12 | ) {} 13 | ref() {} 14 | unref() {} 15 | start() {} 16 | 17 | addEventListener(type: string, listener: (...args: any[]) => void): void { 18 | this.on(type, listener); 19 | } 20 | 21 | removeEventListener(type: string, listener: (...args: any[]) => void): void { 22 | this.off(type, listener); 23 | } 24 | 25 | dispatchEvent(event: Event) { 26 | return this.emit(event.type, event); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/runtime/node/internal/timers/set-timeout.ts: -------------------------------------------------------------------------------- 1 | import type nodeTimers from "node:timers"; 2 | import { Timeout } from "./timeout.ts"; 3 | 4 | export function setTimeoutFallbackPromises( 5 | delay?: number, 6 | value?: T, 7 | options?: nodeTimers.TimerOptions, 8 | ): Promise { 9 | return new Promise((res) => { 10 | // NOTE: we are ignoring options?.signal? as promise is immediately resolved 11 | res(value as T | PromiseLike); 12 | }); 13 | } 14 | 15 | export function setTimeoutFallback( 16 | callback: TimerHandler, 17 | ms?: number, 18 | ): NodeJS.Timeout; 19 | export function setTimeoutFallback( 20 | callback: TimerHandler, 21 | ms?: number, 22 | ...args: TArgs 23 | ) { 24 | return new Timeout(callback, args); 25 | } 26 | setTimeoutFallback.__promisify__ = setTimeoutFallbackPromises; 27 | -------------------------------------------------------------------------------- /src/runtime/node/internal/timers/timeout.ts: -------------------------------------------------------------------------------- 1 | import { createNotImplementedError } from "../../../_internal/utils.ts"; 2 | 3 | export class Timeout implements NodeJS.Timeout { 4 | constructor(callback: TimerHandler, args: TArgs) { 5 | if (typeof callback === "function") { 6 | callback(...args); 7 | } 8 | } 9 | close(): this { 10 | throw createNotImplementedError("node.timers.timeout.close"); 11 | } 12 | _onTimeout(...args: any[]): void { 13 | throw createNotImplementedError("node.timers.timeout._onTimeout"); 14 | } 15 | ref() { 16 | return this; 17 | } 18 | unref() { 19 | return this; 20 | } 21 | hasRef() { 22 | return false; 23 | } 24 | refresh() { 25 | return this; 26 | } 27 | [Symbol.dispose]() {} 28 | [Symbol.toPrimitive]() { 29 | return 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/runtime/node/internal/tls/server.ts: -------------------------------------------------------------------------------- 1 | import type nodeTls from "node:tls"; 2 | import { createNotImplementedError } from "../../../_internal/utils.ts"; 3 | import { Server as _Server } from "node:net"; 4 | 5 | export class Server extends _Server implements nodeTls.Server { 6 | constructor( 7 | arg1?: nodeTls.TlsOptions | ((socket: nodeTls.TLSSocket) => void), 8 | arg2?: (socket: nodeTls.TLSSocket) => void, 9 | ) { 10 | super(arg1 as any, arg2 as any); 11 | } 12 | 13 | addContext(hostname: string, context: nodeTls.SecureContextOptions) {} 14 | setSecureContext(options: nodeTls.SecureContextOptions) {} 15 | setTicketKeys(_keys: Buffer) { 16 | throw createNotImplementedError("Server.setTicketKeys"); 17 | } 18 | getTicketKeys(): Buffer { 19 | throw createNotImplementedError("Server.getTicketKeys"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/runtime/npm/node-fetch.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/node-fetch/node-fetch 2 | 3 | // Native browser APIs 4 | export const fetch = (...args: Parameters<(typeof globalThis)["fetch"]>) => 5 | globalThis.fetch(...args); 6 | 7 | export const Headers = globalThis.Headers; 8 | export const Request = globalThis.Request; 9 | export const Response = globalThis.Response; 10 | export const AbortController = globalThis.AbortController; 11 | 12 | // Error handling 13 | export const FetchError = Error; 14 | export const AbortError = Error; 15 | 16 | // Top-level exported helpers (from node-fetch v3) 17 | const redirectStatus = new Set([301, 302, 303, 307, 308]); 18 | export const isRedirect = (code: number) => redirectStatus.has(code); 19 | 20 | // node-fetch v2 21 | fetch.Promise = globalThis.Promise; 22 | fetch.isRedirect = isRedirect; 23 | 24 | export default fetch; 25 | -------------------------------------------------------------------------------- /src/runtime/node/internal/timers/immediate.ts: -------------------------------------------------------------------------------- 1 | export class Immediate implements NodeJS.Immediate { 2 | _onImmediate: (...args: TArgs) => void; 3 | private _timeout?: NodeJS.Timeout; 4 | 5 | constructor(callback: (...args: TArgs) => void, args: TArgs) { 6 | this._onImmediate = callback; 7 | if ("setTimeout" in globalThis) { 8 | this._timeout = setTimeout(callback, 0, ...args); 9 | } else { 10 | callback(...args); 11 | } 12 | } 13 | 14 | ref(): this { 15 | this._timeout?.ref(); 16 | return this; 17 | } 18 | unref(): this { 19 | this._timeout?.unref(); 20 | return this; 21 | } 22 | 23 | hasRef(): boolean { 24 | return this._timeout?.hasRef() ?? false; 25 | } 26 | 27 | [Symbol.dispose]() { 28 | if ("clearTimeout" in globalThis) { 29 | clearTimeout(this._timeout); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/runtime/node/internal/buffer/file.ts: -------------------------------------------------------------------------------- 1 | import type nodeBuffer from "node:buffer"; 2 | 3 | export class File extends Blob implements nodeBuffer.File { 4 | readonly __unenv__ = true; 5 | 6 | size: number = 0; 7 | type: any = ""; 8 | name: string = ""; 9 | lastModified: number = 0; 10 | 11 | constructor(...args: any[]) { 12 | super(...args); 13 | throw new Error("[unenv] buffer.File is not implemented"); 14 | } 15 | 16 | arrayBuffer(): Promise { 17 | throw new Error("Not implemented"); 18 | } 19 | 20 | slice(): any { 21 | throw new Error("Not implemented"); 22 | } 23 | 24 | text(): any { 25 | throw new Error("Not implemented"); 26 | } 27 | 28 | stream(): any { 29 | throw new Error("Not implemented"); 30 | } 31 | 32 | bytes(): Promise> { 33 | throw new Error("Not implemented"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/runtime/node/internal/vm/script.ts: -------------------------------------------------------------------------------- 1 | import type nodeVm from "node:vm"; 2 | import { createNotImplementedError } from "../../../_internal/utils.ts"; 3 | 4 | export class Script implements nodeVm.Script { 5 | runInContext( 6 | contextifiedObject: nodeVm.Context, 7 | options?: nodeVm.RunningScriptOptions | undefined, 8 | ) { 9 | throw createNotImplementedError("Script.runInContext"); 10 | } 11 | runInNewContext( 12 | contextObject?: nodeVm.Context | undefined, 13 | options?: nodeVm.RunningScriptInNewContextOptions | undefined, 14 | ) { 15 | throw createNotImplementedError("Script.runInNewContext"); 16 | } 17 | runInThisContext(options?: nodeVm.RunningScriptOptions | undefined) { 18 | throw createNotImplementedError("Script.runInThisContext"); 19 | } 20 | createCachedData(): Buffer { 21 | throw createNotImplementedError("Script.createCachedData"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/node/test-url-format-invalid-input.mjs: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob//v22.7.0/test/parallel/test-url-format-invalid-input.js 2 | 3 | import assert from "node:assert"; 4 | 5 | import url from "../../src/runtime/node/url.ts"; 6 | 7 | const throwsObjsAndReportTypes = [ 8 | undefined, 9 | null, 10 | true, 11 | false, 12 | 0, 13 | function () {}, 14 | Symbol("foo"), 15 | ]; 16 | 17 | for (const urlObject of throwsObjsAndReportTypes) { 18 | assert.throws( 19 | () => { 20 | url.format(urlObject); 21 | }, 22 | { 23 | code: "ERR_INVALID_ARG_TYPE", 24 | name: "TypeError", 25 | message: 26 | 'The "urlObject" argument must be of type Object or string. Received ' + 27 | (urlObject ? urlObject.toString() : urlObject), 28 | }, 29 | ); 30 | } 31 | assert.strictEqual(url.format(""), ""); 32 | assert.strictEqual(url.format({}), ""); 33 | -------------------------------------------------------------------------------- /src/runtime/node/internal/util/promisify.ts: -------------------------------------------------------------------------------- 1 | import type nodeUtil from "node:util"; 2 | 3 | const customSymbol = /*@__PURE__*/ Symbol("customPromisify"); 4 | 5 | type Fn = (...args: any[]) => any; 6 | 7 | function _promisify(fn: Fn & { [customSymbol]?: Fn }) { 8 | if (fn[customSymbol]) { 9 | return fn[customSymbol]; 10 | } 11 | return function (...args: any[]) { 12 | return new Promise((resolve, reject) => { 13 | try { 14 | // @ts-ignore 15 | fn.call(this, ...args, (err, val) => { 16 | if (err) { 17 | return reject(err); 18 | } 19 | resolve(val); 20 | }); 21 | } catch (error) { 22 | reject(error); 23 | } 24 | }); 25 | }; 26 | } 27 | 28 | // @ts-ignore 29 | export const promisify: typeof nodeUtil.promisify = /*@__PURE__*/ Object.assign( 30 | _promisify, 31 | { 32 | custom: customSymbol, 33 | }, 34 | ); 35 | -------------------------------------------------------------------------------- /src/runtime/node/async_hooks.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/events.html 2 | import type nodeAsyncHooks from "node:async_hooks"; 3 | 4 | import { AsyncLocalStorage } from "./internal/async_hooks/async-local-storage.ts"; 5 | import { AsyncResource } from "./internal/async_hooks/async-resource.ts"; 6 | 7 | import { 8 | asyncWrapProviders, 9 | createHook, 10 | executionAsyncId, 11 | executionAsyncResource, 12 | triggerAsyncId, 13 | } from "./internal/async_hooks/async-hook.ts"; 14 | 15 | export { AsyncLocalStorage } from "./internal/async_hooks/async-local-storage.ts"; 16 | export { AsyncResource } from "./internal/async_hooks/async-resource.ts"; 17 | 18 | export * from "./internal/async_hooks/async-hook.ts"; 19 | 20 | export default { 21 | // @ts-expect-error 22 | asyncWrapProviders, 23 | AsyncLocalStorage, 24 | AsyncResource, 25 | createHook, 26 | executionAsyncId, 27 | executionAsyncResource, 28 | triggerAsyncId, 29 | } satisfies typeof nodeAsyncHooks; 30 | -------------------------------------------------------------------------------- /src/runtime/node/timers/promises.ts: -------------------------------------------------------------------------------- 1 | import type nodeTimersPromises from "node:timers/promises"; 2 | import { Scheduler } from "../internal/timers/scheduler.ts"; 3 | import { setTimeoutFallbackPromises } from "../internal/timers/set-timeout.ts"; 4 | import { setIntervalFallbackPromises } from "../internal/timers/set-interval.ts"; 5 | import { setImmediateFallbackPromises } from "../internal/timers/set-immediate.ts"; 6 | 7 | export { setTimeoutFallbackPromises as setTimeout } from "../internal/timers/set-timeout.ts"; 8 | export { setIntervalFallbackPromises as setInterval } from "../internal/timers/set-interval.ts"; 9 | export { setImmediateFallbackPromises as setImmediate } from "../internal/timers/set-immediate.ts"; 10 | 11 | export const scheduler = new Scheduler(); 12 | 13 | export default { 14 | scheduler, 15 | setImmediate: setImmediateFallbackPromises, 16 | setInterval: setIntervalFallbackPromises, 17 | setTimeout: setTimeoutFallbackPromises, 18 | } satisfies typeof nodeTimersPromises; 19 | -------------------------------------------------------------------------------- /src/runtime/node/internal/process/hrtime.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/process.html#processhrtime 2 | export const hrtime: NodeJS.Process["hrtime"] = /*@__PURE__*/ Object.assign( 3 | function hrtime(startTime?: [number, number] | undefined) { 4 | const now = Date.now(); 5 | // millis to seconds 6 | const seconds = Math.trunc(now / 1000); 7 | // convert millis to nanos 8 | const nanos = (now % 1000) * 1_000_000; 9 | 10 | if (startTime) { 11 | let diffSeconds = seconds - startTime[0]; 12 | let diffNanos = nanos - startTime[0]; 13 | 14 | if (diffNanos < 0) { 15 | diffSeconds = diffSeconds - 1; 16 | diffNanos = 1_000_000_000 + diffNanos; 17 | } 18 | return [diffSeconds, diffNanos] as [number, number]; 19 | } 20 | 21 | return [seconds, nanos] as [number, number]; 22 | }, 23 | { 24 | bigint: function bigint() { 25 | // Convert milliseconds to nanoseconds 26 | return BigInt(Date.now() * 1_000_000); 27 | }, 28 | }, 29 | ); 30 | -------------------------------------------------------------------------------- /test/node/test-querystring-multichar-separator.mjs: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob//v22.7.0/test/parallel/test-querystring-multichar-separator.js 2 | 3 | import assert from "node:assert"; 4 | 5 | import qs from "../../src/runtime/node/querystring.ts"; 6 | 7 | function check(actual, expected) { 8 | assert.ok(!(actual instanceof Object)); 9 | assert.deepStrictEqual( 10 | Object.keys(actual).sort(), 11 | Object.keys(expected).sort(), 12 | ); 13 | for (const key of Object.keys(expected)) { 14 | assert.deepStrictEqual(actual[key], expected[key]); 15 | } 16 | } 17 | 18 | check(qs.parse("foo=>bar&&bar=>baz", "&&", "=>"), { foo: "bar", bar: "baz" }); 19 | 20 | check( 21 | qs.stringify({ foo: "bar", bar: "baz" }, "&&", "=>"), 22 | "foo=>bar&&bar=>baz", 23 | ); 24 | 25 | check(qs.parse("foo==>bar, bar==>baz", ", ", "==>"), { 26 | foo: "bar", 27 | bar: "baz", 28 | }); 29 | 30 | check( 31 | qs.stringify({ foo: "bar", bar: "baz" }, ", ", "==>"), 32 | "foo==>bar, bar==>baz", 33 | ); 34 | -------------------------------------------------------------------------------- /src/runtime/node/internal/worker_threads/worker.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "node:events"; 2 | import type nodeWorkerThreads from "node:worker_threads"; 3 | import { Readable } from "node:stream"; 4 | 5 | export class Worker extends EventEmitter implements nodeWorkerThreads.Worker { 6 | stdin = null; 7 | stdout = new Readable(); 8 | stderr = new Readable(); 9 | threadId = 0; 10 | performance = { 11 | eventLoopUtilization: () => ({ idle: 0, active: 0, utilization: 0 }), 12 | }; 13 | postMessage( 14 | _value: any, 15 | _transferList?: readonly nodeWorkerThreads.TransferListItem[] | undefined, 16 | ) {} 17 | postMessageToThread( 18 | _threadId: unknown, 19 | _value: unknown, 20 | _transferList?: unknown, 21 | _timeout?: unknown, 22 | ): Promise { 23 | return Promise.resolve(); 24 | } 25 | ref() {} 26 | unref() {} 27 | terminate() { 28 | return Promise.resolve(0); 29 | } 30 | getHeapSnapshot() { 31 | return Promise.resolve(new Readable()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/runtime/node/https.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/https.html 2 | import type nodeHttps from "node:https"; 3 | import { notImplemented, notImplementedClass } from "../_internal/utils.ts"; 4 | import { Agent as HttpAgent } from "./internal/http/agent.ts"; 5 | 6 | export const Server: typeof nodeHttps.Server = 7 | /*@__PURE__*/ notImplementedClass("https.Server"); 8 | 9 | export const Agent: typeof nodeHttps.Agent = 10 | HttpAgent as unknown as typeof nodeHttps.Agent; 11 | 12 | export const globalAgent: typeof nodeHttps.globalAgent = 13 | /*@__PURE__*/ new Agent(); 14 | 15 | export const get = 16 | /*@__PURE__*/ notImplemented("https.get"); 17 | 18 | export const createServer = 19 | /*@__PURE__*/ notImplemented( 20 | "https.createServer", 21 | ); 22 | 23 | export const request = 24 | /*@__PURE__*/ notImplemented("https.request"); 25 | 26 | export default { 27 | Server, 28 | Agent, 29 | globalAgent, 30 | get, 31 | createServer, 32 | request, 33 | } satisfies typeof nodeHttps; 34 | -------------------------------------------------------------------------------- /src/runtime/node/internal/zlib/formats/gzip.ts: -------------------------------------------------------------------------------- 1 | import type nodeZlib from "node:zlib"; 2 | import { notImplemented } from "../../../../_internal/utils.ts"; 3 | import { 4 | ZlibCompress, 5 | ZLibDecompress, 6 | notImplementedCompress, 7 | } from "./_shared.ts"; 8 | 9 | // Gzip Compression 10 | 11 | export class Gzip extends ZlibCompress { 12 | readonly _format = "gzip"; 13 | } 14 | 15 | export const gzip: typeof nodeZlib.gzip = notImplementedCompress("gzip"); 16 | 17 | export const createGzip: typeof nodeZlib.createGzip = () => new Gzip(); 18 | 19 | export const gzipSync: typeof nodeZlib.gzipSync = 20 | /*@__PURE__*/ notImplemented("zlib.gzipSync"); 21 | 22 | // Gzip Decompression 23 | 24 | export class Gunzip extends ZLibDecompress { 25 | readonly _format = "gzip"; 26 | } 27 | 28 | export const gunzip: typeof nodeZlib.gunzip = notImplementedCompress("gunzip"); 29 | 30 | export const createGunzip: typeof nodeZlib.createGunzip = () => new Gunzip(); 31 | 32 | export const gunzipSync: typeof nodeZlib.gunzipSync = 33 | /*@__PURE__*/ notImplemented("zlib.gunzipSync"); 34 | -------------------------------------------------------------------------------- /test/node/test-url-domain-ascii-unicode.mjs: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob//v22.7.0/test/parallel/test-url-domain-ascii-unicode.js 2 | 3 | import assert from "node:assert"; 4 | 5 | import url from "../../src/runtime/node/url.ts"; 6 | 7 | const domainToASCII = url.domainToASCII; 8 | 9 | const domainToUnicode = url.domainToUnicode; 10 | 11 | const domainWithASCII = [ 12 | ["ıíd", "xn--d-iga7r"], 13 | ["يٴ", "xn--mhb8f"], 14 | ["www.ϧƽəʐ.com", "www.xn--cja62apfr6c.com"], 15 | ["новини.com", "xn--b1amarcd.com"], 16 | ["名がドメイン.com", "xn--v8jxj3d1dzdz08w.com"], 17 | ["افغانستا.icom.museum", "xn--mgbaal8b0b9b2b.icom.museum"], 18 | ["الجزائر.icom.fake", "xn--lgbbat1ad8j.icom.fake"], 19 | ["भारत.org", "xn--h2brj9c.org"], 20 | ]; 21 | 22 | for (const pair of domainWithASCII) { 23 | const domain = pair[0]; 24 | const ascii = pair[1]; 25 | const domainConvertedToASCII = domainToASCII(domain); 26 | assert.strictEqual(domainConvertedToASCII, ascii); 27 | const asciiConvertedToUnicode = domainToUnicode(ascii); 28 | assert.strictEqual(asciiConvertedToUnicode, domain); 29 | } 30 | -------------------------------------------------------------------------------- /src/runtime/node/readline.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/readline.html#readlineclearlinestream-dir-callback 2 | import type nodeReadline from "node:readline"; 3 | import noop from "../mock/noop.ts"; 4 | import promises from "node:readline/promises"; 5 | import { Interface } from "./internal/readline/interface.ts"; 6 | 7 | export { promises }; 8 | 9 | export { Interface } from "./internal/readline/interface.ts"; 10 | 11 | export const clearLine: typeof nodeReadline.clearLine = () => false; 12 | export const clearScreenDown: typeof nodeReadline.clearScreenDown = () => false; 13 | export const createInterface: typeof nodeReadline.createInterface = () => 14 | new Interface(); 15 | export const cursorTo: typeof nodeReadline.cursorTo = () => false; 16 | export const emitKeypressEvents: typeof nodeReadline.emitKeypressEvents = noop; 17 | export const moveCursor: typeof nodeReadline.moveCursor = () => false; 18 | 19 | export default { 20 | clearLine, 21 | clearScreenDown, 22 | createInterface, 23 | cursorTo, 24 | emitKeypressEvents, 25 | moveCursor, 26 | // @ts-expect-error 27 | Interface, 28 | promises, 29 | } satisfies typeof nodeReadline; 30 | -------------------------------------------------------------------------------- /test/node-coverage.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { x } from "tinyexec"; 3 | 4 | describe("node coverage", () => { 5 | it("collect and check", async () => { 6 | const { exitCode, stdout, stderr } = await x( 7 | "node", 8 | [ 9 | "--disable-warning=ExperimentalWarning", 10 | "--experimental-strip-types", 11 | "./node-coverage.ts", 12 | "--json", 13 | ], 14 | { 15 | nodeOptions: { 16 | cwd: __dirname, 17 | }, 18 | }, 19 | ); 20 | expect(exitCode).toBe(0); 21 | expect(stderr.replaceAll(/\(node:\d+\) /g, "")).toMatchInlineSnapshot(` 22 | "[DEP0040] DeprecationWarning: The \`punycode\` module is deprecated. Please use a userland alternative instead. 23 | (Use \`node --trace-deprecation ...\` to show where the warning was created) 24 | [DEP0025] DeprecationWarning: sys is deprecated. Use util instead. 25 | " 26 | `); 27 | const coverage = JSON.parse(stdout); 28 | for (const mod of coverage) { 29 | expect(mod.unsupportedExports, mod.name).length(0); 30 | } 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Pooya Parsa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/runtime/node/events.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/events.html 2 | import type nodeEvents from "node:events"; 3 | 4 | import { _EventEmitter } from "./internal/events/events.ts"; 5 | import { notImplemented } from "../_internal/utils.ts"; 6 | 7 | export { 8 | _EventEmitter as EventEmitter, 9 | EventEmitterAsyncResource, 10 | addAbortListener, 11 | getEventListeners, 12 | getMaxListeners, 13 | on, 14 | once, 15 | } from "./internal/events/events.ts"; 16 | 17 | export const usingDomains = false; 18 | 19 | export const captureRejectionSymbol = 20 | /*@__PURE__*/ Symbol.for("nodejs.rejection"); 21 | 22 | export const captureRejections = false; 23 | 24 | export const errorMonitor = /*@__PURE__*/ Symbol.for("events.errorMonitor"); 25 | 26 | export const defaultMaxListeners = 10; 27 | 28 | export const setMaxListeners = /*@__PURE__*/ notImplemented( 29 | "node:events.setMaxListeners", 30 | ); 31 | 32 | export const listenerCount = /*@__PURE__*/ notImplemented( 33 | "node:events.listenerCount", 34 | ); 35 | 36 | export const init = /*@__PURE__*/ notImplemented("node:events.init"); 37 | 38 | export default _EventEmitter as typeof nodeEvents; 39 | -------------------------------------------------------------------------------- /src/runtime/node/internal/stream/duplex.ts: -------------------------------------------------------------------------------- 1 | import type nodeStream from "node:stream"; 2 | import { mergeFns } from "../../../_internal/utils.ts"; 3 | import { Readable } from "./readable.ts"; 4 | import { Writable } from "./writable.ts"; 5 | 6 | // Docs: https://nodejs.org/api/stream.html#stream_duplex_and_transform_streams 7 | // Implementation: https://github.com/nodejs/node/blob/master/lib/internal/streams/duplex.js 8 | 9 | type DuplexClass = new () => nodeStream.Duplex; 10 | 11 | const __Duplex: DuplexClass = class { 12 | allowHalfOpen: boolean = true; 13 | private _destroy: (error?: Error) => void; 14 | 15 | constructor(readable = new Readable(), writable = new Writable()) { 16 | Object.assign(this, readable); 17 | Object.assign(this, writable); 18 | this._destroy = mergeFns(readable._destroy, writable._destroy); 19 | } 20 | } as any; 21 | 22 | function getDuplex() { 23 | Object.assign(__Duplex.prototype, Readable.prototype); 24 | Object.assign(__Duplex.prototype, Writable.prototype); 25 | return __Duplex; 26 | } 27 | 28 | export const _Duplex = /* #__PURE__ */ getDuplex(); 29 | 30 | export const Duplex: typeof nodeStream.Duplex = 31 | (globalThis as any).Duplex || _Duplex; 32 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: { branches: [main] } 5 | pull_request: { branches: [main] } 6 | 7 | jobs: 8 | tests: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v6 12 | - run: npm i -g --force corepack && corepack enable 13 | - uses: actions/setup-node@v6 14 | with: { node-version-file: ".nvmrc", cache: pnpm } 15 | - run: pnpm install 16 | - run: pnpm lint 17 | - run: pnpm test:types 18 | - run: pnpm build 19 | - run: pnpm vitest --coverage 20 | - uses: codecov/codecov-action@v5 21 | with: { token: "${{ secrets.CODECOV_TOKEN }}" } 22 | publish: 23 | runs-on: ubuntu-latest 24 | permissions: { id-token: write, contents: read } 25 | needs: tests 26 | if: contains('refs/heads/main', github.ref) && github.event_name == 'push' 27 | steps: 28 | - uses: actions/checkout@v6 29 | with: { fetch-depth: 0 } 30 | - run: npm i -fg corepack && corepack enable 31 | - uses: actions/setup-node@v6 32 | with: { node-version: lts/*, cache: "pnpm" } 33 | - run: pnpm install 34 | - run: pnpm changelogen --bump --canary nightly 35 | - run: npm i -g npm@latest && npm publish --tag latest 36 | -------------------------------------------------------------------------------- /src/runtime/node/fs/promises.ts: -------------------------------------------------------------------------------- 1 | import type nodeFsPromises from "node:fs/promises"; 2 | 3 | import { 4 | access, 5 | appendFile, 6 | chmod, 7 | chown, 8 | copyFile, 9 | cp, 10 | glob, 11 | lchmod, 12 | lchown, 13 | link, 14 | lstat, 15 | lutimes, 16 | mkdir, 17 | mkdtemp, 18 | open, 19 | opendir, 20 | readFile, 21 | readdir, 22 | readlink, 23 | realpath, 24 | rename, 25 | rm, 26 | rmdir, 27 | stat, 28 | statfs, 29 | symlink, 30 | truncate, 31 | unlink, 32 | utimes, 33 | watch, 34 | writeFile, 35 | } from "../internal/fs/promises.ts"; 36 | 37 | import * as constants from "../internal/fs/constants.ts"; 38 | 39 | export { constants }; 40 | 41 | export * from "../internal/fs/promises.ts"; 42 | 43 | export default { 44 | constants: constants as any, 45 | access, 46 | appendFile, 47 | chmod, 48 | chown, 49 | copyFile, 50 | cp, 51 | glob, 52 | lchmod, 53 | lchown, 54 | link, 55 | lstat, 56 | lutimes, 57 | mkdir, 58 | mkdtemp, 59 | open, 60 | opendir, 61 | readFile, 62 | readdir, 63 | readlink, 64 | realpath, 65 | rename, 66 | rm, 67 | rmdir, 68 | stat, 69 | statfs, 70 | symlink, 71 | truncate, 72 | unlink, 73 | utimes, 74 | watch, 75 | writeFile, 76 | } satisfies typeof nodeFsPromises; 77 | -------------------------------------------------------------------------------- /src/runtime/node/internal/zlib/formats/brotli.ts: -------------------------------------------------------------------------------- 1 | import type nodeZlib from "node:zlib"; 2 | import { notImplemented } from "../../../../_internal/utils.ts"; 3 | import { 4 | ZlibCompress, 5 | ZLibDecompress, 6 | notImplementedCompress, 7 | } from "./_shared.ts"; 8 | 9 | // Brotli Compression 10 | 11 | export class BrotliCompress extends ZlibCompress { 12 | readonly _format = "brotli"; 13 | } 14 | 15 | export const brotliCompress: typeof nodeZlib.brotliCompress = 16 | notImplementedCompress("brotliCompress"); 17 | 18 | export const createBrotliCompress: typeof nodeZlib.createBrotliCompress = () => 19 | new BrotliCompress(); 20 | 21 | export const brotliCompressSync: typeof nodeZlib.brotliCompressSync = 22 | /*@__PURE__*/ notImplemented("zlib.brotliCompressSync"); 23 | 24 | // Brotli Decompression 25 | 26 | export class BrotliDecompress extends ZLibDecompress { 27 | readonly _format = "brotli"; 28 | } 29 | 30 | export const brotliDecompress: typeof nodeZlib.brotliDecompress = 31 | notImplementedCompress("brotliDecompress"); 32 | 33 | export const createBrotliDecompress: typeof nodeZlib.createBrotliDecompress = 34 | () => new BrotliDecompress(); 35 | 36 | export const brotliDecompressSync: typeof nodeZlib.brotliDecompressSync = 37 | /*@__PURE__*/ notImplemented("zlib.brotliDecompressSync"); 38 | -------------------------------------------------------------------------------- /src/runtime/node/internal/net/server.ts: -------------------------------------------------------------------------------- 1 | import type nodeNet from "node:net"; 2 | import { createNotImplementedError } from "../../../_internal/utils.ts"; 3 | import { EventEmitter } from "node:events"; 4 | 5 | // Docs: https://nodejs.org/api/net.html#net_class_net_server 6 | export class Server extends EventEmitter implements nodeNet.Server { 7 | readonly __unenv__ = true; 8 | 9 | maxConnections: number = 1; 10 | connections: number = 0; 11 | readonly listening: boolean = false; 12 | 13 | constructor( 14 | arg1?: nodeNet.ServerOpts | ((socket: nodeNet.Socket) => void), 15 | arg2?: (socket: nodeNet.Socket) => void, 16 | ) { 17 | super(); 18 | } 19 | 20 | listen(): this { 21 | throw createNotImplementedError("node:net.Server.listen()"); 22 | } 23 | 24 | close(callback?: (err?: Error) => void): this { 25 | throw createNotImplementedError("node:net.Server.close()"); 26 | } 27 | 28 | address(): nodeNet.AddressInfo | string | null { 29 | return null; 30 | } 31 | 32 | getConnections(cb: (error: Error | null, count: number) => void): void { 33 | cb(null, 0); 34 | } 35 | 36 | ref(): this { 37 | return this; 38 | } 39 | 40 | unref(): this { 41 | return this; 42 | } 43 | 44 | [Symbol.asyncDispose](): Promise { 45 | return Promise.resolve(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/runtime/node/internal/dns/constants.ts: -------------------------------------------------------------------------------- 1 | // npx -y node@22.14 -e 'const dns=require("dns");console.log(Object.entries(dns).filter(e => ["string", "number"].includes(typeof e[1])).map(([k,v]) => `export const ${k} = ${JSON.stringify(v)}`).join("\n"))' 2 | 3 | export const ADDRCONFIG = 1024; 4 | export const ALL = 256; 5 | export const V4MAPPED = 2048; 6 | export const NODATA = "ENODATA"; 7 | export const FORMERR = "EFORMERR"; 8 | export const SERVFAIL = "ESERVFAIL"; 9 | export const NOTFOUND = "ENOTFOUND"; 10 | export const NOTIMP = "ENOTIMP"; 11 | export const REFUSED = "EREFUSED"; 12 | export const BADQUERY = "EBADQUERY"; 13 | export const BADNAME = "EBADNAME"; 14 | export const BADFAMILY = "EBADFAMILY"; 15 | export const BADRESP = "EBADRESP"; 16 | export const CONNREFUSED = "ECONNREFUSED"; 17 | export const TIMEOUT = "ETIMEOUT"; 18 | export const EOF = "EOF"; 19 | export const FILE = "EFILE"; 20 | export const NOMEM = "ENOMEM"; 21 | export const DESTRUCTION = "EDESTRUCTION"; 22 | export const BADSTR = "EBADSTR"; 23 | export const BADFLAGS = "EBADFLAGS"; 24 | export const NONAME = "ENONAME"; 25 | export const BADHINTS = "EBADHINTS"; 26 | export const NOTINITIALIZED = "ENOTINITIALIZED"; 27 | export const LOADIPHLPAPI = "ELOADIPHLPAPI"; 28 | export const ADDRGETNETWORKPARAMS = "EADDRGETNETWORKPARAMS"; 29 | export const CANCELLED = "ECANCELLED"; 30 | -------------------------------------------------------------------------------- /src/runtime/node/repl.ts: -------------------------------------------------------------------------------- 1 | import type nodeRepl from "node:repl"; 2 | import { builtinModules as _builtinModules } from "node:module"; 3 | import { notImplemented, notImplementedClass } from "../_internal/utils.ts"; 4 | 5 | export const writer = 6 | /*@__PURE__*/ notImplementedClass("repl.writer"); 7 | 8 | export const start = 9 | /*@__PURE__*/ notImplemented("repl.start"); 10 | 11 | export const Recoverable = 12 | /*@__PURE__*/ notImplementedClass( 13 | "repl.Recoverable", 14 | ); 15 | 16 | export const REPLServer = 17 | /*@__PURE__*/ notImplementedClass( 18 | "repl.REPLServer", 19 | ); 20 | 21 | export const REPL_MODE_SLOPPY: unique symbol = 22 | /*@__PURE__*/ Symbol("repl-sloppy"); 23 | 24 | export const REPL_MODE_STRICT: unique symbol = 25 | /*@__PURE__*/ Symbol("repl-strict"); 26 | 27 | export const builtinModules = /*@__PURE__*/ _builtinModules.filter( 28 | (m) => m[0] !== "_", 29 | ); 30 | 31 | export const _builtinLibs = builtinModules; 32 | 33 | export default { 34 | writer, 35 | start, 36 | Recoverable, 37 | REPLServer, 38 | builtinModules, 39 | _builtinLibs, 40 | // @ts-expect-error 41 | REPL_MODE_SLOPPY, 42 | // @ts-expect-error 43 | REPL_MODE_STRICT, 44 | } satisfies typeof nodeRepl; 45 | -------------------------------------------------------------------------------- /lib/mock.cjs: -------------------------------------------------------------------------------- 1 | Object.defineProperty(exports, "__esModule", { 2 | value: true 3 | }); 4 | 5 | function createMock(name, overrides = {}) { 6 | const proxyFn = function () { /* noop */ }; 7 | proxyFn.prototype.name = name; 8 | const props = {}; 9 | const proxy = new Proxy(proxyFn, { 10 | get(_target, prop) { 11 | if (prop === "caller") { 12 | return null; 13 | } 14 | if (prop === "__createMock__") { 15 | return createMock; 16 | } 17 | if (prop === "__unenv__") { 18 | return true; 19 | } 20 | if (prop in overrides) { 21 | return overrides[prop]; 22 | } 23 | if (prop === "then") { 24 | return (fn) => Promise.resolve(fn()); 25 | } 26 | if (prop === "catch") { 27 | return (fn) => Promise.resolve(); 28 | } 29 | if (prop === "finally") { 30 | return (fn) => Promise.resolve(fn()); 31 | } 32 | return props[prop] = props[prop] || createMock(`${name}.${prop.toString()}`); 33 | }, 34 | apply(_target, _this, _args) { 35 | return createMock(`${name}()`); 36 | }, 37 | construct(_target, _args, _newT) { 38 | return createMock(`[${name}]`); 39 | }, 40 | enumerate() { 41 | return []; 42 | } 43 | }); 44 | return proxy; 45 | } 46 | 47 | module.exports = createMock("mock"); 48 | -------------------------------------------------------------------------------- /src/runtime/node/internal/process/env.ts: -------------------------------------------------------------------------------- 1 | const _envShim = Object.create(null); 2 | 3 | // Keep a reference to the original process to avoid circular references after polyfilling 4 | const originalProcess = globalThis["process"]; 5 | 6 | const _getEnv = (useShim?: boolean) => 7 | (globalThis as any).__env__ || 8 | originalProcess?.env || 9 | (useShim ? _envShim : globalThis); 10 | 11 | export const env: NodeJS.Process["env"] = /*@__PURE__*/ new Proxy(_envShim, { 12 | get(_, prop) { 13 | const env = _getEnv(); 14 | return env[prop as string] ?? _envShim[prop]; 15 | }, 16 | has(_, prop) { 17 | const env = _getEnv(); 18 | return prop in env || prop in _envShim; 19 | }, 20 | set(_, prop, value) { 21 | const env = _getEnv(true); 22 | env[prop as string] = value; 23 | return true; 24 | }, 25 | deleteProperty(_, prop) { 26 | const env = _getEnv(true); 27 | delete env[prop as string]; 28 | return true; 29 | }, 30 | ownKeys() { 31 | const env = _getEnv(); 32 | return Object.keys(env); 33 | }, 34 | getOwnPropertyDescriptor(_, prop) { 35 | const env = _getEnv(); 36 | if (prop in env) { 37 | return { 38 | value: env[prop as string], 39 | writable: true, 40 | enumerable: true, 41 | configurable: true, 42 | }; 43 | } 44 | return undefined; 45 | }, 46 | }); 47 | -------------------------------------------------------------------------------- /src/runtime/node/internal/readline/interface.ts: -------------------------------------------------------------------------------- 1 | import type nodeReadline from "node:readline"; 2 | import type { Abortable } from "node:events"; 3 | import { EventEmitter } from "node:events"; 4 | 5 | export class Interface extends EventEmitter implements nodeReadline.Interface { 6 | terminal = false; 7 | line = ""; 8 | cursor = 0; 9 | 10 | getPrompt() { 11 | return ""; 12 | } 13 | setPrompt(prompt: string): void {} 14 | prompt(preserveCursor?: boolean | undefined): void {} 15 | question(query: string, callback: (answer: string) => void): void; 16 | question( 17 | query: string, 18 | options: Abortable, 19 | callback: (answer: string) => void, 20 | ): void; 21 | question(query: unknown, options: unknown, callback?: unknown): void { 22 | callback && typeof callback === "function" && callback(""); 23 | } 24 | 25 | resume() { 26 | return this; 27 | } 28 | close() {} 29 | write(data: string | Buffer, key?: nodeReadline.Key | undefined): void; 30 | write(data: string | Buffer | null | undefined, key: nodeReadline.Key): void; 31 | write(data: unknown, key?: unknown): void {} 32 | getCursorPos(): nodeReadline.CursorPos { 33 | return { 34 | rows: 0, 35 | cols: 0, 36 | }; 37 | } 38 | pause() { 39 | return this; 40 | } 41 | 42 | async *[Symbol.asyncIterator](): NodeJS.AsyncIterator { 43 | yield ""; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/runtime/npm/whatwg-url/index.ts: -------------------------------------------------------------------------------- 1 | // https://www.npmjs.com/package/whatwg-url 2 | import { notImplemented } from "../../_internal/utils.ts"; 3 | 4 | export const URL = globalThis.URL; 5 | export const URLSearchParams = globalThis.URLSearchParams; 6 | 7 | export const parseURL = /*@__PURE__*/ notImplemented("whatwg-url.parseURL"); 8 | export const basicURLParse = /*@__PURE__*/ notImplemented( 9 | "whatwg-url.basicURLParse", 10 | ); 11 | export const serializeURL = /*@__PURE__*/ notImplemented( 12 | "whatwg-url.serializeURL", 13 | ); 14 | export const serializeHost = /*@__PURE__*/ notImplemented( 15 | "whatwg-url.serializeHost", 16 | ); 17 | export const serializeInteger = /*@__PURE__*/ notImplemented( 18 | "whatwg-url.serializeInteger", 19 | ); 20 | export const serializeURLOrigin = /*@__PURE__*/ notImplemented( 21 | "whatwg-url.serializeURLOrigin", 22 | ); 23 | export const setTheUsername = /*@__PURE__*/ notImplemented( 24 | "whatwg-url.setTheUsername", 25 | ); 26 | export const setThePassword = /*@__PURE__*/ notImplemented( 27 | "whatwg-url.setThePassword", 28 | ); 29 | export const cannotHaveAUsernamePasswordPort = /*@__PURE__*/ notImplemented( 30 | "whatwg-url.cannotHaveAUsernamePasswordPort", 31 | ); 32 | export const percentDecodeBytes = /*@__PURE__*/ notImplemented( 33 | "whatwg-url.percentDecodeBytes", 34 | ); 35 | export const percentDecodeString = /*@__PURE__*/ notImplemented( 36 | "whatwg-url.percentDecodeString", 37 | ); 38 | -------------------------------------------------------------------------------- /src/runtime/mock/proxy.ts: -------------------------------------------------------------------------------- 1 | function createMock(name: string, overrides: any = {}): any { 2 | const proxyFn = function () {}; 3 | proxyFn.prototype.name = name; 4 | const props: any = {}; 5 | const proxy = new Proxy(proxyFn, { 6 | get(_target, prop) { 7 | if (prop === "caller") { 8 | return null; 9 | } 10 | if (prop === "__createMock__") { 11 | return createMock; 12 | } 13 | if (prop === "__unenv__") { 14 | return true; 15 | } 16 | if (prop in overrides) { 17 | return overrides[prop]; 18 | } 19 | if (prop === "then") { 20 | return (fn: any) => Promise.resolve(fn()); 21 | } 22 | if (prop === "catch") { 23 | return (fn: any) => Promise.resolve(); 24 | } 25 | if (prop === "finally") { 26 | return (fn: any) => Promise.resolve(fn()); 27 | } 28 | // @ts-ignore 29 | return (props[prop] = 30 | props[prop] || createMock(`${name}.${prop.toString()}`)); 31 | }, 32 | apply(_target, _this, _args) { 33 | return createMock(`${name}()`); 34 | }, 35 | construct(_target, _args, _newT) { 36 | return createMock(`[${name}]`) as object; 37 | }, 38 | // @ts-ignore (ES6-only - removed in ES7) 39 | // https://github.com/tc39/ecma262/issues/161 40 | enumerate() { 41 | return []; 42 | }, 43 | }); 44 | return proxy; 45 | } 46 | 47 | export default createMock("mock"); 48 | -------------------------------------------------------------------------------- /src/runtime/node/internal/util/mime.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | MIMEType as MIMETypeT, 3 | MIMEParams as MIMEParamsT, 4 | } from "node:util"; 5 | 6 | // https://nodejs.org/api/util.html#class-utilmimetype 7 | 8 | export class MIMEType implements MIMETypeT { 9 | readonly __unenv__ = true; 10 | 11 | params = new MIMEParams(); 12 | type: string; 13 | subtype: string; 14 | 15 | constructor(input: string | { toString: () => string }) { 16 | const [essence = "", ...params] = String(input).split(";"); 17 | const [type = "", subtype = ""] = essence.split("/"); 18 | this.type = type; 19 | this.subtype = subtype; 20 | this.params = new MIMEParams(); 21 | for (const param of params) { 22 | const [name, value] = param.split("="); 23 | this.params.set(name, value); 24 | } 25 | } 26 | 27 | get essence() { 28 | return this.type + "/" + this.subtype; 29 | } 30 | 31 | toString() { 32 | const paramsStr = this.params.toString(); 33 | return this.essence + (paramsStr ? `;${paramsStr}` : ""); 34 | } 35 | } 36 | 37 | // https://nodejs.org/api/util.html#util_class_util_mimeparams 38 | 39 | export class MIMEParams extends Map implements MIMEParamsT { 40 | readonly __unenv__ = true; 41 | 42 | get(name: string) { 43 | return (super.get(name) || null) as any; 44 | } 45 | 46 | toString() { 47 | return [...this.entries()] 48 | .map(([name, value]) => `${name}=${value}`) 49 | .join("&"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/runtime/node/child_process.ts: -------------------------------------------------------------------------------- 1 | import { notImplemented, notImplementedClass } from "../_internal/utils.ts"; 2 | import type nodeChildProcess from "node:child_process"; 3 | 4 | export const ChildProcess: typeof nodeChildProcess.ChildProcess = 5 | /*@__PURE__*/ notImplementedClass("child_process.ChildProcess"); 6 | 7 | export const _forkChild = /*@__PURE__*/ notImplemented( 8 | "child_process.ChildProcess", 9 | ); 10 | 11 | export const exec: typeof nodeChildProcess.exec = 12 | /*@__PURE__*/ notImplemented("child_process.exec"); 13 | export const execFile: typeof nodeChildProcess.execFile = 14 | /*@__PURE__*/ notImplemented("child_process.execFile"); 15 | export const execFileSync: typeof nodeChildProcess.execFileSync = 16 | /*@__PURE__*/ notImplemented("child_process.execFileSync"); 17 | export const execSync: typeof nodeChildProcess.execSync = 18 | /*@__PURE__*/ notImplemented("child_process.execSyn"); 19 | export const fork: typeof nodeChildProcess.fork = 20 | /*@__PURE__*/ notImplemented("child_process.fork"); 21 | export const spawn: typeof nodeChildProcess.spawn = 22 | /*@__PURE__*/ notImplemented("child_process.spawn"); 23 | export const spawnSync: typeof nodeChildProcess.spawnSync = 24 | /*@__PURE__*/ notImplemented("child_process.spawnSync"); 25 | 26 | export default { 27 | ChildProcess, 28 | _forkChild, 29 | exec, 30 | execFile, 31 | execFileSync, 32 | execSync, 33 | fork, 34 | spawn, 35 | spawnSync, 36 | } as /* TODO: use satisfies */ typeof nodeChildProcess; 37 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import unjs from "eslint-config-unjs"; 2 | 3 | // https://github.com/unjs/eslint-config 4 | export default unjs( 5 | { 6 | ignores: ["runtime/**"], 7 | rules: { 8 | "@typescript-eslint/no-unused-vars": 0, 9 | "unicorn/no-null": 0, 10 | "unicorn/prefer-math-trunc": 0, 11 | "unicorn/prefer-code-point": 0, 12 | "unicorn/text-encoding-identifier-case": 0, 13 | "prefer-rest-params": 0, 14 | "prefer-spread": 0, 15 | "unicorn/prefer-event-target": 0, 16 | "unicorn/prefer-ternary": 0, 17 | "unicorn/number-literal-case": 0, 18 | "generator-star-spacing": 0, 19 | "unicorn/no-nested-ternary": 0, 20 | "require-await": 0, 21 | "unicorn/switch-case-braces": 0, 22 | "unicorn/prefer-string-replace-all": 0, 23 | "no-empty": 0, 24 | "no-func-assign": 0, 25 | "unicorn/filename-case": 0, 26 | "@typescript-eslint/no-unused-expressions": 0, 27 | "unicorn/prefer-global-this": 0, 28 | "unicorn/prefer-math-min-max": 0, 29 | "unicorn/prefer-export-from": 0, 30 | "no-restricted-imports": [ 31 | "error", 32 | { 33 | patterns: [ 34 | { 35 | group: ["src/*"], 36 | message: "Use relative imports instead.", 37 | }, 38 | ], 39 | }, 40 | ], 41 | }, 42 | }, 43 | { 44 | languageOptions: { 45 | globals: { 46 | Deno: "readonly", 47 | }, 48 | }, 49 | }, 50 | ); 51 | -------------------------------------------------------------------------------- /src/runtime/node/internal/dgram/socket.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "node:events"; 2 | import type nodeNet from "node:net"; 3 | import type nodeDgram from "node:dgram"; 4 | 5 | export class Socket extends EventEmitter implements nodeDgram.Socket { 6 | readonly __unenv__ = true; 7 | 8 | bind(): this { 9 | return this; 10 | } 11 | close(): this { 12 | return this; 13 | } 14 | ref(): this { 15 | return this; 16 | } 17 | unref(): this { 18 | return this; 19 | } 20 | getRecvBufferSize(): number { 21 | return 100_000; 22 | } 23 | getSendBufferSize(): number { 24 | return 10_000; 25 | } 26 | getSendQueueSize(): number { 27 | return 0; 28 | } 29 | getSendQueueCount(): number { 30 | return 0; 31 | } 32 | setMulticastLoopback(): boolean { 33 | return false; 34 | } 35 | setMulticastTTL(): number { 36 | return 1; 37 | } 38 | setTTL(): number { 39 | return 1; 40 | } 41 | address(): nodeNet.AddressInfo { 42 | return { address: "127.0.0.1", family: "IPv4", port: 1234 }; 43 | } 44 | 45 | remoteAddress(): nodeNet.AddressInfo { 46 | throw new Error("ERR_SOCKET_DGRAM_NOT_CONNECTED"); 47 | } 48 | 49 | [Symbol.asyncDispose]() { 50 | return Promise.resolve(); 51 | } 52 | 53 | addMembership() {} 54 | addSourceSpecificMembership() {} 55 | connect() {} 56 | disconnect() {} 57 | dropMembership() {} 58 | dropSourceSpecificMembership() {} 59 | send() {} 60 | setSendBufferSize() {} 61 | setBroadcast() {} 62 | setRecvBufferSize() {} 63 | setMulticastInterface() {} 64 | } 65 | -------------------------------------------------------------------------------- /src/runtime/node/path.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/path.html 2 | // https://github.com/unjs/pathe 3 | import type nodePath from "node:path"; 4 | 5 | import { notImplemented } from "../_internal/utils.ts"; 6 | 7 | import { 8 | basename, 9 | dirname, 10 | extname, 11 | format, 12 | isAbsolute, 13 | join, 14 | normalize, 15 | parse, 16 | relative, 17 | resolve, 18 | toNamespacedPath, 19 | } from "pathe"; 20 | 21 | export { 22 | basename, 23 | dirname, 24 | extname, 25 | format, 26 | isAbsolute, 27 | join, 28 | normalize, 29 | parse, 30 | relative, 31 | resolve, 32 | toNamespacedPath, 33 | } from "pathe"; 34 | 35 | export const sep = "/" as const; 36 | export const delimiter = ":" as const; 37 | 38 | const _pathModule = { 39 | sep, 40 | delimiter, 41 | basename, 42 | dirname, 43 | extname, 44 | format, 45 | isAbsolute, 46 | join, 47 | normalize, 48 | parse, 49 | relative, 50 | resolve, 51 | toNamespacedPath, 52 | posix: undefined as any, 53 | win32: undefined as any, 54 | _makeLong: (path: string) => path, 55 | // https://github.com/unjs/pathe/issues/182 56 | matchesGlob: /*@__PURE__*/ notImplemented(`path.matchesGlob`), 57 | }; 58 | _pathModule.posix = _pathModule; 59 | _pathModule.win32 = _pathModule; 60 | 61 | export const posix: typeof nodePath.posix = _pathModule; 62 | export const win32: typeof nodePath.posix = _pathModule; 63 | 64 | export const _makeLong = _pathModule._makeLong; 65 | 66 | export const matchesGlob = _pathModule.matchesGlob; 67 | 68 | export default _pathModule satisfies typeof nodePath; 69 | -------------------------------------------------------------------------------- /src/runtime/node/internal/async_hooks/async-local-storage.ts: -------------------------------------------------------------------------------- 1 | import type nodeAsyncHooks from "node:async_hooks"; 2 | 3 | // https://nodejs.org/api/async_context.html#class-asynclocalstorage 4 | 5 | class _AsyncLocalStorage implements nodeAsyncHooks.AsyncLocalStorage { 6 | readonly __unenv__ = true; 7 | 8 | _currentStore: undefined | T; 9 | _enterStore: undefined | T; 10 | _enabled: boolean = true; 11 | 12 | getStore() { 13 | return this._currentStore ?? this._enterStore; 14 | } 15 | 16 | disable() { 17 | this._enabled = false; 18 | } 19 | 20 | enable() { 21 | this._enabled = true; 22 | } 23 | 24 | enterWith(store: any) { 25 | this._enterStore = store; 26 | } 27 | 28 | run( 29 | store: any, 30 | callback: (...args: TArgs) => R, 31 | ...args: TArgs 32 | ): R { 33 | this._currentStore = store; 34 | const res = callback(...args); 35 | this._currentStore = undefined; 36 | return res; 37 | } 38 | 39 | exit( 40 | callback: (...args: TArgs) => R, 41 | ...args: TArgs 42 | ): R { 43 | const _previousStore = this._currentStore; 44 | this._currentStore = undefined; 45 | const res = callback(...args); 46 | this._currentStore = _previousStore; 47 | return res; 48 | } 49 | 50 | static snapshot(): any { 51 | throw new Error("[unenv] `AsyncLocalStorage.snapshot` is not implemented!"); 52 | } 53 | } 54 | 55 | export const AsyncLocalStorage: typeof nodeAsyncHooks.AsyncLocalStorage = 56 | (globalThis as any).AsyncLocalStorage || _AsyncLocalStorage; 57 | -------------------------------------------------------------------------------- /test/node/test-querystring-escape.mjs: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob//v22.7.0/test/parallel/test-querystring-escape.js 2 | 3 | import assert from "node:assert"; 4 | 5 | import qs from "../../src/runtime/node/querystring.ts"; 6 | 7 | assert.strictEqual(qs.escape(5), "5"); 8 | assert.strictEqual(qs.escape("test"), "test"); 9 | assert.strictEqual(qs.escape({}), "%5Bobject%20Object%5D"); 10 | assert.strictEqual(qs.escape([5, 10]), "5%2C10"); 11 | assert.strictEqual(qs.escape("Ŋōđĕ"), "%C5%8A%C5%8D%C4%91%C4%95"); 12 | assert.strictEqual(qs.escape("testŊōđĕ"), "test%C5%8A%C5%8D%C4%91%C4%95"); 13 | assert.strictEqual( 14 | qs.escape(`${String.fromCharCode(0xd8_00 + 1)}test`), 15 | "%F0%90%91%B4est", 16 | ); 17 | 18 | assert.throws(() => qs.escape(String.fromCharCode(0xd8_00 + 1)), { 19 | code: "ERR_INVALID_URI", 20 | name: "URIError", 21 | message: "URI malformed", 22 | }); 23 | 24 | // Using toString for objects 25 | assert.strictEqual( 26 | qs.escape({ test: 5, toString: () => "test", valueOf: () => 10 }), 27 | "test", 28 | ); 29 | 30 | // `toString` is not callable, must throw an error. 31 | // Error message will vary between different JavaScript engines, so only check 32 | // that it is a `TypeError`. 33 | assert.throws(() => qs.escape({ toString: 5 }), TypeError); 34 | 35 | // Should use valueOf instead of non-callable toString. 36 | assert.strictEqual(qs.escape({ toString: 5, valueOf: () => "test" }), "test"); 37 | 38 | // Error message will vary between different JavaScript engines, so only check 39 | // that it is a `TypeError`. 40 | assert.throws(() => qs.escape(Symbol("test")), TypeError); 41 | -------------------------------------------------------------------------------- /src/runtime/node/assert/strict.ts: -------------------------------------------------------------------------------- 1 | import type nodeAssert from "node:assert"; 2 | 3 | import { 4 | AssertionError, 5 | CallTracker, 6 | strict, 7 | fail, 8 | ok, 9 | throws, 10 | rejects, 11 | doesNotThrow, 12 | doesNotReject, 13 | ifError, 14 | match, 15 | doesNotMatch, 16 | notDeepStrictEqual, 17 | notDeepStrictEqual as notDeepEqual, 18 | strictEqual, 19 | strictEqual as equal, 20 | notStrictEqual, 21 | notStrictEqual as notEqual, 22 | deepStrictEqual, 23 | deepStrictEqual as deepEqual, 24 | partialDeepStrictEqual, 25 | } from "../assert.ts"; 26 | 27 | export { 28 | AssertionError, 29 | CallTracker, 30 | strict, 31 | fail, 32 | ok, 33 | throws, 34 | rejects, 35 | doesNotThrow, 36 | doesNotReject, 37 | ifError, 38 | match, 39 | doesNotMatch, 40 | notDeepStrictEqual, 41 | notDeepStrictEqual as notDeepEqual, 42 | strictEqual, 43 | strictEqual as equal, 44 | notStrictEqual, 45 | notStrictEqual as notEqual, 46 | deepStrictEqual, 47 | deepStrictEqual as deepEqual, 48 | partialDeepStrictEqual, 49 | } from "../assert.ts"; 50 | 51 | export default Object.assign(ok, { 52 | AssertionError, 53 | CallTracker, 54 | strict, 55 | fail, 56 | ok, 57 | throws, 58 | rejects, 59 | doesNotThrow, 60 | doesNotReject, 61 | ifError, 62 | match, 63 | doesNotMatch, 64 | notDeepStrictEqual, 65 | notDeepEqual, 66 | strictEqual, 67 | equal, 68 | notStrictEqual, 69 | notEqual, 70 | deepStrictEqual, 71 | deepEqual, 72 | partialDeepStrictEqual, 73 | }) as typeof nodeAssert.strict; // TODO: utils are strict by default so should be typed as strict! 74 | -------------------------------------------------------------------------------- /test/workerd.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { x } from "tinyexec"; 3 | 4 | describe("tests in workerd", () => { 5 | it("run", async () => { 6 | const { exitCode, stderr } = await x("node", ["./workerd/main.mjs"], { 7 | nodeOptions: { 8 | cwd: __dirname, 9 | }, 10 | }); 11 | expect(exitCode, stderr).toBe(0); 12 | expect(stderr.replaceAll(/\(node:\d+\) |^.+: debug: | \(.+\)$/gm, "")) 13 | .toMatchInlineSnapshot(` 14 | "[ TEST ] tests:crypto_getRandomValues 15 | [ PASS ] tests:crypto_getRandomValues 16 | [ TEST ] tests:unenv_polyfills_buffer 17 | [ PASS ] tests:unenv_polyfills_buffer 18 | [ TEST ] tests:unenv_polyfills_path 19 | [ PASS ] tests:unenv_polyfills_path 20 | [ TEST ] tests:url_parse 21 | [DeprecationWarning] [unenv] [node:url] DEP0169: \`url.parse()\` behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for \`url.parse()\` vulnerabilities. 22 | [ PASS ] tests:url_parse 23 | [ TEST ] tests:workerd_dns 24 | [ PASS ] tests:workerd_dns 25 | [ TEST ] tests:workerd_implements_buffer 26 | [ PASS ] tests:workerd_implements_buffer 27 | [ TEST ] tests:workerd_modules 28 | [ PASS ] tests:workerd_modules 29 | [ TEST ] tests:workerd_net 30 | [ PASS ] tests:workerd_net 31 | [ TEST ] tests:workerd_path 32 | [ PASS ] tests:workerd_path 33 | [ TEST ] tests:workerd_timers 34 | [ PASS ] tests:workerd_timers 35 | " 36 | `); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/runtime/node/internal/perf_hooks/constants.ts: -------------------------------------------------------------------------------- 1 | // npx -y node@22.14 -e 'const {constants}=require("perf_hooks");console.log(Object.entries(Object.getOwnPropertyDescriptors(constants)).map(([k,v]) => `export const ${k} = ${JSON.stringify(v.value)}`).join("\n"))' 2 | 3 | export const NODE_PERFORMANCE_GC_MAJOR = 4; 4 | export const NODE_PERFORMANCE_GC_MINOR = 1; 5 | export const NODE_PERFORMANCE_GC_INCREMENTAL = 8; 6 | export const NODE_PERFORMANCE_GC_WEAKCB = 16; 7 | export const NODE_PERFORMANCE_GC_FLAGS_NO = 0; 8 | export const NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED = 2; 9 | export const NODE_PERFORMANCE_GC_FLAGS_FORCED = 4; 10 | export const NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING = 8; 11 | export const NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE = 16; 12 | export const NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY = 32; 13 | export const NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE = 64; 14 | export const NODE_PERFORMANCE_ENTRY_TYPE_GC = 0; 15 | export const NODE_PERFORMANCE_ENTRY_TYPE_HTTP = 1; 16 | export const NODE_PERFORMANCE_ENTRY_TYPE_HTTP2 = 2; 17 | export const NODE_PERFORMANCE_ENTRY_TYPE_NET = 3; 18 | export const NODE_PERFORMANCE_ENTRY_TYPE_DNS = 4; 19 | export const NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN_TIMESTAMP = 0; 20 | export const NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN = 1; 21 | export const NODE_PERFORMANCE_MILESTONE_ENVIRONMENT = 2; 22 | export const NODE_PERFORMANCE_MILESTONE_NODE_START = 3; 23 | export const NODE_PERFORMANCE_MILESTONE_V8_START = 4; 24 | export const NODE_PERFORMANCE_MILESTONE_LOOP_START = 5; 25 | export const NODE_PERFORMANCE_MILESTONE_LOOP_EXIT = 6; 26 | export const NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE = 7; 27 | -------------------------------------------------------------------------------- /src/runtime/node/buffer.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/buffer.html 2 | import type nodeBuffer from "node:buffer"; 3 | import { notImplemented } from "../_internal/utils.ts"; 4 | import { 5 | Buffer as _Buffer, 6 | kMaxLength, 7 | INSPECT_MAX_BYTES, 8 | SlowBuffer, 9 | } from "./internal/buffer/buffer.ts"; 10 | import { File } from "./internal/buffer/file.ts"; 11 | 12 | export { 13 | kMaxLength, 14 | INSPECT_MAX_BYTES, 15 | SlowBuffer, 16 | } from "./internal/buffer/buffer.ts"; 17 | 18 | export const Buffer = globalThis.Buffer || _Buffer; 19 | 20 | export { File } from "./internal/buffer/file.ts"; 21 | 22 | // @ts-expect-eerror https://github.com/unjs/unenv/issues/64 23 | export const Blob = globalThis.Blob as unknown as typeof nodeBuffer.Blob; 24 | export const resolveObjectURL = /*@__PURE__*/ notImplemented( 25 | "buffer.resolveObjectURL", 26 | ); 27 | export const transcode = /*@__PURE__*/ notImplemented("buffer.transcode"); 28 | export const isUtf8 = /*@__PURE__*/ notImplemented("buffer.isUtf8"); 29 | export const isAscii = /*@__PURE__*/ notImplemented("buffer.isAscii"); 30 | 31 | export const btoa = globalThis.btoa.bind(globalThis); 32 | export const atob = globalThis.atob.bind(globalThis); 33 | 34 | export const kStringMaxLength = 0; // TODO 35 | export const constants = { 36 | MAX_LENGTH: kMaxLength, 37 | MAX_STRING_LENGTH: kStringMaxLength, 38 | }; 39 | 40 | export default { 41 | Buffer, 42 | SlowBuffer: SlowBuffer as any as typeof nodeBuffer.SlowBuffer, 43 | kMaxLength, 44 | INSPECT_MAX_BYTES, 45 | Blob, 46 | resolveObjectURL, 47 | transcode, 48 | btoa, 49 | atob, 50 | kStringMaxLength, 51 | constants, 52 | isUtf8, 53 | isAscii, 54 | File, 55 | } satisfies typeof nodeBuffer; 56 | -------------------------------------------------------------------------------- /src/runtime/node/internal/perf_hooks/histogram.ts: -------------------------------------------------------------------------------- 1 | import type nodePerfHooks from "node:perf_hooks"; 2 | import { createNotImplementedError } from "../../../_internal/utils.ts"; 3 | 4 | class Histogram implements nodePerfHooks.Histogram { 5 | min = 9_223_372_036_854_776_000; 6 | max = 0; 7 | mean = Number.NaN; 8 | exceeds = 0; 9 | stddev = Number.NaN; 10 | count: number = 0; 11 | countBigInt: bigint = BigInt(0); 12 | exceedsBigInt: bigint = BigInt(0); 13 | maxBigInt: number = 0; 14 | minBigInt: bigint = BigInt(9_223_372_036_854_775_807n); 15 | percentiles: Map = new Map(); 16 | percentilesBigInt: Map = new Map(); 17 | percentileBigInt(_percentile: number): bigint { 18 | throw createNotImplementedError("Histogram.percentileBigInt"); 19 | } 20 | percentile(percentile: number): number { 21 | return this.percentiles.get(percentile) ?? Number.NaN; 22 | } 23 | reset(): void { 24 | throw createNotImplementedError("Histogram.reset"); 25 | } 26 | } 27 | 28 | export class IntervalHistogram 29 | extends Histogram 30 | implements nodePerfHooks.IntervalHistogram 31 | { 32 | enable() { 33 | return true; 34 | } 35 | disable() { 36 | return true; 37 | } 38 | } 39 | 40 | export class RecordableHistogram 41 | extends Histogram 42 | implements nodePerfHooks.RecordableHistogram 43 | { 44 | record(val: number | bigint): void { 45 | throw createNotImplementedError("RecordableHistogram.record"); 46 | } 47 | recordDelta(): void { 48 | throw createNotImplementedError("RecordableHistogram.recordDelta"); 49 | } 50 | add(other: nodePerfHooks.RecordableHistogram): void { 51 | throw createNotImplementedError("RecordableHistogram.add"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/runtime/node/internal/diagnostics_channel/channel.ts: -------------------------------------------------------------------------------- 1 | import { createNotImplementedError } from "../../../_internal/utils.ts"; 2 | import type nodeDiagnosticsChannel from "node:diagnostics_channel"; 3 | 4 | const channels: Record = {}; 5 | export const getChannels = () => channels; 6 | 7 | export class Channel 8 | implements nodeDiagnosticsChannel.Channel 9 | { 10 | readonly __unenv__ = true; 11 | 12 | name: nodeDiagnosticsChannel.Channel["name"]; 13 | 14 | get hasSubscribers() { 15 | return this._subscribers.length > 0; 16 | } 17 | 18 | _subscribers: nodeDiagnosticsChannel.ChannelListener[]; 19 | 20 | constructor(name: nodeDiagnosticsChannel.Channel["name"]) { 21 | this.name = name; 22 | this._subscribers = []; 23 | 24 | const channels = getChannels(); 25 | channels[name] = this; 26 | } 27 | 28 | subscribe(onMessage: nodeDiagnosticsChannel.ChannelListener) { 29 | this._subscribers.push(onMessage); 30 | } 31 | 32 | unsubscribe(onMessage: nodeDiagnosticsChannel.ChannelListener) { 33 | const index = this._subscribers.indexOf(onMessage); 34 | if (index === -1) return false; 35 | 36 | this._subscribers.splice(index, 1); 37 | return true; 38 | } 39 | 40 | publish(message: unknown): void { 41 | for (const subscriber of this._subscribers) { 42 | subscriber(message, this.name); 43 | } 44 | } 45 | 46 | bindStore() { 47 | throw createNotImplementedError("Channel.bindStore"); 48 | } 49 | 50 | unbindStore() { 51 | throw createNotImplementedError("Channel.unbindStore"); 52 | } 53 | 54 | runStores() { 55 | throw createNotImplementedError("Channel.runStores"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/runtime/node/inspector/promises.ts: -------------------------------------------------------------------------------- 1 | import type nodeInspectorPromises from "node:inspector/promises"; 2 | import { notImplemented, notImplementedClass } from "../../_internal/utils.ts"; 3 | import noop from "../../mock/noop.ts"; 4 | 5 | export const console: typeof nodeInspectorPromises.console = { 6 | debug: noop, 7 | error: noop, 8 | info: noop, 9 | log: noop, 10 | warn: noop, 11 | dir: noop, 12 | dirxml: noop, 13 | table: noop, 14 | trace: noop, 15 | group: noop, 16 | groupCollapsed: noop, 17 | groupEnd: noop, 18 | clear: noop, 19 | count: noop, 20 | countReset: noop, 21 | assert: noop, 22 | profile: noop, 23 | profileEnd: noop, 24 | time: noop, 25 | timeLog: noop, 26 | timeStamp: noop, 27 | }; 28 | 29 | export const Network = /*@__PURE__*/ notImplementedClass< 30 | typeof nodeInspectorPromises.Network 31 | >("inspectorPromises.Network"); 32 | 33 | export const Session = /*@__PURE__*/ notImplementedClass< 34 | typeof nodeInspectorPromises.Session 35 | >("inspectorPromises.Session"); 36 | 37 | export const url = /*@__PURE__*/ notImplemented< 38 | typeof nodeInspectorPromises.url 39 | >("inspectorPromises.url"); 40 | 41 | export const waitForDebugger = /*@__PURE__*/ notImplemented< 42 | typeof nodeInspectorPromises.waitForDebugger 43 | >("inspectorPromises.waitForDebugger"); 44 | 45 | export const open = /*@__PURE__*/ notImplemented< 46 | typeof nodeInspectorPromises.open 47 | >("inspectorPromises.open"); 48 | 49 | export const close = /*@__PURE__*/ notImplemented< 50 | typeof nodeInspectorPromises.close 51 | >("inspectorPromises.close"); 52 | 53 | export default { 54 | close, 55 | console, 56 | Network, 57 | open, 58 | Session, 59 | url, 60 | waitForDebugger, 61 | } satisfies typeof nodeInspectorPromises; 62 | -------------------------------------------------------------------------------- /src/runtime/npm/debug.ts: -------------------------------------------------------------------------------- 1 | // https://www.npmjs.com/package/debug 2 | 3 | import type { Debug, Debugger, Formatters } from "debug"; 4 | 5 | function createDebug(namespace: string): Debugger { 6 | return Object.assign( 7 | (...args: any[]) => { 8 | const env = globalThis.process?.env.DEBUG; 9 | if (!env || (env !== "*" && !env.startsWith(namespace))) return; 10 | console.debug(...args); 11 | }, 12 | { 13 | color: "#000000", 14 | diff: 0, 15 | enabled: true, 16 | log: console.debug.bind(console), 17 | namespace, 18 | destroy: () => false, 19 | extend: (ns: string, _del?: string) => createDebug(namespace + ns), 20 | }, 21 | ); 22 | } 23 | 24 | const debug: Debug = Object.assign(createDebug, { 25 | coerce: (val: any) => val, 26 | disable: () => "", 27 | enable: (_namespaces: string) => {}, 28 | enabled: (_namespaces: string) => true, 29 | formatArgs(this: Debugger, args: any[]) { 30 | args[0] = `${this.namespace} ${args[0]}`; 31 | }, 32 | log: console.debug.bind(console), 33 | selectColor: (_namespace: string) => 0, 34 | humanize: (num: any) => `${num}ms` as any, 35 | inspectOpts: {}, 36 | names: [] as RegExp[], 37 | skips: [] as RegExp[], 38 | formatters: {} as Formatters, 39 | }); 40 | 41 | export const coerce = debug.coerce; 42 | export const disable = debug.disable; 43 | export const enable = debug.enable; 44 | export const enabled = debug.enabled; 45 | export const formatArgs = debug.formatArgs; 46 | export const log = debug.log; 47 | export const selectColor = debug.selectColor; 48 | export const humanize = debug.humanize as any; 49 | export const names = debug.names; 50 | export const skips = debug.skips; 51 | export const formatters = debug.formatters; 52 | 53 | export default debug; 54 | -------------------------------------------------------------------------------- /test/node/test-url-urltooptions.mjs: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob//v22.7.0/test/parallel/test-url-urltooptions.js 2 | 3 | import assert from "node:assert"; 4 | 5 | import url from "../../src/runtime/node/url.ts"; 6 | 7 | // Test urlToHttpOptions 8 | const urlObj = new URL("http://user:pass@foo.bar.com:21/aaa/zzz?l=24#test"); 9 | const opts = url.urlToHttpOptions(urlObj); 10 | assert.strictEqual(opts instanceof URL, false); 11 | assert.strictEqual(opts.protocol, "http:"); 12 | assert.strictEqual(opts.auth, "user:pass"); 13 | assert.strictEqual(opts.hostname, "foo.bar.com"); 14 | assert.strictEqual(opts.port, 21); 15 | assert.strictEqual(opts.path, "/aaa/zzz?l=24"); 16 | assert.strictEqual(opts.pathname, "/aaa/zzz"); 17 | assert.strictEqual(opts.search, "?l=24"); 18 | assert.strictEqual(opts.hash, "#test"); 19 | 20 | const { hostname } = url.urlToHttpOptions(new URL("http://[::1]:21")); 21 | assert.strictEqual(hostname, "::1"); 22 | 23 | // If a WHATWG URL object is copied, it is possible that the resulting copy 24 | // contains the Symbols that Node uses for brand checking, but not the data 25 | // properties, which are getters. Verify that urlToHttpOptions() can handle 26 | // such a case. 27 | const copiedUrlObj = { ...urlObj }; 28 | const copiedOpts = url.urlToHttpOptions(copiedUrlObj); 29 | assert.strictEqual(copiedOpts instanceof URL, false); 30 | assert.strictEqual(copiedOpts.protocol, undefined); 31 | assert.strictEqual(copiedOpts.auth, undefined); 32 | assert.strictEqual(copiedOpts.hostname, undefined); 33 | assert.strictEqual(copiedOpts.port, Number.NaN); 34 | assert.strictEqual(copiedOpts.path, ""); 35 | assert.strictEqual(copiedOpts.pathname, undefined); 36 | assert.strictEqual(copiedOpts.search, undefined); 37 | assert.strictEqual(copiedOpts.hash, undefined); 38 | assert.strictEqual(copiedOpts.href, undefined); 39 | -------------------------------------------------------------------------------- /src/runtime/node/internal/url/constants.ts: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob/v22.7.0/lib/internal/constants.js 2 | 3 | export const CHAR_UPPERCASE_A = 65; 4 | export const CHAR_LOWERCASE_A = 97; 5 | export const CHAR_UPPERCASE_Z = 90; 6 | export const CHAR_LOWERCASE_Z = 122; 7 | export const CHAR_UPPERCASE_C = 67; 8 | export const CHAR_LOWERCASE_B = 98; 9 | export const CHAR_LOWERCASE_E = 101; 10 | export const CHAR_LOWERCASE_N = 110; 11 | export const CHAR_DOT = 46; 12 | export const CHAR_FORWARD_SLASH = 47; 13 | export const CHAR_BACKWARD_SLASH = 92; 14 | export const CHAR_VERTICAL_LINE = 124; 15 | export const CHAR_COLON = 58; 16 | export const CHAR_QUESTION_MARK = 63; 17 | export const CHAR_UNDERSCORE = 95; 18 | export const CHAR_LINE_FEED = 10; 19 | export const CHAR_CARRIAGE_RETURN = 13; 20 | export const CHAR_TAB = 9; 21 | export const CHAR_FORM_FEED = 12; 22 | export const CHAR_EXCLAMATION_MARK = 33; 23 | export const CHAR_HASH = 35; 24 | export const CHAR_SPACE = 32; 25 | export const CHAR_NO_BREAK_SPACE = 160; 26 | export const CHAR_ZERO_WIDTH_NOBREAK_SPACE = 65_279; 27 | export const CHAR_LEFT_SQUARE_BRACKET = 91; 28 | export const CHAR_RIGHT_SQUARE_BRACKET = 93; 29 | export const CHAR_LEFT_ANGLE_BRACKET = 60; 30 | export const CHAR_RIGHT_ANGLE_BRACKET = 62; 31 | export const CHAR_LEFT_CURLY_BRACKET = 123; 32 | export const CHAR_RIGHT_CURLY_BRACKET = 125; 33 | export const CHAR_HYPHEN_MINUS = 45; 34 | export const CHAR_PLUS = 43; 35 | export const CHAR_DOUBLE_QUOTE = 34; 36 | export const CHAR_SINGLE_QUOTE = 39; 37 | export const CHAR_PERCENT = 37; 38 | export const CHAR_SEMICOLON = 59; 39 | export const CHAR_CIRCUMFLEX_ACCENT = 94; 40 | export const CHAR_GRAVE_ACCENT = 96; 41 | export const CHAR_AT = 64; 42 | export const CHAR_AMPERSAND = 38; 43 | export const CHAR_EQUAL = 61; 44 | export const CHAR_0 = 48; 45 | export const CHAR_9 = 57; 46 | -------------------------------------------------------------------------------- /src/runtime/node/internal/process/nexttick.ts: -------------------------------------------------------------------------------- 1 | // https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask 2 | // https://nodejs.org/api/process.html#when-to-use-queuemicrotask-vs-processnexttick 3 | export const nextTick: NodeJS.Process["nextTick"] = globalThis.queueMicrotask 4 | ? (cb, ...args) => { 5 | globalThis.queueMicrotask(cb.bind(undefined, ...args)); 6 | } 7 | : /*@__PURE__*/ createNextTickWithTimeout(); 8 | 9 | // Fallback for runtimes not implementing queueMicrotask 10 | function createNextTickWithTimeout() { 11 | type Callback = () => any; 12 | let queue: Callback[] = []; 13 | let draining = false; 14 | let currentQueue: Callback[] | undefined; 15 | let queueIndex = -1; 16 | 17 | function cleanUpNextTick() { 18 | if (!draining || !currentQueue) { 19 | return; 20 | } 21 | draining = false; 22 | if (currentQueue.length > 0) { 23 | queue = [...currentQueue, ...queue]; 24 | } else { 25 | queueIndex = -1; 26 | } 27 | if (queue.length > 0) { 28 | drainQueue(); 29 | } 30 | } 31 | 32 | function drainQueue() { 33 | if (draining) { 34 | return; 35 | } 36 | const timeout = setTimeout(cleanUpNextTick); 37 | draining = true; 38 | let len = queue.length; 39 | while (len) { 40 | currentQueue = queue; 41 | queue = []; 42 | while (++queueIndex < len) { 43 | if (currentQueue) { 44 | currentQueue[queueIndex](); 45 | } 46 | } 47 | queueIndex = -1; 48 | len = queue.length; 49 | } 50 | currentQueue = undefined; 51 | draining = false; 52 | clearTimeout(timeout); 53 | } 54 | 55 | const nextTick = (cb: Callback, ...args: any[]) => { 56 | queue.push(cb.bind(undefined, ...args)); 57 | if (queue.length === 1 && !draining) { 58 | setTimeout(drainQueue); 59 | } 60 | }; 61 | 62 | return nextTick; 63 | } 64 | -------------------------------------------------------------------------------- /src/runtime/_internal/utils.ts: -------------------------------------------------------------------------------- 1 | import type { HeadersObject } from "./types.ts"; 2 | 3 | /*@__NO_SIDE_EFFECTS__*/ 4 | export function rawHeaders(headers: HeadersObject) { 5 | const rawHeaders = []; 6 | for (const key in headers) { 7 | if (Array.isArray(headers[key])) { 8 | for (const h of headers[key] as any) { 9 | rawHeaders.push(key, h); 10 | } 11 | } else { 12 | rawHeaders.push(key, headers[key]); 13 | } 14 | } 15 | return rawHeaders; 16 | } 17 | 18 | type Fn = (...args: any[]) => any; 19 | 20 | /*@__NO_SIDE_EFFECTS__*/ 21 | export function mergeFns(...functions: Fn[]) { 22 | return function (...args: any[]) { 23 | for (const fn of functions) { 24 | fn(...args); 25 | } 26 | }; 27 | } 28 | 29 | /*@__NO_SIDE_EFFECTS__*/ 30 | export function createNotImplementedError(name: string) { 31 | return new Error(`[unenv] ${name} is not implemented yet!`); 32 | } 33 | 34 | /*@__NO_SIDE_EFFECTS__*/ 35 | export function notImplemented any>( 36 | name: string, 37 | ): Fn { 38 | const fn = (): ReturnType => { 39 | throw createNotImplementedError(name); 40 | }; 41 | return Object.assign(fn, { __unenv__: true }) as unknown as Fn; 42 | } 43 | 44 | export interface Promisifiable { 45 | (): any; 46 | native: Promisifiable; 47 | __promisify__: () => Promise; 48 | } 49 | 50 | /*@__NO_SIDE_EFFECTS__*/ 51 | export function notImplementedAsync(name: string): Promisifiable { 52 | const fn = notImplemented(name) as any; 53 | fn.__promisify__ = () => notImplemented(name + ".__promisify__"); 54 | fn.native = fn; 55 | return fn; 56 | } 57 | 58 | /*@__NO_SIDE_EFFECTS__*/ 59 | export function notImplementedClass(name: string): T { 60 | return class { 61 | readonly __unenv__ = true; 62 | constructor() { 63 | throw new Error(`[unenv] ${name} is not implemented yet!`); 64 | } 65 | } as T; 66 | } 67 | -------------------------------------------------------------------------------- /src/runtime/node/timers.ts: -------------------------------------------------------------------------------- 1 | import { notImplemented } from "../_internal/utils.ts"; 2 | import noop from "../mock/noop.ts"; 3 | import type nodeTimers from "node:timers"; 4 | import promises from "node:timers/promises"; 5 | import { setTimeoutFallback } from "./internal/timers/set-timeout.ts"; 6 | import { 7 | setImmediateFallback, 8 | clearImmediateFallback, 9 | } from "./internal/timers/set-immediate.ts"; 10 | import { setIntervalFallback } from "./internal/timers/set-interval.ts"; 11 | 12 | export { promises }; 13 | 14 | export const clearImmediate: typeof nodeTimers.clearImmediate = 15 | globalThis.clearImmediate?.bind(globalThis) || clearImmediateFallback; 16 | export const clearInterval: typeof nodeTimers.clearInterval = 17 | globalThis.clearInterval?.bind(globalThis) || noop; 18 | export const clearTimeout: typeof nodeTimers.clearTimeout = 19 | globalThis.clearTimeout?.bind(globalThis) || noop; 20 | 21 | export const setImmediate: typeof nodeTimers.setImmediate = 22 | globalThis.setImmediate?.bind(globalThis) || setImmediateFallback; 23 | export const setTimeout: typeof nodeTimers.setTimeout = 24 | globalThis.setTimeout?.bind(globalThis) || setTimeoutFallback; 25 | export const setInterval: typeof nodeTimers.setInterval = 26 | globalThis.setInterval?.bind(globalThis) || setIntervalFallback; 27 | 28 | export const active = function active(timeout: NodeJS.Timeout | undefined) { 29 | timeout?.refresh?.(); 30 | }; 31 | export const _unrefActive = active; 32 | export const enroll = /*@__PURE__*/ notImplemented("timers.enroll"); 33 | export const unenroll = /*@__PURE__*/ notImplemented("timers.unenroll"); 34 | 35 | export default { 36 | // @ts-expect-error deprecated 37 | _unrefActive, 38 | active, 39 | clearImmediate, 40 | clearInterval, 41 | clearTimeout, 42 | enroll, 43 | promises, 44 | setImmediate, 45 | setInterval, 46 | setTimeout, 47 | unenroll, 48 | } satisfies typeof nodeTimers; 49 | -------------------------------------------------------------------------------- /test/mock.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import noop from "../src/runtime/mock/noop"; 3 | import empty from "../src/runtime/mock/empty"; 4 | import proxy from "../src/runtime/mock/proxy"; 5 | 6 | describe("mock utils", () => { 7 | describe("noop", () => { 8 | it("noop", () => { 9 | expect(noop()).toBeUndefined(); 10 | }); 11 | }); 12 | 13 | describe("empty", () => { 14 | it("empty", () => { 15 | expect(Object.keys(empty)).toHaveLength(0); 16 | expect(empty.__unenv__).toBe(true); 17 | expect(Object.isFrozen(empty)).toBe(true); 18 | expect(Object.getPrototypeOf(empty)).toBe(null); 19 | }); 20 | }); 21 | 22 | describe("proxy", () => { 23 | it("nesting", () => { 24 | const p = new proxy.foo.bar(); 25 | expect(p.__unenv__).toBe(true); 26 | }); 27 | 28 | it("calling", () => { 29 | const p = proxy(); 30 | expect(p.caller).toBe(null); 31 | expect(proxy().__unenv__).toBe(true); 32 | }); 33 | 34 | it("overrides", () => { 35 | const p = proxy.__createMock__("foo", { a: 1 }); 36 | expect(p.a).toBe(1); 37 | }); 38 | 39 | describe("promises", () => { 40 | it(".then", async () => { 41 | const p = proxy(); 42 | const resolved = await p.then(() => true); 43 | expect(resolved).toBe(true); 44 | }); 45 | 46 | it(".catch", async () => { 47 | const p = proxy(); 48 | let caught = false; 49 | const res = await p 50 | .catch(() => { 51 | caught = true; 52 | }) 53 | .then(() => true); 54 | expect(res).toBe(true); 55 | expect(caught).toBe(false); 56 | }); 57 | 58 | it(".finally", async () => { 59 | const p = proxy(); 60 | let finallyCalled = false; 61 | await p.finally(() => { 62 | finallyCalled = true; 63 | }); 64 | expect(finallyCalled).toBe(true); 65 | }); 66 | }); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /src/runtime/node/internal/util/log.ts: -------------------------------------------------------------------------------- 1 | import type nodeUtil from "node:util"; 2 | 3 | export const log = (...args: any[]) => { 4 | console.log(...args); 5 | }; 6 | 7 | export const debuglog: typeof nodeUtil.debuglog = (section, _cb) => { 8 | const fn = (msg: string, ...params: any[]) => { 9 | if (fn.enabled) { 10 | console.debug(`[${section}] ${msg}`, ...params); 11 | } 12 | }; 13 | fn.enabled = true; 14 | return fn; 15 | }; 16 | 17 | export const debug: typeof nodeUtil.debug = debuglog; 18 | 19 | // @ts-ignore 20 | export const inspect: typeof nodeUtil.inspect = (object) => 21 | JSON.stringify(object, null, 2); 22 | 23 | export const format: typeof nodeUtil.format = (...args) => _format(...args); 24 | 25 | export const formatWithOptions: typeof nodeUtil.formatWithOptions = ( 26 | _options, 27 | ...args 28 | ) => _format(...args); 29 | 30 | // Source: https://github.com/tmpfs/format-util/blob/0c989942c959b179eec294a4e725afd63e743f18/format.js 31 | function _format(fmt: string, ...args: any[]) { 32 | const re = /(%?)(%([djos]))/g; 33 | if (args.length > 0) { 34 | fmt = fmt.replace(re, (match, escaped, ptn, flag) => { 35 | let arg = args.shift(); 36 | switch (flag) { 37 | case "o": 38 | if (Array.isArray(arg)) { 39 | arg = JSON.stringify(arg); 40 | break; 41 | } 42 | break; 43 | case "s": 44 | arg = "" + arg; 45 | break; 46 | case "d": 47 | arg = Number(arg); 48 | break; 49 | case "j": 50 | arg = JSON.stringify(arg); 51 | break; 52 | } 53 | if (!escaped) { 54 | return arg; 55 | } 56 | args.unshift(arg); 57 | return match; 58 | }); 59 | } 60 | 61 | // arguments remain after formatting 62 | if (args.length > 0) { 63 | fmt += " " + args.join(" "); 64 | } 65 | 66 | // update escaped %% values 67 | fmt = fmt.replace(/%{2}/g, "%"); 68 | 69 | return "" + fmt; 70 | } 71 | -------------------------------------------------------------------------------- /src/runtime/node/diagnostics_channel.ts: -------------------------------------------------------------------------------- 1 | import type nodeDiagnosticsChannel from "node:diagnostics_channel"; 2 | import { 3 | Channel, 4 | getChannels, 5 | } from "./internal/diagnostics_channel/channel.ts"; 6 | import { TracingChannel } from "./internal/diagnostics_channel/tracing-channel.ts"; 7 | 8 | export { Channel } from "./internal/diagnostics_channel/channel.ts"; 9 | 10 | export const channel: typeof nodeDiagnosticsChannel.channel = function (name) { 11 | const channels = getChannels(); 12 | if (name in channels) { 13 | return channels[name]; 14 | } 15 | return new Channel(name); 16 | }; 17 | 18 | export const hasSubscribers: typeof nodeDiagnosticsChannel.hasSubscribers = 19 | function (name) { 20 | const channels = getChannels(); 21 | const channel = channels[name]; 22 | return channel && channel.hasSubscribers; 23 | }; 24 | 25 | export const subscribe: typeof nodeDiagnosticsChannel.subscribe = function ( 26 | name, 27 | onMessage, 28 | ) { 29 | channel(name).subscribe(onMessage); 30 | }; 31 | 32 | export const unsubscribe: typeof nodeDiagnosticsChannel.unsubscribe = function ( 33 | name, 34 | onMessage, 35 | ) { 36 | return (channel(name) as Channel).unsubscribe(onMessage); 37 | }; 38 | 39 | export const tracingChannel: typeof nodeDiagnosticsChannel.tracingChannel = 40 | function ( 41 | name: 42 | | string 43 | | nodeDiagnosticsChannel.TracingChannelCollection, 44 | ) { 45 | return new TracingChannel(name); 46 | }; 47 | 48 | // TracingChannel is incorrectly exposed on the `diagnostics_channel` type. In addition, its type 49 | // takes a constructor with no arguments, whereas the node implementation takes a name (matching `tracingChannel`) 50 | export default { 51 | Channel, 52 | channel, 53 | hasSubscribers, 54 | subscribe, 55 | tracingChannel, 56 | unsubscribe, 57 | } satisfies Omit; 58 | -------------------------------------------------------------------------------- /src/runtime/node/vm.ts: -------------------------------------------------------------------------------- 1 | import type nodeVm from "node:vm"; 2 | import { notImplemented } from "../_internal/utils.ts"; 3 | import { Script } from "./internal/vm/script.ts"; 4 | import * as constants from "./internal/vm/constants.ts"; 5 | 6 | export { Script } from "./internal/vm/script.ts"; 7 | 8 | export * as constants from "./internal/vm/constants.ts"; 9 | 10 | export const compileFunction: typeof nodeVm.compileFunction = 11 | /*@__PURE__*/ notImplemented("vm.compileFunction"); 12 | 13 | const _contextSymbol = /*@__PURE__*/ Symbol("uenv.vm.context"); 14 | 15 | export const createContext: typeof nodeVm.createContext = 16 | function createContext() { 17 | return Object.create(null, { 18 | [_contextSymbol]: { 19 | value: true, 20 | }, 21 | }); 22 | }; 23 | 24 | export const createScript = function createScript() { 25 | return new Script(); 26 | }; 27 | 28 | export const isContext: typeof nodeVm.isContext = (context) => { 29 | return context && context[_contextSymbol as any] === true; 30 | }; 31 | 32 | export const measureMemory: typeof nodeVm.measureMemory = () => 33 | Promise.resolve({ 34 | total: { jsMemoryEstimate: 0, jsMemoryRange: [1, 2] }, 35 | WebAssembly: { code: 0, metadata: 0 }, 36 | }); 37 | 38 | export const runInContext: typeof nodeVm.runInContext = 39 | /*@__PURE__*/ notImplemented("vm.runInContext"); 40 | 41 | export const runInNewContext: typeof nodeVm.runInNewContext = 42 | /*@__PURE__*/ notImplemented("vm.runInNewContext"); 43 | 44 | export const runInThisContext: typeof nodeVm.runInThisContext = 45 | /*@__PURE__*/ notImplemented("vm.runInThisContext"); 46 | 47 | export default { 48 | Script, 49 | compileFunction, 50 | constants: constants as unknown as typeof nodeVm.constants, 51 | createContext, 52 | isContext, 53 | measureMemory, 54 | runInContext, 55 | runInNewContext, 56 | runInThisContext, 57 | // @ts-expect-error 58 | createScript, 59 | } satisfies Omit< 60 | typeof nodeVm, 61 | "Module" | "SourceTextModule" | "SyntheticModule" 62 | >; 63 | -------------------------------------------------------------------------------- /src/runtime/node/internal/url/errors.ts: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob/v22.7.0/lib/internal/errors.js 2 | 3 | function fmt(val: unknown): string { 4 | if (Array.isArray(val)) { 5 | return val.map((v) => fmt(v)).join(" or "); 6 | } 7 | if (!val) { 8 | return "" + val; 9 | } 10 | return val.toString(); 11 | } 12 | 13 | export class ERR_INVALID_ARG_VALUE extends TypeError { 14 | code = "ERR_INVALID_ARG_VALUE"; 15 | constructor(name: string, value: unknown, reason: string) { 16 | super( 17 | `The ${name.includes(".") ? "property" : "argument"} '${name}' ${reason}. Received ${value}`, 18 | ); 19 | } 20 | } 21 | 22 | export class ERR_INVALID_ARG_TYPE extends TypeError { 23 | code = "ERR_INVALID_ARG_TYPE"; 24 | constructor(name: string, expected: unknown, actual: unknown) { 25 | super( 26 | `The "${name}" argument must be of type ${fmt(expected)}. Received ${fmt(actual)}`, 27 | ); 28 | } 29 | } 30 | 31 | export class ERR_INVALID_URL extends TypeError { 32 | code = "ERR_INVALID_URL"; 33 | input: string; 34 | base?: string; 35 | constructor(input: string, base?: string) { 36 | // Don't include URL in message. 37 | // (See https://github.com/nodejs/node/pull/38614) 38 | super("Invalid URL"); 39 | 40 | this.input = input; 41 | 42 | if (base != null) { 43 | this.base = base; 44 | } 45 | } 46 | } 47 | 48 | export class ERR_INVALID_URL_SCHEME extends TypeError { 49 | code = "ERR_INVALID_URL_SCHEME"; 50 | constructor(expected: string) { 51 | super(`The URL must be of scheme ${expected}`); 52 | } 53 | } 54 | 55 | export class ERR_INVALID_FILE_URL_PATH extends TypeError { 56 | code = "ERR_INVALID_FILE_URL_PATH"; 57 | constructor(path: string) { 58 | super(`Invalid ile URL path: ${path}`); 59 | } 60 | } 61 | 62 | export class ERR_INVALID_FILE_URL_HOST extends TypeError { 63 | code = "ERR_INVALID_FILE_URL_HOST"; 64 | constructor(host: string) { 65 | super(`File URL host must be "localhost" or empty on ${host}`); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/runtime/node/internal/http/request.ts: -------------------------------------------------------------------------------- 1 | import type NodeHttp from "node:http"; 2 | import { Socket } from "node:net"; 3 | import { Readable } from "node:stream"; 4 | import { rawHeaders } from "../../../_internal/utils.ts"; 5 | 6 | // Docs: https://nodejs.org/api/http.html#http_class_http_incomingmessage 7 | // Implementation: https://github.com/nodejs/node/blob/master/lib/_http_incoming.js 8 | 9 | export class IncomingMessage 10 | extends Readable 11 | implements NodeHttp.IncomingMessage 12 | { 13 | public __unenv__ = {}; 14 | 15 | public aborted: boolean = false; 16 | public httpVersion: string = "1.1"; 17 | public httpVersionMajor: number = 1; 18 | public httpVersionMinor: number = 1; 19 | public complete: boolean = true; 20 | public connection: Socket; 21 | public socket: Socket; 22 | public headers: NodeHttp.IncomingHttpHeaders = {}; 23 | public trailers = {}; 24 | public method: string = "GET"; 25 | public url: string = "/"; 26 | public statusCode: number = 200; 27 | public statusMessage: string = ""; 28 | public closed: boolean = false; 29 | public errored: Error | null = null; 30 | 31 | readable: boolean = false; 32 | 33 | constructor(socket?: Socket) { 34 | super(); 35 | this.socket = this.connection = socket || new Socket(); 36 | } 37 | 38 | get rawHeaders() { 39 | return rawHeaders(this.headers); 40 | } 41 | 42 | get rawTrailers() { 43 | return []; 44 | } 45 | 46 | setTimeout(_msecs: number, _callback?: () => void) { 47 | return this; 48 | } 49 | 50 | get headersDistinct() { 51 | return _distinct(this.headers); 52 | } 53 | 54 | get trailersDistinct() { 55 | return _distinct(this.trailers); 56 | } 57 | 58 | _read() {} 59 | } 60 | 61 | function _distinct(obj: Record) { 62 | const d: Record = {}; 63 | for (const [key, value] of Object.entries(obj)) { 64 | if (key) { 65 | d[key as string] = (Array.isArray(value) ? value : [value]).filter( 66 | Boolean, 67 | ); 68 | } 69 | } 70 | return d; 71 | } 72 | -------------------------------------------------------------------------------- /src/runtime/node/internal/async_hooks/async-resource.ts: -------------------------------------------------------------------------------- 1 | import type nodeAsyncHooks from "node:async_hooks"; 2 | import { executionAsyncId } from "./async-hook.ts"; 3 | 4 | // https://nodejs.org/api/async_context.html#class-asyncresource 5 | 6 | let _asyncIdCounter = 100; 7 | 8 | class _AsyncResource implements nodeAsyncHooks.AsyncResource { 9 | readonly __unenv__ = true; 10 | 11 | type: string; 12 | _asyncId: undefined | number; 13 | _triggerAsyncId: undefined | number | nodeAsyncHooks.AsyncResourceOptions; 14 | 15 | constructor( 16 | type: string, 17 | triggerAsyncId: 18 | | number 19 | | nodeAsyncHooks.AsyncResourceOptions = executionAsyncId(), 20 | ) { 21 | this.type = type; 22 | this._asyncId = -1 * _asyncIdCounter++; 23 | this._triggerAsyncId = 24 | typeof triggerAsyncId === "number" 25 | ? triggerAsyncId 26 | : triggerAsyncId?.triggerAsyncId; 27 | } 28 | 29 | static bind any, ThisArg>( 30 | fn: Func, 31 | type?: string, 32 | thisArg?: ThisArg, 33 | ) { 34 | const resource = new AsyncResource(type ?? "anonymous"); 35 | return resource.bind(fn); 36 | } 37 | 38 | bind any>(fn: Func, thisArg?: any) { 39 | const binded = (...args: any[]) => 40 | this.runInAsyncScope(fn, thisArg, ...args); 41 | binded.asyncResource = this; 42 | return binded as any; 43 | } 44 | 45 | runInAsyncScope( 46 | fn: (this: This, ...args: any[]) => Result, 47 | thisArg?: This, 48 | ...args: any[] 49 | ): Result { 50 | const result = fn.apply(thisArg as This, args); 51 | return result; 52 | } 53 | 54 | emitDestroy(): this { 55 | return this; 56 | } 57 | 58 | asyncId(): number { 59 | return this._asyncId as number; 60 | } 61 | 62 | triggerAsyncId(): number { 63 | return this._triggerAsyncId as number; 64 | } 65 | } 66 | 67 | export const AsyncResource: typeof nodeAsyncHooks.AsyncResource = 68 | (globalThis as any).AsyncResource || _AsyncResource; 69 | -------------------------------------------------------------------------------- /src/runtime/node/internal/tty/write-stream.ts: -------------------------------------------------------------------------------- 1 | import type nodeTty from "node:tty"; 2 | 3 | export class WriteStream implements Partial { 4 | fd: number; 5 | columns = 80; 6 | rows = 24; 7 | isTTY = false; 8 | 9 | constructor(fd: number) { 10 | this.fd = fd; 11 | } 12 | 13 | clearLine(dir: nodeTty.Direction, callback?: (() => void) | undefined) { 14 | callback && callback(); 15 | return false; 16 | } 17 | 18 | clearScreenDown(callback?: (() => void) | undefined) { 19 | callback && callback(); 20 | return false; 21 | } 22 | 23 | cursorTo( 24 | x: number, 25 | y?: number | undefined, 26 | callback?: (() => void) | undefined, 27 | ): boolean; 28 | cursorTo(x: number, callback: () => void): boolean; 29 | cursorTo(x: unknown, y?: unknown, callback?: unknown): boolean { 30 | callback && typeof callback === "function" && callback(); 31 | return false; 32 | } 33 | 34 | moveCursor(dx: number, dy: number, callback?: (() => void) | undefined) { 35 | callback && callback(); 36 | return false; 37 | } 38 | 39 | getColorDepth(env?: object | undefined): number { 40 | return 1; 41 | } 42 | 43 | hasColors(count?: number | undefined): boolean; 44 | hasColors(env?: object | undefined): boolean; 45 | hasColors(count: number, env?: object | undefined): boolean; 46 | hasColors(count?: unknown, env?: unknown): boolean { 47 | return false; 48 | } 49 | 50 | getWindowSize(): [number, number] { 51 | return [this.columns, this.rows]; 52 | } 53 | 54 | write(buffer: Uint8Array | string, cb?: (err?: Error) => void): boolean; 55 | write( 56 | str: Uint8Array | string, 57 | encoding?: BufferEncoding, 58 | cb?: (err?: Error) => void, 59 | ): boolean; 60 | write(str: unknown, encoding?: unknown, cb?: unknown): boolean { 61 | if (str instanceof Uint8Array) { 62 | str = new TextDecoder().decode(str); 63 | } 64 | try { 65 | console.log(str); 66 | } catch {} 67 | cb && typeof cb === "function" && cb(); 68 | return false; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/runtime/web/performance/index.ts: -------------------------------------------------------------------------------- 1 | // https://developer.mozilla.org/en-US/docs/Web/API/Performance_API 2 | 3 | import { 4 | type _PerformanceEntryType, 5 | _PerformanceEntry, 6 | _PerformanceMark, 7 | _PerformanceMeasure, 8 | _PerformanceResourceTiming, 9 | _Performance, 10 | _PerformanceObserver, 11 | _PerformanceObserverEntryList, 12 | } from "./_polyfills.ts"; 13 | 14 | export { 15 | type _PerformanceEntryType, 16 | _PerformanceEntry, 17 | _PerformanceMark, 18 | _PerformanceMeasure, 19 | _PerformanceResourceTiming, 20 | _Performance, 21 | _PerformanceObserver, 22 | _PerformanceObserverEntryList, 23 | } from "./_polyfills.ts"; 24 | 25 | export const PerformanceEntry: typeof globalThis.PerformanceEntry = 26 | globalThis.PerformanceEntry || _PerformanceEntry; 27 | 28 | export const PerformanceMark: typeof globalThis.PerformanceMark = 29 | globalThis.PerformanceMark || _PerformanceMark; 30 | 31 | export const PerformanceMeasure: typeof globalThis.PerformanceMeasure = 32 | globalThis.PerformanceMeasure || _PerformanceMeasure; 33 | 34 | export const PerformanceResourceTiming: typeof globalThis.PerformanceResourceTiming = 35 | globalThis.PerformanceResourceTiming || _PerformanceResourceTiming; 36 | 37 | export const PerformanceObserver: typeof globalThis.PerformanceObserver = 38 | globalThis.PerformanceObserver || _PerformanceObserver; 39 | 40 | export const Performance: typeof globalThis.Performance = 41 | globalThis.Performance || _Performance; 42 | 43 | export const PerformanceObserverEntryList: typeof globalThis.PerformanceObserverEntryList = 44 | globalThis.PerformanceObserverEntryList || _PerformanceObserverEntryList; 45 | 46 | // workerd implements a subset of globalThis.performance (as of last check, only timeOrigin set to 0 + now() implemented) 47 | // We already use performance.now() from globalThis.performance, if provided (see top of this file) 48 | // If we detect this condition, we can just use polyfill instead. 49 | export const performance = 50 | globalThis.performance && "addEventListener" in globalThis.performance 51 | ? globalThis.performance 52 | : new _Performance(); 53 | -------------------------------------------------------------------------------- /src/runtime/node/internal/tls/tls-socket.ts: -------------------------------------------------------------------------------- 1 | import type nodeTls from "node:tls"; 2 | import { Socket } from "node:net"; 3 | import { createNotImplementedError } from "../../../_internal/utils.ts"; 4 | 5 | export class TLSSocket extends Socket implements nodeTls.TLSSocket { 6 | authorized = false; 7 | encrypted = true as const; 8 | alpnProtocol = null; 9 | authorizationError: Error = new Error( 10 | "[unenv] TLSSocket.authorizationError is not implemented yet!", 11 | ); 12 | exportKeyingMaterial(): Buffer { 13 | throw createNotImplementedError("TLSSocket.exportKeyingMaterial"); 14 | } 15 | getCipher(): nodeTls.CipherNameAndProtocol { 16 | throw createNotImplementedError("TLSSocket.getCipher"); 17 | } 18 | getPeerCertificate(detailed: true): nodeTls.DetailedPeerCertificate; 19 | getPeerCertificate(detailed?: false): nodeTls.PeerCertificate; 20 | getPeerCertificate( 21 | detailed?: boolean, 22 | ): nodeTls.PeerCertificate | nodeTls.DetailedPeerCertificate; 23 | getPeerCertificate( 24 | _detailed?: boolean, 25 | ): nodeTls.PeerCertificate | nodeTls.DetailedPeerCertificate { 26 | throw createNotImplementedError("TLSSocket.getPeerCertificate"); 27 | } 28 | getCertificate() { 29 | return null; 30 | } 31 | getEphemeralKeyInfo() { 32 | return null; 33 | } 34 | getFinished(): undefined {} 35 | getPeerFinished(): undefined {} 36 | getProtocol() { 37 | return null; 38 | } 39 | getSession(): undefined {} 40 | getSharedSigalgs() { 41 | return []; 42 | } 43 | getTLSTicket(): undefined {} 44 | isSessionReused() { 45 | return false; 46 | } 47 | renegotiate( 48 | options: { 49 | rejectUnauthorized?: boolean | undefined; 50 | requestCert?: boolean | undefined; 51 | }, 52 | callback: (err: Error | null) => void, 53 | ): undefined { 54 | if (typeof callback === "function") { 55 | callback(null); 56 | } 57 | } 58 | setMaxSendFragment(size: number) { 59 | return false; 60 | } 61 | disableRenegotiation() {} 62 | enableTrace() {} 63 | getPeerX509Certificate(): undefined {} 64 | getX509Certificate(): undefined {} 65 | } 66 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export interface CreateEnvOptions { 2 | /** 3 | * Node.js compatibility. 4 | * 5 | * - Add `alias` entries for Node.js builtins as `` and `node:`. 6 | * - Add `inject` entries for Node.js globals `global`, `Buffer`, and `process`. 7 | * 8 | * Default: `true` 9 | */ 10 | nodeCompat?: boolean; 11 | 12 | /** 13 | * Add `alias` entries to replace npm packages like `node-fetch` with lighter shims. 14 | * 15 | * Default: `false` 16 | */ 17 | npmShims?: boolean; 18 | 19 | /** 20 | * Additional presets. 21 | */ 22 | presets?: Preset[]; 23 | 24 | /** 25 | * Additional overrides. 26 | */ 27 | overrides?: Partial; 28 | 29 | /** 30 | * Resolve paths in the environment to absolute paths. 31 | * 32 | * Default: `false` 33 | */ 34 | resolve?: boolean | EnvResolveOptions; 35 | } 36 | 37 | export interface EnvResolveOptions { 38 | /** 39 | * Paths to resolve imports from. 40 | * 41 | * Always unenv path is appended. 42 | */ 43 | paths?: (string | URL)[]; 44 | } 45 | 46 | /** 47 | * Environment defined by presets. 48 | */ 49 | export interface Environment { 50 | alias: Record; 51 | // A `false` value is used to drop an inject entry from a parent Environment. 52 | inject: Record; 53 | polyfill: string[]; 54 | external: string[]; 55 | } 56 | 57 | /** 58 | * Environment returned by `defineEnv`. 59 | * 60 | * It differs from the preset's Environment as the `inject` map never contains a `false` value. 61 | */ 62 | export interface ResolvedEnvironment extends Environment { 63 | inject: Record; 64 | polyfill: string[]; 65 | external: string[]; 66 | } 67 | 68 | export interface Preset extends Partial { 69 | meta?: { 70 | /** 71 | * Preset name. 72 | */ 73 | readonly name?: string; 74 | /** 75 | * Preset version. 76 | */ 77 | readonly version?: string; 78 | /** 79 | * Path or URL to preset entry (used for resolving absolute paths). 80 | */ 81 | readonly url?: string | URL; 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /src/runtime/node/inspector.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/inspector.html 2 | import { notImplementedClass, notImplemented } from "../_internal/utils.ts"; 3 | import noop from "../mock/noop.ts"; 4 | import type nodeInspector from "node:inspector"; 5 | 6 | export const close: typeof nodeInspector.close = noop; 7 | 8 | export const console: nodeInspector.InspectorConsole = { 9 | debug: noop, 10 | error: noop, 11 | info: noop, 12 | log: noop, 13 | warn: noop, 14 | dir: noop, 15 | dirxml: noop, 16 | table: noop, 17 | trace: noop, 18 | group: noop, 19 | groupCollapsed: noop, 20 | groupEnd: noop, 21 | clear: noop, 22 | count: noop, 23 | countReset: noop, 24 | assert: noop, 25 | profile: noop, 26 | profileEnd: noop, 27 | time: noop, 28 | timeLog: noop, 29 | timeStamp: noop, 30 | }; 31 | 32 | export const open: typeof nodeInspector.open = () => ({ 33 | __unenv__: true, 34 | [Symbol.dispose]() { 35 | return Promise.resolve(); 36 | }, 37 | }); 38 | 39 | export const url: typeof nodeInspector.url = () => undefined; 40 | 41 | export const waitForDebugger: typeof nodeInspector.waitForDebugger = noop; 42 | 43 | // `node:inspector` and `node:inspector/promises` share the same implementation with only Session being in the promises module: 44 | // https://github.com/nodejs/node/blob/main/lib/inspector/promises.js 45 | export const Session: typeof nodeInspector.Session = 46 | /*@__PURE__*/ notImplementedClass("inspector.Session"); 47 | 48 | export const Network: typeof nodeInspector.Network = /*@__PURE__*/ { 49 | loadingFailed: /*@__PURE__*/ notImplemented( 50 | "inspector.Network.loadingFailed", 51 | ), 52 | loadingFinished: /*@__PURE__*/ notImplemented( 53 | "inspector.Network.loadingFinished", 54 | ), 55 | requestWillBeSent: /*@__PURE__*/ notImplemented( 56 | "inspector.Network.requestWillBeSent", 57 | ), 58 | responseReceived: /*@__PURE__*/ notImplemented( 59 | "inspector.Network.responseReceived", 60 | ), 61 | }; 62 | 63 | export default { 64 | Session, 65 | close, 66 | console, 67 | open, 68 | url, 69 | waitForDebugger, 70 | Network, 71 | } satisfies typeof nodeInspector; 72 | -------------------------------------------------------------------------------- /src/runtime/node/tls.ts: -------------------------------------------------------------------------------- 1 | import type nodeTls from "node:tls"; 2 | import { notImplemented } from "../_internal/utils.ts"; 3 | import { TLSSocket } from "./internal/tls/tls-socket.ts"; 4 | import { Server } from "./internal/tls/server.ts"; 5 | import { SecureContext } from "./internal/tls/secure-context.ts"; 6 | 7 | // prettier-ignore 8 | import { CLIENT_RENEG_LIMIT, CLIENT_RENEG_WINDOW, DEFAULT_CIPHERS, DEFAULT_ECDH_CURVE, DEFAULT_MAX_VERSION, DEFAULT_MIN_VERSION } from "./internal/tls/constants.ts" 9 | 10 | export * from "./internal/tls/constants.ts"; 11 | 12 | export { TLSSocket } from "./internal/tls/tls-socket.ts"; 13 | export { Server } from "./internal/tls/server.ts"; 14 | export { SecureContext } from "./internal/tls/secure-context.ts"; 15 | 16 | export const connect: typeof nodeTls.connect = function connect() { 17 | return new TLSSocket(); 18 | }; 19 | 20 | export const createServer: typeof nodeTls.createServer = 21 | function createServer() { 22 | return new Server(); 23 | }; 24 | export const checkServerIdentity: typeof nodeTls.checkServerIdentity = 25 | /*@__PURE__*/ notImplemented("tls.checkServerIdentity"); 26 | export const convertALPNProtocols = /*@__PURE__*/ notImplemented( 27 | "tls.convertALPNProtocols", 28 | ); 29 | export const createSecureContext: typeof nodeTls.createSecureContext = 30 | /*@__PURE__*/ notImplemented("tls.createSecureContext"); 31 | export const createSecurePair: typeof nodeTls.createSecurePair = 32 | /*@__PURE__*/ notImplemented("tls.createSecurePair"); 33 | export const getCiphers: typeof nodeTls.getCiphers = 34 | /*@__PURE__*/ notImplemented("tls.getCiphers"); 35 | 36 | export const rootCertificates: typeof nodeTls.rootCertificates = []; 37 | 38 | export default { 39 | CLIENT_RENEG_LIMIT, 40 | CLIENT_RENEG_WINDOW, 41 | DEFAULT_CIPHERS, 42 | DEFAULT_ECDH_CURVE, 43 | DEFAULT_MAX_VERSION, 44 | DEFAULT_MIN_VERSION, 45 | SecureContext, 46 | Server, 47 | TLSSocket, 48 | checkServerIdentity, 49 | connect, 50 | convertALPNProtocols, 51 | createSecureContext, 52 | createSecurePair, 53 | createServer, 54 | getCiphers, 55 | rootCertificates, 56 | } as /* TODO: use satisfies */ typeof nodeTls; 57 | -------------------------------------------------------------------------------- /test/node/test-querystring-maxKeys-non-finite.mjs: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob//v22.7.0/test/parallel/test-querystring-maxKeys-non-finite.js 2 | 3 | // This test was originally written to test a regression 4 | // that was introduced by 5 | // https://github.com/nodejs/node/pull/2288#issuecomment-179543894 6 | 7 | import assert from "node:assert"; 8 | 9 | import qs from "../../src/runtime/node/querystring.ts"; 10 | 11 | // Taken from express-js/body-parser 12 | // https://github.com/expressjs/body-parser/blob/ed25264fb494cf0c8bc992b8257092cd4f694d5e/test/urlencoded.js#L636-L651 13 | function createManyParams(count) { 14 | let str = ""; 15 | 16 | if (count === 0) { 17 | return str; 18 | } 19 | 20 | str += "0=0"; 21 | 22 | for (let i = 1; i < count; i++) { 23 | const n = i.toString(36); 24 | str += `&${n}=${n}`; 25 | } 26 | 27 | return str; 28 | } 29 | 30 | const count = 10_000; 31 | const originalMaxLength = 1000; 32 | const params = createManyParams(count); 33 | 34 | // thealphanerd 35 | // 27def4f introduced a change to parse that would cause Infinity 36 | // to be passed to String.prototype.split as an argument for limit 37 | // In this instance split will always return an empty array 38 | // this test confirms that the output of parse is the expected length 39 | // when passed Infinity as the argument for maxKeys 40 | const resultInfinity = qs.parse(params, undefined, undefined, { 41 | maxKeys: Infinity, 42 | }); 43 | const resultNaN = qs.parse(params, undefined, undefined, { 44 | maxKeys: Number.NaN, 45 | }); 46 | const resultInfinityString = qs.parse(params, undefined, undefined, { 47 | maxKeys: "Infinity", 48 | }); 49 | const resultNaNString = qs.parse(params, undefined, undefined, { 50 | maxKeys: "NaN", 51 | }); 52 | 53 | // Non Finite maxKeys should return the length of input 54 | assert.strictEqual(Object.keys(resultInfinity).length, count); 55 | assert.strictEqual(Object.keys(resultNaN).length, count); 56 | // Strings maxKeys should return the maxLength 57 | // defined by parses internals 58 | assert.strictEqual(Object.keys(resultInfinityString).length, originalMaxLength); 59 | assert.strictEqual(Object.keys(resultNaNString).length, originalMaxLength); 60 | -------------------------------------------------------------------------------- /src/runtime/node/internal/fs/constants.ts: -------------------------------------------------------------------------------- 1 | // npx -y node@22.14 -e 'const{constants}=require("fs");console.log(Object.entries(constants).map(([k,v]) => `export const ${k} = ${JSON.stringify(v)}`).join("\n"))' 2 | 3 | export const UV_FS_SYMLINK_DIR = 1; 4 | export const UV_FS_SYMLINK_JUNCTION = 2; 5 | export const O_RDONLY = 0; 6 | export const O_WRONLY = 1; 7 | export const O_RDWR = 2; 8 | export const UV_DIRENT_UNKNOWN = 0; 9 | export const UV_DIRENT_FILE = 1; 10 | export const UV_DIRENT_DIR = 2; 11 | export const UV_DIRENT_LINK = 3; 12 | export const UV_DIRENT_FIFO = 4; 13 | export const UV_DIRENT_SOCKET = 5; 14 | export const UV_DIRENT_CHAR = 6; 15 | export const UV_DIRENT_BLOCK = 7; 16 | export const EXTENSIONLESS_FORMAT_JAVASCRIPT = 0; 17 | export const EXTENSIONLESS_FORMAT_WASM = 1; 18 | export const S_IFMT = 61_440; 19 | export const S_IFREG = 32_768; 20 | export const S_IFDIR = 16_384; 21 | export const S_IFCHR = 8192; 22 | export const S_IFBLK = 24_576; 23 | export const S_IFIFO = 4096; 24 | export const S_IFLNK = 40_960; 25 | export const S_IFSOCK = 49_152; 26 | export const O_CREAT = 64; 27 | export const O_EXCL = 128; 28 | export const UV_FS_O_FILEMAP = 0; 29 | export const O_NOCTTY = 256; 30 | export const O_TRUNC = 512; 31 | export const O_APPEND = 1024; 32 | export const O_DIRECTORY = 65_536; 33 | export const O_NOATIME = 262_144; 34 | export const O_NOFOLLOW = 131_072; 35 | export const O_SYNC = 1_052_672; 36 | export const O_DSYNC = 4096; 37 | export const O_DIRECT = 16_384; 38 | export const O_NONBLOCK = 2048; 39 | export const S_IRWXU = 448; 40 | export const S_IRUSR = 256; 41 | export const S_IWUSR = 128; 42 | export const S_IXUSR = 64; 43 | export const S_IRWXG = 56; 44 | export const S_IRGRP = 32; 45 | export const S_IWGRP = 16; 46 | export const S_IXGRP = 8; 47 | export const S_IRWXO = 7; 48 | export const S_IROTH = 4; 49 | export const S_IWOTH = 2; 50 | export const S_IXOTH = 1; 51 | export const F_OK = 0; 52 | export const R_OK = 4; 53 | export const W_OK = 2; 54 | export const X_OK = 1; 55 | export const UV_FS_COPYFILE_EXCL = 1; 56 | export const COPYFILE_EXCL = 1; 57 | export const UV_FS_COPYFILE_FICLONE = 2; 58 | export const COPYFILE_FICLONE = 2; 59 | export const UV_FS_COPYFILE_FICLONE_FORCE = 4; 60 | export const COPYFILE_FICLONE_FORCE = 4; 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unenv", 3 | "version": "2.0.0-rc.24", 4 | "description": "", 5 | "repository": "unjs/unenv", 6 | "license": "MIT", 7 | "sideEffects": false, 8 | "type": "module", 9 | "exports": { 10 | ".": { 11 | "types": "./dist/index.d.mts", 12 | "default": "./dist/index.mjs" 13 | }, 14 | "./package.json": "./package.json", 15 | "./mock/proxy-cjs": { 16 | "types": "./lib/mock.d.cts", 17 | "default": "./lib/mock.cjs" 18 | }, 19 | "./mock/proxy-cjs/*": { 20 | "types": "./lib/mock.d.cts", 21 | "default": "./lib/mock.cjs" 22 | }, 23 | "./*": { 24 | "types": "./dist/runtime/*.d.mts", 25 | "default": "./dist/runtime/*.mjs" 26 | } 27 | }, 28 | "types": "./dist/index.d.mts", 29 | "files": [ 30 | "dist", 31 | "lib" 32 | ], 33 | "scripts": { 34 | "build": "obuild", 35 | "build:watch": "pnpm node-ts --watch ./scripts/build.ts", 36 | "node-ts": "node --disable-warning=ExperimentalWarning --experimental-strip-types", 37 | "dev": "vitest", 38 | "lint": "eslint . && prettier -c src test", 39 | "lint:fix": "pnpm node-ts ./test/node-coverage.ts && automd && eslint --fix . && prettier -w src test", 40 | "prepack": "pnpm run build", 41 | "release": "pnpm test && changelogen --release --push --publish --prerelease --publishTag rc", 42 | "test": "pnpm lint && pnpm test:types && pnpm build && pnpm vitest --run", 43 | "test:types": "tsc --noEmit" 44 | }, 45 | "dependencies": { 46 | "pathe": "^2.0.3" 47 | }, 48 | "devDependencies": { 49 | "@parcel/watcher": "^2.5.1", 50 | "@types/debug": "^4.1.12", 51 | "@types/node": "22.14.1", 52 | "@vitest/coverage-v8": "^4.0.13", 53 | "automd": "^0.4.2", 54 | "changelogen": "^0.6.2", 55 | "consola": "^3.4.2", 56 | "esbuild": "^0.27.0", 57 | "eslint": "^9.39.1", 58 | "eslint-config-unjs": "^0.5.0", 59 | "exsolve": "^1.0.8", 60 | "jiti": "^2.6.1", 61 | "magic-string": "^0.30.21", 62 | "obuild": "^0.4.2", 63 | "prettier": "^3.6.2", 64 | "tinyexec": "^1.0.2", 65 | "typescript": "^5.9.3", 66 | "vitest": "^4.0.13", 67 | "workerd": "^1.20251121.0", 68 | "wrangler": "^4.50.0" 69 | }, 70 | "packageManager": "pnpm@10.23.0" 71 | } 72 | -------------------------------------------------------------------------------- /test/env.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { defineEnv } from "../src"; 3 | import { builtinModules } from "node:module"; 4 | import { existsSync } from "node:fs"; 5 | 6 | const nodeBuiltinModules = ["node:sqlite"]; 7 | 8 | describe("defineEnv", () => { 9 | it("defaults", () => { 10 | const { env } = defineEnv(); 11 | expect(env).toMatchObject({ 12 | alias: {}, 13 | external: [], 14 | inject: {}, 15 | polyfill: [], 16 | }); 17 | }); 18 | 19 | it("overrides", () => { 20 | const { env } = defineEnv({ 21 | nodeCompat: true, 22 | overrides: { alias: { foo: "bar" } }, 23 | }); 24 | expect(env.alias.foo).toBe("bar"); 25 | }); 26 | 27 | it("has aliases for all builtinModules", () => { 28 | const { env } = defineEnv({ nodeCompat: true }); 29 | for (const id of builtinModules) { 30 | expect(env.alias[id]).toBeDefined(); 31 | } 32 | }); 33 | 34 | it("has aliases for all node: builtin modules", () => { 35 | const { env } = defineEnv({ nodeCompat: true }); 36 | for (const id of builtinModules) { 37 | expect(`node:` + env.alias[id]).toBeDefined(); 38 | } 39 | for (const id of nodeBuiltinModules) { 40 | expect(env.alias[id]).toBeDefined(); 41 | } 42 | }); 43 | 44 | it("nagate", () => { 45 | const { env } = defineEnv({ 46 | nodeCompat: false, 47 | overrides: { 48 | polyfill: ["foo", "bar", "!foo"], 49 | external: ["foo", "bar", "!foo"], 50 | }, 51 | }); 52 | expect(env.polyfill).toEqual(["bar"]); 53 | expect(env.external).toEqual(["bar"]); 54 | }); 55 | 56 | describe("resolvePath", () => { 57 | it("resolves all nodeCompat paths", () => { 58 | const { env } = defineEnv({ nodeCompat: true, resolve: true }); 59 | for (const [from, to] of Object.entries(env.alias)) { 60 | expect(existsSync(to), `Alias: ${from} ~> ${to}`).toBe(true); 61 | } 62 | for (const path of env.polyfill) { 63 | expect(existsSync(path), path).toBe(true); 64 | } 65 | for (const inject of Object.values(env.inject)) { 66 | const to = Array.isArray(inject) ? inject[0] : inject; 67 | expect(existsSync(to), inject.toString()).toBe(true); 68 | } 69 | }); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /src/runtime/node/internal/zlib/formats/deflate.ts: -------------------------------------------------------------------------------- 1 | import type nodeZlib from "node:zlib"; 2 | import { createNotImplementedError } from "../../../../_internal/utils.ts"; 3 | import { notImplemented } from "../../../../_internal/utils.ts"; 4 | import { 5 | ZlibCompress, 6 | ZLibDecompress, 7 | notImplementedCompress, 8 | } from "./_shared.ts"; 9 | 10 | // Deflate Compression 11 | 12 | export class Deflate extends ZlibCompress { 13 | readonly _format = "deflate"; 14 | 15 | params(level: number, strategy: number, callback: () => void) { 16 | throw createNotImplementedError("Deflate.params"); 17 | } 18 | reset() { 19 | throw createNotImplementedError("Deflate.reset"); 20 | } 21 | } 22 | 23 | export const deflate: typeof nodeZlib.deflate = 24 | notImplementedCompress("deflate"); 25 | 26 | export const createDeflate: typeof nodeZlib.createDeflate = () => new Deflate(); 27 | 28 | export const deflateSync: typeof nodeZlib.deflateSync = 29 | /*@__PURE__*/ notImplemented("zlib.deflateSync"); 30 | 31 | // Deflate Decompress(Inflate) 32 | 33 | export class Inflate extends ZLibDecompress { 34 | readonly _format = "deflate"; 35 | 36 | reset() { 37 | throw createNotImplementedError("Inflate.reset"); 38 | } 39 | } 40 | 41 | export const inflate: typeof nodeZlib.inflate = 42 | notImplementedCompress("inflate"); 43 | 44 | export const createInflate: typeof nodeZlib.createInflate = () => new Inflate(); 45 | 46 | export const inflateSync: typeof nodeZlib.inflateSync = 47 | /*@__PURE__*/ notImplemented("zlib.inflateSync"); 48 | 49 | // Deflate Raw Compression 50 | 51 | export class DeflateRaw extends Deflate {} 52 | 53 | export const deflateRaw: typeof nodeZlib.deflateRaw = 54 | notImplementedCompress("deflateRaw"); 55 | 56 | export const createDeflateRaw: typeof nodeZlib.createDeflateRaw = () => 57 | new DeflateRaw(); 58 | 59 | export const deflateRawSync: typeof nodeZlib.deflateRawSync = 60 | /*@__PURE__*/ notImplemented("zlib.deflateRawSync"); 61 | 62 | // Inflate Raw Decompress (Inflate Raw) 63 | 64 | export class InflateRaw extends Inflate {} 65 | 66 | export const inflateRaw: typeof nodeZlib.inflateRaw = 67 | notImplementedCompress("inflateRaw"); 68 | 69 | export const createInflateRaw: typeof nodeZlib.createInflateRaw = () => 70 | new InflateRaw(); 71 | 72 | export const inflateRawSync: typeof nodeZlib.inflateRawSync = 73 | /*@__PURE__*/ notImplemented("zlib.inflateRawSync"); 74 | -------------------------------------------------------------------------------- /src/runtime/node/internal/zlib/formats/_shared.ts: -------------------------------------------------------------------------------- 1 | import type nodeZlib from "node:zlib"; 2 | import { Transform, type TransformOptions } from "node:stream"; 3 | import { createNotImplementedError } from "../../../../_internal/utils.ts"; 4 | 5 | // Compression 6 | 7 | export abstract class ZlibCompress extends Transform { 8 | readonly __unenv__ = true; 9 | 10 | readonly bytesRead = 0; 11 | readonly bytesWritten = 0; 12 | 13 | abstract readonly _format: 14 | | undefined 15 | | "deflate" 16 | | "gzip" 17 | | "zlib" 18 | | "brotli" 19 | | "zip"; 20 | 21 | constructor(opts?: TransformOptions) { 22 | super(opts); 23 | throw createNotImplementedError("zlib is not implemented yet!"); 24 | } 25 | close(callback?: () => void) { 26 | if (typeof callback === "function") { 27 | callback(); 28 | } 29 | } 30 | flush(kind?: number | undefined, callback?: (() => void) | undefined): void; 31 | flush(callback?: (() => void) | undefined): void; 32 | flush(kind?: unknown, callback?: unknown): void { 33 | if (typeof callback === "function") { 34 | callback(); 35 | } 36 | } 37 | } 38 | 39 | // Decompression 40 | 41 | export abstract class ZLibDecompress extends ZlibCompress {} 42 | 43 | // Mock Compress/Decompress Function factory 44 | 45 | export interface CompressFunction { 46 | ( 47 | buf: nodeZlib.InputType, 48 | options?: any, 49 | callback?: nodeZlib.CompressCallback, 50 | ): void; 51 | (buf: Buffer, callback?: nodeZlib.CompressCallback): void; 52 | __promisify__(buffer: nodeZlib.InputType, options?: any): Promise; 53 | } 54 | 55 | export function notImplementedCompress(format: string): CompressFunction { 56 | const fn = function ( 57 | _buf: nodeZlib.InputType, 58 | arg2?: nodeZlib.ZlibOptions | nodeZlib.CompressCallback, 59 | arg3?: nodeZlib.CompressCallback, 60 | ) { 61 | const cb = typeof arg2 === "function" ? arg2 : arg3; 62 | const err = new Error(`[unenv] zlib ${format} compression not supported.`); 63 | if (typeof cb === "function") { 64 | cb(err, Buffer.from("")); 65 | } else { 66 | throw err; 67 | } 68 | }; 69 | return Object.assign(fn, { 70 | __promisify__: (buffer: nodeZlib.InputType, options: any) => { 71 | return new Promise((resolve, reject) => { 72 | fn(buffer, options, (err, result) => 73 | err ? reject(err) : resolve(result), 74 | ); 75 | }); 76 | }, 77 | }); 78 | } 79 | -------------------------------------------------------------------------------- /src/runtime/node/internal/util/legacy-types.ts: -------------------------------------------------------------------------------- 1 | import type nodeUtil from "node:util"; 2 | 3 | export const isRegExp: typeof nodeUtil.isRegExp = (val): val is RegExp => 4 | val instanceof RegExp; 5 | 6 | export const isDate: typeof nodeUtil.isDate = (val): val is Date => 7 | val instanceof Date; 8 | 9 | export const isArray: typeof nodeUtil.isArray = (val): val is unknown[] => 10 | Array.isArray(val); 11 | 12 | export const isBoolean: typeof nodeUtil.isBoolean = (val): val is boolean => 13 | typeof val === "boolean"; 14 | 15 | export const isNull: typeof nodeUtil.isNull = (val): val is null => 16 | val === null; 17 | 18 | export const isNullOrUndefined: typeof nodeUtil.isNullOrUndefined = ( 19 | val, 20 | ): val is null | undefined => val === null || val === undefined; 21 | 22 | export const isNumber: typeof nodeUtil.isNumber = (val): val is number => 23 | typeof val === "number"; 24 | 25 | export const isString: typeof nodeUtil.isString = (val): val is string => 26 | typeof val === "string"; 27 | 28 | export const isSymbol: typeof nodeUtil.isSymbol = (val): val is symbol => 29 | typeof val === "symbol"; 30 | 31 | export const isUndefined: typeof nodeUtil.isUndefined = ( 32 | val, 33 | ): val is undefined => val === undefined; 34 | 35 | // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type 36 | export const isFunction: typeof nodeUtil.isFunction = (val): val is Function => 37 | typeof val === "function"; 38 | 39 | export const isBuffer: typeof nodeUtil.isBuffer = (val: any): val is Buffer => { 40 | return ( 41 | val && 42 | typeof val === "object" && 43 | typeof val.copy === "function" && 44 | typeof val.fill === "function" && 45 | typeof val.readUInt8 === "function" 46 | ); 47 | }; 48 | 49 | export const isDeepStrictEqual: typeof nodeUtil.isDeepStrictEqual = (a, b) => 50 | JSON.stringify(a) === JSON.stringify(b); 51 | 52 | export const isObject: typeof nodeUtil.isObject = (val) => 53 | val !== null && 54 | typeof val === "object" && 55 | // eslint-disable-next-line no-prototype-builtins 56 | Object.getPrototypeOf(val).isPrototypeOf(Object); 57 | 58 | export const isError: typeof nodeUtil.isError = (val): val is Error => 59 | val instanceof Error; 60 | 61 | // Source https://github.com/jonschlinkert/is-primitive/blob/b22c524da5cbac075f14145780ec4b3637afd7dc/index.js 62 | export const isPrimitive: typeof nodeUtil.isPrimitive = (val) => { 63 | if (typeof val === "object") { 64 | return val === null; 65 | } 66 | return typeof val !== "function"; 67 | }; 68 | -------------------------------------------------------------------------------- /src/runtime/node/process.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/process.html 2 | import { Process } from "./internal/process/process.ts"; 3 | import { env as UnenvEnv } from "./internal/process/env.ts"; 4 | import { hrtime as UnenvHrTime } from "./internal/process/hrtime.ts"; 5 | import { nextTick as UnenvNextTick } from "./internal/process/nexttick.ts"; 6 | 7 | const unenvProcess = new Process({ 8 | env: UnenvEnv, 9 | hrtime: UnenvHrTime, 10 | nextTick: UnenvNextTick, 11 | }); 12 | 13 | export default unenvProcess satisfies NodeJS.Process; 14 | 15 | export const { 16 | abort, 17 | addListener, 18 | allowedNodeEnvironmentFlags, 19 | hasUncaughtExceptionCaptureCallback, 20 | setUncaughtExceptionCaptureCallback, 21 | loadEnvFile, 22 | sourceMapsEnabled, 23 | arch, 24 | argv, 25 | argv0, 26 | chdir, 27 | config, 28 | connected, 29 | constrainedMemory, 30 | availableMemory, 31 | cpuUsage, 32 | cwd, 33 | debugPort, 34 | dlopen, 35 | disconnect, 36 | emit, 37 | emitWarning, 38 | env, 39 | eventNames, 40 | execArgv, 41 | execPath, 42 | exit, 43 | finalization, 44 | features, 45 | getBuiltinModule, 46 | getActiveResourcesInfo, 47 | getMaxListeners, 48 | hrtime, 49 | kill, 50 | listeners, 51 | listenerCount, 52 | memoryUsage, 53 | nextTick, 54 | on, 55 | off, 56 | once, 57 | pid, 58 | platform, 59 | ppid, 60 | prependListener, 61 | prependOnceListener, 62 | rawListeners, 63 | release, 64 | removeAllListeners, 65 | removeListener, 66 | report, 67 | resourceUsage, 68 | setMaxListeners, 69 | setSourceMapsEnabled, 70 | stderr, 71 | stdin, 72 | stdout, 73 | title, 74 | umask, 75 | uptime, 76 | version, 77 | versions, 78 | domain, 79 | initgroups, 80 | moduleLoadList, 81 | reallyExit, 82 | openStdin, 83 | assert, 84 | binding, 85 | send, 86 | exitCode, 87 | channel, 88 | getegid, 89 | geteuid, 90 | getgid, 91 | getgroups, 92 | getuid, 93 | setegid, 94 | seteuid, 95 | setgid, 96 | setgroups, 97 | setuid, 98 | permission, 99 | mainModule, 100 | ref, 101 | unref, 102 | _events, 103 | _eventsCount, 104 | _exiting, 105 | _maxListeners, 106 | _debugEnd, 107 | _debugProcess, 108 | _fatalException, 109 | _getActiveHandles, 110 | _getActiveRequests, 111 | _kill, 112 | _preload_modules, 113 | _rawDebug, 114 | _startProfilerIdleNotifier, 115 | _stopProfilerIdleNotifier, 116 | _tickCallback, 117 | _disconnect, 118 | _handleQueue, 119 | _pendingMessage, 120 | _channel, 121 | _send, 122 | _linkedBinding, 123 | } = unenvProcess; 124 | -------------------------------------------------------------------------------- /test/node/test-url-parse-invalid-input.mjs: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob//v22.7.0/test/parallel/test-url-parse-invalid-input.js 2 | 3 | import assert from "node:assert"; 4 | 5 | import url from "../../src/runtime/node/url.ts"; 6 | 7 | // https://github.com/joyent/node/issues/568 8 | for (const [val, type] of [ 9 | [undefined, "undefined"], 10 | [null, "object"], 11 | [true, "boolean"], 12 | [false, "boolean"], 13 | [0, "number"], 14 | [0, "number"], 15 | [[], "object"], 16 | [{}, "object"], 17 | [() => {}, "function"], 18 | [Symbol("foo"), "symbol"], 19 | ]) { 20 | assert.throws( 21 | () => { 22 | url.parse(val); 23 | }, 24 | { 25 | code: "ERR_INVALID_ARG_TYPE", 26 | name: "TypeError", 27 | message: 28 | 'The "url" argument must be of type string. Received ' + 29 | (val ? val.toString() : val), 30 | }, 31 | ); 32 | } 33 | 34 | assert.throws( 35 | () => { 36 | url.parse("http://%E0%A4%A@fail"); 37 | }, 38 | (e) => { 39 | // The error should be a URIError. 40 | if (!(e instanceof URIError)) return false; 41 | 42 | // The error should be from the JS engine and not from Node.js. 43 | // JS engine errors do not have the `code` property. 44 | return e.code === undefined; 45 | }, 46 | ); 47 | 48 | assert.throws( 49 | () => { 50 | url.parse("http://[127.0.0.1\u0000c8763]:8000/"); 51 | }, 52 | { code: "ERR_INVALID_URL", input: "http://[127.0.0.1\u0000c8763]:8000/" }, 53 | ); 54 | 55 | // An array of Unicode code points whose Unicode NFKD contains a "bad 56 | // character". 57 | const badIDNA = (() => { 58 | const BAD_CHARS = String.raw`#%/:?@[\]^|`; 59 | const out = []; 60 | for (let i = 0x80; i < 0x11_00_00; i++) { 61 | const cp = String.fromCodePoint(i); 62 | for (const badChar of BAD_CHARS) { 63 | if (cp.normalize("NFKD").includes(badChar)) { 64 | out.push(cp); 65 | } 66 | } 67 | } 68 | return out; 69 | })(); 70 | 71 | // The generation logic above should at a minimum produce these two 72 | // characters. 73 | 74 | // TODO: this is not being caught 75 | 76 | // assert(badIDNA.includes("℀")); 77 | // assert(badIDNA.includes("@")); 78 | 79 | // for (const badCodePoint of badIDNA) { 80 | // const badURL = `http://fail${badCodePoint}fail.com/`; 81 | // assert.throws( 82 | // () => { 83 | // url.parse(badURL); 84 | // }, 85 | // (e) => e.code === "ERR_INVALID_URL", 86 | // `parsing ${badURL}`, 87 | // ); 88 | // } 89 | 90 | // assert.throws( 91 | // () => { 92 | // url.parse("http://\u00AD/bad.com/"); 93 | // }, 94 | // (e) => e.code === "ERR_INVALID_URL", 95 | // "parsing http://\u00AD/bad.com/", 96 | // ); 97 | -------------------------------------------------------------------------------- /src/runtime/node/internal/http/constants.ts: -------------------------------------------------------------------------------- 1 | export const METHODS = [ 2 | "ACL", 3 | "BIND", 4 | "CHECKOUT", 5 | "CONNECT", 6 | "COPY", 7 | "DELETE", 8 | "GET", 9 | "HEAD", 10 | "LINK", 11 | "LOCK", 12 | "M-SEARCH", 13 | "MERGE", 14 | "MKACTIVITY", 15 | "MKCALENDAR", 16 | "MKCOL", 17 | "MOVE", 18 | "NOTIFY", 19 | "OPTIONS", 20 | "PATCH", 21 | "POST", 22 | "PRI", 23 | "PROPFIND", 24 | "PROPPATCH", 25 | "PURGE", 26 | "PUT", 27 | "REBIND", 28 | "REPORT", 29 | "SEARCH", 30 | "SOURCE", 31 | "SUBSCRIBE", 32 | "TRACE", 33 | "UNBIND", 34 | "UNLINK", 35 | "UNLOCK", 36 | "UNSUBSCRIBE", 37 | ]; 38 | 39 | export const STATUS_CODES = { 40 | 100: "Continue", 41 | 101: "Switching Protocols", 42 | 102: "Processing", 43 | 103: "Early Hints", 44 | 200: "OK", 45 | 201: "Created", 46 | 202: "Accepted", 47 | 203: "Non-Authoritative Information", 48 | 204: "No Content", 49 | 205: "Reset Content", 50 | 206: "Partial Content", 51 | 207: "Multi-Status", 52 | 208: "Already Reported", 53 | 226: "IM Used", 54 | 300: "Multiple Choices", 55 | 301: "Moved Permanently", 56 | 302: "Found", 57 | 303: "See Other", 58 | 304: "Not Modified", 59 | 305: "Use Proxy", 60 | 307: "Temporary Redirect", 61 | 308: "Permanent Redirect", 62 | 400: "Bad Request", 63 | 401: "Unauthorized", 64 | 402: "Payment Required", 65 | 403: "Forbidden", 66 | 404: "Not Found", 67 | 405: "Method Not Allowed", 68 | 406: "Not Acceptable", 69 | 407: "Proxy Authentication Required", 70 | 408: "Request Timeout", 71 | 409: "Conflict", 72 | 410: "Gone", 73 | 411: "Length Required", 74 | 412: "Precondition Failed", 75 | 413: "Payload Too Large", 76 | 414: "URI Too Long", 77 | 415: "Unsupported Media Type", 78 | 416: "Range Not Satisfiable", 79 | 417: "Expectation Failed", 80 | 418: "I'm a Teapot", 81 | 421: "Misdirected Request", 82 | 422: "Unprocessable Entity", 83 | 423: "Locked", 84 | 424: "Failed Dependency", 85 | 425: "Too Early", 86 | 426: "Upgrade Required", 87 | 428: "Precondition Required", 88 | 429: "Too Many Requests", 89 | 431: "Request Header Fields Too Large", 90 | 451: "Unavailable For Legal Reasons", 91 | 500: "Internal Server Error", 92 | 501: "Not Implemented", 93 | 502: "Bad Gateway", 94 | 503: "Service Unavailable", 95 | 504: "Gateway Timeout", 96 | 505: "HTTP Version Not Supported", 97 | 506: "Variant Also Negotiates", 98 | 507: "Insufficient Storage", 99 | 508: "Loop Detected", 100 | 509: "Bandwidth Limit Exceeded", 101 | 510: "Not Extended", 102 | 511: "Network Authentication Required", 103 | }; 104 | 105 | export const maxHeaderSize = 16_384; 106 | -------------------------------------------------------------------------------- /test/node/test-url-parse-query.mjs: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob//v22.7.0/test/parallel/test-url-parse-query.js 2 | 3 | import assert from "node:assert"; 4 | 5 | import url from "../../src/runtime/node/url.ts"; 6 | 7 | function createWithNoPrototype(properties = []) { 8 | const noProto = { __proto__: null }; 9 | for (const property of properties) { 10 | noProto[property.key] = property.value; 11 | } 12 | return noProto; 13 | } 14 | 15 | function check(actual, expected) { 16 | assert.notStrictEqual(Object.getPrototypeOf(actual), Object.prototype); 17 | assert.deepStrictEqual( 18 | Object.keys(actual).sort(), 19 | Object.keys(expected).sort(), 20 | ); 21 | for (const key of Object.keys(expected)) { 22 | assert.deepStrictEqual(actual[key], expected[key]); 23 | } 24 | } 25 | 26 | const parseTestsWithQueryString = { 27 | "/foo/bar?baz=quux#frag": { 28 | href: "/foo/bar?baz=quux#frag", 29 | hash: "#frag", 30 | search: "?baz=quux", 31 | query: createWithNoPrototype([{ key: "baz", value: "quux" }]), 32 | pathname: "/foo/bar", 33 | path: "/foo/bar?baz=quux", 34 | }, 35 | "http://example.com": { 36 | href: "http://example.com/", 37 | protocol: "http:", 38 | slashes: true, 39 | host: "example.com", 40 | hostname: "example.com", 41 | query: createWithNoPrototype(), 42 | search: null, 43 | pathname: "/", 44 | path: "/", 45 | }, 46 | "/example": { 47 | protocol: null, 48 | slashes: null, 49 | auth: undefined, 50 | host: null, 51 | port: null, 52 | hostname: null, 53 | hash: null, 54 | search: null, 55 | query: createWithNoPrototype(), 56 | pathname: "/example", 57 | path: "/example", 58 | href: "/example", 59 | }, 60 | "/example?query=value": { 61 | protocol: null, 62 | slashes: null, 63 | auth: undefined, 64 | host: null, 65 | port: null, 66 | hostname: null, 67 | hash: null, 68 | search: "?query=value", 69 | query: createWithNoPrototype([{ key: "query", value: "value" }]), 70 | pathname: "/example", 71 | path: "/example?query=value", 72 | href: "/example?query=value", 73 | }, 74 | }; 75 | for (const u in parseTestsWithQueryString) { 76 | const actual = url.parse(u, true); 77 | const expected = Object.assign(new url.Url(), parseTestsWithQueryString[u]); 78 | for (const i in actual) { 79 | if (actual[i] === null && expected[i] === undefined) { 80 | expected[i] = null; 81 | } 82 | } 83 | 84 | const properties = Object.keys(actual).sort(); 85 | assert.deepStrictEqual(properties, Object.keys(expected).sort()); 86 | for (const property of properties) { 87 | if (property === "query") { 88 | check(actual[property], expected[property]); 89 | } else { 90 | assert.deepStrictEqual(actual[property], expected[property]); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/runtime/node/cluster.ts: -------------------------------------------------------------------------------- 1 | import type nodeCluster from "node:cluster"; 2 | import type { 3 | Cluster as NodeCluster, 4 | Worker as NodeClusterWorker, 5 | ClusterSettings as NodeClusterSettings, 6 | } from "node:cluster"; 7 | import { EventEmitter } from "node:events"; 8 | import { notImplemented } from "../_internal/utils.ts"; 9 | 10 | export const SCHED_NONE: typeof nodeCluster.SCHED_NONE = 1; 11 | export const SCHED_RR: typeof nodeCluster.SCHED_RR = 2; 12 | 13 | export const isMaster: typeof nodeCluster.isMaster = true; 14 | export const isPrimary: typeof nodeCluster.isPrimary = true; 15 | export const isWorker: typeof nodeCluster.isWorker = false; 16 | 17 | export const schedulingPolicy: typeof nodeCluster.schedulingPolicy = SCHED_RR; 18 | export const settings: typeof nodeCluster.settings = {}; 19 | export const workers: typeof nodeCluster.workers = {}; 20 | 21 | export const fork: typeof nodeCluster.fork = 22 | /*@__PURE__*/ notImplemented("cluster.fork"); 23 | 24 | export const disconnect: typeof nodeCluster.disconnect = 25 | /*@__PURE__*/ notImplemented("cluster.disconnect"); 26 | 27 | export const setupPrimary: typeof nodeCluster.setupPrimary = 28 | /*@__PURE__*/ notImplemented("cluster.setupPrimary"); 29 | 30 | export const setupMaster: typeof nodeCluster.setupMaster = 31 | /*@__PURE__*/ notImplemented("cluster.setupMaster"); 32 | 33 | // Make ESM coverage happy 34 | export const _events = []; 35 | export const _eventsCount = 0; 36 | export const _maxListeners = 0; 37 | 38 | export class Worker extends EventEmitter implements NodeClusterWorker { 39 | _connected: boolean = false; 40 | id = 0; 41 | get process() { 42 | return globalThis.process as any; 43 | } 44 | get exitedAfterDisconnect() { 45 | return this._connected; 46 | } 47 | isConnected(): boolean { 48 | return this._connected; 49 | } 50 | isDead(): boolean { 51 | return true; 52 | } 53 | send(message: any, sendHandle?: any, options?: any, callback?: any): boolean { 54 | return false; 55 | } 56 | kill(signal?: string): void { 57 | this._connected = false; 58 | } 59 | destroy(signal?: string): void { 60 | this._connected = false; 61 | } 62 | disconnect(): this { 63 | this._connected = false; 64 | return this; 65 | } 66 | } 67 | 68 | class _Cluster extends EventEmitter implements NodeCluster { 69 | Worker = Worker; 70 | isMaster = isMaster; 71 | isPrimary = isPrimary; 72 | isWorker = isWorker; 73 | SCHED_NONE = SCHED_NONE; 74 | SCHED_RR = SCHED_RR; 75 | schedulingPolicy = SCHED_RR; 76 | settings = settings; 77 | workers = workers; 78 | setupPrimary(_settings?: NodeClusterSettings): void { 79 | setupPrimary(); 80 | } 81 | setupMaster(_settings?: NodeClusterSettings): void { 82 | setupMaster(); 83 | } 84 | disconnect(): void { 85 | disconnect(); 86 | } 87 | fork(env?: any): NodeClusterWorker { 88 | return fork(env); 89 | } 90 | } 91 | 92 | export default new _Cluster(); 93 | -------------------------------------------------------------------------------- /src/runtime/node/internal/crypto/constants.ts: -------------------------------------------------------------------------------- 1 | // npx -y node@22.14 -e 'const{constants}=require("crypto");console.log(Object.entries(constants).map(([k,v]) => `export const ${k} = ${JSON.stringify(v)}`).join("\n"))' 2 | 3 | export const SSL_OP_ALL = 2_147_485_776; 4 | export const SSL_OP_ALLOW_NO_DHE_KEX = 1024; 5 | export const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 262_144; 6 | export const SSL_OP_CIPHER_SERVER_PREFERENCE = 4_194_304; 7 | export const SSL_OP_CISCO_ANYCONNECT = 32_768; 8 | export const SSL_OP_COOKIE_EXCHANGE = 8192; 9 | export const SSL_OP_CRYPTOPRO_TLSEXT_BUG = 2_147_483_648; 10 | export const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 2048; 11 | export const SSL_OP_LEGACY_SERVER_CONNECT = 4; 12 | export const SSL_OP_NO_COMPRESSION = 131_072; 13 | export const SSL_OP_NO_ENCRYPT_THEN_MAC = 524_288; 14 | export const SSL_OP_NO_QUERY_MTU = 4096; 15 | export const SSL_OP_NO_RENEGOTIATION = 1_073_741_824; 16 | export const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 65_536; 17 | export const SSL_OP_NO_SSLv2 = 0; 18 | export const SSL_OP_NO_SSLv3 = 33_554_432; 19 | export const SSL_OP_NO_TICKET = 16_384; 20 | export const SSL_OP_NO_TLSv1 = 67_108_864; 21 | export const SSL_OP_NO_TLSv1_1 = 268_435_456; 22 | export const SSL_OP_NO_TLSv1_2 = 134_217_728; 23 | export const SSL_OP_NO_TLSv1_3 = 536_870_912; 24 | export const SSL_OP_PRIORITIZE_CHACHA = 2_097_152; 25 | export const SSL_OP_TLS_ROLLBACK_BUG = 8_388_608; 26 | 27 | export const ENGINE_METHOD_RSA = 1; 28 | export const ENGINE_METHOD_DSA = 2; 29 | export const ENGINE_METHOD_DH = 4; 30 | export const ENGINE_METHOD_RAND = 8; 31 | export const ENGINE_METHOD_EC = 2048; 32 | export const ENGINE_METHOD_CIPHERS = 64; 33 | export const ENGINE_METHOD_DIGESTS = 128; 34 | export const ENGINE_METHOD_PKEY_METHS = 512; 35 | export const ENGINE_METHOD_PKEY_ASN1_METHS = 1024; 36 | export const ENGINE_METHOD_ALL = 65_535; 37 | export const ENGINE_METHOD_NONE = 0; 38 | 39 | export const DH_CHECK_P_NOT_SAFE_PRIME = 2; 40 | export const DH_CHECK_P_NOT_PRIME = 1; 41 | export const DH_UNABLE_TO_CHECK_GENERATOR = 4; 42 | export const DH_NOT_SUITABLE_GENERATOR = 8; 43 | 44 | export const RSA_PKCS1_PADDING = 1; 45 | export const RSA_NO_PADDING = 3; 46 | export const RSA_PKCS1_OAEP_PADDING = 4; 47 | export const RSA_X931_PADDING = 5; 48 | export const RSA_PKCS1_PSS_PADDING = 6; 49 | export const RSA_PSS_SALTLEN_DIGEST = -1; 50 | export const RSA_PSS_SALTLEN_MAX_SIGN = -2; 51 | export const RSA_PSS_SALTLEN_AUTO = -2; 52 | 53 | export const POINT_CONVERSION_COMPRESSED = 2; 54 | export const POINT_CONVERSION_UNCOMPRESSED = 4; 55 | export const POINT_CONVERSION_HYBRID = 6; 56 | 57 | // Versions explicitly set to 0 to avoid version misdetections 58 | 59 | export const defaultCoreCipherList = ""; 60 | export const defaultCipherList = ""; 61 | 62 | export const OPENSSL_VERSION_NUMBER = 0; 63 | export const TLS1_VERSION = 0; 64 | export const TLS1_1_VERSION = 0; 65 | export const TLS1_2_VERSION = 0; 66 | export const TLS1_3_VERSION = 0; 67 | -------------------------------------------------------------------------------- /src/runtime/node/internal/os/constants.ts: -------------------------------------------------------------------------------- 1 | // npx -y node@22.14 -e 'const{constants}=require("os");console.log(Object.entries(constants).map(([k,v]) => `export const ${k} = ${JSON.stringify(v)}`).join("\n"))' 2 | 3 | export const UV_UDP_REUSEADDR = 4; 4 | export const dlopen = { 5 | RTLD_LAZY: 1, 6 | RTLD_NOW: 2, 7 | RTLD_GLOBAL: 256, 8 | RTLD_LOCAL: 0, 9 | RTLD_DEEPBIND: 8, 10 | }; 11 | export const errno = { 12 | E2BIG: 7, 13 | EACCES: 13, 14 | EADDRINUSE: 98, 15 | EADDRNOTAVAIL: 99, 16 | EAFNOSUPPORT: 97, 17 | EAGAIN: 11, 18 | EALREADY: 114, 19 | EBADF: 9, 20 | EBADMSG: 74, 21 | EBUSY: 16, 22 | ECANCELED: 125, 23 | ECHILD: 10, 24 | ECONNABORTED: 103, 25 | ECONNREFUSED: 111, 26 | ECONNRESET: 104, 27 | EDEADLK: 35, 28 | EDESTADDRREQ: 89, 29 | EDOM: 33, 30 | EDQUOT: 122, 31 | EEXIST: 17, 32 | EFAULT: 14, 33 | EFBIG: 27, 34 | EHOSTUNREACH: 113, 35 | EIDRM: 43, 36 | EILSEQ: 84, 37 | EINPROGRESS: 115, 38 | EINTR: 4, 39 | EINVAL: 22, 40 | EIO: 5, 41 | EISCONN: 106, 42 | EISDIR: 21, 43 | ELOOP: 40, 44 | EMFILE: 24, 45 | EMLINK: 31, 46 | EMSGSIZE: 90, 47 | EMULTIHOP: 72, 48 | ENAMETOOLONG: 36, 49 | ENETDOWN: 100, 50 | ENETRESET: 102, 51 | ENETUNREACH: 101, 52 | ENFILE: 23, 53 | ENOBUFS: 105, 54 | ENODATA: 61, 55 | ENODEV: 19, 56 | ENOENT: 2, 57 | ENOEXEC: 8, 58 | ENOLCK: 37, 59 | ENOLINK: 67, 60 | ENOMEM: 12, 61 | ENOMSG: 42, 62 | ENOPROTOOPT: 92, 63 | ENOSPC: 28, 64 | ENOSR: 63, 65 | ENOSTR: 60, 66 | ENOSYS: 38, 67 | ENOTCONN: 107, 68 | ENOTDIR: 20, 69 | ENOTEMPTY: 39, 70 | ENOTSOCK: 88, 71 | ENOTSUP: 95, 72 | ENOTTY: 25, 73 | ENXIO: 6, 74 | EOPNOTSUPP: 95, 75 | EOVERFLOW: 75, 76 | EPERM: 1, 77 | EPIPE: 32, 78 | EPROTO: 71, 79 | EPROTONOSUPPORT: 93, 80 | EPROTOTYPE: 91, 81 | ERANGE: 34, 82 | EROFS: 30, 83 | ESPIPE: 29, 84 | ESRCH: 3, 85 | ESTALE: 116, 86 | ETIME: 62, 87 | ETIMEDOUT: 110, 88 | ETXTBSY: 26, 89 | EWOULDBLOCK: 11, 90 | EXDEV: 18, 91 | }; 92 | export const signals = { 93 | SIGHUP: 1, 94 | SIGINT: 2, 95 | SIGQUIT: 3, 96 | SIGILL: 4, 97 | SIGTRAP: 5, 98 | SIGABRT: 6, 99 | SIGIOT: 6, 100 | SIGBUS: 7, 101 | SIGFPE: 8, 102 | SIGKILL: 9, 103 | SIGUSR1: 10, 104 | SIGSEGV: 11, 105 | SIGUSR2: 12, 106 | SIGPIPE: 13, 107 | SIGALRM: 14, 108 | SIGTERM: 15, 109 | SIGCHLD: 17, 110 | SIGSTKFLT: 16, 111 | SIGCONT: 18, 112 | SIGSTOP: 19, 113 | SIGTSTP: 20, 114 | SIGTTIN: 21, 115 | SIGTTOU: 22, 116 | SIGURG: 23, 117 | SIGXCPU: 24, 118 | SIGXFSZ: 25, 119 | SIGVTALRM: 26, 120 | SIGPROF: 27, 121 | SIGWINCH: 28, 122 | SIGIO: 29, 123 | SIGPOLL: 29, 124 | SIGPWR: 30, 125 | SIGSYS: 31, 126 | }; 127 | export const priority = { 128 | PRIORITY_LOW: 19, 129 | PRIORITY_BELOW_NORMAL: 10, 130 | PRIORITY_NORMAL: 0, 131 | PRIORITY_ABOVE_NORMAL: -7, 132 | PRIORITY_HIGH: -14, 133 | PRIORITY_HIGHEST: -20, 134 | }; 135 | -------------------------------------------------------------------------------- /src/runtime/node/internal/buffer/ieee754.ts: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/feross/ieee754/blob/8a0041f3d5e41b7cfcf0e0158fcf84b071709bda/index.js 2 | 3 | /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ 4 | export function read( 5 | buffer: Uint8Array, 6 | offset: number, 7 | isLE: boolean, 8 | mLen: number, 9 | nBytes: number, 10 | ) { 11 | let e, m; 12 | const eLen = nBytes * 8 - mLen - 1; 13 | const eMax = (1 << eLen) - 1; 14 | const eBias = eMax >> 1; 15 | let nBits = -7; 16 | let i = isLE ? nBytes - 1 : 0; 17 | const d = isLE ? -1 : 1; 18 | let s = buffer[offset + i]; 19 | 20 | i += d; 21 | 22 | e = s & ((1 << -nBits) - 1); 23 | s >>= -nBits; 24 | nBits += eLen; 25 | while (nBits > 0) { 26 | e = e * 256 + buffer[offset + i]; 27 | i += d; 28 | nBits -= 8; 29 | } 30 | 31 | m = e & ((1 << -nBits) - 1); 32 | e >>= -nBits; 33 | nBits += mLen; 34 | while (nBits > 0) { 35 | m = m * 256 + buffer[offset + i]; 36 | i += d; 37 | nBits -= 8; 38 | } 39 | 40 | if (e === 0) { 41 | e = 1 - eBias; 42 | } else if (e === eMax) { 43 | return m ? Number.NaN : (s ? -1 : 1) * Number.POSITIVE_INFINITY; 44 | } else { 45 | m = m + Math.pow(2, mLen); 46 | e = e - eBias; 47 | } 48 | return (s ? -1 : 1) * m * Math.pow(2, e - mLen); 49 | } 50 | 51 | export function write( 52 | buffer: Uint8Array, 53 | value: number, 54 | offset: number, 55 | isLE: boolean, 56 | mLen: number, 57 | nBytes: number, 58 | ) { 59 | let e, m, c; 60 | let eLen = nBytes * 8 - mLen - 1; 61 | const eMax = (1 << eLen) - 1; 62 | const eBias = eMax >> 1; 63 | const rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0; 64 | let i = isLE ? 0 : nBytes - 1; 65 | const d = isLE ? 1 : -1; 66 | const s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; 67 | 68 | value = Math.abs(value); 69 | 70 | if (Number.isNaN(value) || value === Number.POSITIVE_INFINITY) { 71 | m = Number.isNaN(value) ? 1 : 0; 72 | e = eMax; 73 | } else { 74 | e = Math.floor(Math.log2(value)); 75 | if (value * (c = Math.pow(2, -e)) < 1) { 76 | e--; 77 | c *= 2; 78 | } 79 | value += e + eBias >= 1 ? rt / c : rt * Math.pow(2, 1 - eBias); 80 | if (value * c >= 2) { 81 | e++; 82 | c /= 2; 83 | } 84 | 85 | if (e + eBias >= eMax) { 86 | m = 0; 87 | e = eMax; 88 | } else if (e + eBias >= 1) { 89 | m = (value * c - 1) * Math.pow(2, mLen); 90 | e = e + eBias; 91 | } else { 92 | m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); 93 | e = 0; 94 | } 95 | } 96 | 97 | while (mLen >= 8) { 98 | buffer[offset + i] = m & 0xff; 99 | i += d; 100 | m /= 256; 101 | mLen -= 8; 102 | } 103 | 104 | e = (e << mLen) | m; 105 | eLen += mLen; 106 | while (eLen > 0) { 107 | buffer[offset + i] = e & 0xff; 108 | i += d; 109 | e /= 256; 110 | eLen -= 8; 111 | } 112 | 113 | buffer[offset + i - d] |= s * 128; 114 | } 115 | -------------------------------------------------------------------------------- /src/runtime/node/http.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/http.html 2 | import type nodeHttp from "node:http"; 3 | import { notImplemented, notImplementedClass } from "../_internal/utils.ts"; 4 | import { IncomingMessage } from "./internal/http/request.ts"; 5 | import { ServerResponse } from "./internal/http/response.ts"; 6 | import { Agent } from "./internal/http/agent.ts"; 7 | import { 8 | METHODS, 9 | STATUS_CODES, 10 | maxHeaderSize, 11 | } from "./internal/http/constants.ts"; 12 | 13 | export { METHODS, STATUS_CODES, maxHeaderSize }; 14 | export * from "./internal/http/request.ts"; 15 | export * from "./internal/http/response.ts"; 16 | export { Agent } from "./internal/http/agent.ts"; 17 | 18 | export const createServer = 19 | /*@__PURE__*/ notImplemented( 20 | "http.createServer", 21 | ); 22 | export const request = 23 | /*@__PURE__*/ notImplemented("http.request"); 24 | export const get = 25 | /*@__PURE__*/ notImplemented("http.get"); 26 | 27 | export const Server: typeof nodeHttp.Server = 28 | /*@__PURE__*/ notImplementedClass("http.Server"); 29 | 30 | export const OutgoingMessage: typeof nodeHttp.OutgoingMessage = 31 | /*@__PURE__*/ notImplementedClass("http.OutgoingMessage"); 32 | 33 | export const ClientRequest: typeof nodeHttp.ClientRequest = 34 | /*@__PURE__*/ notImplementedClass("http.ClientRequest"); 35 | 36 | export const globalAgent: typeof nodeHttp.globalAgent = new Agent(); 37 | 38 | export const validateHeaderName = /*@__PURE__*/ notImplemented< 39 | typeof nodeHttp.validateHeaderName 40 | >("http.validateHeaderName"); 41 | 42 | export const validateHeaderValue = /*@__PURE__*/ notImplemented< 43 | typeof nodeHttp.validateHeaderValue 44 | >("http.validateHeaderValue"); 45 | 46 | export const setMaxIdleHTTPParsers = /*@__PURE__*/ notImplemented< 47 | typeof nodeHttp.setMaxIdleHTTPParsers 48 | >("http.setMaxIdleHTTPParsers"); 49 | 50 | export const _connectionListener = /*@__PURE__*/ notImplemented( 51 | "http._connectionListener", 52 | ); 53 | 54 | export const WebSocket = 55 | globalThis.WebSocket || 56 | /*@__PURE__*/ notImplementedClass("WebSocket"); 57 | 58 | export const CloseEvent = 59 | globalThis.CloseEvent || 60 | /*@__PURE__*/ notImplementedClass("CloseEvent"); 61 | 62 | export const MessageEvent = 63 | globalThis.MessageEvent || 64 | /*@__PURE__*/ notImplementedClass("MessageEvent"); 65 | 66 | export default { 67 | METHODS, 68 | STATUS_CODES, 69 | maxHeaderSize, 70 | IncomingMessage: IncomingMessage as any as typeof nodeHttp.IncomingMessage, 71 | ServerResponse: ServerResponse as any as typeof nodeHttp.ServerResponse, 72 | WebSocket: WebSocket as any as typeof nodeHttp.WebSocket, 73 | CloseEvent: CloseEvent as any as typeof nodeHttp.CloseEvent, 74 | MessageEvent: MessageEvent as any as typeof nodeHttp.MessageEvent, 75 | createServer, 76 | request, 77 | get, 78 | Server, 79 | OutgoingMessage, 80 | ClientRequest, 81 | Agent, 82 | globalAgent, 83 | validateHeaderName, 84 | validateHeaderValue, 85 | setMaxIdleHTTPParsers, 86 | _connectionListener, 87 | } as /* TODO: use satisfies */ typeof nodeHttp; 88 | -------------------------------------------------------------------------------- /src/runtime/node/worker_threads.ts: -------------------------------------------------------------------------------- 1 | import type nodeWorkerThreads from "node:worker_threads"; 2 | import { BroadcastChannel } from "./internal/worker_threads/broadcast-channel.ts"; 3 | import { MessageChannel } from "./internal/worker_threads/message-channel.ts"; 4 | import { MessagePort } from "./internal/worker_threads/message-port.ts"; 5 | import { Worker } from "./internal/worker_threads/worker.ts"; 6 | 7 | import { notImplemented } from "../_internal/utils.ts"; 8 | 9 | export { BroadcastChannel } from "./internal/worker_threads/broadcast-channel.ts"; 10 | export { MessageChannel } from "./internal/worker_threads/message-channel.ts"; 11 | export { MessagePort } from "./internal/worker_threads/message-port.ts"; 12 | export { Worker } from "./internal/worker_threads/worker.ts"; 13 | 14 | const _environmentData = new Map(); 15 | export const getEnvironmentData: typeof nodeWorkerThreads.getEnvironmentData = 16 | function getEnvironmentData(key) { 17 | return _environmentData.get(key as string)!; 18 | }; 19 | export const setEnvironmentData: typeof nodeWorkerThreads.setEnvironmentData = 20 | function setEnvironmentData(key, value) { 21 | _environmentData.set(key as string, value); 22 | }; 23 | 24 | export const isMainThread: typeof nodeWorkerThreads.isMainThread = true; 25 | 26 | export const isMarkedAsUntransferable: any /* Node.js 22 */ = () => false; 27 | export const markAsUntransferable: typeof nodeWorkerThreads.markAsUntransferable = 28 | function markAsUntransferable(value) { 29 | // noop 30 | }; 31 | 32 | export const markAsUncloneable: typeof nodeWorkerThreads.markAsUncloneable = 33 | () => { 34 | // noop 35 | }; 36 | 37 | export const moveMessagePortToContext: typeof nodeWorkerThreads.moveMessagePortToContext = 38 | () => new MessagePort(); 39 | 40 | export const parentPort: typeof nodeWorkerThreads.parentPort = null; 41 | 42 | export const receiveMessageOnPort: typeof nodeWorkerThreads.receiveMessageOnPort = 43 | () => undefined; 44 | 45 | export const SHARE_ENV = /*@__PURE__*/ Symbol.for( 46 | "nodejs.worker_threads.SHARE_ENV", 47 | ) as typeof nodeWorkerThreads.SHARE_ENV; 48 | 49 | export const resourceLimits: typeof nodeWorkerThreads.resourceLimits = {}; 50 | 51 | export const threadId: typeof nodeWorkerThreads.threadId = 0; 52 | 53 | export const workerData: typeof nodeWorkerThreads.workerData = null; 54 | 55 | // https://nodejs.org/api/worker_threads.html#workerpostmessagetothreadthreadid-value-transferlist-timeout 56 | export const postMessageToThread = /*@__PURE__*/ notImplemented( 57 | "worker_threads.postMessageToThread", 58 | ); 59 | 60 | export const isInternalThread = false; 61 | 62 | export default { 63 | BroadcastChannel, 64 | MessageChannel, 65 | MessagePort, 66 | Worker, 67 | SHARE_ENV, 68 | getEnvironmentData, 69 | isMainThread, 70 | isMarkedAsUntransferable, 71 | markAsUntransferable, 72 | markAsUncloneable, 73 | moveMessagePortToContext, 74 | parentPort, 75 | receiveMessageOnPort, 76 | resourceLimits, 77 | setEnvironmentData, 78 | postMessageToThread, 79 | threadId, 80 | workerData, 81 | isInternalThread, 82 | } as /* TODO: use satisfies */ typeof nodeWorkerThreads; 83 | -------------------------------------------------------------------------------- /src/runtime/node/internal/net/socket.ts: -------------------------------------------------------------------------------- 1 | import type nodeNet from "node:net"; 2 | import { 3 | type Callback, 4 | type BufferEncoding, 5 | } from "../../../_internal/types.ts"; 6 | // Relative stream import required, see https://github.com/unjs/unenv/issues/353 7 | import { Duplex } from "../stream/duplex.ts"; 8 | 9 | // Docs: https://nodejs.org/api/net.html#net_class_net_socket 10 | export class Socket extends Duplex implements nodeNet.Socket { 11 | readonly __unenv__ = true; 12 | 13 | readonly bufferSize: number = 0; 14 | readonly bytesRead: number = 0; 15 | readonly bytesWritten: number = 0; 16 | readonly connecting: boolean = false; 17 | readonly destroyed: boolean = false; 18 | readonly pending: boolean = false; 19 | readonly localAddress: string = ""; 20 | readonly localPort: number = 0; 21 | readonly remoteAddress?: string = ""; 22 | readonly remoteFamily?: string = ""; 23 | readonly remotePort?: number = 0; 24 | readonly autoSelectFamilyAttemptedAddresses = []; 25 | readonly readyState: nodeNet.SocketReadyState = "readOnly"; 26 | 27 | constructor(_options?: nodeNet.SocketConstructorOpts) { 28 | super(); 29 | } 30 | 31 | write( 32 | _buffer: Uint8Array | string, 33 | _arg1?: BufferEncoding | Callback, 34 | _arg2?: Callback, 35 | ): boolean { 36 | return false; 37 | } 38 | 39 | connect( 40 | _arg1: number | string | nodeNet.SocketConnectOpts, 41 | _arg2?: string | Callback, 42 | _arg3?: Callback, 43 | ) { 44 | return this; 45 | } 46 | 47 | end( 48 | _arg1?: Callback | Uint8Array | string, 49 | _arg2?: BufferEncoding | Callback, 50 | _arg3?: Callback, 51 | ) { 52 | return this; 53 | } 54 | 55 | setEncoding(_encoding?: BufferEncoding): this { 56 | return this; 57 | } 58 | 59 | pause() { 60 | return this; 61 | } 62 | 63 | resume() { 64 | return this; 65 | } 66 | 67 | setTimeout(_timeout: number, _callback?: Callback): this { 68 | return this; 69 | } 70 | 71 | setNoDelay(_noDelay?: boolean): this { 72 | return this; 73 | } 74 | 75 | setKeepAlive(_enable?: boolean, _initialDelay?: number): this { 76 | return this; 77 | } 78 | 79 | address() { 80 | return {}; 81 | } 82 | 83 | unref() { 84 | return this; 85 | } 86 | 87 | ref() { 88 | return this; 89 | } 90 | 91 | destroySoon() { 92 | this.destroy(); 93 | } 94 | 95 | resetAndDestroy() { 96 | const err = new Error("ERR_SOCKET_CLOSED"); 97 | (err as any).code = "ERR_SOCKET_CLOSED"; 98 | this.destroy(err); 99 | return this; 100 | } 101 | } 102 | 103 | export class SocketAddress implements nodeNet.SocketAddress { 104 | readonly __unenv__ = true; 105 | 106 | address: string; 107 | family: "ipv4" | "ipv6"; 108 | port: number; 109 | flowlabel: number; 110 | 111 | static parse(_address: string, _port?: number) { 112 | return undefined; // successful 113 | } 114 | 115 | constructor(options: nodeNet.SocketAddress) { 116 | this.address = options.address; 117 | this.family = options.family; 118 | this.port = options.port; 119 | this.flowlabel = options.flowlabel; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/runtime/node/net.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/net.html 2 | import type nodeNet from "node:net"; 3 | 4 | import { notImplemented, notImplementedClass } from "../_internal/utils.ts"; 5 | 6 | import { Socket, SocketAddress } from "./internal/net/socket.ts"; 7 | import { Server } from "./internal/net/server.ts"; 8 | 9 | export { Server } from "./internal/net/server.ts"; 10 | 11 | // require('node:net').Socket === require('node:net').Stream 12 | export { 13 | Socket, 14 | SocketAddress, 15 | Socket as Stream, 16 | } from "./internal/net/socket.ts"; 17 | 18 | export const createServer = /*@__PURE__*/ notImplemented( 19 | "net.createServer", 20 | ) as typeof nodeNet.createServer; 21 | 22 | export const BlockList = /*@__PURE__*/ notImplementedClass( 23 | "net.BlockList", 24 | ) as typeof nodeNet.BlockList; 25 | 26 | export const connect = /*@__PURE__*/ notImplemented( 27 | "net.connect", 28 | ) as typeof nodeNet.connect; 29 | 30 | export const createConnection = /*@__PURE__*/ notImplemented( 31 | "net.createConnection", 32 | ) as typeof nodeNet.createConnection; 33 | 34 | export const getDefaultAutoSelectFamily = /*@__PURE__*/ notImplemented( 35 | "net.getDefaultAutoSelectFamily", 36 | ) as typeof nodeNet.getDefaultAutoSelectFamily; 37 | 38 | export const setDefaultAutoSelectFamily = /*@__PURE__*/ notImplemented( 39 | "net.setDefaultAutoSelectFamily", 40 | ) as typeof nodeNet.setDefaultAutoSelectFamily; 41 | 42 | export const getDefaultAutoSelectFamilyAttemptTimeout = 43 | /*@__PURE__*/ notImplemented( 44 | "net.getDefaultAutoSelectFamilyAttemptTimeout", 45 | ) as typeof nodeNet.getDefaultAutoSelectFamilyAttemptTimeout; 46 | 47 | export const setDefaultAutoSelectFamilyAttemptTimeout = 48 | /*@__PURE__*/ notImplemented( 49 | "net.setDefaultAutoSelectFamilyAttemptTimeout", 50 | ) as typeof nodeNet.setDefaultAutoSelectFamilyAttemptTimeout; 51 | 52 | const IPV4Regex = /^(?:\d{1,3}\.){3}\d{1,3}$/; 53 | export const isIPv4: typeof nodeNet.isIPv4 = (host: string) => 54 | IPV4Regex.test(host); 55 | 56 | const IPV6Regex = /^([\dA-Fa-f]{1,4}:){7}[\dA-Fa-f]{1,4}$/; 57 | export const isIPv6: typeof nodeNet.isIPv6 = (host: string) => 58 | IPV6Regex.test(host); 59 | 60 | export const isIP: typeof nodeNet.isIP = (host: string) => { 61 | if (isIPv4(host)) { 62 | return 4; 63 | } 64 | if (isIPv6(host)) { 65 | return 6; 66 | } 67 | return 0; 68 | }; 69 | 70 | // --- internal --- 71 | export const _createServerHandle = /*@__PURE__*/ notImplemented( 72 | "net._createServerHandle", 73 | ); 74 | 75 | export const _normalizeArgs = 76 | /*@__PURE__*/ notImplemented("net._normalizeArgs"); 77 | 78 | export const _setSimultaneousAccepts = /*@__PURE__*/ notImplemented( 79 | "net._setSimultaneousAccepts", 80 | ); 81 | 82 | const exports: typeof nodeNet = { 83 | Socket: Socket, 84 | // @ts-expect-error (deprecated alias) 85 | Stream: Socket, 86 | Server, 87 | BlockList, 88 | SocketAddress, 89 | createServer, 90 | connect, 91 | createConnection, 92 | isIPv4, 93 | isIPv6, 94 | isIP, 95 | getDefaultAutoSelectFamily, 96 | getDefaultAutoSelectFamilyAttemptTimeout, 97 | setDefaultAutoSelectFamily, 98 | setDefaultAutoSelectFamilyAttemptTimeout, 99 | _createServerHandle, 100 | _normalizeArgs, 101 | _setSimultaneousAccepts, 102 | }; 103 | 104 | export default exports; 105 | -------------------------------------------------------------------------------- /src/runtime/node/console.ts: -------------------------------------------------------------------------------- 1 | import type nodeConsole from "node:console"; 2 | import { Writable } from "node:stream"; 3 | import noop from "../mock/noop.ts"; 4 | import { notImplemented, notImplementedClass } from "../_internal/utils.ts"; 5 | 6 | const _console = globalThis.console; 7 | 8 | // undocumented public APIs 9 | export const _ignoreErrors: boolean = true; 10 | export const _stderr: Writable = new Writable(); 11 | export const _stdout: Writable = new Writable(); 12 | 13 | export const log: typeof nodeConsole.log = _console?.log ?? noop; 14 | export const info: typeof nodeConsole.info = _console?.info ?? log; 15 | export const trace: typeof nodeConsole.trace = _console?.trace ?? info; 16 | export const debug: typeof nodeConsole.debug = _console?.debug ?? log; 17 | export const table: typeof nodeConsole.table = _console?.table ?? log; 18 | export const error: typeof nodeConsole.error = _console?.error ?? log; 19 | export const warn: typeof nodeConsole.warn = _console?.warn ?? error; 20 | 21 | // https://developer.chrome.com/docs/devtools/console/api#createtask 22 | export const createTask = 23 | (_console as any)?.createTask ?? 24 | /*@__PURE__*/ notImplemented("console.createTask"); 25 | 26 | export const assert: typeof nodeConsole.assert = 27 | /*@__PURE__*/ notImplemented("console.assert"); 28 | 29 | // noop 30 | export const clear: typeof nodeConsole.clear = _console?.clear ?? noop; 31 | export const count: typeof nodeConsole.count = _console?.count ?? noop; 32 | export const countReset: typeof nodeConsole.countReset = 33 | _console?.countReset ?? noop; 34 | export const dir: typeof nodeConsole.dir = _console?.dir ?? noop; 35 | export const dirxml: typeof nodeConsole.dirxml = _console?.dirxml ?? noop; 36 | export const group: typeof nodeConsole.group = _console?.group ?? noop; 37 | export const groupEnd: typeof nodeConsole.groupEnd = _console?.groupEnd ?? noop; 38 | export const groupCollapsed: typeof nodeConsole.groupCollapsed = 39 | _console?.groupCollapsed ?? noop; 40 | export const profile: typeof nodeConsole.profile = _console?.profile ?? noop; 41 | export const profileEnd: typeof nodeConsole.profileEnd = 42 | _console?.profileEnd ?? noop; 43 | export const time: typeof nodeConsole.time = _console?.time ?? noop; 44 | export const timeEnd: typeof nodeConsole.timeEnd = _console?.timeEnd ?? noop; 45 | export const timeLog: typeof nodeConsole.timeLog = _console?.timeLog ?? noop; 46 | export const timeStamp: typeof nodeConsole.timeStamp = 47 | _console?.timeStamp ?? noop; 48 | 49 | export const Console: typeof nodeConsole.Console = 50 | _console?.Console ?? /*@__PURE__*/ notImplementedClass("console.Console"); 51 | 52 | export const _times = /*@__PURE__*/ new Map(); 53 | 54 | export function context() { 55 | // TODO: Should be Console with all the methods 56 | return _console; 57 | } 58 | 59 | export const _stdoutErrorHandler = noop; 60 | 61 | export const _stderrErrorHandler = noop; 62 | 63 | export default { 64 | // @ts-expect-error 65 | _times, 66 | _ignoreErrors, 67 | _stdoutErrorHandler, 68 | _stderrErrorHandler, 69 | _stdout, 70 | _stderr, 71 | assert, 72 | clear, 73 | Console, 74 | count, 75 | countReset, 76 | debug, 77 | dir, 78 | dirxml, 79 | error, 80 | context, 81 | createTask, 82 | group, 83 | groupEnd, 84 | groupCollapsed, 85 | info, 86 | log, 87 | profile, 88 | profileEnd, 89 | table, 90 | time, 91 | timeEnd, 92 | timeLog, 93 | timeStamp, 94 | trace, 95 | warn, 96 | } satisfies typeof nodeConsole; 97 | -------------------------------------------------------------------------------- /src/runtime/node/stream/web.ts: -------------------------------------------------------------------------------- 1 | import type nodeStreamWeb from "node:stream/web"; 2 | import { notImplemented } from "../../_internal/utils.ts"; 3 | 4 | export const ReadableStream = 5 | globalThis.ReadableStream || 6 | /*@__PURE__*/ notImplemented("stream.web.ReadableStream"); 7 | export const ReadableStreamDefaultReader = 8 | globalThis.ReadableStreamDefaultReader || 9 | /*@__PURE__*/ notImplemented("stream.web.ReadableStreamDefaultReader"); 10 | // @ts-ignore 11 | export const ReadableStreamBYOBReader = 12 | globalThis.ReadableStreamBYOBReader || 13 | /*@__PURE__*/ notImplemented("stream.web.ReadableStreamBYOBReader"); 14 | // @ts-ignore 15 | export const ReadableStreamBYOBRequest = 16 | globalThis.ReadableStreamBYOBRequest || 17 | /*@__PURE__*/ notImplemented("stream.web.ReadableStreamBYOBRequest"); 18 | // @ts-ignore 19 | export const ReadableByteStreamController = 20 | globalThis.ReadableByteStreamController || 21 | /*@__PURE__*/ notImplemented("stream.web.ReadableByteStreamController"); 22 | export const ReadableStreamDefaultController = 23 | globalThis.ReadableStreamDefaultController || 24 | /*@__PURE__*/ notImplemented("stream.web.ReadableStreamDefaultController"); 25 | export const TransformStream = 26 | globalThis.TransformStream || 27 | /*@__PURE__*/ notImplemented("stream.web.TransformStream"); 28 | export const TransformStreamDefaultController = 29 | globalThis.TransformStreamDefaultController || 30 | /*@__PURE__*/ notImplemented("stream.web.TransformStreamDefaultController"); 31 | export const WritableStream = 32 | globalThis.WritableStream || 33 | /*@__PURE__*/ notImplemented("stream.web.WritableStream"); 34 | export const WritableStreamDefaultWriter = 35 | globalThis.WritableStreamDefaultWriter || 36 | /*@__PURE__*/ notImplemented("stream.web.WritableStreamDefaultWriter"); 37 | export const WritableStreamDefaultController = 38 | globalThis.WritableStreamDefaultController || 39 | /*@__PURE__*/ notImplemented("stream.web.WritableStreamDefaultController"); 40 | export const ByteLengthQueuingStrategy = 41 | globalThis.ByteLengthQueuingStrategy || 42 | /*@__PURE__*/ notImplemented("stream.web.ByteLengthQueuingStrategy"); 43 | export const CountQueuingStrategy = 44 | globalThis.CountQueuingStrategy || 45 | /*@__PURE__*/ notImplemented("stream.web.CountQueuingStrategy"); 46 | export const TextEncoderStream = 47 | globalThis.TextEncoderStream || 48 | /*@__PURE__*/ notImplemented("stream.web.TextEncoderStream"); 49 | export const TextDecoderStream = 50 | globalThis.TextDecoderStream || 51 | /*@__PURE__*/ notImplemented("stream.web.TextDecoderStream"); 52 | export const DecompressionStream = 53 | globalThis.DecompressionStream || 54 | /*@__PURE__*/ notImplemented("stream.web.DecompressionStream"); 55 | export const CompressionStream = 56 | globalThis.DecompressionStream || 57 | /*@__PURE__*/ notImplemented("stream.web.CompressionStream"); 58 | 59 | // @ts-ignore 60 | export default { 61 | ReadableStream, 62 | ReadableStreamDefaultReader, 63 | ReadableStreamBYOBReader, 64 | ReadableStreamBYOBRequest, 65 | ReadableByteStreamController, 66 | ReadableStreamDefaultController, 67 | TransformStream, 68 | TransformStreamDefaultController, 69 | WritableStream, 70 | WritableStreamDefaultWriter, 71 | WritableStreamDefaultController, 72 | ByteLengthQueuingStrategy, 73 | CountQueuingStrategy, 74 | TextEncoderStream, 75 | TextDecoderStream, 76 | DecompressionStream, 77 | CompressionStream, 78 | } as /* TODO: use satisfies */ typeof nodeStreamWeb; 79 | -------------------------------------------------------------------------------- /src/runtime/node/perf_hooks.ts: -------------------------------------------------------------------------------- 1 | import type nodePerfHooks from "node:perf_hooks"; 2 | 3 | import { 4 | IntervalHistogram, 5 | RecordableHistogram, 6 | } from "./internal/perf_hooks/histogram.ts"; 7 | 8 | import { 9 | performance, 10 | Performance, 11 | PerformanceEntry, 12 | PerformanceMark, 13 | PerformanceMeasure, 14 | PerformanceObserverEntryList, 15 | PerformanceObserver, 16 | PerformanceResourceTiming, 17 | } from "./internal/perf_hooks/performance.ts"; 18 | 19 | export * from "./internal/perf_hooks/performance.ts"; 20 | 21 | // prettier-ignore 22 | import { 23 | NODE_PERFORMANCE_GC_MAJOR, NODE_PERFORMANCE_GC_MINOR, NODE_PERFORMANCE_GC_INCREMENTAL, NODE_PERFORMANCE_GC_WEAKCB, NODE_PERFORMANCE_GC_FLAGS_NO, NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED, NODE_PERFORMANCE_GC_FLAGS_FORCED, NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING, NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE, NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY, NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE, NODE_PERFORMANCE_ENTRY_TYPE_GC, NODE_PERFORMANCE_ENTRY_TYPE_HTTP, NODE_PERFORMANCE_ENTRY_TYPE_HTTP2, NODE_PERFORMANCE_ENTRY_TYPE_NET, NODE_PERFORMANCE_ENTRY_TYPE_DNS, NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN_TIMESTAMP, NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN, NODE_PERFORMANCE_MILESTONE_ENVIRONMENT, NODE_PERFORMANCE_MILESTONE_NODE_START, NODE_PERFORMANCE_MILESTONE_V8_START, NODE_PERFORMANCE_MILESTONE_LOOP_START, NODE_PERFORMANCE_MILESTONE_LOOP_EXIT, NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE 24 | } from "./internal/perf_hooks/constants.ts"; 25 | 26 | // prettier-ignore 27 | export const constants = { 28 | NODE_PERFORMANCE_GC_MAJOR, NODE_PERFORMANCE_GC_MINOR, NODE_PERFORMANCE_GC_INCREMENTAL, NODE_PERFORMANCE_GC_WEAKCB, NODE_PERFORMANCE_GC_FLAGS_NO, NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED, NODE_PERFORMANCE_GC_FLAGS_FORCED, NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING, NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE, NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY, NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE, NODE_PERFORMANCE_ENTRY_TYPE_GC, NODE_PERFORMANCE_ENTRY_TYPE_HTTP, NODE_PERFORMANCE_ENTRY_TYPE_HTTP2, NODE_PERFORMANCE_ENTRY_TYPE_NET, NODE_PERFORMANCE_ENTRY_TYPE_DNS, NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN_TIMESTAMP, NODE_PERFORMANCE_MILESTONE_TIME_ORIGIN, NODE_PERFORMANCE_MILESTONE_ENVIRONMENT, NODE_PERFORMANCE_MILESTONE_NODE_START, NODE_PERFORMANCE_MILESTONE_V8_START, NODE_PERFORMANCE_MILESTONE_LOOP_START, NODE_PERFORMANCE_MILESTONE_LOOP_EXIT, NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE 29 | } as unknown as typeof nodePerfHooks.constants; 30 | 31 | export const monitorEventLoopDelay: typeof nodePerfHooks.monitorEventLoopDelay = 32 | function (_options) { 33 | return new IntervalHistogram(); 34 | }; 35 | 36 | export const createHistogram: typeof nodePerfHooks.createHistogram = function ( 37 | _options, 38 | ) { 39 | return new RecordableHistogram(); 40 | }; 41 | 42 | export default { 43 | Performance, 44 | PerformanceMark, 45 | // @ts-expect-error TODO: resolve type-mismatch between web and node 46 | PerformanceEntry, 47 | // @ts-expect-error TODO: resolve type-mismatch between web and node 48 | PerformanceMeasure, 49 | // @ts-expect-error TODO: resolve type-mismatch between web and node 50 | PerformanceObserverEntryList, 51 | // @ts-expect-error TODO: resolve type-mismatch between web and node 52 | PerformanceObserver, 53 | // @ts-expect-error TODO: resolve type-mismatch between web and node 54 | PerformanceResourceTiming, 55 | // @ts-expect-error TODO: resolve type-mismatch between web and node 56 | performance, 57 | constants, 58 | createHistogram, 59 | monitorEventLoopDelay, 60 | } satisfies Omit; // @types/node bug: PerformanceNodeTiming is included in the types but doesn't exist in the runtime 61 | -------------------------------------------------------------------------------- /src/preset.ts: -------------------------------------------------------------------------------- 1 | export const nodeCompatAliases = { 2 | _http_agent: "unenv/mock/proxy-cjs", 3 | _http_client: "unenv/mock/proxy-cjs", 4 | _http_common: "unenv/mock/proxy-cjs", 5 | _http_incoming: "unenv/mock/proxy-cjs", 6 | _http_outgoing: "unenv/mock/proxy-cjs", 7 | _http_server: "unenv/mock/proxy-cjs", 8 | _stream_duplex: "unenv/mock/proxy-cjs", 9 | _stream_passthrough: "unenv/mock/proxy-cjs", 10 | _stream_readable: "unenv/mock/proxy-cjs", 11 | _stream_transform: "unenv/mock/proxy-cjs", 12 | _stream_wrap: "unenv/mock/proxy-cjs", 13 | _stream_writable: "unenv/mock/proxy-cjs", 14 | _tls_common: "unenv/mock/proxy-cjs", 15 | _tls_wrap: "unenv/mock/proxy-cjs", 16 | assert: "unenv/node/assert", 17 | "assert/strict": "unenv/node/assert/strict", 18 | async_hooks: "unenv/node/async_hooks", 19 | buffer: "unenv/node/buffer", 20 | child_process: "unenv/node/child_process", 21 | cluster: "unenv/node/cluster", 22 | console: "unenv/node/console", 23 | constants: "unenv/node/constants", 24 | crypto: "unenv/node/crypto", 25 | dgram: "unenv/node/dgram", 26 | diagnostics_channel: "unenv/node/diagnostics_channel", 27 | dns: "unenv/node/dns", 28 | "dns/promises": "unenv/node/dns/promises", 29 | domain: "unenv/node/domain", 30 | events: "unenv/node/events", 31 | fs: "unenv/node/fs", 32 | "fs/promises": "unenv/node/fs/promises", 33 | http: "unenv/node/http", 34 | http2: "unenv/node/http2", 35 | https: "unenv/node/https", 36 | inspector: "unenv/node/inspector", 37 | "inspector/promises": "unenv/node/inspector/promises", 38 | module: "unenv/node/module", 39 | net: "unenv/node/net", 40 | os: "unenv/node/os", 41 | path: "unenv/node/path", 42 | "path/posix": "unenv/node/path", 43 | "path/win32": "unenv/node/path", 44 | perf_hooks: "unenv/node/perf_hooks", 45 | process: "unenv/node/process", 46 | punycode: "unenv/node/punycode", 47 | querystring: "unenv/node/querystring", 48 | readline: "unenv/node/readline", 49 | "readline/promises": "unenv/node/readline/promises", 50 | repl: "unenv/node/repl", 51 | stream: "unenv/node/stream", 52 | "stream/consumers": "unenv/node/stream/consumers", 53 | "stream/promises": "unenv/node/stream/promises", 54 | "stream/web": "unenv/node/stream/web", 55 | string_decoder: "unenv/node/string_decoder", 56 | sys: "unenv/node/util", 57 | timers: "unenv/node/timers", 58 | "timers/promises": "unenv/node/timers/promises", 59 | tls: "unenv/node/tls", 60 | trace_events: "unenv/node/trace_events", 61 | tty: "unenv/node/tty", 62 | url: "unenv/node/url", 63 | util: "unenv/node/util", 64 | "util/types": "unenv/node/util/types", 65 | v8: "unenv/node/v8", 66 | vm: "unenv/node/vm", 67 | wasi: "unenv/node/wasi", 68 | worker_threads: "unenv/node/worker_threads", 69 | zlib: "unenv/node/zlib", 70 | 71 | // These only are available via "node:" protocol 72 | "node:sqlite": "unenv/node/sqlite", 73 | } as const; 74 | 75 | export const nodeCompatInjects = { 76 | process: "unenv/node/process", 77 | global: "unenv/polyfill/globalthis", 78 | Buffer: ["node:buffer", "Buffer"], 79 | clearImmediate: ["node:timers", "clearImmediate"], 80 | setImmediate: ["node:timers", "setImmediate"], 81 | } as const; 82 | 83 | export const npmShims = { 84 | "cross-fetch": "unenv/npm/cross-fetch", 85 | debug: "unenv/npm/debug", 86 | fsevents: "unenv/npm/fsevents", 87 | inherits: "unenv/npm/inherits", 88 | "node-fetch": "unenv/npm/node-fetch", 89 | "node-fetch-native": "unenv/npm/node-fetch", 90 | "whatwg-url": "unenv/npm/whatwg-url/index", 91 | "whatwg-url/webidl2js-wrapper": "unenv/npm/whatwg-url/webidl2js-wrapper", 92 | // polyfills 93 | "cross-fetch/polyfill": "unenv/mock/empty", 94 | "node-fetch-native/polyfill": "unenv/mock/empty", 95 | "isomorphic-fetch": "unenv/mock/empty", 96 | } as const; 97 | -------------------------------------------------------------------------------- /src/runtime/node/internal/fs/promises.ts: -------------------------------------------------------------------------------- 1 | import type nodeFsPromises from "node:fs/promises"; 2 | import { notImplemented } from "../../../_internal/utils.ts"; 3 | 4 | export const access = 5 | /*@__PURE__*/ notImplemented("fs.access"); 6 | export const copyFile = 7 | /*@__PURE__*/ notImplemented("fs.copyFile"); 8 | export const cp = 9 | /*@__PURE__*/ notImplemented("fs.cp"); 10 | export const open = 11 | /*@__PURE__*/ notImplemented("fs.open"); 12 | export const opendir = 13 | /*@__PURE__*/ notImplemented("fs.opendir"); 14 | export const rename = 15 | /*@__PURE__*/ notImplemented("fs.rename"); 16 | export const truncate = 17 | /*@__PURE__*/ notImplemented("fs.truncate"); 18 | export const rm = 19 | /*@__PURE__*/ notImplemented("fs.rm"); 20 | export const rmdir = 21 | /*@__PURE__*/ notImplemented("fs.rmdir"); 22 | export const mkdir = /*@__PURE__*/ notImplemented( 23 | "fs.mkdir", 24 | ) as typeof nodeFsPromises.mkdir; 25 | export const readdir = /*@__PURE__*/ notImplemented< 26 | typeof nodeFsPromises.readdir 27 | >("fs.readdir") as unknown as typeof nodeFsPromises.readdir; 28 | export const readlink = /*@__PURE__*/ notImplemented< 29 | typeof nodeFsPromises.readlink 30 | >("fs.readlink") as typeof nodeFsPromises.readlink; 31 | export const symlink = 32 | /*@__PURE__*/ notImplemented("fs.symlink"); 33 | export const lstat = /*@__PURE__*/ notImplemented( 34 | "fs.lstat", 35 | ) as typeof nodeFsPromises.lstat; 36 | export const stat = /*@__PURE__*/ notImplemented( 37 | "fs.stat", 38 | ) as typeof nodeFsPromises.stat; 39 | export const link = 40 | /*@__PURE__*/ notImplemented("fs.link"); 41 | export const unlink = 42 | /*@__PURE__*/ notImplemented("fs.unlink"); 43 | export const chmod = 44 | /*@__PURE__*/ notImplemented("fs.chmod"); 45 | export const lchmod = 46 | /*@__PURE__*/ notImplemented("fs.lchmod"); 47 | export const lchown = 48 | /*@__PURE__*/ notImplemented("fs.lchown"); 49 | export const chown = 50 | /*@__PURE__*/ notImplemented("fs.chown"); 51 | export const utimes = 52 | /*@__PURE__*/ notImplemented("fs.utimes"); 53 | export const lutimes = 54 | /*@__PURE__*/ notImplemented("fs.lutimes"); 55 | export const realpath = /*@__PURE__*/ notImplemented< 56 | typeof nodeFsPromises.realpath 57 | >("fs.realpath") as typeof nodeFsPromises.realpath; 58 | export const mkdtemp = /*@__PURE__*/ notImplemented< 59 | typeof nodeFsPromises.mkdtemp 60 | >("fs.mkdtemp") as typeof nodeFsPromises.mkdtemp; 61 | export const writeFile = 62 | /*@__PURE__*/ notImplemented("fs.writeFile"); 63 | export const appendFile = 64 | /*@__PURE__*/ notImplemented( 65 | "fs.appendFile", 66 | ); 67 | export const readFile = /*@__PURE__*/ notImplemented< 68 | typeof nodeFsPromises.readFile 69 | >("fs.readFile") as typeof nodeFsPromises.readFile; 70 | export const watch = /*@__PURE__*/ notImplemented( 71 | "fs.watch", 72 | ) as typeof nodeFsPromises.watch; 73 | export const statfs = /*@__PURE__*/ notImplemented< 74 | typeof nodeFsPromises.statfs 75 | >("fs.statfs") as typeof nodeFsPromises.statfs; 76 | export const glob = 77 | /*@__PURE__*/ notImplemented("fs.glob"); 78 | -------------------------------------------------------------------------------- /src/runtime/node/internal/querystring/querystring.ts: -------------------------------------------------------------------------------- 1 | // Source: https://github.com/nodejs/node/blob/v22.7.0/lib/internal/querystring.js 2 | 3 | class ERR_INVALID_URI extends URIError { 4 | code = "ERR_INVALID_URI"; 5 | constructor() { 6 | super("URI malformed"); 7 | } 8 | } 9 | 10 | const hexTable = Array.from({ length: 256 }) as string[]; 11 | for (let i = 0; i < 256; ++i) 12 | hexTable[i] = 13 | "%" + 14 | String.prototype.toUpperCase.call( 15 | (i < 16 ? "0" : "") + Number.prototype.toString.call(i, 16), 16 | ); 17 | 18 | // prettier-ignore 19 | const isHexTable = new Int8Array([ 20 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 21 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 22 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32 - 47 23 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 24 | 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64 - 79 25 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 - 95 26 | 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96 - 111 27 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 112 - 127 28 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 ... 29 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ... 256 36 | ]); 37 | 38 | /** 39 | * @param {string} str 40 | * @param {Int8Array} noEscapeTable 41 | * @param {string[]} hexTable 42 | * @returns {string} 43 | */ 44 | function encodeStr( 45 | str: string, 46 | noEscapeTable: Int8Array, 47 | hexTable: string[], 48 | ): string { 49 | const len = str.length; 50 | if (len === 0) return ""; 51 | 52 | let out = ""; 53 | let lastPos = 0; 54 | let i = 0; 55 | 56 | outer: for (; i < len; i++) { 57 | let c = String.prototype.charCodeAt.call(str, i); 58 | 59 | // ASCII 60 | while (c < 0x80) { 61 | if (noEscapeTable[c] !== 1) { 62 | if (lastPos < i) out += String.prototype.slice.call(str, lastPos, i); 63 | lastPos = i + 1; 64 | out += hexTable[c]; 65 | } 66 | 67 | if (++i === len) break outer; 68 | 69 | c = String.prototype.charCodeAt.call(str, i); 70 | } 71 | 72 | if (lastPos < i) out += String.prototype.slice.call(str, lastPos, i); 73 | 74 | // Multi-byte characters ... 75 | if (c < 0x8_00) { 76 | lastPos = i + 1; 77 | out += hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)]; 78 | continue; 79 | } 80 | if (c < 0xd8_00 || c >= 0xe0_00) { 81 | lastPos = i + 1; 82 | out += 83 | hexTable[0xe0 | (c >> 12)] + 84 | hexTable[0x80 | ((c >> 6) & 0x3f)] + 85 | hexTable[0x80 | (c & 0x3f)]; 86 | continue; 87 | } 88 | // Surrogate pair 89 | ++i; 90 | 91 | // This branch should never happen because all URLSearchParams entries 92 | // should already be converted to USVString. But, included for 93 | // completion's sake anyway. 94 | if (i >= len) throw new ERR_INVALID_URI(); 95 | 96 | const c2 = String.prototype.charCodeAt.call(str, i) & 0x3_ff; 97 | 98 | lastPos = i + 1; 99 | c = 0x1_00_00 + (((c & 0x3_ff) << 10) | c2); 100 | out += 101 | hexTable[0xf0 | (c >> 18)] + 102 | hexTable[0x80 | ((c >> 12) & 0x3f)] + 103 | hexTable[0x80 | ((c >> 6) & 0x3f)] + 104 | hexTable[0x80 | (c & 0x3f)]; 105 | } 106 | if (lastPos === 0) return str; 107 | if (lastPos < len) return out + String.prototype.slice.call(str, lastPos); 108 | return out; 109 | } 110 | 111 | export { encodeStr, hexTable, isHexTable }; 112 | -------------------------------------------------------------------------------- /src/runtime/node/stream.ts: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/stream.html 2 | import type nodeStream from "node:stream"; 3 | import { notImplemented, notImplementedClass } from "../_internal/utils.ts"; 4 | import { Readable } from "./internal/stream/readable.ts"; 5 | import { Writable } from "./internal/stream/writable.ts"; 6 | import { Duplex } from "./internal/stream/duplex.ts"; 7 | import { Transform } from "./internal/stream/transform.ts"; 8 | 9 | import promises from "node:stream/promises"; 10 | 11 | export { promises }; 12 | 13 | export { Readable } from "./internal/stream/readable.ts"; 14 | export { Writable } from "./internal/stream/writable.ts"; 15 | export { Duplex } from "./internal/stream/duplex.ts"; 16 | export { Transform } from "./internal/stream/transform.ts"; 17 | 18 | export const Stream: nodeStream.Stream = 19 | /*@__PURE__*/ notImplementedClass("stream.Stream"); 20 | 21 | export const PassThrough: nodeStream.PassThrough = 22 | /*@__PURE__*/ notImplementedClass("PassThrough"); 23 | 24 | export const pipeline = /*@__PURE__*/ notImplemented< 25 | typeof nodeStream.pipeline 26 | >("stream.pipeline") as any; 27 | 28 | export const finished = /*@__PURE__*/ notImplemented< 29 | typeof nodeStream.finished 30 | >("stream.finished") as any; 31 | 32 | export const addAbortSignal = /*@__PURE__*/ notImplemented< 33 | typeof nodeStream.addAbortSignal 34 | >("stream.addAbortSignal"); 35 | 36 | export const isDisturbed = /*@__PURE__*/ notImplemented("stream.isDisturbed"); 37 | 38 | export const isReadable = /*@__PURE__*/ notImplemented("stream.isReadable"); 39 | 40 | export const compose = /*@__PURE__*/ notImplemented("stream.compose"); 41 | 42 | export const isErrored = /*@__PURE__*/ notImplemented("stream.isErrored"); 43 | 44 | export const destroy = /*@__PURE__*/ notImplemented("stream.destroy"); 45 | 46 | export const _isUint8Array = /*@__PURE__*/ notImplemented( 47 | "stream._isUint8Array", 48 | ); 49 | 50 | export const _uint8ArrayToBuffer = /*@__PURE__*/ notImplemented( 51 | "stream._uint8ArrayToBuffer", 52 | ); 53 | 54 | export const _isArrayBufferView = /*@__PURE__*/ notImplemented( 55 | "stream._isArrayBufferView", 56 | ); 57 | 58 | export const duplexPair = /*@__PURE__*/ notImplemented("stream.duplexPair"); 59 | 60 | export const getDefaultHighWaterMark = /*@__PURE__*/ notImplemented( 61 | "stream.getDefaultHighWaterMark", 62 | ); 63 | 64 | export const isDestroyed = /*@__PURE__*/ notImplemented("stream.isDestroyed"); 65 | 66 | export const isWritable = /*@__PURE__*/ notImplemented("stream.isWritable"); 67 | 68 | export const setDefaultHighWaterMark = /*@__PURE__*/ notImplemented( 69 | "stream.setDefaultHighWaterMark", 70 | ); 71 | 72 | export default { 73 | Readable: Readable as unknown as typeof nodeStream.Readable, 74 | Writable: Writable as unknown as typeof nodeStream.Writable, 75 | Duplex: Duplex as unknown as typeof nodeStream.Duplex, 76 | Transform: Transform as unknown as typeof nodeStream.Transform, 77 | Stream: Stream as unknown as typeof nodeStream.Stream, 78 | PassThrough: PassThrough as unknown as typeof nodeStream.PassThrough, 79 | pipeline, 80 | finished, 81 | addAbortSignal, 82 | promises, 83 | isDisturbed, 84 | isReadable, 85 | compose, 86 | _uint8ArrayToBuffer, 87 | isErrored, 88 | destroy, 89 | _isUint8Array, 90 | _isArrayBufferView, 91 | duplexPair, 92 | getDefaultHighWaterMark, 93 | isDestroyed, 94 | isWritable, 95 | setDefaultHighWaterMark, 96 | } as /* TODO: use satisfies */ typeof nodeStream & { 97 | isDisturbed: any; 98 | isReadable: any; 99 | compose: any; 100 | isErrored: any; 101 | destroy: any; 102 | _isUint8Array: any; 103 | _uint8ArrayToBuffer: any; 104 | _isArrayBufferView: any; 105 | duplexPair: any; 106 | getDefaultHighWaterMark: any; 107 | isDestroyed: any; 108 | isWritable: any; 109 | setDefaultHighWaterMark: any; 110 | }; 111 | -------------------------------------------------------------------------------- /src/runtime/node/internal/diagnostics_channel/tracing-channel.ts: -------------------------------------------------------------------------------- 1 | import { createNotImplementedError } from "../../../_internal/utils.ts"; 2 | import type nodeDagnosticsChannel from "node:diagnostics_channel"; 3 | import { Channel } from "./channel.ts"; 4 | 5 | export class TracingChannel< 6 | StoreType = unknown, 7 | ContextType extends object = object, 8 | > implements nodeDagnosticsChannel.TracingChannel 9 | { 10 | readonly __unenv__ = true; 11 | 12 | asyncEnd: Channel = new Channel("asyncEnd"); 13 | asyncStart: Channel = new Channel("asyncStart"); 14 | end: Channel = new Channel("end"); 15 | error: Channel = new Channel("error"); 16 | start: Channel = new Channel("start"); 17 | 18 | constructor( 19 | nameOrChannels: 20 | | string 21 | | nodeDagnosticsChannel.TracingChannelCollection, 22 | ) { 23 | if (typeof nameOrChannels === "string") { 24 | this.asyncEnd = new Channel( 25 | `trace:${nameOrChannels}:asyncEnd`, 26 | ); 27 | this.asyncStart = new Channel( 28 | `trace:${nameOrChannels}:asyncStart`, 29 | ); 30 | this.end = new Channel( 31 | `trace:${nameOrChannels}:end`, 32 | ); 33 | this.error = new Channel( 34 | `trace:${nameOrChannels}:error`, 35 | ); 36 | this.start = new Channel( 37 | `trace:${nameOrChannels}:start`, 38 | ); 39 | } else { 40 | this.asyncStart = nameOrChannels.asyncStart as Channel< 41 | StoreType, 42 | ContextType 43 | >; 44 | this.asyncEnd = nameOrChannels.asyncEnd as Channel< 45 | StoreType, 46 | ContextType 47 | >; 48 | this.end = nameOrChannels.end as Channel; 49 | this.error = nameOrChannels.error as Channel; 50 | this.start = nameOrChannels.start as Channel; 51 | } 52 | } 53 | 54 | subscribe( 55 | handlers: nodeDagnosticsChannel.TracingChannelSubscribers, 56 | ): void { 57 | this.asyncEnd?.subscribe( 58 | handlers.asyncEnd as nodeDagnosticsChannel.ChannelListener, 59 | ); 60 | this.asyncStart?.subscribe( 61 | handlers.asyncStart as nodeDagnosticsChannel.ChannelListener, 62 | ); 63 | this.end?.subscribe(handlers.end as nodeDagnosticsChannel.ChannelListener); 64 | this.error?.subscribe( 65 | handlers.error as nodeDagnosticsChannel.ChannelListener, 66 | ); 67 | this.start?.subscribe( 68 | handlers.start as nodeDagnosticsChannel.ChannelListener, 69 | ); 70 | } 71 | 72 | unsubscribe( 73 | handlers: nodeDagnosticsChannel.TracingChannelSubscribers, 74 | ): void { 75 | this.asyncEnd?.unsubscribe( 76 | handlers.asyncEnd as nodeDagnosticsChannel.ChannelListener, 77 | ); 78 | this.asyncStart?.unsubscribe( 79 | handlers.asyncStart as nodeDagnosticsChannel.ChannelListener, 80 | ); 81 | this.end?.unsubscribe( 82 | handlers.end as nodeDagnosticsChannel.ChannelListener, 83 | ); 84 | this.error?.unsubscribe( 85 | handlers.error as nodeDagnosticsChannel.ChannelListener, 86 | ); 87 | this.start?.unsubscribe( 88 | handlers.start as nodeDagnosticsChannel.ChannelListener, 89 | ); 90 | } 91 | 92 | traceSync() { 93 | throw createNotImplementedError("TracingChannel.traceSync"); 94 | } 95 | 96 | tracePromise() { 97 | throw createNotImplementedError("TracingChannel.tracePromise"); 98 | } 99 | 100 | traceCallback() { 101 | throw createNotImplementedError("TracingChannel.traceCallback"); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/runtime/node/internal/async_hooks/async-hook.ts: -------------------------------------------------------------------------------- 1 | import type nodeAsyncHooks from "node:async_hooks"; 2 | 3 | // https://nodejs.org/api/async_hooks.html 4 | 5 | type NodeAsyncHook = ReturnType; 6 | 7 | const kInit = /*@__PURE__*/ Symbol("init"); 8 | const kBefore = /*@__PURE__*/ Symbol("before"); 9 | const kAfter = /*@__PURE__*/ Symbol("after"); 10 | const kDestroy = /*@__PURE__*/ Symbol("destroy"); 11 | const kPromiseResolve = /*@__PURE__*/ Symbol("promiseResolve"); 12 | 13 | class _AsyncHook implements NodeAsyncHook { 14 | readonly __unenv__ = true; 15 | 16 | _enabled: boolean = false; 17 | _callbacks: nodeAsyncHooks.HookCallbacks = {}; 18 | 19 | constructor(callbacks: nodeAsyncHooks.HookCallbacks = {}) { 20 | this._callbacks = callbacks; 21 | } 22 | 23 | enable() { 24 | this._enabled = true; 25 | return this; 26 | } 27 | 28 | disable() { 29 | this._enabled = false; 30 | return this; 31 | } 32 | 33 | get [kInit]() { 34 | return this._callbacks.init; 35 | } 36 | 37 | get [kBefore]() { 38 | return this._callbacks.before; 39 | } 40 | 41 | get [kAfter]() { 42 | return this._callbacks.after; 43 | } 44 | 45 | get [kDestroy]() { 46 | return this._callbacks.destroy; 47 | } 48 | 49 | get [kPromiseResolve]() { 50 | return this._callbacks.promiseResolve; 51 | } 52 | } 53 | 54 | export const createHook: typeof nodeAsyncHooks.createHook = function createHook( 55 | callbacks, 56 | ) { 57 | const asyncHook = new _AsyncHook(callbacks); 58 | return asyncHook; 59 | }; 60 | 61 | export const executionAsyncId: typeof nodeAsyncHooks.executionAsyncId = 62 | function executionAsyncId() { 63 | return 0; 64 | }; 65 | 66 | export const executionAsyncResource: typeof nodeAsyncHooks.executionAsyncResource = 67 | function () { 68 | return Object.create(null); 69 | }; 70 | 71 | export const triggerAsyncId: typeof nodeAsyncHooks.triggerAsyncId = 72 | function () { 73 | return 0; 74 | }; 75 | 76 | // @ts-expect-error @types/node is missing this one - this is a bug in typings 77 | export const asyncWrapProviders: typeof nodeAsyncHooks.asyncWrapProviders = 78 | Object.assign(Object.create(null), { 79 | NONE: 0, 80 | DIRHANDLE: 1, 81 | DNSCHANNEL: 2, 82 | ELDHISTOGRAM: 3, 83 | FILEHANDLE: 4, 84 | FILEHANDLECLOSEREQ: 5, 85 | BLOBREADER: 6, 86 | FSEVENTWRAP: 7, 87 | FSREQCALLBACK: 8, 88 | FSREQPROMISE: 9, 89 | GETADDRINFOREQWRAP: 10, 90 | GETNAMEINFOREQWRAP: 11, 91 | HEAPSNAPSHOT: 12, 92 | HTTP2SESSION: 13, 93 | HTTP2STREAM: 14, 94 | HTTP2PING: 15, 95 | HTTP2SETTINGS: 16, 96 | HTTPINCOMINGMESSAGE: 17, 97 | HTTPCLIENTREQUEST: 18, 98 | JSSTREAM: 19, 99 | JSUDPWRAP: 20, 100 | MESSAGEPORT: 21, 101 | PIPECONNECTWRAP: 22, 102 | PIPESERVERWRAP: 23, 103 | PIPEWRAP: 24, 104 | PROCESSWRAP: 25, 105 | PROMISE: 26, 106 | QUERYWRAP: 27, 107 | QUIC_ENDPOINT: 28, 108 | QUIC_LOGSTREAM: 29, 109 | QUIC_PACKET: 30, 110 | QUIC_SESSION: 31, 111 | QUIC_STREAM: 32, 112 | QUIC_UDP: 33, 113 | SHUTDOWNWRAP: 34, 114 | SIGNALWRAP: 35, 115 | STATWATCHER: 36, 116 | STREAMPIPE: 37, 117 | TCPCONNECTWRAP: 38, 118 | TCPSERVERWRAP: 39, 119 | TCPWRAP: 40, 120 | TTYWRAP: 41, 121 | UDPSENDWRAP: 42, 122 | UDPWRAP: 43, 123 | SIGINTWATCHDOG: 44, 124 | WORKER: 45, 125 | WORKERHEAPSNAPSHOT: 46, 126 | WRITEWRAP: 47, 127 | ZLIB: 48, 128 | CHECKPRIMEREQUEST: 49, 129 | PBKDF2REQUEST: 50, 130 | KEYPAIRGENREQUEST: 51, 131 | KEYGENREQUEST: 52, 132 | KEYEXPORTREQUEST: 53, 133 | CIPHERREQUEST: 54, 134 | DERIVEBITSREQUEST: 55, 135 | HASHREQUEST: 56, 136 | RANDOMBYTESREQUEST: 57, 137 | RANDOMPRIMEREQUEST: 58, 138 | SCRYPTREQUEST: 59, 139 | SIGNREQUEST: 60, 140 | TLSWRAP: 61, 141 | VERIFYREQUEST: 62, 142 | }); 143 | --------------------------------------------------------------------------------