swagger-typescript-api 13.12.1 → 13.12.3

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.
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./chunk-D7D4PA-g.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import * as module from "node:module";
3
3
  import consola, { consola as consola$1 } from "consola";
4
4
  import * as esToolkit from "es-toolkit";
@@ -17,6 +17,8 @@ import * as swagger2openapi from "swagger2openapi";
17
17
  import * as fs from "node:fs";
18
18
  import SwaggerParser from "@apidevtools/swagger-parser";
19
19
  import * as YAML from "yaml";
20
+ import * as dns from "node:dns/promises";
21
+ import * as net from "node:net";
20
22
  import * as url$1 from "node:url";
21
23
  import url from "node:url";
22
24
  import { Eta } from "eta";
@@ -169,7 +171,7 @@ var ComponentTypeNameResolver = class extends NameResolver {
169
171
  //#endregion
170
172
  //#region package.json
171
173
  var name = "swagger-typescript-api";
172
- var version = "13.12.1";
174
+ var version = "13.12.3";
173
175
  var description = "Generate the API client for Fetch or Axios from an OpenAPI Specification";
174
176
  //#endregion
175
177
  //#region src/constants.ts
@@ -237,6 +239,12 @@ const SCHEMA_TYPES$1 = {
237
239
  COMPLEX_UNKNOWN: "__unknown"
238
240
  };
239
241
  //#endregion
242
+ //#region src/util/escape-js-string-literal.ts
243
+ /** Escapes a value for insertion into a double-quoted JS/TS string literal (without surrounding quotes). */
244
+ function escapeJsStringLiteral(value) {
245
+ return JSON.stringify(value).slice(1, -1);
246
+ }
247
+ //#endregion
240
248
  //#region src/util/object-assign.ts
241
249
  const objectAssign = (target, updater) => {
242
250
  if (!updater) return;
@@ -462,7 +470,7 @@ var CodeGenConfig = class {
462
470
  /**
463
471
  * "$A"
464
472
  */
465
- StringValue: (content) => `"${content}"`,
473
+ StringValue: (content) => `"${escapeJsStringLiteral(String(content))}"`,
466
474
  /**
467
475
  * $A
468
476
  */
@@ -1842,6 +1850,15 @@ var SchemaParserFabric = class {
1842
1850
  };
1843
1851
  };
1844
1852
  //#endregion
1853
+ //#region src/util/escape-js-template-literal-with-path-params.ts
1854
+ /**
1855
+ * Escapes `\`, backticks, and `${` for insertion into a JS template literal
1856
+ * (without surrounding backticks).
1857
+ */
1858
+ function escapeJsTemplateLiteralStatic(value) {
1859
+ return value.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
1860
+ }
1861
+ //#endregion
1845
1862
  //#region src/util/id.ts
1846
1863
  const generateId = () => crypto.randomUUID();
1847
1864
  //#endregion
@@ -1964,10 +1981,11 @@ var SchemaRoutes = class {
1964
1981
  in: "path"
1965
1982
  });
1966
1983
  }
1984
+ const escapedRouteName = escapeJsTemplateLiteralStatic(routeName || "");
1967
1985
  let fixedRoute = pathParams.reduce((fixedRoute, pathParam, i, arr) => {
1968
1986
  const insertion = this.config.hooks.onInsertPathParam(pathParam.name, i, arr, fixedRoute) || pathParam.name;
1969
1987
  return fixedRoute.replace(pathParam.$match, `\${${insertion}}`);
1970
- }, routeName || "");
1988
+ }, escapedRouteName);
1971
1989
  const queryParamMatches = fixedRoute.match(/(\{\?.*\})/g);
1972
1990
  const queryParams = [];
1973
1991
  if (queryParamMatches?.length) {
@@ -2673,6 +2691,118 @@ function parseSchemaContent(content) {
2673
2691
  }
2674
2692
  }
2675
2693
  //#endregion
2694
+ //#region src/util/remote-schema-fetch.ts
2695
+ const MAX_REDIRECTS = 5;
2696
+ function isPrivateIpv4(ip) {
2697
+ const match = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
2698
+ if (!match) return false;
2699
+ const octets = match.slice(1).map(Number);
2700
+ if (octets.some((octet) => octet > 255)) return false;
2701
+ const [a, b] = octets;
2702
+ return a === 0 || a === 10 || a === 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168;
2703
+ }
2704
+ function isPrivateIpv6(ip) {
2705
+ const normalized = ip.toLowerCase();
2706
+ if (normalized === "::" || normalized === "::1") return true;
2707
+ if (normalized.startsWith("fe80:")) return true;
2708
+ const firstHextet = normalized.split(":")[0] ?? "";
2709
+ if (firstHextet >= "fc00" && firstHextet <= "fdff") return true;
2710
+ const ipv4Mapped = normalized.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
2711
+ if (ipv4Mapped?.[1]) return isPrivateIpv4(ipv4Mapped[1]);
2712
+ const ipv4MappedHex = normalized.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
2713
+ if (ipv4MappedHex?.[1] && ipv4MappedHex?.[2]) {
2714
+ const h1 = parseInt(ipv4MappedHex[1], 16);
2715
+ const h2 = parseInt(ipv4MappedHex[2], 16);
2716
+ return isPrivateIpv4(`${h1 >> 8 & 255}.${h1 & 255}.${h2 >> 8 & 255}.${h2 & 255}`);
2717
+ }
2718
+ return false;
2719
+ }
2720
+ function isPrivateIp(ip) {
2721
+ const family = net.isIP(ip);
2722
+ if (family === 4) return isPrivateIpv4(ip);
2723
+ if (family === 6) return isPrivateIpv6(ip);
2724
+ return false;
2725
+ }
2726
+ function isBlockedHostname(hostname) {
2727
+ const normalized = hostname.toLowerCase();
2728
+ return normalized === "localhost" || normalized.endsWith(".localhost");
2729
+ }
2730
+ async function resolveHostnameAddresses(hostname) {
2731
+ try {
2732
+ return (await dns.lookup(hostname, {
2733
+ all: true,
2734
+ verbatim: true
2735
+ })).map((record) => record.address);
2736
+ } catch {
2737
+ return [];
2738
+ }
2739
+ }
2740
+ async function isPublicRemoteHost(urlString) {
2741
+ let parsed;
2742
+ try {
2743
+ parsed = new URL(urlString);
2744
+ } catch {
2745
+ return false;
2746
+ }
2747
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;
2748
+ const hostname = parsed.hostname.startsWith("[") && parsed.hostname.endsWith("]") ? parsed.hostname.slice(1, -1) : parsed.hostname;
2749
+ if (isBlockedHostname(hostname)) return false;
2750
+ if (net.isIP(hostname)) return !isPrivateIp(hostname);
2751
+ const addresses = await resolveHostnameAddresses(hostname);
2752
+ if (addresses.length === 0) return false;
2753
+ return addresses.every((address) => !isPrivateIp(address));
2754
+ }
2755
+ function isSameHttpOrigin(a, b) {
2756
+ if (typeof b !== "string") return false;
2757
+ try {
2758
+ const urlA = new URL(a);
2759
+ const urlB = new URL(b);
2760
+ return urlA.protocol === urlB.protocol && urlA.host === urlB.host;
2761
+ } catch {
2762
+ return false;
2763
+ }
2764
+ }
2765
+ async function isRemoteSchemaFetchAllowed(urlString, policy) {
2766
+ const { specSourceUrl, allowExplicitSpecUrl = false } = policy;
2767
+ if (allowExplicitSpecUrl && typeof specSourceUrl === "string" && stripUrlHash(urlString) === stripUrlHash(specSourceUrl)) return true;
2768
+ if (typeof specSourceUrl === "string" && isSameHttpOrigin(urlString, specSourceUrl)) return true;
2769
+ return isPublicRemoteHost(urlString);
2770
+ }
2771
+ function stripUrlHash(urlString) {
2772
+ return urlString.split("#")[0] || urlString;
2773
+ }
2774
+ function resolveRedirectUrl(location, baseUrl) {
2775
+ try {
2776
+ return new URL(location, baseUrl).toString();
2777
+ } catch {
2778
+ return null;
2779
+ }
2780
+ }
2781
+ async function fetchRemoteSchemaResponse(urlString, init, policy) {
2782
+ let currentUrl = urlString;
2783
+ let redirectCount = 0;
2784
+ while (true) {
2785
+ if (!await isRemoteSchemaFetchAllowed(currentUrl, {
2786
+ specSourceUrl: policy.specSourceUrl,
2787
+ allowExplicitSpecUrl: policy.allowExplicitSpecUrl && redirectCount === 0
2788
+ })) return null;
2789
+ const response = await fetch(currentUrl, {
2790
+ ...init,
2791
+ redirect: "manual"
2792
+ });
2793
+ if (response.status >= 300 && response.status < 400) {
2794
+ const location = response.headers.get("location");
2795
+ if (!location || redirectCount >= MAX_REDIRECTS) return null;
2796
+ const redirectUrl = resolveRedirectUrl(location, currentUrl);
2797
+ if (!redirectUrl) return null;
2798
+ currentUrl = redirectUrl;
2799
+ redirectCount += 1;
2800
+ continue;
2801
+ }
2802
+ return response;
2803
+ }
2804
+ }
2805
+ //#endregion
2676
2806
  //#region src/resolved-swagger-schema.ts
2677
2807
  var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
2678
2808
  config;
@@ -2715,8 +2845,13 @@ var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
2715
2845
  isHttpUrl(value) {
2716
2846
  return /^https?:\/\//i.test(value);
2717
2847
  }
2718
- getRemoteRequestHeaders() {
2719
- return Object.assign({}, this.config.authorizationToken ? { Authorization: this.config.authorizationToken } : {}, this.config.requestOptions?.headers || {});
2848
+ isExplicitSpecUrl(url) {
2849
+ return typeof this.config.url === "string" && this.stripHash(url) === this.stripHash(this.config.url);
2850
+ }
2851
+ getRemoteRequestHeaders(targetUrl) {
2852
+ const headers = {};
2853
+ if (this.config.authorizationToken && targetUrl && typeof this.config.url === "string" && isSameHttpOrigin(targetUrl, this.config.url)) headers.Authorization = this.config.authorizationToken;
2854
+ return Object.assign(headers, this.config.requestOptions?.headers || {});
2720
2855
  }
2721
2856
  stripHash(urlOrPath) {
2722
2857
  return urlOrPath.split("#")[0] || urlOrPath;
@@ -2861,8 +2996,11 @@ var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
2861
2996
  }
2862
2997
  async fetchRemoteSchemaDocument(url) {
2863
2998
  try {
2864
- const response = await fetch(url, { headers: this.getRemoteRequestHeaders() });
2865
- if (!response.ok) return null;
2999
+ const response = await fetchRemoteSchemaResponse(url, { headers: this.getRemoteRequestHeaders(url) }, {
3000
+ specSourceUrl: typeof this.config.url === "string" ? this.config.url : void 0,
3001
+ allowExplicitSpecUrl: this.isExplicitSpecUrl(url)
3002
+ });
3003
+ if (!response?.ok) return null;
2866
3004
  const content = await response.text();
2867
3005
  try {
2868
3006
  const parsed = parseSchemaContent(content);
@@ -2893,7 +3031,7 @@ var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
2893
3031
  const [externalPath = ""] = normalizedRef.split("#");
2894
3032
  if (!externalPath) continue;
2895
3033
  const absoluteUrl = this.resolveAbsoluteUrl(externalPath, currentUrl);
2896
- if (absoluteUrl && !visited.has(absoluteUrl)) queue.push(absoluteUrl);
3034
+ if (absoluteUrl && !visited.has(absoluteUrl) && await isRemoteSchemaFetchAllowed(absoluteUrl, { specSourceUrl: this.config.url })) queue.push(absoluteUrl);
2897
3035
  }
2898
3036
  }
2899
3037
  }
@@ -3113,7 +3251,7 @@ var ResolvedSwaggerSchema = class ResolvedSwaggerSchema {
3113
3251
  external: true,
3114
3252
  http: {
3115
3253
  ...config.requestOptions,
3116
- headers: Object.assign({}, config.authorizationToken ? { Authorization: config.authorizationToken } : {}, config.requestOptions?.headers ?? {})
3254
+ headers: config.requestOptions?.headers ?? {}
3117
3255
  }
3118
3256
  }
3119
3257
  };
@@ -3902,7 +4040,7 @@ var CodeGenProcess = class {
3902
4040
  description: ""
3903
4041
  }, externalDocs || {}),
3904
4042
  tags: compact(tags || []),
3905
- baseUrl: serverUrl,
4043
+ baseUrl: escapeJsStringLiteral(serverUrl ?? ""),
3906
4044
  title,
3907
4045
  version
3908
4046
  };
@@ -4073,4 +4211,4 @@ async function generateApi(config) {
4073
4211
  //#endregion
4074
4212
  export { SCHEMA_TYPES as a, constants_exports as c, version as d, RequestContentKind as i, description as l, generateTemplates as n, CodeGenConfig as o, TemplatesGenConfig as r, HTTP_CLIENT as s, generateApi as t, name as u };
4075
4213
 
4076
- //# sourceMappingURL=src-BI71PJBk.mjs.map
4214
+ //# sourceMappingURL=src-Dzta9jYV.mjs.map