vercel 54.12.0 → 54.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.
- package/dist/chunks/{add-4F6CBPSE.js → add-SYDJV2T4.js} +4 -4
- package/dist/chunks/{chunk-OBWYK3NL.js → chunk-2OG4XEO7.js} +1 -1
- package/dist/chunks/{chunk-DITVV3KE.js → chunk-4643KU3X.js} +1 -1
- package/dist/chunks/{chunk-NLEBTR3S.js → chunk-4XUOV2X3.js} +1 -1
- package/dist/chunks/{chunk-NZDGG7W3.js → chunk-AYYWS2SR.js} +1 -1
- package/dist/chunks/{chunk-2WND2XFN.js → chunk-BKBME5J7.js} +1 -1
- package/dist/chunks/{chunk-IDTFK3CR.js → chunk-EF7I74B3.js} +1 -6
- package/dist/chunks/{chunk-APC5GMBX.js → chunk-EWCHYBUM.js} +1 -1
- package/dist/chunks/{chunk-WNYUBBFH.js → chunk-H2V3VLCZ.js} +2 -2
- package/dist/chunks/{chunk-FJP2X2TE.js → chunk-HFZBZ5RL.js} +2 -2
- package/dist/chunks/{chunk-IOV7PLXQ.js → chunk-HZCLVVUY.js} +4 -4
- package/dist/chunks/{chunk-7IAMAKFC.js → chunk-KY27SDWY.js} +1 -1
- package/dist/chunks/{chunk-HVYPWTJQ.js → chunk-MPJHH4XH.js} +27 -5
- package/dist/chunks/{chunk-ZYNF76YT.js → chunk-MVNPVHFE.js} +340 -53
- package/dist/chunks/{chunk-42PRZ45G.js → chunk-OBN3CMNI.js} +4 -4
- package/dist/chunks/{chunk-B744TFL4.js → chunk-RWBYP6J5.js} +1 -1
- package/dist/chunks/{chunk-JRPLGVXQ.js → chunk-S6JBHRRQ.js} +1 -1
- package/dist/chunks/{chunk-LGWH2KFI.js → chunk-TUDFOYDC.js} +3 -3
- package/dist/chunks/{chunk-HYFP6VVA.js → chunk-VX2CL5SM.js} +2 -2
- package/dist/chunks/{chunk-ADBU633H.js → chunk-X4M2XSJZ.js} +1 -1
- package/dist/chunks/{compile-vercel-config-CGU7GBYQ.js → compile-vercel-config-ANNU2HBR.js} +1 -1
- package/dist/chunks/{delete-XKC6CE3R.js → delete-CSL7GQUM.js} +2 -2
- package/dist/chunks/{disable-F2RLDMXX.js → disable-WRZTPAJJ.js} +2 -2
- package/dist/chunks/{discard-N4MILEID.js → discard-L2YVL23C.js} +2 -2
- package/dist/chunks/{edit-PMIBPG7J.js → edit-VXYNQVBR.js} +3 -3
- package/dist/chunks/{enable-AON5KGOT.js → enable-OWXV2G3V.js} +2 -2
- package/dist/chunks/{export-OQKO5JVC.js → export-6KAIMGH6.js} +2 -2
- package/dist/chunks/{inspect-7TLOVORH.js → inspect-UZ5CC3HV.js} +3 -3
- package/dist/chunks/{list-SCOE3N4I.js → list-7BYAGN5B.js} +3 -3
- package/dist/chunks/{list-RJHF6SWM.js → list-PHVOL64I.js} +2 -2
- package/dist/chunks/{ls-CFTCULV5.js → ls-5QIP5PDC.js} +4 -4
- package/dist/chunks/{publish-6VOT42HN.js → publish-6KB6TNYM.js} +2 -2
- package/dist/chunks/{query-OHEBAPTS.js → query-2PCHFFUA.js} +2 -2
- package/dist/chunks/{reorder-GMIEF42H.js → reorder-AN4IH7VE.js} +2 -2
- package/dist/chunks/{restore-JY2JCHOY.js → restore-CA72EKHV.js} +2 -2
- package/dist/chunks/{rm-FQB3M5YP.js → rm-ZEX7PISI.js} +4 -4
- package/dist/chunks/{rule-inspect-2JWJRPGL.js → rule-inspect-ZMHGGEUM.js} +4 -4
- package/dist/chunks/{rules-MULKOWZ5.js → rules-XNQ4LDXH.js} +6 -6
- package/dist/chunks/{schema-4YC2WD3R.js → schema-Q2JNER6Z.js} +2 -2
- package/dist/chunks/{update-T4SXDA7F.js → update-WMWLJRV2.js} +4 -4
- package/dist/commands/build/index.js +9 -9
- package/dist/commands/deploy/index.js +10 -10
- package/dist/commands/dev/index.js +8 -8
- package/dist/commands/env/index.js +4 -4
- package/dist/commands/link/index.js +7 -7
- package/dist/commands/list/index.js +3 -3
- package/dist/commands-bulk.js +156 -97
- package/dist/index.js +8 -8
- package/dist/version.mjs +1 -1
- package/package.json +19 -19
|
@@ -8,22 +8,22 @@ import {
|
|
|
8
8
|
getUpdateCommandInfo,
|
|
9
9
|
isGlobal,
|
|
10
10
|
isNativeBinaryInstall
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-4XUOV2X3.js";
|
|
12
12
|
import {
|
|
13
13
|
getGlobalPathConfig,
|
|
14
14
|
writeToConfigFile
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-H2V3VLCZ.js";
|
|
16
16
|
import {
|
|
17
17
|
apiCommand,
|
|
18
18
|
listSubcommand2 as listSubcommand,
|
|
19
19
|
loginCommand
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-MPJHH4XH.js";
|
|
21
21
|
import {
|
|
22
22
|
help
|
|
23
23
|
} from "./chunk-VNUNCNPE.js";
|
|
24
24
|
import {
|
|
25
25
|
login
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-EF7I74B3.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(
|
|
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(
|
|
847
|
+
const dir = join(cachePath, "..");
|
|
755
848
|
await mkdir(dir, { recursive: true });
|
|
756
|
-
await writeFile(
|
|
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(
|
|
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
|
-
|
|
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 &&
|
|
829
|
-
const resolved =
|
|
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 =
|
|
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 =
|
|
2484
|
+
const openApi = createOpenApiCache(client, specUrl);
|
|
2225
2485
|
const success = await openApi.loadWithSpinner(forceRefresh);
|
|
2226
2486
|
if (!success) {
|
|
2227
|
-
output_manager_default.error(
|
|
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
|
|
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 =
|
|
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({
|
|
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
|
|
2366
|
-
|
|
2367
|
-
|
|
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
|
|
2374
|
-
|
|
2375
|
-
|
|
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
|
|
2390
|
-
|
|
2391
|
-
|
|
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 =
|
|
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"])
|
|
@@ -6,13 +6,13 @@ const __filename = __fileURLToPath(import.meta.url);
|
|
|
6
6
|
const __dirname = __dirname_(__filename);
|
|
7
7
|
import {
|
|
8
8
|
writeProjectSettings
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-S6JBHRRQ.js";
|
|
10
10
|
import {
|
|
11
11
|
ensureLink
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-HFZBZ5RL.js";
|
|
13
13
|
import {
|
|
14
14
|
pullCommand
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-BKBME5J7.js";
|
|
16
16
|
import {
|
|
17
17
|
help
|
|
18
18
|
} from "./chunk-VNUNCNPE.js";
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
envPullCommandLogic,
|
|
24
24
|
humanizePath,
|
|
25
25
|
parseTarget
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-EF7I74B3.js";
|
|
27
27
|
import {
|
|
28
28
|
TelemetryClient
|
|
29
29
|
} from "./chunk-J5273CSE.js";
|