@zimic/interceptor 1.1.0-canary.1 → 1.1.0-canary.2

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
@@ -931,16 +931,88 @@ var LocalHttpRequestHandler = class {
931
931
  };
932
932
  var LocalHttpRequestHandler_default = LocalHttpRequestHandler;
933
933
 
934
- // ../zimic-utils/dist/chunk-4RR2YNYT.mjs
935
- var URL_PATH_PARAM_REGEX = /\/:([^/]+)/g;
936
- function createRegExpFromURL(url) {
937
- URL_PATH_PARAM_REGEX.lastIndex = 0;
938
- const urlWithReplacedPathParams = encodeURI(url).replace(/([.()*?+$\\])/g, "\\$1").replace(URL_PATH_PARAM_REGEX, "/(?<$1>[^/]+)").replace(/^(\/)|(\/)$/g, "");
939
- return new RegExp(`^(?:/)?${urlWithReplacedPathParams}(?:/)?$`);
934
+ // ../zimic-utils/dist/chunk-7KDKOZM7.mjs
935
+ function getExtraPatternsToEscape() {
936
+ return /([.(){}+$])/g;
940
937
  }
941
- __name(createRegExpFromURL, "createRegExpFromURL");
942
- __name2(createRegExpFromURL, "createRegExpFromURL");
943
- var createRegExpFromURL_default = createRegExpFromURL;
938
+ __name(getExtraPatternsToEscape, "getExtraPatternsToEscape");
939
+ __name2(getExtraPatternsToEscape, "getExtraPatternsToEscape");
940
+ function getURIEncodedBackSlashPattern() {
941
+ return /%5C/g;
942
+ }
943
+ __name(getURIEncodedBackSlashPattern, "getURIEncodedBackSlashPattern");
944
+ __name2(getURIEncodedBackSlashPattern, "getURIEncodedBackSlashPattern");
945
+ function getPathParamPattern() {
946
+ return /(?<escape>\\)?:(?<identifier>[$_\p{ID_Start}][$\p{ID_Continue}]+)/gu;
947
+ }
948
+ __name(getPathParamPattern, "getPathParamPattern");
949
+ __name2(getPathParamPattern, "getPathParamPattern");
950
+ function getRepeatingPathParamPattern() {
951
+ return /(?<escape>\\)?:(?<identifier>[$_\p{ID_Start}][$\p{ID_Continue}]+)\\+/gu;
952
+ }
953
+ __name(getRepeatingPathParamPattern, "getRepeatingPathParamPattern");
954
+ __name2(getRepeatingPathParamPattern, "getRepeatingPathParamPattern");
955
+ function getOptionalPathParamPattern() {
956
+ return /(?<leadingSlash>\/)?(?<escape>\\)?:(?<identifier>[$_\p{ID_Start}][$\p{ID_Continue}]+)\?(?<trailingSlash>\/)?/gu;
957
+ }
958
+ __name(getOptionalPathParamPattern, "getOptionalPathParamPattern");
959
+ __name2(getOptionalPathParamPattern, "getOptionalPathParamPattern");
960
+ function getOptionalRepeatingPathParamPattern() {
961
+ return /(?<leadingSlash>\/)?(?<escape>\\)?:(?<identifier>[$_\p{ID_Start}][$\p{ID_Continue}]+)\*(?<trailingSlash>\/)?/gu;
962
+ }
963
+ __name(getOptionalRepeatingPathParamPattern, "getOptionalRepeatingPathParamPattern");
964
+ __name2(getOptionalRepeatingPathParamPattern, "getOptionalRepeatingPathParamPattern");
965
+ function createParametrizedPathPattern(path) {
966
+ const replacedURL = encodeURI(path).replace(/^\/+/g, "").replace(/\/+$/g, "").replace(getExtraPatternsToEscape(), "\\$1").replace(getURIEncodedBackSlashPattern(), "\\").replace(
967
+ getOptionalRepeatingPathParamPattern(),
968
+ (_match, leadingSlash, escape, identifier, trailingSlash) => {
969
+ if (escape) {
970
+ return `:${identifier}`;
971
+ }
972
+ const hasSegmentBeforePrefix = leadingSlash === "/";
973
+ const prefixExpression = hasSegmentBeforePrefix ? "/?" : leadingSlash;
974
+ const hasSegmentAfterSuffix = trailingSlash === "/";
975
+ const suffixExpression = hasSegmentAfterSuffix ? "/?" : trailingSlash;
976
+ if (prefixExpression && suffixExpression) {
977
+ return `(?:${prefixExpression}(?<${identifier}>.+?)?${suffixExpression})?`;
978
+ } else if (prefixExpression) {
979
+ return `(?:${prefixExpression}(?<${identifier}>.+?))?`;
980
+ } else if (suffixExpression) {
981
+ return `(?:(?<${identifier}>.+?)${suffixExpression})?`;
982
+ } else {
983
+ return `(?<${identifier}>.+?)?`;
984
+ }
985
+ }
986
+ ).replace(getRepeatingPathParamPattern(), (_match, escape, identifier) => {
987
+ return escape ? `:${identifier}` : `(?<${identifier}>.+)`;
988
+ }).replace(
989
+ getOptionalPathParamPattern(),
990
+ (_match, leadingSlash, escape, identifier, trailingSlash) => {
991
+ if (escape) {
992
+ return `:${identifier}`;
993
+ }
994
+ const hasNoSegmentBeforePrefix = leadingSlash === "/";
995
+ const prefixExpression = hasNoSegmentBeforePrefix ? "/?" : leadingSlash;
996
+ const hasNoSegmentAfterSuffix = trailingSlash === "/";
997
+ const suffixExpression = hasNoSegmentAfterSuffix ? "/?" : trailingSlash;
998
+ if (prefixExpression && suffixExpression) {
999
+ return `(?:${prefixExpression}(?<${identifier}>[^\\/]+?)?${suffixExpression})`;
1000
+ } else if (prefixExpression) {
1001
+ return `(?:${prefixExpression}(?<${identifier}>[^\\/]+?))?`;
1002
+ } else if (suffixExpression) {
1003
+ return `(?:(?<${identifier}>[^\\/]+?)${suffixExpression})?`;
1004
+ } else {
1005
+ return `(?<${identifier}>[^\\/]+?)?`;
1006
+ }
1007
+ }
1008
+ ).replace(getPathParamPattern(), (_match, escape, identifier) => {
1009
+ return escape ? `:${identifier}` : `(?<${identifier}>[^\\/]+?)`;
1010
+ });
1011
+ return new RegExp(`^/?${replacedURL}/?$`);
1012
+ }
1013
+ __name(createParametrizedPathPattern, "createParametrizedPathPattern");
1014
+ __name2(createParametrizedPathPattern, "createParametrizedPathPattern");
1015
+ var createParametrizedPathPattern_default = createParametrizedPathPattern;
944
1016
 
945
1017
  // ../zimic-utils/dist/url/excludeURLParams.mjs
946
1018
  function excludeURLParams(url) {
@@ -954,25 +1026,6 @@ __name(excludeURLParams, "excludeURLParams");
954
1026
  __name2(excludeURLParams, "excludeURLParams");
955
1027
  var excludeURLParams_default = excludeURLParams;
956
1028
 
957
- // ../zimic-utils/dist/url/joinURL.mjs
958
- function joinURL(...parts) {
959
- return parts.map((part, index) => {
960
- const isFirstPart = index === 0;
961
- const isLastPart = index === parts.length - 1;
962
- let partAsString = part.toString();
963
- if (!isFirstPart) {
964
- partAsString = partAsString.replace(/^\//, "");
965
- }
966
- if (!isLastPart) {
967
- partAsString = partAsString.replace(/\/$/, "");
968
- }
969
- return partAsString;
970
- }).filter((part) => part.length > 0).join("/");
971
- }
972
- __name(joinURL, "joinURL");
973
- __name2(joinURL, "joinURL");
974
- var joinURL_default = joinURL;
975
-
976
1029
  // ../zimic-utils/dist/url/validateURLProtocol.mjs
977
1030
  var UnsupportedURLProtocolError = class extends TypeError {
978
1031
  static {
@@ -1171,12 +1224,12 @@ var HttpInterceptorWorker = class _HttpInterceptorWorker {
1171
1224
  request
1172
1225
  );
1173
1226
  }
1174
- static async parseRawRequest(originalRawRequest, options = {}) {
1227
+ static async parseRawRequest(originalRawRequest, options) {
1175
1228
  const rawRequest = originalRawRequest.clone();
1176
1229
  const rawRequestClone = rawRequest.clone();
1177
1230
  const parsedBody = await this.parseRawBody(rawRequest);
1178
1231
  const headers = new HttpHeaders(rawRequest.headers);
1179
- const pathParams = options.urlRegex ? this.parseRawPathParams(options.urlRegex, rawRequest) : {};
1232
+ const pathParams = this.parseRawPathParams(rawRequest, options);
1180
1233
  const parsedURL = new URL(rawRequest.url);
1181
1234
  const searchParams = new HttpSearchParams(parsedURL.searchParams);
1182
1235
  const parsedRequest = new Proxy(rawRequest, {
@@ -1270,10 +1323,9 @@ var HttpInterceptorWorker = class _HttpInterceptorWorker {
1270
1323
  static isHiddenResponseProperty(property) {
1271
1324
  return HTTP_INTERCEPTOR_RESPONSE_HIDDEN_PROPERTIES.has(property);
1272
1325
  }
1273
- static parseRawPathParams(matchedURLRegex, request) {
1274
- const match = request.url.match(matchedURLRegex);
1275
- const pathParams = { ...match?.groups };
1276
- return pathParams;
1326
+ static parseRawPathParams(request, options) {
1327
+ const match = options?.pathPattern.exec(request.url.replace(options.baseURL, ""));
1328
+ return { ...match?.groups };
1277
1329
  }
1278
1330
  static async parseRawBody(resource) {
1279
1331
  const contentType = resource.headers.get("content-type");
@@ -1626,13 +1678,12 @@ var HttpInterceptorClient = class {
1626
1678
  return;
1627
1679
  }
1628
1680
  this.handlerClientsByMethod[handler.method].set(handler.path, handlerClients);
1629
- const url = joinURL_default(this.baseURLAsString, handler.path);
1630
- const urlRegex = createRegExpFromURL_default(url);
1631
- const registrationResult = this.workerOrThrow.use(this, handler.method, url, async (context) => {
1681
+ const pathPattern = createParametrizedPathPattern_default(handler.path);
1682
+ const registrationResult = this.workerOrThrow.use(this, handler.method, handler.path, async (context) => {
1632
1683
  const response = await this.handleInterceptedRequest(
1633
- urlRegex,
1634
1684
  handler.method,
1635
1685
  handler.path,
1686
+ pathPattern,
1636
1687
  context
1637
1688
  );
1638
1689
  return response;
@@ -1641,9 +1692,10 @@ var HttpInterceptorClient = class {
1641
1692
  handler.registerSyncPromise(registrationResult);
1642
1693
  }
1643
1694
  }
1644
- async handleInterceptedRequest(matchedURLRegex, method, path, { request }) {
1695
+ async handleInterceptedRequest(method, path, pathPattern, { request }) {
1645
1696
  const parsedRequest = await HttpInterceptorWorker_default.parseRawRequest(request, {
1646
- urlRegex: matchedURLRegex
1697
+ baseURL: this.baseURLAsString,
1698
+ pathPattern
1647
1699
  });
1648
1700
  const matchedHandler = await this.findMatchedHandler(method, path, parsedRequest);
1649
1701
  if (!matchedHandler) {
@@ -1715,7 +1767,7 @@ var HttpInterceptorClient = class {
1715
1767
  };
1716
1768
  var HttpInterceptorClient_default = HttpInterceptorClient;
1717
1769
 
1718
- // ../zimic-utils/dist/url/validateURLPathParams.mjs
1770
+ // ../zimic-utils/dist/url/validatePathParams.mjs
1719
1771
  var DuplicatedPathParamError = class extends Error {
1720
1772
  static {
1721
1773
  __name(this, "DuplicatedPathParamError");
@@ -1723,41 +1775,46 @@ var DuplicatedPathParamError = class extends Error {
1723
1775
  static {
1724
1776
  __name2(this, "DuplicatedPathParamError");
1725
1777
  }
1726
- constructor(url, paramName) {
1778
+ constructor(path, paramName) {
1727
1779
  super(
1728
- `The path parameter '${paramName}' appears more than once in the URL '${url.toString()}'. This is not supported. Please make sure that each parameter is unique.`
1780
+ `The path parameter '${paramName}' appears more than once in '${path}'. This is not supported. Please make sure that each parameter is unique.`
1729
1781
  );
1730
1782
  this.name = "DuplicatedPathParamError";
1731
1783
  }
1732
1784
  };
1733
- function validateURLPathParams(url) {
1734
- URL_PATH_PARAM_REGEX.lastIndex = 0;
1735
- const matches = url.toString().matchAll(URL_PATH_PARAM_REGEX);
1785
+ function validatePathParams(path) {
1786
+ const pathParamMatches = path.toString().matchAll(getPathParamPattern());
1736
1787
  const uniqueParamNames = /* @__PURE__ */ new Set();
1737
- for (const match of matches) {
1738
- const paramName = match[1];
1788
+ for (const paramMatch of pathParamMatches) {
1789
+ const paramName = paramMatch.groups?.identifier;
1790
+ if (!paramName) {
1791
+ continue;
1792
+ }
1739
1793
  if (uniqueParamNames.has(paramName)) {
1740
- throw new DuplicatedPathParamError(url, paramName);
1794
+ throw new DuplicatedPathParamError(path, paramName);
1741
1795
  }
1742
1796
  uniqueParamNames.add(paramName);
1743
1797
  }
1744
1798
  }
1745
- __name(validateURLPathParams, "validateURLPathParams");
1746
- __name2(validateURLPathParams, "validateURLPathParams");
1747
- var validateURLPathParams_default = validateURLPathParams;
1799
+ __name(validatePathParams, "validatePathParams");
1800
+ __name2(validatePathParams, "validatePathParams");
1801
+ var validatePathParams_default = validatePathParams;
1748
1802
  var LocalHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
1749
1803
  static {
1750
1804
  __name(this, "LocalHttpInterceptorWorker");
1751
1805
  }
1752
1806
  internalWorker;
1753
- defaultHttpHandler;
1754
- httpHandlerGroups = [];
1807
+ httpHandlersByMethod = {
1808
+ GET: [],
1809
+ POST: [],
1810
+ PATCH: [],
1811
+ PUT: [],
1812
+ DELETE: [],
1813
+ HEAD: [],
1814
+ OPTIONS: []
1815
+ };
1755
1816
  constructor(_options) {
1756
1817
  super();
1757
- this.defaultHttpHandler = http.all("*", async (context) => {
1758
- const request = context.request;
1759
- return this.bypassOrRejectUnhandledRequest(request);
1760
- });
1761
1818
  }
1762
1819
  get type() {
1763
1820
  return "local";
@@ -1773,11 +1830,16 @@ var LocalHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
1773
1830
  return this.internalWorker;
1774
1831
  }
1775
1832
  createInternalWorker() {
1833
+ const mswHttpHandler = http.all("*", async (context) => {
1834
+ const request = context.request;
1835
+ const response = await this.createResponseForRequest(request);
1836
+ return response;
1837
+ });
1776
1838
  if (isServerSide() && "setupServer" in mswNode) {
1777
- return mswNode.setupServer(this.defaultHttpHandler);
1839
+ return mswNode.setupServer(mswHttpHandler);
1778
1840
  }
1779
1841
  if (isClientSide() && "setupWorker" in mswBrowser) {
1780
- return mswBrowser.setupWorker(this.defaultHttpHandler);
1842
+ return mswBrowser.setupWorker(mswHttpHandler);
1781
1843
  }
1782
1844
  throw new UnknownHttpInterceptorPlatformError_default();
1783
1845
  }
@@ -1841,34 +1903,60 @@ var LocalHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
1841
1903
  hasInternalNodeWorker() {
1842
1904
  return !this.hasInternalBrowserWorker();
1843
1905
  }
1844
- use(interceptor, method, rawURL, createResponse) {
1845
- const lowercaseMethod = method.toLowerCase();
1846
- const url = new URL(rawURL);
1847
- excludeURLParams_default(url);
1848
- validateURLPathParams_default(url);
1849
- const httpHandler = http[lowercaseMethod](url.toString(), async (context) => {
1850
- const request = context.request;
1851
- const requestClone = request.clone();
1852
- let response = null;
1853
- try {
1854
- response = await createResponse({ ...context, request });
1855
- } catch (error) {
1856
- console.error(error);
1857
- }
1858
- if (!response) {
1859
- return this.bypassOrRejectUnhandledRequest(requestClone);
1906
+ use(interceptor, method, path, createResponse) {
1907
+ if (!this.isRunning) {
1908
+ throw new NotRunningHttpInterceptorError_default();
1909
+ }
1910
+ validatePathParams_default(path);
1911
+ const methodHandlers = this.httpHandlersByMethod[method];
1912
+ const handler = {
1913
+ baseURL: interceptor.baseURLAsString,
1914
+ method,
1915
+ pathPattern: createParametrizedPathPattern_default(path),
1916
+ interceptor,
1917
+ createResponse: /* @__PURE__ */ __name(async (context) => {
1918
+ const request = context.request;
1919
+ const requestClone = request.clone();
1920
+ let response = null;
1921
+ try {
1922
+ response = await createResponse({ ...context, request });
1923
+ } catch (error) {
1924
+ console.error(error);
1925
+ }
1926
+ if (!response) {
1927
+ return this.bypassOrRejectUnhandledRequest(requestClone);
1928
+ }
1929
+ if (context.request.method === "HEAD") {
1930
+ return new Response(null, {
1931
+ status: response.status,
1932
+ statusText: response.statusText,
1933
+ headers: response.headers
1934
+ });
1935
+ }
1936
+ return response;
1937
+ }, "createResponse")
1938
+ };
1939
+ methodHandlers.push(handler);
1940
+ }
1941
+ async createResponseForRequest(request) {
1942
+ const methodHandlers = this.httpHandlersByMethod[request.method];
1943
+ const requestURL = excludeURLParams_default(new URL(request.url));
1944
+ const requestURLAsString = requestURL.href === `${requestURL.origin}/` ? requestURL.origin : requestURL.href;
1945
+ for (let handlerIndex = methodHandlers.length - 1; handlerIndex >= 0; handlerIndex--) {
1946
+ const handler = methodHandlers[handlerIndex];
1947
+ const matchesBaseURL = requestURLAsString.startsWith(handler.baseURL);
1948
+ if (!matchesBaseURL) {
1949
+ continue;
1860
1950
  }
1861
- if (context.request.method === "HEAD") {
1862
- return new Response(null, {
1863
- status: response.status,
1864
- statusText: response.statusText,
1865
- headers: response.headers
1866
- });
1951
+ const requestPath = requestURLAsString.replace(handler.baseURL, "");
1952
+ const matchesPath = handler.pathPattern.test(requestPath);
1953
+ if (!matchesPath) {
1954
+ continue;
1867
1955
  }
1956
+ const response = await handler.createResponse({ request });
1868
1957
  return response;
1869
- });
1870
- this.internalWorkerOrThrow.use(httpHandler);
1871
- this.httpHandlerGroups.push({ interceptor, httpHandler });
1958
+ }
1959
+ return this.bypassOrRejectUnhandledRequest(request);
1872
1960
  }
1873
1961
  async bypassOrRejectUnhandledRequest(request) {
1874
1962
  const requestClone = request.clone();
@@ -1882,18 +1970,27 @@ var LocalHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
1882
1970
  }
1883
1971
  clearHandlers() {
1884
1972
  this.internalWorkerOrThrow.resetHandlers();
1885
- this.httpHandlerGroups = [];
1973
+ for (const handlers of Object.values(this.httpHandlersByMethod)) {
1974
+ handlers.length = 0;
1975
+ }
1886
1976
  }
1887
1977
  clearInterceptorHandlers(interceptor) {
1888
- const groupToRemoveIndex = this.httpHandlerGroups.findIndex((group) => group.interceptor === interceptor);
1889
- removeArrayIndex(this.httpHandlerGroups, groupToRemoveIndex);
1890
- this.internalWorkerOrThrow.resetHandlers();
1891
- for (const { httpHandler } of this.httpHandlerGroups) {
1892
- this.internalWorkerOrThrow.use(httpHandler);
1978
+ if (!this.isRunning) {
1979
+ throw new NotRunningHttpInterceptorError_default();
1980
+ }
1981
+ for (const methodHandlers of Object.values(this.httpHandlersByMethod)) {
1982
+ const groupToRemoveIndex = methodHandlers.findIndex((group) => group.interceptor === interceptor);
1983
+ removeArrayIndex(methodHandlers, groupToRemoveIndex);
1893
1984
  }
1894
1985
  }
1895
1986
  get interceptorsWithHandlers() {
1896
- return this.httpHandlerGroups.map((group) => group.interceptor);
1987
+ const interceptors = /* @__PURE__ */ new Set();
1988
+ for (const handlers of Object.values(this.httpHandlersByMethod)) {
1989
+ for (const handler of handlers) {
1990
+ interceptors.add(handler.interceptor);
1991
+ }
1992
+ }
1993
+ return Array.from(interceptors);
1897
1994
  }
1898
1995
  };
1899
1996
  var LocalHttpInterceptorWorker_default = LocalHttpInterceptorWorker;
@@ -2473,21 +2570,17 @@ var RemoteHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
2473
2570
  this.isRunning = false;
2474
2571
  });
2475
2572
  }
2476
- async use(interceptor, method, rawURL, createResponse) {
2573
+ async use(interceptor, method, path, createResponse) {
2477
2574
  if (!this.isRunning) {
2478
2575
  throw new NotRunningHttpInterceptorError_default();
2479
2576
  }
2577
+ validatePathParams_default(path);
2480
2578
  const crypto = await importCrypto();
2481
- const url = new URL(rawURL);
2482
- excludeURLParams_default(url);
2483
- validateURLPathParams_default(url);
2484
2579
  const handler = {
2485
2580
  id: crypto.randomUUID(),
2486
- url: {
2487
- base: interceptor.baseURLAsString,
2488
- full: url.toString()
2489
- },
2581
+ baseURL: interceptor.baseURLAsString,
2490
2582
  method,
2583
+ path,
2491
2584
  interceptor,
2492
2585
  async createResponse(context) {
2493
2586
  const response = await createResponse(context);
@@ -2497,8 +2590,9 @@ var RemoteHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
2497
2590
  this.httpHandlers.set(handler.id, handler);
2498
2591
  await this.webSocketClient.request("interceptors/workers/commit", {
2499
2592
  id: handler.id,
2500
- url: handler.url,
2501
- method
2593
+ baseURL: handler.baseURL,
2594
+ method: handler.method,
2595
+ path: handler.path
2502
2596
  });
2503
2597
  }
2504
2598
  async clearHandlers() {
@@ -2522,8 +2616,9 @@ var RemoteHttpInterceptorWorker = class extends HttpInterceptorWorker_default {
2522
2616
  if (this.webSocketClient.isRunning) {
2523
2617
  const groupsToRecommit = Array.from(this.httpHandlers.values(), (handler) => ({
2524
2618
  id: handler.id,
2525
- url: handler.url,
2526
- method: handler.method
2619
+ baseURL: handler.baseURL,
2620
+ method: handler.method,
2621
+ path: handler.path
2527
2622
  }));
2528
2623
  await this.webSocketClient.request("interceptors/workers/reset", groupsToRecommit);
2529
2624
  }