aboutsummaryrefslogtreecommitdiff
path: root/src/js/node
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/node')
-rw-r--r--src/js/node/assert.js45
-rw-r--r--src/js/node/async_hooks.js5
-rw-r--r--src/js/node/child_process.js37
-rw-r--r--src/js/node/crypto.js126
-rw-r--r--src/js/node/dns.promises.js4
-rw-r--r--src/js/node/events.js25
-rw-r--r--src/js/node/fs.js135
-rw-r--r--src/js/node/fs.promises.ts85
-rw-r--r--src/js/node/http.ts (renamed from src/js/node/http.js)463
-rw-r--r--src/js/node/https.js4
-rw-r--r--src/js/node/https.ts65
-rw-r--r--src/js/node/net.js158
-rw-r--r--src/js/node/os.js23
-rw-r--r--src/js/node/path.js1
-rw-r--r--src/js/node/perf_hooks.js15
-rw-r--r--src/js/node/readline.js10
-rw-r--r--src/js/node/readline.promises.js6
-rw-r--r--src/js/node/stream.consumers.js2
-rw-r--r--src/js/node/stream.js123
-rw-r--r--src/js/node/stream.promises.js4
-rw-r--r--src/js/node/timers.promises.js1
-rw-r--r--src/js/node/tls.js413
-rw-r--r--src/js/node/trace_events.ts2
-rw-r--r--src/js/node/url.js1194
-rw-r--r--src/js/node/util.js136
-rw-r--r--src/js/node/zlib.js110
26 files changed, 2217 insertions, 975 deletions
diff --git a/src/js/node/assert.js b/src/js/node/assert.js
index 3cf158f57..ba4df43cc 100644
--- a/src/js/node/assert.js
+++ b/src/js/node/assert.js
@@ -1,43 +1,12 @@
// Hardcoded module "node:assert"
-var { Bun } = import.meta.primordials;
+var { Bun } = globalThis[Symbol.for("Bun.lazy")]("primordials");
+import util from "node:util";
+
var isDeepEqual = Bun.deepEquals;
-var __create = Object.create;
-var __defProp = Object.defineProperty;
-var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
-var __getOwnPropNames = Object.getOwnPropertyNames;
-var __getProtoOf = Object.getPrototypeOf,
- __hasOwnProp = Object.prototype.hasOwnProperty;
-var __markAsModule = target => __defProp(target, "__esModule", { value: !0 });
var __commonJS = (cb, mod) =>
function () {
return mod || (0, cb[Object.keys(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
-var __reExport = (target, module2, desc) => {
- if ((module2 && typeof module2 == "object") || typeof module2 == "function")
- for (let key of __getOwnPropNames(module2))
- !__hasOwnProp.call(target, key) &&
- key !== "default" &&
- __defProp(target, key, {
- get: () => module2[key],
- enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable,
- });
- return target;
- },
- __toModule = module2 =>
- __reExport(
- __markAsModule(
- __defProp(
- module2 != null ? __create(__getProtoOf(module2)) : {},
- "default",
- module2 && module2.__esModule && "default" in module2
- ? { get: () => module2.default, enumerable: !0 }
- : { value: module2, enumerable: !0 },
- ),
- ),
- module2,
- );
-
-var require = path => import.meta.require(path);
// assert/build/internal/errors.js
var require_errors = __commonJS({
@@ -175,7 +144,6 @@ var require_errors = __commonJS({
"ERR_INVALID_ARG_VALUE",
function (name, value) {
var reason = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "is invalid";
- util === void 0 && (util = require("util"));
var inspected = util.inspect(value);
return (
inspected.length > 128 && (inspected = "".concat(inspected.slice(0, 128), "...")),
@@ -387,8 +355,7 @@ var require_assertion_error = __commonJS({
_typeof(obj)
);
}
- var _require = require("util"),
- inspect = _require.inspect,
+ var inspect = util.inspect,
_require2 = require_errors(),
ERR_INVALID_ARG_TYPE = _require2.codes.ERR_INVALID_ARG_TYPE;
function endsWith(str, search, this_len) {
@@ -871,9 +838,9 @@ var require_assert = __commonJS({
ERR_INVALID_RETURN_VALUE = _require$codes.ERR_INVALID_RETURN_VALUE,
ERR_MISSING_ARGS = _require$codes.ERR_MISSING_ARGS,
AssertionError = require_assertion_error(),
- _require2 = require("util"),
+ _require2 = util,
inspect = _require2.inspect,
- _require$types = require("util").types,
+ _require$types = util.types,
isPromise = _require$types.isPromise,
isRegExp = _require$types.isRegExp,
objectAssign = Object.assign,
diff --git a/src/js/node/async_hooks.js b/src/js/node/async_hooks.js
index 7887bb64f..ec82ce8aa 100644
--- a/src/js/node/async_hooks.js
+++ b/src/js/node/async_hooks.js
@@ -1,8 +1,5 @@
// Hardcoded module "node:async_hooks"
-var drainMicrotasks = () => {
- ({ drainMicrotasks } = import.meta.require("bun:jsc"));
- drainMicrotasks();
-};
+import { drainMicrotasks } from "bun:jsc";
var notImplemented = () => {
console.warn(
diff --git a/src/js/node/child_process.js b/src/js/node/child_process.js
index 691c9e096..29b203219 100644
--- a/src/js/node/child_process.js
+++ b/src/js/node/child_process.js
@@ -1,15 +1,11 @@
// Hardcoded module "node:child_process"
-const EventEmitter = import.meta.require("node:events");
-const {
- Readable: { fromWeb: ReadableFromWeb },
- NativeWritable,
-} = import.meta.require("node:stream");
-const {
- constants: { signals },
-} = import.meta.require("node:os");
-const { promisify } = import.meta.require("node:util");
-
-const { ArrayBuffer, Uint8Array, String, Object, Buffer, Promise } = import.meta.primordials;
+import { EventEmitter } from "node:events";
+import * as StreamModule from "node:stream";
+import { constants } from "node:os";
+import { promisify } from "node:util";
+const signals = constants.signals;
+
+const { ArrayBuffer, Uint8Array, String, Object, Buffer, Promise } = globalThis[Symbol.for("Bun.lazy")]("primordials");
var ObjectPrototypeHasOwnProperty = Object.prototype.hasOwnProperty;
var ObjectCreate = Object.create;
@@ -21,8 +17,6 @@ var BufferIsEncoding = Buffer.isEncoding;
var kEmptyObject = ObjectCreate(null);
var ArrayPrototypePush = Array.prototype.push;
-var ArrayPrototypeReduce = Array.prototype.reduce;
-var ArrayPrototypeFilter = Array.prototype.filter;
var ArrayPrototypeJoin = Array.prototype.join;
var ArrayPrototypeMap = Array.prototype.map;
var ArrayPrototypeIncludes = Array.prototype.includes;
@@ -60,6 +54,9 @@ if (__TRACK_STDIO__) {
};
}
+var NativeWritable;
+var ReadableFromWeb;
+
// Sections:
// 1. Exported child_process functions
// 2. child_process helpers
@@ -961,6 +958,10 @@ export class ChildProcess extends EventEmitter {
debug("ChildProcess: getBunSpawnIo: this.#handle is undefined");
}
}
+
+ NativeWritable ||= StreamModule.NativeWritable;
+ ReadableFromWeb ||= StreamModule.Readable.fromWeb;
+
const io = this.#stdioOptions[i];
switch (i) {
case 0: {
@@ -979,15 +980,7 @@ export class ChildProcess extends EventEmitter {
case 1: {
switch (io) {
case "pipe":
- return ReadableFromWeb(
- this.#handle[fdToStdioName(i)],
- __TRACK_STDIO__
- ? {
- encoding,
- __id: `PARENT_${fdToStdioName(i).toUpperCase()}-${globalThis.__getId()}`,
- }
- : { encoding },
- );
+ return ReadableFromWeb(this.#handle[fdToStdioName(i)], { encoding });
case "inherit":
return process[fdToStdioName(i)] || null;
case "destroyed":
diff --git a/src/js/node/crypto.js b/src/js/node/crypto.js
index a644499c8..20e052e3e 100644
--- a/src/js/node/crypto.js
+++ b/src/js/node/crypto.js
@@ -5,10 +5,12 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf,
__hasOwnProp = Object.prototype.hasOwnProperty;
+import { StringDecoder } from "node:string_decoder";
+import * as BufferModule from "node:buffer";
+import * as StreamModule from "node:stream";
const MAX_STRING_LENGTH = 536870888;
-
-var __require = id => import.meta.require(id);
+var Buffer = globalThis.Buffer;
const crypto = globalThis.crypto;
const globalCrypto = crypto;
@@ -48,7 +50,7 @@ var __export = (target, all) => {
// node_modules/safe-buffer/index.js
var require_safe_buffer = __commonJS({
"node_modules/safe-buffer/index.js"(exports, module) {
- var buffer = __require("buffer"),
+ var buffer = BufferModule,
Buffer2 = buffer.Buffer;
function copyProps(src, dst) {
for (var key in src) dst[key] = src[key];
@@ -146,21 +148,20 @@ var require_hash_base = __commonJS({
"node_modules/hash-base/index.js"(exports, module) {
"use strict";
var Buffer2 = require_safe_buffer().Buffer,
- Transform = __require("readable-stream").Transform,
inherits = require_inherits_browser();
function throwIfNotStringOrBuffer(val, prefix) {
if (!Buffer2.isBuffer(val) && typeof val != "string")
throw new TypeError(prefix + " must be a string or a buffer");
}
function HashBase(blockSize) {
- Transform.call(this),
+ StreamModule.Transform.call(this),
(this._block = Buffer2.allocUnsafe(blockSize)),
(this._blockSize = blockSize),
(this._blockOffset = 0),
(this._length = [0, 0, 0, 0]),
(this._finalized = !1);
}
- inherits(HashBase, Transform);
+ inherits(HashBase, StreamModule.Transform);
HashBase.prototype._transform = function (chunk, encoding, callback) {
var error = null;
try {
@@ -341,7 +342,7 @@ var require_md5 = __commonJS({
var require_ripemd160 = __commonJS({
"node_modules/ripemd160/index.js"(exports, module) {
"use strict";
- var Buffer2 = __require("buffer").Buffer,
+ var Buffer2 = Buffer,
inherits = require_inherits_browser(),
HashBase = require_hash_base(),
ARRAY16 = new Array(16),
@@ -1063,25 +1064,20 @@ var require_sha2 = __commonJS({
},
});
-// stream.js
-var stream_exports = import.meta.require("node:stream");
-
// node_modules/cipher-base/index.js
var require_cipher_base = __commonJS({
"node_modules/cipher-base/index.js"(exports, module) {
var Buffer2 = require_safe_buffer().Buffer,
- Transform = stream_exports.Transform,
- StringDecoder = __require("string_decoder").StringDecoder,
inherits = require_inherits_browser();
function CipherBase(hashMode) {
- Transform.call(this),
+ StreamModule.Transform.call(this),
(this.hashMode = typeof hashMode == "string"),
this.hashMode ? (this[hashMode] = this._finalOrDigest) : (this.final = this._finalOrDigest),
this._final && ((this.__final = this._final), (this._final = null)),
(this._decoder = null),
(this._encoding = null);
}
- inherits(CipherBase, Transform);
+ inherits(CipherBase, StreamModule.Transform);
CipherBase.prototype.update = function (data, inputEnc, outputEnc) {
typeof data == "string" && (data = Buffer2.from(data, inputEnc));
var outData = this._update(data);
@@ -1134,15 +1130,13 @@ var require_cipher_base = __commonJS({
var require_browser2 = __commonJS({
"node_modules/create-hash/browser.js"(exports, module) {
("use strict");
- const { Transform } = stream_exports;
-
// does not become a node stream unless you create it into one
const LazyHash = function Hash(algorithm, options) {
this._options = options;
this._hasher = new CryptoHasher(algorithm, options);
this._finalized = false;
};
- LazyHash.prototype = Object.create(Transform.prototype);
+ LazyHash.prototype = Object.create(StreamModule.Transform.prototype);
LazyHash.prototype.update = function update(data, encoding) {
this._checkFinalized();
this._hasher.update(data, encoding);
@@ -1169,7 +1163,7 @@ var require_browser2 = __commonJS({
};
const lazyHashFullInitProto = {
- __proto__: Transform.prototype,
+ __proto__: StreamModule.Transform.prototype,
...LazyHash.prototype,
_transform(data, encoding, callback) {
this.update(data, encoding);
@@ -1271,7 +1265,7 @@ var require_browser2 = __commonJS({
Object.defineProperty(LazyHash.prototype, method, {
get() {
Object.setPrototypeOf(this, lazyHashFullInitProto);
- Transform.call(this, this._options);
+ StreamModule.Transform.call(this, this._options);
return this[method];
},
enumerable: false,
@@ -3330,12 +3324,7 @@ var require_bn = __commonJS({
this._init(number || 0, base || 10, endian || "be"));
}
typeof module2 == "object" ? (module2.exports = BN) : (exports2.BN = BN), (BN.BN = BN), (BN.wordSize = 26);
- var Buffer2;
- try {
- typeof window < "u" && typeof window.Buffer < "u"
- ? (Buffer2 = window.Buffer)
- : (Buffer2 = __require("buffer").Buffer);
- } catch {}
+ var Buffer2 = Buffer;
(BN.isBN = function (num) {
return num instanceof BN
? !0
@@ -5322,12 +5311,7 @@ var require_bn2 = __commonJS({
this._init(number || 0, base || 10, endian || "be"));
}
typeof module2 == "object" ? (module2.exports = BN) : (exports2.BN = BN), (BN.BN = BN), (BN.wordSize = 26);
- var Buffer2;
- try {
- typeof window < "u" && typeof window.Buffer < "u"
- ? (Buffer2 = window.Buffer)
- : (Buffer2 = __require("buffer").Buffer);
- } catch {}
+ var Buffer2 = Buffer;
(BN.isBN = function (num) {
return num instanceof BN
? !0
@@ -7670,12 +7654,7 @@ var require_bn3 = __commonJS({
this._init(number || 0, base || 10, endian || "be"));
}
typeof module2 == "object" ? (module2.exports = BN) : (exports2.BN = BN), (BN.BN = BN), (BN.wordSize = 26);
- var Buffer2;
- try {
- typeof window < "u" && typeof window.Buffer < "u"
- ? (Buffer2 = window.Buffer)
- : (Buffer2 = __require("buffer").Buffer);
- } catch {}
+ var Buffer2 = Buffer;
(BN.isBN = function (num) {
return num instanceof BN
? !0
@@ -9797,12 +9776,7 @@ var require_bn4 = __commonJS({
this._init(number || 0, base || 10, endian || "be"));
}
typeof module2 == "object" ? (module2.exports = BN) : (exports2.BN = BN), (BN.BN = BN), (BN.wordSize = 26);
- var Buffer2;
- try {
- typeof window < "u" && typeof window.Buffer < "u"
- ? (Buffer2 = window.Buffer)
- : (Buffer2 = __require("buffer").Buffer);
- } catch {}
+ var Buffer2 = Buffer;
(BN.isBN = function (num) {
return num instanceof BN
? !0
@@ -15491,12 +15465,8 @@ var require_bn5 = __commonJS({
this._init(number || 0, base || 10, endian || "be"));
}
typeof module2 == "object" ? (module2.exports = BN) : (exports2.BN = BN), (BN.BN = BN), (BN.wordSize = 26);
- var Buffer2;
- try {
- typeof window < "u" && typeof window.Buffer < "u"
- ? (Buffer2 = window.Buffer)
- : (Buffer2 = __require("buffer").Buffer);
- } catch {}
+ var Buffer2 = Buffer;
+
(BN.isBN = function (num) {
return num instanceof BN
? !0
@@ -17461,8 +17431,8 @@ var require_bn5 = __commonJS({
var require_safer = __commonJS({
"node_modules/safer-buffer/safer.js"(exports, module) {
"use strict";
- var buffer = __require("buffer"),
- Buffer2 = buffer.Buffer,
+ var buffer = BufferModule,
+ Buffer2 = Buffer,
safer = {},
key;
for (key in buffer)
@@ -19334,7 +19304,6 @@ var require_browser8 = __commonJS({
"node_modules/browserify-sign/browser/index.js"(exports, module) {
var Buffer2 = require_safe_buffer().Buffer,
createHash = require_browser2(),
- stream = __require("readable-stream"),
inherits = require_inherits_browser(),
sign = require_sign(),
verify = require_verify(),
@@ -19343,7 +19312,7 @@ var require_browser8 = __commonJS({
(algorithms[key].id = Buffer2.from(algorithms[key].id, "hex")), (algorithms[key.toLowerCase()] = algorithms[key]);
});
function Sign(algorithm) {
- stream.Writable.call(this);
+ StreamModule.Writable.call(this);
var data = algorithms[algorithm];
if (!data) throw new Error("Unknown message digest");
(this._hashType = data.hash),
@@ -19351,7 +19320,7 @@ var require_browser8 = __commonJS({
(this._tag = data.id),
(this._signType = data.sign);
}
- inherits(Sign, stream.Writable);
+ inherits(Sign, StreamModule.Writable);
Sign.prototype._write = function (data, _, done) {
this._hash.update(data), done();
};
@@ -19365,12 +19334,12 @@ var require_browser8 = __commonJS({
return enc ? sig.toString(enc) : sig;
};
function Verify(algorithm) {
- stream.Writable.call(this);
+ StreamModule.Writable.call(this);
var data = algorithms[algorithm];
if (!data) throw new Error("Unknown message digest");
(this._hash = createHash(data.hash)), (this._tag = data.id), (this._signType = data.sign);
}
- inherits(Verify, stream.Writable);
+ inherits(Verify, StreamModule.Writable);
Verify.prototype._write = function (data, _, done) {
this._hash.update(data), done();
};
@@ -19423,12 +19392,7 @@ var require_bn6 = __commonJS({
this._init(number || 0, base || 10, endian || "be"));
}
typeof module2 == "object" ? (module2.exports = BN) : (exports2.BN = BN), (BN.BN = BN), (BN.wordSize = 26);
- var Buffer2;
- try {
- typeof window < "u" && typeof window.Buffer < "u"
- ? (Buffer2 = window.Buffer)
- : (Buffer2 = __require("buffer").Buffer);
- } catch {}
+ var Buffer2 = Buffer;
(BN.isBN = function (num) {
return num instanceof BN
? !0
@@ -23788,6 +23752,7 @@ var crypto_exports = {
var DEFAULT_ENCODING = "buffer",
getRandomValues = array => crypto.getRandomValues(array),
randomUUID = () => crypto.randomUUID(),
+ randomInt = (...args) => crypto.randomInt(...args),
timingSafeEqual =
"timingSafeEqual" in crypto
? (a, b) => {
@@ -23837,11 +23802,35 @@ timingSafeEqual &&
Object.defineProperty(scryptSync, "name", {
value: "::bunternal::",
}));
+
+const harcoded_curves = [
+ "p192",
+ "p224",
+ "p256",
+ "p384",
+ "p521",
+ "curve25519",
+ "ed25519",
+ "secp256k1",
+ "secp224r1",
+ "prime256v1",
+ "prime192v1",
+ "ed25519",
+ "secp384r1",
+ "secp521r1",
+];
+
+function getCurves() {
+ return harcoded_curves;
+}
+
var webcrypto = crypto;
__export(crypto_exports, {
DEFAULT_ENCODING: () => DEFAULT_ENCODING,
getRandomValues: () => getRandomValues,
randomUUID: () => randomUUID,
+ randomInt: () => randomInt,
+ getCurves: () => getCurves,
scrypt: () => scrypt,
scryptSync: () => scryptSync,
timingSafeEqual: () => timingSafeEqual,
@@ -23890,6 +23879,17 @@ export const {
createCredentials,
constants,
} = crypto_exports;
-export { DEFAULT_ENCODING, getRandomValues, randomUUID, scrypt, scryptSync, timingSafeEqual, webcrypto };
+
+export {
+ DEFAULT_ENCODING,
+ getRandomValues,
+ getCurves,
+ randomUUID,
+ randomInt,
+ scrypt,
+ scryptSync,
+ timingSafeEqual,
+ webcrypto,
+};
export default crypto_exports;
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
diff --git a/src/js/node/dns.promises.js b/src/js/node/dns.promises.js
index b41cc2b22..bcc47faee 100644
--- a/src/js/node/dns.promises.js
+++ b/src/js/node/dns.promises.js
@@ -1,11 +1,12 @@
// Hardcoded module "node:dns/promises"
-const { promises } = import.meta.require("node:dns");
+import { promises } from "node:dns";
export const {
lookup,
lookupService,
resolve,
resolve4,
+ resolve6,
resolveAny,
resolveCname,
resolveCaa,
@@ -27,6 +28,7 @@ export default {
lookupService,
resolve,
resolve4,
+ resolve6,
resolveAny,
resolveCname,
resolveCaa,
diff --git a/src/js/node/events.js b/src/js/node/events.js
index e42f89ad1..111fdb524 100644
--- a/src/js/node/events.js
+++ b/src/js/node/events.js
@@ -1,7 +1,8 @@
// Reimplementation of https://nodejs.org/api/events.html
// Reference: https://github.com/nodejs/node/blob/main/lib/events.js
import { throwNotImplemented } from "../shared";
-var { isPromise, Array, Object } = import.meta.primordials;
+
+var { isPromise, Array, Object } = globalThis[Symbol.for("Bun.lazy")]("primordials");
const SymbolFor = Symbol.for;
const ObjectDefineProperty = Object.defineProperty;
const kCapture = Symbol("kCapture");
@@ -386,8 +387,6 @@ Object.defineProperties(EventEmitter, {
EventEmitter.init = EventEmitter;
EventEmitter[Symbol.for("CommonJS")] = 0;
-export default EventEmitter;
-
function eventTargetAgnosticRemoveListener(emitter, name, listener, flags) {
if (typeof emitter.removeListener === "function") {
emitter.removeListener(name, listener);
@@ -454,10 +453,24 @@ function checkListener(listener) {
}
}
-export class EventEmitterAsyncResource extends EventEmitter {
+class EventEmitterAsyncResource extends EventEmitter {
constructor(options = undefined) {
throwNotImplemented("EventEmitterAsyncResource", 1832);
}
}
-
-EventEmitter.EventEmitterAsyncResource = EventEmitterAsyncResource;
+const usingDomains = false;
+// EventEmitter[Symbol.for("CommonJS")] = 0;
+Object.assign(EventEmitter, { once, on, getEventListeners, setMaxListeners, listenerCount, EventEmitterAsyncResource });
+export {
+ EventEmitter,
+ captureRejectionSymbol,
+ kErrorMonitor as errorMonitor,
+ getEventListeners,
+ listenerCount,
+ on,
+ once,
+ setMaxListeners,
+ usingDomains,
+ EventEmitterAsyncResource,
+};
+export default EventEmitter;
diff --git a/src/js/node/fs.js b/src/js/node/fs.js
index f117020dd..072102c35 100644
--- a/src/js/node/fs.js
+++ b/src/js/node/fs.js
@@ -1,12 +1,73 @@
-// Hardcoded module "node:fs"
-var { direct, isPromise, isCallable } = import.meta.primordials;
-var promises = import.meta.require("node:fs/promises");
+export var ReadStream;
+export var WriteStream;
+
+import { EventEmitter } from "node:events";
-var { Readable, NativeWritable, _getNativeReadableStreamPrototype, eos: eos_ } = import.meta.require("node:stream");
-var NativeReadable = _getNativeReadableStreamPrototype(2, Readable); // 2 means native type is a file here
+// Hardcoded module "node:fs"
+var { direct, isPromise, isCallable } = globalThis[Symbol.for("Bun.lazy")]("primordials");
+import promises from "node:fs/promises";
+export { default as promises } from "node:fs/promises";
+import * as Stream from "node:stream";
var fs = Bun.fs();
var debug = process.env.DEBUG ? console.log : () => {};
+
+class FSWatcher extends EventEmitter {
+ #watcher;
+ #listener;
+ constructor(path, options, listener) {
+ super();
+
+ if (typeof options === "function") {
+ listener = options;
+ options = {};
+ } else if (typeof options === "string") {
+ options = { encoding: options };
+ }
+
+ if (typeof listener !== "function") {
+ listener = () => {};
+ }
+
+ this.#listener = listener;
+ try {
+ this.#watcher = fs.watch(path, options || {}, this.#onEvent.bind(this));
+ } catch (e) {
+ if (!e.message?.startsWith("FileNotFound")) {
+ throw e;
+ }
+ const notFound = new Error(`ENOENT: no such file or directory, watch '${path}'`);
+ notFound.code = "ENOENT";
+ notFound.errno = -2;
+ notFound.path = path;
+ notFound.syscall = "watch";
+ notFound.filename = path;
+ throw notFound;
+ }
+ }
+
+ #onEvent(eventType, filenameOrError) {
+ if (eventType === "error" || eventType === "close") {
+ this.emit(eventType, filenameOrError);
+ } else {
+ this.emit("change", eventType, filenameOrError);
+ this.#listener(eventType, filenameOrError);
+ }
+ }
+
+ close() {
+ this.#watcher?.close();
+ this.#watcher = null;
+ }
+
+ ref() {
+ this.#watcher?.ref();
+ }
+
+ unref() {
+ this.#watcher?.unref();
+ }
+}
export var access = function access(...args) {
callbackify(fs.accessSync, args);
},
@@ -151,9 +212,45 @@ export var access = function access(...args) {
lutimesSync = fs.lutimesSync.bind(fs),
rmSync = fs.rmSync.bind(fs),
rmdirSync = fs.rmdirSync.bind(fs),
+ writev = (fd, buffers, position, callback) => {
+ if (typeof position === "function") {
+ callback = position;
+ position = null;
+ }
+
+ queueMicrotask(() => {
+ try {
+ var written = fs.writevSync(fd, buffers, position);
+ } catch (e) {
+ callback(e);
+ }
+
+ callback(null, written, buffers);
+ });
+ },
+ writevSync = fs.writevSync.bind(fs),
+ readv = (fd, buffers, position, callback) => {
+ if (typeof position === "function") {
+ callback = position;
+ position = null;
+ }
+
+ queueMicrotask(() => {
+ try {
+ var written = fs.readvSync(fd, buffers, position);
+ } catch (e) {
+ callback(e);
+ }
+
+ callback(null, written, buffers);
+ });
+ },
+ readvSync = fs.readvSync.bind(fs),
Dirent = fs.Dirent,
Stats = fs.Stats,
- promises = import.meta.require("node:fs/promises");
+ watch = function watch(path, options, listener) {
+ return new FSWatcher(path, options, listener);
+ };
function callbackify(fsFunction, args) {
try {
@@ -222,7 +319,8 @@ var defaultReadStreamOptions = {
};
var ReadStreamClass;
-export var ReadStream = (function (InternalReadStream) {
+
+ReadStream = (function (InternalReadStream) {
ReadStreamClass = InternalReadStream;
Object.defineProperty(ReadStreamClass.prototype, Symbol.toStringTag, {
value: "ReadStream",
@@ -241,7 +339,7 @@ export var ReadStream = (function (InternalReadStream) {
},
);
})(
- class ReadStream extends NativeReadable {
+ class ReadStream extends Stream._getNativeReadableStreamPrototype(2, Stream.Readable) {
constructor(pathOrFd, options = defaultReadStreamOptions) {
if (typeof options !== "object" || !options) {
throw new TypeError("Expected options to be an object");
@@ -569,7 +667,7 @@ var defaultWriteStreamOptions = {
};
var WriteStreamClass;
-export var WriteStream = (function (InternalWriteStream) {
+WriteStream = (function (InternalWriteStream) {
WriteStreamClass = InternalWriteStream;
Object.defineProperty(WriteStreamClass.prototype, Symbol.toStringTag, {
value: "WritesStream",
@@ -577,8 +675,8 @@ export var WriteStream = (function (InternalWriteStream) {
});
return Object.defineProperty(
- function WriteStream(options) {
- return new InternalWriteStream(options);
+ function WriteStream(path, options) {
+ return new InternalWriteStream(path, options);
},
Symbol.hasInstance,
{
@@ -588,7 +686,7 @@ export var WriteStream = (function (InternalWriteStream) {
},
);
})(
- class WriteStream extends NativeWritable {
+ class WriteStream extends Stream.NativeWritable {
constructor(path, options = defaultWriteStreamOptions) {
if (!options) {
throw new TypeError("Expected options to be an object");
@@ -877,7 +975,7 @@ export function createWriteStream(path, options) {
}
// NOTE: This was too smart and doesn't actually work
-// export var WriteStream = Object.defineProperty(
+// WriteStream = Object.defineProperty(
// function WriteStream(path, options) {
// var _InternalWriteStream = getLazyWriteStream();
// return new _InternalWriteStream(path, options);
@@ -886,7 +984,7 @@ export function createWriteStream(path, options) {
// { value: (instance) => instance[writeStreamSymbol] === true },
// );
-// export var ReadStream = Object.defineProperty(
+// ReadStream = Object.defineProperty(
// function ReadStream(path, options) {
// var _InternalReadStream = getLazyReadStream();
// return new _InternalReadStream(path, options);
@@ -1002,7 +1100,12 @@ export default {
writeSync,
WriteStream,
ReadStream,
-
+ watch,
+ FSWatcher,
+ writev,
+ writevSync,
+ readv,
+ readvSync,
[Symbol.for("::bunternal::")]: {
ReadStreamClass,
WriteStreamClass,
@@ -1014,3 +1117,5 @@ export default {
// return getLazyReadStream();
// },
};
+
+export { constants } from "node:fs/promises";
diff --git a/src/js/node/fs.promises.ts b/src/js/node/fs.promises.ts
index de802928b..12278ef53 100644
--- a/src/js/node/fs.promises.ts
+++ b/src/js/node/fs.promises.ts
@@ -1,4 +1,5 @@
// Hardcoded module "node:fs/promises"
+
// Note: `constants` is injected into the top of this file
declare var constants: typeof import("node:fs/promises").constants;
@@ -38,6 +39,55 @@ var promisify = {
},
}[notrace];
+export function watch(
+ filename: string | Buffer | URL,
+ options: { encoding?: BufferEncoding; persistent?: boolean; recursive?: boolean; signal?: AbortSignal } = {},
+) {
+ type Event = {
+ eventType: string;
+ filename: string | Buffer | undefined;
+ };
+ const events: Array<Event> = [];
+ if (filename instanceof URL) {
+ throw new TypeError("Watch URLs are not supported yet");
+ } else if (Buffer.isBuffer(filename)) {
+ filename = filename.toString();
+ } else if (typeof filename !== "string") {
+ throw new TypeError("Expected path to be a string or Buffer");
+ }
+ let nextEventResolve: Function | null = null;
+ if (typeof options === "string") {
+ options = { encoding: options };
+ }
+ fs.watch(filename, options || {}, (eventType: string, filename: string | Buffer | undefined) => {
+ events.push({ eventType, filename });
+ if (nextEventResolve) {
+ const resolve = nextEventResolve;
+ nextEventResolve = null;
+ resolve();
+ }
+ });
+ return {
+ async *[Symbol.asyncIterator]() {
+ let closed = false;
+ while (!closed) {
+ while (events.length) {
+ let event = events.shift() as Event;
+ if (event.eventType === "close") {
+ closed = true;
+ break;
+ }
+ if (event.eventType === "error") {
+ closed = true;
+ throw event.filename;
+ }
+ yield event;
+ }
+ await new Promise((resolve: Function) => (nextEventResolve = resolve));
+ }
+ },
+ };
+}
export var access = promisify(fs.accessSync),
appendFile = promisify(fs.appendFileSync),
close = promisify(fs.closeSync),
@@ -73,7 +123,37 @@ export var access = promisify(fs.accessSync),
utimes = promisify(fs.utimesSync),
lutimes = promisify(fs.lutimesSync),
rm = promisify(fs.rmSync),
- rmdir = promisify(fs.rmdirSync);
+ rmdir = promisify(fs.rmdirSync),
+ writev = (fd, buffers, position) => {
+ return new Promise((resolve, reject) => {
+ try {
+ var bytesWritten = fs.writevSync(fd, buffers, position);
+ } catch (err) {
+ reject(err);
+ return;
+ }
+
+ resolve({
+ bytesWritten,
+ buffers,
+ });
+ });
+ },
+ readv = (fd, buffers, position) => {
+ return new Promise((resolve, reject) => {
+ try {
+ var bytesRead = fs.readvSync(fd, buffers, position);
+ } catch (err) {
+ reject(err);
+ return;
+ }
+
+ resolve({
+ bytesRead,
+ buffers,
+ });
+ });
+ };
export default {
access,
@@ -112,6 +192,9 @@ export default {
lutimes,
rm,
rmdir,
+ watch,
+ writev,
+ readv,
constants,
[Symbol.for("CommonJS")]: 0,
};
diff --git a/src/js/node/http.js b/src/js/node/http.ts
index 8839c9af7..fe075c832 100644
--- a/src/js/node/http.js
+++ b/src/js/node/http.ts
@@ -1,10 +1,63 @@
// Hardcoded module "node:http"
-const { EventEmitter } = import.meta.require("node:events");
-const { isIPv6 } = import.meta.require("node:net");
-const { Readable, Writable, Duplex } = import.meta.require("node:stream");
-const { URL } = import.meta.require("node:url");
-const { newArrayWithSize, String, Object, Array } = import.meta.primordials;
-const { isTypedArray } = import.meta.require("util/types");
+import { EventEmitter } from "node:events";
+import { Readable, Writable, Duplex } from "node:stream";
+import { isTypedArray } from "util/types";
+
+const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
+/**
+ * True if val contains an invalid field-vchar
+ * field-value = *( field-content / obs-fold )
+ * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+ * field-vchar = VCHAR / obs-text
+ */
+function checkInvalidHeaderChar(val: string) {
+ return RegExpPrototypeExec.call(headerCharRegex, val) !== null;
+}
+
+export const validateHeaderName = (name, label) => {
+ if (typeof name !== "string" || !name || !checkIsHttpToken(name)) {
+ // throw new ERR_INVALID_HTTP_TOKEN(label || "Header name", name);
+ throw new Error("ERR_INVALID_HTTP_TOKEN");
+ }
+};
+
+export const validateHeaderValue = (name, value) => {
+ if (value === undefined) {
+ // throw new ERR_HTTP_INVALID_HEADER_VALUE(value, name);
+ throw new Error("ERR_HTTP_INVALID_HEADER_VALUE");
+ }
+ if (checkInvalidHeaderChar(value)) {
+ // throw new ERR_INVALID_CHAR("header content", name);
+ throw new Error("ERR_INVALID_CHAR");
+ }
+};
+
+// Cheaper to duplicate this than to import it from node:net
+function isIPv6(input) {
+ 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 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,})?$",
+ );
+
+ return IPv6Reg.test(input);
+}
+
+// TODO: add primordial for URL
+// Importing from node:url is unnecessary
+const { URL } = globalThis;
+
+const { newArrayWithSize, String, Object, Array } = globalThis[Symbol.for("Bun.lazy")]("primordials");
const globalReportError = globalThis.reportError;
const setTimeout = globalThis.setTimeout;
@@ -39,7 +92,6 @@ const INVALID_PATH_REGEX = /[^\u0021-\u00ff]/;
const NODE_HTTP_WARNING =
"WARN: Agent is mostly unused in Bun's implementation of http. If you see strange behavior, this is probably the cause.";
-var _globalAgent;
var _defaultHTTPSAgent;
var kInternalRequest = Symbol("kInternalRequest");
var kInternalSocketData = Symbol.for("::bunternal::");
@@ -57,18 +109,40 @@ function isValidTLSArray(obj) {
}
}
+class ERR_INVALID_ARG_TYPE extends TypeError {
+ constructor(name, expected, actual) {
+ super(`The ${name} argument must be of type ${expected}. Received type ${typeof actual}`);
+ this.code = "ERR_INVALID_ARG_TYPE";
+ }
+}
+
+function validateMsecs(numberlike: any, field: string) {
+ if (typeof numberlike !== "number" || numberlike < 0) {
+ throw new ERR_INVALID_ARG_TYPE(field, "number", numberlike);
+ }
+
+ return numberlike;
+}
+function validateFunction(callable: any, field: string) {
+ if (typeof callable !== "function") {
+ throw new ERR_INVALID_ARG_TYPE(field, "Function", callable);
+ }
+
+ return callable;
+}
+
function getHeader(headers, name) {
if (!headers) return;
const result = headers.get(name);
return result == null ? undefined : result;
}
+type FakeSocket = InstanceType<typeof FakeSocket>;
var FakeSocket = class Socket extends Duplex {
bytesRead = 0;
bytesWritten = 0;
connecting = false;
- remoteAddress = null;
- localAddress = "127.0.0.1";
+ remoteAddress: string | null = null;
remotePort;
timeout = 0;
@@ -149,25 +223,25 @@ export function createServer(options, callback) {
}
export class Agent extends EventEmitter {
- #defaultPort = 80;
- #protocol = "http:";
- #options;
- #requests;
- #sockets;
- #freeSockets;
-
- #keepAliveMsecs;
- #keepAlive;
- #maxSockets;
- #maxFreeSockets;
- #scheduling;
- #maxTotalSockets;
- #totalSocketCount;
+ defaultPort = 80;
+ protocol = "http:";
+ options;
+ requests;
+ sockets;
+ freeSockets;
+
+ keepAliveMsecs;
+ keepAlive;
+ maxSockets;
+ maxFreeSockets;
+ scheduling;
+ maxTotalSockets;
+ totalSocketCount;
#fakeSocket;
static get globalAgent() {
- return (_globalAgent ??= new Agent());
+ return globalAgent;
}
static get defaultMaxSockets() {
@@ -176,75 +250,23 @@ export class Agent extends EventEmitter {
constructor(options = kEmptyObject) {
super();
- this.#options = options = { ...options, path: null };
+ this.options = options = { ...options, path: null };
if (options.noDelay === undefined) options.noDelay = true;
// Don't confuse net and make it think that we're connecting to a pipe
- this.#requests = kEmptyObject;
- this.#sockets = kEmptyObject;
- this.#freeSockets = kEmptyObject;
-
- this.#keepAliveMsecs = options.keepAliveMsecs || 1000;
- this.#keepAlive = options.keepAlive || false;
- this.#maxSockets = options.maxSockets || Agent.defaultMaxSockets;
- this.#maxFreeSockets = options.maxFreeSockets || 256;
- this.#scheduling = options.scheduling || "lifo";
- this.#maxTotalSockets = options.maxTotalSockets;
- this.#totalSocketCount = 0;
- this.#defaultPort = options.defaultPort || 80;
- this.#protocol = options.protocol || "http:";
- }
+ this.requests = kEmptyObject;
+ this.sockets = kEmptyObject;
+ this.freeSockets = kEmptyObject;
- get defaultPort() {
- return this.#defaultPort;
- }
-
- get protocol() {
- return this.#protocol;
- }
-
- get requests() {
- return this.#requests;
- }
-
- get sockets() {
- return this.#sockets;
- }
-
- get freeSockets() {
- return this.#freeSockets;
- }
-
- get options() {
- return this.#options;
- }
-
- get keepAliveMsecs() {
- return this.#keepAliveMsecs;
- }
-
- get keepAlive() {
- return this.#keepAlive;
- }
-
- get maxSockets() {
- return this.#maxSockets;
- }
-
- get maxFreeSockets() {
- return this.#maxFreeSockets;
- }
-
- get scheduling() {
- return this.#scheduling;
- }
-
- get maxTotalSockets() {
- return this.#maxTotalSockets;
- }
-
- get totalSocketCount() {
- return this.#totalSocketCount;
+ this.keepAliveMsecs = options.keepAliveMsecs || 1000;
+ this.keepAlive = options.keepAlive || false;
+ this.maxSockets = options.maxSockets || Agent.defaultMaxSockets;
+ this.maxFreeSockets = options.maxFreeSockets || 256;
+ this.scheduling = options.scheduling || "lifo";
+ this.maxTotalSockets = options.maxTotalSockets;
+ this.totalSocketCount = 0;
+ this.defaultPort = options.defaultPort || 80;
+ this.protocol = options.protocol || "http:";
}
createConnection() {
@@ -315,6 +337,7 @@ export class Server extends EventEmitter {
#tls;
#is_tls = false;
listening = false;
+ serverName;
constructor(options, callback) {
super();
@@ -403,7 +426,7 @@ export class Server extends EventEmitter {
// not actually implemented
}
- close(optionalCallback) {
+ close(optionalCallback?) {
const server = this.#server;
if (!server) {
if (typeof optionalCallback === "function")
@@ -459,7 +482,7 @@ export class Server extends EventEmitter {
if (tls) {
this.serverName = tls.serverName || host || "localhost";
}
- this.#server = Bun.serve({
+ this.#server = Bun.serve<any>({
tls,
port,
hostname: host,
@@ -555,6 +578,9 @@ function getDefaultHTTPSAgent() {
}
export class IncomingMessage extends Readable {
+ method: string;
+ complete: boolean;
+
constructor(req, defaultIncomingOpts) {
const method = req.method;
@@ -579,7 +605,7 @@ export class IncomingMessage extends Readable {
this.#type = type;
this.complete = !!this.#noBody;
- this.#bodyStream = null;
+ this.#bodyStream = undefined;
const socket = new FakeSocket();
socket.remoteAddress = url.hostname;
socket.remotePort = url.port;
@@ -594,8 +620,8 @@ export class IncomingMessage extends Readable {
rawHeaders;
_consuming = false;
_dumped = false;
- #bodyStream = null;
- #fakeSocket = undefined;
+ #bodyStream: ReadableStreamDefaultReader | undefined;
+ #fakeSocket: FakeSocket | undefined;
#noBody = false;
#aborted = false;
#req;
@@ -625,14 +651,19 @@ export class IncomingMessage extends Readable {
callback();
}
- #closeBodyStream() {
- debug("closeBodyStream()");
- var bodyStream = this.#bodyStream;
- if (bodyStream == null) return;
- this.complete = true;
- this.#bodyStream = undefined;
- this.push(null);
- // process.nextTick(destroyBodyStreamNT, bodyStream);
+ async #consumeStream(reader: ReadableStreamDefaultReader) {
+ while (true) {
+ var { done, value } = await reader.readMany();
+ if (this.#aborted) return;
+ if (done) {
+ this.push(null);
+ this.destroy();
+ break;
+ }
+ for (var v of value) {
+ this.push(v);
+ }
+ }
}
_read(size) {
@@ -640,37 +671,13 @@ export class IncomingMessage extends Readable {
this.push(null);
this.complete = true;
} else if (this.#bodyStream == null) {
- const contentLength = this.#req.headers.get("content-length");
- let remaining = contentLength ? parseInt(contentLength, 10) : 0;
- this.#bodyStream = Readable.fromWeb(this.#req.body, {
- highWaterMark: Number.isFinite(remaining) ? Math.min(remaining, 16384) : 16384,
- });
-
- const isBodySizeKnown = remaining > 0 && Number.isSafeInteger(remaining);
-
- if (isBodySizeKnown) {
- this.#bodyStream.on("data", chunk => {
- debug("body size known", remaining);
- this.push(chunk);
- // when we are streaming a known body size, automatically close the stream when we have read enough
- remaining -= chunk?.byteLength ?? 0;
- if (remaining <= 0) {
- this.#closeBodyStream();
- }
- });
- } else {
- this.#bodyStream.on("data", chunk => {
- this.push(chunk);
- });
+ const reader = this.#req.body?.getReader() as ReadableStreamDefaultReader;
+ if (!reader) {
+ this.push(null);
+ return;
}
-
- // this can be closed by the time we get here if enough data was synchronously available
- this.#bodyStream &&
- this.#bodyStream.on("end", () => {
- this.#closeBodyStream();
- });
- } else {
- // this.#bodyStream.read(size);
+ this.#bodyStream = reader;
+ this.#consumeStream(reader);
}
}
@@ -678,11 +685,15 @@ export class IncomingMessage extends Readable {
return this.#aborted;
}
- abort() {
+ #abort() {
if (this.#aborted) return;
this.#aborted = true;
-
- this.#closeBodyStream();
+ var bodyStream = this.#bodyStream;
+ if (!bodyStream) return;
+ bodyStream.cancel();
+ this.complete = true;
+ this.#bodyStream = undefined;
+ this.push(null);
}
get connection() {
@@ -803,13 +814,17 @@ export class OutgoingMessage extends Writable {
headersSent = false;
sendDate = true;
req;
+ timeout;
#finished = false;
[kEndCalled] = false;
#fakeSocket;
- #timeoutTimer = null;
- [kAbortController] = null;
+ #timeoutTimer?: Timer;
+ [kAbortController]: AbortController | null = null;
+
+ // Express "compress" package uses this
+ _implicitHeader() {}
// For compat with IncomingRequest
get headers() {
@@ -902,27 +917,50 @@ export class OutgoingMessage extends Writable {
[kClearTimeout]() {
if (this.#timeoutTimer) {
clearTimeout(this.#timeoutTimer);
- this.#timeoutTimer = null;
+ this.removeAllListeners("timeout");
+ this.#timeoutTimer = undefined;
}
}
+ #onTimeout() {
+ this.#timeoutTimer = undefined;
+ this[kAbortController]?.abort();
+ this.emit("timeout");
+ }
+
setTimeout(msecs, callback) {
- if (this.#timeoutTimer) return this;
- if (callback) {
- this.on("timeout", callback);
- }
+ if (this.destroyed) return this;
+
+ this.timeout = msecs = validateMsecs(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.#timeoutTimer!);
+
+ if (msecs === 0) {
+ if (callback !== undefined) {
+ validateFunction(callback, "callback");
+ this.removeListener("timeout", callback);
+ }
+
+ this.#timeoutTimer = undefined;
+ } else {
+ this.#timeoutTimer = setTimeout(this.#onTimeout.bind(this), msecs).unref();
- this.#timeoutTimer = setTimeout(async () => {
- this.#timeoutTimer = null;
- this[kAbortController]?.abort();
- this.emit("timeout");
- }, msecs);
+ if (callback !== undefined) {
+ validateFunction(callback, "callback");
+ this.once("timeout", callback);
+ }
+ }
return this;
}
}
+let OriginalWriteHeadFn, OriginalImplicitHeadFn;
export class ServerResponse extends Writable {
+ declare _writableState: any;
+
constructor({ req, reply }) {
super();
this.req = req;
@@ -935,6 +973,10 @@ export class ServerResponse extends Writable {
this.#firstWrite = undefined;
this._writableState.decodeStrings = false;
this.#deferred = undefined;
+
+ // this is matching node's behaviour
+ // https://github.com/nodejs/node/blob/cf8c6994e0f764af02da4fa70bc5962142181bf3/lib/_http_server.js#L192
+ if (req.method === "HEAD") this._hasBody = false;
}
req;
@@ -950,8 +992,14 @@ export class ServerResponse extends Writable {
_defaultKeepAlive = false;
_removedConnection = false;
_removedContLen = false;
- #deferred = undefined;
+ _hasBody = true;
+ #deferred: (() => void) | undefined = undefined;
#finished = false;
+ // Express "compress" package uses this
+ _implicitHeader() {
+ // @ts-ignore
+ this.writeHead(this.statusCode);
+ }
_write(chunk, encoding, callback) {
if (!this.#firstWrite && !this.headersSent) {
@@ -1013,11 +1061,20 @@ export class ServerResponse extends Writable {
);
}
+ #drainHeadersIfObservable() {
+ if (this._implicitHeader === OriginalImplicitHeadFn && this.writeHead === OriginalWriteHeadFn) {
+ return;
+ }
+
+ this._implicitHeader();
+ }
+
_final(callback) {
if (!this.headersSent) {
var data = this.#firstWrite || "";
this.#firstWrite = undefined;
this.#finished = true;
+ this.#drainHeadersIfObservable();
this._reply(
new Response(data, {
headers: this.#headers,
@@ -1136,9 +1193,12 @@ export class ServerResponse extends Writable {
}
}
+OriginalWriteHeadFn = ServerResponse.prototype.writeHead;
+OriginalImplicitHeadFn = ServerResponse.prototype._implicitHeader;
+
export class ClientRequest extends OutgoingMessage {
#timeout;
- #res = null;
+ #res: IncomingMessage | null = null;
#upgradeOrConnect = false;
#parser = null;
#maxHeadersCount = null;
@@ -1150,15 +1210,15 @@ export class ClientRequest extends OutgoingMessage {
#useDefaultPort;
#joinDuplicateHeaders;
#maxHeaderSize;
- #agent = _globalAgent;
+ #agent = globalAgent;
#path;
#socketPath;
- #body = null;
+ #body: string | null = null;
#fetchRequest;
- #signal = null;
- [kAbortController] = null;
- #timeoutTimer = null;
+ #signal: AbortSignal | null = null;
+ [kAbortController]: AbortController | null = null;
+ #timeoutTimer?: Timer = undefined;
#options;
#finished;
@@ -1227,6 +1287,9 @@ export class ClientRequest extends OutgoingMessage {
redirect: "manual",
verbose: Boolean(__DEBUG__),
signal: this[kAbortController].signal,
+
+ // Timeouts are handled via this.setTimeout.
+ timeout: false,
},
)
.then(response => {
@@ -1258,7 +1321,7 @@ export class ClientRequest extends OutgoingMessage {
abort() {
if (this.aborted) return;
- this[kAbortController].abort();
+ this[kAbortController]!.abort();
// TODO: Close stream if body streaming
}
@@ -1298,8 +1361,8 @@ export class ClientRequest extends OutgoingMessage {
} else {
protocol = defaultAgent.protocol || "http:";
}
- this.#protocol = protocol;
}
+ this.#protocol = protocol;
switch (this.#agent?.protocol) {
case undefined: {
@@ -1351,8 +1414,6 @@ export class ClientRequest extends OutgoingMessage {
this.#socketPath = options.socketPath;
- if (options.timeout !== undefined) this.setTimeout(options.timeout, null);
-
const signal = options.signal;
if (signal) {
//We still want to control abort function and timeout so signal call our AbortController
@@ -1430,7 +1491,12 @@ export class ClientRequest extends OutgoingMessage {
this.#reusedSocket = false;
this.#host = host;
this.#protocol = protocol;
- this.#timeoutTimer = null;
+
+ var timeout = options.timeout;
+ if (timeout !== undefined && timeout !== 0) {
+ this.setTimeout(timeout, undefined);
+ }
+
const headersArray = ArrayIsArray(headers);
if (!headersArray) {
var headers = options.headers;
@@ -1485,17 +1551,8 @@ export class ClientRequest extends OutgoingMessage {
// this[kUniqueHeaders] = parseUniqueHeadersOption(options.uniqueHeaders);
- var optsWithoutSignal = options;
- if (optsWithoutSignal.signal) {
- optsWithoutSignal = ObjectAssign({}, options);
- delete optsWithoutSignal.signal;
- }
+ var { signal: _signal, ...optsWithoutSignal } = options;
this.#options = optsWithoutSignal;
-
- var timeout = options.timeout;
- if (timeout) {
- this.setTimeout(timeout);
- }
}
setSocketKeepAlive(enable = true, initialDelay = 0) {
@@ -1508,21 +1565,41 @@ export class ClientRequest extends OutgoingMessage {
[kClearTimeout]() {
if (this.#timeoutTimer) {
clearTimeout(this.#timeoutTimer);
- this.#timeoutTimer = null;
+ this.#timeoutTimer = undefined;
+ this.removeAllListeners("timeout");
}
}
+ #onTimeout() {
+ this.#timeoutTimer = undefined;
+ this[kAbortController]?.abort();
+ this.emit("timeout");
+ }
+
setTimeout(msecs, callback) {
- if (this.#timeoutTimer) return this;
- if (callback) {
- this.on("timeout", callback);
- }
+ if (this.destroyed) return this;
- this.#timeoutTimer = setTimeout(async () => {
- this.#timeoutTimer = null;
- this[kAbortController]?.abort();
- this.emit("timeout");
- }, msecs);
+ this.timeout = msecs = validateMsecs(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.#timeoutTimer!);
+
+ if (msecs === 0) {
+ if (callback !== undefined) {
+ validateFunction(callback, "callback");
+ this.removeListener("timeout", callback);
+ }
+
+ this.#timeoutTimer = undefined;
+ } else {
+ this.#timeoutTimer = setTimeout(this.#onTimeout.bind(this), msecs).unref();
+
+ if (callback !== undefined) {
+ validateFunction(callback, "callback");
+ this.once("timeout", callback);
+ }
+ }
return this;
}
@@ -1702,7 +1779,7 @@ function _normalizeArgs(args) {
}
const arg0 = args[0];
- let options = {};
+ let options: any = {};
if (typeof arg0 === "object" && arg0 !== null) {
// (options[...][, cb])
options = arg0;
@@ -1763,6 +1840,20 @@ function _writeHead(statusCode, reason, obj, response) {
}
}
}
+
+ if (statusCode === 204 || statusCode === 304 || (statusCode >= 100 && statusCode <= 199)) {
+ // RFC 2616, 10.2.5:
+ // The 204 response MUST NOT include a message-body, and thus is always
+ // terminated by the first empty line after the header fields.
+ // RFC 2616, 10.3.5:
+ // The 304 response MUST NOT contain a message-body, and thus is always
+ // terminated by the first empty line after the header fields.
+ // RFC 2616, 10.1 Informational 1xx:
+ // This class of status code indicates a provisional response,
+ // consisting only of the Status-Line and optional headers, and is
+ // terminated by an empty line.
+ response._hasBody = false;
+ }
}
/**
@@ -1789,6 +1880,7 @@ export function get(url, options, cb) {
return req;
}
+export var globalAgent = new Agent();
var defaultObject = {
Agent,
Server,
@@ -1800,15 +1892,14 @@ var defaultObject = {
request,
get,
maxHeaderSize: 16384,
- // validateHeaderName,
- // validateHeaderValue,
+ validateHeaderName,
+ validateHeaderValue,
setMaxIdleHTTPParsers(max) {
debug(`${NODE_HTTP_WARNING}\n`, "setMaxIdleHTTPParsers() is a no-op");
},
- get globalAgent() {
- return (_globalAgent ??= new Agent());
- },
- set globalAgent(agent) {},
+ globalAgent,
+ ClientRequest,
+ OutgoingMessage,
[Symbol.for("CommonJS")]: 0,
};
diff --git a/src/js/node/https.js b/src/js/node/https.js
deleted file mode 100644
index 8253e2905..000000000
--- a/src/js/node/https.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// Hardcoded module "node:https"
-export * from "node:http";
-const HTTP = import.meta.require("node:http");
-export default HTTP;
diff --git a/src/js/node/https.ts b/src/js/node/https.ts
new file mode 100644
index 000000000..08eb89a01
--- /dev/null
+++ b/src/js/node/https.ts
@@ -0,0 +1,65 @@
+// Hardcoded module "node:https"
+import * as http from "node:http";
+
+var {
+ Agent,
+ Server,
+ METHODS,
+ STATUS_CODES,
+ createServer,
+ ServerResponse,
+ IncomingMessage,
+ maxHeaderSize,
+ validateHeaderName,
+ validateHeaderValue,
+ globalAgent,
+} = http;
+
+function request(input, options, cb) {
+ if (input && typeof input === "object" && !(input instanceof URL)) {
+ input.protocol ??= "https:";
+ } else if (typeof options === "object") {
+ options.protocol ??= "https:";
+ }
+
+ return http.request(input, options, cb);
+}
+
+function get(input, options, cb) {
+ const req = request(input, options, cb);
+ req.end();
+ return req;
+}
+
+var defaultExport = {
+ Agent,
+ Server,
+ METHODS,
+ STATUS_CODES,
+ createServer,
+ ServerResponse,
+ IncomingMessage,
+ request,
+ get,
+ maxHeaderSize,
+ validateHeaderName,
+ validateHeaderValue,
+ globalAgent,
+};
+
+export {
+ Agent,
+ Server,
+ METHODS,
+ STATUS_CODES,
+ createServer,
+ ServerResponse,
+ IncomingMessage,
+ request,
+ get,
+ maxHeaderSize,
+ validateHeaderName,
+ validateHeaderValue,
+ globalAgent,
+};
+export default defaultExport;
diff --git a/src/js/node/net.js b/src/js/node/net.js
index e767d0096..6c690b349 100644
--- a/src/js/node/net.js
+++ b/src/js/node/net.js
@@ -19,6 +19,8 @@
// 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 { Duplex } from "node:stream";
+import { EventEmitter } from "node:events";
// IPv4 Segment
const v4Seg = "(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])";
@@ -54,16 +56,15 @@ function isIP(s) {
return 0;
}
-const { Bun, createFIFO, Object } = import.meta.primordials;
+const { Bun, createFIFO, Object } = globalThis[Symbol.for("Bun.lazy")]("primordials");
const { connect: bunConnect } = Bun;
-const { Duplex } = import.meta.require("node:stream");
-const { EventEmitter } = import.meta.require("node:events");
var { setTimeout } = globalThis;
const bunTlsSymbol = Symbol.for("::buntls::");
const bunSocketServerHandlers = Symbol.for("::bunsocket_serverhandlers::");
const bunSocketServerConnections = Symbol.for("::bunnetserverconnections::");
const bunSocketServerOptions = Symbol.for("::bunnetserveroptions::");
+const bunSocketInternal = Symbol.for("::bunnetsocketinternal::");
var SocketClass;
const Socket = (function (InternalSocket) {
@@ -117,13 +118,18 @@ const Socket = (function (InternalSocket) {
const self = socket.data;
socket.timeout(self.timeout);
socket.ref();
- self.#socket = socket;
+ self[bunSocketInternal] = socket;
self.connecting = false;
- self.emit("connect", self);
+ if (!self.#upgraded) {
+ // this is not actually emitted on nodejs when socket used on the connection
+ // this is already emmited on non-TLS socket and on TLS socket is emmited secureConnect on handshake
+ self.emit("connect", self);
+ }
Socket.#Drain(socket);
},
handshake(socket, success, verifyError) {
const { data: self } = socket;
+
self._securePending = false;
self.secureConnecting = false;
self._secureEstablished = !!success;
@@ -164,7 +170,7 @@ const Socket = (function (InternalSocket) {
if (self.#closed) return;
self.#closed = true;
//socket cannot be used after close
- self.#socket = null;
+ self[bunSocketInternal] = null;
const queue = self.#readQueue;
if (queue.isEmpty()) {
if (self.push(null)) return;
@@ -289,23 +295,35 @@ const Socket = (function (InternalSocket) {
localAddress = "127.0.0.1";
#readQueue = createFIFO();
remotePort;
- #socket;
+ [bunSocketInternal] = null;
timeout = 0;
#writeCallback;
#writeChunk;
#pendingRead;
isServer = false;
+ _handle;
+ _parent;
+ _parentWrap;
+ #socket;
+ #upgraded;
constructor(options) {
- const { signal, write, read, allowHalfOpen = false, ...opts } = options || {};
+ const { socket, signal, write, read, allowHalfOpen = false, ...opts } = options || {};
super({
...opts,
allowHalfOpen,
readable: true,
writable: true,
});
+ this._handle = this;
+ this._parent = this;
+ this._parentWrap = this;
this.#pendingRead = undefined;
+ this.#upgraded = false;
+ if (socket instanceof Socket) {
+ this.#socket = socket;
+ }
signal?.once("abort", () => this.destroy());
this.once("connect", () => this.emit("ready"));
}
@@ -327,7 +345,7 @@ const Socket = (function (InternalSocket) {
socket.data = this;
socket.timeout(this.timeout);
socket.ref();
- this.#socket = socket;
+ this[bunSocketInternal] = socket;
this.connecting = false;
this.emit("connect", this);
Socket.#Drain(socket);
@@ -335,6 +353,7 @@ const Socket = (function (InternalSocket) {
connect(port, host, connectListener) {
var path;
+ var connection = this.#socket;
if (typeof port === "string") {
path = port;
port = undefined;
@@ -357,6 +376,7 @@ const Socket = (function (InternalSocket) {
port,
host,
path,
+ socket,
// TODOs
localAddress,
localPort,
@@ -371,7 +391,11 @@ const Socket = (function (InternalSocket) {
pauseOnConnect,
servername,
} = port;
+
this.servername = servername;
+ if (socket) {
+ connection = socket;
+ }
}
if (!pauseOnConnect) {
@@ -399,41 +423,109 @@ const Socket = (function (InternalSocket) {
} else {
tls.rejectUnauthorized = rejectUnauthorized;
tls.requestCert = true;
+ if (!connection && tls.socket) {
+ connection = tls.socket;
+ }
+ }
+ }
+ if (connection) {
+ if (
+ typeof connection !== "object" ||
+ !(connection instanceof Socket) ||
+ typeof connection[bunTlsSymbol] === "function"
+ ) {
+ throw new TypeError("socket must be an instance of net.Socket");
}
}
-
this.authorized = false;
this.secureConnecting = true;
this._secureEstablished = false;
this._securePending = true;
if (connectListener) this.on("secureConnect", connectListener);
} else if (connectListener) this.on("connect", connectListener);
- bunConnect(
- path
- ? {
+ // start using existing connection
+
+ if (connection) {
+ const socket = connection[bunSocketInternal];
+
+ if (socket) {
+ this.connecting = true;
+ this.#upgraded = true;
+ const result = socket.upgradeTLS({
+ data: this,
+ tls,
+ socket: Socket.#Handlers,
+ });
+ if (result) {
+ const [raw, tls] = result;
+ // replace socket
+ connection[bunSocketInternal] = raw;
+ raw.timeout(raw.timeout);
+ raw.connecting = false;
+ this[bunSocketInternal] = tls;
+ } else {
+ this[bunSocketInternal] = null;
+ throw new Error("Invalid socket");
+ }
+ } else {
+ // wait to be connected
+ connection.once("connect", () => {
+ const socket = connection[bunSocketInternal];
+ if (!socket) return;
+
+ this.connecting = true;
+ this.#upgraded = true;
+ const result = socket.upgradeTLS({
data: this,
- unix: path,
- socket: Socket.#Handlers,
tls,
- }
- : {
- data: this,
- hostname: host || "localhost",
- port: port,
socket: Socket.#Handlers,
- tls,
- },
- );
+ });
+
+ if (result) {
+ const [raw, tls] = result;
+ // replace socket
+ connection[bunSocketInternal] = raw;
+ raw.timeout(raw.timeout);
+ raw.connecting = false;
+ this[bunSocketInternal] = tls;
+ } else {
+ this[bunSocketInternal] = null;
+ throw new Error("Invalid socket");
+ }
+ });
+ }
+ } else if (path) {
+ // start using unix socket
+ bunConnect({
+ data: this,
+ unix: path,
+ socket: Socket.#Handlers,
+ tls,
+ }).catch(error => {
+ this.emit("error", error);
+ });
+ } else {
+ // default start
+ bunConnect({
+ data: this,
+ hostname: host || "localhost",
+ port: port,
+ socket: Socket.#Handlers,
+ tls,
+ }).catch(error => {
+ this.emit("error", error);
+ });
+ }
return this;
}
_destroy(err, callback) {
- this.#socket?.end();
+ this[bunSocketInternal]?.end();
callback(err);
}
_final(callback) {
- this.#socket?.end();
+ this[bunSocketInternal]?.end();
callback();
}
@@ -446,7 +538,7 @@ const Socket = (function (InternalSocket) {
}
get localPort() {
- return this.#socket?.localPort;
+ return this[bunSocketInternal]?.localPort;
}
get pending() {
@@ -472,11 +564,11 @@ const Socket = (function (InternalSocket) {
}
ref() {
- this.#socket?.ref();
+ this[bunSocketInternal]?.ref();
}
get remoteAddress() {
- return this.#socket?.remoteAddress;
+ return this[bunSocketInternal]?.remoteAddress;
}
get remoteFamily() {
@@ -484,7 +576,7 @@ const Socket = (function (InternalSocket) {
}
resetAndDestroy() {
- this.#socket?.end();
+ this[bunSocketInternal]?.end();
}
setKeepAlive(enable = false, initialDelay = 0) {
@@ -498,19 +590,19 @@ const Socket = (function (InternalSocket) {
}
setTimeout(timeout, callback) {
- this.#socket?.timeout(timeout);
+ this[bunSocketInternal]?.timeout(timeout);
this.timeout = timeout;
if (callback) this.once("timeout", callback);
return this;
}
unref() {
- this.#socket?.unref();
+ this[bunSocketInternal]?.unref();
}
_write(chunk, encoding, callback) {
- if (typeof chunk == "string" && encoding !== "utf8") chunk = Buffer.from(chunk, encoding);
- var written = this.#socket?.write(chunk);
+ if (typeof chunk == "string" && encoding !== "ascii") chunk = Buffer.from(chunk, encoding);
+ var written = this[bunSocketInternal]?.write(chunk);
if (written == chunk.length) {
callback();
} else if (this.#writeCallback) {
diff --git a/src/js/node/os.js b/src/js/node/os.js
index 3315708ad..3cd0288bd 100644
--- a/src/js/node/os.js
+++ b/src/js/node/os.js
@@ -1,4 +1,22 @@
// Hardcoded module "node:os"
+
+export var tmpdir = function () {
+ var lazy = Symbol.for("Bun.lazy");
+ var primordials = globalThis[lazy]("primordials");
+
+ var { Bun } = primordials;
+ var env = Bun.env;
+
+ tmpdir = function () {
+ var path = env["TMPDIR"] || env["TMP"] || env["TEMP"] || "/tmp";
+ const length = path.length;
+ if (length > 1 && path[length - 1] === "/") path = path.slice(0, -1);
+ return path;
+ };
+
+ return tmpdir();
+};
+
function bound(obj) {
return {
arch: obj.arch.bind(obj),
@@ -13,7 +31,9 @@ function bound(obj) {
platform: obj.platform.bind(obj),
release: obj.release.bind(obj),
setPriority: obj.setPriority.bind(obj),
- tmpdir: obj.tmpdir.bind(obj),
+ get tmpdir() {
+ return tmpdir;
+ },
totalmem: obj.totalmem.bind(obj),
type: obj.type.bind(obj),
uptime: obj.uptime.bind(obj),
@@ -42,7 +62,6 @@ export var {
platform,
release,
setPriority,
- tmpdir,
totalmem,
type,
uptime,
diff --git a/src/js/node/path.js b/src/js/node/path.js
index bcdd1f7f7..7c20d520b 100644
--- a/src/js/node/path.js
+++ b/src/js/node/path.js
@@ -1,6 +1,5 @@
// Hardcoded module "node:path"
export const createModule = obj => Object.assign(Object.create(null), obj);
-
function bound(obj) {
var result = createModule({
basename: obj.basename.bind(obj),
diff --git a/src/js/node/perf_hooks.js b/src/js/node/perf_hooks.js
index fb5929c57..592868ab5 100644
--- a/src/js/node/perf_hooks.js
+++ b/src/js/node/perf_hooks.js
@@ -1,6 +1,20 @@
// Hardcoded module "node:perf_hooks"
import { throwNotImplemented } from "../shared";
+export var constants = {
+ NODE_PERFORMANCE_GC_MAJOR: 4,
+ NODE_PERFORMANCE_GC_MINOR: 1,
+ NODE_PERFORMANCE_GC_INCREMENTAL: 8,
+ NODE_PERFORMANCE_GC_WEAKCB: 16,
+ NODE_PERFORMANCE_GC_FLAGS_NO: 0,
+ NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED: 2,
+ NODE_PERFORMANCE_GC_FLAGS_FORCED: 4,
+ NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING: 8,
+ NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE: 16,
+ NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY: 32,
+ NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE: 64,
+};
+
export var performance = globalThis.performance;
export class PerformanceObserver {
@@ -22,6 +36,7 @@ export class PerformanceNodeTiming {
export default {
performance,
+ constants,
PerformanceEntry,
PerformanceNodeTiming,
[Symbol.for("CommonJS")]: 0,
diff --git a/src/js/node/readline.js b/src/js/node/readline.js
index 0c253e8a0..64e73172a 100644
--- a/src/js/node/readline.js
+++ b/src/js/node/readline.js
@@ -25,10 +25,10 @@
// ----------------------------------------------------------------------------
// Section: Imports
// ----------------------------------------------------------------------------
-var { Array, RegExp, String, Bun } = import.meta.primordials;
-var EventEmitter = import.meta.require("node:events");
-var { clearTimeout, setTimeout } = import.meta.require("timers");
-var { StringDecoder } = import.meta.require("string_decoder");
+var { Array, RegExp, String, Bun } = globalThis[Symbol.for("Bun.lazy")]("primordials");
+import { EventEmitter } from "node:events";
+import { clearTimeout, setTimeout } from "timers";
+import { StringDecoder } from "string_decoder";
var isWritable;
var { inspect } = Bun;
@@ -1573,7 +1573,7 @@ function InterfaceConstructor(input, output, completer, terminal) {
}
ObjectSetPrototypeOf(InterfaceConstructor.prototype, EventEmitter.prototype);
-ObjectSetPrototypeOf(InterfaceConstructor, EventEmitter);
+// ObjectSetPrototypeOf(InterfaceConstructor, EventEmitter);
var _Interface = class Interface extends InterfaceConstructor {
// TODO: Enumerate all the properties of the class
diff --git a/src/js/node/readline.promises.js b/src/js/node/readline.promises.js
index 94d9b3f96..6890235b4 100644
--- a/src/js/node/readline.promises.js
+++ b/src/js/node/readline.promises.js
@@ -1,7 +1,7 @@
// Hardcoded module "node:readline/promises"
-var {
- promises: { Readline, Interface, createInterface },
-} = import.meta.require("node:readline");
+import { promises } from "node:readline";
+
+export const { Readline, Interface, createInterface } = promises;
export default {
Readline,
diff --git a/src/js/node/stream.consumers.js b/src/js/node/stream.consumers.js
index 39d436eed..a1f85ab94 100644
--- a/src/js/node/stream.consumers.js
+++ b/src/js/node/stream.consumers.js
@@ -1,5 +1,5 @@
// Hardcoded module "node:stream/consumers" / "readable-stream/consumer"
-const { Bun } = import.meta.primordials;
+const { Bun } = globalThis[Symbol.for("Bun.lazy")]("primordials");
export const arrayBuffer = Bun.readableStreamToArrayBuffer;
export const text = Bun.readableStreamToText;
diff --git a/src/js/node/stream.js b/src/js/node/stream.js
index 67d82d287..30c76d797 100644
--- a/src/js/node/stream.js
+++ b/src/js/node/stream.js
@@ -1,13 +1,20 @@
// Hardcoded module "node:stream" / "readable-stream"
// "readable-stream" npm package
// just transpiled
-var { isPromise, isCallable, direct, Object } = import.meta.primordials;
-globalThis.__IDS_TO_TRACK = process.env.DEBUG_TRACK_EE?.length
- ? process.env.DEBUG_TRACK_EE.split(",")
- : process.env.DEBUG_STREAMS?.length
- ? process.env.DEBUG_STREAMS.split(",")
- : null;
+// This must go at the top of the file, before any side effects.
+// IS_BUN_DEVELOPMENT is a bundle-only global variable that is set to true when
+// building a development bundle.
+const __TRACK_EE__ = IS_BUN_DEVELOPMENT && !!process.env.DEBUG_TRACK_EE;
+const __DEBUG__ = IS_BUN_DEVELOPMENT && !!(process.env.DEBUG || process.env.DEBUG_STREAMS || __TRACK_EE__);
+
+if (__DEBUG__) {
+ globalThis.__IDS_TO_TRACK = process.env.DEBUG_TRACK_EE?.length
+ ? process.env.DEBUG_TRACK_EE.split(",")
+ : process.env.DEBUG_STREAMS?.length
+ ? process.env.DEBUG_STREAMS.split(",")
+ : null;
+}
// Separating DEBUG, DEBUG_STREAMS and DEBUG_TRACK_EE env vars makes it easier to focus on the
// events in this file rather than all debug output across all files
@@ -16,9 +23,6 @@ globalThis.__IDS_TO_TRACK = process.env.DEBUG_TRACK_EE?.length
// The events and/or all of the outputs for the given stream IDs assigned at stream construction
// By default, child_process gives
-const __TRACK_EE__ = !!process.env.DEBUG_TRACK_EE;
-const __DEBUG__ = !!(process.env.DEBUG || process.env.DEBUG_STREAMS || __TRACK_EE__);
-
var debug = __DEBUG__
? globalThis.__IDS_TO_TRACK
? // If we are tracking IDs for debug event emitters, we should prefix the debug output with the ID
@@ -30,6 +34,10 @@ var debug = __DEBUG__
: (...args) => console.log(...args.slice(0, -1))
: () => {};
+var { isPromise, isCallable, direct, Object } = globalThis[Symbol.for("Bun.lazy")]("primordials");
+import { EventEmitter as EE } from "bun:events_native";
+import { StringDecoder } from "node:string_decoder";
+
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -37,48 +45,6 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __ObjectSetPrototypeOf = Object.setPrototypeOf;
-var __require = x => import.meta.require(x);
-
-var _EE = __require("bun:events_native");
-
-function DebugEventEmitter(opts) {
- if (!(this instanceof DebugEventEmitter)) return new DebugEventEmitter(opts);
- _EE.call(this, opts);
- const __id = opts.__id;
- if (__id) {
- __defProp(this, "__id", {
- value: __id,
- readable: true,
- writable: false,
- enumerable: false,
- });
- }
-}
-
-__ObjectSetPrototypeOf(DebugEventEmitter.prototype, _EE.prototype);
-__ObjectSetPrototypeOf(DebugEventEmitter, _EE);
-
-DebugEventEmitter.prototype.emit = function (event, ...args) {
- var __id = this.__id;
- if (__id) {
- debug("emit", event, ...args, __id);
- } else {
- debug("emit", event, ...args);
- }
- return _EE.prototype.emit.call(this, event, ...args);
-};
-DebugEventEmitter.prototype.on = function (event, handler) {
- var __id = this.__id;
- if (__id) {
- debug("on", event, "added", __id);
- } else {
- debug("on", event, "added");
- }
- return _EE.prototype.on.call(this, event, handler);
-};
-DebugEventEmitter.prototype.addListener = function (event, handler) {
- return this.on(event, handler);
-};
var __commonJS = (cb, mod) =>
function __require2() {
@@ -260,9 +226,8 @@ var require_primordials = __commonJS({
var require_util = __commonJS({
"node_modules/readable-stream/lib/ours/util.js"(exports, module) {
"use strict";
- var bufferModule = __require("buffer");
+
var AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
- var Blob = globalThis.Blob || bufferModule.Blob;
var isBlob =
typeof Blob !== "undefined"
? function isBlob2(b) {
@@ -1388,7 +1353,6 @@ var require_end_of_stream = __commonJS({
var require_operators = __commonJS({
"node_modules/readable-stream/lib/internal/streams/operators.js"(exports, module) {
"use strict";
- var AbortController = globalThis.AbortController || __require("abort-controller").AbortController;
var {
codes: { ERR_INVALID_ARG_TYPE, ERR_MISSING_ARGS, ERR_OUT_OF_RANGE },
AbortError,
@@ -2084,13 +2048,6 @@ var require_legacy = __commonJS({
"node_modules/readable-stream/lib/internal/streams/legacy.js"(exports, module) {
"use strict";
var { ArrayIsArray, ObjectSetPrototypeOf } = require_primordials();
- var { EventEmitter: _EE } = __require("bun:events_native");
- var EE;
- if (__TRACK_EE__) {
- EE = DebugEventEmitter;
- } else {
- EE = _EE;
- }
function Stream(options) {
if (!(this instanceof Stream)) return new Stream(options);
@@ -2332,6 +2289,7 @@ var require_from = __commonJS({
});
var _ReadableFromWeb;
+var _ReadableFromWebForUndici;
// node_modules/readable-stream/lib/internal/streams/readable.js
var require_readable = __commonJS({
@@ -2352,7 +2310,6 @@ var require_readable = __commonJS({
} = require_primordials();
var ReadableState = globalThis[Symbol.for("Bun.lazy")]("bun:stream").ReadableState;
- var { EventEmitter: EE } = __require("bun:events_native");
var { Stream, prependListener } = require_legacy();
function Readable(options) {
@@ -2537,6 +2494,8 @@ var require_readable = __commonJS({
}
}
+ _ReadableFromWebForUndici = ReadableFromWeb;
+
/**
* @param {ReadableStream} readableStream
* @param {{
@@ -2596,7 +2555,7 @@ var require_readable = __commonJS({
}
module.exports = Readable;
- _ReadableFromWeb = ReadableFromWeb;
+ _ReadableFromWeb = newStreamReadableFromReadableStream;
var { addAbortSignal } = require_add_abort_signal();
var eos = require_end_of_stream();
@@ -2626,7 +2585,6 @@ var require_readable = __commonJS({
},
} = require_errors();
var { validateObject } = require_validators();
- var { StringDecoder } = __require("string_decoder");
var from = require_from();
var nop = () => {};
var { errorOrDestroy } = destroyImpl;
@@ -3422,7 +3380,6 @@ var require_writable = __commonJS({
SymbolHasInstance,
} = require_primordials();
- var { EventEmitter: EE } = __require("bun:events_native");
var Stream = require_legacy().Stream;
var destroyImpl = require_destroy();
var { addAbortSignal } = require_add_abort_signal();
@@ -4048,7 +4005,6 @@ var require_writable = __commonJS({
var require_duplexify = __commonJS({
"node_modules/readable-stream/lib/internal/streams/duplexify.js"(exports, module) {
"use strict";
- var bufferModule = __require("buffer");
var {
isReadable,
isWritable,
@@ -4068,7 +4024,6 @@ var require_duplexify = __commonJS({
var Readable = require_readable();
var { createDeferredPromise } = require_util();
var from = require_from();
- var Blob = globalThis.Blob || bufferModule.Blob;
var isBlob =
typeof Blob !== "undefined"
? function isBlob2(b) {
@@ -4077,7 +4032,6 @@ var require_duplexify = __commonJS({
: function isBlob2(b) {
return false;
};
- var AbortController = globalThis.AbortController || __require("abort-controller").AbortController;
var { FunctionPrototypeCall } = require_primordials();
class Duplexify extends Duplex {
constructor(options) {
@@ -4619,7 +4573,6 @@ var require_pipeline = __commonJS({
} = require_errors();
var { validateFunction, validateAbortSignal } = require_validators();
var { isIterable, isReadable, isReadableNodeStream, isNodeStream } = require_utils();
- var AbortController = globalThis.AbortController || __require("abort-controller").AbortController;
var PassThrough;
var Readable;
function destroyer(stream, reading, writing) {
@@ -5304,7 +5257,7 @@ function createNativeStreamReadable(nativeType, Readable) {
const finalizer = new FinalizationRegistry(ptr => ptr && deinit(ptr));
const MIN_BUFFER_SIZE = 512;
var NativeReadable = class NativeReadable extends Readable {
- #ptr;
+ #bunNativePtr;
#refCount = 1;
#constructed = false;
#remainingChunk = undefined;
@@ -5319,12 +5272,12 @@ function createNativeStreamReadable(nativeType, Readable) {
} else {
this.#highWaterMark = 256 * 1024;
}
- this.#ptr = ptr;
+ this.#bunNativePtr = ptr;
this.#constructed = false;
this.#remainingChunk = undefined;
this.#pendingRead = false;
this.#unregisterToken = {};
- finalizer.register(this, this.#ptr, this.#unregisterToken);
+ finalizer.register(this, this.#bunNativePtr, this.#unregisterToken);
}
// maxToRead is by default the highWaterMark passed from the Readable.read call to this fn
@@ -5337,7 +5290,7 @@ function createNativeStreamReadable(nativeType, Readable) {
return;
}
- var ptr = this.#ptr;
+ var ptr = this.#bunNativePtr;
__DEBUG__ && debug("ptr @ NativeReadable._read", ptr, this.__id);
if (ptr === 0) {
this.push(null);
@@ -5403,10 +5356,10 @@ function createNativeStreamReadable(nativeType, Readable) {
return chunk;
}
- push(result, encoding) {
- __DEBUG__ && debug("NativeReadable push -- result, encoding", result, encoding, this.__id);
- return super.push(...arguments);
- }
+ // push(result, encoding) {
+ // __DEBUG__ && debug("NativeReadable push -- result, encoding", result, encoding, this.__id);
+ // return super.push(...arguments);
+ // }
#handleResult(result, view, isClosed) {
__DEBUG__ && debug("result, isClosed @ #handleResult", result, isClosed, this.__id);
@@ -5419,7 +5372,9 @@ function createNativeStreamReadable(nativeType, Readable) {
return handleNumberResult(this, result, view, isClosed);
} else if (typeof result === "boolean") {
- this.push(null);
+ process.nextTick(() => {
+ this.push(null);
+ });
return view?.byteLength ?? 0 > 0 ? view : undefined;
} else if (ArrayBuffer.isView(result)) {
if (result.byteLength >= this.#highWaterMark && !this.#hasResized && !isClosed) {
@@ -5458,14 +5413,14 @@ function createNativeStreamReadable(nativeType, Readable) {
}
_destroy(error, callback) {
- var ptr = this.#ptr;
+ var ptr = this.#bunNativePtr;
if (ptr === 0) {
callback(error);
return;
}
finalizer.unregister(this.#unregisterToken);
- this.#ptr = 0;
+ this.#bunNativePtr = 0;
if (updateRef) {
updateRef(ptr, false);
}
@@ -5475,7 +5430,7 @@ function createNativeStreamReadable(nativeType, Readable) {
}
ref() {
- var ptr = this.#ptr;
+ var ptr = this.#bunNativePtr;
if (ptr === 0) return;
if (this.#refCount++ === 0) {
updateRef(ptr, true);
@@ -5483,7 +5438,7 @@ function createNativeStreamReadable(nativeType, Readable) {
}
unref() {
- var ptr = this.#ptr;
+ var ptr = this.#bunNativePtr;
if (ptr === 0) return;
if (this.#refCount-- === 1) {
updateRef(ptr, false);
@@ -5632,7 +5587,7 @@ var NativeWritable = class NativeWritable extends Writable {
const stream_exports = require_ours();
stream_exports[Symbol.for("CommonJS")] = 0;
-stream_exports[Symbol.for("::bunternal::")] = { _ReadableFromWeb };
+stream_exports[Symbol.for("::bunternal::")] = { _ReadableFromWeb, _ReadableFromWebForUndici };
export default stream_exports;
export var _uint8ArrayToBuffer = stream_exports._uint8ArrayToBuffer;
export var _isUint8Array = stream_exports._isUint8Array;
@@ -5654,4 +5609,4 @@ export var Stream = stream_exports.Stream;
export var eos = (stream_exports["eos"] = require_end_of_stream);
export var _getNativeReadableStreamPrototype = stream_exports._getNativeReadableStreamPrototype;
export var NativeWritable = stream_exports.NativeWritable;
-export var promises = Stream.promise;
+export var promises = Stream.promises;
diff --git a/src/js/node/stream.promises.js b/src/js/node/stream.promises.js
index d00c424a6..323785a4c 100644
--- a/src/js/node/stream.promises.js
+++ b/src/js/node/stream.promises.js
@@ -1,5 +1,5 @@
-// Hardcoded module "node:stream"
-var { promises } = import.meta.require("node:stream");
+// Hardcoded module "node:stream/promises"
+import { promises } from "node:stream";
export var { pipeline, finished } = promises;
diff --git a/src/js/node/timers.promises.js b/src/js/node/timers.promises.js
index 2bb7bce49..3e2e7bcd5 100644
--- a/src/js/node/timers.promises.js
+++ b/src/js/node/timers.promises.js
@@ -233,3 +233,4 @@ function setIntervalPromise(after = 1, value, options = {}) {
}
export { setTimeoutPromise as setTimeout, setImmediatePromise as setImmediate, setIntervalPromise as setInterval };
+export default { setTimeout: setTimeoutPromise, setImmediate: setImmediatePromise, setInterval: setIntervalPromise };
diff --git a/src/js/node/tls.js b/src/js/node/tls.js
index b3b089daf..310a36620 100644
--- a/src/js/node/tls.js
+++ b/src/js/node/tls.js
@@ -1,7 +1,30 @@
// Hardcoded module "node:tls"
-import { isTypedArray } from "util/types";
-
+import { isArrayBufferView, isTypedArray } from "util/types";
+import net, { Server as NetServer } from "node:net";
+const InternalTCPSocket = net[Symbol.for("::bunternal::")];
+const bunSocketInternal = Symbol.for("::bunnetsocketinternal::");
+
+const { RegExp, Array, String } = globalThis[Symbol.for("Bun.lazy")]("primordials");
+const SymbolReplace = Symbol.replace;
+const RegExpPrototypeSymbolReplace = RegExp.prototype[SymbolReplace];
+const RegExpPrototypeExec = RegExp.prototype.exec;
+
+const StringPrototypeStartsWith = String.prototype.startsWith;
+const StringPrototypeSlice = String.prototype.slice;
+const StringPrototypeIncludes = String.prototype.includes;
+const StringPrototypeSplit = String.prototype.split;
+const StringPrototypeIndexOf = String.prototype.indexOf;
+const StringPrototypeSubstring = String.prototype.substring;
+const StringPrototypeEndsWith = String.prototype.endsWith;
+
+const ArrayPrototypeIncludes = Array.prototype.includes;
+const ArrayPrototypeJoin = Array.prototype.join;
+const ArrayPrototypeForEach = Array.prototype.forEach;
+const ArrayPrototypePush = Array.prototype.push;
+const ArrayPrototypeSome = Array.prototype.some;
+const ArrayPrototypeReduce = Array.prototype.reduce;
function parseCertString() {
+ // Removed since JAN 2022 Node v18.0.0+ https://github.com/nodejs/node/pull/41479
throwNotImplemented("Not implemented");
}
@@ -16,6 +39,164 @@ function isValidTLSArray(obj) {
}
}
+function unfqdn(host) {
+ return RegExpPrototypeSymbolReplace(/[.]$/, host, "");
+}
+
+function splitHost(host) {
+ return StringPrototypeSplit.call(RegExpPrototypeSymbolReplace(/[A-Z]/g, unfqdn(host), toLowerCase), ".");
+}
+
+function check(hostParts, pattern, wildcards) {
+ // Empty strings, null, undefined, etc. never match.
+ if (!pattern) return false;
+
+ const patternParts = splitHost(pattern);
+
+ if (hostParts.length !== patternParts.length) return false;
+
+ // Pattern has empty components, e.g. "bad..example.com".
+ if (ArrayPrototypeIncludes.call(patternParts, "")) return false;
+
+ // RFC 6125 allows IDNA U-labels (Unicode) in names but we have no
+ // good way to detect their encoding or normalize them so we simply
+ // reject them. Control characters and blanks are rejected as well
+ // because nothing good can come from accepting them.
+ const isBad = s => RegExpPrototypeExec.call(/[^\u0021-\u007F]/u, s) !== null;
+ if (ArrayPrototypeSome.call(patternParts, isBad)) return false;
+
+ // Check host parts from right to left first.
+ for (let i = hostParts.length - 1; i > 0; i -= 1) {
+ if (hostParts[i] !== patternParts[i]) return false;
+ }
+
+ const hostSubdomain = hostParts[0];
+ const patternSubdomain = patternParts[0];
+ const patternSubdomainParts = StringPrototypeSplit.call(patternSubdomain, "*");
+
+ // Short-circuit when the subdomain does not contain a wildcard.
+ // RFC 6125 does not allow wildcard substitution for components
+ // containing IDNA A-labels (Punycode) so match those verbatim.
+ if (patternSubdomainParts.length === 1 || StringPrototypeIncludes.call(patternSubdomain, "xn--"))
+ return hostSubdomain === patternSubdomain;
+
+ if (!wildcards) return false;
+
+ // More than one wildcard is always wrong.
+ if (patternSubdomainParts.length > 2) return false;
+
+ // *.tld wildcards are not allowed.
+ if (patternParts.length <= 2) return false;
+
+ const { 0: prefix, 1: suffix } = patternSubdomainParts;
+
+ if (prefix.length + suffix.length > hostSubdomain.length) return false;
+
+ if (!StringPrototypeStartsWith.call(hostSubdomain, prefix)) return false;
+
+ if (!StringPrototypeEndsWith.call(hostSubdomain, suffix)) return false;
+
+ return true;
+}
+
+// This pattern is used to determine the length of escaped sequences within
+// the subject alt names string. It allows any valid JSON string literal.
+// This MUST match the JSON specification (ECMA-404 / RFC8259) exactly.
+const jsonStringPattern =
+ // eslint-disable-next-line no-control-regex
+ /^"(?:[^"\\\u0000-\u001f]|\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4}))*"/;
+
+function splitEscapedAltNames(altNames) {
+ const result = [];
+ let currentToken = "";
+ let offset = 0;
+ while (offset !== altNames.length) {
+ const nextSep = StringPrototypeIndexOf.call(altNames, ", ", offset);
+ const nextQuote = StringPrototypeIndexOf.call(altNames, '"', offset);
+ if (nextQuote !== -1 && (nextSep === -1 || nextQuote < nextSep)) {
+ // There is a quote character and there is no separator before the quote.
+ currentToken += StringPrototypeSubstring.call(altNames, offset, nextQuote);
+ const match = RegExpPrototypeExec.call(jsonStringPattern, StringPrototypeSubstring.call(altNames, nextQuote));
+ if (!match) {
+ let error = new SyntaxError("ERR_TLS_CERT_ALTNAME_FORMAT: Invalid subject alternative name string");
+ error.name = ERR_TLS_CERT_ALTNAME_FORMAT;
+ throw error;
+ }
+ currentToken += JSON.parse(match[0]);
+ offset = nextQuote + match[0].length;
+ } else if (nextSep !== -1) {
+ // There is a separator and no quote before it.
+ currentToken += StringPrototypeSubstring.call(altNames, offset, nextSep);
+ ArrayPrototypePush.call(result, currentToken);
+ currentToken = "";
+ offset = nextSep + 2;
+ } else {
+ currentToken += StringPrototypeSubstring.call(altNames, offset);
+ offset = altNames.length;
+ }
+ }
+ ArrayPrototypePush.call(result, currentToken);
+ return result;
+}
+function checkServerIdentity(hostname, cert) {
+ const subject = cert.subject;
+ const altNames = cert.subjectaltname;
+ const dnsNames = [];
+ const ips = [];
+
+ hostname = "" + hostname;
+
+ if (altNames) {
+ const splitAltNames = StringPrototypeIncludes.call(altNames, '"')
+ ? splitEscapedAltNames(altNames)
+ : StringPrototypeSplit.call(altNames, ", ");
+ ArrayPrototypeForEach.call(splitAltNames, name => {
+ if (StringPrototypeStartsWith.call(name, "DNS:")) {
+ ArrayPrototypePush.call(dnsNames, StringPrototypeSlice.call(name, 4));
+ } else if (StringPrototypeStartsWith.call(name, "IP Address:")) {
+ ArrayPrototypePush.call(ips, canonicalizeIP(StringPrototypeSlice.call(name, 11)));
+ }
+ });
+ }
+
+ let valid = false;
+ let reason = "Unknown reason";
+
+ hostname = unfqdn(hostname); // Remove trailing dot for error messages.
+
+ if (net.isIP(hostname)) {
+ valid = ArrayPrototypeIncludes.call(ips, canonicalizeIP(hostname));
+ if (!valid) reason = `IP: ${hostname} is not in the cert's list: ` + ArrayPrototypeJoin.call(ips, ", ");
+ } else if (dnsNames.length > 0 || subject?.CN) {
+ const hostParts = splitHost(hostname);
+ const wildcard = pattern => check(hostParts, pattern, true);
+
+ if (dnsNames.length > 0) {
+ valid = ArrayPrototypeSome.call(dnsNames, wildcard);
+ if (!valid) reason = `Host: ${hostname}. is not in the cert's altnames: ${altNames}`;
+ } else {
+ // Match against Common Name only if no supported identifiers exist.
+ const cn = subject.CN;
+
+ if (ArrayIsArray(cn)) valid = ArrayPrototypeSome.call(cn, wildcard);
+ else if (cn) valid = wildcard(cn);
+
+ if (!valid) reason = `Host: ${hostname}. is not cert's CN: ${cn}`;
+ }
+ } else {
+ reason = "Cert does not contain a DNS name";
+ }
+
+ if (!valid) {
+ let error = new Error(`ERR_TLS_CERT_ALTNAME_INVALID: Hostname/IP does not match certificate's altnames: ${reason}`);
+ error.name = "ERR_TLS_CERT_ALTNAME_INVALID";
+ error.reason = reason;
+ error.host = host;
+ error.cert = cert;
+ return error;
+ }
+}
+
var InternalSecureContext = class SecureContext {
context;
@@ -81,7 +262,35 @@ function createSecureContext(options) {
return new SecureContext(options);
}
-const { [Symbol.for("::bunternal::")]: InternalTCPSocket, Server: NetServer } = import.meta.require("net");
+// Translate some fields from the handle's C-friendly format into more idiomatic
+// javascript object representations before passing them back to the user. Can
+// be used on any cert object, but changing the name would be semver-major.
+function translatePeerCertificate(c) {
+ if (!c) return null;
+
+ if (c.issuerCertificate != null && c.issuerCertificate !== c) {
+ c.issuerCertificate = translatePeerCertificate(c.issuerCertificate);
+ }
+ if (c.infoAccess != null) {
+ const info = c.infoAccess;
+ c.infoAccess = { __proto__: null };
+
+ // XXX: More key validation?
+ RegExpPrototypeSymbolReplace(/([^\n:]*):([^\n]*)(?:\n|$)/g, info, (all, key, val) => {
+ if (val.charCodeAt(0) === 0x22) {
+ // The translatePeerCertificate function is only
+ // used on internally created legacy certificate
+ // objects, and any value that contains a quote
+ // will always be a valid JSON string literal,
+ // so this should never throw.
+ val = JSONParse(val);
+ }
+ if (key in c.infoAccess) ArrayPrototypePush.call(c.infoAccess[key], val);
+ else c.infoAccess[key] = [val];
+ });
+ }
+ return c;
+}
const buntls = Symbol.for("::buntls::");
@@ -107,8 +316,22 @@ const TLSSocket = (function (InternalTLSSocket) {
})(
class TLSSocket extends InternalTCPSocket {
#secureContext;
- constructor(options) {
- super(options);
+ ALPNProtocols;
+ #socket;
+
+ constructor(socket, options) {
+ super(socket instanceof InternalTCPSocket ? options : options || socket);
+ options = options || socket || {};
+ if (typeof options === "object") {
+ const { ALPNProtocols } = options;
+ if (ALPNProtocols) {
+ convertALPNProtocols(ALPNProtocols, this);
+ }
+ if (socket instanceof InternalTCPSocket) {
+ this.#socket = socket;
+ }
+ }
+
this.#secureContext = options.secureContext || createSecureContext(options);
this.authorized = false;
this.secureConnecting = true;
@@ -123,28 +346,52 @@ const TLSSocket = (function (InternalTLSSocket) {
secureConnecting = false;
_SNICallback;
servername;
- alpnProtocol;
authorized = false;
authorizationError;
encrypted = true;
- exportKeyingMaterial() {
- throw Error("Not implented in Bun yet");
+ _start() {
+ // some frameworks uses this _start internal implementation is suposed to start TLS handshake
+ // on Bun we auto start this after on_open callback and when wrapping we start it after the socket is attached to the net.Socket/tls.Socket
}
- setMaxSendFragment() {
+
+ exportKeyingMaterial(length, label, context) {
+ //SSL_export_keying_material
throw Error("Not implented in Bun yet");
}
- setServername() {
+ setMaxSendFragment(size) {
+ // SSL_set_max_send_fragment
throw Error("Not implented in Bun yet");
}
+ setServername(name) {
+ if (this.isServer) {
+ let error = new Error("ERR_TLS_SNI_FROM_SERVER: Cannot issue SNI from a TLS server-side socket");
+ error.name = "ERR_TLS_SNI_FROM_SERVER";
+ throw error;
+ }
+ // if the socket is detached we can't set the servername but we set this property so when open will auto set to it
+ this.servername = name;
+ this[bunSocketInternal]?.setServername(name);
+ }
setSession() {
throw Error("Not implented in Bun yet");
}
getPeerCertificate() {
+ // need to implement peerCertificate on socket.zig
+ // const cert = this[bunSocketInternal]?.peerCertificate;
+ // if(cert) {
+ // return translatePeerCertificate(cert);
+ // }
throw Error("Not implented in Bun yet");
}
getCertificate() {
+ // need to implement certificate on socket.zig
+ // const cert = this[bunSocketInternal]?.certificate;
+ // if(cert) {
+ // It's not a peer cert, but the formatting is identical.
+ // return translatePeerCertificate(cert);
+ // }
throw Error("Not implented in Bun yet");
}
getPeerX509Certificate() {
@@ -154,16 +401,17 @@ const TLSSocket = (function (InternalTLSSocket) {
throw Error("Not implented in Bun yet");
}
- [buntls](port, host) {
- var { servername } = this;
- if (servername) {
- return {
- serverName: typeof servername === "string" ? servername : host,
- ...this.#secureContext,
- };
- }
+ get alpnProtocol() {
+ return this[bunSocketInternal]?.alpnProtocol;
+ }
- return true;
+ [buntls](port, host) {
+ return {
+ socket: this.#socket,
+ ALPNProtocols: this.ALPNProtocols,
+ serverName: this.servername || host || "localhost",
+ ...this.#secureContext,
+ };
}
},
);
@@ -177,9 +425,12 @@ class Server extends NetServer {
_rejectUnauthorized;
_requestCert;
servername;
+ ALPNProtocols;
+ #checkServerIdentity;
constructor(options, secureConnectionListener) {
super(options, secureConnectionListener);
+ this.#checkServerIdentity = options?.checkServerIdentity || checkServerIdentity;
this.setSecureContext(options);
}
emit(event, args) {
@@ -197,6 +448,12 @@ class Server extends NetServer {
options = options.context;
}
if (options) {
+ const { ALPNProtocols } = options;
+
+ if (ALPNProtocols) {
+ convertALPNProtocols(ALPNProtocols, this);
+ }
+
let key = options.key;
if (key) {
if (!isValidTLSArray(key)) {
@@ -277,6 +534,8 @@ class Server extends NetServer {
// Client always is NONE on set_verify
rejectUnauthorized: isClient ? false : this._rejectUnauthorized,
requestCert: isClient ? false : this._requestCert,
+ ALPNProtocols: this.ALPNProtocols,
+ checkServerIdentity: this.#checkServerIdentity,
},
SocketClass,
];
@@ -286,7 +545,7 @@ class Server extends NetServer {
function createServer(options, connectionListener) {
return new Server(options, connectionListener);
}
-export const CLIENT_RENEG_LIMIT = 3,
+const CLIENT_RENEG_LIMIT = 3,
CLIENT_RENEG_WINDOW = 600,
DEFAULT_ECDH_CURVE = "auto",
// https://github.com/Jarred-Sumner/uSockets/blob/fafc241e8664243fc0c51d69684d5d02b9805134/src/crypto/openssl.c#L519-L523
@@ -296,6 +555,11 @@ export const CLIENT_RENEG_LIMIT = 3,
DEFAULT_MAX_VERSION = "TLSv1.3",
createConnection = (port, host, connectListener) => {
if (typeof port === "object") {
+ port.checkServerIdentity || checkServerIdentity;
+ const { ALPNProtocols } = port;
+ if (ALPNProtocols) {
+ convertALPNProtocols(ALPNProtocols, port);
+ }
// port is option pass Socket options and let connect handle connection options
return new TLSSocket(port).connect(port, host, connectListener);
}
@@ -304,34 +568,103 @@ export const CLIENT_RENEG_LIMIT = 3,
},
connect = createConnection;
-var exports = {
- createSecureContext,
- parseCertString,
+function getCiphers() {
+ return DEFAULT_CIPHERS.split(":");
+}
- getCiphers() {
- return DEFAULT_CIPHERS.split(":");
- },
+function getCurves() {
+ return;
+}
- getCurves() {
- return;
- },
+// Convert protocols array into valid OpenSSL protocols list
+// ("\x06spdy/2\x08http/1.1\x08http/1.0")
+function convertProtocols(protocols) {
+ const lens = new Array(protocols.length);
+ const buff = Buffer.allocUnsafe(
+ ArrayPrototypeReduce.call(
+ protocols,
+ (p, c, i) => {
+ const len = Buffer.byteLength(c);
+ if (len > 255) {
+ throw new RangeError(
+ "The byte length of the protocol at index " + `${i} exceeds the maximum length.`,
+ "<= 255",
+ len,
+ true,
+ );
+ }
+ lens[i] = len;
+ return p + 1 + len;
+ },
+ 0,
+ ),
+ );
- convertALPNProtocols(protocols, out) {},
- TLSSocket,
- SecureContext,
+ let offset = 0;
+ for (let i = 0, c = protocols.length; i < c; i++) {
+ buff[offset++] = lens[i];
+ buff.write(protocols[i], offset);
+ offset += lens[i];
+ }
+
+ return buff;
+}
+
+function convertALPNProtocols(protocols, out) {
+ // If protocols is Array - translate it into buffer
+ if (Array.isArray(protocols)) {
+ out.ALPNProtocols = convertProtocols(protocols);
+ } else if (isTypedArray(protocols)) {
+ // Copy new buffer not to be modified by user.
+ out.ALPNProtocols = Buffer.from(protocols);
+ } else if (isArrayBufferView(protocols)) {
+ out.ALPNProtocols = Buffer.from(
+ protocols.buffer.slice(protocols.byteOffset, protocols.byteOffset + protocols.byteLength),
+ );
+ } else if (Buffer.isBuffer(protocols)) {
+ out.ALPNProtocols = protocols;
+ }
+}
+
+var exports = {
+ [Symbol.for("CommonJS")]: 0,
CLIENT_RENEG_LIMIT,
CLIENT_RENEG_WINDOW,
- DEFAULT_ECDH_CURVE,
+ connect,
+ convertALPNProtocols,
+ createConnection,
+ createSecureContext,
+ createServer,
DEFAULT_CIPHERS,
- DEFAULT_MIN_VERSION,
+ DEFAULT_ECDH_CURVE,
DEFAULT_MAX_VERSION,
- [Symbol.for("CommonJS")]: 0,
+ DEFAULT_MIN_VERSION,
+ getCiphers,
+ getCurves,
+ parseCertString,
+ SecureContext,
+ Server,
+ TLSSocket,
+};
+
+export {
+ CLIENT_RENEG_LIMIT,
+ CLIENT_RENEG_WINDOW,
connect,
+ convertALPNProtocols,
createConnection,
- Server,
+ createSecureContext,
createServer,
+ DEFAULT_CIPHERS,
+ DEFAULT_ECDH_CURVE,
+ DEFAULT_MAX_VERSION,
+ DEFAULT_MIN_VERSION,
+ getCiphers,
+ getCurves,
+ parseCertString,
+ SecureContext,
+ checkServerIdentity,
+ Server,
+ TLSSocket,
+ exports as default,
};
-
-export default exports;
-
-export { createSecureContext, parseCertString, TLSSocket, SecureContext };
diff --git a/src/js/node/trace_events.ts b/src/js/node/trace_events.ts
index 789c41222..7edcc57d0 100644
--- a/src/js/node/trace_events.ts
+++ b/src/js/node/trace_events.ts
@@ -13,10 +13,12 @@ function ERR_INVALID_ARG_TYPE(name, type, value) {
function createTracing(opts) {
if (typeof opts !== "object" || opts == null) {
+ // @ts-ignore
throw new ERR_INVALID_ARG_TYPE("options", "Object", opts);
}
// TODO: validate categories
+ // @ts-ignore
return new Tracing(opts);
}
diff --git a/src/js/node/url.js b/src/js/node/url.js
index f9a4427ce..bb7093bcc 100644
--- a/src/js/node/url.js
+++ b/src/js/node/url.js
@@ -1,398 +1,852 @@
-// Hardcoded module "node:url"
+/*
+ * 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 { URL: F, URLSearchParams: M, [Symbol.for("Bun.lazy")]: S } = globalThis;
-function it(s) {
- return typeof s == "string";
+
+const { URL, URLSearchParams } = globalThis;
+
+function Url() {
+ this.protocol = null;
+ this.slashes = null;
+ this.auth = null;
+ this.host = null;
+ this.port = null;
+ this.hostname = null;
+ this.hash = null;
+ this.search = null;
+ this.query = null;
+ this.pathname = null;
+ this.path = null;
+ this.href = null;
}
-function D(s) {
- return typeof s == "object" && s !== null;
-}
-function I(s) {
- return s === null;
-}
-function E(s) {
- return s == null;
-}
-function ft(s) {
- return s === void 0;
-}
-function m() {
- (this.protocol = null),
- (this.slashes = null),
- (this.auth = null),
- (this.host = null),
- (this.port = null),
- (this.hostname = null),
- (this.hash = null),
- (this.search = null),
- (this.query = null),
- (this.pathname = null),
- (this.path = null),
- (this.href = null);
-}
-var tt = /^([a-z0-9.+-]+:)/i,
- st = /:[0-9]*$/,
- ht = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
- et = [
- "<",
- ">",
- '"',
- "`",
- " ",
- "\r",
- `
-`,
- " ",
- ],
- rt = ["{", "}", "|", "\\", "^", "`"].concat(et),
- B = ["'"].concat(rt),
- G = ["%", "/", "?", ";", "#"].concat(B),
- J = ["/", "?", "#"],
- ot = 255,
- K = /^[+a-z0-9A-Z_-]{0,63}$/,
- at = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
- nt = { javascript: !0, "javascript:": !0 },
- N = { javascript: !0, "javascript:": !0 },
- R = {
- http: !0,
- https: !0,
- ftp: !0,
- gopher: !0,
- file: !0,
- "http:": !0,
- "https:": !0,
- "ftp:": !0,
- "gopher:": !0,
- "file:": !0,
+
+// Reference: RFC 3986, RFC 1808, RFC 2396
+
+/*
+ * define these here so at least they only have to be
+ * compiled once on the first module load.
+ */
+var protocolPattern = /^([a-z0-9.+-]+:)/i,
+ portPattern = /:[0-9]*$/,
+ // Special case for a simple path URL
+ simplePathPattern = /^(\/\/?(?!\/)[^?\s]*)(\?[^\s]*)?$/,
+ /*
+ * RFC 2396: characters reserved for delimiting URLs.
+ * We actually just auto-escape these.
+ */
+ delims = ["<", ">", '"', "`", " ", "\r", "\n", "\t"],
+ // RFC 2396: characters not allowed for various reasons.
+ unwise = ["{", "}", "|", "\\", "^", "`"].concat(delims),
+ // Allowed by RFCs, but cause of XSS attacks. Always escape these.
+ autoEscape = ["'"].concat(unwise),
+ /*
+ * Characters that are never ever allowed in a hostname.
+ * Note that any invalid chars are also handled, but these
+ * are the ones that are *expected* to be seen, so we fast-path
+ * them.
+ */
+ nonHostChars = ["%", "/", "?", ";", "#"].concat(autoEscape),
+ hostEndingChars = ["/", "?", "#"],
+ hostnameMaxLen = 255,
+ hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
+ hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
+ // protocols that can allow "unsafe" and "unwise" chars.
+ unsafeProtocol = {
+ javascript: true,
+ "javascript:": true,
+ },
+ // protocols that never have a hostname.
+ hostlessProtocol = {
+ javascript: true,
+ "javascript:": true,
},
- Z = {
- parse(s) {
- var r = decodeURIComponent;
- return (s + "")
- .replace(/\+/g, " ")
- .split("&")
- .filter(Boolean)
- .reduce(function (t, o, a) {
- var l = o.split("="),
- f = r(l[0] || ""),
- h = r(l[1] || ""),
- g = t[f];
- return (t[f] = g === void 0 ? h : [].concat(g, h)), t;
- }, {});
- },
- stringify(s) {
- var r = encodeURIComponent;
- return Object.keys(s || {})
- .reduce(function (t, o) {
- return (
- [].concat(s[o]).forEach(function (a) {
- t.push(r(o) + "=" + r(a));
- }),
- t
- );
- }, [])
- .join("&")
- .replace(/\s/g, "+");
- },
+ // protocols that always contain a // bit.
+ slashedProtocol = {
+ http: true,
+ https: true,
+ ftp: true,
+ gopher: true,
+ file: true,
+ "http:": true,
+ "https:": true,
+ "ftp:": true,
+ "gopher:": true,
+ "file:": true,
};
-function A(s, r, t) {
- if (s && D(s) && s instanceof m) return s;
- var o = new m();
- return o.parse(s, r, t), o;
+
+function urlParse(url, parseQueryString, slashesDenoteHost) {
+ if (url && typeof url === "object" && url instanceof Url) {
+ return url;
+ }
+
+ var u = new Url();
+ u.parse(url, parseQueryString, slashesDenoteHost);
+ return u;
}
-m.prototype.parse = function (s, r, t) {
- if (!it(s)) throw new TypeError("Parameter 'url' must be a string, not " + typeof s);
- var o = s.indexOf("?"),
- a = o !== -1 && o < s.indexOf("#") ? "?" : "#",
- l = s.split(a),
- f = /\\/g;
- (l[0] = l[0].replace(f, "/")), (s = l.join(a));
- var h = s;
- if (((h = h.trim()), !t && s.split("#").length === 1)) {
- var g = ht.exec(h);
- if (g)
- return (
- (this.path = h),
- (this.href = h),
- (this.pathname = g[1]),
- g[2]
- ? ((this.search = g[2]),
- r ? (this.query = Z.parse(this.search.substr(1))) : (this.query = this.search.substr(1)))
- : r && ((this.search = ""), (this.query = {})),
- this
- );
- }
- var c = tt.exec(h);
- if (c) {
- c = c[0];
- var v = c.toLowerCase();
- (this.protocol = v), (h = h.substr(c.length));
- }
- if (t || c || h.match(/^\/\/[^@\/]+@[^@\/]+/)) {
- var j = h.substr(0, 2) === "//";
- j && !(c && N[c]) && ((h = h.substr(2)), (this.slashes = !0));
- }
- if (!N[c] && (j || (c && !R[c]))) {
- for (var u = -1, n = 0; n < J.length; n++) {
- var b = h.indexOf(J[n]);
- b !== -1 && (u === -1 || b < u) && (u = b);
+
+Url.prototype.parse = function (url, parseQueryString, slashesDenoteHost) {
+ if (typeof url !== "string") {
+ throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
+ }
+
+ /*
+ * Copy chrome, IE, opera backslash-handling behavior.
+ * Back slashes before the query string get converted to forward slashes
+ * See: https://code.google.com/p/chromium/issues/detail?id=25916
+ */
+ var queryIndex = url.indexOf("?"),
+ splitter = queryIndex !== -1 && queryIndex < url.indexOf("#") ? "?" : "#",
+ uSplit = url.split(splitter),
+ slashRegex = /\\/g;
+ uSplit[0] = uSplit[0].replace(slashRegex, "/");
+ url = uSplit.join(splitter);
+
+ var rest = url;
+
+ /*
+ * trim before proceeding.
+ * This is to support parse stuff like " http://foo.com \n"
+ */
+ rest = rest.trim();
+
+ if (!slashesDenoteHost && url.split("#").length === 1) {
+ // Try fast path regexp
+ var simplePath = simplePathPattern.exec(rest);
+ if (simplePath) {
+ this.path = rest;
+ this.href = rest;
+ this.pathname = simplePath[1];
+ if (simplePath[2]) {
+ this.search = simplePath[2];
+ if (parseQueryString) {
+ this.query = new URLSearchParams(this.search.substr(1)).toJSON();
+ } else {
+ this.query = this.search.substr(1);
+ }
+ } else if (parseQueryString) {
+ this.search = "";
+ this.query = {};
+ }
+ return this;
+ }
+ }
+
+ var proto = protocolPattern.exec(rest);
+ if (proto) {
+ proto = proto[0];
+ var lowerProto = proto.toLowerCase();
+ this.protocol = lowerProto;
+ rest = rest.substr(proto.length);
+ }
+
+ /*
+ * figure out if it's got a host
+ * user@server is *always* interpreted as a hostname, and url
+ * resolution will treat //foo/bar as host=foo,path=bar because that's
+ * how the browser resolves relative URLs.
+ */
+ if (slashesDenoteHost || proto || rest.match(/^\/\/[^@/]+@[^@/]+/)) {
+ var slashes = rest.substr(0, 2) === "//";
+ if (slashes && !(proto && hostlessProtocol[proto])) {
+ rest = rest.substr(2);
+ this.slashes = true;
+ }
+ }
+
+ if (!hostlessProtocol[proto] && (slashes || (proto && !slashedProtocol[proto]))) {
+ /*
+ * there's a hostname.
+ * the first instance of /, ?, ;, or # ends the host.
+ *
+ * If there is an @ in the hostname, then non-host chars *are* allowed
+ * to the left of the last @ sign, unless some host-ending character
+ * comes *before* the @-sign.
+ * URLs are obnoxious.
+ *
+ * ex:
+ * http://a@b@c/ => user:a@b host:c
+ * http://a@b?@c => user:a host:c path:/?@c
+ */
+
+ /*
+ * v0.12 TODO(isaacs): This is not quite how Chrome does things.
+ * Review our test case against browsers more comprehensively.
+ */
+
+ // find the first instance of any hostEndingChars
+ var hostEnd = -1;
+ for (var i = 0; i < hostEndingChars.length; i++) {
+ var hec = rest.indexOf(hostEndingChars[i]);
+ if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {
+ hostEnd = hec;
+ }
+ }
+
+ /*
+ * at this point, either we have an explicit point where the
+ * auth portion cannot go past, or the last @ char is the decider.
+ */
+ var auth, atSign;
+ if (hostEnd === -1) {
+ // atSign can be anywhere.
+ atSign = rest.lastIndexOf("@");
+ } else {
+ /*
+ * atSign must be in auth portion.
+ * http://a@b/c@d => host:b auth:a path:/c@d
+ */
+ atSign = rest.lastIndexOf("@", hostEnd);
+ }
+
+ /*
+ * Now we have a portion which is definitely the auth.
+ * Pull that off.
+ */
+ if (atSign !== -1) {
+ auth = rest.slice(0, atSign);
+ rest = rest.slice(atSign + 1);
+ this.auth = decodeURIComponent(auth);
}
- var P, p;
- u === -1 ? (p = h.lastIndexOf("@")) : (p = h.lastIndexOf("@", u)),
- p !== -1 && ((P = h.slice(0, p)), (h = h.slice(p + 1)), (this.auth = decodeURIComponent(P))),
- (u = -1);
- for (var n = 0; n < G.length; n++) {
- var b = h.indexOf(G[n]);
- b !== -1 && (u === -1 || b < u) && (u = b);
+
+ // the host is the remaining to the left of the first non-host char
+ hostEnd = -1;
+ for (var i = 0; i < nonHostChars.length; i++) {
+ var hec = rest.indexOf(nonHostChars[i]);
+ if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {
+ hostEnd = hec;
+ }
+ }
+ // if we still have not hit it, then the entire thing is a host.
+ if (hostEnd === -1) {
+ hostEnd = rest.length;
}
- u === -1 && (u = h.length),
- (this.host = h.slice(0, u)),
- (h = h.slice(u)),
- this.parseHost(),
- (this.hostname = this.hostname || "");
- var C = this.hostname[0] === "[" && this.hostname[this.hostname.length - 1] === "]";
- if (!C)
- for (var e = this.hostname.split(/\./), n = 0, i = e.length; n < i; n++) {
- var d = e[n];
- if (!!d && !d.match(K)) {
- for (var y = "", x = 0, _ = d.length; x < _; x++) d.charCodeAt(x) > 127 ? (y += "x") : (y += d[x]);
- if (!y.match(K)) {
- var q = e.slice(0, n),
- O = e.slice(n + 1),
- U = d.match(at);
- U && (q.push(U[1]), O.unshift(U[2])),
- O.length && (h = "/" + O.join(".") + h),
- (this.hostname = q.join("."));
+
+ this.host = rest.slice(0, hostEnd);
+ rest = rest.slice(hostEnd);
+
+ // pull out port.
+ this.parseHost();
+
+ /*
+ * we've indicated that there is a hostname,
+ * so even if it's empty, it has to be present.
+ */
+ this.hostname = this.hostname || "";
+
+ /*
+ * if hostname begins with [ and ends with ]
+ * assume that it's an IPv6 address.
+ */
+ var ipv6Hostname = this.hostname[0] === "[" && this.hostname[this.hostname.length - 1] === "]";
+
+ // validate a little.
+ if (!ipv6Hostname) {
+ var hostparts = this.hostname.split(/\./);
+ for (var i = 0, l = hostparts.length; i < l; i++) {
+ var part = hostparts[i];
+ if (!part) {
+ continue;
+ }
+ if (!part.match(hostnamePartPattern)) {
+ var newpart = "";
+ for (var j = 0, k = part.length; j < k; j++) {
+ if (part.charCodeAt(j) > 127) {
+ /*
+ * we replace non-ASCII char with a temporary placeholder
+ * we need this to make sure size of hostname is not
+ * broken by replacing non-ASCII by nothing
+ */
+ newpart += "x";
+ } else {
+ newpart += part[j];
+ }
+ }
+ // we test again with ASCII char only
+ if (!newpart.match(hostnamePartPattern)) {
+ var validParts = hostparts.slice(0, i);
+ var notHost = hostparts.slice(i + 1);
+ var bit = part.match(hostnamePartStart);
+ if (bit) {
+ validParts.push(bit[1]);
+ notHost.unshift(bit[2]);
+ }
+ if (notHost.length) {
+ rest = "/" + notHost.join(".") + rest;
+ }
+ this.hostname = validParts.join(".");
break;
}
}
}
- this.hostname.length > ot ? (this.hostname = "") : (this.hostname = this.hostname.toLowerCase()),
- C || (this.hostname = new F(`https://${this.hostname}`).hostname);
- var w = this.port ? ":" + this.port : "",
- H = this.hostname || "";
- (this.host = H + w),
- (this.href += this.host),
- C && ((this.hostname = this.hostname.substr(1, this.hostname.length - 2)), h[0] !== "/" && (h = "/" + h));
- }
- if (!nt[v])
- for (var n = 0, i = B.length; n < i; n++) {
- var L = B[n];
- if (h.indexOf(L) !== -1) {
- var z = encodeURIComponent(L);
- z === L && (z = escape(L)), (h = h.split(L).join(z));
+ }
+
+ if (this.hostname.length > hostnameMaxLen) {
+ this.hostname = "";
+ } else {
+ // hostnames are always lower case.
+ this.hostname = this.hostname.toLowerCase();
+ }
+
+ if (!ipv6Hostname) {
+ /*
+ * IDNA Support: Returns a punycoded representation of "domain".
+ * It only converts parts of the domain name that
+ * have non-ASCII characters, i.e. it doesn't matter if
+ * you call it with a domain that already is ASCII-only.
+ */
+ this.hostname = new URL("http://" + this.hostname).hostname;
+ }
+
+ var p = this.port ? ":" + this.port : "";
+ var h = this.hostname || "";
+ this.host = h + p;
+ this.href += this.host;
+
+ /*
+ * strip [ and ] from the hostname
+ * the host field still retains them, though
+ */
+ if (ipv6Hostname) {
+ this.hostname = this.hostname.substr(1, this.hostname.length - 2);
+ if (rest[0] !== "/") {
+ rest = "/" + rest;
+ }
+ }
+ }
+
+ /*
+ * now rest is set to the post-host stuff.
+ * chop off any delim chars.
+ */
+ if (!unsafeProtocol[lowerProto]) {
+ /*
+ * First, make 100% sure that any "autoEscape" chars get
+ * escaped, even if encodeURIComponent doesn't think they
+ * need to be.
+ */
+ for (var i = 0, l = autoEscape.length; i < l; i++) {
+ var ae = autoEscape[i];
+ if (rest.indexOf(ae) === -1) {
+ continue;
+ }
+ var esc = encodeURIComponent(ae);
+ if (esc === ae) {
+ esc = escape(ae);
}
+ rest = rest.split(ae).join(esc);
+ }
+ }
+
+ // chop off from the tail first.
+ var hash = rest.indexOf("#");
+ if (hash !== -1) {
+ // got a fragment string.
+ this.hash = rest.substr(hash);
+ rest = rest.slice(0, hash);
+ }
+ var qm = rest.indexOf("?");
+ if (qm !== -1) {
+ this.search = rest.substr(qm);
+ this.query = rest.substr(qm + 1);
+ if (parseQueryString) {
+ this.query = new URLSearchParams(this.query);
}
- var $ = h.indexOf("#");
- $ !== -1 && ((this.hash = h.substr($)), (h = h.slice(0, $)));
- var T = h.indexOf("?");
- if (
- (T !== -1
- ? ((this.search = h.substr(T)),
- (this.query = h.substr(T + 1)),
- r && (this.query = Z.parse(this.query)),
- (h = h.slice(0, T)))
- : r && ((this.search = ""), (this.query = {})),
- h && (this.pathname = h),
- R[v] && this.hostname && !this.pathname && (this.pathname = "/"),
- this.pathname || this.search)
- ) {
- var w = this.pathname || "",
- Q = this.search || "";
- this.path = w + Q;
- }
- return (this.href = this.format()), this;
+ rest = rest.slice(0, qm);
+ } else if (parseQueryString) {
+ // no query string, but parseQueryString still requested
+ this.search = "";
+ this.query = {};
+ }
+ if (rest) {
+ this.pathname = rest;
+ }
+ if (slashedProtocol[lowerProto] && this.hostname && !this.pathname) {
+ this.pathname = "/";
+ }
+
+ // to support http.request
+ if (this.pathname || this.search) {
+ var p = this.pathname || "";
+ var s = this.search || "";
+ this.path = p + s;
+ }
+
+ // finally, reconstruct the href based on what has been validated.
+ this.href = this.format();
+ return this;
};
-function V(s) {
- return it(s) && (s = A(s)), s instanceof m ? s.format() : m.prototype.format.call(s);
+
+// format a parsed object into a url string
+function urlFormat(obj) {
+ /*
+ * ensure it's an object, and not a string url.
+ * If it's an obj, this is a no-op.
+ * this way, you can call url_format() on strings
+ * to clean up potentially wonky urls.
+ */
+ if (typeof obj === "string") {
+ obj = urlParse(obj);
+ }
+ if (!(obj instanceof Url)) {
+ return Url.prototype.format.call(obj);
+ }
+ return obj.format();
}
-m.prototype.format = function () {
- var s = this.auth || "";
- s && ((s = encodeURIComponent(s)), (s = s.replace(/%3A/i, ":")), (s += "@"));
- var r = this.protocol || "",
- t = this.pathname || "",
- o = this.hash || "",
- a = !1,
- l = "";
- this.host
- ? (a = s + this.host)
- : this.hostname &&
- ((a = s + (this.hostname.indexOf(":") === -1 ? this.hostname : "[" + this.hostname + "]")),
- this.port && (a += ":" + this.port)),
- this.query && D(this.query) && Object.keys(this.query).length && (l = Z.stringify(this.query));
- var f = this.search || (l && "?" + l) || "";
- return (
- r && r.substr(-1) !== ":" && (r += ":"),
- this.slashes || ((!r || R[r]) && a !== !1)
- ? ((a = "//" + (a || "")), t && t.charAt(0) !== "/" && (t = "/" + t))
- : a || (a = ""),
- o && o.charAt(0) !== "#" && (o = "#" + o),
- f && f.charAt(0) !== "?" && (f = "?" + f),
- (t = t.replace(/[?#]/g, function (h) {
- return encodeURIComponent(h);
- })),
- (f = f.replace("#", "%23")),
- r + a + t + f + o
- );
+
+Url.prototype.format = function () {
+ var auth = this.auth || "";
+ if (auth) {
+ auth = encodeURIComponent(auth);
+ auth = auth.replace(/%3A/i, ":");
+ auth += "@";
+ }
+
+ var protocol = this.protocol || "",
+ pathname = this.pathname || "",
+ hash = this.hash || "",
+ host = false,
+ query = "";
+
+ if (this.host) {
+ host = auth + this.host;
+ } else if (this.hostname) {
+ host = auth + (this.hostname.indexOf(":") === -1 ? this.hostname : "[" + this.hostname + "]");
+ if (this.port) {
+ host += ":" + this.port;
+ }
+ }
+
+ if (this.query && typeof this.query === "object" && Object.keys(this.query).length) {
+ query = new URLSearchParams(this.query).toString();
+ }
+
+ var search = this.search || (query && "?" + query) || "";
+
+ if (protocol && protocol.substr(-1) !== ":") {
+ protocol += ":";
+ }
+
+ /*
+ * only the slashedProtocols get the //. Not mailto:, xmpp:, etc.
+ * unless they had them to begin with.
+ */
+ if (this.slashes || ((!protocol || slashedProtocol[protocol]) && host !== false)) {
+ host = "//" + (host || "");
+ if (pathname && pathname.charAt(0) !== "/") {
+ pathname = "/" + pathname;
+ }
+ } else if (!host) {
+ host = "";
+ }
+
+ if (hash && hash.charAt(0) !== "#") {
+ hash = "#" + hash;
+ }
+ if (search && search.charAt(0) !== "?") {
+ search = "?" + search;
+ }
+
+ pathname = pathname.replace(/[?#]/g, function (match) {
+ return encodeURIComponent(match);
+ });
+ search = search.replace("#", "%23");
+
+ return protocol + host + pathname + search + hash;
};
-function W(s, r) {
- return A(s, !1, !0).resolve(r);
+
+function urlResolve(source, relative) {
+ return urlParse(source, false, true).resolve(relative);
}
-m.prototype.resolve = function (s) {
- return this.resolveObject(A(s, !1, !0)).format();
+
+Url.prototype.resolve = function (relative) {
+ return this.resolveObject(urlParse(relative, false, true)).format();
};
-function X(s, r) {
- return s ? A(s, !1, !0).resolveObject(r) : r;
+
+function urlResolveObject(source, relative) {
+ if (!source) {
+ return relative;
+ }
+ return urlParse(source, false, true).resolveObject(relative);
}
-(m.prototype.resolveObject = function (s) {
- if (it(s)) {
- var r = new m();
- r.parse(s, !1, !0), (s = r);
- }
- for (var t = new m(), o = Object.keys(this), a = 0; a < o.length; a++) {
- var l = o[a];
- t[l] = this[l];
- }
- if (((t.hash = s.hash), s.href === "")) return (t.href = t.format()), t;
- if (s.slashes && !s.protocol) {
- for (var f = Object.keys(s), h = 0; h < f.length; h++) {
- var g = f[h];
- g !== "protocol" && (t[g] = s[g]);
+
+Url.prototype.resolveObject = function (relative) {
+ if (typeof relative === "string") {
+ var rel = new Url();
+ rel.parse(relative, false, true);
+ relative = rel;
+ }
+
+ var result = new Url();
+ var tkeys = Object.keys(this);
+ for (var tk = 0; tk < tkeys.length; tk++) {
+ var tkey = tkeys[tk];
+ result[tkey] = this[tkey];
+ }
+
+ /*
+ * hash is always overridden, no matter what.
+ * even href="" will remove it.
+ */
+ result.hash = relative.hash;
+
+ // if the relative url is empty, then there's nothing left to do here.
+ if (relative.href === "") {
+ result.href = result.format();
+ return result;
+ }
+
+ // hrefs like //foo/bar always cut to the protocol.
+ if (relative.slashes && !relative.protocol) {
+ // take everything except the protocol from relative
+ var rkeys = Object.keys(relative);
+ for (var rk = 0; rk < rkeys.length; rk++) {
+ var rkey = rkeys[rk];
+ if (rkey !== "protocol") {
+ result[rkey] = relative[rkey];
+ }
}
- return R[t.protocol] && t.hostname && !t.pathname && (t.path = t.pathname = "/"), (t.href = t.format()), t;
+
+ // urlParse appends trailing / to urls like http://www.example.com
+ if (slashedProtocol[result.protocol] && result.hostname && !result.pathname) {
+ result.pathname = "/";
+ result.path = result.pathname;
+ }
+
+ result.href = result.format();
+ return result;
}
- if (s.protocol && s.protocol !== t.protocol) {
- if (!R[s.protocol]) {
- for (var c = Object.keys(s), v = 0; v < c.length; v++) {
- var j = c[v];
- t[j] = s[j];
+
+ if (relative.protocol && relative.protocol !== result.protocol) {
+ /*
+ * if it's a known url protocol, then changing
+ * the protocol does weird things
+ * first, if it's not file:, then we MUST have a host,
+ * and if there was a path
+ * to begin with, then we MUST have a path.
+ * if it is file:, then the host is dropped,
+ * because that's known to be hostless.
+ * anything else is assumed to be absolute.
+ */
+ if (!slashedProtocol[relative.protocol]) {
+ var keys = Object.keys(relative);
+ for (var v = 0; v < keys.length; v++) {
+ var k = keys[v];
+ result[k] = relative[k];
}
- return (t.href = t.format()), t;
+ result.href = result.format();
+ return result;
}
- if (((t.protocol = s.protocol), !s.host && !N[s.protocol])) {
- for (var i = (s.pathname || "").split("/"); i.length && !(s.host = i.shift()); );
- s.host || (s.host = ""),
- s.hostname || (s.hostname = ""),
- i[0] !== "" && i.unshift(""),
- i.length < 2 && i.unshift(""),
- (t.pathname = i.join("/"));
- } else t.pathname = s.pathname;
- if (
- ((t.search = s.search),
- (t.query = s.query),
- (t.host = s.host || ""),
- (t.auth = s.auth),
- (t.hostname = s.hostname || s.host),
- (t.port = s.port),
- t.pathname || t.search)
- ) {
- var u = t.pathname || "",
- n = t.search || "";
- t.path = u + n;
+
+ result.protocol = relative.protocol;
+ if (!relative.host && !hostlessProtocol[relative.protocol]) {
+ var relPath = (relative.pathname || "").split("/");
+ while (relPath.length && !(relative.host = relPath.shift())) {}
+ if (!relative.host) {
+ relative.host = "";
+ }
+ if (!relative.hostname) {
+ relative.hostname = "";
+ }
+ if (relPath[0] !== "") {
+ relPath.unshift("");
+ }
+ if (relPath.length < 2) {
+ relPath.unshift("");
+ }
+ result.pathname = relPath.join("/");
+ } else {
+ result.pathname = relative.pathname;
}
- return (t.slashes = t.slashes || s.slashes), (t.href = t.format()), t;
- }
- var b = t.pathname && t.pathname.charAt(0) === "/",
- P = s.host || (s.pathname && s.pathname.charAt(0) === "/"),
- p = P || b || (t.host && s.pathname),
- C = p,
- e = (t.pathname && t.pathname.split("/")) || [],
- i = (s.pathname && s.pathname.split("/")) || [],
- d = t.protocol && !R[t.protocol];
- if (
- (d &&
- ((t.hostname = ""),
- (t.port = null),
- t.host && (e[0] === "" ? (e[0] = t.host) : e.unshift(t.host)),
- (t.host = ""),
- s.protocol &&
- ((s.hostname = null),
- (s.port = null),
- s.host && (i[0] === "" ? (i[0] = s.host) : i.unshift(s.host)),
- (s.host = null)),
- (p = p && (i[0] === "" || e[0] === ""))),
- P)
- )
- (t.host = s.host || s.host === "" ? s.host : t.host),
- (t.hostname = s.hostname || s.hostname === "" ? s.hostname : t.hostname),
- (t.search = s.search),
- (t.query = s.query),
- (e = i);
- else if (i.length) e || (e = []), e.pop(), (e = e.concat(i)), (t.search = s.search), (t.query = s.query);
- else if (!E(s.search)) {
- if (d) {
- t.hostname = t.host = e.shift();
- var y = t.host && t.host.indexOf("@") > 0 ? t.host.split("@") : !1;
- y && ((t.auth = y.shift()), (t.host = t.hostname = y.shift()));
+ result.search = relative.search;
+ result.query = relative.query;
+ result.host = relative.host || "";
+ result.auth = relative.auth;
+ result.hostname = relative.hostname || relative.host;
+ result.port = relative.port;
+ // to support http.request
+ if (result.pathname || result.search) {
+ var p = result.pathname || "";
+ var s = result.search || "";
+ result.path = p + s;
}
- return (
- (t.search = s.search),
- (t.query = s.query),
- (!I(t.pathname) || !I(t.search)) && (t.path = (t.pathname ? t.pathname : "") + (t.search ? t.search : "")),
- (t.href = t.format()),
- t
- );
- }
- if (!e.length)
- return (t.pathname = null), t.search ? (t.path = "/" + t.search) : (t.path = null), (t.href = t.format()), t;
- for (
- var x = e.slice(-1)[0],
- _ = ((t.host || s.host || e.length > 1) && (x === "." || x === "..")) || x === "",
- q = 0,
- O = e.length;
- O >= 0;
- O--
- )
- (x = e[O]), x === "." ? e.splice(O, 1) : x === ".." ? (e.splice(O, 1), q++) : q && (e.splice(O, 1), q--);
- if (!p && !C) for (; q--; q) e.unshift("..");
- p && e[0] !== "" && (!e[0] || e[0].charAt(0) !== "/") && e.unshift(""),
- _ && e.join("/").substr(-1) !== "/" && e.push("");
- var U = e[0] === "" || (e[0] && e[0].charAt(0) === "/");
- if (d) {
- t.hostname = t.host = U ? "" : e.length ? e.shift() : "";
- var y = t.host && t.host.indexOf("@") > 0 ? t.host.split("@") : !1;
- y && ((t.auth = y.shift()), (t.host = t.hostname = y.shift()));
- }
- return (
- (p = p || (t.host && e.length)),
- p && !U && e.unshift(""),
- e.length ? (t.pathname = e.join("/")) : ((t.pathname = null), (t.path = null)),
- (!I(t.pathname) || !I(t.search)) && (t.path = (t.pathname ? t.pathname : "") + (t.search ? t.search : "")),
- (t.auth = s.auth || t.auth),
- (t.slashes = t.slashes || s.slashes),
- (t.href = t.format()),
- t
- );
-}),
- (m.prototype.parseHost = function () {
- var s = this.host,
- r = st.exec(s);
- r && ((r = r[0]), r !== ":" && (this.port = r.substr(1)), (s = s.substr(0, s.length - r.length))),
- s && (this.hostname = s);
- });
-var Y, k;
-S && ((Y = S("pathToFileURL")), (k = S("fileURLToPath")));
-var ut = {
- parse: A,
- resolve: W,
- resolveObject: X,
- format: V,
- Url: m,
- pathToFileURL: Y,
- fileURLToPath: k,
- URL: F,
- URLSearchParams: M,
+ result.slashes = result.slashes || relative.slashes;
+ result.href = result.format();
+ return result;
+ }
+
+ var isSourceAbs = result.pathname && result.pathname.charAt(0) === "/",
+ isRelAbs = relative.host || (relative.pathname && relative.pathname.charAt(0) === "/"),
+ mustEndAbs = isRelAbs || isSourceAbs || (result.host && relative.pathname),
+ removeAllDots = mustEndAbs,
+ srcPath = (result.pathname && result.pathname.split("/")) || [],
+ relPath = (relative.pathname && relative.pathname.split("/")) || [],
+ psychotic = result.protocol && !slashedProtocol[result.protocol];
+
+ /*
+ * if the url is a non-slashed url, then relative
+ * links like ../.. should be able
+ * to crawl up to the hostname, as well. This is strange.
+ * result.protocol has already been set by now.
+ * Later on, put the first path part into the host field.
+ */
+ if (psychotic) {
+ result.hostname = "";
+ result.port = null;
+ if (result.host) {
+ if (srcPath[0] === "") {
+ srcPath[0] = result.host;
+ } else {
+ srcPath.unshift(result.host);
+ }
+ }
+ result.host = "";
+ if (relative.protocol) {
+ relative.hostname = null;
+ relative.port = null;
+ if (relative.host) {
+ if (relPath[0] === "") {
+ relPath[0] = relative.host;
+ } else {
+ relPath.unshift(relative.host);
+ }
+ }
+ relative.host = null;
+ }
+ mustEndAbs = mustEndAbs && (relPath[0] === "" || srcPath[0] === "");
+ }
+
+ if (isRelAbs) {
+ // it's absolute.
+ result.host = relative.host || relative.host === "" ? relative.host : result.host;
+ result.hostname = relative.hostname || relative.hostname === "" ? relative.hostname : result.hostname;
+ result.search = relative.search;
+ result.query = relative.query;
+ srcPath = relPath;
+ // fall through to the dot-handling below.
+ } else if (relPath.length) {
+ /*
+ * it's relative
+ * throw away the existing file, and take the new path instead.
+ */
+ if (!srcPath) {
+ srcPath = [];
+ }
+ srcPath.pop();
+ srcPath = srcPath.concat(relPath);
+ result.search = relative.search;
+ result.query = relative.query;
+ } else if (relative.search != null) {
+ /*
+ * just pull out the search.
+ * like href='?foo'.
+ * Put this after the other two cases because it simplifies the booleans
+ */
+ if (psychotic) {
+ result.host = srcPath.shift();
+ result.hostname = result.host;
+ /*
+ * occationaly the auth can get stuck only in host
+ * this especially happens in cases like
+ * url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+ */
+ var authInHost = result.host && result.host.indexOf("@") > 0 ? result.host.split("@") : false;
+ if (authInHost) {
+ result.auth = authInHost.shift();
+ result.hostname = authInHost.shift();
+ result.host = result.hostname;
+ }
+ }
+ result.search = relative.search;
+ result.query = relative.query;
+ // to support http.request
+ if (result.pathname !== null || result.search !== null) {
+ result.path = (result.pathname ? result.pathname : "") + (result.search ? result.search : "");
+ }
+ result.href = result.format();
+ return result;
+ }
+
+ if (!srcPath.length) {
+ /*
+ * no path at all. easy.
+ * we've already handled the other stuff above.
+ */
+ result.pathname = null;
+ // to support http.request
+ if (result.search) {
+ result.path = "/" + result.search;
+ } else {
+ result.path = null;
+ }
+ result.href = result.format();
+ return result;
+ }
+
+ /*
+ * if a url ENDs in . or .., then it must get a trailing slash.
+ * however, if it ends in anything else non-slashy,
+ * then it must NOT get a trailing slash.
+ */
+ var last = srcPath.slice(-1)[0];
+ var hasTrailingSlash =
+ ((result.host || relative.host || srcPath.length > 1) && (last === "." || last === "..")) || last === "";
+
+ /*
+ * strip single dots, resolve double dots to parent dir
+ * if the path tries to go above the root, `up` ends up > 0
+ */
+ var up = 0;
+ for (var i = srcPath.length; i >= 0; i--) {
+ last = srcPath[i];
+ if (last === ".") {
+ srcPath.splice(i, 1);
+ } else if (last === "..") {
+ srcPath.splice(i, 1);
+ up++;
+ } else if (up) {
+ srcPath.splice(i, 1);
+ up--;
+ }
+ }
+
+ // if the path is allowed to go above the root, restore leading ..s
+ if (!mustEndAbs && !removeAllDots) {
+ for (; up--; up) {
+ srcPath.unshift("..");
+ }
+ }
+
+ if (mustEndAbs && srcPath[0] !== "" && (!srcPath[0] || srcPath[0].charAt(0) !== "/")) {
+ srcPath.unshift("");
+ }
+
+ if (hasTrailingSlash && srcPath.join("/").substr(-1) !== "/") {
+ srcPath.push("");
+ }
+
+ var isAbsolute = srcPath[0] === "" || (srcPath[0] && srcPath[0].charAt(0) === "/");
+
+ // put the host back
+ if (psychotic) {
+ result.hostname = isAbsolute ? "" : srcPath.length ? srcPath.shift() : "";
+ result.host = result.hostname;
+ /*
+ * occationaly the auth can get stuck only in host
+ * this especially happens in cases like
+ * url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+ */
+ var authInHost = result.host && result.host.indexOf("@") > 0 ? result.host.split("@") : false;
+ if (authInHost) {
+ result.auth = authInHost.shift();
+ result.hostname = authInHost.shift();
+ result.host = result.hostname;
+ }
+ }
+
+ mustEndAbs = mustEndAbs || (result.host && srcPath.length);
+
+ if (mustEndAbs && !isAbsolute) {
+ srcPath.unshift("");
+ }
+
+ if (srcPath.length > 0) {
+ result.pathname = srcPath.join("/");
+ } else {
+ result.pathname = null;
+ result.path = null;
+ }
+
+ // to support request.http
+ if (result.pathname !== null || result.search !== null) {
+ result.path = (result.pathname ? result.pathname : "") + (result.search ? result.search : "");
+ }
+ result.auth = relative.auth || result.auth;
+ result.slashes = result.slashes || relative.slashes;
+ result.href = result.format();
+ return result;
+};
+
+Url.prototype.parseHost = function () {
+ var host = this.host;
+ var port = portPattern.exec(host);
+ if (port) {
+ port = port[0];
+ if (port !== ":") {
+ this.port = port.substr(1);
+ }
+ host = host.substr(0, host.length - port.length);
+ }
+ if (host) {
+ this.hostname = host;
+ }
+};
+function urlToHttpOptions(url) {
+ const options = {
+ 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;
+}
+
+const lazy = globalThis[Symbol.for("Bun.lazy")];
+const pathToFileURL = lazy("pathToFileURL");
+const fileURLToPath = lazy("fileURLToPath");
+const defaultObject = {
+ parse: urlParse,
+ resolve: urlResolve,
+ resolveObject: urlResolveObject,
+ format: urlFormat,
+ Url,
+ URLSearchParams,
+ URL,
+ pathToFileURL,
+ fileURLToPath,
+ urlToHttpOptions,
+ [Symbol.for("CommonJS")]: 0,
};
-("use strict");
+
export {
- F as URL,
- M as URLSearchParams,
- m as Url,
- ut as default,
- k as fileURLToPath,
- V as format,
- A as parse,
- Y as pathToFileURL,
- W as resolve,
- X as resolveObject,
+ defaultObject as default,
+ urlParse as parse,
+ urlResolve as resolve,
+ urlResolveObject as resolveObject,
+ urlFormat as format,
+ Url,
+ URLSearchParams,
+ URL,
+ pathToFileURL,
+ fileURLToPath,
+ urlToHttpOptions,
};
diff --git a/src/js/node/util.js b/src/js/node/util.js
index 282f4b371..2ec4aadb9 100644
--- a/src/js/node/util.js
+++ b/src/js/node/util.js
@@ -1,4 +1,11 @@
// Hardcoded module "node:util"
+import * as types from "node:util/types";
+export { default as types } from "node:util/types";
+
+var cjs_exports = {};
+
+export default cjs_exports;
+
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) =>
function __require() {
@@ -17,6 +24,10 @@ export function isBuffer(value) {
);
}
+function isFunction(value) {
+ return typeof value === "function";
+}
+
// node_modules/inherits/inherits_browser.js
var require_inherits_browser = __commonJS({
"node_modules/inherits/inherits_browser.js"(exports, module2) {
@@ -35,9 +46,6 @@ var require_inherits_browser = __commonJS({
});
const deepEquals = Bun.deepEquals;
const isDeepStrictEqual = (a, b) => deepEquals(a, b, true);
-const exports = {
- isDeepStrictEqual,
-};
var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
var formatRegExp = /%[sdj%]/g;
function format(f) {
@@ -78,21 +86,19 @@ function format(f) {
}
return str;
}
-exports.format = format;
-function deprecate(fn, msg) {
- if (typeof process !== "undefined" && process.noDeprecation === true) {
+
+function deprecate(fn, msg, code) {
+ if (process.noDeprecation === true) {
return fn;
}
- if (typeof process === "undefined") {
- return function () {
- return exports.deprecate(fn, msg).apply(this, arguments);
- };
- }
+
var warned = false;
function deprecated() {
if (!warned) {
if (process.throwDeprecation) {
- throw new Error(msg);
+ var err = new Error(msg);
+ if (code) err.code = code;
+ throw err;
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
@@ -104,7 +110,7 @@ function deprecate(fn, msg) {
}
return deprecated;
}
-exports.deprecate = deprecate;
+
var debugs = {};
var debugEnvRegex = /^$/;
if (process.env.NODE_DEBUG) {
@@ -123,7 +129,7 @@ function debuglog(set) {
if (debugEnvRegex.test(set)) {
var pid = process.pid;
debugs[set] = function () {
- var msg = exports.format.apply(exports, arguments);
+ var msg = format.apply(cjs_exports, arguments);
console.error("%s %d: %s", set, pid, msg);
};
} else {
@@ -132,7 +138,6 @@ function debuglog(set) {
}
return debugs[set];
}
-exports.debuglog = debuglog;
function inspect(obj, opts) {
var ctx = {
seen: [],
@@ -143,7 +148,7 @@ function inspect(obj, opts) {
if (isBoolean(opts)) {
ctx.showHidden = opts;
} else if (opts) {
- exports._extend(ctx, opts);
+ _extend(ctx, opts);
}
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
@@ -152,7 +157,6 @@ function inspect(obj, opts) {
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
-exports.inspect = inspect;
inspect.colors = {
bold: [1, 22],
italic: [3, 23],
@@ -201,7 +205,7 @@ function formatValue(ctx, value, recurseTimes) {
ctx.customInspect &&
value &&
isFunction(value.inspect) &&
- value.inspect !== exports.inspect &&
+ value.inspect !== inspect &&
!(value.constructor && value.constructor.prototype === value)
) {
var ret = value.inspect(recurseTimes, ctx);
@@ -388,51 +392,42 @@ function reduceToSingleString(output, base, braces) {
}
return braces[0] + base + " " + output.join(", ") + " " + braces[1];
}
-const types = import.meta.require("node:util/types");
-exports.types = types;
+
function isArray(ar) {
return Array.isArray(ar);
}
-exports.isArray = isArray;
+
function isBoolean(arg) {
return typeof arg === "boolean";
}
-exports.isBoolean = isBoolean;
+
function isNull(arg) {
return arg === null;
}
-exports.isNull = isNull;
+
function isNullOrUndefined(arg) {
return arg == null;
}
-exports.isNullOrUndefined = isNullOrUndefined;
+
function isNumber(arg) {
return typeof arg === "number";
}
-exports.isNumber = isNumber;
+
function isString(arg) {
return typeof arg === "string";
}
-exports.isString = isString;
function isSymbol(arg) {
return typeof arg === "symbol";
}
-exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
-exports.isUndefined = isUndefined;
-var isRegExp = (exports.isRegExp = exports.types.isRegExp);
+var isRegExp = types.isRegExp;
function isObject(arg) {
return typeof arg === "object" && arg !== null;
}
-exports.isObject = isObject;
-var isDate = (exports.isDate = exports.types.isDate);
-var isError = (exports.isError = exports.types.isNativeError);
-function isFunction(arg) {
- return typeof arg === "function";
-}
-var isFunction = (exports.isFunction = isFunction);
+var isDate = types.isDate;
+var isError = types.isNativeError;
function isPrimitive(arg) {
return (
arg === null ||
@@ -443,8 +438,6 @@ function isPrimitive(arg) {
typeof arg === "undefined"
);
}
-exports.isPrimitive = isPrimitive;
-exports.isBuffer = isBuffer;
function pad(n) {
return n < 10 ? "0" + n.toString(10) : n.toString(10);
}
@@ -454,11 +447,11 @@ function timestamp() {
var time = [pad(d.getHours()), pad(d.getMinutes()), pad(d.getSeconds())].join(":");
return [d.getDate(), months[d.getMonth()], time].join(" ");
}
-var log = (exports.log = function () {
- console.log("%s - %s", timestamp(), exports.format.apply(exports, arguments));
-});
-var inherits = (exports.inherits = require_inherits_browser());
-var _extend = (exports._extend = function (origin, add) {
+var log = function log() {
+ console.log("%s - %s", timestamp(), format.apply(cjs_exports, arguments));
+};
+var inherits = (inherits = require_inherits_browser());
+var _extend = function (origin, add) {
if (!add || !isObject(add)) return origin;
var keys = Object.keys(add);
var i = keys.length;
@@ -466,12 +459,12 @@ var _extend = (exports._extend = function (origin, add) {
origin[keys[i]] = add[keys[i]];
}
return origin;
-});
+};
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
var kCustomPromisifiedSymbol = Symbol.for("util.promisify.custom");
-var promisify = (exports.promisify = function promisify(original) {
+var promisify = function promisify(original) {
if (typeof original !== "function") throw new TypeError('The "original" argument must be of type Function');
if (kCustomPromisifiedSymbol && original[kCustomPromisifiedSymbol]) {
var fn = original[kCustomPromisifiedSymbol];
@@ -519,12 +512,13 @@ var promisify = (exports.promisify = function promisify(original) {
configurable: true,
});
return Object.defineProperties(fn, getOwnPropertyDescriptors(original));
-});
-exports.promisify.custom = kCustomPromisifiedSymbol;
+};
+promisify.custom = kCustomPromisifiedSymbol;
function callbackifyOnRejected(reason, cb) {
if (!reason) {
var newReason = new Error("Promise was rejected with a falsy value");
newReason.reason = reason;
+ newReason.code = "ERR_FALSY_VALUE_REJECTION";
reason = newReason;
}
return cb(reason);
@@ -545,10 +539,10 @@ function callbackify(original) {
};
original.apply(this, args).then(
function (ret) {
- process.nextTick(cb, null, null, ret);
+ process.nextTick(cb, null, ret);
},
function (rej) {
- process.nextTick(callbackifyOnRejected, null, rej, cb);
+ process.nextTick(callbackifyOnRejected, rej, cb);
},
);
}
@@ -556,11 +550,44 @@ function callbackify(original) {
Object.defineProperties(callbackified, getOwnPropertyDescriptors(original));
return callbackified;
}
-exports.callbackify = callbackify;
-export var TextDecoder = (exports.TextDecoder = globalThis.TextDecoder);
-export var TextEncoder = (exports.TextEncoder = globalThis.TextEncoder);
-exports[Symbol.for("CommonJS")] = 0;
-export default exports;
+export var TextDecoder = globalThis.TextDecoder;
+export var TextEncoder = globalThis.TextEncoder;
+var toUSVString = input => {
+ return (input + "").toWellFormed();
+};
+
+Object.assign(cjs_exports, {
+ format,
+ deprecate,
+ debuglog,
+ _extend,
+ inspect,
+ types,
+ isArray,
+ isBoolean,
+ isNull,
+ isNullOrUndefined,
+ isNumber,
+ isString,
+ isSymbol,
+ isUndefined,
+ isRegExp,
+ isObject,
+ isDate,
+ isFunction,
+ isError,
+ isPrimitive,
+ isBuffer,
+ log,
+ inherits,
+ toUSVString,
+ promisify,
+ callbackify,
+ isDeepStrictEqual,
+ TextDecoder,
+ TextEncoder,
+ [Symbol.for("CommonJS")]: 0,
+});
export {
format,
@@ -586,4 +613,5 @@ export {
promisify,
callbackify,
isDeepStrictEqual,
+ toUSVString,
};
diff --git a/src/js/node/zlib.js b/src/js/node/zlib.js
index 1414f4664..77a9e8089 100644
--- a/src/js/node/zlib.js
+++ b/src/js/node/zlib.js
@@ -3,6 +3,41 @@
// This is a very slow module!
// It should really be fixed. It will show up in benchmarking. It also loads
// slowly. We need to fix it!
+import { default as assert } from "node:assert";
+import * as AssertModule from "node:assert";
+import * as BufferModule from "node:buffer";
+import * as StreamModule from "node:stream";
+import * as Util from "node:util";
+
+export var Deflate,
+ Inflate,
+ Gzip,
+ Gunzip,
+ DeflateRaw,
+ InflateRaw,
+ Unzip,
+ createDeflate,
+ createInflate,
+ createDeflateRaw,
+ createInflateRaw,
+ createGzip,
+ createGunzip,
+ createUnzip,
+ deflate,
+ deflateSync,
+ gzip,
+ gzipSync,
+ deflateRaw,
+ deflateRawSync,
+ unzip,
+ unzipSync,
+ inflate,
+ inflateSync,
+ gunzip,
+ gunzipSync,
+ inflateRaw,
+ inflateRawSync,
+ constants;
var __create = Object.create;
var __defProp = Object.defineProperty;
@@ -38,8 +73,6 @@ var __toESM = (mod, isNodeMode, target) => (
);
var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
-const require = id => import.meta.require(id);
-
// node_modules/pako/lib/zlib/zstream.js
var require_zstream = __commonJS({
"node_modules/pako/lib/zlib/zstream.js"(exports, module2) {
@@ -3593,7 +3626,7 @@ var require_constants = __commonJS({
var require_binding = __commonJS({
"node_modules/browserify-zlib/lib/binding.js"(exports) {
"use strict";
- var assert = require("assert");
+
var Zstream = require_zstream();
var zlib_deflate = require_deflate();
var zlib_inflate = require_inflate();
@@ -3937,12 +3970,12 @@ var require_binding = __commonJS({
var require_lib = __commonJS({
"node_modules/browserify-zlib/lib/index.js"(exports) {
"use strict";
- var Buffer2 = require("buffer").Buffer;
- var Transform = require("stream").Transform;
+ var Buffer2 = BufferModule.Buffer;
+ var Transform = StreamModule.Transform;
var binding = require_binding();
- var util = require("util");
- var assert = require("assert").ok;
- var kMaxLength = require("buffer").kMaxLength;
+ var util = Util;
+ var assert = AssertModule.ok;
+ var kMaxLength = BufferModule.kMaxLength;
var kRangeErrorMessage =
"Cannot create final Buffer. It would be larger than 0x" + kMaxLength.toString(16) + " bytes";
binding.Z_MIN_WINDOWBITS = 8;
@@ -4437,36 +4470,35 @@ var require_lib = __commonJS({
// zlib.js
var zlib_exports = require_lib();
zlib_exports[Symbol.for("CommonJS")] = 0;
+
export default zlib_exports;
-export var {
- Deflate,
- Inflate,
- Gzip,
- Gunzip,
- DeflateRaw,
- InflateRaw,
- Unzip,
- createDeflate,
- createInflate,
- createDeflateRaw,
- createInflateRaw,
- createGzip,
- createGunzip,
- createUnzip,
- deflate,
- deflateSync,
- gzip,
- gzipSync,
- deflateRaw,
- deflateRawSync,
- unzip,
- unzipSync,
- inflate,
- inflateSync,
- gunzip,
- gunzipSync,
- inflateRaw,
- inflateRawSync,
- constants,
-} = zlib_exports;
+Deflate = zlib_exports.Deflate;
+Inflate = zlib_exports.Inflate;
+Gzip = zlib_exports.Gzip;
+Gunzip = zlib_exports.Gunzip;
+DeflateRaw = zlib_exports.DeflateRaw;
+InflateRaw = zlib_exports.InflateRaw;
+Unzip = zlib_exports.Unzip;
+createDeflate = zlib_exports.createDeflate;
+createInflate = zlib_exports.createInflate;
+createDeflateRaw = zlib_exports.createDeflateRaw;
+createInflateRaw = zlib_exports.createInflateRaw;
+createGzip = zlib_exports.createGzip;
+createGunzip = zlib_exports.createGunzip;
+createUnzip = zlib_exports.createUnzip;
+deflate = zlib_exports.deflate;
+deflateSync = zlib_exports.deflateSync;
+gzip = zlib_exports.gzip;
+gzipSync = zlib_exports.gzipSync;
+deflateRaw = zlib_exports.deflateRaw;
+deflateRawSync = zlib_exports.deflateRawSync;
+unzip = zlib_exports.unzip;
+unzipSync = zlib_exports.unzipSync;
+inflate = zlib_exports.inflate;
+inflateSync = zlib_exports.inflateSync;
+gunzip = zlib_exports.gunzip;
+gunzipSync = zlib_exports.gunzipSync;
+inflateRaw = zlib_exports.inflateRaw;
+inflateRawSync = zlib_exports.inflateRawSync;
+constants = zlib_exports.constants;