@zimic/interceptor 1.2.7-canary.2 → 1.3.0-canary.0

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.
package/dist/http.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { InvalidFormDataError as InvalidFormDataError$1, InvalidJSONError as InvalidJSONError$1, HTTP_METHODS, HttpHeaders, HttpSearchParams, HttpFormData, parseHttpBody } from '@zimic/http';
2
2
  import color2 from 'picocolors';
3
- import { http, passthrough } from 'msw';
3
+ import { http, bypass, passthrough } from 'msw';
4
4
  import * as mswBrowser from 'msw/browser';
5
5
  import * as mswNode from 'msw/node';
6
6
  import ClientSocket from 'isomorphic-ws';
@@ -1042,6 +1042,7 @@ var DEFAULT_UNHANDLED_REQUEST_STRATEGY = Object.freeze({
1042
1042
  });
1043
1043
 
1044
1044
  // src/http/interceptorWorker/HttpInterceptorWorker.ts
1045
+ var RESPONSE_ACTION_SYMBOL = Symbol.for("HttpResponse.action");
1045
1046
  var HttpInterceptorWorker = class _HttpInterceptorWorker {
1046
1047
  platform = null;
1047
1048
  isRunning = false;
@@ -1138,17 +1139,57 @@ var HttpInterceptorWorker = class _HttpInterceptorWorker {
1138
1139
  }
1139
1140
  return interceptor.onUnhandledRequest;
1140
1141
  }
1141
- static createResponseFromDeclaration(request, declaration) {
1142
+ static setResponseAction(response, action) {
1143
+ Object.defineProperty(response, RESPONSE_ACTION_SYMBOL, {
1144
+ value: action,
1145
+ enumerable: false,
1146
+ configurable: false,
1147
+ writable: false
1148
+ });
1149
+ }
1150
+ static getResponseAction(response) {
1151
+ if (!(RESPONSE_ACTION_SYMBOL in response)) {
1152
+ return void 0;
1153
+ }
1154
+ const action = response[RESPONSE_ACTION_SYMBOL];
1155
+ if (action !== "bypass" && action !== "reject") {
1156
+ return void 0;
1157
+ }
1158
+ return action;
1159
+ }
1160
+ createBypassedResponse() {
1161
+ const response = Response.redirect("about:blank", 302);
1162
+ _HttpInterceptorWorker.setResponseAction(response, "bypass");
1163
+ return response;
1164
+ }
1165
+ static isBypassedResponse(response) {
1166
+ return this.getResponseAction(response) === "bypass";
1167
+ }
1168
+ createRejectedResponse() {
1169
+ const response = Response.error();
1170
+ _HttpInterceptorWorker.setResponseAction(response, "reject");
1171
+ return response;
1172
+ }
1173
+ static isRejectedResponse(response) {
1174
+ return this.getResponseAction(response) === "reject";
1175
+ }
1176
+ createResponseFromDeclaration(request, declaration) {
1177
+ if ("action" in declaration) {
1178
+ if (declaration.action === "bypass") {
1179
+ return this.createBypassedResponse();
1180
+ } else {
1181
+ return this.createRejectedResponse();
1182
+ }
1183
+ }
1142
1184
  const headers = new HttpHeaders(declaration.headers);
1143
- const status = declaration.status;
1144
- const canHaveBody = methodCanHaveResponseBody(request.method) && status !== 204;
1185
+ const canHaveBody = methodCanHaveResponseBody(request.method) && declaration.status !== 204;
1145
1186
  if (!canHaveBody) {
1146
- return new Response(null, { headers, status });
1187
+ return new Response(null, { headers, status: declaration.status });
1147
1188
  }
1148
1189
  if (typeof declaration.body === "string" || declaration.body === null || declaration.body === void 0 || declaration.body instanceof FormData || declaration.body instanceof URLSearchParams || declaration.body instanceof Blob || declaration.body instanceof ArrayBuffer || declaration.body instanceof ReadableStream) {
1149
- return new Response(declaration.body ?? null, { headers, status });
1190
+ return new Response(declaration.body ?? null, { headers, status: declaration.status });
1150
1191
  }
1151
- return Response.json(declaration.body, { headers, status });
1192
+ return Response.json(declaration.body, { headers, status: declaration.status });
1152
1193
  }
1153
1194
  static async parseRawUnhandledRequest(request) {
1154
1195
  return this.parseRawRequest(
@@ -1577,8 +1618,9 @@ var HttpInterceptorClient = class {
1577
1618
  if (!responseDeclaration) {
1578
1619
  return null;
1579
1620
  }
1580
- const response = HttpInterceptorWorker_default.createResponseFromDeclaration(request, responseDeclaration);
1581
- if (this.requestSaving.enabled) {
1621
+ const response = await this.workerOrThrow.createResponseFromDeclaration(request, responseDeclaration);
1622
+ const shouldSaveInterceptedRequest = this.requestSaving.enabled && response && !HttpInterceptorWorker_default.isRejectedResponse(response);
1623
+ if (shouldSaveInterceptedRequest) {
1582
1624
  const responseClone = response.clone();
1583
1625
  const parsedResponse = await HttpInterceptorWorker_default.parseRawResponse(responseClone);
1584
1626
  matchedHandler.saveInterceptedRequest(parsedRequest, parsedResponse);
@@ -1795,7 +1837,7 @@ var LocalHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
1795
1837
  const requestClone = request.clone();
1796
1838
  let response = null;
1797
1839
  try {
1798
- response = await createResponse({ ...context, request });
1840
+ response = await createResponse({ request });
1799
1841
  } catch (error) {
1800
1842
  console.error(error);
1801
1843
  }
@@ -1814,6 +1856,23 @@ var LocalHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
1814
1856
  };
1815
1857
  methodHandlers.push(handler);
1816
1858
  }
1859
+ async createResponseFromDeclaration(request, declaration) {
1860
+ const requestClone = request.clone();
1861
+ const response = await super.createResponseFromDeclaration(request, declaration);
1862
+ if (response && HttpInterceptorWorker_default.isBypassedResponse(response)) {
1863
+ try {
1864
+ const response2 = await fetch(bypass(requestClone));
1865
+ return response2;
1866
+ } catch (error) {
1867
+ console.error(error);
1868
+ return null;
1869
+ }
1870
+ }
1871
+ if (response && HttpInterceptorWorker_default.isRejectedResponse(response)) {
1872
+ return response;
1873
+ }
1874
+ return response;
1875
+ }
1817
1876
  async createResponseForRequest(request) {
1818
1877
  const methodHandlers = this.httpHandlersByMethod[request.method];
1819
1878
  const requestURL = excludeNonPathParams_default(new URL(request.url));
@@ -1871,6 +1930,17 @@ var LocalHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
1871
1930
  };
1872
1931
  var LocalHttpInterceptorWorker_default = LocalHttpInterceptorWorker;
1873
1932
 
1933
+ // src/server/errors/UnsupportedResponseBypassError.ts
1934
+ var UnsupportedResponseBypassError = class extends Error {
1935
+ constructor() {
1936
+ super(
1937
+ "Remote interceptors cannot bypass responses. Use `{ action: 'reject' }` instead.\n\nLearn more: https://zimic.dev/docs/interceptor/api/http-request-handler#handlerrespond"
1938
+ );
1939
+ this.name = "UnsupportedResponseBypassError";
1940
+ }
1941
+ };
1942
+ var UnsupportedResponseBypassError_default = UnsupportedResponseBypassError;
1943
+
1874
1944
  // src/utils/crypto.ts
1875
1945
  var importCrypto = createCachedDynamicImport_default(async () => {
1876
1946
  const globalCrypto = globalThis.crypto;
@@ -1898,6 +1968,8 @@ async function serializeResponse(response) {
1898
1968
  const responseClone = response.clone();
1899
1969
  const serializedBody = responseClone.body ? convertArrayBufferToBase64(await responseClone.arrayBuffer()) : null;
1900
1970
  return {
1971
+ type: response.type,
1972
+ action: HttpInterceptorWorker_default.getResponseAction(response),
1901
1973
  status: response.status,
1902
1974
  statusText: response.statusText,
1903
1975
  headers: Object.fromEntries(response.headers),
@@ -2374,8 +2446,8 @@ var RemoteHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
2374
2446
  const request = deserializeRequest(serializedRequest);
2375
2447
  try {
2376
2448
  const rawResponse = await handler?.createResponse({ request }) ?? null;
2377
- const response = rawResponse && request.method === "HEAD" ? new Response(null, rawResponse) : rawResponse;
2378
- if (response) {
2449
+ if (rawResponse) {
2450
+ const response = methodCanHaveResponseBody(request.method) ? rawResponse : new Response(null, rawResponse);
2379
2451
  return { response: await serializeResponse(response) };
2380
2452
  }
2381
2453
  } catch (error) {
@@ -2422,10 +2494,7 @@ var RemoteHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
2422
2494
  method,
2423
2495
  path,
2424
2496
  interceptor,
2425
- async createResponse(context) {
2426
- const response = await createResponse(context);
2427
- return response;
2428
- }
2497
+ createResponse
2429
2498
  };
2430
2499
  this.httpHandlers.set(handler.id, handler);
2431
2500
  await this.webSocketClient.request("interceptors/workers/commit", {
@@ -2435,6 +2504,16 @@ var RemoteHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
2435
2504
  path: handler.path
2436
2505
  });
2437
2506
  }
2507
+ async createResponseFromDeclaration(request, declaration) {
2508
+ const response = await super.createResponseFromDeclaration(request, declaration);
2509
+ if (response && HttpInterceptorWorker_default.isBypassedResponse(response)) {
2510
+ throw new UnsupportedResponseBypassError_default();
2511
+ }
2512
+ if (response && HttpInterceptorWorker_default.isRejectedResponse(response)) {
2513
+ return response;
2514
+ }
2515
+ return response;
2516
+ }
2438
2517
  async clearHandlers(options = {}) {
2439
2518
  if (!this.isRunning) {
2440
2519
  throw new NotRunningHttpInterceptorError_default();
@@ -2794,6 +2873,8 @@ var InvalidFormDataError = class extends InvalidFormDataError$1 {
2794
2873
  };
2795
2874
  var InvalidJSONError = class extends InvalidJSONError$1 {
2796
2875
  };
2876
+ /* istanbul ignore if -- @preserve
2877
+ * This is just a type guard to ensure the value is valid. In practice, this condition should never be true. */
2797
2878
  /* istanbul ignore next -- @preserve
2798
2879
  * Ignoring because there will always be a handler for the given method and path at this point. */
2799
2880
  /* istanbul ignore if -- @preserve