summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/internal
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-02-14 17:38:45 +0100
committerGitHub <noreply@github.com>2023-02-14 17:38:45 +0100
commitd47147fb6ad229b1c039aff9d0959b6e281f4df5 (patch)
tree6e9e790f2b9bc71b5f0c9c7e64b95cae31579d58 /ext/node/polyfills/internal
parent1d00bbe47e2ca14e2d2151518e02b2324461a065 (diff)
feat(ext/node): embed std/node into the snapshot (#17724)
This commit moves "deno_std/node" in "ext/node" crate. The code is transpiled and snapshotted during the build process. During the first pass a minimal amount of work was done to create the snapshot, a lot of code in "ext/node" depends on presence of "Deno" global. This code will be gradually fixed in the follow up PRs to migrate it to import relevant APIs from "internal:" modules. Currently the code from snapshot is not used in any way, and all Node/npm compatibility still uses code from "https://deno.land/std/node" (or from the location specified by "DENO_NODE_COMPAT_URL"). This will also be handled in a follow up PRs. --------- Co-authored-by: crowlkats <crowlkats@toaxl.com> Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
Diffstat (limited to 'ext/node/polyfills/internal')
-rw-r--r--ext/node/polyfills/internal/assert.mjs16
-rw-r--r--ext/node/polyfills/internal/async_hooks.ts420
-rw-r--r--ext/node/polyfills/internal/blob.mjs7
-rw-r--r--ext/node/polyfills/internal/buffer.d.ts2074
-rw-r--r--ext/node/polyfills/internal/buffer.mjs2607
-rw-r--r--ext/node/polyfills/internal/child_process.ts1026
-rw-r--r--ext/node/polyfills/internal/cli_table.ts85
-rw-r--r--ext/node/polyfills/internal/console/constructor.mjs677
-rw-r--r--ext/node/polyfills/internal/constants.ts105
-rw-r--r--ext/node/polyfills/internal/crypto/_hex.ts19
-rw-r--r--ext/node/polyfills/internal/crypto/_keys.ts16
-rw-r--r--ext/node/polyfills/internal/crypto/_randomBytes.ts70
-rw-r--r--ext/node/polyfills/internal/crypto/_randomFill.ts84
-rw-r--r--ext/node/polyfills/internal/crypto/_randomInt.ts60
-rw-r--r--ext/node/polyfills/internal/crypto/certificate.ts23
-rw-r--r--ext/node/polyfills/internal/crypto/cipher.ts292
-rw-r--r--ext/node/polyfills/internal/crypto/constants.ts5
-rw-r--r--ext/node/polyfills/internal/crypto/diffiehellman.ts306
-rw-r--r--ext/node/polyfills/internal/crypto/hash.ts230
-rw-r--r--ext/node/polyfills/internal/crypto/hkdf.ts130
-rw-r--r--ext/node/polyfills/internal/crypto/keygen.ts682
-rw-r--r--ext/node/polyfills/internal/crypto/keys.ts294
-rw-r--r--ext/node/polyfills/internal/crypto/pbkdf2.ts183
-rw-r--r--ext/node/polyfills/internal/crypto/random.ts140
-rw-r--r--ext/node/polyfills/internal/crypto/scrypt.ts278
-rw-r--r--ext/node/polyfills/internal/crypto/sig.ts148
-rw-r--r--ext/node/polyfills/internal/crypto/types.ts46
-rw-r--r--ext/node/polyfills/internal/crypto/util.ts129
-rw-r--r--ext/node/polyfills/internal/crypto/x509.ts186
-rw-r--r--ext/node/polyfills/internal/dgram.ts129
-rw-r--r--ext/node/polyfills/internal/dns/promises.ts511
-rw-r--r--ext/node/polyfills/internal/dns/utils.ts456
-rw-r--r--ext/node/polyfills/internal/dtrace.ts41
-rw-r--r--ext/node/polyfills/internal/error_codes.ts7
-rw-r--r--ext/node/polyfills/internal/errors.ts2864
-rw-r--r--ext/node/polyfills/internal/event_target.mjs1111
-rw-r--r--ext/node/polyfills/internal/fixed_queue.ts123
-rw-r--r--ext/node/polyfills/internal/freelist.ts30
-rw-r--r--ext/node/polyfills/internal/fs/streams.d.ts326
-rw-r--r--ext/node/polyfills/internal/fs/streams.mjs494
-rw-r--r--ext/node/polyfills/internal/fs/utils.mjs1045
-rw-r--r--ext/node/polyfills/internal/hide_stack_frames.ts16
-rw-r--r--ext/node/polyfills/internal/http.ts38
-rw-r--r--ext/node/polyfills/internal/idna.ts461
-rw-r--r--ext/node/polyfills/internal/net.ts95
-rw-r--r--ext/node/polyfills/internal/normalize_encoding.mjs72
-rw-r--r--ext/node/polyfills/internal/options.ts45
-rw-r--r--ext/node/polyfills/internal/primordials.mjs30
-rw-r--r--ext/node/polyfills/internal/process/per_thread.mjs272
-rw-r--r--ext/node/polyfills/internal/querystring.ts92
-rw-r--r--ext/node/polyfills/internal/readline/callbacks.mjs137
-rw-r--r--ext/node/polyfills/internal/readline/emitKeypressEvents.mjs106
-rw-r--r--ext/node/polyfills/internal/readline/interface.mjs1223
-rw-r--r--ext/node/polyfills/internal/readline/promises.mjs139
-rw-r--r--ext/node/polyfills/internal/readline/symbols.mjs34
-rw-r--r--ext/node/polyfills/internal/readline/utils.mjs580
-rw-r--r--ext/node/polyfills/internal/stream_base_commons.ts355
-rw-r--r--ext/node/polyfills/internal/streams/add-abort-signal.mjs48
-rw-r--r--ext/node/polyfills/internal/streams/buffer_list.mjs188
-rw-r--r--ext/node/polyfills/internal/streams/destroy.mjs320
-rw-r--r--ext/node/polyfills/internal/streams/duplex.mjs9
-rw-r--r--ext/node/polyfills/internal/streams/end-of-stream.mjs229
-rw-r--r--ext/node/polyfills/internal/streams/lazy_transform.mjs53
-rw-r--r--ext/node/polyfills/internal/streams/legacy.mjs113
-rw-r--r--ext/node/polyfills/internal/streams/passthrough.mjs7
-rw-r--r--ext/node/polyfills/internal/streams/readable.mjs9
-rw-r--r--ext/node/polyfills/internal/streams/state.mjs10
-rw-r--r--ext/node/polyfills/internal/streams/transform.mjs7
-rw-r--r--ext/node/polyfills/internal/streams/utils.mjs242
-rw-r--r--ext/node/polyfills/internal/streams/writable.mjs9
-rw-r--r--ext/node/polyfills/internal/test/binding.ts16
-rw-r--r--ext/node/polyfills/internal/timers.mjs125
-rw-r--r--ext/node/polyfills/internal/url.ts49
-rw-r--r--ext/node/polyfills/internal/util.mjs141
-rw-r--r--ext/node/polyfills/internal/util/comparisons.ts681
-rw-r--r--ext/node/polyfills/internal/util/debuglog.ts121
-rw-r--r--ext/node/polyfills/internal/util/inspect.mjs2237
-rw-r--r--ext/node/polyfills/internal/util/types.ts143
-rw-r--r--ext/node/polyfills/internal/validators.mjs317
79 files changed, 26244 insertions, 0 deletions
diff --git a/ext/node/polyfills/internal/assert.mjs b/ext/node/polyfills/internal/assert.mjs
new file mode 100644
index 000000000..fcdb32a05
--- /dev/null
+++ b/ext/node/polyfills/internal/assert.mjs
@@ -0,0 +1,16 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { ERR_INTERNAL_ASSERTION } from "internal:deno_node/polyfills/internal/errors.ts";
+
+function assert(value, message) {
+ if (!value) {
+ throw new ERR_INTERNAL_ASSERTION(message);
+ }
+}
+
+function fail(message) {
+ throw new ERR_INTERNAL_ASSERTION(message);
+}
+
+assert.fail = fail;
+
+export default assert;
diff --git a/ext/node/polyfills/internal/async_hooks.ts b/ext/node/polyfills/internal/async_hooks.ts
new file mode 100644
index 000000000..8bf513e46
--- /dev/null
+++ b/ext/node/polyfills/internal/async_hooks.ts
@@ -0,0 +1,420 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+// deno-lint-ignore camelcase
+import * as async_wrap from "internal:deno_node/polyfills/internal_binding/async_wrap.ts";
+import { ERR_ASYNC_CALLBACK } from "internal:deno_node/polyfills/internal/errors.ts";
+export {
+ asyncIdSymbol,
+ ownerSymbol,
+} from "internal:deno_node/polyfills/internal_binding/symbols.ts";
+
+interface ActiveHooks {
+ array: AsyncHook[];
+ // deno-lint-ignore camelcase
+ call_depth: number;
+ // deno-lint-ignore camelcase
+ tmp_array: AsyncHook[] | null;
+ // deno-lint-ignore camelcase
+ tmp_fields: number[] | null;
+}
+
+// Properties in active_hooks are used to keep track of the set of hooks being
+// executed in case another hook is enabled/disabled. The new set of hooks is
+// then restored once the active set of hooks is finished executing.
+// deno-lint-ignore camelcase
+const active_hooks: ActiveHooks = {
+ // Array of all AsyncHooks that will be iterated whenever an async event
+ // fires. Using var instead of (preferably const) in order to assign
+ // active_hooks.tmp_array if a hook is enabled/disabled during hook
+ // execution.
+ array: [],
+ // Use a counter to track nested calls of async hook callbacks and make sure
+ // the active_hooks.array isn't altered mid execution.
+ // deno-lint-ignore camelcase
+ call_depth: 0,
+ // Use to temporarily store and updated active_hooks.array if the user
+ // enables or disables a hook while hooks are being processed. If a hook is
+ // enabled() or disabled() during hook execution then the current set of
+ // active hooks is duplicated and set equal to active_hooks.tmp_array. Any
+ // subsequent changes are on the duplicated array. When all hooks have
+ // completed executing active_hooks.tmp_array is assigned to
+ // active_hooks.array.
+ // deno-lint-ignore camelcase
+ tmp_array: null,
+ // Keep track of the field counts held in active_hooks.tmp_array. Because the
+ // async_hook_fields can't be reassigned, store each uint32 in an array that
+ // is written back to async_hook_fields when active_hooks.array is restored.
+ // deno-lint-ignore camelcase
+ tmp_fields: null,
+};
+
+export const registerDestroyHook = async_wrap.registerDestroyHook;
+const {
+ // deno-lint-ignore camelcase
+ async_hook_fields,
+ // deno-lint-ignore camelcase
+ asyncIdFields: async_id_fields,
+ newAsyncId,
+ constants,
+} = async_wrap;
+export { newAsyncId };
+const {
+ kInit,
+ kBefore,
+ kAfter,
+ kDestroy,
+ kPromiseResolve,
+ kTotals,
+ kCheck,
+ kDefaultTriggerAsyncId,
+ kStackLength,
+} = constants;
+
+// deno-lint-ignore camelcase
+const resource_symbol = Symbol("resource");
+// deno-lint-ignore camelcase
+export const async_id_symbol = Symbol("trigger_async_id");
+// deno-lint-ignore camelcase
+export const trigger_async_id_symbol = Symbol("trigger_async_id");
+// deno-lint-ignore camelcase
+export const init_symbol = Symbol("init");
+// deno-lint-ignore camelcase
+export const before_symbol = Symbol("before");
+// deno-lint-ignore camelcase
+export const after_symbol = Symbol("after");
+// deno-lint-ignore camelcase
+export const destroy_symbol = Symbol("destroy");
+// deno-lint-ignore camelcase
+export const promise_resolve_symbol = Symbol("promiseResolve");
+
+export const symbols = {
+ // deno-lint-ignore camelcase
+ async_id_symbol,
+ // deno-lint-ignore camelcase
+ trigger_async_id_symbol,
+ // deno-lint-ignore camelcase
+ init_symbol,
+ // deno-lint-ignore camelcase
+ before_symbol,
+ // deno-lint-ignore camelcase
+ after_symbol,
+ // deno-lint-ignore camelcase
+ destroy_symbol,
+ // deno-lint-ignore camelcase
+ promise_resolve_symbol,
+};
+
+// deno-lint-ignore no-explicit-any
+function lookupPublicResource(resource: any) {
+ if (typeof resource !== "object" || resource === null) return resource;
+ // TODO(addaleax): Merge this with owner_symbol and use it across all
+ // AsyncWrap instances.
+ const publicResource = resource[resource_symbol];
+ if (publicResource !== undefined) {
+ return publicResource;
+ }
+ return resource;
+}
+
+// Used by C++ to call all init() callbacks. Because some state can be setup
+// from C++ there's no need to perform all the same operations as in
+// emitInitScript.
+function emitInitNative(
+ asyncId: number,
+ // deno-lint-ignore no-explicit-any
+ type: any,
+ triggerAsyncId: number,
+ // deno-lint-ignore no-explicit-any
+ resource: any,
+) {
+ active_hooks.call_depth += 1;
+ resource = lookupPublicResource(resource);
+ // Use a single try/catch for all hooks to avoid setting up one per iteration.
+ try {
+ for (let i = 0; i < active_hooks.array.length; i++) {
+ if (typeof active_hooks.array[i][init_symbol] === "function") {
+ active_hooks.array[i][init_symbol](
+ asyncId,
+ type,
+ triggerAsyncId,
+ resource,
+ );
+ }
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ active_hooks.call_depth -= 1;
+ }
+
+ // Hooks can only be restored if there have been no recursive hook calls.
+ // Also the active hooks do not need to be restored if enable()/disable()
+ // weren't called during hook execution, in which case active_hooks.tmp_array
+ // will be null.
+ if (active_hooks.call_depth === 0 && active_hooks.tmp_array !== null) {
+ restoreActiveHooks();
+ }
+}
+
+function getHookArrays(): [AsyncHook[], number[] | Uint32Array] {
+ if (active_hooks.call_depth === 0) {
+ return [active_hooks.array, async_hook_fields];
+ }
+ // If this hook is being enabled while in the middle of processing the array
+ // of currently active hooks then duplicate the current set of active hooks
+ // and store this there. This shouldn't fire until the next time hooks are
+ // processed.
+ if (active_hooks.tmp_array === null) {
+ storeActiveHooks();
+ }
+ return [active_hooks.tmp_array!, active_hooks.tmp_fields!];
+}
+
+function storeActiveHooks() {
+ active_hooks.tmp_array = active_hooks.array.slice();
+ // Don't want to make the assumption that kInit to kDestroy are indexes 0 to
+ // 4. So do this the long way.
+ active_hooks.tmp_fields = [];
+ copyHooks(active_hooks.tmp_fields, async_hook_fields);
+}
+
+function copyHooks(
+ destination: number[] | Uint32Array,
+ source: number[] | Uint32Array,
+) {
+ destination[kInit] = source[kInit];
+ destination[kBefore] = source[kBefore];
+ destination[kAfter] = source[kAfter];
+ destination[kDestroy] = source[kDestroy];
+ destination[kPromiseResolve] = source[kPromiseResolve];
+}
+
+// Then restore the correct hooks array in case any hooks were added/removed
+// during hook callback execution.
+function restoreActiveHooks() {
+ active_hooks.array = active_hooks.tmp_array!;
+ copyHooks(async_hook_fields, active_hooks.tmp_fields!);
+
+ active_hooks.tmp_array = null;
+ active_hooks.tmp_fields = null;
+}
+
+// deno-lint-ignore no-unused-vars
+let wantPromiseHook = false;
+function enableHooks() {
+ async_hook_fields[kCheck] += 1;
+
+ // TODO(kt3k): Uncomment this
+ // setCallbackTrampoline(callbackTrampoline);
+}
+
+function disableHooks() {
+ async_hook_fields[kCheck] -= 1;
+
+ wantPromiseHook = false;
+
+ // TODO(kt3k): Uncomment the below
+ // setCallbackTrampoline();
+
+ // Delay the call to `disablePromiseHook()` because we might currently be
+ // between the `before` and `after` calls of a Promise.
+ // TODO(kt3k): Uncomment the below
+ // enqueueMicrotask(disablePromiseHookIfNecessary);
+}
+
+// Return the triggerAsyncId meant for the constructor calling it. It's up to
+// the user to safeguard this call and make sure it's zero'd out when the
+// constructor is complete.
+export function getDefaultTriggerAsyncId() {
+ const defaultTriggerAsyncId =
+ async_id_fields[async_wrap.UidFields.kDefaultTriggerAsyncId];
+ // If defaultTriggerAsyncId isn't set, use the executionAsyncId
+ if (defaultTriggerAsyncId < 0) {
+ return async_id_fields[async_wrap.UidFields.kExecutionAsyncId];
+ }
+ return defaultTriggerAsyncId;
+}
+
+export function defaultTriggerAsyncIdScope(
+ triggerAsyncId: number | undefined,
+ // deno-lint-ignore no-explicit-any
+ block: (...arg: any[]) => void,
+ ...args: unknown[]
+) {
+ if (triggerAsyncId === undefined) {
+ return block.apply(null, args);
+ }
+ // CHECK(NumberIsSafeInteger(triggerAsyncId))
+ // CHECK(triggerAsyncId > 0)
+ const oldDefaultTriggerAsyncId = async_id_fields[kDefaultTriggerAsyncId];
+ async_id_fields[kDefaultTriggerAsyncId] = triggerAsyncId;
+
+ try {
+ return block.apply(null, args);
+ } finally {
+ async_id_fields[kDefaultTriggerAsyncId] = oldDefaultTriggerAsyncId;
+ }
+}
+
+function hasHooks(key: number) {
+ return async_hook_fields[key] > 0;
+}
+
+export function enabledHooksExist() {
+ return hasHooks(kCheck);
+}
+
+export function initHooksExist() {
+ return hasHooks(kInit);
+}
+
+export function afterHooksExist() {
+ return hasHooks(kAfter);
+}
+
+export function destroyHooksExist() {
+ return hasHooks(kDestroy);
+}
+
+export function promiseResolveHooksExist() {
+ return hasHooks(kPromiseResolve);
+}
+
+function emitInitScript(
+ asyncId: number,
+ // deno-lint-ignore no-explicit-any
+ type: any,
+ triggerAsyncId: number,
+ // deno-lint-ignore no-explicit-any
+ resource: any,
+) {
+ // Short circuit all checks for the common case. Which is that no hooks have
+ // been set. Do this to remove performance impact for embedders (and core).
+ if (!hasHooks(kInit)) {
+ return;
+ }
+
+ if (triggerAsyncId === null) {
+ triggerAsyncId = getDefaultTriggerAsyncId();
+ }
+
+ emitInitNative(asyncId, type, triggerAsyncId, resource);
+}
+export { emitInitScript as emitInit };
+
+export function hasAsyncIdStack() {
+ return hasHooks(kStackLength);
+}
+
+export { constants };
+
+type Fn = (...args: unknown[]) => unknown;
+
+export class AsyncHook {
+ [init_symbol]: Fn;
+ [before_symbol]: Fn;
+ [after_symbol]: Fn;
+ [destroy_symbol]: Fn;
+ [promise_resolve_symbol]: Fn;
+
+ constructor({
+ init,
+ before,
+ after,
+ destroy,
+ promiseResolve,
+ }: {
+ init: Fn;
+ before: Fn;
+ after: Fn;
+ destroy: Fn;
+ promiseResolve: Fn;
+ }) {
+ if (init !== undefined && typeof init !== "function") {
+ throw new ERR_ASYNC_CALLBACK("hook.init");
+ }
+ if (before !== undefined && typeof before !== "function") {
+ throw new ERR_ASYNC_CALLBACK("hook.before");
+ }
+ if (after !== undefined && typeof after !== "function") {
+ throw new ERR_ASYNC_CALLBACK("hook.after");
+ }
+ if (destroy !== undefined && typeof destroy !== "function") {
+ throw new ERR_ASYNC_CALLBACK("hook.destroy");
+ }
+ if (promiseResolve !== undefined && typeof promiseResolve !== "function") {
+ throw new ERR_ASYNC_CALLBACK("hook.promiseResolve");
+ }
+
+ this[init_symbol] = init;
+ this[before_symbol] = before;
+ this[after_symbol] = after;
+ this[destroy_symbol] = destroy;
+ this[promise_resolve_symbol] = promiseResolve;
+ }
+
+ enable() {
+ // The set of callbacks for a hook should be the same regardless of whether
+ // enable()/disable() are run during their execution. The following
+ // references are reassigned to the tmp arrays if a hook is currently being
+ // processed.
+ // deno-lint-ignore camelcase
+ const { 0: hooks_array, 1: hook_fields } = getHookArrays();
+
+ // Each hook is only allowed to be added once.
+ if (hooks_array.includes(this)) {
+ return this;
+ }
+
+ // deno-lint-ignore camelcase
+ const prev_kTotals = hook_fields[kTotals];
+
+ // createHook() has already enforced that the callbacks are all functions,
+ // so here simply increment the count of whether each callbacks exists or
+ // not.
+ hook_fields[kTotals] = hook_fields[kInit] += +!!this[init_symbol];
+ hook_fields[kTotals] += hook_fields[kBefore] += +!!this[before_symbol];
+ hook_fields[kTotals] += hook_fields[kAfter] += +!!this[after_symbol];
+ hook_fields[kTotals] += hook_fields[kDestroy] += +!!this[destroy_symbol];
+ hook_fields[kTotals] += hook_fields[kPromiseResolve] +=
+ +!!this[promise_resolve_symbol];
+ hooks_array.push(this);
+
+ if (prev_kTotals === 0 && hook_fields[kTotals] > 0) {
+ enableHooks();
+ }
+
+ // TODO(kt3k): Uncomment the below
+ // updatePromiseHookMode();
+
+ return this;
+ }
+
+ disable() {
+ // deno-lint-ignore camelcase
+ const { 0: hooks_array, 1: hook_fields } = getHookArrays();
+
+ const index = hooks_array.indexOf(this);
+ if (index === -1) {
+ return this;
+ }
+
+ // deno-lint-ignore camelcase
+ const prev_kTotals = hook_fields[kTotals];
+
+ hook_fields[kTotals] = hook_fields[kInit] -= +!!this[init_symbol];
+ hook_fields[kTotals] += hook_fields[kBefore] -= +!!this[before_symbol];
+ hook_fields[kTotals] += hook_fields[kAfter] -= +!!this[after_symbol];
+ hook_fields[kTotals] += hook_fields[kDestroy] -= +!!this[destroy_symbol];
+ hook_fields[kTotals] += hook_fields[kPromiseResolve] -=
+ +!!this[promise_resolve_symbol];
+ hooks_array.splice(index, 1);
+
+ if (prev_kTotals > 0 && hook_fields[kTotals] === 0) {
+ disableHooks();
+ }
+
+ return this;
+ }
+}
diff --git a/ext/node/polyfills/internal/blob.mjs b/ext/node/polyfills/internal/blob.mjs
new file mode 100644
index 000000000..1b685fad4
--- /dev/null
+++ b/ext/node/polyfills/internal/blob.mjs
@@ -0,0 +1,7 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Node's implementation checks for a symbol they put in the blob prototype
+// Since the implementation of Blob is Deno's, the only option is to check the
+// objects constructor
+export function isBlob(object) {
+ return object instanceof Blob;
+}
diff --git a/ext/node/polyfills/internal/buffer.d.ts b/ext/node/polyfills/internal/buffer.d.ts
new file mode 100644
index 000000000..638674467
--- /dev/null
+++ b/ext/node/polyfills/internal/buffer.d.ts
@@ -0,0 +1,2074 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright DefinitelyTyped contributors. All rights reserved. MIT license.
+
+/**
+ * One of many allowed encodings for the buffer content
+ * - ascii
+ * - base64
+ * - base64url
+ * - binary
+ * - hex
+ * - latin1
+ * - ucs-2
+ * - ucs2
+ * - utf-8
+ * - utf16le
+ * - utf8
+ */
+type Encoding = unknown;
+
+type WithImplicitCoercion<T> =
+ | T
+ | {
+ valueOf(): T;
+ };
+
+/**
+ * `Buffer` objects are used to represent a fixed-length sequence of bytes. Many
+ * Node.js APIs support `Buffer`s.
+ *
+ * The `Buffer` class is a subclass of JavaScript's [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) class and
+ * extends it with methods that cover additional use cases. Node.js APIs accept
+ * plain [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) s wherever `Buffer`s are supported as well.
+ *
+ * While the `Buffer` class is available within the global scope, it is still
+ * recommended to explicitly reference it via an import or require statement.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * // Creates a zero-filled Buffer of length 10.
+ * const buf1 = Buffer.alloc(10);
+ *
+ * // Creates a Buffer of length 10,
+ * // filled with bytes which all have the value `1`.
+ * const buf2 = Buffer.alloc(10, 1);
+ *
+ * // Creates an uninitialized buffer of length 10.
+ * // This is faster than calling Buffer.alloc() but the returned
+ * // Buffer instance might contain old data that needs to be
+ * // overwritten using fill(), write(), or other functions that fill the Buffer's
+ * // contents.
+ * const buf3 = Buffer.allocUnsafe(10);
+ *
+ * // Creates a Buffer containing the bytes [1, 2, 3].
+ * const buf4 = Buffer.from([1, 2, 3]);
+ *
+ * // Creates a Buffer containing the bytes [1, 1, 1, 1] – the entries
+ * // are all truncated using `(value &#x26; 255)` to fit into the range 0–255.
+ * const buf5 = Buffer.from([257, 257.5, -255, '1']);
+ *
+ * // Creates a Buffer containing the UTF-8-encoded bytes for the string 'tést':
+ * // [0x74, 0xc3, 0xa9, 0x73, 0x74] (in hexadecimal notation)
+ * // [116, 195, 169, 115, 116] (in decimal notation)
+ * const buf6 = Buffer.from('tést');
+ *
+ * // Creates a Buffer containing the Latin-1 bytes [0x74, 0xe9, 0x73, 0x74].
+ * const buf7 = Buffer.from('tést', 'latin1');
+ * ```
+ * @see [source](https://github.com/nodejs/node/blob/v16.9.0/lib/buffer.js)
+ */
+export class Buffer extends Uint8Array {
+ /**
+ * Allocates a new buffer containing the given {str}.
+ *
+ * @param str String to store in buffer.
+ * @param encoding encoding to use, optional. Default is 'utf8'
+ * @deprecated since v10.0.0 - Use `Buffer.from(string[, encoding])` instead.
+ */
+ constructor(str: string, encoding?: Encoding);
+ /**
+ * Allocates a new buffer of {size} octets.
+ *
+ * @param size count of octets to allocate.
+ * @deprecated since v10.0.0 - Use `Buffer.alloc()` instead (also see `Buffer.allocUnsafe()`).
+ */
+ constructor(size: number);
+ /**
+ * Allocates a new buffer containing the given {array} of octets.
+ *
+ * @param array The octets to store.
+ * @deprecated since v10.0.0 - Use `Buffer.from(array)` instead.
+ */
+ constructor(array: Uint8Array);
+ /**
+ * Produces a Buffer backed by the same allocated memory as
+ * the given {ArrayBuffer}/{SharedArrayBuffer}.
+ *
+ * @param arrayBuffer The ArrayBuffer with which to share memory.
+ * @deprecated since v10.0.0 - Use `Buffer.from(arrayBuffer[, byteOffset[, length]])` instead.
+ */
+ constructor(arrayBuffer: ArrayBuffer | SharedArrayBuffer);
+ /**
+ * Allocates a new buffer containing the given {array} of octets.
+ *
+ * @param array The octets to store.
+ * @deprecated since v10.0.0 - Use `Buffer.from(array)` instead.
+ */
+ constructor(array: ReadonlyArray<unknown>);
+ /**
+ * Copies the passed {buffer} data onto a new {Buffer} instance.
+ *
+ * @param buffer The buffer to copy.
+ * @deprecated since v10.0.0 - Use `Buffer.from(buffer)` instead.
+ */
+ constructor(buffer: Buffer);
+ /**
+ * Allocates a new `Buffer` using an `array` of bytes in the range `0` – `255`.
+ * Array entries outside that range will be truncated to fit into it.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * // Creates a new Buffer containing the UTF-8 bytes of the string 'buffer'.
+ * const buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);
+ * ```
+ *
+ * A `TypeError` will be thrown if `array` is not an `Array` or another type
+ * appropriate for `Buffer.from()` variants.
+ *
+ * `Buffer.from(array)` and `Buffer.from(string)` may also use the internal`Buffer` pool like `Buffer.allocUnsafe()` does.
+ * @since v5.10.0
+ */
+ static from(
+ arrayBuffer: WithImplicitCoercion<ArrayBuffer | SharedArrayBuffer>,
+ byteOffset?: number,
+ length?: number,
+ ): Buffer;
+ /**
+ * Creates a new Buffer using the passed {data}
+ * @param data data to create a new Buffer
+ */
+ static from(data: Uint8Array | ReadonlyArray<number>): Buffer;
+ static from(
+ data: WithImplicitCoercion<Uint8Array | ReadonlyArray<number> | string>,
+ ): Buffer;
+ /**
+ * Creates a new Buffer containing the given JavaScript string {str}.
+ * If provided, the {encoding} parameter identifies the character encoding.
+ * If not provided, {encoding} defaults to 'utf8'.
+ */
+ static from(
+ str:
+ | WithImplicitCoercion<string>
+ | {
+ [Symbol.toPrimitive](hint: "string"): string;
+ },
+ encoding?: Encoding,
+ ): Buffer;
+ /**
+ * Creates a new Buffer using the passed {data}
+ * @param values to create a new Buffer
+ */
+ static of(...items: number[]): Buffer;
+ /**
+ * Returns `true` if `obj` is a `Buffer`, `false` otherwise.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * Buffer.isBuffer(Buffer.alloc(10)); // true
+ * Buffer.isBuffer(Buffer.from('foo')); // true
+ * Buffer.isBuffer('a string'); // false
+ * Buffer.isBuffer([]); // false
+ * Buffer.isBuffer(new Uint8Array(1024)); // false
+ * ```
+ * @since v0.1.101
+ */
+ static isBuffer(obj: unknown): obj is Buffer;
+ /**
+ * Returns `true` if `encoding` is the name of a supported character encoding,
+ * or `false` otherwise.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * console.log(Buffer.isEncoding('utf8'));
+ * // Prints: true
+ *
+ * console.log(Buffer.isEncoding('hex'));
+ * // Prints: true
+ *
+ * console.log(Buffer.isEncoding('utf/8'));
+ * // Prints: false
+ *
+ * console.log(Buffer.isEncoding(''));
+ * // Prints: false
+ * ```
+ * @since v0.9.1
+ * @param encoding A character encoding name to check.
+ */
+ static isEncoding(encoding: string): boolean;
+ /**
+ * Returns the byte length of a string when encoded using `encoding`.
+ * This is not the same as [`String.prototype.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length), which does not account
+ * for the encoding that is used to convert the string into bytes.
+ *
+ * For `'base64'`, `'base64url'`, and `'hex'`, this function assumes valid input.
+ * For strings that contain non-base64/hex-encoded data (e.g. whitespace), the
+ * return value might be greater than the length of a `Buffer` created from the
+ * string.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const str = '\u00bd + \u00bc = \u00be';
+ *
+ * console.log(`${str}: ${str.length} characters, ` +
+ * `${Buffer.byteLength(str, 'utf8')} bytes`);
+ * // Prints: œ + Œ = Ÿ: 9 characters, 12 bytes
+ * ```
+ *
+ * When `string` is a
+ * `Buffer`/[`DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView)/[`TypedArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/-
+ * Reference/Global_Objects/TypedArray)/[`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)/[`SharedArrayBuffer`](https://develop-
+ * er.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer), the byte length as reported by `.byteLength`is returned.
+ * @since v0.1.90
+ * @param string A value to calculate the length of.
+ * @param [encoding='utf8'] If `string` is a string, this is its encoding.
+ * @return The number of bytes contained within `string`.
+ */
+ static byteLength(
+ string:
+ | string
+ | ArrayBufferView
+ | ArrayBuffer
+ | SharedArrayBuffer,
+ encoding?: Encoding,
+ ): number;
+ /**
+ * Returns a new `Buffer` which is the result of concatenating all the `Buffer`instances in the `list` together.
+ *
+ * If the list has no items, or if the `totalLength` is 0, then a new zero-length`Buffer` is returned.
+ *
+ * If `totalLength` is not provided, it is calculated from the `Buffer` instances
+ * in `list` by adding their lengths.
+ *
+ * If `totalLength` is provided, it is coerced to an unsigned integer. If the
+ * combined length of the `Buffer`s in `list` exceeds `totalLength`, the result is
+ * truncated to `totalLength`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * // Create a single `Buffer` from a list of three `Buffer` instances.
+ *
+ * const buf1 = Buffer.alloc(10);
+ * const buf2 = Buffer.alloc(14);
+ * const buf3 = Buffer.alloc(18);
+ * const totalLength = buf1.length + buf2.length + buf3.length;
+ *
+ * console.log(totalLength);
+ * // Prints: 42
+ *
+ * const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);
+ *
+ * console.log(bufA);
+ * // Prints: <Buffer 00 00 00 00 ...>
+ * console.log(bufA.length);
+ * // Prints: 42
+ * ```
+ *
+ * `Buffer.concat()` may also use the internal `Buffer` pool like `Buffer.allocUnsafe()` does.
+ * @since v0.7.11
+ * @param list List of `Buffer` or {@link Uint8Array} instances to concatenate.
+ * @param totalLength Total length of the `Buffer` instances in `list` when concatenated.
+ */
+ static concat(
+ list: ReadonlyArray<Uint8Array>,
+ totalLength?: number,
+ ): Buffer;
+ /**
+ * Compares `buf1` to `buf2`, typically for the purpose of sorting arrays of`Buffer` instances. This is equivalent to calling `buf1.compare(buf2)`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf1 = Buffer.from('1234');
+ * const buf2 = Buffer.from('0123');
+ * const arr = [buf1, buf2];
+ *
+ * console.log(arr.sort(Buffer.compare));
+ * // Prints: [ <Buffer 30 31 32 33>, <Buffer 31 32 33 34> ]
+ * // (This result is equal to: [buf2, buf1].)
+ * ```
+ * @since v0.11.13
+ * @return Either `-1`, `0`, or `1`, depending on the result of the comparison. See `compare` for details.
+ */
+ static compare(buf1: Uint8Array, buf2: Uint8Array): number;
+ /**
+ * Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the`Buffer` will be zero-filled.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.alloc(5);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 00 00 00 00 00>
+ * ```
+ *
+ * If `size` is larger than {@link constants.MAX_LENGTH} or smaller than 0, `ERR_INVALID_ARG_VALUE` is thrown.
+ *
+ * If `fill` is specified, the allocated `Buffer` will be initialized by calling `buf.fill(fill)`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.alloc(5, 'a');
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 61 61 61 61 61>
+ * ```
+ *
+ * If both `fill` and `encoding` are specified, the allocated `Buffer` will be
+ * initialized by calling `buf.fill(fill, encoding)`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
+ * ```
+ *
+ * Calling `Buffer.alloc()` can be measurably slower than the alternative `Buffer.allocUnsafe()` but ensures that the newly created `Buffer` instance
+ * contents will never contain sensitive data from previous allocations, including
+ * data that might not have been allocated for `Buffer`s.
+ *
+ * A `TypeError` will be thrown if `size` is not a number.
+ * @since v5.10.0
+ * @param size The desired length of the new `Buffer`.
+ * @param [fill=0] A value to pre-fill the new `Buffer` with.
+ * @param [encoding='utf8'] If `fill` is a string, this is its encoding.
+ */
+ static alloc(
+ size: number,
+ fill?: string | Uint8Array | number,
+ encoding?: Encoding,
+ ): Buffer;
+ /**
+ * Allocates a new `Buffer` of `size` bytes. If `size` is larger than {@link constants.MAX_LENGTH} or smaller than 0, `ERR_INVALID_ARG_VALUE` is thrown.
+ *
+ * The underlying memory for `Buffer` instances created in this way is _not_
+ * _initialized_. The contents of the newly created `Buffer` are unknown and_may contain sensitive data_. Use `Buffer.alloc()` instead to initialize`Buffer` instances with zeroes.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(10);
+ *
+ * console.log(buf);
+ * // Prints (contents may vary): <Buffer a0 8b 28 3f 01 00 00 00 50 32>
+ *
+ * buf.fill(0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 00 00 00 00 00 00 00 00 00 00>
+ * ```
+ *
+ * A `TypeError` will be thrown if `size` is not a number.
+ *
+ * The `Buffer` module pre-allocates an internal `Buffer` instance of
+ * size `Buffer.poolSize` that is used as a pool for the fast allocation of new`Buffer` instances created using `Buffer.allocUnsafe()`,`Buffer.from(array)`, `Buffer.concat()`, and the
+ * deprecated`new Buffer(size)` constructor only when `size` is less than or equal
+ * to `Buffer.poolSize >> 1` (floor of `Buffer.poolSize` divided by two).
+ *
+ * Use of this pre-allocated internal memory pool is a key difference between
+ * calling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`.
+ * Specifically, `Buffer.alloc(size, fill)` will _never_ use the internal `Buffer`pool, while `Buffer.allocUnsafe(size).fill(fill)`_will_ use the internal`Buffer` pool if `size` is less
+ * than or equal to half `Buffer.poolSize`. The
+ * difference is subtle but can be important when an application requires the
+ * additional performance that `Buffer.allocUnsafe()` provides.
+ * @since v5.10.0
+ * @param size The desired length of the new `Buffer`.
+ */
+ static allocUnsafe(size: number): Buffer;
+ /**
+ * Allocates a new `Buffer` of `size` bytes. If `size` is larger than {@link constants.MAX_LENGTH} or smaller than 0, `ERR_INVALID_ARG_VALUE` is thrown. A zero-length `Buffer` is created
+ * if `size` is 0.
+ *
+ * The underlying memory for `Buffer` instances created in this way is _not_
+ * _initialized_. The contents of the newly created `Buffer` are unknown and_may contain sensitive data_. Use `buf.fill(0)` to initialize
+ * such `Buffer` instances with zeroes.
+ *
+ * When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances,
+ * allocations under 4 KB are sliced from a single pre-allocated `Buffer`. This
+ * allows applications to avoid the garbage collection overhead of creating many
+ * individually allocated `Buffer` instances. This approach improves both
+ * performance and memory usage by eliminating the need to track and clean up as
+ * many individual `ArrayBuffer` objects.
+ *
+ * However, in the case where a developer may need to retain a small chunk of
+ * memory from a pool for an indeterminate amount of time, it may be appropriate
+ * to create an un-pooled `Buffer` instance using `Buffer.allocUnsafeSlow()` and
+ * then copying out the relevant bits.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * // Need to keep around a few small chunks of memory.
+ * const store = [];
+ *
+ * socket.on('readable', () => {
+ * let data;
+ * while (null !== (data = readable.read())) {
+ * // Allocate for retained data.
+ * const sb = Buffer.allocUnsafeSlow(10);
+ *
+ * // Copy the data into the new allocation.
+ * data.copy(sb, 0, 0, 10);
+ *
+ * store.push(sb);
+ * }
+ * });
+ * ```
+ *
+ * A `TypeError` will be thrown if `size` is not a number.
+ * @since v5.12.0
+ * @param size The desired length of the new `Buffer`.
+ */
+ static allocUnsafeSlow(size: number): Buffer;
+ // /**
+ // * This is the size (in bytes) of pre-allocated internal `Buffer` instances used
+ // * for pooling. This value may be modified.
+ // * @since v0.11.3
+ // */
+ // static poolSize: number;
+
+ /**
+ * Writes `string` to `buf` at `offset` according to the character encoding in`encoding`. The `length` parameter is the number of bytes to write. If `buf` did
+ * not contain enough space to fit the entire string, only part of `string` will be
+ * written. However, partially encoded characters will not be written.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.alloc(256);
+ *
+ * const len = buf.write('\u00bd + \u00bc = \u00be', 0);
+ *
+ * console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);
+ * // Prints: 12 bytes: œ + Œ = Ÿ
+ *
+ * const buffer = Buffer.alloc(10);
+ *
+ * const length = buffer.write('abcd', 8);
+ *
+ * console.log(`${length} bytes: ${buffer.toString('utf8', 8, 10)}`);
+ * // Prints: 2 bytes : ab
+ * ```
+ * @since v0.1.90
+ * @param string String to write to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write `string`.
+ * @param [length=buf.length - offset] Maximum number of bytes to write (written bytes will not exceed `buf.length - offset`).
+ * @param [encoding='utf8'] The character encoding of `string`.
+ * @return Number of bytes written.
+ */
+ write(string: string, encoding?: Encoding): number;
+ write(string: string, offset: number, encoding?: Encoding): number;
+ write(
+ string: string,
+ offset: number,
+ length: number,
+ encoding?: Encoding,
+ ): number;
+ /**
+ * Decodes `buf` to a string according to the specified character encoding in`encoding`. `start` and `end` may be passed to decode only a subset of `buf`.
+ *
+ * If `encoding` is `'utf8'` and a byte sequence in the input is not valid UTF-8,
+ * then each invalid byte is replaced with the replacement character `U+FFFD`.
+ *
+ * The maximum length of a string instance (in UTF-16 code units) is available
+ * as {@link constants.MAX_STRING_LENGTH}.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf1 = Buffer.allocUnsafe(26);
+ *
+ * for (let i = 0; i < 26; i++) {
+ * // 97 is the decimal ASCII value for 'a'.
+ * buf1[i] = i + 97;
+ * }
+ *
+ * console.log(buf1.toString('utf8'));
+ * // Prints: abcdefghijklmnopqrstuvwxyz
+ * console.log(buf1.toString('utf8', 0, 5));
+ * // Prints: abcde
+ *
+ * const buf2 = Buffer.from('tést');
+ *
+ * console.log(buf2.toString('hex'));
+ * // Prints: 74c3a97374
+ * console.log(buf2.toString('utf8', 0, 3));
+ * // Prints: té
+ * console.log(buf2.toString(undefined, 0, 3));
+ * // Prints: té
+ * ```
+ * @since v0.1.90
+ * @param [encoding='utf8'] The character encoding to use.
+ * @param [start=0] The byte offset to start decoding at.
+ * @param [end=buf.length] The byte offset to stop decoding at (not inclusive).
+ */
+ toString(encoding?: Encoding, start?: number, end?: number): string;
+ /**
+ * Returns a JSON representation of `buf`. [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) implicitly calls
+ * this function when stringifying a `Buffer` instance.
+ *
+ * `Buffer.from()` accepts objects in the format returned from this method.
+ * In particular, `Buffer.from(buf.toJSON())` works like `Buffer.from(buf)`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
+ * const json = JSON.stringify(buf);
+ *
+ * console.log(json);
+ * // Prints: {"type":"Buffer","data":[1,2,3,4,5]}
+ *
+ * const copy = JSON.parse(json, (key, value) => {
+ * return value &#x26;&#x26; value.type === 'Buffer' ?
+ * Buffer.from(value) :
+ * value;
+ * });
+ *
+ * console.log(copy);
+ * // Prints: <Buffer 01 02 03 04 05>
+ * ```
+ * @since v0.9.2
+ */
+ toJSON(): {
+ type: "Buffer";
+ data: number[];
+ };
+ /**
+ * Returns `true` if both `buf` and `otherBuffer` have exactly the same bytes,`false` otherwise. Equivalent to `buf.compare(otherBuffer) === 0`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf1 = Buffer.from('ABC');
+ * const buf2 = Buffer.from('414243', 'hex');
+ * const buf3 = Buffer.from('ABCD');
+ *
+ * console.log(buf1.equals(buf2));
+ * // Prints: true
+ * console.log(buf1.equals(buf3));
+ * // Prints: false
+ * ```
+ * @since v0.11.13
+ * @param otherBuffer A `Buffer` or {@link Uint8Array} with which to compare `buf`.
+ */
+ equals(otherBuffer: Uint8Array): boolean;
+ /**
+ * Compares `buf` with `target` and returns a number indicating whether `buf`comes before, after, or is the same as `target` in sort order.
+ * Comparison is based on the actual sequence of bytes in each `Buffer`.
+ *
+ * * `0` is returned if `target` is the same as `buf`
+ * * `1` is returned if `target` should come _before_`buf` when sorted.
+ * * `-1` is returned if `target` should come _after_`buf` when sorted.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf1 = Buffer.from('ABC');
+ * const buf2 = Buffer.from('BCD');
+ * const buf3 = Buffer.from('ABCD');
+ *
+ * console.log(buf1.compare(buf1));
+ * // Prints: 0
+ * console.log(buf1.compare(buf2));
+ * // Prints: -1
+ * console.log(buf1.compare(buf3));
+ * // Prints: -1
+ * console.log(buf2.compare(buf1));
+ * // Prints: 1
+ * console.log(buf2.compare(buf3));
+ * // Prints: 1
+ * console.log([buf1, buf2, buf3].sort(Buffer.compare));
+ * // Prints: [ <Buffer 41 42 43>, <Buffer 41 42 43 44>, <Buffer 42 43 44> ]
+ * // (This result is equal to: [buf1, buf3, buf2].)
+ * ```
+ *
+ * The optional `targetStart`, `targetEnd`, `sourceStart`, and `sourceEnd`arguments can be used to limit the comparison to specific ranges within `target`and `buf` respectively.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf1 = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ * const buf2 = Buffer.from([5, 6, 7, 8, 9, 1, 2, 3, 4]);
+ *
+ * console.log(buf1.compare(buf2, 5, 9, 0, 4));
+ * // Prints: 0
+ * console.log(buf1.compare(buf2, 0, 6, 4));
+ * // Prints: -1
+ * console.log(buf1.compare(buf2, 5, 6, 5));
+ * // Prints: 1
+ * ```
+ *
+ * `ERR_OUT_OF_RANGE` is thrown if `targetStart < 0`, `sourceStart < 0`,`targetEnd > target.byteLength`, or `sourceEnd > source.byteLength`.
+ * @since v0.11.13
+ * @param target A `Buffer` or {@link Uint8Array} with which to compare `buf`.
+ * @param [targetStart=0] The offset within `target` at which to begin comparison.
+ * @param [targetEnd=target.length] The offset within `target` at which to end comparison (not inclusive).
+ * @param [sourceStart=0] The offset within `buf` at which to begin comparison.
+ * @param [sourceEnd=buf.length] The offset within `buf` at which to end comparison (not inclusive).
+ */
+ compare(
+ target: Uint8Array,
+ targetStart?: number,
+ targetEnd?: number,
+ sourceStart?: number,
+ sourceEnd?: number,
+ ): number;
+ /**
+ * Copies data from a region of `buf` to a region in `target`, even if the `target`memory region overlaps with `buf`.
+ *
+ * [`TypedArray.prototype.set()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/set) performs the same operation, and is available
+ * for all TypedArrays, including Node.js `Buffer`s, although it takes
+ * different function arguments.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * // Create two `Buffer` instances.
+ * const buf1 = Buffer.allocUnsafe(26);
+ * const buf2 = Buffer.allocUnsafe(26).fill('!');
+ *
+ * for (let i = 0; i < 26; i++) {
+ * // 97 is the decimal ASCII value for 'a'.
+ * buf1[i] = i + 97;
+ * }
+ *
+ * // Copy `buf1` bytes 16 through 19 into `buf2` starting at byte 8 of `buf2`.
+ * buf1.copy(buf2, 8, 16, 20);
+ * // This is equivalent to:
+ * // buf2.set(buf1.subarray(16, 20), 8);
+ *
+ * console.log(buf2.toString('ascii', 0, 25));
+ * // Prints: !!!!!!!!qrst!!!!!!!!!!!!!
+ * ```
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * // Create a `Buffer` and copy data from one region to an overlapping region
+ * // within the same `Buffer`.
+ *
+ * const buf = Buffer.allocUnsafe(26);
+ *
+ * for (let i = 0; i < 26; i++) {
+ * // 97 is the decimal ASCII value for 'a'.
+ * buf[i] = i + 97;
+ * }
+ *
+ * buf.copy(buf, 0, 4, 10);
+ *
+ * console.log(buf.toString());
+ * // Prints: efghijghijklmnopqrstuvwxyz
+ * ```
+ * @since v0.1.90
+ * @param target A `Buffer` or {@link Uint8Array} to copy into.
+ * @param [targetStart=0] The offset within `target` at which to begin writing.
+ * @param [sourceStart=0] The offset within `buf` from which to begin copying.
+ * @param [sourceEnd=buf.length] The offset within `buf` at which to stop copying (not inclusive).
+ * @return The number of bytes copied.
+ */
+ copy(
+ target: Uint8Array,
+ targetStart?: number,
+ sourceStart?: number,
+ sourceEnd?: number,
+ ): number;
+ /**
+ * Returns a new `Buffer` that references the same memory as the original, but
+ * offset and cropped by the `start` and `end` indices.
+ *
+ * This is the same behavior as `buf.subarray()`.
+ *
+ * This method is not compatible with the `Uint8Array.prototype.slice()`,
+ * which is a superclass of `Buffer`. To copy the slice, use`Uint8Array.prototype.slice()`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from('buffer');
+ *
+ * const copiedBuf = Uint8Array.prototype.slice.call(buf);
+ * copiedBuf[0]++;
+ * console.log(copiedBuf.toString());
+ * // Prints: cuffer
+ *
+ * console.log(buf.toString());
+ * // Prints: buffer
+ * ```
+ * @since v0.3.0
+ * @param [start=0] Where the new `Buffer` will start.
+ * @param [end=buf.length] Where the new `Buffer` will end (not inclusive).
+ */
+ slice(start?: number, end?: number): Buffer;
+ /**
+ * Returns a new `Buffer` that references the same memory as the original, but
+ * offset and cropped by the `start` and `end` indices.
+ *
+ * Specifying `end` greater than `buf.length` will return the same result as
+ * that of `end` equal to `buf.length`.
+ *
+ * This method is inherited from [`TypedArray.prototype.subarray()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray).
+ *
+ * Modifying the new `Buffer` slice will modify the memory in the original `Buffer`because the allocated memory of the two objects overlap.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * // Create a `Buffer` with the ASCII alphabet, take a slice, and modify one byte
+ * // from the original `Buffer`.
+ *
+ * const buf1 = Buffer.allocUnsafe(26);
+ *
+ * for (let i = 0; i < 26; i++) {
+ * // 97 is the decimal ASCII value for 'a'.
+ * buf1[i] = i + 97;
+ * }
+ *
+ * const buf2 = buf1.subarray(0, 3);
+ *
+ * console.log(buf2.toString('ascii', 0, buf2.length));
+ * // Prints: abc
+ *
+ * buf1[0] = 33;
+ *
+ * console.log(buf2.toString('ascii', 0, buf2.length));
+ * // Prints: !bc
+ * ```
+ *
+ * Specifying negative indexes causes the slice to be generated relative to the
+ * end of `buf` rather than the beginning.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from('buffer');
+ *
+ * console.log(buf.subarray(-6, -1).toString());
+ * // Prints: buffe
+ * // (Equivalent to buf.subarray(0, 5).)
+ *
+ * console.log(buf.subarray(-6, -2).toString());
+ * // Prints: buff
+ * // (Equivalent to buf.subarray(0, 4).)
+ *
+ * console.log(buf.subarray(-5, -2).toString());
+ * // Prints: uff
+ * // (Equivalent to buf.subarray(1, 4).)
+ * ```
+ * @since v3.0.0
+ * @param [start=0] Where the new `Buffer` will start.
+ * @param [end=buf.length] Where the new `Buffer` will end (not inclusive).
+ */
+ subarray(start?: number, end?: number): Buffer;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as big-endian.
+ *
+ * `value` is interpreted and written as a two's complement signed integer.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(8);
+ *
+ * buf.writeBigInt64BE(0x0102030405060708n, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 01 02 03 04 05 06 07 08>
+ * ```
+ * @since v12.0.0, v10.20.0
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 8`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeBigInt64BE(value: bigint, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as little-endian.
+ *
+ * `value` is interpreted and written as a two's complement signed integer.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(8);
+ *
+ * buf.writeBigInt64LE(0x0102030405060708n, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 08 07 06 05 04 03 02 01>
+ * ```
+ * @since v12.0.0, v10.20.0
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 8`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeBigInt64LE(value: bigint, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as big-endian.
+ *
+ * This function is also available under the `writeBigUint64BE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(8);
+ *
+ * buf.writeBigUInt64BE(0xdecafafecacefaden, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer de ca fa fe ca ce fa de>
+ * ```
+ * @since v12.0.0, v10.20.0
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 8`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeBigUInt64BE(value: bigint, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as little-endian
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(8);
+ *
+ * buf.writeBigUInt64LE(0xdecafafecacefaden, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer de fa ce ca fe fa ca de>
+ * ```
+ *
+ * This function is also available under the `writeBigUint64LE` alias.
+ * @since v12.0.0, v10.20.0
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 8`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeBigUInt64LE(value: bigint, offset?: number): number;
+ /**
+ * Writes `byteLength` bytes of `value` to `buf` at the specified `offset`as little-endian. Supports up to 48 bits of accuracy. Behavior is undefined
+ * when `value` is anything other than an unsigned integer.
+ *
+ * This function is also available under the `writeUintLE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(6);
+ *
+ * buf.writeUIntLE(0x1234567890ab, 0, 6);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer ab 90 78 56 34 12>
+ * ```
+ * @since v0.5.5
+ * @param value Number to be written to `buf`.
+ * @param offset Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - byteLength`.
+ * @param byteLength Number of bytes to write. Must satisfy `0 < byteLength <= 6`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeUIntLE(value: number, offset: number, byteLength: number): number;
+ /**
+ * Writes `byteLength` bytes of `value` to `buf` at the specified `offset`as big-endian. Supports up to 48 bits of accuracy. Behavior is undefined
+ * when `value` is anything other than an unsigned integer.
+ *
+ * This function is also available under the `writeUintBE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(6);
+ *
+ * buf.writeUIntBE(0x1234567890ab, 0, 6);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 12 34 56 78 90 ab>
+ * ```
+ * @since v0.5.5
+ * @param value Number to be written to `buf`.
+ * @param offset Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - byteLength`.
+ * @param byteLength Number of bytes to write. Must satisfy `0 < byteLength <= 6`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeUIntBE(value: number, offset: number, byteLength: number): number;
+ /**
+ * Writes `byteLength` bytes of `value` to `buf` at the specified `offset`as little-endian. Supports up to 48 bits of accuracy. Behavior is undefined
+ * when `value` is anything other than a signed integer.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(6);
+ *
+ * buf.writeIntLE(0x1234567890ab, 0, 6);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer ab 90 78 56 34 12>
+ * ```
+ * @since v0.11.15
+ * @param value Number to be written to `buf`.
+ * @param offset Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - byteLength`.
+ * @param byteLength Number of bytes to write. Must satisfy `0 < byteLength <= 6`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeIntLE(value: number, offset: number, byteLength: number): number;
+ /**
+ * Writes `byteLength` bytes of `value` to `buf` at the specified `offset`as big-endian. Supports up to 48 bits of accuracy. Behavior is undefined when`value` is anything other than a
+ * signed integer.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(6);
+ *
+ * buf.writeIntBE(0x1234567890ab, 0, 6);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 12 34 56 78 90 ab>
+ * ```
+ * @since v0.11.15
+ * @param value Number to be written to `buf`.
+ * @param offset Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - byteLength`.
+ * @param byteLength Number of bytes to write. Must satisfy `0 < byteLength <= 6`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeIntBE(value: number, offset: number, byteLength: number): number;
+ /**
+ * Reads an unsigned, big-endian 64-bit integer from `buf` at the specified`offset`.
+ *
+ * This function is also available under the `readBigUint64BE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);
+ *
+ * console.log(buf.readBigUInt64BE(0));
+ * // Prints: 4294967295n
+ * ```
+ * @since v12.0.0, v10.20.0
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 8`.
+ */
+ readBigUInt64BE(offset?: number): bigint;
+ /**
+ * Reads an unsigned, little-endian 64-bit integer from `buf` at the specified`offset`.
+ *
+ * This function is also available under the `readBigUint64LE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);
+ *
+ * console.log(buf.readBigUInt64LE(0));
+ * // Prints: 18446744069414584320n
+ * ```
+ * @since v12.0.0, v10.20.0
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 8`.
+ */
+ readBigUInt64LE(offset?: number): bigint;
+ /**
+ * Reads a signed, big-endian 64-bit integer from `buf` at the specified `offset`.
+ *
+ * Integers read from a `Buffer` are interpreted as two's complement signed
+ * values.
+ * @since v12.0.0, v10.20.0
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 8`.
+ */
+ readBigInt64BE(offset?: number): bigint;
+ /**
+ * Reads a signed, little-endian 64-bit integer from `buf` at the specified`offset`.
+ *
+ * Integers read from a `Buffer` are interpreted as two's complement signed
+ * values.
+ * @since v12.0.0, v10.20.0
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 8`.
+ */
+ readBigInt64LE(offset?: number): bigint;
+ /**
+ * Reads `byteLength` number of bytes from `buf` at the specified `offset`and interprets the result as an unsigned, little-endian integer supporting
+ * up to 48 bits of accuracy.
+ *
+ * This function is also available under the `readUintLE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
+ *
+ * console.log(buf.readUIntLE(0, 6).toString(16));
+ * // Prints: ab9078563412
+ * ```
+ * @since v0.11.15
+ * @param offset Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - byteLength`.
+ * @param byteLength Number of bytes to read. Must satisfy `0 < byteLength <= 6`.
+ */
+ readUIntLE(offset: number, byteLength: number): number;
+ /**
+ * Reads `byteLength` number of bytes from `buf` at the specified `offset`and interprets the result as an unsigned big-endian integer supporting
+ * up to 48 bits of accuracy.
+ *
+ * This function is also available under the `readUintBE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
+ *
+ * console.log(buf.readUIntBE(0, 6).toString(16));
+ * // Prints: 1234567890ab
+ * console.log(buf.readUIntBE(1, 6).toString(16));
+ * // Throws ERR_OUT_OF_RANGE.
+ * ```
+ * @since v0.11.15
+ * @param offset Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - byteLength`.
+ * @param byteLength Number of bytes to read. Must satisfy `0 < byteLength <= 6`.
+ */
+ readUIntBE(offset: number, byteLength: number): number;
+ /**
+ * Reads `byteLength` number of bytes from `buf` at the specified `offset`and interprets the result as a little-endian, two's complement signed value
+ * supporting up to 48 bits of accuracy.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
+ *
+ * console.log(buf.readIntLE(0, 6).toString(16));
+ * // Prints: -546f87a9cbee
+ * ```
+ * @since v0.11.15
+ * @param offset Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - byteLength`.
+ * @param byteLength Number of bytes to read. Must satisfy `0 < byteLength <= 6`.
+ */
+ readIntLE(offset: number, byteLength: number): number;
+ /**
+ * Reads `byteLength` number of bytes from `buf` at the specified `offset`and interprets the result as a big-endian, two's complement signed value
+ * supporting up to 48 bits of accuracy.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
+ *
+ * console.log(buf.readIntBE(0, 6).toString(16));
+ * // Prints: 1234567890ab
+ * console.log(buf.readIntBE(1, 6).toString(16));
+ * // Throws ERR_OUT_OF_RANGE.
+ * console.log(buf.readIntBE(1, 0).toString(16));
+ * // Throws ERR_OUT_OF_RANGE.
+ * ```
+ * @since v0.11.15
+ * @param offset Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - byteLength`.
+ * @param byteLength Number of bytes to read. Must satisfy `0 < byteLength <= 6`.
+ */
+ readIntBE(offset: number, byteLength: number): number;
+ /**
+ * Reads an unsigned 8-bit integer from `buf` at the specified `offset`.
+ *
+ * This function is also available under the `readUint8` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([1, -2]);
+ *
+ * console.log(buf.readUInt8(0));
+ * // Prints: 1
+ * console.log(buf.readUInt8(1));
+ * // Prints: 254
+ * console.log(buf.readUInt8(2));
+ * // Throws ERR_OUT_OF_RANGE.
+ * ```
+ * @since v0.5.0
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 1`.
+ */
+ readUInt8(offset?: number): number;
+ /**
+ * Reads an unsigned, little-endian 16-bit integer from `buf` at the specified`offset`.
+ *
+ * This function is also available under the `readUint16LE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x12, 0x34, 0x56]);
+ *
+ * console.log(buf.readUInt16LE(0).toString(16));
+ * // Prints: 3412
+ * console.log(buf.readUInt16LE(1).toString(16));
+ * // Prints: 5634
+ * console.log(buf.readUInt16LE(2).toString(16));
+ * // Throws ERR_OUT_OF_RANGE.
+ * ```
+ * @since v0.5.5
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 2`.
+ */
+ readUInt16LE(offset?: number): number;
+ /**
+ * Reads an unsigned, big-endian 16-bit integer from `buf` at the specified`offset`.
+ *
+ * This function is also available under the `readUint16BE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x12, 0x34, 0x56]);
+ *
+ * console.log(buf.readUInt16BE(0).toString(16));
+ * // Prints: 1234
+ * console.log(buf.readUInt16BE(1).toString(16));
+ * // Prints: 3456
+ * ```
+ * @since v0.5.5
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 2`.
+ */
+ readUInt16BE(offset?: number): number;
+ /**
+ * Reads an unsigned, little-endian 32-bit integer from `buf` at the specified`offset`.
+ *
+ * This function is also available under the `readUint32LE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x12, 0x34, 0x56, 0x78]);
+ *
+ * console.log(buf.readUInt32LE(0).toString(16));
+ * // Prints: 78563412
+ * console.log(buf.readUInt32LE(1).toString(16));
+ * // Throws ERR_OUT_OF_RANGE.
+ * ```
+ * @since v0.5.5
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.
+ */
+ readUInt32LE(offset?: number): number;
+ /**
+ * Reads an unsigned, big-endian 32-bit integer from `buf` at the specified`offset`.
+ *
+ * This function is also available under the `readUint32BE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0x12, 0x34, 0x56, 0x78]);
+ *
+ * console.log(buf.readUInt32BE(0).toString(16));
+ * // Prints: 12345678
+ * ```
+ * @since v0.5.5
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.
+ */
+ readUInt32BE(offset?: number): number;
+ /**
+ * Reads a signed 8-bit integer from `buf` at the specified `offset`.
+ *
+ * Integers read from a `Buffer` are interpreted as two's complement signed values.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([-1, 5]);
+ *
+ * console.log(buf.readInt8(0));
+ * // Prints: -1
+ * console.log(buf.readInt8(1));
+ * // Prints: 5
+ * console.log(buf.readInt8(2));
+ * // Throws ERR_OUT_OF_RANGE.
+ * ```
+ * @since v0.5.0
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 1`.
+ */
+ readInt8(offset?: number): number;
+ /**
+ * Reads a signed, little-endian 16-bit integer from `buf` at the specified`offset`.
+ *
+ * Integers read from a `Buffer` are interpreted as two's complement signed values.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0, 5]);
+ *
+ * console.log(buf.readInt16LE(0));
+ * // Prints: 1280
+ * console.log(buf.readInt16LE(1));
+ * // Throws ERR_OUT_OF_RANGE.
+ * ```
+ * @since v0.5.5
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 2`.
+ */
+ readInt16LE(offset?: number): number;
+ /**
+ * Reads a signed, big-endian 16-bit integer from `buf` at the specified `offset`.
+ *
+ * Integers read from a `Buffer` are interpreted as two's complement signed values.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0, 5]);
+ *
+ * console.log(buf.readInt16BE(0));
+ * // Prints: 5
+ * ```
+ * @since v0.5.5
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 2`.
+ */
+ readInt16BE(offset?: number): number;
+ /**
+ * Reads a signed, little-endian 32-bit integer from `buf` at the specified`offset`.
+ *
+ * Integers read from a `Buffer` are interpreted as two's complement signed values.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0, 0, 0, 5]);
+ *
+ * console.log(buf.readInt32LE(0));
+ * // Prints: 83886080
+ * console.log(buf.readInt32LE(1));
+ * // Throws ERR_OUT_OF_RANGE.
+ * ```
+ * @since v0.5.5
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.
+ */
+ readInt32LE(offset?: number): number;
+ /**
+ * Reads a signed, big-endian 32-bit integer from `buf` at the specified `offset`.
+ *
+ * Integers read from a `Buffer` are interpreted as two's complement signed values.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([0, 0, 0, 5]);
+ *
+ * console.log(buf.readInt32BE(0));
+ * // Prints: 5
+ * ```
+ * @since v0.5.5
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.
+ */
+ readInt32BE(offset?: number): number;
+ /**
+ * Reads a 32-bit, little-endian float from `buf` at the specified `offset`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([1, 2, 3, 4]);
+ *
+ * console.log(buf.readFloatLE(0));
+ * // Prints: 1.539989614439558e-36
+ * console.log(buf.readFloatLE(1));
+ * // Throws ERR_OUT_OF_RANGE.
+ * ```
+ * @since v0.11.15
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.
+ */
+ readFloatLE(offset?: number): number;
+ /**
+ * Reads a 32-bit, big-endian float from `buf` at the specified `offset`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([1, 2, 3, 4]);
+ *
+ * console.log(buf.readFloatBE(0));
+ * // Prints: 2.387939260590663e-38
+ * ```
+ * @since v0.11.15
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 4`.
+ */
+ readFloatBE(offset?: number): number;
+ /**
+ * Reads a 64-bit, little-endian double from `buf` at the specified `offset`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
+ *
+ * console.log(buf.readDoubleLE(0));
+ * // Prints: 5.447603722011605e-270
+ * console.log(buf.readDoubleLE(1));
+ * // Throws ERR_OUT_OF_RANGE.
+ * ```
+ * @since v0.11.15
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 8`.
+ */
+ readDoubleLE(offset?: number): number;
+ /**
+ * Reads a 64-bit, big-endian double from `buf` at the specified `offset`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
+ *
+ * console.log(buf.readDoubleBE(0));
+ * // Prints: 8.20788039913184e-304
+ * ```
+ * @since v0.11.15
+ * @param [offset=0] Number of bytes to skip before starting to read. Must satisfy `0 <= offset <= buf.length - 8`.
+ */
+ readDoubleBE(offset?: number): number;
+ reverse(): this;
+ /**
+ * Interprets `buf` as an array of unsigned 16-bit integers and swaps the
+ * byte order _in-place_. Throws `ERR_INVALID_BUFFER_SIZE` if `buf.length` is not a multiple of 2.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
+ *
+ * console.log(buf1);
+ * // Prints: <Buffer 01 02 03 04 05 06 07 08>
+ *
+ * buf1.swap16();
+ *
+ * console.log(buf1);
+ * // Prints: <Buffer 02 01 04 03 06 05 08 07>
+ *
+ * const buf2 = Buffer.from([0x1, 0x2, 0x3]);
+ *
+ * buf2.swap16();
+ * // Throws ERR_INVALID_BUFFER_SIZE.
+ * ```
+ *
+ * One convenient use of `buf.swap16()` is to perform a fast in-place conversion
+ * between UTF-16 little-endian and UTF-16 big-endian:
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from('This is little-endian UTF-16', 'utf16le');
+ * buf.swap16(); // Convert to big-endian UTF-16 text.
+ * ```
+ * @since v5.10.0
+ * @return A reference to `buf`.
+ */
+ swap16(): Buffer;
+ /**
+ * Interprets `buf` as an array of unsigned 32-bit integers and swaps the
+ * byte order _in-place_. Throws `ERR_INVALID_BUFFER_SIZE` if `buf.length` is not a multiple of 4.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
+ *
+ * console.log(buf1);
+ * // Prints: <Buffer 01 02 03 04 05 06 07 08>
+ *
+ * buf1.swap32();
+ *
+ * console.log(buf1);
+ * // Prints: <Buffer 04 03 02 01 08 07 06 05>
+ *
+ * const buf2 = Buffer.from([0x1, 0x2, 0x3]);
+ *
+ * buf2.swap32();
+ * // Throws ERR_INVALID_BUFFER_SIZE.
+ * ```
+ * @since v5.10.0
+ * @return A reference to `buf`.
+ */
+ swap32(): Buffer;
+ /**
+ * Interprets `buf` as an array of 64-bit numbers and swaps byte order _in-place_.
+ * Throws `ERR_INVALID_BUFFER_SIZE` if `buf.length` is not a multiple of 8.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
+ *
+ * console.log(buf1);
+ * // Prints: <Buffer 01 02 03 04 05 06 07 08>
+ *
+ * buf1.swap64();
+ *
+ * console.log(buf1);
+ * // Prints: <Buffer 08 07 06 05 04 03 02 01>
+ *
+ * const buf2 = Buffer.from([0x1, 0x2, 0x3]);
+ *
+ * buf2.swap64();
+ * // Throws ERR_INVALID_BUFFER_SIZE.
+ * ```
+ * @since v6.3.0
+ * @return A reference to `buf`.
+ */
+ swap64(): Buffer;
+ /**
+ * Writes `value` to `buf` at the specified `offset`. `value` must be a
+ * valid unsigned 8-bit integer. Behavior is undefined when `value` is anything
+ * other than an unsigned 8-bit integer.
+ *
+ * This function is also available under the `writeUint8` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(4);
+ *
+ * buf.writeUInt8(0x3, 0);
+ * buf.writeUInt8(0x4, 1);
+ * buf.writeUInt8(0x23, 2);
+ * buf.writeUInt8(0x42, 3);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 03 04 23 42>
+ * ```
+ * @since v0.5.0
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 1`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeUInt8(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as little-endian. The `value`must be a valid unsigned 16-bit integer. Behavior is undefined when `value` is
+ * anything other than an unsigned 16-bit integer.
+ *
+ * This function is also available under the `writeUint16LE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(4);
+ *
+ * buf.writeUInt16LE(0xdead, 0);
+ * buf.writeUInt16LE(0xbeef, 2);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer ad de ef be>
+ * ```
+ * @since v0.5.5
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 2`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeUInt16LE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as big-endian. The `value`must be a valid unsigned 16-bit integer. Behavior is undefined when `value`is anything other than an
+ * unsigned 16-bit integer.
+ *
+ * This function is also available under the `writeUint16BE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(4);
+ *
+ * buf.writeUInt16BE(0xdead, 0);
+ * buf.writeUInt16BE(0xbeef, 2);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer de ad be ef>
+ * ```
+ * @since v0.5.5
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 2`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeUInt16BE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as little-endian. The `value`must be a valid unsigned 32-bit integer. Behavior is undefined when `value` is
+ * anything other than an unsigned 32-bit integer.
+ *
+ * This function is also available under the `writeUint32LE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(4);
+ *
+ * buf.writeUInt32LE(0xfeedface, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer ce fa ed fe>
+ * ```
+ * @since v0.5.5
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeUInt32LE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as big-endian. The `value`must be a valid unsigned 32-bit integer. Behavior is undefined when `value`is anything other than an
+ * unsigned 32-bit integer.
+ *
+ * This function is also available under the `writeUint32BE` alias.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(4);
+ *
+ * buf.writeUInt32BE(0xfeedface, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer fe ed fa ce>
+ * ```
+ * @since v0.5.5
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeUInt32BE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset`. `value` must be a valid
+ * signed 8-bit integer. Behavior is undefined when `value` is anything other than
+ * a signed 8-bit integer.
+ *
+ * `value` is interpreted and written as a two's complement signed integer.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(2);
+ *
+ * buf.writeInt8(2, 0);
+ * buf.writeInt8(-2, 1);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 02 fe>
+ * ```
+ * @since v0.5.0
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 1`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeInt8(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as little-endian. The `value`must be a valid signed 16-bit integer. Behavior is undefined when `value` is
+ * anything other than a signed 16-bit integer.
+ *
+ * The `value` is interpreted and written as a two's complement signed integer.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(2);
+ *
+ * buf.writeInt16LE(0x0304, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 04 03>
+ * ```
+ * @since v0.5.5
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 2`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeInt16LE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as big-endian. The `value`must be a valid signed 16-bit integer. Behavior is undefined when `value` is
+ * anything other than a signed 16-bit integer.
+ *
+ * The `value` is interpreted and written as a two's complement signed integer.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(2);
+ *
+ * buf.writeInt16BE(0x0102, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 01 02>
+ * ```
+ * @since v0.5.5
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 2`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeInt16BE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as little-endian. The `value`must be a valid signed 32-bit integer. Behavior is undefined when `value` is
+ * anything other than a signed 32-bit integer.
+ *
+ * The `value` is interpreted and written as a two's complement signed integer.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(4);
+ *
+ * buf.writeInt32LE(0x05060708, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 08 07 06 05>
+ * ```
+ * @since v0.5.5
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeInt32LE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as big-endian. The `value`must be a valid signed 32-bit integer. Behavior is undefined when `value` is
+ * anything other than a signed 32-bit integer.
+ *
+ * The `value` is interpreted and written as a two's complement signed integer.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(4);
+ *
+ * buf.writeInt32BE(0x01020304, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 01 02 03 04>
+ * ```
+ * @since v0.5.5
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeInt32BE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as little-endian. Behavior is
+ * undefined when `value` is anything other than a JavaScript number.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(4);
+ *
+ * buf.writeFloatLE(0xcafebabe, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer bb fe 4a 4f>
+ * ```
+ * @since v0.11.15
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeFloatLE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as big-endian. Behavior is
+ * undefined when `value` is anything other than a JavaScript number.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(4);
+ *
+ * buf.writeFloatBE(0xcafebabe, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 4f 4a fe bb>
+ * ```
+ * @since v0.11.15
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 4`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeFloatBE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as little-endian. The `value`must be a JavaScript number. Behavior is undefined when `value` is anything
+ * other than a JavaScript number.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(8);
+ *
+ * buf.writeDoubleLE(123.456, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 77 be 9f 1a 2f dd 5e 40>
+ * ```
+ * @since v0.11.15
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 8`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeDoubleLE(value: number, offset?: number): number;
+ /**
+ * Writes `value` to `buf` at the specified `offset` as big-endian. The `value`must be a JavaScript number. Behavior is undefined when `value` is anything
+ * other than a JavaScript number.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(8);
+ *
+ * buf.writeDoubleBE(123.456, 0);
+ *
+ * console.log(buf);
+ * // Prints: <Buffer 40 5e dd 2f 1a 9f be 77>
+ * ```
+ * @since v0.11.15
+ * @param value Number to be written to `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to write. Must satisfy `0 <= offset <= buf.length - 8`.
+ * @return `offset` plus the number of bytes written.
+ */
+ writeDoubleBE(value: number, offset?: number): number;
+ /**
+ * Fills `buf` with the specified `value`. If the `offset` and `end` are not given,
+ * the entire `buf` will be filled:
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * // Fill a `Buffer` with the ASCII character 'h'.
+ *
+ * const b = Buffer.allocUnsafe(50).fill('h');
+ *
+ * console.log(b.toString());
+ * // Prints: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
+ * ```
+ *
+ * `value` is coerced to a `uint32` value if it is not a string, `Buffer`, or
+ * integer. If the resulting integer is greater than `255` (decimal), `buf` will be
+ * filled with `value &#x26; 255`.
+ *
+ * If the final write of a `fill()` operation falls on a multi-byte character,
+ * then only the bytes of that character that fit into `buf` are written:
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * // Fill a `Buffer` with character that takes up two bytes in UTF-8.
+ *
+ * console.log(Buffer.allocUnsafe(5).fill('\u0222'));
+ * // Prints: <Buffer c8 a2 c8 a2 c8>
+ * ```
+ *
+ * If `value` contains invalid characters, it is truncated; if no valid
+ * fill data remains, an exception is thrown:
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.allocUnsafe(5);
+ *
+ * console.log(buf.fill('a'));
+ * // Prints: <Buffer 61 61 61 61 61>
+ * console.log(buf.fill('aazz', 'hex'));
+ * // Prints: <Buffer aa aa aa aa aa>
+ * console.log(buf.fill('zz', 'hex'));
+ * // Throws an exception.
+ * ```
+ * @since v0.5.0
+ * @param value The value with which to fill `buf`.
+ * @param [offset=0] Number of bytes to skip before starting to fill `buf`.
+ * @param [end=buf.length] Where to stop filling `buf` (not inclusive).
+ * @param [encoding='utf8'] The encoding for `value` if `value` is a string.
+ * @return A reference to `buf`.
+ */
+ fill(
+ value: string | Uint8Array | number,
+ offset?: number,
+ end?: number,
+ encoding?: Encoding,
+ ): this;
+ /**
+ * If `value` is:
+ *
+ * * a string, `value` is interpreted according to the character encoding in`encoding`.
+ * * a `Buffer` or [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array), `value` will be used in its entirety.
+ * To compare a partial `Buffer`, use `buf.slice()`.
+ * * a number, `value` will be interpreted as an unsigned 8-bit integer
+ * value between `0` and `255`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from('this is a buffer');
+ *
+ * console.log(buf.indexOf('this'));
+ * // Prints: 0
+ * console.log(buf.indexOf('is'));
+ * // Prints: 2
+ * console.log(buf.indexOf(Buffer.from('a buffer')));
+ * // Prints: 8
+ * console.log(buf.indexOf(97));
+ * // Prints: 8 (97 is the decimal ASCII value for 'a')
+ * console.log(buf.indexOf(Buffer.from('a buffer example')));
+ * // Prints: -1
+ * console.log(buf.indexOf(Buffer.from('a buffer example').slice(0, 8)));
+ * // Prints: 8
+ *
+ * const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'utf16le');
+ *
+ * console.log(utf16Buffer.indexOf('\u03a3', 0, 'utf16le'));
+ * // Prints: 4
+ * console.log(utf16Buffer.indexOf('\u03a3', -4, 'utf16le'));
+ * // Prints: 6
+ * ```
+ *
+ * If `value` is not a string, number, or `Buffer`, this method will throw a`TypeError`. If `value` is a number, it will be coerced to a valid byte value,
+ * an integer between 0 and 255.
+ *
+ * If `byteOffset` is not a number, it will be coerced to a number. If the result
+ * of coercion is `NaN` or `0`, then the entire buffer will be searched. This
+ * behavior matches [`String.prototype.indexOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf).
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const b = Buffer.from('abcdef');
+ *
+ * // Passing a value that's a number, but not a valid byte.
+ * // Prints: 2, equivalent to searching for 99 or 'c'.
+ * console.log(b.indexOf(99.9));
+ * console.log(b.indexOf(256 + 99));
+ *
+ * // Passing a byteOffset that coerces to NaN or 0.
+ * // Prints: 1, searching the whole buffer.
+ * console.log(b.indexOf('b', undefined));
+ * console.log(b.indexOf('b', {}));
+ * console.log(b.indexOf('b', null));
+ * console.log(b.indexOf('b', []));
+ * ```
+ *
+ * If `value` is an empty string or empty `Buffer` and `byteOffset` is less
+ * than `buf.length`, `byteOffset` will be returned. If `value` is empty and`byteOffset` is at least `buf.length`, `buf.length` will be returned.
+ * @since v1.5.0
+ * @param value What to search for.
+ * @param [byteOffset=0] Where to begin searching in `buf`. If negative, then offset is calculated from the end of `buf`.
+ * @param [encoding='utf8'] If `value` is a string, this is the encoding used to determine the binary representation of the string that will be searched for in `buf`.
+ * @return The index of the first occurrence of `value` in `buf`, or `-1` if `buf` does not contain `value`.
+ */
+ indexOf(
+ value: string | number | Uint8Array,
+ byteOffset?: number,
+ encoding?: Encoding,
+ ): number;
+ /**
+ * Identical to `buf.indexOf()`, except the last occurrence of `value` is found
+ * rather than the first occurrence.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from('this buffer is a buffer');
+ *
+ * console.log(buf.lastIndexOf('this'));
+ * // Prints: 0
+ * console.log(buf.lastIndexOf('buffer'));
+ * // Prints: 17
+ * console.log(buf.lastIndexOf(Buffer.from('buffer')));
+ * // Prints: 17
+ * console.log(buf.lastIndexOf(97));
+ * // Prints: 15 (97 is the decimal ASCII value for 'a')
+ * console.log(buf.lastIndexOf(Buffer.from('yolo')));
+ * // Prints: -1
+ * console.log(buf.lastIndexOf('buffer', 5));
+ * // Prints: 5
+ * console.log(buf.lastIndexOf('buffer', 4));
+ * // Prints: -1
+ *
+ * const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'utf16le');
+ *
+ * console.log(utf16Buffer.lastIndexOf('\u03a3', undefined, 'utf16le'));
+ * // Prints: 6
+ * console.log(utf16Buffer.lastIndexOf('\u03a3', -5, 'utf16le'));
+ * // Prints: 4
+ * ```
+ *
+ * If `value` is not a string, number, or `Buffer`, this method will throw a`TypeError`. If `value` is a number, it will be coerced to a valid byte value,
+ * an integer between 0 and 255.
+ *
+ * If `byteOffset` is not a number, it will be coerced to a number. Any arguments
+ * that coerce to `NaN`, like `{}` or `undefined`, will search the whole buffer.
+ * This behavior matches [`String.prototype.lastIndexOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf).
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const b = Buffer.from('abcdef');
+ *
+ * // Passing a value that's a number, but not a valid byte.
+ * // Prints: 2, equivalent to searching for 99 or 'c'.
+ * console.log(b.lastIndexOf(99.9));
+ * console.log(b.lastIndexOf(256 + 99));
+ *
+ * // Passing a byteOffset that coerces to NaN.
+ * // Prints: 1, searching the whole buffer.
+ * console.log(b.lastIndexOf('b', undefined));
+ * console.log(b.lastIndexOf('b', {}));
+ *
+ * // Passing a byteOffset that coerces to 0.
+ * // Prints: -1, equivalent to passing 0.
+ * console.log(b.lastIndexOf('b', null));
+ * console.log(b.lastIndexOf('b', []));
+ * ```
+ *
+ * If `value` is an empty string or empty `Buffer`, `byteOffset` will be returned.
+ * @since v6.0.0
+ * @param value What to search for.
+ * @param [byteOffset=buf.length - 1] Where to begin searching in `buf`. If negative, then offset is calculated from the end of `buf`.
+ * @param [encoding='utf8'] If `value` is a string, this is the encoding used to determine the binary representation of the string that will be searched for in `buf`.
+ * @return The index of the last occurrence of `value` in `buf`, or `-1` if `buf` does not contain `value`.
+ */
+ lastIndexOf(
+ value: string | number | Uint8Array,
+ byteOffset?: number,
+ encoding?: Encoding,
+ ): number;
+ /**
+ * Creates and returns an [iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) of `[index, byte]` pairs from the contents
+ * of `buf`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * // Log the entire contents of a `Buffer`.
+ *
+ * const buf = Buffer.from('buffer');
+ *
+ * for (const pair of buf.entries()) {
+ * console.log(pair);
+ * }
+ * // Prints:
+ * // [0, 98]
+ * // [1, 117]
+ * // [2, 102]
+ * // [3, 102]
+ * // [4, 101]
+ * // [5, 114]
+ * ```
+ * @since v1.1.0
+ */
+ entries(): IterableIterator<[number, number]>;
+ /**
+ * Equivalent to `buf.indexOf() !== -1`.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from('this is a buffer');
+ *
+ * console.log(buf.includes('this'));
+ * // Prints: true
+ * console.log(buf.includes('is'));
+ * // Prints: true
+ * console.log(buf.includes(Buffer.from('a buffer')));
+ * // Prints: true
+ * console.log(buf.includes(97));
+ * // Prints: true (97 is the decimal ASCII value for 'a')
+ * console.log(buf.includes(Buffer.from('a buffer example')));
+ * // Prints: false
+ * console.log(buf.includes(Buffer.from('a buffer example').slice(0, 8)));
+ * // Prints: true
+ * console.log(buf.includes('this', 4));
+ * // Prints: false
+ * ```
+ * @since v5.3.0
+ * @param value What to search for.
+ * @param [byteOffset=0] Where to begin searching in `buf`. If negative, then offset is calculated from the end of `buf`.
+ * @param [encoding='utf8'] If `value` is a string, this is its encoding.
+ * @return `true` if `value` was found in `buf`, `false` otherwise.
+ */
+ includes(
+ value: string | number | Buffer,
+ byteOffset?: number,
+ encoding?: Encoding,
+ ): boolean;
+ /**
+ * Creates and returns an [iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) of `buf` keys (indices).
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from('buffer');
+ *
+ * for (const key of buf.keys()) {
+ * console.log(key);
+ * }
+ * // Prints:
+ * // 0
+ * // 1
+ * // 2
+ * // 3
+ * // 4
+ * // 5
+ * ```
+ * @since v1.1.0
+ */
+ keys(): IterableIterator<number>;
+ /**
+ * Creates and returns an [iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) for `buf` values (bytes). This function is
+ * called automatically when a `Buffer` is used in a `for..of` statement.
+ *
+ * ```js
+ * import { Buffer } from "internal:deno_node/polyfills/internal/buffer";
+ *
+ * const buf = Buffer.from('buffer');
+ *
+ * for (const value of buf.values()) {
+ * console.log(value);
+ * }
+ * // Prints:
+ * // 98
+ * // 117
+ * // 102
+ * // 102
+ * // 101
+ * // 114
+ *
+ * for (const value of buf) {
+ * console.log(value);
+ * }
+ * // Prints:
+ * // 98
+ * // 117
+ * // 102
+ * // 102
+ * // 101
+ * // 114
+ * ```
+ * @since v1.1.0
+ */
+ values(): IterableIterator<number>;
+}
+
+export const SlowBuffer: {
+ /** @deprecated since v6.0.0, use `Buffer.allocUnsafeSlow()` */
+ new (size: number): Buffer;
+ prototype: Buffer;
+};
+
+export const atob: typeof globalThis.atob;
+export const Blob: Blob;
+export const btoa: typeof globalThis.btoa;
+export const constants: {
+ MAX_LENGTH: number;
+ MAX_STRING_LENGTH: number;
+};
+export const kMaxLength: number;
+export const kStringMaxLength: number;
+
+declare const exports: {
+ atob: typeof atob;
+ Blob: Blob;
+ btoa: typeof btoa;
+ Buffer: Buffer;
+ constants: typeof constants;
+ kMaxLength: typeof kMaxLength;
+ kStringMaxLength: typeof kStringMaxLength;
+ SlowBuffer: typeof SlowBuffer;
+};
+
+export default exports;
diff --git a/ext/node/polyfills/internal/buffer.mjs b/ext/node/polyfills/internal/buffer.mjs
new file mode 100644
index 000000000..506f90507
--- /dev/null
+++ b/ext/node/polyfills/internal/buffer.mjs
@@ -0,0 +1,2607 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Copyright Feross Aboukhadijeh, and other contributors. All rights reserved. MIT license.
+
+import { TextDecoder, TextEncoder } from "internal:deno_web/08_text_encoding.js";
+import { codes } from "internal:deno_node/polyfills/internal/error_codes.ts";
+import { encodings } from "internal:deno_node/polyfills/internal_binding/string_decoder.ts";
+import { indexOfBuffer, indexOfNumber } from "internal:deno_node/polyfills/internal_binding/buffer.ts";
+import {
+ asciiToBytes,
+ base64ToBytes,
+ base64UrlToBytes,
+ bytesToAscii,
+ bytesToUtf16le,
+ hexToBytes,
+ utf16leToBytes,
+} from "internal:deno_node/polyfills/internal_binding/_utils.ts";
+import { isAnyArrayBuffer, isArrayBufferView } from "internal:deno_node/polyfills/internal/util/types.ts";
+import { normalizeEncoding } from "internal:deno_node/polyfills/internal/util.mjs";
+import { validateBuffer } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { isUint8Array } from "internal:deno_node/polyfills/internal/util/types.ts";
+import { forgivingBase64Encode, forgivingBase64UrlEncode } from "internal:deno_web/00_infra.js";
+
+const utf8Encoder = new TextEncoder();
+
+// Temporary buffers to convert numbers.
+const float32Array = new Float32Array(1);
+const uInt8Float32Array = new Uint8Array(float32Array.buffer);
+const float64Array = new Float64Array(1);
+const uInt8Float64Array = new Uint8Array(float64Array.buffer);
+
+// Check endianness.
+float32Array[0] = -1; // 0xBF800000
+// Either it is [0, 0, 128, 191] or [191, 128, 0, 0]. It is not possible to
+// check this with `os.endianness()` because that is determined at compile time.
+export const bigEndian = uInt8Float32Array[3] === 0;
+
+export const kMaxLength = 2147483647;
+export const kStringMaxLength = 536870888;
+const MAX_UINT32 = 2 ** 32;
+
+const customInspectSymbol =
+ typeof Symbol === "function" && typeof Symbol["for"] === "function"
+ ? Symbol["for"]("nodejs.util.inspect.custom")
+ : null;
+
+const INSPECT_MAX_BYTES = 50;
+
+export const constants = {
+ MAX_LENGTH: kMaxLength,
+ MAX_STRING_LENGTH: kStringMaxLength,
+};
+
+Object.defineProperty(Buffer.prototype, "parent", {
+ enumerable: true,
+ get: function () {
+ if (!Buffer.isBuffer(this)) {
+ return void 0;
+ }
+ return this.buffer;
+ },
+});
+
+Object.defineProperty(Buffer.prototype, "offset", {
+ enumerable: true,
+ get: function () {
+ if (!Buffer.isBuffer(this)) {
+ return void 0;
+ }
+ return this.byteOffset;
+ },
+});
+
+function createBuffer(length) {
+ if (length > kMaxLength) {
+ throw new RangeError(
+ 'The value "' + length + '" is invalid for option "size"',
+ );
+ }
+ const buf = new Uint8Array(length);
+ Object.setPrototypeOf(buf, Buffer.prototype);
+ return buf;
+}
+
+export function Buffer(arg, encodingOrOffset, length) {
+ if (typeof arg === "number") {
+ if (typeof encodingOrOffset === "string") {
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ "string",
+ "string",
+ arg,
+ );
+ }
+ return _allocUnsafe(arg);
+ }
+ return _from(arg, encodingOrOffset, length);
+}
+
+Buffer.poolSize = 8192;
+
+function _from(value, encodingOrOffset, length) {
+ if (typeof value === "string") {
+ return fromString(value, encodingOrOffset);
+ }
+
+ if (typeof value === "object" && value !== null) {
+ if (isAnyArrayBuffer(value)) {
+ return fromArrayBuffer(value, encodingOrOffset, length);
+ }
+
+ const valueOf = value.valueOf && value.valueOf();
+ if (
+ valueOf != null &&
+ valueOf !== value &&
+ (typeof valueOf === "string" || typeof valueOf === "object")
+ ) {
+ return _from(valueOf, encodingOrOffset, length);
+ }
+
+ const b = fromObject(value);
+ if (b) {
+ return b;
+ }
+
+ if (typeof value[Symbol.toPrimitive] === "function") {
+ const primitive = value[Symbol.toPrimitive]("string");
+ if (typeof primitive === "string") {
+ return fromString(primitive, encodingOrOffset);
+ }
+ }
+ }
+
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ "first argument",
+ ["string", "Buffer", "ArrayBuffer", "Array", "Array-like Object"],
+ value,
+ );
+}
+
+Buffer.from = function from(value, encodingOrOffset, length) {
+ return _from(value, encodingOrOffset, length);
+};
+
+Object.setPrototypeOf(Buffer.prototype, Uint8Array.prototype);
+
+Object.setPrototypeOf(Buffer, Uint8Array);
+
+function assertSize(size) {
+ validateNumber(size, "size");
+ if (!(size >= 0 && size <= kMaxLength)) {
+ throw new codes.ERR_INVALID_ARG_VALUE.RangeError("size", size);
+ }
+}
+
+function _alloc(size, fill, encoding) {
+ assertSize(size);
+
+ const buffer = createBuffer(size);
+ if (fill !== undefined) {
+ if (encoding !== undefined && typeof encoding !== "string") {
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ "encoding",
+ "string",
+ encoding,
+ );
+ }
+ return buffer.fill(fill, encoding);
+ }
+ return buffer;
+}
+
+Buffer.alloc = function alloc(size, fill, encoding) {
+ return _alloc(size, fill, encoding);
+};
+
+function _allocUnsafe(size) {
+ assertSize(size);
+ return createBuffer(size < 0 ? 0 : checked(size) | 0);
+}
+
+Buffer.allocUnsafe = function allocUnsafe(size) {
+ return _allocUnsafe(size);
+};
+
+Buffer.allocUnsafeSlow = function allocUnsafeSlow(size) {
+ return _allocUnsafe(size);
+};
+
+function fromString(string, encoding) {
+ if (typeof encoding !== "string" || encoding === "") {
+ encoding = "utf8";
+ }
+ if (!Buffer.isEncoding(encoding)) {
+ throw new codes.ERR_UNKNOWN_ENCODING(encoding);
+ }
+ const length = byteLength(string, encoding) | 0;
+ let buf = createBuffer(length);
+ const actual = buf.write(string, encoding);
+ if (actual !== length) {
+ buf = buf.slice(0, actual);
+ }
+ return buf;
+}
+
+function fromArrayLike(array) {
+ const length = array.length < 0 ? 0 : checked(array.length) | 0;
+ const buf = createBuffer(length);
+ for (let i = 0; i < length; i += 1) {
+ buf[i] = array[i] & 255;
+ }
+ return buf;
+}
+
+function fromObject(obj) {
+ if (obj.length !== undefined || isAnyArrayBuffer(obj.buffer)) {
+ if (typeof obj.length !== "number") {
+ return createBuffer(0);
+ }
+ return fromArrayLike(obj);
+ }
+
+ if (obj.type === "Buffer" && Array.isArray(obj.data)) {
+ return fromArrayLike(obj.data);
+ }
+}
+
+function checked(length) {
+ if (length >= kMaxLength) {
+ throw new RangeError(
+ "Attempt to allocate Buffer larger than maximum size: 0x" +
+ kMaxLength.toString(16) + " bytes",
+ );
+ }
+ return length | 0;
+}
+
+export function SlowBuffer(length) {
+ assertSize(length);
+ return Buffer.alloc(+length);
+}
+
+Object.setPrototypeOf(SlowBuffer.prototype, Uint8Array.prototype);
+
+Object.setPrototypeOf(SlowBuffer, Uint8Array);
+
+Buffer.isBuffer = function isBuffer(b) {
+ return b != null && b._isBuffer === true && b !== Buffer.prototype;
+};
+
+Buffer.compare = function compare(a, b) {
+ if (isInstance(a, Uint8Array)) {
+ a = Buffer.from(a, a.offset, a.byteLength);
+ }
+ if (isInstance(b, Uint8Array)) {
+ b = Buffer.from(b, b.offset, b.byteLength);
+ }
+ if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
+ throw new TypeError(
+ 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array',
+ );
+ }
+ if (a === b) {
+ return 0;
+ }
+ let x = a.length;
+ let y = b.length;
+ for (let i = 0, len = Math.min(x, y); i < len; ++i) {
+ if (a[i] !== b[i]) {
+ x = a[i];
+ y = b[i];
+ break;
+ }
+ }
+ if (x < y) {
+ return -1;
+ }
+ if (y < x) {
+ return 1;
+ }
+ return 0;
+};
+
+Buffer.isEncoding = function isEncoding(encoding) {
+ return typeof encoding === "string" && encoding.length !== 0 &&
+ normalizeEncoding(encoding) !== undefined;
+};
+
+Buffer.concat = function concat(list, length) {
+ if (!Array.isArray(list)) {
+ throw new codes.ERR_INVALID_ARG_TYPE("list", "Array", list);
+ }
+
+ if (list.length === 0) {
+ return Buffer.alloc(0);
+ }
+
+ if (length === undefined) {
+ length = 0;
+ for (let i = 0; i < list.length; i++) {
+ if (list[i].length) {
+ length += list[i].length;
+ }
+ }
+ } else {
+ validateOffset(length, "length");
+ }
+
+ const buffer = Buffer.allocUnsafe(length);
+ let pos = 0;
+ for (let i = 0; i < list.length; i++) {
+ const buf = list[i];
+ if (!isUint8Array(buf)) {
+ // TODO(BridgeAR): This should not be of type ERR_INVALID_ARG_TYPE.
+ // Instead, find the proper error code for this.
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ `list[${i}]`,
+ ["Buffer", "Uint8Array"],
+ list[i],
+ );
+ }
+ pos += _copyActual(buf, buffer, pos, 0, buf.length);
+ }
+
+ // Note: `length` is always equal to `buffer.length` at this point
+ if (pos < length) {
+ // Zero-fill the remaining bytes if the specified `length` was more than
+ // the actual total length, i.e. if we have some remaining allocated bytes
+ // there were not initialized.
+ buffer.fill(0, pos, length);
+ }
+
+ return buffer;
+};
+
+function byteLength(string, encoding) {
+ if (typeof string !== "string") {
+ if (isArrayBufferView(string) || isAnyArrayBuffer(string)) {
+ return string.byteLength;
+ }
+
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ "string",
+ ["string", "Buffer", "ArrayBuffer"],
+ string,
+ );
+ }
+
+ const len = string.length;
+ const mustMatch = arguments.length > 2 && arguments[2] === true;
+ if (!mustMatch && len === 0) {
+ return 0;
+ }
+
+ if (!encoding) {
+ return (mustMatch ? -1 : byteLengthUtf8(string));
+ }
+
+ const ops = getEncodingOps(encoding);
+ if (ops === undefined) {
+ return (mustMatch ? -1 : byteLengthUtf8(string));
+ }
+ return ops.byteLength(string);
+}
+
+Buffer.byteLength = byteLength;
+
+Buffer.prototype._isBuffer = true;
+
+function swap(b, n, m) {
+ const i = b[n];
+ b[n] = b[m];
+ b[m] = i;
+}
+
+Buffer.prototype.swap16 = function swap16() {
+ const len = this.length;
+ if (len % 2 !== 0) {
+ throw new RangeError("Buffer size must be a multiple of 16-bits");
+ }
+ for (let i = 0; i < len; i += 2) {
+ swap(this, i, i + 1);
+ }
+ return this;
+};
+
+Buffer.prototype.swap32 = function swap32() {
+ const len = this.length;
+ if (len % 4 !== 0) {
+ throw new RangeError("Buffer size must be a multiple of 32-bits");
+ }
+ for (let i = 0; i < len; i += 4) {
+ swap(this, i, i + 3);
+ swap(this, i + 1, i + 2);
+ }
+ return this;
+};
+
+Buffer.prototype.swap64 = function swap64() {
+ const len = this.length;
+ if (len % 8 !== 0) {
+ throw new RangeError("Buffer size must be a multiple of 64-bits");
+ }
+ for (let i = 0; i < len; i += 8) {
+ swap(this, i, i + 7);
+ swap(this, i + 1, i + 6);
+ swap(this, i + 2, i + 5);
+ swap(this, i + 3, i + 4);
+ }
+ return this;
+};
+
+Buffer.prototype.toString = function toString(encoding, start, end) {
+ if (arguments.length === 0) {
+ return this.utf8Slice(0, this.length);
+ }
+
+ const len = this.length;
+
+ if (start <= 0) {
+ start = 0;
+ } else if (start >= len) {
+ return "";
+ } else {
+ start |= 0;
+ }
+
+ if (end === undefined || end > len) {
+ end = len;
+ } else {
+ end |= 0;
+ }
+
+ if (end <= start) {
+ return "";
+ }
+
+ if (encoding === undefined) {
+ return this.utf8Slice(start, end);
+ }
+
+ const ops = getEncodingOps(encoding);
+ if (ops === undefined) {
+ throw new codes.ERR_UNKNOWN_ENCODING(encoding);
+ }
+
+ return ops.slice(this, start, end);
+};
+
+Buffer.prototype.toLocaleString = Buffer.prototype.toString;
+
+Buffer.prototype.equals = function equals(b) {
+ if (!isUint8Array(b)) {
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ "otherBuffer",
+ ["Buffer", "Uint8Array"],
+ b,
+ );
+ }
+ if (this === b) {
+ return true;
+ }
+ return Buffer.compare(this, b) === 0;
+};
+
+Buffer.prototype.inspect = function inspect() {
+ let str = "";
+ const max = INSPECT_MAX_BYTES;
+ str = this.toString("hex", 0, max).replace(/(.{2})/g, "$1 ").trim();
+ if (this.length > max) {
+ str += " ... ";
+ }
+ return "<Buffer " + str + ">";
+};
+
+if (customInspectSymbol) {
+ Buffer.prototype[customInspectSymbol] = Buffer.prototype.inspect;
+}
+
+Buffer.prototype.compare = function compare(
+ target,
+ start,
+ end,
+ thisStart,
+ thisEnd,
+) {
+ if (isInstance(target, Uint8Array)) {
+ target = Buffer.from(target, target.offset, target.byteLength);
+ }
+ if (!Buffer.isBuffer(target)) {
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ "target",
+ ["Buffer", "Uint8Array"],
+ target,
+ );
+ }
+
+ if (start === undefined) {
+ start = 0;
+ } else {
+ validateOffset(start, "targetStart", 0, kMaxLength);
+ }
+
+ if (end === undefined) {
+ end = target.length;
+ } else {
+ validateOffset(end, "targetEnd", 0, target.length);
+ }
+
+ if (thisStart === undefined) {
+ thisStart = 0;
+ } else {
+ validateOffset(start, "sourceStart", 0, kMaxLength);
+ }
+
+ if (thisEnd === undefined) {
+ thisEnd = this.length;
+ } else {
+ validateOffset(end, "sourceEnd", 0, this.length);
+ }
+
+ if (
+ start < 0 || end > target.length || thisStart < 0 ||
+ thisEnd > this.length
+ ) {
+ throw new codes.ERR_OUT_OF_RANGE("out of range index", "range");
+ }
+
+ if (thisStart >= thisEnd && start >= end) {
+ return 0;
+ }
+ if (thisStart >= thisEnd) {
+ return -1;
+ }
+ if (start >= end) {
+ return 1;
+ }
+ start >>>= 0;
+ end >>>= 0;
+ thisStart >>>= 0;
+ thisEnd >>>= 0;
+ if (this === target) {
+ return 0;
+ }
+ let x = thisEnd - thisStart;
+ let y = end - start;
+ const len = Math.min(x, y);
+ const thisCopy = this.slice(thisStart, thisEnd);
+ const targetCopy = target.slice(start, end);
+ for (let i = 0; i < len; ++i) {
+ if (thisCopy[i] !== targetCopy[i]) {
+ x = thisCopy[i];
+ y = targetCopy[i];
+ break;
+ }
+ }
+ if (x < y) {
+ return -1;
+ }
+ if (y < x) {
+ return 1;
+ }
+ return 0;
+};
+
+function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) {
+ validateBuffer(buffer);
+
+ if (typeof byteOffset === "string") {
+ encoding = byteOffset;
+ byteOffset = undefined;
+ } else if (byteOffset > 0x7fffffff) {
+ byteOffset = 0x7fffffff;
+ } else if (byteOffset < -0x80000000) {
+ byteOffset = -0x80000000;
+ }
+ byteOffset = +byteOffset;
+ if (Number.isNaN(byteOffset)) {
+ byteOffset = dir ? 0 : (buffer.length || buffer.byteLength);
+ }
+ dir = !!dir;
+
+ if (typeof val === "number") {
+ return indexOfNumber(buffer, val >>> 0, byteOffset, dir);
+ }
+
+ let ops;
+ if (encoding === undefined) {
+ ops = encodingOps.utf8;
+ } else {
+ ops = getEncodingOps(encoding);
+ }
+
+ if (typeof val === "string") {
+ if (ops === undefined) {
+ throw new codes.ERR_UNKNOWN_ENCODING(encoding);
+ }
+ return ops.indexOf(buffer, val, byteOffset, dir);
+ }
+
+ if (isUint8Array(val)) {
+ const encodingVal = ops === undefined ? encodingsMap.utf8 : ops.encodingVal;
+ return indexOfBuffer(buffer, val, byteOffset, encodingVal, dir);
+ }
+
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ "value",
+ ["number", "string", "Buffer", "Uint8Array"],
+ val,
+ );
+}
+
+Buffer.prototype.includes = function includes(val, byteOffset, encoding) {
+ return this.indexOf(val, byteOffset, encoding) !== -1;
+};
+
+Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) {
+ return bidirectionalIndexOf(this, val, byteOffset, encoding, true);
+};
+
+Buffer.prototype.lastIndexOf = function lastIndexOf(
+ val,
+ byteOffset,
+ encoding,
+) {
+ return bidirectionalIndexOf(this, val, byteOffset, encoding, false);
+};
+
+Buffer.prototype.asciiSlice = function asciiSlice(offset, length) {
+ if (offset === 0 && length === this.length) {
+ return bytesToAscii(this);
+ } else {
+ return bytesToAscii(this.slice(offset, length));
+ }
+};
+
+Buffer.prototype.asciiWrite = function asciiWrite(string, offset, length) {
+ return blitBuffer(asciiToBytes(string), this, offset, length);
+};
+
+Buffer.prototype.base64Slice = function base64Slice(
+ offset,
+ length,
+) {
+ if (offset === 0 && length === this.length) {
+ return forgivingBase64Encode(this);
+ } else {
+ return forgivingBase64Encode(this.slice(offset, length));
+ }
+};
+
+Buffer.prototype.base64Write = function base64Write(
+ string,
+ offset,
+ length,
+) {
+ return blitBuffer(base64ToBytes(string), this, offset, length);
+};
+
+Buffer.prototype.base64urlSlice = function base64urlSlice(
+ offset,
+ length,
+) {
+ if (offset === 0 && length === this.length) {
+ return forgivingBase64UrlEncode(this);
+ } else {
+ return forgivingBase64UrlEncode(this.slice(offset, length));
+ }
+};
+
+Buffer.prototype.base64urlWrite = function base64urlWrite(
+ string,
+ offset,
+ length,
+) {
+ return blitBuffer(base64UrlToBytes(string), this, offset, length);
+};
+
+Buffer.prototype.hexWrite = function hexWrite(string, offset, length) {
+ return blitBuffer(
+ hexToBytes(string, this.length - offset),
+ this,
+ offset,
+ length,
+ );
+};
+
+Buffer.prototype.hexSlice = function hexSlice(string, offset, length) {
+ return _hexSlice(this, string, offset, length);
+};
+
+Buffer.prototype.latin1Slice = function latin1Slice(
+ string,
+ offset,
+ length,
+) {
+ return _latin1Slice(this, string, offset, length);
+};
+
+Buffer.prototype.latin1Write = function latin1Write(
+ string,
+ offset,
+ length,
+) {
+ return blitBuffer(asciiToBytes(string), this, offset, length);
+};
+
+Buffer.prototype.ucs2Slice = function ucs2Slice(offset, length) {
+ if (offset === 0 && length === this.length) {
+ return bytesToUtf16le(this);
+ } else {
+ return bytesToUtf16le(this.slice(offset, length));
+ }
+};
+
+Buffer.prototype.ucs2Write = function ucs2Write(string, offset, length) {
+ return blitBuffer(
+ utf16leToBytes(string, this.length - offset),
+ this,
+ offset,
+ length,
+ );
+};
+
+Buffer.prototype.utf8Slice = function utf8Slice(string, offset, length) {
+ return _utf8Slice(this, string, offset, length);
+};
+
+Buffer.prototype.utf8Write = function utf8Write(string, offset, length) {
+ return blitBuffer(
+ utf8ToBytes(string, this.length - offset),
+ this,
+ offset,
+ length,
+ );
+};
+
+Buffer.prototype.write = function write(string, offset, length, encoding) {
+ // Buffer#write(string);
+ if (offset === undefined) {
+ return this.utf8Write(string, 0, this.length);
+ }
+ // Buffer#write(string, encoding)
+ if (length === undefined && typeof offset === "string") {
+ encoding = offset;
+ length = this.length;
+ offset = 0;
+
+ // Buffer#write(string, offset[, length][, encoding])
+ } else {
+ validateOffset(offset, "offset", 0, this.length);
+
+ const remaining = this.length - offset;
+
+ if (length === undefined) {
+ length = remaining;
+ } else if (typeof length === "string") {
+ encoding = length;
+ length = remaining;
+ } else {
+ validateOffset(length, "length", 0, this.length);
+ if (length > remaining) {
+ length = remaining;
+ }
+ }
+ }
+
+ if (!encoding) {
+ return this.utf8Write(string, offset, length);
+ }
+
+ const ops = getEncodingOps(encoding);
+ if (ops === undefined) {
+ throw new codes.ERR_UNKNOWN_ENCODING(encoding);
+ }
+ return ops.write(this, string, offset, length);
+};
+
+Buffer.prototype.toJSON = function toJSON() {
+ return {
+ type: "Buffer",
+ data: Array.prototype.slice.call(this._arr || this, 0),
+ };
+};
+function fromArrayBuffer(obj, byteOffset, length) {
+ // Convert byteOffset to integer
+ if (byteOffset === undefined) {
+ byteOffset = 0;
+ } else {
+ byteOffset = +byteOffset;
+ if (Number.isNaN(byteOffset)) {
+ byteOffset = 0;
+ }
+ }
+
+ const maxLength = obj.byteLength - byteOffset;
+
+ if (maxLength < 0) {
+ throw new codes.ERR_BUFFER_OUT_OF_BOUNDS("offset");
+ }
+
+ if (length === undefined) {
+ length = maxLength;
+ } else {
+ // Convert length to non-negative integer.
+ length = +length;
+ if (length > 0) {
+ if (length > maxLength) {
+ throw new codes.ERR_BUFFER_OUT_OF_BOUNDS("length");
+ }
+ } else {
+ length = 0;
+ }
+ }
+
+ const buffer = new Uint8Array(obj, byteOffset, length);
+ Object.setPrototypeOf(buffer, Buffer.prototype);
+ return buffer;
+}
+
+function _base64Slice(buf, start, end) {
+ if (start === 0 && end === buf.length) {
+ return forgivingBase64Encode(buf);
+ } else {
+ return forgivingBase64Encode(buf.slice(start, end));
+ }
+}
+
+const decoder = new TextDecoder();
+
+function _utf8Slice(buf, start, end) {
+ return decoder.decode(buf.slice(start, end));
+}
+
+function _latin1Slice(buf, start, end) {
+ let ret = "";
+ end = Math.min(buf.length, end);
+ for (let i = start; i < end; ++i) {
+ ret += String.fromCharCode(buf[i]);
+ }
+ return ret;
+}
+
+function _hexSlice(buf, start, end) {
+ const len = buf.length;
+ if (!start || start < 0) {
+ start = 0;
+ }
+ if (!end || end < 0 || end > len) {
+ end = len;
+ }
+ let out = "";
+ for (let i = start; i < end; ++i) {
+ out += hexSliceLookupTable[buf[i]];
+ }
+ return out;
+}
+
+Buffer.prototype.slice = function slice(start, end) {
+ const len = this.length;
+ start = ~~start;
+ end = end === void 0 ? len : ~~end;
+ if (start < 0) {
+ start += len;
+ if (start < 0) {
+ start = 0;
+ }
+ } else if (start > len) {
+ start = len;
+ }
+ if (end < 0) {
+ end += len;
+ if (end < 0) {
+ end = 0;
+ }
+ } else if (end > len) {
+ end = len;
+ }
+ if (end < start) {
+ end = start;
+ }
+ const newBuf = this.subarray(start, end);
+ Object.setPrototypeOf(newBuf, Buffer.prototype);
+ return newBuf;
+};
+
+Buffer.prototype.readUintLE = Buffer.prototype.readUIntLE = function readUIntLE(
+ offset,
+ byteLength,
+) {
+ if (offset === undefined) {
+ throw new codes.ERR_INVALID_ARG_TYPE("offset", "number", offset);
+ }
+ if (byteLength === 6) {
+ return readUInt48LE(this, offset);
+ }
+ if (byteLength === 5) {
+ return readUInt40LE(this, offset);
+ }
+ if (byteLength === 3) {
+ return readUInt24LE(this, offset);
+ }
+ if (byteLength === 4) {
+ return this.readUInt32LE(offset);
+ }
+ if (byteLength === 2) {
+ return this.readUInt16LE(offset);
+ }
+ if (byteLength === 1) {
+ return this.readUInt8(offset);
+ }
+
+ boundsError(byteLength, 6, "byteLength");
+};
+
+Buffer.prototype.readUintBE = Buffer.prototype.readUIntBE = function readUIntBE(
+ offset,
+ byteLength,
+) {
+ if (offset === undefined) {
+ throw new codes.ERR_INVALID_ARG_TYPE("offset", "number", offset);
+ }
+ if (byteLength === 6) {
+ return readUInt48BE(this, offset);
+ }
+ if (byteLength === 5) {
+ return readUInt40BE(this, offset);
+ }
+ if (byteLength === 3) {
+ return readUInt24BE(this, offset);
+ }
+ if (byteLength === 4) {
+ return this.readUInt32BE(offset);
+ }
+ if (byteLength === 2) {
+ return this.readUInt16BE(offset);
+ }
+ if (byteLength === 1) {
+ return this.readUInt8(offset);
+ }
+
+ boundsError(byteLength, 6, "byteLength");
+};
+
+Buffer.prototype.readUint8 = Buffer.prototype.readUInt8 = function readUInt8(
+ offset = 0,
+) {
+ validateNumber(offset, "offset");
+ const val = this[offset];
+ if (val === undefined) {
+ boundsError(offset, this.length - 1);
+ }
+
+ return val;
+};
+
+Buffer.prototype.readUint16BE = Buffer.prototype.readUInt16BE = readUInt16BE;
+
+Buffer.prototype.readUint16LE =
+ Buffer.prototype.readUInt16LE =
+ function readUInt16LE(offset = 0) {
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 1];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, this.length - 2);
+ }
+
+ return first + last * 2 ** 8;
+ };
+
+Buffer.prototype.readUint32LE =
+ Buffer.prototype.readUInt32LE =
+ function readUInt32LE(offset = 0) {
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 3];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, this.length - 4);
+ }
+
+ return first +
+ this[++offset] * 2 ** 8 +
+ this[++offset] * 2 ** 16 +
+ last * 2 ** 24;
+ };
+
+Buffer.prototype.readUint32BE = Buffer.prototype.readUInt32BE = readUInt32BE;
+
+Buffer.prototype.readBigUint64LE =
+ Buffer.prototype.readBigUInt64LE =
+ defineBigIntMethod(
+ function readBigUInt64LE(offset) {
+ offset = offset >>> 0;
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 7];
+ if (first === void 0 || last === void 0) {
+ boundsError(offset, this.length - 8);
+ }
+ const lo = first + this[++offset] * 2 ** 8 +
+ this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 24;
+ const hi = this[++offset] + this[++offset] * 2 ** 8 +
+ this[++offset] * 2 ** 16 + last * 2 ** 24;
+ return BigInt(lo) + (BigInt(hi) << BigInt(32));
+ },
+ );
+
+Buffer.prototype.readBigUint64BE =
+ Buffer.prototype.readBigUInt64BE =
+ defineBigIntMethod(
+ function readBigUInt64BE(offset) {
+ offset = offset >>> 0;
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 7];
+ if (first === void 0 || last === void 0) {
+ boundsError(offset, this.length - 8);
+ }
+ const hi = first * 2 ** 24 + this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 8 + this[++offset];
+ const lo = this[++offset] * 2 ** 24 + this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 8 + last;
+ return (BigInt(hi) << BigInt(32)) + BigInt(lo);
+ },
+ );
+
+Buffer.prototype.readIntLE = function readIntLE(
+ offset,
+ byteLength,
+) {
+ if (offset === undefined) {
+ throw new codes.ERR_INVALID_ARG_TYPE("offset", "number", offset);
+ }
+ if (byteLength === 6) {
+ return readInt48LE(this, offset);
+ }
+ if (byteLength === 5) {
+ return readInt40LE(this, offset);
+ }
+ if (byteLength === 3) {
+ return readInt24LE(this, offset);
+ }
+ if (byteLength === 4) {
+ return this.readInt32LE(offset);
+ }
+ if (byteLength === 2) {
+ return this.readInt16LE(offset);
+ }
+ if (byteLength === 1) {
+ return this.readInt8(offset);
+ }
+
+ boundsError(byteLength, 6, "byteLength");
+};
+
+Buffer.prototype.readIntBE = function readIntBE(offset, byteLength) {
+ if (offset === undefined) {
+ throw new codes.ERR_INVALID_ARG_TYPE("offset", "number", offset);
+ }
+ if (byteLength === 6) {
+ return readInt48BE(this, offset);
+ }
+ if (byteLength === 5) {
+ return readInt40BE(this, offset);
+ }
+ if (byteLength === 3) {
+ return readInt24BE(this, offset);
+ }
+ if (byteLength === 4) {
+ return this.readInt32BE(offset);
+ }
+ if (byteLength === 2) {
+ return this.readInt16BE(offset);
+ }
+ if (byteLength === 1) {
+ return this.readInt8(offset);
+ }
+
+ boundsError(byteLength, 6, "byteLength");
+};
+
+Buffer.prototype.readInt8 = function readInt8(offset = 0) {
+ validateNumber(offset, "offset");
+ const val = this[offset];
+ if (val === undefined) {
+ boundsError(offset, this.length - 1);
+ }
+
+ return val | (val & 2 ** 7) * 0x1fffffe;
+};
+
+Buffer.prototype.readInt16LE = function readInt16LE(offset = 0) {
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 1];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, this.length - 2);
+ }
+
+ const val = first + last * 2 ** 8;
+ return val | (val & 2 ** 15) * 0x1fffe;
+};
+
+Buffer.prototype.readInt16BE = function readInt16BE(offset = 0) {
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 1];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, this.length - 2);
+ }
+
+ const val = first * 2 ** 8 + last;
+ return val | (val & 2 ** 15) * 0x1fffe;
+};
+
+Buffer.prototype.readInt32LE = function readInt32LE(offset = 0) {
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 3];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, this.length - 4);
+ }
+
+ return first +
+ this[++offset] * 2 ** 8 +
+ this[++offset] * 2 ** 16 +
+ (last << 24); // Overflow
+};
+
+Buffer.prototype.readInt32BE = function readInt32BE(offset = 0) {
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 3];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, this.length - 4);
+ }
+
+ return (first << 24) + // Overflow
+ this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 8 +
+ last;
+};
+
+Buffer.prototype.readBigInt64LE = defineBigIntMethod(
+ function readBigInt64LE(offset) {
+ offset = offset >>> 0;
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 7];
+ if (first === void 0 || last === void 0) {
+ boundsError(offset, this.length - 8);
+ }
+ const val = this[offset + 4] + this[offset + 5] * 2 ** 8 +
+ this[offset + 6] * 2 ** 16 + (last << 24);
+ return (BigInt(val) << BigInt(32)) +
+ BigInt(
+ first + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 24,
+ );
+ },
+);
+
+Buffer.prototype.readBigInt64BE = defineBigIntMethod(
+ function readBigInt64BE(offset) {
+ offset = offset >>> 0;
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 7];
+ if (first === void 0 || last === void 0) {
+ boundsError(offset, this.length - 8);
+ }
+ const val = (first << 24) + this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 8 + this[++offset];
+ return (BigInt(val) << BigInt(32)) +
+ BigInt(
+ this[++offset] * 2 ** 24 + this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 8 + last,
+ );
+ },
+);
+
+Buffer.prototype.readFloatLE = function readFloatLE(offset) {
+ return bigEndian
+ ? readFloatBackwards(this, offset)
+ : readFloatForwards(this, offset);
+};
+
+Buffer.prototype.readFloatBE = function readFloatBE(offset) {
+ return bigEndian
+ ? readFloatForwards(this, offset)
+ : readFloatBackwards(this, offset);
+};
+
+Buffer.prototype.readDoubleLE = function readDoubleLE(offset) {
+ return bigEndian
+ ? readDoubleBackwards(this, offset)
+ : readDoubleForwards(this, offset);
+};
+
+Buffer.prototype.readDoubleBE = function readDoubleBE(offset) {
+ return bigEndian
+ ? readDoubleForwards(this, offset)
+ : readDoubleBackwards(this, offset);
+};
+
+Buffer.prototype.writeUintLE =
+ Buffer.prototype.writeUIntLE =
+ function writeUIntLE(value, offset, byteLength) {
+ if (byteLength === 6) {
+ return writeU_Int48LE(this, value, offset, 0, 0xffffffffffff);
+ }
+ if (byteLength === 5) {
+ return writeU_Int40LE(this, value, offset, 0, 0xffffffffff);
+ }
+ if (byteLength === 3) {
+ return writeU_Int24LE(this, value, offset, 0, 0xffffff);
+ }
+ if (byteLength === 4) {
+ return writeU_Int32LE(this, value, offset, 0, 0xffffffff);
+ }
+ if (byteLength === 2) {
+ return writeU_Int16LE(this, value, offset, 0, 0xffff);
+ }
+ if (byteLength === 1) {
+ return writeU_Int8(this, value, offset, 0, 0xff);
+ }
+
+ boundsError(byteLength, 6, "byteLength");
+ };
+
+Buffer.prototype.writeUintBE =
+ Buffer.prototype.writeUIntBE =
+ function writeUIntBE(value, offset, byteLength) {
+ if (byteLength === 6) {
+ return writeU_Int48BE(this, value, offset, 0, 0xffffffffffff);
+ }
+ if (byteLength === 5) {
+ return writeU_Int40BE(this, value, offset, 0, 0xffffffffff);
+ }
+ if (byteLength === 3) {
+ return writeU_Int24BE(this, value, offset, 0, 0xffffff);
+ }
+ if (byteLength === 4) {
+ return writeU_Int32BE(this, value, offset, 0, 0xffffffff);
+ }
+ if (byteLength === 2) {
+ return writeU_Int16BE(this, value, offset, 0, 0xffff);
+ }
+ if (byteLength === 1) {
+ return writeU_Int8(this, value, offset, 0, 0xff);
+ }
+
+ boundsError(byteLength, 6, "byteLength");
+ };
+
+Buffer.prototype.writeUint8 = Buffer.prototype.writeUInt8 = function writeUInt8(
+ value,
+ offset = 0,
+) {
+ return writeU_Int8(this, value, offset, 0, 0xff);
+};
+
+Buffer.prototype.writeUint16LE =
+ Buffer.prototype.writeUInt16LE =
+ function writeUInt16LE(value, offset = 0) {
+ return writeU_Int16LE(this, value, offset, 0, 0xffff);
+ };
+
+Buffer.prototype.writeUint16BE =
+ Buffer.prototype.writeUInt16BE =
+ function writeUInt16BE(value, offset = 0) {
+ return writeU_Int16BE(this, value, offset, 0, 0xffff);
+ };
+
+Buffer.prototype.writeUint32LE =
+ Buffer.prototype.writeUInt32LE =
+ function writeUInt32LE(value, offset = 0) {
+ return _writeUInt32LE(this, value, offset, 0, 0xffffffff);
+ };
+
+Buffer.prototype.writeUint32BE =
+ Buffer.prototype.writeUInt32BE =
+ function writeUInt32BE(value, offset = 0) {
+ return _writeUInt32BE(this, value, offset, 0, 0xffffffff);
+ };
+
+function wrtBigUInt64LE(buf, value, offset, min, max) {
+ checkIntBI(value, min, max, buf, offset, 7);
+ let lo = Number(value & BigInt(4294967295));
+ buf[offset++] = lo;
+ lo = lo >> 8;
+ buf[offset++] = lo;
+ lo = lo >> 8;
+ buf[offset++] = lo;
+ lo = lo >> 8;
+ buf[offset++] = lo;
+ let hi = Number(value >> BigInt(32) & BigInt(4294967295));
+ buf[offset++] = hi;
+ hi = hi >> 8;
+ buf[offset++] = hi;
+ hi = hi >> 8;
+ buf[offset++] = hi;
+ hi = hi >> 8;
+ buf[offset++] = hi;
+ return offset;
+}
+
+function wrtBigUInt64BE(buf, value, offset, min, max) {
+ checkIntBI(value, min, max, buf, offset, 7);
+ let lo = Number(value & BigInt(4294967295));
+ buf[offset + 7] = lo;
+ lo = lo >> 8;
+ buf[offset + 6] = lo;
+ lo = lo >> 8;
+ buf[offset + 5] = lo;
+ lo = lo >> 8;
+ buf[offset + 4] = lo;
+ let hi = Number(value >> BigInt(32) & BigInt(4294967295));
+ buf[offset + 3] = hi;
+ hi = hi >> 8;
+ buf[offset + 2] = hi;
+ hi = hi >> 8;
+ buf[offset + 1] = hi;
+ hi = hi >> 8;
+ buf[offset] = hi;
+ return offset + 8;
+}
+
+Buffer.prototype.writeBigUint64LE =
+ Buffer.prototype.writeBigUInt64LE =
+ defineBigIntMethod(
+ function writeBigUInt64LE(value, offset = 0) {
+ return wrtBigUInt64LE(
+ this,
+ value,
+ offset,
+ BigInt(0),
+ BigInt("0xffffffffffffffff"),
+ );
+ },
+ );
+
+Buffer.prototype.writeBigUint64BE =
+ Buffer.prototype.writeBigUInt64BE =
+ defineBigIntMethod(
+ function writeBigUInt64BE(value, offset = 0) {
+ return wrtBigUInt64BE(
+ this,
+ value,
+ offset,
+ BigInt(0),
+ BigInt("0xffffffffffffffff"),
+ );
+ },
+ );
+
+Buffer.prototype.writeIntLE = function writeIntLE(
+ value,
+ offset,
+ byteLength,
+) {
+ if (byteLength === 6) {
+ return writeU_Int48LE(
+ this,
+ value,
+ offset,
+ -0x800000000000,
+ 0x7fffffffffff,
+ );
+ }
+ if (byteLength === 5) {
+ return writeU_Int40LE(this, value, offset, -0x8000000000, 0x7fffffffff);
+ }
+ if (byteLength === 3) {
+ return writeU_Int24LE(this, value, offset, -0x800000, 0x7fffff);
+ }
+ if (byteLength === 4) {
+ return writeU_Int32LE(this, value, offset, -0x80000000, 0x7fffffff);
+ }
+ if (byteLength === 2) {
+ return writeU_Int16LE(this, value, offset, -0x8000, 0x7fff);
+ }
+ if (byteLength === 1) {
+ return writeU_Int8(this, value, offset, -0x80, 0x7f);
+ }
+
+ boundsError(byteLength, 6, "byteLength");
+};
+
+Buffer.prototype.writeIntBE = function writeIntBE(
+ value,
+ offset,
+ byteLength,
+) {
+ if (byteLength === 6) {
+ return writeU_Int48BE(
+ this,
+ value,
+ offset,
+ -0x800000000000,
+ 0x7fffffffffff,
+ );
+ }
+ if (byteLength === 5) {
+ return writeU_Int40BE(this, value, offset, -0x8000000000, 0x7fffffffff);
+ }
+ if (byteLength === 3) {
+ return writeU_Int24BE(this, value, offset, -0x800000, 0x7fffff);
+ }
+ if (byteLength === 4) {
+ return writeU_Int32BE(this, value, offset, -0x80000000, 0x7fffffff);
+ }
+ if (byteLength === 2) {
+ return writeU_Int16BE(this, value, offset, -0x8000, 0x7fff);
+ }
+ if (byteLength === 1) {
+ return writeU_Int8(this, value, offset, -0x80, 0x7f);
+ }
+
+ boundsError(byteLength, 6, "byteLength");
+};
+
+Buffer.prototype.writeInt8 = function writeInt8(value, offset = 0) {
+ return writeU_Int8(this, value, offset, -0x80, 0x7f);
+};
+
+Buffer.prototype.writeInt16LE = function writeInt16LE(value, offset = 0) {
+ return writeU_Int16LE(this, value, offset, -0x8000, 0x7fff);
+};
+
+Buffer.prototype.writeInt16BE = function writeInt16BE(
+ value,
+ offset = 0,
+) {
+ return writeU_Int16BE(this, value, offset, -0x8000, 0x7fff);
+};
+
+Buffer.prototype.writeInt32LE = function writeInt32LE(value, offset = 0) {
+ return writeU_Int32LE(this, value, offset, -0x80000000, 0x7fffffff);
+};
+
+Buffer.prototype.writeInt32BE = function writeInt32BE(value, offset = 0) {
+ return writeU_Int32BE(this, value, offset, -0x80000000, 0x7fffffff);
+};
+
+Buffer.prototype.writeBigInt64LE = defineBigIntMethod(
+ function writeBigInt64LE(value, offset = 0) {
+ return wrtBigUInt64LE(
+ this,
+ value,
+ offset,
+ -BigInt("0x8000000000000000"),
+ BigInt("0x7fffffffffffffff"),
+ );
+ },
+);
+
+Buffer.prototype.writeBigInt64BE = defineBigIntMethod(
+ function writeBigInt64BE(value, offset = 0) {
+ return wrtBigUInt64BE(
+ this,
+ value,
+ offset,
+ -BigInt("0x8000000000000000"),
+ BigInt("0x7fffffffffffffff"),
+ );
+ },
+);
+
+Buffer.prototype.writeFloatLE = function writeFloatLE(
+ value,
+ offset,
+) {
+ return bigEndian
+ ? writeFloatBackwards(this, value, offset)
+ : writeFloatForwards(this, value, offset);
+};
+
+Buffer.prototype.writeFloatBE = function writeFloatBE(
+ value,
+ offset,
+) {
+ return bigEndian
+ ? writeFloatForwards(this, value, offset)
+ : writeFloatBackwards(this, value, offset);
+};
+
+Buffer.prototype.writeDoubleLE = function writeDoubleLE(
+ value,
+ offset,
+) {
+ return bigEndian
+ ? writeDoubleBackwards(this, value, offset)
+ : writeDoubleForwards(this, value, offset);
+};
+
+Buffer.prototype.writeDoubleBE = function writeDoubleBE(
+ value,
+ offset,
+) {
+ return bigEndian
+ ? writeDoubleForwards(this, value, offset)
+ : writeDoubleBackwards(this, value, offset);
+};
+
+Buffer.prototype.copy = function copy(
+ target,
+ targetStart,
+ sourceStart,
+ sourceEnd,
+) {
+ if (!isUint8Array(this)) {
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ "source",
+ ["Buffer", "Uint8Array"],
+ this,
+ );
+ }
+
+ if (!isUint8Array(target)) {
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ "target",
+ ["Buffer", "Uint8Array"],
+ target,
+ );
+ }
+
+ if (targetStart === undefined) {
+ targetStart = 0;
+ } else {
+ targetStart = toInteger(targetStart, 0);
+ if (targetStart < 0) {
+ throw new codes.ERR_OUT_OF_RANGE("targetStart", ">= 0", targetStart);
+ }
+ }
+
+ if (sourceStart === undefined) {
+ sourceStart = 0;
+ } else {
+ sourceStart = toInteger(sourceStart, 0);
+ if (sourceStart < 0) {
+ throw new codes.ERR_OUT_OF_RANGE("sourceStart", ">= 0", sourceStart);
+ }
+ if (sourceStart >= MAX_UINT32) {
+ throw new codes.ERR_OUT_OF_RANGE(
+ "sourceStart",
+ `< ${MAX_UINT32}`,
+ sourceStart,
+ );
+ }
+ }
+
+ if (sourceEnd === undefined) {
+ sourceEnd = this.length;
+ } else {
+ sourceEnd = toInteger(sourceEnd, 0);
+ if (sourceEnd < 0) {
+ throw new codes.ERR_OUT_OF_RANGE("sourceEnd", ">= 0", sourceEnd);
+ }
+ if (sourceEnd >= MAX_UINT32) {
+ throw new codes.ERR_OUT_OF_RANGE(
+ "sourceEnd",
+ `< ${MAX_UINT32}`,
+ sourceEnd,
+ );
+ }
+ }
+
+ if (targetStart >= target.length) {
+ return 0;
+ }
+
+ if (sourceEnd > 0 && sourceEnd < sourceStart) {
+ sourceEnd = sourceStart;
+ }
+ if (sourceEnd === sourceStart) {
+ return 0;
+ }
+ if (target.length === 0 || this.length === 0) {
+ return 0;
+ }
+
+ if (sourceEnd > this.length) {
+ sourceEnd = this.length;
+ }
+
+ if (target.length - targetStart < sourceEnd - sourceStart) {
+ sourceEnd = target.length - targetStart + sourceStart;
+ }
+
+ const len = sourceEnd - sourceStart;
+ if (
+ this === target && typeof Uint8Array.prototype.copyWithin === "function"
+ ) {
+ this.copyWithin(targetStart, sourceStart, sourceEnd);
+ } else {
+ Uint8Array.prototype.set.call(
+ target,
+ this.subarray(sourceStart, sourceEnd),
+ targetStart,
+ );
+ }
+ return len;
+};
+
+Buffer.prototype.fill = function fill(val, start, end, encoding) {
+ if (typeof val === "string") {
+ if (typeof start === "string") {
+ encoding = start;
+ start = 0;
+ end = this.length;
+ } else if (typeof end === "string") {
+ encoding = end;
+ end = this.length;
+ }
+ if (encoding !== void 0 && typeof encoding !== "string") {
+ throw new TypeError("encoding must be a string");
+ }
+ if (typeof encoding === "string" && !Buffer.isEncoding(encoding)) {
+ throw new TypeError("Unknown encoding: " + encoding);
+ }
+ if (val.length === 1) {
+ const code = val.charCodeAt(0);
+ if (encoding === "utf8" && code < 128 || encoding === "latin1") {
+ val = code;
+ }
+ }
+ } else if (typeof val === "number") {
+ val = val & 255;
+ } else if (typeof val === "boolean") {
+ val = Number(val);
+ }
+ if (start < 0 || this.length < start || this.length < end) {
+ throw new RangeError("Out of range index");
+ }
+ if (end <= start) {
+ return this;
+ }
+ start = start >>> 0;
+ end = end === void 0 ? this.length : end >>> 0;
+ if (!val) {
+ val = 0;
+ }
+ let i;
+ if (typeof val === "number") {
+ for (i = start; i < end; ++i) {
+ this[i] = val;
+ }
+ } else {
+ const bytes = Buffer.isBuffer(val) ? val : Buffer.from(val, encoding);
+ const len = bytes.length;
+ if (len === 0) {
+ throw new codes.ERR_INVALID_ARG_VALUE(
+ "value",
+ val,
+ );
+ }
+ for (i = 0; i < end - start; ++i) {
+ this[i + start] = bytes[i % len];
+ }
+ }
+ return this;
+};
+
+function checkBounds(buf, offset, byteLength2) {
+ validateNumber(offset, "offset");
+ if (buf[offset] === void 0 || buf[offset + byteLength2] === void 0) {
+ boundsError(offset, buf.length - (byteLength2 + 1));
+ }
+}
+
+function checkIntBI(value, min, max, buf, offset, byteLength2) {
+ if (value > max || value < min) {
+ const n = typeof min === "bigint" ? "n" : "";
+ let range;
+ if (byteLength2 > 3) {
+ if (min === 0 || min === BigInt(0)) {
+ range = `>= 0${n} and < 2${n} ** ${(byteLength2 + 1) * 8}${n}`;
+ } else {
+ range = `>= -(2${n} ** ${(byteLength2 + 1) * 8 - 1}${n}) and < 2 ** ${
+ (byteLength2 + 1) * 8 - 1
+ }${n}`;
+ }
+ } else {
+ range = `>= ${min}${n} and <= ${max}${n}`;
+ }
+ throw new codes.ERR_OUT_OF_RANGE("value", range, value);
+ }
+ checkBounds(buf, offset, byteLength2);
+}
+
+function utf8ToBytes(string, units) {
+ units = units || Infinity;
+ let codePoint;
+ const length = string.length;
+ let leadSurrogate = null;
+ const bytes = [];
+ for (let i = 0; i < length; ++i) {
+ codePoint = string.charCodeAt(i);
+ if (codePoint > 55295 && codePoint < 57344) {
+ if (!leadSurrogate) {
+ if (codePoint > 56319) {
+ if ((units -= 3) > -1) {
+ bytes.push(239, 191, 189);
+ }
+ continue;
+ } else if (i + 1 === length) {
+ if ((units -= 3) > -1) {
+ bytes.push(239, 191, 189);
+ }
+ continue;
+ }
+ leadSurrogate = codePoint;
+ continue;
+ }
+ if (codePoint < 56320) {
+ if ((units -= 3) > -1) {
+ bytes.push(239, 191, 189);
+ }
+ leadSurrogate = codePoint;
+ continue;
+ }
+ codePoint = (leadSurrogate - 55296 << 10 | codePoint - 56320) + 65536;
+ } else if (leadSurrogate) {
+ if ((units -= 3) > -1) {
+ bytes.push(239, 191, 189);
+ }
+ }
+ leadSurrogate = null;
+ if (codePoint < 128) {
+ if ((units -= 1) < 0) {
+ break;
+ }
+ bytes.push(codePoint);
+ } else if (codePoint < 2048) {
+ if ((units -= 2) < 0) {
+ break;
+ }
+ bytes.push(codePoint >> 6 | 192, codePoint & 63 | 128);
+ } else if (codePoint < 65536) {
+ if ((units -= 3) < 0) {
+ break;
+ }
+ bytes.push(
+ codePoint >> 12 | 224,
+ codePoint >> 6 & 63 | 128,
+ codePoint & 63 | 128,
+ );
+ } else if (codePoint < 1114112) {
+ if ((units -= 4) < 0) {
+ break;
+ }
+ bytes.push(
+ codePoint >> 18 | 240,
+ codePoint >> 12 & 63 | 128,
+ codePoint >> 6 & 63 | 128,
+ codePoint & 63 | 128,
+ );
+ } else {
+ throw new Error("Invalid code point");
+ }
+ }
+ return bytes;
+}
+
+function blitBuffer(src, dst, offset, byteLength) {
+ let i;
+ const length = byteLength === undefined ? src.length : byteLength;
+ for (i = 0; i < length; ++i) {
+ if (i + offset >= dst.length || i >= src.length) {
+ break;
+ }
+ dst[i + offset] = src[i];
+ }
+ return i;
+}
+
+function isInstance(obj, type) {
+ return obj instanceof type ||
+ obj != null && obj.constructor != null &&
+ obj.constructor.name != null && obj.constructor.name === type.name;
+}
+
+const hexSliceLookupTable = function () {
+ const alphabet = "0123456789abcdef";
+ const table = new Array(256);
+ for (let i = 0; i < 16; ++i) {
+ const i16 = i * 16;
+ for (let j = 0; j < 16; ++j) {
+ table[i16 + j] = alphabet[i] + alphabet[j];
+ }
+ }
+ return table;
+}();
+
+function defineBigIntMethod(fn) {
+ return typeof BigInt === "undefined" ? BufferBigIntNotDefined : fn;
+}
+
+function BufferBigIntNotDefined() {
+ throw new Error("BigInt not supported");
+}
+
+export const atob = globalThis.atob;
+export const Blob = globalThis.Blob;
+export const btoa = globalThis.btoa;
+
+export function readUInt48LE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 5];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 6);
+ }
+
+ return first +
+ buf[++offset] * 2 ** 8 +
+ buf[++offset] * 2 ** 16 +
+ buf[++offset] * 2 ** 24 +
+ (buf[++offset] + last * 2 ** 8) * 2 ** 32;
+}
+
+export function readUInt40LE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 4];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 5);
+ }
+
+ return first +
+ buf[++offset] * 2 ** 8 +
+ buf[++offset] * 2 ** 16 +
+ buf[++offset] * 2 ** 24 +
+ last * 2 ** 32;
+}
+
+export function readUInt24LE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 2];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 3);
+ }
+
+ return first + buf[++offset] * 2 ** 8 + last * 2 ** 16;
+}
+
+export function readUInt48BE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 5];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 6);
+ }
+
+ return (first * 2 ** 8 + buf[++offset]) * 2 ** 32 +
+ buf[++offset] * 2 ** 24 +
+ buf[++offset] * 2 ** 16 +
+ buf[++offset] * 2 ** 8 +
+ last;
+}
+
+export function readUInt40BE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 4];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 5);
+ }
+
+ return first * 2 ** 32 +
+ buf[++offset] * 2 ** 24 +
+ buf[++offset] * 2 ** 16 +
+ buf[++offset] * 2 ** 8 +
+ last;
+}
+
+export function readUInt24BE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 2];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 3);
+ }
+
+ return first * 2 ** 16 + buf[++offset] * 2 ** 8 + last;
+}
+
+export function readUInt16BE(offset = 0) {
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 1];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, this.length - 2);
+ }
+
+ return first * 2 ** 8 + last;
+}
+
+export function readUInt32BE(offset = 0) {
+ validateNumber(offset, "offset");
+ const first = this[offset];
+ const last = this[offset + 3];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, this.length - 4);
+ }
+
+ return first * 2 ** 24 +
+ this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 8 +
+ last;
+}
+
+export function readDoubleBackwards(buffer, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buffer[offset];
+ const last = buffer[offset + 7];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buffer.length - 8);
+ }
+
+ uInt8Float64Array[7] = first;
+ uInt8Float64Array[6] = buffer[++offset];
+ uInt8Float64Array[5] = buffer[++offset];
+ uInt8Float64Array[4] = buffer[++offset];
+ uInt8Float64Array[3] = buffer[++offset];
+ uInt8Float64Array[2] = buffer[++offset];
+ uInt8Float64Array[1] = buffer[++offset];
+ uInt8Float64Array[0] = last;
+ return float64Array[0];
+}
+
+export function readDoubleForwards(buffer, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buffer[offset];
+ const last = buffer[offset + 7];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buffer.length - 8);
+ }
+
+ uInt8Float64Array[0] = first;
+ uInt8Float64Array[1] = buffer[++offset];
+ uInt8Float64Array[2] = buffer[++offset];
+ uInt8Float64Array[3] = buffer[++offset];
+ uInt8Float64Array[4] = buffer[++offset];
+ uInt8Float64Array[5] = buffer[++offset];
+ uInt8Float64Array[6] = buffer[++offset];
+ uInt8Float64Array[7] = last;
+ return float64Array[0];
+}
+
+export function writeDoubleForwards(buffer, val, offset = 0) {
+ val = +val;
+ checkBounds(buffer, offset, 7);
+
+ float64Array[0] = val;
+ buffer[offset++] = uInt8Float64Array[0];
+ buffer[offset++] = uInt8Float64Array[1];
+ buffer[offset++] = uInt8Float64Array[2];
+ buffer[offset++] = uInt8Float64Array[3];
+ buffer[offset++] = uInt8Float64Array[4];
+ buffer[offset++] = uInt8Float64Array[5];
+ buffer[offset++] = uInt8Float64Array[6];
+ buffer[offset++] = uInt8Float64Array[7];
+ return offset;
+}
+
+export function writeDoubleBackwards(buffer, val, offset = 0) {
+ val = +val;
+ checkBounds(buffer, offset, 7);
+
+ float64Array[0] = val;
+ buffer[offset++] = uInt8Float64Array[7];
+ buffer[offset++] = uInt8Float64Array[6];
+ buffer[offset++] = uInt8Float64Array[5];
+ buffer[offset++] = uInt8Float64Array[4];
+ buffer[offset++] = uInt8Float64Array[3];
+ buffer[offset++] = uInt8Float64Array[2];
+ buffer[offset++] = uInt8Float64Array[1];
+ buffer[offset++] = uInt8Float64Array[0];
+ return offset;
+}
+
+export function readFloatBackwards(buffer, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buffer[offset];
+ const last = buffer[offset + 3];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buffer.length - 4);
+ }
+
+ uInt8Float32Array[3] = first;
+ uInt8Float32Array[2] = buffer[++offset];
+ uInt8Float32Array[1] = buffer[++offset];
+ uInt8Float32Array[0] = last;
+ return float32Array[0];
+}
+
+export function readFloatForwards(buffer, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buffer[offset];
+ const last = buffer[offset + 3];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buffer.length - 4);
+ }
+
+ uInt8Float32Array[0] = first;
+ uInt8Float32Array[1] = buffer[++offset];
+ uInt8Float32Array[2] = buffer[++offset];
+ uInt8Float32Array[3] = last;
+ return float32Array[0];
+}
+
+export function writeFloatForwards(buffer, val, offset = 0) {
+ val = +val;
+ checkBounds(buffer, offset, 3);
+
+ float32Array[0] = val;
+ buffer[offset++] = uInt8Float32Array[0];
+ buffer[offset++] = uInt8Float32Array[1];
+ buffer[offset++] = uInt8Float32Array[2];
+ buffer[offset++] = uInt8Float32Array[3];
+ return offset;
+}
+
+export function writeFloatBackwards(buffer, val, offset = 0) {
+ val = +val;
+ checkBounds(buffer, offset, 3);
+
+ float32Array[0] = val;
+ buffer[offset++] = uInt8Float32Array[3];
+ buffer[offset++] = uInt8Float32Array[2];
+ buffer[offset++] = uInt8Float32Array[1];
+ buffer[offset++] = uInt8Float32Array[0];
+ return offset;
+}
+
+export function readInt24LE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 2];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 3);
+ }
+
+ const val = first + buf[++offset] * 2 ** 8 + last * 2 ** 16;
+ return val | (val & 2 ** 23) * 0x1fe;
+}
+
+export function readInt40LE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 4];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 5);
+ }
+
+ return (last | (last & 2 ** 7) * 0x1fffffe) * 2 ** 32 +
+ first +
+ buf[++offset] * 2 ** 8 +
+ buf[++offset] * 2 ** 16 +
+ buf[++offset] * 2 ** 24;
+}
+
+export function readInt48LE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 5];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 6);
+ }
+
+ const val = buf[offset + 4] + last * 2 ** 8;
+ return (val | (val & 2 ** 15) * 0x1fffe) * 2 ** 32 +
+ first +
+ buf[++offset] * 2 ** 8 +
+ buf[++offset] * 2 ** 16 +
+ buf[++offset] * 2 ** 24;
+}
+
+export function readInt24BE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 2];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 3);
+ }
+
+ const val = first * 2 ** 16 + buf[++offset] * 2 ** 8 + last;
+ return val | (val & 2 ** 23) * 0x1fe;
+}
+
+export function readInt48BE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 5];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 6);
+ }
+
+ const val = buf[++offset] + first * 2 ** 8;
+ return (val | (val & 2 ** 15) * 0x1fffe) * 2 ** 32 +
+ buf[++offset] * 2 ** 24 +
+ buf[++offset] * 2 ** 16 +
+ buf[++offset] * 2 ** 8 +
+ last;
+}
+
+export function readInt40BE(buf, offset = 0) {
+ validateNumber(offset, "offset");
+ const first = buf[offset];
+ const last = buf[offset + 4];
+ if (first === undefined || last === undefined) {
+ boundsError(offset, buf.length - 5);
+ }
+
+ return (first | (first & 2 ** 7) * 0x1fffffe) * 2 ** 32 +
+ buf[++offset] * 2 ** 24 +
+ buf[++offset] * 2 ** 16 +
+ buf[++offset] * 2 ** 8 +
+ last;
+}
+
+export function byteLengthUtf8(str) {
+ return utf8Encoder.encode(str).length;
+}
+
+function base64ByteLength(str, bytes) {
+ // Handle padding
+ if (str.charCodeAt(bytes - 1) === 0x3D) {
+ bytes--;
+ }
+ if (bytes > 1 && str.charCodeAt(bytes - 1) === 0x3D) {
+ bytes--;
+ }
+
+ // Base64 ratio: 3/4
+ return (bytes * 3) >>> 2;
+}
+
+export const encodingsMap = Object.create(null);
+for (let i = 0; i < encodings.length; ++i) {
+ encodingsMap[encodings[i]] = i;
+}
+
+export const encodingOps = {
+ ascii: {
+ byteLength: (string) => string.length,
+ encoding: "ascii",
+ encodingVal: encodingsMap.ascii,
+ indexOf: (buf, val, byteOffset, dir) =>
+ indexOfBuffer(
+ buf,
+ asciiToBytes(val),
+ byteOffset,
+ encodingsMap.ascii,
+ dir,
+ ),
+ slice: (buf, start, end) => buf.asciiSlice(start, end),
+ write: (buf, string, offset, len) => buf.asciiWrite(string, offset, len),
+ },
+ base64: {
+ byteLength: (string) => base64ByteLength(string, string.length),
+ encoding: "base64",
+ encodingVal: encodingsMap.base64,
+ indexOf: (buf, val, byteOffset, dir) =>
+ indexOfBuffer(
+ buf,
+ base64ToBytes(val),
+ byteOffset,
+ encodingsMap.base64,
+ dir,
+ ),
+ slice: (buf, start, end) => buf.base64Slice(start, end),
+ write: (buf, string, offset, len) => buf.base64Write(string, offset, len),
+ },
+ base64url: {
+ byteLength: (string) => base64ByteLength(string, string.length),
+ encoding: "base64url",
+ encodingVal: encodingsMap.base64url,
+ indexOf: (buf, val, byteOffset, dir) =>
+ indexOfBuffer(
+ buf,
+ base64UrlToBytes(val),
+ byteOffset,
+ encodingsMap.base64url,
+ dir,
+ ),
+ slice: (buf, start, end) => buf.base64urlSlice(start, end),
+ write: (buf, string, offset, len) =>
+ buf.base64urlWrite(string, offset, len),
+ },
+ hex: {
+ byteLength: (string) => string.length >>> 1,
+ encoding: "hex",
+ encodingVal: encodingsMap.hex,
+ indexOf: (buf, val, byteOffset, dir) =>
+ indexOfBuffer(
+ buf,
+ hexToBytes(val),
+ byteOffset,
+ encodingsMap.hex,
+ dir,
+ ),
+ slice: (buf, start, end) => buf.hexSlice(start, end),
+ write: (buf, string, offset, len) => buf.hexWrite(string, offset, len),
+ },
+ latin1: {
+ byteLength: (string) => string.length,
+ encoding: "latin1",
+ encodingVal: encodingsMap.latin1,
+ indexOf: (buf, val, byteOffset, dir) =>
+ indexOfBuffer(
+ buf,
+ asciiToBytes(val),
+ byteOffset,
+ encodingsMap.latin1,
+ dir,
+ ),
+ slice: (buf, start, end) => buf.latin1Slice(start, end),
+ write: (buf, string, offset, len) => buf.latin1Write(string, offset, len),
+ },
+ ucs2: {
+ byteLength: (string) => string.length * 2,
+ encoding: "ucs2",
+ encodingVal: encodingsMap.utf16le,
+ indexOf: (buf, val, byteOffset, dir) =>
+ indexOfBuffer(
+ buf,
+ utf16leToBytes(val),
+ byteOffset,
+ encodingsMap.utf16le,
+ dir,
+ ),
+ slice: (buf, start, end) => buf.ucs2Slice(start, end),
+ write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len),
+ },
+ utf8: {
+ byteLength: byteLengthUtf8,
+ encoding: "utf8",
+ encodingVal: encodingsMap.utf8,
+ indexOf: (buf, val, byteOffset, dir) =>
+ indexOfBuffer(
+ buf,
+ utf8Encoder.encode(val),
+ byteOffset,
+ encodingsMap.utf8,
+ dir,
+ ),
+ slice: (buf, start, end) => buf.utf8Slice(start, end),
+ write: (buf, string, offset, len) => buf.utf8Write(string, offset, len),
+ },
+ utf16le: {
+ byteLength: (string) => string.length * 2,
+ encoding: "utf16le",
+ encodingVal: encodingsMap.utf16le,
+ indexOf: (buf, val, byteOffset, dir) =>
+ indexOfBuffer(
+ buf,
+ utf16leToBytes(val),
+ byteOffset,
+ encodingsMap.utf16le,
+ dir,
+ ),
+ slice: (buf, start, end) => buf.ucs2Slice(start, end),
+ write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len),
+ },
+};
+
+export function getEncodingOps(encoding) {
+ encoding = String(encoding).toLowerCase();
+ switch (encoding.length) {
+ case 4:
+ if (encoding === "utf8") return encodingOps.utf8;
+ if (encoding === "ucs2") return encodingOps.ucs2;
+ break;
+ case 5:
+ if (encoding === "utf-8") return encodingOps.utf8;
+ if (encoding === "ascii") return encodingOps.ascii;
+ if (encoding === "ucs-2") return encodingOps.ucs2;
+ break;
+ case 7:
+ if (encoding === "utf16le") {
+ return encodingOps.utf16le;
+ }
+ break;
+ case 8:
+ if (encoding === "utf-16le") {
+ return encodingOps.utf16le;
+ }
+ break;
+ // deno-lint-ignore no-fallthrough
+ case 6:
+ if (encoding === "latin1" || encoding === "binary") {
+ return encodingOps.latin1;
+ }
+ if (encoding === "base64") return encodingOps.base64;
+ case 3:
+ if (encoding === "hex") {
+ return encodingOps.hex;
+ }
+ break;
+ case 9:
+ if (encoding === "base64url") {
+ return encodingOps.base64url;
+ }
+ break;
+ }
+}
+
+export function _copyActual(
+ source,
+ target,
+ targetStart,
+ sourceStart,
+ sourceEnd,
+) {
+ if (sourceEnd - sourceStart > target.length - targetStart) {
+ sourceEnd = sourceStart + target.length - targetStart;
+ }
+
+ let nb = sourceEnd - sourceStart;
+ const sourceLen = source.length - sourceStart;
+ if (nb > sourceLen) {
+ nb = sourceLen;
+ }
+
+ if (sourceStart !== 0 || sourceEnd < source.length) {
+ source = new Uint8Array(source.buffer, source.byteOffset + sourceStart, nb);
+ }
+
+ target.set(source, targetStart);
+
+ return nb;
+}
+
+export function boundsError(value, length, type) {
+ if (Math.floor(value) !== value) {
+ validateNumber(value, type);
+ throw new codes.ERR_OUT_OF_RANGE(type || "offset", "an integer", value);
+ }
+
+ if (length < 0) {
+ throw new codes.ERR_BUFFER_OUT_OF_BOUNDS();
+ }
+
+ throw new codes.ERR_OUT_OF_RANGE(
+ type || "offset",
+ `>= ${type ? 1 : 0} and <= ${length}`,
+ value,
+ );
+}
+
+export function validateNumber(value, name) {
+ if (typeof value !== "number") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "number", value);
+ }
+}
+
+function checkInt(value, min, max, buf, offset, byteLength) {
+ if (value > max || value < min) {
+ const n = typeof min === "bigint" ? "n" : "";
+ let range;
+ if (byteLength > 3) {
+ if (min === 0 || min === 0n) {
+ range = `>= 0${n} and < 2${n} ** ${(byteLength + 1) * 8}${n}`;
+ } else {
+ range = `>= -(2${n} ** ${(byteLength + 1) * 8 - 1}${n}) and ` +
+ `< 2${n} ** ${(byteLength + 1) * 8 - 1}${n}`;
+ }
+ } else {
+ range = `>= ${min}${n} and <= ${max}${n}`;
+ }
+ throw new codes.ERR_OUT_OF_RANGE("value", range, value);
+ }
+ checkBounds(buf, offset, byteLength);
+}
+
+export function toInteger(n, defaultVal) {
+ n = +n;
+ if (
+ !Number.isNaN(n) &&
+ n >= Number.MIN_SAFE_INTEGER &&
+ n <= Number.MAX_SAFE_INTEGER
+ ) {
+ return ((n % 1) === 0 ? n : Math.floor(n));
+ }
+ return defaultVal;
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int8(buf, value, offset, min, max) {
+ value = +value;
+ validateNumber(offset, "offset");
+ if (value > max || value < min) {
+ throw new codes.ERR_OUT_OF_RANGE("value", `>= ${min} and <= ${max}`, value);
+ }
+ if (buf[offset] === undefined) {
+ boundsError(offset, buf.length - 1);
+ }
+
+ buf[offset] = value;
+ return offset + 1;
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int16BE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 1);
+
+ buf[offset++] = value >>> 8;
+ buf[offset++] = value;
+ return offset;
+}
+
+export function _writeUInt32LE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 3);
+
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ return offset;
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int16LE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 1);
+
+ buf[offset++] = value;
+ buf[offset++] = value >>> 8;
+ return offset;
+}
+
+export function _writeUInt32BE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 3);
+
+ buf[offset + 3] = value;
+ value = value >>> 8;
+ buf[offset + 2] = value;
+ value = value >>> 8;
+ buf[offset + 1] = value;
+ value = value >>> 8;
+ buf[offset] = value;
+ return offset + 4;
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int48BE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 5);
+
+ const newVal = Math.floor(value * 2 ** -32);
+ buf[offset++] = newVal >>> 8;
+ buf[offset++] = newVal;
+ buf[offset + 3] = value;
+ value = value >>> 8;
+ buf[offset + 2] = value;
+ value = value >>> 8;
+ buf[offset + 1] = value;
+ value = value >>> 8;
+ buf[offset] = value;
+ return offset + 4;
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int40BE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 4);
+
+ buf[offset++] = Math.floor(value * 2 ** -32);
+ buf[offset + 3] = value;
+ value = value >>> 8;
+ buf[offset + 2] = value;
+ value = value >>> 8;
+ buf[offset + 1] = value;
+ value = value >>> 8;
+ buf[offset] = value;
+ return offset + 4;
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int32BE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 3);
+
+ buf[offset + 3] = value;
+ value = value >>> 8;
+ buf[offset + 2] = value;
+ value = value >>> 8;
+ buf[offset + 1] = value;
+ value = value >>> 8;
+ buf[offset] = value;
+ return offset + 4;
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int24BE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 2);
+
+ buf[offset + 2] = value;
+ value = value >>> 8;
+ buf[offset + 1] = value;
+ value = value >>> 8;
+ buf[offset] = value;
+ return offset + 3;
+}
+
+export function validateOffset(
+ value,
+ name,
+ min = 0,
+ max = Number.MAX_SAFE_INTEGER,
+) {
+ if (typeof value !== "number") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "number", value);
+ }
+ if (!Number.isInteger(value)) {
+ throw new codes.ERR_OUT_OF_RANGE(name, "an integer", value);
+ }
+ if (value < min || value > max) {
+ throw new codes.ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
+ }
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int48LE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 5);
+
+ const newVal = Math.floor(value * 2 ** -32);
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ buf[offset++] = newVal;
+ buf[offset++] = newVal >>> 8;
+ return offset;
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int40LE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 4);
+
+ const newVal = value;
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ buf[offset++] = Math.floor(newVal * 2 ** -32);
+ return offset;
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int32LE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 3);
+
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ return offset;
+}
+
+// deno-lint-ignore camelcase
+export function writeU_Int24LE(buf, value, offset, min, max) {
+ value = +value;
+ checkInt(value, min, max, buf, offset, 2);
+
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ value = value >>> 8;
+ buf[offset++] = value;
+ return offset;
+}
+
+export default {
+ atob,
+ btoa,
+ Blob,
+ Buffer,
+ constants,
+ kMaxLength,
+ kStringMaxLength,
+ SlowBuffer,
+};
diff --git a/ext/node/polyfills/internal/child_process.ts b/ext/node/polyfills/internal/child_process.ts
new file mode 100644
index 000000000..92aa8d4fa
--- /dev/null
+++ b/ext/node/polyfills/internal/child_process.ts
@@ -0,0 +1,1026 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+// This module implements 'child_process' module of Node.JS API.
+// ref: https://nodejs.org/api/child_process.html
+import { assert } from "internal:deno_node/polyfills/_util/asserts.ts";
+import { EventEmitter } from "internal:deno_node/polyfills/events.ts";
+import { os } from "internal:deno_node/polyfills/internal_binding/constants.ts";
+import {
+ notImplemented,
+ warnNotImplemented,
+} from "internal:deno_node/polyfills/_utils.ts";
+import {
+ Readable,
+ Stream,
+ Writable,
+} from "internal:deno_node/polyfills/stream.ts";
+import { deferred } from "internal:deno_node/polyfills/_util/async.ts";
+import { isWindows } from "internal:deno_node/polyfills/_util/os.ts";
+import { nextTick } from "internal:deno_node/polyfills/_next_tick.ts";
+import {
+ AbortError,
+ ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_ARG_VALUE,
+ ERR_UNKNOWN_SIGNAL,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { errnoException } from "internal:deno_node/polyfills/internal/errors.ts";
+import { ErrnoException } from "internal:deno_node/polyfills/_global.d.ts";
+import { codeMap } from "internal:deno_node/polyfills/internal_binding/uv.ts";
+import {
+ isInt32,
+ validateBoolean,
+ validateObject,
+ validateString,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import {
+ ArrayIsArray,
+ ArrayPrototypeFilter,
+ ArrayPrototypeJoin,
+ ArrayPrototypePush,
+ ArrayPrototypeSlice,
+ ArrayPrototypeSort,
+ ArrayPrototypeUnshift,
+ ObjectPrototypeHasOwnProperty,
+ StringPrototypeToUpperCase,
+} from "internal:deno_node/polyfills/internal/primordials.mjs";
+import { kEmptyObject } from "internal:deno_node/polyfills/internal/util.mjs";
+import { getValidatedPath } from "internal:deno_node/polyfills/internal/fs/utils.mjs";
+import process from "internal:deno_node/polyfills/process.ts";
+
+export function mapValues<T, O>(
+ record: Readonly<Record<string, T>>,
+ transformer: (value: T) => O,
+): Record<string, O> {
+ const ret: Record<string, O> = {};
+ const entries = Object.entries(record);
+
+ for (const [key, value] of entries) {
+ const mappedValue = transformer(value);
+
+ ret[key] = mappedValue;
+ }
+
+ return ret;
+}
+
+type NodeStdio = "pipe" | "overlapped" | "ignore" | "inherit" | "ipc";
+type DenoStdio = "inherit" | "piped" | "null";
+
+// @ts-ignore Deno[Deno.internal] is used on purpose here
+const DenoCommand = Deno[Deno.internal]?.nodeUnstable?.Command ||
+ Deno.Command;
+
+export function stdioStringToArray(
+ stdio: NodeStdio,
+ channel: NodeStdio | number,
+) {
+ const options: (NodeStdio | number)[] = [];
+
+ switch (stdio) {
+ case "ignore":
+ case "overlapped":
+ case "pipe":
+ options.push(stdio, stdio, stdio);
+ break;
+ case "inherit":
+ options.push(stdio, stdio, stdio);
+ break;
+ default:
+ throw new ERR_INVALID_ARG_VALUE("stdio", stdio);
+ }
+
+ if (channel) options.push(channel);
+
+ return options;
+}
+
+export class ChildProcess extends EventEmitter {
+ /**
+ * The exit code of the child process. This property will be `null` until the child process exits.
+ */
+ exitCode: number | null = null;
+
+ /**
+ * This property is set to `true` after `kill()` is called.
+ */
+ killed = false;
+
+ /**
+ * The PID of this child process.
+ */
+ pid!: number;
+
+ /**
+ * The signal received by this child process.
+ */
+ signalCode: string | null = null;
+
+ /**
+ * Command line arguments given to this child process.
+ */
+ spawnargs: string[];
+
+ /**
+ * The executable file name of this child process.
+ */
+ spawnfile: string;
+
+ /**
+ * This property represents the child process's stdin.
+ */
+ stdin: Writable | null = null;
+
+ /**
+ * This property represents the child process's stdout.
+ */
+ stdout: Readable | null = null;
+
+ /**
+ * This property represents the child process's stderr.
+ */
+ stderr: Readable | null = null;
+
+ /**
+ * Pipes to this child process.
+ */
+ stdio: [Writable | null, Readable | null, Readable | null] = [
+ null,
+ null,
+ null,
+ ];
+
+ #process!: Deno.ChildProcess;
+ #spawned = deferred<void>();
+
+ constructor(
+ command: string,
+ args?: string[],
+ options?: ChildProcessOptions,
+ ) {
+ super();
+
+ const {
+ env = {},
+ stdio = ["pipe", "pipe", "pipe"],
+ cwd,
+ shell = false,
+ signal,
+ windowsVerbatimArguments = false,
+ } = options || {};
+ const [
+ stdin = "pipe",
+ stdout = "pipe",
+ stderr = "pipe",
+ _channel, // TODO(kt3k): handle this correctly
+ ] = normalizeStdioOption(stdio);
+ const [cmd, cmdArgs] = buildCommand(
+ command,
+ args || [],
+ shell,
+ );
+ this.spawnfile = cmd;
+ this.spawnargs = [cmd, ...cmdArgs];
+
+ const stringEnv = mapValues(env, (value) => value.toString());
+
+ try {
+ this.#process = new DenoCommand(cmd, {
+ args: cmdArgs,
+ cwd,
+ env: stringEnv,
+ stdin: toDenoStdio(stdin as NodeStdio | number),
+ stdout: toDenoStdio(stdout as NodeStdio | number),
+ stderr: toDenoStdio(stderr as NodeStdio | number),
+ windowsRawArguments: windowsVerbatimArguments,
+ }).spawn();
+ this.pid = this.#process.pid;
+
+ if (stdin === "pipe") {
+ assert(this.#process.stdin);
+ this.stdin = Writable.fromWeb(this.#process.stdin);
+ }
+
+ if (stdout === "pipe") {
+ assert(this.#process.stdout);
+ this.stdout = Readable.fromWeb(this.#process.stdout);
+ }
+
+ if (stderr === "pipe") {
+ assert(this.#process.stderr);
+ this.stderr = Readable.fromWeb(this.#process.stderr);
+ }
+
+ this.stdio[0] = this.stdin;
+ this.stdio[1] = this.stdout;
+ this.stdio[2] = this.stderr;
+
+ nextTick(() => {
+ this.emit("spawn");
+ this.#spawned.resolve();
+ });
+
+ if (signal) {
+ const onAbortListener = () => {
+ try {
+ if (this.kill("SIGKILL")) {
+ this.emit("error", new AbortError());
+ }
+ } catch (err) {
+ this.emit("error", err);
+ }
+ };
+ if (signal.aborted) {
+ nextTick(onAbortListener);
+ } else {
+ signal.addEventListener("abort", onAbortListener, { once: true });
+ this.addListener(
+ "exit",
+ () => signal.removeEventListener("abort", onAbortListener),
+ );
+ }
+ }
+
+ (async () => {
+ const status = await this.#process.status;
+ this.exitCode = status.code;
+ this.#spawned.then(async () => {
+ const exitCode = this.signalCode == null ? this.exitCode : null;
+ const signalCode = this.signalCode == null ? null : this.signalCode;
+ // The 'exit' and 'close' events must be emitted after the 'spawn' event.
+ this.emit("exit", exitCode, signalCode);
+ await this.#_waitForChildStreamsToClose();
+ this.#closePipes();
+ this.emit("close", exitCode, signalCode);
+ });
+ })();
+ } catch (err) {
+ this.#_handleError(err);
+ }
+ }
+
+ /**
+ * @param signal NOTE: this parameter is not yet implemented.
+ */
+ kill(signal?: number | string): boolean {
+ if (this.killed) {
+ return this.killed;
+ }
+
+ const denoSignal = signal == null ? "SIGTERM" : toDenoSignal(signal);
+ this.#closePipes();
+ try {
+ this.#process.kill(denoSignal);
+ } catch (err) {
+ const alreadyClosed = err instanceof TypeError ||
+ err instanceof Deno.errors.PermissionDenied;
+ if (!alreadyClosed) {
+ throw err;
+ }
+ }
+ this.killed = true;
+ this.signalCode = denoSignal;
+ return this.killed;
+ }
+
+ ref() {
+ this.#process.ref();
+ }
+
+ unref() {
+ this.#process.unref();
+ }
+
+ disconnect() {
+ warnNotImplemented("ChildProcess.prototype.disconnect");
+ }
+
+ async #_waitForChildStreamsToClose() {
+ const promises = [] as Array<Promise<void>>;
+ if (this.stdin && !this.stdin.destroyed) {
+ assert(this.stdin);
+ this.stdin.destroy();
+ promises.push(waitForStreamToClose(this.stdin));
+ }
+ if (this.stdout && !this.stdout.destroyed) {
+ promises.push(waitForReadableToClose(this.stdout));
+ }
+ if (this.stderr && !this.stderr.destroyed) {
+ promises.push(waitForReadableToClose(this.stderr));
+ }
+ await Promise.all(promises);
+ }
+
+ #_handleError(err: unknown) {
+ nextTick(() => {
+ this.emit("error", err); // TODO(uki00a) Convert `err` into nodejs's `SystemError` class.
+ });
+ }
+
+ #closePipes() {
+ if (this.stdin) {
+ assert(this.stdin);
+ this.stdin.destroy();
+ }
+ }
+}
+
+const supportedNodeStdioTypes: NodeStdio[] = ["pipe", "ignore", "inherit"];
+function toDenoStdio(
+ pipe: NodeStdio | number | Stream | null | undefined,
+): DenoStdio {
+ if (
+ !supportedNodeStdioTypes.includes(pipe as NodeStdio) ||
+ typeof pipe === "number" || pipe instanceof Stream
+ ) {
+ notImplemented(`toDenoStdio pipe=${typeof pipe} (${pipe})`);
+ }
+ switch (pipe) {
+ case "pipe":
+ case undefined:
+ case null:
+ return "piped";
+ case "ignore":
+ return "null";
+ case "inherit":
+ return "inherit";
+ default:
+ notImplemented(`toDenoStdio pipe=${typeof pipe} (${pipe})`);
+ }
+}
+
+function toDenoSignal(signal: number | string): Deno.Signal {
+ if (typeof signal === "number") {
+ for (const name of keys(os.signals)) {
+ if (os.signals[name] === signal) {
+ return name as Deno.Signal;
+ }
+ }
+ throw new ERR_UNKNOWN_SIGNAL(String(signal));
+ }
+
+ const denoSignal = signal as Deno.Signal;
+ if (denoSignal in os.signals) {
+ return denoSignal;
+ }
+ throw new ERR_UNKNOWN_SIGNAL(signal);
+}
+
+function keys<T extends Record<string, unknown>>(object: T): Array<keyof T> {
+ return Object.keys(object);
+}
+
+export interface ChildProcessOptions {
+ /**
+ * Current working directory of the child process.
+ */
+ cwd?: string | URL;
+
+ /**
+ * Environment variables passed to the child process.
+ */
+ env?: Record<string, string | number | boolean>;
+
+ /**
+ * This option defines child process's stdio configuration.
+ * @see https://nodejs.org/api/child_process.html#child_process_options_stdio
+ */
+ stdio?: Array<NodeStdio | number | Stream | null | undefined> | NodeStdio;
+
+ /**
+ * NOTE: This option is not yet implemented.
+ */
+ detached?: boolean;
+
+ /**
+ * NOTE: This option is not yet implemented.
+ */
+ uid?: number;
+
+ /**
+ * NOTE: This option is not yet implemented.
+ */
+ gid?: number;
+
+ /**
+ * NOTE: This option is not yet implemented.
+ */
+ argv0?: string;
+
+ /**
+ * * If this option is `true`, run the command in the shell.
+ * * If this option is a string, run the command in the specified shell.
+ */
+ shell?: string | boolean;
+
+ /**
+ * Allows aborting the child process using an AbortSignal.
+ */
+ signal?: AbortSignal;
+
+ /**
+ * NOTE: This option is not yet implemented.
+ */
+ serialization?: "json" | "advanced";
+
+ /** No quoting or escaping of arguments is done on Windows. Ignored on Unix.
+ * Default: false. */
+ windowsVerbatimArguments?: boolean;
+
+ /**
+ * NOTE: This option is not yet implemented.
+ */
+ windowsHide?: boolean;
+}
+
+function copyProcessEnvToEnv(
+ env: Record<string, string | number | boolean | undefined>,
+ name: string,
+ optionEnv?: Record<string, string | number | boolean>,
+) {
+ if (
+ Deno.env.get(name) &&
+ (!optionEnv ||
+ !ObjectPrototypeHasOwnProperty(optionEnv, name))
+ ) {
+ env[name] = Deno.env.get(name);
+ }
+}
+
+function normalizeStdioOption(
+ stdio: Array<NodeStdio | number | null | undefined | Stream> | NodeStdio = [
+ "pipe",
+ "pipe",
+ "pipe",
+ ],
+) {
+ if (Array.isArray(stdio)) {
+ return stdio;
+ } else {
+ switch (stdio) {
+ case "overlapped":
+ if (isWindows) {
+ notImplemented("normalizeStdioOption overlapped (on windows)");
+ }
+ // 'overlapped' is same as 'piped' on non Windows system.
+ return ["pipe", "pipe", "pipe"];
+ case "pipe":
+ return ["pipe", "pipe", "pipe"];
+ case "inherit":
+ return ["inherit", "inherit", "inherit"];
+ case "ignore":
+ return ["ignore", "ignore", "ignore"];
+ default:
+ notImplemented(`normalizeStdioOption stdio=${typeof stdio} (${stdio})`);
+ }
+ }
+}
+
+export function normalizeSpawnArguments(
+ file: string,
+ args: string[],
+ options: SpawnOptions & SpawnSyncOptions,
+) {
+ validateString(file, "file");
+
+ if (file.length === 0) {
+ throw new ERR_INVALID_ARG_VALUE("file", file, "cannot be empty");
+ }
+
+ if (ArrayIsArray(args)) {
+ args = ArrayPrototypeSlice(args);
+ } else if (args == null) {
+ args = [];
+ } else if (typeof args !== "object") {
+ throw new ERR_INVALID_ARG_TYPE("args", "object", args);
+ } else {
+ options = args;
+ args = [];
+ }
+
+ if (options === undefined) {
+ options = kEmptyObject;
+ } else {
+ validateObject(options, "options");
+ }
+
+ let cwd = options.cwd;
+
+ // Validate the cwd, if present.
+ if (cwd != null) {
+ cwd = getValidatedPath(cwd, "options.cwd") as string;
+ }
+
+ // Validate detached, if present.
+ if (options.detached != null) {
+ validateBoolean(options.detached, "options.detached");
+ }
+
+ // Validate the uid, if present.
+ if (options.uid != null && !isInt32(options.uid)) {
+ throw new ERR_INVALID_ARG_TYPE("options.uid", "int32", options.uid);
+ }
+
+ // Validate the gid, if present.
+ if (options.gid != null && !isInt32(options.gid)) {
+ throw new ERR_INVALID_ARG_TYPE("options.gid", "int32", options.gid);
+ }
+
+ // Validate the shell, if present.
+ if (
+ options.shell != null &&
+ typeof options.shell !== "boolean" &&
+ typeof options.shell !== "string"
+ ) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "options.shell",
+ ["boolean", "string"],
+ options.shell,
+ );
+ }
+
+ // Validate argv0, if present.
+ if (options.argv0 != null) {
+ validateString(options.argv0, "options.argv0");
+ }
+
+ // Validate windowsHide, if present.
+ if (options.windowsHide != null) {
+ validateBoolean(options.windowsHide, "options.windowsHide");
+ }
+
+ // Validate windowsVerbatimArguments, if present.
+ let { windowsVerbatimArguments } = options;
+ if (windowsVerbatimArguments != null) {
+ validateBoolean(
+ windowsVerbatimArguments,
+ "options.windowsVerbatimArguments",
+ );
+ }
+
+ if (options.shell) {
+ const command = ArrayPrototypeJoin([file, ...args], " ");
+ // Set the shell, switches, and commands.
+ if (process.platform === "win32") {
+ if (typeof options.shell === "string") {
+ file = options.shell;
+ } else {
+ file = Deno.env.get("comspec") || "cmd.exe";
+ }
+ // '/d /s /c' is used only for cmd.exe.
+ if (/^(?:.*\\)?cmd(?:\.exe)?$/i.exec(file) !== null) {
+ args = ["/d", "/s", "/c", `"${command}"`];
+ windowsVerbatimArguments = true;
+ } else {
+ args = ["-c", command];
+ }
+ } else {
+ /** TODO: add Android condition */
+ if (typeof options.shell === "string") {
+ file = options.shell;
+ } else {
+ file = "/bin/sh";
+ }
+ args = ["-c", command];
+ }
+ }
+
+ if (typeof options.argv0 === "string") {
+ ArrayPrototypeUnshift(args, options.argv0);
+ } else {
+ ArrayPrototypeUnshift(args, file);
+ }
+
+ const env = options.env || Deno.env.toObject();
+ const envPairs: string[][] = [];
+
+ // process.env.NODE_V8_COVERAGE always propagates, making it possible to
+ // collect coverage for programs that spawn with white-listed environment.
+ copyProcessEnvToEnv(env, "NODE_V8_COVERAGE", options.env);
+
+ /** TODO: add `isZOS` condition */
+
+ let envKeys: string[] = [];
+ // Prototype values are intentionally included.
+ for (const key in env) {
+ if (Object.hasOwn(env, key)) {
+ ArrayPrototypePush(envKeys, key);
+ }
+ }
+
+ if (process.platform === "win32") {
+ // On Windows env keys are case insensitive. Filter out duplicates,
+ // keeping only the first one (in lexicographic order)
+ /** TODO: implement SafeSet and makeSafe */
+ const sawKey = new Set();
+ envKeys = ArrayPrototypeFilter(
+ ArrayPrototypeSort(envKeys),
+ (key: string) => {
+ const uppercaseKey = StringPrototypeToUpperCase(key);
+ if (sawKey.has(uppercaseKey)) {
+ return false;
+ }
+ sawKey.add(uppercaseKey);
+ return true;
+ },
+ );
+ }
+
+ for (const key of envKeys) {
+ const value = env[key];
+ if (value !== undefined) {
+ ArrayPrototypePush(envPairs, `${key}=${value}`);
+ }
+ }
+
+ return {
+ // Make a shallow copy so we don't clobber the user's options object.
+ ...options,
+ args,
+ cwd,
+ detached: !!options.detached,
+ envPairs,
+ file,
+ windowsHide: !!options.windowsHide,
+ windowsVerbatimArguments: !!windowsVerbatimArguments,
+ };
+}
+
+function waitForReadableToClose(readable: Readable) {
+ readable.resume(); // Ensure buffered data will be consumed.
+ return waitForStreamToClose(readable as unknown as Stream);
+}
+
+function waitForStreamToClose(stream: Stream) {
+ const promise = deferred<void>();
+ const cleanup = () => {
+ stream.removeListener("close", onClose);
+ stream.removeListener("error", onError);
+ };
+ const onClose = () => {
+ cleanup();
+ promise.resolve();
+ };
+ const onError = (err: Error) => {
+ cleanup();
+ promise.reject(err);
+ };
+ stream.once("close", onClose);
+ stream.once("error", onError);
+ return promise;
+}
+
+/**
+ * This function is based on https://github.com/nodejs/node/blob/fc6426ccc4b4cb73076356fb6dbf46a28953af01/lib/child_process.js#L504-L528.
+ * Copyright Joyent, Inc. and other Node contributors. All rights reserved. MIT license.
+ */
+function buildCommand(
+ file: string,
+ args: string[],
+ shell: string | boolean,
+): [string, string[]] {
+ if (file === Deno.execPath()) {
+ // The user is trying to spawn another Deno process as Node.js.
+ args = toDenoArgs(args);
+ }
+
+ if (shell) {
+ const command = [file, ...args].join(" ");
+
+ // Set the shell, switches, and commands.
+ if (isWindows) {
+ if (typeof shell === "string") {
+ file = shell;
+ } else {
+ file = Deno.env.get("comspec") || "cmd.exe";
+ }
+ // '/d /s /c' is used only for cmd.exe.
+ if (/^(?:.*\\)?cmd(?:\.exe)?$/i.test(file)) {
+ args = ["/d", "/s", "/c", `"${command}"`];
+ } else {
+ args = ["-c", command];
+ }
+ } else {
+ if (typeof shell === "string") {
+ file = shell;
+ } else {
+ file = "/bin/sh";
+ }
+ args = ["-c", command];
+ }
+ }
+ return [file, args];
+}
+
+function _createSpawnSyncError(
+ status: string,
+ command: string,
+ args: string[] = [],
+): ErrnoException {
+ const error = errnoException(
+ codeMap.get(status),
+ "spawnSync " + command,
+ );
+ error.path = command;
+ error.spawnargs = args;
+ return error;
+}
+
+export interface SpawnOptions extends ChildProcessOptions {
+ /**
+ * NOTE: This option is not yet implemented.
+ */
+ timeout?: number;
+ /**
+ * NOTE: This option is not yet implemented.
+ */
+ killSignal?: string;
+}
+
+export interface SpawnSyncOptions extends
+ Pick<
+ ChildProcessOptions,
+ | "cwd"
+ | "env"
+ | "argv0"
+ | "stdio"
+ | "uid"
+ | "gid"
+ | "shell"
+ | "windowsVerbatimArguments"
+ | "windowsHide"
+ > {
+ input?: string | Buffer | DataView;
+ timeout?: number;
+ maxBuffer?: number;
+ encoding?: string;
+ /**
+ * NOTE: This option is not yet implemented.
+ */
+ killSignal?: string;
+}
+
+export interface SpawnSyncResult {
+ pid?: number;
+ output?: [string | null, string | Buffer | null, string | Buffer | null];
+ stdout?: Buffer | string | null;
+ stderr?: Buffer | string | null;
+ status?: number | null;
+ signal?: string | null;
+ error?: Error;
+}
+
+function parseSpawnSyncOutputStreams(
+ output: Deno.CommandOutput,
+ name: "stdout" | "stderr",
+): string | Buffer | null {
+ // new Deno.Command().outputSync() returns getters for stdout and stderr that throw when set
+ // to 'inherit'.
+ try {
+ return Buffer.from(output[name]) as string | Buffer;
+ } catch {
+ return null;
+ }
+}
+
+export function spawnSync(
+ command: string,
+ args: string[],
+ options: SpawnSyncOptions,
+): SpawnSyncResult {
+ const {
+ env = Deno.env.toObject(),
+ stdio = ["pipe", "pipe", "pipe"],
+ shell = false,
+ cwd,
+ encoding,
+ uid,
+ gid,
+ maxBuffer,
+ windowsVerbatimArguments = false,
+ } = options;
+ const normalizedStdio = normalizeStdioOption(stdio);
+ [command, args] = buildCommand(command, args ?? [], shell);
+
+ const result: SpawnSyncResult = {};
+ try {
+ const output = new DenoCommand(command, {
+ args,
+ cwd,
+ env,
+ stdout: toDenoStdio(normalizedStdio[1] as NodeStdio | number),
+ stderr: toDenoStdio(normalizedStdio[2] as NodeStdio | number),
+ uid,
+ gid,
+ windowsRawArguments: windowsVerbatimArguments,
+ }).outputSync();
+
+ const status = output.signal ? null : 0;
+ let stdout = parseSpawnSyncOutputStreams(output, "stdout");
+ let stderr = parseSpawnSyncOutputStreams(output, "stderr");
+
+ if (
+ (stdout && stdout.length > maxBuffer!) ||
+ (stderr && stderr.length > maxBuffer!)
+ ) {
+ result.error = _createSpawnSyncError("ENOBUFS", command, args);
+ }
+
+ if (encoding && encoding !== "buffer") {
+ stdout = stdout && stdout.toString(encoding);
+ stderr = stderr && stderr.toString(encoding);
+ }
+
+ result.status = status;
+ result.signal = output.signal;
+ result.stdout = stdout;
+ result.stderr = stderr;
+ result.output = [output.signal, stdout, stderr];
+ } catch (err) {
+ if (err instanceof Deno.errors.NotFound) {
+ result.error = _createSpawnSyncError("ENOENT", command, args);
+ }
+ }
+ return result;
+}
+
+// These are Node.js CLI flags that expect a value. It's necessary to
+// understand these flags in order to properly replace flags passed to the
+// child process. For example, -e is a Node flag for eval mode if it is part
+// of process.execArgv. However, -e could also be an application flag if it is
+// part of process.execv instead. We only want to process execArgv flags.
+const kLongArgType = 1;
+const kShortArgType = 2;
+const kLongArg = { type: kLongArgType };
+const kShortArg = { type: kShortArgType };
+const kNodeFlagsMap = new Map([
+ ["--build-snapshot", kLongArg],
+ ["-c", kShortArg],
+ ["--check", kLongArg],
+ ["-C", kShortArg],
+ ["--conditions", kLongArg],
+ ["--cpu-prof-dir", kLongArg],
+ ["--cpu-prof-interval", kLongArg],
+ ["--cpu-prof-name", kLongArg],
+ ["--diagnostic-dir", kLongArg],
+ ["--disable-proto", kLongArg],
+ ["--dns-result-order", kLongArg],
+ ["-e", kShortArg],
+ ["--eval", kLongArg],
+ ["--experimental-loader", kLongArg],
+ ["--experimental-policy", kLongArg],
+ ["--experimental-specifier-resolution", kLongArg],
+ ["--heapsnapshot-near-heap-limit", kLongArg],
+ ["--heapsnapshot-signal", kLongArg],
+ ["--heap-prof-dir", kLongArg],
+ ["--heap-prof-interval", kLongArg],
+ ["--heap-prof-name", kLongArg],
+ ["--icu-data-dir", kLongArg],
+ ["--input-type", kLongArg],
+ ["--inspect-publish-uid", kLongArg],
+ ["--max-http-header-size", kLongArg],
+ ["--openssl-config", kLongArg],
+ ["-p", kShortArg],
+ ["--print", kLongArg],
+ ["--policy-integrity", kLongArg],
+ ["--prof-process", kLongArg],
+ ["-r", kShortArg],
+ ["--require", kLongArg],
+ ["--redirect-warnings", kLongArg],
+ ["--report-dir", kLongArg],
+ ["--report-directory", kLongArg],
+ ["--report-filename", kLongArg],
+ ["--report-signal", kLongArg],
+ ["--secure-heap", kLongArg],
+ ["--secure-heap-min", kLongArg],
+ ["--snapshot-blob", kLongArg],
+ ["--title", kLongArg],
+ ["--tls-cipher-list", kLongArg],
+ ["--tls-keylog", kLongArg],
+ ["--unhandled-rejections", kLongArg],
+ ["--use-largepages", kLongArg],
+ ["--v8-pool-size", kLongArg],
+]);
+const kDenoSubcommands = new Set([
+ "bench",
+ "bundle",
+ "cache",
+ "check",
+ "compile",
+ "completions",
+ "coverage",
+ "doc",
+ "eval",
+ "fmt",
+ "help",
+ "info",
+ "init",
+ "install",
+ "lint",
+ "lsp",
+ "repl",
+ "run",
+ "tasks",
+ "test",
+ "types",
+ "uninstall",
+ "upgrade",
+ "vendor",
+]);
+
+function toDenoArgs(args: string[]): string[] {
+ if (args.length === 0) {
+ return args;
+ }
+
+ // Update this logic as more CLI arguments are mapped from Node to Deno.
+ const denoArgs: string[] = [];
+ let useRunArgs = true;
+
+ for (let i = 0; i < args.length; i++) {
+ const arg = args[i];
+
+ if (arg.charAt(0) !== "-" || arg === "--") {
+ // Not a flag or no more arguments.
+
+ // If the arg is a Deno subcommand, then the child process is being
+ // spawned as Deno, not Deno in Node compat mode. In this case, bail out
+ // and return the original args.
+ if (kDenoSubcommands.has(arg)) {
+ return args;
+ }
+
+ // Copy of the rest of the arguments to the output.
+ for (let j = i; j < args.length; j++) {
+ denoArgs.push(args[j]);
+ }
+
+ break;
+ }
+
+ // Something that looks like a flag was passed.
+ let flag = arg;
+ let flagInfo = kNodeFlagsMap.get(arg);
+ let isLongWithValue = false;
+ let flagValue;
+
+ if (flagInfo === undefined) {
+ // If the flag was not found, it's either not a known flag or it's a long
+ // flag containing an '='.
+ const splitAt = arg.indexOf("=");
+
+ if (splitAt !== -1) {
+ flag = arg.slice(0, splitAt);
+ flagInfo = kNodeFlagsMap.get(flag);
+ flagValue = arg.slice(splitAt + 1);
+ isLongWithValue = true;
+ }
+ }
+
+ if (flagInfo === undefined) {
+ // Not a known flag that expects a value. Just copy it to the output.
+ denoArgs.push(arg);
+ continue;
+ }
+
+ // This is a flag with a value. Get the value if we don't already have it.
+ if (flagValue === undefined) {
+ i++;
+
+ if (i >= args.length) {
+ // There was user error. There should be another arg for the value, but
+ // there isn't one. Just copy the arg to the output. It's not going
+ // to work anyway.
+ denoArgs.push(arg);
+ continue;
+ }
+
+ flagValue = args[i];
+ }
+
+ // Remap Node's eval flags to Deno.
+ if (flag === "-e" || flag === "--eval") {
+ denoArgs.push("eval", flagValue);
+ useRunArgs = false;
+ } else if (isLongWithValue) {
+ denoArgs.push(arg);
+ } else {
+ denoArgs.push(flag, flagValue);
+ }
+ }
+
+ if (useRunArgs) {
+ // -A is not ideal, but needed to propagate permissions.
+ // --unstable is needed for Node compat.
+ denoArgs.unshift("run", "-A", "--unstable");
+ }
+
+ return denoArgs;
+}
+
+export default {
+ ChildProcess,
+ normalizeSpawnArguments,
+ stdioStringToArray,
+ spawnSync,
+};
diff --git a/ext/node/polyfills/internal/cli_table.ts b/ext/node/polyfills/internal/cli_table.ts
new file mode 100644
index 000000000..68cc6d044
--- /dev/null
+++ b/ext/node/polyfills/internal/cli_table.ts
@@ -0,0 +1,85 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+import { getStringWidth } from "internal:deno_node/polyfills/internal/util/inspect.mjs";
+
+// The use of Unicode characters below is the only non-comment use of non-ASCII
+// Unicode characters in Node.js built-in modules. If they are ever removed or
+// rewritten with \u escapes, then a test will need to be (re-)added to Node.js
+// core to verify that Unicode characters work in built-ins.
+// Refs: https://github.com/nodejs/node/issues/10673
+const tableChars = {
+ middleMiddle: "─",
+ rowMiddle: "┌",
+ topRight: "┐",
+ topLeft: "┌",
+ leftMiddle: "├",
+ topMiddle: "┬",
+ bottomRight: "┘",
+ bottomLeft: "└",
+ bottomMiddle: "┮",
+ rightMiddle: "─",
+ left: "│ ",
+ right: " │",
+ middle: " │ ",
+};
+
+const renderRow = (row: string[], columnWidths: number[]) => {
+ let out = tableChars.left;
+ for (let i = 0; i < row.length; i++) {
+ const cell = row[i];
+ const len = getStringWidth(cell);
+ const needed = (columnWidths[i] - len) / 2;
+ // round(needed) + ceil(needed) will always add up to the amount
+ // of spaces we need while also left justifying the output.
+ out += " ".repeat(needed) + cell +
+ " ".repeat(Math.ceil(needed));
+ if (i !== row.length - 1) {
+ out += tableChars.middle;
+ }
+ }
+ out += tableChars.right;
+ return out;
+};
+
+const table = (head: string[], columns: string[][]) => {
+ const rows: string[][] = [];
+ const columnWidths = head.map((h) => getStringWidth(h));
+ const longestColumn = Math.max(...columns.map((a) => a.length));
+
+ for (let i = 0; i < head.length; i++) {
+ const column = columns[i];
+ for (let j = 0; j < longestColumn; j++) {
+ if (rows[j] === undefined) {
+ rows[j] = [];
+ }
+ const value = rows[j][i] = Object.hasOwn(column, j) ? column[j] : "";
+ const width = columnWidths[i] || 0;
+ const counted = getStringWidth(value);
+ columnWidths[i] = Math.max(width, counted);
+ }
+ }
+
+ const divider = columnWidths.map((i) =>
+ tableChars.middleMiddle.repeat(i + 2)
+ );
+
+ let result = tableChars.topLeft +
+ divider.join(tableChars.topMiddle) +
+ tableChars.topRight + "\n" +
+ renderRow(head, columnWidths) + "\n" +
+ tableChars.leftMiddle +
+ divider.join(tableChars.rowMiddle) +
+ tableChars.rightMiddle + "\n";
+
+ for (const row of rows) {
+ result += `${renderRow(row, columnWidths)}\n`;
+ }
+
+ result += tableChars.bottomLeft +
+ divider.join(tableChars.bottomMiddle) +
+ tableChars.bottomRight;
+
+ return result;
+};
+export default table;
diff --git a/ext/node/polyfills/internal/console/constructor.mjs b/ext/node/polyfills/internal/console/constructor.mjs
new file mode 100644
index 000000000..362c97f68
--- /dev/null
+++ b/ext/node/polyfills/internal/console/constructor.mjs
@@ -0,0 +1,677 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+// Mock trace for now
+const trace = () => {};
+import {
+ ERR_CONSOLE_WRITABLE_STREAM,
+ ERR_INCOMPATIBLE_OPTION_PAIR,
+ ERR_INVALID_ARG_VALUE,
+ isStackOverflowError,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ validateArray,
+ validateInteger,
+ validateObject,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+const previewEntries = (iter, isKeyValue) => {
+ if (isKeyValue) {
+ const arr = [...iter];
+ if (Array.isArray(arr[0]) && arr[0].length === 2) {
+ return [[].concat(...arr), true];
+ }
+ return [arr, false];
+ } else {
+ return [...iter];
+ }
+};
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+const { isBuffer } = Buffer;
+import { formatWithOptions, inspect } from "internal:deno_node/polyfills/internal/util/inspect.mjs";
+import {
+ isMap,
+ isMapIterator,
+ isSet,
+ isSetIterator,
+ isTypedArray,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+import {
+ CHAR_LOWERCASE_B as kTraceBegin,
+ CHAR_LOWERCASE_E as kTraceEnd,
+ CHAR_LOWERCASE_N as kTraceInstant,
+ CHAR_UPPERCASE_C as kTraceCount,
+} from "internal:deno_node/polyfills/internal/constants.ts";
+import { clearScreenDown, cursorTo } from "internal:deno_node/polyfills/internal/readline/callbacks.mjs";
+import cliTable from "internal:deno_node/polyfills/internal/cli_table.ts";
+const kCounts = Symbol("counts");
+
+const kTraceConsoleCategory = "node,node.console";
+
+const kSecond = 1000;
+const kMinute = 60 * kSecond;
+const kHour = 60 * kMinute;
+const kMaxGroupIndentation = 1000;
+
+// Track amount of indentation required via `console.group()`.
+const kGroupIndent = Symbol("kGroupIndent");
+const kGroupIndentationWidth = Symbol("kGroupIndentWidth");
+const kFormatForStderr = Symbol("kFormatForStderr");
+const kFormatForStdout = Symbol("kFormatForStdout");
+const kGetInspectOptions = Symbol("kGetInspectOptions");
+const kColorMode = Symbol("kColorMode");
+const kIsConsole = Symbol("kIsConsole");
+const kWriteToConsole = Symbol("kWriteToConsole");
+const kBindProperties = Symbol("kBindProperties");
+const kBindStreamsEager = Symbol("kBindStreamsEager");
+const kBindStreamsLazy = Symbol("kBindStreamsLazy");
+const kUseStdout = Symbol("kUseStdout");
+const kUseStderr = Symbol("kUseStderr");
+
+const optionsMap = new WeakMap();
+
+function Console(options /* or: stdout, stderr, ignoreErrors = true */) {
+ // We have to test new.target here to see if this function is called
+ // with new, because we need to define a custom instanceof to accommodate
+ // the global console.
+ if (!new.target) {
+ return Reflect.construct(Console, arguments);
+ }
+
+ if (!options || typeof options.write === "function") {
+ options = {
+ stdout: options,
+ stderr: arguments[1],
+ ignoreErrors: arguments[2],
+ };
+ }
+
+ const {
+ stdout,
+ stderr = stdout,
+ ignoreErrors = true,
+ colorMode = "auto",
+ inspectOptions,
+ groupIndentation,
+ } = options;
+
+ if (!stdout || typeof stdout.write !== "function") {
+ throw new ERR_CONSOLE_WRITABLE_STREAM("stdout");
+ }
+ if (!stderr || typeof stderr.write !== "function") {
+ throw new ERR_CONSOLE_WRITABLE_STREAM("stderr");
+ }
+
+ if (typeof colorMode !== "boolean" && colorMode !== "auto") {
+ throw new ERR_INVALID_ARG_VALUE("colorMode", colorMode);
+ }
+
+ if (groupIndentation !== undefined) {
+ validateInteger(
+ groupIndentation,
+ "groupIndentation",
+ 0,
+ kMaxGroupIndentation,
+ );
+ }
+
+ if (inspectOptions !== undefined) {
+ validateObject(inspectOptions, "options.inspectOptions");
+
+ if (
+ inspectOptions.colors !== undefined &&
+ options.colorMode !== undefined
+ ) {
+ throw new ERR_INCOMPATIBLE_OPTION_PAIR(
+ "options.inspectOptions.color",
+ "colorMode",
+ );
+ }
+ optionsMap.set(this, inspectOptions);
+ }
+
+ // Bind the prototype functions to this Console instance
+ Object.keys(Console.prototype).forEach((key) => {
+ // We have to bind the methods grabbed from the instance instead of from
+ // the prototype so that users extending the Console can override them
+ // from the prototype chain of the subclass.
+ this[key] = this[key].bind(this);
+ Object.defineProperty(this[key], "name", {
+ value: key,
+ });
+ });
+
+ this[kBindStreamsEager](stdout, stderr);
+ this[kBindProperties](ignoreErrors, colorMode, groupIndentation);
+}
+
+const consolePropAttributes = {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+};
+
+// Fixup global.console instanceof global.console.Console
+Object.defineProperty(Console, Symbol.hasInstance, {
+ value(instance) {
+ return instance === console || instance[kIsConsole];
+ },
+});
+
+const kColorInspectOptions = { colors: true };
+const kNoColorInspectOptions = {};
+
+Object.defineProperties(Console.prototype, {
+ [kBindStreamsEager]: {
+ ...consolePropAttributes,
+ // Eager version for the Console constructor
+ value: function (stdout, stderr) {
+ Object.defineProperties(this, {
+ "_stdout": { ...consolePropAttributes, value: stdout },
+ "_stderr": { ...consolePropAttributes, value: stderr },
+ });
+ },
+ },
+ [kBindStreamsLazy]: {
+ ...consolePropAttributes,
+ // Lazily load the stdout and stderr from an object so we don't
+ // create the stdio streams when they are not even accessed
+ value: function (object) {
+ let stdout;
+ let stderr;
+ Object.defineProperties(this, {
+ "_stdout": {
+ enumerable: false,
+ configurable: true,
+ get() {
+ if (!stdout) stdout = object.stdout;
+ return stdout;
+ },
+ set(value) {
+ stdout = value;
+ },
+ },
+ "_stderr": {
+ enumerable: false,
+ configurable: true,
+ get() {
+ if (!stderr) stderr = object.stderr;
+ return stderr;
+ },
+ set(value) {
+ stderr = value;
+ },
+ },
+ });
+ },
+ },
+ [kBindProperties]: {
+ ...consolePropAttributes,
+ value: function (ignoreErrors, colorMode, groupIndentation = 2) {
+ Object.defineProperties(this, {
+ "_stdoutErrorHandler": {
+ ...consolePropAttributes,
+ value: createWriteErrorHandler(this, kUseStdout),
+ },
+ "_stderrErrorHandler": {
+ ...consolePropAttributes,
+ value: createWriteErrorHandler(this, kUseStderr),
+ },
+ "_ignoreErrors": {
+ ...consolePropAttributes,
+ value: Boolean(ignoreErrors),
+ },
+ "_times": { ...consolePropAttributes, value: new Map() },
+ // Corresponds to https://console.spec.whatwg.org/#count-map
+ [kCounts]: { ...consolePropAttributes, value: new Map() },
+ [kColorMode]: { ...consolePropAttributes, value: colorMode },
+ [kIsConsole]: { ...consolePropAttributes, value: true },
+ [kGroupIndent]: { ...consolePropAttributes, value: "" },
+ [kGroupIndentationWidth]: {
+ ...consolePropAttributes,
+ value: groupIndentation,
+ },
+ [Symbol.toStringTag]: {
+ writable: false,
+ enumerable: false,
+ configurable: true,
+ value: "console",
+ },
+ });
+ },
+ },
+ [kWriteToConsole]: {
+ ...consolePropAttributes,
+ value: function (streamSymbol, string) {
+ const ignoreErrors = this._ignoreErrors;
+ const groupIndent = this[kGroupIndent];
+
+ const useStdout = streamSymbol === kUseStdout;
+ const stream = useStdout ? this._stdout : this._stderr;
+ const errorHandler = useStdout
+ ? this._stdoutErrorHandler
+ : this._stderrErrorHandler;
+
+ if (groupIndent.length !== 0) {
+ if (string.includes("\n")) {
+ string = string.replace(/\n/g, `\n${groupIndent}`);
+ }
+ string = groupIndent + string;
+ }
+ string += "\n";
+
+ if (ignoreErrors === false) return stream.write(string);
+
+ // There may be an error occurring synchronously (e.g. for files or TTYs
+ // on POSIX systems) or asynchronously (e.g. pipes on POSIX systems), so
+ // handle both situations.
+ try {
+ // Add and later remove a noop error handler to catch synchronous
+ // errors.
+ if (stream.listenerCount("error") === 0) {
+ stream.once("error", noop);
+ }
+
+ stream.write(string, errorHandler);
+ } catch (e) {
+ // Console is a debugging utility, so it swallowing errors is not
+ // desirable even in edge cases such as low stack space.
+ if (isStackOverflowError(e)) {
+ throw e;
+ }
+ // Sorry, there's no proper way to pass along the error here.
+ } finally {
+ stream.removeListener("error", noop);
+ }
+ },
+ },
+ [kGetInspectOptions]: {
+ ...consolePropAttributes,
+ value: function (stream) {
+ let color = this[kColorMode];
+ if (color === "auto") {
+ color = stream.isTTY && (
+ typeof stream.getColorDepth === "function"
+ ? stream.getColorDepth() > 2
+ : true
+ );
+ }
+
+ const options = optionsMap.get(this);
+ if (options) {
+ if (options.colors === undefined) {
+ options.colors = color;
+ }
+ return options;
+ }
+
+ return color ? kColorInspectOptions : kNoColorInspectOptions;
+ },
+ },
+ [kFormatForStdout]: {
+ ...consolePropAttributes,
+ value: function (args) {
+ const opts = this[kGetInspectOptions](this._stdout);
+ args.unshift(opts);
+ return Reflect.apply(formatWithOptions, null, args);
+ },
+ },
+ [kFormatForStderr]: {
+ ...consolePropAttributes,
+ value: function (args) {
+ const opts = this[kGetInspectOptions](this._stderr);
+ args.unshift(opts);
+ return Reflect.apply(formatWithOptions, null, args);
+ },
+ },
+});
+
+// Make a function that can serve as the callback passed to `stream.write()`.
+function createWriteErrorHandler(instance, streamSymbol) {
+ return (err) => {
+ // This conditional evaluates to true if and only if there was an error
+ // that was not already emitted (which happens when the _write callback
+ // is invoked asynchronously).
+ const stream = streamSymbol === kUseStdout
+ ? instance._stdout
+ : instance._stderr;
+ if (err !== null && !stream._writableState.errorEmitted) {
+ // If there was an error, it will be emitted on `stream` as
+ // an `error` event. Adding a `once` listener will keep that error
+ // from becoming an uncaught exception, but since the handler is
+ // removed after the event, non-console.* writes won't be affected.
+ // we are only adding noop if there is no one else listening for 'error'
+ if (stream.listenerCount("error") === 0) {
+ stream.once("error", noop);
+ }
+ }
+ };
+}
+
+const consoleMethods = {
+ log(...args) {
+ this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args));
+ },
+
+ warn(...args) {
+ this[kWriteToConsole](kUseStderr, this[kFormatForStderr](args));
+ },
+
+ dir(object, options) {
+ this[kWriteToConsole](
+ kUseStdout,
+ inspect(object, {
+ customInspect: false,
+ ...this[kGetInspectOptions](this._stdout),
+ ...options,
+ }),
+ );
+ },
+
+ time(label = "default") {
+ // Coerces everything other than Symbol to a string
+ label = `${label}`;
+ if (this._times.has(label)) {
+ emitWarning(`Label '${label}' already exists for console.time()`);
+ return;
+ }
+ trace(kTraceBegin, kTraceConsoleCategory, `time::${label}`, 0);
+ this._times.set(label, process.hrtime());
+ },
+
+ timeEnd(label = "default") {
+ // Coerces everything other than Symbol to a string
+ label = `${label}`;
+ const found = timeLogImpl(this, "timeEnd", label);
+ trace(kTraceEnd, kTraceConsoleCategory, `time::${label}`, 0);
+ if (found) {
+ this._times.delete(label);
+ }
+ },
+
+ timeLog(label = "default", ...data) {
+ // Coerces everything other than Symbol to a string
+ label = `${label}`;
+ timeLogImpl(this, "timeLog", label, data);
+ trace(kTraceInstant, kTraceConsoleCategory, `time::${label}`, 0);
+ },
+
+ trace: function trace(...args) {
+ const err = {
+ name: "Trace",
+ message: this[kFormatForStderr](args),
+ };
+ Error.captureStackTrace(err, trace);
+ this.error(err.stack);
+ },
+
+ assert(expression, ...args) {
+ if (!expression) {
+ args[0] = `Assertion failed${args.length === 0 ? "" : `: ${args[0]}`}`;
+ // The arguments will be formatted in warn() again
+ Reflect.apply(this.warn, this, args);
+ }
+ },
+
+ // Defined by: https://console.spec.whatwg.org/#clear
+ clear() {
+ // It only makes sense to clear if _stdout is a TTY.
+ // Otherwise, do nothing.
+ if (this._stdout.isTTY && process.env.TERM !== "dumb") {
+ cursorTo(this._stdout, 0, 0);
+ clearScreenDown(this._stdout);
+ }
+ },
+
+ // Defined by: https://console.spec.whatwg.org/#count
+ count(label = "default") {
+ // Ensures that label is a string, and only things that can be
+ // coerced to strings. e.g. Symbol is not allowed
+ label = `${label}`;
+ const counts = this[kCounts];
+ let count = counts.get(label);
+ if (count === undefined) {
+ count = 1;
+ } else {
+ count++;
+ }
+ counts.set(label, count);
+ trace(kTraceCount, kTraceConsoleCategory, `count::${label}`, 0, count);
+ this.log(`${label}: ${count}`);
+ },
+
+ // Defined by: https://console.spec.whatwg.org/#countreset
+ countReset(label = "default") {
+ const counts = this[kCounts];
+ if (!counts.has(label)) {
+ emitWarning(`Count for '${label}' does not exist`);
+ return;
+ }
+ trace(kTraceCount, kTraceConsoleCategory, `count::${label}`, 0, 0);
+ counts.delete(`${label}`);
+ },
+
+ group(...data) {
+ if (data.length > 0) {
+ Reflect.apply(this.log, this, data);
+ }
+ this[kGroupIndent] += " ".repeat(this[kGroupIndentationWidth]);
+ },
+
+ groupEnd() {
+ this[kGroupIndent] = this[kGroupIndent].slice(
+ 0,
+ this[kGroupIndent].length - this[kGroupIndentationWidth],
+ );
+ },
+
+ // https://console.spec.whatwg.org/#table
+ table(tabularData, properties) {
+ console.log("tabularData", tabularData);
+ if (properties !== undefined) {
+ validateArray(properties, "properties");
+ }
+
+ if (tabularData === null || typeof tabularData !== "object") {
+ return this.log(tabularData);
+ }
+
+ const final = (k, v) => this.log(cliTable(k, v));
+
+ const _inspect = (v) => {
+ const depth = v !== null &&
+ typeof v === "object" &&
+ !isArray(v) &&
+ Object.keys(v).length > 2
+ ? -1
+ : 0;
+ const opt = {
+ depth,
+ maxArrayLength: 3,
+ breakLength: Infinity,
+ ...this[kGetInspectOptions](this._stdout),
+ };
+ return inspect(v, opt);
+ };
+ const getIndexArray = (length) =>
+ Array.from(
+ { length },
+ (_, i) => _inspect(i),
+ );
+
+ const mapIter = isMapIterator(tabularData);
+ let isKeyValue = false;
+ let i = 0;
+ if (mapIter) {
+ const res = previewEntries(tabularData, true);
+ tabularData = res[0];
+ isKeyValue = res[1];
+ }
+
+ if (isKeyValue || isMap(tabularData)) {
+ const keys = [];
+ const values = [];
+ let length = 0;
+ if (mapIter) {
+ for (; i < tabularData.length / 2; ++i) {
+ keys.push(_inspect(tabularData[i * 2]));
+ values.push(_inspect(tabularData[i * 2 + 1]));
+ length++;
+ }
+ } else {
+ for (const { 0: k, 1: v } of tabularData) {
+ keys.push(_inspect(k));
+ values.push(_inspect(v));
+ length++;
+ }
+ }
+ return final([
+ iterKey,
+ keyKey,
+ valuesKey,
+ ], [
+ getIndexArray(length),
+ keys,
+ values,
+ ]);
+ }
+
+ const setIter = isSetIterator(tabularData);
+ if (setIter) {
+ tabularData = previewEntries(tabularData);
+ }
+
+ const setlike = setIter || mapIter || isSet(tabularData);
+ if (setlike) {
+ const values = [];
+ let length = 0;
+ console.log("tabularData", tabularData);
+ for (const v of tabularData) {
+ values.push(_inspect(v));
+ length++;
+ }
+ return final([iterKey, valuesKey], [getIndexArray(length), values]);
+ }
+
+ const map = Object.create(null);
+ let hasPrimitives = false;
+ const valuesKeyArray = [];
+ const indexKeyArray = Object.keys(tabularData);
+
+ for (; i < indexKeyArray.length; i++) {
+ const item = tabularData[indexKeyArray[i]];
+ const primitive = item === null ||
+ (typeof item !== "function" && typeof item !== "object");
+ if (properties === undefined && primitive) {
+ hasPrimitives = true;
+ valuesKeyArray[i] = _inspect(item);
+ } else {
+ const keys = properties || Object.keys(item);
+ for (const key of keys) {
+ if (map[key] === undefined) {
+ map[key] = [];
+ }
+ if (
+ (primitive && properties) ||
+ !Object.hasOwn(item, key)
+ ) {
+ map[key][i] = "";
+ } else {
+ map[key][i] = _inspect(item[key]);
+ }
+ }
+ }
+ }
+
+ const keys = Object.keys(map);
+ const values = Object.values(map);
+ if (hasPrimitives) {
+ keys.push(valuesKey);
+ values.push(valuesKeyArray);
+ }
+ keys.unshift(indexKey);
+ values.unshift(indexKeyArray);
+
+ return final(keys, values);
+ },
+};
+
+// Returns true if label was found
+function timeLogImpl(self, name, label, data) {
+ const time = self._times.get(label);
+ if (time === undefined) {
+ emitWarning(`No such label '${label}' for console.${name}()`);
+ return false;
+ }
+ const duration = process.hrtime(time);
+ const ms = duration[0] * 1000 + duration[1] / 1e6;
+
+ const formatted = formatTime(ms);
+
+ if (data === undefined) {
+ self.log("%s: %s", label, formatted);
+ } else {
+ self.log("%s: %s", label, formatted, ...data);
+ }
+ return true;
+}
+
+function pad(value) {
+ return `${value}`.padStart(2, "0");
+}
+
+function formatTime(ms) {
+ let hours = 0;
+ let minutes = 0;
+ let seconds = 0;
+
+ if (ms >= kSecond) {
+ if (ms >= kMinute) {
+ if (ms >= kHour) {
+ hours = Math.floor(ms / kHour);
+ ms = ms % kHour;
+ }
+ minutes = Math.floor(ms / kMinute);
+ ms = ms % kMinute;
+ }
+ seconds = ms / kSecond;
+ }
+
+ if (hours !== 0 || minutes !== 0) {
+ ({ 0: seconds, 1: ms } = seconds.toFixed(3).split("."));
+ const res = hours !== 0 ? `${hours}:${pad(minutes)}` : minutes;
+ return `${res}:${pad(seconds)}.${ms} (${hours !== 0 ? "h:m" : ""}m:ss.mmm)`;
+ }
+
+ if (seconds !== 0) {
+ return `${seconds.toFixed(3)}s`;
+ }
+
+ return `${Number(ms.toFixed(3))}ms`;
+}
+
+const keyKey = "Key";
+const valuesKey = "Values";
+const indexKey = "(index)";
+const iterKey = "(iteration index)";
+
+const isArray = (v) => Array.isArray(v) || isTypedArray(v) || isBuffer(v);
+
+function noop() {}
+
+for (const method of Reflect.ownKeys(consoleMethods)) {
+ Console.prototype[method] = consoleMethods[method];
+}
+
+Console.prototype.debug = Console.prototype.log;
+Console.prototype.info = Console.prototype.log;
+Console.prototype.dirxml = Console.prototype.log;
+Console.prototype.error = Console.prototype.warn;
+Console.prototype.groupCollapsed = Console.prototype.group;
+
+export { Console, formatTime, kBindProperties, kBindStreamsLazy };
+export default {
+ Console,
+ kBindStreamsLazy,
+ kBindProperties,
+ formatTime,
+};
diff --git a/ext/node/polyfills/internal/constants.ts b/ext/node/polyfills/internal/constants.ts
new file mode 100644
index 000000000..5c5cafe8d
--- /dev/null
+++ b/ext/node/polyfills/internal/constants.ts
@@ -0,0 +1,105 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+const { ops } = globalThis.__bootstrap.core;
+const isWindows = ops.op_node_build_os() === "windows";
+
+// Alphabet chars.
+export const CHAR_UPPERCASE_A = 65; /* A */
+export const CHAR_LOWERCASE_A = 97; /* a */
+export const CHAR_UPPERCASE_Z = 90; /* Z */
+export const CHAR_LOWERCASE_Z = 122; /* z */
+export const CHAR_UPPERCASE_C = 67; /* C */
+export const CHAR_LOWERCASE_B = 98; /* b */
+export const CHAR_LOWERCASE_E = 101; /* e */
+export const CHAR_LOWERCASE_N = 110; /* n */
+
+// Non-alphabetic chars.
+export const CHAR_DOT = 46; /* . */
+export const CHAR_FORWARD_SLASH = 47; /* / */
+export const CHAR_BACKWARD_SLASH = 92; /* \ */
+export const CHAR_VERTICAL_LINE = 124; /* | */
+export const CHAR_COLON = 58; /* = */
+export const CHAR_QUESTION_MARK = 63; /* ? */
+export const CHAR_UNDERSCORE = 95; /* _ */
+export const CHAR_LINE_FEED = 10; /* \n */
+export const CHAR_CARRIAGE_RETURN = 13; /* \r */
+export const CHAR_TAB = 9; /* \t */
+export const CHAR_FORM_FEED = 12; /* \f */
+export const CHAR_EXCLAMATION_MARK = 33; /* ! */
+export const CHAR_HASH = 35; /* # */
+export const CHAR_SPACE = 32; /* */
+export const CHAR_NO_BREAK_SPACE = 160; /* \u00A0 */
+export const CHAR_ZERO_WIDTH_NOBREAK_SPACE = 65279; /* \uFEFF */
+export const CHAR_LEFT_SQUARE_BRACKET = 91; /* [ */
+export const CHAR_RIGHT_SQUARE_BRACKET = 93; /* ] */
+export const CHAR_LEFT_ANGLE_BRACKET = 60; /* < */
+export const CHAR_RIGHT_ANGLE_BRACKET = 62; /* > */
+export const CHAR_LEFT_CURLY_BRACKET = 123; /* { */
+export const CHAR_RIGHT_CURLY_BRACKET = 125; /* } */
+export const CHAR_HYPHEN_MINUS = 45; /* - */
+export const CHAR_PLUS = 43; /* + */
+export const CHAR_DOUBLE_QUOTE = 34; /* " */
+export const CHAR_SINGLE_QUOTE = 39; /* ' */
+export const CHAR_PERCENT = 37; /* % */
+export const CHAR_SEMICOLON = 59; /* ; */
+export const CHAR_CIRCUMFLEX_ACCENT = 94; /* ^ */
+export const CHAR_GRAVE_ACCENT = 96; /* ` */
+export const CHAR_AT = 64; /* @ */
+export const CHAR_AMPERSAND = 38; /* & */
+export const CHAR_EQUAL = 61; /* = */
+
+// Digits
+export const CHAR_0 = 48; /* 0 */
+export const CHAR_9 = 57; /* 9 */
+
+export const EOL = isWindows ? "\r\n" : "\n";
+
+export default {
+ CHAR_UPPERCASE_A,
+ CHAR_LOWERCASE_A,
+ CHAR_UPPERCASE_Z,
+ CHAR_LOWERCASE_Z,
+ CHAR_UPPERCASE_C,
+ CHAR_LOWERCASE_B,
+ CHAR_LOWERCASE_E,
+ CHAR_LOWERCASE_N,
+ CHAR_DOT,
+ CHAR_FORWARD_SLASH,
+ CHAR_BACKWARD_SLASH,
+ CHAR_VERTICAL_LINE,
+ CHAR_COLON,
+ CHAR_QUESTION_MARK,
+ CHAR_UNDERSCORE,
+ CHAR_LINE_FEED,
+ CHAR_CARRIAGE_RETURN,
+ CHAR_TAB,
+ CHAR_FORM_FEED,
+ CHAR_EXCLAMATION_MARK,
+ CHAR_HASH,
+ CHAR_SPACE,
+ CHAR_NO_BREAK_SPACE,
+ CHAR_ZERO_WIDTH_NOBREAK_SPACE,
+ CHAR_LEFT_SQUARE_BRACKET,
+ CHAR_RIGHT_SQUARE_BRACKET,
+ CHAR_LEFT_ANGLE_BRACKET,
+ CHAR_RIGHT_ANGLE_BRACKET,
+ CHAR_LEFT_CURLY_BRACKET,
+ CHAR_RIGHT_CURLY_BRACKET,
+ CHAR_HYPHEN_MINUS,
+ CHAR_PLUS,
+ CHAR_DOUBLE_QUOTE,
+ CHAR_SINGLE_QUOTE,
+ CHAR_PERCENT,
+ CHAR_SEMICOLON,
+ CHAR_CIRCUMFLEX_ACCENT,
+ CHAR_GRAVE_ACCENT,
+ CHAR_AT,
+ CHAR_AMPERSAND,
+ CHAR_EQUAL,
+
+ CHAR_0,
+ CHAR_9,
+
+ EOL,
+};
diff --git a/ext/node/polyfills/internal/crypto/_hex.ts b/ext/node/polyfills/internal/crypto/_hex.ts
new file mode 100644
index 000000000..5cc44aaa8
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/_hex.ts
@@ -0,0 +1,19 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+// deno-fmt-ignore
+const hexTable = new Uint8Array([
+ 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 97, 98,
+ 99, 100, 101, 102
+]);
+
+/** Encodes `src` into `src.length * 2` bytes. */
+export function encode(src: Uint8Array): Uint8Array {
+ const dst = new Uint8Array(src.length * 2);
+ for (let i = 0; i < dst.length; i++) {
+ const v = src[i];
+ dst[i * 2] = hexTable[v >> 4];
+ dst[i * 2 + 1] = hexTable[v & 0x0f];
+ }
+ return dst;
+}
diff --git a/ext/node/polyfills/internal/crypto/_keys.ts b/ext/node/polyfills/internal/crypto/_keys.ts
new file mode 100644
index 000000000..794582bf1
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/_keys.ts
@@ -0,0 +1,16 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { kKeyObject } from "internal:deno_node/polyfills/internal/crypto/constants.ts";
+
+export const kKeyType = Symbol("kKeyType");
+
+export function isKeyObject(obj: unknown): boolean {
+ return (
+ obj != null && (obj as Record<symbol, unknown>)[kKeyType] !== undefined
+ );
+}
+
+export function isCryptoKey(obj: unknown): boolean {
+ return (
+ obj != null && (obj as Record<symbol, unknown>)[kKeyObject] !== undefined
+ );
+}
diff --git a/ext/node/polyfills/internal/crypto/_randomBytes.ts b/ext/node/polyfills/internal/crypto/_randomBytes.ts
new file mode 100644
index 000000000..41678fcf1
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/_randomBytes.ts
@@ -0,0 +1,70 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+
+export const MAX_RANDOM_VALUES = 65536;
+export const MAX_SIZE = 4294967295;
+
+function generateRandomBytes(size: number) {
+ if (size > MAX_SIZE) {
+ throw new RangeError(
+ `The value of "size" is out of range. It must be >= 0 && <= ${MAX_SIZE}. Received ${size}`,
+ );
+ }
+
+ const bytes = Buffer.allocUnsafe(size);
+
+ //Work around for getRandomValues max generation
+ if (size > MAX_RANDOM_VALUES) {
+ for (let generated = 0; generated < size; generated += MAX_RANDOM_VALUES) {
+ globalThis.crypto.getRandomValues(
+ bytes.slice(generated, generated + MAX_RANDOM_VALUES),
+ );
+ }
+ } else {
+ globalThis.crypto.getRandomValues(bytes);
+ }
+
+ return bytes;
+}
+
+/**
+ * @param size Buffer length, must be equal or greater than zero
+ */
+export default function randomBytes(size: number): Buffer;
+export default function randomBytes(
+ size: number,
+ cb?: (err: Error | null, buf?: Buffer) => void,
+): void;
+export default function randomBytes(
+ size: number,
+ cb?: (err: Error | null, buf?: Buffer) => void,
+): Buffer | void {
+ if (typeof cb === "function") {
+ let err: Error | null = null, bytes: Buffer;
+ try {
+ bytes = generateRandomBytes(size);
+ } catch (e) {
+ //NodeJS nonsense
+ //If the size is out of range it will throw sync, otherwise throw async
+ if (
+ e instanceof RangeError &&
+ e.message.includes('The value of "size" is out of range')
+ ) {
+ throw e;
+ } else if (e instanceof Error) {
+ err = e;
+ } else {
+ err = new Error("[non-error thrown]");
+ }
+ }
+ setTimeout(() => {
+ if (err) {
+ cb(err);
+ } else {
+ cb(null, bytes);
+ }
+ }, 0);
+ } else {
+ return generateRandomBytes(size);
+ }
+}
diff --git a/ext/node/polyfills/internal/crypto/_randomFill.ts b/ext/node/polyfills/internal/crypto/_randomFill.ts
new file mode 100644
index 000000000..045072696
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/_randomFill.ts
@@ -0,0 +1,84 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import randomBytes, {
+ MAX_SIZE as kMaxUint32,
+} from "internal:deno_node/polyfills/internal/crypto/_randomBytes.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+
+const kBufferMaxLength = 0x7fffffff;
+
+function assertOffset(offset: number, length: number) {
+ if (offset > kMaxUint32 || offset < 0) {
+ throw new TypeError("offset must be a uint32");
+ }
+
+ if (offset > kBufferMaxLength || offset > length) {
+ throw new RangeError("offset out of range");
+ }
+}
+
+function assertSize(size: number, offset: number, length: number) {
+ if (size > kMaxUint32 || size < 0) {
+ throw new TypeError("size must be a uint32");
+ }
+
+ if (size + offset > length || size > kBufferMaxLength) {
+ throw new RangeError("buffer too small");
+ }
+}
+
+export default function randomFill(
+ buf: Buffer,
+ cb: (err: Error | null, buf: Buffer) => void,
+): void;
+
+export default function randomFill(
+ buf: Buffer,
+ offset: number,
+ cb: (err: Error | null, buf: Buffer) => void,
+): void;
+
+export default function randomFill(
+ buf: Buffer,
+ offset: number,
+ size: number,
+ cb: (err: Error | null, buf: Buffer) => void,
+): void;
+
+export default function randomFill(
+ buf: Buffer,
+ offset?: number | ((err: Error | null, buf: Buffer) => void),
+ size?: number | ((err: Error | null, buf: Buffer) => void),
+ cb?: (err: Error | null, buf: Buffer) => void,
+) {
+ if (typeof offset === "function") {
+ cb = offset;
+ offset = 0;
+ size = buf.length;
+ } else if (typeof size === "function") {
+ cb = size;
+ size = buf.length - Number(offset as number);
+ }
+
+ assertOffset(offset as number, buf.length);
+ assertSize(size as number, offset as number, buf.length);
+
+ randomBytes(size as number, (err, bytes) => {
+ if (err) return cb!(err, buf);
+ bytes?.copy(buf, offset as number);
+ cb!(null, buf);
+ });
+}
+
+export function randomFillSync(buf: Buffer, offset = 0, size?: number) {
+ assertOffset(offset, buf.length);
+
+ if (size === undefined) size = buf.length - offset;
+
+ assertSize(size, offset, buf.length);
+
+ const bytes = randomBytes(size);
+
+ bytes.copy(buf, offset);
+
+ return buf;
+}
diff --git a/ext/node/polyfills/internal/crypto/_randomInt.ts b/ext/node/polyfills/internal/crypto/_randomInt.ts
new file mode 100644
index 000000000..637251541
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/_randomInt.ts
@@ -0,0 +1,60 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+export default function randomInt(max: number): number;
+export default function randomInt(min: number, max: number): number;
+export default function randomInt(
+ max: number,
+ cb: (err: Error | null, n?: number) => void,
+): void;
+export default function randomInt(
+ min: number,
+ max: number,
+ cb: (err: Error | null, n?: number) => void,
+): void;
+
+export default function randomInt(
+ max: number,
+ min?: ((err: Error | null, n?: number) => void) | number,
+ cb?: (err: Error | null, n?: number) => void,
+): number | void {
+ if (typeof max === "number" && typeof min === "number") {
+ [max, min] = [min, max];
+ }
+ if (min === undefined) min = 0;
+ else if (typeof min === "function") {
+ cb = min;
+ min = 0;
+ }
+
+ if (
+ !Number.isSafeInteger(min) ||
+ typeof max === "number" && !Number.isSafeInteger(max)
+ ) {
+ throw new Error("max or min is not a Safe Number");
+ }
+
+ if (max - min > Math.pow(2, 48)) {
+ throw new RangeError("max - min should be less than 2^48!");
+ }
+
+ if (min >= max) {
+ throw new Error("Min is bigger than Max!");
+ }
+
+ const randomBuffer = new Uint32Array(1);
+
+ globalThis.crypto.getRandomValues(randomBuffer);
+
+ const randomNumber = randomBuffer[0] / (0xffffffff + 1);
+
+ min = Math.ceil(min);
+ max = Math.floor(max);
+
+ const result = Math.floor(randomNumber * (max - min)) + min;
+
+ if (cb) {
+ cb(null, result);
+ return;
+ }
+
+ return result;
+}
diff --git a/ext/node/polyfills/internal/crypto/certificate.ts b/ext/node/polyfills/internal/crypto/certificate.ts
new file mode 100644
index 000000000..f6fb333a9
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/certificate.ts
@@ -0,0 +1,23 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { BinaryLike } from "internal:deno_node/polyfills/internal/crypto/types.ts";
+
+export class Certificate {
+ static Certificate = Certificate;
+ static exportChallenge(_spkac: BinaryLike, _encoding?: string): Buffer {
+ notImplemented("crypto.Certificate.exportChallenge");
+ }
+
+ static exportPublicKey(_spkac: BinaryLike, _encoding?: string): Buffer {
+ notImplemented("crypto.Certificate.exportPublicKey");
+ }
+
+ static verifySpkac(_spkac: BinaryLike, _encoding?: string): boolean {
+ notImplemented("crypto.Certificate.verifySpkac");
+ }
+}
+
+export default Certificate;
diff --git a/ext/node/polyfills/internal/crypto/cipher.ts b/ext/node/polyfills/internal/crypto/cipher.ts
new file mode 100644
index 000000000..2778b40fa
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/cipher.ts
@@ -0,0 +1,292 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { ERR_INVALID_ARG_TYPE } from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ validateInt32,
+ validateObject,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import type { TransformOptions } from "internal:deno_node/polyfills/_stream.d.ts";
+import { Transform } from "internal:deno_node/polyfills/_stream.mjs";
+import { KeyObject } from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import type { BufferEncoding } from "internal:deno_node/polyfills/_global.d.ts";
+import type {
+ BinaryLike,
+ Encoding,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import {
+ privateDecrypt,
+ privateEncrypt,
+ publicDecrypt,
+ publicEncrypt,
+} from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/mod.js";
+
+export {
+ privateDecrypt,
+ privateEncrypt,
+ publicDecrypt,
+ publicEncrypt,
+} from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/mod.js";
+
+export type CipherCCMTypes =
+ | "aes-128-ccm"
+ | "aes-192-ccm"
+ | "aes-256-ccm"
+ | "chacha20-poly1305";
+export type CipherGCMTypes = "aes-128-gcm" | "aes-192-gcm" | "aes-256-gcm";
+export type CipherOCBTypes = "aes-128-ocb" | "aes-192-ocb" | "aes-256-ocb";
+
+export type CipherKey = BinaryLike | KeyObject;
+
+export interface CipherCCMOptions extends TransformOptions {
+ authTagLength: number;
+}
+
+export interface CipherGCMOptions extends TransformOptions {
+ authTagLength?: number | undefined;
+}
+
+export interface CipherOCBOptions extends TransformOptions {
+ authTagLength: number;
+}
+
+export interface Cipher extends ReturnType<typeof Transform> {
+ update(data: BinaryLike): Buffer;
+ update(data: string, inputEncoding: Encoding): Buffer;
+ update(
+ data: ArrayBufferView,
+ inputEncoding: undefined,
+ outputEncoding: Encoding,
+ ): string;
+ update(
+ data: string,
+ inputEncoding: Encoding | undefined,
+ outputEncoding: Encoding,
+ ): string;
+
+ final(): Buffer;
+ final(outputEncoding: BufferEncoding): string;
+
+ setAutoPadding(autoPadding?: boolean): this;
+}
+
+export type Decipher = Cipher;
+
+export interface CipherCCM extends Cipher {
+ setAAD(
+ buffer: ArrayBufferView,
+ options: {
+ plaintextLength: number;
+ },
+ ): this;
+ getAuthTag(): Buffer;
+}
+
+export interface CipherGCM extends Cipher {
+ setAAD(
+ buffer: ArrayBufferView,
+ options?: {
+ plaintextLength: number;
+ },
+ ): this;
+ getAuthTag(): Buffer;
+}
+
+export interface CipherOCB extends Cipher {
+ setAAD(
+ buffer: ArrayBufferView,
+ options?: {
+ plaintextLength: number;
+ },
+ ): this;
+ getAuthTag(): Buffer;
+}
+
+export interface DecipherCCM extends Decipher {
+ setAuthTag(buffer: ArrayBufferView): this;
+ setAAD(
+ buffer: ArrayBufferView,
+ options: {
+ plaintextLength: number;
+ },
+ ): this;
+}
+
+export interface DecipherGCM extends Decipher {
+ setAuthTag(buffer: ArrayBufferView): this;
+ setAAD(
+ buffer: ArrayBufferView,
+ options?: {
+ plaintextLength: number;
+ },
+ ): this;
+}
+
+export interface DecipherOCB extends Decipher {
+ setAuthTag(buffer: ArrayBufferView): this;
+ setAAD(
+ buffer: ArrayBufferView,
+ options?: {
+ plaintextLength: number;
+ },
+ ): this;
+}
+
+export class Cipheriv extends Transform implements Cipher {
+ constructor(
+ _cipher: string,
+ _key: CipherKey,
+ _iv: BinaryLike | null,
+ _options?: TransformOptions,
+ ) {
+ super();
+
+ notImplemented("crypto.Cipheriv");
+ }
+
+ final(): Buffer;
+ final(outputEncoding: BufferEncoding): string;
+ final(_outputEncoding?: string): Buffer | string {
+ notImplemented("crypto.Cipheriv.prototype.final");
+ }
+
+ getAuthTag(): Buffer {
+ notImplemented("crypto.Cipheriv.prototype.getAuthTag");
+ }
+
+ setAAD(
+ _buffer: ArrayBufferView,
+ _options?: {
+ plaintextLength: number;
+ },
+ ): this {
+ notImplemented("crypto.Cipheriv.prototype.setAAD");
+ }
+
+ setAutoPadding(_autoPadding?: boolean): this {
+ notImplemented("crypto.Cipheriv.prototype.setAutoPadding");
+ }
+
+ update(data: BinaryLike): Buffer;
+ update(data: string, inputEncoding: Encoding): Buffer;
+ update(
+ data: ArrayBufferView,
+ inputEncoding: undefined,
+ outputEncoding: Encoding,
+ ): string;
+ update(
+ data: string,
+ inputEncoding: Encoding | undefined,
+ outputEncoding: Encoding,
+ ): string;
+ update(
+ _data: string | BinaryLike | ArrayBufferView,
+ _inputEncoding?: Encoding,
+ _outputEncoding?: Encoding,
+ ): Buffer | string {
+ notImplemented("crypto.Cipheriv.prototype.update");
+ }
+}
+
+export class Decipheriv extends Transform implements Cipher {
+ constructor(
+ _cipher: string,
+ _key: CipherKey,
+ _iv: BinaryLike | null,
+ _options?: TransformOptions,
+ ) {
+ super();
+
+ notImplemented("crypto.Decipheriv");
+ }
+
+ final(): Buffer;
+ final(outputEncoding: BufferEncoding): string;
+ final(_outputEncoding?: string): Buffer | string {
+ notImplemented("crypto.Decipheriv.prototype.final");
+ }
+
+ setAAD(
+ _buffer: ArrayBufferView,
+ _options?: {
+ plaintextLength: number;
+ },
+ ): this {
+ notImplemented("crypto.Decipheriv.prototype.setAAD");
+ }
+
+ setAuthTag(_buffer: BinaryLike, _encoding?: string): this {
+ notImplemented("crypto.Decipheriv.prototype.setAuthTag");
+ }
+
+ setAutoPadding(_autoPadding?: boolean): this {
+ notImplemented("crypto.Decipheriv.prototype.setAutoPadding");
+ }
+
+ update(data: BinaryLike): Buffer;
+ update(data: string, inputEncoding: Encoding): Buffer;
+ update(
+ data: ArrayBufferView,
+ inputEncoding: undefined,
+ outputEncoding: Encoding,
+ ): string;
+ update(
+ data: string,
+ inputEncoding: Encoding | undefined,
+ outputEncoding: Encoding,
+ ): string;
+ update(
+ _data: string | BinaryLike | ArrayBufferView,
+ _inputEncoding?: Encoding,
+ _outputEncoding?: Encoding,
+ ): Buffer | string {
+ notImplemented("crypto.Decipheriv.prototype.update");
+ }
+}
+
+export function getCipherInfo(
+ nameOrNid: string | number,
+ options?: { keyLength?: number; ivLength?: number },
+) {
+ if (typeof nameOrNid !== "string" && typeof nameOrNid !== "number") {
+ throw new ERR_INVALID_ARG_TYPE(
+ "nameOrNid",
+ ["string", "number"],
+ nameOrNid,
+ );
+ }
+
+ if (typeof nameOrNid === "number") {
+ validateInt32(nameOrNid, "nameOrNid");
+ }
+
+ let keyLength, ivLength;
+
+ if (options !== undefined) {
+ validateObject(options, "options");
+
+ ({ keyLength, ivLength } = options);
+
+ if (keyLength !== undefined) {
+ validateInt32(keyLength, "options.keyLength");
+ }
+
+ if (ivLength !== undefined) {
+ validateInt32(ivLength, "options.ivLength");
+ }
+ }
+
+ notImplemented("crypto.getCipherInfo");
+}
+
+export default {
+ privateDecrypt,
+ privateEncrypt,
+ publicDecrypt,
+ publicEncrypt,
+ Cipheriv,
+ Decipheriv,
+ getCipherInfo,
+};
diff --git a/ext/node/polyfills/internal/crypto/constants.ts b/ext/node/polyfills/internal/crypto/constants.ts
new file mode 100644
index 000000000..d62415360
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/constants.ts
@@ -0,0 +1,5 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+export const kHandle = Symbol("kHandle");
+export const kKeyObject = Symbol("kKeyObject");
diff --git a/ext/node/polyfills/internal/crypto/diffiehellman.ts b/ext/node/polyfills/internal/crypto/diffiehellman.ts
new file mode 100644
index 000000000..eb903ccb3
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/diffiehellman.ts
@@ -0,0 +1,306 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import {
+ isAnyArrayBuffer,
+ isArrayBufferView,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+import { ERR_INVALID_ARG_TYPE } from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ validateInt32,
+ validateString,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ getDefaultEncoding,
+ toBuf,
+} from "internal:deno_node/polyfills/internal/crypto/util.ts";
+import type {
+ BinaryLike,
+ BinaryToTextEncoding,
+ ECDHKeyFormat,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import { KeyObject } from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import type { BufferEncoding } from "internal:deno_node/polyfills/_global.d.ts";
+
+const DH_GENERATOR = 2;
+
+export class DiffieHellman {
+ verifyError!: number;
+
+ constructor(
+ sizeOrKey: unknown,
+ keyEncoding?: unknown,
+ generator?: unknown,
+ genEncoding?: unknown,
+ ) {
+ if (
+ typeof sizeOrKey !== "number" &&
+ typeof sizeOrKey !== "string" &&
+ !isArrayBufferView(sizeOrKey) &&
+ !isAnyArrayBuffer(sizeOrKey)
+ ) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "sizeOrKey",
+ ["number", "string", "ArrayBuffer", "Buffer", "TypedArray", "DataView"],
+ sizeOrKey,
+ );
+ }
+
+ if (typeof sizeOrKey === "number") {
+ validateInt32(sizeOrKey, "sizeOrKey");
+ }
+
+ if (
+ keyEncoding &&
+ !Buffer.isEncoding(keyEncoding as BinaryToTextEncoding) &&
+ keyEncoding !== "buffer"
+ ) {
+ genEncoding = generator;
+ generator = keyEncoding;
+ keyEncoding = false;
+ }
+
+ const encoding = getDefaultEncoding();
+ keyEncoding = keyEncoding || encoding;
+ genEncoding = genEncoding || encoding;
+
+ if (typeof sizeOrKey !== "number") {
+ sizeOrKey = toBuf(sizeOrKey as string, keyEncoding as string);
+ }
+
+ if (!generator) {
+ generator = DH_GENERATOR;
+ } else if (typeof generator === "number") {
+ validateInt32(generator, "generator");
+ } else if (typeof generator === "string") {
+ generator = toBuf(generator, genEncoding as string);
+ } else if (!isArrayBufferView(generator) && !isAnyArrayBuffer(generator)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "generator",
+ ["number", "string", "ArrayBuffer", "Buffer", "TypedArray", "DataView"],
+ generator,
+ );
+ }
+
+ notImplemented("crypto.DiffieHellman");
+ }
+
+ computeSecret(otherPublicKey: ArrayBufferView): Buffer;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ ): Buffer;
+ computeSecret(
+ otherPublicKey: ArrayBufferView,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ _otherPublicKey: ArrayBufferView | string,
+ _inputEncoding?: BinaryToTextEncoding,
+ _outputEncoding?: BinaryToTextEncoding,
+ ): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.computeSecret");
+ }
+
+ generateKeys(): Buffer;
+ generateKeys(encoding: BinaryToTextEncoding): string;
+ generateKeys(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.generateKeys");
+ }
+
+ getGenerator(): Buffer;
+ getGenerator(encoding: BinaryToTextEncoding): string;
+ getGenerator(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getGenerator");
+ }
+
+ getPrime(): Buffer;
+ getPrime(encoding: BinaryToTextEncoding): string;
+ getPrime(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPrime");
+ }
+
+ getPrivateKey(): Buffer;
+ getPrivateKey(encoding: BinaryToTextEncoding): string;
+ getPrivateKey(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPrivateKey");
+ }
+
+ getPublicKey(): Buffer;
+ getPublicKey(encoding: BinaryToTextEncoding): string;
+ getPublicKey(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPublicKey");
+ }
+
+ setPrivateKey(privateKey: ArrayBufferView): void;
+ setPrivateKey(privateKey: string, encoding: BufferEncoding): void;
+ setPrivateKey(
+ _privateKey: ArrayBufferView | string,
+ _encoding?: BufferEncoding,
+ ) {
+ notImplemented("crypto.DiffieHellman.prototype.setPrivateKey");
+ }
+
+ setPublicKey(publicKey: ArrayBufferView): void;
+ setPublicKey(publicKey: string, encoding: BufferEncoding): void;
+ setPublicKey(
+ _publicKey: ArrayBufferView | string,
+ _encoding?: BufferEncoding,
+ ) {
+ notImplemented("crypto.DiffieHellman.prototype.setPublicKey");
+ }
+}
+
+export class DiffieHellmanGroup {
+ verifyError!: number;
+
+ constructor(_name: string) {
+ notImplemented("crypto.DiffieHellmanGroup");
+ }
+
+ computeSecret(otherPublicKey: ArrayBufferView): Buffer;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ ): Buffer;
+ computeSecret(
+ otherPublicKey: ArrayBufferView,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ _otherPublicKey: ArrayBufferView | string,
+ _inputEncoding?: BinaryToTextEncoding,
+ _outputEncoding?: BinaryToTextEncoding,
+ ): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.computeSecret");
+ }
+
+ generateKeys(): Buffer;
+ generateKeys(encoding: BinaryToTextEncoding): string;
+ generateKeys(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.generateKeys");
+ }
+
+ getGenerator(): Buffer;
+ getGenerator(encoding: BinaryToTextEncoding): string;
+ getGenerator(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getGenerator");
+ }
+
+ getPrime(): Buffer;
+ getPrime(encoding: BinaryToTextEncoding): string;
+ getPrime(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPrime");
+ }
+
+ getPrivateKey(): Buffer;
+ getPrivateKey(encoding: BinaryToTextEncoding): string;
+ getPrivateKey(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPrivateKey");
+ }
+
+ getPublicKey(): Buffer;
+ getPublicKey(encoding: BinaryToTextEncoding): string;
+ getPublicKey(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.DiffieHellman.prototype.getPublicKey");
+ }
+}
+
+export class ECDH {
+ constructor(curve: string) {
+ validateString(curve, "curve");
+
+ notImplemented("crypto.ECDH");
+ }
+
+ static convertKey(
+ _key: BinaryLike,
+ _curve: string,
+ _inputEncoding?: BinaryToTextEncoding,
+ _outputEncoding?: "latin1" | "hex" | "base64" | "base64url",
+ _format?: "uncompressed" | "compressed" | "hybrid",
+ ): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.convertKey");
+ }
+
+ computeSecret(otherPublicKey: ArrayBufferView): Buffer;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ ): Buffer;
+ computeSecret(
+ otherPublicKey: ArrayBufferView,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ otherPublicKey: string,
+ inputEncoding: BinaryToTextEncoding,
+ outputEncoding: BinaryToTextEncoding,
+ ): string;
+ computeSecret(
+ _otherPublicKey: ArrayBufferView | string,
+ _inputEncoding?: BinaryToTextEncoding,
+ _outputEncoding?: BinaryToTextEncoding,
+ ): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.computeSecret");
+ }
+
+ generateKeys(): Buffer;
+ generateKeys(encoding: BinaryToTextEncoding, format?: ECDHKeyFormat): string;
+ generateKeys(
+ _encoding?: BinaryToTextEncoding,
+ _format?: ECDHKeyFormat,
+ ): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.generateKeys");
+ }
+
+ getPrivateKey(): Buffer;
+ getPrivateKey(encoding: BinaryToTextEncoding): string;
+ getPrivateKey(_encoding?: BinaryToTextEncoding): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.getPrivateKey");
+ }
+
+ getPublicKey(): Buffer;
+ getPublicKey(encoding: BinaryToTextEncoding, format?: ECDHKeyFormat): string;
+ getPublicKey(
+ _encoding?: BinaryToTextEncoding,
+ _format?: ECDHKeyFormat,
+ ): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.getPublicKey");
+ }
+
+ setPrivateKey(privateKey: ArrayBufferView): void;
+ setPrivateKey(privateKey: string, encoding: BinaryToTextEncoding): void;
+ setPrivateKey(
+ _privateKey: ArrayBufferView | string,
+ _encoding?: BinaryToTextEncoding,
+ ): Buffer | string {
+ notImplemented("crypto.ECDH.prototype.setPrivateKey");
+ }
+}
+
+export function diffieHellman(_options: {
+ privateKey: KeyObject;
+ publicKey: KeyObject;
+}): Buffer {
+ notImplemented("crypto.diffieHellman");
+}
+
+export default {
+ DiffieHellman,
+ DiffieHellmanGroup,
+ ECDH,
+ diffieHellman,
+};
diff --git a/ext/node/polyfills/internal/crypto/hash.ts b/ext/node/polyfills/internal/crypto/hash.ts
new file mode 100644
index 000000000..7995e5f8c
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/hash.ts
@@ -0,0 +1,230 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import {
+ TextDecoder,
+ TextEncoder,
+} from "internal:deno_web/08_text_encoding.js";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { Transform } from "internal:deno_node/polyfills/stream.ts";
+import { encode as encodeToHex } from "internal:deno_node/polyfills/internal/crypto/_hex.ts";
+import {
+ forgivingBase64Encode as encodeToBase64,
+ forgivingBase64UrlEncode as encodeToBase64Url,
+} from "internal:deno_web/00_infra.js";
+import type { TransformOptions } from "internal:deno_node/polyfills/_stream.d.ts";
+import { validateString } from "internal:deno_node/polyfills/internal/validators.mjs";
+import type {
+ BinaryToTextEncoding,
+ Encoding,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import {
+ KeyObject,
+ prepareSecretKey,
+} from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+
+const { ops } = globalThis.__bootstrap.core;
+
+const coerceToBytes = (data: string | BufferSource): Uint8Array => {
+ if (data instanceof Uint8Array) {
+ return data;
+ } else if (typeof data === "string") {
+ // This assumes UTF-8, which may not be correct.
+ return new TextEncoder().encode(data);
+ } else if (ArrayBuffer.isView(data)) {
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
+ } else if (data instanceof ArrayBuffer) {
+ return new Uint8Array(data);
+ } else {
+ throw new TypeError("expected data to be string | BufferSource");
+ }
+};
+
+/**
+ * The Hash class is a utility for creating hash digests of data. It can be used in one of two ways:
+ *
+ * - As a stream that is both readable and writable, where data is written to produce a computed hash digest on the readable side, or
+ * - Using the hash.update() and hash.digest() methods to produce the computed hash.
+ *
+ * The crypto.createHash() method is used to create Hash instances. Hash objects are not to be created directly using the new keyword.
+ */
+export class Hash extends Transform {
+ #context: number;
+
+ constructor(
+ algorithm: string | number,
+ _opts?: TransformOptions,
+ ) {
+ super({
+ transform(chunk: string, _encoding: string, callback: () => void) {
+ ops.op_node_hash_update(context, coerceToBytes(chunk));
+ callback();
+ },
+ flush(callback: () => void) {
+ this.push(context.digest(undefined));
+ callback();
+ },
+ });
+
+ if (typeof algorithm === "string") {
+ this.#context = ops.op_node_create_hash(
+ algorithm,
+ );
+ } else {
+ this.#context = algorithm;
+ }
+
+ const context = this.#context;
+ }
+
+ copy(): Hash {
+ return new Hash(ops.op_node_clone_hash(this.#context));
+ }
+
+ /**
+ * Updates the hash content with the given data.
+ */
+ update(data: string | ArrayBuffer, _encoding?: string): this {
+ let bytes;
+ if (typeof data === "string") {
+ data = new TextEncoder().encode(data);
+ bytes = coerceToBytes(data);
+ } else {
+ bytes = coerceToBytes(data);
+ }
+
+ ops.op_node_hash_update(this.#context, bytes);
+
+ return this;
+ }
+
+ /**
+ * Calculates the digest of all of the data.
+ *
+ * If encoding is provided a string will be returned; otherwise a Buffer is returned.
+ *
+ * Supported encodings are currently 'hex', 'binary', 'base64', 'base64url'.
+ */
+ digest(encoding?: string): Buffer | string {
+ const digest = this.#context.digest(undefined);
+ if (encoding === undefined) {
+ return Buffer.from(digest);
+ }
+
+ switch (encoding) {
+ case "hex":
+ return new TextDecoder().decode(encodeToHex(new Uint8Array(digest)));
+ case "binary":
+ return String.fromCharCode(...digest);
+ case "base64":
+ return encodeToBase64(digest);
+ case "base64url":
+ return encodeToBase64Url(digest);
+ case "buffer":
+ return Buffer.from(digest);
+ default:
+ return Buffer.from(digest).toString(encoding);
+ }
+ }
+}
+
+export function Hmac(
+ hmac: string,
+ key: string | ArrayBuffer | KeyObject,
+ options?: TransformOptions,
+): Hmac {
+ return new HmacImpl(hmac, key, options);
+}
+
+type Hmac = HmacImpl;
+
+class HmacImpl extends Transform {
+ #ipad: Uint8Array;
+ #opad: Uint8Array;
+ #ZEROES = Buffer.alloc(128);
+ #algorithm: string;
+ #hash: Hash;
+
+ constructor(
+ hmac: string,
+ key: string | ArrayBuffer | KeyObject,
+ options?: TransformOptions,
+ ) {
+ super({
+ transform(chunk: string, encoding: string, callback: () => void) {
+ // deno-lint-ignore no-explicit-any
+ self.update(coerceToBytes(chunk), encoding as any);
+ callback();
+ },
+ flush(callback: () => void) {
+ this.push(self.digest());
+ callback();
+ },
+ });
+ // deno-lint-ignore no-this-alias
+ const self = this;
+ if (key instanceof KeyObject) {
+ notImplemented("Hmac: KeyObject key is not implemented");
+ }
+
+ validateString(hmac, "hmac");
+ const u8Key = prepareSecretKey(key, options?.encoding) as Buffer;
+
+ const alg = hmac.toLowerCase();
+ this.#hash = new Hash(alg, options);
+ this.#algorithm = alg;
+ const blockSize = (alg === "sha512" || alg === "sha384") ? 128 : 64;
+ const keySize = u8Key.length;
+
+ let bufKey: Buffer;
+
+ if (keySize > blockSize) {
+ bufKey = this.#hash.update(u8Key).digest() as Buffer;
+ } else {
+ bufKey = Buffer.concat([u8Key, this.#ZEROES], blockSize);
+ }
+
+ this.#ipad = Buffer.allocUnsafe(blockSize);
+ this.#opad = Buffer.allocUnsafe(blockSize);
+
+ for (let i = 0; i < blockSize; i++) {
+ this.#ipad[i] = bufKey[i] ^ 0x36;
+ this.#opad[i] = bufKey[i] ^ 0x5C;
+ }
+
+ this.#hash = new Hash(alg);
+ this.#hash.update(this.#ipad);
+ }
+
+ digest(): Buffer;
+ digest(encoding: BinaryToTextEncoding): string;
+ digest(encoding?: BinaryToTextEncoding): Buffer | string {
+ const result = this.#hash.digest();
+
+ return new Hash(this.#algorithm).update(this.#opad).update(result).digest(
+ encoding,
+ );
+ }
+
+ update(data: string | ArrayBuffer, inputEncoding?: Encoding): this {
+ this.#hash.update(data, inputEncoding);
+ return this;
+ }
+}
+
+Hmac.prototype = HmacImpl.prototype;
+
+/**
+ * Creates and returns a Hash object that can be used to generate hash digests
+ * using the given `algorithm`. Optional `options` argument controls stream behavior.
+ */
+export function createHash(algorithm: string, opts?: TransformOptions) {
+ return new Hash(algorithm, opts);
+}
+
+export default {
+ Hash,
+ Hmac,
+ createHash,
+};
diff --git a/ext/node/polyfills/internal/crypto/hkdf.ts b/ext/node/polyfills/internal/crypto/hkdf.ts
new file mode 100644
index 000000000..aebdd9152
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/hkdf.ts
@@ -0,0 +1,130 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import {
+ validateFunction,
+ validateInteger,
+ validateString,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import {
+ ERR_INVALID_ARG_TYPE,
+ ERR_OUT_OF_RANGE,
+ hideStackFrames,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ toBuf,
+ validateByteSource,
+} from "internal:deno_node/polyfills/internal/crypto/util.ts";
+import {
+ createSecretKey,
+ isKeyObject,
+ KeyObject,
+} from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import type { BinaryLike } from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import { kMaxLength } from "internal:deno_node/polyfills/internal/buffer.mjs";
+import {
+ isAnyArrayBuffer,
+ isArrayBufferView,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+
+const validateParameters = hideStackFrames((hash, key, salt, info, length) => {
+ key = prepareKey(key);
+ salt = toBuf(salt);
+ info = toBuf(info);
+
+ validateString(hash, "digest");
+ validateByteSource(salt, "salt");
+ validateByteSource(info, "info");
+
+ validateInteger(length, "length", 0, kMaxLength);
+
+ if (info.byteLength > 1024) {
+ throw new ERR_OUT_OF_RANGE(
+ "info",
+ "must not contain more than 1024 bytes",
+ info.byteLength,
+ );
+ }
+
+ return {
+ hash,
+ key,
+ salt,
+ info,
+ length,
+ };
+});
+
+function prepareKey(key: BinaryLike | KeyObject) {
+ if (isKeyObject(key)) {
+ return key;
+ }
+
+ if (isAnyArrayBuffer(key)) {
+ return createSecretKey(new Uint8Array(key as unknown as ArrayBufferLike));
+ }
+
+ key = toBuf(key as string);
+
+ if (!isArrayBufferView(key)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "ikm",
+ [
+ "string",
+ "SecretKeyObject",
+ "ArrayBuffer",
+ "TypedArray",
+ "DataView",
+ "Buffer",
+ ],
+ key,
+ );
+ }
+
+ return createSecretKey(key);
+}
+
+export function hkdf(
+ hash: string,
+ key: BinaryLike | KeyObject,
+ salt: BinaryLike,
+ info: BinaryLike,
+ length: number,
+ callback: (err: Error | null, derivedKey: ArrayBuffer) => void,
+) {
+ ({ hash, key, salt, info, length } = validateParameters(
+ hash,
+ key,
+ salt,
+ info,
+ length,
+ ));
+
+ validateFunction(callback, "callback");
+
+ notImplemented("crypto.hkdf");
+}
+
+export function hkdfSync(
+ hash: string,
+ key: BinaryLike | KeyObject,
+ salt: BinaryLike,
+ info: BinaryLike,
+ length: number,
+) {
+ ({ hash, key, salt, info, length } = validateParameters(
+ hash,
+ key,
+ salt,
+ info,
+ length,
+ ));
+
+ notImplemented("crypto.hkdfSync");
+}
+
+export default {
+ hkdf,
+ hkdfSync,
+};
diff --git a/ext/node/polyfills/internal/crypto/keygen.ts b/ext/node/polyfills/internal/crypto/keygen.ts
new file mode 100644
index 000000000..1a947b95b
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/keygen.ts
@@ -0,0 +1,682 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { KeyObject } from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ KeyFormat,
+ KeyType,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+
+export function generateKey(
+ _type: "hmac" | "aes",
+ _options: {
+ length: number;
+ },
+ _callback: (err: Error | null, key: KeyObject) => void,
+) {
+ notImplemented("crypto.generateKey");
+}
+
+export interface BasePrivateKeyEncodingOptions<T extends KeyFormat> {
+ format: T;
+ cipher?: string | undefined;
+ passphrase?: string | undefined;
+}
+
+export interface RSAKeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Public exponent
+ * @default 0x10001
+ */
+ publicExponent?: number | undefined;
+ publicKeyEncoding: {
+ type: "pkcs1" | "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs1" | "pkcs8";
+ };
+}
+
+export interface RSAPSSKeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Public exponent
+ * @default 0x10001
+ */
+ publicExponent?: number | undefined;
+ /**
+ * Name of the message digest
+ */
+ hashAlgorithm?: string;
+ /**
+ * Name of the message digest used by MGF1
+ */
+ mgf1HashAlgorithm?: string;
+ /**
+ * Minimal salt length in bytes
+ */
+ saltLength?: string;
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface DSAKeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Size of q in bits
+ */
+ divisorLength: number;
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface ECKeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ /**
+ * Name of the curve to use.
+ */
+ namedCurve: string;
+ publicKeyEncoding: {
+ type: "pkcs1" | "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "sec1" | "pkcs8";
+ };
+}
+
+export interface ED25519KeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface ED448KeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface X25519KeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface X448KeyPairOptions<
+ PubF extends KeyFormat,
+ PrivF extends KeyFormat,
+> {
+ publicKeyEncoding: {
+ type: "spki";
+ format: PubF;
+ };
+ privateKeyEncoding: BasePrivateKeyEncodingOptions<PrivF> & {
+ type: "pkcs8";
+ };
+}
+
+export interface RSAKeyPairKeyObjectOptions {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Public exponent
+ * @default 0x10001
+ */
+ publicExponent?: number | undefined;
+}
+
+export interface RSAPSSKeyPairKeyObjectOptions {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Public exponent
+ * @default 0x10001
+ */
+ publicExponent?: number | undefined;
+ /**
+ * Name of the message digest
+ */
+ hashAlgorithm?: string;
+ /**
+ * Name of the message digest used by MGF1
+ */
+ mgf1HashAlgorithm?: string;
+ /**
+ * Minimal salt length in bytes
+ */
+ saltLength?: string;
+}
+
+export interface DSAKeyPairKeyObjectOptions {
+ /**
+ * Key size in bits
+ */
+ modulusLength: number;
+ /**
+ * Size of q in bits
+ */
+ divisorLength: number;
+}
+
+// deno-lint-ignore no-empty-interface
+export interface ED25519KeyPairKeyObjectOptions {}
+
+// deno-lint-ignore no-empty-interface
+export interface ED448KeyPairKeyObjectOptions {}
+
+// deno-lint-ignore no-empty-interface
+export interface X25519KeyPairKeyObjectOptions {}
+
+// deno-lint-ignore no-empty-interface
+export interface X448KeyPairKeyObjectOptions {}
+
+export interface ECKeyPairKeyObjectOptions {
+ /**
+ * Name of the curve to use
+ */
+ namedCurve: string;
+}
+
+export function generateKeyPair(
+ type: "rsa",
+ options: RSAKeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa",
+ options: RSAKeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa",
+ options: RSAKeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa",
+ options: RSAKeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa",
+ options: RSAKeyPairKeyObjectOptions,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairKeyObjectOptions,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "dsa",
+ options: DSAKeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "dsa",
+ options: DSAKeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "dsa",
+ options: DSAKeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "dsa",
+ options: DSAKeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "dsa",
+ options: DSAKeyPairKeyObjectOptions,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "ec",
+ options: ECKeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ec",
+ options: ECKeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ec",
+ options: ECKeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ec",
+ options: ECKeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ec",
+ options: ECKeyPairKeyObjectOptions,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ed25519",
+ options: ED25519KeyPairKeyObjectOptions | undefined,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "ed448",
+ options: ED448KeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ed448",
+ options: ED448KeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ed448",
+ options: ED448KeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "ed448",
+ options: ED448KeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "ed448",
+ options: ED448KeyPairKeyObjectOptions | undefined,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "x25519",
+ options: X25519KeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "x25519",
+ options: X25519KeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "x25519",
+ options: X25519KeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "x25519",
+ options: X25519KeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "x25519",
+ options: X25519KeyPairKeyObjectOptions | undefined,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ type: "x448",
+ options: X448KeyPairOptions<"pem", "pem">,
+ callback: (err: Error | null, publicKey: string, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "x448",
+ options: X448KeyPairOptions<"pem", "der">,
+ callback: (err: Error | null, publicKey: string, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "x448",
+ options: X448KeyPairOptions<"der", "pem">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: string) => void,
+): void;
+export function generateKeyPair(
+ type: "x448",
+ options: X448KeyPairOptions<"der", "der">,
+ callback: (err: Error | null, publicKey: Buffer, privateKey: Buffer) => void,
+): void;
+export function generateKeyPair(
+ type: "x448",
+ options: X448KeyPairKeyObjectOptions | undefined,
+ callback: (
+ err: Error | null,
+ publicKey: KeyObject,
+ privateKey: KeyObject,
+ ) => void,
+): void;
+export function generateKeyPair(
+ _type: KeyType,
+ _options: unknown,
+ _callback: (
+ err: Error | null,
+ // deno-lint-ignore no-explicit-any
+ publicKey: any,
+ // deno-lint-ignore no-explicit-any
+ privateKey: any,
+ ) => void,
+) {
+ notImplemented("crypto.generateKeyPair");
+}
+
+export interface KeyPairKeyObjectResult {
+ publicKey: KeyObject;
+ privateKey: KeyObject;
+}
+
+export interface KeyPairSyncResult<
+ T1 extends string | Buffer,
+ T2 extends string | Buffer,
+> {
+ publicKey: T1;
+ privateKey: T2;
+}
+
+export function generateKeyPairSync(
+ type: "rsa",
+ options: RSAKeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "rsa",
+ options: RSAKeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "rsa",
+ options: RSAKeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "rsa",
+ options: RSAKeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "rsa",
+ options: RSAKeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "rsa-pss",
+ options: RSAPSSKeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "dsa",
+ options: DSAKeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "dsa",
+ options: DSAKeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "dsa",
+ options: DSAKeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "dsa",
+ options: DSAKeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "dsa",
+ options: DSAKeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "ec",
+ options: ECKeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "ec",
+ options: ECKeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "ec",
+ options: ECKeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "ec",
+ options: ECKeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "ec",
+ options: ECKeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "ed25519",
+ options: ED25519KeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "ed25519",
+ options?: ED25519KeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "ed448",
+ options: ED448KeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "ed448",
+ options: ED448KeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "ed448",
+ options: ED448KeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "ed448",
+ options: ED448KeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "ed448",
+ options?: ED448KeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "x25519",
+ options: X25519KeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "x25519",
+ options: X25519KeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "x25519",
+ options: X25519KeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "x25519",
+ options: X25519KeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "x25519",
+ options?: X25519KeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ type: "x448",
+ options: X448KeyPairOptions<"pem", "pem">,
+): KeyPairSyncResult<string, string>;
+export function generateKeyPairSync(
+ type: "x448",
+ options: X448KeyPairOptions<"pem", "der">,
+): KeyPairSyncResult<string, Buffer>;
+export function generateKeyPairSync(
+ type: "x448",
+ options: X448KeyPairOptions<"der", "pem">,
+): KeyPairSyncResult<Buffer, string>;
+export function generateKeyPairSync(
+ type: "x448",
+ options: X448KeyPairOptions<"der", "der">,
+): KeyPairSyncResult<Buffer, Buffer>;
+export function generateKeyPairSync(
+ type: "x448",
+ options?: X448KeyPairKeyObjectOptions,
+): KeyPairKeyObjectResult;
+export function generateKeyPairSync(
+ _type: KeyType,
+ _options: unknown,
+):
+ | KeyPairKeyObjectResult
+ | KeyPairSyncResult<string | Buffer, string | Buffer> {
+ notImplemented("crypto.generateKeyPairSync");
+}
+
+export function generateKeySync(
+ _type: "hmac" | "aes",
+ _options: {
+ length: number;
+ },
+): KeyObject {
+ notImplemented("crypto.generateKeySync");
+}
+
+export default {
+ generateKey,
+ generateKeySync,
+ generateKeyPair,
+ generateKeyPairSync,
+};
diff --git a/ext/node/polyfills/internal/crypto/keys.ts b/ext/node/polyfills/internal/crypto/keys.ts
new file mode 100644
index 000000000..7c9e7bad9
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/keys.ts
@@ -0,0 +1,294 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import {
+ kHandle,
+ kKeyObject,
+} from "internal:deno_node/polyfills/internal/crypto/constants.ts";
+import {
+ ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE,
+ ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_ARG_VALUE,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import type {
+ KeyFormat,
+ KeyType,
+ PrivateKeyInput,
+ PublicKeyInput,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ isAnyArrayBuffer,
+ isArrayBufferView,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+import { hideStackFrames } from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ isCryptoKey as isCryptoKey_,
+ isKeyObject as isKeyObject_,
+ kKeyType,
+} from "internal:deno_node/polyfills/internal/crypto/_keys.ts";
+
+const getArrayBufferOrView = hideStackFrames(
+ (
+ buffer,
+ name,
+ encoding,
+ ):
+ | ArrayBuffer
+ | SharedArrayBuffer
+ | Buffer
+ | DataView
+ | BigInt64Array
+ | BigUint64Array
+ | Float32Array
+ | Float64Array
+ | Int8Array
+ | Int16Array
+ | Int32Array
+ | Uint8Array
+ | Uint8ClampedArray
+ | Uint16Array
+ | Uint32Array => {
+ if (isAnyArrayBuffer(buffer)) {
+ return buffer;
+ }
+ if (typeof buffer === "string") {
+ if (encoding === "buffer") {
+ encoding = "utf8";
+ }
+ return Buffer.from(buffer, encoding);
+ }
+ if (!isArrayBufferView(buffer)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ name,
+ [
+ "string",
+ "ArrayBuffer",
+ "Buffer",
+ "TypedArray",
+ "DataView",
+ ],
+ buffer,
+ );
+ }
+ return buffer;
+ },
+);
+
+export interface AsymmetricKeyDetails {
+ /**
+ * Key size in bits (RSA, DSA).
+ */
+ modulusLength?: number | undefined;
+ /**
+ * Public exponent (RSA).
+ */
+ publicExponent?: bigint | undefined;
+ /**
+ * Name of the message digest (RSA-PSS).
+ */
+ hashAlgorithm?: string | undefined;
+ /**
+ * Name of the message digest used by MGF1 (RSA-PSS).
+ */
+ mgf1HashAlgorithm?: string | undefined;
+ /**
+ * Minimal salt length in bytes (RSA-PSS).
+ */
+ saltLength?: number | undefined;
+ /**
+ * Size of q in bits (DSA).
+ */
+ divisorLength?: number | undefined;
+ /**
+ * Name of the curve (EC).
+ */
+ namedCurve?: string | undefined;
+}
+
+export type KeyObjectType = "secret" | "public" | "private";
+
+export interface KeyExportOptions<T extends KeyFormat> {
+ type: "pkcs1" | "spki" | "pkcs8" | "sec1";
+ format: T;
+ cipher?: string | undefined;
+ passphrase?: string | Buffer | undefined;
+}
+
+export interface JwkKeyExportOptions {
+ format: "jwk";
+}
+
+export function isKeyObject(obj: unknown): obj is KeyObject {
+ return isKeyObject_(obj);
+}
+
+export function isCryptoKey(
+ obj: unknown,
+): obj is { type: string; [kKeyObject]: KeyObject } {
+ return isCryptoKey_(obj);
+}
+
+export class KeyObject {
+ [kKeyType]: KeyObjectType;
+ [kHandle]: unknown;
+
+ constructor(type: KeyObjectType, handle: unknown) {
+ if (type !== "secret" && type !== "public" && type !== "private") {
+ throw new ERR_INVALID_ARG_VALUE("type", type);
+ }
+
+ if (typeof handle !== "object") {
+ throw new ERR_INVALID_ARG_TYPE("handle", "object", handle);
+ }
+
+ this[kKeyType] = type;
+
+ Object.defineProperty(this, kHandle, {
+ value: handle,
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ });
+ }
+
+ get type(): KeyObjectType {
+ return this[kKeyType];
+ }
+
+ get asymmetricKeyDetails(): AsymmetricKeyDetails | undefined {
+ notImplemented("crypto.KeyObject.prototype.asymmetricKeyDetails");
+
+ return undefined;
+ }
+
+ get asymmetricKeyType(): KeyType | undefined {
+ notImplemented("crypto.KeyObject.prototype.asymmetricKeyType");
+
+ return undefined;
+ }
+
+ get symmetricKeySize(): number | undefined {
+ notImplemented("crypto.KeyObject.prototype.symmetricKeySize");
+
+ return undefined;
+ }
+
+ static from(key: CryptoKey): KeyObject {
+ if (!isCryptoKey(key)) {
+ throw new ERR_INVALID_ARG_TYPE("key", "CryptoKey", key);
+ }
+
+ notImplemented("crypto.KeyObject.prototype.from");
+ }
+
+ equals(otherKeyObject: KeyObject): boolean {
+ if (!isKeyObject(otherKeyObject)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "otherKeyObject",
+ "KeyObject",
+ otherKeyObject,
+ );
+ }
+
+ notImplemented("crypto.KeyObject.prototype.equals");
+ }
+
+ export(options: KeyExportOptions<"pem">): string | Buffer;
+ export(options?: KeyExportOptions<"der">): Buffer;
+ export(options?: JwkKeyExportOptions): JsonWebKey;
+ export(_options?: unknown): string | Buffer | JsonWebKey {
+ notImplemented("crypto.KeyObject.prototype.asymmetricKeyType");
+ }
+}
+
+export interface JsonWebKeyInput {
+ key: JsonWebKey;
+ format: "jwk";
+}
+
+export function createPrivateKey(
+ _key: PrivateKeyInput | string | Buffer | JsonWebKeyInput,
+): KeyObject {
+ notImplemented("crypto.createPrivateKey");
+}
+
+export function createPublicKey(
+ _key: PublicKeyInput | string | Buffer | KeyObject | JsonWebKeyInput,
+): KeyObject {
+ notImplemented("crypto.createPublicKey");
+}
+
+function getKeyTypes(allowKeyObject: boolean, bufferOnly = false) {
+ const types = [
+ "ArrayBuffer",
+ "Buffer",
+ "TypedArray",
+ "DataView",
+ "string", // Only if bufferOnly == false
+ "KeyObject", // Only if allowKeyObject == true && bufferOnly == false
+ "CryptoKey", // Only if allowKeyObject == true && bufferOnly == false
+ ];
+ if (bufferOnly) {
+ return types.slice(0, 4);
+ } else if (!allowKeyObject) {
+ return types.slice(0, 5);
+ }
+ return types;
+}
+
+export function prepareSecretKey(
+ key: string | ArrayBuffer | KeyObject,
+ encoding: string | undefined,
+ bufferOnly = false,
+) {
+ if (!bufferOnly) {
+ if (isKeyObject(key)) {
+ if (key.type !== "secret") {
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, "secret");
+ }
+ return key[kHandle];
+ } else if (isCryptoKey(key)) {
+ if (key.type !== "secret") {
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, "secret");
+ }
+ return key[kKeyObject][kHandle];
+ }
+ }
+ if (
+ typeof key !== "string" &&
+ !isArrayBufferView(key) &&
+ !isAnyArrayBuffer(key)
+ ) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "key",
+ getKeyTypes(!bufferOnly, bufferOnly),
+ key,
+ );
+ }
+
+ return getArrayBufferOrView(key, "key", encoding);
+}
+
+export function createSecretKey(key: ArrayBufferView): KeyObject;
+export function createSecretKey(
+ key: string,
+ encoding: string,
+): KeyObject;
+export function createSecretKey(
+ _key: string | ArrayBufferView,
+ _encoding?: string,
+): KeyObject {
+ notImplemented("crypto.createSecretKey");
+}
+
+export default {
+ createPrivateKey,
+ createPublicKey,
+ createSecretKey,
+ isKeyObject,
+ isCryptoKey,
+ KeyObject,
+ prepareSecretKey,
+};
diff --git a/ext/node/polyfills/internal/crypto/pbkdf2.ts b/ext/node/polyfills/internal/crypto/pbkdf2.ts
new file mode 100644
index 000000000..a3d821ae7
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/pbkdf2.ts
@@ -0,0 +1,183 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { createHash } from "internal:deno_node/polyfills/internal/crypto/hash.ts";
+import { HASH_DATA } from "internal:deno_node/polyfills/internal/crypto/types.ts";
+
+export const MAX_ALLOC = Math.pow(2, 30) - 1;
+
+export type NormalizedAlgorithms =
+ | "md5"
+ | "ripemd160"
+ | "sha1"
+ | "sha224"
+ | "sha256"
+ | "sha384"
+ | "sha512";
+
+export type Algorithms =
+ | "md5"
+ | "ripemd160"
+ | "rmd160"
+ | "sha1"
+ | "sha224"
+ | "sha256"
+ | "sha384"
+ | "sha512";
+
+const createHasher = (algorithm: string) => (value: Uint8Array) =>
+ Buffer.from(createHash(algorithm).update(value).digest() as Buffer);
+
+function getZeroes(zeros: number) {
+ return Buffer.alloc(zeros);
+}
+
+const sizes = {
+ md5: 16,
+ sha1: 20,
+ sha224: 28,
+ sha256: 32,
+ sha384: 48,
+ sha512: 64,
+ rmd160: 20,
+ ripemd160: 20,
+};
+
+function toBuffer(bufferable: HASH_DATA) {
+ if (bufferable instanceof Uint8Array || typeof bufferable === "string") {
+ return Buffer.from(bufferable as Uint8Array);
+ } else {
+ return Buffer.from(bufferable.buffer);
+ }
+}
+
+export class Hmac {
+ hash: (value: Uint8Array) => Buffer;
+ ipad1: Buffer;
+ opad: Buffer;
+ alg: string;
+ blocksize: number;
+ size: number;
+ ipad2: Buffer;
+
+ constructor(alg: Algorithms, key: Buffer, saltLen: number) {
+ this.hash = createHasher(alg);
+
+ const blocksize = alg === "sha512" || alg === "sha384" ? 128 : 64;
+
+ if (key.length > blocksize) {
+ key = this.hash(key);
+ } else if (key.length < blocksize) {
+ key = Buffer.concat([key, getZeroes(blocksize - key.length)], blocksize);
+ }
+
+ const ipad = Buffer.allocUnsafe(blocksize + sizes[alg]);
+ const opad = Buffer.allocUnsafe(blocksize + sizes[alg]);
+ for (let i = 0; i < blocksize; i++) {
+ ipad[i] = key[i] ^ 0x36;
+ opad[i] = key[i] ^ 0x5c;
+ }
+
+ const ipad1 = Buffer.allocUnsafe(blocksize + saltLen + 4);
+ ipad.copy(ipad1, 0, 0, blocksize);
+
+ this.ipad1 = ipad1;
+ this.ipad2 = ipad;
+ this.opad = opad;
+ this.alg = alg;
+ this.blocksize = blocksize;
+ this.size = sizes[alg];
+ }
+
+ run(data: Buffer, ipad: Buffer) {
+ data.copy(ipad, this.blocksize);
+ const h = this.hash(ipad);
+ h.copy(this.opad, this.blocksize);
+ return this.hash(this.opad);
+ }
+}
+
+/**
+ * @param iterations Needs to be higher or equal than zero
+ * @param keylen Needs to be higher or equal than zero but less than max allocation size (2^30)
+ * @param digest Algorithm to be used for encryption
+ */
+export function pbkdf2Sync(
+ password: HASH_DATA,
+ salt: HASH_DATA,
+ iterations: number,
+ keylen: number,
+ digest: Algorithms = "sha1",
+): Buffer {
+ if (typeof iterations !== "number" || iterations < 0) {
+ throw new TypeError("Bad iterations");
+ }
+ if (typeof keylen !== "number" || keylen < 0 || keylen > MAX_ALLOC) {
+ throw new TypeError("Bad key length");
+ }
+
+ const bufferedPassword = toBuffer(password);
+ const bufferedSalt = toBuffer(salt);
+
+ const hmac = new Hmac(digest, bufferedPassword, bufferedSalt.length);
+
+ const DK = Buffer.allocUnsafe(keylen);
+ const block1 = Buffer.allocUnsafe(bufferedSalt.length + 4);
+ bufferedSalt.copy(block1, 0, 0, bufferedSalt.length);
+
+ let destPos = 0;
+ const hLen = sizes[digest];
+ const l = Math.ceil(keylen / hLen);
+
+ for (let i = 1; i <= l; i++) {
+ block1.writeUInt32BE(i, bufferedSalt.length);
+
+ const T = hmac.run(block1, hmac.ipad1);
+ let U = T;
+
+ for (let j = 1; j < iterations; j++) {
+ U = hmac.run(U, hmac.ipad2);
+ for (let k = 0; k < hLen; k++) T[k] ^= U[k];
+ }
+
+ T.copy(DK, destPos);
+ destPos += hLen;
+ }
+
+ return DK;
+}
+
+/**
+ * @param iterations Needs to be higher or equal than zero
+ * @param keylen Needs to be higher or equal than zero but less than max allocation size (2^30)
+ * @param digest Algorithm to be used for encryption
+ */
+export function pbkdf2(
+ password: HASH_DATA,
+ salt: HASH_DATA,
+ iterations: number,
+ keylen: number,
+ digest: Algorithms = "sha1",
+ callback: (err: Error | null, derivedKey?: Buffer) => void,
+) {
+ setTimeout(() => {
+ let err = null,
+ res;
+ try {
+ res = pbkdf2Sync(password, salt, iterations, keylen, digest);
+ } catch (e) {
+ err = e;
+ }
+ if (err) {
+ callback(err instanceof Error ? err : new Error("[non-error thrown]"));
+ } else {
+ callback(null, res);
+ }
+ }, 0);
+}
+
+export default {
+ Hmac,
+ MAX_ALLOC,
+ pbkdf2,
+ pbkdf2Sync,
+};
diff --git a/ext/node/polyfills/internal/crypto/random.ts b/ext/node/polyfills/internal/crypto/random.ts
new file mode 100644
index 000000000..158ea40da
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/random.ts
@@ -0,0 +1,140 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import randomBytes from "internal:deno_node/polyfills/internal/crypto/_randomBytes.ts";
+import randomFill, {
+ randomFillSync,
+} from "internal:deno_node/polyfills/internal/crypto/_randomFill.ts";
+import randomInt from "internal:deno_node/polyfills/internal/crypto/_randomInt.ts";
+
+export { default as randomBytes } from "internal:deno_node/polyfills/internal/crypto/_randomBytes.ts";
+export {
+ default as randomFill,
+ randomFillSync,
+} from "internal:deno_node/polyfills/internal/crypto/_randomFill.ts";
+export { default as randomInt } from "internal:deno_node/polyfills/internal/crypto/_randomInt.ts";
+
+export type LargeNumberLike =
+ | ArrayBufferView
+ | SharedArrayBuffer
+ | ArrayBuffer
+ | bigint;
+
+export interface CheckPrimeOptions {
+ /**
+ * The number of Miller-Rabin probabilistic primality iterations to perform.
+ * When the value is 0 (zero), a number of checks is used that yields a false positive rate of at most 2-64 for random input.
+ * Care must be used when selecting a number of checks.
+ * Refer to the OpenSSL documentation for the BN_is_prime_ex function nchecks options for more details.
+ *
+ * @default 0
+ */
+ checks?: number | undefined;
+}
+
+export function checkPrime(
+ candidate: LargeNumberLike,
+ callback: (err: Error | null, result: boolean) => void,
+): void;
+export function checkPrime(
+ candidate: LargeNumberLike,
+ options: CheckPrimeOptions,
+ callback: (err: Error | null, result: boolean) => void,
+): void;
+export function checkPrime(
+ _candidate: LargeNumberLike,
+ _options?: CheckPrimeOptions | ((err: Error | null, result: boolean) => void),
+ _callback?: (err: Error | null, result: boolean) => void,
+) {
+ notImplemented("crypto.checkPrime");
+}
+
+export function checkPrimeSync(
+ _candidate: LargeNumberLike,
+ _options?: CheckPrimeOptions,
+): boolean {
+ notImplemented("crypto.checkPrimeSync");
+}
+
+export interface GeneratePrimeOptions {
+ add?: LargeNumberLike | undefined;
+ rem?: LargeNumberLike | undefined;
+ /**
+ * @default false
+ */
+ safe?: boolean | undefined;
+ bigint?: boolean | undefined;
+}
+
+export interface GeneratePrimeOptionsBigInt extends GeneratePrimeOptions {
+ bigint: true;
+}
+
+export interface GeneratePrimeOptionsArrayBuffer extends GeneratePrimeOptions {
+ bigint?: false | undefined;
+}
+
+export function generatePrime(
+ size: number,
+ callback: (err: Error | null, prime: ArrayBuffer) => void,
+): void;
+export function generatePrime(
+ size: number,
+ options: GeneratePrimeOptionsBigInt,
+ callback: (err: Error | null, prime: bigint) => void,
+): void;
+export function generatePrime(
+ size: number,
+ options: GeneratePrimeOptionsArrayBuffer,
+ callback: (err: Error | null, prime: ArrayBuffer) => void,
+): void;
+export function generatePrime(
+ size: number,
+ options: GeneratePrimeOptions,
+ callback: (err: Error | null, prime: ArrayBuffer | bigint) => void,
+): void;
+export function generatePrime(
+ _size: number,
+ _options?: unknown,
+ _callback?: unknown,
+) {
+ notImplemented("crypto.generatePrime");
+}
+
+export function generatePrimeSync(size: number): ArrayBuffer;
+export function generatePrimeSync(
+ size: number,
+ options: GeneratePrimeOptionsBigInt,
+): bigint;
+export function generatePrimeSync(
+ size: number,
+ options: GeneratePrimeOptionsArrayBuffer,
+): ArrayBuffer;
+export function generatePrimeSync(
+ size: number,
+ options: GeneratePrimeOptions,
+): ArrayBuffer | bigint;
+export function generatePrimeSync(
+ _size: number,
+ _options?:
+ | GeneratePrimeOptionsBigInt
+ | GeneratePrimeOptionsArrayBuffer
+ | GeneratePrimeOptions,
+): ArrayBuffer | bigint {
+ notImplemented("crypto.generatePrimeSync");
+}
+
+export const randomUUID = () => globalThis.crypto.randomUUID();
+
+export default {
+ checkPrime,
+ checkPrimeSync,
+ generatePrime,
+ generatePrimeSync,
+ randomUUID,
+ randomInt,
+ randomBytes,
+ randomFill,
+ randomFillSync,
+};
diff --git a/ext/node/polyfills/internal/crypto/scrypt.ts b/ext/node/polyfills/internal/crypto/scrypt.ts
new file mode 100644
index 000000000..1bdafb63d
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/scrypt.ts
@@ -0,0 +1,278 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+/*
+MIT License
+
+Copyright (c) 2018 cryptocoinjs
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { pbkdf2Sync as pbkdf2 } from "internal:deno_node/polyfills/internal/crypto/pbkdf2.ts";
+import { HASH_DATA } from "internal:deno_node/polyfills/internal/crypto/types.ts";
+
+type Opts = Partial<{
+ N: number;
+ cost: number;
+ p: number;
+ parallelization: number;
+ r: number;
+ blockSize: number;
+ maxmem: number;
+}>;
+
+const fixOpts = (opts?: Opts) => {
+ const out = { N: 16384, p: 1, r: 8, maxmem: 32 << 20 };
+ if (!opts) return out;
+
+ if (opts.N) out.N = opts.N;
+ else if (opts.cost) out.N = opts.cost;
+
+ if (opts.p) out.p = opts.p;
+ else if (opts.parallelization) out.p = opts.parallelization;
+
+ if (opts.r) out.r = opts.r;
+ else if (opts.blockSize) out.r = opts.blockSize;
+
+ if (opts.maxmem) out.maxmem = opts.maxmem;
+
+ return out;
+};
+
+function blockxor(S: Buffer, Si: number, D: Buffer, Di: number, len: number) {
+ let i = -1;
+ while (++i < len) D[Di + i] ^= S[Si + i];
+}
+function arraycopy(
+ src: Buffer,
+ srcPos: number,
+ dest: Buffer,
+ destPos: number,
+ length: number,
+) {
+ src.copy(dest, destPos, srcPos, srcPos + length);
+}
+
+const R = (a: number, b: number) => (a << b) | (a >>> (32 - b));
+
+class ScryptRom {
+ B: Buffer;
+ r: number;
+ N: number;
+ p: number;
+ XY: Buffer;
+ V: Buffer;
+ B32: Int32Array;
+ x: Int32Array;
+ _X: Buffer;
+ constructor(b: Buffer, r: number, N: number, p: number) {
+ this.B = b;
+ this.r = r;
+ this.N = N;
+ this.p = p;
+ this.XY = Buffer.allocUnsafe(256 * r);
+ this.V = Buffer.allocUnsafe(128 * r * N);
+ this.B32 = new Int32Array(16); // salsa20_8
+ this.x = new Int32Array(16); // salsa20_8
+ this._X = Buffer.allocUnsafe(64); // blockmix_salsa8
+ }
+
+ run() {
+ const p = this.p | 0;
+ const r = this.r | 0;
+ for (let i = 0; i < p; i++) this.scryptROMix(i, r);
+
+ return this.B;
+ }
+
+ scryptROMix(i: number, r: number) {
+ const blockStart = i * 128 * r;
+ const offset = (2 * r - 1) * 64;
+ const blockLen = 128 * r;
+ const B = this.B;
+ const N = this.N | 0;
+ const V = this.V;
+ const XY = this.XY;
+ B.copy(XY, 0, blockStart, blockStart + blockLen);
+ for (let i1 = 0; i1 < N; i1++) {
+ XY.copy(V, i1 * blockLen, 0, blockLen);
+ this.blockmix_salsa8(blockLen);
+ }
+
+ let j: number;
+ for (let i2 = 0; i2 < N; i2++) {
+ j = XY.readUInt32LE(offset) & (N - 1);
+ blockxor(V, j * blockLen, XY, 0, blockLen);
+ this.blockmix_salsa8(blockLen);
+ }
+ XY.copy(B, blockStart, 0, blockLen);
+ }
+
+ blockmix_salsa8(blockLen: number) {
+ const BY = this.XY;
+ const r = this.r;
+ const _X = this._X;
+ arraycopy(BY, (2 * r - 1) * 64, _X, 0, 64);
+ let i;
+ for (i = 0; i < 2 * r; i++) {
+ blockxor(BY, i * 64, _X, 0, 64);
+ this.salsa20_8();
+ arraycopy(_X, 0, BY, blockLen + i * 64, 64);
+ }
+ for (i = 0; i < r; i++) {
+ arraycopy(BY, blockLen + i * 2 * 64, BY, i * 64, 64);
+ arraycopy(BY, blockLen + (i * 2 + 1) * 64, BY, (i + r) * 64, 64);
+ }
+ }
+
+ salsa20_8() {
+ const B32 = this.B32;
+ const B = this._X;
+ const x = this.x;
+
+ let i;
+ for (i = 0; i < 16; i++) {
+ B32[i] = (B[i * 4 + 0] & 0xff) << 0;
+ B32[i] |= (B[i * 4 + 1] & 0xff) << 8;
+ B32[i] |= (B[i * 4 + 2] & 0xff) << 16;
+ B32[i] |= (B[i * 4 + 3] & 0xff) << 24;
+ }
+
+ for (i = 0; i < 16; i++) x[i] = B32[i];
+
+ for (i = 0; i < 4; i++) {
+ x[4] ^= R(x[0] + x[12], 7);
+ x[8] ^= R(x[4] + x[0], 9);
+ x[12] ^= R(x[8] + x[4], 13);
+ x[0] ^= R(x[12] + x[8], 18);
+ x[9] ^= R(x[5] + x[1], 7);
+ x[13] ^= R(x[9] + x[5], 9);
+ x[1] ^= R(x[13] + x[9], 13);
+ x[5] ^= R(x[1] + x[13], 18);
+ x[14] ^= R(x[10] + x[6], 7);
+ x[2] ^= R(x[14] + x[10], 9);
+ x[6] ^= R(x[2] + x[14], 13);
+ x[10] ^= R(x[6] + x[2], 18);
+ x[3] ^= R(x[15] + x[11], 7);
+ x[7] ^= R(x[3] + x[15], 9);
+ x[11] ^= R(x[7] + x[3], 13);
+ x[15] ^= R(x[11] + x[7], 18);
+ x[1] ^= R(x[0] + x[3], 7);
+ x[2] ^= R(x[1] + x[0], 9);
+ x[3] ^= R(x[2] + x[1], 13);
+ x[0] ^= R(x[3] + x[2], 18);
+ x[6] ^= R(x[5] + x[4], 7);
+ x[7] ^= R(x[6] + x[5], 9);
+ x[4] ^= R(x[7] + x[6], 13);
+ x[5] ^= R(x[4] + x[7], 18);
+ x[11] ^= R(x[10] + x[9], 7);
+ x[8] ^= R(x[11] + x[10], 9);
+ x[9] ^= R(x[8] + x[11], 13);
+ x[10] ^= R(x[9] + x[8], 18);
+ x[12] ^= R(x[15] + x[14], 7);
+ x[13] ^= R(x[12] + x[15], 9);
+ x[14] ^= R(x[13] + x[12], 13);
+ x[15] ^= R(x[14] + x[13], 18);
+ }
+ for (i = 0; i < 16; i++) B32[i] += x[i];
+
+ let bi;
+
+ for (i = 0; i < 16; i++) {
+ bi = i * 4;
+ B[bi + 0] = (B32[i] >> 0) & 0xff;
+ B[bi + 1] = (B32[i] >> 8) & 0xff;
+ B[bi + 2] = (B32[i] >> 16) & 0xff;
+ B[bi + 3] = (B32[i] >> 24) & 0xff;
+ }
+ }
+
+ clean() {
+ this.XY.fill(0);
+ this.V.fill(0);
+ this._X.fill(0);
+ this.B.fill(0);
+ for (let i = 0; i < 16; i++) {
+ this.B32[i] = 0;
+ this.x[i] = 0;
+ }
+ }
+}
+
+export function scryptSync(
+ password: HASH_DATA,
+ salt: HASH_DATA,
+ keylen: number,
+ _opts?: Opts,
+): Buffer {
+ const { N, r, p, maxmem } = fixOpts(_opts);
+
+ const blen = p * 128 * r;
+
+ if (32 * r * (N + 2) * 4 + blen > maxmem) {
+ throw new Error("excedes max memory");
+ }
+
+ const b = pbkdf2(password, salt, 1, blen, "sha256");
+
+ const scryptRom = new ScryptRom(b, r, N, p);
+ const out = scryptRom.run();
+
+ const fin = pbkdf2(password, out, 1, keylen, "sha256");
+ scryptRom.clean();
+ return fin;
+}
+
+type Callback = (err: unknown, result?: Buffer) => void;
+
+export function scrypt(
+ password: HASH_DATA,
+ salt: HASH_DATA,
+ keylen: number,
+ _opts: Opts | null | Callback,
+ cb?: Callback,
+) {
+ if (!cb) {
+ cb = _opts as Callback;
+ _opts = null;
+ }
+ const { N, r, p, maxmem } = fixOpts(_opts as Opts);
+
+ const blen = p * 128 * r;
+ if (32 * r * (N + 2) * 4 + blen > maxmem) {
+ throw new Error("excedes max memory");
+ }
+
+ try {
+ const b = pbkdf2(password, salt, 1, blen, "sha256");
+
+ const scryptRom = new ScryptRom(b, r, N, p);
+ const out = scryptRom.run();
+ const result = pbkdf2(password, out, 1, keylen, "sha256");
+ scryptRom.clean();
+ cb(null, result);
+ } catch (err: unknown) {
+ return cb(err);
+ }
+}
+
+export default {
+ scrypt,
+ scryptSync,
+};
diff --git a/ext/node/polyfills/internal/crypto/sig.ts b/ext/node/polyfills/internal/crypto/sig.ts
new file mode 100644
index 000000000..6c163c8e5
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/sig.ts
@@ -0,0 +1,148 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import { validateString } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import type { WritableOptions } from "internal:deno_node/polyfills/_stream.d.ts";
+import Writable from "internal:deno_node/polyfills/internal/streams/writable.mjs";
+import type {
+ BinaryLike,
+ BinaryToTextEncoding,
+ Encoding,
+ PrivateKeyInput,
+ PublicKeyInput,
+} from "internal:deno_node/polyfills/internal/crypto/types.ts";
+import { KeyObject } from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+
+export type DSAEncoding = "der" | "ieee-p1363";
+
+export interface SigningOptions {
+ padding?: number | undefined;
+ saltLength?: number | undefined;
+ dsaEncoding?: DSAEncoding | undefined;
+}
+
+export interface SignPrivateKeyInput extends PrivateKeyInput, SigningOptions {}
+
+export interface SignKeyObjectInput extends SigningOptions {
+ key: KeyObject;
+}
+export interface VerifyPublicKeyInput extends PublicKeyInput, SigningOptions {}
+
+export interface VerifyKeyObjectInput extends SigningOptions {
+ key: KeyObject;
+}
+
+export type KeyLike = string | Buffer | KeyObject;
+
+export class Sign extends Writable {
+ constructor(algorithm: string, _options?: WritableOptions) {
+ validateString(algorithm, "algorithm");
+
+ super();
+
+ notImplemented("crypto.Sign");
+ }
+
+ sign(privateKey: KeyLike | SignKeyObjectInput | SignPrivateKeyInput): Buffer;
+ sign(
+ privateKey: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
+ outputFormat: BinaryToTextEncoding,
+ ): string;
+ sign(
+ _privateKey: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
+ _outputEncoding?: BinaryToTextEncoding,
+ ): Buffer | string {
+ notImplemented("crypto.Sign.prototype.sign");
+ }
+
+ update(data: BinaryLike): this;
+ update(data: string, inputEncoding: Encoding): this;
+ update(_data: BinaryLike | string, _inputEncoding?: Encoding): this {
+ notImplemented("crypto.Sign.prototype.update");
+ }
+}
+
+export class Verify extends Writable {
+ constructor(algorithm: string, _options?: WritableOptions) {
+ validateString(algorithm, "algorithm");
+
+ super();
+
+ notImplemented("crypto.Verify");
+ }
+
+ update(data: BinaryLike): this;
+ update(data: string, inputEncoding: Encoding): this;
+ update(_data: BinaryLike, _inputEncoding?: string): this {
+ notImplemented("crypto.Sign.prototype.update");
+ }
+
+ verify(
+ object: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ signature: ArrayBufferView,
+ ): boolean;
+ verify(
+ object: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ signature: string,
+ signatureEncoding?: BinaryToTextEncoding,
+ ): boolean;
+ verify(
+ _object: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ _signature: ArrayBufferView | string,
+ _signatureEncoding?: BinaryToTextEncoding,
+ ): boolean {
+ notImplemented("crypto.Sign.prototype.sign");
+ }
+}
+
+export function signOneShot(
+ algorithm: string | null | undefined,
+ data: ArrayBufferView,
+ key: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
+): Buffer;
+export function signOneShot(
+ algorithm: string | null | undefined,
+ data: ArrayBufferView,
+ key: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
+ callback: (error: Error | null, data: Buffer) => void,
+): void;
+export function signOneShot(
+ _algorithm: string | null | undefined,
+ _data: ArrayBufferView,
+ _key: KeyLike | SignKeyObjectInput | SignPrivateKeyInput,
+ _callback?: (error: Error | null, data: Buffer) => void,
+): Buffer | void {
+ notImplemented("crypto.sign");
+}
+
+export function verifyOneShot(
+ algorithm: string | null | undefined,
+ data: ArrayBufferView,
+ key: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ signature: ArrayBufferView,
+): boolean;
+export function verifyOneShot(
+ algorithm: string | null | undefined,
+ data: ArrayBufferView,
+ key: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ signature: ArrayBufferView,
+ callback: (error: Error | null, result: boolean) => void,
+): void;
+export function verifyOneShot(
+ _algorithm: string | null | undefined,
+ _data: ArrayBufferView,
+ _key: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput,
+ _signature: ArrayBufferView,
+ _callback?: (error: Error | null, result: boolean) => void,
+): boolean | void {
+ notImplemented("crypto.verify");
+}
+
+export default {
+ signOneShot,
+ verifyOneShot,
+ Sign,
+ Verify,
+};
diff --git a/ext/node/polyfills/internal/crypto/types.ts b/ext/node/polyfills/internal/crypto/types.ts
new file mode 100644
index 000000000..3bb9ec160
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/types.ts
@@ -0,0 +1,46 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+
+export type HASH_DATA = string | ArrayBufferView | Buffer;
+
+export type BinaryToTextEncoding = "base64" | "base64url" | "hex" | "binary";
+
+export type CharacterEncoding = "utf8" | "utf-8" | "utf16le" | "latin1";
+
+export type LegacyCharacterEncoding = "ascii" | "binary" | "ucs2" | "ucs-2";
+
+export type Encoding =
+ | BinaryToTextEncoding
+ | CharacterEncoding
+ | LegacyCharacterEncoding;
+
+export type ECDHKeyFormat = "compressed" | "uncompressed" | "hybrid";
+
+export type BinaryLike = string | ArrayBufferView;
+
+export type KeyFormat = "pem" | "der";
+
+export type KeyType =
+ | "rsa"
+ | "rsa-pss"
+ | "dsa"
+ | "ec"
+ | "ed25519"
+ | "ed448"
+ | "x25519"
+ | "x448";
+
+export interface PrivateKeyInput {
+ key: string | Buffer;
+ format?: KeyFormat | undefined;
+ type?: "pkcs1" | "pkcs8" | "sec1" | undefined;
+ passphrase?: string | Buffer | undefined;
+}
+
+export interface PublicKeyInput {
+ key: string | Buffer;
+ format?: KeyFormat | undefined;
+ type?: "pkcs1" | "spki" | undefined;
+}
diff --git a/ext/node/polyfills/internal/crypto/util.ts b/ext/node/polyfills/internal/crypto/util.ts
new file mode 100644
index 000000000..f9fce8b2d
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/util.ts
@@ -0,0 +1,129 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { getCiphers } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/mod.js";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ ERR_INVALID_ARG_TYPE,
+ hideStackFrames,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ isAnyArrayBuffer,
+ isArrayBufferView,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+import { crypto as constants } from "internal:deno_node/polyfills/internal_binding/constants.ts";
+import {
+ kHandle,
+ kKeyObject,
+} from "internal:deno_node/polyfills/internal/crypto/constants.ts";
+
+// TODO(kt3k): Generate this list from `digestAlgorithms`
+// of std/crypto/_wasm/mod.ts
+const digestAlgorithms = [
+ "blake2b256",
+ "blake2b384",
+ "blake2b",
+ "blake2s",
+ "blake3",
+ "keccak-224",
+ "keccak-256",
+ "keccak-384",
+ "keccak-512",
+ "sha384",
+ "sha3-224",
+ "sha3-256",
+ "sha3-384",
+ "sha3-512",
+ "shake128",
+ "shake256",
+ "tiger",
+ "rmd160",
+ "sha224",
+ "sha256",
+ "sha512",
+ "md4",
+ "md5",
+ "sha1",
+];
+
+let defaultEncoding = "buffer";
+
+export function setDefaultEncoding(val: string) {
+ defaultEncoding = val;
+}
+
+export function getDefaultEncoding(): string {
+ return defaultEncoding;
+}
+
+// This is here because many functions accepted binary strings without
+// any explicit encoding in older versions of node, and we don't want
+// to break them unnecessarily.
+export function toBuf(val: string | Buffer, encoding?: string): Buffer {
+ if (typeof val === "string") {
+ if (encoding === "buffer") {
+ encoding = "utf8";
+ }
+
+ return Buffer.from(val, encoding);
+ }
+
+ return val;
+}
+
+export const validateByteSource = hideStackFrames((val, name) => {
+ val = toBuf(val);
+
+ if (isAnyArrayBuffer(val) || isArrayBufferView(val)) {
+ return;
+ }
+
+ throw new ERR_INVALID_ARG_TYPE(
+ name,
+ ["string", "ArrayBuffer", "TypedArray", "DataView", "Buffer"],
+ val,
+ );
+});
+
+/**
+ * Returns an array of the names of the supported hash algorithms, such as 'sha1'.
+ */
+export function getHashes(): readonly string[] {
+ return digestAlgorithms;
+}
+
+export function getCurves(): readonly string[] {
+ notImplemented("crypto.getCurves");
+}
+
+export interface SecureHeapUsage {
+ total: number;
+ min: number;
+ used: number;
+ utilization: number;
+}
+
+export function secureHeapUsed(): SecureHeapUsage {
+ notImplemented("crypto.secureHeapUsed");
+}
+
+export function setEngine(_engine: string, _flags: typeof constants) {
+ notImplemented("crypto.setEngine");
+}
+
+export { getCiphers, kHandle, kKeyObject };
+
+export default {
+ getDefaultEncoding,
+ getHashes,
+ setDefaultEncoding,
+ getCiphers,
+ getCurves,
+ secureHeapUsed,
+ setEngine,
+ validateByteSource,
+ toBuf,
+ kHandle,
+ kKeyObject,
+};
diff --git a/ext/node/polyfills/internal/crypto/x509.ts b/ext/node/polyfills/internal/crypto/x509.ts
new file mode 100644
index 000000000..0722d7865
--- /dev/null
+++ b/ext/node/polyfills/internal/crypto/x509.ts
@@ -0,0 +1,186 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { KeyObject } from "internal:deno_node/polyfills/internal/crypto/keys.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { ERR_INVALID_ARG_TYPE } from "internal:deno_node/polyfills/internal/errors.ts";
+import { isArrayBufferView } from "internal:deno_node/polyfills/internal/util/types.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+import { BinaryLike } from "internal:deno_node/polyfills/internal/crypto/types.ts";
+
+// deno-lint-ignore no-explicit-any
+export type PeerCertificate = any;
+
+export interface X509CheckOptions {
+ /**
+ * @default 'always'
+ */
+ subject: "always" | "never";
+ /**
+ * @default true
+ */
+ wildcards: boolean;
+ /**
+ * @default true
+ */
+ partialWildcards: boolean;
+ /**
+ * @default false
+ */
+ multiLabelWildcards: boolean;
+ /**
+ * @default false
+ */
+ singleLabelSubdomains: boolean;
+}
+
+export class X509Certificate {
+ constructor(buffer: BinaryLike) {
+ if (typeof buffer === "string") {
+ buffer = Buffer.from(buffer);
+ }
+
+ if (!isArrayBufferView(buffer)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "buffer",
+ ["string", "Buffer", "TypedArray", "DataView"],
+ buffer,
+ );
+ }
+
+ notImplemented("crypto.X509Certificate");
+ }
+
+ get ca(): boolean {
+ notImplemented("crypto.X509Certificate.prototype.ca");
+
+ return false;
+ }
+
+ checkEmail(
+ _email: string,
+ _options?: Pick<X509CheckOptions, "subject">,
+ ): string | undefined {
+ notImplemented("crypto.X509Certificate.prototype.checkEmail");
+ }
+
+ checkHost(_name: string, _options?: X509CheckOptions): string | undefined {
+ notImplemented("crypto.X509Certificate.prototype.checkHost");
+ }
+
+ checkIP(_ip: string): string | undefined {
+ notImplemented("crypto.X509Certificate.prototype.checkIP");
+ }
+
+ checkIssued(_otherCert: X509Certificate): boolean {
+ notImplemented("crypto.X509Certificate.prototype.checkIssued");
+ }
+
+ checkPrivateKey(_privateKey: KeyObject): boolean {
+ notImplemented("crypto.X509Certificate.prototype.checkPrivateKey");
+ }
+
+ get fingerprint(): string {
+ notImplemented("crypto.X509Certificate.prototype.fingerprint");
+
+ return "";
+ }
+
+ get fingerprint256(): string {
+ notImplemented("crypto.X509Certificate.prototype.fingerprint256");
+
+ return "";
+ }
+
+ get fingerprint512(): string {
+ notImplemented("crypto.X509Certificate.prototype.fingerprint512");
+
+ return "";
+ }
+
+ get infoAccess(): string | undefined {
+ notImplemented("crypto.X509Certificate.prototype.infoAccess");
+
+ return "";
+ }
+
+ get issuer(): string {
+ notImplemented("crypto.X509Certificate.prototype.issuer");
+
+ return "";
+ }
+
+ get issuerCertificate(): X509Certificate | undefined {
+ notImplemented("crypto.X509Certificate.prototype.issuerCertificate");
+
+ return {} as X509Certificate;
+ }
+
+ get keyUsage(): string[] {
+ notImplemented("crypto.X509Certificate.prototype.keyUsage");
+
+ return [];
+ }
+
+ get publicKey(): KeyObject {
+ notImplemented("crypto.X509Certificate.prototype.publicKey");
+
+ return {} as KeyObject;
+ }
+
+ get raw(): Buffer {
+ notImplemented("crypto.X509Certificate.prototype.raw");
+
+ return {} as Buffer;
+ }
+
+ get serialNumber(): string {
+ notImplemented("crypto.X509Certificate.prototype.serialNumber");
+
+ return "";
+ }
+
+ get subject(): string {
+ notImplemented("crypto.X509Certificate.prototype.subject");
+
+ return "";
+ }
+
+ get subjectAltName(): string | undefined {
+ notImplemented("crypto.X509Certificate.prototype.subjectAltName");
+
+ return "";
+ }
+
+ toJSON(): string {
+ return this.toString();
+ }
+
+ toLegacyObject(): PeerCertificate {
+ notImplemented("crypto.X509Certificate.prototype.toLegacyObject");
+ }
+
+ toString(): string {
+ notImplemented("crypto.X509Certificate.prototype.toString");
+ }
+
+ get validFrom(): string {
+ notImplemented("crypto.X509Certificate.prototype.validFrom");
+
+ return "";
+ }
+
+ get validTo(): string {
+ notImplemented("crypto.X509Certificate.prototype.validTo");
+
+ return "";
+ }
+
+ verify(_publicKey: KeyObject): boolean {
+ notImplemented("crypto.X509Certificate.prototype.verify");
+ }
+}
+
+export default {
+ X509Certificate,
+};
diff --git a/ext/node/polyfills/internal/dgram.ts b/ext/node/polyfills/internal/dgram.ts
new file mode 100644
index 000000000..8e8e50fab
--- /dev/null
+++ b/ext/node/polyfills/internal/dgram.ts
@@ -0,0 +1,129 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import { lookup as defaultLookup } from "internal:deno_node/polyfills/dns.ts";
+import {
+ isInt32,
+ validateFunction,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import type { ErrnoException } from "internal:deno_node/polyfills/internal/errors.ts";
+import { ERR_SOCKET_BAD_TYPE } from "internal:deno_node/polyfills/internal/errors.ts";
+import { UDP } from "internal:deno_node/polyfills/internal_binding/udp_wrap.ts";
+import { guessHandleType } from "internal:deno_node/polyfills/internal_binding/util.ts";
+import { codeMap } from "internal:deno_node/polyfills/internal_binding/uv.ts";
+
+export type SocketType = "udp4" | "udp6";
+
+export const kStateSymbol: unique symbol = Symbol("kStateSymbol");
+
+function lookup4(
+ lookup: typeof defaultLookup,
+ address: string,
+ callback: (
+ err: ErrnoException | null,
+ address: string,
+ family: number,
+ ) => void,
+) {
+ return lookup(address || "127.0.0.1", 4, callback);
+}
+
+function lookup6(
+ lookup: typeof defaultLookup,
+ address: string,
+ callback: (
+ err: ErrnoException | null,
+ address: string,
+ family: number,
+ ) => void,
+) {
+ return lookup(address || "::1", 6, callback);
+}
+
+export function newHandle(
+ type: SocketType,
+ lookup?: typeof defaultLookup,
+): UDP {
+ if (lookup === undefined) {
+ lookup = defaultLookup;
+ } else {
+ validateFunction(lookup, "lookup");
+ }
+
+ if (type === "udp4") {
+ const handle = new UDP();
+
+ handle.lookup = lookup4.bind(handle, lookup);
+
+ return handle;
+ }
+
+ if (type === "udp6") {
+ const handle = new UDP();
+
+ handle.lookup = lookup6.bind(handle, lookup);
+ handle.bind = handle.bind6;
+ handle.connect = handle.connect6;
+ handle.send = handle.send6;
+
+ return handle;
+ }
+
+ throw new ERR_SOCKET_BAD_TYPE();
+}
+
+export function _createSocketHandle(
+ address: string,
+ port: number,
+ addressType: SocketType,
+ fd: number,
+ flags: number,
+) {
+ const handle = newHandle(addressType);
+ let err;
+
+ if (isInt32(fd) && fd > 0) {
+ const type = guessHandleType(fd);
+
+ if (type !== "UDP") {
+ err = codeMap.get("EINVAL")!;
+ } else {
+ err = handle.open(fd);
+ }
+ } else if (port || address) {
+ err = handle.bind(address, port || 0, flags);
+ }
+
+ if (err) {
+ handle.close();
+
+ return err;
+ }
+
+ return handle;
+}
+
+export default {
+ kStateSymbol,
+ newHandle,
+ _createSocketHandle,
+};
diff --git a/ext/node/polyfills/internal/dns/promises.ts b/ext/node/polyfills/internal/dns/promises.ts
new file mode 100644
index 000000000..e5e15dc87
--- /dev/null
+++ b/ext/node/polyfills/internal/dns/promises.ts
@@ -0,0 +1,511 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import {
+ validateBoolean,
+ validateNumber,
+ validateOneOf,
+ validateString,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import { isIP } from "internal:deno_node/polyfills/internal/net.ts";
+import {
+ emitInvalidHostnameWarning,
+ getDefaultResolver,
+ getDefaultVerbatim,
+ isFamily,
+ isLookupOptions,
+ Resolver as CallbackResolver,
+ validateHints,
+} from "internal:deno_node/polyfills/internal/dns/utils.ts";
+import type {
+ LookupAddress,
+ LookupAllOptions,
+ LookupOneOptions,
+ LookupOptions,
+ Records,
+ ResolveOptions,
+ ResolveWithTtlOptions,
+} from "internal:deno_node/polyfills/internal/dns/utils.ts";
+import {
+ dnsException,
+ ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_ARG_VALUE,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ ChannelWrapQuery,
+ getaddrinfo,
+ GetAddrInfoReqWrap,
+ QueryReqWrap,
+} from "internal:deno_node/polyfills/internal_binding/cares_wrap.ts";
+import { toASCII } from "internal:deno_node/polyfills/internal/idna.ts";
+
+function onlookup(
+ this: GetAddrInfoReqWrap,
+ err: number | null,
+ addresses: string[],
+) {
+ if (err) {
+ this.reject(dnsException(err, "getaddrinfo", this.hostname));
+ return;
+ }
+
+ const family = this.family || isIP(addresses[0]);
+ this.resolve({ address: addresses[0], family });
+}
+
+function onlookupall(
+ this: GetAddrInfoReqWrap,
+ err: number | null,
+ addresses: string[],
+) {
+ if (err) {
+ this.reject(dnsException(err, "getaddrinfo", this.hostname));
+
+ return;
+ }
+
+ const family = this.family;
+ const parsedAddresses = [];
+
+ for (let i = 0; i < addresses.length; i++) {
+ const address = addresses[i];
+ parsedAddresses[i] = {
+ address,
+ family: family ? family : isIP(address),
+ };
+ }
+
+ this.resolve(parsedAddresses);
+}
+
+function createLookupPromise(
+ family: number,
+ hostname: string,
+ all: boolean,
+ hints: number,
+ verbatim: boolean,
+): Promise<void | LookupAddress | LookupAddress[]> {
+ return new Promise((resolve, reject) => {
+ if (!hostname) {
+ emitInvalidHostnameWarning(hostname);
+ resolve(all ? [] : { address: null, family: family === 6 ? 6 : 4 });
+
+ return;
+ }
+
+ const matchedFamily = isIP(hostname);
+
+ if (matchedFamily !== 0) {
+ const result = { address: hostname, family: matchedFamily };
+ resolve(all ? [result] : result);
+
+ return;
+ }
+
+ const req = new GetAddrInfoReqWrap();
+
+ req.family = family;
+ req.hostname = hostname;
+ req.oncomplete = all ? onlookupall : onlookup;
+ req.resolve = resolve;
+ req.reject = reject;
+
+ const err = getaddrinfo(req, toASCII(hostname), family, hints, verbatim);
+
+ if (err) {
+ reject(dnsException(err, "getaddrinfo", hostname));
+ }
+ });
+}
+
+const validFamilies = [0, 4, 6];
+
+export function lookup(
+ hostname: string,
+ family: number,
+): Promise<void | LookupAddress | LookupAddress[]>;
+export function lookup(
+ hostname: string,
+ options: LookupOneOptions,
+): Promise<void | LookupAddress | LookupAddress[]>;
+export function lookup(
+ hostname: string,
+ options: LookupAllOptions,
+): Promise<void | LookupAddress | LookupAddress[]>;
+export function lookup(
+ hostname: string,
+ options: LookupOptions,
+): Promise<void | LookupAddress | LookupAddress[]>;
+export function lookup(
+ hostname: string,
+ options: unknown,
+): Promise<void | LookupAddress | LookupAddress[]> {
+ let hints = 0;
+ let family = 0;
+ let all = false;
+ let verbatim = getDefaultVerbatim();
+
+ // Parse arguments
+ if (hostname) {
+ validateString(hostname, "hostname");
+ }
+
+ if (isFamily(options)) {
+ validateOneOf(options, "family", validFamilies);
+ family = options;
+ } else if (!isLookupOptions(options)) {
+ throw new ERR_INVALID_ARG_TYPE("options", ["integer", "object"], options);
+ } else {
+ if (options?.hints != null) {
+ validateNumber(options.hints, "options.hints");
+ hints = options.hints >>> 0;
+ validateHints(hints);
+ }
+
+ if (options?.family != null) {
+ validateOneOf(options.family, "options.family", validFamilies);
+ family = options.family;
+ }
+
+ if (options?.all != null) {
+ validateBoolean(options.all, "options.all");
+ all = options.all;
+ }
+
+ if (options?.verbatim != null) {
+ validateBoolean(options.verbatim, "options.verbatim");
+ verbatim = options.verbatim;
+ }
+ }
+
+ return createLookupPromise(family, hostname, all, hints, verbatim);
+}
+
+function onresolve(
+ this: QueryReqWrap,
+ err: number,
+ records: Records,
+ ttls?: number[],
+) {
+ if (err) {
+ this.reject(dnsException(err, this.bindingName, this.hostname));
+
+ return;
+ }
+
+ const parsedRecords = ttls && this.ttl
+ ? (records as string[]).map((address: string, index: number) => ({
+ address,
+ ttl: ttls[index],
+ }))
+ : records;
+
+ this.resolve(parsedRecords);
+}
+
+function createResolverPromise(
+ resolver: Resolver,
+ bindingName: keyof ChannelWrapQuery,
+ hostname: string,
+ ttl: boolean,
+) {
+ return new Promise((resolve, reject) => {
+ const req = new QueryReqWrap();
+
+ req.bindingName = bindingName;
+ req.hostname = hostname;
+ req.oncomplete = onresolve;
+ req.resolve = resolve;
+ req.reject = reject;
+ req.ttl = ttl;
+
+ const err = resolver._handle[bindingName](req, toASCII(hostname));
+
+ if (err) {
+ reject(dnsException(err, bindingName, hostname));
+ }
+ });
+}
+
+function resolver(bindingName: keyof ChannelWrapQuery) {
+ function query(
+ this: Resolver,
+ name: string,
+ options?: unknown,
+ ) {
+ validateString(name, "name");
+
+ const ttl = !!(options && (options as ResolveOptions).ttl);
+
+ return createResolverPromise(this, bindingName, name, ttl);
+ }
+
+ Object.defineProperty(query, "name", { value: bindingName });
+
+ return query;
+}
+
+const resolveMap = Object.create(null);
+
+class Resolver extends CallbackResolver {
+ // deno-lint-ignore no-explicit-any
+ [resolveMethod: string]: any;
+}
+
+Resolver.prototype.resolveAny = resolveMap.ANY = resolver("queryAny");
+Resolver.prototype.resolve4 = resolveMap.A = resolver("queryA");
+Resolver.prototype.resolve6 = resolveMap.AAAA = resolver("queryAaaa");
+Resolver.prototype.resolveCaa = resolveMap.CAA = resolver("queryCaa");
+Resolver.prototype.resolveCname = resolveMap.CNAME = resolver("queryCname");
+Resolver.prototype.resolveMx = resolveMap.MX = resolver("queryMx");
+Resolver.prototype.resolveNs = resolveMap.NS = resolver("queryNs");
+Resolver.prototype.resolveTxt = resolveMap.TXT = resolver("queryTxt");
+Resolver.prototype.resolveSrv = resolveMap.SRV = resolver("querySrv");
+Resolver.prototype.resolvePtr = resolveMap.PTR = resolver("queryPtr");
+Resolver.prototype.resolveNaptr = resolveMap.NAPTR = resolver("queryNaptr");
+Resolver.prototype.resolveSoa = resolveMap.SOA = resolver("querySoa");
+Resolver.prototype.reverse = resolver("getHostByAddr");
+Resolver.prototype.resolve = _resolve;
+
+function _resolve(
+ this: Resolver,
+ hostname: string,
+ rrtype?: string,
+) {
+ let resolver;
+
+ if (typeof hostname !== "string") {
+ throw new ERR_INVALID_ARG_TYPE("name", "string", hostname);
+ }
+
+ if (rrtype !== undefined) {
+ validateString(rrtype, "rrtype");
+
+ resolver = resolveMap[rrtype];
+
+ if (typeof resolver !== "function") {
+ throw new ERR_INVALID_ARG_VALUE("rrtype", rrtype);
+ }
+ } else {
+ resolver = resolveMap.A;
+ }
+
+ return Reflect.apply(resolver, this, [hostname]);
+}
+
+// The Node implementation uses `bindDefaultResolver` to set the follow methods
+// on `module.exports` bound to the current `defaultResolver`. We don't have
+// the same ability in ESM but can simulate this (at some cost) by explicitly
+// exporting these methods which dynamically bind to the default resolver when
+// called.
+
+export function getServers(): string[] {
+ return Resolver.prototype.getServers.bind(getDefaultResolver())();
+}
+
+export function resolveAny(
+ hostname: string,
+) {
+ return Resolver.prototype.resolveAny.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ );
+}
+
+export function resolve4(
+ hostname: string,
+): Promise<void>;
+export function resolve4(
+ hostname: string,
+ options: ResolveWithTtlOptions,
+): Promise<void>;
+export function resolve4(
+ hostname: string,
+ options: ResolveOptions,
+): Promise<void>;
+export function resolve4(hostname: string, options?: unknown) {
+ return Resolver.prototype.resolve4.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ options,
+ );
+}
+
+export function resolve6(hostname: string): Promise<void>;
+export function resolve6(
+ hostname: string,
+ options: ResolveWithTtlOptions,
+): Promise<void>;
+export function resolve6(
+ hostname: string,
+ options: ResolveOptions,
+): Promise<void>;
+export function resolve6(hostname: string, options?: unknown) {
+ return Resolver.prototype.resolve6.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ options,
+ );
+}
+
+export function resolveCaa(
+ hostname: string,
+) {
+ return Resolver.prototype.resolveCaa.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ );
+}
+
+export function resolveCname(
+ hostname: string,
+) {
+ return Resolver.prototype.resolveCname.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ );
+}
+
+export function resolveMx(
+ hostname: string,
+) {
+ return Resolver.prototype.resolveMx.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ );
+}
+
+export function resolveNs(hostname: string) {
+ return Resolver.prototype.resolveNs.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ );
+}
+
+export function resolveTxt(hostname: string) {
+ return Resolver.prototype.resolveTxt.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ );
+}
+
+export function resolveSrv(hostname: string) {
+ return Resolver.prototype.resolveSrv.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ );
+}
+
+export function resolvePtr(hostname: string) {
+ return Resolver.prototype.resolvePtr.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ );
+}
+
+export function resolveNaptr(hostname: string) {
+ return Resolver.prototype.resolveNaptr.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ );
+}
+
+export function resolveSoa(hostname: string) {
+ return Resolver.prototype.resolveSoa.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ );
+}
+
+export function reverse(ip: string) {
+ return Resolver.prototype.reverse.bind(getDefaultResolver() as Resolver)(
+ ip,
+ );
+}
+
+export function resolve(
+ hostname: string,
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "A",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "AAAA",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "ANY",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "CNAME",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "MX",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "NAPTR",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "NS",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "PTR",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "SOA",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "SRV",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: "TXT",
+): Promise<void>;
+export function resolve(
+ hostname: string,
+ rrtype: string,
+): Promise<void>;
+export function resolve(hostname: string, rrtype?: string) {
+ return Resolver.prototype.resolve.bind(getDefaultResolver() as Resolver)(
+ hostname,
+ rrtype,
+ );
+}
+
+export { Resolver };
+
+export default {
+ lookup,
+ Resolver,
+ getServers,
+ resolveAny,
+ resolve4,
+ resolve6,
+ resolveCaa,
+ resolveCname,
+ resolveMx,
+ resolveNs,
+ resolveTxt,
+ resolveSrv,
+ resolvePtr,
+ resolveNaptr,
+ resolveSoa,
+ resolve,
+ reverse,
+};
diff --git a/ext/node/polyfills/internal/dns/utils.ts b/ext/node/polyfills/internal/dns/utils.ts
new file mode 100644
index 000000000..0afd10617
--- /dev/null
+++ b/ext/node/polyfills/internal/dns/utils.ts
@@ -0,0 +1,456 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import { getOptionValue } from "internal:deno_node/polyfills/internal/options.ts";
+import { emitWarning } from "internal:deno_node/polyfills/process.ts";
+import {
+ AI_ADDRCONFIG,
+ AI_ALL,
+ AI_V4MAPPED,
+} from "internal:deno_node/polyfills/internal_binding/ares.ts";
+import {
+ ChannelWrap,
+ strerror,
+} from "internal:deno_node/polyfills/internal_binding/cares_wrap.ts";
+import {
+ ERR_DNS_SET_SERVERS_FAILED,
+ ERR_INVALID_ARG_VALUE,
+ ERR_INVALID_IP_ADDRESS,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import type { ErrnoException } from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ validateArray,
+ validateInt32,
+ validateOneOf,
+ validateString,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import { isIP } from "internal:deno_node/polyfills/internal/net.ts";
+
+export interface LookupOptions {
+ family?: number | undefined;
+ hints?: number | undefined;
+ all?: boolean | undefined;
+ verbatim?: boolean | undefined;
+}
+
+export interface LookupOneOptions extends LookupOptions {
+ all?: false | undefined;
+}
+
+export interface LookupAllOptions extends LookupOptions {
+ all: true;
+}
+
+export interface LookupAddress {
+ address: string | null;
+ family: number;
+}
+
+export function isLookupOptions(
+ options: unknown,
+): options is LookupOptions | undefined {
+ return typeof options === "object" || typeof options === "undefined";
+}
+
+export function isLookupCallback(
+ options: unknown,
+): options is (...args: unknown[]) => void {
+ return typeof options === "function";
+}
+
+export function isFamily(options: unknown): options is number {
+ return typeof options === "number";
+}
+
+export interface ResolveOptions {
+ ttl?: boolean;
+}
+
+export interface ResolveWithTtlOptions extends ResolveOptions {
+ ttl: true;
+}
+
+export interface RecordWithTtl {
+ address: string;
+ ttl: number;
+}
+
+export interface AnyARecord extends RecordWithTtl {
+ type: "A";
+}
+
+export interface AnyAaaaRecord extends RecordWithTtl {
+ type: "AAAA";
+}
+
+export interface CaaRecord {
+ critial: number;
+ issue?: string | undefined;
+ issuewild?: string | undefined;
+ iodef?: string | undefined;
+ contactemail?: string | undefined;
+ contactphone?: string | undefined;
+}
+
+export interface MxRecord {
+ priority: number;
+ exchange: string;
+}
+
+export interface AnyMxRecord extends MxRecord {
+ type: "MX";
+}
+
+export interface NaptrRecord {
+ flags: string;
+ service: string;
+ regexp: string;
+ replacement: string;
+ order: number;
+ preference: number;
+}
+
+export interface AnyNaptrRecord extends NaptrRecord {
+ type: "NAPTR";
+}
+
+export interface SoaRecord {
+ nsname: string;
+ hostmaster: string;
+ serial: number;
+ refresh: number;
+ retry: number;
+ expire: number;
+ minttl: number;
+}
+
+export interface AnySoaRecord extends SoaRecord {
+ type: "SOA";
+}
+
+export interface SrvRecord {
+ priority: number;
+ weight: number;
+ port: number;
+ name: string;
+}
+
+export interface AnySrvRecord extends SrvRecord {
+ type: "SRV";
+}
+
+export interface AnyTxtRecord {
+ type: "TXT";
+ entries: string[];
+}
+
+export interface AnyNsRecord {
+ type: "NS";
+ value: string;
+}
+
+export interface AnyPtrRecord {
+ type: "PTR";
+ value: string;
+}
+
+export interface AnyCnameRecord {
+ type: "CNAME";
+ value: string;
+}
+
+export type AnyRecord =
+ | AnyARecord
+ | AnyAaaaRecord
+ | AnyCnameRecord
+ | AnyMxRecord
+ | AnyNaptrRecord
+ | AnyNsRecord
+ | AnyPtrRecord
+ | AnySoaRecord
+ | AnySrvRecord
+ | AnyTxtRecord;
+
+export type Records =
+ | string[]
+ | AnyRecord[]
+ | MxRecord[]
+ | NaptrRecord[]
+ | SoaRecord
+ | SrvRecord[]
+ | string[];
+
+export type ResolveCallback = (
+ err: ErrnoException | null,
+ addresses: Records,
+) => void;
+
+export function isResolveCallback(
+ callback: unknown,
+): callback is ResolveCallback {
+ return typeof callback === "function";
+}
+
+const IANA_DNS_PORT = 53;
+const IPv6RE = /^\[([^[\]]*)\]/;
+const addrSplitRE = /(^.+?)(?::(\d+))?$/;
+
+export function validateTimeout(options?: { timeout?: number }) {
+ const { timeout = -1 } = { ...options };
+ validateInt32(timeout, "options.timeout", -1, 2 ** 31 - 1);
+ return timeout;
+}
+
+export function validateTries(options?: { tries?: number }) {
+ const { tries = 4 } = { ...options };
+ validateInt32(tries, "options.tries", 1, 2 ** 31 - 1);
+ return tries;
+}
+
+export interface ResolverOptions {
+ timeout?: number | undefined;
+ /**
+ * @default 4
+ */
+ tries?: number;
+}
+
+/**
+ * An independent resolver for DNS requests.
+ *
+ * Creating a new resolver uses the default server settings. Setting
+ * the servers used for a resolver using `resolver.setServers()` does not affect
+ * other resolvers:
+ *
+ * ```js
+ * const { Resolver } = require('dns');
+ * const resolver = new Resolver();
+ * resolver.setServers(['4.4.4.4']);
+ *
+ * // This request will use the server at 4.4.4.4, independent of global settings.
+ * resolver.resolve4('example.org', (err, addresses) => {
+ * // ...
+ * });
+ * ```
+ *
+ * The following methods from the `dns` module are available:
+ *
+ * - `resolver.getServers()`
+ * - `resolver.resolve()`
+ * - `resolver.resolve4()`
+ * - `resolver.resolve6()`
+ * - `resolver.resolveAny()`
+ * - `resolver.resolveCaa()`
+ * - `resolver.resolveCname()`
+ * - `resolver.resolveMx()`
+ * - `resolver.resolveNaptr()`
+ * - `resolver.resolveNs()`
+ * - `resolver.resolvePtr()`
+ * - `resolver.resolveSoa()`
+ * - `resolver.resolveSrv()`
+ * - `resolver.resolveTxt()`
+ * - `resolver.reverse()`
+ * - `resolver.setServers()`
+ */
+export class Resolver {
+ _handle!: ChannelWrap;
+
+ constructor(options?: ResolverOptions) {
+ const timeout = validateTimeout(options);
+ const tries = validateTries(options);
+ this._handle = new ChannelWrap(timeout, tries);
+ }
+
+ cancel() {
+ this._handle.cancel();
+ }
+
+ getServers(): string[] {
+ return this._handle.getServers().map((val: [string, number]) => {
+ if (!val[1] || val[1] === IANA_DNS_PORT) {
+ return val[0];
+ }
+
+ const host = isIP(val[0]) === 6 ? `[${val[0]}]` : val[0];
+ return `${host}:${val[1]}`;
+ });
+ }
+
+ setServers(servers: ReadonlyArray<string>) {
+ validateArray(servers, "servers");
+
+ // Cache the original servers because in the event of an error while
+ // setting the servers, c-ares won't have any servers available for
+ // resolution.
+ const orig = this._handle.getServers();
+ const newSet: [number, string, number][] = [];
+
+ servers.forEach((serv, index) => {
+ validateString(serv, `servers[${index}]`);
+ let ipVersion = isIP(serv);
+
+ if (ipVersion !== 0) {
+ return newSet.push([ipVersion, serv, IANA_DNS_PORT]);
+ }
+
+ const match = serv.match(IPv6RE);
+
+ // Check for an IPv6 in brackets.
+ if (match) {
+ ipVersion = isIP(match[1]);
+
+ if (ipVersion !== 0) {
+ const port = Number.parseInt(serv.replace(addrSplitRE, "$2")) ||
+ IANA_DNS_PORT;
+
+ return newSet.push([ipVersion, match[1], port]);
+ }
+ }
+
+ // addr::port
+ const addrSplitMatch = serv.match(addrSplitRE);
+
+ if (addrSplitMatch) {
+ const hostIP = addrSplitMatch[1];
+ const port = addrSplitMatch[2] || `${IANA_DNS_PORT}`;
+
+ ipVersion = isIP(hostIP);
+
+ if (ipVersion !== 0) {
+ return newSet.push([ipVersion, hostIP, Number.parseInt(port)]);
+ }
+ }
+
+ throw new ERR_INVALID_IP_ADDRESS(serv);
+ });
+
+ const errorNumber = this._handle.setServers(newSet);
+
+ if (errorNumber !== 0) {
+ // Reset the servers to the old servers, because ares probably unset them.
+ this._handle.setServers(orig.join(","));
+ const err = strerror(errorNumber);
+
+ throw new ERR_DNS_SET_SERVERS_FAILED(err, servers.toString());
+ }
+ }
+
+ /**
+ * The resolver instance will send its requests from the specified IP address.
+ * This allows programs to specify outbound interfaces when used on multi-homed
+ * systems.
+ *
+ * If a v4 or v6 address is not specified, it is set to the default, and the
+ * operating system will choose a local address automatically.
+ *
+ * The resolver will use the v4 local address when making requests to IPv4 DNS
+ * servers, and the v6 local address when making requests to IPv6 DNS servers.
+ * The `rrtype` of resolution requests has no impact on the local address used.
+ *
+ * @param [ipv4='0.0.0.0'] A string representation of an IPv4 address.
+ * @param [ipv6='::0'] A string representation of an IPv6 address.
+ */
+ setLocalAddress(ipv4: string, ipv6?: string) {
+ validateString(ipv4, "ipv4");
+
+ if (ipv6 !== undefined) {
+ validateString(ipv6, "ipv6");
+ }
+
+ this._handle.setLocalAddress(ipv4, ipv6);
+ }
+}
+
+let defaultResolver = new Resolver();
+
+export function getDefaultResolver(): Resolver {
+ return defaultResolver;
+}
+
+export function setDefaultResolver<T extends Resolver>(resolver: T) {
+ defaultResolver = resolver;
+}
+
+export function validateHints(hints: number) {
+ if ((hints & ~(AI_ADDRCONFIG | AI_ALL | AI_V4MAPPED)) !== 0) {
+ throw new ERR_INVALID_ARG_VALUE("hints", hints, "is invalid");
+ }
+}
+
+let invalidHostnameWarningEmitted = false;
+
+export function emitInvalidHostnameWarning(hostname: string) {
+ if (invalidHostnameWarningEmitted) {
+ return;
+ }
+
+ invalidHostnameWarningEmitted = true;
+
+ emitWarning(
+ `The provided hostname "${hostname}" is not a valid ` +
+ "hostname, and is supported in the dns module solely for compatibility.",
+ "DeprecationWarning",
+ "DEP0118",
+ );
+}
+
+let dnsOrder = getOptionValue("--dns-result-order") || "ipv4first";
+
+export function getDefaultVerbatim() {
+ switch (dnsOrder) {
+ case "verbatim": {
+ return true;
+ }
+ case "ipv4first": {
+ return false;
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
+/**
+ * Set the default value of `verbatim` in `lookup` and `dnsPromises.lookup()`.
+ * The value could be:
+ *
+ * - `ipv4first`: sets default `verbatim` `false`.
+ * - `verbatim`: sets default `verbatim` `true`.
+ *
+ * The default is `ipv4first` and `setDefaultResultOrder` have higher
+ * priority than `--dns-result-order`. When using `worker threads`,
+ * `setDefaultResultOrder` from the main thread won't affect the default
+ * dns orders in workers.
+ *
+ * @param order must be `'ipv4first'` or `'verbatim'`.
+ */
+export function setDefaultResultOrder(order: "ipv4first" | "verbatim") {
+ validateOneOf(order, "dnsOrder", ["verbatim", "ipv4first"]);
+ dnsOrder = order;
+}
+
+export function defaultResolverSetServers(servers: string[]) {
+ const resolver = new Resolver();
+
+ resolver.setServers(servers);
+ setDefaultResolver(resolver);
+}
diff --git a/ext/node/polyfills/internal/dtrace.ts b/ext/node/polyfills/internal/dtrace.ts
new file mode 100644
index 000000000..5a4470336
--- /dev/null
+++ b/ext/node/polyfills/internal/dtrace.ts
@@ -0,0 +1,41 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// deno-lint-ignore-file
+
+const {
+ DTRACE_HTTP_CLIENT_REQUEST = (..._args: any[]) => {},
+ DTRACE_HTTP_CLIENT_RESPONSE = (..._args: any[]) => {},
+ DTRACE_HTTP_SERVER_REQUEST = (..._args: any[]) => {},
+ DTRACE_HTTP_SERVER_RESPONSE = (..._args: any[]) => {},
+ DTRACE_NET_SERVER_CONNECTION = (..._args: any[]) => {},
+ DTRACE_NET_STREAM_END = (..._args: any[]) => {},
+} = {};
+
+export {
+ DTRACE_HTTP_CLIENT_REQUEST,
+ DTRACE_HTTP_CLIENT_RESPONSE,
+ DTRACE_HTTP_SERVER_REQUEST,
+ DTRACE_HTTP_SERVER_RESPONSE,
+ DTRACE_NET_SERVER_CONNECTION,
+ DTRACE_NET_STREAM_END,
+};
diff --git a/ext/node/polyfills/internal/error_codes.ts b/ext/node/polyfills/internal/error_codes.ts
new file mode 100644
index 000000000..6af88bb11
--- /dev/null
+++ b/ext/node/polyfills/internal/error_codes.ts
@@ -0,0 +1,7 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+// Lazily initializes the error classes in this object.
+// This trick is necessary for avoiding circular dendencies between
+// `internal/errors` and other modules.
+// deno-lint-ignore no-explicit-any
+export const codes: Record<string, any> = {};
diff --git a/ext/node/polyfills/internal/errors.ts b/ext/node/polyfills/internal/errors.ts
new file mode 100644
index 000000000..67f729f8d
--- /dev/null
+++ b/ext/node/polyfills/internal/errors.ts
@@ -0,0 +1,2864 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Node.js contributors. All rights reserved. MIT License.
+/** NOT IMPLEMENTED
+ * ERR_MANIFEST_ASSERT_INTEGRITY
+ * ERR_QUICSESSION_VERSION_NEGOTIATION
+ * ERR_REQUIRE_ESM
+ * ERR_TLS_CERT_ALTNAME_INVALID
+ * ERR_WORKER_INVALID_EXEC_ARGV
+ * ERR_WORKER_PATH
+ * ERR_QUIC_ERROR
+ * ERR_SYSTEM_ERROR //System error, shouldn't ever happen inside Deno
+ * ERR_TTY_INIT_FAILED //System error, shouldn't ever happen inside Deno
+ * ERR_INVALID_PACKAGE_CONFIG // package.json stuff, probably useless
+ */
+
+import { inspect } from "internal:deno_node/polyfills/internal/util/inspect.mjs";
+import { codes } from "internal:deno_node/polyfills/internal/error_codes.ts";
+import {
+ codeMap,
+ errorMap,
+ mapSysErrnoToUvErrno,
+} from "internal:deno_node/polyfills/internal_binding/uv.ts";
+import { assert } from "internal:deno_node/polyfills/_util/asserts.ts";
+import { isWindows } from "internal:deno_node/polyfills/_util/os.ts";
+import { os as osConstants } from "internal:deno_node/polyfills/internal_binding/constants.ts";
+import { hideStackFrames } from "internal:deno_node/polyfills/internal/hide_stack_frames.ts";
+import { getSystemErrorName } from "internal:deno_node/polyfills/_utils.ts";
+
+export { errorMap };
+
+const kIsNodeError = Symbol("kIsNodeError");
+
+/**
+ * @see https://github.com/nodejs/node/blob/f3eb224/lib/internal/errors.js
+ */
+const classRegExp = /^([A-Z][a-z0-9]*)+$/;
+
+/**
+ * @see https://github.com/nodejs/node/blob/f3eb224/lib/internal/errors.js
+ * @description Sorted by a rough estimate on most frequently used entries.
+ */
+const kTypes = [
+ "string",
+ "function",
+ "number",
+ "object",
+ // Accept 'Function' and 'Object' as alternative to the lower cased version.
+ "Function",
+ "Object",
+ "boolean",
+ "bigint",
+ "symbol",
+];
+
+// Node uses an AbortError that isn't exactly the same as the DOMException
+// to make usage of the error in userland and readable-stream easier.
+// It is a regular error with `.code` and `.name`.
+export class AbortError extends Error {
+ code: string;
+
+ constructor(message = "The operation was aborted", options?: ErrorOptions) {
+ if (options !== undefined && typeof options !== "object") {
+ throw new codes.ERR_INVALID_ARG_TYPE("options", "Object", options);
+ }
+ super(message, options);
+ this.code = "ABORT_ERR";
+ this.name = "AbortError";
+ }
+}
+
+let maxStackErrorName: string | undefined;
+let maxStackErrorMessage: string | undefined;
+/**
+ * Returns true if `err.name` and `err.message` are equal to engine-specific
+ * values indicating max call stack size has been exceeded.
+ * "Maximum call stack size exceeded" in V8.
+ */
+export function isStackOverflowError(err: Error): boolean {
+ if (maxStackErrorMessage === undefined) {
+ try {
+ // deno-lint-ignore no-inner-declarations
+ function overflowStack() {
+ overflowStack();
+ }
+ overflowStack();
+ // deno-lint-ignore no-explicit-any
+ } catch (err: any) {
+ maxStackErrorMessage = err.message;
+ maxStackErrorName = err.name;
+ }
+ }
+
+ return err && err.name === maxStackErrorName &&
+ err.message === maxStackErrorMessage;
+}
+
+function addNumericalSeparator(val: string) {
+ let res = "";
+ let i = val.length;
+ const start = val[0] === "-" ? 1 : 0;
+ for (; i >= start + 4; i -= 3) {
+ res = `_${val.slice(i - 3, i)}${res}`;
+ }
+ return `${val.slice(0, i)}${res}`;
+}
+
+const captureLargerStackTrace = hideStackFrames(
+ function captureLargerStackTrace(err) {
+ // @ts-ignore this function is not available in lib.dom.d.ts
+ Error.captureStackTrace(err);
+
+ return err;
+ },
+);
+
+export interface ErrnoException extends Error {
+ errno?: number;
+ code?: string;
+ path?: string;
+ syscall?: string;
+ spawnargs?: string[];
+}
+
+/**
+ * This creates an error compatible with errors produced in the C++
+ * This function should replace the deprecated
+ * `exceptionWithHostPort()` function.
+ *
+ * @param err A libuv error number
+ * @param syscall
+ * @param address
+ * @param port
+ * @return The error.
+ */
+export const uvExceptionWithHostPort = hideStackFrames(
+ function uvExceptionWithHostPort(
+ err: number,
+ syscall: string,
+ address?: string | null,
+ port?: number | null,
+ ) {
+ const { 0: code, 1: uvmsg } = uvErrmapGet(err) || uvUnmappedError;
+ const message = `${syscall} ${code}: ${uvmsg}`;
+ let details = "";
+
+ if (port && port > 0) {
+ details = ` ${address}:${port}`;
+ } else if (address) {
+ details = ` ${address}`;
+ }
+
+ // deno-lint-ignore no-explicit-any
+ const ex: any = new Error(`${message}${details}`);
+ ex.code = code;
+ ex.errno = err;
+ ex.syscall = syscall;
+ ex.address = address;
+
+ if (port) {
+ ex.port = port;
+ }
+
+ return captureLargerStackTrace(ex);
+ },
+);
+
+/**
+ * This used to be `util._errnoException()`.
+ *
+ * @param err A libuv error number
+ * @param syscall
+ * @param original
+ * @return A `ErrnoException`
+ */
+export const errnoException = hideStackFrames(function errnoException(
+ err,
+ syscall,
+ original?,
+): ErrnoException {
+ const code = getSystemErrorName(err);
+ const message = original
+ ? `${syscall} ${code} ${original}`
+ : `${syscall} ${code}`;
+
+ // deno-lint-ignore no-explicit-any
+ const ex: any = new Error(message);
+ ex.errno = err;
+ ex.code = code;
+ ex.syscall = syscall;
+
+ return captureLargerStackTrace(ex);
+});
+
+function uvErrmapGet(name: number) {
+ return errorMap.get(name);
+}
+
+const uvUnmappedError = ["UNKNOWN", "unknown error"];
+
+/**
+ * This creates an error compatible with errors produced in the C++
+ * function UVException using a context object with data assembled in C++.
+ * The goal is to migrate them to ERR_* errors later when compatibility is
+ * not a concern.
+ *
+ * @param ctx
+ * @return The error.
+ */
+export const uvException = hideStackFrames(function uvException(ctx) {
+ const { 0: code, 1: uvmsg } = uvErrmapGet(ctx.errno) || uvUnmappedError;
+
+ let message = `${code}: ${ctx.message || uvmsg}, ${ctx.syscall}`;
+
+ let path;
+ let dest;
+
+ if (ctx.path) {
+ path = ctx.path.toString();
+ message += ` '${path}'`;
+ }
+ if (ctx.dest) {
+ dest = ctx.dest.toString();
+ message += ` -> '${dest}'`;
+ }
+
+ // deno-lint-ignore no-explicit-any
+ const err: any = new Error(message);
+
+ for (const prop of Object.keys(ctx)) {
+ if (prop === "message" || prop === "path" || prop === "dest") {
+ continue;
+ }
+
+ err[prop] = ctx[prop];
+ }
+
+ err.code = code;
+
+ if (path) {
+ err.path = path;
+ }
+
+ if (dest) {
+ err.dest = dest;
+ }
+
+ return captureLargerStackTrace(err);
+});
+
+/**
+ * Deprecated, new function is `uvExceptionWithHostPort()`
+ * New function added the error description directly
+ * from C++. this method for backwards compatibility
+ * @param err A libuv error number
+ * @param syscall
+ * @param address
+ * @param port
+ * @param additional
+ */
+export const exceptionWithHostPort = hideStackFrames(
+ function exceptionWithHostPort(
+ err: number,
+ syscall: string,
+ address: string,
+ port: number,
+ additional?: string,
+ ) {
+ const code = getSystemErrorName(err);
+ let details = "";
+
+ if (port && port > 0) {
+ details = ` ${address}:${port}`;
+ } else if (address) {
+ details = ` ${address}`;
+ }
+
+ if (additional) {
+ details += ` - Local (${additional})`;
+ }
+
+ // deno-lint-ignore no-explicit-any
+ const ex: any = new Error(`${syscall} ${code}${details}`);
+ ex.errno = err;
+ ex.code = code;
+ ex.syscall = syscall;
+ ex.address = address;
+
+ if (port) {
+ ex.port = port;
+ }
+
+ return captureLargerStackTrace(ex);
+ },
+);
+
+/**
+ * @param code A libuv error number or a c-ares error code
+ * @param syscall
+ * @param hostname
+ */
+export const dnsException = hideStackFrames(function (code, syscall, hostname) {
+ let errno;
+
+ // If `code` is of type number, it is a libuv error number, else it is a
+ // c-ares error code.
+ if (typeof code === "number") {
+ errno = code;
+ // ENOTFOUND is not a proper POSIX error, but this error has been in place
+ // long enough that it's not practical to remove it.
+ if (
+ code === codeMap.get("EAI_NODATA") ||
+ code === codeMap.get("EAI_NONAME")
+ ) {
+ code = "ENOTFOUND"; // Fabricated error name.
+ } else {
+ code = getSystemErrorName(code);
+ }
+ }
+
+ const message = `${syscall} ${code}${hostname ? ` ${hostname}` : ""}`;
+
+ // deno-lint-ignore no-explicit-any
+ const ex: any = new Error(message);
+ ex.errno = errno;
+ ex.code = code;
+ ex.syscall = syscall;
+
+ if (hostname) {
+ ex.hostname = hostname;
+ }
+
+ return captureLargerStackTrace(ex);
+});
+
+/**
+ * All error instances in Node have additional methods and properties
+ * This export class is meant to be extended by these instances abstracting native JS error instances
+ */
+export class NodeErrorAbstraction extends Error {
+ code: string;
+
+ constructor(name: string, code: string, message: string) {
+ super(message);
+ this.code = code;
+ this.name = name;
+ //This number changes depending on the name of this class
+ //20 characters as of now
+ this.stack = this.stack && `${name} [${this.code}]${this.stack.slice(20)}`;
+ }
+
+ override toString() {
+ return `${this.name} [${this.code}]: ${this.message}`;
+ }
+}
+
+export class NodeError extends NodeErrorAbstraction {
+ constructor(code: string, message: string) {
+ super(Error.prototype.name, code, message);
+ }
+}
+
+export class NodeSyntaxError extends NodeErrorAbstraction
+ implements SyntaxError {
+ constructor(code: string, message: string) {
+ super(SyntaxError.prototype.name, code, message);
+ Object.setPrototypeOf(this, SyntaxError.prototype);
+ this.toString = function () {
+ return `${this.name} [${this.code}]: ${this.message}`;
+ };
+ }
+}
+
+export class NodeRangeError extends NodeErrorAbstraction {
+ constructor(code: string, message: string) {
+ super(RangeError.prototype.name, code, message);
+ Object.setPrototypeOf(this, RangeError.prototype);
+ this.toString = function () {
+ return `${this.name} [${this.code}]: ${this.message}`;
+ };
+ }
+}
+
+export class NodeTypeError extends NodeErrorAbstraction implements TypeError {
+ constructor(code: string, message: string) {
+ super(TypeError.prototype.name, code, message);
+ Object.setPrototypeOf(this, TypeError.prototype);
+ this.toString = function () {
+ return `${this.name} [${this.code}]: ${this.message}`;
+ };
+ }
+}
+
+export class NodeURIError extends NodeErrorAbstraction implements URIError {
+ constructor(code: string, message: string) {
+ super(URIError.prototype.name, code, message);
+ Object.setPrototypeOf(this, URIError.prototype);
+ this.toString = function () {
+ return `${this.name} [${this.code}]: ${this.message}`;
+ };
+ }
+}
+
+export interface NodeSystemErrorCtx {
+ code: string;
+ syscall: string;
+ message: string;
+ errno: number;
+ path?: string;
+ dest?: string;
+}
+// A specialized Error that includes an additional info property with
+// additional information about the error condition.
+// It has the properties present in a UVException but with a custom error
+// message followed by the uv error code and uv error message.
+// It also has its own error code with the original uv error context put into
+// `err.info`.
+// The context passed into this error must have .code, .syscall and .message,
+// and may have .path and .dest.
+class NodeSystemError extends NodeErrorAbstraction {
+ constructor(key: string, context: NodeSystemErrorCtx, msgPrefix: string) {
+ let message = `${msgPrefix}: ${context.syscall} returned ` +
+ `${context.code} (${context.message})`;
+
+ if (context.path !== undefined) {
+ message += ` ${context.path}`;
+ }
+ if (context.dest !== undefined) {
+ message += ` => ${context.dest}`;
+ }
+
+ super("SystemError", key, message);
+
+ captureLargerStackTrace(this);
+
+ Object.defineProperties(this, {
+ [kIsNodeError]: {
+ value: true,
+ enumerable: false,
+ writable: false,
+ configurable: true,
+ },
+ info: {
+ value: context,
+ enumerable: true,
+ configurable: true,
+ writable: false,
+ },
+ errno: {
+ get() {
+ return context.errno;
+ },
+ set: (value) => {
+ context.errno = value;
+ },
+ enumerable: true,
+ configurable: true,
+ },
+ syscall: {
+ get() {
+ return context.syscall;
+ },
+ set: (value) => {
+ context.syscall = value;
+ },
+ enumerable: true,
+ configurable: true,
+ },
+ });
+
+ if (context.path !== undefined) {
+ Object.defineProperty(this, "path", {
+ get() {
+ return context.path;
+ },
+ set: (value) => {
+ context.path = value;
+ },
+ enumerable: true,
+ configurable: true,
+ });
+ }
+
+ if (context.dest !== undefined) {
+ Object.defineProperty(this, "dest", {
+ get() {
+ return context.dest;
+ },
+ set: (value) => {
+ context.dest = value;
+ },
+ enumerable: true,
+ configurable: true,
+ });
+ }
+ }
+
+ override toString() {
+ return `${this.name} [${this.code}]: ${this.message}`;
+ }
+}
+
+function makeSystemErrorWithCode(key: string, msgPrfix: string) {
+ return class NodeError extends NodeSystemError {
+ constructor(ctx: NodeSystemErrorCtx) {
+ super(key, ctx, msgPrfix);
+ }
+ };
+}
+
+export const ERR_FS_EISDIR = makeSystemErrorWithCode(
+ "ERR_FS_EISDIR",
+ "Path is a directory",
+);
+
+function createInvalidArgType(
+ name: string,
+ expected: string | string[],
+): string {
+ // https://github.com/nodejs/node/blob/f3eb224/lib/internal/errors.js#L1037-L1087
+ expected = Array.isArray(expected) ? expected : [expected];
+ let msg = "The ";
+ if (name.endsWith(" argument")) {
+ // For cases like 'first argument'
+ msg += `${name} `;
+ } else {
+ const type = name.includes(".") ? "property" : "argument";
+ msg += `"${name}" ${type} `;
+ }
+ msg += "must be ";
+
+ const types = [];
+ const instances = [];
+ const other = [];
+ for (const value of expected) {
+ if (kTypes.includes(value)) {
+ types.push(value.toLocaleLowerCase());
+ } else if (classRegExp.test(value)) {
+ instances.push(value);
+ } else {
+ other.push(value);
+ }
+ }
+
+ // Special handle `object` in case other instances are allowed to outline
+ // the differences between each other.
+ if (instances.length > 0) {
+ const pos = types.indexOf("object");
+ if (pos !== -1) {
+ types.splice(pos, 1);
+ instances.push("Object");
+ }
+ }
+
+ if (types.length > 0) {
+ if (types.length > 2) {
+ const last = types.pop();
+ msg += `one of type ${types.join(", ")}, or ${last}`;
+ } else if (types.length === 2) {
+ msg += `one of type ${types[0]} or ${types[1]}`;
+ } else {
+ msg += `of type ${types[0]}`;
+ }
+ if (instances.length > 0 || other.length > 0) {
+ msg += " or ";
+ }
+ }
+
+ if (instances.length > 0) {
+ if (instances.length > 2) {
+ const last = instances.pop();
+ msg += `an instance of ${instances.join(", ")}, or ${last}`;
+ } else {
+ msg += `an instance of ${instances[0]}`;
+ if (instances.length === 2) {
+ msg += ` or ${instances[1]}`;
+ }
+ }
+ if (other.length > 0) {
+ msg += " or ";
+ }
+ }
+
+ if (other.length > 0) {
+ if (other.length > 2) {
+ const last = other.pop();
+ msg += `one of ${other.join(", ")}, or ${last}`;
+ } else if (other.length === 2) {
+ msg += `one of ${other[0]} or ${other[1]}`;
+ } else {
+ if (other[0].toLowerCase() !== other[0]) {
+ msg += "an ";
+ }
+ msg += `${other[0]}`;
+ }
+ }
+
+ return msg;
+}
+
+export class ERR_INVALID_ARG_TYPE_RANGE extends NodeRangeError {
+ constructor(name: string, expected: string | string[], actual: unknown) {
+ const msg = createInvalidArgType(name, expected);
+
+ super("ERR_INVALID_ARG_TYPE", `${msg}.${invalidArgTypeHelper(actual)}`);
+ }
+}
+
+export class ERR_INVALID_ARG_TYPE extends NodeTypeError {
+ constructor(name: string, expected: string | string[], actual: unknown) {
+ const msg = createInvalidArgType(name, expected);
+
+ super("ERR_INVALID_ARG_TYPE", `${msg}.${invalidArgTypeHelper(actual)}`);
+ }
+
+ static RangeError = ERR_INVALID_ARG_TYPE_RANGE;
+}
+
+export class ERR_INVALID_ARG_VALUE_RANGE extends NodeRangeError {
+ constructor(name: string, value: unknown, reason: string = "is invalid") {
+ const type = name.includes(".") ? "property" : "argument";
+ const inspected = inspect(value);
+
+ super(
+ "ERR_INVALID_ARG_VALUE",
+ `The ${type} '${name}' ${reason}. Received ${inspected}`,
+ );
+ }
+}
+
+export class ERR_INVALID_ARG_VALUE extends NodeTypeError {
+ constructor(name: string, value: unknown, reason: string = "is invalid") {
+ const type = name.includes(".") ? "property" : "argument";
+ const inspected = inspect(value);
+
+ super(
+ "ERR_INVALID_ARG_VALUE",
+ `The ${type} '${name}' ${reason}. Received ${inspected}`,
+ );
+ }
+
+ static RangeError = ERR_INVALID_ARG_VALUE_RANGE;
+}
+
+// A helper function to simplify checking for ERR_INVALID_ARG_TYPE output.
+// deno-lint-ignore no-explicit-any
+function invalidArgTypeHelper(input: any) {
+ if (input == null) {
+ return ` Received ${input}`;
+ }
+ if (typeof input === "function" && input.name) {
+ return ` Received function ${input.name}`;
+ }
+ if (typeof input === "object") {
+ if (input.constructor && input.constructor.name) {
+ return ` Received an instance of ${input.constructor.name}`;
+ }
+ return ` Received ${inspect(input, { depth: -1 })}`;
+ }
+ let inspected = inspect(input, { colors: false });
+ if (inspected.length > 25) {
+ inspected = `${inspected.slice(0, 25)}...`;
+ }
+ return ` Received type ${typeof input} (${inspected})`;
+}
+
+export class ERR_OUT_OF_RANGE extends RangeError {
+ code = "ERR_OUT_OF_RANGE";
+
+ constructor(
+ str: string,
+ range: string,
+ input: unknown,
+ replaceDefaultBoolean = false,
+ ) {
+ assert(range, 'Missing "range" argument');
+ let msg = replaceDefaultBoolean
+ ? str
+ : `The value of "${str}" is out of range.`;
+ let received;
+ if (Number.isInteger(input) && Math.abs(input as number) > 2 ** 32) {
+ received = addNumericalSeparator(String(input));
+ } else if (typeof input === "bigint") {
+ received = String(input);
+ if (input > 2n ** 32n || input < -(2n ** 32n)) {
+ received = addNumericalSeparator(received);
+ }
+ received += "n";
+ } else {
+ received = inspect(input);
+ }
+ msg += ` It must be ${range}. Received ${received}`;
+
+ super(msg);
+
+ const { name } = this;
+ // Add the error code to the name to include it in the stack trace.
+ this.name = `${name} [${this.code}]`;
+ // Access the stack to generate the error message including the error code from the name.
+ this.stack;
+ // Reset the name to the actual name.
+ this.name = name;
+ }
+}
+
+export class ERR_AMBIGUOUS_ARGUMENT extends NodeTypeError {
+ constructor(x: string, y: string) {
+ super("ERR_AMBIGUOUS_ARGUMENT", `The "${x}" argument is ambiguous. ${y}`);
+ }
+}
+
+export class ERR_ARG_NOT_ITERABLE extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_ARG_NOT_ITERABLE", `${x} must be iterable`);
+ }
+}
+
+export class ERR_ASSERTION extends NodeError {
+ constructor(x: string) {
+ super("ERR_ASSERTION", `${x}`);
+ }
+}
+
+export class ERR_ASYNC_CALLBACK extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_ASYNC_CALLBACK", `${x} must be a function`);
+ }
+}
+
+export class ERR_ASYNC_TYPE extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_ASYNC_TYPE", `Invalid name for async "type": ${x}`);
+ }
+}
+
+export class ERR_BROTLI_INVALID_PARAM extends NodeRangeError {
+ constructor(x: string) {
+ super("ERR_BROTLI_INVALID_PARAM", `${x} is not a valid Brotli parameter`);
+ }
+}
+
+export class ERR_BUFFER_OUT_OF_BOUNDS extends NodeRangeError {
+ constructor(name?: string) {
+ super(
+ "ERR_BUFFER_OUT_OF_BOUNDS",
+ name
+ ? `"${name}" is outside of buffer bounds`
+ : "Attempt to access memory outside buffer bounds",
+ );
+ }
+}
+
+export class ERR_BUFFER_TOO_LARGE extends NodeRangeError {
+ constructor(x: string) {
+ super(
+ "ERR_BUFFER_TOO_LARGE",
+ `Cannot create a Buffer larger than ${x} bytes`,
+ );
+ }
+}
+
+export class ERR_CANNOT_WATCH_SIGINT extends NodeError {
+ constructor() {
+ super("ERR_CANNOT_WATCH_SIGINT", "Cannot watch for SIGINT signals");
+ }
+}
+
+export class ERR_CHILD_CLOSED_BEFORE_REPLY extends NodeError {
+ constructor() {
+ super(
+ "ERR_CHILD_CLOSED_BEFORE_REPLY",
+ "Child closed before reply received",
+ );
+ }
+}
+
+export class ERR_CHILD_PROCESS_IPC_REQUIRED extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_CHILD_PROCESS_IPC_REQUIRED",
+ `Forked processes must have an IPC channel, missing value 'ipc' in ${x}`,
+ );
+ }
+}
+
+export class ERR_CHILD_PROCESS_STDIO_MAXBUFFER extends NodeRangeError {
+ constructor(x: string) {
+ super(
+ "ERR_CHILD_PROCESS_STDIO_MAXBUFFER",
+ `${x} maxBuffer length exceeded`,
+ );
+ }
+}
+
+export class ERR_CONSOLE_WRITABLE_STREAM extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_CONSOLE_WRITABLE_STREAM",
+ `Console expects a writable stream instance for ${x}`,
+ );
+ }
+}
+
+export class ERR_CONTEXT_NOT_INITIALIZED extends NodeError {
+ constructor() {
+ super("ERR_CONTEXT_NOT_INITIALIZED", "context used is not initialized");
+ }
+}
+
+export class ERR_CPU_USAGE extends NodeError {
+ constructor(x: string) {
+ super("ERR_CPU_USAGE", `Unable to obtain cpu usage ${x}`);
+ }
+}
+
+export class ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED extends NodeError {
+ constructor() {
+ super(
+ "ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED",
+ "Custom engines not supported by this OpenSSL",
+ );
+ }
+}
+
+export class ERR_CRYPTO_ECDH_INVALID_FORMAT extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_CRYPTO_ECDH_INVALID_FORMAT", `Invalid ECDH format: ${x}`);
+ }
+}
+
+export class ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY extends NodeError {
+ constructor() {
+ super(
+ "ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY",
+ "Public key is not valid for specified curve",
+ );
+ }
+}
+
+export class ERR_CRYPTO_ENGINE_UNKNOWN extends NodeError {
+ constructor(x: string) {
+ super("ERR_CRYPTO_ENGINE_UNKNOWN", `Engine "${x}" was not found`);
+ }
+}
+
+export class ERR_CRYPTO_FIPS_FORCED extends NodeError {
+ constructor() {
+ super(
+ "ERR_CRYPTO_FIPS_FORCED",
+ "Cannot set FIPS mode, it was forced with --force-fips at startup.",
+ );
+ }
+}
+
+export class ERR_CRYPTO_FIPS_UNAVAILABLE extends NodeError {
+ constructor() {
+ super(
+ "ERR_CRYPTO_FIPS_UNAVAILABLE",
+ "Cannot set FIPS mode in a non-FIPS build.",
+ );
+ }
+}
+
+export class ERR_CRYPTO_HASH_FINALIZED extends NodeError {
+ constructor() {
+ super("ERR_CRYPTO_HASH_FINALIZED", "Digest already called");
+ }
+}
+
+export class ERR_CRYPTO_HASH_UPDATE_FAILED extends NodeError {
+ constructor() {
+ super("ERR_CRYPTO_HASH_UPDATE_FAILED", "Hash update failed");
+ }
+}
+
+export class ERR_CRYPTO_INCOMPATIBLE_KEY extends NodeError {
+ constructor(x: string, y: string) {
+ super("ERR_CRYPTO_INCOMPATIBLE_KEY", `Incompatible ${x}: ${y}`);
+ }
+}
+
+export class ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS extends NodeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS",
+ `The selected key encoding ${x} ${y}.`,
+ );
+ }
+}
+
+export class ERR_CRYPTO_INVALID_DIGEST extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_CRYPTO_INVALID_DIGEST", `Invalid digest: ${x}`);
+ }
+}
+
+export class ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE extends NodeTypeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE",
+ `Invalid key object type ${x}, expected ${y}.`,
+ );
+ }
+}
+
+export class ERR_CRYPTO_INVALID_STATE extends NodeError {
+ constructor(x: string) {
+ super("ERR_CRYPTO_INVALID_STATE", `Invalid state for operation ${x}`);
+ }
+}
+
+export class ERR_CRYPTO_PBKDF2_ERROR extends NodeError {
+ constructor() {
+ super("ERR_CRYPTO_PBKDF2_ERROR", "PBKDF2 error");
+ }
+}
+
+export class ERR_CRYPTO_SCRYPT_INVALID_PARAMETER extends NodeError {
+ constructor() {
+ super("ERR_CRYPTO_SCRYPT_INVALID_PARAMETER", "Invalid scrypt parameter");
+ }
+}
+
+export class ERR_CRYPTO_SCRYPT_NOT_SUPPORTED extends NodeError {
+ constructor() {
+ super("ERR_CRYPTO_SCRYPT_NOT_SUPPORTED", "Scrypt algorithm not supported");
+ }
+}
+
+export class ERR_CRYPTO_SIGN_KEY_REQUIRED extends NodeError {
+ constructor() {
+ super("ERR_CRYPTO_SIGN_KEY_REQUIRED", "No key provided to sign");
+ }
+}
+
+export class ERR_DIR_CLOSED extends NodeError {
+ constructor() {
+ super("ERR_DIR_CLOSED", "Directory handle was closed");
+ }
+}
+
+export class ERR_DIR_CONCURRENT_OPERATION extends NodeError {
+ constructor() {
+ super(
+ "ERR_DIR_CONCURRENT_OPERATION",
+ "Cannot do synchronous work on directory handle with concurrent asynchronous operations",
+ );
+ }
+}
+
+export class ERR_DNS_SET_SERVERS_FAILED extends NodeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_DNS_SET_SERVERS_FAILED",
+ `c-ares failed to set servers: "${x}" [${y}]`,
+ );
+ }
+}
+
+export class ERR_DOMAIN_CALLBACK_NOT_AVAILABLE extends NodeError {
+ constructor() {
+ super(
+ "ERR_DOMAIN_CALLBACK_NOT_AVAILABLE",
+ "A callback was registered through " +
+ "process.setUncaughtExceptionCaptureCallback(), which is mutually " +
+ "exclusive with using the `domain` module",
+ );
+ }
+}
+
+export class ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE
+ extends NodeError {
+ constructor() {
+ super(
+ "ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE",
+ "The `domain` module is in use, which is mutually exclusive with calling " +
+ "process.setUncaughtExceptionCaptureCallback()",
+ );
+ }
+}
+
+export class ERR_ENCODING_INVALID_ENCODED_DATA extends NodeErrorAbstraction
+ implements TypeError {
+ errno: number;
+ constructor(encoding: string, ret: number) {
+ super(
+ TypeError.prototype.name,
+ "ERR_ENCODING_INVALID_ENCODED_DATA",
+ `The encoded data was not valid for encoding ${encoding}`,
+ );
+ Object.setPrototypeOf(this, TypeError.prototype);
+
+ this.errno = ret;
+ }
+}
+
+export class ERR_ENCODING_NOT_SUPPORTED extends NodeRangeError {
+ constructor(x: string) {
+ super("ERR_ENCODING_NOT_SUPPORTED", `The "${x}" encoding is not supported`);
+ }
+}
+export class ERR_EVAL_ESM_CANNOT_PRINT extends NodeError {
+ constructor() {
+ super("ERR_EVAL_ESM_CANNOT_PRINT", `--print cannot be used with ESM input`);
+ }
+}
+export class ERR_EVENT_RECURSION extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_EVENT_RECURSION",
+ `The event "${x}" is already being dispatched`,
+ );
+ }
+}
+export class ERR_FEATURE_UNAVAILABLE_ON_PLATFORM extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM",
+ `The feature ${x} is unavailable on the current platform, which is being used to run Node.js`,
+ );
+ }
+}
+export class ERR_FS_FILE_TOO_LARGE extends NodeRangeError {
+ constructor(x: string) {
+ super("ERR_FS_FILE_TOO_LARGE", `File size (${x}) is greater than 2 GB`);
+ }
+}
+export class ERR_FS_INVALID_SYMLINK_TYPE extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_FS_INVALID_SYMLINK_TYPE",
+ `Symlink type must be one of "dir", "file", or "junction". Received "${x}"`,
+ );
+ }
+}
+export class ERR_HTTP2_ALTSVC_INVALID_ORIGIN extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_ALTSVC_INVALID_ORIGIN",
+ `HTTP/2 ALTSVC frames require a valid origin`,
+ );
+ }
+}
+export class ERR_HTTP2_ALTSVC_LENGTH extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_ALTSVC_LENGTH",
+ `HTTP/2 ALTSVC frames are limited to 16382 bytes`,
+ );
+ }
+}
+export class ERR_HTTP2_CONNECT_AUTHORITY extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_CONNECT_AUTHORITY",
+ `:authority header is required for CONNECT requests`,
+ );
+ }
+}
+export class ERR_HTTP2_CONNECT_PATH extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_CONNECT_PATH",
+ `The :path header is forbidden for CONNECT requests`,
+ );
+ }
+}
+export class ERR_HTTP2_CONNECT_SCHEME extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_CONNECT_SCHEME",
+ `The :scheme header is forbidden for CONNECT requests`,
+ );
+ }
+}
+export class ERR_HTTP2_GOAWAY_SESSION extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_GOAWAY_SESSION",
+ `New streams cannot be created after receiving a GOAWAY`,
+ );
+ }
+}
+export class ERR_HTTP2_HEADERS_AFTER_RESPOND extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_HEADERS_AFTER_RESPOND",
+ `Cannot specify additional headers after response initiated`,
+ );
+ }
+}
+export class ERR_HTTP2_HEADERS_SENT extends NodeError {
+ constructor() {
+ super("ERR_HTTP2_HEADERS_SENT", `Response has already been initiated.`);
+ }
+}
+export class ERR_HTTP2_HEADER_SINGLE_VALUE extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_HTTP2_HEADER_SINGLE_VALUE",
+ `Header field "${x}" must only have a single value`,
+ );
+ }
+}
+export class ERR_HTTP2_INFO_STATUS_NOT_ALLOWED extends NodeRangeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_INFO_STATUS_NOT_ALLOWED",
+ `Informational status codes cannot be used`,
+ );
+ }
+}
+export class ERR_HTTP2_INVALID_CONNECTION_HEADERS extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_HTTP2_INVALID_CONNECTION_HEADERS",
+ `HTTP/1 Connection specific headers are forbidden: "${x}"`,
+ );
+ }
+}
+export class ERR_HTTP2_INVALID_HEADER_VALUE extends NodeTypeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_HTTP2_INVALID_HEADER_VALUE",
+ `Invalid value "${x}" for header "${y}"`,
+ );
+ }
+}
+export class ERR_HTTP2_INVALID_INFO_STATUS extends NodeRangeError {
+ constructor(x: string) {
+ super(
+ "ERR_HTTP2_INVALID_INFO_STATUS",
+ `Invalid informational status code: ${x}`,
+ );
+ }
+}
+export class ERR_HTTP2_INVALID_ORIGIN extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_INVALID_ORIGIN",
+ `HTTP/2 ORIGIN frames require a valid origin`,
+ );
+ }
+}
+export class ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH extends NodeRangeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH",
+ `Packed settings length must be a multiple of six`,
+ );
+ }
+}
+export class ERR_HTTP2_INVALID_PSEUDOHEADER extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_HTTP2_INVALID_PSEUDOHEADER",
+ `"${x}" is an invalid pseudoheader or is used incorrectly`,
+ );
+ }
+}
+export class ERR_HTTP2_INVALID_SESSION extends NodeError {
+ constructor() {
+ super("ERR_HTTP2_INVALID_SESSION", `The session has been destroyed`);
+ }
+}
+export class ERR_HTTP2_INVALID_STREAM extends NodeError {
+ constructor() {
+ super("ERR_HTTP2_INVALID_STREAM", `The stream has been destroyed`);
+ }
+}
+export class ERR_HTTP2_MAX_PENDING_SETTINGS_ACK extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_MAX_PENDING_SETTINGS_ACK",
+ `Maximum number of pending settings acknowledgements`,
+ );
+ }
+}
+export class ERR_HTTP2_NESTED_PUSH extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_NESTED_PUSH",
+ `A push stream cannot initiate another push stream.`,
+ );
+ }
+}
+export class ERR_HTTP2_NO_SOCKET_MANIPULATION extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_NO_SOCKET_MANIPULATION",
+ `HTTP/2 sockets should not be directly manipulated (e.g. read and written)`,
+ );
+ }
+}
+export class ERR_HTTP2_ORIGIN_LENGTH extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_ORIGIN_LENGTH",
+ `HTTP/2 ORIGIN frames are limited to 16382 bytes`,
+ );
+ }
+}
+export class ERR_HTTP2_OUT_OF_STREAMS extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_OUT_OF_STREAMS",
+ `No stream ID is available because maximum stream ID has been reached`,
+ );
+ }
+}
+export class ERR_HTTP2_PAYLOAD_FORBIDDEN extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_HTTP2_PAYLOAD_FORBIDDEN",
+ `Responses with ${x} status must not have a payload`,
+ );
+ }
+}
+export class ERR_HTTP2_PING_CANCEL extends NodeError {
+ constructor() {
+ super("ERR_HTTP2_PING_CANCEL", `HTTP2 ping cancelled`);
+ }
+}
+export class ERR_HTTP2_PING_LENGTH extends NodeRangeError {
+ constructor() {
+ super("ERR_HTTP2_PING_LENGTH", `HTTP2 ping payload must be 8 bytes`);
+ }
+}
+export class ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED",
+ `Cannot set HTTP/2 pseudo-headers`,
+ );
+ }
+}
+export class ERR_HTTP2_PUSH_DISABLED extends NodeError {
+ constructor() {
+ super("ERR_HTTP2_PUSH_DISABLED", `HTTP/2 client has disabled push streams`);
+ }
+}
+export class ERR_HTTP2_SEND_FILE extends NodeError {
+ constructor() {
+ super("ERR_HTTP2_SEND_FILE", `Directories cannot be sent`);
+ }
+}
+export class ERR_HTTP2_SEND_FILE_NOSEEK extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_SEND_FILE_NOSEEK",
+ `Offset or length can only be specified for regular files`,
+ );
+ }
+}
+export class ERR_HTTP2_SESSION_ERROR extends NodeError {
+ constructor(x: string) {
+ super("ERR_HTTP2_SESSION_ERROR", `Session closed with error code ${x}`);
+ }
+}
+export class ERR_HTTP2_SETTINGS_CANCEL extends NodeError {
+ constructor() {
+ super("ERR_HTTP2_SETTINGS_CANCEL", `HTTP2 session settings canceled`);
+ }
+}
+export class ERR_HTTP2_SOCKET_BOUND extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_SOCKET_BOUND",
+ `The socket is already bound to an Http2Session`,
+ );
+ }
+}
+export class ERR_HTTP2_SOCKET_UNBOUND extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_SOCKET_UNBOUND",
+ `The socket has been disconnected from the Http2Session`,
+ );
+ }
+}
+export class ERR_HTTP2_STATUS_101 extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_STATUS_101",
+ `HTTP status code 101 (Switching Protocols) is forbidden in HTTP/2`,
+ );
+ }
+}
+export class ERR_HTTP2_STATUS_INVALID extends NodeRangeError {
+ constructor(x: string) {
+ super("ERR_HTTP2_STATUS_INVALID", `Invalid status code: ${x}`);
+ }
+}
+export class ERR_HTTP2_STREAM_ERROR extends NodeError {
+ constructor(x: string) {
+ super("ERR_HTTP2_STREAM_ERROR", `Stream closed with error code ${x}`);
+ }
+}
+export class ERR_HTTP2_STREAM_SELF_DEPENDENCY extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_STREAM_SELF_DEPENDENCY",
+ `A stream cannot depend on itself`,
+ );
+ }
+}
+export class ERR_HTTP2_TRAILERS_ALREADY_SENT extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_TRAILERS_ALREADY_SENT",
+ `Trailing headers have already been sent`,
+ );
+ }
+}
+export class ERR_HTTP2_TRAILERS_NOT_READY extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP2_TRAILERS_NOT_READY",
+ `Trailing headers cannot be sent until after the wantTrailers event is emitted`,
+ );
+ }
+}
+export class ERR_HTTP2_UNSUPPORTED_PROTOCOL extends NodeError {
+ constructor(x: string) {
+ super("ERR_HTTP2_UNSUPPORTED_PROTOCOL", `protocol "${x}" is unsupported.`);
+ }
+}
+export class ERR_HTTP_HEADERS_SENT extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_HTTP_HEADERS_SENT",
+ `Cannot ${x} headers after they are sent to the client`,
+ );
+ }
+}
+export class ERR_HTTP_INVALID_HEADER_VALUE extends NodeTypeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_HTTP_INVALID_HEADER_VALUE",
+ `Invalid value "${x}" for header "${y}"`,
+ );
+ }
+}
+export class ERR_HTTP_INVALID_STATUS_CODE extends NodeRangeError {
+ constructor(x: string) {
+ super("ERR_HTTP_INVALID_STATUS_CODE", `Invalid status code: ${x}`);
+ }
+}
+export class ERR_HTTP_SOCKET_ENCODING extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP_SOCKET_ENCODING",
+ `Changing the socket encoding is not allowed per RFC7230 Section 3.`,
+ );
+ }
+}
+export class ERR_HTTP_TRAILER_INVALID extends NodeError {
+ constructor() {
+ super(
+ "ERR_HTTP_TRAILER_INVALID",
+ `Trailers are invalid with this transfer encoding`,
+ );
+ }
+}
+export class ERR_INCOMPATIBLE_OPTION_PAIR extends NodeTypeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_INCOMPATIBLE_OPTION_PAIR",
+ `Option "${x}" cannot be used in combination with option "${y}"`,
+ );
+ }
+}
+export class ERR_INPUT_TYPE_NOT_ALLOWED extends NodeError {
+ constructor() {
+ super(
+ "ERR_INPUT_TYPE_NOT_ALLOWED",
+ `--input-type can only be used with string input via --eval, --print, or STDIN`,
+ );
+ }
+}
+export class ERR_INSPECTOR_ALREADY_ACTIVATED extends NodeError {
+ constructor() {
+ super(
+ "ERR_INSPECTOR_ALREADY_ACTIVATED",
+ `Inspector is already activated. Close it with inspector.close() before activating it again.`,
+ );
+ }
+}
+export class ERR_INSPECTOR_ALREADY_CONNECTED extends NodeError {
+ constructor(x: string) {
+ super("ERR_INSPECTOR_ALREADY_CONNECTED", `${x} is already connected`);
+ }
+}
+export class ERR_INSPECTOR_CLOSED extends NodeError {
+ constructor() {
+ super("ERR_INSPECTOR_CLOSED", `Session was closed`);
+ }
+}
+export class ERR_INSPECTOR_COMMAND extends NodeError {
+ constructor(x: number, y: string) {
+ super("ERR_INSPECTOR_COMMAND", `Inspector error ${x}: ${y}`);
+ }
+}
+export class ERR_INSPECTOR_NOT_ACTIVE extends NodeError {
+ constructor() {
+ super("ERR_INSPECTOR_NOT_ACTIVE", `Inspector is not active`);
+ }
+}
+export class ERR_INSPECTOR_NOT_AVAILABLE extends NodeError {
+ constructor() {
+ super("ERR_INSPECTOR_NOT_AVAILABLE", `Inspector is not available`);
+ }
+}
+export class ERR_INSPECTOR_NOT_CONNECTED extends NodeError {
+ constructor() {
+ super("ERR_INSPECTOR_NOT_CONNECTED", `Session is not connected`);
+ }
+}
+export class ERR_INSPECTOR_NOT_WORKER extends NodeError {
+ constructor() {
+ super("ERR_INSPECTOR_NOT_WORKER", `Current thread is not a worker`);
+ }
+}
+export class ERR_INVALID_ASYNC_ID extends NodeRangeError {
+ constructor(x: string, y: string | number) {
+ super("ERR_INVALID_ASYNC_ID", `Invalid ${x} value: ${y}`);
+ }
+}
+export class ERR_INVALID_BUFFER_SIZE extends NodeRangeError {
+ constructor(x: string) {
+ super("ERR_INVALID_BUFFER_SIZE", `Buffer size must be a multiple of ${x}`);
+ }
+}
+export class ERR_INVALID_CURSOR_POS extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_INVALID_CURSOR_POS",
+ `Cannot set cursor row without setting its column`,
+ );
+ }
+}
+export class ERR_INVALID_FD extends NodeRangeError {
+ constructor(x: string) {
+ super("ERR_INVALID_FD", `"fd" must be a positive integer: ${x}`);
+ }
+}
+export class ERR_INVALID_FD_TYPE extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_INVALID_FD_TYPE", `Unsupported fd type: ${x}`);
+ }
+}
+export class ERR_INVALID_FILE_URL_HOST extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_INVALID_FILE_URL_HOST",
+ `File URL host must be "localhost" or empty on ${x}`,
+ );
+ }
+}
+export class ERR_INVALID_FILE_URL_PATH extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_INVALID_FILE_URL_PATH", `File URL path ${x}`);
+ }
+}
+export class ERR_INVALID_HANDLE_TYPE extends NodeTypeError {
+ constructor() {
+ super("ERR_INVALID_HANDLE_TYPE", `This handle type cannot be sent`);
+ }
+}
+export class ERR_INVALID_HTTP_TOKEN extends NodeTypeError {
+ constructor(x: string, y: string) {
+ super("ERR_INVALID_HTTP_TOKEN", `${x} must be a valid HTTP token ["${y}"]`);
+ }
+}
+export class ERR_INVALID_IP_ADDRESS extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_INVALID_IP_ADDRESS", `Invalid IP address: ${x}`);
+ }
+}
+export class ERR_INVALID_OPT_VALUE_ENCODING extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_INVALID_OPT_VALUE_ENCODING",
+ `The value "${x}" is invalid for option "encoding"`,
+ );
+ }
+}
+export class ERR_INVALID_PERFORMANCE_MARK extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_INVALID_PERFORMANCE_MARK",
+ `The "${x}" performance mark has not been set`,
+ );
+ }
+}
+export class ERR_INVALID_PROTOCOL extends NodeTypeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_INVALID_PROTOCOL",
+ `Protocol "${x}" not supported. Expected "${y}"`,
+ );
+ }
+}
+export class ERR_INVALID_REPL_EVAL_CONFIG extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_INVALID_REPL_EVAL_CONFIG",
+ `Cannot specify both "breakEvalOnSigint" and "eval" for REPL`,
+ );
+ }
+}
+export class ERR_INVALID_REPL_INPUT extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_INVALID_REPL_INPUT", `${x}`);
+ }
+}
+export class ERR_INVALID_SYNC_FORK_INPUT extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_INVALID_SYNC_FORK_INPUT",
+ `Asynchronous forks do not support Buffer, TypedArray, DataView or string input: ${x}`,
+ );
+ }
+}
+export class ERR_INVALID_THIS extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_INVALID_THIS", `Value of "this" must be of type ${x}`);
+ }
+}
+export class ERR_INVALID_TUPLE extends NodeTypeError {
+ constructor(x: string, y: string) {
+ super("ERR_INVALID_TUPLE", `${x} must be an iterable ${y} tuple`);
+ }
+}
+export class ERR_INVALID_URI extends NodeURIError {
+ constructor() {
+ super("ERR_INVALID_URI", `URI malformed`);
+ }
+}
+export class ERR_IPC_CHANNEL_CLOSED extends NodeError {
+ constructor() {
+ super("ERR_IPC_CHANNEL_CLOSED", `Channel closed`);
+ }
+}
+export class ERR_IPC_DISCONNECTED extends NodeError {
+ constructor() {
+ super("ERR_IPC_DISCONNECTED", `IPC channel is already disconnected`);
+ }
+}
+export class ERR_IPC_ONE_PIPE extends NodeError {
+ constructor() {
+ super("ERR_IPC_ONE_PIPE", `Child process can have only one IPC pipe`);
+ }
+}
+export class ERR_IPC_SYNC_FORK extends NodeError {
+ constructor() {
+ super("ERR_IPC_SYNC_FORK", `IPC cannot be used with synchronous forks`);
+ }
+}
+export class ERR_MANIFEST_DEPENDENCY_MISSING extends NodeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_MANIFEST_DEPENDENCY_MISSING",
+ `Manifest resource ${x} does not list ${y} as a dependency specifier`,
+ );
+ }
+}
+export class ERR_MANIFEST_INTEGRITY_MISMATCH extends NodeSyntaxError {
+ constructor(x: string) {
+ super(
+ "ERR_MANIFEST_INTEGRITY_MISMATCH",
+ `Manifest resource ${x} has multiple entries but integrity lists do not match`,
+ );
+ }
+}
+export class ERR_MANIFEST_INVALID_RESOURCE_FIELD extends NodeTypeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_MANIFEST_INVALID_RESOURCE_FIELD",
+ `Manifest resource ${x} has invalid property value for ${y}`,
+ );
+ }
+}
+export class ERR_MANIFEST_TDZ extends NodeError {
+ constructor() {
+ super("ERR_MANIFEST_TDZ", `Manifest initialization has not yet run`);
+ }
+}
+export class ERR_MANIFEST_UNKNOWN_ONERROR extends NodeSyntaxError {
+ constructor(x: string) {
+ super(
+ "ERR_MANIFEST_UNKNOWN_ONERROR",
+ `Manifest specified unknown error behavior "${x}".`,
+ );
+ }
+}
+export class ERR_METHOD_NOT_IMPLEMENTED extends NodeError {
+ constructor(x: string) {
+ super("ERR_METHOD_NOT_IMPLEMENTED", `The ${x} method is not implemented`);
+ }
+}
+export class ERR_MISSING_ARGS extends NodeTypeError {
+ constructor(...args: (string | string[])[]) {
+ let msg = "The ";
+
+ const len = args.length;
+
+ const wrap = (a: unknown) => `"${a}"`;
+
+ args = args.map((a) =>
+ Array.isArray(a) ? a.map(wrap).join(" or ") : wrap(a)
+ );
+
+ switch (len) {
+ case 1:
+ msg += `${args[0]} argument`;
+ break;
+ case 2:
+ msg += `${args[0]} and ${args[1]} arguments`;
+ break;
+ default:
+ msg += args.slice(0, len - 1).join(", ");
+ msg += `, and ${args[len - 1]} arguments`;
+ break;
+ }
+
+ super("ERR_MISSING_ARGS", `${msg} must be specified`);
+ }
+}
+export class ERR_MISSING_OPTION extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_MISSING_OPTION", `${x} is required`);
+ }
+}
+export class ERR_MULTIPLE_CALLBACK extends NodeError {
+ constructor() {
+ super("ERR_MULTIPLE_CALLBACK", `Callback called multiple times`);
+ }
+}
+export class ERR_NAPI_CONS_FUNCTION extends NodeTypeError {
+ constructor() {
+ super("ERR_NAPI_CONS_FUNCTION", `Constructor must be a function`);
+ }
+}
+export class ERR_NAPI_INVALID_DATAVIEW_ARGS extends NodeRangeError {
+ constructor() {
+ super(
+ "ERR_NAPI_INVALID_DATAVIEW_ARGS",
+ `byte_offset + byte_length should be less than or equal to the size in bytes of the array passed in`,
+ );
+ }
+}
+export class ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT extends NodeRangeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT",
+ `start offset of ${x} should be a multiple of ${y}`,
+ );
+ }
+}
+export class ERR_NAPI_INVALID_TYPEDARRAY_LENGTH extends NodeRangeError {
+ constructor() {
+ super("ERR_NAPI_INVALID_TYPEDARRAY_LENGTH", `Invalid typed array length`);
+ }
+}
+export class ERR_NO_CRYPTO extends NodeError {
+ constructor() {
+ super(
+ "ERR_NO_CRYPTO",
+ `Node.js is not compiled with OpenSSL crypto support`,
+ );
+ }
+}
+export class ERR_NO_ICU extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_NO_ICU",
+ `${x} is not supported on Node.js compiled without ICU`,
+ );
+ }
+}
+export class ERR_QUICCLIENTSESSION_FAILED extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_QUICCLIENTSESSION_FAILED",
+ `Failed to create a new QuicClientSession: ${x}`,
+ );
+ }
+}
+export class ERR_QUICCLIENTSESSION_FAILED_SETSOCKET extends NodeError {
+ constructor() {
+ super(
+ "ERR_QUICCLIENTSESSION_FAILED_SETSOCKET",
+ `Failed to set the QuicSocket`,
+ );
+ }
+}
+export class ERR_QUICSESSION_DESTROYED extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_QUICSESSION_DESTROYED",
+ `Cannot call ${x} after a QuicSession has been destroyed`,
+ );
+ }
+}
+export class ERR_QUICSESSION_INVALID_DCID extends NodeError {
+ constructor(x: string) {
+ super("ERR_QUICSESSION_INVALID_DCID", `Invalid DCID value: ${x}`);
+ }
+}
+export class ERR_QUICSESSION_UPDATEKEY extends NodeError {
+ constructor() {
+ super("ERR_QUICSESSION_UPDATEKEY", `Unable to update QuicSession keys`);
+ }
+}
+export class ERR_QUICSOCKET_DESTROYED extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_QUICSOCKET_DESTROYED",
+ `Cannot call ${x} after a QuicSocket has been destroyed`,
+ );
+ }
+}
+export class ERR_QUICSOCKET_INVALID_STATELESS_RESET_SECRET_LENGTH
+ extends NodeError {
+ constructor() {
+ super(
+ "ERR_QUICSOCKET_INVALID_STATELESS_RESET_SECRET_LENGTH",
+ `The stateResetToken must be exactly 16-bytes in length`,
+ );
+ }
+}
+export class ERR_QUICSOCKET_LISTENING extends NodeError {
+ constructor() {
+ super("ERR_QUICSOCKET_LISTENING", `This QuicSocket is already listening`);
+ }
+}
+export class ERR_QUICSOCKET_UNBOUND extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_QUICSOCKET_UNBOUND",
+ `Cannot call ${x} before a QuicSocket has been bound`,
+ );
+ }
+}
+export class ERR_QUICSTREAM_DESTROYED extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_QUICSTREAM_DESTROYED",
+ `Cannot call ${x} after a QuicStream has been destroyed`,
+ );
+ }
+}
+export class ERR_QUICSTREAM_INVALID_PUSH extends NodeError {
+ constructor() {
+ super(
+ "ERR_QUICSTREAM_INVALID_PUSH",
+ `Push streams are only supported on client-initiated, bidirectional streams`,
+ );
+ }
+}
+export class ERR_QUICSTREAM_OPEN_FAILED extends NodeError {
+ constructor() {
+ super("ERR_QUICSTREAM_OPEN_FAILED", `Opening a new QuicStream failed`);
+ }
+}
+export class ERR_QUICSTREAM_UNSUPPORTED_PUSH extends NodeError {
+ constructor() {
+ super(
+ "ERR_QUICSTREAM_UNSUPPORTED_PUSH",
+ `Push streams are not supported on this QuicSession`,
+ );
+ }
+}
+export class ERR_QUIC_TLS13_REQUIRED extends NodeError {
+ constructor() {
+ super("ERR_QUIC_TLS13_REQUIRED", `QUIC requires TLS version 1.3`);
+ }
+}
+export class ERR_SCRIPT_EXECUTION_INTERRUPTED extends NodeError {
+ constructor() {
+ super(
+ "ERR_SCRIPT_EXECUTION_INTERRUPTED",
+ "Script execution was interrupted by `SIGINT`",
+ );
+ }
+}
+export class ERR_SERVER_ALREADY_LISTEN extends NodeError {
+ constructor() {
+ super(
+ "ERR_SERVER_ALREADY_LISTEN",
+ `Listen method has been called more than once without closing.`,
+ );
+ }
+}
+export class ERR_SERVER_NOT_RUNNING extends NodeError {
+ constructor() {
+ super("ERR_SERVER_NOT_RUNNING", `Server is not running.`);
+ }
+}
+export class ERR_SOCKET_ALREADY_BOUND extends NodeError {
+ constructor() {
+ super("ERR_SOCKET_ALREADY_BOUND", `Socket is already bound`);
+ }
+}
+export class ERR_SOCKET_BAD_BUFFER_SIZE extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_SOCKET_BAD_BUFFER_SIZE",
+ `Buffer size must be a positive integer`,
+ );
+ }
+}
+export class ERR_SOCKET_BAD_PORT extends NodeRangeError {
+ constructor(name: string, port: unknown, allowZero = true) {
+ assert(
+ typeof allowZero === "boolean",
+ "The 'allowZero' argument must be of type boolean.",
+ );
+
+ const operator = allowZero ? ">=" : ">";
+
+ super(
+ "ERR_SOCKET_BAD_PORT",
+ `${name} should be ${operator} 0 and < 65536. Received ${port}.`,
+ );
+ }
+}
+export class ERR_SOCKET_BAD_TYPE extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_SOCKET_BAD_TYPE",
+ `Bad socket type specified. Valid types are: udp4, udp6`,
+ );
+ }
+}
+export class ERR_SOCKET_BUFFER_SIZE extends NodeSystemError {
+ constructor(ctx: NodeSystemErrorCtx) {
+ super("ERR_SOCKET_BUFFER_SIZE", ctx, "Could not get or set buffer size");
+ }
+}
+export class ERR_SOCKET_CLOSED extends NodeError {
+ constructor() {
+ super("ERR_SOCKET_CLOSED", `Socket is closed`);
+ }
+}
+export class ERR_SOCKET_DGRAM_IS_CONNECTED extends NodeError {
+ constructor() {
+ super("ERR_SOCKET_DGRAM_IS_CONNECTED", `Already connected`);
+ }
+}
+export class ERR_SOCKET_DGRAM_NOT_CONNECTED extends NodeError {
+ constructor() {
+ super("ERR_SOCKET_DGRAM_NOT_CONNECTED", `Not connected`);
+ }
+}
+export class ERR_SOCKET_DGRAM_NOT_RUNNING extends NodeError {
+ constructor() {
+ super("ERR_SOCKET_DGRAM_NOT_RUNNING", `Not running`);
+ }
+}
+export class ERR_SRI_PARSE extends NodeSyntaxError {
+ constructor(name: string, char: string, position: number) {
+ super(
+ "ERR_SRI_PARSE",
+ `Subresource Integrity string ${name} had an unexpected ${char} at position ${position}`,
+ );
+ }
+}
+export class ERR_STREAM_ALREADY_FINISHED extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_STREAM_ALREADY_FINISHED",
+ `Cannot call ${x} after a stream was finished`,
+ );
+ }
+}
+export class ERR_STREAM_CANNOT_PIPE extends NodeError {
+ constructor() {
+ super("ERR_STREAM_CANNOT_PIPE", `Cannot pipe, not readable`);
+ }
+}
+export class ERR_STREAM_DESTROYED extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_STREAM_DESTROYED",
+ `Cannot call ${x} after a stream was destroyed`,
+ );
+ }
+}
+export class ERR_STREAM_NULL_VALUES extends NodeTypeError {
+ constructor() {
+ super("ERR_STREAM_NULL_VALUES", `May not write null values to stream`);
+ }
+}
+export class ERR_STREAM_PREMATURE_CLOSE extends NodeError {
+ constructor() {
+ super("ERR_STREAM_PREMATURE_CLOSE", `Premature close`);
+ }
+}
+export class ERR_STREAM_PUSH_AFTER_EOF extends NodeError {
+ constructor() {
+ super("ERR_STREAM_PUSH_AFTER_EOF", `stream.push() after EOF`);
+ }
+}
+export class ERR_STREAM_UNSHIFT_AFTER_END_EVENT extends NodeError {
+ constructor() {
+ super(
+ "ERR_STREAM_UNSHIFT_AFTER_END_EVENT",
+ `stream.unshift() after end event`,
+ );
+ }
+}
+export class ERR_STREAM_WRAP extends NodeError {
+ constructor() {
+ super(
+ "ERR_STREAM_WRAP",
+ `Stream has StringDecoder set or is in objectMode`,
+ );
+ }
+}
+export class ERR_STREAM_WRITE_AFTER_END extends NodeError {
+ constructor() {
+ super("ERR_STREAM_WRITE_AFTER_END", `write after end`);
+ }
+}
+export class ERR_SYNTHETIC extends NodeError {
+ constructor() {
+ super("ERR_SYNTHETIC", `JavaScript Callstack`);
+ }
+}
+export class ERR_TLS_CERT_ALTNAME_INVALID extends NodeError {
+ reason: string;
+ host: string;
+ cert: string;
+
+ constructor(reason: string, host: string, cert: string) {
+ super(
+ "ERR_TLS_CERT_ALTNAME_INVALID",
+ `Hostname/IP does not match certificate's altnames: ${reason}`,
+ );
+ this.reason = reason;
+ this.host = host;
+ this.cert = cert;
+ }
+}
+export class ERR_TLS_DH_PARAM_SIZE extends NodeError {
+ constructor(x: string) {
+ super("ERR_TLS_DH_PARAM_SIZE", `DH parameter size ${x} is less than 2048`);
+ }
+}
+export class ERR_TLS_HANDSHAKE_TIMEOUT extends NodeError {
+ constructor() {
+ super("ERR_TLS_HANDSHAKE_TIMEOUT", `TLS handshake timeout`);
+ }
+}
+export class ERR_TLS_INVALID_CONTEXT extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_TLS_INVALID_CONTEXT", `${x} must be a SecureContext`);
+ }
+}
+export class ERR_TLS_INVALID_STATE extends NodeError {
+ constructor() {
+ super(
+ "ERR_TLS_INVALID_STATE",
+ `TLS socket connection must be securely established`,
+ );
+ }
+}
+export class ERR_TLS_INVALID_PROTOCOL_VERSION extends NodeTypeError {
+ constructor(protocol: string, x: string) {
+ super(
+ "ERR_TLS_INVALID_PROTOCOL_VERSION",
+ `${protocol} is not a valid ${x} TLS protocol version`,
+ );
+ }
+}
+export class ERR_TLS_PROTOCOL_VERSION_CONFLICT extends NodeTypeError {
+ constructor(prevProtocol: string, protocol: string) {
+ super(
+ "ERR_TLS_PROTOCOL_VERSION_CONFLICT",
+ `TLS protocol version ${prevProtocol} conflicts with secureProtocol ${protocol}`,
+ );
+ }
+}
+export class ERR_TLS_RENEGOTIATION_DISABLED extends NodeError {
+ constructor() {
+ super(
+ "ERR_TLS_RENEGOTIATION_DISABLED",
+ `TLS session renegotiation disabled for this socket`,
+ );
+ }
+}
+export class ERR_TLS_REQUIRED_SERVER_NAME extends NodeError {
+ constructor() {
+ super(
+ "ERR_TLS_REQUIRED_SERVER_NAME",
+ `"servername" is required parameter for Server.addContext`,
+ );
+ }
+}
+export class ERR_TLS_SESSION_ATTACK extends NodeError {
+ constructor() {
+ super(
+ "ERR_TLS_SESSION_ATTACK",
+ `TLS session renegotiation attack detected`,
+ );
+ }
+}
+export class ERR_TLS_SNI_FROM_SERVER extends NodeError {
+ constructor() {
+ super(
+ "ERR_TLS_SNI_FROM_SERVER",
+ `Cannot issue SNI from a TLS server-side socket`,
+ );
+ }
+}
+export class ERR_TRACE_EVENTS_CATEGORY_REQUIRED extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_TRACE_EVENTS_CATEGORY_REQUIRED",
+ `At least one category is required`,
+ );
+ }
+}
+export class ERR_TRACE_EVENTS_UNAVAILABLE extends NodeError {
+ constructor() {
+ super("ERR_TRACE_EVENTS_UNAVAILABLE", `Trace events are unavailable`);
+ }
+}
+export class ERR_UNAVAILABLE_DURING_EXIT extends NodeError {
+ constructor() {
+ super(
+ "ERR_UNAVAILABLE_DURING_EXIT",
+ `Cannot call function in process exit handler`,
+ );
+ }
+}
+export class ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET extends NodeError {
+ constructor() {
+ super(
+ "ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET",
+ "`process.setupUncaughtExceptionCapture()` was called while a capture callback was already active",
+ );
+ }
+}
+export class ERR_UNESCAPED_CHARACTERS extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_UNESCAPED_CHARACTERS", `${x} contains unescaped characters`);
+ }
+}
+export class ERR_UNHANDLED_ERROR extends NodeError {
+ constructor(x: string) {
+ super("ERR_UNHANDLED_ERROR", `Unhandled error. (${x})`);
+ }
+}
+export class ERR_UNKNOWN_BUILTIN_MODULE extends NodeError {
+ constructor(x: string) {
+ super("ERR_UNKNOWN_BUILTIN_MODULE", `No such built-in module: ${x}`);
+ }
+}
+export class ERR_UNKNOWN_CREDENTIAL extends NodeError {
+ constructor(x: string, y: string) {
+ super("ERR_UNKNOWN_CREDENTIAL", `${x} identifier does not exist: ${y}`);
+ }
+}
+export class ERR_UNKNOWN_ENCODING extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_UNKNOWN_ENCODING", `Unknown encoding: ${x}`);
+ }
+}
+export class ERR_UNKNOWN_FILE_EXTENSION extends NodeTypeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_UNKNOWN_FILE_EXTENSION",
+ `Unknown file extension "${x}" for ${y}`,
+ );
+ }
+}
+export class ERR_UNKNOWN_MODULE_FORMAT extends NodeRangeError {
+ constructor(x: string) {
+ super("ERR_UNKNOWN_MODULE_FORMAT", `Unknown module format: ${x}`);
+ }
+}
+export class ERR_UNKNOWN_SIGNAL extends NodeTypeError {
+ constructor(x: string) {
+ super("ERR_UNKNOWN_SIGNAL", `Unknown signal: ${x}`);
+ }
+}
+export class ERR_UNSUPPORTED_DIR_IMPORT extends NodeError {
+ constructor(x: string, y: string) {
+ super(
+ "ERR_UNSUPPORTED_DIR_IMPORT",
+ `Directory import '${x}' is not supported resolving ES modules, imported from ${y}`,
+ );
+ }
+}
+export class ERR_UNSUPPORTED_ESM_URL_SCHEME extends NodeError {
+ constructor() {
+ super(
+ "ERR_UNSUPPORTED_ESM_URL_SCHEME",
+ `Only file and data URLs are supported by the default ESM loader`,
+ );
+ }
+}
+export class ERR_USE_AFTER_CLOSE extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_USE_AFTER_CLOSE",
+ `${x} was closed`,
+ );
+ }
+}
+export class ERR_V8BREAKITERATOR extends NodeError {
+ constructor() {
+ super(
+ "ERR_V8BREAKITERATOR",
+ `Full ICU data not installed. See https://github.com/nodejs/node/wiki/Intl`,
+ );
+ }
+}
+export class ERR_VALID_PERFORMANCE_ENTRY_TYPE extends NodeError {
+ constructor() {
+ super(
+ "ERR_VALID_PERFORMANCE_ENTRY_TYPE",
+ `At least one valid performance entry type is required`,
+ );
+ }
+}
+export class ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING extends NodeTypeError {
+ constructor() {
+ super(
+ "ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING",
+ `A dynamic import callback was not specified.`,
+ );
+ }
+}
+export class ERR_VM_MODULE_ALREADY_LINKED extends NodeError {
+ constructor() {
+ super("ERR_VM_MODULE_ALREADY_LINKED", `Module has already been linked`);
+ }
+}
+export class ERR_VM_MODULE_CANNOT_CREATE_CACHED_DATA extends NodeError {
+ constructor() {
+ super(
+ "ERR_VM_MODULE_CANNOT_CREATE_CACHED_DATA",
+ `Cached data cannot be created for a module which has been evaluated`,
+ );
+ }
+}
+export class ERR_VM_MODULE_DIFFERENT_CONTEXT extends NodeError {
+ constructor() {
+ super(
+ "ERR_VM_MODULE_DIFFERENT_CONTEXT",
+ `Linked modules must use the same context`,
+ );
+ }
+}
+export class ERR_VM_MODULE_LINKING_ERRORED extends NodeError {
+ constructor() {
+ super(
+ "ERR_VM_MODULE_LINKING_ERRORED",
+ `Linking has already failed for the provided module`,
+ );
+ }
+}
+export class ERR_VM_MODULE_NOT_MODULE extends NodeError {
+ constructor() {
+ super(
+ "ERR_VM_MODULE_NOT_MODULE",
+ `Provided module is not an instance of Module`,
+ );
+ }
+}
+export class ERR_VM_MODULE_STATUS extends NodeError {
+ constructor(x: string) {
+ super("ERR_VM_MODULE_STATUS", `Module status ${x}`);
+ }
+}
+export class ERR_WASI_ALREADY_STARTED extends NodeError {
+ constructor() {
+ super("ERR_WASI_ALREADY_STARTED", `WASI instance has already started`);
+ }
+}
+export class ERR_WORKER_INIT_FAILED extends NodeError {
+ constructor(x: string) {
+ super("ERR_WORKER_INIT_FAILED", `Worker initialization failure: ${x}`);
+ }
+}
+export class ERR_WORKER_NOT_RUNNING extends NodeError {
+ constructor() {
+ super("ERR_WORKER_NOT_RUNNING", `Worker instance not running`);
+ }
+}
+export class ERR_WORKER_OUT_OF_MEMORY extends NodeError {
+ constructor(x: string) {
+ super(
+ "ERR_WORKER_OUT_OF_MEMORY",
+ `Worker terminated due to reaching memory limit: ${x}`,
+ );
+ }
+}
+export class ERR_WORKER_UNSERIALIZABLE_ERROR extends NodeError {
+ constructor() {
+ super(
+ "ERR_WORKER_UNSERIALIZABLE_ERROR",
+ `Serializing an uncaught exception failed`,
+ );
+ }
+}
+export class ERR_WORKER_UNSUPPORTED_EXTENSION extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_WORKER_UNSUPPORTED_EXTENSION",
+ `The worker script extension must be ".js", ".mjs", or ".cjs". Received "${x}"`,
+ );
+ }
+}
+export class ERR_WORKER_UNSUPPORTED_OPERATION extends NodeTypeError {
+ constructor(x: string) {
+ super(
+ "ERR_WORKER_UNSUPPORTED_OPERATION",
+ `${x} is not supported in workers`,
+ );
+ }
+}
+export class ERR_ZLIB_INITIALIZATION_FAILED extends NodeError {
+ constructor() {
+ super("ERR_ZLIB_INITIALIZATION_FAILED", `Initialization failed`);
+ }
+}
+export class ERR_FALSY_VALUE_REJECTION extends NodeError {
+ reason: string;
+ constructor(reason: string) {
+ super("ERR_FALSY_VALUE_REJECTION", "Promise was rejected with falsy value");
+ this.reason = reason;
+ }
+}
+export class ERR_HTTP2_INVALID_SETTING_VALUE extends NodeRangeError {
+ actual: unknown;
+ min?: number;
+ max?: number;
+
+ constructor(name: string, actual: unknown, min?: number, max?: number) {
+ super(
+ "ERR_HTTP2_INVALID_SETTING_VALUE",
+ `Invalid value for setting "${name}": ${actual}`,
+ );
+ this.actual = actual;
+ if (min !== undefined) {
+ this.min = min;
+ this.max = max;
+ }
+ }
+}
+export class ERR_HTTP2_STREAM_CANCEL extends NodeError {
+ override cause?: Error;
+ constructor(error: Error) {
+ super(
+ "ERR_HTTP2_STREAM_CANCEL",
+ typeof error.message === "string"
+ ? `The pending stream has been canceled (caused by: ${error.message})`
+ : "The pending stream has been canceled",
+ );
+ if (error) {
+ this.cause = error;
+ }
+ }
+}
+
+export class ERR_INVALID_ADDRESS_FAMILY extends NodeRangeError {
+ host: string;
+ port: number;
+ constructor(addressType: string, host: string, port: number) {
+ super(
+ "ERR_INVALID_ADDRESS_FAMILY",
+ `Invalid address family: ${addressType} ${host}:${port}`,
+ );
+ this.host = host;
+ this.port = port;
+ }
+}
+
+export class ERR_INVALID_CHAR extends NodeTypeError {
+ constructor(name: string, field?: string) {
+ super(
+ "ERR_INVALID_CHAR",
+ field
+ ? `Invalid character in ${name}`
+ : `Invalid character in ${name} ["${field}"]`,
+ );
+ }
+}
+
+export class ERR_INVALID_OPT_VALUE extends NodeTypeError {
+ constructor(name: string, value: unknown) {
+ super(
+ "ERR_INVALID_OPT_VALUE",
+ `The value "${value}" is invalid for option "${name}"`,
+ );
+ }
+}
+
+export class ERR_INVALID_RETURN_PROPERTY extends NodeTypeError {
+ constructor(input: string, name: string, prop: string, value: string) {
+ super(
+ "ERR_INVALID_RETURN_PROPERTY",
+ `Expected a valid ${input} to be returned for the "${prop}" from the "${name}" function but got ${value}.`,
+ );
+ }
+}
+
+// deno-lint-ignore no-explicit-any
+function buildReturnPropertyType(value: any) {
+ if (value && value.constructor && value.constructor.name) {
+ return `instance of ${value.constructor.name}`;
+ } else {
+ return `type ${typeof value}`;
+ }
+}
+
+export class ERR_INVALID_RETURN_PROPERTY_VALUE extends NodeTypeError {
+ constructor(input: string, name: string, prop: string, value: unknown) {
+ super(
+ "ERR_INVALID_RETURN_PROPERTY_VALUE",
+ `Expected ${input} to be returned for the "${prop}" from the "${name}" function but got ${
+ buildReturnPropertyType(
+ value,
+ )
+ }.`,
+ );
+ }
+}
+
+export class ERR_INVALID_RETURN_VALUE extends NodeTypeError {
+ constructor(input: string, name: string, value: unknown) {
+ super(
+ "ERR_INVALID_RETURN_VALUE",
+ `Expected ${input} to be returned from the "${name}" function but got ${
+ determineSpecificType(
+ value,
+ )
+ }.`,
+ );
+ }
+}
+
+export class ERR_INVALID_URL extends NodeTypeError {
+ input: string;
+ constructor(input: string) {
+ super("ERR_INVALID_URL", `Invalid URL: ${input}`);
+ this.input = input;
+ }
+}
+
+export class ERR_INVALID_URL_SCHEME extends NodeTypeError {
+ constructor(expected: string | [string] | [string, string]) {
+ expected = Array.isArray(expected) ? expected : [expected];
+ const res = expected.length === 2
+ ? `one of scheme ${expected[0]} or ${expected[1]}`
+ : `of scheme ${expected[0]}`;
+ super("ERR_INVALID_URL_SCHEME", `The URL must be ${res}`);
+ }
+}
+
+export class ERR_MODULE_NOT_FOUND extends NodeError {
+ constructor(path: string, base: string, type: string = "package") {
+ super(
+ "ERR_MODULE_NOT_FOUND",
+ `Cannot find ${type} '${path}' imported from ${base}`,
+ );
+ }
+}
+
+export class ERR_INVALID_PACKAGE_CONFIG extends NodeError {
+ constructor(path: string, base?: string, message?: string) {
+ const msg = `Invalid package config ${path}${
+ base ? ` while importing ${base}` : ""
+ }${message ? `. ${message}` : ""}`;
+ super("ERR_INVALID_PACKAGE_CONFIG", msg);
+ }
+}
+
+export class ERR_INVALID_MODULE_SPECIFIER extends NodeTypeError {
+ constructor(request: string, reason: string, base?: string) {
+ super(
+ "ERR_INVALID_MODULE_SPECIFIER",
+ `Invalid module "${request}" ${reason}${
+ base ? ` imported from ${base}` : ""
+ }`,
+ );
+ }
+}
+
+export class ERR_INVALID_PACKAGE_TARGET extends NodeError {
+ constructor(
+ pkgPath: string,
+ key: string,
+ // deno-lint-ignore no-explicit-any
+ target: any,
+ isImport?: boolean,
+ base?: string,
+ ) {
+ let msg: string;
+ const relError = typeof target === "string" &&
+ !isImport &&
+ target.length &&
+ !target.startsWith("./");
+ if (key === ".") {
+ assert(isImport === false);
+ msg = `Invalid "exports" main target ${JSON.stringify(target)} defined ` +
+ `in the package config ${pkgPath}package.json${
+ base ? ` imported from ${base}` : ""
+ }${relError ? '; targets must start with "./"' : ""}`;
+ } else {
+ msg = `Invalid "${isImport ? "imports" : "exports"}" target ${
+ JSON.stringify(
+ target,
+ )
+ } defined for '${key}' in the package config ${pkgPath}package.json${
+ base ? ` imported from ${base}` : ""
+ }${relError ? '; targets must start with "./"' : ""}`;
+ }
+ super("ERR_INVALID_PACKAGE_TARGET", msg);
+ }
+}
+
+export class ERR_PACKAGE_IMPORT_NOT_DEFINED extends NodeTypeError {
+ constructor(
+ specifier: string,
+ packagePath: string | undefined,
+ base: string,
+ ) {
+ const msg = `Package import specifier "${specifier}" is not defined${
+ packagePath ? ` in package ${packagePath}package.json` : ""
+ } imported from ${base}`;
+
+ super("ERR_PACKAGE_IMPORT_NOT_DEFINED", msg);
+ }
+}
+
+export class ERR_PACKAGE_PATH_NOT_EXPORTED extends NodeError {
+ constructor(subpath: string, pkgPath: string, basePath?: string) {
+ let msg: string;
+ if (subpath === ".") {
+ msg = `No "exports" main defined in ${pkgPath}package.json${
+ basePath ? ` imported from ${basePath}` : ""
+ }`;
+ } else {
+ msg =
+ `Package subpath '${subpath}' is not defined by "exports" in ${pkgPath}package.json${
+ basePath ? ` imported from ${basePath}` : ""
+ }`;
+ }
+
+ super("ERR_PACKAGE_PATH_NOT_EXPORTED", msg);
+ }
+}
+
+export class ERR_INTERNAL_ASSERTION extends NodeError {
+ constructor(message?: string) {
+ const suffix = "This is caused by either a bug in Node.js " +
+ "or incorrect usage of Node.js internals.\n" +
+ "Please open an issue with this stack trace at " +
+ "https://github.com/nodejs/node/issues\n";
+ super(
+ "ERR_INTERNAL_ASSERTION",
+ message === undefined ? suffix : `${message}\n${suffix}`,
+ );
+ }
+}
+
+// Using `fs.rmdir` on a path that is a file results in an ENOENT error on Windows and an ENOTDIR error on POSIX.
+export class ERR_FS_RMDIR_ENOTDIR extends NodeSystemError {
+ constructor(path: string) {
+ const code = isWindows ? "ENOENT" : "ENOTDIR";
+ const ctx: NodeSystemErrorCtx = {
+ message: "not a directory",
+ path,
+ syscall: "rmdir",
+ code,
+ errno: isWindows ? osConstants.errno.ENOENT : osConstants.errno.ENOTDIR,
+ };
+ super(code, ctx, "Path is not a directory");
+ }
+}
+
+interface UvExceptionContext {
+ syscall: string;
+ path?: string;
+}
+export function denoErrorToNodeError(e: Error, ctx: UvExceptionContext) {
+ const errno = extractOsErrorNumberFromErrorMessage(e);
+ if (typeof errno === "undefined") {
+ return e;
+ }
+
+ const ex = uvException({
+ errno: mapSysErrnoToUvErrno(errno),
+ ...ctx,
+ });
+ return ex;
+}
+
+function extractOsErrorNumberFromErrorMessage(e: unknown): number | undefined {
+ const match = e instanceof Error
+ ? e.message.match(/\(os error (\d+)\)/)
+ : false;
+
+ if (match) {
+ return +match[1];
+ }
+
+ return undefined;
+}
+
+export function connResetException(msg: string) {
+ const ex = new Error(msg);
+ // deno-lint-ignore no-explicit-any
+ (ex as any).code = "ECONNRESET";
+ return ex;
+}
+
+export function aggregateTwoErrors(
+ innerError: AggregateError,
+ outerError: AggregateError & { code: string },
+) {
+ if (innerError && outerError && innerError !== outerError) {
+ if (Array.isArray(outerError.errors)) {
+ // If `outerError` is already an `AggregateError`.
+ outerError.errors.push(innerError);
+ return outerError;
+ }
+ // eslint-disable-next-line no-restricted-syntax
+ const err = new AggregateError(
+ [
+ outerError,
+ innerError,
+ ],
+ outerError.message,
+ );
+ // deno-lint-ignore no-explicit-any
+ (err as any).code = outerError.code;
+ return err;
+ }
+ return innerError || outerError;
+}
+codes.ERR_IPC_CHANNEL_CLOSED = ERR_IPC_CHANNEL_CLOSED;
+codes.ERR_INVALID_ARG_TYPE = ERR_INVALID_ARG_TYPE;
+codes.ERR_INVALID_ARG_VALUE = ERR_INVALID_ARG_VALUE;
+codes.ERR_OUT_OF_RANGE = ERR_OUT_OF_RANGE;
+codes.ERR_SOCKET_BAD_PORT = ERR_SOCKET_BAD_PORT;
+codes.ERR_BUFFER_OUT_OF_BOUNDS = ERR_BUFFER_OUT_OF_BOUNDS;
+codes.ERR_UNKNOWN_ENCODING = ERR_UNKNOWN_ENCODING;
+// TODO(kt3k): assign all error classes here.
+
+/**
+ * This creates a generic Node.js error.
+ *
+ * @param message The error message.
+ * @param errorProperties Object with additional properties to be added to the error.
+ * @returns
+ */
+const genericNodeError = hideStackFrames(
+ function genericNodeError(message, errorProperties) {
+ // eslint-disable-next-line no-restricted-syntax
+ const err = new Error(message);
+ Object.assign(err, errorProperties);
+
+ return err;
+ },
+);
+
+/**
+ * Determine the specific type of a value for type-mismatch errors.
+ * @param {*} value
+ * @returns {string}
+ */
+// deno-lint-ignore no-explicit-any
+function determineSpecificType(value: any) {
+ if (value == null) {
+ return "" + value;
+ }
+ if (typeof value === "function" && value.name) {
+ return `function ${value.name}`;
+ }
+ if (typeof value === "object") {
+ if (value.constructor?.name) {
+ return `an instance of ${value.constructor.name}`;
+ }
+ return `${inspect(value, { depth: -1 })}`;
+ }
+ let inspected = inspect(value, { colors: false });
+ if (inspected.length > 28) inspected = `${inspected.slice(0, 25)}...`;
+
+ return `type ${typeof value} (${inspected})`;
+}
+
+export { codes, genericNodeError, hideStackFrames };
+
+export default {
+ AbortError,
+ ERR_AMBIGUOUS_ARGUMENT,
+ ERR_ARG_NOT_ITERABLE,
+ ERR_ASSERTION,
+ ERR_ASYNC_CALLBACK,
+ ERR_ASYNC_TYPE,
+ ERR_BROTLI_INVALID_PARAM,
+ ERR_BUFFER_OUT_OF_BOUNDS,
+ ERR_BUFFER_TOO_LARGE,
+ ERR_CANNOT_WATCH_SIGINT,
+ ERR_CHILD_CLOSED_BEFORE_REPLY,
+ ERR_CHILD_PROCESS_IPC_REQUIRED,
+ ERR_CHILD_PROCESS_STDIO_MAXBUFFER,
+ ERR_CONSOLE_WRITABLE_STREAM,
+ ERR_CONTEXT_NOT_INITIALIZED,
+ ERR_CPU_USAGE,
+ ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED,
+ ERR_CRYPTO_ECDH_INVALID_FORMAT,
+ ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY,
+ ERR_CRYPTO_ENGINE_UNKNOWN,
+ ERR_CRYPTO_FIPS_FORCED,
+ ERR_CRYPTO_FIPS_UNAVAILABLE,
+ ERR_CRYPTO_HASH_FINALIZED,
+ ERR_CRYPTO_HASH_UPDATE_FAILED,
+ ERR_CRYPTO_INCOMPATIBLE_KEY,
+ ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS,
+ ERR_CRYPTO_INVALID_DIGEST,
+ ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE,
+ ERR_CRYPTO_INVALID_STATE,
+ ERR_CRYPTO_PBKDF2_ERROR,
+ ERR_CRYPTO_SCRYPT_INVALID_PARAMETER,
+ ERR_CRYPTO_SCRYPT_NOT_SUPPORTED,
+ ERR_CRYPTO_SIGN_KEY_REQUIRED,
+ ERR_DIR_CLOSED,
+ ERR_DIR_CONCURRENT_OPERATION,
+ ERR_DNS_SET_SERVERS_FAILED,
+ ERR_DOMAIN_CALLBACK_NOT_AVAILABLE,
+ ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE,
+ ERR_ENCODING_INVALID_ENCODED_DATA,
+ ERR_ENCODING_NOT_SUPPORTED,
+ ERR_EVAL_ESM_CANNOT_PRINT,
+ ERR_EVENT_RECURSION,
+ ERR_FALSY_VALUE_REJECTION,
+ ERR_FEATURE_UNAVAILABLE_ON_PLATFORM,
+ ERR_FS_EISDIR,
+ ERR_FS_FILE_TOO_LARGE,
+ ERR_FS_INVALID_SYMLINK_TYPE,
+ ERR_FS_RMDIR_ENOTDIR,
+ ERR_HTTP2_ALTSVC_INVALID_ORIGIN,
+ ERR_HTTP2_ALTSVC_LENGTH,
+ ERR_HTTP2_CONNECT_AUTHORITY,
+ ERR_HTTP2_CONNECT_PATH,
+ ERR_HTTP2_CONNECT_SCHEME,
+ ERR_HTTP2_GOAWAY_SESSION,
+ ERR_HTTP2_HEADERS_AFTER_RESPOND,
+ ERR_HTTP2_HEADERS_SENT,
+ ERR_HTTP2_HEADER_SINGLE_VALUE,
+ ERR_HTTP2_INFO_STATUS_NOT_ALLOWED,
+ ERR_HTTP2_INVALID_CONNECTION_HEADERS,
+ ERR_HTTP2_INVALID_HEADER_VALUE,
+ ERR_HTTP2_INVALID_INFO_STATUS,
+ ERR_HTTP2_INVALID_ORIGIN,
+ ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH,
+ ERR_HTTP2_INVALID_PSEUDOHEADER,
+ ERR_HTTP2_INVALID_SESSION,
+ ERR_HTTP2_INVALID_SETTING_VALUE,
+ ERR_HTTP2_INVALID_STREAM,
+ ERR_HTTP2_MAX_PENDING_SETTINGS_ACK,
+ ERR_HTTP2_NESTED_PUSH,
+ ERR_HTTP2_NO_SOCKET_MANIPULATION,
+ ERR_HTTP2_ORIGIN_LENGTH,
+ ERR_HTTP2_OUT_OF_STREAMS,
+ ERR_HTTP2_PAYLOAD_FORBIDDEN,
+ ERR_HTTP2_PING_CANCEL,
+ ERR_HTTP2_PING_LENGTH,
+ ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED,
+ ERR_HTTP2_PUSH_DISABLED,
+ ERR_HTTP2_SEND_FILE,
+ ERR_HTTP2_SEND_FILE_NOSEEK,
+ ERR_HTTP2_SESSION_ERROR,
+ ERR_HTTP2_SETTINGS_CANCEL,
+ ERR_HTTP2_SOCKET_BOUND,
+ ERR_HTTP2_SOCKET_UNBOUND,
+ ERR_HTTP2_STATUS_101,
+ ERR_HTTP2_STATUS_INVALID,
+ ERR_HTTP2_STREAM_CANCEL,
+ ERR_HTTP2_STREAM_ERROR,
+ ERR_HTTP2_STREAM_SELF_DEPENDENCY,
+ ERR_HTTP2_TRAILERS_ALREADY_SENT,
+ ERR_HTTP2_TRAILERS_NOT_READY,
+ ERR_HTTP2_UNSUPPORTED_PROTOCOL,
+ ERR_HTTP_HEADERS_SENT,
+ ERR_HTTP_INVALID_HEADER_VALUE,
+ ERR_HTTP_INVALID_STATUS_CODE,
+ ERR_HTTP_SOCKET_ENCODING,
+ ERR_HTTP_TRAILER_INVALID,
+ ERR_INCOMPATIBLE_OPTION_PAIR,
+ ERR_INPUT_TYPE_NOT_ALLOWED,
+ ERR_INSPECTOR_ALREADY_ACTIVATED,
+ ERR_INSPECTOR_ALREADY_CONNECTED,
+ ERR_INSPECTOR_CLOSED,
+ ERR_INSPECTOR_COMMAND,
+ ERR_INSPECTOR_NOT_ACTIVE,
+ ERR_INSPECTOR_NOT_AVAILABLE,
+ ERR_INSPECTOR_NOT_CONNECTED,
+ ERR_INSPECTOR_NOT_WORKER,
+ ERR_INTERNAL_ASSERTION,
+ ERR_INVALID_ADDRESS_FAMILY,
+ ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_ARG_TYPE_RANGE,
+ ERR_INVALID_ARG_VALUE,
+ ERR_INVALID_ARG_VALUE_RANGE,
+ ERR_INVALID_ASYNC_ID,
+ ERR_INVALID_BUFFER_SIZE,
+ ERR_INVALID_CHAR,
+ ERR_INVALID_CURSOR_POS,
+ ERR_INVALID_FD,
+ ERR_INVALID_FD_TYPE,
+ ERR_INVALID_FILE_URL_HOST,
+ ERR_INVALID_FILE_URL_PATH,
+ ERR_INVALID_HANDLE_TYPE,
+ ERR_INVALID_HTTP_TOKEN,
+ ERR_INVALID_IP_ADDRESS,
+ ERR_INVALID_MODULE_SPECIFIER,
+ ERR_INVALID_OPT_VALUE,
+ ERR_INVALID_OPT_VALUE_ENCODING,
+ ERR_INVALID_PACKAGE_CONFIG,
+ ERR_INVALID_PACKAGE_TARGET,
+ ERR_INVALID_PERFORMANCE_MARK,
+ ERR_INVALID_PROTOCOL,
+ ERR_INVALID_REPL_EVAL_CONFIG,
+ ERR_INVALID_REPL_INPUT,
+ ERR_INVALID_RETURN_PROPERTY,
+ ERR_INVALID_RETURN_PROPERTY_VALUE,
+ ERR_INVALID_RETURN_VALUE,
+ ERR_INVALID_SYNC_FORK_INPUT,
+ ERR_INVALID_THIS,
+ ERR_INVALID_TUPLE,
+ ERR_INVALID_URI,
+ ERR_INVALID_URL,
+ ERR_INVALID_URL_SCHEME,
+ ERR_IPC_CHANNEL_CLOSED,
+ ERR_IPC_DISCONNECTED,
+ ERR_IPC_ONE_PIPE,
+ ERR_IPC_SYNC_FORK,
+ ERR_MANIFEST_DEPENDENCY_MISSING,
+ ERR_MANIFEST_INTEGRITY_MISMATCH,
+ ERR_MANIFEST_INVALID_RESOURCE_FIELD,
+ ERR_MANIFEST_TDZ,
+ ERR_MANIFEST_UNKNOWN_ONERROR,
+ ERR_METHOD_NOT_IMPLEMENTED,
+ ERR_MISSING_ARGS,
+ ERR_MISSING_OPTION,
+ ERR_MODULE_NOT_FOUND,
+ ERR_MULTIPLE_CALLBACK,
+ ERR_NAPI_CONS_FUNCTION,
+ ERR_NAPI_INVALID_DATAVIEW_ARGS,
+ ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT,
+ ERR_NAPI_INVALID_TYPEDARRAY_LENGTH,
+ ERR_NO_CRYPTO,
+ ERR_NO_ICU,
+ ERR_OUT_OF_RANGE,
+ ERR_PACKAGE_IMPORT_NOT_DEFINED,
+ ERR_PACKAGE_PATH_NOT_EXPORTED,
+ ERR_QUICCLIENTSESSION_FAILED,
+ ERR_QUICCLIENTSESSION_FAILED_SETSOCKET,
+ ERR_QUICSESSION_DESTROYED,
+ ERR_QUICSESSION_INVALID_DCID,
+ ERR_QUICSESSION_UPDATEKEY,
+ ERR_QUICSOCKET_DESTROYED,
+ ERR_QUICSOCKET_INVALID_STATELESS_RESET_SECRET_LENGTH,
+ ERR_QUICSOCKET_LISTENING,
+ ERR_QUICSOCKET_UNBOUND,
+ ERR_QUICSTREAM_DESTROYED,
+ ERR_QUICSTREAM_INVALID_PUSH,
+ ERR_QUICSTREAM_OPEN_FAILED,
+ ERR_QUICSTREAM_UNSUPPORTED_PUSH,
+ ERR_QUIC_TLS13_REQUIRED,
+ ERR_SCRIPT_EXECUTION_INTERRUPTED,
+ ERR_SERVER_ALREADY_LISTEN,
+ ERR_SERVER_NOT_RUNNING,
+ ERR_SOCKET_ALREADY_BOUND,
+ ERR_SOCKET_BAD_BUFFER_SIZE,
+ ERR_SOCKET_BAD_PORT,
+ ERR_SOCKET_BAD_TYPE,
+ ERR_SOCKET_BUFFER_SIZE,
+ ERR_SOCKET_CLOSED,
+ ERR_SOCKET_DGRAM_IS_CONNECTED,
+ ERR_SOCKET_DGRAM_NOT_CONNECTED,
+ ERR_SOCKET_DGRAM_NOT_RUNNING,
+ ERR_SRI_PARSE,
+ ERR_STREAM_ALREADY_FINISHED,
+ ERR_STREAM_CANNOT_PIPE,
+ ERR_STREAM_DESTROYED,
+ ERR_STREAM_NULL_VALUES,
+ ERR_STREAM_PREMATURE_CLOSE,
+ ERR_STREAM_PUSH_AFTER_EOF,
+ ERR_STREAM_UNSHIFT_AFTER_END_EVENT,
+ ERR_STREAM_WRAP,
+ ERR_STREAM_WRITE_AFTER_END,
+ ERR_SYNTHETIC,
+ ERR_TLS_CERT_ALTNAME_INVALID,
+ ERR_TLS_DH_PARAM_SIZE,
+ ERR_TLS_HANDSHAKE_TIMEOUT,
+ ERR_TLS_INVALID_CONTEXT,
+ ERR_TLS_INVALID_PROTOCOL_VERSION,
+ ERR_TLS_INVALID_STATE,
+ ERR_TLS_PROTOCOL_VERSION_CONFLICT,
+ ERR_TLS_RENEGOTIATION_DISABLED,
+ ERR_TLS_REQUIRED_SERVER_NAME,
+ ERR_TLS_SESSION_ATTACK,
+ ERR_TLS_SNI_FROM_SERVER,
+ ERR_TRACE_EVENTS_CATEGORY_REQUIRED,
+ ERR_TRACE_EVENTS_UNAVAILABLE,
+ ERR_UNAVAILABLE_DURING_EXIT,
+ ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET,
+ ERR_UNESCAPED_CHARACTERS,
+ ERR_UNHANDLED_ERROR,
+ ERR_UNKNOWN_BUILTIN_MODULE,
+ ERR_UNKNOWN_CREDENTIAL,
+ ERR_UNKNOWN_ENCODING,
+ ERR_UNKNOWN_FILE_EXTENSION,
+ ERR_UNKNOWN_MODULE_FORMAT,
+ ERR_UNKNOWN_SIGNAL,
+ ERR_UNSUPPORTED_DIR_IMPORT,
+ ERR_UNSUPPORTED_ESM_URL_SCHEME,
+ ERR_USE_AFTER_CLOSE,
+ ERR_V8BREAKITERATOR,
+ ERR_VALID_PERFORMANCE_ENTRY_TYPE,
+ ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING,
+ ERR_VM_MODULE_ALREADY_LINKED,
+ ERR_VM_MODULE_CANNOT_CREATE_CACHED_DATA,
+ ERR_VM_MODULE_DIFFERENT_CONTEXT,
+ ERR_VM_MODULE_LINKING_ERRORED,
+ ERR_VM_MODULE_NOT_MODULE,
+ ERR_VM_MODULE_STATUS,
+ ERR_WASI_ALREADY_STARTED,
+ ERR_WORKER_INIT_FAILED,
+ ERR_WORKER_NOT_RUNNING,
+ ERR_WORKER_OUT_OF_MEMORY,
+ ERR_WORKER_UNSERIALIZABLE_ERROR,
+ ERR_WORKER_UNSUPPORTED_EXTENSION,
+ ERR_WORKER_UNSUPPORTED_OPERATION,
+ ERR_ZLIB_INITIALIZATION_FAILED,
+ NodeError,
+ NodeErrorAbstraction,
+ NodeRangeError,
+ NodeSyntaxError,
+ NodeTypeError,
+ NodeURIError,
+ aggregateTwoErrors,
+ codes,
+ connResetException,
+ denoErrorToNodeError,
+ dnsException,
+ errnoException,
+ errorMap,
+ exceptionWithHostPort,
+ genericNodeError,
+ hideStackFrames,
+ isStackOverflowError,
+ uvException,
+ uvExceptionWithHostPort,
+};
diff --git a/ext/node/polyfills/internal/event_target.mjs b/ext/node/polyfills/internal/event_target.mjs
new file mode 100644
index 000000000..d542fba94
--- /dev/null
+++ b/ext/node/polyfills/internal/event_target.mjs
@@ -0,0 +1,1111 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Node.js contributors. All rights reserved. MIT License.
+
+import {
+ ERR_EVENT_RECURSION,
+ ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_THIS,
+ ERR_MISSING_ARGS,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+import { validateObject, validateString } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { emitWarning } from "internal:deno_node/polyfills/process.ts";
+import { nextTick } from "internal:deno_node/polyfills/_next_tick.ts";
+import { Event as WebEvent, EventTarget as WebEventTarget } from "internal:deno_web/02_event.js";
+
+import {
+ customInspectSymbol,
+ kEmptyObject,
+ kEnumerableProperty,
+} from "internal:deno_node/polyfills/internal/util.mjs";
+import { inspect } from "internal:deno_node/polyfills/util.ts";
+
+const kIsEventTarget = Symbol.for("nodejs.event_target");
+const kIsNodeEventTarget = Symbol("kIsNodeEventTarget");
+
+import { EventEmitter } from "internal:deno_node/polyfills/events.ts";
+const {
+ kMaxEventTargetListeners,
+ kMaxEventTargetListenersWarned,
+} = EventEmitter;
+
+const kEvents = Symbol("kEvents");
+const kIsBeingDispatched = Symbol("kIsBeingDispatched");
+const kStop = Symbol("kStop");
+const kTarget = Symbol("kTarget");
+const kHandlers = Symbol("khandlers");
+const kWeakHandler = Symbol("kWeak");
+
+const kHybridDispatch = Symbol.for("nodejs.internal.kHybridDispatch");
+const kCreateEvent = Symbol("kCreateEvent");
+const kNewListener = Symbol("kNewListener");
+const kRemoveListener = Symbol("kRemoveListener");
+const kIsNodeStyleListener = Symbol("kIsNodeStyleListener");
+const kTrustEvent = Symbol("kTrustEvent");
+
+const kType = Symbol("type");
+const kDetail = Symbol("detail");
+const kDefaultPrevented = Symbol("defaultPrevented");
+const kCancelable = Symbol("cancelable");
+const kTimestamp = Symbol("timestamp");
+const kBubbles = Symbol("bubbles");
+const kComposed = Symbol("composed");
+const kPropagationStopped = Symbol("propagationStopped");
+
+function isEvent(value) {
+ return typeof value?.[kType] === "string";
+}
+
+class Event extends WebEvent {
+ /**
+ * @param {string} type
+ * @param {{
+ * bubbles?: boolean,
+ * cancelable?: boolean,
+ * composed?: boolean,
+ * }} [options]
+ */
+ constructor(type, options = null) {
+ super(type, options);
+ if (arguments.length === 0) {
+ throw new ERR_MISSING_ARGS("type");
+ }
+ validateObject(options, "options", {
+ allowArray: true,
+ allowFunction: true,
+ nullable: true,
+ });
+ const { cancelable, bubbles, composed } = { ...options };
+ this[kCancelable] = !!cancelable;
+ this[kBubbles] = !!bubbles;
+ this[kComposed] = !!composed;
+ this[kType] = `${type}`;
+ this[kDefaultPrevented] = false;
+ this[kTimestamp] = performance.now();
+ this[kPropagationStopped] = false;
+ this[kTarget] = null;
+ this[kIsBeingDispatched] = false;
+ }
+
+ [customInspectSymbol](depth, options) {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ const name = this.constructor.name;
+ if (depth < 0) {
+ return name;
+ }
+
+ const opts = Object.assign({}, options, {
+ depth: NumberIsInteger(options.depth) ? options.depth - 1 : options.depth,
+ });
+
+ return `${name} ${
+ inspect({
+ type: this[kType],
+ defaultPrevented: this[kDefaultPrevented],
+ cancelable: this[kCancelable],
+ timeStamp: this[kTimestamp],
+ }, opts)
+ }`;
+ }
+
+ stopImmediatePropagation() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ this[kStop] = true;
+ }
+
+ preventDefault() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ this[kDefaultPrevented] = true;
+ }
+
+ /**
+ * @type {EventTarget}
+ */
+ get target() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kTarget];
+ }
+
+ /**
+ * @type {EventTarget}
+ */
+ get currentTarget() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kTarget];
+ }
+
+ /**
+ * @type {EventTarget}
+ */
+ get srcElement() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kTarget];
+ }
+
+ /**
+ * @type {string}
+ */
+ get type() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kType];
+ }
+
+ /**
+ * @type {boolean}
+ */
+ get cancelable() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kCancelable];
+ }
+
+ /**
+ * @type {boolean}
+ */
+ get defaultPrevented() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kCancelable] && this[kDefaultPrevented];
+ }
+
+ /**
+ * @type {number}
+ */
+ get timeStamp() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kTimestamp];
+ }
+
+ // The following are non-op and unused properties/methods from Web API Event.
+ // These are not supported in Node.js and are provided purely for
+ // API completeness.
+ /**
+ * @returns {EventTarget[]}
+ */
+ composedPath() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kIsBeingDispatched] ? [this[kTarget]] : [];
+ }
+
+ /**
+ * @type {boolean}
+ */
+ get returnValue() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return !this.defaultPrevented;
+ }
+
+ /**
+ * @type {boolean}
+ */
+ get bubbles() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kBubbles];
+ }
+
+ /**
+ * @type {boolean}
+ */
+ get composed() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kComposed];
+ }
+
+ /**
+ * @type {number}
+ */
+ get eventPhase() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kIsBeingDispatched] ? Event.AT_TARGET : Event.NONE;
+ }
+
+ /**
+ * @type {boolean}
+ */
+ get cancelBubble() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ return this[kPropagationStopped];
+ }
+
+ /**
+ * @type {boolean}
+ */
+ set cancelBubble(value) {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ if (value) {
+ this.stopPropagation();
+ }
+ }
+
+ stopPropagation() {
+ if (!isEvent(this)) {
+ throw new ERR_INVALID_THIS("Event");
+ }
+ this[kPropagationStopped] = true;
+ }
+
+ static NONE = 0;
+ static CAPTURING_PHASE = 1;
+ static AT_TARGET = 2;
+ static BUBBLING_PHASE = 3;
+}
+
+Object.defineProperties(
+ Event.prototype,
+ {
+ [Symbol.toStringTag]: {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+ value: "Event",
+ },
+ stopImmediatePropagation: kEnumerableProperty,
+ preventDefault: kEnumerableProperty,
+ target: kEnumerableProperty,
+ currentTarget: kEnumerableProperty,
+ srcElement: kEnumerableProperty,
+ type: kEnumerableProperty,
+ cancelable: kEnumerableProperty,
+ defaultPrevented: kEnumerableProperty,
+ timeStamp: kEnumerableProperty,
+ composedPath: kEnumerableProperty,
+ returnValue: kEnumerableProperty,
+ bubbles: kEnumerableProperty,
+ composed: kEnumerableProperty,
+ eventPhase: kEnumerableProperty,
+ cancelBubble: kEnumerableProperty,
+ stopPropagation: kEnumerableProperty,
+ },
+);
+
+function isCustomEvent(value) {
+ return isEvent(value) && (value?.[kDetail] !== undefined);
+}
+
+class CustomEvent extends Event {
+ /**
+ * @constructor
+ * @param {string} type
+ * @param {{
+ * bubbles?: boolean,
+ * cancelable?: boolean,
+ * composed?: boolean,
+ * detail?: any,
+ * }} [options]
+ */
+ constructor(type, options = kEmptyObject) {
+ if (arguments.length === 0) {
+ throw new ERR_MISSING_ARGS("type");
+ }
+ super(type, options);
+ this[kDetail] = options?.detail ?? null;
+ }
+
+ /**
+ * @type {any}
+ */
+ get detail() {
+ if (!isCustomEvent(this)) {
+ throw new ERR_INVALID_THIS("CustomEvent");
+ }
+ return this[kDetail];
+ }
+}
+
+Object.defineProperties(CustomEvent.prototype, {
+ [Symbol.toStringTag]: {
+ __proto__: null,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+ value: "CustomEvent",
+ },
+ detail: kEnumerableProperty,
+});
+
+class NodeCustomEvent extends Event {
+ constructor(type, options) {
+ super(type, options);
+ if (options?.detail) {
+ this.detail = options.detail;
+ }
+ }
+}
+
+// Weak listener cleanup
+// This has to be lazy for snapshots to work
+let weakListenersState = null;
+// The resource needs to retain the callback so that it doesn't
+// get garbage collected now that it's weak.
+let objectToWeakListenerMap = null;
+function weakListeners() {
+ weakListenersState ??= new FinalizationRegistry(
+ (listener) => listener.remove(),
+ );
+ objectToWeakListenerMap ??= new WeakMap();
+ return { registry: weakListenersState, map: objectToWeakListenerMap };
+}
+
+// The listeners for an EventTarget are maintained as a linked list.
+// Unfortunately, the way EventTarget is defined, listeners are accounted
+// using the tuple [handler,capture], and even if we don't actually make
+// use of capture or bubbling, in order to be spec compliant we have to
+// take on the additional complexity of supporting it. Fortunately, using
+// the linked list makes dispatching faster, even if adding/removing is
+// slower.
+class Listener {
+ constructor(
+ previous,
+ listener,
+ once,
+ capture,
+ passive,
+ isNodeStyleListener,
+ weak,
+ ) {
+ this.next = undefined;
+ if (previous !== undefined) {
+ previous.next = this;
+ }
+ this.previous = previous;
+ this.listener = listener;
+ // TODO(benjamingr) these 4 can be 'flags' to save 3 slots
+ this.once = once;
+ this.capture = capture;
+ this.passive = passive;
+ this.isNodeStyleListener = isNodeStyleListener;
+ this.removed = false;
+ this.weak = Boolean(weak); // Don't retain the object
+
+ if (this.weak) {
+ this.callback = new WeakRef(listener);
+ weakListeners().registry.register(listener, this, this);
+ // Make the retainer retain the listener in a WeakMap
+ weakListeners().map.set(weak, listener);
+ this.listener = this.callback;
+ } else if (typeof listener === "function") {
+ this.callback = listener;
+ this.listener = listener;
+ } else {
+ this.callback = Function.prototype.bind.call(
+ listener.handleEvent,
+ listener,
+ );
+ this.listener = listener;
+ }
+ }
+
+ same(listener, capture) {
+ const myListener = this.weak ? this.listener.deref() : this.listener;
+ return myListener === listener && this.capture === capture;
+ }
+
+ remove() {
+ if (this.previous !== undefined) {
+ this.previous.next = this.next;
+ }
+ if (this.next !== undefined) {
+ this.next.previous = this.previous;
+ }
+ this.removed = true;
+ if (this.weak) {
+ weakListeners().registry.unregister(this);
+ }
+ }
+}
+
+function initEventTarget(self) {
+ self[kEvents] = new Map();
+ self[kMaxEventTargetListeners] = EventEmitter.defaultMaxListeners;
+ self[kMaxEventTargetListenersWarned] = false;
+}
+
+class EventTarget extends WebEventTarget {
+ // Used in checking whether an object is an EventTarget. This is a well-known
+ // symbol as EventTarget may be used cross-realm.
+ // Ref: https://github.com/nodejs/node/pull/33661
+ static [kIsEventTarget] = true;
+
+ constructor() {
+ super();
+ initEventTarget(this);
+ }
+
+ [kNewListener](size, type, _listener, _once, _capture, _passive, _weak) {
+ if (
+ this[kMaxEventTargetListeners] > 0 &&
+ size > this[kMaxEventTargetListeners] &&
+ !this[kMaxEventTargetListenersWarned]
+ ) {
+ this[kMaxEventTargetListenersWarned] = true;
+ // No error code for this since it is a Warning
+ // eslint-disable-next-line no-restricted-syntax
+ const w = new Error(
+ "Possible EventTarget memory leak detected. " +
+ `${size} ${type} listeners ` +
+ `added to ${inspect(this, { depth: -1 })}. Use ` +
+ "events.setMaxListeners() to increase limit",
+ );
+ w.name = "MaxListenersExceededWarning";
+ w.target = this;
+ w.type = type;
+ w.count = size;
+ emitWarning(w);
+ }
+ }
+ [kRemoveListener](_size, _type, _listener, _capture) {}
+
+ /**
+ * @callback EventTargetCallback
+ * @param {Event} event
+ */
+
+ /**
+ * @typedef {{ handleEvent: EventTargetCallback }} EventListener
+ */
+
+ /**
+ * @param {string} type
+ * @param {EventTargetCallback|EventListener} listener
+ * @param {{
+ * capture?: boolean,
+ * once?: boolean,
+ * passive?: boolean,
+ * signal?: AbortSignal
+ * }} [options]
+ */
+ addEventListener(type, listener, options = {}) {
+ if (!isEventTarget(this)) {
+ throw new ERR_INVALID_THIS("EventTarget");
+ }
+ if (arguments.length < 2) {
+ throw new ERR_MISSING_ARGS("type", "listener");
+ }
+
+ // We validateOptions before the shouldAddListeners check because the spec
+ // requires us to hit getters.
+ const {
+ once,
+ capture,
+ passive,
+ signal,
+ isNodeStyleListener,
+ weak,
+ } = validateEventListenerOptions(options);
+
+ if (!shouldAddListener(listener)) {
+ // The DOM silently allows passing undefined as a second argument
+ // No error code for this since it is a Warning
+ // eslint-disable-next-line no-restricted-syntax
+ const w = new Error(
+ `addEventListener called with ${listener}` +
+ " which has no effect.",
+ );
+ w.name = "AddEventListenerArgumentTypeWarning";
+ w.target = this;
+ w.type = type;
+ emitWarning(w);
+ return;
+ }
+ type = String(type);
+
+ if (signal) {
+ if (signal.aborted) {
+ return;
+ }
+ // TODO(benjamingr) make this weak somehow? ideally the signal would
+ // not prevent the event target from GC.
+ signal.addEventListener("abort", () => {
+ this.removeEventListener(type, listener, options);
+ }, { once: true, [kWeakHandler]: this });
+ }
+
+ let root = this[kEvents].get(type);
+
+ if (root === undefined) {
+ root = { size: 1, next: undefined };
+ // This is the first handler in our linked list.
+ new Listener(
+ root,
+ listener,
+ once,
+ capture,
+ passive,
+ isNodeStyleListener,
+ weak,
+ );
+ this[kNewListener](
+ root.size,
+ type,
+ listener,
+ once,
+ capture,
+ passive,
+ weak,
+ );
+ this[kEvents].set(type, root);
+ return;
+ }
+
+ let handler = root.next;
+ let previous = root;
+
+ // We have to walk the linked list to see if we have a match
+ while (handler !== undefined && !handler.same(listener, capture)) {
+ previous = handler;
+ handler = handler.next;
+ }
+
+ if (handler !== undefined) { // Duplicate! Ignore
+ return;
+ }
+
+ new Listener(
+ previous,
+ listener,
+ once,
+ capture,
+ passive,
+ isNodeStyleListener,
+ weak,
+ );
+ root.size++;
+ this[kNewListener](root.size, type, listener, once, capture, passive, weak);
+ }
+
+ /**
+ * @param {string} type
+ * @param {EventTargetCallback|EventListener} listener
+ * @param {{
+ * capture?: boolean,
+ * }} [options]
+ */
+ removeEventListener(type, listener, options = {}) {
+ if (!isEventTarget(this)) {
+ throw new ERR_INVALID_THIS("EventTarget");
+ }
+ if (!shouldAddListener(listener)) {
+ return;
+ }
+
+ type = String(type);
+ const capture = options?.capture === true;
+
+ const root = this[kEvents].get(type);
+ if (root === undefined || root.next === undefined) {
+ return;
+ }
+
+ let handler = root.next;
+ while (handler !== undefined) {
+ if (handler.same(listener, capture)) {
+ handler.remove();
+ root.size--;
+ if (root.size === 0) {
+ this[kEvents].delete(type);
+ }
+ this[kRemoveListener](root.size, type, listener, capture);
+ break;
+ }
+ handler = handler.next;
+ }
+ }
+
+ /**
+ * @param {Event} event
+ */
+ dispatchEvent(event) {
+ if (!isEventTarget(this)) {
+ throw new ERR_INVALID_THIS("EventTarget");
+ }
+
+ if (!(event instanceof globalThis.Event)) {
+ throw new ERR_INVALID_ARG_TYPE("event", "Event", event);
+ }
+
+ if (event[kIsBeingDispatched]) {
+ throw new ERR_EVENT_RECURSION(event.type);
+ }
+
+ this[kHybridDispatch](event, event.type, event);
+
+ return event.defaultPrevented !== true;
+ }
+
+ [kHybridDispatch](nodeValue, type, event) {
+ const createEvent = () => {
+ if (event === undefined) {
+ event = this[kCreateEvent](nodeValue, type);
+ event[kTarget] = this;
+ event[kIsBeingDispatched] = true;
+ }
+ return event;
+ };
+ if (event !== undefined) {
+ event[kTarget] = this;
+ event[kIsBeingDispatched] = true;
+ }
+
+ const root = this[kEvents].get(type);
+ if (root === undefined || root.next === undefined) {
+ if (event !== undefined) {
+ event[kIsBeingDispatched] = false;
+ }
+ return true;
+ }
+
+ let handler = root.next;
+ let next;
+
+ while (
+ handler !== undefined &&
+ (handler.passive || event?.[kStop] !== true)
+ ) {
+ // Cache the next item in case this iteration removes the current one
+ next = handler.next;
+
+ if (handler.removed) {
+ // Deal with the case an event is removed while event handlers are
+ // Being processed (removeEventListener called from a listener)
+ handler = next;
+ continue;
+ }
+ if (handler.once) {
+ handler.remove();
+ root.size--;
+ const { listener, capture } = handler;
+ this[kRemoveListener](root.size, type, listener, capture);
+ }
+
+ try {
+ let arg;
+ if (handler.isNodeStyleListener) {
+ arg = nodeValue;
+ } else {
+ arg = createEvent();
+ }
+ const callback = handler.weak
+ ? handler.callback.deref()
+ : handler.callback;
+ let result;
+ if (callback) {
+ result = callback.call(this, arg);
+ if (!handler.isNodeStyleListener) {
+ arg[kIsBeingDispatched] = false;
+ }
+ }
+ if (result !== undefined && result !== null) {
+ addCatch(result);
+ }
+ } catch (err) {
+ emitUncaughtException(err);
+ }
+
+ handler = next;
+ }
+
+ if (event !== undefined) {
+ event[kIsBeingDispatched] = false;
+ }
+ }
+
+ [kCreateEvent](nodeValue, type) {
+ return new NodeCustomEvent(type, { detail: nodeValue });
+ }
+ [customInspectSymbol](depth, options) {
+ if (!isEventTarget(this)) {
+ throw new ERR_INVALID_THIS("EventTarget");
+ }
+ const name = this.constructor.name;
+ if (depth < 0) {
+ return name;
+ }
+
+ const opts = ObjectAssign({}, options, {
+ depth: Number.isInteger(options.depth)
+ ? options.depth - 1
+ : options.depth,
+ });
+
+ return `${name} ${inspect({}, opts)}`;
+ }
+}
+
+Object.defineProperties(EventTarget.prototype, {
+ addEventListener: kEnumerableProperty,
+ removeEventListener: kEnumerableProperty,
+ dispatchEvent: kEnumerableProperty,
+ [Symbol.toStringTag]: {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+ value: "EventTarget",
+ },
+});
+
+function initNodeEventTarget(self) {
+ initEventTarget(self);
+}
+
+class NodeEventTarget extends EventTarget {
+ static [kIsNodeEventTarget] = true;
+ static defaultMaxListeners = 10;
+
+ constructor() {
+ super();
+ initNodeEventTarget(this);
+ }
+
+ /**
+ * @param {number} n
+ */
+ setMaxListeners(n) {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ EventEmitter.setMaxListeners(n, this);
+ }
+
+ /**
+ * @returns {number}
+ */
+ getMaxListeners() {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ return this[kMaxEventTargetListeners];
+ }
+
+ /**
+ * @returns {string[]}
+ */
+ eventNames() {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ return Array.from(this[kEvents].keys());
+ }
+
+ /**
+ * @param {string} [type]
+ * @returns {number}
+ */
+ listenerCount(type) {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ const root = this[kEvents].get(String(type));
+ return root !== undefined ? root.size : 0;
+ }
+
+ /**
+ * @param {string} type
+ * @param {EventTargetCallback|EventListener} listener
+ * @param {{
+ * capture?: boolean,
+ * }} [options]
+ * @returns {NodeEventTarget}
+ */
+ off(type, listener, options) {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ this.removeEventListener(type, listener, options);
+ return this;
+ }
+
+ /**
+ * @param {string} type
+ * @param {EventTargetCallback|EventListener} listener
+ * @param {{
+ * capture?: boolean,
+ * }} [options]
+ * @returns {NodeEventTarget}
+ */
+ removeListener(type, listener, options) {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ this.removeEventListener(type, listener, options);
+ return this;
+ }
+
+ /**
+ * @param {string} type
+ * @param {EventTargetCallback|EventListener} listener
+ * @returns {NodeEventTarget}
+ */
+ on(type, listener) {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ this.addEventListener(type, listener, { [kIsNodeStyleListener]: true });
+ return this;
+ }
+
+ /**
+ * @param {string} type
+ * @param {EventTargetCallback|EventListener} listener
+ * @returns {NodeEventTarget}
+ */
+ addListener(type, listener) {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ this.addEventListener(type, listener, { [kIsNodeStyleListener]: true });
+ return this;
+ }
+
+ /**
+ * @param {string} type
+ * @param {any} arg
+ * @returns {boolean}
+ */
+ emit(type, arg) {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ validateString(type, "type");
+ const hadListeners = this.listenerCount(type) > 0;
+ this[kHybridDispatch](arg, type);
+ return hadListeners;
+ }
+
+ /**
+ * @param {string} type
+ * @param {EventTargetCallback|EventListener} listener
+ * @returns {NodeEventTarget}
+ */
+ once(type, listener) {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ this.addEventListener(type, listener, {
+ once: true,
+ [kIsNodeStyleListener]: true,
+ });
+ return this;
+ }
+
+ /**
+ * @param {string} type
+ * @returns {NodeEventTarget}
+ */
+ removeAllListeners(type) {
+ if (!isNodeEventTarget(this)) {
+ throw new ERR_INVALID_THIS("NodeEventTarget");
+ }
+ if (type !== undefined) {
+ this[kEvents].delete(String(type));
+ } else {
+ this[kEvents].clear();
+ }
+
+ return this;
+ }
+}
+
+Object.defineProperties(NodeEventTarget.prototype, {
+ setMaxListeners: kEnumerableProperty,
+ getMaxListeners: kEnumerableProperty,
+ eventNames: kEnumerableProperty,
+ listenerCount: kEnumerableProperty,
+ off: kEnumerableProperty,
+ removeListener: kEnumerableProperty,
+ on: kEnumerableProperty,
+ addListener: kEnumerableProperty,
+ once: kEnumerableProperty,
+ emit: kEnumerableProperty,
+ removeAllListeners: kEnumerableProperty,
+});
+
+// EventTarget API
+
+function shouldAddListener(listener) {
+ if (
+ typeof listener === "function" ||
+ typeof listener?.handleEvent === "function"
+ ) {
+ return true;
+ }
+
+ if (listener == null) {
+ return false;
+ }
+
+ throw new ERR_INVALID_ARG_TYPE("listener", "EventListener", listener);
+}
+
+function validateEventListenerOptions(options) {
+ if (typeof options === "boolean") {
+ return { capture: options };
+ }
+
+ if (options === null) {
+ return {};
+ }
+ validateObject(options, "options", {
+ allowArray: true,
+ allowFunction: true,
+ });
+ return {
+ once: Boolean(options.once),
+ capture: Boolean(options.capture),
+ passive: Boolean(options.passive),
+ signal: options.signal,
+ weak: options[kWeakHandler],
+ isNodeStyleListener: Boolean(options[kIsNodeStyleListener]),
+ };
+}
+
+function isEventTarget(obj) {
+ return obj instanceof globalThis.EventTarget;
+}
+
+function isNodeEventTarget(obj) {
+ return obj?.constructor?.[kIsNodeEventTarget];
+}
+
+function addCatch(promise) {
+ const then = promise.then;
+ if (typeof then === "function") {
+ then.call(promise, undefined, function (err) {
+ // The callback is called with nextTick to avoid a follow-up
+ // rejection from this promise.
+ emitUncaughtException(err);
+ });
+ }
+}
+
+function emitUncaughtException(err) {
+ nextTick(() => {
+ throw err;
+ });
+}
+
+function makeEventHandler(handler) {
+ // Event handlers are dispatched in the order they were first set
+ // See https://github.com/nodejs/node/pull/35949#issuecomment-722496598
+ function eventHandler(...args) {
+ if (typeof eventHandler.handler !== "function") {
+ return;
+ }
+ return Reflect.apply(eventHandler.handler, this, args);
+ }
+ eventHandler.handler = handler;
+ return eventHandler;
+}
+
+function defineEventHandler(emitter, name) {
+ // 8.1.5.1 Event handlers - basically `on[eventName]` attributes
+ Object.defineProperty(emitter, `on${name}`, {
+ get() {
+ return this[kHandlers]?.get(name)?.handler ?? null;
+ },
+ set(value) {
+ if (!this[kHandlers]) {
+ this[kHandlers] = new Map();
+ }
+ let wrappedHandler = this[kHandlers]?.get(name);
+ if (wrappedHandler) {
+ if (typeof wrappedHandler.handler === "function") {
+ this[kEvents].get(name).size--;
+ const size = this[kEvents].get(name).size;
+ this[kRemoveListener](size, name, wrappedHandler.handler, false);
+ }
+ wrappedHandler.handler = value;
+ if (typeof wrappedHandler.handler === "function") {
+ this[kEvents].get(name).size++;
+ const size = this[kEvents].get(name).size;
+ this[kNewListener](size, name, value, false, false, false, false);
+ }
+ } else {
+ wrappedHandler = makeEventHandler(value);
+ this.addEventListener(name, wrappedHandler);
+ }
+ this[kHandlers].set(name, wrappedHandler);
+ },
+ configurable: true,
+ enumerable: true,
+ });
+}
+
+const EventEmitterMixin = (Superclass) => {
+ class MixedEventEmitter extends Superclass {
+ constructor(...args) {
+ super(...args);
+ EventEmitter.call(this);
+ }
+ }
+ const protoProps = Object.getOwnPropertyDescriptors(EventEmitter.prototype);
+ delete protoProps.constructor;
+ Object.defineProperties(MixedEventEmitter.prototype, protoProps);
+ return MixedEventEmitter;
+};
+
+export {
+ CustomEvent,
+ defineEventHandler,
+ Event,
+ EventEmitterMixin,
+ EventTarget,
+ initEventTarget,
+ initNodeEventTarget,
+ isEventTarget,
+ kCreateEvent,
+ kEvents,
+ kNewListener,
+ kRemoveListener,
+ kTrustEvent,
+ kWeakHandler,
+ NodeEventTarget,
+};
+
+export default {
+ CustomEvent,
+ Event,
+ EventEmitterMixin,
+ EventTarget,
+ NodeEventTarget,
+ defineEventHandler,
+ initEventTarget,
+ initNodeEventTarget,
+ kCreateEvent,
+ kNewListener,
+ kTrustEvent,
+ kRemoveListener,
+ kEvents,
+ kWeakHandler,
+ isEventTarget,
+};
diff --git a/ext/node/polyfills/internal/fixed_queue.ts b/ext/node/polyfills/internal/fixed_queue.ts
new file mode 100644
index 000000000..e6b8db70f
--- /dev/null
+++ b/ext/node/polyfills/internal/fixed_queue.ts
@@ -0,0 +1,123 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+
+// Currently optimal queue size, tested on V8 6.0 - 6.6. Must be power of two.
+const kSize = 2048;
+const kMask = kSize - 1;
+
+// The FixedQueue is implemented as a singly-linked list of fixed-size
+// circular buffers. It looks something like this:
+//
+// head tail
+// | |
+// v v
+// +-----------+ <-----\ +-----------+ <------\ +-----------+
+// | [null] | \----- | next | \------- | next |
+// +-----------+ +-----------+ +-----------+
+// | item | <-- bottom | item | <-- bottom | [empty] |
+// | item | | item | | [empty] |
+// | item | | item | | [empty] |
+// | item | | item | | [empty] |
+// | item | | item | bottom --> | item |
+// | item | | item | | item |
+// | ... | | ... | | ... |
+// | item | | item | | item |
+// | item | | item | | item |
+// | [empty] | <-- top | item | | item |
+// | [empty] | | item | | item |
+// | [empty] | | [empty] | <-- top top --> | [empty] |
+// +-----------+ +-----------+ +-----------+
+//
+// Or, if there is only one circular buffer, it looks something
+// like either of these:
+//
+// head tail head tail
+// | | | |
+// v v v v
+// +-----------+ +-----------+
+// | [null] | | [null] |
+// +-----------+ +-----------+
+// | [empty] | | item |
+// | [empty] | | item |
+// | item | <-- bottom top --> | [empty] |
+// | item | | [empty] |
+// | [empty] | <-- top bottom --> | item |
+// | [empty] | | item |
+// +-----------+ +-----------+
+//
+// Adding a value means moving `top` forward by one, removing means
+// moving `bottom` forward by one. After reaching the end, the queue
+// wraps around.
+//
+// When `top === bottom` the current queue is empty and when
+// `top + 1 === bottom` it's full. This wastes a single space of storage
+// but allows much quicker checks.
+
+class FixedCircularBuffer {
+ bottom: number;
+ top: number;
+ list: undefined | Array<unknown>;
+ next: FixedCircularBuffer | null;
+
+ constructor() {
+ this.bottom = 0;
+ this.top = 0;
+ this.list = new Array(kSize);
+ this.next = null;
+ }
+
+ isEmpty() {
+ return this.top === this.bottom;
+ }
+
+ isFull() {
+ return ((this.top + 1) & kMask) === this.bottom;
+ }
+
+ push(data: unknown) {
+ this.list![this.top] = data;
+ this.top = (this.top + 1) & kMask;
+ }
+
+ shift() {
+ const nextItem = this.list![this.bottom];
+ if (nextItem === undefined) {
+ return null;
+ }
+ this.list![this.bottom] = undefined;
+ this.bottom = (this.bottom + 1) & kMask;
+ return nextItem;
+ }
+}
+
+export class FixedQueue {
+ head: FixedCircularBuffer;
+ tail: FixedCircularBuffer;
+
+ constructor() {
+ this.head = this.tail = new FixedCircularBuffer();
+ }
+
+ isEmpty() {
+ return this.head.isEmpty();
+ }
+
+ push(data: unknown) {
+ if (this.head.isFull()) {
+ // Head is full: Creates a new queue, sets the old queue's `.next` to it,
+ // and sets it as the new main queue.
+ this.head = this.head.next = new FixedCircularBuffer();
+ }
+ this.head.push(data);
+ }
+
+ shift() {
+ const tail = this.tail;
+ const next = tail.shift();
+ if (tail.isEmpty() && tail.next !== null) {
+ // If there is another queue, it forms the new tail.
+ this.tail = tail.next;
+ }
+ return next;
+ }
+}
diff --git a/ext/node/polyfills/internal/freelist.ts b/ext/node/polyfills/internal/freelist.ts
new file mode 100644
index 000000000..8faba8e68
--- /dev/null
+++ b/ext/node/polyfills/internal/freelist.ts
@@ -0,0 +1,30 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+type Fn<T> = (...args: unknown[]) => T;
+export class FreeList<T> {
+ name: string;
+ ctor: Fn<T>;
+ max: number;
+ list: Array<T>;
+ constructor(name: string, max: number, ctor: Fn<T>) {
+ this.name = name;
+ this.ctor = ctor;
+ this.max = max;
+ this.list = [];
+ }
+
+ alloc(): T {
+ return this.list.length > 0
+ ? this.list.pop()
+ : Reflect.apply(this.ctor, this, arguments);
+ }
+
+ free(obj: T) {
+ if (this.list.length < this.max) {
+ this.list.push(obj);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/ext/node/polyfills/internal/fs/streams.d.ts b/ext/node/polyfills/internal/fs/streams.d.ts
new file mode 100644
index 000000000..9e70c2431
--- /dev/null
+++ b/ext/node/polyfills/internal/fs/streams.d.ts
@@ -0,0 +1,326 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright DefinitelyTyped contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file no-explicit-any
+
+import * as stream from "internal:deno_node/polyfills/_stream.d.ts";
+import * as promises from "internal:deno_node/polyfills/fs/promises.ts";
+
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ BufferEncoding,
+ ErrnoException,
+} from "internal:deno_node/polyfills/_global.d.ts";
+
+type PathLike = string | Buffer | URL;
+
+/**
+ * Instances of `fs.ReadStream` are created and returned using the {@link createReadStream} function.
+ * @since v0.1.93
+ */
+export class ReadStream extends stream.Readable {
+ close(callback?: (err?: ErrnoException | null) => void): void;
+ /**
+ * The number of bytes that have been read so far.
+ * @since v6.4.0
+ */
+ bytesRead: number;
+ /**
+ * The path to the file the stream is reading from as specified in the first
+ * argument to `fs.createReadStream()`. If `path` is passed as a string, then`readStream.path` will be a string. If `path` is passed as a `Buffer`, then`readStream.path` will be a
+ * `Buffer`. If `fd` is specified, then`readStream.path` will be `undefined`.
+ * @since v0.1.93
+ */
+ path: string | Buffer;
+ /**
+ * This property is `true` if the underlying file has not been opened yet,
+ * i.e. before the `'ready'` event is emitted.
+ * @since v11.2.0, v10.16.0
+ */
+ pending: boolean;
+ /**
+ * events.EventEmitter
+ * 1. open
+ * 2. close
+ * 3. ready
+ */
+ addListener(event: "close", listener: () => void): this;
+ addListener(event: "data", listener: (chunk: Buffer | string) => void): this;
+ addListener(event: "end", listener: () => void): this;
+ addListener(event: "error", listener: (err: Error) => void): this;
+ addListener(event: "open", listener: (fd: number) => void): this;
+ addListener(event: "pause", listener: () => void): this;
+ addListener(event: "readable", listener: () => void): this;
+ addListener(event: "ready", listener: () => void): this;
+ addListener(event: "resume", listener: () => void): this;
+ addListener(event: string | symbol, listener: (...args: any[]) => void): this;
+ on(event: "close", listener: () => void): this;
+ on(event: "data", listener: (chunk: Buffer | string) => void): this;
+ on(event: "end", listener: () => void): this;
+ on(event: "error", listener: (err: Error) => void): this;
+ on(event: "open", listener: (fd: number) => void): this;
+ on(event: "pause", listener: () => void): this;
+ on(event: "readable", listener: () => void): this;
+ on(event: "ready", listener: () => void): this;
+ on(event: "resume", listener: () => void): this;
+ on(event: string | symbol, listener: (...args: any[]) => void): this;
+ once(event: "close", listener: () => void): this;
+ once(event: "data", listener: (chunk: Buffer | string) => void): this;
+ once(event: "end", listener: () => void): this;
+ once(event: "error", listener: (err: Error) => void): this;
+ once(event: "open", listener: (fd: number) => void): this;
+ once(event: "pause", listener: () => void): this;
+ once(event: "readable", listener: () => void): this;
+ once(event: "ready", listener: () => void): this;
+ once(event: "resume", listener: () => void): this;
+ once(event: string | symbol, listener: (...args: any[]) => void): this;
+ prependListener(event: "close", listener: () => void): this;
+ prependListener(
+ event: "data",
+ listener: (chunk: Buffer | string) => void,
+ ): this;
+ prependListener(event: "end", listener: () => void): this;
+ prependListener(event: "error", listener: (err: Error) => void): this;
+ prependListener(event: "open", listener: (fd: number) => void): this;
+ prependListener(event: "pause", listener: () => void): this;
+ prependListener(event: "readable", listener: () => void): this;
+ prependListener(event: "ready", listener: () => void): this;
+ prependListener(event: "resume", listener: () => void): this;
+ prependListener(
+ event: string | symbol,
+ listener: (...args: any[]) => void,
+ ): this;
+ prependOnceListener(event: "close", listener: () => void): this;
+ prependOnceListener(
+ event: "data",
+ listener: (chunk: Buffer | string) => void,
+ ): this;
+ prependOnceListener(event: "end", listener: () => void): this;
+ prependOnceListener(event: "error", listener: (err: Error) => void): this;
+ prependOnceListener(event: "open", listener: (fd: number) => void): this;
+ prependOnceListener(event: "pause", listener: () => void): this;
+ prependOnceListener(event: "readable", listener: () => void): this;
+ prependOnceListener(event: "ready", listener: () => void): this;
+ prependOnceListener(event: "resume", listener: () => void): this;
+ prependOnceListener(
+ event: string | symbol,
+ listener: (...args: any[]) => void,
+ ): this;
+}
+/**
+ * * Extends `stream.Writable`
+ *
+ * Instances of `fs.WriteStream` are created and returned using the {@link createWriteStream} function.
+ * @since v0.1.93
+ */
+export class WriteStream extends stream.Writable {
+ /**
+ * Closes `writeStream`. Optionally accepts a
+ * callback that will be executed once the `writeStream`is closed.
+ * @since v0.9.4
+ */
+ close(callback?: (err?: ErrnoException | null) => void): void;
+ /**
+ * The number of bytes written so far. Does not include data that is still queued
+ * for writing.
+ * @since v0.4.7
+ */
+ bytesWritten: number;
+ /**
+ * The path to the file the stream is writing to as specified in the first
+ * argument to {@link createWriteStream}. If `path` is passed as a string, then`writeStream.path` will be a string. If `path` is passed as a `Buffer`, then`writeStream.path` will be a
+ * `Buffer`.
+ * @since v0.1.93
+ */
+ path: string | Buffer;
+ /**
+ * This property is `true` if the underlying file has not been opened yet,
+ * i.e. before the `'ready'` event is emitted.
+ * @since v11.2.0
+ */
+ pending: boolean;
+ /**
+ * events.EventEmitter
+ * 1. open
+ * 2. close
+ * 3. ready
+ */
+ addListener(event: "close", listener: () => void): this;
+ addListener(event: "drain", listener: () => void): this;
+ addListener(event: "error", listener: (err: Error) => void): this;
+ addListener(event: "finish", listener: () => void): this;
+ addListener(event: "open", listener: (fd: number) => void): this;
+ addListener(event: "pipe", listener: (src: stream.Readable) => void): this;
+ addListener(event: "ready", listener: () => void): this;
+ addListener(event: "unpipe", listener: (src: stream.Readable) => void): this;
+ addListener(event: string | symbol, listener: (...args: any[]) => void): this;
+ on(event: "close", listener: () => void): this;
+ on(event: "drain", listener: () => void): this;
+ on(event: "error", listener: (err: Error) => void): this;
+ on(event: "finish", listener: () => void): this;
+ on(event: "open", listener: (fd: number) => void): this;
+ on(event: "pipe", listener: (src: stream.Readable) => void): this;
+ on(event: "ready", listener: () => void): this;
+ on(event: "unpipe", listener: (src: stream.Readable) => void): this;
+ on(event: string | symbol, listener: (...args: any[]) => void): this;
+ once(event: "close", listener: () => void): this;
+ once(event: "drain", listener: () => void): this;
+ once(event: "error", listener: (err: Error) => void): this;
+ once(event: "finish", listener: () => void): this;
+ once(event: "open", listener: (fd: number) => void): this;
+ once(event: "pipe", listener: (src: stream.Readable) => void): this;
+ once(event: "ready", listener: () => void): this;
+ once(event: "unpipe", listener: (src: stream.Readable) => void): this;
+ once(event: string | symbol, listener: (...args: any[]) => void): this;
+ prependListener(event: "close", listener: () => void): this;
+ prependListener(event: "drain", listener: () => void): this;
+ prependListener(event: "error", listener: (err: Error) => void): this;
+ prependListener(event: "finish", listener: () => void): this;
+ prependListener(event: "open", listener: (fd: number) => void): this;
+ prependListener(
+ event: "pipe",
+ listener: (src: stream.Readable) => void,
+ ): this;
+ prependListener(event: "ready", listener: () => void): this;
+ prependListener(
+ event: "unpipe",
+ listener: (src: stream.Readable) => void,
+ ): this;
+ prependListener(
+ event: string | symbol,
+ listener: (...args: any[]) => void,
+ ): this;
+ prependOnceListener(event: "close", listener: () => void): this;
+ prependOnceListener(event: "drain", listener: () => void): this;
+ prependOnceListener(event: "error", listener: (err: Error) => void): this;
+ prependOnceListener(event: "finish", listener: () => void): this;
+ prependOnceListener(event: "open", listener: (fd: number) => void): this;
+ prependOnceListener(
+ event: "pipe",
+ listener: (src: stream.Readable) => void,
+ ): this;
+ prependOnceListener(event: "ready", listener: () => void): this;
+ prependOnceListener(
+ event: "unpipe",
+ listener: (src: stream.Readable) => void,
+ ): this;
+ prependOnceListener(
+ event: string | symbol,
+ listener: (...args: any[]) => void,
+ ): this;
+}
+interface StreamOptions {
+ flags?: string | undefined;
+ encoding?: BufferEncoding | undefined;
+ // @ts-ignore promises.FileHandle is not implemented
+ fd?: number | promises.FileHandle | undefined;
+ mode?: number | undefined;
+ autoClose?: boolean | undefined;
+ /**
+ * @default false
+ */
+ emitClose?: boolean | undefined;
+ start?: number | undefined;
+ highWaterMark?: number | undefined;
+}
+interface ReadStreamOptions extends StreamOptions {
+ end?: number | undefined;
+}
+/**
+ * Unlike the 16 kb default `highWaterMark` for a `stream.Readable`, the stream
+ * returned by this method has a default `highWaterMark` of 64 kb.
+ *
+ * `options` can include `start` and `end` values to read a range of bytes from
+ * the file instead of the entire file. Both `start` and `end` are inclusive and
+ * start counting at 0, allowed values are in the
+ * \[0, [`Number.MAX_SAFE_INTEGER`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER)\] range. If `fd` is specified and `start` is
+ * omitted or `undefined`, `fs.createReadStream()` reads sequentially from the
+ * current file position. The `encoding` can be any one of those accepted by `Buffer`.
+ *
+ * If `fd` is specified, `ReadStream` will ignore the `path` argument and will use
+ * the specified file descriptor. This means that no `'open'` event will be
+ * emitted. `fd` should be blocking; non-blocking `fd`s should be passed to `net.Socket`.
+ *
+ * If `fd` points to a character device that only supports blocking reads
+ * (such as keyboard or sound card), read operations do not finish until data is
+ * available. This can prevent the process from exiting and the stream from
+ * closing naturally.
+ *
+ * By default, the stream will emit a `'close'` event after it has been
+ * destroyed. Set the `emitClose` option to `false` to change this behavior.
+ *
+ * By providing the `fs` option, it is possible to override the corresponding `fs`implementations for `open`, `read`, and `close`. When providing the `fs` option,
+ * an override for `read` is required. If no `fd` is provided, an override for`open` is also required. If `autoClose` is `true`, an override for `close` is
+ * also required.
+ *
+ * ```js
+ * import { createReadStream } from "internal:deno_node/polyfills/internal/fs/fs";
+ *
+ * // Create a stream from some character device.
+ * const stream = createReadStream('/dev/input/event0');
+ * setTimeout(() => {
+ * stream.close(); // This may not close the stream.
+ * // Artificially marking end-of-stream, as if the underlying resource had
+ * // indicated end-of-file by itself, allows the stream to close.
+ * // This does not cancel pending read operations, and if there is such an
+ * // operation, the process may still not be able to exit successfully
+ * // until it finishes.
+ * stream.push(null);
+ * stream.read(0);
+ * }, 100);
+ * ```
+ *
+ * If `autoClose` is false, then the file descriptor won't be closed, even if
+ * there's an error. It is the application's responsibility to close it and make
+ * sure there's no file descriptor leak. If `autoClose` is set to true (default
+ * behavior), on `'error'` or `'end'` the file descriptor will be closed
+ * automatically.
+ *
+ * `mode` sets the file mode (permission and sticky bits), but only if the
+ * file was created.
+ *
+ * An example to read the last 10 bytes of a file which is 100 bytes long:
+ *
+ * ```js
+ * import { createReadStream } from "internal:deno_node/polyfills/internal/fs/fs";
+ *
+ * createReadStream('sample.txt', { start: 90, end: 99 });
+ * ```
+ *
+ * If `options` is a string, then it specifies the encoding.
+ * @since v0.1.31
+ */
+export function createReadStream(
+ path: PathLike,
+ options?: BufferEncoding | ReadStreamOptions,
+): ReadStream;
+/**
+ * `options` may also include a `start` option to allow writing data at some
+ * position past the beginning of the file, allowed values are in the
+ * \[0, [`Number.MAX_SAFE_INTEGER`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER)\] range. Modifying a file rather than
+ * replacing it may require the `flags` option to be set to `r+` rather than the
+ * default `w`. The `encoding` can be any one of those accepted by `Buffer`.
+ *
+ * If `autoClose` is set to true (default behavior) on `'error'` or `'finish'`the file descriptor will be closed automatically. If `autoClose` is false,
+ * then the file descriptor won't be closed, even if there's an error.
+ * It is the application's responsibility to close it and make sure there's no
+ * file descriptor leak.
+ *
+ * By default, the stream will emit a `'close'` event after it has been
+ * destroyed. Set the `emitClose` option to `false` to change this behavior.
+ *
+ * By providing the `fs` option it is possible to override the corresponding `fs`implementations for `open`, `write`, `writev` and `close`. Overriding `write()`without `writev()` can reduce
+ * performance as some optimizations (`_writev()`)
+ * will be disabled. When providing the `fs` option, overrides for at least one of`write` and `writev` are required. If no `fd` option is supplied, an override
+ * for `open` is also required. If `autoClose` is `true`, an override for `close`is also required.
+ *
+ * Like `fs.ReadStream`, if `fd` is specified, `fs.WriteStream` will ignore the`path` argument and will use the specified file descriptor. This means that no`'open'` event will be
+ * emitted. `fd` should be blocking; non-blocking `fd`s
+ * should be passed to `net.Socket`.
+ *
+ * If `options` is a string, then it specifies the encoding.
+ * @since v0.1.31
+ */
+export function createWriteStream(
+ path: PathLike,
+ options?: BufferEncoding | StreamOptions,
+): WriteStream;
diff --git a/ext/node/polyfills/internal/fs/streams.mjs b/ext/node/polyfills/internal/fs/streams.mjs
new file mode 100644
index 000000000..4d751df76
--- /dev/null
+++ b/ext/node/polyfills/internal/fs/streams.mjs
@@ -0,0 +1,494 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+import { ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE } from "internal:deno_node/polyfills/internal/errors.ts";
+import { kEmptyObject } from "internal:deno_node/polyfills/internal/util.mjs";
+import { deprecate } from "internal:deno_node/polyfills/util.ts";
+import { validateFunction, validateInteger } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { errorOrDestroy } from "internal:deno_node/polyfills/internal/streams/destroy.mjs";
+import { open as fsOpen } from "internal:deno_node/polyfills/_fs/_fs_open.ts";
+import { read as fsRead } from "internal:deno_node/polyfills/_fs/_fs_read.ts";
+import { write as fsWrite } from "internal:deno_node/polyfills/_fs/_fs_write.mjs";
+import { writev as fsWritev } from "internal:deno_node/polyfills/_fs/_fs_writev.mjs";
+import { close as fsClose } from "internal:deno_node/polyfills/_fs/_fs_close.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ copyObject,
+ getOptions,
+ getValidatedFd,
+ validatePath,
+} from "internal:deno_node/polyfills/internal/fs/utils.mjs";
+import { finished, Readable, Writable } from "internal:deno_node/polyfills/stream.ts";
+import { toPathIfFileURL } from "internal:deno_node/polyfills/internal/url.ts";
+import { nextTick } from "internal:deno_node/polyfills/_next_tick.ts";
+const kIoDone = Symbol("kIoDone");
+const kIsPerformingIO = Symbol("kIsPerformingIO");
+
+const kFs = Symbol("kFs");
+
+function _construct(callback) {
+ // deno-lint-ignore no-this-alias
+ const stream = this;
+ if (typeof stream.fd === "number") {
+ callback();
+ return;
+ }
+
+ if (stream.open !== openWriteFs && stream.open !== openReadFs) {
+ // Backwards compat for monkey patching open().
+ const orgEmit = stream.emit;
+ stream.emit = function (...args) {
+ if (args[0] === "open") {
+ this.emit = orgEmit;
+ callback();
+ Reflect.apply(orgEmit, this, args);
+ } else if (args[0] === "error") {
+ this.emit = orgEmit;
+ callback(args[1]);
+ } else {
+ Reflect.apply(orgEmit, this, args);
+ }
+ };
+ stream.open();
+ } else {
+ stream[kFs].open(
+ stream.path.toString(),
+ stream.flags,
+ stream.mode,
+ (er, fd) => {
+ if (er) {
+ callback(er);
+ } else {
+ stream.fd = fd;
+ callback();
+ stream.emit("open", stream.fd);
+ stream.emit("ready");
+ }
+ },
+ );
+ }
+}
+
+function close(stream, err, cb) {
+ if (!stream.fd) {
+ cb(err);
+ } else {
+ stream[kFs].close(stream.fd, (er) => {
+ cb(er || err);
+ });
+ stream.fd = null;
+ }
+}
+
+function importFd(stream, options) {
+ if (typeof options.fd === "number") {
+ // When fd is a raw descriptor, we must keep our fingers crossed
+ // that the descriptor won't get closed, or worse, replaced with
+ // another one
+ // https://github.com/nodejs/node/issues/35862
+ if (stream instanceof ReadStream) {
+ stream[kFs] = options.fs || { read: fsRead, close: fsClose };
+ }
+ if (stream instanceof WriteStream) {
+ stream[kFs] = options.fs ||
+ { write: fsWrite, writev: fsWritev, close: fsClose };
+ }
+ return options.fd;
+ }
+
+ throw new ERR_INVALID_ARG_TYPE("options.fd", ["number"], options.fd);
+}
+
+export function ReadStream(path, options) {
+ if (!(this instanceof ReadStream)) {
+ return new ReadStream(path, options);
+ }
+
+ // A little bit bigger buffer and water marks by default
+ options = copyObject(getOptions(options, kEmptyObject));
+ if (options.highWaterMark === undefined) {
+ options.highWaterMark = 64 * 1024;
+ }
+
+ if (options.autoDestroy === undefined) {
+ options.autoDestroy = false;
+ }
+
+ if (options.fd == null) {
+ this.fd = null;
+ this[kFs] = options.fs || { open: fsOpen, read: fsRead, close: fsClose };
+ validateFunction(this[kFs].open, "options.fs.open");
+
+ // Path will be ignored when fd is specified, so it can be falsy
+ this.path = toPathIfFileURL(path);
+ this.flags = options.flags === undefined ? "r" : options.flags;
+ this.mode = options.mode === undefined ? 0o666 : options.mode;
+
+ validatePath(this.path);
+ } else {
+ this.fd = getValidatedFd(importFd(this, options));
+ }
+
+ options.autoDestroy = options.autoClose === undefined
+ ? true
+ : options.autoClose;
+
+ validateFunction(this[kFs].read, "options.fs.read");
+
+ if (options.autoDestroy) {
+ validateFunction(this[kFs].close, "options.fs.close");
+ }
+
+ this.start = options.start;
+ this.end = options.end ?? Infinity;
+ this.pos = undefined;
+ this.bytesRead = 0;
+ this[kIsPerformingIO] = false;
+
+ if (this.start !== undefined) {
+ validateInteger(this.start, "start", 0);
+
+ this.pos = this.start;
+ }
+
+ if (this.end !== Infinity) {
+ validateInteger(this.end, "end", 0);
+
+ if (this.start !== undefined && this.start > this.end) {
+ throw new ERR_OUT_OF_RANGE(
+ "start",
+ `<= "end" (here: ${this.end})`,
+ this.start,
+ );
+ }
+ }
+
+ Reflect.apply(Readable, this, [options]);
+}
+
+Object.setPrototypeOf(ReadStream.prototype, Readable.prototype);
+Object.setPrototypeOf(ReadStream, Readable);
+
+Object.defineProperty(ReadStream.prototype, "autoClose", {
+ get() {
+ return this._readableState.autoDestroy;
+ },
+ set(val) {
+ this._readableState.autoDestroy = val;
+ },
+});
+
+const openReadFs = deprecate(
+ function () {
+ // Noop.
+ },
+ "ReadStream.prototype.open() is deprecated",
+ "DEP0135",
+);
+ReadStream.prototype.open = openReadFs;
+
+ReadStream.prototype._construct = _construct;
+
+ReadStream.prototype._read = async function (n) {
+ n = this.pos !== undefined
+ ? Math.min(this.end - this.pos + 1, n)
+ : Math.min(this.end - this.bytesRead + 1, n);
+
+ if (n <= 0) {
+ this.push(null);
+ return;
+ }
+
+ const buf = Buffer.allocUnsafeSlow(n);
+
+ let error = null;
+ let bytesRead = null;
+ let buffer = undefined;
+
+ this[kIsPerformingIO] = true;
+
+ await new Promise((resolve) => {
+ this[kFs]
+ .read(
+ this.fd,
+ buf,
+ 0,
+ n,
+ this.pos ?? null,
+ (_er, _bytesRead, _buf) => {
+ error = _er;
+ bytesRead = _bytesRead;
+ buffer = _buf;
+ return resolve(true);
+ },
+ );
+ });
+
+ this[kIsPerformingIO] = false;
+
+ // Tell ._destroy() that it's safe to close the fd now.
+ if (this.destroyed) {
+ this.emit(kIoDone, error);
+ return;
+ }
+
+ if (error) {
+ errorOrDestroy(this, error);
+ } else if (
+ typeof bytesRead === "number" &&
+ bytesRead > 0
+ ) {
+ if (this.pos !== undefined) {
+ this.pos += bytesRead;
+ }
+
+ this.bytesRead += bytesRead;
+
+ if (bytesRead !== buffer.length) {
+ // Slow path. Shrink to fit.
+ // Copy instead of slice so that we don't retain
+ // large backing buffer for small reads.
+ const dst = Buffer.allocUnsafeSlow(bytesRead);
+ buffer.copy(dst, 0, 0, bytesRead);
+ buffer = dst;
+ }
+
+ this.push(buffer);
+ } else {
+ this.push(null);
+ }
+};
+
+ReadStream.prototype._destroy = function (err, cb) {
+ // Usually for async IO it is safe to close a file descriptor
+ // even when there are pending operations. However, due to platform
+ // differences file IO is implemented using synchronous operations
+ // running in a thread pool. Therefore, file descriptors are not safe
+ // to close while used in a pending read or write operation. Wait for
+ // any pending IO (kIsPerformingIO) to complete (kIoDone).
+ if (this[kIsPerformingIO]) {
+ this.once(kIoDone, (er) => close(this, err || er, cb));
+ } else {
+ close(this, err, cb);
+ }
+};
+
+ReadStream.prototype.close = function (cb) {
+ if (typeof cb === "function") finished(this, cb);
+ this.destroy();
+};
+
+Object.defineProperty(ReadStream.prototype, "pending", {
+ get() {
+ return this.fd === null;
+ },
+ configurable: true,
+});
+
+export function WriteStream(path, options) {
+ if (!(this instanceof WriteStream)) {
+ return new WriteStream(path, options);
+ }
+
+ options = copyObject(getOptions(options, kEmptyObject));
+
+ // Only buffers are supported.
+ options.decodeStrings = true;
+
+ if (options.fd == null) {
+ this.fd = null;
+ this[kFs] = options.fs ||
+ { open: fsOpen, write: fsWrite, writev: fsWritev, close: fsClose };
+ validateFunction(this[kFs].open, "options.fs.open");
+
+ // Path will be ignored when fd is specified, so it can be falsy
+ this.path = toPathIfFileURL(path);
+ this.flags = options.flags === undefined ? "w" : options.flags;
+ this.mode = options.mode === undefined ? 0o666 : options.mode;
+
+ validatePath(this.path);
+ } else {
+ this.fd = getValidatedFd(importFd(this, options));
+ }
+
+ options.autoDestroy = options.autoClose === undefined
+ ? true
+ : options.autoClose;
+
+ if (!this[kFs].write && !this[kFs].writev) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "options.fs.write",
+ "function",
+ this[kFs].write,
+ );
+ }
+
+ if (this[kFs].write) {
+ validateFunction(this[kFs].write, "options.fs.write");
+ }
+
+ if (this[kFs].writev) {
+ validateFunction(this[kFs].writev, "options.fs.writev");
+ }
+
+ if (options.autoDestroy) {
+ validateFunction(this[kFs].close, "options.fs.close");
+ }
+
+ // It's enough to override either, in which case only one will be used.
+ if (!this[kFs].write) {
+ this._write = null;
+ }
+ if (!this[kFs].writev) {
+ this._writev = null;
+ }
+
+ this.start = options.start;
+ this.pos = undefined;
+ this.bytesWritten = 0;
+ this[kIsPerformingIO] = false;
+
+ if (this.start !== undefined) {
+ validateInteger(this.start, "start", 0);
+
+ this.pos = this.start;
+ }
+
+ Reflect.apply(Writable, this, [options]);
+
+ if (options.encoding) {
+ this.setDefaultEncoding(options.encoding);
+ }
+}
+
+Object.setPrototypeOf(WriteStream.prototype, Writable.prototype);
+Object.setPrototypeOf(WriteStream, Writable);
+
+Object.defineProperty(WriteStream.prototype, "autoClose", {
+ get() {
+ return this._writableState.autoDestroy;
+ },
+ set(val) {
+ this._writableState.autoDestroy = val;
+ },
+});
+
+const openWriteFs = deprecate(
+ function () {
+ // Noop.
+ },
+ "WriteStream.prototype.open() is deprecated",
+ "DEP0135",
+);
+WriteStream.prototype.open = openWriteFs;
+
+WriteStream.prototype._construct = _construct;
+
+WriteStream.prototype._write = function (data, _encoding, cb) {
+ this[kIsPerformingIO] = true;
+ this[kFs].write(this.fd, data, 0, data.length, this.pos, (er, bytes) => {
+ this[kIsPerformingIO] = false;
+ if (this.destroyed) {
+ // Tell ._destroy() that it's safe to close the fd now.
+ cb(er);
+ return this.emit(kIoDone, er);
+ }
+
+ if (er) {
+ return cb(er);
+ }
+
+ this.bytesWritten += bytes;
+ cb();
+ });
+
+ if (this.pos !== undefined) {
+ this.pos += data.length;
+ }
+};
+
+WriteStream.prototype._writev = function (data, cb) {
+ const len = data.length;
+ const chunks = new Array(len);
+ let size = 0;
+
+ for (let i = 0; i < len; i++) {
+ const chunk = data[i].chunk;
+
+ chunks[i] = chunk;
+ size += chunk.length;
+ }
+
+ this[kIsPerformingIO] = true;
+ this[kFs].writev(this.fd, chunks, this.pos ?? null, (er, bytes) => {
+ this[kIsPerformingIO] = false;
+ if (this.destroyed) {
+ // Tell ._destroy() that it's safe to close the fd now.
+ cb(er);
+ return this.emit(kIoDone, er);
+ }
+
+ if (er) {
+ return cb(er);
+ }
+
+ this.bytesWritten += bytes;
+ cb();
+ });
+
+ if (this.pos !== undefined) {
+ this.pos += size;
+ }
+};
+
+WriteStream.prototype._destroy = function (err, cb) {
+ // Usually for async IO it is safe to close a file descriptor
+ // even when there are pending operations. However, due to platform
+ // differences file IO is implemented using synchronous operations
+ // running in a thread pool. Therefore, file descriptors are not safe
+ // to close while used in a pending read or write operation. Wait for
+ // any pending IO (kIsPerformingIO) to complete (kIoDone).
+ if (this[kIsPerformingIO]) {
+ this.once(kIoDone, (er) => close(this, err || er, cb));
+ } else {
+ close(this, err, cb);
+ }
+};
+
+WriteStream.prototype.close = function (cb) {
+ if (cb) {
+ if (this.closed) {
+ nextTick(cb);
+ return;
+ }
+ this.on("close", cb);
+ }
+
+ // If we are not autoClosing, we should call
+ // destroy on 'finish'.
+ if (!this.autoClose) {
+ this.on("finish", this.destroy);
+ }
+
+ // We use end() instead of destroy() because of
+ // https://github.com/nodejs/node/issues/2006
+ this.end();
+};
+
+// There is no shutdown() for files.
+WriteStream.prototype.destroySoon = WriteStream.prototype.end;
+
+Object.defineProperty(WriteStream.prototype, "pending", {
+ get() {
+ return this.fd === null;
+ },
+ configurable: true,
+});
+
+export function createReadStream(path, options) {
+ return new ReadStream(path, options);
+}
+
+export function createWriteStream(path, options) {
+ return new WriteStream(path, options);
+}
diff --git a/ext/node/polyfills/internal/fs/utils.mjs b/ext/node/polyfills/internal/fs/utils.mjs
new file mode 100644
index 000000000..9d74c5eee
--- /dev/null
+++ b/ext/node/polyfills/internal/fs/utils.mjs
@@ -0,0 +1,1045 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+"use strict";
+
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ ERR_FS_EISDIR,
+ ERR_FS_INVALID_SYMLINK_TYPE,
+ ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_ARG_VALUE,
+ ERR_OUT_OF_RANGE,
+ hideStackFrames,
+ uvException,
+} from "internal:deno_node/polyfills/internal/errors.ts";
+
+import {
+ isArrayBufferView,
+ isBigUint64Array,
+ isDate,
+ isUint8Array,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+import { once } from "internal:deno_node/polyfills/internal/util.mjs";
+import { deprecate } from "internal:deno_node/polyfills/util.ts";
+import { toPathIfFileURL } from "internal:deno_node/polyfills/internal/url.ts";
+import {
+ validateAbortSignal,
+ validateBoolean,
+ validateFunction,
+ validateInt32,
+ validateInteger,
+ validateObject,
+ validateUint32,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import pathModule from "internal:deno_node/polyfills/path.ts";
+const kType = Symbol("type");
+const kStats = Symbol("stats");
+import assert from "internal:deno_node/polyfills/internal/assert.mjs";
+import { lstat, lstatSync } from "internal:deno_node/polyfills/_fs/_fs_lstat.ts";
+import { stat, statSync } from "internal:deno_node/polyfills/_fs/_fs_stat.ts";
+import { isWindows } from "internal:deno_node/polyfills/_util/os.ts";
+import process from "internal:deno_node/polyfills/process.ts";
+
+import {
+ fs as fsConstants,
+ os as osConstants,
+} from "internal:deno_node/polyfills/internal_binding/constants.ts";
+const {
+ F_OK = 0,
+ W_OK = 0,
+ R_OK = 0,
+ X_OK = 0,
+ COPYFILE_EXCL,
+ COPYFILE_FICLONE,
+ COPYFILE_FICLONE_FORCE,
+ O_APPEND,
+ O_CREAT,
+ O_EXCL,
+ O_RDONLY,
+ O_RDWR,
+ O_SYNC,
+ O_TRUNC,
+ O_WRONLY,
+ S_IFBLK,
+ S_IFCHR,
+ S_IFDIR,
+ S_IFIFO,
+ S_IFLNK,
+ S_IFMT,
+ S_IFREG,
+ S_IFSOCK,
+ UV_FS_SYMLINK_DIR,
+ UV_FS_SYMLINK_JUNCTION,
+ UV_DIRENT_UNKNOWN,
+ UV_DIRENT_FILE,
+ UV_DIRENT_DIR,
+ UV_DIRENT_LINK,
+ UV_DIRENT_FIFO,
+ UV_DIRENT_SOCKET,
+ UV_DIRENT_CHAR,
+ UV_DIRENT_BLOCK,
+} = fsConstants;
+
+// The access modes can be any of F_OK, R_OK, W_OK or X_OK. Some might not be
+// available on specific systems. They can be used in combination as well
+// (F_OK | R_OK | W_OK | X_OK).
+const kMinimumAccessMode = Math.min(F_OK, W_OK, R_OK, X_OK);
+const kMaximumAccessMode = F_OK | W_OK | R_OK | X_OK;
+
+const kDefaultCopyMode = 0;
+// The copy modes can be any of COPYFILE_EXCL, COPYFILE_FICLONE or
+// COPYFILE_FICLONE_FORCE. They can be used in combination as well
+// (COPYFILE_EXCL | COPYFILE_FICLONE | COPYFILE_FICLONE_FORCE).
+const kMinimumCopyMode = Math.min(
+ kDefaultCopyMode,
+ COPYFILE_EXCL,
+ COPYFILE_FICLONE,
+ COPYFILE_FICLONE_FORCE,
+);
+const kMaximumCopyMode = COPYFILE_EXCL |
+ COPYFILE_FICLONE |
+ COPYFILE_FICLONE_FORCE;
+
+// Most platforms don't allow reads or writes >= 2 GB.
+// See https://github.com/libuv/libuv/pull/1501.
+const kIoMaxLength = 2 ** 31 - 1;
+
+// Use 64kb in case the file type is not a regular file and thus do not know the
+// actual file size. Increasing the value further results in more frequent over
+// allocation for small files and consumes CPU time and memory that should be
+// used else wise.
+// Use up to 512kb per read otherwise to partition reading big files to prevent
+// blocking other threads in case the available threads are all in use.
+const kReadFileUnknownBufferLength = 64 * 1024;
+const kReadFileBufferLength = 512 * 1024;
+
+const kWriteFileMaxChunkSize = 512 * 1024;
+
+export const kMaxUserId = 2 ** 32 - 1;
+
+export function assertEncoding(encoding) {
+ if (encoding && !Buffer.isEncoding(encoding)) {
+ const reason = "is invalid encoding";
+ throw new ERR_INVALID_ARG_VALUE(encoding, "encoding", reason);
+ }
+}
+
+export class Dirent {
+ constructor(name, type) {
+ this.name = name;
+ this[kType] = type;
+ }
+
+ isDirectory() {
+ return this[kType] === UV_DIRENT_DIR;
+ }
+
+ isFile() {
+ return this[kType] === UV_DIRENT_FILE;
+ }
+
+ isBlockDevice() {
+ return this[kType] === UV_DIRENT_BLOCK;
+ }
+
+ isCharacterDevice() {
+ return this[kType] === UV_DIRENT_CHAR;
+ }
+
+ isSymbolicLink() {
+ return this[kType] === UV_DIRENT_LINK;
+ }
+
+ isFIFO() {
+ return this[kType] === UV_DIRENT_FIFO;
+ }
+
+ isSocket() {
+ return this[kType] === UV_DIRENT_SOCKET;
+ }
+}
+
+class DirentFromStats extends Dirent {
+ constructor(name, stats) {
+ super(name, null);
+ this[kStats] = stats;
+ }
+}
+
+for (const name of Reflect.ownKeys(Dirent.prototype)) {
+ if (name === "constructor") {
+ continue;
+ }
+ DirentFromStats.prototype[name] = function () {
+ return this[kStats][name]();
+ };
+}
+
+export function copyObject(source) {
+ const target = {};
+ for (const key in source) {
+ target[key] = source[key];
+ }
+ return target;
+}
+
+const bufferSep = Buffer.from(pathModule.sep);
+
+function join(path, name) {
+ if (
+ (typeof path === "string" || isUint8Array(path)) &&
+ name === undefined
+ ) {
+ return path;
+ }
+
+ if (typeof path === "string" && isUint8Array(name)) {
+ const pathBuffer = Buffer.from(pathModule.join(path, pathModule.sep));
+ return Buffer.concat([pathBuffer, name]);
+ }
+
+ if (typeof path === "string" && typeof name === "string") {
+ return pathModule.join(path, name);
+ }
+
+ if (isUint8Array(path) && isUint8Array(name)) {
+ return Buffer.concat([path, bufferSep, name]);
+ }
+
+ throw new ERR_INVALID_ARG_TYPE(
+ "path",
+ ["string", "Buffer"],
+ path,
+ );
+}
+
+export function getDirents(path, { 0: names, 1: types }, callback) {
+ let i;
+ if (typeof callback === "function") {
+ const len = names.length;
+ let toFinish = 0;
+ callback = once(callback);
+ for (i = 0; i < len; i++) {
+ const type = types[i];
+ if (type === UV_DIRENT_UNKNOWN) {
+ const name = names[i];
+ const idx = i;
+ toFinish++;
+ let filepath;
+ try {
+ filepath = join(path, name);
+ } catch (err) {
+ callback(err);
+ return;
+ }
+ lstat(filepath, (err, stats) => {
+ if (err) {
+ callback(err);
+ return;
+ }
+ names[idx] = new DirentFromStats(name, stats);
+ if (--toFinish === 0) {
+ callback(null, names);
+ }
+ });
+ } else {
+ names[i] = new Dirent(names[i], types[i]);
+ }
+ }
+ if (toFinish === 0) {
+ callback(null, names);
+ }
+ } else {
+ const len = names.length;
+ for (i = 0; i < len; i++) {
+ names[i] = getDirent(path, names[i], types[i]);
+ }
+ return names;
+ }
+}
+
+export function getDirent(path, name, type, callback) {
+ if (typeof callback === "function") {
+ if (type === UV_DIRENT_UNKNOWN) {
+ let filepath;
+ try {
+ filepath = join(path, name);
+ } catch (err) {
+ callback(err);
+ return;
+ }
+ lstat(filepath, (err, stats) => {
+ if (err) {
+ callback(err);
+ return;
+ }
+ callback(null, new DirentFromStats(name, stats));
+ });
+ } else {
+ callback(null, new Dirent(name, type));
+ }
+ } else if (type === UV_DIRENT_UNKNOWN) {
+ const stats = lstatSync(join(path, name));
+ return new DirentFromStats(name, stats);
+ } else {
+ return new Dirent(name, type);
+ }
+}
+
+export function getOptions(options, defaultOptions) {
+ if (
+ options === null || options === undefined ||
+ typeof options === "function"
+ ) {
+ return defaultOptions;
+ }
+
+ if (typeof options === "string") {
+ defaultOptions = { ...defaultOptions };
+ defaultOptions.encoding = options;
+ options = defaultOptions;
+ } else if (typeof options !== "object") {
+ throw new ERR_INVALID_ARG_TYPE("options", ["string", "Object"], options);
+ }
+
+ if (options.encoding !== "buffer") {
+ assertEncoding(options.encoding);
+ }
+
+ if (options.signal !== undefined) {
+ validateAbortSignal(options.signal, "options.signal");
+ }
+ return options;
+}
+
+/**
+ * @param {InternalFSBinding.FSSyncContext} ctx
+ */
+export function handleErrorFromBinding(ctx) {
+ if (ctx.errno !== undefined) { // libuv error numbers
+ const err = uvException(ctx);
+ Error.captureStackTrace(err, handleErrorFromBinding);
+ throw err;
+ }
+ if (ctx.error !== undefined) { // Errors created in C++ land.
+ // TODO(joyeecheung): currently, ctx.error are encoding errors
+ // usually caused by memory problems. We need to figure out proper error
+ // code(s) for this.
+ Error.captureStackTrace(ctx.error, handleErrorFromBinding);
+ throw ctx.error;
+ }
+}
+
+// Check if the path contains null types if it is a string nor Uint8Array,
+// otherwise return silently.
+export const nullCheck = hideStackFrames(
+ (path, propName, throwError = true) => {
+ const pathIsString = typeof path === "string";
+ const pathIsUint8Array = isUint8Array(path);
+
+ // We can only perform meaningful checks on strings and Uint8Arrays.
+ if (
+ (!pathIsString && !pathIsUint8Array) ||
+ (pathIsString && !path.includes("\u0000")) ||
+ (pathIsUint8Array && !path.includes(0))
+ ) {
+ return;
+ }
+
+ const err = new ERR_INVALID_ARG_VALUE(
+ propName,
+ path,
+ "must be a string or Uint8Array without null bytes",
+ );
+ if (throwError) {
+ throw err;
+ }
+ return err;
+ },
+);
+
+export function preprocessSymlinkDestination(path, type, linkPath) {
+ if (!isWindows) {
+ // No preprocessing is needed on Unix.
+ return path;
+ }
+ path = "" + path;
+ if (type === "junction") {
+ // Junctions paths need to be absolute and \\?\-prefixed.
+ // A relative target is relative to the link's parent directory.
+ path = pathModule.resolve(linkPath, "..", path);
+ return pathModule.toNamespacedPath(path);
+ }
+ if (pathModule.isAbsolute(path)) {
+ // If the path is absolute, use the \\?\-prefix to enable long filenames
+ return pathModule.toNamespacedPath(path);
+ }
+ // Windows symlinks don't tolerate forward slashes.
+ return path.replace(/\//g, "\\");
+}
+
+// Constructor for file stats.
+function StatsBase(
+ dev,
+ mode,
+ nlink,
+ uid,
+ gid,
+ rdev,
+ blksize,
+ ino,
+ size,
+ blocks,
+) {
+ this.dev = dev;
+ this.mode = mode;
+ this.nlink = nlink;
+ this.uid = uid;
+ this.gid = gid;
+ this.rdev = rdev;
+ this.blksize = blksize;
+ this.ino = ino;
+ this.size = size;
+ this.blocks = blocks;
+}
+
+StatsBase.prototype.isDirectory = function () {
+ return this._checkModeProperty(S_IFDIR);
+};
+
+StatsBase.prototype.isFile = function () {
+ return this._checkModeProperty(S_IFREG);
+};
+
+StatsBase.prototype.isBlockDevice = function () {
+ return this._checkModeProperty(S_IFBLK);
+};
+
+StatsBase.prototype.isCharacterDevice = function () {
+ return this._checkModeProperty(S_IFCHR);
+};
+
+StatsBase.prototype.isSymbolicLink = function () {
+ return this._checkModeProperty(S_IFLNK);
+};
+
+StatsBase.prototype.isFIFO = function () {
+ return this._checkModeProperty(S_IFIFO);
+};
+
+StatsBase.prototype.isSocket = function () {
+ return this._checkModeProperty(S_IFSOCK);
+};
+
+const kNsPerMsBigInt = 10n ** 6n;
+const kNsPerSecBigInt = 10n ** 9n;
+const kMsPerSec = 10 ** 3;
+const kNsPerMs = 10 ** 6;
+function msFromTimeSpec(sec, nsec) {
+ return sec * kMsPerSec + nsec / kNsPerMs;
+}
+
+function nsFromTimeSpecBigInt(sec, nsec) {
+ return sec * kNsPerSecBigInt + nsec;
+}
+
+// The Date constructor performs Math.floor() to the timestamp.
+// https://www.ecma-international.org/ecma-262/#sec-timeclip
+// Since there may be a precision loss when the timestamp is
+// converted to a floating point number, we manually round
+// the timestamp here before passing it to Date().
+// Refs: https://github.com/nodejs/node/pull/12607
+function dateFromMs(ms) {
+ return new Date(Number(ms) + 0.5);
+}
+
+export function BigIntStats(
+ dev,
+ mode,
+ nlink,
+ uid,
+ gid,
+ rdev,
+ blksize,
+ ino,
+ size,
+ blocks,
+ atimeNs,
+ mtimeNs,
+ ctimeNs,
+ birthtimeNs,
+) {
+ Reflect.apply(StatsBase, this, [
+ dev,
+ mode,
+ nlink,
+ uid,
+ gid,
+ rdev,
+ blksize,
+ ino,
+ size,
+ blocks,
+ ]);
+
+ this.atimeMs = atimeNs / kNsPerMsBigInt;
+ this.mtimeMs = mtimeNs / kNsPerMsBigInt;
+ this.ctimeMs = ctimeNs / kNsPerMsBigInt;
+ this.birthtimeMs = birthtimeNs / kNsPerMsBigInt;
+ this.atimeNs = atimeNs;
+ this.mtimeNs = mtimeNs;
+ this.ctimeNs = ctimeNs;
+ this.birthtimeNs = birthtimeNs;
+ this.atime = dateFromMs(this.atimeMs);
+ this.mtime = dateFromMs(this.mtimeMs);
+ this.ctime = dateFromMs(this.ctimeMs);
+ this.birthtime = dateFromMs(this.birthtimeMs);
+}
+
+Object.setPrototypeOf(BigIntStats.prototype, StatsBase.prototype);
+Object.setPrototypeOf(BigIntStats, StatsBase);
+
+BigIntStats.prototype._checkModeProperty = function (property) {
+ if (
+ isWindows && (property === S_IFIFO || property === S_IFBLK ||
+ property === S_IFSOCK)
+ ) {
+ return false; // Some types are not available on Windows
+ }
+ return (this.mode & BigInt(S_IFMT)) === BigInt(property);
+};
+
+export function Stats(
+ dev,
+ mode,
+ nlink,
+ uid,
+ gid,
+ rdev,
+ blksize,
+ ino,
+ size,
+ blocks,
+ atimeMs,
+ mtimeMs,
+ ctimeMs,
+ birthtimeMs,
+) {
+ StatsBase.call(
+ this,
+ dev,
+ mode,
+ nlink,
+ uid,
+ gid,
+ rdev,
+ blksize,
+ ino,
+ size,
+ blocks,
+ );
+ this.atimeMs = atimeMs;
+ this.mtimeMs = mtimeMs;
+ this.ctimeMs = ctimeMs;
+ this.birthtimeMs = birthtimeMs;
+ this.atime = dateFromMs(atimeMs);
+ this.mtime = dateFromMs(mtimeMs);
+ this.ctime = dateFromMs(ctimeMs);
+ this.birthtime = dateFromMs(birthtimeMs);
+}
+
+Object.setPrototypeOf(Stats.prototype, StatsBase.prototype);
+Object.setPrototypeOf(Stats, StatsBase);
+
+// HACK: Workaround for https://github.com/standard-things/esm/issues/821.
+// TODO(ronag): Remove this as soon as `esm` publishes a fixed version.
+Stats.prototype.isFile = StatsBase.prototype.isFile;
+
+Stats.prototype._checkModeProperty = function (property) {
+ if (
+ isWindows && (property === S_IFIFO || property === S_IFBLK ||
+ property === S_IFSOCK)
+ ) {
+ return false; // Some types are not available on Windows
+ }
+ return (this.mode & S_IFMT) === property;
+};
+
+/**
+ * @param {Float64Array | BigUint64Array} stats
+ * @param {number} offset
+ * @returns
+ */
+export function getStatsFromBinding(stats, offset = 0) {
+ if (isBigUint64Array(stats)) {
+ return new BigIntStats(
+ stats[0 + offset],
+ stats[1 + offset],
+ stats[2 + offset],
+ stats[3 + offset],
+ stats[4 + offset],
+ stats[5 + offset],
+ stats[6 + offset],
+ stats[7 + offset],
+ stats[8 + offset],
+ stats[9 + offset],
+ nsFromTimeSpecBigInt(stats[10 + offset], stats[11 + offset]),
+ nsFromTimeSpecBigInt(stats[12 + offset], stats[13 + offset]),
+ nsFromTimeSpecBigInt(stats[14 + offset], stats[15 + offset]),
+ nsFromTimeSpecBigInt(stats[16 + offset], stats[17 + offset]),
+ );
+ }
+ return new Stats(
+ stats[0 + offset],
+ stats[1 + offset],
+ stats[2 + offset],
+ stats[3 + offset],
+ stats[4 + offset],
+ stats[5 + offset],
+ stats[6 + offset],
+ stats[7 + offset],
+ stats[8 + offset],
+ stats[9 + offset],
+ msFromTimeSpec(stats[10 + offset], stats[11 + offset]),
+ msFromTimeSpec(stats[12 + offset], stats[13 + offset]),
+ msFromTimeSpec(stats[14 + offset], stats[15 + offset]),
+ msFromTimeSpec(stats[16 + offset], stats[17 + offset]),
+ );
+}
+
+export function stringToFlags(flags, name = "flags") {
+ if (typeof flags === "number") {
+ validateInt32(flags, name);
+ return flags;
+ }
+
+ if (flags == null) {
+ return O_RDONLY;
+ }
+
+ switch (flags) {
+ case "r":
+ return O_RDONLY;
+ case "rs": // Fall through.
+ case "sr":
+ return O_RDONLY | O_SYNC;
+ case "r+":
+ return O_RDWR;
+ case "rs+": // Fall through.
+ case "sr+":
+ return O_RDWR | O_SYNC;
+
+ case "w":
+ return O_TRUNC | O_CREAT | O_WRONLY;
+ case "wx": // Fall through.
+ case "xw":
+ return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
+
+ case "w+":
+ return O_TRUNC | O_CREAT | O_RDWR;
+ case "wx+": // Fall through.
+ case "xw+":
+ return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
+
+ case "a":
+ return O_APPEND | O_CREAT | O_WRONLY;
+ case "ax": // Fall through.
+ case "xa":
+ return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
+ case "as": // Fall through.
+ case "sa":
+ return O_APPEND | O_CREAT | O_WRONLY | O_SYNC;
+
+ case "a+":
+ return O_APPEND | O_CREAT | O_RDWR;
+ case "ax+": // Fall through.
+ case "xa+":
+ return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
+ case "as+": // Fall through.
+ case "sa+":
+ return O_APPEND | O_CREAT | O_RDWR | O_SYNC;
+ }
+
+ throw new ERR_INVALID_ARG_VALUE("flags", flags);
+}
+
+export const stringToSymlinkType = hideStackFrames((type) => {
+ let flags = 0;
+ if (typeof type === "string") {
+ switch (type) {
+ case "dir":
+ flags |= UV_FS_SYMLINK_DIR;
+ break;
+ case "junction":
+ flags |= UV_FS_SYMLINK_JUNCTION;
+ break;
+ case "file":
+ break;
+ default:
+ throw new ERR_FS_INVALID_SYMLINK_TYPE(type);
+ }
+ }
+ return flags;
+});
+
+// converts Date or number to a fractional UNIX timestamp
+export function toUnixTimestamp(time, name = "time") {
+ // eslint-disable-next-line eqeqeq
+ if (typeof time === "string" && +time == time) {
+ return +time;
+ }
+ if (Number.isFinite(time)) {
+ if (time < 0) {
+ return Date.now() / 1000;
+ }
+ return time;
+ }
+ if (isDate(time)) {
+ // Convert to 123.456 UNIX timestamp
+ return Date.getTime(time) / 1000;
+ }
+ throw new ERR_INVALID_ARG_TYPE(name, ["Date", "Time in seconds"], time);
+}
+
+export const validateOffsetLengthRead = hideStackFrames(
+ (offset, length, bufferLength) => {
+ if (offset < 0) {
+ throw new ERR_OUT_OF_RANGE("offset", ">= 0", offset);
+ }
+ if (length < 0) {
+ throw new ERR_OUT_OF_RANGE("length", ">= 0", length);
+ }
+ if (offset + length > bufferLength) {
+ throw new ERR_OUT_OF_RANGE(
+ "length",
+ `<= ${bufferLength - offset}`,
+ length,
+ );
+ }
+ },
+);
+
+export const validateOffsetLengthWrite = hideStackFrames(
+ (offset, length, byteLength) => {
+ if (offset > byteLength) {
+ throw new ERR_OUT_OF_RANGE("offset", `<= ${byteLength}`, offset);
+ }
+
+ if (length > byteLength - offset) {
+ throw new ERR_OUT_OF_RANGE("length", `<= ${byteLength - offset}`, length);
+ }
+
+ if (length < 0) {
+ throw new ERR_OUT_OF_RANGE("length", ">= 0", length);
+ }
+
+ validateInt32(length, "length", 0);
+ },
+);
+
+export const validatePath = hideStackFrames((path, propName = "path") => {
+ if (typeof path !== "string" && !isUint8Array(path)) {
+ throw new ERR_INVALID_ARG_TYPE(propName, ["string", "Buffer", "URL"], path);
+ }
+
+ const err = nullCheck(path, propName, false);
+
+ if (err !== undefined) {
+ throw err;
+ }
+});
+
+export const getValidatedPath = hideStackFrames(
+ (fileURLOrPath, propName = "path") => {
+ const path = toPathIfFileURL(fileURLOrPath);
+ validatePath(path, propName);
+ return path;
+ },
+);
+
+export const getValidatedFd = hideStackFrames((fd, propName = "fd") => {
+ if (Object.is(fd, -0)) {
+ return 0;
+ }
+
+ validateInt32(fd, propName, 0);
+
+ return fd;
+});
+
+export const validateBufferArray = hideStackFrames(
+ (buffers, propName = "buffers") => {
+ if (!Array.isArray(buffers)) {
+ throw new ERR_INVALID_ARG_TYPE(propName, "ArrayBufferView[]", buffers);
+ }
+
+ for (let i = 0; i < buffers.length; i++) {
+ if (!isArrayBufferView(buffers[i])) {
+ throw new ERR_INVALID_ARG_TYPE(propName, "ArrayBufferView[]", buffers);
+ }
+ }
+
+ return buffers;
+ },
+);
+
+let nonPortableTemplateWarn = true;
+
+export function warnOnNonPortableTemplate(template) {
+ // Template strings passed to the mkdtemp() family of functions should not
+ // end with 'X' because they are handled inconsistently across platforms.
+ if (nonPortableTemplateWarn && template.endsWith("X")) {
+ process.emitWarning(
+ "mkdtemp() templates ending with X are not portable. " +
+ "For details see: https://nodejs.org/api/fs.html",
+ );
+ nonPortableTemplateWarn = false;
+ }
+}
+
+const defaultCpOptions = {
+ dereference: false,
+ errorOnExist: false,
+ filter: undefined,
+ force: true,
+ preserveTimestamps: false,
+ recursive: false,
+};
+
+const defaultRmOptions = {
+ recursive: false,
+ force: false,
+ retryDelay: 100,
+ maxRetries: 0,
+};
+
+const defaultRmdirOptions = {
+ retryDelay: 100,
+ maxRetries: 0,
+ recursive: false,
+};
+
+export const validateCpOptions = hideStackFrames((options) => {
+ if (options === undefined) {
+ return { ...defaultCpOptions };
+ }
+ validateObject(options, "options");
+ options = { ...defaultCpOptions, ...options };
+ validateBoolean(options.dereference, "options.dereference");
+ validateBoolean(options.errorOnExist, "options.errorOnExist");
+ validateBoolean(options.force, "options.force");
+ validateBoolean(options.preserveTimestamps, "options.preserveTimestamps");
+ validateBoolean(options.recursive, "options.recursive");
+ if (options.filter !== undefined) {
+ validateFunction(options.filter, "options.filter");
+ }
+ return options;
+});
+
+export const validateRmOptions = hideStackFrames(
+ (path, options, expectDir, cb) => {
+ options = validateRmdirOptions(options, defaultRmOptions);
+ validateBoolean(options.force, "options.force");
+
+ stat(path, (err, stats) => {
+ if (err) {
+ if (options.force && err.code === "ENOENT") {
+ return cb(null, options);
+ }
+ return cb(err, options);
+ }
+
+ if (expectDir && !stats.isDirectory()) {
+ return cb(false);
+ }
+
+ if (stats.isDirectory() && !options.recursive) {
+ return cb(
+ new ERR_FS_EISDIR({
+ code: "EISDIR",
+ message: "is a directory",
+ path,
+ syscall: "rm",
+ errno: osConstants.errno.EISDIR,
+ }),
+ );
+ }
+ return cb(null, options);
+ });
+ },
+);
+
+export const validateRmOptionsSync = hideStackFrames(
+ (path, options, expectDir) => {
+ options = validateRmdirOptions(options, defaultRmOptions);
+ validateBoolean(options.force, "options.force");
+
+ if (!options.force || expectDir || !options.recursive) {
+ const isDirectory = statSync(path, { throwIfNoEntry: !options.force })
+ ?.isDirectory();
+
+ if (expectDir && !isDirectory) {
+ return false;
+ }
+
+ if (isDirectory && !options.recursive) {
+ throw new ERR_FS_EISDIR({
+ code: "EISDIR",
+ message: "is a directory",
+ path,
+ syscall: "rm",
+ errno: EISDIR,
+ });
+ }
+ }
+
+ return options;
+ },
+);
+
+let recursiveRmdirWarned = process.noDeprecation;
+export function emitRecursiveRmdirWarning() {
+ if (!recursiveRmdirWarned) {
+ process.emitWarning(
+ "In future versions of Node.js, fs.rmdir(path, { recursive: true }) " +
+ "will be removed. Use fs.rm(path, { recursive: true }) instead",
+ "DeprecationWarning",
+ "DEP0147",
+ );
+ recursiveRmdirWarned = true;
+ }
+}
+
+export const validateRmdirOptions = hideStackFrames(
+ (options, defaults = defaultRmdirOptions) => {
+ if (options === undefined) {
+ return defaults;
+ }
+ validateObject(options, "options");
+
+ options = { ...defaults, ...options };
+
+ validateBoolean(options.recursive, "options.recursive");
+ validateInt32(options.retryDelay, "options.retryDelay", 0);
+ validateUint32(options.maxRetries, "options.maxRetries");
+
+ return options;
+ },
+);
+
+export const getValidMode = hideStackFrames((mode, type) => {
+ let min = kMinimumAccessMode;
+ let max = kMaximumAccessMode;
+ let def = F_OK;
+ if (type === "copyFile") {
+ min = kMinimumCopyMode;
+ max = kMaximumCopyMode;
+ def = mode || kDefaultCopyMode;
+ } else {
+ assert(type === "access");
+ }
+ if (mode == null) {
+ return def;
+ }
+ if (Number.isInteger(mode) && mode >= min && mode <= max) {
+ return mode;
+ }
+ if (typeof mode !== "number") {
+ throw new ERR_INVALID_ARG_TYPE("mode", "integer", mode);
+ }
+ throw new ERR_OUT_OF_RANGE(
+ "mode",
+ `an integer >= ${min} && <= ${max}`,
+ mode,
+ );
+});
+
+export const validateStringAfterArrayBufferView = hideStackFrames(
+ (buffer, name) => {
+ if (typeof buffer === "string") {
+ return;
+ }
+
+ if (
+ typeof buffer === "object" &&
+ buffer !== null &&
+ typeof buffer.toString === "function" &&
+ Object.prototype.hasOwnProperty.call(buffer, "toString")
+ ) {
+ return;
+ }
+
+ throw new ERR_INVALID_ARG_TYPE(
+ name,
+ ["string", "Buffer", "TypedArray", "DataView"],
+ buffer,
+ );
+ },
+);
+
+export const validatePosition = hideStackFrames((position) => {
+ if (typeof position === "number") {
+ validateInteger(position, "position");
+ } else if (typeof position === "bigint") {
+ if (!(position >= -(2n ** 63n) && position <= 2n ** 63n - 1n)) {
+ throw new ERR_OUT_OF_RANGE(
+ "position",
+ `>= ${-(2n ** 63n)} && <= ${2n ** 63n - 1n}`,
+ position,
+ );
+ }
+ } else {
+ throw new ERR_INVALID_ARG_TYPE("position", ["integer", "bigint"], position);
+ }
+});
+
+export const realpathCacheKey = Symbol("realpathCacheKey");
+export const constants = {
+ kIoMaxLength,
+ kMaxUserId,
+ kReadFileBufferLength,
+ kReadFileUnknownBufferLength,
+ kWriteFileMaxChunkSize,
+};
+
+export const showStringCoercionDeprecation = deprecate(
+ () => {},
+ "Implicit coercion of objects with own toString property is deprecated.",
+ "DEP0162",
+);
+
+export default {
+ constants,
+ assertEncoding,
+ BigIntStats, // for testing
+ copyObject,
+ Dirent,
+ emitRecursiveRmdirWarning,
+ getDirent,
+ getDirents,
+ getOptions,
+ getValidatedFd,
+ getValidatedPath,
+ getValidMode,
+ handleErrorFromBinding,
+ kMaxUserId,
+ nullCheck,
+ preprocessSymlinkDestination,
+ realpathCacheKey,
+ getStatsFromBinding,
+ showStringCoercionDeprecation,
+ stringToFlags,
+ stringToSymlinkType,
+ Stats,
+ toUnixTimestamp,
+ validateBufferArray,
+ validateCpOptions,
+ validateOffsetLengthRead,
+ validateOffsetLengthWrite,
+ validatePath,
+ validatePosition,
+ validateRmOptions,
+ validateRmOptionsSync,
+ validateRmdirOptions,
+ validateStringAfterArrayBufferView,
+ warnOnNonPortableTemplate,
+};
diff --git a/ext/node/polyfills/internal/hide_stack_frames.ts b/ext/node/polyfills/internal/hide_stack_frames.ts
new file mode 100644
index 000000000..e1a6e4c27
--- /dev/null
+++ b/ext/node/polyfills/internal/hide_stack_frames.ts
@@ -0,0 +1,16 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+// deno-lint-ignore no-explicit-any
+type GenericFunction = (...args: any[]) => any;
+
+/** This function removes unnecessary frames from Node.js core errors. */
+export function hideStackFrames<T extends GenericFunction = GenericFunction>(
+ fn: T,
+): T {
+ // We rename the functions that will be hidden to cut off the stacktrace
+ // at the outermost one.
+ const hidden = "__node_internal_" + fn.name;
+ Object.defineProperty(fn, "name", { value: hidden });
+
+ return fn;
+}
diff --git a/ext/node/polyfills/internal/http.ts b/ext/node/polyfills/internal/http.ts
new file mode 100644
index 000000000..f541039dc
--- /dev/null
+++ b/ext/node/polyfills/internal/http.ts
@@ -0,0 +1,38 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+import { setUnrefTimeout } from "internal:deno_node/polyfills/timers.ts";
+import { notImplemented } from "internal:deno_node/polyfills/_utils.ts";
+
+let utcCache: string | undefined;
+
+export function utcDate() {
+ if (!utcCache) cache();
+ return utcCache;
+}
+
+function cache() {
+ const d = new Date();
+ utcCache = d.toUTCString();
+ setUnrefTimeout(resetCache, 1000 - d.getMilliseconds());
+}
+
+function resetCache() {
+ utcCache = undefined;
+}
+
+export function emitStatistics(
+ _statistics: { startTime: [number, number] } | null,
+) {
+ notImplemented("internal/http.emitStatistics");
+}
+
+export const kOutHeaders = Symbol("kOutHeaders");
+export const kNeedDrain = Symbol("kNeedDrain");
+
+export default {
+ utcDate,
+ emitStatistics,
+ kOutHeaders,
+ kNeedDrain,
+};
diff --git a/ext/node/polyfills/internal/idna.ts b/ext/node/polyfills/internal/idna.ts
new file mode 100644
index 000000000..f71c06eba
--- /dev/null
+++ b/ext/node/polyfills/internal/idna.ts
@@ -0,0 +1,461 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Copyright Mathias Bynens <https://mathiasbynens.be/>
+
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Adapted from https://github.com/mathiasbynens/punycode.js
+
+// TODO(cmorten): migrate punycode logic to "icu" internal binding and/or "url"
+// internal module so there can be re-use within the "url" module etc.
+
+"use strict";
+
+/** Highest positive signed 32-bit float value */
+const maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
+
+/** Bootstring parameters */
+const base = 36;
+const tMin = 1;
+const tMax = 26;
+const skew = 38;
+const damp = 700;
+const initialBias = 72;
+const initialN = 128; // 0x80
+const delimiter = "-"; // '\x2D'
+
+/** Regular expressions */
+export const regexPunycode = /^xn--/;
+export const regexNonASCII = /[^\0-\x7E]/; // non-ASCII chars
+const regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
+
+/** Error messages */
+const errors: Record<string, string> = {
+ "overflow": "Overflow: input needs wider integers to process",
+ "not-basic": "Illegal input >= 0x80 (not a basic code point)",
+ "invalid-input": "Invalid input",
+};
+
+/** Convenience shortcuts */
+const baseMinusTMin = base - tMin;
+const floor = Math.floor;
+
+/**
+ * A generic error utility function.
+ *
+ * @param type The error type.
+ * @return Throws a `RangeError` with the applicable error message.
+ */
+function error(type: string) {
+ throw new RangeError(errors[type]);
+}
+
+/**
+ * A simple `Array#map`-like wrapper to work with domain name strings or email
+ * addresses.
+ *
+ * @param domain The domain name or email address.
+ * @param callback The function that gets called for every
+ * character.
+ * @return A new string of characters returned by the callback
+ * function.
+ */
+function mapDomain(str: string, fn: (label: string) => string) {
+ const parts = str.split("@");
+ let result = "";
+
+ if (parts.length > 1) {
+ // In email addresses, only the domain name should be punycoded. Leave
+ // the local part (i.e. everything up to `@`) intact.
+ result = parts[0] + "@";
+ str = parts[1];
+ }
+
+ // Avoid `split(regex)` for IE8 compatibility. See #17.
+ str = str.replace(regexSeparators, "\x2E");
+ const labels = str.split(".");
+ const encoded = labels.map(fn).join(".");
+
+ return result + encoded;
+}
+
+/**
+ * Creates an array containing the numeric code points of each Unicode
+ * character in the string. While JavaScript uses UCS-2 internally,
+ * this function will convert a pair of surrogate halves (each of which
+ * UCS-2 exposes as separate characters) into a single code point,
+ * matching UTF-16.
+ *
+ * @param str The Unicode input string (UCS-2).
+ * @return The new array of code points.
+ */
+function ucs2decode(str: string) {
+ const output = [];
+ let counter = 0;
+ const length = str.length;
+
+ while (counter < length) {
+ const value = str.charCodeAt(counter++);
+
+ if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+ // It's a high surrogate, and there is a next character.
+ const extra = str.charCodeAt(counter++);
+
+ if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
+ output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+ } else {
+ // It's an unmatched surrogate; only append this code unit, in case the
+ // next code unit is the high surrogate of a surrogate pair.
+ output.push(value);
+ counter--;
+ }
+ } else {
+ output.push(value);
+ }
+ }
+
+ return output;
+}
+
+/**
+ * Creates a string based on an array of numeric code points.
+ * @see `punycode.ucs2.decode`
+ * @memberOf punycode.ucs2
+ * @name encode
+ * @param codePoints The array of numeric code points.
+ * @returns The new Unicode string (UCS-2).
+ */
+function ucs2encode(array: number[]) {
+ return String.fromCodePoint(...array);
+}
+
+export const ucs2 = {
+ decode: ucs2decode,
+ encode: ucs2encode,
+};
+
+/**
+ * Converts a basic code point into a digit/integer.
+ * @see `digitToBasic()`
+ * @private
+ * @param codePoint The basic numeric code point value.
+ * @returns The numeric value of a basic code point (for use in
+ * representing integers) in the range `0` to `base - 1`, or `base` if
+ * the code point does not represent a value.
+ */
+function basicToDigit(codePoint: number) {
+ if (codePoint - 0x30 < 0x0A) {
+ return codePoint - 0x16;
+ }
+ if (codePoint - 0x41 < 0x1A) {
+ return codePoint - 0x41;
+ }
+ if (codePoint - 0x61 < 0x1A) {
+ return codePoint - 0x61;
+ }
+ return base;
+}
+
+/**
+ * Converts a digit/integer into a basic code point.
+ *
+ * @param digit The numeric value of a basic code point.
+ * @return The basic code point whose value (when used for
+ * representing integers) is `digit`, which needs to be in the range
+ * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+ * used; else, the lowercase form is used. The behavior is undefined
+ * if `flag` is non-zero and `digit` has no uppercase form.
+ */
+function digitToBasic(digit: number, flag: number) {
+ // 0..25 map to ASCII a..z or A..Z
+ // 26..35 map to ASCII 0..9
+ return digit + 22 + 75 * Number(digit < 26) - (Number(flag != 0) << 5);
+}
+
+/**
+ * Bias adaptation function as per section 3.4 of RFC 3492.
+ * https://tools.ietf.org/html/rfc3492#section-3.4
+ */
+function adapt(delta: number, numPoints: number, firstTime: boolean) {
+ let k = 0;
+ delta = firstTime ? Math.floor(delta / damp) : delta >> 1;
+ delta += Math.floor(delta / numPoints);
+
+ for (; /* no initialization */ delta > baseMinusTMin * tMax >> 1; k += base) {
+ delta = Math.floor(delta / baseMinusTMin);
+ }
+
+ return Math.floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+}
+
+/**
+ * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+ * symbols.
+ * @memberOf punycode
+ * @param input The Punycode string of ASCII-only symbols.
+ * @returns The resulting string of Unicode symbols.
+ */
+export function decode(input: string): string {
+ // Don't use UCS-2.
+ const output = [];
+ const inputLength = input.length;
+ let i = 0;
+ let n = initialN;
+ let bias = initialBias;
+
+ // Handle the basic code points: let `basic` be the number of input code
+ // points before the last delimiter, or `0` if there is none, then copy
+ // the first basic code points to the output.
+
+ let basic = input.lastIndexOf(delimiter);
+ if (basic < 0) {
+ basic = 0;
+ }
+
+ for (let j = 0; j < basic; ++j) {
+ // if it's not a basic code point
+ if (input.charCodeAt(j) >= 0x80) {
+ error("not-basic");
+ }
+ output.push(input.charCodeAt(j));
+ }
+
+ // Main decoding loop: start just after the last delimiter if any basic code
+ // points were copied; start at the beginning otherwise.
+
+ for (
+ let index = basic > 0 ? basic + 1 : 0;
+ index < inputLength;
+ /* no final expression */
+ ) {
+ // `index` is the index of the next character to be consumed.
+ // Decode a generalized variable-length integer into `delta`,
+ // which gets added to `i`. The overflow checking is easier
+ // if we increase `i` as we go, then subtract off its starting
+ // value at the end to obtain `delta`.
+ const oldi = i;
+ for (let w = 1, k = base;; /* no condition */ k += base) {
+ if (index >= inputLength) {
+ error("invalid-input");
+ }
+
+ const digit = basicToDigit(input.charCodeAt(index++));
+
+ if (digit >= base || digit > floor((maxInt - i) / w)) {
+ error("overflow");
+ }
+
+ i += digit * w;
+ const t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+ if (digit < t) {
+ break;
+ }
+
+ const baseMinusT = base - t;
+ if (w > floor(maxInt / baseMinusT)) {
+ error("overflow");
+ }
+
+ w *= baseMinusT;
+ }
+
+ const out = output.length + 1;
+ bias = adapt(i - oldi, out, oldi == 0);
+
+ // `i` was supposed to wrap around from `out` to `0`,
+ // incrementing `n` each time, so we'll fix that now:
+ if (floor(i / out) > maxInt - n) {
+ error("overflow");
+ }
+
+ n += floor(i / out);
+ i %= out;
+
+ // Insert `n` at position `i` of the output.
+ output.splice(i++, 0, n);
+ }
+
+ return String.fromCodePoint(...output);
+}
+
+/**
+ * Converts a string of Unicode symbols (e.g. a domain name label) to a
+ * Punycode string of ASCII-only symbols.
+ *
+ * @param str The string of Unicode symbols.
+ * @return The resulting Punycode string of ASCII-only symbols.
+ */
+export function encode(str: string) {
+ const output = [];
+
+ // Convert the input in UCS-2 to an array of Unicode code points.
+ const input = ucs2decode(str);
+
+ // Cache the length.
+ const inputLength = input.length;
+
+ // Initialize the state.
+ let n = initialN;
+ let delta = 0;
+ let bias = initialBias;
+
+ // Handle the basic code points.
+ for (const currentValue of input) {
+ if (currentValue < 0x80) {
+ output.push(String.fromCharCode(currentValue));
+ }
+ }
+
+ const basicLength = output.length;
+ let handledCPCount = basicLength;
+
+ // `handledCPCount` is the number of code points that have been handled;
+ // `basicLength` is the number of basic code points.
+
+ // Finish the basic string with a delimiter unless it's empty.
+ if (basicLength) {
+ output.push(delimiter);
+ }
+
+ // Main encoding loop:
+ while (handledCPCount < inputLength) {
+ // All non-basic code points < n have been handled already. Find the next
+ // larger one:
+ let m = maxInt;
+
+ for (const currentValue of input) {
+ if (currentValue >= n && currentValue < m) {
+ m = currentValue;
+ }
+ }
+
+ // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+ // but guard against overflow.
+ const handledCPCountPlusOne = handledCPCount + 1;
+
+ if (m - n > Math.floor((maxInt - delta) / handledCPCountPlusOne)) {
+ error("overflow");
+ }
+
+ delta += (m - n) * handledCPCountPlusOne;
+ n = m;
+
+ for (const currentValue of input) {
+ if (currentValue < n && ++delta > maxInt) {
+ error("overflow");
+ }
+
+ if (currentValue == n) {
+ // Represent delta as a generalized variable-length integer.
+ let q = delta;
+
+ for (let k = base;; /* no condition */ k += base) {
+ const t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+ if (q < t) {
+ break;
+ }
+
+ const qMinusT = q - t;
+ const baseMinusT = base - t;
+
+ output.push(
+ String.fromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)),
+ );
+
+ q = Math.floor(qMinusT / baseMinusT);
+ }
+
+ output.push(String.fromCharCode(digitToBasic(q, 0)));
+
+ bias = adapt(
+ delta,
+ handledCPCountPlusOne,
+ handledCPCount == basicLength,
+ );
+
+ delta = 0;
+ ++handledCPCount;
+ }
+ }
+
+ ++delta;
+ ++n;
+ }
+
+ return output.join("");
+}
+
+/**
+ * Converts a Punycode string representing a domain name or an email address
+ * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+ * it doesn't matter if you call it on a string that has already been
+ * converted to Unicode.
+ * @memberOf punycode
+ * @param input The Punycoded domain name or email address to
+ * convert to Unicode.
+ * @returns The Unicode representation of the given Punycode
+ * string.
+ */
+export function toUnicode(input: string) {
+ return mapDomain(input, function (string) {
+ return regexPunycode.test(string)
+ ? decode(string.slice(4).toLowerCase())
+ : string;
+ });
+}
+
+/**
+ * Converts a Unicode string representing a domain name or an email address to
+ * Punycode. Only the non-ASCII parts of the domain name will be converted,
+ * i.e. it doesn't matter if you call it with a domain that's already in
+ * ASCII.
+ *
+ * @param input The domain name or email address to convert, as a
+ * Unicode string.
+ * @return The Punycode representation of the given domain name or
+ * email address.
+ */
+export function toASCII(input: string): string {
+ return mapDomain(input, function (str: string) {
+ return regexNonASCII.test(str) ? "xn--" + encode(str) : str;
+ });
+}
diff --git a/ext/node/polyfills/internal/net.ts b/ext/node/polyfills/internal/net.ts
new file mode 100644
index 000000000..2e3a92dfd
--- /dev/null
+++ b/ext/node/polyfills/internal/net.ts
@@ -0,0 +1,95 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { uvException } from "internal:deno_node/polyfills/internal/errors.ts";
+import { writeBuffer } from "internal:deno_node/polyfills/internal_binding/node_file.ts";
+
+// IPv4 Segment
+const v4Seg = "(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])";
+const v4Str = `(${v4Seg}[.]){3}${v4Seg}`;
+const IPv4Reg = new RegExp(`^${v4Str}$`);
+
+// IPv6 Segment
+const v6Seg = "(?:[0-9a-fA-F]{1,4})";
+const IPv6Reg = new RegExp(
+ "^(" +
+ `(?:${v6Seg}:){7}(?:${v6Seg}|:)|` +
+ `(?:${v6Seg}:){6}(?:${v4Str}|:${v6Seg}|:)|` +
+ `(?:${v6Seg}:){5}(?::${v4Str}|(:${v6Seg}){1,2}|:)|` +
+ `(?:${v6Seg}:){4}(?:(:${v6Seg}){0,1}:${v4Str}|(:${v6Seg}){1,3}|:)|` +
+ `(?:${v6Seg}:){3}(?:(:${v6Seg}){0,2}:${v4Str}|(:${v6Seg}){1,4}|:)|` +
+ `(?:${v6Seg}:){2}(?:(:${v6Seg}){0,3}:${v4Str}|(:${v6Seg}){1,5}|:)|` +
+ `(?:${v6Seg}:){1}(?:(:${v6Seg}){0,4}:${v4Str}|(:${v6Seg}){1,6}|:)|` +
+ `(?::((?::${v6Seg}){0,5}:${v4Str}|(?::${v6Seg}){1,7}|:))` +
+ ")(%[0-9a-zA-Z-.:]{1,})?$",
+);
+
+export function isIPv4(ip: string) {
+ return RegExp.prototype.test.call(IPv4Reg, ip);
+}
+
+export function isIPv6(ip: string) {
+ return RegExp.prototype.test.call(IPv6Reg, ip);
+}
+
+export function isIP(ip: string) {
+ if (isIPv4(ip)) {
+ return 4;
+ }
+ if (isIPv6(ip)) {
+ return 6;
+ }
+
+ return 0;
+}
+
+export function makeSyncWrite(fd: number) {
+ return function (
+ // deno-lint-ignore no-explicit-any
+ this: any,
+ // deno-lint-ignore no-explicit-any
+ chunk: any,
+ enc: string,
+ cb: (err?: Error) => void,
+ ) {
+ if (enc !== "buffer") {
+ chunk = Buffer.from(chunk, enc);
+ }
+
+ this._handle.bytesWritten += chunk.length;
+
+ const ctx: { errno?: number } = {};
+ writeBuffer(fd, chunk, 0, chunk.length, null, ctx);
+
+ if (ctx.errno !== undefined) {
+ const ex = uvException(ctx);
+ ex.errno = ctx.errno;
+
+ return cb(ex);
+ }
+
+ cb();
+ };
+}
+
+export const normalizedArgsSymbol = Symbol("normalizedArgs");
diff --git a/ext/node/polyfills/internal/normalize_encoding.mjs b/ext/node/polyfills/internal/normalize_encoding.mjs
new file mode 100644
index 000000000..788c86c56
--- /dev/null
+++ b/ext/node/polyfills/internal/normalize_encoding.mjs
@@ -0,0 +1,72 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+export function normalizeEncoding(enc) {
+ if (enc == null || enc === "utf8" || enc === "utf-8") return "utf8";
+ return slowCases(enc);
+}
+
+export function slowCases(enc) {
+ switch (enc.length) {
+ case 4:
+ if (enc === "UTF8") return "utf8";
+ if (enc === "ucs2" || enc === "UCS2") return "utf16le";
+ enc = `${enc}`.toLowerCase();
+ if (enc === "utf8") return "utf8";
+ if (enc === "ucs2") return "utf16le";
+ break;
+ case 3:
+ if (
+ enc === "hex" || enc === "HEX" ||
+ `${enc}`.toLowerCase() === "hex"
+ ) {
+ return "hex";
+ }
+ break;
+ case 5:
+ if (enc === "ascii") return "ascii";
+ if (enc === "ucs-2") return "utf16le";
+ if (enc === "UTF-8") return "utf8";
+ if (enc === "ASCII") return "ascii";
+ if (enc === "UCS-2") return "utf16le";
+ enc = `${enc}`.toLowerCase();
+ if (enc === "utf-8") return "utf8";
+ if (enc === "ascii") return "ascii";
+ if (enc === "ucs-2") return "utf16le";
+ break;
+ case 6:
+ if (enc === "base64") return "base64";
+ if (enc === "latin1" || enc === "binary") return "latin1";
+ if (enc === "BASE64") return "base64";
+ if (enc === "LATIN1" || enc === "BINARY") return "latin1";
+ enc = `${enc}`.toLowerCase();
+ if (enc === "base64") return "base64";
+ if (enc === "latin1" || enc === "binary") return "latin1";
+ break;
+ case 7:
+ if (
+ enc === "utf16le" || enc === "UTF16LE" ||
+ `${enc}`.toLowerCase() === "utf16le"
+ ) {
+ return "utf16le";
+ }
+ break;
+ case 8:
+ if (
+ enc === "utf-16le" || enc === "UTF-16LE" ||
+ `${enc}`.toLowerCase() === "utf-16le"
+ ) {
+ return "utf16le";
+ }
+ break;
+ case 9:
+ if (
+ enc === "base64url" || enc === "BASE64URL" ||
+ `${enc}`.toLowerCase() === "base64url"
+ ) {
+ return "base64url";
+ }
+ break;
+ default:
+ if (enc === "") return "utf8";
+ }
+}
diff --git a/ext/node/polyfills/internal/options.ts b/ext/node/polyfills/internal/options.ts
new file mode 100644
index 000000000..68ccf0528
--- /dev/null
+++ b/ext/node/polyfills/internal/options.ts
@@ -0,0 +1,45 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import { getOptions } from "internal:deno_node/polyfills/internal_binding/node_options.ts";
+
+let optionsMap: Map<string, { value: string }>;
+
+function getOptionsFromBinding() {
+ if (!optionsMap) {
+ ({ options: optionsMap } = getOptions());
+ }
+
+ return optionsMap;
+}
+
+export function getOptionValue(optionName: string) {
+ const options = getOptionsFromBinding();
+
+ if (optionName.startsWith("--no-")) {
+ const option = options.get("--" + optionName.slice(5));
+
+ return option && !option.value;
+ }
+
+ return options.get(optionName)?.value;
+}
diff --git a/ext/node/polyfills/internal/primordials.mjs b/ext/node/polyfills/internal/primordials.mjs
new file mode 100644
index 000000000..1639efdb5
--- /dev/null
+++ b/ext/node/polyfills/internal/primordials.mjs
@@ -0,0 +1,30 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+export const ArrayIsArray = Array.isArray;
+export const ArrayPrototypeFilter = (that, ...args) => that.filter(...args);
+export const ArrayPrototypeForEach = (that, ...args) => that.forEach(...args);
+export const ArrayPrototypeIncludes = (that, ...args) => that.includes(...args);
+export const ArrayPrototypeJoin = (that, ...args) => that.join(...args);
+export const ArrayPrototypePush = (that, ...args) => that.push(...args);
+export const ArrayPrototypeSlice = (that, ...args) => that.slice(...args);
+export const ArrayPrototypeSome = (that, ...args) => that.some(...args);
+export const ArrayPrototypeSort = (that, ...args) => that.sort(...args);
+export const ArrayPrototypeUnshift = (that, ...args) => that.unshift(...args);
+export const ObjectAssign = Object.assign;
+export const ObjectCreate = Object.create;
+export const ObjectPrototypeHasOwnProperty = Object.hasOwn;
+export const RegExpPrototypeTest = (that, ...args) => that.test(...args);
+export const RegExpPrototypeExec = RegExp.prototype.exec;
+export const StringFromCharCode = String.fromCharCode;
+export const StringPrototypeCharCodeAt = (that, ...args) =>
+ that.charCodeAt(...args);
+export const StringPrototypeEndsWith = (that, ...args) =>
+ that.endsWith(...args);
+export const StringPrototypeIncludes = (that, ...args) =>
+ that.includes(...args);
+export const StringPrototypeReplace = (that, ...args) => that.replace(...args);
+export const StringPrototypeSlice = (that, ...args) => that.slice(...args);
+export const StringPrototypeSplit = (that, ...args) => that.split(...args);
+export const StringPrototypeStartsWith = (that, ...args) =>
+ that.startsWith(...args);
+export const StringPrototypeToUpperCase = (that) => that.toUpperCase();
diff --git a/ext/node/polyfills/internal/process/per_thread.mjs b/ext/node/polyfills/internal/process/per_thread.mjs
new file mode 100644
index 000000000..3146083d1
--- /dev/null
+++ b/ext/node/polyfills/internal/process/per_thread.mjs
@@ -0,0 +1,272 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+const kInternal = Symbol("internal properties");
+
+const replaceUnderscoresRegex = /_/g;
+const leadingDashesRegex = /^--?/;
+const trailingValuesRegex = /=.*$/;
+
+// This builds the initial process.allowedNodeEnvironmentFlags
+// from data in the config binding.
+export function buildAllowedFlags() {
+ const allowedNodeEnvironmentFlags = [
+ "--track-heap-objects",
+ "--no-track-heap-objects",
+ "--node-snapshot",
+ "--no-node-snapshot",
+ "--require",
+ "--max-old-space-size",
+ "--trace-exit",
+ "--no-trace-exit",
+ "--disallow-code-generation-from-strings",
+ "--experimental-json-modules",
+ "--no-experimental-json-modules",
+ "--interpreted-frames-native-stack",
+ "--inspect-brk",
+ "--no-inspect-brk",
+ "--trace-tls",
+ "--no-trace-tls",
+ "--stack-trace-limit",
+ "--experimental-repl-await",
+ "--no-experimental-repl-await",
+ "--preserve-symlinks",
+ "--no-preserve-symlinks",
+ "--report-uncaught-exception",
+ "--no-report-uncaught-exception",
+ "--experimental-modules",
+ "--no-experimental-modules",
+ "--report-signal",
+ "--jitless",
+ "--inspect-port",
+ "--heapsnapshot-near-heap-limit",
+ "--tls-keylog",
+ "--force-context-aware",
+ "--no-force-context-aware",
+ "--napi-modules",
+ "--abort-on-uncaught-exception",
+ "--diagnostic-dir",
+ "--verify-base-objects",
+ "--no-verify-base-objects",
+ "--unhandled-rejections",
+ "--perf-basic-prof",
+ "--trace-atomics-wait",
+ "--no-trace-atomics-wait",
+ "--deprecation",
+ "--no-deprecation",
+ "--perf-basic-prof-only-functions",
+ "--perf-prof",
+ "--max-http-header-size",
+ "--report-on-signal",
+ "--no-report-on-signal",
+ "--throw-deprecation",
+ "--no-throw-deprecation",
+ "--warnings",
+ "--no-warnings",
+ "--force-fips",
+ "--no-force-fips",
+ "--pending-deprecation",
+ "--no-pending-deprecation",
+ "--input-type",
+ "--tls-max-v1.3",
+ "--no-tls-max-v1.3",
+ "--tls-min-v1.2",
+ "--no-tls-min-v1.2",
+ "--inspect",
+ "--no-inspect",
+ "--heapsnapshot-signal",
+ "--trace-warnings",
+ "--no-trace-warnings",
+ "--trace-event-categories",
+ "--experimental-worker",
+ "--tls-max-v1.2",
+ "--no-tls-max-v1.2",
+ "--perf-prof-unwinding-info",
+ "--preserve-symlinks-main",
+ "--no-preserve-symlinks-main",
+ "--policy-integrity",
+ "--experimental-wasm-modules",
+ "--no-experimental-wasm-modules",
+ "--node-memory-debug",
+ "--inspect-publish-uid",
+ "--tls-min-v1.3",
+ "--no-tls-min-v1.3",
+ "--experimental-specifier-resolution",
+ "--secure-heap",
+ "--tls-min-v1.0",
+ "--no-tls-min-v1.0",
+ "--redirect-warnings",
+ "--experimental-report",
+ "--trace-event-file-pattern",
+ "--trace-uncaught",
+ "--no-trace-uncaught",
+ "--experimental-loader",
+ "--http-parser",
+ "--dns-result-order",
+ "--trace-sigint",
+ "--no-trace-sigint",
+ "--secure-heap-min",
+ "--enable-fips",
+ "--no-enable-fips",
+ "--enable-source-maps",
+ "--no-enable-source-maps",
+ "--insecure-http-parser",
+ "--no-insecure-http-parser",
+ "--use-openssl-ca",
+ "--no-use-openssl-ca",
+ "--tls-cipher-list",
+ "--experimental-top-level-await",
+ "--no-experimental-top-level-await",
+ "--openssl-config",
+ "--icu-data-dir",
+ "--v8-pool-size",
+ "--report-on-fatalerror",
+ "--no-report-on-fatalerror",
+ "--title",
+ "--tls-min-v1.1",
+ "--no-tls-min-v1.1",
+ "--report-filename",
+ "--trace-deprecation",
+ "--no-trace-deprecation",
+ "--report-compact",
+ "--no-report-compact",
+ "--experimental-policy",
+ "--experimental-import-meta-resolve",
+ "--no-experimental-import-meta-resolve",
+ "--zero-fill-buffers",
+ "--no-zero-fill-buffers",
+ "--report-dir",
+ "--use-bundled-ca",
+ "--no-use-bundled-ca",
+ "--experimental-vm-modules",
+ "--no-experimental-vm-modules",
+ "--force-async-hooks-checks",
+ "--no-force-async-hooks-checks",
+ "--frozen-intrinsics",
+ "--no-frozen-intrinsics",
+ "--huge-max-old-generation-size",
+ "--disable-proto",
+ "--debug-arraybuffer-allocations",
+ "--no-debug-arraybuffer-allocations",
+ "--conditions",
+ "--experimental-wasi-unstable-preview1",
+ "--no-experimental-wasi-unstable-preview1",
+ "--trace-sync-io",
+ "--no-trace-sync-io",
+ "--use-largepages",
+ "--experimental-abortcontroller",
+ "--debug-port",
+ "--es-module-specifier-resolution",
+ "--prof-process",
+ "-C",
+ "--loader",
+ "--report-directory",
+ "-r",
+ "--trace-events-enabled",
+ ];
+
+ /*
+ function isAccepted(to) {
+ if (!to.startsWith("-") || to === "--") return true;
+ const recursiveExpansion = aliases.get(to);
+ if (recursiveExpansion) {
+ if (recursiveExpansion[0] === to) {
+ recursiveExpansion.splice(0, 1);
+ }
+ return recursiveExpansion.every(isAccepted);
+ }
+ return options.get(to).envVarSettings === kAllowedInEnvironment;
+ }
+ for (const { 0: from, 1: expansion } of aliases) {
+ if (expansion.every(isAccepted)) {
+ let canonical = from;
+ if (canonical.endsWith("=")) {
+ canonical = canonical.slice(0, canonical.length - 1);
+ }
+ if (canonical.endsWith(" <arg>")) {
+ canonical = canonical.slice(0, canonical.length - 4);
+ }
+ allowedNodeEnvironmentFlags.push(canonical);
+ }
+ }
+ */
+
+ const trimLeadingDashes = (flag) => flag.replace(leadingDashesRegex, "");
+
+ // Save these for comparison against flags provided to
+ // process.allowedNodeEnvironmentFlags.has() which lack leading dashes.
+ const nodeFlags = allowedNodeEnvironmentFlags.map(trimLeadingDashes);
+
+ class NodeEnvironmentFlagsSet extends Set {
+ constructor(array) {
+ super();
+ this[kInternal] = { array };
+ }
+
+ add() {
+ // No-op, `Set` API compatible
+ return this;
+ }
+
+ delete() {
+ // No-op, `Set` API compatible
+ return false;
+ }
+
+ clear() {
+ // No-op, `Set` API compatible
+ }
+
+ has(key) {
+ // This will return `true` based on various possible
+ // permutations of a flag, including present/missing leading
+ // dash(es) and/or underscores-for-dashes.
+ // Strips any values after `=`, inclusive.
+ // TODO(addaleax): It might be more flexible to run the option parser
+ // on a dummy option set and see whether it rejects the argument or
+ // not.
+ if (typeof key === "string") {
+ key = key.replace(replaceUnderscoresRegex, "-");
+ if (leadingDashesRegex.test(key)) {
+ key = key.replace(trailingValuesRegex, "");
+ return this[kInternal].array.includes(key);
+ }
+ return nodeFlags.includes(key);
+ }
+ return false;
+ }
+
+ entries() {
+ this[kInternal].set ??= new Set(this[kInternal].array);
+ return this[kInternal].set.entries();
+ }
+
+ forEach(callback, thisArg = undefined) {
+ this[kInternal].array.forEach((v) =>
+ Reflect.apply(callback, thisArg, [v, v, this])
+ );
+ }
+
+ get size() {
+ return this[kInternal].array.length;
+ }
+
+ values() {
+ this[kInternal].set ??= new Set(this[kInternal].array);
+ return this[kInternal].set.values();
+ }
+ }
+ NodeEnvironmentFlagsSet.prototype.keys =
+ NodeEnvironmentFlagsSet
+ .prototype[Symbol.iterator] =
+ NodeEnvironmentFlagsSet.prototype.values;
+
+ Object.freeze(NodeEnvironmentFlagsSet.prototype.constructor);
+ Object.freeze(NodeEnvironmentFlagsSet.prototype);
+
+ return Object.freeze(
+ new NodeEnvironmentFlagsSet(
+ allowedNodeEnvironmentFlags,
+ ),
+ );
+}
diff --git a/ext/node/polyfills/internal/querystring.ts b/ext/node/polyfills/internal/querystring.ts
new file mode 100644
index 000000000..c00803afe
--- /dev/null
+++ b/ext/node/polyfills/internal/querystring.ts
@@ -0,0 +1,92 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { ERR_INVALID_URI } from "internal:deno_node/polyfills/internal/errors.ts";
+
+export const hexTable = new Array(256);
+for (let i = 0; i < 256; ++i) {
+ hexTable[i] = "%" + ((i < 16 ? "0" : "") + i.toString(16)).toUpperCase();
+}
+
+// deno-fmt-ignore
+export const isHexTable = new Int8Array([
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32 - 47
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63
+ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64 - 79
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 - 95
+ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96 - 111
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 112 - 127
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 ...
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ... 256
+]);
+
+export function encodeStr(
+ str: string,
+ noEscapeTable: Int8Array,
+ hexTable: string[],
+): string {
+ const len = str.length;
+ if (len === 0) return "";
+
+ let out = "";
+ let lastPos = 0;
+
+ for (let i = 0; i < len; i++) {
+ let c = str.charCodeAt(i);
+ // ASCII
+ if (c < 0x80) {
+ if (noEscapeTable[c] === 1) continue;
+ if (lastPos < i) out += str.slice(lastPos, i);
+ lastPos = i + 1;
+ out += hexTable[c];
+ continue;
+ }
+
+ if (lastPos < i) out += str.slice(lastPos, i);
+
+ // Multi-byte characters ...
+ if (c < 0x800) {
+ lastPos = i + 1;
+ out += hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)];
+ continue;
+ }
+ if (c < 0xd800 || c >= 0xe000) {
+ lastPos = i + 1;
+ out += hexTable[0xe0 | (c >> 12)] +
+ hexTable[0x80 | ((c >> 6) & 0x3f)] +
+ hexTable[0x80 | (c & 0x3f)];
+ continue;
+ }
+ // Surrogate pair
+ ++i;
+
+ // This branch should never happen because all URLSearchParams entries
+ // should already be converted to USVString. But, included for
+ // completion's sake anyway.
+ if (i >= len) throw new ERR_INVALID_URI();
+
+ const c2 = str.charCodeAt(i) & 0x3ff;
+
+ lastPos = i + 1;
+ c = 0x10000 + (((c & 0x3ff) << 10) | c2);
+ out += hexTable[0xf0 | (c >> 18)] +
+ hexTable[0x80 | ((c >> 12) & 0x3f)] +
+ hexTable[0x80 | ((c >> 6) & 0x3f)] +
+ hexTable[0x80 | (c & 0x3f)];
+ }
+ if (lastPos === 0) return str;
+ if (lastPos < len) return out + str.slice(lastPos);
+ return out;
+}
+
+export default {
+ hexTable,
+ encodeStr,
+ isHexTable,
+};
diff --git a/ext/node/polyfills/internal/readline/callbacks.mjs b/ext/node/polyfills/internal/readline/callbacks.mjs
new file mode 100644
index 000000000..3be88c899
--- /dev/null
+++ b/ext/node/polyfills/internal/readline/callbacks.mjs
@@ -0,0 +1,137 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"use strict";
+
+import { ERR_INVALID_ARG_VALUE, ERR_INVALID_CURSOR_POS } from "internal:deno_node/polyfills/internal/errors.ts";
+
+import { validateFunction } from "internal:deno_node/polyfills/internal/validators.mjs";
+
+import { CSI } from "internal:deno_node/polyfills/internal/readline/utils.mjs";
+
+const {
+ kClearLine,
+ kClearScreenDown,
+ kClearToLineBeginning,
+ kClearToLineEnd,
+} = CSI;
+
+/**
+ * moves the cursor to the x and y coordinate on the given stream
+ */
+
+export function cursorTo(stream, x, y, callback) {
+ if (callback !== undefined) {
+ validateFunction(callback, "callback");
+ }
+
+ if (typeof y === "function") {
+ callback = y;
+ y = undefined;
+ }
+
+ if (Number.isNaN(x)) throw new ERR_INVALID_ARG_VALUE("x", x);
+ if (Number.isNaN(y)) throw new ERR_INVALID_ARG_VALUE("y", y);
+
+ if (stream == null || (typeof x !== "number" && typeof y !== "number")) {
+ if (typeof callback === "function") process.nextTick(callback, null);
+ return true;
+ }
+
+ if (typeof x !== "number") throw new ERR_INVALID_CURSOR_POS();
+
+ const data = typeof y !== "number" ? CSI`${x + 1}G` : CSI`${y + 1};${x + 1}H`;
+ return stream.write(data, callback);
+}
+
+/**
+ * moves the cursor relative to its current location
+ */
+
+export function moveCursor(stream, dx, dy, callback) {
+ if (callback !== undefined) {
+ validateFunction(callback, "callback");
+ }
+
+ if (stream == null || !(dx || dy)) {
+ if (typeof callback === "function") process.nextTick(callback, null);
+ return true;
+ }
+
+ let data = "";
+
+ if (dx < 0) {
+ data += CSI`${-dx}D`;
+ } else if (dx > 0) {
+ data += CSI`${dx}C`;
+ }
+
+ if (dy < 0) {
+ data += CSI`${-dy}A`;
+ } else if (dy > 0) {
+ data += CSI`${dy}B`;
+ }
+
+ return stream.write(data, callback);
+}
+
+/**
+ * clears the current line the cursor is on:
+ * -1 for left of the cursor
+ * +1 for right of the cursor
+ * 0 for the entire line
+ */
+
+export function clearLine(stream, dir, callback) {
+ if (callback !== undefined) {
+ validateFunction(callback, "callback");
+ }
+
+ if (stream === null || stream === undefined) {
+ if (typeof callback === "function") process.nextTick(callback, null);
+ return true;
+ }
+
+ const type = dir < 0
+ ? kClearToLineBeginning
+ : dir > 0
+ ? kClearToLineEnd
+ : kClearLine;
+ return stream.write(type, callback);
+}
+
+/**
+ * clears the screen from the current position of the cursor down
+ */
+
+export function clearScreenDown(stream, callback) {
+ if (callback !== undefined) {
+ validateFunction(callback, "callback");
+ }
+
+ if (stream === null || stream === undefined) {
+ if (typeof callback === "function") process.nextTick(callback, null);
+ return true;
+ }
+
+ return stream.write(kClearScreenDown, callback);
+}
diff --git a/ext/node/polyfills/internal/readline/emitKeypressEvents.mjs b/ext/node/polyfills/internal/readline/emitKeypressEvents.mjs
new file mode 100644
index 000000000..7f68dac47
--- /dev/null
+++ b/ext/node/polyfills/internal/readline/emitKeypressEvents.mjs
@@ -0,0 +1,106 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import { charLengthAt, CSI, emitKeys } from "internal:deno_node/polyfills/internal/readline/utils.mjs";
+import { kSawKeyPress } from "internal:deno_node/polyfills/internal/readline/symbols.mjs";
+import { clearTimeout, setTimeout } from "internal:deno_node/polyfills/timers.ts";
+
+const {
+ kEscape,
+} = CSI;
+
+import { StringDecoder } from "internal:deno_node/polyfills/string_decoder.ts";
+
+const KEYPRESS_DECODER = Symbol("keypress-decoder");
+const ESCAPE_DECODER = Symbol("escape-decoder");
+
+// GNU readline library - keyseq-timeout is 500ms (default)
+const ESCAPE_CODE_TIMEOUT = 500;
+
+/**
+ * accepts a readable Stream instance and makes it emit "keypress" events
+ */
+
+export function emitKeypressEvents(stream, iface = {}) {
+ if (stream[KEYPRESS_DECODER]) return;
+
+ stream[KEYPRESS_DECODER] = new StringDecoder("utf8");
+
+ stream[ESCAPE_DECODER] = emitKeys(stream);
+ stream[ESCAPE_DECODER].next();
+
+ const triggerEscape = () => stream[ESCAPE_DECODER].next("");
+ const { escapeCodeTimeout = ESCAPE_CODE_TIMEOUT } = iface;
+ let timeoutId;
+
+ function onData(input) {
+ if (stream.listenerCount("keypress") > 0) {
+ const string = stream[KEYPRESS_DECODER].write(input);
+ if (string) {
+ clearTimeout(timeoutId);
+
+ // This supports characters of length 2.
+ iface[kSawKeyPress] = charLengthAt(string, 0) === string.length;
+ iface.isCompletionEnabled = false;
+
+ let length = 0;
+ for (const character of string[Symbol.iterator]()) {
+ length += character.length;
+ if (length === string.length) {
+ iface.isCompletionEnabled = true;
+ }
+
+ try {
+ stream[ESCAPE_DECODER].next(character);
+ // Escape letter at the tail position
+ if (length === string.length && character === kEscape) {
+ timeoutId = setTimeout(triggerEscape, escapeCodeTimeout);
+ }
+ } catch (err) {
+ // If the generator throws (it could happen in the `keypress`
+ // event), we need to restart it.
+ stream[ESCAPE_DECODER] = emitKeys(stream);
+ stream[ESCAPE_DECODER].next();
+ throw err;
+ }
+ }
+ }
+ } else {
+ // Nobody's watching anyway
+ stream.removeListener("data", onData);
+ stream.on("newListener", onNewListener);
+ }
+ }
+
+ function onNewListener(event) {
+ if (event === "keypress") {
+ stream.on("data", onData);
+ stream.removeListener("newListener", onNewListener);
+ }
+ }
+
+ if (stream.listenerCount("keypress") > 0) {
+ stream.on("data", onData);
+ } else {
+ stream.on("newListener", onNewListener);
+ }
+}
diff --git a/ext/node/polyfills/internal/readline/interface.mjs b/ext/node/polyfills/internal/readline/interface.mjs
new file mode 100644
index 000000000..41d05fbf2
--- /dev/null
+++ b/ext/node/polyfills/internal/readline/interface.mjs
@@ -0,0 +1,1223 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// deno-lint-ignore-file camelcase no-inner-declarations no-this-alias
+
+import { ERR_INVALID_ARG_VALUE, ERR_USE_AFTER_CLOSE } from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ validateAbortSignal,
+ validateArray,
+ validateString,
+ validateUint32,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import {
+ // inspect,
+ getStringWidth,
+ stripVTControlCharacters,
+} from "internal:deno_node/polyfills/internal/util/inspect.mjs";
+import EventEmitter from "internal:deno_node/polyfills/events.ts";
+import { emitKeypressEvents } from "internal:deno_node/polyfills/internal/readline/emitKeypressEvents.mjs";
+import {
+ charLengthAt,
+ charLengthLeft,
+ commonPrefix,
+ kSubstringSearch,
+} from "internal:deno_node/polyfills/internal/readline/utils.mjs";
+import { clearScreenDown, cursorTo, moveCursor } from "internal:deno_node/polyfills/internal/readline/callbacks.mjs";
+import { Readable } from "internal:deno_node/polyfills/_stream.mjs";
+
+import { StringDecoder } from "internal:deno_node/polyfills/string_decoder.ts";
+import {
+ kAddHistory,
+ kDecoder,
+ kDeleteLeft,
+ kDeleteLineLeft,
+ kDeleteLineRight,
+ kDeleteRight,
+ kDeleteWordLeft,
+ kDeleteWordRight,
+ kGetDisplayPos,
+ kHistoryNext,
+ kHistoryPrev,
+ kInsertString,
+ kLine,
+ kLine_buffer,
+ kMoveCursor,
+ kNormalWrite,
+ kOldPrompt,
+ kOnLine,
+ kPreviousKey,
+ kPrompt,
+ kQuestionCallback,
+ kRefreshLine,
+ kSawKeyPress,
+ kSawReturnAt,
+ kSetRawMode,
+ kTabComplete,
+ kTabCompleter,
+ kTtyWrite,
+ kWordLeft,
+ kWordRight,
+ kWriteToOutput,
+} from "internal:deno_node/polyfills/internal/readline/symbols.mjs";
+
+const kHistorySize = 30;
+const kMincrlfDelay = 100;
+// \r\n, \n, or \r followed by something other than \n
+const lineEnding = /\r?\n|\r(?!\n)/;
+
+const kLineObjectStream = Symbol("line object stream");
+export const kQuestionCancel = Symbol("kQuestionCancel");
+export const kQuestion = Symbol("kQuestion");
+
+// GNU readline library - keyseq-timeout is 500ms (default)
+const ESCAPE_CODE_TIMEOUT = 500;
+
+export {
+ kAddHistory,
+ kDecoder,
+ kDeleteLeft,
+ kDeleteLineLeft,
+ kDeleteLineRight,
+ kDeleteRight,
+ kDeleteWordLeft,
+ kDeleteWordRight,
+ kGetDisplayPos,
+ kHistoryNext,
+ kHistoryPrev,
+ kInsertString,
+ kLine,
+ kLine_buffer,
+ kMoveCursor,
+ kNormalWrite,
+ kOldPrompt,
+ kOnLine,
+ kPreviousKey,
+ kPrompt,
+ kQuestionCallback,
+ kRefreshLine,
+ kSawKeyPress,
+ kSawReturnAt,
+ kSetRawMode,
+ kTabComplete,
+ kTabCompleter,
+ kTtyWrite,
+ kWordLeft,
+ kWordRight,
+ kWriteToOutput,
+};
+
+export function InterfaceConstructor(input, output, completer, terminal) {
+ this[kSawReturnAt] = 0;
+ // TODO(BridgeAR): Document this property. The name is not ideal, so we
+ // might want to expose an alias and document that instead.
+ this.isCompletionEnabled = true;
+ this[kSawKeyPress] = false;
+ this[kPreviousKey] = null;
+ this.escapeCodeTimeout = ESCAPE_CODE_TIMEOUT;
+ this.tabSize = 8;
+ Function.prototype.call(EventEmitter, this);
+
+ let history;
+ let historySize;
+ let removeHistoryDuplicates = false;
+ let crlfDelay;
+ let prompt = "> ";
+ let signal;
+
+ if (input?.input) {
+ // An options object was given
+ output = input.output;
+ completer = input.completer;
+ terminal = input.terminal;
+ history = input.history;
+ historySize = input.historySize;
+ signal = input.signal;
+ if (input.tabSize !== undefined) {
+ validateUint32(input.tabSize, "tabSize", true);
+ this.tabSize = input.tabSize;
+ }
+ removeHistoryDuplicates = input.removeHistoryDuplicates;
+ if (input.prompt !== undefined) {
+ prompt = input.prompt;
+ }
+ if (input.escapeCodeTimeout !== undefined) {
+ if (Number.isFinite(input.escapeCodeTimeout)) {
+ this.escapeCodeTimeout = input.escapeCodeTimeout;
+ } else {
+ throw new ERR_INVALID_ARG_VALUE(
+ "input.escapeCodeTimeout",
+ this.escapeCodeTimeout,
+ );
+ }
+ }
+
+ if (signal) {
+ validateAbortSignal(signal, "options.signal");
+ }
+
+ crlfDelay = input.crlfDelay;
+ input = input.input;
+ }
+
+ if (completer !== undefined && typeof completer !== "function") {
+ throw new ERR_INVALID_ARG_VALUE("completer", completer);
+ }
+
+ if (history === undefined) {
+ history = [];
+ } else {
+ validateArray(history, "history");
+ }
+
+ if (historySize === undefined) {
+ historySize = kHistorySize;
+ }
+
+ if (
+ typeof historySize !== "number" ||
+ Number.isNaN(historySize) ||
+ historySize < 0
+ ) {
+ throw new ERR_INVALID_ARG_VALUE.RangeError("historySize", historySize);
+ }
+
+ // Backwards compat; check the isTTY prop of the output stream
+ // when `terminal` was not specified
+ if (terminal === undefined && !(output === null || output === undefined)) {
+ terminal = !!output.isTTY;
+ }
+
+ const self = this;
+
+ this.line = "";
+ this[kSubstringSearch] = null;
+ this.output = output;
+ this.input = input;
+ this.history = history;
+ this.historySize = historySize;
+ this.removeHistoryDuplicates = !!removeHistoryDuplicates;
+ this.crlfDelay = crlfDelay
+ ? Math.max(kMincrlfDelay, crlfDelay)
+ : kMincrlfDelay;
+ this.completer = completer;
+
+ this.setPrompt(prompt);
+
+ this.terminal = !!terminal;
+
+ function onerror(err) {
+ self.emit("error", err);
+ }
+
+ function ondata(data) {
+ self[kNormalWrite](data);
+ }
+
+ function onend() {
+ if (
+ typeof self[kLine_buffer] === "string" &&
+ self[kLine_buffer].length > 0
+ ) {
+ self.emit("line", self[kLine_buffer]);
+ }
+ self.close();
+ }
+
+ function ontermend() {
+ if (typeof self.line === "string" && self.line.length > 0) {
+ self.emit("line", self.line);
+ }
+ self.close();
+ }
+
+ function onkeypress(s, key) {
+ self[kTtyWrite](s, key);
+ if (key && key.sequence) {
+ // If the key.sequence is half of a surrogate pair
+ // (>= 0xd800 and <= 0xdfff), refresh the line so
+ // the character is displayed appropriately.
+ const ch = key.sequence.codePointAt(0);
+ if (ch >= 0xd800 && ch <= 0xdfff) self[kRefreshLine]();
+ }
+ }
+
+ function onresize() {
+ self[kRefreshLine]();
+ }
+
+ this[kLineObjectStream] = undefined;
+
+ input.on("error", onerror);
+
+ if (!this.terminal) {
+ function onSelfCloseWithoutTerminal() {
+ input.removeListener("data", ondata);
+ input.removeListener("error", onerror);
+ input.removeListener("end", onend);
+ }
+
+ input.on("data", ondata);
+ input.on("end", onend);
+ self.once("close", onSelfCloseWithoutTerminal);
+ this[kDecoder] = new StringDecoder("utf8");
+ } else {
+ function onSelfCloseWithTerminal() {
+ input.removeListener("keypress", onkeypress);
+ input.removeListener("error", onerror);
+ input.removeListener("end", ontermend);
+ if (output !== null && output !== undefined) {
+ output.removeListener("resize", onresize);
+ }
+ }
+
+ emitKeypressEvents(input, this);
+
+ // `input` usually refers to stdin
+ input.on("keypress", onkeypress);
+ input.on("end", ontermend);
+
+ this[kSetRawMode](true);
+ this.terminal = true;
+
+ // Cursor position on the line.
+ this.cursor = 0;
+
+ this.historyIndex = -1;
+
+ if (output !== null && output !== undefined) {
+ output.on("resize", onresize);
+ }
+
+ self.once("close", onSelfCloseWithTerminal);
+ }
+
+ if (signal) {
+ const onAborted = () => self.close();
+ if (signal.aborted) {
+ process.nextTick(onAborted);
+ } else {
+ signal.addEventListener("abort", onAborted, { once: true });
+ self.once("close", () => signal.removeEventListener("abort", onAborted));
+ }
+ }
+
+ // Current line
+ this.line = "";
+
+ input.resume();
+}
+
+Object.setPrototypeOf(InterfaceConstructor.prototype, EventEmitter.prototype);
+Object.setPrototypeOf(InterfaceConstructor, EventEmitter);
+
+export class Interface extends InterfaceConstructor {
+ // eslint-disable-next-line no-useless-constructor
+ constructor(input, output, completer, terminal) {
+ super(input, output, completer, terminal);
+ }
+ get columns() {
+ if (this.output && this.output.columns) return this.output.columns;
+ return Infinity;
+ }
+
+ /**
+ * Sets the prompt written to the output.
+ * @param {string} prompt
+ * @returns {void}
+ */
+ setPrompt(prompt) {
+ this[kPrompt] = prompt;
+ }
+
+ /**
+ * Returns the current prompt used by `rl.prompt()`.
+ * @returns {string}
+ */
+ getPrompt() {
+ return this[kPrompt];
+ }
+
+ [kSetRawMode](mode) {
+ const wasInRawMode = this.input.isRaw;
+
+ if (typeof this.input.setRawMode === "function") {
+ this.input.setRawMode(mode);
+ }
+
+ return wasInRawMode;
+ }
+
+ /**
+ * Writes the configured `prompt` to a new line in `output`.
+ * @param {boolean} [preserveCursor]
+ * @returns {void}
+ */
+ prompt(preserveCursor) {
+ if (this.paused) this.resume();
+ if (this.terminal && process.env.TERM !== "dumb") {
+ if (!preserveCursor) this.cursor = 0;
+ this[kRefreshLine]();
+ } else {
+ this[kWriteToOutput](this[kPrompt]);
+ }
+ }
+
+ [kQuestion](query, cb) {
+ if (this.closed) {
+ throw new ERR_USE_AFTER_CLOSE("readline");
+ }
+ if (this[kQuestionCallback]) {
+ this.prompt();
+ } else {
+ this[kOldPrompt] = this[kPrompt];
+ this.setPrompt(query);
+ this[kQuestionCallback] = cb;
+ this.prompt();
+ }
+ }
+
+ [kOnLine](line) {
+ if (this[kQuestionCallback]) {
+ const cb = this[kQuestionCallback];
+ this[kQuestionCallback] = null;
+ this.setPrompt(this[kOldPrompt]);
+ cb(line);
+ } else {
+ this.emit("line", line);
+ }
+ }
+
+ [kQuestionCancel]() {
+ if (this[kQuestionCallback]) {
+ this[kQuestionCallback] = null;
+ this.setPrompt(this[kOldPrompt]);
+ this.clearLine();
+ }
+ }
+
+ [kWriteToOutput](stringToWrite) {
+ validateString(stringToWrite, "stringToWrite");
+
+ if (this.output !== null && this.output !== undefined) {
+ this.output.write(stringToWrite);
+ }
+ }
+
+ [kAddHistory]() {
+ if (this.line.length === 0) return "";
+
+ // If the history is disabled then return the line
+ if (this.historySize === 0) return this.line;
+
+ // If the trimmed line is empty then return the line
+ if (this.line.trim().length === 0) return this.line;
+
+ if (this.history.length === 0 || this.history[0] !== this.line) {
+ if (this.removeHistoryDuplicates) {
+ // Remove older history line if identical to new one
+ const dupIndex = this.history.indexOf(this.line);
+ if (dupIndex !== -1) this.history.splice(dupIndex, 1);
+ }
+
+ this.history.unshift(this.line);
+
+ // Only store so many
+ if (this.history.length > this.historySize) {
+ this.history.pop();
+ }
+ }
+
+ this.historyIndex = -1;
+
+ // The listener could change the history object, possibly
+ // to remove the last added entry if it is sensitive and should
+ // not be persisted in the history, like a password
+ const line = this.history[0];
+
+ // Emit history event to notify listeners of update
+ this.emit("history", this.history);
+
+ return line;
+ }
+
+ [kRefreshLine]() {
+ // line length
+ const line = this[kPrompt] + this.line;
+ const dispPos = this[kGetDisplayPos](line);
+ const lineCols = dispPos.cols;
+ const lineRows = dispPos.rows;
+
+ // cursor position
+ const cursorPos = this.getCursorPos();
+
+ // First move to the bottom of the current line, based on cursor pos
+ const prevRows = this.prevRows || 0;
+ if (prevRows > 0) {
+ moveCursor(this.output, 0, -prevRows);
+ }
+
+ // Cursor to left edge.
+ cursorTo(this.output, 0);
+ // erase data
+ clearScreenDown(this.output);
+
+ // Write the prompt and the current buffer content.
+ this[kWriteToOutput](line);
+
+ // Force terminal to allocate a new line
+ if (lineCols === 0) {
+ this[kWriteToOutput](" ");
+ }
+
+ // Move cursor to original position.
+ cursorTo(this.output, cursorPos.cols);
+
+ const diff = lineRows - cursorPos.rows;
+ if (diff > 0) {
+ moveCursor(this.output, 0, -diff);
+ }
+
+ this.prevRows = cursorPos.rows;
+ }
+
+ /**
+ * Closes the `readline.Interface` instance.
+ * @returns {void}
+ */
+ close() {
+ if (this.closed) return;
+ this.pause();
+ if (this.terminal) {
+ this[kSetRawMode](false);
+ }
+ this.closed = true;
+ this.emit("close");
+ }
+
+ /**
+ * Pauses the `input` stream.
+ * @returns {void | Interface}
+ */
+ pause() {
+ if (this.paused) return;
+ this.input.pause();
+ this.paused = true;
+ this.emit("pause");
+ return this;
+ }
+
+ /**
+ * Resumes the `input` stream if paused.
+ * @returns {void | Interface}
+ */
+ resume() {
+ if (!this.paused) return;
+ this.input.resume();
+ this.paused = false;
+ this.emit("resume");
+ return this;
+ }
+
+ /**
+ * Writes either `data` or a `key` sequence identified by
+ * `key` to the `output`.
+ * @param {string} d
+ * @param {{
+ * ctrl?: boolean;
+ * meta?: boolean;
+ * shift?: boolean;
+ * name?: string;
+ * }} [key]
+ * @returns {void}
+ */
+ write(d, key) {
+ if (this.paused) this.resume();
+ if (this.terminal) {
+ this[kTtyWrite](d, key);
+ } else {
+ this[kNormalWrite](d);
+ }
+ }
+
+ [kNormalWrite](b) {
+ if (b === undefined) {
+ return;
+ }
+ let string = this[kDecoder].write(b);
+ if (
+ this[kSawReturnAt] &&
+ Date.now() - this[kSawReturnAt] <= this.crlfDelay
+ ) {
+ string = string.replace(/^\n/, "");
+ this[kSawReturnAt] = 0;
+ }
+
+ // Run test() on the new string chunk, not on the entire line buffer.
+ const newPartContainsEnding = lineEnding.test(string);
+
+ if (this[kLine_buffer]) {
+ string = this[kLine_buffer] + string;
+ this[kLine_buffer] = null;
+ }
+ if (newPartContainsEnding) {
+ this[kSawReturnAt] = string.endsWith("\r") ? Date.now() : 0;
+
+ // Got one or more newlines; process into "line" events
+ const lines = string.split(lineEnding);
+ // Either '' or (conceivably) the unfinished portion of the next line
+ string = lines.pop();
+ this[kLine_buffer] = string;
+ for (let n = 0; n < lines.length; n++) this[kOnLine](lines[n]);
+ } else if (string) {
+ // No newlines this time, save what we have for next time
+ this[kLine_buffer] = string;
+ }
+ }
+
+ [kInsertString](c) {
+ if (this.cursor < this.line.length) {
+ const beg = this.line.slice(0, this.cursor);
+ const end = this.line.slice(
+ this.cursor,
+ this.line.length,
+ );
+ this.line = beg + c + end;
+ this.cursor += c.length;
+ this[kRefreshLine]();
+ } else {
+ this.line += c;
+ this.cursor += c.length;
+
+ if (this.getCursorPos().cols === 0) {
+ this[kRefreshLine]();
+ } else {
+ this[kWriteToOutput](c);
+ }
+ }
+ }
+
+ async [kTabComplete](lastKeypressWasTab) {
+ this.pause();
+ const string = this.line.slice(0, this.cursor);
+ let value;
+ try {
+ value = await this.completer(string);
+ } catch (err) {
+ // TODO(bartlomieju): inspect is not ported yet
+ // this[kWriteToOutput](`Tab completion error: ${inspect(err)}`);
+ this[kWriteToOutput](`Tab completion error: ${err}`);
+ return;
+ } finally {
+ this.resume();
+ }
+ this[kTabCompleter](lastKeypressWasTab, value);
+ }
+
+ [kTabCompleter](lastKeypressWasTab, { 0: completions, 1: completeOn }) {
+ // Result and the text that was completed.
+
+ if (!completions || completions.length === 0) {
+ return;
+ }
+
+ // If there is a common prefix to all matches, then apply that portion.
+ const prefix = commonPrefix(
+ completions.filter((e) => e !== ""),
+ );
+ if (
+ prefix.startsWith(completeOn) &&
+ prefix.length > completeOn.length
+ ) {
+ this[kInsertString](prefix.slice(completeOn.length));
+ return;
+ } else if (!completeOn.startsWith(prefix)) {
+ this.line = this.line.slice(0, this.cursor - completeOn.length) +
+ prefix +
+ this.line.slice(this.cursor, this.line.length);
+ this.cursor = this.cursor - completeOn.length + prefix.length;
+ this._refreshLine();
+ return;
+ }
+
+ if (!lastKeypressWasTab) {
+ return;
+ }
+
+ // Apply/show completions.
+ const completionsWidth = completions.map(
+ (e) => getStringWidth(e),
+ );
+ const width = Math.max.apply(completionsWidth) + 2; // 2 space padding
+ let maxColumns = Math.floor(this.columns / width) || 1;
+ if (maxColumns === Infinity) {
+ maxColumns = 1;
+ }
+ let output = "\r\n";
+ let lineIndex = 0;
+ let whitespace = 0;
+ for (let i = 0; i < completions.length; i++) {
+ const completion = completions[i];
+ if (completion === "" || lineIndex === maxColumns) {
+ output += "\r\n";
+ lineIndex = 0;
+ whitespace = 0;
+ } else {
+ output += " ".repeat(whitespace);
+ }
+ if (completion !== "") {
+ output += completion;
+ whitespace = width - completionsWidth[i];
+ lineIndex++;
+ } else {
+ output += "\r\n";
+ }
+ }
+ if (lineIndex !== 0) {
+ output += "\r\n\r\n";
+ }
+ this[kWriteToOutput](output);
+ this[kRefreshLine]();
+ }
+
+ [kWordLeft]() {
+ if (this.cursor > 0) {
+ // Reverse the string and match a word near beginning
+ // to avoid quadratic time complexity
+ const leading = this.line.slice(0, this.cursor);
+ const reversed = Array.from(leading).reverse().join("");
+ const match = reversed.match(/^\s*(?:[^\w\s]+|\w+)?/);
+ this[kMoveCursor](-match[0].length);
+ }
+ }
+
+ [kWordRight]() {
+ if (this.cursor < this.line.length) {
+ const trailing = this.line.slice(this.cursor);
+ const match = trailing.match(/^(?:\s+|[^\w\s]+|\w+)\s*/);
+ this[kMoveCursor](match[0].length);
+ }
+ }
+
+ [kDeleteLeft]() {
+ if (this.cursor > 0 && this.line.length > 0) {
+ // The number of UTF-16 units comprising the character to the left
+ const charSize = charLengthLeft(this.line, this.cursor);
+ this.line = this.line.slice(0, this.cursor - charSize) +
+ this.line.slice(this.cursor, this.line.length);
+
+ this.cursor -= charSize;
+ this[kRefreshLine]();
+ }
+ }
+
+ [kDeleteRight]() {
+ if (this.cursor < this.line.length) {
+ // The number of UTF-16 units comprising the character to the left
+ const charSize = charLengthAt(this.line, this.cursor);
+ this.line = this.line.slice(0, this.cursor) +
+ this.line.slice(
+ this.cursor + charSize,
+ this.line.length,
+ );
+ this[kRefreshLine]();
+ }
+ }
+
+ [kDeleteWordLeft]() {
+ if (this.cursor > 0) {
+ // Reverse the string and match a word near beginning
+ // to avoid quadratic time complexity
+ let leading = this.line.slice(0, this.cursor);
+ const reversed = Array.from(leading).reverse().join("");
+ const match = reversed.match(/^\s*(?:[^\w\s]+|\w+)?/);
+ leading = leading.slice(
+ 0,
+ leading.length - match[0].length,
+ );
+ this.line = leading +
+ this.line.slice(this.cursor, this.line.length);
+ this.cursor = leading.length;
+ this[kRefreshLine]();
+ }
+ }
+
+ [kDeleteWordRight]() {
+ if (this.cursor < this.line.length) {
+ const trailing = this.line.slice(this.cursor);
+ const match = trailing.match(/^(?:\s+|\W+|\w+)\s*/);
+ this.line = this.line.slice(0, this.cursor) +
+ trailing.slice(match[0].length);
+ this[kRefreshLine]();
+ }
+ }
+
+ [kDeleteLineLeft]() {
+ this.line = this.line.slice(this.cursor);
+ this.cursor = 0;
+ this[kRefreshLine]();
+ }
+
+ [kDeleteLineRight]() {
+ this.line = this.line.slice(0, this.cursor);
+ this[kRefreshLine]();
+ }
+
+ clearLine() {
+ this[kMoveCursor](+Infinity);
+ this[kWriteToOutput]("\r\n");
+ this.line = "";
+ this.cursor = 0;
+ this.prevRows = 0;
+ }
+
+ [kLine]() {
+ const line = this[kAddHistory]();
+ this.clearLine();
+ this[kOnLine](line);
+ }
+
+ // TODO(BridgeAR): Add underscores to the search part and a red background in
+ // case no match is found. This should only be the visual part and not the
+ // actual line content!
+ // TODO(BridgeAR): In case the substring based search is active and the end is
+ // reached, show a comment how to search the history as before. E.g., using
+ // <ctrl> + N. Only show this after two/three UPs or DOWNs, not on the first
+ // one.
+ [kHistoryNext]() {
+ if (this.historyIndex >= 0) {
+ const search = this[kSubstringSearch] || "";
+ let index = this.historyIndex - 1;
+ while (
+ index >= 0 &&
+ (!this.history[index].startsWith(search) ||
+ this.line === this.history[index])
+ ) {
+ index--;
+ }
+ if (index === -1) {
+ this.line = search;
+ } else {
+ this.line = this.history[index];
+ }
+ this.historyIndex = index;
+ this.cursor = this.line.length; // Set cursor to end of line.
+ this[kRefreshLine]();
+ }
+ }
+
+ [kHistoryPrev]() {
+ if (this.historyIndex < this.history.length && this.history.length) {
+ const search = this[kSubstringSearch] || "";
+ let index = this.historyIndex + 1;
+ while (
+ index < this.history.length &&
+ (!this.history[index].startsWith(search) ||
+ this.line === this.history[index])
+ ) {
+ index++;
+ }
+ if (index === this.history.length) {
+ this.line = search;
+ } else {
+ this.line = this.history[index];
+ }
+ this.historyIndex = index;
+ this.cursor = this.line.length; // Set cursor to end of line.
+ this[kRefreshLine]();
+ }
+ }
+
+ // Returns the last character's display position of the given string
+ [kGetDisplayPos](str) {
+ let offset = 0;
+ const col = this.columns;
+ let rows = 0;
+ str = stripVTControlCharacters(str);
+ for (const char of str[Symbol.iterator]()) {
+ if (char === "\n") {
+ // Rows must be incremented by 1 even if offset = 0 or col = +Infinity.
+ rows += Math.ceil(offset / col) || 1;
+ offset = 0;
+ continue;
+ }
+ // Tabs must be aligned by an offset of the tab size.
+ if (char === "\t") {
+ offset += this.tabSize - (offset % this.tabSize);
+ continue;
+ }
+ const width = getStringWidth(char);
+ if (width === 0 || width === 1) {
+ offset += width;
+ } else {
+ // width === 2
+ if ((offset + 1) % col === 0) {
+ offset++;
+ }
+ offset += 2;
+ }
+ }
+ const cols = offset % col;
+ rows += (offset - cols) / col;
+ return { cols, rows };
+ }
+
+ /**
+ * Returns the real position of the cursor in relation
+ * to the input prompt + string.
+ * @returns {{
+ * rows: number;
+ * cols: number;
+ * }}
+ */
+ getCursorPos() {
+ const strBeforeCursor = this[kPrompt] +
+ this.line.slice(0, this.cursor);
+ return this[kGetDisplayPos](strBeforeCursor);
+ }
+
+ // This function moves cursor dx places to the right
+ // (-dx for left) and refreshes the line if it is needed.
+ [kMoveCursor](dx) {
+ if (dx === 0) {
+ return;
+ }
+ const oldPos = this.getCursorPos();
+ this.cursor += dx;
+
+ // Bounds check
+ if (this.cursor < 0) {
+ this.cursor = 0;
+ } else if (this.cursor > this.line.length) {
+ this.cursor = this.line.length;
+ }
+
+ const newPos = this.getCursorPos();
+
+ // Check if cursor stayed on the line.
+ if (oldPos.rows === newPos.rows) {
+ const diffWidth = newPos.cols - oldPos.cols;
+ moveCursor(this.output, diffWidth, 0);
+ } else {
+ this[kRefreshLine]();
+ }
+ }
+
+ // Handle a write from the tty
+ [kTtyWrite](s, key) {
+ const previousKey = this[kPreviousKey];
+ key = key || {};
+ this[kPreviousKey] = key;
+
+ // Activate or deactivate substring search.
+ if (
+ (key.name === "up" || key.name === "down") &&
+ !key.ctrl &&
+ !key.meta &&
+ !key.shift
+ ) {
+ if (this[kSubstringSearch] === null) {
+ this[kSubstringSearch] = this.line.slice(
+ 0,
+ this.cursor,
+ );
+ }
+ } else if (this[kSubstringSearch] !== null) {
+ this[kSubstringSearch] = null;
+ // Reset the index in case there's no match.
+ if (this.history.length === this.historyIndex) {
+ this.historyIndex = -1;
+ }
+ }
+
+ // Ignore escape key, fixes
+ // https://github.com/nodejs/node-v0.x-archive/issues/2876.
+ if (key.name === "escape") return;
+
+ if (key.ctrl && key.shift) {
+ /* Control and shift pressed */
+ switch (key.name) {
+ // TODO(BridgeAR): The transmitted escape sequence is `\b` and that is
+ // identical to <ctrl>-h. It should have a unique escape sequence.
+ case "backspace":
+ this[kDeleteLineLeft]();
+ break;
+
+ case "delete":
+ this[kDeleteLineRight]();
+ break;
+ }
+ } else if (key.ctrl) {
+ /* Control key pressed */
+
+ switch (key.name) {
+ case "c":
+ if (this.listenerCount("SIGINT") > 0) {
+ this.emit("SIGINT");
+ } else {
+ // This readline instance is finished
+ this.close();
+ }
+ break;
+
+ case "h": // delete left
+ this[kDeleteLeft]();
+ break;
+
+ case "d": // delete right or EOF
+ if (this.cursor === 0 && this.line.length === 0) {
+ // This readline instance is finished
+ this.close();
+ } else if (this.cursor < this.line.length) {
+ this[kDeleteRight]();
+ }
+ break;
+
+ case "u": // Delete from current to start of line
+ this[kDeleteLineLeft]();
+ break;
+
+ case "k": // Delete from current to end of line
+ this[kDeleteLineRight]();
+ break;
+
+ case "a": // Go to the start of the line
+ this[kMoveCursor](-Infinity);
+ break;
+
+ case "e": // Go to the end of the line
+ this[kMoveCursor](+Infinity);
+ break;
+
+ case "b": // back one character
+ this[kMoveCursor](-charLengthLeft(this.line, this.cursor));
+ break;
+
+ case "f": // Forward one character
+ this[kMoveCursor](+charLengthAt(this.line, this.cursor));
+ break;
+
+ case "l": // Clear the whole screen
+ cursorTo(this.output, 0, 0);
+ clearScreenDown(this.output);
+ this[kRefreshLine]();
+ break;
+
+ case "n": // next history item
+ this[kHistoryNext]();
+ break;
+
+ case "p": // Previous history item
+ this[kHistoryPrev]();
+ break;
+
+ case "z":
+ if (process.platform === "win32") break;
+ if (this.listenerCount("SIGTSTP") > 0) {
+ this.emit("SIGTSTP");
+ } else {
+ process.once("SIGCONT", () => {
+ // Don't raise events if stream has already been abandoned.
+ if (!this.paused) {
+ // Stream must be paused and resumed after SIGCONT to catch
+ // SIGINT, SIGTSTP, and EOF.
+ this.pause();
+ this.emit("SIGCONT");
+ }
+ // Explicitly re-enable "raw mode" and move the cursor to
+ // the correct position.
+ // See https://github.com/joyent/node/issues/3295.
+ this[kSetRawMode](true);
+ this[kRefreshLine]();
+ });
+ this[kSetRawMode](false);
+ process.kill(process.pid, "SIGTSTP");
+ }
+ break;
+
+ case "w": // Delete backwards to a word boundary
+ // TODO(BridgeAR): The transmitted escape sequence is `\b` and that is
+ // identical to <ctrl>-h. It should have a unique escape sequence.
+ // Falls through
+ case "backspace":
+ this[kDeleteWordLeft]();
+ break;
+
+ case "delete": // Delete forward to a word boundary
+ this[kDeleteWordRight]();
+ break;
+
+ case "left":
+ this[kWordLeft]();
+ break;
+
+ case "right":
+ this[kWordRight]();
+ break;
+ }
+ } else if (key.meta) {
+ /* Meta key pressed */
+
+ switch (key.name) {
+ case "b": // backward word
+ this[kWordLeft]();
+ break;
+
+ case "f": // forward word
+ this[kWordRight]();
+ break;
+
+ case "d": // delete forward word
+ case "delete":
+ this[kDeleteWordRight]();
+ break;
+
+ case "backspace": // Delete backwards to a word boundary
+ this[kDeleteWordLeft]();
+ break;
+ }
+ } else {
+ /* No modifier keys used */
+
+ // \r bookkeeping is only relevant if a \n comes right after.
+ if (this[kSawReturnAt] && key.name !== "enter") this[kSawReturnAt] = 0;
+
+ switch (key.name) {
+ case "return": // Carriage return, i.e. \r
+ this[kSawReturnAt] = Date.now();
+ this[kLine]();
+ break;
+
+ case "enter":
+ // When key interval > crlfDelay
+ if (
+ this[kSawReturnAt] === 0 ||
+ Date.now() - this[kSawReturnAt] > this.crlfDelay
+ ) {
+ this[kLine]();
+ }
+ this[kSawReturnAt] = 0;
+ break;
+
+ case "backspace":
+ this[kDeleteLeft]();
+ break;
+
+ case "delete":
+ this[kDeleteRight]();
+ break;
+
+ case "left":
+ // Obtain the code point to the left
+ this[kMoveCursor](-charLengthLeft(this.line, this.cursor));
+ break;
+
+ case "right":
+ this[kMoveCursor](+charLengthAt(this.line, this.cursor));
+ break;
+
+ case "home":
+ this[kMoveCursor](-Infinity);
+ break;
+
+ case "end":
+ this[kMoveCursor](+Infinity);
+ break;
+
+ case "up":
+ this[kHistoryPrev]();
+ break;
+
+ case "down":
+ this[kHistoryNext]();
+ break;
+
+ case "tab":
+ // If tab completion enabled, do that...
+ if (
+ typeof this.completer === "function" &&
+ this.isCompletionEnabled
+ ) {
+ const lastKeypressWasTab = previousKey &&
+ previousKey.name === "tab";
+ this[kTabComplete](lastKeypressWasTab);
+ break;
+ }
+ // falls through
+ default:
+ if (typeof s === "string" && s) {
+ const lines = s.split(/\r\n|\n|\r/);
+ for (let i = 0, len = lines.length; i < len; i++) {
+ if (i > 0) {
+ this[kLine]();
+ }
+ this[kInsertString](lines[i]);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates an `AsyncIterator` object that iterates through
+ * each line in the input stream as a string.
+ * @typedef {{
+ * [Symbol.asyncIterator]: () => InterfaceAsyncIterator,
+ * next: () => Promise<string>
+ * }} InterfaceAsyncIterator
+ * @returns {InterfaceAsyncIterator}
+ */
+ [Symbol.asyncIterator]() {
+ if (this[kLineObjectStream] === undefined) {
+ const readable = new Readable({
+ objectMode: true,
+ read: () => {
+ this.resume();
+ },
+ destroy: (err, cb) => {
+ this.off("line", lineListener);
+ this.off("close", closeListener);
+ this.close();
+ cb(err);
+ },
+ });
+ const lineListener = (input) => {
+ if (!readable.push(input)) {
+ // TODO(rexagod): drain to resume flow
+ this.pause();
+ }
+ };
+ const closeListener = () => {
+ readable.push(null);
+ };
+ const errorListener = (err) => {
+ readable.destroy(err);
+ };
+ this.on("error", errorListener);
+ this.on("line", lineListener);
+ this.on("close", closeListener);
+ this[kLineObjectStream] = readable;
+ }
+
+ return this[kLineObjectStream][Symbol.asyncIterator]();
+ }
+}
diff --git a/ext/node/polyfills/internal/readline/promises.mjs b/ext/node/polyfills/internal/readline/promises.mjs
new file mode 100644
index 000000000..36aa3de12
--- /dev/null
+++ b/ext/node/polyfills/internal/readline/promises.mjs
@@ -0,0 +1,139 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+
+import { ArrayPrototypeJoin, ArrayPrototypePush } from "internal:deno_node/polyfills/internal/primordials.mjs";
+
+import { CSI } from "internal:deno_node/polyfills/internal/readline/utils.mjs";
+import { validateBoolean, validateInteger } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { isWritable } from "internal:deno_node/polyfills/internal/streams/utils.mjs";
+import { ERR_INVALID_ARG_TYPE } from "internal:deno_node/polyfills/internal/errors.ts";
+
+const {
+ kClearToLineBeginning,
+ kClearToLineEnd,
+ kClearLine,
+ kClearScreenDown,
+} = CSI;
+
+export class Readline {
+ #autoCommit = false;
+ #stream;
+ #todo = [];
+
+ constructor(stream, options = undefined) {
+ if (!isWritable(stream)) {
+ throw new ERR_INVALID_ARG_TYPE("stream", "Writable", stream);
+ }
+ this.#stream = stream;
+ if (options?.autoCommit != null) {
+ validateBoolean(options.autoCommit, "options.autoCommit");
+ this.#autoCommit = options.autoCommit;
+ }
+ }
+
+ /**
+ * Moves the cursor to the x and y coordinate on the given stream.
+ * @param {integer} x
+ * @param {integer} [y]
+ * @returns {Readline} this
+ */
+ cursorTo(x, y = undefined) {
+ validateInteger(x, "x");
+ if (y != null) validateInteger(y, "y");
+
+ const data = y == null ? CSI`${x + 1}G` : CSI`${y + 1};${x + 1}H`;
+ if (this.#autoCommit) process.nextTick(() => this.#stream.write(data));
+ else ArrayPrototypePush(this.#todo, data);
+
+ return this;
+ }
+
+ /**
+ * Moves the cursor relative to its current location.
+ * @param {integer} dx
+ * @param {integer} dy
+ * @returns {Readline} this
+ */
+ moveCursor(dx, dy) {
+ if (dx || dy) {
+ validateInteger(dx, "dx");
+ validateInteger(dy, "dy");
+
+ let data = "";
+
+ if (dx < 0) {
+ data += CSI`${-dx}D`;
+ } else if (dx > 0) {
+ data += CSI`${dx}C`;
+ }
+
+ if (dy < 0) {
+ data += CSI`${-dy}A`;
+ } else if (dy > 0) {
+ data += CSI`${dy}B`;
+ }
+ if (this.#autoCommit) process.nextTick(() => this.#stream.write(data));
+ else ArrayPrototypePush(this.#todo, data);
+ }
+ return this;
+ }
+
+ /**
+ * Clears the current line the cursor is on.
+ * @param {-1|0|1} dir Direction to clear:
+ * -1 for left of the cursor
+ * +1 for right of the cursor
+ * 0 for the entire line
+ * @returns {Readline} this
+ */
+ clearLine(dir) {
+ validateInteger(dir, "dir", -1, 1);
+
+ const data = dir < 0
+ ? kClearToLineBeginning
+ : dir > 0
+ ? kClearToLineEnd
+ : kClearLine;
+ if (this.#autoCommit) process.nextTick(() => this.#stream.write(data));
+ else ArrayPrototypePush(this.#todo, data);
+ return this;
+ }
+
+ /**
+ * Clears the screen from the current position of the cursor down.
+ * @returns {Readline} this
+ */
+ clearScreenDown() {
+ if (this.#autoCommit) {
+ process.nextTick(() => this.#stream.write(kClearScreenDown));
+ } else {
+ ArrayPrototypePush(this.#todo, kClearScreenDown);
+ }
+ return this;
+ }
+
+ /**
+ * Sends all the pending actions to the associated `stream` and clears the
+ * internal list of pending actions.
+ * @returns {Promise<void>} Resolves when all pending actions have been
+ * flushed to the associated `stream`.
+ */
+ commit() {
+ return new Promise((resolve) => {
+ this.#stream.write(ArrayPrototypeJoin(this.#todo, ""), resolve);
+ this.#todo = [];
+ });
+ }
+
+ /**
+ * Clears the internal list of pending actions without sending it to the
+ * associated `stream`.
+ * @returns {Readline} this
+ */
+ rollback() {
+ this.#todo = [];
+ return this;
+ }
+}
+
+export default Readline;
diff --git a/ext/node/polyfills/internal/readline/symbols.mjs b/ext/node/polyfills/internal/readline/symbols.mjs
new file mode 100644
index 000000000..3a05c64d2
--- /dev/null
+++ b/ext/node/polyfills/internal/readline/symbols.mjs
@@ -0,0 +1,34 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+
+export const kAddHistory = Symbol("_addHistory");
+export const kDecoder = Symbol("_decoder");
+export const kDeleteLeft = Symbol("_deleteLeft");
+export const kDeleteLineLeft = Symbol("_deleteLineLeft");
+export const kDeleteLineRight = Symbol("_deleteLineRight");
+export const kDeleteRight = Symbol("_deleteRight");
+export const kDeleteWordLeft = Symbol("_deleteWordLeft");
+export const kDeleteWordRight = Symbol("_deleteWordRight");
+export const kGetDisplayPos = Symbol("_getDisplayPos");
+export const kHistoryNext = Symbol("_historyNext");
+export const kHistoryPrev = Symbol("_historyPrev");
+export const kInsertString = Symbol("_insertString");
+export const kLine = Symbol("_line");
+export const kLine_buffer = Symbol("_line_buffer");
+export const kMoveCursor = Symbol("_moveCursor");
+export const kNormalWrite = Symbol("_normalWrite");
+export const kOldPrompt = Symbol("_oldPrompt");
+export const kOnLine = Symbol("_onLine");
+export const kPreviousKey = Symbol("_previousKey");
+export const kPrompt = Symbol("_prompt");
+export const kQuestionCallback = Symbol("_questionCallback");
+export const kRefreshLine = Symbol("_refreshLine");
+export const kSawKeyPress = Symbol("_sawKeyPress");
+export const kSawReturnAt = Symbol("_sawReturnAt");
+export const kSetRawMode = Symbol("_setRawMode");
+export const kTabComplete = Symbol("_tabComplete");
+export const kTabCompleter = Symbol("_tabCompleter");
+export const kTtyWrite = Symbol("_ttyWrite");
+export const kWordLeft = Symbol("_wordLeft");
+export const kWordRight = Symbol("_wordRight");
+export const kWriteToOutput = Symbol("_writeToOutput");
diff --git a/ext/node/polyfills/internal/readline/utils.mjs b/ext/node/polyfills/internal/readline/utils.mjs
new file mode 100644
index 000000000..6224f112b
--- /dev/null
+++ b/ext/node/polyfills/internal/readline/utils.mjs
@@ -0,0 +1,580 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"use strict";
+
+const kUTF16SurrogateThreshold = 0x10000; // 2 ** 16
+const kEscape = "\x1b";
+export const kSubstringSearch = Symbol("kSubstringSearch");
+
+export function CSI(strings, ...args) {
+ let ret = `${kEscape}[`;
+ for (let n = 0; n < strings.length; n++) {
+ ret += strings[n];
+ if (n < args.length) {
+ ret += args[n];
+ }
+ }
+ return ret;
+}
+
+CSI.kEscape = kEscape;
+CSI.kClearToLineBeginning = CSI`1K`;
+CSI.kClearToLineEnd = CSI`0K`;
+CSI.kClearLine = CSI`2K`;
+CSI.kClearScreenDown = CSI`0J`;
+
+// TODO(BridgeAR): Treat combined characters as single character, i.e,
+// 'a\u0301' and '\u0301a' (both have the same visual output).
+// Check Canonical_Combining_Class in
+// http://userguide.icu-project.org/strings/properties
+export function charLengthLeft(str, i) {
+ if (i <= 0) {
+ return 0;
+ }
+ if (
+ (i > 1 &&
+ str.codePointAt(i - 2) >= kUTF16SurrogateThreshold) ||
+ str.codePointAt(i - 1) >= kUTF16SurrogateThreshold
+ ) {
+ return 2;
+ }
+ return 1;
+}
+
+export function charLengthAt(str, i) {
+ if (str.length <= i) {
+ // Pretend to move to the right. This is necessary to autocomplete while
+ // moving to the right.
+ return 1;
+ }
+ return str.codePointAt(i) >= kUTF16SurrogateThreshold ? 2 : 1;
+}
+
+/*
+ Some patterns seen in terminal key escape codes, derived from combos seen
+ at http://www.midnight-commander.org/browser/lib/tty/key.c
+
+ ESC letter
+ ESC [ letter
+ ESC [ modifier letter
+ ESC [ 1 ; modifier letter
+ ESC [ num char
+ ESC [ num ; modifier char
+ ESC O letter
+ ESC O modifier letter
+ ESC O 1 ; modifier letter
+ ESC N letter
+ ESC [ [ num ; modifier char
+ ESC [ [ 1 ; modifier letter
+ ESC ESC [ num char
+ ESC ESC O letter
+
+ - char is usually ~ but $ and ^ also happen with rxvt
+ - modifier is 1 +
+ (shift * 1) +
+ (left_alt * 2) +
+ (ctrl * 4) +
+ (right_alt * 8)
+ - two leading ESCs apparently mean the same as one leading ESC
+*/
+export function* emitKeys(stream) {
+ while (true) {
+ let ch = yield;
+ let s = ch;
+ let escaped = false;
+ const key = {
+ sequence: null,
+ name: undefined,
+ ctrl: false,
+ meta: false,
+ shift: false,
+ };
+
+ if (ch === kEscape) {
+ escaped = true;
+ s += ch = yield;
+
+ if (ch === kEscape) {
+ s += ch = yield;
+ }
+ }
+
+ if (escaped && (ch === "O" || ch === "[")) {
+ // ANSI escape sequence
+ let code = ch;
+ let modifier = 0;
+
+ if (ch === "O") {
+ // ESC O letter
+ // ESC O modifier letter
+ s += ch = yield;
+
+ if (ch >= "0" && ch <= "9") {
+ modifier = (ch >> 0) - 1;
+ s += ch = yield;
+ }
+
+ code += ch;
+ } else if (ch === "[") {
+ // ESC [ letter
+ // ESC [ modifier letter
+ // ESC [ [ modifier letter
+ // ESC [ [ num char
+ s += ch = yield;
+
+ if (ch === "[") {
+ // \x1b[[A
+ // ^--- escape codes might have a second bracket
+ code += ch;
+ s += ch = yield;
+ }
+
+ /*
+ * Here and later we try to buffer just enough data to get
+ * a complete ascii sequence.
+ *
+ * We have basically two classes of ascii characters to process:
+ *
+ * 1. `\x1b[24;5~` should be parsed as { code: '[24~', modifier: 5 }
+ *
+ * This particular example is featuring Ctrl+F12 in xterm.
+ *
+ * - `;5` part is optional, e.g. it could be `\x1b[24~`
+ * - first part can contain one or two digits
+ *
+ * So the generic regexp is like /^\d\d?(;\d)?[~^$]$/
+ *
+ * 2. `\x1b[1;5H` should be parsed as { code: '[H', modifier: 5 }
+ *
+ * This particular example is featuring Ctrl+Home in xterm.
+ *
+ * - `1;5` part is optional, e.g. it could be `\x1b[H`
+ * - `1;` part is optional, e.g. it could be `\x1b[5H`
+ *
+ * So the generic regexp is like /^((\d;)?\d)?[A-Za-z]$/
+ */
+ const cmdStart = s.length - 1;
+
+ // Skip one or two leading digits
+ if (ch >= "0" && ch <= "9") {
+ s += ch = yield;
+
+ if (ch >= "0" && ch <= "9") {
+ s += ch = yield;
+ }
+ }
+
+ // skip modifier
+ if (ch === ";") {
+ s += ch = yield;
+
+ if (ch >= "0" && ch <= "9") {
+ s += yield;
+ }
+ }
+
+ /*
+ * We buffered enough data, now trying to extract code
+ * and modifier from it
+ */
+ const cmd = s.slice(cmdStart);
+ let match;
+
+ if ((match = cmd.match(/^(\d\d?)(;(\d))?([~^$])$/))) {
+ code += match[1] + match[4];
+ modifier = (match[3] || 1) - 1;
+ } else if (
+ (match = cmd.match(/^((\d;)?(\d))?([A-Za-z])$/))
+ ) {
+ code += match[4];
+ modifier = (match[3] || 1) - 1;
+ } else {
+ code += cmd;
+ }
+ }
+
+ // Parse the key modifier
+ key.ctrl = !!(modifier & 4);
+ key.meta = !!(modifier & 10);
+ key.shift = !!(modifier & 1);
+ key.code = code;
+
+ // Parse the key itself
+ switch (code) {
+ /* xterm/gnome ESC [ letter (with modifier) */
+ case "[P":
+ key.name = "f1";
+ break;
+ case "[Q":
+ key.name = "f2";
+ break;
+ case "[R":
+ key.name = "f3";
+ break;
+ case "[S":
+ key.name = "f4";
+ break;
+
+ /* xterm/gnome ESC O letter (without modifier) */
+
+ case "OP":
+ key.name = "f1";
+ break;
+ case "OQ":
+ key.name = "f2";
+ break;
+ case "OR":
+ key.name = "f3";
+ break;
+ case "OS":
+ key.name = "f4";
+ break;
+
+ /* xterm/rxvt ESC [ number ~ */
+
+ case "[11~":
+ key.name = "f1";
+ break;
+ case "[12~":
+ key.name = "f2";
+ break;
+ case "[13~":
+ key.name = "f3";
+ break;
+ case "[14~":
+ key.name = "f4";
+ break;
+
+ /* from Cygwin and used in libuv */
+
+ case "[[A":
+ key.name = "f1";
+ break;
+ case "[[B":
+ key.name = "f2";
+ break;
+ case "[[C":
+ key.name = "f3";
+ break;
+ case "[[D":
+ key.name = "f4";
+ break;
+ case "[[E":
+ key.name = "f5";
+ break;
+
+ /* common */
+
+ case "[15~":
+ key.name = "f5";
+ break;
+ case "[17~":
+ key.name = "f6";
+ break;
+ case "[18~":
+ key.name = "f7";
+ break;
+ case "[19~":
+ key.name = "f8";
+ break;
+ case "[20~":
+ key.name = "f9";
+ break;
+ case "[21~":
+ key.name = "f10";
+ break;
+ case "[23~":
+ key.name = "f11";
+ break;
+ case "[24~":
+ key.name = "f12";
+ break;
+
+ /* xterm ESC [ letter */
+
+ case "[A":
+ key.name = "up";
+ break;
+ case "[B":
+ key.name = "down";
+ break;
+ case "[C":
+ key.name = "right";
+ break;
+ case "[D":
+ key.name = "left";
+ break;
+ case "[E":
+ key.name = "clear";
+ break;
+ case "[F":
+ key.name = "end";
+ break;
+ case "[H":
+ key.name = "home";
+ break;
+
+ /* xterm/gnome ESC O letter */
+
+ case "OA":
+ key.name = "up";
+ break;
+ case "OB":
+ key.name = "down";
+ break;
+ case "OC":
+ key.name = "right";
+ break;
+ case "OD":
+ key.name = "left";
+ break;
+ case "OE":
+ key.name = "clear";
+ break;
+ case "OF":
+ key.name = "end";
+ break;
+ case "OH":
+ key.name = "home";
+ break;
+
+ /* xterm/rxvt ESC [ number ~ */
+
+ case "[1~":
+ key.name = "home";
+ break;
+ case "[2~":
+ key.name = "insert";
+ break;
+ case "[3~":
+ key.name = "delete";
+ break;
+ case "[4~":
+ key.name = "end";
+ break;
+ case "[5~":
+ key.name = "pageup";
+ break;
+ case "[6~":
+ key.name = "pagedown";
+ break;
+
+ /* putty */
+
+ case "[[5~":
+ key.name = "pageup";
+ break;
+ case "[[6~":
+ key.name = "pagedown";
+ break;
+
+ /* rxvt */
+
+ case "[7~":
+ key.name = "home";
+ break;
+ case "[8~":
+ key.name = "end";
+ break;
+
+ /* rxvt keys with modifiers */
+
+ case "[a":
+ key.name = "up";
+ key.shift = true;
+ break;
+ case "[b":
+ key.name = "down";
+ key.shift = true;
+ break;
+ case "[c":
+ key.name = "right";
+ key.shift = true;
+ break;
+ case "[d":
+ key.name = "left";
+ key.shift = true;
+ break;
+ case "[e":
+ key.name = "clear";
+ key.shift = true;
+ break;
+
+ case "[2$":
+ key.name = "insert";
+ key.shift = true;
+ break;
+ case "[3$":
+ key.name = "delete";
+ key.shift = true;
+ break;
+ case "[5$":
+ key.name = "pageup";
+ key.shift = true;
+ break;
+ case "[6$":
+ key.name = "pagedown";
+ key.shift = true;
+ break;
+ case "[7$":
+ key.name = "home";
+ key.shift = true;
+ break;
+ case "[8$":
+ key.name = "end";
+ key.shift = true;
+ break;
+
+ case "Oa":
+ key.name = "up";
+ key.ctrl = true;
+ break;
+ case "Ob":
+ key.name = "down";
+ key.ctrl = true;
+ break;
+ case "Oc":
+ key.name = "right";
+ key.ctrl = true;
+ break;
+ case "Od":
+ key.name = "left";
+ key.ctrl = true;
+ break;
+ case "Oe":
+ key.name = "clear";
+ key.ctrl = true;
+ break;
+
+ case "[2^":
+ key.name = "insert";
+ key.ctrl = true;
+ break;
+ case "[3^":
+ key.name = "delete";
+ key.ctrl = true;
+ break;
+ case "[5^":
+ key.name = "pageup";
+ key.ctrl = true;
+ break;
+ case "[6^":
+ key.name = "pagedown";
+ key.ctrl = true;
+ break;
+ case "[7^":
+ key.name = "home";
+ key.ctrl = true;
+ break;
+ case "[8^":
+ key.name = "end";
+ key.ctrl = true;
+ break;
+
+ /* misc. */
+
+ case "[Z":
+ key.name = "tab";
+ key.shift = true;
+ break;
+ default:
+ key.name = "undefined";
+ break;
+ }
+ } else if (ch === "\r") {
+ // carriage return
+ key.name = "return";
+ key.meta = escaped;
+ } else if (ch === "\n") {
+ // Enter, should have been called linefeed
+ key.name = "enter";
+ key.meta = escaped;
+ } else if (ch === "\t") {
+ // tab
+ key.name = "tab";
+ key.meta = escaped;
+ } else if (ch === "\b" || ch === "\x7f") {
+ // backspace or ctrl+h
+ key.name = "backspace";
+ key.meta = escaped;
+ } else if (ch === kEscape) {
+ // escape key
+ key.name = "escape";
+ key.meta = escaped;
+ } else if (ch === " ") {
+ key.name = "space";
+ key.meta = escaped;
+ } else if (!escaped && ch <= "\x1a") {
+ // ctrl+letter
+ key.name = String.fromCharCode(
+ ch.charCodeAt() + "a".charCodeAt() - 1,
+ );
+ key.ctrl = true;
+ } else if (/^[0-9A-Za-z]$/.test(ch)) {
+ // Letter, number, shift+letter
+ key.name = ch.toLowerCase();
+ key.shift = /^[A-Z]$/.test(ch);
+ key.meta = escaped;
+ } else if (escaped) {
+ // Escape sequence timeout
+ key.name = ch.length ? undefined : "escape";
+ key.meta = true;
+ }
+
+ key.sequence = s;
+
+ if (s.length !== 0 && (key.name !== undefined || escaped)) {
+ /* Named character or sequence */
+ stream.emit("keypress", escaped ? undefined : s, key);
+ } else if (charLengthAt(s, 0) === s.length) {
+ /* Single unnamed character, e.g. "." */
+ stream.emit("keypress", s, key);
+ }
+ /* Unrecognized or broken escape sequence, don't emit anything */
+ }
+}
+
+// This runs in O(n log n).
+export function commonPrefix(strings) {
+ if (strings.length === 1) {
+ return strings[0];
+ }
+ const sorted = strings.slice().sort();
+ const min = sorted[0];
+ const max = sorted[sorted.length - 1];
+ for (let i = 0; i < min.length; i++) {
+ if (min[i] !== max[i]) {
+ return min.slice(0, i);
+ }
+ }
+ return min;
+}
+
+export default {
+ CSI,
+ charLengthAt,
+ charLengthLeft,
+ emitKeys,
+ commonPrefix,
+ kSubstringSearch,
+};
diff --git a/ext/node/polyfills/internal/stream_base_commons.ts b/ext/node/polyfills/internal/stream_base_commons.ts
new file mode 100644
index 000000000..dd1c74d0f
--- /dev/null
+++ b/ext/node/polyfills/internal/stream_base_commons.ts
@@ -0,0 +1,355 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import { ownerSymbol } from "internal:deno_node/polyfills/internal/async_hooks.ts";
+import {
+ kArrayBufferOffset,
+ kBytesWritten,
+ kLastWriteWasAsync,
+ LibuvStreamWrap,
+ streamBaseState,
+ WriteWrap,
+} from "internal:deno_node/polyfills/internal_binding/stream_wrap.ts";
+import { isUint8Array } from "internal:deno_node/polyfills/internal/util/types.ts";
+import { errnoException } from "internal:deno_node/polyfills/internal/errors.ts";
+import {
+ getTimerDuration,
+ kTimeout,
+} from "internal:deno_node/polyfills/internal/timers.mjs";
+import { setUnrefTimeout } from "internal:deno_node/polyfills/timers.ts";
+import { validateFunction } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { codeMap } from "internal:deno_node/polyfills/internal_binding/uv.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+
+export const kMaybeDestroy = Symbol("kMaybeDestroy");
+export const kUpdateTimer = Symbol("kUpdateTimer");
+export const kAfterAsyncWrite = Symbol("kAfterAsyncWrite");
+export const kHandle = Symbol("kHandle");
+export const kSession = Symbol("kSession");
+export const kBuffer = Symbol("kBuffer");
+export const kBufferGen = Symbol("kBufferGen");
+export const kBufferCb = Symbol("kBufferCb");
+
+// deno-lint-ignore no-explicit-any
+function handleWriteReq(req: any, data: any, encoding: string) {
+ const { handle } = req;
+
+ switch (encoding) {
+ case "buffer": {
+ const ret = handle.writeBuffer(req, data);
+
+ if (streamBaseState[kLastWriteWasAsync]) {
+ req.buffer = data;
+ }
+
+ return ret;
+ }
+ case "latin1":
+ case "binary":
+ return handle.writeLatin1String(req, data);
+ case "utf8":
+ case "utf-8":
+ return handle.writeUtf8String(req, data);
+ case "ascii":
+ return handle.writeAsciiString(req, data);
+ case "ucs2":
+ case "ucs-2":
+ case "utf16le":
+ case "utf-16le":
+ return handle.writeUcs2String(req, data);
+ default: {
+ const buffer = Buffer.from(data, encoding);
+ const ret = handle.writeBuffer(req, buffer);
+
+ if (streamBaseState[kLastWriteWasAsync]) {
+ req.buffer = buffer;
+ }
+
+ return ret;
+ }
+ }
+}
+
+// deno-lint-ignore no-explicit-any
+function onWriteComplete(this: any, status: number) {
+ let stream = this.handle[ownerSymbol];
+
+ if (stream.constructor.name === "ReusedHandle") {
+ stream = stream.handle;
+ }
+
+ if (stream.destroyed) {
+ if (typeof this.callback === "function") {
+ this.callback(null);
+ }
+
+ return;
+ }
+
+ if (status < 0) {
+ const ex = errnoException(status, "write", this.error);
+
+ if (typeof this.callback === "function") {
+ this.callback(ex);
+ } else {
+ stream.destroy(ex);
+ }
+
+ return;
+ }
+
+ stream[kUpdateTimer]();
+ stream[kAfterAsyncWrite](this);
+
+ if (typeof this.callback === "function") {
+ this.callback(null);
+ }
+}
+
+function createWriteWrap(
+ handle: LibuvStreamWrap,
+ callback: (err?: Error | null) => void,
+) {
+ const req = new WriteWrap<LibuvStreamWrap>();
+
+ req.handle = handle;
+ req.oncomplete = onWriteComplete;
+ req.async = false;
+ req.bytes = 0;
+ req.buffer = null;
+ req.callback = callback;
+
+ return req;
+}
+
+export function writevGeneric(
+ // deno-lint-ignore no-explicit-any
+ owner: any,
+ // deno-lint-ignore no-explicit-any
+ data: any,
+ cb: (err?: Error | null) => void,
+) {
+ const req = createWriteWrap(owner[kHandle], cb);
+ const allBuffers = data.allBuffers;
+ let chunks;
+
+ if (allBuffers) {
+ chunks = data;
+
+ for (let i = 0; i < data.length; i++) {
+ data[i] = data[i].chunk;
+ }
+ } else {
+ chunks = new Array(data.length << 1);
+
+ for (let i = 0; i < data.length; i++) {
+ const entry = data[i];
+ chunks[i * 2] = entry.chunk;
+ chunks[i * 2 + 1] = entry.encoding;
+ }
+ }
+
+ const err = req.handle.writev(req, chunks, allBuffers);
+
+ // Retain chunks
+ if (err === 0) {
+ req._chunks = chunks;
+ }
+
+ afterWriteDispatched(req, err, cb);
+
+ return req;
+}
+
+export function writeGeneric(
+ // deno-lint-ignore no-explicit-any
+ owner: any,
+ // deno-lint-ignore no-explicit-any
+ data: any,
+ encoding: string,
+ cb: (err?: Error | null) => void,
+) {
+ const req = createWriteWrap(owner[kHandle], cb);
+ const err = handleWriteReq(req, data, encoding);
+
+ afterWriteDispatched(req, err, cb);
+
+ return req;
+}
+
+function afterWriteDispatched(
+ // deno-lint-ignore no-explicit-any
+ req: any,
+ err: number,
+ cb: (err?: Error | null) => void,
+) {
+ req.bytes = streamBaseState[kBytesWritten];
+ req.async = !!streamBaseState[kLastWriteWasAsync];
+
+ if (err !== 0) {
+ return cb(errnoException(err, "write", req.error));
+ }
+
+ if (!req.async && typeof req.callback === "function") {
+ req.callback();
+ }
+}
+
+// Here we differ from Node slightly. Node makes use of the `kReadBytesOrError`
+// entry of the `streamBaseState` array from the `stream_wrap` internal binding.
+// Here we pass the `nread` value directly to this method as async Deno APIs
+// don't grant us the ability to rely on some mutable array entry setting.
+export function onStreamRead(
+ // deno-lint-ignore no-explicit-any
+ this: any,
+ arrayBuffer: Uint8Array,
+ nread: number,
+) {
+ // deno-lint-ignore no-this-alias
+ const handle = this;
+
+ let stream = this[ownerSymbol];
+
+ if (stream.constructor.name === "ReusedHandle") {
+ stream = stream.handle;
+ }
+
+ stream[kUpdateTimer]();
+
+ if (nread > 0 && !stream.destroyed) {
+ let ret;
+ let result;
+ const userBuf = stream[kBuffer];
+
+ if (userBuf) {
+ result = stream[kBufferCb](nread, userBuf) !== false;
+ const bufGen = stream[kBufferGen];
+
+ if (bufGen !== null) {
+ const nextBuf = bufGen();
+
+ if (isUint8Array(nextBuf)) {
+ stream[kBuffer] = ret = nextBuf;
+ }
+ }
+ } else {
+ const offset = streamBaseState[kArrayBufferOffset];
+ const buf = Buffer.from(arrayBuffer, offset, nread);
+ result = stream.push(buf);
+ }
+
+ if (!result) {
+ handle.reading = false;
+
+ if (!stream.destroyed) {
+ const err = handle.readStop();
+
+ if (err) {
+ stream.destroy(errnoException(err, "read"));
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ if (nread === 0) {
+ return;
+ }
+
+ if (nread !== codeMap.get("EOF")) {
+ // CallJSOnreadMethod expects the return value to be a buffer.
+ // Ref: https://github.com/nodejs/node/pull/34375
+ stream.destroy(errnoException(nread, "read"));
+
+ return;
+ }
+
+ // Defer this until we actually emit end
+ if (stream._readableState.endEmitted) {
+ if (stream[kMaybeDestroy]) {
+ stream[kMaybeDestroy]();
+ }
+ } else {
+ if (stream[kMaybeDestroy]) {
+ stream.on("end", stream[kMaybeDestroy]);
+ }
+
+ if (handle.readStop) {
+ const err = handle.readStop();
+
+ if (err) {
+ // CallJSOnreadMethod expects the return value to be a buffer.
+ // Ref: https://github.com/nodejs/node/pull/34375
+ stream.destroy(errnoException(err, "read"));
+
+ return;
+ }
+ }
+
+ // Push a null to signal the end of data.
+ // Do it before `maybeDestroy` for correct order of events:
+ // `end` -> `close`
+ stream.push(null);
+ stream.read(0);
+ }
+}
+
+export function setStreamTimeout(
+ // deno-lint-ignore no-explicit-any
+ this: any,
+ msecs: number,
+ callback?: () => void,
+) {
+ if (this.destroyed) {
+ return this;
+ }
+
+ this.timeout = msecs;
+
+ // Type checking identical to timers.enroll()
+ msecs = getTimerDuration(msecs, "msecs");
+
+ // Attempt to clear an existing timer in both cases -
+ // even if it will be rescheduled we don't want to leak an existing timer.
+ clearTimeout(this[kTimeout]);
+
+ if (msecs === 0) {
+ if (callback !== undefined) {
+ validateFunction(callback, "callback");
+ this.removeListener("timeout", callback);
+ }
+ } else {
+ this[kTimeout] = setUnrefTimeout(this._onTimeout.bind(this), msecs);
+
+ if (this[kSession]) {
+ this[kSession][kUpdateTimer]();
+ }
+
+ if (callback !== undefined) {
+ validateFunction(callback, "callback");
+ this.once("timeout", callback);
+ }
+ }
+
+ return this;
+}
diff --git a/ext/node/polyfills/internal/streams/add-abort-signal.mjs b/ext/node/polyfills/internal/streams/add-abort-signal.mjs
new file mode 100644
index 000000000..5d7512f1c
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/add-abort-signal.mjs
@@ -0,0 +1,48 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import { AbortError, ERR_INVALID_ARG_TYPE } from "internal:deno_node/polyfills/internal/errors.ts";
+import eos from "internal:deno_node/polyfills/internal/streams/end-of-stream.mjs";
+
+// This method is inlined here for readable-stream
+// It also does not allow for signal to not exist on the stream
+// https://github.com/nodejs/node/pull/36061#discussion_r533718029
+const validateAbortSignal = (signal, name) => {
+ if (
+ typeof signal !== "object" ||
+ !("aborted" in signal)
+ ) {
+ throw new ERR_INVALID_ARG_TYPE(name, "AbortSignal", signal);
+ }
+};
+
+function isStream(obj) {
+ return !!(obj && typeof obj.pipe === "function");
+}
+
+function addAbortSignal(signal, stream) {
+ validateAbortSignal(signal, "signal");
+ if (!isStream(stream)) {
+ throw new ERR_INVALID_ARG_TYPE("stream", "stream.Stream", stream);
+ }
+ return addAbortSignalNoValidate(signal, stream);
+}
+function addAbortSignalNoValidate(signal, stream) {
+ if (typeof signal !== "object" || !("aborted" in signal)) {
+ return stream;
+ }
+ const onAbort = () => {
+ stream.destroy(new AbortError());
+ };
+ if (signal.aborted) {
+ onAbort();
+ } else {
+ signal.addEventListener("abort", onAbort);
+ eos(stream, () => signal.removeEventListener("abort", onAbort));
+ }
+ return stream;
+}
+
+export default { addAbortSignal, addAbortSignalNoValidate };
+export { addAbortSignal, addAbortSignalNoValidate };
diff --git a/ext/node/polyfills/internal/streams/buffer_list.mjs b/ext/node/polyfills/internal/streams/buffer_list.mjs
new file mode 100644
index 000000000..3016ffba5
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/buffer_list.mjs
@@ -0,0 +1,188 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import { inspect } from "internal:deno_node/polyfills/internal/util/inspect.mjs";
+
+class BufferList {
+ constructor() {
+ this.head = null;
+ this.tail = null;
+ this.length = 0;
+ }
+
+ push(v) {
+ const entry = { data: v, next: null };
+ if (this.length > 0) {
+ this.tail.next = entry;
+ } else {
+ this.head = entry;
+ }
+ this.tail = entry;
+ ++this.length;
+ }
+
+ unshift(v) {
+ const entry = { data: v, next: this.head };
+ if (this.length === 0) {
+ this.tail = entry;
+ }
+ this.head = entry;
+ ++this.length;
+ }
+
+ shift() {
+ if (this.length === 0) {
+ return;
+ }
+ const ret = this.head.data;
+ if (this.length === 1) {
+ this.head = this.tail = null;
+ } else {
+ this.head = this.head.next;
+ }
+ --this.length;
+ return ret;
+ }
+
+ clear() {
+ this.head = this.tail = null;
+ this.length = 0;
+ }
+
+ join(s) {
+ if (this.length === 0) {
+ return "";
+ }
+ let p = this.head;
+ let ret = "" + p.data;
+ while (p = p.next) {
+ ret += s + p.data;
+ }
+ return ret;
+ }
+
+ concat(n) {
+ if (this.length === 0) {
+ return Buffer.alloc(0);
+ }
+ const ret = Buffer.allocUnsafe(n >>> 0);
+ let p = this.head;
+ let i = 0;
+ while (p) {
+ ret.set(p.data, i);
+ i += p.data.length;
+ p = p.next;
+ }
+ return ret;
+ }
+
+ // Consumes a specified amount of bytes or characters from the buffered data.
+ consume(n, hasStrings) {
+ const data = this.head.data;
+ if (n < data.length) {
+ // `slice` is the same for buffers and strings.
+ const slice = data.slice(0, n);
+ this.head.data = data.slice(n);
+ return slice;
+ }
+ if (n === data.length) {
+ // First chunk is a perfect match.
+ return this.shift();
+ }
+ // Result spans more than one buffer.
+ return hasStrings ? this._getString(n) : this._getBuffer(n);
+ }
+
+ first() {
+ return this.head.data;
+ }
+
+ *[Symbol.iterator]() {
+ for (let p = this.head; p; p = p.next) {
+ yield p.data;
+ }
+ }
+
+ // Consumes a specified amount of characters from the buffered data.
+ _getString(n) {
+ let ret = "";
+ let p = this.head;
+ let c = 0;
+ do {
+ const str = p.data;
+ if (n > str.length) {
+ ret += str;
+ n -= str.length;
+ } else {
+ if (n === str.length) {
+ ret += str;
+ ++c;
+ if (p.next) {
+ this.head = p.next;
+ } else {
+ this.head = this.tail = null;
+ }
+ } else {
+ ret += str.slice(0, n);
+ this.head = p;
+ p.data = str.slice(n);
+ }
+ break;
+ }
+ ++c;
+ } while (p = p.next);
+ this.length -= c;
+ return ret;
+ }
+
+ // Consumes a specified amount of bytes from the buffered data.
+ _getBuffer(n) {
+ const ret = Buffer.allocUnsafe(n);
+ const retLen = n;
+ let p = this.head;
+ let c = 0;
+ do {
+ const buf = p.data;
+ if (n > buf.length) {
+ ret.set(buf, retLen - n);
+ n -= buf.length;
+ } else {
+ if (n === buf.length) {
+ ret.set(buf, retLen - n);
+ ++c;
+ if (p.next) {
+ this.head = p.next;
+ } else {
+ this.head = this.tail = null;
+ }
+ } else {
+ ret.set(
+ new Uint8Array(buf.buffer, buf.byteOffset, n),
+ retLen - n,
+ );
+ this.head = p;
+ p.data = buf.slice(n);
+ }
+ break;
+ }
+ ++c;
+ } while (p = p.next);
+ this.length -= c;
+ return ret;
+ }
+
+ // Make sure the linked list only shows the minimal necessary information.
+ [inspect.custom](_, options) {
+ return inspect(this, {
+ ...options,
+ // Only inspect one level.
+ depth: 0,
+ // It should not recurse.
+ customInspect: false,
+ });
+ }
+}
+
+export default BufferList;
diff --git a/ext/node/polyfills/internal/streams/destroy.mjs b/ext/node/polyfills/internal/streams/destroy.mjs
new file mode 100644
index 000000000..b065f2119
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/destroy.mjs
@@ -0,0 +1,320 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import { aggregateTwoErrors, ERR_MULTIPLE_CALLBACK } from "internal:deno_node/polyfills/internal/errors.ts";
+import * as process from "internal:deno_node/polyfills/_process/process.ts";
+
+const kDestroy = Symbol("kDestroy");
+const kConstruct = Symbol("kConstruct");
+
+function checkError(err, w, r) {
+ if (err) {
+ // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364
+ err.stack; // eslint-disable-line no-unused-expressions
+
+ if (w && !w.errored) {
+ w.errored = err;
+ }
+ if (r && !r.errored) {
+ r.errored = err;
+ }
+ }
+}
+
+// Backwards compat. cb() is undocumented and unused in core but
+// unfortunately might be used by modules.
+function destroy(err, cb) {
+ const r = this._readableState;
+ const w = this._writableState;
+ // With duplex streams we use the writable side for state.
+ const s = w || r;
+
+ if ((w && w.destroyed) || (r && r.destroyed)) {
+ if (typeof cb === "function") {
+ cb();
+ }
+
+ return this;
+ }
+
+ // We set destroyed to true before firing error callbacks in order
+ // to make it re-entrance safe in case destroy() is called within callbacks
+ checkError(err, w, r);
+
+ if (w) {
+ w.destroyed = true;
+ }
+ if (r) {
+ r.destroyed = true;
+ }
+
+ // If still constructing then defer calling _destroy.
+ if (!s.constructed) {
+ this.once(kDestroy, function (er) {
+ _destroy(this, aggregateTwoErrors(er, err), cb);
+ });
+ } else {
+ _destroy(this, err, cb);
+ }
+
+ return this;
+}
+
+function _destroy(self, err, cb) {
+ let called = false;
+
+ function onDestroy(err) {
+ if (called) {
+ return;
+ }
+ called = true;
+
+ const r = self._readableState;
+ const w = self._writableState;
+
+ checkError(err, w, r);
+
+ if (w) {
+ w.closed = true;
+ }
+ if (r) {
+ r.closed = true;
+ }
+
+ if (typeof cb === "function") {
+ cb(err);
+ }
+
+ if (err) {
+ process.nextTick(emitErrorCloseNT, self, err);
+ } else {
+ process.nextTick(emitCloseNT, self);
+ }
+ }
+ try {
+ const result = self._destroy(err || null, onDestroy);
+ if (result != null) {
+ const then = result.then;
+ if (typeof then === "function") {
+ then.call(
+ result,
+ function () {
+ process.nextTick(onDestroy, null);
+ },
+ function (err) {
+ process.nextTick(onDestroy, err);
+ },
+ );
+ }
+ }
+ } catch (err) {
+ onDestroy(err);
+ }
+}
+
+function emitErrorCloseNT(self, err) {
+ emitErrorNT(self, err);
+ emitCloseNT(self);
+}
+
+function emitCloseNT(self) {
+ const r = self._readableState;
+ const w = self._writableState;
+
+ if (w) {
+ w.closeEmitted = true;
+ }
+ if (r) {
+ r.closeEmitted = true;
+ }
+
+ if ((w && w.emitClose) || (r && r.emitClose)) {
+ self.emit("close");
+ }
+}
+
+function emitErrorNT(self, err) {
+ const r = self._readableState;
+ const w = self._writableState;
+
+ if ((w && w.errorEmitted) || (r && r.errorEmitted)) {
+ return;
+ }
+
+ if (w) {
+ w.errorEmitted = true;
+ }
+ if (r) {
+ r.errorEmitted = true;
+ }
+
+ self.emit("error", err);
+}
+
+function undestroy() {
+ const r = this._readableState;
+ const w = this._writableState;
+
+ if (r) {
+ r.constructed = true;
+ r.closed = false;
+ r.closeEmitted = false;
+ r.destroyed = false;
+ r.errored = null;
+ r.errorEmitted = false;
+ r.reading = false;
+ r.ended = false;
+ r.endEmitted = false;
+ }
+
+ if (w) {
+ w.constructed = true;
+ w.destroyed = false;
+ w.closed = false;
+ w.closeEmitted = false;
+ w.errored = null;
+ w.errorEmitted = false;
+ w.ended = false;
+ w.ending = false;
+ w.finalCalled = false;
+ w.prefinished = false;
+ w.finished = false;
+ }
+}
+
+function errorOrDestroy(stream, err, sync) {
+ // We have tests that rely on errors being emitted
+ // in the same tick, so changing this is semver major.
+ // For now when you opt-in to autoDestroy we allow
+ // the error to be emitted nextTick. In a future
+ // semver major update we should change the default to this.
+
+ const r = stream._readableState;
+ const w = stream._writableState;
+
+ if ((w && w.destroyed) || (r && r.destroyed)) {
+ return this;
+ }
+
+ if ((r && r.autoDestroy) || (w && w.autoDestroy)) {
+ stream.destroy(err);
+ } else if (err) {
+ // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364
+ err.stack; // eslint-disable-line no-unused-expressions
+
+ if (w && !w.errored) {
+ w.errored = err;
+ }
+ if (r && !r.errored) {
+ r.errored = err;
+ }
+ if (sync) {
+ process.nextTick(emitErrorNT, stream, err);
+ } else {
+ emitErrorNT(stream, err);
+ }
+ }
+}
+
+function construct(stream, cb) {
+ if (typeof stream._construct !== "function") {
+ return;
+ }
+
+ const r = stream._readableState;
+ const w = stream._writableState;
+
+ if (r) {
+ r.constructed = false;
+ }
+ if (w) {
+ w.constructed = false;
+ }
+
+ stream.once(kConstruct, cb);
+
+ if (stream.listenerCount(kConstruct) > 1) {
+ // Duplex
+ return;
+ }
+
+ process.nextTick(constructNT, stream);
+}
+
+function constructNT(stream) {
+ let called = false;
+
+ function onConstruct(err) {
+ if (called) {
+ errorOrDestroy(stream, err ?? new ERR_MULTIPLE_CALLBACK());
+ return;
+ }
+ called = true;
+
+ const r = stream._readableState;
+ const w = stream._writableState;
+ const s = w || r;
+
+ if (r) {
+ r.constructed = true;
+ }
+ if (w) {
+ w.constructed = true;
+ }
+
+ if (s.destroyed) {
+ stream.emit(kDestroy, err);
+ } else if (err) {
+ errorOrDestroy(stream, err, true);
+ } else {
+ process.nextTick(emitConstructNT, stream);
+ }
+ }
+
+ try {
+ const result = stream._construct(onConstruct);
+ if (result != null) {
+ const then = result.then;
+ if (typeof then === "function") {
+ then.call(
+ result,
+ function () {
+ process.nextTick(onConstruct, null);
+ },
+ function (err) {
+ process.nextTick(onConstruct, err);
+ },
+ );
+ }
+ }
+ } catch (err) {
+ onConstruct(err);
+ }
+}
+
+function emitConstructNT(stream) {
+ stream.emit(kConstruct);
+}
+
+function isRequest(stream) {
+ return stream && stream.setHeader && typeof stream.abort === "function";
+}
+
+// Normalize destroy for legacy.
+function destroyer(stream, err) {
+ if (!stream) return;
+ if (isRequest(stream)) return stream.abort();
+ if (isRequest(stream.req)) return stream.req.abort();
+ if (typeof stream.destroy === "function") return stream.destroy(err);
+ if (typeof stream.close === "function") return stream.close();
+}
+
+export default {
+ construct,
+ destroyer,
+ destroy,
+ undestroy,
+ errorOrDestroy,
+};
+export { construct, destroy, destroyer, errorOrDestroy, undestroy };
diff --git a/ext/node/polyfills/internal/streams/duplex.mjs b/ext/node/polyfills/internal/streams/duplex.mjs
new file mode 100644
index 000000000..b2086d467
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/duplex.mjs
@@ -0,0 +1,9 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import { Duplex } from "internal:deno_node/polyfills/_stream.mjs";
+const { from, fromWeb, toWeb } = Duplex;
+
+export default Duplex;
+export { from, fromWeb, toWeb };
diff --git a/ext/node/polyfills/internal/streams/end-of-stream.mjs b/ext/node/polyfills/internal/streams/end-of-stream.mjs
new file mode 100644
index 000000000..b5c380d56
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/end-of-stream.mjs
@@ -0,0 +1,229 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import { AbortError, ERR_STREAM_PREMATURE_CLOSE } from "internal:deno_node/polyfills/internal/errors.ts";
+import { once } from "internal:deno_node/polyfills/internal/util.mjs";
+import {
+ validateAbortSignal,
+ validateFunction,
+ validateObject,
+} from "internal:deno_node/polyfills/internal/validators.mjs";
+import * as process from "internal:deno_node/polyfills/_process/process.ts";
+
+function isRequest(stream) {
+ return stream.setHeader && typeof stream.abort === "function";
+}
+
+function isServerResponse(stream) {
+ return (
+ typeof stream._sent100 === "boolean" &&
+ typeof stream._removedConnection === "boolean" &&
+ typeof stream._removedContLen === "boolean" &&
+ typeof stream._removedTE === "boolean" &&
+ typeof stream._closed === "boolean"
+ );
+}
+
+function isReadable(stream) {
+ return typeof stream.readable === "boolean" ||
+ typeof stream.readableEnded === "boolean" ||
+ !!stream._readableState;
+}
+
+function isWritable(stream) {
+ return typeof stream.writable === "boolean" ||
+ typeof stream.writableEnded === "boolean" ||
+ !!stream._writableState;
+}
+
+function isWritableFinished(stream) {
+ if (stream.writableFinished) return true;
+ const wState = stream._writableState;
+ if (!wState || wState.errored) return false;
+ return wState.finished || (wState.ended && wState.length === 0);
+}
+
+const nop = () => {};
+
+function isReadableEnded(stream) {
+ if (stream.readableEnded) return true;
+ const rState = stream._readableState;
+ if (!rState || rState.errored) return false;
+ return rState.endEmitted || (rState.ended && rState.length === 0);
+}
+
+function eos(stream, options, callback) {
+ if (arguments.length === 2) {
+ callback = options;
+ options = {};
+ } else if (options == null) {
+ options = {};
+ } else {
+ validateObject(options, "options");
+ }
+ validateFunction(callback, "callback");
+ validateAbortSignal(options.signal, "options.signal");
+
+ callback = once(callback);
+
+ const readable = options.readable ||
+ (options.readable !== false && isReadable(stream));
+ const writable = options.writable ||
+ (options.writable !== false && isWritable(stream));
+
+ const wState = stream._writableState;
+ const rState = stream._readableState;
+ const state = wState || rState;
+
+ const onlegacyfinish = () => {
+ if (!stream.writable) onfinish();
+ };
+
+ // TODO (ronag): Improve soft detection to include core modules and
+ // common ecosystem modules that do properly emit 'close' but fail
+ // this generic check.
+ let willEmitClose = isServerResponse(stream) || (
+ state &&
+ state.autoDestroy &&
+ state.emitClose &&
+ state.closed === false &&
+ isReadable(stream) === readable &&
+ isWritable(stream) === writable
+ );
+
+ let writableFinished = stream.writableFinished ||
+ (wState && wState.finished);
+ const onfinish = () => {
+ writableFinished = true;
+ // Stream should not be destroyed here. If it is that
+ // means that user space is doing something differently and
+ // we cannot trust willEmitClose.
+ if (stream.destroyed) willEmitClose = false;
+
+ if (willEmitClose && (!stream.readable || readable)) return;
+ if (!readable || readableEnded) callback.call(stream);
+ };
+
+ let readableEnded = stream.readableEnded ||
+ (rState && rState.endEmitted);
+ const onend = () => {
+ readableEnded = true;
+ // Stream should not be destroyed here. If it is that
+ // means that user space is doing something differently and
+ // we cannot trust willEmitClose.
+ if (stream.destroyed) willEmitClose = false;
+
+ if (willEmitClose && (!stream.writable || writable)) return;
+ if (!writable || writableFinished) callback.call(stream);
+ };
+
+ const onerror = (err) => {
+ callback.call(stream, err);
+ };
+
+ const onclose = () => {
+ if (readable && !readableEnded) {
+ if (!isReadableEnded(stream)) {
+ return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE());
+ }
+ }
+ if (writable && !writableFinished) {
+ if (!isWritableFinished(stream)) {
+ return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE());
+ }
+ }
+ callback.call(stream);
+ };
+
+ const onrequest = () => {
+ stream.req.on("finish", onfinish);
+ };
+
+ if (isRequest(stream)) {
+ stream.on("complete", onfinish);
+ if (!willEmitClose) {
+ stream.on("abort", onclose);
+ }
+ if (stream.req) onrequest();
+ else stream.on("request", onrequest);
+ } else if (writable && !wState) { // legacy streams
+ stream.on("end", onlegacyfinish);
+ stream.on("close", onlegacyfinish);
+ }
+
+ // Not all streams will emit 'close' after 'aborted'.
+ if (!willEmitClose && typeof stream.aborted === "boolean") {
+ stream.on("aborted", onclose);
+ }
+
+ stream.on("end", onend);
+ stream.on("finish", onfinish);
+ if (options.error !== false) stream.on("error", onerror);
+ stream.on("close", onclose);
+
+ // _closed is for OutgoingMessage which is not a proper Writable.
+ const closed = (!wState && !rState && stream._closed === true) || (
+ (wState && wState.closed) ||
+ (rState && rState.closed) ||
+ (wState && wState.errorEmitted) ||
+ (rState && rState.errorEmitted) ||
+ (rState && stream.req && stream.aborted) ||
+ (
+ (!wState || !willEmitClose || typeof wState.closed !== "boolean") &&
+ (!rState || !willEmitClose || typeof rState.closed !== "boolean") &&
+ (!writable || (wState && wState.finished)) &&
+ (!readable || (rState && rState.endEmitted))
+ )
+ );
+
+ if (closed) {
+ // TODO(ronag): Re-throw error if errorEmitted?
+ // TODO(ronag): Throw premature close as if finished was called?
+ // before being closed? i.e. if closed but not errored, ended or finished.
+ // TODO(ronag): Throw some kind of error? Does it make sense
+ // to call finished() on a "finished" stream?
+ // TODO(ronag): willEmitClose?
+ process.nextTick(() => {
+ callback();
+ });
+ }
+
+ const cleanup = () => {
+ callback = nop;
+ stream.removeListener("aborted", onclose);
+ stream.removeListener("complete", onfinish);
+ stream.removeListener("abort", onclose);
+ stream.removeListener("request", onrequest);
+ if (stream.req) stream.req.removeListener("finish", onfinish);
+ stream.removeListener("end", onlegacyfinish);
+ stream.removeListener("close", onlegacyfinish);
+ stream.removeListener("finish", onfinish);
+ stream.removeListener("end", onend);
+ stream.removeListener("error", onerror);
+ stream.removeListener("close", onclose);
+ };
+
+ if (options.signal && !closed) {
+ const abort = () => {
+ // Keep it because cleanup removes it.
+ const endCallback = callback;
+ cleanup();
+ endCallback.call(stream, new AbortError());
+ };
+ if (options.signal.aborted) {
+ process.nextTick(abort);
+ } else {
+ const originalCallback = callback;
+ callback = once((...args) => {
+ options.signal.removeEventListener("abort", abort);
+ originalCallback.apply(stream, args);
+ });
+ options.signal.addEventListener("abort", abort);
+ }
+ }
+
+ return cleanup;
+}
+
+export default eos;
diff --git a/ext/node/polyfills/internal/streams/lazy_transform.mjs b/ext/node/polyfills/internal/streams/lazy_transform.mjs
new file mode 100644
index 000000000..2bb93bd91
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/lazy_transform.mjs
@@ -0,0 +1,53 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import { getDefaultEncoding } from "internal:deno_node/polyfills/internal/crypto/util.ts";
+import stream from "internal:deno_node/polyfills/stream.ts";
+
+function LazyTransform(options) {
+ this._options = options;
+}
+Object.setPrototypeOf(LazyTransform.prototype, stream.Transform.prototype);
+Object.setPrototypeOf(LazyTransform, stream.Transform);
+
+function makeGetter(name) {
+ return function () {
+ stream.Transform.call(this, this._options);
+ this._writableState.decodeStrings = false;
+
+ if (!this._options || !this._options.defaultEncoding) {
+ this._writableState.defaultEncoding = getDefaultEncoding();
+ }
+
+ return this[name];
+ };
+}
+
+function makeSetter(name) {
+ return function (val) {
+ Object.defineProperty(this, name, {
+ value: val,
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ });
+ };
+}
+
+Object.defineProperties(LazyTransform.prototype, {
+ _readableState: {
+ get: makeGetter("_readableState"),
+ set: makeSetter("_readableState"),
+ configurable: true,
+ enumerable: true,
+ },
+ _writableState: {
+ get: makeGetter("_writableState"),
+ set: makeSetter("_writableState"),
+ configurable: true,
+ enumerable: true,
+ },
+});
+
+export default LazyTransform;
diff --git a/ext/node/polyfills/internal/streams/legacy.mjs b/ext/node/polyfills/internal/streams/legacy.mjs
new file mode 100644
index 000000000..0de18956f
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/legacy.mjs
@@ -0,0 +1,113 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import EE from "internal:deno_node/polyfills/events.ts";
+
+function Stream(opts) {
+ EE.call(this, opts);
+}
+Object.setPrototypeOf(Stream.prototype, EE.prototype);
+Object.setPrototypeOf(Stream, EE);
+
+Stream.prototype.pipe = function (dest, options) {
+ // deno-lint-ignore no-this-alias
+ const source = this;
+
+ function ondata(chunk) {
+ if (dest.writable && dest.write(chunk) === false && source.pause) {
+ source.pause();
+ }
+ }
+
+ source.on("data", ondata);
+
+ function ondrain() {
+ if (source.readable && source.resume) {
+ source.resume();
+ }
+ }
+
+ dest.on("drain", ondrain);
+
+ // If the 'end' option is not supplied, dest.end() will be called when
+ // source gets the 'end' or 'close' events. Only dest.end() once.
+ if (!dest._isStdio && (!options || options.end !== false)) {
+ source.on("end", onend);
+ source.on("close", onclose);
+ }
+
+ let didOnEnd = false;
+ function onend() {
+ if (didOnEnd) return;
+ didOnEnd = true;
+
+ dest.end();
+ }
+
+ function onclose() {
+ if (didOnEnd) return;
+ didOnEnd = true;
+
+ if (typeof dest.destroy === "function") dest.destroy();
+ }
+
+ // Don't leave dangling pipes when there are errors.
+ function onerror(er) {
+ cleanup();
+ if (EE.listenerCount(this, "error") === 0) {
+ this.emit("error", er);
+ }
+ }
+
+ prependListener(source, "error", onerror);
+ prependListener(dest, "error", onerror);
+
+ // Remove all the event listeners that were added.
+ function cleanup() {
+ source.removeListener("data", ondata);
+ dest.removeListener("drain", ondrain);
+
+ source.removeListener("end", onend);
+ source.removeListener("close", onclose);
+
+ source.removeListener("error", onerror);
+ dest.removeListener("error", onerror);
+
+ source.removeListener("end", cleanup);
+ source.removeListener("close", cleanup);
+
+ dest.removeListener("close", cleanup);
+ }
+
+ source.on("end", cleanup);
+ source.on("close", cleanup);
+
+ dest.on("close", cleanup);
+ dest.emit("pipe", source);
+
+ // Allow for unix-like usage: A.pipe(B).pipe(C)
+ return dest;
+};
+
+function prependListener(emitter, event, fn) {
+ // Sadly this is not cacheable as some libraries bundle their own
+ // event emitter implementation with them.
+ if (typeof emitter.prependListener === "function") {
+ return emitter.prependListener(event, fn);
+ }
+
+ // This is a hack to make sure that our error handler is attached before any
+ // userland ones. NEVER DO THIS. This is here only because this code needs
+ // to continue to work with older versions of Node.js that do not include
+ // the prependListener() method. The goal is to eventually remove this hack.
+ if (!emitter._events || !emitter._events[event]) {
+ emitter.on(event, fn);
+ } else if (Array.isArray(emitter._events[event])) {
+ emitter._events[event].unshift(fn);
+ } else {
+ emitter._events[event] = [fn, emitter._events[event]];
+ }
+}
+
+export { prependListener, Stream };
diff --git a/ext/node/polyfills/internal/streams/passthrough.mjs b/ext/node/polyfills/internal/streams/passthrough.mjs
new file mode 100644
index 000000000..136a0484a
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/passthrough.mjs
@@ -0,0 +1,7 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import { PassThrough } from "internal:deno_node/polyfills/_stream.mjs";
+
+export default PassThrough;
diff --git a/ext/node/polyfills/internal/streams/readable.mjs b/ext/node/polyfills/internal/streams/readable.mjs
new file mode 100644
index 000000000..36133d297
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/readable.mjs
@@ -0,0 +1,9 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import { Readable } from "internal:deno_node/polyfills/_stream.mjs";
+const { ReadableState, _fromList, from, fromWeb, toWeb, wrap } = Readable;
+
+export default Readable;
+export { _fromList, from, fromWeb, ReadableState, toWeb, wrap };
diff --git a/ext/node/polyfills/internal/streams/state.mjs b/ext/node/polyfills/internal/streams/state.mjs
new file mode 100644
index 000000000..93708fe9d
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/state.mjs
@@ -0,0 +1,10 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+function getDefaultHighWaterMark(objectMode) {
+ return objectMode ? 16 : 16 * 1024;
+}
+
+export default { getDefaultHighWaterMark };
+export { getDefaultHighWaterMark };
diff --git a/ext/node/polyfills/internal/streams/transform.mjs b/ext/node/polyfills/internal/streams/transform.mjs
new file mode 100644
index 000000000..3fc4fa5cd
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/transform.mjs
@@ -0,0 +1,7 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import { Transform } from "internal:deno_node/polyfills/_stream.mjs";
+
+export default Transform;
diff --git a/ext/node/polyfills/internal/streams/utils.mjs b/ext/node/polyfills/internal/streams/utils.mjs
new file mode 100644
index 000000000..a575f831d
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/utils.mjs
@@ -0,0 +1,242 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+const kIsDisturbed = Symbol("kIsDisturbed");
+
+function isReadableNodeStream(obj) {
+ return !!(
+ obj &&
+ typeof obj.pipe === "function" &&
+ typeof obj.on === "function" &&
+ (!obj._writableState || obj._readableState?.readable !== false) && // Duplex
+ (!obj._writableState || obj._readableState) // Writable has .pipe.
+ );
+}
+
+function isWritableNodeStream(obj) {
+ return !!(
+ obj &&
+ typeof obj.write === "function" &&
+ typeof obj.on === "function" &&
+ (!obj._readableState || obj._writableState?.writable !== false) // Duplex
+ );
+}
+
+function isDuplexNodeStream(obj) {
+ return !!(
+ obj &&
+ (typeof obj.pipe === "function" && obj._readableState) &&
+ typeof obj.on === "function" &&
+ typeof obj.write === "function"
+ );
+}
+
+function isNodeStream(obj) {
+ return (
+ obj &&
+ (
+ obj._readableState ||
+ obj._writableState ||
+ (typeof obj.write === "function" && typeof obj.on === "function") ||
+ (typeof obj.pipe === "function" && typeof obj.on === "function")
+ )
+ );
+}
+
+function isDestroyed(stream) {
+ if (!isNodeStream(stream)) return null;
+ const wState = stream._writableState;
+ const rState = stream._readableState;
+ const state = wState || rState;
+ return !!(stream.destroyed || state?.destroyed);
+}
+
+// Have been end():d.
+function isWritableEnded(stream) {
+ if (!isWritableNodeStream(stream)) return null;
+ if (stream.writableEnded === true) return true;
+ const wState = stream._writableState;
+ if (wState?.errored) return false;
+ if (typeof wState?.ended !== "boolean") return null;
+ return wState.ended;
+}
+
+// Have emitted 'finish'.
+function isWritableFinished(stream, strict) {
+ if (!isWritableNodeStream(stream)) return null;
+ if (stream.writableFinished === true) return true;
+ const wState = stream._writableState;
+ if (wState?.errored) return false;
+ if (typeof wState?.finished !== "boolean") return null;
+ return !!(
+ wState.finished ||
+ (strict === false && wState.ended === true && wState.length === 0)
+ );
+}
+
+// Have been push(null):d.
+function isReadableEnded(stream) {
+ if (!isReadableNodeStream(stream)) return null;
+ if (stream.readableEnded === true) return true;
+ const rState = stream._readableState;
+ if (!rState || rState.errored) return false;
+ if (typeof rState?.ended !== "boolean") return null;
+ return rState.ended;
+}
+
+// Have emitted 'end'.
+function isReadableFinished(stream, strict) {
+ if (!isReadableNodeStream(stream)) return null;
+ const rState = stream._readableState;
+ if (rState?.errored) return false;
+ if (typeof rState?.endEmitted !== "boolean") return null;
+ return !!(
+ rState.endEmitted ||
+ (strict === false && rState.ended === true && rState.length === 0)
+ );
+}
+
+function isDisturbed(stream) {
+ return !!(stream && (
+ stream.readableDidRead ||
+ stream.readableAborted ||
+ stream[kIsDisturbed]
+ ));
+}
+
+function isReadable(stream) {
+ const r = isReadableNodeStream(stream);
+ if (r === null || typeof stream?.readable !== "boolean") return null;
+ if (isDestroyed(stream)) return false;
+ return r && stream.readable && !isReadableFinished(stream);
+}
+
+function isWritable(stream) {
+ const r = isWritableNodeStream(stream);
+ if (r === null || typeof stream?.writable !== "boolean") return null;
+ if (isDestroyed(stream)) return false;
+ return r && stream.writable && !isWritableEnded(stream);
+}
+
+function isFinished(stream, opts) {
+ if (!isNodeStream(stream)) {
+ return null;
+ }
+
+ if (isDestroyed(stream)) {
+ return true;
+ }
+
+ if (opts?.readable !== false && isReadable(stream)) {
+ return false;
+ }
+
+ if (opts?.writable !== false && isWritable(stream)) {
+ return false;
+ }
+
+ return true;
+}
+
+function isClosed(stream) {
+ if (!isNodeStream(stream)) {
+ return null;
+ }
+
+ const wState = stream._writableState;
+ const rState = stream._readableState;
+
+ if (
+ typeof wState?.closed === "boolean" ||
+ typeof rState?.closed === "boolean"
+ ) {
+ return wState?.closed || rState?.closed;
+ }
+
+ if (typeof stream._closed === "boolean" && isOutgoingMessage(stream)) {
+ return stream._closed;
+ }
+
+ return null;
+}
+
+function isOutgoingMessage(stream) {
+ return (
+ typeof stream._closed === "boolean" &&
+ typeof stream._defaultKeepAlive === "boolean" &&
+ typeof stream._removedConnection === "boolean" &&
+ typeof stream._removedContLen === "boolean"
+ );
+}
+
+function isServerResponse(stream) {
+ return (
+ typeof stream._sent100 === "boolean" &&
+ isOutgoingMessage(stream)
+ );
+}
+
+function isServerRequest(stream) {
+ return (
+ typeof stream._consuming === "boolean" &&
+ typeof stream._dumped === "boolean" &&
+ stream.req?.upgradeOrConnect === undefined
+ );
+}
+
+function willEmitClose(stream) {
+ if (!isNodeStream(stream)) return null;
+
+ const wState = stream._writableState;
+ const rState = stream._readableState;
+ const state = wState || rState;
+
+ return (!state && isServerResponse(stream)) || !!(
+ state &&
+ state.autoDestroy &&
+ state.emitClose &&
+ state.closed === false
+ );
+}
+
+export default {
+ isDisturbed,
+ kIsDisturbed,
+ isClosed,
+ isDestroyed,
+ isDuplexNodeStream,
+ isFinished,
+ isReadable,
+ isReadableNodeStream,
+ isReadableEnded,
+ isReadableFinished,
+ isNodeStream,
+ isWritable,
+ isWritableNodeStream,
+ isWritableEnded,
+ isWritableFinished,
+ isServerRequest,
+ isServerResponse,
+ willEmitClose,
+};
+export {
+ isClosed,
+ isDestroyed,
+ isDisturbed,
+ isDuplexNodeStream,
+ isFinished,
+ isNodeStream,
+ isReadable,
+ isReadableEnded,
+ isReadableFinished,
+ isReadableNodeStream,
+ isServerRequest,
+ isServerResponse,
+ isWritable,
+ isWritableEnded,
+ isWritableFinished,
+ isWritableNodeStream,
+ kIsDisturbed,
+ willEmitClose,
+};
diff --git a/ext/node/polyfills/internal/streams/writable.mjs b/ext/node/polyfills/internal/streams/writable.mjs
new file mode 100644
index 000000000..6f4d77960
--- /dev/null
+++ b/ext/node/polyfills/internal/streams/writable.mjs
@@ -0,0 +1,9 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// deno-lint-ignore-file
+
+import { Writable } from "internal:deno_node/polyfills/_stream.mjs";
+const { WritableState, fromWeb, toWeb } = Writable;
+
+export default Writable;
+export { fromWeb, toWeb, WritableState };
diff --git a/ext/node/polyfills/internal/test/binding.ts b/ext/node/polyfills/internal/test/binding.ts
new file mode 100644
index 000000000..996cc57aa
--- /dev/null
+++ b/ext/node/polyfills/internal/test/binding.ts
@@ -0,0 +1,16 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and Node.js contributors. All rights reserved. MIT license.
+import { getBinding } from "internal:deno_node/polyfills/internal_binding/mod.ts";
+import type { BindingName } from "internal:deno_node/polyfills/internal_binding/mod.ts";
+
+export function internalBinding(name: BindingName) {
+ return getBinding(name);
+}
+
+// TODO(kt3k): export actual primordials
+export const primordials = {};
+
+export default {
+ internalBinding,
+ primordials,
+};
diff --git a/ext/node/polyfills/internal/timers.mjs b/ext/node/polyfills/internal/timers.mjs
new file mode 100644
index 000000000..648fb1bc1
--- /dev/null
+++ b/ext/node/polyfills/internal/timers.mjs
@@ -0,0 +1,125 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+import { inspect } from "internal:deno_node/polyfills/internal/util/inspect.mjs";
+import { validateFunction, validateNumber } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { ERR_OUT_OF_RANGE } from "internal:deno_node/polyfills/internal/errors.ts";
+import { emitWarning } from "internal:deno_node/polyfills/process.ts";
+
+const setTimeout_ = globalThis.setTimeout;
+const clearTimeout_ = globalThis.clearTimeout;
+const setInterval_ = globalThis.setInterval;
+
+// Timeout values > TIMEOUT_MAX are set to 1.
+export const TIMEOUT_MAX = 2 ** 31 - 1;
+
+export const kTimerId = Symbol("timerId");
+export const kTimeout = Symbol("timeout");
+const kRefed = Symbol("refed");
+const createTimer = Symbol("createTimer");
+
+// Timer constructor function.
+export function Timeout(callback, after, args, isRepeat, isRefed) {
+ if (typeof after === "number" && after > TIMEOUT_MAX) {
+ after = 1;
+ }
+ this._idleTimeout = after;
+ this._onTimeout = callback;
+ this._timerArgs = args;
+ this._isRepeat = isRepeat;
+ this[kRefed] = isRefed;
+ this[kTimerId] = this[createTimer]();
+}
+
+Timeout.prototype[createTimer] = function () {
+ const callback = this._onTimeout;
+ const cb = (...args) => callback.bind(this)(...args);
+ const id = this._isRepeat
+ ? setInterval_(cb, this._idleTimeout, ...this._timerArgs)
+ : setTimeout_(cb, this._idleTimeout, ...this._timerArgs);
+ if (!this[kRefed]) {
+ Deno.unrefTimer(id);
+ }
+ return id;
+};
+
+// Make sure the linked list only shows the minimal necessary information.
+Timeout.prototype[inspect.custom] = function (_, options) {
+ return inspect(this, {
+ ...options,
+ // Only inspect one level.
+ depth: 0,
+ // It should not recurse.
+ customInspect: false,
+ });
+};
+
+Timeout.prototype.refresh = function () {
+ clearTimeout_(this[kTimerId]);
+ this[kTimerId] = this[createTimer]();
+ return this;
+};
+
+Timeout.prototype.unref = function () {
+ if (this[kRefed]) {
+ this[kRefed] = false;
+ Deno.unrefTimer(this[kTimerId]);
+ }
+ return this;
+};
+
+Timeout.prototype.ref = function () {
+ if (!this[kRefed]) {
+ this[kRefed] = true;
+ Deno.refTimer(this[kTimerId]);
+ }
+ return this;
+};
+
+Timeout.prototype.hasRef = function () {
+ return this[kRefed];
+};
+
+Timeout.prototype[Symbol.toPrimitive] = function () {
+ return this[kTimerId];
+};
+
+/**
+ * @param {number} msecs
+ * @param {string} name
+ * @returns
+ */
+export function getTimerDuration(msecs, name) {
+ validateNumber(msecs, name);
+
+ if (msecs < 0 || !Number.isFinite(msecs)) {
+ throw new ERR_OUT_OF_RANGE(name, "a non-negative finite number", msecs);
+ }
+
+ // Ensure that msecs fits into signed int32
+ if (msecs > TIMEOUT_MAX) {
+ emitWarning(
+ `${msecs} does not fit into a 32-bit signed integer.` +
+ `\nTimer duration was truncated to ${TIMEOUT_MAX}.`,
+ "TimeoutOverflowWarning",
+ );
+
+ return TIMEOUT_MAX;
+ }
+
+ return msecs;
+}
+
+export function setUnrefTimeout(callback, timeout, ...args) {
+ validateFunction(callback, "callback");
+ return new Timeout(callback, timeout, args, false, false);
+}
+
+export default {
+ getTimerDuration,
+ kTimerId,
+ kTimeout,
+ setUnrefTimeout,
+ Timeout,
+ TIMEOUT_MAX,
+};
diff --git a/ext/node/polyfills/internal/url.ts b/ext/node/polyfills/internal/url.ts
new file mode 100644
index 000000000..415ad9be6
--- /dev/null
+++ b/ext/node/polyfills/internal/url.ts
@@ -0,0 +1,49 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { fileURLToPath } from "internal:deno_node/polyfills/url.ts";
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+
+const searchParams = Symbol("query");
+
+export function toPathIfFileURL(
+ fileURLOrPath: string | Buffer | URL,
+): string | Buffer {
+ if (!(fileURLOrPath instanceof URL)) {
+ return fileURLOrPath;
+ }
+ return fileURLToPath(fileURLOrPath);
+}
+
+// Utility function that converts a URL object into an ordinary
+// options object as expected by the http.request and https.request
+// APIs.
+// deno-lint-ignore no-explicit-any
+export function urlToHttpOptions(url: any): any {
+ // deno-lint-ignore no-explicit-any
+ const options: any = {
+ protocol: url.protocol,
+ hostname: typeof url.hostname === "string" &&
+ url.hostname.startsWith("[")
+ ? url.hostname.slice(1, -1)
+ : url.hostname,
+ hash: url.hash,
+ search: url.search,
+ pathname: url.pathname,
+ path: `${url.pathname || ""}${url.search || ""}`,
+ href: url.href,
+ };
+ if (url.port !== "") {
+ options.port = Number(url.port);
+ }
+ if (url.username || url.password) {
+ options.auth = `${decodeURIComponent(url.username)}:${
+ decodeURIComponent(url.password)
+ }`;
+ }
+ return options;
+}
+
+export { searchParams as searchParamsSymbol };
+
+export default {
+ toPathIfFileURL,
+};
diff --git a/ext/node/polyfills/internal/util.mjs b/ext/node/polyfills/internal/util.mjs
new file mode 100644
index 000000000..ba26c6a6a
--- /dev/null
+++ b/ext/node/polyfills/internal/util.mjs
@@ -0,0 +1,141 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { validateFunction } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { normalizeEncoding, slowCases } from "internal:deno_node/polyfills/internal/normalize_encoding.mjs";
+export { normalizeEncoding, slowCases };
+import { ObjectCreate, StringPrototypeToUpperCase } from "internal:deno_node/polyfills/internal/primordials.mjs";
+import { ERR_UNKNOWN_SIGNAL } from "internal:deno_node/polyfills/internal/errors.ts";
+import { os } from "internal:deno_node/polyfills/internal_binding/constants.ts";
+
+export const customInspectSymbol = Symbol.for("nodejs.util.inspect.custom");
+export const kEnumerableProperty = Object.create(null);
+kEnumerableProperty.enumerable = true;
+
+export const kEmptyObject = Object.freeze(Object.create(null));
+
+export function once(callback) {
+ let called = false;
+ return function (...args) {
+ if (called) return;
+ called = true;
+ Reflect.apply(callback, this, args);
+ };
+}
+
+export function createDeferredPromise() {
+ let resolve;
+ let reject;
+ const promise = new Promise((res, rej) => {
+ resolve = res;
+ reject = rej;
+ });
+
+ return { promise, resolve, reject };
+}
+
+// In addition to being accessible through util.promisify.custom,
+// this symbol is registered globally and can be accessed in any environment as
+// Symbol.for('nodejs.util.promisify.custom').
+const kCustomPromisifiedSymbol = Symbol.for("nodejs.util.promisify.custom");
+// This is an internal Node symbol used by functions returning multiple
+// arguments, e.g. ['bytesRead', 'buffer'] for fs.read().
+const kCustomPromisifyArgsSymbol = Symbol.for(
+ "nodejs.util.promisify.customArgs",
+);
+
+export const customPromisifyArgs = kCustomPromisifyArgsSymbol;
+
+export function promisify(
+ original,
+) {
+ validateFunction(original, "original");
+ if (original[kCustomPromisifiedSymbol]) {
+ const fn = original[kCustomPromisifiedSymbol];
+
+ validateFunction(fn, "util.promisify.custom");
+
+ return Object.defineProperty(fn, kCustomPromisifiedSymbol, {
+ value: fn,
+ enumerable: false,
+ writable: false,
+ configurable: true,
+ });
+ }
+
+ // Names to create an object from in case the callback receives multiple
+ // arguments, e.g. ['bytesRead', 'buffer'] for fs.read.
+ const argumentNames = original[kCustomPromisifyArgsSymbol];
+ function fn(...args) {
+ return new Promise((resolve, reject) => {
+ args.push((err, ...values) => {
+ if (err) {
+ return reject(err);
+ }
+ if (argumentNames !== undefined && values.length > 1) {
+ const obj = {};
+ for (let i = 0; i < argumentNames.length; i++) {
+ obj[argumentNames[i]] = values[i];
+ }
+ resolve(obj);
+ } else {
+ resolve(values[0]);
+ }
+ });
+ Reflect.apply(original, this, args);
+ });
+ }
+
+ Object.setPrototypeOf(fn, Object.getPrototypeOf(original));
+
+ Object.defineProperty(fn, kCustomPromisifiedSymbol, {
+ value: fn,
+ enumerable: false,
+ writable: false,
+ configurable: true,
+ });
+ return Object.defineProperties(
+ fn,
+ Object.getOwnPropertyDescriptors(original),
+ );
+}
+
+let signalsToNamesMapping;
+function getSignalsToNamesMapping() {
+ if (signalsToNamesMapping !== undefined) {
+ return signalsToNamesMapping;
+ }
+
+ signalsToNamesMapping = ObjectCreate(null);
+ for (const key in os.signals) {
+ signalsToNamesMapping[os.signals[key]] = key;
+ }
+
+ return signalsToNamesMapping;
+}
+
+export function convertToValidSignal(signal) {
+ if (typeof signal === "number" && getSignalsToNamesMapping()[signal]) {
+ return signal;
+ }
+
+ if (typeof signal === "string") {
+ const signalName = os.signals[StringPrototypeToUpperCase(signal)];
+ if (signalName) return signalName;
+ }
+
+ throw new ERR_UNKNOWN_SIGNAL(signal);
+}
+
+promisify.custom = kCustomPromisifiedSymbol;
+
+export default {
+ convertToValidSignal,
+ createDeferredPromise,
+ customInspectSymbol,
+ customPromisifyArgs,
+ kEmptyObject,
+ kEnumerableProperty,
+ normalizeEncoding,
+ once,
+ promisify,
+ slowCases,
+};
diff --git a/ext/node/polyfills/internal/util/comparisons.ts b/ext/node/polyfills/internal/util/comparisons.ts
new file mode 100644
index 000000000..1620e468b
--- /dev/null
+++ b/ext/node/polyfills/internal/util/comparisons.ts
@@ -0,0 +1,681 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+// deno-lint-ignore-file
+import {
+ isAnyArrayBuffer,
+ isArrayBufferView,
+ isBigIntObject,
+ isBooleanObject,
+ isBoxedPrimitive,
+ isDate,
+ isFloat32Array,
+ isFloat64Array,
+ isMap,
+ isNativeError,
+ isNumberObject,
+ isRegExp,
+ isSet,
+ isStringObject,
+ isSymbolObject,
+ isTypedArray,
+} from "internal:deno_node/polyfills/internal/util/types.ts";
+
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+import {
+ getOwnNonIndexProperties,
+ ONLY_ENUMERABLE,
+ SKIP_SYMBOLS,
+} from "internal:deno_node/polyfills/internal_binding/util.ts";
+
+enum valueType {
+ noIterator,
+ isArray,
+ isSet,
+ isMap,
+}
+
+interface Memo {
+ val1: Map<unknown, unknown>;
+ val2: Map<unknown, unknown>;
+ position: number;
+}
+let memo: Memo;
+
+export function isDeepStrictEqual(val1: unknown, val2: unknown): boolean {
+ return innerDeepEqual(val1, val2, true);
+}
+export function isDeepEqual(val1: unknown, val2: unknown): boolean {
+ return innerDeepEqual(val1, val2, false);
+}
+
+function innerDeepEqual(
+ val1: unknown,
+ val2: unknown,
+ strict: boolean,
+ memos = memo,
+): boolean {
+ // Basic case covered by Strict Equality Comparison
+ if (val1 === val2) {
+ if (val1 !== 0) return true;
+ return strict ? Object.is(val1, val2) : true;
+ }
+ if (strict) {
+ // Cases where the values are not objects
+ // If both values are Not a Number NaN
+ if (typeof val1 !== "object") {
+ return (
+ typeof val1 === "number" && Number.isNaN(val1) && Number.isNaN(val2)
+ );
+ }
+ // If either value is null
+ if (typeof val2 !== "object" || val1 === null || val2 === null) {
+ return false;
+ }
+ // If the prototype are not the same
+ if (Object.getPrototypeOf(val1) !== Object.getPrototypeOf(val2)) {
+ return false;
+ }
+ } else {
+ // Non strict case where values are either null or NaN
+ if (val1 === null || typeof val1 !== "object") {
+ if (val2 === null || typeof val2 !== "object") {
+ return val1 == val2 || (Number.isNaN(val1) && Number.isNaN(val2));
+ }
+ return false;
+ }
+ if (val2 === null || typeof val2 !== "object") {
+ return false;
+ }
+ }
+
+ const val1Tag = Object.prototype.toString.call(val1);
+ const val2Tag = Object.prototype.toString.call(val2);
+
+ // prototype must be Strictly Equal
+ if (
+ val1Tag !== val2Tag
+ ) {
+ return false;
+ }
+
+ // handling when values are array
+ if (Array.isArray(val1)) {
+ // quick rejection cases
+ if (!Array.isArray(val2) || val1.length !== val2.length) {
+ return false;
+ }
+ const filter = strict ? ONLY_ENUMERABLE : ONLY_ENUMERABLE | SKIP_SYMBOLS;
+ const keys1 = getOwnNonIndexProperties(val1, filter);
+ const keys2 = getOwnNonIndexProperties(val2, filter);
+ if (keys1.length !== keys2.length) {
+ return false;
+ }
+ return keyCheck(val1, val2, strict, memos, valueType.isArray, keys1);
+ } else if (val1Tag === "[object Object]") {
+ return keyCheck(
+ val1 as object,
+ val2 as object,
+ strict,
+ memos,
+ valueType.noIterator,
+ );
+ } else if (val1 instanceof Date) {
+ if (!(val2 instanceof Date) || val1.getTime() !== val2.getTime()) {
+ return false;
+ }
+ } else if (val1 instanceof RegExp) {
+ if (!(val2 instanceof RegExp) || !areSimilarRegExps(val1, val2)) {
+ return false;
+ }
+ } else if (isNativeError(val1) || val1 instanceof Error) {
+ // stack may or may not be same, hence it shouldn't be compared
+ if (
+ // How to handle the type errors here
+ (!isNativeError(val2) && !(val2 instanceof Error)) ||
+ (val1 as Error).message !== (val2 as Error).message ||
+ (val1 as Error).name !== (val2 as Error).name
+ ) {
+ return false;
+ }
+ } else if (isArrayBufferView(val1)) {
+ const TypedArrayPrototypeGetSymbolToStringTag = (
+ val:
+ | BigInt64Array
+ | BigUint64Array
+ | Float32Array
+ | Float64Array
+ | Int8Array
+ | Int16Array
+ | Int32Array
+ | Uint8Array
+ | Uint8ClampedArray
+ | Uint16Array
+ | Uint32Array,
+ ) =>
+ Object.getOwnPropertySymbols(val)
+ .map((item) => item.toString())
+ .toString();
+ if (
+ isTypedArray(val1) &&
+ isTypedArray(val2) &&
+ (TypedArrayPrototypeGetSymbolToStringTag(val1) !==
+ TypedArrayPrototypeGetSymbolToStringTag(val2))
+ ) {
+ return false;
+ }
+
+ if (!strict && (isFloat32Array(val1) || isFloat64Array(val1))) {
+ if (!areSimilarFloatArrays(val1, val2)) {
+ return false;
+ }
+ } else if (!areSimilarTypedArrays(val1, val2)) {
+ return false;
+ }
+ const filter = strict ? ONLY_ENUMERABLE : ONLY_ENUMERABLE | SKIP_SYMBOLS;
+ const keysVal1 = getOwnNonIndexProperties(val1 as object, filter);
+ const keysVal2 = getOwnNonIndexProperties(val2 as object, filter);
+ if (keysVal1.length !== keysVal2.length) {
+ return false;
+ }
+ return keyCheck(
+ val1 as object,
+ val2 as object,
+ strict,
+ memos,
+ valueType.noIterator,
+ keysVal1,
+ );
+ } else if (isSet(val1)) {
+ if (
+ !isSet(val2) ||
+ (val1 as Set<unknown>).size !== (val2 as Set<unknown>).size
+ ) {
+ return false;
+ }
+ return keyCheck(
+ val1 as object,
+ val2 as object,
+ strict,
+ memos,
+ valueType.isSet,
+ );
+ } else if (isMap(val1)) {
+ if (
+ !isMap(val2) || val1.size !== val2.size
+ ) {
+ return false;
+ }
+ return keyCheck(
+ val1 as object,
+ val2 as object,
+ strict,
+ memos,
+ valueType.isMap,
+ );
+ } else if (isAnyArrayBuffer(val1)) {
+ if (!isAnyArrayBuffer(val2) || !areEqualArrayBuffers(val1, val2)) {
+ return false;
+ }
+ } else if (isBoxedPrimitive(val1)) {
+ if (!isEqualBoxedPrimitive(val1, val2)) {
+ return false;
+ }
+ } else if (
+ Array.isArray(val2) ||
+ isArrayBufferView(val2) ||
+ isSet(val2) ||
+ isMap(val2) ||
+ isDate(val2) ||
+ isRegExp(val2) ||
+ isAnyArrayBuffer(val2) ||
+ isBoxedPrimitive(val2) ||
+ isNativeError(val2) ||
+ val2 instanceof Error
+ ) {
+ return false;
+ }
+ return keyCheck(
+ val1 as object,
+ val2 as object,
+ strict,
+ memos,
+ valueType.noIterator,
+ );
+}
+
+function keyCheck(
+ val1: object,
+ val2: object,
+ strict: boolean,
+ memos: Memo,
+ iterationType: valueType,
+ aKeys: (string | symbol)[] = [],
+) {
+ if (arguments.length === 5) {
+ aKeys = Object.keys(val1);
+ const bKeys = Object.keys(val2);
+
+ // The pair must have the same number of owned properties.
+ if (aKeys.length !== bKeys.length) {
+ return false;
+ }
+ }
+
+ // Cheap key test
+ let i = 0;
+ for (; i < aKeys.length; i++) {
+ if (!val2.propertyIsEnumerable(aKeys[i])) {
+ return false;
+ }
+ }
+
+ if (strict && arguments.length === 5) {
+ const symbolKeysA = Object.getOwnPropertySymbols(val1);
+ if (symbolKeysA.length !== 0) {
+ let count = 0;
+ for (i = 0; i < symbolKeysA.length; i++) {
+ const key = symbolKeysA[i];
+ if (val1.propertyIsEnumerable(key)) {
+ if (!val2.propertyIsEnumerable(key)) {
+ return false;
+ }
+ // added toString here
+ aKeys.push(key.toString());
+ count++;
+ } else if (val2.propertyIsEnumerable(key)) {
+ return false;
+ }
+ }
+ const symbolKeysB = Object.getOwnPropertySymbols(val2);
+ if (
+ symbolKeysA.length !== symbolKeysB.length &&
+ getEnumerables(val2, symbolKeysB).length !== count
+ ) {
+ return false;
+ }
+ } else {
+ const symbolKeysB = Object.getOwnPropertySymbols(val2);
+ if (
+ symbolKeysB.length !== 0 &&
+ getEnumerables(val2, symbolKeysB).length !== 0
+ ) {
+ return false;
+ }
+ }
+ }
+ if (
+ aKeys.length === 0 &&
+ (iterationType === valueType.noIterator ||
+ (iterationType === valueType.isArray && (val1 as []).length === 0) ||
+ (val1 as Set<unknown>).size === 0)
+ ) {
+ return true;
+ }
+
+ if (memos === undefined) {
+ memos = {
+ val1: new Map(),
+ val2: new Map(),
+ position: 0,
+ };
+ } else {
+ const val2MemoA = memos.val1.get(val1);
+ if (val2MemoA !== undefined) {
+ const val2MemoB = memos.val2.get(val2);
+ if (val2MemoB !== undefined) {
+ return val2MemoA === val2MemoB;
+ }
+ }
+ memos.position++;
+ }
+
+ memos.val1.set(val1, memos.position);
+ memos.val2.set(val2, memos.position);
+
+ const areEq = objEquiv(val1, val2, strict, aKeys, memos, iterationType);
+
+ memos.val1.delete(val1);
+ memos.val2.delete(val2);
+
+ return areEq;
+}
+
+function areSimilarRegExps(a: RegExp, b: RegExp) {
+ return a.source === b.source && a.flags === b.flags &&
+ a.lastIndex === b.lastIndex;
+}
+
+// TODO(standvpmnt): add type for arguments
+function areSimilarFloatArrays(arr1: any, arr2: any): boolean {
+ if (arr1.byteLength !== arr2.byteLength) {
+ return false;
+ }
+ for (let i = 0; i < arr1.byteLength; i++) {
+ if (arr1[i] !== arr2[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// TODO(standvpmnt): add type for arguments
+function areSimilarTypedArrays(arr1: any, arr2: any): boolean {
+ if (arr1.byteLength !== arr2.byteLength) {
+ return false;
+ }
+ return (
+ Buffer.compare(
+ new Uint8Array(arr1.buffer, arr1.byteOffset, arr1.byteLength),
+ new Uint8Array(arr2.buffer, arr2.byteOffset, arr2.byteLength),
+ ) === 0
+ );
+}
+// TODO(standvpmnt): add type for arguments
+function areEqualArrayBuffers(buf1: any, buf2: any): boolean {
+ return (
+ buf1.byteLength === buf2.byteLength &&
+ Buffer.compare(new Uint8Array(buf1), new Uint8Array(buf2)) === 0
+ );
+}
+
+// TODO(standvpmnt): this check of getOwnPropertySymbols and getOwnPropertyNames
+// length is sufficient to handle the current test case, however this will fail
+// to catch a scenario wherein the getOwnPropertySymbols and getOwnPropertyNames
+// length is the same(will be very contrived but a possible shortcoming
+function isEqualBoxedPrimitive(a: any, b: any): boolean {
+ if (
+ Object.getOwnPropertyNames(a).length !==
+ Object.getOwnPropertyNames(b).length
+ ) {
+ return false;
+ }
+ if (
+ Object.getOwnPropertySymbols(a).length !==
+ Object.getOwnPropertySymbols(b).length
+ ) {
+ return false;
+ }
+ if (isNumberObject(a)) {
+ return (
+ isNumberObject(b) &&
+ Object.is(
+ Number.prototype.valueOf.call(a),
+ Number.prototype.valueOf.call(b),
+ )
+ );
+ }
+ if (isStringObject(a)) {
+ return (
+ isStringObject(b) &&
+ (String.prototype.valueOf.call(a) === String.prototype.valueOf.call(b))
+ );
+ }
+ if (isBooleanObject(a)) {
+ return (
+ isBooleanObject(b) &&
+ (Boolean.prototype.valueOf.call(a) === Boolean.prototype.valueOf.call(b))
+ );
+ }
+ if (isBigIntObject(a)) {
+ return (
+ isBigIntObject(b) &&
+ (BigInt.prototype.valueOf.call(a) === BigInt.prototype.valueOf.call(b))
+ );
+ }
+ if (isSymbolObject(a)) {
+ return (
+ isSymbolObject(b) &&
+ (Symbol.prototype.valueOf.call(a) ===
+ Symbol.prototype.valueOf.call(b))
+ );
+ }
+ // assert.fail(`Unknown boxed type ${val1}`);
+ // return false;
+ throw Error(`Unknown boxed type`);
+}
+
+function getEnumerables(val: any, keys: any) {
+ return keys.filter((key: string) => val.propertyIsEnumerable(key));
+}
+
+function objEquiv(
+ obj1: any,
+ obj2: any,
+ strict: boolean,
+ keys: any,
+ memos: Memo,
+ iterationType: valueType,
+): boolean {
+ let i = 0;
+
+ if (iterationType === valueType.isSet) {
+ if (!setEquiv(obj1, obj2, strict, memos)) {
+ return false;
+ }
+ } else if (iterationType === valueType.isMap) {
+ if (!mapEquiv(obj1, obj2, strict, memos)) {
+ return false;
+ }
+ } else if (iterationType === valueType.isArray) {
+ for (; i < obj1.length; i++) {
+ if (obj1.hasOwnProperty(i)) {
+ if (
+ !obj2.hasOwnProperty(i) ||
+ !innerDeepEqual(obj1[i], obj2[i], strict, memos)
+ ) {
+ return false;
+ }
+ } else if (obj2.hasOwnProperty(i)) {
+ return false;
+ } else {
+ const keys1 = Object.keys(obj1);
+ for (; i < keys1.length; i++) {
+ const key = keys1[i];
+ if (
+ !obj2.hasOwnProperty(key) ||
+ !innerDeepEqual(obj1[key], obj2[key], strict, memos)
+ ) {
+ return false;
+ }
+ }
+ if (keys1.length !== Object.keys(obj2).length) {
+ return false;
+ }
+ if (keys1.length !== Object.keys(obj2).length) {
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ // Expensive test
+ for (i = 0; i < keys.length; i++) {
+ const key = keys[i];
+ if (!innerDeepEqual(obj1[key], obj2[key], strict, memos)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function findLooseMatchingPrimitives(
+ primitive: unknown,
+): boolean | null | undefined {
+ switch (typeof primitive) {
+ case "undefined":
+ return null;
+ case "object":
+ return undefined;
+ case "symbol":
+ return false;
+ case "string":
+ primitive = +primitive;
+ case "number":
+ if (Number.isNaN(primitive)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function setMightHaveLoosePrim(
+ set1: Set<unknown>,
+ set2: Set<unknown>,
+ primitive: any,
+) {
+ const altValue = findLooseMatchingPrimitives(primitive);
+ if (altValue != null) return altValue;
+
+ return set2.has(altValue) && !set1.has(altValue);
+}
+
+function setHasEqualElement(
+ set: any,
+ val1: any,
+ strict: boolean,
+ memos: Memo,
+): boolean {
+ for (const val2 of set) {
+ if (innerDeepEqual(val1, val2, strict, memos)) {
+ set.delete(val2);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function setEquiv(set1: any, set2: any, strict: boolean, memos: Memo): boolean {
+ let set = null;
+ for (const item of set1) {
+ if (typeof item === "object" && item !== null) {
+ if (set === null) {
+ // What is SafeSet from primordials?
+ // set = new SafeSet();
+ set = new Set();
+ }
+ set.add(item);
+ } else if (!set2.has(item)) {
+ if (strict) return false;
+
+ if (!setMightHaveLoosePrim(set1, set2, item)) {
+ return false;
+ }
+
+ if (set === null) {
+ set = new Set();
+ }
+ set.add(item);
+ }
+ }
+
+ if (set !== null) {
+ for (const item of set2) {
+ if (typeof item === "object" && item !== null) {
+ if (!setHasEqualElement(set, item, strict, memos)) return false;
+ } else if (
+ !strict &&
+ !set1.has(item) &&
+ !setHasEqualElement(set, item, strict, memos)
+ ) {
+ return false;
+ }
+ }
+ return set.size === 0;
+ }
+
+ return true;
+}
+
+// TODO(standvpmnt): add types for argument
+function mapMightHaveLoosePrimitive(
+ map1: Map<unknown, unknown>,
+ map2: Map<unknown, unknown>,
+ primitive: any,
+ item: any,
+ memos: Memo,
+): boolean {
+ const altValue = findLooseMatchingPrimitives(primitive);
+ if (altValue != null) {
+ return altValue;
+ }
+ const curB = map2.get(altValue);
+ if (
+ (curB === undefined && !map2.has(altValue)) ||
+ !innerDeepEqual(item, curB, false, memo)
+ ) {
+ return false;
+ }
+ return !map1.has(altValue) && innerDeepEqual(item, curB, false, memos);
+}
+
+function mapEquiv(map1: any, map2: any, strict: boolean, memos: Memo): boolean {
+ let set = null;
+
+ for (const { 0: key, 1: item1 } of map1) {
+ if (typeof key === "object" && key !== null) {
+ if (set === null) {
+ set = new Set();
+ }
+ set.add(key);
+ } else {
+ const item2 = map2.get(key);
+ if (
+ (
+ (item2 === undefined && !map2.has(key)) ||
+ !innerDeepEqual(item1, item2, strict, memos)
+ )
+ ) {
+ if (strict) return false;
+ if (!mapMightHaveLoosePrimitive(map1, map2, key, item1, memos)) {
+ return false;
+ }
+ if (set === null) {
+ set = new Set();
+ }
+ set.add(key);
+ }
+ }
+ }
+
+ if (set !== null) {
+ for (const { 0: key, 1: item } of map2) {
+ if (typeof key === "object" && key !== null) {
+ if (!mapHasEqualEntry(set, map1, key, item, strict, memos)) {
+ return false;
+ }
+ } else if (
+ !strict && (!map1.has(key) ||
+ !innerDeepEqual(map1.get(key), item, false, memos)) &&
+ !mapHasEqualEntry(set, map1, key, item, false, memos)
+ ) {
+ return false;
+ }
+ }
+ return set.size === 0;
+ }
+
+ return true;
+}
+
+function mapHasEqualEntry(
+ set: any,
+ map: any,
+ key1: any,
+ item1: any,
+ strict: boolean,
+ memos: Memo,
+): boolean {
+ for (const key2 of set) {
+ if (
+ innerDeepEqual(key1, key2, strict, memos) &&
+ innerDeepEqual(item1, map.get(key2), strict, memos)
+ ) {
+ set.delete(key2);
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/ext/node/polyfills/internal/util/debuglog.ts b/ext/node/polyfills/internal/util/debuglog.ts
new file mode 100644
index 000000000..498facbd1
--- /dev/null
+++ b/ext/node/polyfills/internal/util/debuglog.ts
@@ -0,0 +1,121 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+import { inspect } from "internal:deno_node/polyfills/internal/util/inspect.mjs";
+
+// `debugImpls` and `testEnabled` are deliberately not initialized so any call
+// to `debuglog()` before `initializeDebugEnv()` is called will throw.
+let debugImpls: Record<string, (...args: unknown[]) => void>;
+let testEnabled: (str: string) => boolean;
+
+// `debugEnv` is initial value of process.env.NODE_DEBUG
+function initializeDebugEnv(debugEnv: string) {
+ debugImpls = Object.create(null);
+ if (debugEnv) {
+ // This is run before any user code, it's OK not to use primordials.
+ debugEnv = debugEnv.replace(/[|\\{}()[\]^$+?.]/g, "\\$&")
+ .replaceAll("*", ".*")
+ .replaceAll(",", "$|^");
+ const debugEnvRegex = new RegExp(`^${debugEnv}$`, "i");
+ testEnabled = (str) => debugEnvRegex.exec(str) !== null;
+ } else {
+ testEnabled = () => false;
+ }
+}
+
+// Emits warning when user sets
+// NODE_DEBUG=http or NODE_DEBUG=http2.
+function emitWarningIfNeeded(set: string) {
+ if ("HTTP" === set || "HTTP2" === set) {
+ console.warn(
+ "Setting the NODE_DEBUG environment variable " +
+ "to '" + set.toLowerCase() + "' can expose sensitive " +
+ "data (such as passwords, tokens and authentication headers) " +
+ "in the resulting log.",
+ );
+ }
+}
+
+const noop = () => {};
+
+function debuglogImpl(
+ enabled: boolean,
+ set: string,
+): (...args: unknown[]) => void {
+ if (debugImpls[set] === undefined) {
+ if (enabled) {
+ emitWarningIfNeeded(set);
+ debugImpls[set] = function debug(...args: unknown[]) {
+ const msg = args.map((arg) => inspect(arg)).join(" ");
+ console.error("%s %s: %s", set, String(Deno.pid), msg);
+ };
+ } else {
+ debugImpls[set] = noop;
+ }
+ }
+
+ return debugImpls[set];
+}
+
+// debuglogImpl depends on process.pid and process.env.NODE_DEBUG,
+// so it needs to be called lazily in top scopes of internal modules
+// that may be loaded before these run time states are allowed to
+// be accessed.
+export function debuglog(
+ set: string,
+ cb?: (debug: (...args: unknown[]) => void) => void,
+) {
+ function init() {
+ set = set.toUpperCase();
+ enabled = testEnabled(set);
+ }
+
+ let debug = (...args: unknown[]): void => {
+ init();
+ // Only invokes debuglogImpl() when the debug function is
+ // called for the first time.
+ debug = debuglogImpl(enabled, set);
+
+ if (typeof cb === "function") {
+ cb(debug);
+ }
+
+ return debug(...args);
+ };
+
+ let enabled: boolean;
+ let test = () => {
+ init();
+ test = () => enabled;
+ return enabled;
+ };
+
+ const logger = (...args: unknown[]) => debug(...args);
+
+ Object.defineProperty(logger, "enabled", {
+ get() {
+ return test();
+ },
+ configurable: true,
+ enumerable: true,
+ });
+
+ return logger;
+}
+
+let debugEnv;
+/* TODO(kt3k): enable initializing debugEnv.
+It's not possible to access env var when snapshotting.
+
+try {
+ debugEnv = Deno.env.get("NODE_DEBUG") ?? "";
+} catch (error) {
+ if (error instanceof Deno.errors.PermissionDenied) {
+ debugEnv = "";
+ } else {
+ throw error;
+ }
+}
+*/
+initializeDebugEnv(debugEnv);
+
+export default { debuglog };
diff --git a/ext/node/polyfills/internal/util/inspect.mjs b/ext/node/polyfills/internal/util/inspect.mjs
new file mode 100644
index 000000000..53a878aa3
--- /dev/null
+++ b/ext/node/polyfills/internal/util/inspect.mjs
@@ -0,0 +1,2237 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import * as types from "internal:deno_node/polyfills/internal/util/types.ts";
+import { validateObject, validateString } from "internal:deno_node/polyfills/internal/validators.mjs";
+import { codes } from "internal:deno_node/polyfills/internal/error_codes.ts";
+
+import {
+ ALL_PROPERTIES,
+ getOwnNonIndexProperties,
+ ONLY_ENUMERABLE,
+} from "internal:deno_node/polyfills/internal_binding/util.ts";
+
+const kObjectType = 0;
+const kArrayType = 1;
+const kArrayExtrasType = 2;
+
+const kMinLineLength = 16;
+
+// Constants to map the iterator state.
+const kWeak = 0;
+const kIterator = 1;
+const kMapEntries = 2;
+
+const kPending = 0;
+const kRejected = 2;
+
+// Escaped control characters (plus the single quote and the backslash). Use
+// empty strings to fill up unused entries.
+// deno-fmt-ignore
+const meta = [
+ '\\x00', '\\x01', '\\x02', '\\x03', '\\x04', '\\x05', '\\x06', '\\x07', // x07
+ '\\b', '\\t', '\\n', '\\x0B', '\\f', '\\r', '\\x0E', '\\x0F', // x0F
+ '\\x10', '\\x11', '\\x12', '\\x13', '\\x14', '\\x15', '\\x16', '\\x17', // x17
+ '\\x18', '\\x19', '\\x1A', '\\x1B', '\\x1C', '\\x1D', '\\x1E', '\\x1F', // x1F
+ '', '', '', '', '', '', '', "\\'", '', '', '', '', '', '', '', '', // x2F
+ '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', // x3F
+ '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', // x4F
+ '', '', '', '', '', '', '', '', '', '', '', '', '\\\\', '', '', '', // x5F
+ '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', // x6F
+ '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '\\x7F', // x7F
+ '\\x80', '\\x81', '\\x82', '\\x83', '\\x84', '\\x85', '\\x86', '\\x87', // x87
+ '\\x88', '\\x89', '\\x8A', '\\x8B', '\\x8C', '\\x8D', '\\x8E', '\\x8F', // x8F
+ '\\x90', '\\x91', '\\x92', '\\x93', '\\x94', '\\x95', '\\x96', '\\x97', // x97
+ '\\x98', '\\x99', '\\x9A', '\\x9B', '\\x9C', '\\x9D', '\\x9E', '\\x9F', // x9F
+];
+
+// https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot
+const isUndetectableObject = (v) => typeof v === "undefined" && v !== undefined;
+
+// deno-lint-ignore no-control-regex
+const strEscapeSequencesRegExp = /[\x00-\x1f\x27\x5c\x7f-\x9f]/;
+// deno-lint-ignore no-control-regex
+const strEscapeSequencesReplacer = /[\x00-\x1f\x27\x5c\x7f-\x9f]/g;
+// deno-lint-ignore no-control-regex
+const strEscapeSequencesRegExpSingle = /[\x00-\x1f\x5c\x7f-\x9f]/;
+// deno-lint-ignore no-control-regex
+const strEscapeSequencesReplacerSingle = /[\x00-\x1f\x5c\x7f-\x9f]/g;
+
+const keyStrRegExp = /^[a-zA-Z_][a-zA-Z_0-9]*$/;
+const numberRegExp = /^(0|[1-9][0-9]*)$/;
+const nodeModulesRegExp = /[/\\]node_modules[/\\](.+?)(?=[/\\])/g;
+
+const classRegExp = /^(\s+[^(]*?)\s*{/;
+// eslint-disable-next-line node-core/no-unescaped-regexp-dot
+const stripCommentsRegExp = /(\/\/.*?\n)|(\/\*(.|\n)*?\*\/)/g;
+
+const inspectDefaultOptions = {
+ showHidden: false,
+ depth: 2,
+ colors: false,
+ customInspect: true,
+ showProxy: false,
+ maxArrayLength: 100,
+ maxStringLength: 10000,
+ breakLength: 80,
+ compact: 3,
+ sorted: false,
+ getters: false,
+};
+
+function getUserOptions(ctx, isCrossContext) {
+ const ret = {
+ stylize: ctx.stylize,
+ showHidden: ctx.showHidden,
+ depth: ctx.depth,
+ colors: ctx.colors,
+ customInspect: ctx.customInspect,
+ showProxy: ctx.showProxy,
+ maxArrayLength: ctx.maxArrayLength,
+ maxStringLength: ctx.maxStringLength,
+ breakLength: ctx.breakLength,
+ compact: ctx.compact,
+ sorted: ctx.sorted,
+ getters: ctx.getters,
+ ...ctx.userOptions,
+ };
+
+ // Typically, the target value will be an instance of `Object`. If that is
+ // *not* the case, the object may come from another vm.Context, and we want
+ // to avoid passing it objects from this Context in that case, so we remove
+ // the prototype from the returned object itself + the `stylize()` function,
+ // and remove all other non-primitives, including non-primitive user options.
+ if (isCrossContext) {
+ Object.setPrototypeOf(ret, null);
+ for (const key of Object.keys(ret)) {
+ if (
+ (typeof ret[key] === "object" || typeof ret[key] === "function") &&
+ ret[key] !== null
+ ) {
+ delete ret[key];
+ }
+ }
+ ret.stylize = Object.setPrototypeOf((value, flavour) => {
+ let stylized;
+ try {
+ stylized = `${ctx.stylize(value, flavour)}`;
+ } catch {
+ // noop
+ }
+
+ if (typeof stylized !== "string") return value;
+ // `stylized` is a string as it should be, which is safe to pass along.
+ return stylized;
+ }, null);
+ }
+
+ return ret;
+}
+
+/**
+ * Echos the value of any input. Tries to print the value out
+ * in the best way possible given the different types.
+ */
+/* Legacy: value, showHidden, depth, colors */
+export function inspect(value, opts) {
+ // Default options
+ const ctx = {
+ budget: {},
+ indentationLvl: 0,
+ seen: [],
+ currentDepth: 0,
+ stylize: stylizeNoColor,
+ showHidden: inspectDefaultOptions.showHidden,
+ depth: inspectDefaultOptions.depth,
+ colors: inspectDefaultOptions.colors,
+ customInspect: inspectDefaultOptions.customInspect,
+ showProxy: inspectDefaultOptions.showProxy,
+ maxArrayLength: inspectDefaultOptions.maxArrayLength,
+ maxStringLength: inspectDefaultOptions.maxStringLength,
+ breakLength: inspectDefaultOptions.breakLength,
+ compact: inspectDefaultOptions.compact,
+ sorted: inspectDefaultOptions.sorted,
+ getters: inspectDefaultOptions.getters,
+ };
+ if (arguments.length > 1) {
+ // Legacy...
+ if (arguments.length > 2) {
+ if (arguments[2] !== undefined) {
+ ctx.depth = arguments[2];
+ }
+ if (arguments.length > 3 && arguments[3] !== undefined) {
+ ctx.colors = arguments[3];
+ }
+ }
+ // Set user-specified options
+ if (typeof opts === "boolean") {
+ ctx.showHidden = opts;
+ } else if (opts) {
+ const optKeys = Object.keys(opts);
+ for (let i = 0; i < optKeys.length; ++i) {
+ const key = optKeys[i];
+ // TODO(BridgeAR): Find a solution what to do about stylize. Either make
+ // this function public or add a new API with a similar or better
+ // functionality.
+ if (
+ // deno-lint-ignore no-prototype-builtins
+ inspectDefaultOptions.hasOwnProperty(key) ||
+ key === "stylize"
+ ) {
+ ctx[key] = opts[key];
+ } else if (ctx.userOptions === undefined) {
+ // This is required to pass through the actual user input.
+ ctx.userOptions = opts;
+ }
+ }
+ }
+ }
+ if (ctx.colors) ctx.stylize = stylizeWithColor;
+ if (ctx.maxArrayLength === null) ctx.maxArrayLength = Infinity;
+ if (ctx.maxStringLength === null) ctx.maxStringLength = Infinity;
+ return formatValue(ctx, value, 0);
+}
+const customInspectSymbol = Symbol.for("nodejs.util.inspect.custom");
+inspect.custom = customInspectSymbol;
+
+Object.defineProperty(inspect, "defaultOptions", {
+ get() {
+ return inspectDefaultOptions;
+ },
+ set(options) {
+ validateObject(options, "options");
+ return Object.assign(inspectDefaultOptions, options);
+ },
+});
+
+// Set Graphics Rendition https://en.wikipedia.org/wiki/ANSI_escape_code#graphics
+// Each color consists of an array with the color code as first entry and the
+// reset code as second entry.
+const defaultFG = 39;
+const defaultBG = 49;
+inspect.colors = Object.assign(Object.create(null), {
+ reset: [0, 0],
+ bold: [1, 22],
+ dim: [2, 22], // Alias: faint
+ italic: [3, 23],
+ underline: [4, 24],
+ blink: [5, 25],
+ // Swap foreground and background colors
+ inverse: [7, 27], // Alias: swapcolors, swapColors
+ hidden: [8, 28], // Alias: conceal
+ strikethrough: [9, 29], // Alias: strikeThrough, crossedout, crossedOut
+ doubleunderline: [21, 24], // Alias: doubleUnderline
+ black: [30, defaultFG],
+ red: [31, defaultFG],
+ green: [32, defaultFG],
+ yellow: [33, defaultFG],
+ blue: [34, defaultFG],
+ magenta: [35, defaultFG],
+ cyan: [36, defaultFG],
+ white: [37, defaultFG],
+ bgBlack: [40, defaultBG],
+ bgRed: [41, defaultBG],
+ bgGreen: [42, defaultBG],
+ bgYellow: [43, defaultBG],
+ bgBlue: [44, defaultBG],
+ bgMagenta: [45, defaultBG],
+ bgCyan: [46, defaultBG],
+ bgWhite: [47, defaultBG],
+ framed: [51, 54],
+ overlined: [53, 55],
+ gray: [90, defaultFG], // Alias: grey, blackBright
+ redBright: [91, defaultFG],
+ greenBright: [92, defaultFG],
+ yellowBright: [93, defaultFG],
+ blueBright: [94, defaultFG],
+ magentaBright: [95, defaultFG],
+ cyanBright: [96, defaultFG],
+ whiteBright: [97, defaultFG],
+ bgGray: [100, defaultBG], // Alias: bgGrey, bgBlackBright
+ bgRedBright: [101, defaultBG],
+ bgGreenBright: [102, defaultBG],
+ bgYellowBright: [103, defaultBG],
+ bgBlueBright: [104, defaultBG],
+ bgMagentaBright: [105, defaultBG],
+ bgCyanBright: [106, defaultBG],
+ bgWhiteBright: [107, defaultBG],
+});
+
+function defineColorAlias(target, alias) {
+ Object.defineProperty(inspect.colors, alias, {
+ get() {
+ return this[target];
+ },
+ set(value) {
+ this[target] = value;
+ },
+ configurable: true,
+ enumerable: false,
+ });
+}
+
+defineColorAlias("gray", "grey");
+defineColorAlias("gray", "blackBright");
+defineColorAlias("bgGray", "bgGrey");
+defineColorAlias("bgGray", "bgBlackBright");
+defineColorAlias("dim", "faint");
+defineColorAlias("strikethrough", "crossedout");
+defineColorAlias("strikethrough", "strikeThrough");
+defineColorAlias("strikethrough", "crossedOut");
+defineColorAlias("hidden", "conceal");
+defineColorAlias("inverse", "swapColors");
+defineColorAlias("inverse", "swapcolors");
+defineColorAlias("doubleunderline", "doubleUnderline");
+
+// TODO(BridgeAR): Add function style support for more complex styles.
+// Don't use 'blue' not visible on cmd.exe
+inspect.styles = Object.assign(Object.create(null), {
+ special: "cyan",
+ number: "yellow",
+ bigint: "yellow",
+ boolean: "yellow",
+ undefined: "grey",
+ null: "bold",
+ string: "green",
+ symbol: "green",
+ date: "magenta",
+ // "name": intentionally not styling
+ // TODO(BridgeAR): Highlight regular expressions properly.
+ regexp: "red",
+ module: "underline",
+});
+
+function addQuotes(str, quotes) {
+ if (quotes === -1) {
+ return `"${str}"`;
+ }
+ if (quotes === -2) {
+ return `\`${str}\``;
+ }
+ return `'${str}'`;
+}
+
+// TODO(wafuwafu13): Figure out
+const escapeFn = (str) => meta[str.charCodeAt(0)];
+
+// Escape control characters, single quotes and the backslash.
+// This is similar to JSON stringify escaping.
+function strEscape(str) {
+ let escapeTest = strEscapeSequencesRegExp;
+ let escapeReplace = strEscapeSequencesReplacer;
+ let singleQuote = 39;
+
+ // Check for double quotes. If not present, do not escape single quotes and
+ // instead wrap the text in double quotes. If double quotes exist, check for
+ // backticks. If they do not exist, use those as fallback instead of the
+ // double quotes.
+ if (str.includes("'")) {
+ // This invalidates the charCode and therefore can not be matched for
+ // anymore.
+ if (!str.includes('"')) {
+ singleQuote = -1;
+ } else if (
+ !str.includes("`") &&
+ !str.includes("${")
+ ) {
+ singleQuote = -2;
+ }
+ if (singleQuote !== 39) {
+ escapeTest = strEscapeSequencesRegExpSingle;
+ escapeReplace = strEscapeSequencesReplacerSingle;
+ }
+ }
+
+ // Some magic numbers that worked out fine while benchmarking with v8 6.0
+ if (str.length < 5000 && !escapeTest.test(str)) {
+ return addQuotes(str, singleQuote);
+ }
+ if (str.length > 100) {
+ str = str.replace(escapeReplace, escapeFn);
+ return addQuotes(str, singleQuote);
+ }
+
+ let result = "";
+ let last = 0;
+ const lastIndex = str.length;
+ for (let i = 0; i < lastIndex; i++) {
+ const point = str.charCodeAt(i);
+ if (
+ point === singleQuote ||
+ point === 92 ||
+ point < 32 ||
+ (point > 126 && point < 160)
+ ) {
+ if (last === i) {
+ result += meta[point];
+ } else {
+ result += `${str.slice(last, i)}${meta[point]}`;
+ }
+ last = i + 1;
+ }
+ }
+
+ if (last !== lastIndex) {
+ result += str.slice(last);
+ }
+ return addQuotes(result, singleQuote);
+}
+
+function stylizeWithColor(str, styleType) {
+ const style = inspect.styles[styleType];
+ if (style !== undefined) {
+ const color = inspect.colors[style];
+ if (color !== undefined) {
+ return `\u001b[${color[0]}m${str}\u001b[${color[1]}m`;
+ }
+ }
+ return str;
+}
+
+function stylizeNoColor(str) {
+ return str;
+}
+
+// Note: using `formatValue` directly requires the indentation level to be
+// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
+// value afterwards again.
+function formatValue(
+ ctx,
+ value,
+ recurseTimes,
+ typedArray,
+) {
+ // Primitive types cannot have properties.
+ if (
+ typeof value !== "object" &&
+ typeof value !== "function" &&
+ !isUndetectableObject(value)
+ ) {
+ return formatPrimitive(ctx.stylize, value, ctx);
+ }
+ if (value === null) {
+ return ctx.stylize("null", "null");
+ }
+
+ // Memorize the context for custom inspection on proxies.
+ const context = value;
+ // Always check for proxies to prevent side effects and to prevent triggering
+ // any proxy handlers.
+ // TODO(wafuwafu13): Set Proxy
+ const proxy = undefined;
+ // const proxy = getProxyDetails(value, !!ctx.showProxy);
+ // if (proxy !== undefined) {
+ // if (ctx.showProxy) {
+ // return formatProxy(ctx, proxy, recurseTimes);
+ // }
+ // value = proxy;
+ // }
+
+ // Provide a hook for user-specified inspect functions.
+ // Check that value is an object with an inspect function on it.
+ if (ctx.customInspect) {
+ const maybeCustom = value[customInspectSymbol];
+ if (
+ typeof maybeCustom === "function" &&
+ // Filter out the util module, its inspect function is special.
+ maybeCustom !== inspect &&
+ // Also filter out any prototype objects using the circular check.
+ !(value.constructor && value.constructor.prototype === value)
+ ) {
+ // This makes sure the recurseTimes are reported as before while using
+ // a counter internally.
+ const depth = ctx.depth === null ? null : ctx.depth - recurseTimes;
+ const isCrossContext = proxy !== undefined ||
+ !(context instanceof Object);
+ const ret = maybeCustom.call(
+ context,
+ depth,
+ getUserOptions(ctx, isCrossContext),
+ );
+ // If the custom inspection method returned `this`, don't go into
+ // infinite recursion.
+ if (ret !== context) {
+ if (typeof ret !== "string") {
+ return formatValue(ctx, ret, recurseTimes);
+ }
+ return ret.replace(/\n/g, `\n${" ".repeat(ctx.indentationLvl)}`);
+ }
+ }
+ }
+
+ // Using an array here is actually better for the average case than using
+ // a Set. `seen` will only check for the depth and will never grow too large.
+ if (ctx.seen.includes(value)) {
+ let index = 1;
+ if (ctx.circular === undefined) {
+ ctx.circular = new Map();
+ ctx.circular.set(value, index);
+ } else {
+ index = ctx.circular.get(value);
+ if (index === undefined) {
+ index = ctx.circular.size + 1;
+ ctx.circular.set(value, index);
+ }
+ }
+ return ctx.stylize(`[Circular *${index}]`, "special");
+ }
+
+ return formatRaw(ctx, value, recurseTimes, typedArray);
+}
+
+function formatRaw(ctx, value, recurseTimes, typedArray) {
+ let keys;
+ let protoProps;
+ if (ctx.showHidden && (recurseTimes <= ctx.depth || ctx.depth === null)) {
+ protoProps = [];
+ }
+
+ const constructor = getConstructorName(value, ctx, recurseTimes, protoProps);
+ // Reset the variable to check for this later on.
+ if (protoProps !== undefined && protoProps.length === 0) {
+ protoProps = undefined;
+ }
+
+ let tag = value[Symbol.toStringTag];
+ // Only list the tag in case it's non-enumerable / not an own property.
+ // Otherwise we'd print this twice.
+ if (
+ typeof tag !== "string"
+ // TODO(wafuwafu13): Implement
+ // (tag !== "" &&
+ // (ctx.showHidden
+ // ? Object.prototype.hasOwnProperty
+ // : Object.prototype.propertyIsEnumerable)(
+ // value,
+ // Symbol.toStringTag,
+ // ))
+ ) {
+ tag = "";
+ }
+ let base = "";
+ let formatter = getEmptyFormatArray;
+ let braces;
+ let noIterator = true;
+ let i = 0;
+ const filter = ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE;
+
+ let extrasType = kObjectType;
+
+ // Iterators and the rest are split to reduce checks.
+ // We have to check all values in case the constructor is set to null.
+ // Otherwise it would not possible to identify all types properly.
+ if (value[Symbol.iterator] || constructor === null) {
+ noIterator = false;
+ if (Array.isArray(value)) {
+ // Only set the constructor for non ordinary ("Array [...]") arrays.
+ const prefix = (constructor !== "Array" || tag !== "")
+ ? getPrefix(constructor, tag, "Array", `(${value.length})`)
+ : "";
+ keys = getOwnNonIndexProperties(value, filter);
+ braces = [`${prefix}[`, "]"];
+ if (value.length === 0 && keys.length === 0 && protoProps === undefined) {
+ return `${braces[0]}]`;
+ }
+ extrasType = kArrayExtrasType;
+ formatter = formatArray;
+ } else if (types.isSet(value)) {
+ const size = value.size;
+ const prefix = getPrefix(constructor, tag, "Set", `(${size})`);
+ keys = getKeys(value, ctx.showHidden);
+ formatter = constructor !== null
+ ? formatSet.bind(null, value)
+ : formatSet.bind(null, value.values());
+ if (size === 0 && keys.length === 0 && protoProps === undefined) {
+ return `${prefix}{}`;
+ }
+ braces = [`${prefix}{`, "}"];
+ } else if (types.isMap(value)) {
+ const size = value.size;
+ const prefix = getPrefix(constructor, tag, "Map", `(${size})`);
+ keys = getKeys(value, ctx.showHidden);
+ formatter = constructor !== null
+ ? formatMap.bind(null, value)
+ : formatMap.bind(null, value.entries());
+ if (size === 0 && keys.length === 0 && protoProps === undefined) {
+ return `${prefix}{}`;
+ }
+ braces = [`${prefix}{`, "}"];
+ } else if (types.isTypedArray(value)) {
+ keys = getOwnNonIndexProperties(value, filter);
+ const bound = value;
+ const fallback = "";
+ if (constructor === null) {
+ // TODO(wafuwafu13): Implement
+ // fallback = TypedArrayPrototypeGetSymbolToStringTag(value);
+ // // Reconstruct the array information.
+ // bound = new primordials[fallback](value);
+ }
+ const size = value.length;
+ const prefix = getPrefix(constructor, tag, fallback, `(${size})`);
+ braces = [`${prefix}[`, "]"];
+ if (value.length === 0 && keys.length === 0 && !ctx.showHidden) {
+ return `${braces[0]}]`;
+ }
+ // Special handle the value. The original value is required below. The
+ // bound function is required to reconstruct missing information.
+ (formatter) = formatTypedArray.bind(null, bound, size);
+ extrasType = kArrayExtrasType;
+ } else if (types.isMapIterator(value)) {
+ keys = getKeys(value, ctx.showHidden);
+ braces = getIteratorBraces("Map", tag);
+ // Add braces to the formatter parameters.
+ (formatter) = formatIterator.bind(null, braces);
+ } else if (types.isSetIterator(value)) {
+ keys = getKeys(value, ctx.showHidden);
+ braces = getIteratorBraces("Set", tag);
+ // Add braces to the formatter parameters.
+ (formatter) = formatIterator.bind(null, braces);
+ } else {
+ noIterator = true;
+ }
+ }
+ if (noIterator) {
+ keys = getKeys(value, ctx.showHidden);
+ braces = ["{", "}"];
+ if (constructor === "Object") {
+ if (types.isArgumentsObject(value)) {
+ braces[0] = "[Arguments] {";
+ } else if (tag !== "") {
+ braces[0] = `${getPrefix(constructor, tag, "Object")}{`;
+ }
+ if (keys.length === 0 && protoProps === undefined) {
+ return `${braces[0]}}`;
+ }
+ } else if (typeof value === "function") {
+ base = getFunctionBase(value, constructor, tag);
+ if (keys.length === 0 && protoProps === undefined) {
+ return ctx.stylize(base, "special");
+ }
+ } else if (types.isRegExp(value)) {
+ // Make RegExps say that they are RegExps
+ base = RegExp(constructor !== null ? value : new RegExp(value))
+ .toString();
+ const prefix = getPrefix(constructor, tag, "RegExp");
+ if (prefix !== "RegExp ") {
+ base = `${prefix}${base}`;
+ }
+ if (
+ (keys.length === 0 && protoProps === undefined) ||
+ (recurseTimes > ctx.depth && ctx.depth !== null)
+ ) {
+ return ctx.stylize(base, "regexp");
+ }
+ } else if (types.isDate(value)) {
+ // Make dates with properties first say the date
+ base = Number.isNaN(value.getTime())
+ ? value.toString()
+ : value.toISOString();
+ const prefix = getPrefix(constructor, tag, "Date");
+ if (prefix !== "Date ") {
+ base = `${prefix}${base}`;
+ }
+ if (keys.length === 0 && protoProps === undefined) {
+ return ctx.stylize(base, "date");
+ }
+ } else if (value instanceof Error) {
+ base = formatError(value, constructor, tag, ctx, keys);
+ if (keys.length === 0 && protoProps === undefined) {
+ return base;
+ }
+ } else if (types.isAnyArrayBuffer(value)) {
+ // Fast path for ArrayBuffer and SharedArrayBuffer.
+ // Can't do the same for DataView because it has a non-primitive
+ // .buffer property that we need to recurse for.
+ const arrayType = types.isArrayBuffer(value)
+ ? "ArrayBuffer"
+ : "SharedArrayBuffer";
+ const prefix = getPrefix(constructor, tag, arrayType);
+ if (typedArray === undefined) {
+ (formatter) = formatArrayBuffer;
+ } else if (keys.length === 0 && protoProps === undefined) {
+ return prefix +
+ `{ byteLength: ${formatNumber(ctx.stylize, value.byteLength)} }`;
+ }
+ braces[0] = `${prefix}{`;
+ Array.prototype.unshift.call(keys, "byteLength");
+ } else if (types.isDataView(value)) {
+ braces[0] = `${getPrefix(constructor, tag, "DataView")}{`;
+ // .buffer goes last, it's not a primitive like the others.
+ Array.prototype.unshift.call(keys, "byteLength", "byteOffset", "buffer");
+ } else if (types.isPromise(value)) {
+ braces[0] = `${getPrefix(constructor, tag, "Promise")}{`;
+ (formatter) = formatPromise;
+ } else if (types.isWeakSet(value)) {
+ braces[0] = `${getPrefix(constructor, tag, "WeakSet")}{`;
+ (formatter) = ctx.showHidden ? formatWeakSet : formatWeakCollection;
+ } else if (types.isWeakMap(value)) {
+ braces[0] = `${getPrefix(constructor, tag, "WeakMap")}{`;
+ (formatter) = ctx.showHidden ? formatWeakMap : formatWeakCollection;
+ } else if (types.isModuleNamespaceObject(value)) {
+ braces[0] = `${getPrefix(constructor, tag, "Module")}{`;
+ // Special handle keys for namespace objects.
+ (formatter) = formatNamespaceObject.bind(null, keys);
+ } else if (types.isBoxedPrimitive(value)) {
+ base = getBoxedBase(value, ctx, keys, constructor, tag);
+ if (keys.length === 0 && protoProps === undefined) {
+ return base;
+ }
+ } else {
+ if (keys.length === 0 && protoProps === undefined) {
+ // TODO(wafuwafu13): Implement
+ // if (types.isExternal(value)) {
+ // const address = getExternalValue(value).toString(16);
+ // return ctx.stylize(`[External: ${address}]`, 'special');
+ // }
+ return `${getCtxStyle(value, constructor, tag)}{}`;
+ }
+ braces[0] = `${getCtxStyle(value, constructor, tag)}{`;
+ }
+ }
+
+ if (recurseTimes > ctx.depth && ctx.depth !== null) {
+ let constructorName = getCtxStyle(value, constructor, tag).slice(0, -1);
+ if (constructor !== null) {
+ constructorName = `[${constructorName}]`;
+ }
+ return ctx.stylize(constructorName, "special");
+ }
+ recurseTimes += 1;
+
+ ctx.seen.push(value);
+ ctx.currentDepth = recurseTimes;
+ let output;
+ const indentationLvl = ctx.indentationLvl;
+ try {
+ output = formatter(ctx, value, recurseTimes);
+ for (i = 0; i < keys.length; i++) {
+ output.push(
+ formatProperty(ctx, value, recurseTimes, keys[i], extrasType),
+ );
+ }
+ if (protoProps !== undefined) {
+ output.push(...protoProps);
+ }
+ } catch (err) {
+ const constructorName = getCtxStyle(value, constructor, tag).slice(0, -1);
+ return handleMaxCallStackSize(ctx, err, constructorName, indentationLvl);
+ }
+ if (ctx.circular !== undefined) {
+ const index = ctx.circular.get(value);
+ if (index !== undefined) {
+ const reference = ctx.stylize(`<ref *${index}>`, "special");
+ // Add reference always to the very beginning of the output.
+ if (ctx.compact !== true) {
+ base = base === "" ? reference : `${reference} ${base}`;
+ } else {
+ braces[0] = `${reference} ${braces[0]}`;
+ }
+ }
+ }
+ ctx.seen.pop();
+
+ if (ctx.sorted) {
+ const comparator = ctx.sorted === true ? undefined : ctx.sorted;
+ if (extrasType === kObjectType) {
+ output = output.sort(comparator);
+ } else if (keys.length > 1) {
+ const sorted = output.slice(output.length - keys.length).sort(comparator);
+ output.splice(output.length - keys.length, keys.length, ...sorted);
+ }
+ }
+
+ const res = reduceToSingleString(
+ ctx,
+ output,
+ base,
+ braces,
+ extrasType,
+ recurseTimes,
+ value,
+ );
+ const budget = ctx.budget[ctx.indentationLvl] || 0;
+ const newLength = budget + res.length;
+ ctx.budget[ctx.indentationLvl] = newLength;
+ // If any indentationLvl exceeds this limit, limit further inspecting to the
+ // minimum. Otherwise the recursive algorithm might continue inspecting the
+ // object even though the maximum string size (~2 ** 28 on 32 bit systems and
+ // ~2 ** 30 on 64 bit systems) exceeded. The actual output is not limited at
+ // exactly 2 ** 27 but a bit higher. This depends on the object shape.
+ // This limit also makes sure that huge objects don't block the event loop
+ // significantly.
+ if (newLength > 2 ** 27) {
+ ctx.depth = -1;
+ }
+ return res;
+}
+
+const builtInObjects = new Set(
+ Object.getOwnPropertyNames(globalThis).filter((e) =>
+ /^[A-Z][a-zA-Z0-9]+$/.test(e)
+ ),
+);
+
+function addPrototypeProperties(
+ ctx,
+ main,
+ obj,
+ recurseTimes,
+ output,
+) {
+ let depth = 0;
+ let keys;
+ let keySet;
+ do {
+ if (depth !== 0 || main === obj) {
+ obj = Object.getPrototypeOf(obj);
+ // Stop as soon as a null prototype is encountered.
+ if (obj === null) {
+ return;
+ }
+ // Stop as soon as a built-in object type is detected.
+ const descriptor = Object.getOwnPropertyDescriptor(obj, "constructor");
+ if (
+ descriptor !== undefined &&
+ typeof descriptor.value === "function" &&
+ builtInObjects.has(descriptor.value.name)
+ ) {
+ return;
+ }
+ }
+
+ if (depth === 0) {
+ keySet = new Set();
+ } else {
+ Array.prototype.forEach.call(keys, (key) => keySet.add(key));
+ }
+ // Get all own property names and symbols.
+ keys = Reflect.ownKeys(obj);
+ Array.prototype.push.call(ctx.seen, main);
+ for (const key of keys) {
+ // Ignore the `constructor` property and keys that exist on layers above.
+ if (
+ key === "constructor" ||
+ // deno-lint-ignore no-prototype-builtins
+ main.hasOwnProperty(key) ||
+ (depth !== 0 && keySet.has(key))
+ ) {
+ continue;
+ }
+ const desc = Object.getOwnPropertyDescriptor(obj, key);
+ if (typeof desc.value === "function") {
+ continue;
+ }
+ const value = formatProperty(
+ ctx,
+ obj,
+ recurseTimes,
+ key,
+ kObjectType,
+ desc,
+ main,
+ );
+ if (ctx.colors) {
+ // Faint!
+ Array.prototype.push.call(output, `\u001b[2m${value}\u001b[22m`);
+ } else {
+ Array.prototype.push.call(output, value);
+ }
+ }
+ Array.prototype.pop.call(ctx.seen);
+ // Limit the inspection to up to three prototype layers. Using `recurseTimes`
+ // is not a good choice here, because it's as if the properties are declared
+ // on the current object from the users perspective.
+ } while (++depth !== 3);
+}
+
+function getConstructorName(
+ obj,
+ ctx,
+ recurseTimes,
+ protoProps,
+) {
+ let firstProto;
+ const tmp = obj;
+ while (obj || isUndetectableObject(obj)) {
+ const descriptor = Object.getOwnPropertyDescriptor(obj, "constructor");
+ if (
+ descriptor !== undefined &&
+ typeof descriptor.value === "function" &&
+ descriptor.value.name !== "" &&
+ isInstanceof(tmp, descriptor.value)
+ ) {
+ if (
+ protoProps !== undefined &&
+ (firstProto !== obj ||
+ !builtInObjects.has(descriptor.value.name))
+ ) {
+ addPrototypeProperties(
+ ctx,
+ tmp,
+ firstProto || tmp,
+ recurseTimes,
+ protoProps,
+ );
+ }
+ return descriptor.value.name;
+ }
+
+ obj = Object.getPrototypeOf(obj);
+ if (firstProto === undefined) {
+ firstProto = obj;
+ }
+ }
+
+ if (firstProto === null) {
+ return null;
+ }
+
+ // TODO(wafuwafu13): Implement
+ // const res = internalGetConstructorName(tmp);
+ const res = undefined;
+
+ if (recurseTimes > ctx.depth && ctx.depth !== null) {
+ return `${res} <Complex prototype>`;
+ }
+
+ const protoConstr = getConstructorName(
+ firstProto,
+ ctx,
+ recurseTimes + 1,
+ protoProps,
+ );
+
+ if (protoConstr === null) {
+ return `${res} <${
+ inspect(firstProto, {
+ ...ctx,
+ customInspect: false,
+ depth: -1,
+ })
+ }>`;
+ }
+
+ return `${res} <${protoConstr}>`;
+}
+
+function formatPrimitive(fn, value, ctx) {
+ if (typeof value === "string") {
+ let trailer = "";
+ if (value.length > ctx.maxStringLength) {
+ const remaining = value.length - ctx.maxStringLength;
+ value = value.slice(0, ctx.maxStringLength);
+ trailer = `... ${remaining} more character${remaining > 1 ? "s" : ""}`;
+ }
+ if (
+ ctx.compact !== true &&
+ // TODO(BridgeAR): Add unicode support. Use the readline getStringWidth
+ // function.
+ value.length > kMinLineLength &&
+ value.length > ctx.breakLength - ctx.indentationLvl - 4
+ ) {
+ return value
+ .split(/(?<=\n)/)
+ .map((line) => fn(strEscape(line), "string"))
+ .join(` +\n${" ".repeat(ctx.indentationLvl + 2)}`) + trailer;
+ }
+ return fn(strEscape(value), "string") + trailer;
+ }
+ if (typeof value === "number") {
+ return formatNumber(fn, value);
+ }
+ if (typeof value === "bigint") {
+ return formatBigInt(fn, value);
+ }
+ if (typeof value === "boolean") {
+ return fn(`${value}`, "boolean");
+ }
+ if (typeof value === "undefined") {
+ return fn("undefined", "undefined");
+ }
+ // es6 symbol primitive
+ return fn(value.toString(), "symbol");
+}
+
+// Return a new empty array to push in the results of the default formatter.
+function getEmptyFormatArray() {
+ return [];
+}
+
+function isInstanceof(object, proto) {
+ try {
+ return object instanceof proto;
+ } catch {
+ return false;
+ }
+}
+
+function getPrefix(constructor, tag, fallback, size = "") {
+ if (constructor === null) {
+ if (tag !== "" && fallback !== tag) {
+ return `[${fallback}${size}: null prototype] [${tag}] `;
+ }
+ return `[${fallback}${size}: null prototype] `;
+ }
+
+ if (tag !== "" && constructor !== tag) {
+ return `${constructor}${size} [${tag}] `;
+ }
+ return `${constructor}${size} `;
+}
+
+function formatArray(ctx, value, recurseTimes) {
+ const valLen = value.length;
+ const len = Math.min(Math.max(0, ctx.maxArrayLength), valLen);
+
+ const remaining = valLen - len;
+ const output = [];
+ for (let i = 0; i < len; i++) {
+ // Special handle sparse arrays.
+ // deno-lint-ignore no-prototype-builtins
+ if (!value.hasOwnProperty(i)) {
+ return formatSpecialArray(ctx, value, recurseTimes, len, output, i);
+ }
+ output.push(formatProperty(ctx, value, recurseTimes, i, kArrayType));
+ }
+ if (remaining > 0) {
+ output.push(`... ${remaining} more item${remaining > 1 ? "s" : ""}`);
+ }
+ return output;
+}
+
+function getCtxStyle(_value, constructor, tag) {
+ let fallback = "";
+ if (constructor === null) {
+ // TODO(wafuwafu13): Implement
+ // fallback = internalGetConstructorName(value);
+ if (fallback === tag) {
+ fallback = "Object";
+ }
+ }
+ return getPrefix(constructor, tag, fallback);
+}
+
+// Look up the keys of the object.
+function getKeys(value, showHidden) {
+ let keys;
+ const symbols = Object.getOwnPropertySymbols(value);
+ if (showHidden) {
+ keys = Object.getOwnPropertyNames(value);
+ if (symbols.length !== 0) {
+ Array.prototype.push.apply(keys, symbols);
+ }
+ } else {
+ // This might throw if `value` is a Module Namespace Object from an
+ // unevaluated module, but we don't want to perform the actual type
+ // check because it's expensive.
+ // TODO(devsnek): track https://github.com/tc39/ecma262/issues/1209
+ // and modify this logic as needed.
+ try {
+ keys = Object.keys(value);
+ } catch (_err) {
+ // TODO(wafuwafu13): Implement
+ // assert(isNativeError(err) && err.name === 'ReferenceError' &&
+ // isModuleNamespaceObject(value));
+ keys = Object.getOwnPropertyNames(value);
+ }
+ if (symbols.length !== 0) {
+ // TODO(wafuwafu13): Implement
+ // const filter = (key: any) =>
+ //
+ // Object.prototype.propertyIsEnumerable(value, key);
+ // Array.prototype.push.apply(
+ // keys,
+ // symbols.filter(filter),
+ // );
+ }
+ }
+ return keys;
+}
+
+function formatSet(value, ctx, _ignored, recurseTimes) {
+ const output = [];
+ ctx.indentationLvl += 2;
+ for (const v of value) {
+ Array.prototype.push.call(output, formatValue(ctx, v, recurseTimes));
+ }
+ ctx.indentationLvl -= 2;
+ return output;
+}
+
+function formatMap(value, ctx, _gnored, recurseTimes) {
+ const output = [];
+ ctx.indentationLvl += 2;
+ for (const { 0: k, 1: v } of value) {
+ output.push(
+ `${formatValue(ctx, k, recurseTimes)} => ${
+ formatValue(ctx, v, recurseTimes)
+ }`,
+ );
+ }
+ ctx.indentationLvl -= 2;
+ return output;
+}
+
+function formatTypedArray(
+ value,
+ length,
+ ctx,
+ _ignored,
+ recurseTimes,
+) {
+ const maxLength = Math.min(Math.max(0, ctx.maxArrayLength), length);
+ const remaining = value.length - maxLength;
+ const output = new Array(maxLength);
+ const elementFormatter = value.length > 0 && typeof value[0] === "number"
+ ? formatNumber
+ : formatBigInt;
+ for (let i = 0; i < maxLength; ++i) {
+ output[i] = elementFormatter(ctx.stylize, value[i]);
+ }
+ if (remaining > 0) {
+ output[maxLength] = `... ${remaining} more item${remaining > 1 ? "s" : ""}`;
+ }
+ if (ctx.showHidden) {
+ // .buffer goes last, it's not a primitive like the others.
+ // All besides `BYTES_PER_ELEMENT` are actually getters.
+ ctx.indentationLvl += 2;
+ for (
+ const key of [
+ "BYTES_PER_ELEMENT",
+ "length",
+ "byteLength",
+ "byteOffset",
+ "buffer",
+ ]
+ ) {
+ const str = formatValue(ctx, value[key], recurseTimes, true);
+ Array.prototype.push.call(output, `[${key}]: ${str}`);
+ }
+ ctx.indentationLvl -= 2;
+ }
+ return output;
+}
+
+function getIteratorBraces(type, tag) {
+ if (tag !== `${type} Iterator`) {
+ if (tag !== "") {
+ tag += "] [";
+ }
+ tag += `${type} Iterator`;
+ }
+ return [`[${tag}] {`, "}"];
+}
+
+function formatIterator(braces, ctx, value, recurseTimes) {
+ // TODO(wafuwafu13): Implement
+ // const { 0: entries, 1: isKeyValue } = previewEntries(value, true);
+ const { 0: entries, 1: isKeyValue } = value;
+ if (isKeyValue) {
+ // Mark entry iterators as such.
+ braces[0] = braces[0].replace(/ Iterator] {$/, " Entries] {");
+ return formatMapIterInner(ctx, recurseTimes, entries, kMapEntries);
+ }
+
+ return formatSetIterInner(ctx, recurseTimes, entries, kIterator);
+}
+
+function getFunctionBase(value, constructor, tag) {
+ const stringified = Function.prototype.toString.call(value);
+ if (stringified.slice(0, 5) === "class" && stringified.endsWith("}")) {
+ const slice = stringified.slice(5, -1);
+ const bracketIndex = slice.indexOf("{");
+ if (
+ bracketIndex !== -1 &&
+ (!slice.slice(0, bracketIndex).includes("(") ||
+ // Slow path to guarantee that it's indeed a class.
+ classRegExp.test(slice.replace(stripCommentsRegExp)))
+ ) {
+ return getClassBase(value, constructor, tag);
+ }
+ }
+ let type = "Function";
+ if (types.isGeneratorFunction(value)) {
+ type = `Generator${type}`;
+ }
+ if (types.isAsyncFunction(value)) {
+ type = `Async${type}`;
+ }
+ let base = `[${type}`;
+ if (constructor === null) {
+ base += " (null prototype)";
+ }
+ if (value.name === "") {
+ base += " (anonymous)";
+ } else {
+ base += `: ${value.name}`;
+ }
+ base += "]";
+ if (constructor !== type && constructor !== null) {
+ base += ` ${constructor}`;
+ }
+ if (tag !== "" && constructor !== tag) {
+ base += ` [${tag}]`;
+ }
+ return base;
+}
+
+function formatError(
+ err,
+ constructor,
+ tag,
+ ctx,
+ keys,
+) {
+ const name = err.name != null ? String(err.name) : "Error";
+ let len = name.length;
+ let stack = err.stack ? String(err.stack) : err.toString();
+
+ // Do not "duplicate" error properties that are already included in the output
+ // otherwise.
+ if (!ctx.showHidden && keys.length !== 0) {
+ for (const name of ["name", "message", "stack"]) {
+ const index = keys.indexOf(name);
+ // Only hide the property in case it's part of the original stack
+ if (index !== -1 && stack.includes(err[name])) {
+ keys.splice(index, 1);
+ }
+ }
+ }
+
+ // A stack trace may contain arbitrary data. Only manipulate the output
+ // for "regular errors" (errors that "look normal") for now.
+ if (
+ constructor === null ||
+ (name.endsWith("Error") &&
+ stack.startsWith(name) &&
+ (stack.length === len || stack[len] === ":" || stack[len] === "\n"))
+ ) {
+ let fallback = "Error";
+ if (constructor === null) {
+ const start = stack.match(/^([A-Z][a-z_ A-Z0-9[\]()-]+)(?::|\n {4}at)/) ||
+ stack.match(/^([a-z_A-Z0-9-]*Error)$/);
+ fallback = (start && start[1]) || "";
+ len = fallback.length;
+ fallback = fallback || "Error";
+ }
+ const prefix = getPrefix(constructor, tag, fallback).slice(0, -1);
+ if (name !== prefix) {
+ if (prefix.includes(name)) {
+ if (len === 0) {
+ stack = `${prefix}: ${stack}`;
+ } else {
+ stack = `${prefix}${stack.slice(len)}`;
+ }
+ } else {
+ stack = `${prefix} [${name}]${stack.slice(len)}`;
+ }
+ }
+ }
+ // Ignore the error message if it's contained in the stack.
+ let pos = (err.message && stack.indexOf(err.message)) || -1;
+ if (pos !== -1) {
+ pos += err.message.length;
+ }
+ // Wrap the error in brackets in case it has no stack trace.
+ const stackStart = stack.indexOf("\n at", pos);
+ if (stackStart === -1) {
+ stack = `[${stack}]`;
+ } else if (ctx.colors) {
+ // Highlight userland code and node modules.
+ let newStack = stack.slice(0, stackStart);
+ const lines = stack.slice(stackStart + 1).split("\n");
+ for (const line of lines) {
+ // const core = line.match(coreModuleRegExp);
+ // TODO(wafuwafu13): Implement
+ // if (core !== null && NativeModule.exists(core[1])) {
+ // newStack += `\n${ctx.stylize(line, 'undefined')}`;
+ // } else {
+ // This adds underscores to all node_modules to quickly identify them.
+ let nodeModule;
+ newStack += "\n";
+ let pos = 0;
+ // deno-lint-ignore no-cond-assign
+ while (nodeModule = nodeModulesRegExp.exec(line)) {
+ // '/node_modules/'.length === 14
+ newStack += line.slice(pos, nodeModule.index + 14);
+ newStack += ctx.stylize(nodeModule[1], "module");
+ pos = nodeModule.index + nodeModule[0].length;
+ }
+ newStack += pos === 0 ? line : line.slice(pos);
+ // }
+ }
+ stack = newStack;
+ }
+ // The message and the stack have to be indented as well!
+ if (ctx.indentationLvl !== 0) {
+ const indentation = " ".repeat(ctx.indentationLvl);
+ stack = stack.replace(/\n/g, `\n${indentation}`);
+ }
+ return stack;
+}
+
+let hexSlice;
+
+function formatArrayBuffer(ctx, value) {
+ let buffer;
+ try {
+ buffer = new Uint8Array(value);
+ } catch {
+ return [ctx.stylize("(detached)", "special")];
+ }
+ // TODO(wafuwafu13): Implement
+ // if (hexSlice === undefined)
+ // hexSlice = uncurryThis(require('buffer').Buffer.prototype.hexSlice);
+ let str = hexSlice(buffer, 0, Math.min(ctx.maxArrayLength, buffer.length))
+ .replace(/(.{2})/g, "$1 ").trim();
+
+ const remaining = buffer.length - ctx.maxArrayLength;
+ if (remaining > 0) {
+ str += ` ... ${remaining} more byte${remaining > 1 ? "s" : ""}`;
+ }
+ return [`${ctx.stylize("[Uint8Contents]", "special")}: <${str}>`];
+}
+
+function formatNumber(fn, value) {
+ // Format -0 as '-0'. Checking `value === -0` won't distinguish 0 from -0.
+ return fn(Object.is(value, -0) ? "-0" : `${value}`, "number");
+}
+
+function formatPromise(ctx, value, recurseTimes) {
+ let output;
+ // TODO(wafuwafu13): Implement
+ // const { 0: state, 1: result } = getPromiseDetails(value);
+ const { 0: state, 1: result } = value;
+ if (state === kPending) {
+ output = [ctx.stylize("<pending>", "special")];
+ } else {
+ ctx.indentationLvl += 2;
+ const str = formatValue(ctx, result, recurseTimes);
+ ctx.indentationLvl -= 2;
+ output = [
+ state === kRejected
+ ? `${ctx.stylize("<rejected>", "special")} ${str}`
+ : str,
+ ];
+ }
+ return output;
+}
+
+function formatWeakCollection(ctx) {
+ return [ctx.stylize("<items unknown>", "special")];
+}
+
+function formatWeakSet(ctx, value, recurseTimes) {
+ // TODO(wafuwafu13): Implement
+ // const entries = previewEntries(value);
+ const entries = value;
+ return formatSetIterInner(ctx, recurseTimes, entries, kWeak);
+}
+
+function formatWeakMap(ctx, value, recurseTimes) {
+ // TODO(wafuwafu13): Implement
+ // const entries = previewEntries(value);
+ const entries = value;
+ return formatMapIterInner(ctx, recurseTimes, entries, kWeak);
+}
+
+function formatProperty(
+ ctx,
+ value,
+ recurseTimes,
+ key,
+ type,
+ desc,
+ original = value,
+) {
+ let name, str;
+ let extra = " ";
+ desc = desc || Object.getOwnPropertyDescriptor(value, key) ||
+ { value: value[key], enumerable: true };
+ if (desc.value !== undefined) {
+ const diff = (ctx.compact !== true || type !== kObjectType) ? 2 : 3;
+ ctx.indentationLvl += diff;
+ str = formatValue(ctx, desc.value, recurseTimes);
+ if (diff === 3 && ctx.breakLength < getStringWidth(str, ctx.colors)) {
+ extra = `\n${" ".repeat(ctx.indentationLvl)}`;
+ }
+ ctx.indentationLvl -= diff;
+ } else if (desc.get !== undefined) {
+ const label = desc.set !== undefined ? "Getter/Setter" : "Getter";
+ const s = ctx.stylize;
+ const sp = "special";
+ if (
+ ctx.getters && (ctx.getters === true ||
+ (ctx.getters === "get" && desc.set === undefined) ||
+ (ctx.getters === "set" && desc.set !== undefined))
+ ) {
+ try {
+ const tmp = desc.get.call(original);
+ ctx.indentationLvl += 2;
+ if (tmp === null) {
+ str = `${s(`[${label}:`, sp)} ${s("null", "null")}${s("]", sp)}`;
+ } else if (typeof tmp === "object") {
+ str = `${s(`[${label}]`, sp)} ${formatValue(ctx, tmp, recurseTimes)}`;
+ } else {
+ const primitive = formatPrimitive(s, tmp, ctx);
+ str = `${s(`[${label}:`, sp)} ${primitive}${s("]", sp)}`;
+ }
+ ctx.indentationLvl -= 2;
+ } catch (err) {
+ const message = `<Inspection threw (${err.message})>`;
+ str = `${s(`[${label}:`, sp)} ${message}${s("]", sp)}`;
+ }
+ } else {
+ str = ctx.stylize(`[${label}]`, sp);
+ }
+ } else if (desc.set !== undefined) {
+ str = ctx.stylize("[Setter]", "special");
+ } else {
+ str = ctx.stylize("undefined", "undefined");
+ }
+ if (type === kArrayType) {
+ return str;
+ }
+ if (typeof key === "symbol") {
+ const tmp = key.toString().replace(strEscapeSequencesReplacer, escapeFn);
+
+ name = `[${ctx.stylize(tmp, "symbol")}]`;
+ } else if (key === "__proto__") {
+ name = "['__proto__']";
+ } else if (desc.enumerable === false) {
+ const tmp = key.replace(strEscapeSequencesReplacer, escapeFn);
+
+ name = `[${tmp}]`;
+ } else if (keyStrRegExp.test(key)) {
+ name = ctx.stylize(key, "name");
+ } else {
+ name = ctx.stylize(strEscape(key), "string");
+ }
+ return `${name}:${extra}${str}`;
+}
+
+function handleMaxCallStackSize(
+ _ctx,
+ _err,
+ _constructorName,
+ _indentationLvl,
+) {
+ // TODO(wafuwafu13): Implement
+ // if (types.isStackOverflowError(err)) {
+ // ctx.seen.pop();
+ // ctx.indentationLvl = indentationLvl;
+ // return ctx.stylize(
+ // `[${constructorName}: Inspection interrupted ` +
+ // 'prematurely. Maximum call stack size exceeded.]',
+ // 'special'
+ // );
+ // }
+ // /* c8 ignore next */
+ // assert.fail(err.stack);
+}
+
+// deno-lint-ignore no-control-regex
+const colorRegExp = /\u001b\[\d\d?m/g;
+function removeColors(str) {
+ return str.replace(colorRegExp, "");
+}
+
+function isBelowBreakLength(ctx, output, start, base) {
+ // Each entry is separated by at least a comma. Thus, we start with a total
+ // length of at least `output.length`. In addition, some cases have a
+ // whitespace in-between each other that is added to the total as well.
+ // TODO(BridgeAR): Add unicode support. Use the readline getStringWidth
+ // function. Check the performance overhead and make it an opt-in in case it's
+ // significant.
+ let totalLength = output.length + start;
+ if (totalLength + output.length > ctx.breakLength) {
+ return false;
+ }
+ for (let i = 0; i < output.length; i++) {
+ if (ctx.colors) {
+ totalLength += removeColors(output[i]).length;
+ } else {
+ totalLength += output[i].length;
+ }
+ if (totalLength > ctx.breakLength) {
+ return false;
+ }
+ }
+ // Do not line up properties on the same line if `base` contains line breaks.
+ return base === "" || !base.includes("\n");
+}
+
+function formatBigInt(fn, value) {
+ return fn(`${value}n`, "bigint");
+}
+
+function formatNamespaceObject(
+ keys,
+ ctx,
+ value,
+ recurseTimes,
+) {
+ const output = new Array(keys.length);
+ for (let i = 0; i < keys.length; i++) {
+ try {
+ output[i] = formatProperty(
+ ctx,
+ value,
+ recurseTimes,
+ keys[i],
+ kObjectType,
+ );
+ } catch (_err) {
+ // TODO(wafuwfu13): Implement
+ // assert(isNativeError(err) && err.name === 'ReferenceError');
+ // Use the existing functionality. This makes sure the indentation and
+ // line breaks are always correct. Otherwise it is very difficult to keep
+ // this aligned, even though this is a hacky way of dealing with this.
+ const tmp = { [keys[i]]: "" };
+ output[i] = formatProperty(ctx, tmp, recurseTimes, keys[i], kObjectType);
+ const pos = output[i].lastIndexOf(" ");
+ // We have to find the last whitespace and have to replace that value as
+ // it will be visualized as a regular string.
+ output[i] = output[i].slice(0, pos + 1) +
+ ctx.stylize("<uninitialized>", "special");
+ }
+ }
+ // Reset the keys to an empty array. This prevents duplicated inspection.
+ keys.length = 0;
+ return output;
+}
+
+// The array is sparse and/or has extra keys
+function formatSpecialArray(
+ ctx,
+ value,
+ recurseTimes,
+ maxLength,
+ output,
+ i,
+) {
+ const keys = Object.keys(value);
+ let index = i;
+ for (; i < keys.length && output.length < maxLength; i++) {
+ const key = keys[i];
+ const tmp = +key;
+ // Arrays can only have up to 2^32 - 1 entries
+ if (tmp > 2 ** 32 - 2) {
+ break;
+ }
+ if (`${index}` !== key) {
+ if (!numberRegExp.test(key)) {
+ break;
+ }
+ const emptyItems = tmp - index;
+ const ending = emptyItems > 1 ? "s" : "";
+ const message = `<${emptyItems} empty item${ending}>`;
+ output.push(ctx.stylize(message, "undefined"));
+ index = tmp;
+ if (output.length === maxLength) {
+ break;
+ }
+ }
+ output.push(formatProperty(ctx, value, recurseTimes, key, kArrayType));
+ index++;
+ }
+ const remaining = value.length - index;
+ if (output.length !== maxLength) {
+ if (remaining > 0) {
+ const ending = remaining > 1 ? "s" : "";
+ const message = `<${remaining} empty item${ending}>`;
+ output.push(ctx.stylize(message, "undefined"));
+ }
+ } else if (remaining > 0) {
+ output.push(`... ${remaining} more item${remaining > 1 ? "s" : ""}`);
+ }
+ return output;
+}
+
+function getBoxedBase(
+ value,
+ ctx,
+ keys,
+ constructor,
+ tag,
+) {
+ let type;
+ if (types.isNumberObject(value)) {
+ type = "Number";
+ } else if (types.isStringObject(value)) {
+ type = "String";
+ // For boxed Strings, we have to remove the 0-n indexed entries,
+ // since they just noisy up the output and are redundant
+ // Make boxed primitive Strings look like such
+ keys.splice(0, value.length);
+ } else if (types.isBooleanObject(value)) {
+ type = "Boolean";
+ } else if (types.isBigIntObject(value)) {
+ type = "BigInt";
+ } else {
+ type = "Symbol";
+ }
+ let base = `[${type}`;
+ if (type !== constructor) {
+ if (constructor === null) {
+ base += " (null prototype)";
+ } else {
+ base += ` (${constructor})`;
+ }
+ }
+
+ base += `: ${formatPrimitive(stylizeNoColor, value.valueOf(), ctx)}]`;
+ if (tag !== "" && tag !== constructor) {
+ base += ` [${tag}]`;
+ }
+ if (keys.length !== 0 || ctx.stylize === stylizeNoColor) {
+ return base;
+ }
+ return ctx.stylize(base, type.toLowerCase());
+}
+
+function getClassBase(value, constructor, tag) {
+ // deno-lint-ignore no-prototype-builtins
+ const hasName = value.hasOwnProperty("name");
+ const name = (hasName && value.name) || "(anonymous)";
+ let base = `class ${name}`;
+ if (constructor !== "Function" && constructor !== null) {
+ base += ` [${constructor}]`;
+ }
+ if (tag !== "" && constructor !== tag) {
+ base += ` [${tag}]`;
+ }
+ if (constructor !== null) {
+ const superName = Object.getPrototypeOf(value).name;
+ if (superName) {
+ base += ` extends ${superName}`;
+ }
+ } else {
+ base += " extends [null prototype]";
+ }
+ return `[${base}]`;
+}
+
+function reduceToSingleString(
+ ctx,
+ output,
+ base,
+ braces,
+ extrasType,
+ recurseTimes,
+ value,
+) {
+ if (ctx.compact !== true) {
+ if (typeof ctx.compact === "number" && ctx.compact >= 1) {
+ // Memorize the original output length. In case the output is grouped,
+ // prevent lining up the entries on a single line.
+ const entries = output.length;
+ // Group array elements together if the array contains at least six
+ // separate entries.
+ if (extrasType === kArrayExtrasType && entries > 6) {
+ output = groupArrayElements(ctx, output, value);
+ }
+ // `ctx.currentDepth` is set to the most inner depth of the currently
+ // inspected object part while `recurseTimes` is the actual current depth
+ // that is inspected.
+ //
+ // Example:
+ //
+ // const a = { first: [ 1, 2, 3 ], second: { inner: [ 1, 2, 3 ] } }
+ //
+ // The deepest depth of `a` is 2 (a.second.inner) and `a.first` has a max
+ // depth of 1.
+ //
+ // Consolidate all entries of the local most inner depth up to
+ // `ctx.compact`, as long as the properties are smaller than
+ // `ctx.breakLength`.
+ if (
+ ctx.currentDepth - recurseTimes < ctx.compact &&
+ entries === output.length
+ ) {
+ // Line up all entries on a single line in case the entries do not
+ // exceed `breakLength`. Add 10 as constant to start next to all other
+ // factors that may reduce `breakLength`.
+ const start = output.length + ctx.indentationLvl +
+ braces[0].length + base.length + 10;
+ if (isBelowBreakLength(ctx, output, start, base)) {
+ return `${base ? `${base} ` : ""}${braces[0]} ${join(output, ", ")}` +
+ ` ${braces[1]}`;
+ }
+ }
+ }
+ // Line up each entry on an individual line.
+ const indentation = `\n${" ".repeat(ctx.indentationLvl)}`;
+ return `${base ? `${base} ` : ""}${braces[0]}${indentation} ` +
+ `${join(output, `,${indentation} `)}${indentation}${braces[1]}`;
+ }
+ // Line up all entries on a single line in case the entries do not exceed
+ // `breakLength`.
+ if (isBelowBreakLength(ctx, output, 0, base)) {
+ return `${braces[0]}${base ? ` ${base}` : ""} ${join(output, ", ")} ` +
+ braces[1];
+ }
+ const indentation = " ".repeat(ctx.indentationLvl);
+ // If the opening "brace" is too large, like in the case of "Set {",
+ // we need to force the first item to be on the next line or the
+ // items will not line up correctly.
+ const ln = base === "" && braces[0].length === 1
+ ? " "
+ : `${base ? ` ${base}` : ""}\n${indentation} `;
+ // Line up each entry on an individual line.
+ return `${braces[0]}${ln}${join(output, `,\n${indentation} `)} ${braces[1]}`;
+}
+
+// The built-in Array#join is slower in v8 6.0
+function join(output, separator) {
+ let str = "";
+ if (output.length !== 0) {
+ const lastIndex = output.length - 1;
+ for (let i = 0; i < lastIndex; i++) {
+ // It is faster not to use a template string here
+ str += output[i];
+ str += separator;
+ }
+ str += output[lastIndex];
+ }
+ return str;
+}
+
+function groupArrayElements(ctx, output, value) {
+ let totalLength = 0;
+ let maxLength = 0;
+ let i = 0;
+ let outputLength = output.length;
+ if (ctx.maxArrayLength < output.length) {
+ // This makes sure the "... n more items" part is not taken into account.
+ outputLength--;
+ }
+ const separatorSpace = 2; // Add 1 for the space and 1 for the separator.
+ const dataLen = new Array(outputLength);
+ // Calculate the total length of all output entries and the individual max
+ // entries length of all output entries. We have to remove colors first,
+ // otherwise the length would not be calculated properly.
+ for (; i < outputLength; i++) {
+ const len = getStringWidth(output[i], ctx.colors);
+ dataLen[i] = len;
+ totalLength += len + separatorSpace;
+ if (maxLength < len) {
+ maxLength = len;
+ }
+ }
+ // Add two to `maxLength` as we add a single whitespace character plus a comma
+ // in-between two entries.
+ const actualMax = maxLength + separatorSpace;
+ // Check if at least three entries fit next to each other and prevent grouping
+ // of arrays that contains entries of very different length (i.e., if a single
+ // entry is longer than 1/5 of all other entries combined). Otherwise the
+ // space in-between small entries would be enormous.
+ if (
+ actualMax * 3 + ctx.indentationLvl < ctx.breakLength &&
+ (totalLength / actualMax > 5 || maxLength <= 6)
+ ) {
+ const approxCharHeights = 2.5;
+ const averageBias = Math.sqrt(actualMax - totalLength / output.length);
+ const biasedMax = Math.max(actualMax - 3 - averageBias, 1);
+ // Dynamically check how many columns seem possible.
+ const columns = Math.min(
+ // Ideally a square should be drawn. We expect a character to be about 2.5
+ // times as high as wide. This is the area formula to calculate a square
+ // which contains n rectangles of size `actualMax * approxCharHeights`.
+ // Divide that by `actualMax` to receive the correct number of columns.
+ // The added bias increases the columns for short entries.
+ Math.round(
+ Math.sqrt(
+ approxCharHeights * biasedMax * outputLength,
+ ) / biasedMax,
+ ),
+ // Do not exceed the breakLength.
+ Math.floor((ctx.breakLength - ctx.indentationLvl) / actualMax),
+ // Limit array grouping for small `compact` modes as the user requested
+ // minimal grouping.
+ ctx.compact * 4,
+ // Limit the columns to a maximum of fifteen.
+ 15,
+ );
+ // Return with the original output if no grouping should happen.
+ if (columns <= 1) {
+ return output;
+ }
+ const tmp = [];
+ const maxLineLength = [];
+ for (let i = 0; i < columns; i++) {
+ let lineMaxLength = 0;
+ for (let j = i; j < output.length; j += columns) {
+ if (dataLen[j] > lineMaxLength) {
+ lineMaxLength = dataLen[j];
+ }
+ }
+ lineMaxLength += separatorSpace;
+ maxLineLength[i] = lineMaxLength;
+ }
+ let order = String.prototype.padStart;
+ if (value !== undefined) {
+ for (let i = 0; i < output.length; i++) {
+ if (typeof value[i] !== "number" && typeof value[i] !== "bigint") {
+ order = String.prototype.padEnd;
+ break;
+ }
+ }
+ }
+ // Each iteration creates a single line of grouped entries.
+ for (let i = 0; i < outputLength; i += columns) {
+ // The last lines may contain less entries than columns.
+ const max = Math.min(i + columns, outputLength);
+ let str = "";
+ let j = i;
+ for (; j < max - 1; j++) {
+ // Calculate extra color padding in case it's active. This has to be
+ // done line by line as some lines might contain more colors than
+ // others.
+ const padding = maxLineLength[j - i] + output[j].length - dataLen[j];
+ str += `${output[j]}, `.padStart(padding, " ");
+ }
+ if (order === String.prototype.padStart) {
+ const padding = maxLineLength[j - i] +
+ output[j].length -
+ dataLen[j] -
+ separatorSpace;
+ str += output[j].padStart(padding, " ");
+ } else {
+ str += output[j];
+ }
+ Array.prototype.push.call(tmp, str);
+ }
+ if (ctx.maxArrayLength < output.length) {
+ Array.prototype.push.call(tmp, output[outputLength]);
+ }
+ output = tmp;
+ }
+ return output;
+}
+
+function formatMapIterInner(
+ ctx,
+ recurseTimes,
+ entries,
+ state,
+) {
+ const maxArrayLength = Math.max(ctx.maxArrayLength, 0);
+ // Entries exist as [key1, val1, key2, val2, ...]
+ const len = entries.length / 2;
+ const remaining = len - maxArrayLength;
+ const maxLength = Math.min(maxArrayLength, len);
+ let output = new Array(maxLength);
+ let i = 0;
+ ctx.indentationLvl += 2;
+ if (state === kWeak) {
+ for (; i < maxLength; i++) {
+ const pos = i * 2;
+ output[i] = `${formatValue(ctx, entries[pos], recurseTimes)} => ${
+ formatValue(ctx, entries[pos + 1], recurseTimes)
+ }`;
+ }
+ // Sort all entries to have a halfway reliable output (if more entries than
+ // retrieved ones exist, we can not reliably return the same output) if the
+ // output is not sorted anyway.
+ if (!ctx.sorted) {
+ output = output.sort();
+ }
+ } else {
+ for (; i < maxLength; i++) {
+ const pos = i * 2;
+ const res = [
+ formatValue(ctx, entries[pos], recurseTimes),
+ formatValue(ctx, entries[pos + 1], recurseTimes),
+ ];
+ output[i] = reduceToSingleString(
+ ctx,
+ res,
+ "",
+ ["[", "]"],
+ kArrayExtrasType,
+ recurseTimes,
+ );
+ }
+ }
+ ctx.indentationLvl -= 2;
+ if (remaining > 0) {
+ output.push(`... ${remaining} more item${remaining > 1 ? "s" : ""}`);
+ }
+ return output;
+}
+
+function formatSetIterInner(
+ ctx,
+ recurseTimes,
+ entries,
+ state,
+) {
+ const maxArrayLength = Math.max(ctx.maxArrayLength, 0);
+ const maxLength = Math.min(maxArrayLength, entries.length);
+ const output = new Array(maxLength);
+ ctx.indentationLvl += 2;
+ for (let i = 0; i < maxLength; i++) {
+ output[i] = formatValue(ctx, entries[i], recurseTimes);
+ }
+ ctx.indentationLvl -= 2;
+ if (state === kWeak && !ctx.sorted) {
+ // Sort all entries to have a halfway reliable output (if more entries than
+ // retrieved ones exist, we can not reliably return the same output) if the
+ // output is not sorted anyway.
+ output.sort();
+ }
+ const remaining = entries.length - maxLength;
+ if (remaining > 0) {
+ Array.prototype.push.call(
+ output,
+ `... ${remaining} more item${remaining > 1 ? "s" : ""}`,
+ );
+ }
+ return output;
+}
+
+// Regex used for ansi escape code splitting
+// Adopted from https://github.com/chalk/ansi-regex/blob/HEAD/index.js
+// License: MIT, authors: @sindresorhus, Qix-, arjunmehta and LitoMore
+// Matches all ansi escape code sequences in a string
+const ansiPattern = "[\\u001B\\u009B][[\\]()#;?]*" +
+ "(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*" +
+ "|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)" +
+ "|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))";
+const ansi = new RegExp(ansiPattern, "g");
+
+/**
+ * Returns the number of columns required to display the given string.
+ */
+export function getStringWidth(str, removeControlChars = true) {
+ let width = 0;
+
+ if (removeControlChars) {
+ str = stripVTControlCharacters(str);
+ }
+ str = str.normalize("NFC");
+ for (const char of str[Symbol.iterator]()) {
+ const code = char.codePointAt(0);
+ if (isFullWidthCodePoint(code)) {
+ width += 2;
+ } else if (!isZeroWidthCodePoint(code)) {
+ width++;
+ }
+ }
+
+ return width;
+}
+
+/**
+ * Returns true if the character represented by a given
+ * Unicode code point is full-width. Otherwise returns false.
+ */
+const isFullWidthCodePoint = (code) => {
+ // Code points are partially derived from:
+ // https://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt
+ return code >= 0x1100 && (
+ code <= 0x115f || // Hangul Jamo
+ code === 0x2329 || // LEFT-POINTING ANGLE BRACKET
+ code === 0x232a || // RIGHT-POINTING ANGLE BRACKET
+ // CJK Radicals Supplement .. Enclosed CJK Letters and Months
+ (code >= 0x2e80 && code <= 0x3247 && code !== 0x303f) ||
+ // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A
+ (code >= 0x3250 && code <= 0x4dbf) ||
+ // CJK Unified Ideographs .. Yi Radicals
+ (code >= 0x4e00 && code <= 0xa4c6) ||
+ // Hangul Jamo Extended-A
+ (code >= 0xa960 && code <= 0xa97c) ||
+ // Hangul Syllables
+ (code >= 0xac00 && code <= 0xd7a3) ||
+ // CJK Compatibility Ideographs
+ (code >= 0xf900 && code <= 0xfaff) ||
+ // Vertical Forms
+ (code >= 0xfe10 && code <= 0xfe19) ||
+ // CJK Compatibility Forms .. Small Form Variants
+ (code >= 0xfe30 && code <= 0xfe6b) ||
+ // Halfwidth and Fullwidth Forms
+ (code >= 0xff01 && code <= 0xff60) ||
+ (code >= 0xffe0 && code <= 0xffe6) ||
+ // Kana Supplement
+ (code >= 0x1b000 && code <= 0x1b001) ||
+ // Enclosed Ideographic Supplement
+ (code >= 0x1f200 && code <= 0x1f251) ||
+ // Miscellaneous Symbols and Pictographs 0x1f300 - 0x1f5ff
+ // Emoticons 0x1f600 - 0x1f64f
+ (code >= 0x1f300 && code <= 0x1f64f) ||
+ // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane
+ (code >= 0x20000 && code <= 0x3fffd)
+ );
+};
+
+const isZeroWidthCodePoint = (code) => {
+ return code <= 0x1F || // C0 control codes
+ (code >= 0x7F && code <= 0x9F) || // C1 control codes
+ (code >= 0x300 && code <= 0x36F) || // Combining Diacritical Marks
+ (code >= 0x200B && code <= 0x200F) || // Modifying Invisible Characters
+ // Combining Diacritical Marks for Symbols
+ (code >= 0x20D0 && code <= 0x20FF) ||
+ (code >= 0xFE00 && code <= 0xFE0F) || // Variation Selectors
+ (code >= 0xFE20 && code <= 0xFE2F) || // Combining Half Marks
+ (code >= 0xE0100 && code <= 0xE01EF); // Variation Selectors
+};
+
+function hasBuiltInToString(value) {
+ // TODO(wafuwafu13): Implement
+ // // Prevent triggering proxy traps.
+ // const getFullProxy = false;
+ // const proxyTarget = getProxyDetails(value, getFullProxy);
+ const proxyTarget = undefined;
+ if (proxyTarget !== undefined) {
+ value = proxyTarget;
+ }
+
+ // Count objects that have no `toString` function as built-in.
+ if (typeof value.toString !== "function") {
+ return true;
+ }
+
+ // The object has a own `toString` property. Thus it's not not a built-in one.
+ if (Object.prototype.hasOwnProperty.call(value, "toString")) {
+ return false;
+ }
+
+ // Find the object that has the `toString` property as own property in the
+ // prototype chain.
+ let pointer = value;
+ do {
+ pointer = Object.getPrototypeOf(pointer);
+ } while (!Object.prototype.hasOwnProperty.call(pointer, "toString"));
+
+ // Check closer if the object is a built-in.
+ const descriptor = Object.getOwnPropertyDescriptor(pointer, "constructor");
+ return descriptor !== undefined &&
+ typeof descriptor.value === "function" &&
+ builtInObjects.has(descriptor.value.name);
+}
+
+const firstErrorLine = (error) => error.message.split("\n", 1)[0];
+let CIRCULAR_ERROR_MESSAGE;
+function tryStringify(arg) {
+ try {
+ return JSON.stringify(arg);
+ } catch (err) {
+ // Populate the circular error message lazily
+ if (!CIRCULAR_ERROR_MESSAGE) {
+ try {
+ const a = {};
+ a.a = a;
+ JSON.stringify(a);
+ } catch (circularError) {
+ CIRCULAR_ERROR_MESSAGE = firstErrorLine(circularError);
+ }
+ }
+ if (
+ err.name === "TypeError" &&
+ firstErrorLine(err) === CIRCULAR_ERROR_MESSAGE
+ ) {
+ return "[Circular]";
+ }
+ throw err;
+ }
+}
+
+export function format(...args) {
+ return formatWithOptionsInternal(undefined, args);
+}
+
+export function formatWithOptions(inspectOptions, ...args) {
+ if (typeof inspectOptions !== "object" || inspectOptions === null) {
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ "inspectOptions",
+ "object",
+ inspectOptions,
+ );
+ }
+ return formatWithOptionsInternal(inspectOptions, args);
+}
+
+function formatNumberNoColor(number, options) {
+ return formatNumber(
+ stylizeNoColor,
+ number,
+ options?.numericSeparator ?? inspectDefaultOptions.numericSeparator,
+ );
+}
+
+function formatBigIntNoColor(bigint, options) {
+ return formatBigInt(
+ stylizeNoColor,
+ bigint,
+ options?.numericSeparator ?? inspectDefaultOptions.numericSeparator,
+ );
+}
+
+function formatWithOptionsInternal(inspectOptions, args) {
+ const first = args[0];
+ let a = 0;
+ let str = "";
+ let join = "";
+
+ if (typeof first === "string") {
+ if (args.length === 1) {
+ return first;
+ }
+ let tempStr;
+ let lastPos = 0;
+
+ for (let i = 0; i < first.length - 1; i++) {
+ if (first.charCodeAt(i) === 37) { // '%'
+ const nextChar = first.charCodeAt(++i);
+ if (a + 1 !== args.length) {
+ switch (nextChar) {
+ // deno-lint-ignore no-case-declarations
+ case 115: // 's'
+ const tempArg = args[++a];
+ if (typeof tempArg === "number") {
+ tempStr = formatNumberNoColor(tempArg, inspectOptions);
+ } else if (typeof tempArg === "bigint") {
+ tempStr = formatBigIntNoColor(tempArg, inspectOptions);
+ } else if (
+ typeof tempArg !== "object" ||
+ tempArg === null ||
+ !hasBuiltInToString(tempArg)
+ ) {
+ tempStr = String(tempArg);
+ } else {
+ tempStr = inspect(tempArg, {
+ ...inspectOptions,
+ compact: 3,
+ colors: false,
+ depth: 0,
+ });
+ }
+ break;
+ case 106: // 'j'
+ tempStr = tryStringify(args[++a]);
+ break;
+ // deno-lint-ignore no-case-declarations
+ case 100: // 'd'
+ const tempNum = args[++a];
+ if (typeof tempNum === "bigint") {
+ tempStr = formatBigIntNoColor(tempNum, inspectOptions);
+ } else if (typeof tempNum === "symbol") {
+ tempStr = "NaN";
+ } else {
+ tempStr = formatNumberNoColor(Number(tempNum), inspectOptions);
+ }
+ break;
+ case 79: // 'O'
+ tempStr = inspect(args[++a], inspectOptions);
+ break;
+ case 111: // 'o'
+ tempStr = inspect(args[++a], {
+ ...inspectOptions,
+ showHidden: true,
+ showProxy: true,
+ depth: 4,
+ });
+ break;
+ // deno-lint-ignore no-case-declarations
+ case 105: // 'i'
+ const tempInteger = args[++a];
+ if (typeof tempInteger === "bigint") {
+ tempStr = formatBigIntNoColor(tempInteger, inspectOptions);
+ } else if (typeof tempInteger === "symbol") {
+ tempStr = "NaN";
+ } else {
+ tempStr = formatNumberNoColor(
+ Number.parseInt(tempInteger),
+ inspectOptions,
+ );
+ }
+ break;
+ // deno-lint-ignore no-case-declarations
+ case 102: // 'f'
+ const tempFloat = args[++a];
+ if (typeof tempFloat === "symbol") {
+ tempStr = "NaN";
+ } else {
+ tempStr = formatNumberNoColor(
+ Number.parseFloat(tempFloat),
+ inspectOptions,
+ );
+ }
+ break;
+ case 99: // 'c'
+ a += 1;
+ tempStr = "";
+ break;
+ case 37: // '%'
+ str += first.slice(lastPos, i);
+ lastPos = i + 1;
+ continue;
+ default: // Any other character is not a correct placeholder
+ continue;
+ }
+ if (lastPos !== i - 1) {
+ str += first.slice(lastPos, i - 1);
+ }
+ str += tempStr;
+ lastPos = i + 1;
+ } else if (nextChar === 37) {
+ str += first.slice(lastPos, i);
+ lastPos = i + 1;
+ }
+ }
+ }
+ if (lastPos !== 0) {
+ a++;
+ join = " ";
+ if (lastPos < first.length) {
+ str += first.slice(lastPos);
+ }
+ }
+ }
+
+ while (a < args.length) {
+ const value = args[a];
+ str += join;
+ str += typeof value !== "string" ? inspect(value, inspectOptions) : value;
+ join = " ";
+ a++;
+ }
+ return str;
+}
+
+/**
+ * Remove all VT control characters. Use to estimate displayed string width.
+ */
+export function stripVTControlCharacters(str) {
+ validateString(str, "str");
+
+ return str.replace(ansi, "");
+}
+
+export default {
+ format,
+ getStringWidth,
+ inspect,
+ stripVTControlCharacters,
+ formatWithOptions,
+};
diff --git a/ext/node/polyfills/internal/util/types.ts b/ext/node/polyfills/internal/util/types.ts
new file mode 100644
index 000000000..299493bc9
--- /dev/null
+++ b/ext/node/polyfills/internal/util/types.ts
@@ -0,0 +1,143 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+//
+// Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import * as bindingTypes from "internal:deno_node/polyfills/internal_binding/types.ts";
+export {
+ isCryptoKey,
+ isKeyObject,
+} from "internal:deno_node/polyfills/internal/crypto/_keys.ts";
+
+// https://tc39.es/ecma262/#sec-get-%typedarray%.prototype-@@tostringtag
+const _getTypedArrayToStringTag = Object.getOwnPropertyDescriptor(
+ Object.getPrototypeOf(Uint8Array).prototype,
+ Symbol.toStringTag,
+)!.get!;
+
+export function isArrayBufferView(
+ value: unknown,
+): value is
+ | DataView
+ | BigInt64Array
+ | BigUint64Array
+ | Float32Array
+ | Float64Array
+ | Int8Array
+ | Int16Array
+ | Int32Array
+ | Uint8Array
+ | Uint8ClampedArray
+ | Uint16Array
+ | Uint32Array {
+ return ArrayBuffer.isView(value);
+}
+
+export function isBigInt64Array(value: unknown): value is BigInt64Array {
+ return _getTypedArrayToStringTag.call(value) === "BigInt64Array";
+}
+
+export function isBigUint64Array(value: unknown): value is BigUint64Array {
+ return _getTypedArrayToStringTag.call(value) === "BigUint64Array";
+}
+
+export function isFloat32Array(value: unknown): value is Float32Array {
+ return _getTypedArrayToStringTag.call(value) === "Float32Array";
+}
+
+export function isFloat64Array(value: unknown): value is Float64Array {
+ return _getTypedArrayToStringTag.call(value) === "Float64Array";
+}
+
+export function isInt8Array(value: unknown): value is Int8Array {
+ return _getTypedArrayToStringTag.call(value) === "Int8Array";
+}
+
+export function isInt16Array(value: unknown): value is Int16Array {
+ return _getTypedArrayToStringTag.call(value) === "Int16Array";
+}
+
+export function isInt32Array(value: unknown): value is Int32Array {
+ return _getTypedArrayToStringTag.call(value) === "Int32Array";
+}
+
+export function isTypedArray(value: unknown): value is
+ | BigInt64Array
+ | BigUint64Array
+ | Float32Array
+ | Float64Array
+ | Int8Array
+ | Int16Array
+ | Int32Array
+ | Uint8Array
+ | Uint8ClampedArray
+ | Uint16Array
+ | Uint32Array {
+ return _getTypedArrayToStringTag.call(value) !== undefined;
+}
+
+export function isUint8Array(value: unknown): value is Uint8Array {
+ return _getTypedArrayToStringTag.call(value) === "Uint8Array";
+}
+
+export function isUint8ClampedArray(
+ value: unknown,
+): value is Uint8ClampedArray {
+ return _getTypedArrayToStringTag.call(value) === "Uint8ClampedArray";
+}
+
+export function isUint16Array(value: unknown): value is Uint16Array {
+ return _getTypedArrayToStringTag.call(value) === "Uint16Array";
+}
+
+export function isUint32Array(value: unknown): value is Uint32Array {
+ return _getTypedArrayToStringTag.call(value) === "Uint32Array";
+}
+
+export const {
+ // isExternal,
+ isDate,
+ isArgumentsObject,
+ isBigIntObject,
+ isBooleanObject,
+ isNumberObject,
+ isStringObject,
+ isSymbolObject,
+ isNativeError,
+ isRegExp,
+ isAsyncFunction,
+ isGeneratorFunction,
+ isGeneratorObject,
+ isPromise,
+ isMap,
+ isSet,
+ isMapIterator,
+ isSetIterator,
+ isWeakMap,
+ isWeakSet,
+ isArrayBuffer,
+ isDataView,
+ isSharedArrayBuffer,
+ isProxy,
+ isModuleNamespaceObject,
+ isAnyArrayBuffer,
+ isBoxedPrimitive,
+} = bindingTypes;
diff --git a/ext/node/polyfills/internal/validators.mjs b/ext/node/polyfills/internal/validators.mjs
new file mode 100644
index 000000000..bea9e881a
--- /dev/null
+++ b/ext/node/polyfills/internal/validators.mjs
@@ -0,0 +1,317 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+import { codes } from "internal:deno_node/polyfills/internal/error_codes.ts";
+import { hideStackFrames } from "internal:deno_node/polyfills/internal/hide_stack_frames.ts";
+import { isArrayBufferView } from "internal:deno_node/polyfills/internal/util/types.ts";
+import { normalizeEncoding } from "internal:deno_node/polyfills/internal/normalize_encoding.mjs";
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+function isInt32(value) {
+ return value === (value | 0);
+}
+
+/**
+ * @param {unknown} value
+ * @returns {boolean}
+ */
+function isUint32(value) {
+ return value === (value >>> 0);
+}
+
+const octalReg = /^[0-7]+$/;
+const modeDesc = "must be a 32-bit unsigned integer or an octal string";
+
+/**
+ * Parse and validate values that will be converted into mode_t (the S_*
+ * constants). Only valid numbers and octal strings are allowed. They could be
+ * converted to 32-bit unsigned integers or non-negative signed integers in the
+ * C++ land, but any value higher than 0o777 will result in platform-specific
+ * behaviors.
+ *
+ * @param {*} value Values to be validated
+ * @param {string} name Name of the argument
+ * @param {number} [def] If specified, will be returned for invalid values
+ * @returns {number}
+ */
+function parseFileMode(value, name, def) {
+ value ??= def;
+ if (typeof value === "string") {
+ if (!octalReg.test(value)) {
+ throw new codes.ERR_INVALID_ARG_VALUE(name, value, modeDesc);
+ }
+ value = Number.parseInt(value, 8);
+ }
+
+ validateInt32(value, name, 0, 2 ** 32 - 1);
+ return value;
+}
+
+const validateBuffer = hideStackFrames((buffer, name = "buffer") => {
+ if (!isArrayBufferView(buffer)) {
+ throw new codes.ERR_INVALID_ARG_TYPE(
+ name,
+ ["Buffer", "TypedArray", "DataView"],
+ buffer,
+ );
+ }
+});
+
+const validateInteger = hideStackFrames(
+ (
+ value,
+ name,
+ min = Number.MIN_SAFE_INTEGER,
+ max = Number.MAX_SAFE_INTEGER,
+ ) => {
+ if (typeof value !== "number") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "number", value);
+ }
+ if (!Number.isInteger(value)) {
+ throw new codes.ERR_OUT_OF_RANGE(name, "an integer", value);
+ }
+ if (value < min || value > max) {
+ throw new codes.ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
+ }
+ },
+);
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ * @param {{
+ * allowArray?: boolean,
+ * allowFunction?: boolean,
+ * nullable?: boolean
+ * }} [options]
+ */
+const validateObject = hideStackFrames((value, name, options) => {
+ const useDefaultOptions = options == null;
+ const allowArray = useDefaultOptions ? false : options.allowArray;
+ const allowFunction = useDefaultOptions ? false : options.allowFunction;
+ const nullable = useDefaultOptions ? false : options.nullable;
+ if (
+ (!nullable && value === null) ||
+ (!allowArray && Array.isArray(value)) ||
+ (typeof value !== "object" && (
+ !allowFunction || typeof value !== "function"
+ ))
+ ) {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "Object", value);
+ }
+});
+
+const validateInt32 = hideStackFrames(
+ (value, name, min = -2147483648, max = 2147483647) => {
+ // The defaults for min and max correspond to the limits of 32-bit integers.
+ if (!isInt32(value)) {
+ if (typeof value !== "number") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "number", value);
+ }
+
+ if (!Number.isInteger(value)) {
+ throw new codes.ERR_OUT_OF_RANGE(name, "an integer", value);
+ }
+
+ throw new codes.ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
+ }
+
+ if (value < min || value > max) {
+ throw new codes.ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
+ }
+ },
+);
+
+const validateUint32 = hideStackFrames(
+ (value, name, positive) => {
+ if (!isUint32(value)) {
+ if (typeof value !== "number") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "number", value);
+ }
+ if (!Number.isInteger(value)) {
+ throw new codes.ERR_OUT_OF_RANGE(name, "an integer", value);
+ }
+ const min = positive ? 1 : 0;
+ // 2 ** 32 === 4294967296
+ throw new codes.ERR_OUT_OF_RANGE(
+ name,
+ `>= ${min} && < 4294967296`,
+ value,
+ );
+ }
+ if (positive && value === 0) {
+ throw new codes.ERR_OUT_OF_RANGE(name, ">= 1 && < 4294967296", value);
+ }
+ },
+);
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ */
+function validateString(value, name) {
+ if (typeof value !== "string") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "string", value);
+ }
+}
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ */
+function validateNumber(value, name) {
+ if (typeof value !== "number") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "number", value);
+ }
+}
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ */
+function validateBoolean(value, name) {
+ if (typeof value !== "boolean") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "boolean", value);
+ }
+}
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ * @param {unknown[]} oneOf
+ */
+const validateOneOf = hideStackFrames(
+ (value, name, oneOf) => {
+ if (!Array.prototype.includes.call(oneOf, value)) {
+ const allowed = Array.prototype.join.call(
+ Array.prototype.map.call(
+ oneOf,
+ (v) => (typeof v === "string" ? `'${v}'` : String(v)),
+ ),
+ ", ",
+ );
+ const reason = "must be one of: " + allowed;
+
+ throw new codes.ERR_INVALID_ARG_VALUE(name, value, reason);
+ }
+ },
+);
+
+export function validateEncoding(data, encoding) {
+ const normalizedEncoding = normalizeEncoding(encoding);
+ const length = data.length;
+
+ if (normalizedEncoding === "hex" && length % 2 !== 0) {
+ throw new codes.ERR_INVALID_ARG_VALUE(
+ "encoding",
+ encoding,
+ `is invalid for data of length ${length}`,
+ );
+ }
+}
+
+// Check that the port number is not NaN when coerced to a number,
+// is an integer and that it falls within the legal range of port numbers.
+/**
+ * @param {string} name
+ * @returns {number}
+ */
+function validatePort(port, name = "Port", allowZero = true) {
+ if (
+ (typeof port !== "number" && typeof port !== "string") ||
+ (typeof port === "string" &&
+ String.prototype.trim.call(port).length === 0) ||
+ +port !== (+port >>> 0) ||
+ port > 0xFFFF ||
+ (port === 0 && !allowZero)
+ ) {
+ throw new codes.ERR_SOCKET_BAD_PORT(name, port, allowZero);
+ }
+
+ return port;
+}
+
+/**
+ * @param {unknown} signal
+ * @param {string} name
+ */
+const validateAbortSignal = hideStackFrames(
+ (signal, name) => {
+ if (
+ signal !== undefined &&
+ (signal === null ||
+ typeof signal !== "object" ||
+ !("aborted" in signal))
+ ) {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "AbortSignal", signal);
+ }
+ },
+);
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ */
+const validateFunction = hideStackFrames(
+ (value, name) => {
+ if (typeof value !== "function") {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "Function", value);
+ }
+ },
+);
+
+/**
+ * @param {unknown} value
+ * @param {string} name
+ */
+const validateArray = hideStackFrames(
+ (value, name, minLength = 0) => {
+ if (!Array.isArray(value)) {
+ throw new codes.ERR_INVALID_ARG_TYPE(name, "Array", value);
+ }
+ if (value.length < minLength) {
+ const reason = `must be longer than ${minLength}`;
+ throw new codes.ERR_INVALID_ARG_VALUE(name, value, reason);
+ }
+ },
+);
+
+export default {
+ isInt32,
+ isUint32,
+ parseFileMode,
+ validateAbortSignal,
+ validateArray,
+ validateBoolean,
+ validateBuffer,
+ validateFunction,
+ validateInt32,
+ validateInteger,
+ validateNumber,
+ validateObject,
+ validateOneOf,
+ validatePort,
+ validateString,
+ validateUint32,
+};
+export {
+ isInt32,
+ isUint32,
+ parseFileMode,
+ validateAbortSignal,
+ validateArray,
+ validateBoolean,
+ validateBuffer,
+ validateFunction,
+ validateInt32,
+ validateInteger,
+ validateNumber,
+ validateObject,
+ validateOneOf,
+ validatePort,
+ validateString,
+ validateUint32,
+};