import { RequestController, createServerErrorResponse, emitAsync, handleRequest, isPropertyAccessible } from "./chunk-5KMS5CTP.mjs"; import { FetchResponse, INTERNAL_REQUEST_ID_HEADER_NAME, Interceptor, createRequestId } from "./chunk-I7HQIBT7.mjs"; // src/interceptors/ClientRequest/index.ts import http2 from "http"; import https2 from "https"; // src/interceptors/ClientRequest/MockHttpSocket.ts import net2 from "net"; import { HTTPParser } from "_http_common"; import { STATUS_CODES, IncomingMessage, ServerResponse } from "http"; import { Readable } from "stream"; import { invariant } from "outvariant"; // src/interceptors/Socket/MockSocket.ts import net from "net"; // src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts function normalizeSocketWriteArgs(args) { const normalized = [args[0], void 0, void 0]; if (typeof args[1] === "string") { normalized[1] = args[1]; } else if (typeof args[1] === "function") { normalized[2] = args[1]; } if (typeof args[2] === "function") { normalized[2] = args[2]; } return normalized; } // src/interceptors/Socket/MockSocket.ts var MockSocket = class extends net.Socket { constructor(options) { super(); this.options = options; this.connecting = false; this.connect(); this._final = (callback) => { callback(null); }; } connect() { this.connecting = true; return this; } write(...args) { const [chunk, encoding, callback] = normalizeSocketWriteArgs( args ); this.options.write(chunk, encoding, callback); return true; } end(...args) { const [chunk, encoding, callback] = normalizeSocketWriteArgs( args ); this.options.write(chunk, encoding, callback); return super.end.apply(this, args); } push(chunk, encoding) { this.options.read(chunk, encoding); return super.push(chunk, encoding); } }; // src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts function baseUrlFromConnectionOptions(options) { if ("href" in options) { return new URL(options.href); } const protocol = options.port === 443 ? "https:" : "http:"; const host = options.host; const url = new URL(`${protocol}//${host}`); if (options.port) { url.port = options.port.toString(); } if (options.path) { url.pathname = options.path; } if (options.auth) { const [username, password] = options.auth.split(":"); url.username = username; url.password = password; } return url; } // src/interceptors/ClientRequest/utils/recordRawHeaders.ts var kRawHeaders = Symbol("kRawHeaders"); var kRestorePatches = Symbol("kRestorePatches"); function recordRawHeader(headers, args, behavior) { ensureRawHeadersSymbol(headers, []); const rawHeaders = Reflect.get(headers, kRawHeaders); if (behavior === "set") { for (let index = rawHeaders.length - 1; index >= 0; index--) { if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) { rawHeaders.splice(index, 1); } } } rawHeaders.push(args); } function ensureRawHeadersSymbol(headers, rawHeaders) { if (Reflect.has(headers, kRawHeaders)) { return; } defineRawHeadersSymbol(headers, rawHeaders); } function defineRawHeadersSymbol(headers, rawHeaders) { Object.defineProperty(headers, kRawHeaders, { value: rawHeaders, enumerable: false, // Mark the symbol as configurable so its value can be overridden. // Overrides happen when merging raw headers from multiple sources. // E.g. new Request(new Request(url, { headers }), { headers }) configurable: true }); } function recordRawFetchHeaders() { if (Reflect.get(Headers, kRestorePatches)) { return Reflect.get(Headers, kRestorePatches); } const { Headers: OriginalHeaders, Request: OriginalRequest, Response: OriginalResponse } = globalThis; const { set, append, delete: headersDeleteMethod } = Headers.prototype; Object.defineProperty(Headers, kRestorePatches, { value: () => { Headers.prototype.set = set; Headers.prototype.append = append; Headers.prototype.delete = headersDeleteMethod; globalThis.Headers = OriginalHeaders; globalThis.Request = OriginalRequest; globalThis.Response = OriginalResponse; Reflect.deleteProperty(Headers, kRestorePatches); }, enumerable: false, /** * @note Mark this property as configurable * so we can delete it using `Reflect.delete` during cleanup. */ configurable: true }); Object.defineProperty(globalThis, "Headers", { enumerable: true, writable: true, value: new Proxy(Headers, { construct(target, args, newTarget) { const headersInit = args[0] || []; if (headersInit instanceof Headers && Reflect.has(headersInit, kRawHeaders)) { const headers2 = Reflect.construct( target, [Reflect.get(headersInit, kRawHeaders)], newTarget ); ensureRawHeadersSymbol(headers2, [ /** * @note Spread the retrieved headers to clone them. * This prevents multiple Headers instances from pointing * at the same internal "rawHeaders" array. */ ...Reflect.get(headersInit, kRawHeaders) ]); return headers2; } const headers = Reflect.construct(target, args, newTarget); if (!Reflect.has(headers, kRawHeaders)) { const rawHeadersInit = Array.isArray(headersInit) ? headersInit : Object.entries(headersInit); ensureRawHeadersSymbol(headers, rawHeadersInit); } return headers; } }) }); Headers.prototype.set = new Proxy(Headers.prototype.set, { apply(target, thisArg, args) { recordRawHeader(thisArg, args, "set"); return Reflect.apply(target, thisArg, args); } }); Headers.prototype.append = new Proxy(Headers.prototype.append, { apply(target, thisArg, args) { recordRawHeader(thisArg, args, "append"); return Reflect.apply(target, thisArg, args); } }); Headers.prototype.delete = new Proxy(Headers.prototype.delete, { apply(target, thisArg, args) { const rawHeaders = Reflect.get(thisArg, kRawHeaders); if (rawHeaders) { for (let index = rawHeaders.length - 1; index >= 0; index--) { if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) { rawHeaders.splice(index, 1); } } } return Reflect.apply(target, thisArg, args); } }); Object.defineProperty(globalThis, "Request", { enumerable: true, writable: true, value: new Proxy(Request, { construct(target, args, newTarget) { const request = Reflect.construct(target, args, newTarget); const inferredRawHeaders = []; if (typeof args[0] === "object" && args[0].headers != null) { inferredRawHeaders.push(...inferRawHeaders(args[0].headers)); } if (typeof args[1] === "object" && args[1].headers != null) { inferredRawHeaders.push(...inferRawHeaders(args[1].headers)); } if (inferredRawHeaders.length > 0) { ensureRawHeadersSymbol(request.headers, inferredRawHeaders); } return request; } }) }); Object.defineProperty(globalThis, "Response", { enumerable: true, writable: true, value: new Proxy(Response, { construct(target, args, newTarget) { const response = Reflect.construct(target, args, newTarget); if (typeof args[1] === "object" && args[1].headers != null) { ensureRawHeadersSymbol( response.headers, inferRawHeaders(args[1].headers) ); } return response; } }) }); } function restoreHeadersPrototype() { if (!Reflect.get(Headers, kRestorePatches)) { return; } Reflect.get(Headers, kRestorePatches)(); } function getRawFetchHeaders(headers) { if (!Reflect.has(headers, kRawHeaders)) { return Array.from(headers.entries()); } const rawHeaders = Reflect.get(headers, kRawHeaders); return rawHeaders.length > 0 ? rawHeaders : Array.from(headers.entries()); } function inferRawHeaders(headers) { if (headers instanceof Headers) { return Reflect.get(headers, kRawHeaders) || []; } return Reflect.get(new Headers(headers), kRawHeaders); } // src/interceptors/ClientRequest/MockHttpSocket.ts var kRequestId = Symbol("kRequestId"); var MockHttpSocket = class extends MockSocket { constructor(options) { super({ write: (chunk, encoding, callback) => { var _a; if (this.socketState !== "passthrough") { this.writeBuffer.push([chunk, encoding, callback]); } if (chunk) { if (this.socketState === "passthrough") { (_a = this.originalSocket) == null ? void 0 : _a.write(chunk, encoding, callback); } this.requestParser.execute( Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding) ); } }, read: (chunk) => { if (chunk !== null) { this.responseParser.execute( Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk) ); } } }); this.writeBuffer = []; this.socketState = "unknown"; this.onRequestStart = (versionMajor, versionMinor, rawHeaders, _, path, __, ___, ____, shouldKeepAlive) => { var _a; this.shouldKeepAlive = shouldKeepAlive; const url = new URL(path, this.baseUrl); const method = ((_a = this.connectionOptions.method) == null ? void 0 : _a.toUpperCase()) || "GET"; const headers = FetchResponse.parseRawHeaders(rawHeaders); const canHaveBody = method !== "GET" && method !== "HEAD"; if (url.username || url.password) { if (!headers.has("authorization")) { headers.set("authorization", `Basic ${url.username}:${url.password}`); } url.username = ""; url.password = ""; } if (canHaveBody) { this.requestStream = new Readable({ /** * @note Provide the `read()` method so a `Readable` could be * used as the actual request body (the stream calls "read()"). * We control the queue in the onRequestBody/End functions. */ read: () => { this.flushWriteBuffer(); } }); } const requestId = createRequestId(); this.request = new Request(url, { method, headers, credentials: "same-origin", // @ts-expect-error Undocumented Fetch property. duplex: canHaveBody ? "half" : void 0, body: canHaveBody ? Readable.toWeb(this.requestStream) : null }); Reflect.set(this.request, kRequestId, requestId); if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) { this.passthrough(); return; } this.onRequest({ requestId, request: this.request, socket: this }); }; this.onResponseStart = (versionMajor, versionMinor, rawHeaders, method, url, status, statusText) => { const headers = FetchResponse.parseRawHeaders(rawHeaders); const response = new FetchResponse( /** * @note The Fetch API response instance exposed to the consumer * is created over the response stream of the HTTP parser. It is NOT * related to the Socket instance. This way, you can read response body * in response listener while the Socket instance delays the emission * of "end" and other events until those response listeners are finished. */ FetchResponse.isResponseWithBody(status) ? Readable.toWeb( this.responseStream = new Readable({ read() { } }) ) : null, { url, status, statusText, headers } ); invariant( this.request, "Failed to handle a response: request does not exist" ); if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) { return; } this.responseListenersPromise = this.onResponse({ response, isMockedResponse: this.socketState === "mock", requestId: Reflect.get(this.request, kRequestId), request: this.request, socket: this }); }; this.connectionOptions = options.connectionOptions; this.createConnection = options.createConnection; this.onRequest = options.onRequest; this.onResponse = options.onResponse; this.baseUrl = baseUrlFromConnectionOptions(this.connectionOptions); this.requestParser = new HTTPParser(); this.requestParser.initialize(HTTPParser.REQUEST, {}); this.requestParser[HTTPParser.kOnHeadersComplete] = this.onRequestStart.bind(this); this.requestParser[HTTPParser.kOnBody] = this.onRequestBody.bind(this); this.requestParser[HTTPParser.kOnMessageComplete] = this.onRequestEnd.bind(this); this.responseParser = new HTTPParser(); this.responseParser.initialize(HTTPParser.RESPONSE, {}); this.responseParser[HTTPParser.kOnHeadersComplete] = this.onResponseStart.bind(this); this.responseParser[HTTPParser.kOnBody] = this.onResponseBody.bind(this); this.responseParser[HTTPParser.kOnMessageComplete] = this.onResponseEnd.bind(this); this.once("finish", () => this.requestParser.free()); if (this.baseUrl.protocol === "https:") { Reflect.set(this, "encrypted", true); Reflect.set(this, "authorized", false); Reflect.set(this, "getProtocol", () => "TLSv1.3"); Reflect.set(this, "getSession", () => void 0); Reflect.set(this, "isSessionReused", () => false); } } emit(event, ...args) { const emitEvent = super.emit.bind(this, event, ...args); if (this.responseListenersPromise) { this.responseListenersPromise.finally(emitEvent); return this.listenerCount(event) > 0; } return emitEvent(); } destroy(error) { this.responseParser.free(); if (error) { this.emit("error", error); } return super.destroy(error); } /** * Establish this Socket connection as-is and pipe * its data/events through this Socket. */ passthrough() { this.socketState = "passthrough"; if (this.destroyed) { return; } const socket = this.createConnection(); this.originalSocket = socket; this.once("error", (error) => { socket.destroy(error); }); this.address = socket.address.bind(socket); let writeArgs; let headersWritten = false; while (writeArgs = this.writeBuffer.shift()) { if (writeArgs !== void 0) { if (!headersWritten) { const [chunk, encoding, callback] = writeArgs; const chunkString = chunk.toString(); const chunkBeforeRequestHeaders = chunkString.slice( 0, chunkString.indexOf("\r\n") + 2 ); const chunkAfterRequestHeaders = chunkString.slice( chunk.indexOf("\r\n\r\n") ); const rawRequestHeaders = getRawFetchHeaders(this.request.headers); const requestHeadersString = rawRequestHeaders.filter(([name]) => { return name.toLowerCase() !== INTERNAL_REQUEST_ID_HEADER_NAME; }).map(([name, value]) => `${name}: ${value}`).join("\r\n"); const headersChunk = `${chunkBeforeRequestHeaders}${requestHeadersString}${chunkAfterRequestHeaders}`; socket.write(headersChunk, encoding, callback); headersWritten = true; continue; } socket.write(...writeArgs); } } if (Reflect.get(socket, "encrypted")) { const tlsProperties = [ "encrypted", "authorized", "getProtocol", "getSession", "isSessionReused" ]; tlsProperties.forEach((propertyName) => { Object.defineProperty(this, propertyName, { enumerable: true, get: () => { const value = Reflect.get(socket, propertyName); return typeof value === "function" ? value.bind(socket) : value; } }); }); } socket.on("lookup", (...args) => this.emit("lookup", ...args)).on("connect", () => { this.connecting = socket.connecting; this.emit("connect"); }).on("secureConnect", () => this.emit("secureConnect")).on("secure", () => this.emit("secure")).on("session", (session) => this.emit("session", session)).on("ready", () => this.emit("ready")).on("drain", () => this.emit("drain")).on("data", (chunk) => { this.push(chunk); }).on("error", (error) => { Reflect.set(this, "_hadError", Reflect.get(socket, "_hadError")); this.emit("error", error); }).on("resume", () => this.emit("resume")).on("timeout", () => this.emit("timeout")).on("prefinish", () => this.emit("prefinish")).on("finish", () => this.emit("finish")).on("close", (hadError) => this.emit("close", hadError)).on("end", () => this.emit("end")); } /** * Convert the given Fetch API `Response` instance to an * HTTP message and push it to the socket. */ async respondWith(response) { var _a; if (this.destroyed) { return; } if (isPropertyAccessible(response, "type") && response.type === "error") { this.errorWith(new TypeError("Network error")); return; } this.mockConnect(); this.socketState = "mock"; this.flushWriteBuffer(); const serverResponse = new ServerResponse(new IncomingMessage(this)); serverResponse.assignSocket( new MockSocket({ write: (chunk, encoding, callback) => { this.push(chunk, encoding); callback == null ? void 0 : callback(); }, read() { } }) ); serverResponse.removeHeader("connection"); serverResponse.removeHeader("date"); const rawResponseHeaders = getRawFetchHeaders(response.headers); serverResponse.writeHead( response.status, response.statusText || STATUS_CODES[response.status], rawResponseHeaders ); this.once("error", () => { serverResponse.destroy(); }); if (response.body) { try { const reader = response.body.getReader(); while (true) { const { done, value } = await reader.read(); if (done) { serverResponse.end(); break; } serverResponse.write(value); } } catch (error) { this.respondWith(createServerErrorResponse(error)); return; } } else { serverResponse.end(); } if (!this.shouldKeepAlive) { this.emit("readable"); (_a = this.responseStream) == null ? void 0 : _a.push(null); this.push(null); } } /** * Close this socket connection with the given error. */ errorWith(error) { this.destroy(error); } mockConnect() { this.connecting = false; const isIPv6 = net2.isIPv6(this.connectionOptions.hostname) || this.connectionOptions.family === 6; const addressInfo = { address: isIPv6 ? "::1" : "127.0.0.1", family: isIPv6 ? "IPv6" : "IPv4", port: this.connectionOptions.port }; this.address = () => addressInfo; this.emit( "lookup", null, addressInfo.address, addressInfo.family === "IPv6" ? 6 : 4, this.connectionOptions.host ); this.emit("connect"); this.emit("ready"); if (this.baseUrl.protocol === "https:") { this.emit("secure"); this.emit("secureConnect"); this.emit( "session", this.connectionOptions.session || Buffer.from("mock-session-renegotiate") ); this.emit("session", Buffer.from("mock-session-resume")); } } flushWriteBuffer() { for (const writeCall of this.writeBuffer) { if (typeof writeCall[2] === "function") { writeCall[2](); writeCall[2] = void 0; } } } onRequestBody(chunk) { invariant( this.requestStream, "Failed to write to a request stream: stream does not exist" ); this.requestStream.push(chunk); } onRequestEnd() { if (this.requestStream) { this.requestStream.push(null); } } onResponseBody(chunk) { invariant( this.responseStream, "Failed to write to a response stream: stream does not exist" ); this.responseStream.push(chunk); } onResponseEnd() { if (this.responseStream) { this.responseStream.push(null); } } }; // src/interceptors/ClientRequest/agents.ts import http from "http"; import https from "https"; var MockAgent = class extends http.Agent { constructor(options) { super(); this.customAgent = options.customAgent; this.onRequest = options.onRequest; this.onResponse = options.onResponse; } createConnection(options, callback) { const createConnection = this.customAgent instanceof http.Agent ? this.customAgent.createConnection : super.createConnection; const createConnectionOptions = this.customAgent instanceof http.Agent ? { ...options, ...this.customAgent.options } : options; const socket = new MockHttpSocket({ connectionOptions: options, createConnection: createConnection.bind( this.customAgent || this, createConnectionOptions, callback ), onRequest: this.onRequest.bind(this), onResponse: this.onResponse.bind(this) }); return socket; } }; var MockHttpsAgent = class extends https.Agent { constructor(options) { super(); this.customAgent = options.customAgent; this.onRequest = options.onRequest; this.onResponse = options.onResponse; } createConnection(options, callback) { const createConnection = this.customAgent instanceof https.Agent ? this.customAgent.createConnection : super.createConnection; const createConnectionOptions = this.customAgent instanceof https.Agent ? { ...options, ...this.customAgent.options } : options; const socket = new MockHttpSocket({ connectionOptions: options, createConnection: createConnection.bind( this.customAgent || this, createConnectionOptions, callback ), onRequest: this.onRequest.bind(this), onResponse: this.onResponse.bind(this) }); return socket; } }; // src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts import { urlToHttpOptions } from "url"; import { Agent as HttpAgent, globalAgent as httpGlobalAgent } from "http"; import { Agent as HttpsAgent, globalAgent as httpsGlobalAgent } from "https"; import { URL as URL2, parse as parseUrl } from "url"; import { Logger as Logger3 } from "@open-draft/logger"; // src/utils/getUrlByRequestOptions.ts import { Agent } from "http"; import { Logger } from "@open-draft/logger"; var logger = new Logger("utils getUrlByRequestOptions"); var DEFAULT_PATH = "/"; var DEFAULT_PROTOCOL = "http:"; var DEFAULT_HOSTNAME = "localhost"; var SSL_PORT = 443; function getAgent(options) { return options.agent instanceof Agent ? options.agent : void 0; } function getProtocolByRequestOptions(options) { var _a; if (options.protocol) { return options.protocol; } const agent = getAgent(options); const agentProtocol = agent == null ? void 0 : agent.protocol; if (agentProtocol) { return agentProtocol; } const port = getPortByRequestOptions(options); const isSecureRequest = options.cert || port === SSL_PORT; return isSecureRequest ? "https:" : ((_a = options.uri) == null ? void 0 : _a.protocol) || DEFAULT_PROTOCOL; } function getPortByRequestOptions(options) { if (options.port) { return Number(options.port); } const agent = getAgent(options); if (agent == null ? void 0 : agent.options.port) { return Number(agent.options.port); } if (agent == null ? void 0 : agent.defaultPort) { return Number(agent.defaultPort); } return void 0; } function getAuthByRequestOptions(options) { if (options.auth) { const [username, password] = options.auth.split(":"); return { username, password }; } } function isRawIPv6Address(host) { return host.includes(":") && !host.startsWith("[") && !host.endsWith("]"); } function getHostname(options) { let host = options.hostname || options.host; if (host) { if (isRawIPv6Address(host)) { host = `[${host}]`; } return new URL(`http://${host}`).hostname; } return DEFAULT_HOSTNAME; } function getUrlByRequestOptions(options) { logger.info("request options", options); if (options.uri) { logger.info( 'constructing url from explicitly provided "options.uri": %s', options.uri ); return new URL(options.uri.href); } logger.info("figuring out url from request options..."); const protocol = getProtocolByRequestOptions(options); logger.info("protocol", protocol); const port = getPortByRequestOptions(options); logger.info("port", port); const hostname = getHostname(options); logger.info("hostname", hostname); const path = options.path || DEFAULT_PATH; logger.info("path", path); const credentials = getAuthByRequestOptions(options); logger.info("credentials", credentials); const authString = credentials ? `${credentials.username}:${credentials.password}@` : ""; logger.info("auth string:", authString); const portString = typeof port !== "undefined" ? `:${port}` : ""; const url = new URL(`${protocol}//${hostname}${portString}${path}`); url.username = (credentials == null ? void 0 : credentials.username) || ""; url.password = (credentials == null ? void 0 : credentials.password) || ""; logger.info("created url:", url); return url; } // src/utils/cloneObject.ts import { Logger as Logger2 } from "@open-draft/logger"; var logger2 = new Logger2("cloneObject"); function isPlainObject(obj) { var _a; logger2.info("is plain object?", obj); if (obj == null || !((_a = obj.constructor) == null ? void 0 : _a.name)) { logger2.info("given object is undefined, not a plain object..."); return false; } logger2.info("checking the object constructor:", obj.constructor.name); return obj.constructor.name === "Object"; } function cloneObject(obj) { logger2.info("cloning object:", obj); const enumerableProperties = Object.entries(obj).reduce( (acc, [key, value]) => { logger2.info("analyzing key-value pair:", key, value); acc[key] = isPlainObject(value) ? cloneObject(value) : value; return acc; }, {} ); return isPlainObject(obj) ? enumerableProperties : Object.assign(Object.getPrototypeOf(obj), enumerableProperties); } // src/utils/isObject.ts function isObject(value, loose = false) { return loose ? Object.prototype.toString.call(value).startsWith("[object ") : Object.prototype.toString.call(value) === "[object Object]"; } // src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts var logger3 = new Logger3("http normalizeClientRequestArgs"); function resolveRequestOptions(args, url) { if (typeof args[1] === "undefined" || typeof args[1] === "function") { logger3.info("request options not provided, deriving from the url", url); return urlToHttpOptions(url); } if (args[1]) { logger3.info("has custom RequestOptions!", args[1]); const requestOptionsFromUrl = urlToHttpOptions(url); logger3.info("derived RequestOptions from the URL:", requestOptionsFromUrl); logger3.info("cloning RequestOptions..."); const clonedRequestOptions = cloneObject(args[1]); logger3.info("successfully cloned RequestOptions!", clonedRequestOptions); return { ...requestOptionsFromUrl, ...clonedRequestOptions }; } logger3.info("using an empty object as request options"); return {}; } function overrideUrlByRequestOptions(url, options) { url.host = options.host || url.host; url.hostname = options.hostname || url.hostname; url.port = options.port ? options.port.toString() : url.port; if (options.path) { const parsedOptionsPath = parseUrl(options.path, false); url.pathname = parsedOptionsPath.pathname || ""; url.search = parsedOptionsPath.search || ""; } return url; } function resolveCallback(args) { return typeof args[1] === "function" ? args[1] : args[2]; } function normalizeClientRequestArgs(defaultProtocol, args) { let url; let options; let callback; logger3.info("arguments", args); logger3.info("using default protocol:", defaultProtocol); if (args.length === 0) { const url2 = new URL2("http://localhost"); const options2 = resolveRequestOptions(args, url2); return [url2, options2]; } if (typeof args[0] === "string") { logger3.info("first argument is a location string:", args[0]); url = new URL2(args[0]); logger3.info("created a url:", url); const requestOptionsFromUrl = urlToHttpOptions(url); logger3.info("request options from url:", requestOptionsFromUrl); options = resolveRequestOptions(args, url); logger3.info("resolved request options:", options); callback = resolveCallback(args); } else if (args[0] instanceof URL2) { url = args[0]; logger3.info("first argument is a URL:", url); if (typeof args[1] !== "undefined" && isObject(args[1])) { url = overrideUrlByRequestOptions(url, args[1]); } options = resolveRequestOptions(args, url); logger3.info("derived request options:", options); callback = resolveCallback(args); } else if ("hash" in args[0] && !("method" in args[0])) { const [legacyUrl] = args; logger3.info("first argument is a legacy URL:", legacyUrl); if (legacyUrl.hostname === null) { logger3.info("given legacy URL is relative (no hostname)"); return isObject(args[1]) ? normalizeClientRequestArgs(defaultProtocol, [ { path: legacyUrl.path, ...args[1] }, args[2] ]) : normalizeClientRequestArgs(defaultProtocol, [ { path: legacyUrl.path }, args[1] ]); } logger3.info("given legacy url is absolute"); const resolvedUrl = new URL2(legacyUrl.href); return args[1] === void 0 ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl]) : typeof args[1] === "function" ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl, args[1]]) : normalizeClientRequestArgs(defaultProtocol, [ resolvedUrl, args[1], args[2] ]); } else if (isObject(args[0])) { options = { ...args[0] }; logger3.info("first argument is RequestOptions:", options); options.protocol = options.protocol || defaultProtocol; logger3.info("normalized request options:", options); url = getUrlByRequestOptions(options); logger3.info("created a URL from RequestOptions:", url.href); callback = resolveCallback(args); } else { throw new Error( `Failed to construct ClientRequest with these parameters: ${args}` ); } options.protocol = options.protocol || url.protocol; options.method = options.method || "GET"; if (typeof options.agent === "undefined") { const agent = options.protocol === "https:" ? new HttpsAgent({ // Any other value other than false is considered as true, so we don't add this property if undefined. ..."rejectUnauthorized" in options && { rejectUnauthorized: options.rejectUnauthorized } }) : new HttpAgent(); options.agent = agent; logger3.info("resolved fallback agent:", agent); } if (!options._defaultAgent) { logger3.info( 'has no default agent, setting the default agent for "%s"', options.protocol ); options._defaultAgent = options.protocol === "https:" ? httpsGlobalAgent : httpGlobalAgent; } logger3.info("successfully resolved url:", url.href); logger3.info("successfully resolved options:", options); logger3.info("successfully resolved callback:", callback); if (!(url instanceof URL2)) { url = url.toString(); } return [url, options, callback]; } // src/interceptors/ClientRequest/index.ts var _ClientRequestInterceptor = class extends Interceptor { constructor() { super(_ClientRequestInterceptor.symbol); this.onRequest = async ({ request, socket }) => { const requestId = Reflect.get(request, kRequestId); const controller = new RequestController(request); const isRequestHandled = await handleRequest({ request, requestId, controller, emitter: this.emitter, onResponse: (response) => { socket.respondWith(response); }, onRequestError: (response) => { socket.respondWith(response); }, onError: (error) => { if (error instanceof Error) { socket.errorWith(error); } } }); if (!isRequestHandled) { return socket.passthrough(); } }; this.onResponse = async ({ requestId, request, response, isMockedResponse }) => { return emitAsync(this.emitter, "response", { requestId, request, response, isMockedResponse }); }; } setup() { const { get: originalGet, request: originalRequest } = http2; const { get: originalHttpsGet, request: originalHttpsRequest } = https2; const onRequest = this.onRequest.bind(this); const onResponse = this.onResponse.bind(this); http2.request = new Proxy(http2.request, { apply: (target, thisArg, args) => { const [url, options, callback] = normalizeClientRequestArgs( "http:", args ); const mockAgent = new MockAgent({ customAgent: options.agent, onRequest, onResponse }); options.agent = mockAgent; return Reflect.apply(target, thisArg, [url, options, callback]); } }); http2.get = new Proxy(http2.get, { apply: (target, thisArg, args) => { const [url, options, callback] = normalizeClientRequestArgs( "http:", args ); const mockAgent = new MockAgent({ customAgent: options.agent, onRequest, onResponse }); options.agent = mockAgent; return Reflect.apply(target, thisArg, [url, options, callback]); } }); https2.request = new Proxy(https2.request, { apply: (target, thisArg, args) => { const [url, options, callback] = normalizeClientRequestArgs( "https:", args ); const mockAgent = new MockHttpsAgent({ customAgent: options.agent, onRequest, onResponse }); options.agent = mockAgent; return Reflect.apply(target, thisArg, [url, options, callback]); } }); https2.get = new Proxy(https2.get, { apply: (target, thisArg, args) => { const [url, options, callback] = normalizeClientRequestArgs( "https:", args ); const mockAgent = new MockHttpsAgent({ customAgent: options.agent, onRequest, onResponse }); options.agent = mockAgent; return Reflect.apply(target, thisArg, [url, options, callback]); } }); recordRawFetchHeaders(); this.subscriptions.push(() => { http2.get = originalGet; http2.request = originalRequest; https2.get = originalHttpsGet; https2.request = originalHttpsRequest; restoreHeadersPrototype(); }); } }; var ClientRequestInterceptor = _ClientRequestInterceptor; ClientRequestInterceptor.symbol = Symbol("client-request-interceptor"); export { ClientRequestInterceptor }; //# sourceMappingURL=chunk-FWJSC2QD.mjs.map