vercel 54.12.0 → 54.12.1

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 (50) hide show
  1. package/dist/chunks/{add-4F6CBPSE.js → add-5YK3M2KO.js} +4 -4
  2. package/dist/chunks/{chunk-HVYPWTJQ.js → chunk-222H5MYY.js} +27 -5
  3. package/dist/chunks/{chunk-WNYUBBFH.js → chunk-25I7H5PE.js} +2 -2
  4. package/dist/chunks/{chunk-ADBU633H.js → chunk-2RKOZW37.js} +1 -1
  5. package/dist/chunks/{chunk-LGWH2KFI.js → chunk-2VD6MP2S.js} +3 -3
  6. package/dist/chunks/{chunk-HYFP6VVA.js → chunk-3PICWXS2.js} +2 -2
  7. package/dist/chunks/{chunk-OBWYK3NL.js → chunk-AMAIJW4M.js} +1 -1
  8. package/dist/chunks/{chunk-ZYNF76YT.js → chunk-ASVZLQHG.js} +340 -53
  9. package/dist/chunks/{chunk-NZDGG7W3.js → chunk-CLUKKIJ2.js} +1 -1
  10. package/dist/chunks/{chunk-7IAMAKFC.js → chunk-DW6I2NB5.js} +1 -1
  11. package/dist/chunks/{chunk-DITVV3KE.js → chunk-EACELZBS.js} +1 -1
  12. package/dist/chunks/{chunk-2WND2XFN.js → chunk-FVDFTZNG.js} +1 -1
  13. package/dist/chunks/{chunk-IOV7PLXQ.js → chunk-H5BA73FD.js} +4 -4
  14. package/dist/chunks/{chunk-42PRZ45G.js → chunk-LCH4AM3G.js} +4 -4
  15. package/dist/chunks/{chunk-FJP2X2TE.js → chunk-LMA2ECMW.js} +2 -2
  16. package/dist/chunks/{chunk-NLEBTR3S.js → chunk-OKWVPKJJ.js} +1 -1
  17. package/dist/chunks/{chunk-APC5GMBX.js → chunk-OX7C563N.js} +1 -1
  18. package/dist/chunks/{chunk-IDTFK3CR.js → chunk-QNCTSLLG.js} +1 -1
  19. package/dist/chunks/{chunk-JRPLGVXQ.js → chunk-W3JJBXIV.js} +1 -1
  20. package/dist/chunks/{chunk-B744TFL4.js → chunk-XNIDT5YQ.js} +1 -1
  21. package/dist/chunks/{compile-vercel-config-CGU7GBYQ.js → compile-vercel-config-I3T4AEXU.js} +1 -1
  22. package/dist/chunks/{delete-XKC6CE3R.js → delete-OD4WVKF4.js} +2 -2
  23. package/dist/chunks/{disable-F2RLDMXX.js → disable-SH5IOSNN.js} +2 -2
  24. package/dist/chunks/{discard-N4MILEID.js → discard-UORFIAA7.js} +2 -2
  25. package/dist/chunks/{edit-PMIBPG7J.js → edit-XFOZPNOL.js} +3 -3
  26. package/dist/chunks/{enable-AON5KGOT.js → enable-EVLFH26N.js} +2 -2
  27. package/dist/chunks/{export-OQKO5JVC.js → export-WJSCQI55.js} +2 -2
  28. package/dist/chunks/{inspect-7TLOVORH.js → inspect-HWK54XQ6.js} +3 -3
  29. package/dist/chunks/{list-RJHF6SWM.js → list-IYZBA423.js} +2 -2
  30. package/dist/chunks/{list-SCOE3N4I.js → list-KZ647RZP.js} +3 -3
  31. package/dist/chunks/{ls-CFTCULV5.js → ls-ZCBISAGK.js} +4 -4
  32. package/dist/chunks/{publish-6VOT42HN.js → publish-YR3J3EPP.js} +2 -2
  33. package/dist/chunks/{query-OHEBAPTS.js → query-X2QQO76U.js} +2 -2
  34. package/dist/chunks/{reorder-GMIEF42H.js → reorder-MCF2HGT2.js} +2 -2
  35. package/dist/chunks/{restore-JY2JCHOY.js → restore-OYG5VNC5.js} +2 -2
  36. package/dist/chunks/{rm-FQB3M5YP.js → rm-P5AQ5QOK.js} +4 -4
  37. package/dist/chunks/{rule-inspect-2JWJRPGL.js → rule-inspect-PLVOGWS6.js} +4 -4
  38. package/dist/chunks/{rules-MULKOWZ5.js → rules-EVN4EVS7.js} +6 -6
  39. package/dist/chunks/{schema-4YC2WD3R.js → schema-QMTPSIKA.js} +2 -2
  40. package/dist/chunks/{update-T4SXDA7F.js → update-3ZZK7JLD.js} +4 -4
  41. package/dist/commands/build/index.js +9 -9
  42. package/dist/commands/deploy/index.js +10 -10
  43. package/dist/commands/dev/index.js +8 -8
  44. package/dist/commands/env/index.js +4 -4
  45. package/dist/commands/link/index.js +7 -7
  46. package/dist/commands/list/index.js +3 -3
  47. package/dist/commands-bulk.js +156 -97
  48. package/dist/index.js +8 -8
  49. package/dist/version.mjs +1 -1
  50. package/package.json +18 -18
@@ -8,22 +8,22 @@ import {
8
8
  getUpdateCommandInfo,
9
9
  isGlobal,
10
10
  isNativeBinaryInstall
11
- } from "./chunk-NLEBTR3S.js";
11
+ } from "./chunk-OKWVPKJJ.js";
12
12
  import {
13
13
  getGlobalPathConfig,
14
14
  writeToConfigFile
15
- } from "./chunk-WNYUBBFH.js";
15
+ } from "./chunk-25I7H5PE.js";
16
16
  import {
17
17
  apiCommand,
18
18
  listSubcommand2 as listSubcommand,
19
19
  loginCommand
20
- } from "./chunk-HVYPWTJQ.js";
20
+ } from "./chunk-222H5MYY.js";
21
21
  import {
22
22
  help
23
23
  } from "./chunk-VNUNCNPE.js";
24
24
  import {
25
25
  login
26
- } from "./chunk-IDTFK3CR.js";
26
+ } from "./chunk-QNCTSLLG.js";
27
27
  import {
28
28
  TelemetryClient
29
29
  } from "./chunk-J5273CSE.js";
@@ -575,15 +575,79 @@ import { readFile, writeFile, mkdir } from "fs/promises";
575
575
 
576
576
  // src/util/openapi/constants.ts
577
577
  var OPENAPI_URL = "https://openapi.vercel.sh/";
578
+ var SSO_API_URL = "https://vercel.com/sso-api";
578
579
  var CACHE_FILE = "openapi-spec.json";
579
580
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
580
581
  var FETCH_TIMEOUT_MS = 10 * 1e3;
582
+ var MAX_OPENAPI_SPEC_BYTES = 50 * 1024 * 1024;
583
+
584
+ // src/util/openapi/read-spec-response.ts
585
+ async function readSpecResponse(response, url, maxBytes = MAX_OPENAPI_SPEC_BYTES) {
586
+ const contentLength = response.headers.get("content-length");
587
+ if (contentLength) {
588
+ const bytes = Number(contentLength);
589
+ if (Number.isFinite(bytes) && bytes > maxBytes) {
590
+ throw new Error(
591
+ `OpenAPI spec from ${url} exceeds the ${maxBytes} byte limit.`
592
+ );
593
+ }
594
+ }
595
+ if (!response.body) {
596
+ throw new Error(`OpenAPI spec from ${url} returned an empty response.`);
597
+ }
598
+ const reader = response.body.getReader();
599
+ const chunks = [];
600
+ let totalBytes = 0;
601
+ while (true) {
602
+ const { done, value } = await reader.read();
603
+ if (done) {
604
+ break;
605
+ }
606
+ if (!value) {
607
+ continue;
608
+ }
609
+ totalBytes += value.byteLength;
610
+ if (totalBytes > maxBytes) {
611
+ await reader.cancel();
612
+ throw new Error(
613
+ `OpenAPI spec from ${url} exceeds the ${maxBytes} byte limit.`
614
+ );
615
+ }
616
+ chunks.push(value);
617
+ }
618
+ const buffer = new Uint8Array(totalBytes);
619
+ let offset = 0;
620
+ for (const chunk of chunks) {
621
+ buffer.set(chunk, offset);
622
+ offset += chunk.byteLength;
623
+ }
624
+ return JSON.parse(new TextDecoder().decode(buffer));
625
+ }
626
+
627
+ // src/util/openapi/spec-url-allowlist.ts
628
+ var ALLOWED_SPEC_HOSTS = ["vercel.sh", "vercel.tools"];
629
+ function assertAllowedSpecUrl(specUrl) {
630
+ const parsedUrl = new URL(specUrl);
631
+ if (parsedUrl.protocol !== "https:") {
632
+ throw new Error("OpenAPI spec URL must use https");
633
+ }
634
+ if (!ALLOWED_SPEC_HOSTS.some((host) => isHostOrSubdomain(parsedUrl, host))) {
635
+ throw new Error("OpenAPI spec URL must be on an allowed origin.");
636
+ }
637
+ return parsedUrl;
638
+ }
639
+ function isHostOrSubdomain(url, host) {
640
+ return url.hostname === host || url.hostname.endsWith(`.${host}`);
641
+ }
581
642
 
582
643
  // src/util/openapi/openapi-cache.ts
583
644
  var OpenApiCache = class {
584
- constructor() {
645
+ constructor(options) {
585
646
  this.spec = null;
647
+ this.error = null;
586
648
  this.cachePath = join(getGlobalPathConfig(), CACHE_FILE);
649
+ this.specUrl = options?.specUrl;
650
+ this.fetchSpecUrl = options?.fetchSpecUrl;
587
651
  }
588
652
  /**
589
653
  * Check if the spec has been loaded
@@ -591,13 +655,23 @@ var OpenApiCache = class {
591
655
  get isLoaded() {
592
656
  return this.spec !== null;
593
657
  }
658
+ get loadError() {
659
+ return this.error;
660
+ }
594
661
  /**
595
662
  * Load the OpenAPI spec, using cache if available and fresh.
596
663
  * Returns true if successful, false otherwise.
597
664
  */
598
665
  async load(forceRefresh = false) {
666
+ return this.loadSpec(forceRefresh);
667
+ }
668
+ async loadSpec(forceRefresh = false) {
669
+ this.error = null;
670
+ if (this.specUrl) {
671
+ return this.loadCustomSpec(this.specUrl);
672
+ }
599
673
  if (!forceRefresh) {
600
- const cached = await this.readCache();
674
+ const cached = await this.readCache(this.cachePath);
601
675
  if (cached && !this.isExpired(cached.fetchedAt)) {
602
676
  output_manager_default.debug("Using cached OpenAPI spec");
603
677
  this.spec = cached.spec;
@@ -606,12 +680,12 @@ var OpenApiCache = class {
606
680
  }
607
681
  try {
608
682
  output_manager_default.debug("Fetching OpenAPI spec from " + OPENAPI_URL);
609
- this.spec = await this.fetchSpec();
610
- await this.saveCache(this.spec);
683
+ this.spec = await this.fetchSpec(OPENAPI_URL);
684
+ await this.saveCache(this.cachePath, this.spec);
611
685
  return true;
612
686
  } catch (err) {
613
687
  output_manager_default.debug(`Failed to fetch OpenAPI spec: ${err}`);
614
- const stale = await this.readCache();
688
+ const stale = await this.readCache(this.cachePath);
615
689
  if (stale) {
616
690
  output_manager_default.debug("Using stale cached OpenAPI spec");
617
691
  this.spec = stale.spec;
@@ -620,6 +694,25 @@ var OpenApiCache = class {
620
694
  return false;
621
695
  }
622
696
  }
697
+ async loadCustomSpec(specUrl) {
698
+ try {
699
+ assertAllowedSpecUrl(specUrl);
700
+ output_manager_default.debug("Fetching OpenAPI spec from " + specUrl);
701
+ const spec = this.fetchSpecUrl ? await this.fetchSpecUrl(specUrl) : await this.fetchSpec(specUrl);
702
+ if (!spec) {
703
+ this.error = `Could not load OpenAPI spec from ${specUrl}.`;
704
+ return false;
705
+ }
706
+ this.validateSpec(spec, specUrl);
707
+ this.spec = spec;
708
+ return Boolean(this.spec);
709
+ } catch (err) {
710
+ const message = err instanceof Error ? err.message : String(err);
711
+ this.error = message;
712
+ output_manager_default.debug(`Failed to fetch OpenAPI spec from ${specUrl}: ${message}`);
713
+ return false;
714
+ }
715
+ }
623
716
  /**
624
717
  * Load the OpenAPI spec with spinner UI.
625
718
  * Returns true if successful, false otherwise.
@@ -735,43 +828,69 @@ var OpenApiCache = class {
735
828
  /**
736
829
  * Read cached spec from disk
737
830
  */
738
- async readCache() {
831
+ async readCache(cachePath) {
739
832
  try {
740
- const content = await readFile(this.cachePath, "utf-8");
833
+ const content = await readFile(cachePath, "utf-8");
741
834
  return JSON.parse(content);
742
835
  } catch {
743
836
  return null;
744
837
  }
745
838
  }
746
839
  /**
747
- * Save spec to disk cache
840
+ * Save public spec to disk cache
748
841
  */
749
- async saveCache(spec) {
842
+ async saveCache(cachePath, spec) {
750
843
  const cached = {
751
844
  fetchedAt: Date.now(),
752
845
  spec
753
846
  };
754
- const dir = join(this.cachePath, "..");
847
+ const dir = join(cachePath, "..");
755
848
  await mkdir(dir, { recursive: true });
756
- await writeFile(this.cachePath, JSON.stringify(cached));
849
+ await writeFile(cachePath, JSON.stringify(cached));
757
850
  output_manager_default.debug("Saved OpenAPI spec to cache");
758
851
  }
759
852
  /**
760
853
  * Fetch OpenAPI spec from remote with timeout
761
854
  */
762
- async fetchSpec() {
855
+ async fetchSpec(url) {
763
856
  const controller = new AbortController();
764
857
  const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
765
858
  try {
766
- const response = await fetch(OPENAPI_URL, { signal: controller.signal });
859
+ const response = await fetch(url, { signal: controller.signal });
767
860
  if (!response.ok) {
768
861
  throw new Error(`Failed to fetch OpenAPI spec: ${response.status}`);
769
862
  }
770
- return await response.json();
863
+ const spec = await readSpecResponse(response, url);
864
+ this.validateSpec(spec, url);
865
+ return spec;
771
866
  } finally {
772
867
  clearTimeout(timeoutId);
773
868
  }
774
869
  }
870
+ validateSpec(spec, url) {
871
+ if (!spec || typeof spec !== "object") {
872
+ throw new Error(
873
+ `Invalid OpenAPI spec from ${url}: expected a JSON object.`
874
+ );
875
+ }
876
+ if (typeof spec.openapi !== "string" || !spec.openapi.startsWith("3.")) {
877
+ throw new Error(
878
+ `Invalid OpenAPI spec from ${url}: expected an OpenAPI 3.x document with an "openapi" field.`
879
+ );
880
+ }
881
+ if (!spec.paths || typeof spec.paths !== "object") {
882
+ throw new Error(
883
+ `Invalid OpenAPI spec from ${url}: expected a "paths" object.`
884
+ );
885
+ }
886
+ for (const path of Object.keys(spec.paths)) {
887
+ if (!path.startsWith("/") || path.startsWith("//")) {
888
+ throw new Error(
889
+ `Invalid OpenAPI spec from ${url}: path "${path}" must be a relative API path.`
890
+ );
891
+ }
892
+ }
893
+ }
775
894
  /**
776
895
  * Check if cached spec is expired
777
896
  */
@@ -779,7 +898,7 @@ var OpenApiCache = class {
779
898
  return Date.now() - fetchedAt > CACHE_TTL_MS;
780
899
  }
781
900
  /**
782
- * Sort endpoints by path, then by method
901
+ * Sort endpoints by path, then by method.
783
902
  */
784
903
  sortEndpoints(endpoints) {
785
904
  return endpoints.sort((a, b) => {
@@ -790,7 +909,7 @@ var OpenApiCache = class {
790
909
  });
791
910
  }
792
911
  /**
793
- * Extract all available endpoints from the spec
912
+ * Extract all available endpoints from the loaded spec.
794
913
  */
795
914
  extractEndpoints() {
796
915
  const endpoints = [];
@@ -820,21 +939,21 @@ var OpenApiCache = class {
820
939
  /**
821
940
  * Resolve a $ref to its actual schema
822
941
  */
823
- resolveSchemaRef(schema) {
942
+ resolveSchemaRef(schema, spec = this.spec) {
824
943
  if (!schema)
825
944
  return void 0;
826
945
  if (schema.$ref) {
827
946
  const match = schema.$ref.match(/^#\/components\/schemas\/(.+)$/);
828
- if (match && this.spec.components?.schemas) {
829
- const resolved = this.spec.components.schemas[match[1]];
830
- return this.resolveSchemaRef(resolved);
947
+ if (match && spec.components?.schemas) {
948
+ const resolved = spec.components.schemas[match[1]];
949
+ return this.resolveSchemaRef(resolved, spec);
831
950
  }
832
951
  return void 0;
833
952
  }
834
953
  if (schema.allOf && schema.allOf.length > 0) {
835
954
  const merged = { type: "object", properties: {}, required: [] };
836
955
  for (const subSchema of schema.allOf) {
837
- const resolved = this.resolveSchemaRef(subSchema);
956
+ const resolved = this.resolveSchemaRef(subSchema, spec);
838
957
  if (resolved) {
839
958
  if (resolved.properties) {
840
959
  merged.properties = {
@@ -955,6 +1074,14 @@ var ApiTelemetryClient = class extends TelemetryClient {
955
1074
  });
956
1075
  }
957
1076
  }
1077
+ trackCliOptionSpecUrl(specUrl) {
1078
+ if (specUrl) {
1079
+ this.trackCliOption({
1080
+ option: "spec-url",
1081
+ value: this.redactedValue
1082
+ });
1083
+ }
1084
+ }
958
1085
  trackCliFlagPaginate(value) {
959
1086
  if (value) {
960
1087
  this.trackCliFlag("paginate");
@@ -1385,6 +1512,133 @@ async function buildRequestForResolvedOperation(endpoint, bodyFields, flags, pos
1385
1512
  };
1386
1513
  }
1387
1514
 
1515
+ // src/util/openapi/spec-url.ts
1516
+ import { createHash } from "crypto";
1517
+ var MAX_REDIRECTS = 3;
1518
+ async function fetchSpecUrl(client, specUrl) {
1519
+ const specOrigin = assertAllowedSpecUrl(specUrl).origin;
1520
+ const probe = await fetchWithTimeout(specUrl, { readSpec: true });
1521
+ if (probe.response.ok) {
1522
+ return probe.spec ?? null;
1523
+ }
1524
+ const nonce = getSetCookieValue(probe.response, "_vercel_sso_nonce");
1525
+ if (!nonce) {
1526
+ output_manager_default.debug(
1527
+ `OpenAPI spec URL returned ${probe.response.status} without a Vercel SSO nonce`
1528
+ );
1529
+ throw new Error(formatHttpError(specUrl, probe.response));
1530
+ }
1531
+ const token = client.authConfig.token;
1532
+ if (!token) {
1533
+ output_manager_default.debug("OpenAPI spec URL requires Vercel authentication");
1534
+ return null;
1535
+ }
1536
+ const hashedNonce = createHash("sha256").update(nonce).digest("hex");
1537
+ const ssoUrl = `${SSO_API_URL}?url=${encodeURIComponent(
1538
+ specUrl
1539
+ )}&nonce=${hashedNonce}`;
1540
+ const sso = await fetchWithTimeout(ssoUrl, {
1541
+ cookie: `authorization=${encodeURIComponent(`Bearer ${token}`)}; isLoggedIn=1`
1542
+ });
1543
+ const location = sso.response.headers.get("location");
1544
+ if (!location || !location.includes("_vercel_jwt=")) {
1545
+ output_manager_default.debug("OpenAPI spec URL: user has no access");
1546
+ throw new Error(formatHttpError(specUrl, sso.response));
1547
+ }
1548
+ const cookies = /* @__PURE__ */ new Map([["_vercel_sso_nonce", nonce]]);
1549
+ let url = location;
1550
+ for (let i = 0; i <= MAX_REDIRECTS; i++) {
1551
+ if (!isSameOriginUrl(url, specOrigin)) {
1552
+ output_manager_default.debug("OpenAPI spec URL: cross-origin redirect rejected");
1553
+ return null;
1554
+ }
1555
+ const { response, spec } = await fetchWithTimeout(url, {
1556
+ cookie: Array.from(cookies, ([name, value]) => `${name}=${value}`).join(
1557
+ "; "
1558
+ ),
1559
+ readSpec: true
1560
+ });
1561
+ if (response.ok) {
1562
+ return spec ?? null;
1563
+ }
1564
+ const next = response.headers.get("location");
1565
+ if (response.status >= 300 && response.status < 400 && next) {
1566
+ const setJwt = getSetCookieValue(response, "_vercel_jwt");
1567
+ if (setJwt) {
1568
+ cookies.set("_vercel_jwt", setJwt);
1569
+ }
1570
+ const nextUrl = new URL(next, url).href;
1571
+ if (!isSameOriginUrl(nextUrl, specOrigin)) {
1572
+ output_manager_default.debug("OpenAPI spec URL: cross-origin redirect rejected");
1573
+ return null;
1574
+ }
1575
+ url = nextUrl;
1576
+ continue;
1577
+ }
1578
+ output_manager_default.debug(`OpenAPI spec URL: unexpected response ${response.status}`);
1579
+ throw new Error(formatHttpError(url, response));
1580
+ }
1581
+ output_manager_default.debug("OpenAPI spec URL: too many redirects");
1582
+ return null;
1583
+ }
1584
+ function createOpenApiCache(client, specUrl) {
1585
+ return new OpenApiCache(
1586
+ specUrl ? {
1587
+ specUrl,
1588
+ fetchSpecUrl: (url) => fetchSpecUrl(client, url)
1589
+ } : void 0
1590
+ );
1591
+ }
1592
+ async function fetchWithTimeout(url, options) {
1593
+ const controller = new AbortController();
1594
+ const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
1595
+ try {
1596
+ const response = await fetch(url, {
1597
+ redirect: "manual",
1598
+ signal: controller.signal,
1599
+ headers: options?.cookie ? { cookie: options.cookie } : void 0
1600
+ });
1601
+ const spec = options?.readSpec && response.ok ? await readSpecResponse(
1602
+ response,
1603
+ formatDiagnosticUrl(url)
1604
+ ) : void 0;
1605
+ return { response, spec };
1606
+ } finally {
1607
+ clearTimeout(timeoutId);
1608
+ }
1609
+ }
1610
+ function isSameOriginUrl(url, origin) {
1611
+ try {
1612
+ return new URL(url).origin === origin;
1613
+ } catch {
1614
+ return false;
1615
+ }
1616
+ }
1617
+ function formatHttpError(url, response) {
1618
+ const statusText = response.statusText ? ` ${response.statusText}` : "";
1619
+ return `Could not load OpenAPI spec from ${formatDiagnosticUrl(url)}: HTTP ${response.status}${statusText}.`;
1620
+ }
1621
+ function formatDiagnosticUrl(url) {
1622
+ try {
1623
+ const parsed = new URL(url);
1624
+ parsed.hash = "";
1625
+ for (const key of parsed.searchParams.keys()) {
1626
+ parsed.searchParams.set(key, "[redacted]");
1627
+ }
1628
+ return parsed.href;
1629
+ } catch {
1630
+ return url;
1631
+ }
1632
+ }
1633
+ function getSetCookieValue(response, name) {
1634
+ const header = response.headers.get("set-cookie");
1635
+ if (!header) {
1636
+ return null;
1637
+ }
1638
+ const match = header.match(new RegExp(`${name}=([^;,\\s]+)`));
1639
+ return match ? match[1] : null;
1640
+ }
1641
+
1388
1642
  // src/util/openapi/vercel-cli-table.ts
1389
1643
  var import_ms = __toESM(require_ms(), 1);
1390
1644
  var import_chalk = __toESM(require_source(), 1);
@@ -1480,7 +1734,7 @@ async function tryOpenApiFallback(client, cliArgs, resolveTag) {
1480
1734
  client.dangerouslySkipPermissions = true;
1481
1735
  }
1482
1736
  if (flags["--help"]) {
1483
- return printOperationHelpForTagCommand(flags, tag, operationHint);
1737
+ return printOperationHelpForTagCommand(client, flags, tag, operationHint);
1484
1738
  }
1485
1739
  return runTagOperation(client, {
1486
1740
  tag,
@@ -1654,9 +1908,12 @@ async function api(client) {
1654
1908
  telemetryClient.trackCliFlagRefresh(true);
1655
1909
  if (lsFlags["--format"])
1656
1910
  telemetryClient.trackCliOptionFormat(lsFlags["--format"]);
1911
+ if (lsFlags["--spec-url"])
1912
+ telemetryClient.trackCliOptionSpecUrl(lsFlags["--spec-url"]);
1657
1913
  return listEndpoints(
1658
1914
  client,
1659
1915
  lsFlags["--refresh"] ?? false,
1916
+ lsFlags["--spec-url"],
1660
1917
  lsFlags["--format"] ?? "table"
1661
1918
  );
1662
1919
  }
@@ -1675,7 +1932,8 @@ async function api(client) {
1675
1932
  if (client.stdin.isTTY) {
1676
1933
  const selected = await promptEndpointSelection(
1677
1934
  client,
1678
- flags["--refresh"] ?? false
1935
+ flags["--refresh"] ?? false,
1936
+ flags["--spec-url"]
1679
1937
  );
1680
1938
  if (!selected) {
1681
1939
  return 1;
@@ -1740,6 +1998,8 @@ async function api(client) {
1740
1998
  telemetryClient.trackCliFlagRaw(true);
1741
1999
  if (flags["--refresh"])
1742
2000
  telemetryClient.trackCliFlagRefresh(true);
2001
+ if (flags["--spec-url"])
2002
+ telemetryClient.trackCliOptionSpecUrl(flags["--spec-url"]);
1743
2003
  if (flags["--generate"])
1744
2004
  telemetryClient.trackCliOptionGenerate(flags["--generate"]);
1745
2005
  if (flags["--dangerously-skip-permissions"])
@@ -1757,11 +2017,11 @@ async function api(client) {
1757
2017
  }
1758
2018
  return executeApiRequest(client, requestConfig, finalFlags);
1759
2019
  }
1760
- async function printOperationHelpForTagCommand(flags, tag, operationId) {
1761
- const openApi = new OpenApiCache();
2020
+ async function printOperationHelpForTagCommand(client, flags, tag, operationId) {
2021
+ const openApi = createOpenApiCache(client, flags["--spec-url"]);
1762
2022
  const loaded = await openApi.loadWithSpinner(flags["--refresh"] ?? false);
1763
2023
  if (!loaded) {
1764
- output_manager_default.error("Could not load API specification");
2024
+ output_manager_default.error(openApi.loadError ?? "Could not load API specification");
1765
2025
  return 1;
1766
2026
  }
1767
2027
  const allEndpoints = openApi.getEndpoints();
@@ -2219,12 +2479,14 @@ function outputResults(client, data, flags) {
2219
2479
  client.stdout.write(formatted + "\n");
2220
2480
  return 0;
2221
2481
  }
2222
- async function promptEndpointSelection(client, forceRefresh) {
2482
+ async function promptEndpointSelection(client, forceRefresh, specUrl) {
2223
2483
  try {
2224
- const openApi = new OpenApiCache();
2484
+ const openApi = createOpenApiCache(client, specUrl);
2225
2485
  const success = await openApi.loadWithSpinner(forceRefresh);
2226
2486
  if (!success) {
2227
- output_manager_default.error("Could not load API specification for endpoint selection");
2487
+ output_manager_default.error(
2488
+ openApi.loadError ?? "Could not load API specification for endpoint selection"
2489
+ );
2228
2490
  return null;
2229
2491
  }
2230
2492
  const endpoints = openApi.getEndpoints();
@@ -2249,7 +2511,8 @@ async function promptEndpointSelection(client, forceRefresh) {
2249
2511
  }
2250
2512
  }
2251
2513
  async function promptForEndpoint(client, endpoints) {
2252
- const allChoices = endpoints.map((ep) => ({
2514
+ const total = endpoints.length;
2515
+ const buildChoices = () => endpoints.map((ep) => ({
2253
2516
  name: `${colorizeMethodPadded(ep.method)} ${ep.path}`,
2254
2517
  value: ep,
2255
2518
  // Show full description if available, otherwise show summary
@@ -2258,10 +2521,10 @@ async function promptForEndpoint(client, endpoints) {
2258
2521
  summary: ep.summary,
2259
2522
  tags: ep.tags
2260
2523
  }));
2261
- const total = allChoices.length;
2262
2524
  return client.input.search({
2263
2525
  message: `Search for an API endpoint (${total} available):`,
2264
2526
  source: async (term) => {
2527
+ const allChoices = buildChoices();
2265
2528
  if (!term) {
2266
2529
  return allChoices;
2267
2530
  }
@@ -2278,11 +2541,11 @@ async function promptForEndpoint(client, endpoints) {
2278
2541
  }
2279
2542
  });
2280
2543
  }
2281
- async function listEndpoints(client, forceRefresh, format) {
2282
- const openApi = new OpenApiCache();
2544
+ async function listEndpoints(client, forceRefresh, specUrl, format) {
2545
+ const openApi = createOpenApiCache(client, specUrl);
2283
2546
  const success = await openApi.loadWithSpinner(forceRefresh);
2284
2547
  if (!success) {
2285
- output_manager_default.error("Could not load API specification");
2548
+ output_manager_default.error(openApi.loadError ?? "Could not load API specification");
2286
2549
  return 1;
2287
2550
  }
2288
2551
  const endpoints = openApi.getEndpoints();
@@ -2307,7 +2570,10 @@ function groupEndpointsByPath(endpoints) {
2307
2570
  const grouped = /* @__PURE__ */ new Map();
2308
2571
  for (const ep of endpoints) {
2309
2572
  const existing = grouped.get(ep.path) || [];
2310
- existing.push({ method: ep.method, summary: ep.summary });
2573
+ existing.push({
2574
+ method: ep.method,
2575
+ summary: ep.summary
2576
+ });
2311
2577
  grouped.set(ep.path, existing);
2312
2578
  }
2313
2579
  const methodOrder = ["GET", "POST", "PUT", "PATCH", "DELETE"];
@@ -2362,18 +2628,20 @@ async function promptForParameters(client, path, parameters, bodyFieldsSpec) {
2362
2628
  const optionalBodyFields = bodyFieldsSpec.filter((f) => !f.required);
2363
2629
  let finalPath = path;
2364
2630
  for (const param of pathParams) {
2365
- const value = await client.input.text({
2366
- message: `Enter value for ${formatPathParam(param.name)}${formatDescription(param.description)}:`,
2367
- validate: createRequiredValidator(param.name)
2368
- });
2631
+ const value = await promptForParameterValue(
2632
+ client,
2633
+ param,
2634
+ `Enter value for ${formatPathParam(param.name)}${formatDescription(param.description)}:`
2635
+ );
2369
2636
  finalPath = finalPath.replace(`{${param.name}}`, encodeURIComponent(value));
2370
2637
  }
2371
2638
  const queryValues = {};
2372
2639
  for (const param of requiredQueryParams) {
2373
- queryValues[param.name] = await client.input.text({
2374
- message: `Enter value for ${import_chalk4.default.cyan(param.name)}${formatDescription(param.description)}:`,
2375
- validate: createRequiredValidator(param.name)
2376
- });
2640
+ queryValues[param.name] = await promptForParameterValue(
2641
+ client,
2642
+ param,
2643
+ `Enter value for ${import_chalk4.default.cyan(param.name)}${formatDescription(param.description)}:`
2644
+ );
2377
2645
  }
2378
2646
  if (optionalQueryParams.length > 0) {
2379
2647
  const selectedOptionalParams = await client.input.checkbox({
@@ -2386,10 +2654,11 @@ async function promptForParameters(client, path, parameters, bodyFieldsSpec) {
2386
2654
  });
2387
2655
  for (const paramName of selectedOptionalParams) {
2388
2656
  const param = optionalQueryParams.find((p) => p.name === paramName);
2389
- queryValues[param.name] = await client.input.text({
2390
- message: `Enter value for ${import_chalk4.default.cyan(param.name)}${formatDescription(param.description)}:`,
2391
- validate: createRequiredValidator(param.name)
2392
- });
2657
+ queryValues[param.name] = await promptForParameterValue(
2658
+ client,
2659
+ param,
2660
+ `Enter value for ${import_chalk4.default.cyan(param.name)}${formatDescription(param.description)}:`
2661
+ );
2393
2662
  }
2394
2663
  }
2395
2664
  const bodyFieldValues = [];
@@ -2418,6 +2687,22 @@ async function promptForParameters(client, path, parameters, bodyFieldsSpec) {
2418
2687
  }
2419
2688
  return { finalUrl: finalPath, bodyFields: bodyFieldValues };
2420
2689
  }
2690
+ async function promptForParameterValue(client, param, message) {
2691
+ const schemaDefault = param.schema?.default !== void 0 ? String(param.schema.default) : void 0;
2692
+ const enumValues = param.schema?.enum;
2693
+ if (enumValues && enumValues.length > 0) {
2694
+ return client.input.select({
2695
+ message,
2696
+ choices: enumValues.map((v) => ({ name: String(v), value: String(v) })),
2697
+ default: schemaDefault
2698
+ });
2699
+ }
2700
+ return client.input.text({
2701
+ message,
2702
+ default: schemaDefault,
2703
+ validate: createRequiredValidator(param.name)
2704
+ });
2705
+ }
2421
2706
  async function promptForBodyField(client, field, required) {
2422
2707
  const description = formatDescription(field.description);
2423
2708
  const optionalHint = required ? "" : import_chalk4.default.dim(" (optional)");
@@ -2458,12 +2743,12 @@ async function runTagOperation(client, options) {
2458
2743
  opts: { store: client.telemetryEventStore }
2459
2744
  });
2460
2745
  const finalFlags = { ...flags };
2461
- const openApi = new OpenApiCache();
2746
+ const openApi = createOpenApiCache(client, finalFlags["--spec-url"]);
2462
2747
  const loaded = await openApi.loadWithSpinner(
2463
2748
  finalFlags["--refresh"] ?? false
2464
2749
  );
2465
2750
  if (!loaded) {
2466
- output_manager_default.error("Could not load API specification");
2751
+ output_manager_default.error(openApi.loadError ?? "Could not load API specification");
2467
2752
  return 1;
2468
2753
  }
2469
2754
  const allEndpoints = openApi.getEndpoints();
@@ -2543,6 +2828,8 @@ async function runTagOperation(client, options) {
2543
2828
  telemetryClient.trackCliFlagRaw(true);
2544
2829
  if (finalFlags["--refresh"])
2545
2830
  telemetryClient.trackCliFlagRefresh(true);
2831
+ if (finalFlags["--spec-url"])
2832
+ telemetryClient.trackCliOptionSpecUrl(finalFlags["--spec-url"]);
2546
2833
  if (finalFlags["--generate"])
2547
2834
  telemetryClient.trackCliOptionGenerate(finalFlags["--generate"]);
2548
2835
  if (finalFlags["--dangerously-skip-permissions"])
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-LJ5WXXG6.js";
11
11
  import {
12
12
  getLinkedProject
13
- } from "./chunk-IDTFK3CR.js";
13
+ } from "./chunk-QNCTSLLG.js";
14
14
  import {
15
15
  buildCommandWithYes,
16
16
  outputAgentError
@@ -6,7 +6,7 @@ const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __dirname_(__filename);
7
7
  import {
8
8
  resolveAlertsScope
9
- } from "./chunk-HYFP6VVA.js";
9
+ } from "./chunk-3PICWXS2.js";
10
10
  import {
11
11
  handleValidationError,
12
12
  outputError,
@@ -18,7 +18,7 @@ import {
18
18
  require_lib,
19
19
  require_minimatch,
20
20
  require_pluralize
21
- } from "./chunk-IDTFK3CR.js";
21
+ } from "./chunk-QNCTSLLG.js";
22
22
  import {
23
23
  CantParseJSONFile,
24
24
  cmd,
@@ -6,7 +6,7 @@ const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __dirname_(__filename);
7
7
  import {
8
8
  getEnvTargetPlaceholder
9
- } from "./chunk-IDTFK3CR.js";
9
+ } from "./chunk-QNCTSLLG.js";
10
10
  import {
11
11
  projectOption,
12
12
  yesOption