@mswjs/interceptors 0.31.1 → 0.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +56 -39
  2. package/lib/node/RemoteHttpInterceptor.d.ts +1 -2
  3. package/lib/node/RemoteHttpInterceptor.js +11 -11
  4. package/lib/node/RemoteHttpInterceptor.mjs +5 -5
  5. package/lib/node/{chunk-LTEXDYJ6.js → chunk-2COJKQQB.js} +3 -3
  6. package/lib/node/chunk-3OJLYEWA.mjs +963 -0
  7. package/lib/node/chunk-3OJLYEWA.mjs.map +1 -0
  8. package/lib/node/chunk-5JMJ55U7.js +963 -0
  9. package/lib/node/chunk-5JMJ55U7.js.map +1 -0
  10. package/lib/node/{chunk-E4AC7YAC.js → chunk-BFLYGQ6D.js} +4 -2
  11. package/lib/node/{chunk-KSHIDGUL.mjs → chunk-DV4PBH4D.mjs} +3 -3
  12. package/lib/node/{chunk-OUWBQF3Z.mjs → chunk-KWV3JXSI.mjs} +14 -14
  13. package/lib/node/chunk-KWV3JXSI.mjs.map +1 -0
  14. package/lib/node/{chunk-6FRASLM3.mjs → chunk-PNWPIDEL.mjs} +2 -2
  15. package/lib/node/{chunk-APT7KA3B.js → chunk-PYD4E2EJ.js} +13 -13
  16. package/lib/node/{chunk-Q7POAM5N.mjs → chunk-TGTPXCLF.mjs} +3 -1
  17. package/lib/node/{chunk-MQJ3JOOK.js → chunk-UXCYRE4F.js} +14 -14
  18. package/lib/node/chunk-UXCYRE4F.js.map +1 -0
  19. package/lib/node/index.js +3 -3
  20. package/lib/node/index.mjs +2 -2
  21. package/lib/node/interceptors/ClientRequest/index.d.ts +83 -14
  22. package/lib/node/interceptors/ClientRequest/index.js +4 -4
  23. package/lib/node/interceptors/ClientRequest/index.mjs +3 -3
  24. package/lib/node/interceptors/XMLHttpRequest/index.js +4 -4
  25. package/lib/node/interceptors/XMLHttpRequest/index.mjs +3 -3
  26. package/lib/node/interceptors/fetch/index.js +10 -10
  27. package/lib/node/interceptors/fetch/index.mjs +2 -2
  28. package/lib/node/presets/node.d.ts +2 -3
  29. package/lib/node/presets/node.js +6 -6
  30. package/lib/node/presets/node.mjs +4 -4
  31. package/package.json +2 -2
  32. package/src/interceptors/ClientRequest/MockHttpSocket.ts +595 -0
  33. package/src/interceptors/ClientRequest/agents.ts +78 -0
  34. package/src/interceptors/ClientRequest/index.test.ts +14 -12
  35. package/src/interceptors/ClientRequest/index.ts +200 -41
  36. package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts +78 -98
  37. package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +40 -22
  38. package/src/interceptors/Socket/MockSocket.test.ts +264 -0
  39. package/src/interceptors/Socket/MockSocket.ts +59 -0
  40. package/src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts +26 -0
  41. package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.test.ts +52 -0
  42. package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts +33 -0
  43. package/src/interceptors/Socket/utils/parseRawHeaders.ts +10 -0
  44. package/lib/node/chunk-IS3CIGXU.js +0 -909
  45. package/lib/node/chunk-IS3CIGXU.js.map +0 -1
  46. package/lib/node/chunk-MQJ3JOOK.js.map +0 -1
  47. package/lib/node/chunk-OMOWHUE6.mjs +0 -909
  48. package/lib/node/chunk-OMOWHUE6.mjs.map +0 -1
  49. package/lib/node/chunk-OUWBQF3Z.mjs.map +0 -1
  50. package/src/interceptors/ClientRequest/NodeClientRequest.test.ts +0 -206
  51. package/src/interceptors/ClientRequest/NodeClientRequest.ts +0 -680
  52. package/src/interceptors/ClientRequest/http.get.ts +0 -30
  53. package/src/interceptors/ClientRequest/http.request.ts +0 -27
  54. package/src/interceptors/ClientRequest/utils/cloneIncomingMessage.test.ts +0 -26
  55. package/src/interceptors/ClientRequest/utils/cloneIncomingMessage.ts +0 -74
  56. package/src/interceptors/ClientRequest/utils/createRequest.test.ts +0 -144
  57. package/src/interceptors/ClientRequest/utils/createRequest.ts +0 -51
  58. package/src/interceptors/ClientRequest/utils/createResponse.test.ts +0 -53
  59. package/src/interceptors/ClientRequest/utils/createResponse.ts +0 -55
  60. package/src/interceptors/ClientRequest/utils/normalizeClientRequestEndArgs.test.ts +0 -41
  61. package/src/interceptors/ClientRequest/utils/normalizeClientRequestEndArgs.ts +0 -53
  62. package/src/interceptors/ClientRequest/utils/normalizeClientRequestWriteArgs.test.ts +0 -36
  63. package/src/interceptors/ClientRequest/utils/normalizeClientRequestWriteArgs.ts +0 -39
  64. /package/lib/node/{chunk-LTEXDYJ6.js.map → chunk-2COJKQQB.js.map} +0 -0
  65. /package/lib/node/{chunk-E4AC7YAC.js.map → chunk-BFLYGQ6D.js.map} +0 -0
  66. /package/lib/node/{chunk-KSHIDGUL.mjs.map → chunk-DV4PBH4D.mjs.map} +0 -0
  67. /package/lib/node/{chunk-6FRASLM3.mjs.map → chunk-PNWPIDEL.mjs.map} +0 -0
  68. /package/lib/node/{chunk-APT7KA3B.js.map → chunk-PYD4E2EJ.js.map} +0 -0
  69. /package/lib/node/{chunk-Q7POAM5N.mjs.map → chunk-TGTPXCLF.mjs.map} +0 -0
@@ -0,0 +1,963 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2
+
3
+
4
+ var _chunkUXCYRE4Fjs = require('./chunk-UXCYRE4F.js');
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+ var _chunkBFLYGQ6Djs = require('./chunk-BFLYGQ6D.js');
13
+
14
+ // src/interceptors/ClientRequest/index.ts
15
+ var _http = require('http'); var _http2 = _interopRequireDefault(_http);
16
+ var _https = require('https'); var _https2 = _interopRequireDefault(_https);
17
+ var _until = require('@open-draft/until');
18
+
19
+ // src/interceptors/ClientRequest/MockHttpSocket.ts
20
+ var _net = require('net'); var _net2 = _interopRequireDefault(_net);
21
+
22
+
23
+ var __http_common = require('_http_common');
24
+
25
+ var _stream = require('stream');
26
+ var _outvariant = require('outvariant');
27
+
28
+ // src/interceptors/Socket/MockSocket.ts
29
+
30
+
31
+ // src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts
32
+ function normalizeSocketWriteArgs(args) {
33
+ const normalized = [args[0], void 0, void 0];
34
+ if (typeof args[1] === "string") {
35
+ normalized[1] = args[1];
36
+ } else if (typeof args[1] === "function") {
37
+ normalized[2] = args[1];
38
+ }
39
+ if (typeof args[2] === "function") {
40
+ normalized[2] = args[2];
41
+ }
42
+ return normalized;
43
+ }
44
+
45
+ // src/interceptors/Socket/MockSocket.ts
46
+ var MockSocket = class extends _net2.default.Socket {
47
+ constructor(options) {
48
+ super();
49
+ this.options = options;
50
+ this.connecting = false;
51
+ this.connect();
52
+ this._final = (callback) => {
53
+ callback(null);
54
+ };
55
+ }
56
+ connect() {
57
+ this.connecting = true;
58
+ return this;
59
+ }
60
+ write(...args) {
61
+ const [chunk, encoding, callback] = normalizeSocketWriteArgs(
62
+ args
63
+ );
64
+ this.options.write(chunk, encoding, callback);
65
+ return true;
66
+ }
67
+ end(...args) {
68
+ const [chunk, encoding, callback] = normalizeSocketWriteArgs(
69
+ args
70
+ );
71
+ this.options.write(chunk, encoding, callback);
72
+ return super.end.apply(this, args);
73
+ }
74
+ push(chunk, encoding) {
75
+ this.options.read(chunk, encoding);
76
+ return super.push(chunk, encoding);
77
+ }
78
+ };
79
+
80
+ // src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts
81
+ function baseUrlFromConnectionOptions(options) {
82
+ if ("href" in options) {
83
+ return new URL(options.href);
84
+ }
85
+ const protocol = options.port === 443 ? "https:" : "http:";
86
+ const host = options.host;
87
+ const url = new URL(`${protocol}//${host}`);
88
+ if (options.port) {
89
+ url.port = options.port.toString();
90
+ }
91
+ if (options.path) {
92
+ url.pathname = options.path;
93
+ }
94
+ if (options.auth) {
95
+ const [username, password] = options.auth.split(":");
96
+ url.username = username;
97
+ url.password = password;
98
+ }
99
+ return url;
100
+ }
101
+
102
+ // src/interceptors/Socket/utils/parseRawHeaders.ts
103
+ function parseRawHeaders(rawHeaders) {
104
+ const headers = new Headers();
105
+ for (let line = 0; line < rawHeaders.length; line += 2) {
106
+ headers.append(rawHeaders[line], rawHeaders[line + 1]);
107
+ }
108
+ return headers;
109
+ }
110
+
111
+ // src/utils/getValueBySymbol.ts
112
+ function getValueBySymbol(symbolName, source) {
113
+ const ownSymbols = Object.getOwnPropertySymbols(source);
114
+ const symbol = ownSymbols.find((symbol2) => {
115
+ return symbol2.description === symbolName;
116
+ });
117
+ if (symbol) {
118
+ return Reflect.get(source, symbol);
119
+ }
120
+ return;
121
+ }
122
+
123
+ // src/utils/isObject.ts
124
+ function isObject(value, loose = false) {
125
+ return loose ? Object.prototype.toString.call(value).startsWith("[object ") : Object.prototype.toString.call(value) === "[object Object]";
126
+ }
127
+
128
+ // src/utils/getRawFetchHeaders.ts
129
+ function getRawFetchHeaders(headers) {
130
+ const headersList = getValueBySymbol("headers list", headers);
131
+ if (!headersList) {
132
+ return;
133
+ }
134
+ const headersMap = getValueBySymbol("headers map", headersList);
135
+ if (!headersMap || !isHeadersMapWithRawHeaderNames(headersMap)) {
136
+ return;
137
+ }
138
+ const rawHeaders = /* @__PURE__ */ new Map();
139
+ headersMap.forEach(({ name, value }) => {
140
+ rawHeaders.set(name, value);
141
+ });
142
+ return rawHeaders;
143
+ }
144
+ function isHeadersMapWithRawHeaderNames(headersMap) {
145
+ return Array.from(
146
+ headersMap.values()
147
+ ).every((value) => {
148
+ return isObject(value) && "name" in value;
149
+ });
150
+ }
151
+
152
+ // src/interceptors/ClientRequest/MockHttpSocket.ts
153
+ var kRequestId = Symbol("kRequestId");
154
+ var MockHttpSocket = class extends MockSocket {
155
+ constructor(options) {
156
+ super({
157
+ write: (chunk, encoding, callback) => {
158
+ this.writeBuffer.push([chunk, encoding, callback]);
159
+ if (chunk) {
160
+ this.requestParser.execute(
161
+ Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding)
162
+ );
163
+ }
164
+ },
165
+ read: (chunk) => {
166
+ if (chunk !== null) {
167
+ this.responseParser.execute(
168
+ Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
169
+ );
170
+ }
171
+ }
172
+ });
173
+ this.writeBuffer = [];
174
+ this.responseType = "bypassed";
175
+ this.onRequestStart = (versionMajor, versionMinor, rawHeaders, _, path, __, ___, ____, shouldKeepAlive) => {
176
+ this.shouldKeepAlive = shouldKeepAlive;
177
+ const url = new URL(path, this.baseUrl);
178
+ const method = this.connectionOptions.method || "GET";
179
+ const headers = parseRawHeaders(rawHeaders);
180
+ const canHaveBody = method !== "GET" && method !== "HEAD";
181
+ if (url.username || url.password) {
182
+ if (!headers.has("authorization")) {
183
+ headers.set("authorization", `Basic ${url.username}:${url.password}`);
184
+ }
185
+ url.username = "";
186
+ url.password = "";
187
+ }
188
+ if (canHaveBody) {
189
+ this.requestStream = new (0, _stream.Readable)({
190
+ /**
191
+ * @note Provide the `read()` method so a `Readable` could be
192
+ * used as the actual request body (the stream calls "read()").
193
+ * We control the queue in the onRequestBody/End functions.
194
+ */
195
+ read: () => {
196
+ this.flushWriteBuffer();
197
+ }
198
+ });
199
+ }
200
+ const requestId = _chunkBFLYGQ6Djs.createRequestId.call(void 0, );
201
+ this.request = new Request(url, {
202
+ method,
203
+ headers,
204
+ credentials: "same-origin",
205
+ // @ts-expect-error Undocumented Fetch property.
206
+ duplex: canHaveBody ? "half" : void 0,
207
+ body: canHaveBody ? _stream.Readable.toWeb(this.requestStream) : null
208
+ });
209
+ Reflect.set(this.request, kRequestId, requestId);
210
+ if (this.request.headers.has(_chunkBFLYGQ6Djs.INTERNAL_REQUEST_ID_HEADER_NAME)) {
211
+ this.passthrough();
212
+ return;
213
+ }
214
+ this.onRequest({
215
+ requestId,
216
+ request: this.request,
217
+ socket: this
218
+ });
219
+ };
220
+ this.onResponseStart = (versionMajor, versionMinor, rawHeaders, method, url, status, statusText) => {
221
+ const headers = parseRawHeaders(rawHeaders);
222
+ const canHaveBody = !_chunkBFLYGQ6Djs.RESPONSE_STATUS_CODES_WITHOUT_BODY.has(status);
223
+ if (canHaveBody) {
224
+ this.responseStream = new (0, _stream.Readable)();
225
+ }
226
+ const response = new Response(
227
+ /**
228
+ * @note The Fetch API response instance exposed to the consumer
229
+ * is created over the response stream of the HTTP parser. It is NOT
230
+ * related to the Socket instance. This way, you can read response body
231
+ * in response listener while the Socket instance delays the emission
232
+ * of "end" and other events until those response listeners are finished.
233
+ */
234
+ canHaveBody ? _stream.Readable.toWeb(this.responseStream) : null,
235
+ {
236
+ status,
237
+ statusText,
238
+ headers
239
+ }
240
+ );
241
+ _outvariant.invariant.call(void 0,
242
+ this.request,
243
+ "Failed to handle a response: request does not exist"
244
+ );
245
+ if (this.request.headers.has(_chunkBFLYGQ6Djs.INTERNAL_REQUEST_ID_HEADER_NAME)) {
246
+ return;
247
+ }
248
+ this.responseListenersPromise = this.onResponse({
249
+ response,
250
+ isMockedResponse: this.responseType === "mock",
251
+ requestId: Reflect.get(this.request, kRequestId),
252
+ request: this.request,
253
+ socket: this
254
+ });
255
+ };
256
+ this.connectionOptions = options.connectionOptions;
257
+ this.createConnection = options.createConnection;
258
+ this.onRequest = options.onRequest;
259
+ this.onResponse = options.onResponse;
260
+ this.baseUrl = baseUrlFromConnectionOptions(this.connectionOptions);
261
+ this.requestParser = new (0, __http_common.HTTPParser)();
262
+ this.requestParser.initialize(__http_common.HTTPParser.REQUEST, {});
263
+ this.requestParser[__http_common.HTTPParser.kOnHeadersComplete] = this.onRequestStart.bind(this);
264
+ this.requestParser[__http_common.HTTPParser.kOnBody] = this.onRequestBody.bind(this);
265
+ this.requestParser[__http_common.HTTPParser.kOnMessageComplete] = this.onRequestEnd.bind(this);
266
+ this.responseParser = new (0, __http_common.HTTPParser)();
267
+ this.responseParser.initialize(__http_common.HTTPParser.RESPONSE, {});
268
+ this.responseParser[__http_common.HTTPParser.kOnHeadersComplete] = this.onResponseStart.bind(this);
269
+ this.responseParser[__http_common.HTTPParser.kOnBody] = this.onResponseBody.bind(this);
270
+ this.responseParser[__http_common.HTTPParser.kOnMessageComplete] = this.onResponseEnd.bind(this);
271
+ this.once("finish", () => this.requestParser.free());
272
+ if (this.baseUrl.protocol === "https:") {
273
+ Reflect.set(this, "encrypted", true);
274
+ Reflect.set(this, "authorized", false);
275
+ Reflect.set(this, "getProtocol", () => "TLSv1.3");
276
+ Reflect.set(this, "getSession", () => void 0);
277
+ Reflect.set(this, "isSessionReused", () => false);
278
+ }
279
+ }
280
+ emit(event, ...args) {
281
+ const emitEvent = super.emit.bind(this, event, ...args);
282
+ if (this.responseListenersPromise) {
283
+ this.responseListenersPromise.finally(emitEvent);
284
+ return this.listenerCount(event) > 0;
285
+ }
286
+ return emitEvent();
287
+ }
288
+ destroy(error) {
289
+ this.responseParser.free();
290
+ if (error) {
291
+ this.emit("error", error);
292
+ }
293
+ return super.destroy(error);
294
+ }
295
+ /**
296
+ * Establish this Socket connection as-is and pipe
297
+ * its data/events through this Socket.
298
+ */
299
+ passthrough() {
300
+ if (this.destroyed) {
301
+ return;
302
+ }
303
+ const socket = this.createConnection();
304
+ this.once("error", (error) => {
305
+ socket.destroy(error);
306
+ });
307
+ this.address = socket.address.bind(socket);
308
+ let writeArgs;
309
+ let headersWritten = false;
310
+ while (writeArgs = this.writeBuffer.shift()) {
311
+ if (writeArgs !== void 0) {
312
+ if (!headersWritten) {
313
+ const [chunk, encoding, callback] = writeArgs;
314
+ const chunkString = chunk.toString();
315
+ const chunkBeforeRequestHeaders = chunkString.slice(
316
+ 0,
317
+ chunkString.indexOf("\r\n") + 2
318
+ );
319
+ const chunkAfterRequestHeaders = chunkString.slice(
320
+ chunk.indexOf("\r\n\r\n")
321
+ );
322
+ const requestHeaders = getRawFetchHeaders(this.request.headers) || this.request.headers;
323
+ const requestHeadersString = Array.from(requestHeaders.entries()).filter(([name]) => name !== _chunkBFLYGQ6Djs.INTERNAL_REQUEST_ID_HEADER_NAME).map(([name, value]) => `${name}: ${value}`).join("\r\n");
324
+ const headersChunk = `${chunkBeforeRequestHeaders}${requestHeadersString}${chunkAfterRequestHeaders}`;
325
+ socket.write(headersChunk, encoding, callback);
326
+ headersWritten = true;
327
+ continue;
328
+ }
329
+ socket.write(...writeArgs);
330
+ }
331
+ }
332
+ if (Reflect.get(socket, "encrypted")) {
333
+ const tlsProperties = [
334
+ "encrypted",
335
+ "authorized",
336
+ "getProtocol",
337
+ "getSession",
338
+ "isSessionReused"
339
+ ];
340
+ tlsProperties.forEach((propertyName) => {
341
+ Object.defineProperty(this, propertyName, {
342
+ enumerable: true,
343
+ get: () => {
344
+ const value = Reflect.get(socket, propertyName);
345
+ return typeof value === "function" ? value.bind(socket) : value;
346
+ }
347
+ });
348
+ });
349
+ }
350
+ socket.on("lookup", (...args) => this.emit("lookup", ...args)).on("connect", () => {
351
+ this.connecting = socket.connecting;
352
+ this.emit("connect");
353
+ }).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) => {
354
+ this.push(chunk);
355
+ }).on("error", (error) => {
356
+ Reflect.set(this, "_hadError", Reflect.get(socket, "_hadError"));
357
+ this.emit("error", error);
358
+ }).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"));
359
+ }
360
+ /**
361
+ * Convert the given Fetch API `Response` instance to an
362
+ * HTTP message and push it to the socket.
363
+ */
364
+ async respondWith(response) {
365
+ var _a;
366
+ if (this.destroyed) {
367
+ return;
368
+ }
369
+ if (_chunkBFLYGQ6Djs.isPropertyAccessible.call(void 0, response, "type") && response.type === "error") {
370
+ this.errorWith(new TypeError("Network error"));
371
+ return;
372
+ }
373
+ this.mockConnect();
374
+ this.responseType = "mock";
375
+ this.flushWriteBuffer();
376
+ const serverResponse = new (0, _http.ServerResponse)(new (0, _http.IncomingMessage)(this));
377
+ serverResponse.assignSocket(
378
+ new MockSocket({
379
+ write: (chunk, encoding, callback) => {
380
+ this.push(chunk, encoding);
381
+ callback == null ? void 0 : callback();
382
+ },
383
+ read() {
384
+ }
385
+ })
386
+ );
387
+ serverResponse.statusCode = response.status;
388
+ serverResponse.statusMessage = response.statusText;
389
+ serverResponse.removeHeader("connection");
390
+ serverResponse.removeHeader("date");
391
+ this.once("error", () => {
392
+ serverResponse.destroy();
393
+ });
394
+ const headers = getRawFetchHeaders(response.headers) || response.headers;
395
+ for (const [name, value] of headers) {
396
+ serverResponse.setHeader(name, value);
397
+ }
398
+ if (response.body) {
399
+ try {
400
+ const reader = response.body.getReader();
401
+ while (true) {
402
+ const { done, value } = await reader.read();
403
+ if (done) {
404
+ serverResponse.end();
405
+ break;
406
+ }
407
+ serverResponse.write(value);
408
+ }
409
+ } catch (error) {
410
+ this.respondWith(_chunkBFLYGQ6Djs.createServerErrorResponse.call(void 0, error));
411
+ return;
412
+ }
413
+ } else {
414
+ serverResponse.end();
415
+ }
416
+ if (!this.shouldKeepAlive) {
417
+ this.emit("readable");
418
+ (_a = this.responseStream) == null ? void 0 : _a.push(null);
419
+ this.push(null);
420
+ }
421
+ }
422
+ /**
423
+ * Close this socket connection with the given error.
424
+ */
425
+ errorWith(error) {
426
+ this.destroy(error);
427
+ }
428
+ mockConnect() {
429
+ this.connecting = false;
430
+ const isIPv6 = _net2.default.isIPv6(this.connectionOptions.hostname) || this.connectionOptions.family === 6;
431
+ const addressInfo = {
432
+ address: isIPv6 ? "::1" : "127.0.0.1",
433
+ family: isIPv6 ? "IPv6" : "IPv4",
434
+ port: this.connectionOptions.port
435
+ };
436
+ this.address = () => addressInfo;
437
+ this.emit(
438
+ "lookup",
439
+ null,
440
+ addressInfo.address,
441
+ addressInfo.family === "IPv6" ? 6 : 4,
442
+ this.connectionOptions.host
443
+ );
444
+ this.emit("connect");
445
+ this.emit("ready");
446
+ if (this.baseUrl.protocol === "https:") {
447
+ this.emit("secure");
448
+ this.emit("secureConnect");
449
+ this.emit(
450
+ "session",
451
+ this.connectionOptions.session || Buffer.from("mock-session-renegotiate")
452
+ );
453
+ this.emit("session", Buffer.from("mock-session-resume"));
454
+ }
455
+ }
456
+ flushWriteBuffer() {
457
+ var _a;
458
+ let args;
459
+ while (args = this.writeBuffer.shift()) {
460
+ (_a = args == null ? void 0 : args[2]) == null ? void 0 : _a.call(args);
461
+ }
462
+ }
463
+ onRequestBody(chunk) {
464
+ _outvariant.invariant.call(void 0,
465
+ this.requestStream,
466
+ "Failed to write to a request stream: stream does not exist"
467
+ );
468
+ this.requestStream.push(chunk);
469
+ }
470
+ onRequestEnd() {
471
+ if (this.requestStream) {
472
+ this.requestStream.push(null);
473
+ }
474
+ }
475
+ onResponseBody(chunk) {
476
+ _outvariant.invariant.call(void 0,
477
+ this.responseStream,
478
+ "Failed to write to a response stream: stream does not exist"
479
+ );
480
+ this.responseStream.push(chunk);
481
+ }
482
+ onResponseEnd() {
483
+ if (this.responseStream) {
484
+ this.responseStream.push(null);
485
+ }
486
+ }
487
+ };
488
+
489
+ // src/interceptors/ClientRequest/agents.ts
490
+
491
+
492
+ var MockAgent = class extends _http2.default.Agent {
493
+ constructor(options) {
494
+ super();
495
+ this.customAgent = options.customAgent;
496
+ this.onRequest = options.onRequest;
497
+ this.onResponse = options.onResponse;
498
+ }
499
+ createConnection(options, callback) {
500
+ const createConnection = this.customAgent instanceof _http2.default.Agent && this.customAgent.createConnection || super.createConnection;
501
+ const socket = new MockHttpSocket({
502
+ connectionOptions: options,
503
+ createConnection: createConnection.bind(this, options, callback),
504
+ onRequest: this.onRequest.bind(this),
505
+ onResponse: this.onResponse.bind(this)
506
+ });
507
+ return socket;
508
+ }
509
+ };
510
+ var MockHttpsAgent = class extends _https2.default.Agent {
511
+ constructor(options) {
512
+ super();
513
+ this.customAgent = options.customAgent;
514
+ this.onRequest = options.onRequest;
515
+ this.onResponse = options.onResponse;
516
+ }
517
+ createConnection(options, callback) {
518
+ const createConnection = this.customAgent instanceof _https2.default.Agent && this.customAgent.createConnection || super.createConnection;
519
+ const socket = new MockHttpSocket({
520
+ connectionOptions: options,
521
+ createConnection: createConnection.bind(this, options, callback),
522
+ onRequest: this.onRequest.bind(this),
523
+ onResponse: this.onResponse.bind(this)
524
+ });
525
+ return socket;
526
+ }
527
+ };
528
+
529
+ // src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts
530
+
531
+
532
+
533
+
534
+
535
+
536
+
537
+
538
+
539
+
540
+
541
+ var _url = require('url');
542
+ var _logger = require('@open-draft/logger');
543
+
544
+ // src/utils/getRequestOptionsByUrl.ts
545
+ function getRequestOptionsByUrl(url) {
546
+ const options = {
547
+ method: "GET",
548
+ protocol: url.protocol,
549
+ hostname: typeof url.hostname === "string" && url.hostname.startsWith("[") ? url.hostname.slice(1, -1) : url.hostname,
550
+ host: url.host,
551
+ path: `${url.pathname}${url.search || ""}`
552
+ };
553
+ if (!!url.port) {
554
+ options.port = Number(url.port);
555
+ }
556
+ if (url.username || url.password) {
557
+ options.auth = `${url.username}:${url.password}`;
558
+ }
559
+ return options;
560
+ }
561
+
562
+ // src/utils/getUrlByRequestOptions.ts
563
+
564
+
565
+ var logger = new (0, _logger.Logger)("utils getUrlByRequestOptions");
566
+ var DEFAULT_PATH = "/";
567
+ var DEFAULT_PROTOCOL = "http:";
568
+ var DEFAULT_HOSTNAME = "localhost";
569
+ var SSL_PORT = 443;
570
+ function getAgent(options) {
571
+ return options.agent instanceof _http.Agent ? options.agent : void 0;
572
+ }
573
+ function getProtocolByRequestOptions(options) {
574
+ var _a;
575
+ if (options.protocol) {
576
+ return options.protocol;
577
+ }
578
+ const agent = getAgent(options);
579
+ const agentProtocol = agent == null ? void 0 : agent.protocol;
580
+ if (agentProtocol) {
581
+ return agentProtocol;
582
+ }
583
+ const port = getPortByRequestOptions(options);
584
+ const isSecureRequest = options.cert || port === SSL_PORT;
585
+ return isSecureRequest ? "https:" : ((_a = options.uri) == null ? void 0 : _a.protocol) || DEFAULT_PROTOCOL;
586
+ }
587
+ function getPortByRequestOptions(options) {
588
+ if (options.port) {
589
+ return Number(options.port);
590
+ }
591
+ const agent = getAgent(options);
592
+ if (agent == null ? void 0 : agent.options.port) {
593
+ return Number(agent.options.port);
594
+ }
595
+ if (agent == null ? void 0 : agent.defaultPort) {
596
+ return Number(agent.defaultPort);
597
+ }
598
+ return void 0;
599
+ }
600
+ function getAuthByRequestOptions(options) {
601
+ if (options.auth) {
602
+ const [username, password] = options.auth.split(":");
603
+ return { username, password };
604
+ }
605
+ }
606
+ function isRawIPv6Address(host) {
607
+ return host.includes(":") && !host.startsWith("[") && !host.endsWith("]");
608
+ }
609
+ function getHostname(options) {
610
+ let host = options.hostname || options.host;
611
+ if (host) {
612
+ if (isRawIPv6Address(host)) {
613
+ host = `[${host}]`;
614
+ }
615
+ return new URL(`http://${host}`).hostname;
616
+ }
617
+ return DEFAULT_HOSTNAME;
618
+ }
619
+ function getUrlByRequestOptions(options) {
620
+ logger.info("request options", options);
621
+ if (options.uri) {
622
+ logger.info(
623
+ 'constructing url from explicitly provided "options.uri": %s',
624
+ options.uri
625
+ );
626
+ return new URL(options.uri.href);
627
+ }
628
+ logger.info("figuring out url from request options...");
629
+ const protocol = getProtocolByRequestOptions(options);
630
+ logger.info("protocol", protocol);
631
+ const port = getPortByRequestOptions(options);
632
+ logger.info("port", port);
633
+ const hostname = getHostname(options);
634
+ logger.info("hostname", hostname);
635
+ const path = options.path || DEFAULT_PATH;
636
+ logger.info("path", path);
637
+ const credentials = getAuthByRequestOptions(options);
638
+ logger.info("credentials", credentials);
639
+ const authString = credentials ? `${credentials.username}:${credentials.password}@` : "";
640
+ logger.info("auth string:", authString);
641
+ const portString = typeof port !== "undefined" ? `:${port}` : "";
642
+ const url = new URL(`${protocol}//${hostname}${portString}${path}`);
643
+ url.username = (credentials == null ? void 0 : credentials.username) || "";
644
+ url.password = (credentials == null ? void 0 : credentials.password) || "";
645
+ logger.info("created url:", url);
646
+ return url;
647
+ }
648
+
649
+ // src/utils/cloneObject.ts
650
+
651
+ var logger2 = new (0, _logger.Logger)("cloneObject");
652
+ function isPlainObject(obj) {
653
+ var _a;
654
+ logger2.info("is plain object?", obj);
655
+ if (obj == null || !((_a = obj.constructor) == null ? void 0 : _a.name)) {
656
+ logger2.info("given object is undefined, not a plain object...");
657
+ return false;
658
+ }
659
+ logger2.info("checking the object constructor:", obj.constructor.name);
660
+ return obj.constructor.name === "Object";
661
+ }
662
+ function cloneObject(obj) {
663
+ logger2.info("cloning object:", obj);
664
+ const enumerableProperties = Object.entries(obj).reduce(
665
+ (acc, [key, value]) => {
666
+ logger2.info("analyzing key-value pair:", key, value);
667
+ acc[key] = isPlainObject(value) ? cloneObject(value) : value;
668
+ return acc;
669
+ },
670
+ {}
671
+ );
672
+ return isPlainObject(obj) ? enumerableProperties : Object.assign(Object.getPrototypeOf(obj), enumerableProperties);
673
+ }
674
+
675
+ // src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts
676
+ var logger3 = new (0, _logger.Logger)("http normalizeClientRequestArgs");
677
+ function resolveRequestOptions(args, url) {
678
+ if (typeof args[1] === "undefined" || typeof args[1] === "function") {
679
+ logger3.info("request options not provided, deriving from the url", url);
680
+ return getRequestOptionsByUrl(url);
681
+ }
682
+ if (args[1]) {
683
+ logger3.info("has custom RequestOptions!", args[1]);
684
+ const requestOptionsFromUrl = getRequestOptionsByUrl(url);
685
+ logger3.info("derived RequestOptions from the URL:", requestOptionsFromUrl);
686
+ logger3.info("cloning RequestOptions...");
687
+ const clonedRequestOptions = cloneObject(args[1]);
688
+ logger3.info("successfully cloned RequestOptions!", clonedRequestOptions);
689
+ return {
690
+ ...requestOptionsFromUrl,
691
+ ...clonedRequestOptions
692
+ };
693
+ }
694
+ logger3.info("using an empty object as request options");
695
+ return {};
696
+ }
697
+ function overrideUrlByRequestOptions(url, options) {
698
+ url.host = options.host || url.host;
699
+ url.hostname = options.hostname || url.hostname;
700
+ url.port = options.port ? options.port.toString() : url.port;
701
+ if (options.path) {
702
+ const parsedOptionsPath = _url.parse.call(void 0, options.path, false);
703
+ url.pathname = parsedOptionsPath.pathname || "";
704
+ url.search = parsedOptionsPath.search || "";
705
+ }
706
+ return url;
707
+ }
708
+ function resolveCallback(args) {
709
+ return typeof args[1] === "function" ? args[1] : args[2];
710
+ }
711
+ function normalizeClientRequestArgs(defaultProtocol, args) {
712
+ let url;
713
+ let options;
714
+ let callback;
715
+ logger3.info("arguments", args);
716
+ logger3.info("using default protocol:", defaultProtocol);
717
+ if (args.length === 0) {
718
+ const url2 = new (0, _url.URL)("http://localhost");
719
+ const options2 = resolveRequestOptions(args, url2);
720
+ return [url2, options2];
721
+ }
722
+ if (typeof args[0] === "string") {
723
+ logger3.info("first argument is a location string:", args[0]);
724
+ url = new (0, _url.URL)(args[0]);
725
+ logger3.info("created a url:", url);
726
+ const requestOptionsFromUrl = getRequestOptionsByUrl(url);
727
+ logger3.info("request options from url:", requestOptionsFromUrl);
728
+ options = resolveRequestOptions(args, url);
729
+ logger3.info("resolved request options:", options);
730
+ callback = resolveCallback(args);
731
+ } else if (args[0] instanceof _url.URL) {
732
+ url = args[0];
733
+ logger3.info("first argument is a URL:", url);
734
+ if (typeof args[1] !== "undefined" && isObject(args[1])) {
735
+ url = overrideUrlByRequestOptions(url, args[1]);
736
+ }
737
+ options = resolveRequestOptions(args, url);
738
+ logger3.info("derived request options:", options);
739
+ callback = resolveCallback(args);
740
+ } else if ("hash" in args[0] && !("method" in args[0])) {
741
+ const [legacyUrl] = args;
742
+ logger3.info("first argument is a legacy URL:", legacyUrl);
743
+ if (legacyUrl.hostname === null) {
744
+ logger3.info("given legacy URL is relative (no hostname)");
745
+ return isObject(args[1]) ? normalizeClientRequestArgs(defaultProtocol, [
746
+ { path: legacyUrl.path, ...args[1] },
747
+ args[2]
748
+ ]) : normalizeClientRequestArgs(defaultProtocol, [
749
+ { path: legacyUrl.path },
750
+ args[1]
751
+ ]);
752
+ }
753
+ logger3.info("given legacy url is absolute");
754
+ const resolvedUrl = new (0, _url.URL)(legacyUrl.href);
755
+ return args[1] === void 0 ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl]) : typeof args[1] === "function" ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl, args[1]]) : normalizeClientRequestArgs(defaultProtocol, [
756
+ resolvedUrl,
757
+ args[1],
758
+ args[2]
759
+ ]);
760
+ } else if (isObject(args[0])) {
761
+ options = { ...args[0] };
762
+ logger3.info("first argument is RequestOptions:", options);
763
+ options.protocol = options.protocol || defaultProtocol;
764
+ logger3.info("normalized request options:", options);
765
+ url = getUrlByRequestOptions(options);
766
+ logger3.info("created a URL from RequestOptions:", url.href);
767
+ callback = resolveCallback(args);
768
+ } else {
769
+ throw new Error(
770
+ `Failed to construct ClientRequest with these parameters: ${args}`
771
+ );
772
+ }
773
+ options.protocol = options.protocol || url.protocol;
774
+ options.method = options.method || "GET";
775
+ if (typeof options.agent === "undefined") {
776
+ const agent = options.protocol === "https:" ? new (0, _https.Agent)({
777
+ rejectUnauthorized: options.rejectUnauthorized
778
+ }) : new (0, _http.Agent)();
779
+ options.agent = agent;
780
+ logger3.info("resolved fallback agent:", agent);
781
+ }
782
+ if (!options._defaultAgent) {
783
+ logger3.info(
784
+ 'has no default agent, setting the default agent for "%s"',
785
+ options.protocol
786
+ );
787
+ options._defaultAgent = options.protocol === "https:" ? _https.globalAgent : _http.globalAgent;
788
+ }
789
+ logger3.info("successfully resolved url:", url.href);
790
+ logger3.info("successfully resolved options:", options);
791
+ logger3.info("successfully resolved callback:", callback);
792
+ if (!(url instanceof _url.URL)) {
793
+ url = url.toString();
794
+ }
795
+ return [url, options, callback];
796
+ }
797
+
798
+ // src/utils/isNodeLikeError.ts
799
+ function isNodeLikeError(error) {
800
+ if (error == null) {
801
+ return false;
802
+ }
803
+ if (!(error instanceof Error)) {
804
+ return false;
805
+ }
806
+ return "code" in error && "errno" in error;
807
+ }
808
+
809
+ // src/interceptors/ClientRequest/index.ts
810
+ var _ClientRequestInterceptor = class extends _chunkBFLYGQ6Djs.Interceptor {
811
+ constructor() {
812
+ super(_ClientRequestInterceptor.symbol);
813
+ this.onRequest = async ({
814
+ request,
815
+ socket
816
+ }) => {
817
+ const requestId = Reflect.get(request, kRequestId);
818
+ const { interactiveRequest, requestController } = _chunkUXCYRE4Fjs.toInteractiveRequest.call(void 0, request);
819
+ this.emitter.once("request", ({ requestId: pendingRequestId }) => {
820
+ if (pendingRequestId !== requestId) {
821
+ return;
822
+ }
823
+ if (requestController.responsePromise.state === "pending") {
824
+ this.logger.info(
825
+ "request has not been handled in listeners, executing fail-safe listener..."
826
+ );
827
+ requestController.responsePromise.resolve(void 0);
828
+ }
829
+ });
830
+ const listenerResult = await _until.until.call(void 0, async () => {
831
+ await _chunkUXCYRE4Fjs.emitAsync.call(void 0, this.emitter, "request", {
832
+ requestId,
833
+ request: interactiveRequest
834
+ });
835
+ return await requestController.responsePromise;
836
+ });
837
+ if (listenerResult.error) {
838
+ if (listenerResult.error instanceof Response) {
839
+ socket.respondWith(listenerResult.error);
840
+ return;
841
+ }
842
+ if (isNodeLikeError(listenerResult.error)) {
843
+ socket.errorWith(listenerResult.error);
844
+ return;
845
+ }
846
+ if (this.emitter.listenerCount("unhandledException") > 0) {
847
+ await _chunkUXCYRE4Fjs.emitAsync.call(void 0, this.emitter, "unhandledException", {
848
+ error: listenerResult.error,
849
+ request,
850
+ requestId,
851
+ controller: {
852
+ respondWith: socket.respondWith.bind(socket),
853
+ errorWith: socket.errorWith.bind(socket)
854
+ }
855
+ });
856
+ if (!socket.connecting || socket.destroyed) {
857
+ return;
858
+ }
859
+ }
860
+ socket.respondWith(_chunkBFLYGQ6Djs.createServerErrorResponse.call(void 0, listenerResult.error));
861
+ return;
862
+ }
863
+ const mockedResponse = listenerResult.data;
864
+ if (mockedResponse) {
865
+ socket.respondWith(mockedResponse);
866
+ return;
867
+ }
868
+ socket.passthrough();
869
+ };
870
+ this.onResponse = async ({
871
+ requestId,
872
+ request,
873
+ response,
874
+ isMockedResponse
875
+ }) => {
876
+ return _chunkUXCYRE4Fjs.emitAsync.call(void 0, this.emitter, "response", {
877
+ requestId,
878
+ request,
879
+ response,
880
+ isMockedResponse
881
+ });
882
+ };
883
+ }
884
+ setup() {
885
+ const { get: originalGet, request: originalRequest } = _http2.default;
886
+ const { get: originalHttpsGet, request: originalHttpsRequest } = _https2.default;
887
+ const onRequest = this.onRequest.bind(this);
888
+ const onResponse = this.onResponse.bind(this);
889
+ _http2.default.request = new Proxy(_http2.default.request, {
890
+ apply: (target, thisArg, args) => {
891
+ const [url, options, callback] = normalizeClientRequestArgs(
892
+ "http:",
893
+ args
894
+ );
895
+ const mockAgent = new MockAgent({
896
+ customAgent: options.agent,
897
+ onRequest,
898
+ onResponse
899
+ });
900
+ options.agent = mockAgent;
901
+ return Reflect.apply(target, thisArg, [url, options, callback]);
902
+ }
903
+ });
904
+ _http2.default.get = new Proxy(_http2.default.get, {
905
+ apply: (target, thisArg, args) => {
906
+ const [url, options, callback] = normalizeClientRequestArgs(
907
+ "http:",
908
+ args
909
+ );
910
+ const mockAgent = new MockAgent({
911
+ customAgent: options.agent,
912
+ onRequest,
913
+ onResponse
914
+ });
915
+ options.agent = mockAgent;
916
+ return Reflect.apply(target, thisArg, [url, options, callback]);
917
+ }
918
+ });
919
+ _https2.default.request = new Proxy(_https2.default.request, {
920
+ apply: (target, thisArg, args) => {
921
+ const [url, options, callback] = normalizeClientRequestArgs(
922
+ "https:",
923
+ args
924
+ );
925
+ const mockAgent = new MockHttpsAgent({
926
+ customAgent: options.agent,
927
+ onRequest,
928
+ onResponse
929
+ });
930
+ options.agent = mockAgent;
931
+ return Reflect.apply(target, thisArg, [url, options, callback]);
932
+ }
933
+ });
934
+ _https2.default.get = new Proxy(_https2.default.get, {
935
+ apply: (target, thisArg, args) => {
936
+ const [url, options, callback] = normalizeClientRequestArgs(
937
+ "https:",
938
+ args
939
+ );
940
+ const mockAgent = new MockHttpsAgent({
941
+ customAgent: options.agent,
942
+ onRequest,
943
+ onResponse
944
+ });
945
+ options.agent = mockAgent;
946
+ return Reflect.apply(target, thisArg, [url, options, callback]);
947
+ }
948
+ });
949
+ this.subscriptions.push(() => {
950
+ _http2.default.get = originalGet;
951
+ _http2.default.request = originalRequest;
952
+ _https2.default.get = originalHttpsGet;
953
+ _https2.default.request = originalHttpsRequest;
954
+ });
955
+ }
956
+ };
957
+ var ClientRequestInterceptor = _ClientRequestInterceptor;
958
+ ClientRequestInterceptor.symbol = Symbol("client-request-interceptor");
959
+
960
+
961
+
962
+ exports.ClientRequestInterceptor = ClientRequestInterceptor;
963
+ //# sourceMappingURL=chunk-5JMJ55U7.js.map