swagger-typescript-api 13.12.1 → 13.12.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.
@@ -54,6 +54,10 @@ let _apidevtools_swagger_parser = require("@apidevtools/swagger-parser");
54
54
  _apidevtools_swagger_parser = __toESM(_apidevtools_swagger_parser, 1);
55
55
  let yaml = require("yaml");
56
56
  yaml = __toESM(yaml, 1);
57
+ let node_dns_promises = require("node:dns/promises");
58
+ node_dns_promises = __toESM(node_dns_promises, 1);
59
+ let node_net = require("node:net");
60
+ node_net = __toESM(node_net, 1);
57
61
  let node_module = require("node:module");
58
62
  node_module = __toESM(node_module, 1);
59
63
  let node_url = require("node:url");
@@ -208,7 +212,7 @@ var ComponentTypeNameResolver = class extends NameResolver {
208
212
  //#endregion
209
213
  //#region package.json
210
214
  var name = "swagger-typescript-api";
211
- var version = "13.12.1";
215
+ var version = "13.12.2";
212
216
  var description = "Generate the API client for Fetch or Axios from an OpenAPI Specification";
213
217
  //#endregion
214
218
  //#region src/constants.ts
@@ -276,6 +280,12 @@ const SCHEMA_TYPES$1 = {
276
280
  COMPLEX_UNKNOWN: "__unknown"
277
281
  };
278
282
  //#endregion
283
+ //#region src/util/escape-js-string-literal.ts
284
+ /** Escapes a value for insertion into a double-quoted JS/TS string literal (without surrounding quotes). */
285
+ function escapeJsStringLiteral(value) {
286
+ return JSON.stringify(value).slice(1, -1);
287
+ }
288
+ //#endregion
279
289
  //#region src/util/object-assign.ts
280
290
  const objectAssign = (target, updater) => {
281
291
  if (!updater) return;
@@ -501,7 +511,7 @@ var CodeGenConfig = class {
501
511
  /**
502
512
  * "$A"
503
513
  */
504
- StringValue: (content) => `"${content}"`,
514
+ StringValue: (content) => `"${escapeJsStringLiteral(String(content))}"`,
505
515
  /**
506
516
  * $A
507
517
  */
@@ -1881,6 +1891,15 @@ var SchemaParserFabric = class {
1881
1891
  };
1882
1892
  };
1883
1893
  //#endregion
1894
+ //#region src/util/escape-js-template-literal-with-path-params.ts
1895
+ /**
1896
+ * Escapes `\`, backticks, and `${` for insertion into a JS template literal
1897
+ * (without surrounding backticks).
1898
+ */
1899
+ function escapeJsTemplateLiteralStatic(value) {
1900
+ return value.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
1901
+ }
1902
+ //#endregion
1884
1903
  //#region src/util/id.ts
1885
1904
  const generateId = () => node_crypto.randomUUID();
1886
1905
  //#endregion
@@ -2003,10 +2022,11 @@ var SchemaRoutes = class {
2003
2022
  in: "path"
2004
2023
  });
2005
2024
  }
2025
+ const escapedRouteName = escapeJsTemplateLiteralStatic(routeName || "");
2006
2026
  let fixedRoute = pathParams.reduce((fixedRoute, pathParam, i, arr) => {
2007
2027
  const insertion = this.config.hooks.onInsertPathParam(pathParam.name, i, arr, fixedRoute) || pathParam.name;
2008
2028
  return fixedRoute.replace(pathParam.$match, `\${${insertion}}`);
2009
- }, routeName || "");
2029
+ }, escapedRouteName);
2010
2030
  const queryParamMatches = fixedRoute.match(/(\{\?.*\})/g);
2011
2031
  const queryParams = [];
2012
2032
  if (queryParamMatches?.length) {
@@ -2712,6 +2732,118 @@ function parseSchemaContent(content) {
2712
2732
  }
2713
2733
  }
2714
2734
  //#endregion
2735
+ //#region src/util/remote-schema-fetch.ts
2736
+ const MAX_REDIRECTS = 5;
2737
+ function isPrivateIpv4(ip) {
2738
+ const match = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
2739
+ if (!match) return false;
2740
+ const octets = match.slice(1).map(Number);
2741
+ if (octets.some((octet) => octet > 255)) return false;
2742
+ const [a, b] = octets;
2743
+ return a === 0 || a === 10 || a === 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168;
2744
+ }
2745
+ function isPrivateIpv6(ip) {
2746
+ const normalized = ip.toLowerCase();
2747
+ if (normalized === "::" || normalized === "::1") return true;
2748
+ if (normalized.startsWith("fe80:")) return true;
2749
+ const firstHextet = normalized.split(":")[0] ?? "";
2750
+ if (firstHextet >= "fc00" && firstHextet <= "fdff") return true;
2751
+ const ipv4Mapped = normalized.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
2752
+ if (ipv4Mapped?.[1]) return isPrivateIpv4(ipv4Mapped[1]);
2753
+ const ipv4MappedHex = normalized.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
2754
+ if (ipv4MappedHex?.[1] && ipv4MappedHex?.[2]) {
2755
+ const h1 = parseInt(ipv4MappedHex[1], 16);
2756
+ const h2 = parseInt(ipv4MappedHex[2], 16);
2757
+ return isPrivateIpv4(`${h1 >> 8 & 255}.${h1 & 255}.${h2 >> 8 & 255}.${h2 & 255}`);
2758
+ }
2759
+ return false;
2760
+ }
2761
+ function isPrivateIp(ip) {
2762
+ const family = node_net.isIP(ip);
2763
+ if (family === 4) return isPrivateIpv4(ip);
2764
+ if (family === 6) return isPrivateIpv6(ip);
2765
+ return false;
2766
+ }
2767
+ function isBlockedHostname(hostname) {
2768
+ const normalized = hostname.toLowerCase();
2769
+ return normalized === "localhost" || normalized.endsWith(".localhost");
2770
+ }
2771
+ async function resolveHostnameAddresses(hostname) {
2772
+ try {
2773
+ return (await node_dns_promises.lookup(hostname, {
2774
+ all: true,
2775
+ verbatim: true
2776
+ })).map((record) => record.address);
2777
+ } catch {
2778
+ return [];
2779
+ }
2780
+ }
2781
+ async function isPublicRemoteHost(urlString) {
2782
+ let parsed;
2783
+ try {
2784
+ parsed = new URL(urlString);
2785
+ } catch {
2786
+ return false;
2787
+ }
2788
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;
2789
+ const hostname = parsed.hostname.startsWith("[") && parsed.hostname.endsWith("]") ? parsed.hostname.slice(1, -1) : parsed.hostname;
2790
+ if (isBlockedHostname(hostname)) return false;
2791
+ if (node_net.isIP(hostname)) return !isPrivateIp(hostname);
2792
+ const addresses = await resolveHostnameAddresses(hostname);
2793
+ if (addresses.length === 0) return false;
2794
+ return addresses.every((address) => !isPrivateIp(address));
2795
+ }
2796
+ function isSameHttpOrigin(a, b) {
2797
+ if (typeof b !== "string") return false;
2798
+ try {
2799
+ const urlA = new URL(a);
2800
+ const urlB = new URL(b);
2801
+ return urlA.protocol === urlB.protocol && urlA.host === urlB.host;
2802
+ } catch {
2803
+ return false;
2804
+ }
2805
+ }
2806
+ async function isRemoteSchemaFetchAllowed(urlString, policy) {
2807
+ const { specSourceUrl, allowExplicitSpecUrl = false } = policy;
2808
+ if (allowExplicitSpecUrl && typeof specSourceUrl === "string" && stripUrlHash(urlString) === stripUrlHash(specSourceUrl)) return true;
2809
+ if (typeof specSourceUrl === "string" && isSameHttpOrigin(urlString, specSourceUrl)) return true;
2810
+ return isPublicRemoteHost(urlString);
2811
+ }
2812
+ function stripUrlHash(urlString) {
2813
+ return urlString.split("#")[0] || urlString;
2814
+ }
2815
+ function resolveRedirectUrl(location, baseUrl) {
2816
+ try {
2817
+ return new URL(location, baseUrl).toString();
2818
+ } catch {
2819
+ return null;
2820
+ }
2821
+ }
2822
+ async function fetchRemoteSchemaResponse(urlString, init, policy) {
2823
+ let currentUrl = urlString;
2824
+ let redirectCount = 0;
2825
+ while (true) {
2826
+ if (!await isRemoteSchemaFetchAllowed(currentUrl, {
2827
+ specSourceUrl: policy.specSourceUrl,
2828
+ allowExplicitSpecUrl: policy.allowExplicitSpecUrl && redirectCount === 0
2829
+ })) return null;
2830
+ const response = await fetch(currentUrl, {
2831
+ ...init,
2832
+ redirect: "manual"
2833
+ });
2834
+ if (response.status >= 300 && response.status < 400) {
2835
+ const location = response.headers.get("location");
2836
+ if (!location || redirectCount >= MAX_REDIRECTS) return null;
2837
+ const redirectUrl = resolveRedirectUrl(location, currentUrl);
2838
+ if (!redirectUrl) return null;
2839
+ currentUrl = redirectUrl;
2840
+ redirectCount += 1;
2841
+ continue;
2842
+ }
2843
+ return response;
2844
+ }
2845
+ }
2846
+ //#endregion
2715
2847
  //#region src/resolved-swagger-schema.ts
2716
2848
  var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
2717
2849
  config;
@@ -2754,8 +2886,13 @@ var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
2754
2886
  isHttpUrl(value) {
2755
2887
  return /^https?:\/\//i.test(value);
2756
2888
  }
2757
- getRemoteRequestHeaders() {
2758
- return Object.assign({}, this.config.authorizationToken ? { Authorization: this.config.authorizationToken } : {}, this.config.requestOptions?.headers || {});
2889
+ isExplicitSpecUrl(url) {
2890
+ return typeof this.config.url === "string" && this.stripHash(url) === this.stripHash(this.config.url);
2891
+ }
2892
+ getRemoteRequestHeaders(targetUrl) {
2893
+ const headers = {};
2894
+ if (this.config.authorizationToken && targetUrl && typeof this.config.url === "string" && isSameHttpOrigin(targetUrl, this.config.url)) headers.Authorization = this.config.authorizationToken;
2895
+ return Object.assign(headers, this.config.requestOptions?.headers || {});
2759
2896
  }
2760
2897
  stripHash(urlOrPath) {
2761
2898
  return urlOrPath.split("#")[0] || urlOrPath;
@@ -2900,8 +3037,11 @@ var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
2900
3037
  }
2901
3038
  async fetchRemoteSchemaDocument(url) {
2902
3039
  try {
2903
- const response = await fetch(url, { headers: this.getRemoteRequestHeaders() });
2904
- if (!response.ok) return null;
3040
+ const response = await fetchRemoteSchemaResponse(url, { headers: this.getRemoteRequestHeaders(url) }, {
3041
+ specSourceUrl: typeof this.config.url === "string" ? this.config.url : void 0,
3042
+ allowExplicitSpecUrl: this.isExplicitSpecUrl(url)
3043
+ });
3044
+ if (!response?.ok) return null;
2905
3045
  const content = await response.text();
2906
3046
  try {
2907
3047
  const parsed = parseSchemaContent(content);
@@ -2932,7 +3072,7 @@ var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
2932
3072
  const [externalPath = ""] = normalizedRef.split("#");
2933
3073
  if (!externalPath) continue;
2934
3074
  const absoluteUrl = this.resolveAbsoluteUrl(externalPath, currentUrl);
2935
- if (absoluteUrl && !visited.has(absoluteUrl)) queue.push(absoluteUrl);
3075
+ if (absoluteUrl && !visited.has(absoluteUrl) && await isRemoteSchemaFetchAllowed(absoluteUrl, { specSourceUrl: this.config.url })) queue.push(absoluteUrl);
2936
3076
  }
2937
3077
  }
2938
3078
  }
@@ -3152,7 +3292,7 @@ var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
3152
3292
  external: true,
3153
3293
  http: {
3154
3294
  ...config.requestOptions,
3155
- headers: Object.assign({}, config.authorizationToken ? { Authorization: config.authorizationToken } : {}, config.requestOptions?.headers ?? {})
3295
+ headers: config.requestOptions?.headers ?? {}
3156
3296
  }
3157
3297
  }
3158
3298
  };
@@ -3941,7 +4081,7 @@ var CodeGenProcess = class {
3941
4081
  description: ""
3942
4082
  }, externalDocs || {}),
3943
4083
  tags: (0, es_toolkit.compact)(tags || []),
3944
- baseUrl: serverUrl,
4084
+ baseUrl: escapeJsStringLiteral(serverUrl ?? ""),
3945
4085
  title,
3946
4086
  version
3947
4087
  };
@@ -4183,4 +4323,4 @@ Object.defineProperty(exports, "version", {
4183
4323
  }
4184
4324
  });
4185
4325
 
4186
- //# sourceMappingURL=src-Cs9lMkwK.cjs.map
4326
+ //# sourceMappingURL=src-VxYc58-l.cjs.map