@mswjs/interceptors 0.25.2 → 0.25.4

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 (30) hide show
  1. package/lib/browser/{chunk-TYEVJTWH.mjs → chunk-AN3YI76R.mjs} +6 -2
  2. package/lib/browser/{chunk-NMG5MQJJ.js → chunk-FFBQOFWV.js} +6 -2
  3. package/lib/browser/interceptors/XMLHttpRequest/index.js +2 -2
  4. package/lib/browser/interceptors/XMLHttpRequest/index.mjs +1 -1
  5. package/lib/browser/presets/browser.js +2 -2
  6. package/lib/browser/presets/browser.mjs +1 -1
  7. package/lib/node/RemoteHttpInterceptor.js +5 -4
  8. package/lib/node/RemoteHttpInterceptor.mjs +3 -2
  9. package/lib/node/chunk-3IYIKC3X.mjs +6 -0
  10. package/lib/node/{chunk-OMRBBJT7.mjs → chunk-6HZYLI7O.mjs} +38 -14
  11. package/lib/node/{chunk-B2CIOP5B.js → chunk-BAS5F5A4.js} +38 -14
  12. package/lib/node/{chunk-7RGC35CC.mjs → chunk-FB53TMYN.mjs} +6 -2
  13. package/lib/node/{chunk-5YAV7CXX.js → chunk-JCWVLTP7.js} +6 -2
  14. package/lib/node/chunk-OGN3ZR35.js +6 -0
  15. package/lib/node/interceptors/ClientRequest/index.js +3 -2
  16. package/lib/node/interceptors/ClientRequest/index.mjs +2 -1
  17. package/lib/node/interceptors/XMLHttpRequest/index.js +3 -2
  18. package/lib/node/interceptors/XMLHttpRequest/index.mjs +2 -1
  19. package/lib/node/presets/node.js +5 -4
  20. package/lib/node/presets/node.mjs +3 -2
  21. package/package.json +2 -2
  22. package/src/interceptors/ClientRequest/NodeClientRequest.ts +47 -27
  23. package/src/interceptors/ClientRequest/http.get.ts +3 -1
  24. package/src/interceptors/ClientRequest/http.request.ts +3 -1
  25. package/src/interceptors/ClientRequest/utils/createRequest.ts +15 -0
  26. package/src/interceptors/ClientRequest/utils/createResponse.test.ts +23 -0
  27. package/src/interceptors/ClientRequest/utils/createResponse.ts +18 -13
  28. package/src/interceptors/XMLHttpRequest/utils/createResponse.ts +4 -2
  29. package/src/utils/getUrlByRequestOptions.ts +12 -2
  30. package/src/utils/responseUtils.ts +5 -0
@@ -202,10 +202,14 @@ function parseJson(data) {
202
202
  }
203
203
  }
204
204
 
205
+ // src/utils/responseUtils.ts
206
+ var responseStatusCodesWithoutBody = [204, 205, 304];
207
+
205
208
  // src/interceptors/XMLHttpRequest/utils/createResponse.ts
206
- var statusCodesWithoutBody = [204, 205, 304];
207
209
  function createResponse(request, body) {
208
- const responseBodyOrNull = statusCodesWithoutBody.includes(request.status) ? null : body;
210
+ const responseBodyOrNull = responseStatusCodesWithoutBody.includes(
211
+ request.status
212
+ ) ? null : body;
209
213
  return new Response(responseBodyOrNull, {
210
214
  status: request.status,
211
215
  statusText: request.statusText,
@@ -202,10 +202,14 @@ function parseJson(data) {
202
202
  }
203
203
  }
204
204
 
205
+ // src/utils/responseUtils.ts
206
+ var responseStatusCodesWithoutBody = [204, 205, 304];
207
+
205
208
  // src/interceptors/XMLHttpRequest/utils/createResponse.ts
206
- var statusCodesWithoutBody = [204, 205, 304];
207
209
  function createResponse(request, body) {
208
- const responseBodyOrNull = statusCodesWithoutBody.includes(request.status) ? null : body;
210
+ const responseBodyOrNull = responseStatusCodesWithoutBody.includes(
211
+ request.status
212
+ ) ? null : body;
209
213
  return new Response(responseBodyOrNull, {
210
214
  status: request.status,
211
215
  statusText: request.statusText,
@@ -1,9 +1,9 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkNMG5MQJJjs = require('../../chunk-NMG5MQJJ.js');
3
+ var _chunkFFBQOFWVjs = require('../../chunk-FFBQOFWV.js');
4
4
  require('../../chunk-3LFH2WCF.js');
5
5
  require('../../chunk-X3NRJIZW.js');
6
6
  require('../../chunk-CWVY2E3W.js');
7
7
 
8
8
 
9
- exports.XMLHttpRequestInterceptor = _chunkNMG5MQJJjs.XMLHttpRequestInterceptor;
9
+ exports.XMLHttpRequestInterceptor = _chunkFFBQOFWVjs.XMLHttpRequestInterceptor;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  XMLHttpRequestInterceptor
3
- } from "../../chunk-TYEVJTWH.mjs";
3
+ } from "../../chunk-AN3YI76R.mjs";
4
4
  import "../../chunk-7II4SWKS.mjs";
5
5
  import "../../chunk-KK6APRON.mjs";
6
6
  import "../../chunk-QPMXOLDO.mjs";
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkNMG5MQJJjs = require('../chunk-NMG5MQJJ.js');
3
+ var _chunkFFBQOFWVjs = require('../chunk-FFBQOFWV.js');
4
4
  require('../chunk-3LFH2WCF.js');
5
5
 
6
6
 
@@ -11,7 +11,7 @@ require('../chunk-CWVY2E3W.js');
11
11
  // src/presets/browser.ts
12
12
  var browser_default = [
13
13
  new (0, _chunkKITNLK66js.FetchInterceptor)(),
14
- new (0, _chunkNMG5MQJJjs.XMLHttpRequestInterceptor)()
14
+ new (0, _chunkFFBQOFWVjs.XMLHttpRequestInterceptor)()
15
15
  ];
16
16
 
17
17
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  XMLHttpRequestInterceptor
3
- } from "../chunk-TYEVJTWH.mjs";
3
+ } from "../chunk-AN3YI76R.mjs";
4
4
  import "../chunk-7II4SWKS.mjs";
5
5
  import {
6
6
  FetchInterceptor
@@ -3,11 +3,12 @@
3
3
  var _chunkUF7QIAQ5js = require('./chunk-UF7QIAQ5.js');
4
4
 
5
5
 
6
- var _chunkB2CIOP5Bjs = require('./chunk-B2CIOP5B.js');
6
+ var _chunkBAS5F5A4js = require('./chunk-BAS5F5A4.js');
7
7
 
8
8
 
9
- var _chunk5YAV7CXXjs = require('./chunk-5YAV7CXX.js');
9
+ var _chunkJCWVLTP7js = require('./chunk-JCWVLTP7.js');
10
10
  require('./chunk-3LFH2WCF.js');
11
+ require('./chunk-OGN3ZR35.js');
11
12
  require('./chunk-VQ4DZOBB.js');
12
13
 
13
14
 
@@ -23,8 +24,8 @@ var RemoteHttpInterceptor = class extends _chunkUF7QIAQ5js.BatchInterceptor {
23
24
  super({
24
25
  name: "remote-interceptor",
25
26
  interceptors: [
26
- new (0, _chunkB2CIOP5Bjs.ClientRequestInterceptor)(),
27
- new (0, _chunk5YAV7CXXjs.XMLHttpRequestInterceptor)()
27
+ new (0, _chunkBAS5F5A4js.ClientRequestInterceptor)(),
28
+ new (0, _chunkJCWVLTP7js.XMLHttpRequestInterceptor)()
28
29
  ]
29
30
  });
30
31
  }
@@ -3,11 +3,12 @@ import {
3
3
  } from "./chunk-UBEFEZXT.mjs";
4
4
  import {
5
5
  ClientRequestInterceptor
6
- } from "./chunk-OMRBBJT7.mjs";
6
+ } from "./chunk-6HZYLI7O.mjs";
7
7
  import {
8
8
  XMLHttpRequestInterceptor
9
- } from "./chunk-7RGC35CC.mjs";
9
+ } from "./chunk-FB53TMYN.mjs";
10
10
  import "./chunk-7II4SWKS.mjs";
11
+ import "./chunk-3IYIKC3X.mjs";
11
12
  import "./chunk-GFH37L5D.mjs";
12
13
  import {
13
14
  emitAsync,
@@ -0,0 +1,6 @@
1
+ // src/utils/responseUtils.ts
2
+ var responseStatusCodesWithoutBody = [204, 205, 304];
3
+
4
+ export {
5
+ responseStatusCodesWithoutBody
6
+ };
@@ -1,3 +1,6 @@
1
+ import {
2
+ responseStatusCodesWithoutBody
3
+ } from "./chunk-3IYIKC3X.mjs";
1
4
  import {
2
5
  emitAsync,
3
6
  toInteractiveRequest,
@@ -103,13 +106,15 @@ function inheritProperties(source, target) {
103
106
 
104
107
  // src/interceptors/ClientRequest/utils/createResponse.ts
105
108
  function createResponse(message) {
106
- const readable = new ReadableStream({
109
+ const responseBodyOrNull = responseStatusCodesWithoutBody.includes(
110
+ message.statusCode || 200
111
+ ) ? null : new ReadableStream({
107
112
  start(controller) {
108
113
  message.on("data", (chunk) => controller.enqueue(chunk));
109
114
  message.on("end", () => controller.close());
110
115
  }
111
116
  });
112
- return new Response(readable, {
117
+ return new Response(responseBodyOrNull, {
113
118
  status: message.statusCode,
114
119
  statusText: message.statusMessage,
115
120
  headers: createHeadersFromIncomingHttpHeaders(message.headers)
@@ -147,6 +152,12 @@ function createRequest(clientRequest) {
147
152
  headers.append(headerName, value.toString());
148
153
  }
149
154
  }
155
+ if (clientRequest.url.username && clientRequest.url.password) {
156
+ const auth = `${clientRequest.url.username}:${clientRequest.url.password}`;
157
+ headers.set("Authorization", `Basic ${btoa(auth)}`);
158
+ clientRequest.url.username = "";
159
+ clientRequest.url.password = "";
160
+ }
150
161
  const method = clientRequest.method || "GET";
151
162
  return new Request(clientRequest.url, {
152
163
  method,
@@ -217,23 +228,27 @@ var _NodeClientRequest = class extends ClientRequest {
217
228
  this.removeHeader("X-Request-Id");
218
229
  return this.passthrough(chunk, encoding, callback);
219
230
  }
220
- this.logger.info(
221
- 'emitting the "request" event for %d listener(s)...',
222
- this.emitter.listenerCount("request")
223
- );
224
231
  this.emitter.once("request", ({ requestId: pendingRequestId }) => {
225
232
  if (pendingRequestId !== requestId) {
226
233
  return;
227
234
  }
228
235
  if (requestController.responsePromise.state === "pending") {
236
+ this.logger.info(
237
+ "request has not been handled in listeners, executing fail-safe listener..."
238
+ );
229
239
  requestController.responsePromise.resolve(void 0);
230
240
  }
231
241
  });
232
242
  until(async () => {
243
+ this.logger.info(
244
+ 'emitting the "request" event for %d listener(s)...',
245
+ this.emitter.listenerCount("request")
246
+ );
233
247
  await emitAsync(this.emitter, "request", {
234
248
  request: interactiveRequest,
235
249
  requestId
236
250
  });
251
+ this.logger.info('all "request" listeners done!');
237
252
  const mockedResponse = await requestController.responsePromise;
238
253
  this.logger.info("event.respondWith called with:", mockedResponse);
239
254
  return mockedResponse;
@@ -249,13 +264,19 @@ var _NodeClientRequest = class extends ClientRequest {
249
264
  "encountered resolver exception, aborting request...",
250
265
  resolverResult.error
251
266
  );
267
+ this.destroyed = true;
252
268
  this.emit("error", resolverResult.error);
253
269
  this.terminate();
254
270
  return this;
255
271
  }
256
272
  const mockedResponse = resolverResult.data;
257
273
  if (mockedResponse) {
258
- this.logger.info("received mocked response:", mockedResponse);
274
+ this.logger.info(
275
+ "received mocked response:",
276
+ mockedResponse.status,
277
+ mockedResponse.statusText
278
+ );
279
+ this.destroyed = false;
259
280
  if (mockedResponse.type === "error") {
260
281
  this.logger.info(
261
282
  "received network error response, aborting request..."
@@ -387,9 +408,13 @@ var _NodeClientRequest = class extends ClientRequest {
387
408
  });
388
409
  }
389
410
  this.logger.info("mocked response headers ready:", headers);
411
+ this.res = this.response;
412
+ this.emit("response", this.response);
390
413
  const isResponseStreamFinished = new DeferredPromise();
391
414
  const finishResponseStream = () => {
392
415
  this.logger.info("finished response stream!");
416
+ this.response.push(null);
417
+ this.response.complete = true;
393
418
  isResponseStreamFinished.resolve();
394
419
  };
395
420
  if (body) {
@@ -407,14 +432,11 @@ var _NodeClientRequest = class extends ClientRequest {
407
432
  } else {
408
433
  finishResponseStream();
409
434
  }
410
- this.res = this.response;
411
- this.emit("response", this.response);
412
435
  isResponseStreamFinished.then(() => {
413
436
  this.logger.info("finalizing response...");
414
- this.response.push(null);
415
- this.response.complete = true;
416
437
  this.response.emit("end");
417
438
  this.terminate();
439
+ this.logger.info("request complete!");
418
440
  });
419
441
  }
420
442
  /**
@@ -560,7 +582,9 @@ function getUrlByRequestOptions(options) {
560
582
  logger3.info("credentials", credentials);
561
583
  const authString = credentials ? `${credentials.username}:${credentials.password}@` : "";
562
584
  logger3.info("auth string:", authString);
563
- const url = new URL(`${protocol}//${authString}${hostname}${path}`);
585
+ const url = new URL(`${protocol}//${hostname}${path}`);
586
+ url.username = (credentials == null ? void 0 : credentials.username) || "";
587
+ url.password = (credentials == null ? void 0 : credentials.password) || "";
564
588
  logger3.info("created url:", url);
565
589
  return url;
566
590
  }
@@ -702,7 +726,7 @@ function normalizeClientRequestArgs(defaultProtocol, ...args) {
702
726
 
703
727
  // src/interceptors/ClientRequest/http.get.ts
704
728
  function get(protocol, options) {
705
- return (...args) => {
729
+ return function interceptorsHttpGet(...args) {
706
730
  const clientRequestArgs = normalizeClientRequestArgs(
707
731
  `${protocol}:`,
708
732
  ...args
@@ -717,7 +741,7 @@ function get(protocol, options) {
717
741
  import { Logger as Logger6 } from "@open-draft/logger";
718
742
  var logger6 = new Logger6("http request");
719
743
  function request(protocol, options) {
720
- return (...args) => {
744
+ return function interceptorsHttpRequest(...args) {
721
745
  logger6.info('request call (protocol "%s"):', protocol, args);
722
746
  const clientRequestArgs = normalizeClientRequestArgs(
723
747
  `${protocol}:`,
@@ -1,5 +1,8 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2
2
 
3
+ var _chunkOGN3ZR35js = require('./chunk-OGN3ZR35.js');
4
+
5
+
3
6
 
4
7
 
5
8
  var _chunk5PTPJLB7js = require('./chunk-5PTPJLB7.js');
@@ -103,13 +106,15 @@ function inheritProperties(source, target) {
103
106
 
104
107
  // src/interceptors/ClientRequest/utils/createResponse.ts
105
108
  function createResponse(message) {
106
- const readable = new ReadableStream({
109
+ const responseBodyOrNull = _chunkOGN3ZR35js.responseStatusCodesWithoutBody.includes(
110
+ message.statusCode || 200
111
+ ) ? null : new ReadableStream({
107
112
  start(controller) {
108
113
  message.on("data", (chunk) => controller.enqueue(chunk));
109
114
  message.on("end", () => controller.close());
110
115
  }
111
116
  });
112
- return new Response(readable, {
117
+ return new Response(responseBodyOrNull, {
113
118
  status: message.statusCode,
114
119
  statusText: message.statusMessage,
115
120
  headers: createHeadersFromIncomingHttpHeaders(message.headers)
@@ -147,6 +152,12 @@ function createRequest(clientRequest) {
147
152
  headers.append(headerName, value.toString());
148
153
  }
149
154
  }
155
+ if (clientRequest.url.username && clientRequest.url.password) {
156
+ const auth = `${clientRequest.url.username}:${clientRequest.url.password}`;
157
+ headers.set("Authorization", `Basic ${btoa(auth)}`);
158
+ clientRequest.url.username = "";
159
+ clientRequest.url.password = "";
160
+ }
150
161
  const method = clientRequest.method || "GET";
151
162
  return new Request(clientRequest.url, {
152
163
  method,
@@ -217,23 +228,27 @@ var _NodeClientRequest = class extends _http.ClientRequest {
217
228
  this.removeHeader("X-Request-Id");
218
229
  return this.passthrough(chunk, encoding, callback);
219
230
  }
220
- this.logger.info(
221
- 'emitting the "request" event for %d listener(s)...',
222
- this.emitter.listenerCount("request")
223
- );
224
231
  this.emitter.once("request", ({ requestId: pendingRequestId }) => {
225
232
  if (pendingRequestId !== requestId) {
226
233
  return;
227
234
  }
228
235
  if (requestController.responsePromise.state === "pending") {
236
+ this.logger.info(
237
+ "request has not been handled in listeners, executing fail-safe listener..."
238
+ );
229
239
  requestController.responsePromise.resolve(void 0);
230
240
  }
231
241
  });
232
242
  _until.until.call(void 0, async () => {
243
+ this.logger.info(
244
+ 'emitting the "request" event for %d listener(s)...',
245
+ this.emitter.listenerCount("request")
246
+ );
233
247
  await _chunk5PTPJLB7js.emitAsync.call(void 0, this.emitter, "request", {
234
248
  request: interactiveRequest,
235
249
  requestId
236
250
  });
251
+ this.logger.info('all "request" listeners done!');
237
252
  const mockedResponse = await requestController.responsePromise;
238
253
  this.logger.info("event.respondWith called with:", mockedResponse);
239
254
  return mockedResponse;
@@ -249,13 +264,19 @@ var _NodeClientRequest = class extends _http.ClientRequest {
249
264
  "encountered resolver exception, aborting request...",
250
265
  resolverResult.error
251
266
  );
267
+ this.destroyed = true;
252
268
  this.emit("error", resolverResult.error);
253
269
  this.terminate();
254
270
  return this;
255
271
  }
256
272
  const mockedResponse = resolverResult.data;
257
273
  if (mockedResponse) {
258
- this.logger.info("received mocked response:", mockedResponse);
274
+ this.logger.info(
275
+ "received mocked response:",
276
+ mockedResponse.status,
277
+ mockedResponse.statusText
278
+ );
279
+ this.destroyed = false;
259
280
  if (mockedResponse.type === "error") {
260
281
  this.logger.info(
261
282
  "received network error response, aborting request..."
@@ -387,9 +408,13 @@ var _NodeClientRequest = class extends _http.ClientRequest {
387
408
  });
388
409
  }
389
410
  this.logger.info("mocked response headers ready:", headers);
411
+ this.res = this.response;
412
+ this.emit("response", this.response);
390
413
  const isResponseStreamFinished = new (0, _deferredpromise.DeferredPromise)();
391
414
  const finishResponseStream = () => {
392
415
  this.logger.info("finished response stream!");
416
+ this.response.push(null);
417
+ this.response.complete = true;
393
418
  isResponseStreamFinished.resolve();
394
419
  };
395
420
  if (body) {
@@ -407,14 +432,11 @@ var _NodeClientRequest = class extends _http.ClientRequest {
407
432
  } else {
408
433
  finishResponseStream();
409
434
  }
410
- this.res = this.response;
411
- this.emit("response", this.response);
412
435
  isResponseStreamFinished.then(() => {
413
436
  this.logger.info("finalizing response...");
414
- this.response.push(null);
415
- this.response.complete = true;
416
437
  this.response.emit("end");
417
438
  this.terminate();
439
+ this.logger.info("request complete!");
418
440
  });
419
441
  }
420
442
  /**
@@ -560,7 +582,9 @@ function getUrlByRequestOptions(options) {
560
582
  logger3.info("credentials", credentials);
561
583
  const authString = credentials ? `${credentials.username}:${credentials.password}@` : "";
562
584
  logger3.info("auth string:", authString);
563
- const url = new URL(`${protocol}//${authString}${hostname}${path}`);
585
+ const url = new URL(`${protocol}//${hostname}${path}`);
586
+ url.username = (credentials == null ? void 0 : credentials.username) || "";
587
+ url.password = (credentials == null ? void 0 : credentials.password) || "";
564
588
  logger3.info("created url:", url);
565
589
  return url;
566
590
  }
@@ -702,7 +726,7 @@ function normalizeClientRequestArgs(defaultProtocol, ...args) {
702
726
 
703
727
  // src/interceptors/ClientRequest/http.get.ts
704
728
  function get(protocol, options) {
705
- return (...args) => {
729
+ return function interceptorsHttpGet(...args) {
706
730
  const clientRequestArgs = normalizeClientRequestArgs(
707
731
  `${protocol}:`,
708
732
  ...args
@@ -717,7 +741,7 @@ function get(protocol, options) {
717
741
 
718
742
  var logger6 = new (0, _logger.Logger)("http request");
719
743
  function request(protocol, options) {
720
- return (...args) => {
744
+ return function interceptorsHttpRequest(...args) {
721
745
  logger6.info('request call (protocol "%s"):', protocol, args);
722
746
  const clientRequestArgs = normalizeClientRequestArgs(
723
747
  `${protocol}:`,
@@ -3,6 +3,9 @@ import {
3
3
  encodeBuffer,
4
4
  toArrayBuffer
5
5
  } from "./chunk-7II4SWKS.mjs";
6
+ import {
7
+ responseStatusCodesWithoutBody
8
+ } from "./chunk-3IYIKC3X.mjs";
6
9
  import {
7
10
  IS_PATCHED_MODULE
8
11
  } from "./chunk-GFH37L5D.mjs";
@@ -205,9 +208,10 @@ function parseJson(data) {
205
208
  }
206
209
 
207
210
  // src/interceptors/XMLHttpRequest/utils/createResponse.ts
208
- var statusCodesWithoutBody = [204, 205, 304];
209
211
  function createResponse(request, body) {
210
- const responseBodyOrNull = statusCodesWithoutBody.includes(request.status) ? null : body;
212
+ const responseBodyOrNull = responseStatusCodesWithoutBody.includes(
213
+ request.status
214
+ ) ? null : body;
211
215
  return new Response(responseBodyOrNull, {
212
216
  status: request.status,
213
217
  statusText: request.statusText,
@@ -5,6 +5,9 @@
5
5
  var _chunk3LFH2WCFjs = require('./chunk-3LFH2WCF.js');
6
6
 
7
7
 
8
+ var _chunkOGN3ZR35js = require('./chunk-OGN3ZR35.js');
9
+
10
+
8
11
  var _chunkVQ4DZOBBjs = require('./chunk-VQ4DZOBB.js');
9
12
 
10
13
 
@@ -205,9 +208,10 @@ function parseJson(data) {
205
208
  }
206
209
 
207
210
  // src/interceptors/XMLHttpRequest/utils/createResponse.ts
208
- var statusCodesWithoutBody = [204, 205, 304];
209
211
  function createResponse(request, body) {
210
- const responseBodyOrNull = statusCodesWithoutBody.includes(request.status) ? null : body;
212
+ const responseBodyOrNull = _chunkOGN3ZR35js.responseStatusCodesWithoutBody.includes(
213
+ request.status
214
+ ) ? null : body;
211
215
  return new Response(responseBodyOrNull, {
212
216
  status: request.status,
213
217
  statusText: request.statusText,
@@ -0,0 +1,6 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/utils/responseUtils.ts
2
+ var responseStatusCodesWithoutBody = [204, 205, 304];
3
+
4
+
5
+
6
+ exports.responseStatusCodesWithoutBody = responseStatusCodesWithoutBody;
@@ -1,8 +1,9 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkB2CIOP5Bjs = require('../../chunk-B2CIOP5B.js');
3
+ var _chunkBAS5F5A4js = require('../../chunk-BAS5F5A4.js');
4
+ require('../../chunk-OGN3ZR35.js');
4
5
  require('../../chunk-5PTPJLB7.js');
5
6
  require('../../chunk-3XFLRXRY.js');
6
7
 
7
8
 
8
- exports.ClientRequestInterceptor = _chunkB2CIOP5Bjs.ClientRequestInterceptor;
9
+ exports.ClientRequestInterceptor = _chunkBAS5F5A4js.ClientRequestInterceptor;
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  ClientRequestInterceptor
3
- } from "../../chunk-OMRBBJT7.mjs";
3
+ } from "../../chunk-6HZYLI7O.mjs";
4
+ import "../../chunk-3IYIKC3X.mjs";
4
5
  import "../../chunk-YQGTMMOZ.mjs";
5
6
  import "../../chunk-GM3YBSM3.mjs";
6
7
  export {
@@ -1,10 +1,11 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunk5YAV7CXXjs = require('../../chunk-5YAV7CXX.js');
3
+ var _chunkJCWVLTP7js = require('../../chunk-JCWVLTP7.js');
4
4
  require('../../chunk-3LFH2WCF.js');
5
+ require('../../chunk-OGN3ZR35.js');
5
6
  require('../../chunk-VQ4DZOBB.js');
6
7
  require('../../chunk-5PTPJLB7.js');
7
8
  require('../../chunk-3XFLRXRY.js');
8
9
 
9
10
 
10
- exports.XMLHttpRequestInterceptor = _chunk5YAV7CXXjs.XMLHttpRequestInterceptor;
11
+ exports.XMLHttpRequestInterceptor = _chunkJCWVLTP7js.XMLHttpRequestInterceptor;
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  XMLHttpRequestInterceptor
3
- } from "../../chunk-7RGC35CC.mjs";
3
+ } from "../../chunk-FB53TMYN.mjs";
4
4
  import "../../chunk-7II4SWKS.mjs";
5
+ import "../../chunk-3IYIKC3X.mjs";
5
6
  import "../../chunk-GFH37L5D.mjs";
6
7
  import "../../chunk-YQGTMMOZ.mjs";
7
8
  import "../../chunk-GM3YBSM3.mjs";
@@ -1,18 +1,19 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkB2CIOP5Bjs = require('../chunk-B2CIOP5B.js');
3
+ var _chunkBAS5F5A4js = require('../chunk-BAS5F5A4.js');
4
4
 
5
5
 
6
- var _chunk5YAV7CXXjs = require('../chunk-5YAV7CXX.js');
6
+ var _chunkJCWVLTP7js = require('../chunk-JCWVLTP7.js');
7
7
  require('../chunk-3LFH2WCF.js');
8
+ require('../chunk-OGN3ZR35.js');
8
9
  require('../chunk-VQ4DZOBB.js');
9
10
  require('../chunk-5PTPJLB7.js');
10
11
  require('../chunk-3XFLRXRY.js');
11
12
 
12
13
  // src/presets/node.ts
13
14
  var node_default = [
14
- new (0, _chunkB2CIOP5Bjs.ClientRequestInterceptor)(),
15
- new (0, _chunk5YAV7CXXjs.XMLHttpRequestInterceptor)()
15
+ new (0, _chunkBAS5F5A4js.ClientRequestInterceptor)(),
16
+ new (0, _chunkJCWVLTP7js.XMLHttpRequestInterceptor)()
16
17
  ];
17
18
 
18
19
 
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  ClientRequestInterceptor
3
- } from "../chunk-OMRBBJT7.mjs";
3
+ } from "../chunk-6HZYLI7O.mjs";
4
4
  import {
5
5
  XMLHttpRequestInterceptor
6
- } from "../chunk-7RGC35CC.mjs";
6
+ } from "../chunk-FB53TMYN.mjs";
7
7
  import "../chunk-7II4SWKS.mjs";
8
+ import "../chunk-3IYIKC3X.mjs";
8
9
  import "../chunk-GFH37L5D.mjs";
9
10
  import "../chunk-YQGTMMOZ.mjs";
10
11
  import "../chunk-GM3YBSM3.mjs";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mswjs/interceptors",
3
3
  "description": "Low-level HTTP/HTTPS/XHR/fetch request interception library.",
4
- "version": "0.25.2",
4
+ "version": "0.25.4",
5
5
  "main": "./lib/node/index.js",
6
6
  "module": "./lib/node/index.mjs",
7
7
  "types": "./lib/node/index.d.ts",
@@ -128,7 +128,7 @@
128
128
  "@open-draft/until": "^2.0.0",
129
129
  "is-node-process": "^1.2.0",
130
130
  "outvariant": "^1.2.1",
131
- "strict-event-emitter": "^0.5.0"
131
+ "strict-event-emitter": "^0.5.1"
132
132
  },
133
133
  "resolutions": {
134
134
  "memfs": "^3.4.13"
@@ -160,13 +160,6 @@ export class NodeClientRequest extends ClientRequest {
160
160
  return this.passthrough(chunk, encoding, callback)
161
161
  }
162
162
 
163
- // Notify the interceptor about the request.
164
- // This will call any "request" listeners the users have.
165
- this.logger.info(
166
- 'emitting the "request" event for %d listener(s)...',
167
- this.emitter.listenerCount('request')
168
- )
169
-
170
163
  // Add the last "request" listener that always resolves
171
164
  // the pending response Promise. This way if the consumer
172
165
  // hasn't handled the request themselves, we will prevent
@@ -181,6 +174,10 @@ export class NodeClientRequest extends ClientRequest {
181
174
  }
182
175
 
183
176
  if (requestController.responsePromise.state === 'pending') {
177
+ this.logger.info(
178
+ 'request has not been handled in listeners, executing fail-safe listener...'
179
+ )
180
+
184
181
  requestController.responsePromise.resolve(undefined)
185
182
  }
186
183
  })
@@ -188,11 +185,20 @@ export class NodeClientRequest extends ClientRequest {
188
185
  // Execute the resolver Promise like a side-effect.
189
186
  // Node.js 16 forces "ClientRequest.end" to be synchronous and return "this".
190
187
  until(async () => {
188
+ // Notify the interceptor about the request.
189
+ // This will call any "request" listeners the users have.
190
+ this.logger.info(
191
+ 'emitting the "request" event for %d listener(s)...',
192
+ this.emitter.listenerCount('request')
193
+ )
194
+
191
195
  await emitAsync(this.emitter, 'request', {
192
196
  request: interactiveRequest,
193
197
  requestId,
194
198
  })
195
199
 
200
+ this.logger.info('all "request" listeners done!')
201
+
196
202
  const mockedResponse = await requestController.responsePromise
197
203
  this.logger.info('event.respondWith called with:', mockedResponse)
198
204
 
@@ -220,6 +226,8 @@ export class NodeClientRequest extends ClientRequest {
220
226
  'encountered resolver exception, aborting request...',
221
227
  resolverResult.error
222
228
  )
229
+
230
+ this.destroyed = true
223
231
  this.emit('error', resolverResult.error)
224
232
  this.terminate()
225
233
 
@@ -229,7 +237,17 @@ export class NodeClientRequest extends ClientRequest {
229
237
  const mockedResponse = resolverResult.data
230
238
 
231
239
  if (mockedResponse) {
232
- this.logger.info('received mocked response:', mockedResponse)
240
+ this.logger.info(
241
+ 'received mocked response:',
242
+ mockedResponse.status,
243
+ mockedResponse.statusText
244
+ )
245
+
246
+ /**
247
+ * @note Ignore this request being destroyed by TLS in Node.js
248
+ * due to connection errors.
249
+ */
250
+ this.destroyed = false
233
251
 
234
252
  // Handle mocked "Response.error" network error responses.
235
253
  if (mockedResponse.type === 'error') {
@@ -448,10 +466,29 @@ export class NodeClientRequest extends ClientRequest {
448
466
  }
449
467
  this.logger.info('mocked response headers ready:', headers)
450
468
 
469
+ /**
470
+ * Set the internal "res" property to the mocked "OutgoingMessage"
471
+ * to make the "ClientRequest" instance think there's data received
472
+ * from the socket.
473
+ * @see https://github.com/nodejs/node/blob/9c405f2591f5833d0247ed0fafdcd68c5b14ce7a/lib/_http_client.js#L501
474
+ *
475
+ * Set the response immediately so the interceptor could stream data
476
+ * chunks to the request client as they come in.
477
+ */
478
+ // @ts-ignore
479
+ this.res = this.response
480
+ this.emit('response', this.response)
481
+
451
482
  const isResponseStreamFinished = new DeferredPromise<void>()
452
483
 
453
484
  const finishResponseStream = () => {
454
485
  this.logger.info('finished response stream!')
486
+
487
+ // Push "null" to indicate that the response body is complete
488
+ // and shouldn't be written to anymore.
489
+ this.response.push(null)
490
+ this.response.complete = true
491
+
455
492
  isResponseStreamFinished.resolve()
456
493
  }
457
494
 
@@ -475,29 +512,12 @@ export class NodeClientRequest extends ClientRequest {
475
512
  finishResponseStream()
476
513
  }
477
514
 
478
- /**
479
- * Set the internal "res" property to the mocked "OutgoingMessage"
480
- * to make the "ClientRequest" instance think there's data received
481
- * from the socket.
482
- * @see https://github.com/nodejs/node/blob/9c405f2591f5833d0247ed0fafdcd68c5b14ce7a/lib/_http_client.js#L501
483
- *
484
- * Set the response immediately so the interceptor could stream data
485
- * chunks to the request client as they come in.
486
- */
487
- // @ts-ignore
488
- this.res = this.response
489
- this.emit('response', this.response)
490
-
491
515
  isResponseStreamFinished.then(() => {
492
516
  this.logger.info('finalizing response...')
493
-
494
- // Push "null" to indicate that the response body is complete
495
- // and shouldn't be written to anymore.
496
- this.response.push(null)
497
- this.response.complete = true
498
517
  this.response.emit('end')
499
-
500
518
  this.terminate()
519
+
520
+ this.logger.info('request complete!')
501
521
  })
502
522
  }
503
523
 
@@ -10,7 +10,9 @@ import {
10
10
  } from './utils/normalizeClientRequestArgs'
11
11
 
12
12
  export function get(protocol: Protocol, options: NodeClientOptions) {
13
- return (...args: ClientRequestArgs): ClientRequest => {
13
+ return function interceptorsHttpGet(
14
+ ...args: ClientRequestArgs
15
+ ): ClientRequest {
14
16
  const clientRequestArgs = normalizeClientRequestArgs(
15
17
  `${protocol}:`,
16
18
  ...args
@@ -13,7 +13,9 @@ import {
13
13
  const logger = new Logger('http request')
14
14
 
15
15
  export function request(protocol: Protocol, options: NodeClientOptions) {
16
- return (...args: ClientRequestArgs): ClientRequest => {
16
+ return function interceptorsHttpRequest(
17
+ ...args: ClientRequestArgs
18
+ ): ClientRequest {
17
19
  logger.info('request call (protocol "%s"):', protocol, args)
18
20
 
19
21
  const clientRequestArgs = normalizeClientRequestArgs(
@@ -20,6 +20,21 @@ export function createRequest(clientRequest: NodeClientRequest): Request {
20
20
  }
21
21
  }
22
22
 
23
+ /**
24
+ * Translate the authentication from the request URL to
25
+ * the request "Authorization" header.
26
+ * @see https://github.com/mswjs/interceptors/issues/438
27
+ */
28
+ if (clientRequest.url.username && clientRequest.url.password) {
29
+ const auth = `${clientRequest.url.username}:${clientRequest.url.password}`
30
+ headers.set('Authorization', `Basic ${btoa(auth)}`)
31
+
32
+ // Remove the credentials from the URL since you cannot
33
+ // construct a Request instance with such a URL.
34
+ clientRequest.url.username = ''
35
+ clientRequest.url.password = ''
36
+ }
37
+
23
38
  const method = clientRequest.method || 'GET'
24
39
 
25
40
  return new Request(clientRequest.url, {
@@ -2,6 +2,7 @@ import { it, expect } from 'vitest'
2
2
  import { Socket } from 'net'
3
3
  import * as http from 'http'
4
4
  import { createResponse } from './createResponse'
5
+ import { responseStatusCodesWithoutBody } from '../../../utils/responseUtils'
5
6
 
6
7
  it('creates a fetch api response from http incoming message', async () => {
7
8
  const message = new http.IncomingMessage(new Socket())
@@ -20,3 +21,25 @@ it('creates a fetch api response from http incoming message', async () => {
20
21
  expect(response.headers.get('content-type')).toBe('application/json')
21
22
  expect(await response.json()).toEqual({ firstName: 'John' })
22
23
  })
24
+
25
+ it.each(responseStatusCodesWithoutBody)(
26
+ 'ignores message body for %i response status',
27
+ (responseStatus) => {
28
+ const message = new http.IncomingMessage(new Socket())
29
+ message.statusCode = responseStatus
30
+
31
+ const response = createResponse(message)
32
+
33
+ // These chunks will be ignored: this response
34
+ // cannot have body. We don't forward this error to
35
+ // the consumer because it's us who converts the
36
+ // internal stream to a Fetch API Response instance.
37
+ // Consumers will rely on the Response API when constructing
38
+ // mocked responses.
39
+ message.emit('data', Buffer.from('hello'))
40
+ message.emit('end')
41
+
42
+ expect(response.status).toBe(responseStatus)
43
+ expect(response.body).toBe(null)
44
+ }
45
+ )
@@ -1,24 +1,29 @@
1
1
  import type { IncomingHttpHeaders, IncomingMessage } from 'http'
2
+ import { responseStatusCodesWithoutBody } from '../../../utils/responseUtils'
2
3
 
3
4
  /**
4
5
  * Creates a Fetch API `Response` instance from the given
5
6
  * `http.IncomingMessage` instance.
6
7
  */
7
8
  export function createResponse(message: IncomingMessage): Response {
8
- const readable = new ReadableStream({
9
- start(controller) {
10
- message.on('data', (chunk) => controller.enqueue(chunk))
11
- message.on('end', () => controller.close())
12
-
13
- /**
14
- * @todo Should also listen to the "error" on the message
15
- * and forward it to the controller. Otherwise the stream
16
- * will pend indefinitely.
17
- */
18
- },
19
- })
9
+ const responseBodyOrNull = responseStatusCodesWithoutBody.includes(
10
+ message.statusCode || 200
11
+ )
12
+ ? null
13
+ : new ReadableStream({
14
+ start(controller) {
15
+ message.on('data', (chunk) => controller.enqueue(chunk))
16
+ message.on('end', () => controller.close())
17
+
18
+ /**
19
+ * @todo Should also listen to the "error" on the message
20
+ * and forward it to the controller. Otherwise the stream
21
+ * will pend indefinitely.
22
+ */
23
+ },
24
+ })
20
25
 
21
- return new Response(readable, {
26
+ return new Response(responseBodyOrNull, {
22
27
  status: message.statusCode,
23
28
  statusText: message.statusMessage,
24
29
  headers: createHeadersFromIncomingHttpHeaders(message.headers),
@@ -1,4 +1,4 @@
1
- const statusCodesWithoutBody = [204, 205, 304]
1
+ import { responseStatusCodesWithoutBody } from '../../../utils/responseUtils'
2
2
 
3
3
  /**
4
4
  * Creates a Fetch API `Response` instance from the given
@@ -16,7 +16,9 @@ export function createResponse(
16
16
  * when constructing a Response instance.
17
17
  * @see https://github.com/mswjs/interceptors/issues/379
18
18
  */
19
- const responseBodyOrNull = statusCodesWithoutBody.includes(request.status)
19
+ const responseBodyOrNull = responseStatusCodesWithoutBody.includes(
20
+ request.status
21
+ )
20
22
  ? null
21
23
  : body
22
24
 
@@ -86,7 +86,14 @@ function getHostByRequestOptions(options: ResolvedRequestOptions): string {
86
86
  return host || DEFAULT_HOST
87
87
  }
88
88
 
89
- function getAuthByRequestOptions(options: ResolvedRequestOptions) {
89
+ interface RequestAuth {
90
+ username: string
91
+ password: string
92
+ }
93
+
94
+ function getAuthByRequestOptions(
95
+ options: ResolvedRequestOptions
96
+ ): RequestAuth | undefined {
90
97
  if (options.auth) {
91
98
  const [username, password] = options.auth.split(':')
92
99
  return { username, password }
@@ -159,7 +166,10 @@ export function getUrlByRequestOptions(options: ResolvedRequestOptions): URL {
159
166
  : ''
160
167
  logger.info('auth string:', authString)
161
168
 
162
- const url = new URL(`${protocol}//${authString}${hostname}${path}`)
169
+ const url = new URL(`${protocol}//${hostname}${path}`)
170
+ url.username = credentials?.username || ''
171
+ url.password = credentials?.password || ''
172
+
163
173
  logger.info('created url:', url)
164
174
 
165
175
  return url
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Response status codes for responses that cannot have body.
3
+ * @see https://fetch.spec.whatwg.org/#statuses
4
+ */
5
+ export const responseStatusCodesWithoutBody = [204, 205, 304]