vercel 51.5.0 → 51.6.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.
- package/dist/chunks/{add-RNQLGEYS.js → add-JALB3DKU.js} +6 -6
- package/dist/chunks/{chunk-DKFFXOHJ.js → chunk-34IM6J7A.js} +5 -2
- package/dist/chunks/{chunk-D2D4FJ6S.js → chunk-3N3AYMMW.js} +33 -18
- package/dist/chunks/{chunk-SG4QOQTF.js → chunk-4X7GBE5B.js} +101 -53
- package/dist/chunks/{chunk-5VKKTHMP.js → chunk-553A6UFX.js} +10 -6
- package/dist/chunks/{chunk-6C33Y3DC.js → chunk-5KFTN63Q.js} +8 -8
- package/dist/chunks/{chunk-TAOVG4PS.js → chunk-7L4XVUFK.js} +2 -2
- package/dist/chunks/{chunk-4DR2FV6O.js → chunk-BBW6EGBQ.js} +1 -1
- package/dist/chunks/{chunk-LDXYSGPZ.js → chunk-C7UTFMYF.js} +2 -2
- package/dist/chunks/chunk-CHUU7VXC.js +2314 -0
- package/dist/chunks/{chunk-BHDZCUTT.js → chunk-DAOAZ2VQ.js} +1 -1
- package/dist/chunks/{chunk-CRZM5WM2.js → chunk-DED5G3HZ.js} +1 -1
- package/dist/chunks/{chunk-G6RXZLQ2.js → chunk-DF4AVQY3.js} +2 -2
- package/dist/chunks/{chunk-HNU5CXW4.js → chunk-FH2OHGXG.js} +2 -2
- package/dist/chunks/{chunk-7MF47FW3.js → chunk-FY3TMBQS.js} +1 -1
- package/dist/chunks/{chunk-5NTBJ33M.js → chunk-HUPHOH2F.js} +1 -1
- package/dist/chunks/{chunk-DVQ4SIWF.js → chunk-LUCCJW67.js} +1 -1
- package/dist/chunks/{chunk-NKJC5SI4.js → chunk-LUJPLXGG.js} +2 -2
- package/dist/chunks/{chunk-VGWGLBUC.js → chunk-MCTAPJSL.js} +1 -1
- package/dist/chunks/{chunk-L2JUC7NX.js → chunk-MGJMZIIT.js} +1 -1
- package/dist/chunks/{chunk-FBY3IEDZ.js → chunk-MUJZV257.js} +8 -8
- package/dist/chunks/{chunk-BJQTGP42.js → chunk-PVZBM6NU.js} +1 -1
- package/dist/chunks/{chunk-BRQBLRFB.js → chunk-QFP6FEBN.js} +1 -1
- package/dist/chunks/{chunk-7ZDERWUW.js → chunk-QHXUBID6.js} +2 -2
- package/dist/chunks/{chunk-HQXVCOH6.js → chunk-RW7LIX2Y.js} +1 -1
- package/dist/chunks/{chunk-AUSDBXUD.js → chunk-U73MZTAR.js} +2 -2
- package/dist/chunks/{chunk-537JTK2U.js → chunk-UG4457SI.js} +260 -102
- package/dist/chunks/{chunk-RFMC2QXQ.js → chunk-VDM5O3P6.js} +3 -3
- package/dist/chunks/{chunk-GE6G37P4.js → chunk-WCTFUOSJ.js} +1 -1
- package/dist/chunks/chunk-WYRFA4PX.js +692 -0
- package/dist/chunks/{chunk-UWKTUK3W.js → chunk-XLKXWNRG.js} +1 -1
- package/dist/chunks/{chunk-P56KWLXY.js → chunk-Z66S4G43.js} +1 -1
- package/dist/chunks/{compile-vercel-config-ZVY7LBE3.js → compile-vercel-config-V2SHBZFW.js} +2 -2
- package/dist/chunks/{delete-SKTJMJNP.js → delete-5RI2PRIT.js} +4 -4
- package/dist/chunks/{disable-AG7I6DPV.js → disable-JPKO7VCV.js} +4 -4
- package/dist/chunks/{discard-LUK6LBLT.js → discard-KXGXXDNX.js} +4 -4
- package/dist/chunks/{edit-3BR5HP3U.js → edit-VFUE5PVU.js} +5 -5
- package/dist/chunks/{enable-4JNLOKSM.js → enable-V2AX2FXX.js} +4 -4
- package/dist/chunks/{export-YLZ6QSHG.js → export-BG3TOT6G.js} +4 -4
- package/dist/chunks/{inspect-HUJLUQAV.js → inspect-3QVCZVKV.js} +6 -6
- package/dist/chunks/{list-RMA56KYZ.js → list-CWTYXKB5.js} +7 -7
- package/dist/chunks/{list-EPU4SB3E.js → list-Y2YMJWEY.js} +4 -4
- package/dist/chunks/{ls-7HHDYE6F.js → ls-SY2CP56I.js} +6 -6
- package/dist/chunks/{publish-6YE4OUDI.js → publish-75IJ4PZS.js} +4 -4
- package/dist/chunks/{query-X6Q4ZSZO.js → query-MLMGNGL2.js} +5 -5
- package/dist/chunks/{reorder-VFM23ESC.js → reorder-757V4BF5.js} +4 -4
- package/dist/chunks/{restore-VX34SXVF.js → restore-KV44XHFS.js} +4 -4
- package/dist/chunks/{rm-5KXF2PY3.js → rm-3EGKFLKW.js} +6 -6
- package/dist/chunks/{rule-inspect-JG7AE5TI.js → rule-inspect-AYUGCLVJ.js} +6 -6
- package/dist/chunks/{rules-XRJBT22L.js → rules-FUFDJOIP.js} +6 -6
- package/dist/chunks/{schema-IMD4VV73.js → schema-CI2XUYTW.js} +6 -6
- package/dist/chunks/{types-QNN5CDCB.js → types-M7LVCA3E.js} +3 -3
- package/dist/chunks/{update-4FMWTIJK.js → update-6EM4XIDW.js} +6 -6
- package/dist/commands/build/index.js +57 -34
- package/dist/commands/deploy/index.js +23 -24
- package/dist/commands/dev/index.js +56 -31
- package/dist/commands/env/index.js +36 -22
- package/dist/commands/link/index.js +21 -21
- package/dist/commands/list/index.js +7 -7
- package/dist/commands-bulk.js +1671 -2533
- package/dist/index.js +41 -21
- package/dist/version.mjs +1 -1
- package/package.json +19 -19
- package/dist/chunks/chunk-6CWW4JIG.js +0 -310
- package/dist/chunks/chunk-O7SQKNIT.js +0 -247
- package/dist/chunks/chunk-RJD5NYGF.js +0 -149
|
@@ -0,0 +1,2314 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module';
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname as __dirname_ } from 'node:path';
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __dirname_(__filename);
|
|
7
|
+
import {
|
|
8
|
+
getUpdateCommand
|
|
9
|
+
} from "./chunk-BBW6EGBQ.js";
|
|
10
|
+
import {
|
|
11
|
+
login
|
|
12
|
+
} from "./chunk-5KFTN63Q.js";
|
|
13
|
+
import {
|
|
14
|
+
apiCommand,
|
|
15
|
+
listSubcommand2 as listSubcommand,
|
|
16
|
+
loginCommand
|
|
17
|
+
} from "./chunk-4X7GBE5B.js";
|
|
18
|
+
import {
|
|
19
|
+
help
|
|
20
|
+
} from "./chunk-C7UTFMYF.js";
|
|
21
|
+
import {
|
|
22
|
+
global_path_default
|
|
23
|
+
} from "./chunk-UG4457SI.js";
|
|
24
|
+
import {
|
|
25
|
+
TelemetryClient
|
|
26
|
+
} from "./chunk-U3WLEFHU.js";
|
|
27
|
+
import {
|
|
28
|
+
getFlagsSpecification,
|
|
29
|
+
parseArguments,
|
|
30
|
+
printError,
|
|
31
|
+
require_strip_ansi
|
|
32
|
+
} from "./chunk-VDM5O3P6.js";
|
|
33
|
+
import {
|
|
34
|
+
packageName
|
|
35
|
+
} from "./chunk-ECRBC4HL.js";
|
|
36
|
+
import {
|
|
37
|
+
output_manager_default
|
|
38
|
+
} from "./chunk-ZQKJVHXY.js";
|
|
39
|
+
import {
|
|
40
|
+
require_source
|
|
41
|
+
} from "./chunk-S7KYDPEM.js";
|
|
42
|
+
import {
|
|
43
|
+
__commonJS,
|
|
44
|
+
__toESM
|
|
45
|
+
} from "./chunk-TZ2YI2VH.js";
|
|
46
|
+
|
|
47
|
+
// ../../node_modules/.pnpm/jaro-winkler@0.2.8/node_modules/jaro-winkler/index.js
|
|
48
|
+
var require_jaro_winkler = __commonJS({
|
|
49
|
+
"../../node_modules/.pnpm/jaro-winkler@0.2.8/node_modules/jaro-winkler/index.js"(exports, module) {
|
|
50
|
+
(function(root) {
|
|
51
|
+
"use strict";
|
|
52
|
+
function extend(a, b) {
|
|
53
|
+
for (var property in b) {
|
|
54
|
+
if (b.hasOwnProperty(property)) {
|
|
55
|
+
a[property] = b[property];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return a;
|
|
59
|
+
}
|
|
60
|
+
function distance2(s1, s2, options) {
|
|
61
|
+
var m = 0;
|
|
62
|
+
var defaults = { caseSensitive: true };
|
|
63
|
+
var settings = extend(defaults, options);
|
|
64
|
+
var i;
|
|
65
|
+
var j;
|
|
66
|
+
if (s1.length === 0 || s2.length === 0) {
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
if (!settings.caseSensitive) {
|
|
70
|
+
s1 = s1.toUpperCase();
|
|
71
|
+
s2 = s2.toUpperCase();
|
|
72
|
+
}
|
|
73
|
+
if (s1 === s2) {
|
|
74
|
+
return 1;
|
|
75
|
+
}
|
|
76
|
+
var range = Math.floor(Math.max(s1.length, s2.length) / 2) - 1;
|
|
77
|
+
var s1Matches = new Array(s1.length);
|
|
78
|
+
var s2Matches = new Array(s2.length);
|
|
79
|
+
for (i = 0; i < s1.length; i++) {
|
|
80
|
+
var low = i >= range ? i - range : 0;
|
|
81
|
+
var high = i + range <= s2.length - 1 ? i + range : s2.length - 1;
|
|
82
|
+
for (j = low; j <= high; j++) {
|
|
83
|
+
if (s1Matches[i] !== true && s2Matches[j] !== true && s1[i] === s2[j]) {
|
|
84
|
+
++m;
|
|
85
|
+
s1Matches[i] = s2Matches[j] = true;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (m === 0) {
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
var k = 0;
|
|
94
|
+
var numTrans = 0;
|
|
95
|
+
for (i = 0; i < s1.length; i++) {
|
|
96
|
+
if (s1Matches[i] === true) {
|
|
97
|
+
for (j = k; j < s2.length; j++) {
|
|
98
|
+
if (s2Matches[j] === true) {
|
|
99
|
+
k = j + 1;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (s1[i] !== s2[j]) {
|
|
104
|
+
++numTrans;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
var weight = (m / s1.length + m / s2.length + (m - numTrans / 2) / m) / 3;
|
|
109
|
+
var l = 0;
|
|
110
|
+
var p = 0.1;
|
|
111
|
+
if (weight > 0.7) {
|
|
112
|
+
while (s1[l] === s2[l] && l < 4) {
|
|
113
|
+
++l;
|
|
114
|
+
}
|
|
115
|
+
weight = weight + l * p * (1 - weight);
|
|
116
|
+
}
|
|
117
|
+
return weight;
|
|
118
|
+
}
|
|
119
|
+
if (typeof define === "function" && define.amd) {
|
|
120
|
+
define([], function() {
|
|
121
|
+
return distance2;
|
|
122
|
+
});
|
|
123
|
+
} else if (typeof exports === "object") {
|
|
124
|
+
module.exports = distance2;
|
|
125
|
+
} else {
|
|
126
|
+
root.distance = distance2;
|
|
127
|
+
}
|
|
128
|
+
})(exports);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// src/util/openapi/openapi-cache.ts
|
|
133
|
+
import { join } from "path";
|
|
134
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
135
|
+
|
|
136
|
+
// src/util/openapi/constants.ts
|
|
137
|
+
var OPENAPI_URL = "https://openapi.vercel.sh/";
|
|
138
|
+
var CACHE_FILE = "openapi-spec.json";
|
|
139
|
+
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
140
|
+
var FETCH_TIMEOUT_MS = 10 * 1e3;
|
|
141
|
+
|
|
142
|
+
// src/util/openapi/openapi-cache.ts
|
|
143
|
+
var OpenApiCache = class {
|
|
144
|
+
constructor() {
|
|
145
|
+
this.spec = null;
|
|
146
|
+
this.cachePath = join(global_path_default(), CACHE_FILE);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Check if the spec has been loaded
|
|
150
|
+
*/
|
|
151
|
+
get isLoaded() {
|
|
152
|
+
return this.spec !== null;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Load the OpenAPI spec, using cache if available and fresh.
|
|
156
|
+
* Returns true if successful, false otherwise.
|
|
157
|
+
*/
|
|
158
|
+
async load(forceRefresh = false) {
|
|
159
|
+
if (!forceRefresh) {
|
|
160
|
+
const cached = await this.readCache();
|
|
161
|
+
if (cached && !this.isExpired(cached.fetchedAt)) {
|
|
162
|
+
output_manager_default.debug("Using cached OpenAPI spec");
|
|
163
|
+
this.spec = cached.spec;
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
output_manager_default.debug("Fetching OpenAPI spec from " + OPENAPI_URL);
|
|
169
|
+
this.spec = await this.fetchSpec();
|
|
170
|
+
await this.saveCache(this.spec);
|
|
171
|
+
return true;
|
|
172
|
+
} catch (err) {
|
|
173
|
+
output_manager_default.debug(`Failed to fetch OpenAPI spec: ${err}`);
|
|
174
|
+
const stale = await this.readCache();
|
|
175
|
+
if (stale) {
|
|
176
|
+
output_manager_default.debug("Using stale cached OpenAPI spec");
|
|
177
|
+
this.spec = stale.spec;
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Load the OpenAPI spec with spinner UI.
|
|
185
|
+
* Returns true if successful, false otherwise.
|
|
186
|
+
*/
|
|
187
|
+
async loadWithSpinner(forceRefresh = false) {
|
|
188
|
+
output_manager_default.spinner(
|
|
189
|
+
forceRefresh ? "Refreshing API endpoints..." : "Loading API endpoints..."
|
|
190
|
+
);
|
|
191
|
+
const success = await this.load(forceRefresh);
|
|
192
|
+
output_manager_default.stopSpinner();
|
|
193
|
+
return success;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get all available endpoints from the loaded spec, sorted by path then method.
|
|
197
|
+
* Throws if spec hasn't been loaded yet.
|
|
198
|
+
*/
|
|
199
|
+
getEndpoints() {
|
|
200
|
+
this.ensureLoaded();
|
|
201
|
+
const endpoints = this.extractEndpoints();
|
|
202
|
+
return this.sortEndpoints(endpoints);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Extract body fields from a requestBody schema.
|
|
206
|
+
* Throws if spec hasn't been loaded yet.
|
|
207
|
+
*/
|
|
208
|
+
getBodyFields(endpoint) {
|
|
209
|
+
this.ensureLoaded();
|
|
210
|
+
if (!endpoint.requestBody?.content)
|
|
211
|
+
return [];
|
|
212
|
+
const jsonContent = endpoint.requestBody.content["application/json"];
|
|
213
|
+
if (!jsonContent?.schema)
|
|
214
|
+
return [];
|
|
215
|
+
const schema = this.resolveSchemaRef(jsonContent.schema);
|
|
216
|
+
if (!schema?.properties)
|
|
217
|
+
return [];
|
|
218
|
+
const requiredFields = new Set(schema.required || []);
|
|
219
|
+
const fields = [];
|
|
220
|
+
for (const [name, propSchema] of Object.entries(schema.properties)) {
|
|
221
|
+
const resolvedProp = this.resolveSchemaRef(propSchema);
|
|
222
|
+
let enumValues = resolvedProp?.enum || propSchema.enum;
|
|
223
|
+
if (!enumValues && (resolvedProp?.type === "array" || propSchema.type === "array")) {
|
|
224
|
+
const items = resolvedProp?.items || propSchema.items;
|
|
225
|
+
if (items) {
|
|
226
|
+
const resolvedItems = this.resolveSchemaRef(items);
|
|
227
|
+
enumValues = resolvedItems?.enum || items.enum;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
fields.push({
|
|
231
|
+
name,
|
|
232
|
+
required: requiredFields.has(name),
|
|
233
|
+
description: resolvedProp?.description || propSchema.description,
|
|
234
|
+
type: resolvedProp?.type || propSchema.type,
|
|
235
|
+
enumValues
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
fields.sort((a, b) => {
|
|
239
|
+
if (a.required !== b.required) {
|
|
240
|
+
return a.required ? -1 : 1;
|
|
241
|
+
}
|
|
242
|
+
return a.name.localeCompare(b.name);
|
|
243
|
+
});
|
|
244
|
+
return fields;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Extract `x-vercel-cli.displayColumns` from the 200 response schema of an
|
|
248
|
+
* endpoint. Returns `null` when the spec has no display hint.
|
|
249
|
+
*/
|
|
250
|
+
getDisplayColumns(endpoint) {
|
|
251
|
+
this.ensureLoaded();
|
|
252
|
+
const pathItem = this.spec.paths[endpoint.path];
|
|
253
|
+
if (!pathItem)
|
|
254
|
+
return null;
|
|
255
|
+
const operation = pathItem[endpoint.method.toLowerCase()];
|
|
256
|
+
if (!operation?.responses)
|
|
257
|
+
return null;
|
|
258
|
+
const ok = operation.responses["200"] || operation.responses["201"];
|
|
259
|
+
if (!ok)
|
|
260
|
+
return null;
|
|
261
|
+
const jsonContent = ok.content?.["application/json"];
|
|
262
|
+
if (!jsonContent?.schema)
|
|
263
|
+
return null;
|
|
264
|
+
return this.findDisplayColumns(jsonContent.schema);
|
|
265
|
+
}
|
|
266
|
+
findDisplayColumns(schema) {
|
|
267
|
+
const xCli = schema["x-vercel-cli"];
|
|
268
|
+
if (xCli?.displayColumns)
|
|
269
|
+
return xCli.displayColumns;
|
|
270
|
+
for (const key of ["oneOf", "allOf", "anyOf"]) {
|
|
271
|
+
const variants = schema[key];
|
|
272
|
+
if (variants) {
|
|
273
|
+
for (const sub of variants) {
|
|
274
|
+
const found = this.findDisplayColumns(sub);
|
|
275
|
+
if (found)
|
|
276
|
+
return found;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
283
|
+
// Private methods
|
|
284
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
285
|
+
/**
|
|
286
|
+
* Ensure the spec is loaded before accessing it
|
|
287
|
+
*/
|
|
288
|
+
ensureLoaded() {
|
|
289
|
+
if (!this.spec) {
|
|
290
|
+
throw new Error(
|
|
291
|
+
"OpenAPI spec not loaded. Call load() or loadWithSpinner() first."
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Read cached spec from disk
|
|
297
|
+
*/
|
|
298
|
+
async readCache() {
|
|
299
|
+
try {
|
|
300
|
+
const content = await readFile(this.cachePath, "utf-8");
|
|
301
|
+
return JSON.parse(content);
|
|
302
|
+
} catch {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Save spec to disk cache
|
|
308
|
+
*/
|
|
309
|
+
async saveCache(spec) {
|
|
310
|
+
const cached = {
|
|
311
|
+
fetchedAt: Date.now(),
|
|
312
|
+
spec
|
|
313
|
+
};
|
|
314
|
+
const dir = join(this.cachePath, "..");
|
|
315
|
+
await mkdir(dir, { recursive: true });
|
|
316
|
+
await writeFile(this.cachePath, JSON.stringify(cached));
|
|
317
|
+
output_manager_default.debug("Saved OpenAPI spec to cache");
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Fetch OpenAPI spec from remote with timeout
|
|
321
|
+
*/
|
|
322
|
+
async fetchSpec() {
|
|
323
|
+
const controller = new AbortController();
|
|
324
|
+
const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
325
|
+
try {
|
|
326
|
+
const response = await fetch(OPENAPI_URL, { signal: controller.signal });
|
|
327
|
+
if (!response.ok) {
|
|
328
|
+
throw new Error(`Failed to fetch OpenAPI spec: ${response.status}`);
|
|
329
|
+
}
|
|
330
|
+
return await response.json();
|
|
331
|
+
} finally {
|
|
332
|
+
clearTimeout(timeoutId);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Check if cached spec is expired
|
|
337
|
+
*/
|
|
338
|
+
isExpired(fetchedAt) {
|
|
339
|
+
return Date.now() - fetchedAt > CACHE_TTL_MS;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Sort endpoints by path, then by method
|
|
343
|
+
*/
|
|
344
|
+
sortEndpoints(endpoints) {
|
|
345
|
+
return endpoints.sort((a, b) => {
|
|
346
|
+
const pathCompare = a.path.localeCompare(b.path);
|
|
347
|
+
if (pathCompare !== 0)
|
|
348
|
+
return pathCompare;
|
|
349
|
+
return a.method.localeCompare(b.method);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Extract all available endpoints from the spec
|
|
354
|
+
*/
|
|
355
|
+
extractEndpoints() {
|
|
356
|
+
const endpoints = [];
|
|
357
|
+
for (const [path, pathItem] of Object.entries(this.spec.paths)) {
|
|
358
|
+
const methods = ["get", "post", "put", "patch", "delete"];
|
|
359
|
+
for (const method of methods) {
|
|
360
|
+
const operation = pathItem[method];
|
|
361
|
+
if (operation) {
|
|
362
|
+
const pathParams = pathItem.parameters || [];
|
|
363
|
+
const opParams = operation.parameters || [];
|
|
364
|
+
const allParams = [...pathParams, ...opParams];
|
|
365
|
+
endpoints.push({
|
|
366
|
+
path,
|
|
367
|
+
method: method.toUpperCase(),
|
|
368
|
+
summary: operation.summary || pathItem.summary || "",
|
|
369
|
+
description: operation.description || pathItem.description || "",
|
|
370
|
+
operationId: operation.operationId || "",
|
|
371
|
+
tags: operation.tags || [],
|
|
372
|
+
parameters: allParams,
|
|
373
|
+
requestBody: operation.requestBody
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return endpoints;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Resolve a $ref to its actual schema
|
|
382
|
+
*/
|
|
383
|
+
resolveSchemaRef(schema) {
|
|
384
|
+
if (!schema)
|
|
385
|
+
return void 0;
|
|
386
|
+
if (schema.$ref) {
|
|
387
|
+
const match = schema.$ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
388
|
+
if (match && this.spec.components?.schemas) {
|
|
389
|
+
const resolved = this.spec.components.schemas[match[1]];
|
|
390
|
+
return this.resolveSchemaRef(resolved);
|
|
391
|
+
}
|
|
392
|
+
return void 0;
|
|
393
|
+
}
|
|
394
|
+
if (schema.allOf && schema.allOf.length > 0) {
|
|
395
|
+
const merged = { type: "object", properties: {}, required: [] };
|
|
396
|
+
for (const subSchema of schema.allOf) {
|
|
397
|
+
const resolved = this.resolveSchemaRef(subSchema);
|
|
398
|
+
if (resolved) {
|
|
399
|
+
if (resolved.properties) {
|
|
400
|
+
merged.properties = {
|
|
401
|
+
...merged.properties,
|
|
402
|
+
...resolved.properties
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
if (resolved.required) {
|
|
406
|
+
merged.required = [
|
|
407
|
+
...merged.required || [],
|
|
408
|
+
...resolved.required
|
|
409
|
+
];
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return merged;
|
|
414
|
+
}
|
|
415
|
+
return schema;
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
// src/util/openapi/matches-cli-api-tag.ts
|
|
420
|
+
async function matchesCliApiTag(tagHint) {
|
|
421
|
+
if (!tagHint || tagHint.startsWith("-") || tagHint.includes("/")) {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
const cache = new OpenApiCache();
|
|
425
|
+
const loaded = await cache.load();
|
|
426
|
+
if (!loaded) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
const endpoints = cache.getEndpoints();
|
|
430
|
+
const lower = tagHint.toLowerCase();
|
|
431
|
+
return endpoints.some((ep) => ep.tags.some((t) => t.toLowerCase() === lower));
|
|
432
|
+
}
|
|
433
|
+
async function resolveOpenApiTagForProjectsCli() {
|
|
434
|
+
if (await matchesCliApiTag("projects")) {
|
|
435
|
+
return "projects";
|
|
436
|
+
}
|
|
437
|
+
if (await matchesCliApiTag("project")) {
|
|
438
|
+
return "project";
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
async function resolveOpenApiTagForTeamsCli() {
|
|
443
|
+
if (await matchesCliApiTag("teams")) {
|
|
444
|
+
return "teams";
|
|
445
|
+
}
|
|
446
|
+
if (await matchesCliApiTag("team")) {
|
|
447
|
+
return "team";
|
|
448
|
+
}
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// src/commands/api/index.ts
|
|
453
|
+
var import_chalk3 = __toESM(require_source(), 1);
|
|
454
|
+
|
|
455
|
+
// src/util/telemetry/commands/api/index.ts
|
|
456
|
+
var ApiTelemetryClient = class extends TelemetryClient {
|
|
457
|
+
trackCliArgumentEndpoint(endpoint) {
|
|
458
|
+
if (endpoint) {
|
|
459
|
+
const normalized = this.normalizeEndpoint(endpoint);
|
|
460
|
+
this.trackCliArgument({
|
|
461
|
+
arg: "endpoint",
|
|
462
|
+
value: normalized
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
trackCliArgumentOperationId(operationId) {
|
|
467
|
+
if (operationId) {
|
|
468
|
+
this.trackCliArgument({
|
|
469
|
+
arg: "operationId",
|
|
470
|
+
value: operationId
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
trackCliOptionMethod(method) {
|
|
475
|
+
if (method) {
|
|
476
|
+
const validMethods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD"];
|
|
477
|
+
const upperMethod = method.toUpperCase();
|
|
478
|
+
const value = validMethods.includes(upperMethod) ? upperMethod : this.redactedValue;
|
|
479
|
+
this.trackCliOption({
|
|
480
|
+
option: "method",
|
|
481
|
+
value
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
trackCliOptionField(fields) {
|
|
486
|
+
if (fields && fields.length > 0) {
|
|
487
|
+
this.trackCliOption({
|
|
488
|
+
option: "field",
|
|
489
|
+
value: this.redactedArgumentsLength(fields)
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
trackCliOptionRawField(fields) {
|
|
494
|
+
if (fields && fields.length > 0) {
|
|
495
|
+
this.trackCliOption({
|
|
496
|
+
option: "raw-field",
|
|
497
|
+
value: this.redactedArgumentsLength(fields)
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
trackCliOptionHeader(headers) {
|
|
502
|
+
if (headers && headers.length > 0) {
|
|
503
|
+
this.trackCliOption({
|
|
504
|
+
option: "header",
|
|
505
|
+
value: this.redactedArgumentsLength(headers)
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
trackCliOptionInput(input) {
|
|
510
|
+
if (input) {
|
|
511
|
+
const value = input === "-" ? "stdin" : "file";
|
|
512
|
+
this.trackCliOption({
|
|
513
|
+
option: "input",
|
|
514
|
+
value
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
trackCliFlagPaginate(value) {
|
|
519
|
+
if (value) {
|
|
520
|
+
this.trackCliFlag("paginate");
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
trackCliFlagInclude(value) {
|
|
524
|
+
if (value) {
|
|
525
|
+
this.trackCliFlag("include");
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
trackCliFlagSilent(value) {
|
|
529
|
+
if (value) {
|
|
530
|
+
this.trackCliFlag("silent");
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
trackCliFlagVerbose(value) {
|
|
534
|
+
if (value) {
|
|
535
|
+
this.trackCliFlag("verbose");
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
trackCliFlagRaw(value) {
|
|
539
|
+
if (value) {
|
|
540
|
+
this.trackCliFlag("raw");
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
trackCliFlagRefresh(value) {
|
|
544
|
+
if (value) {
|
|
545
|
+
this.trackCliFlag("refresh");
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
trackCliOptionGenerate(format) {
|
|
549
|
+
if (format) {
|
|
550
|
+
const validFormats = ["curl"];
|
|
551
|
+
const value = validFormats.includes(format) ? format : this.redactedValue;
|
|
552
|
+
this.trackCliOption({
|
|
553
|
+
option: "generate",
|
|
554
|
+
value
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
trackCliFlagDangerouslySkipPermissions(value) {
|
|
559
|
+
if (value) {
|
|
560
|
+
this.trackCliFlag("dangerously-skip-permissions");
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
trackCliSubcommandList() {
|
|
564
|
+
this.trackCliSubcommand({ subcommand: "list", value: "list" });
|
|
565
|
+
}
|
|
566
|
+
trackCliOptionFormat(format) {
|
|
567
|
+
if (format) {
|
|
568
|
+
const validFormats = ["table", "json"];
|
|
569
|
+
const value = validFormats.includes(format) ? format : this.redactedValue;
|
|
570
|
+
this.trackCliOption({
|
|
571
|
+
option: "format",
|
|
572
|
+
value
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Normalize endpoint by replacing IDs with placeholders for privacy
|
|
578
|
+
*/
|
|
579
|
+
normalizeEndpoint(endpoint) {
|
|
580
|
+
return endpoint.replace(/\/dpl_[a-zA-Z0-9]+/g, "/:deploymentId").replace(/\/prj_[a-zA-Z0-9]+/g, "/:projectId").replace(/\/team_[a-zA-Z0-9]+/g, "/:teamId").replace(/\/[a-f0-9]{24}/g, "/:id").replace(/\/[a-f0-9-]{36}/g, "/:uuid");
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
// src/commands/api/request-builder.ts
|
|
585
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
586
|
+
import { resolve } from "path";
|
|
587
|
+
async function buildRequest(endpoint, flags) {
|
|
588
|
+
const headers = {};
|
|
589
|
+
let body;
|
|
590
|
+
const customHeaders = flags["--header"] || [];
|
|
591
|
+
for (const header of customHeaders) {
|
|
592
|
+
const colonIndex = header.indexOf(":");
|
|
593
|
+
if (colonIndex > 0) {
|
|
594
|
+
const key = header.substring(0, colonIndex).trim();
|
|
595
|
+
const value = header.substring(colonIndex + 1).trim();
|
|
596
|
+
headers[key] = value;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
const fields = flags["--field"] || [];
|
|
600
|
+
const rawFields = flags["--raw-field"] || [];
|
|
601
|
+
if (fields.length > 0 || rawFields.length > 0) {
|
|
602
|
+
body = {};
|
|
603
|
+
for (const field of fields) {
|
|
604
|
+
const { key, value } = await parseField(field, true);
|
|
605
|
+
body[key] = value;
|
|
606
|
+
}
|
|
607
|
+
for (const field of rawFields) {
|
|
608
|
+
const { key, value } = await parseField(field, false);
|
|
609
|
+
body[key] = value;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
if (flags["--input"]) {
|
|
613
|
+
const inputPath = flags["--input"];
|
|
614
|
+
if (inputPath === "-") {
|
|
615
|
+
body = await readStdin();
|
|
616
|
+
} else {
|
|
617
|
+
body = await readFile2(resolve(inputPath), "utf-8");
|
|
618
|
+
}
|
|
619
|
+
if (typeof body === "string") {
|
|
620
|
+
try {
|
|
621
|
+
body = JSON.parse(body);
|
|
622
|
+
} catch {
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
let method = flags["--method"]?.toUpperCase() || "GET";
|
|
627
|
+
if (!flags["--method"] && body) {
|
|
628
|
+
method = "POST";
|
|
629
|
+
}
|
|
630
|
+
return {
|
|
631
|
+
url: endpoint,
|
|
632
|
+
method,
|
|
633
|
+
headers,
|
|
634
|
+
body
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
async function parseCliKeyValueField(field, typed) {
|
|
638
|
+
return parseField(field, typed);
|
|
639
|
+
}
|
|
640
|
+
async function parseField(field, typed) {
|
|
641
|
+
const eqIndex = field.indexOf("=");
|
|
642
|
+
if (eqIndex === -1) {
|
|
643
|
+
throw new Error(`Invalid field format: ${field}. Expected key=value`);
|
|
644
|
+
}
|
|
645
|
+
const key = field.substring(0, eqIndex);
|
|
646
|
+
let value = field.substring(eqIndex + 1);
|
|
647
|
+
if (typed && typeof value === "string") {
|
|
648
|
+
if (value.startsWith("@")) {
|
|
649
|
+
const filePath = value.substring(1);
|
|
650
|
+
if (filePath === "-") {
|
|
651
|
+
value = await readStdin();
|
|
652
|
+
} else {
|
|
653
|
+
value = await readFile2(resolve(filePath), "utf-8");
|
|
654
|
+
}
|
|
655
|
+
if (typeof value === "string") {
|
|
656
|
+
try {
|
|
657
|
+
value = JSON.parse(value);
|
|
658
|
+
} catch {
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
} else if (value === "true") {
|
|
662
|
+
value = true;
|
|
663
|
+
} else if (value === "false") {
|
|
664
|
+
value = false;
|
|
665
|
+
} else if (value === "null") {
|
|
666
|
+
value = null;
|
|
667
|
+
} else if (/^-?\d+$/.test(value)) {
|
|
668
|
+
value = parseInt(value, 10);
|
|
669
|
+
} else if (/^-?\d*\.\d+$/.test(value)) {
|
|
670
|
+
value = parseFloat(value);
|
|
671
|
+
} else if (value.startsWith("[") || value.startsWith("{")) {
|
|
672
|
+
try {
|
|
673
|
+
value = JSON.parse(value);
|
|
674
|
+
} catch {
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return { key, value };
|
|
679
|
+
}
|
|
680
|
+
async function readStdin() {
|
|
681
|
+
const chunks = [];
|
|
682
|
+
for await (const chunk of process.stdin) {
|
|
683
|
+
chunks.push(Buffer.from(chunk));
|
|
684
|
+
}
|
|
685
|
+
return Buffer.concat(chunks).toString(
|
|
686
|
+
"utf-8"
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
function formatOutput(data, options) {
|
|
690
|
+
if (options.raw) {
|
|
691
|
+
if (typeof data === "string") {
|
|
692
|
+
return data;
|
|
693
|
+
}
|
|
694
|
+
return JSON.stringify(data);
|
|
695
|
+
}
|
|
696
|
+
return JSON.stringify(data, null, 2);
|
|
697
|
+
}
|
|
698
|
+
function generateCurlCommand(config, baseUrl) {
|
|
699
|
+
const parts = ["curl"];
|
|
700
|
+
if (config.method !== "GET") {
|
|
701
|
+
parts.push(`-X ${config.method}`);
|
|
702
|
+
}
|
|
703
|
+
parts.push(`-H 'Authorization: Bearer <TOKEN>'`);
|
|
704
|
+
for (const [key, value] of Object.entries(config.headers)) {
|
|
705
|
+
parts.push(`-H '${key}: ${escapeShellArg(value)}'`);
|
|
706
|
+
}
|
|
707
|
+
if (config.body) {
|
|
708
|
+
const bodyStr = typeof config.body === "string" ? config.body : JSON.stringify(config.body);
|
|
709
|
+
parts.push(`-H 'Content-Type: application/json'`);
|
|
710
|
+
parts.push(`-d '${escapeShellArg(bodyStr)}'`);
|
|
711
|
+
}
|
|
712
|
+
const fullUrl = `${baseUrl}${config.url}`;
|
|
713
|
+
parts.push(`'${fullUrl}'`);
|
|
714
|
+
return parts.join(" \\\n ");
|
|
715
|
+
}
|
|
716
|
+
function escapeShellArg(str) {
|
|
717
|
+
return str.replace(/'/g, "'\\''");
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// src/commands/api/operation-request-builder.ts
|
|
721
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
722
|
+
import { resolve as resolve2 } from "path";
|
|
723
|
+
var GLOBAL_CLI_QUERY_PARAMS = /* @__PURE__ */ new Set(["teamId", "slug"]);
|
|
724
|
+
async function parseOperationKeyValuePairs(endpoint, bodyFields, flags, positionalKeyValues) {
|
|
725
|
+
const pathParamNames = new Set(
|
|
726
|
+
endpoint.parameters.filter((p) => p.in === "path").map((p) => p.name)
|
|
727
|
+
);
|
|
728
|
+
const queryParamNames = new Set(
|
|
729
|
+
endpoint.parameters.filter((p) => p.in === "query").map((p) => p.name)
|
|
730
|
+
);
|
|
731
|
+
const headerParamNames = new Set(
|
|
732
|
+
endpoint.parameters.filter((p) => p.in === "header").map((p) => p.name)
|
|
733
|
+
);
|
|
734
|
+
const bodyFieldNames = new Set(bodyFields.map((f) => f.name));
|
|
735
|
+
const pathValues = {};
|
|
736
|
+
const queryValues = {};
|
|
737
|
+
const headerValues = {};
|
|
738
|
+
const body = {};
|
|
739
|
+
async function dispatchPair(field, typed) {
|
|
740
|
+
const eqIndex = field.indexOf("=");
|
|
741
|
+
if (eqIndex === -1) {
|
|
742
|
+
throw new Error(
|
|
743
|
+
`Invalid option "${field}". Expected key=value (or use flags -F / -f).`
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
const key = field.slice(0, eqIndex);
|
|
747
|
+
const param = endpoint.parameters.find((p) => p.name === key);
|
|
748
|
+
if (param?.in === "path") {
|
|
749
|
+
const { value } = await parseCliKeyValueField(field, false);
|
|
750
|
+
pathValues[key] = String(value);
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
if (param?.in === "query") {
|
|
754
|
+
const { value } = await parseCliKeyValueField(field, typed);
|
|
755
|
+
queryValues[key] = typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
if (param?.in === "header") {
|
|
759
|
+
const { value } = await parseCliKeyValueField(field, false);
|
|
760
|
+
headerValues[key] = String(value);
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
if (param?.in === "cookie") {
|
|
764
|
+
throw new Error(
|
|
765
|
+
`Option "${key}" is cookie-based; set it via headers instead.`
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
if (bodyFieldNames.has(key)) {
|
|
769
|
+
const { value } = await parseCliKeyValueField(field, typed);
|
|
770
|
+
body[key] = value;
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
if (!param && pathParamNames.has(key)) {
|
|
774
|
+
const { value } = await parseCliKeyValueField(field, false);
|
|
775
|
+
pathValues[key] = String(value);
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
if (!param && queryParamNames.has(key)) {
|
|
779
|
+
const { value } = await parseCliKeyValueField(field, typed);
|
|
780
|
+
queryValues[key] = typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
if (!param && headerParamNames.has(key)) {
|
|
784
|
+
const { value } = await parseCliKeyValueField(field, false);
|
|
785
|
+
headerValues[key] = String(value);
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
throw new Error(
|
|
789
|
+
`Unknown option "${key}" for operation ${endpoint.operationId}. Check the API docs or run \`vercel api ls --format json\`.`
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
for (const field of flags["--field"] || []) {
|
|
793
|
+
await dispatchPair(field, true);
|
|
794
|
+
}
|
|
795
|
+
for (const field of flags["--raw-field"] || []) {
|
|
796
|
+
await dispatchPair(field, false);
|
|
797
|
+
}
|
|
798
|
+
for (const field of positionalKeyValues) {
|
|
799
|
+
await dispatchPair(field, true);
|
|
800
|
+
}
|
|
801
|
+
return { pathValues, queryValues, headerValues, body };
|
|
802
|
+
}
|
|
803
|
+
function getMissingRequiredOperationParams(endpoint, bodyFields, parsed, flags) {
|
|
804
|
+
const pathParams = endpoint.parameters.filter((p) => p.in === "path");
|
|
805
|
+
const missingPath = pathParams.filter(
|
|
806
|
+
(p) => parsed.pathValues[p.name] === void 0
|
|
807
|
+
);
|
|
808
|
+
const requiredQuery = endpoint.parameters.filter(
|
|
809
|
+
(p) => p.in === "query" && p.required && !GLOBAL_CLI_QUERY_PARAMS.has(p.name)
|
|
810
|
+
);
|
|
811
|
+
const missingQuery = requiredQuery.filter(
|
|
812
|
+
(p) => parsed.queryValues[p.name] === void 0
|
|
813
|
+
);
|
|
814
|
+
const requiredHeader = endpoint.parameters.filter(
|
|
815
|
+
(p) => p.in === "header" && p.required
|
|
816
|
+
);
|
|
817
|
+
const missingHeader = requiredHeader.filter(
|
|
818
|
+
(p) => parsed.headerValues[p.name] === void 0
|
|
819
|
+
);
|
|
820
|
+
const missingBody = bodyFields.filter(
|
|
821
|
+
(f) => f.required && parsed.body[f.name] === void 0 && !flags["--input"]
|
|
822
|
+
);
|
|
823
|
+
return {
|
|
824
|
+
path: missingPath,
|
|
825
|
+
query: missingQuery,
|
|
826
|
+
header: missingHeader,
|
|
827
|
+
body: missingBody
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
function getUnsetOptionalOperationParams(endpoint, bodyFields, parsed, flags) {
|
|
831
|
+
const unsetQuery = endpoint.parameters.filter(
|
|
832
|
+
(p) => p.in === "query" && parsed.queryValues[p.name] === void 0 && (!p.required || GLOBAL_CLI_QUERY_PARAMS.has(p.name))
|
|
833
|
+
);
|
|
834
|
+
const unsetHeader = endpoint.parameters.filter(
|
|
835
|
+
(p) => p.in === "header" && !p.required && parsed.headerValues[p.name] === void 0
|
|
836
|
+
);
|
|
837
|
+
const unsetBody = bodyFields.filter(
|
|
838
|
+
(f) => !f.required && parsed.body[f.name] === void 0 && !flags["--input"]
|
|
839
|
+
);
|
|
840
|
+
return {
|
|
841
|
+
query: unsetQuery,
|
|
842
|
+
header: unsetHeader,
|
|
843
|
+
body: unsetBody
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
async function buildRequestForResolvedOperation(endpoint, bodyFields, flags, positionalKeyValues) {
|
|
847
|
+
const headers = {};
|
|
848
|
+
const customHeaders = flags["--header"] || [];
|
|
849
|
+
for (const header of customHeaders) {
|
|
850
|
+
const colonIndex = header.indexOf(":");
|
|
851
|
+
if (colonIndex > 0) {
|
|
852
|
+
const key = header.substring(0, colonIndex).trim();
|
|
853
|
+
const value = header.substring(colonIndex + 1).trim();
|
|
854
|
+
headers[key] = value;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
const method = (flags["--method"]?.toUpperCase() || endpoint.method).toUpperCase();
|
|
858
|
+
const pathParamNames = new Set(
|
|
859
|
+
endpoint.parameters.filter((p) => p.in === "path").map((p) => p.name)
|
|
860
|
+
);
|
|
861
|
+
const parsed = await parseOperationKeyValuePairs(
|
|
862
|
+
endpoint,
|
|
863
|
+
bodyFields,
|
|
864
|
+
flags,
|
|
865
|
+
positionalKeyValues
|
|
866
|
+
);
|
|
867
|
+
const { pathValues, queryValues, headerValues, body } = parsed;
|
|
868
|
+
for (const [k, v] of Object.entries(headerValues)) {
|
|
869
|
+
headers[k] = v;
|
|
870
|
+
}
|
|
871
|
+
let urlPath = endpoint.path;
|
|
872
|
+
for (const name of pathParamNames) {
|
|
873
|
+
const value = pathValues[name];
|
|
874
|
+
if (value === void 0) {
|
|
875
|
+
throw new Error(
|
|
876
|
+
`Missing required path option {${name}} for ${endpoint.operationId}.`
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
urlPath = urlPath.replace(`{${name}}`, encodeURIComponent(value));
|
|
880
|
+
}
|
|
881
|
+
if (/\{[^}]+\}/.test(urlPath)) {
|
|
882
|
+
throw new Error(
|
|
883
|
+
`Unresolved path placeholders in ${urlPath}. Provide values for all path options.`
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
const requiredQuery = endpoint.parameters.filter(
|
|
887
|
+
(p) => p.in === "query" && p.required && !GLOBAL_CLI_QUERY_PARAMS.has(p.name)
|
|
888
|
+
);
|
|
889
|
+
for (const p of requiredQuery) {
|
|
890
|
+
if (queryValues[p.name] === void 0) {
|
|
891
|
+
throw new Error(
|
|
892
|
+
`Missing required query option "${p.name}" for ${endpoint.operationId}.`
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
const requiredHeader = endpoint.parameters.filter(
|
|
897
|
+
(h) => h.in === "header" && h.required
|
|
898
|
+
);
|
|
899
|
+
for (const h of requiredHeader) {
|
|
900
|
+
if (headerValues[h.name] === void 0) {
|
|
901
|
+
throw new Error(
|
|
902
|
+
`Missing required header option "${h.name}" for ${endpoint.operationId}.`
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
const requiredBody = bodyFields.filter((f) => f.required);
|
|
907
|
+
for (const f of requiredBody) {
|
|
908
|
+
if (body[f.name] === void 0 && !flags["--input"]) {
|
|
909
|
+
throw new Error(
|
|
910
|
+
`Missing required body option "${f.name}" for ${endpoint.operationId}.`
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
const queryString = new URLSearchParams(queryValues).toString();
|
|
915
|
+
if (queryString) {
|
|
916
|
+
urlPath += (urlPath.includes("?") ? "&" : "?") + queryString;
|
|
917
|
+
}
|
|
918
|
+
let finalBody = Object.keys(body).length > 0 ? body : void 0;
|
|
919
|
+
if (flags["--input"]) {
|
|
920
|
+
const inputPath = flags["--input"];
|
|
921
|
+
let inputBody;
|
|
922
|
+
if (inputPath === "-") {
|
|
923
|
+
inputBody = await readStdin();
|
|
924
|
+
} else {
|
|
925
|
+
inputBody = await readFile3(resolve2(inputPath), "utf-8");
|
|
926
|
+
}
|
|
927
|
+
if (typeof inputBody === "string") {
|
|
928
|
+
try {
|
|
929
|
+
finalBody = JSON.parse(inputBody);
|
|
930
|
+
} catch {
|
|
931
|
+
finalBody = inputBody;
|
|
932
|
+
}
|
|
933
|
+
} else {
|
|
934
|
+
finalBody = inputBody;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
if (method === "GET" || method === "HEAD") {
|
|
938
|
+
finalBody = void 0;
|
|
939
|
+
}
|
|
940
|
+
return {
|
|
941
|
+
url: urlPath,
|
|
942
|
+
method,
|
|
943
|
+
headers,
|
|
944
|
+
body: finalBody
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// src/util/openapi/resolve-by-tag-operation.ts
|
|
949
|
+
function resolveEndpointByTagAndOperationId(endpoints, tag, operationHint) {
|
|
950
|
+
const tagLower = tag.toLowerCase();
|
|
951
|
+
const tagMatches = endpoints.filter(
|
|
952
|
+
(ep) => ep.tags.some((t) => t.toLowerCase() === tagLower)
|
|
953
|
+
);
|
|
954
|
+
if (tagMatches.length === 0) {
|
|
955
|
+
return {
|
|
956
|
+
ok: false,
|
|
957
|
+
reason: "no_tag",
|
|
958
|
+
tag,
|
|
959
|
+
tagMatches: [],
|
|
960
|
+
operationHint
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
const withOpId = tagMatches.filter((ep) => ep.operationId.length > 0);
|
|
964
|
+
if (withOpId.length === 0) {
|
|
965
|
+
return {
|
|
966
|
+
ok: false,
|
|
967
|
+
reason: "no_operation",
|
|
968
|
+
tag,
|
|
969
|
+
tagMatches,
|
|
970
|
+
operationHint
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
const hint = operationHint.trim();
|
|
974
|
+
const hintLower = hint.toLowerCase();
|
|
975
|
+
const exact = withOpId.filter((ep) => ep.operationId === hint);
|
|
976
|
+
if (exact.length === 1) {
|
|
977
|
+
return { ok: true, endpoint: exact[0] };
|
|
978
|
+
}
|
|
979
|
+
if (exact.length > 1) {
|
|
980
|
+
return {
|
|
981
|
+
ok: false,
|
|
982
|
+
reason: "ambiguous_operation",
|
|
983
|
+
tag,
|
|
984
|
+
tagMatches: exact,
|
|
985
|
+
operationHint: hint
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
const exactCi = withOpId.filter(
|
|
989
|
+
(ep) => ep.operationId.toLowerCase() === hintLower
|
|
990
|
+
);
|
|
991
|
+
if (exactCi.length === 1) {
|
|
992
|
+
return { ok: true, endpoint: exactCi[0] };
|
|
993
|
+
}
|
|
994
|
+
if (exactCi.length > 1) {
|
|
995
|
+
return {
|
|
996
|
+
ok: false,
|
|
997
|
+
reason: "ambiguous_operation",
|
|
998
|
+
tag,
|
|
999
|
+
tagMatches: exactCi,
|
|
1000
|
+
operationHint: hint
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
return {
|
|
1004
|
+
ok: false,
|
|
1005
|
+
reason: "no_operation",
|
|
1006
|
+
tag,
|
|
1007
|
+
tagMatches,
|
|
1008
|
+
operationHint: hint
|
|
1009
|
+
};
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// src/util/openapi/try-openapi-fallback.ts
|
|
1013
|
+
async function tryOpenApiFallback(client, cliArgs, resolveTag) {
|
|
1014
|
+
if (!process.env.VERCEL_AUTO_API) {
|
|
1015
|
+
return null;
|
|
1016
|
+
}
|
|
1017
|
+
const operationHint = cliArgs[0];
|
|
1018
|
+
if (!operationHint || operationHint.startsWith("-")) {
|
|
1019
|
+
return null;
|
|
1020
|
+
}
|
|
1021
|
+
const tag = await resolveTag();
|
|
1022
|
+
if (!tag) {
|
|
1023
|
+
return null;
|
|
1024
|
+
}
|
|
1025
|
+
const apiFlagsSpec = getFlagsSpecification(apiCommand.options);
|
|
1026
|
+
let apiParsed;
|
|
1027
|
+
try {
|
|
1028
|
+
apiParsed = parseArguments(client.argv.slice(2), apiFlagsSpec, {
|
|
1029
|
+
permissive: true
|
|
1030
|
+
});
|
|
1031
|
+
} catch {
|
|
1032
|
+
return null;
|
|
1033
|
+
}
|
|
1034
|
+
const flags = apiParsed.flags;
|
|
1035
|
+
if (flags["--dangerously-skip-permissions"]) {
|
|
1036
|
+
client.dangerouslySkipPermissions = true;
|
|
1037
|
+
}
|
|
1038
|
+
if (flags["--help"]) {
|
|
1039
|
+
return printOperationHelpForTagCommand(flags, tag, operationHint);
|
|
1040
|
+
}
|
|
1041
|
+
return runTagOperation(client, {
|
|
1042
|
+
tag,
|
|
1043
|
+
operationId: operationHint,
|
|
1044
|
+
flags,
|
|
1045
|
+
positionalOperationFields: cliArgs.slice(1)
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// src/commands/api/constants.ts
|
|
1050
|
+
var API_BASE_URL = "https://api.vercel.com";
|
|
1051
|
+
|
|
1052
|
+
// src/commands/api/format-utils.ts
|
|
1053
|
+
var import_chalk = __toESM(require_source(), 1);
|
|
1054
|
+
function colorizeMethod(method) {
|
|
1055
|
+
switch (method) {
|
|
1056
|
+
case "GET":
|
|
1057
|
+
return import_chalk.default.cyan(method);
|
|
1058
|
+
case "POST":
|
|
1059
|
+
return import_chalk.default.green(method);
|
|
1060
|
+
case "PUT":
|
|
1061
|
+
return import_chalk.default.yellow(method);
|
|
1062
|
+
case "PATCH":
|
|
1063
|
+
return import_chalk.default.blue(method);
|
|
1064
|
+
case "DELETE":
|
|
1065
|
+
return import_chalk.default.red(method);
|
|
1066
|
+
default:
|
|
1067
|
+
return method;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
function colorizeMethodPadded(method, width = 7) {
|
|
1071
|
+
const colored = colorizeMethod(method);
|
|
1072
|
+
const padding = " ".repeat(Math.max(0, width - method.length));
|
|
1073
|
+
return colored + padding;
|
|
1074
|
+
}
|
|
1075
|
+
function formatPathParam(paramName) {
|
|
1076
|
+
return import_chalk.default.cyan(`{${paramName}}`);
|
|
1077
|
+
}
|
|
1078
|
+
function formatTypeHint(type) {
|
|
1079
|
+
return import_chalk.default.dim(`[${type}]`);
|
|
1080
|
+
}
|
|
1081
|
+
function formatDescription(description) {
|
|
1082
|
+
if (!description)
|
|
1083
|
+
return "";
|
|
1084
|
+
return import_chalk.default.gray(` (${description})`);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// src/commands/api/display-columns.ts
|
|
1088
|
+
var import_chalk2 = __toESM(require_source(), 1);
|
|
1089
|
+
function getByPath(obj, path) {
|
|
1090
|
+
let current = obj;
|
|
1091
|
+
for (const segment of path.split(".")) {
|
|
1092
|
+
if (current == null || typeof current !== "object")
|
|
1093
|
+
return void 0;
|
|
1094
|
+
current = current[segment];
|
|
1095
|
+
}
|
|
1096
|
+
return current;
|
|
1097
|
+
}
|
|
1098
|
+
function parseArrayColumns(data, columns) {
|
|
1099
|
+
const entries = Object.entries(columns);
|
|
1100
|
+
const first = entries[0];
|
|
1101
|
+
if (!first)
|
|
1102
|
+
return null;
|
|
1103
|
+
const bracketIdx = first[1].indexOf("[].");
|
|
1104
|
+
if (bracketIdx === -1)
|
|
1105
|
+
return null;
|
|
1106
|
+
const arrayKey = first[1].slice(0, bracketIdx);
|
|
1107
|
+
const rowColumns = {};
|
|
1108
|
+
for (const [label, path] of entries) {
|
|
1109
|
+
const prefix = path.slice(0, bracketIdx);
|
|
1110
|
+
if (prefix !== arrayKey || !path.startsWith(prefix + "[].")) {
|
|
1111
|
+
return null;
|
|
1112
|
+
}
|
|
1113
|
+
rowColumns[label] = path.slice(bracketIdx + 3);
|
|
1114
|
+
}
|
|
1115
|
+
const arr = getByPath(data, arrayKey);
|
|
1116
|
+
if (!Array.isArray(arr))
|
|
1117
|
+
return null;
|
|
1118
|
+
return { rows: arr, rowColumns };
|
|
1119
|
+
}
|
|
1120
|
+
function formatValue(value) {
|
|
1121
|
+
if (value === null || value === void 0)
|
|
1122
|
+
return import_chalk2.default.dim("\u2013");
|
|
1123
|
+
if (typeof value === "number") {
|
|
1124
|
+
if (value > 1e12 && value < 2e12) {
|
|
1125
|
+
return new Date(value).toISOString();
|
|
1126
|
+
}
|
|
1127
|
+
return String(value);
|
|
1128
|
+
}
|
|
1129
|
+
if (typeof value === "boolean")
|
|
1130
|
+
return String(value);
|
|
1131
|
+
if (typeof value === "string")
|
|
1132
|
+
return value;
|
|
1133
|
+
return JSON.stringify(value);
|
|
1134
|
+
}
|
|
1135
|
+
function renderCard(data, columns) {
|
|
1136
|
+
const entries = Object.entries(columns);
|
|
1137
|
+
const maxLabel = Math.max(...entries.map(([label]) => label.length));
|
|
1138
|
+
const lines = entries.map(([label, path]) => {
|
|
1139
|
+
const value = getByPath(data, path);
|
|
1140
|
+
return ` ${import_chalk2.default.gray(label.padEnd(maxLabel))} ${formatValue(value)}`;
|
|
1141
|
+
});
|
|
1142
|
+
return lines.join("\n");
|
|
1143
|
+
}
|
|
1144
|
+
function renderTable(rows, columns) {
|
|
1145
|
+
const entries = Object.entries(columns);
|
|
1146
|
+
const headerRow = entries.map(([label]) => label);
|
|
1147
|
+
const dataRows = rows.map(
|
|
1148
|
+
(row) => entries.map(([, path]) => formatValue(getByPath(row, path)))
|
|
1149
|
+
);
|
|
1150
|
+
const widths = entries.map(([label], colIdx) => {
|
|
1151
|
+
const dataMax = dataRows.reduce(
|
|
1152
|
+
(max, row) => Math.max(max, stripAnsi(row[colIdx]).length),
|
|
1153
|
+
0
|
|
1154
|
+
);
|
|
1155
|
+
return Math.max(label.length, dataMax);
|
|
1156
|
+
});
|
|
1157
|
+
const header = headerRow.map((h, i) => import_chalk2.default.bold(h.padEnd(widths[i]))).join(" ");
|
|
1158
|
+
const body = dataRows.map(
|
|
1159
|
+
(row) => row.map((cell, i) => {
|
|
1160
|
+
const pad = widths[i] - stripAnsi(cell).length;
|
|
1161
|
+
return cell + " ".repeat(Math.max(0, pad));
|
|
1162
|
+
}).join(" ")
|
|
1163
|
+
);
|
|
1164
|
+
return [header, ...body].join("\n");
|
|
1165
|
+
}
|
|
1166
|
+
function stripAnsi(str) {
|
|
1167
|
+
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// src/commands/api/index.ts
|
|
1171
|
+
async function api(client) {
|
|
1172
|
+
const telemetryClient = new ApiTelemetryClient({
|
|
1173
|
+
opts: { store: client.telemetryEventStore }
|
|
1174
|
+
});
|
|
1175
|
+
let parsedArgs;
|
|
1176
|
+
const flagsSpec = getFlagsSpecification(apiCommand.options);
|
|
1177
|
+
try {
|
|
1178
|
+
parsedArgs = parseArguments(client.argv.slice(2), flagsSpec, {
|
|
1179
|
+
permissive: true
|
|
1180
|
+
});
|
|
1181
|
+
} catch (err) {
|
|
1182
|
+
printError(err);
|
|
1183
|
+
return 1;
|
|
1184
|
+
}
|
|
1185
|
+
const { args, flags } = parsedArgs;
|
|
1186
|
+
const needHelp = flags["--help"];
|
|
1187
|
+
const firstArg = args[1];
|
|
1188
|
+
if (firstArg === "ls" || firstArg === "list") {
|
|
1189
|
+
const lsFlagsSpec = getFlagsSpecification(listSubcommand.options);
|
|
1190
|
+
let lsParsedArgs;
|
|
1191
|
+
try {
|
|
1192
|
+
lsParsedArgs = parseArguments(client.argv.slice(2), lsFlagsSpec);
|
|
1193
|
+
} catch (err) {
|
|
1194
|
+
printError(err);
|
|
1195
|
+
return 1;
|
|
1196
|
+
}
|
|
1197
|
+
const lsFlags = lsParsedArgs.flags;
|
|
1198
|
+
if (lsFlags["--help"]) {
|
|
1199
|
+
telemetryClient.trackCliFlagHelp("api", firstArg);
|
|
1200
|
+
output_manager_default.print(
|
|
1201
|
+
help(listSubcommand, {
|
|
1202
|
+
parent: apiCommand,
|
|
1203
|
+
columns: client.stderr.columns
|
|
1204
|
+
})
|
|
1205
|
+
);
|
|
1206
|
+
return 2;
|
|
1207
|
+
}
|
|
1208
|
+
telemetryClient.trackCliSubcommandList();
|
|
1209
|
+
if (lsFlags["--refresh"])
|
|
1210
|
+
telemetryClient.trackCliFlagRefresh(true);
|
|
1211
|
+
if (lsFlags["--format"])
|
|
1212
|
+
telemetryClient.trackCliOptionFormat(lsFlags["--format"]);
|
|
1213
|
+
return listEndpoints(
|
|
1214
|
+
client,
|
|
1215
|
+
lsFlags["--refresh"] ?? false,
|
|
1216
|
+
lsFlags["--format"] ?? "table"
|
|
1217
|
+
);
|
|
1218
|
+
}
|
|
1219
|
+
if (needHelp) {
|
|
1220
|
+
telemetryClient.trackCliFlagHelp("api");
|
|
1221
|
+
output_manager_default.print(help(apiCommand, { columns: client.stderr.columns }));
|
|
1222
|
+
return 2;
|
|
1223
|
+
}
|
|
1224
|
+
if (flags["--dangerously-skip-permissions"]) {
|
|
1225
|
+
client.dangerouslySkipPermissions = true;
|
|
1226
|
+
}
|
|
1227
|
+
let endpoint;
|
|
1228
|
+
let selectedMethod;
|
|
1229
|
+
let selectedBodyFields = [];
|
|
1230
|
+
if (!firstArg) {
|
|
1231
|
+
if (client.stdin.isTTY) {
|
|
1232
|
+
const selected = await promptEndpointSelection(
|
|
1233
|
+
client,
|
|
1234
|
+
flags["--refresh"] ?? false
|
|
1235
|
+
);
|
|
1236
|
+
if (!selected) {
|
|
1237
|
+
return 1;
|
|
1238
|
+
}
|
|
1239
|
+
endpoint = selected.finalUrl;
|
|
1240
|
+
selectedMethod = selected.method;
|
|
1241
|
+
selectedBodyFields = selected.bodyFields;
|
|
1242
|
+
} else {
|
|
1243
|
+
output_manager_default.error("Endpoint is required. Usage: vercel api <endpoint>");
|
|
1244
|
+
return 1;
|
|
1245
|
+
}
|
|
1246
|
+
} else {
|
|
1247
|
+
endpoint = firstArg;
|
|
1248
|
+
}
|
|
1249
|
+
if (endpoint && !endpoint.startsWith("/")) {
|
|
1250
|
+
output_manager_default.error(
|
|
1251
|
+
`Invalid arguments. Use an API path starting with /, or run \`${packageName} api\` interactively.`
|
|
1252
|
+
);
|
|
1253
|
+
return 1;
|
|
1254
|
+
}
|
|
1255
|
+
try {
|
|
1256
|
+
const resolvedUrl = new URL(endpoint, API_BASE_URL);
|
|
1257
|
+
if (resolvedUrl.origin !== API_BASE_URL) {
|
|
1258
|
+
output_manager_default.error(
|
|
1259
|
+
"Invalid endpoint: must be a Vercel API path, not an external URL"
|
|
1260
|
+
);
|
|
1261
|
+
return 1;
|
|
1262
|
+
}
|
|
1263
|
+
} catch {
|
|
1264
|
+
output_manager_default.error("Invalid endpoint URL format");
|
|
1265
|
+
return 1;
|
|
1266
|
+
}
|
|
1267
|
+
const finalFlags = { ...flags };
|
|
1268
|
+
if (selectedMethod && !flags["--method"]) {
|
|
1269
|
+
finalFlags["--method"] = selectedMethod;
|
|
1270
|
+
}
|
|
1271
|
+
if (selectedBodyFields.length > 0) {
|
|
1272
|
+
const existingFields = finalFlags["--field"] || [];
|
|
1273
|
+
finalFlags["--field"] = [...existingFields, ...selectedBodyFields];
|
|
1274
|
+
}
|
|
1275
|
+
let requestConfig;
|
|
1276
|
+
try {
|
|
1277
|
+
requestConfig = await buildRequest(endpoint, finalFlags);
|
|
1278
|
+
} catch (err) {
|
|
1279
|
+
printError(err);
|
|
1280
|
+
return 1;
|
|
1281
|
+
}
|
|
1282
|
+
telemetryClient.trackCliArgumentEndpoint(requestConfig.url);
|
|
1283
|
+
telemetryClient.trackCliArgumentOperationId(void 0);
|
|
1284
|
+
telemetryClient.trackCliOptionMethod(flags["--method"]);
|
|
1285
|
+
telemetryClient.trackCliOptionHeader(flags["--header"]);
|
|
1286
|
+
telemetryClient.trackCliOptionInput(flags["--input"]);
|
|
1287
|
+
if (flags["--paginate"])
|
|
1288
|
+
telemetryClient.trackCliFlagPaginate(true);
|
|
1289
|
+
if (flags["--include"])
|
|
1290
|
+
telemetryClient.trackCliFlagInclude(true);
|
|
1291
|
+
if (flags["--silent"])
|
|
1292
|
+
telemetryClient.trackCliFlagSilent(true);
|
|
1293
|
+
if (flags["--verbose"])
|
|
1294
|
+
telemetryClient.trackCliFlagVerbose(true);
|
|
1295
|
+
if (flags["--raw"])
|
|
1296
|
+
telemetryClient.trackCliFlagRaw(true);
|
|
1297
|
+
if (flags["--refresh"])
|
|
1298
|
+
telemetryClient.trackCliFlagRefresh(true);
|
|
1299
|
+
if (flags["--generate"])
|
|
1300
|
+
telemetryClient.trackCliOptionGenerate(flags["--generate"]);
|
|
1301
|
+
if (flags["--dangerously-skip-permissions"])
|
|
1302
|
+
telemetryClient.trackCliFlagDangerouslySkipPermissions(true);
|
|
1303
|
+
if (flags["--generate"] === "curl") {
|
|
1304
|
+
const curlCmd = generateCurlCommand(
|
|
1305
|
+
requestConfig,
|
|
1306
|
+
"https://api.vercel.com"
|
|
1307
|
+
);
|
|
1308
|
+
output_manager_default.log("");
|
|
1309
|
+
output_manager_default.log("Replace <TOKEN> with your auth token:");
|
|
1310
|
+
output_manager_default.log("");
|
|
1311
|
+
client.stdout.write(curlCmd + "\n");
|
|
1312
|
+
return 0;
|
|
1313
|
+
}
|
|
1314
|
+
return executeApiRequest(client, requestConfig, finalFlags);
|
|
1315
|
+
}
|
|
1316
|
+
async function printOperationHelpForTagCommand(flags, tag, operationId) {
|
|
1317
|
+
const openApi = new OpenApiCache();
|
|
1318
|
+
const loaded = await openApi.loadWithSpinner(flags["--refresh"] ?? false);
|
|
1319
|
+
if (!loaded) {
|
|
1320
|
+
output_manager_default.error("Could not load API specification");
|
|
1321
|
+
return 1;
|
|
1322
|
+
}
|
|
1323
|
+
const allEndpoints = openApi.getEndpoints();
|
|
1324
|
+
const resolved = resolveEndpointByTagAndOperationId(
|
|
1325
|
+
allEndpoints,
|
|
1326
|
+
tag,
|
|
1327
|
+
operationId
|
|
1328
|
+
);
|
|
1329
|
+
if (!resolved.ok) {
|
|
1330
|
+
printTagOperationResolveError(resolved, allEndpoints);
|
|
1331
|
+
return 1;
|
|
1332
|
+
}
|
|
1333
|
+
const ep = resolved.endpoint;
|
|
1334
|
+
const bodyFields = openApi.getBodyFields(ep);
|
|
1335
|
+
printOperationHelpDetails(ep, bodyFields, tag);
|
|
1336
|
+
return 2;
|
|
1337
|
+
}
|
|
1338
|
+
function printOperationHelpDetails(ep, bodyFields, tag) {
|
|
1339
|
+
const lines = [];
|
|
1340
|
+
lines.push("");
|
|
1341
|
+
lines.push(import_chalk3.default.bold(ep.operationId || "(operation)"));
|
|
1342
|
+
const blurb = ep.summary?.trim() || ep.description?.trim();
|
|
1343
|
+
if (blurb) {
|
|
1344
|
+
lines.push("");
|
|
1345
|
+
lines.push(import_chalk3.default.dim(blurb));
|
|
1346
|
+
}
|
|
1347
|
+
lines.push("");
|
|
1348
|
+
lines.push(import_chalk3.default.bold("Options"));
|
|
1349
|
+
lines.push("");
|
|
1350
|
+
const pathParams = ep.parameters.filter((p) => p.in === "path");
|
|
1351
|
+
const orderedParams = [
|
|
1352
|
+
...pathParams,
|
|
1353
|
+
...ep.parameters.filter((p) => p.in === "query"),
|
|
1354
|
+
...ep.parameters.filter((p) => p.in === "header"),
|
|
1355
|
+
...ep.parameters.filter((p) => p.in === "cookie")
|
|
1356
|
+
];
|
|
1357
|
+
for (const p of orderedParams) {
|
|
1358
|
+
const globalNote = p.in === "query" && GLOBAL_CLI_QUERY_PARAMS.has(p.name) ? import_chalk3.default.dim(" (often set via --scope)") : "";
|
|
1359
|
+
let reqLabel;
|
|
1360
|
+
if (p.in === "query") {
|
|
1361
|
+
reqLabel = p.required && !GLOBAL_CLI_QUERY_PARAMS.has(p.name) ? import_chalk3.default.red("required") : import_chalk3.default.dim("optional");
|
|
1362
|
+
} else if (p.in === "path") {
|
|
1363
|
+
reqLabel = p.required !== false ? import_chalk3.default.red("required") : import_chalk3.default.dim("optional");
|
|
1364
|
+
} else if (p.in === "header") {
|
|
1365
|
+
reqLabel = p.required ? import_chalk3.default.red("required") : import_chalk3.default.dim("optional");
|
|
1366
|
+
} else {
|
|
1367
|
+
reqLabel = p.required ? import_chalk3.default.red("required") : import_chalk3.default.dim("optional");
|
|
1368
|
+
}
|
|
1369
|
+
lines.push(
|
|
1370
|
+
` ${import_chalk3.default.cyan(p.name)} ${reqLabel}${globalNote}${formatDescription(p.description)}`
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
for (const f of bodyFields) {
|
|
1374
|
+
const req = f.required ? import_chalk3.default.red("required") : import_chalk3.default.dim("optional");
|
|
1375
|
+
const typeHint = f.type ? ` ${formatTypeHint(f.type)}` : "";
|
|
1376
|
+
lines.push(
|
|
1377
|
+
` ${import_chalk3.default.cyan(f.name)} ${req}${typeHint}${formatDescription(f.description)}`
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
if (orderedParams.length === 0 && bodyFields.length === 0) {
|
|
1381
|
+
lines.push(import_chalk3.default.dim(" (none)"));
|
|
1382
|
+
}
|
|
1383
|
+
lines.push("");
|
|
1384
|
+
lines.push(import_chalk3.default.bold("Example"));
|
|
1385
|
+
const exampleSuffix = pathParams.length > 0 ? ` ${pathParams.map((p) => `${p.name}=<value>`).join(" ")}` : "";
|
|
1386
|
+
lines.push(
|
|
1387
|
+
import_chalk3.default.dim(` ${packageName} api ${tag} ${ep.operationId}${exampleSuffix}`)
|
|
1388
|
+
);
|
|
1389
|
+
lines.push("");
|
|
1390
|
+
output_manager_default.print(lines.join("\n"));
|
|
1391
|
+
}
|
|
1392
|
+
function printMissingOperationParamsHelp(endpoint, missing) {
|
|
1393
|
+
output_manager_default.error(
|
|
1394
|
+
`Missing required options for operation ${import_chalk3.default.bold(endpoint.operationId)}.`
|
|
1395
|
+
);
|
|
1396
|
+
output_manager_default.log(
|
|
1397
|
+
import_chalk3.default.dim(
|
|
1398
|
+
`Pass each as key=value after the operationId, or use -F key=value. Example: \`${packageName} api ${endpoint.tags[0] ?? "tag"} ${endpoint.operationId} idOrName=my-project\``
|
|
1399
|
+
)
|
|
1400
|
+
);
|
|
1401
|
+
output_manager_default.log("");
|
|
1402
|
+
output_manager_default.log(import_chalk3.default.bold("Options"));
|
|
1403
|
+
output_manager_default.log("");
|
|
1404
|
+
for (const p of missing.path) {
|
|
1405
|
+
output_manager_default.log(` ${import_chalk3.default.cyan(p.name)}${formatDescription(p.description)}`);
|
|
1406
|
+
}
|
|
1407
|
+
for (const p of missing.header) {
|
|
1408
|
+
output_manager_default.log(` ${import_chalk3.default.cyan(p.name)}${formatDescription(p.description)}`);
|
|
1409
|
+
}
|
|
1410
|
+
for (const p of missing.query) {
|
|
1411
|
+
output_manager_default.log(` ${import_chalk3.default.cyan(p.name)}${formatDescription(p.description)}`);
|
|
1412
|
+
}
|
|
1413
|
+
for (const f of missing.body) {
|
|
1414
|
+
const typeHint = f.type ? ` ${formatTypeHint(f.type)}` : "";
|
|
1415
|
+
output_manager_default.log(
|
|
1416
|
+
` ${import_chalk3.default.cyan(f.name)}${typeHint}${formatDescription(f.description)}`
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
1419
|
+
output_manager_default.log("");
|
|
1420
|
+
}
|
|
1421
|
+
async function promptMissingParamsForTagOperation(client, endpoint, bodyFields, flags, positionalKeyValues) {
|
|
1422
|
+
const pos = [...positionalKeyValues];
|
|
1423
|
+
while (true) {
|
|
1424
|
+
const parsed = await (async () => {
|
|
1425
|
+
try {
|
|
1426
|
+
return await parseOperationKeyValuePairs(
|
|
1427
|
+
endpoint,
|
|
1428
|
+
bodyFields,
|
|
1429
|
+
flags,
|
|
1430
|
+
pos
|
|
1431
|
+
);
|
|
1432
|
+
} catch (err) {
|
|
1433
|
+
printError(err);
|
|
1434
|
+
return null;
|
|
1435
|
+
}
|
|
1436
|
+
})();
|
|
1437
|
+
if (parsed === null) {
|
|
1438
|
+
return null;
|
|
1439
|
+
}
|
|
1440
|
+
const missing = getMissingRequiredOperationParams(
|
|
1441
|
+
endpoint,
|
|
1442
|
+
bodyFields,
|
|
1443
|
+
parsed,
|
|
1444
|
+
flags
|
|
1445
|
+
);
|
|
1446
|
+
if (missing.path.length === 0 && missing.query.length === 0 && missing.header.length === 0 && missing.body.length === 0) {
|
|
1447
|
+
break;
|
|
1448
|
+
}
|
|
1449
|
+
for (const param of missing.path) {
|
|
1450
|
+
const value = await client.input.text({
|
|
1451
|
+
message: `Enter value for ${formatPathParam(param.name)}${formatDescription(param.description)}:`,
|
|
1452
|
+
validate: createRequiredValidator(param.name)
|
|
1453
|
+
});
|
|
1454
|
+
pos.push(`${param.name}=${value}`);
|
|
1455
|
+
}
|
|
1456
|
+
for (const param of missing.header) {
|
|
1457
|
+
const value = await client.input.text({
|
|
1458
|
+
message: `Enter value for header ${import_chalk3.default.cyan(param.name)}${formatDescription(param.description)}:`,
|
|
1459
|
+
validate: createRequiredValidator(param.name)
|
|
1460
|
+
});
|
|
1461
|
+
pos.push(`${param.name}=${value}`);
|
|
1462
|
+
}
|
|
1463
|
+
for (const param of missing.query) {
|
|
1464
|
+
const value = await client.input.text({
|
|
1465
|
+
message: `Enter value for ${import_chalk3.default.cyan(param.name)}${formatDescription(param.description)}:`,
|
|
1466
|
+
validate: createRequiredValidator(param.name)
|
|
1467
|
+
});
|
|
1468
|
+
pos.push(`${param.name}=${value}`);
|
|
1469
|
+
}
|
|
1470
|
+
for (const field of missing.body) {
|
|
1471
|
+
const value = await promptForBodyField(client, field, true);
|
|
1472
|
+
pos.push(`${field.name}=${value}`);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
return promptUnsetOptionalParamsForTagOperation(
|
|
1476
|
+
client,
|
|
1477
|
+
endpoint,
|
|
1478
|
+
bodyFields,
|
|
1479
|
+
flags,
|
|
1480
|
+
pos
|
|
1481
|
+
);
|
|
1482
|
+
}
|
|
1483
|
+
async function promptUnsetOptionalParamsForTagOperation(client, endpoint, bodyFields, flags, positionalKeyValues) {
|
|
1484
|
+
const pos = [...positionalKeyValues];
|
|
1485
|
+
const parsed = await (async () => {
|
|
1486
|
+
try {
|
|
1487
|
+
return await parseOperationKeyValuePairs(
|
|
1488
|
+
endpoint,
|
|
1489
|
+
bodyFields,
|
|
1490
|
+
flags,
|
|
1491
|
+
pos
|
|
1492
|
+
);
|
|
1493
|
+
} catch (err) {
|
|
1494
|
+
printError(err);
|
|
1495
|
+
return null;
|
|
1496
|
+
}
|
|
1497
|
+
})();
|
|
1498
|
+
if (parsed === null) {
|
|
1499
|
+
return null;
|
|
1500
|
+
}
|
|
1501
|
+
const unset = getUnsetOptionalOperationParams(
|
|
1502
|
+
endpoint,
|
|
1503
|
+
bodyFields,
|
|
1504
|
+
parsed,
|
|
1505
|
+
flags
|
|
1506
|
+
);
|
|
1507
|
+
if (unset.query.length === 0 && unset.header.length === 0 && unset.body.length === 0) {
|
|
1508
|
+
return pos;
|
|
1509
|
+
}
|
|
1510
|
+
if (unset.query.length > 0) {
|
|
1511
|
+
const selected = await client.input.checkbox({
|
|
1512
|
+
message: "Select optional query parameters to include:",
|
|
1513
|
+
pageSize: 20,
|
|
1514
|
+
choices: unset.query.map((p) => ({
|
|
1515
|
+
name: `${import_chalk3.default.cyan(p.name)}${GLOBAL_CLI_QUERY_PARAMS.has(p.name) ? import_chalk3.default.dim(" (team / scope; omit to use CLI default)") : ""}${formatDescription(p.description)}`,
|
|
1516
|
+
value: p.name
|
|
1517
|
+
}))
|
|
1518
|
+
});
|
|
1519
|
+
for (const paramName of selected) {
|
|
1520
|
+
const param = unset.query.find((p) => p.name === paramName);
|
|
1521
|
+
const value = await client.input.text({
|
|
1522
|
+
message: `Enter value for ${import_chalk3.default.cyan(param.name)}${formatDescription(param.description)}:`,
|
|
1523
|
+
validate: createRequiredValidator(param.name)
|
|
1524
|
+
});
|
|
1525
|
+
pos.push(`${param.name}=${value}`);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
if (unset.header.length > 0) {
|
|
1529
|
+
const selected = await client.input.checkbox({
|
|
1530
|
+
message: "Select optional header parameters to include:",
|
|
1531
|
+
pageSize: 20,
|
|
1532
|
+
choices: unset.header.map((p) => ({
|
|
1533
|
+
name: `${import_chalk3.default.cyan(p.name)}${formatDescription(p.description)}`,
|
|
1534
|
+
value: p.name
|
|
1535
|
+
}))
|
|
1536
|
+
});
|
|
1537
|
+
for (const paramName of selected) {
|
|
1538
|
+
const param = unset.header.find((p) => p.name === paramName);
|
|
1539
|
+
const value = await client.input.text({
|
|
1540
|
+
message: `Enter value for header ${import_chalk3.default.cyan(param.name)}${formatDescription(param.description)}:`,
|
|
1541
|
+
validate: createRequiredValidator(param.name)
|
|
1542
|
+
});
|
|
1543
|
+
pos.push(`${param.name}=${value}`);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
if (unset.body.length > 0) {
|
|
1547
|
+
const selected = await client.input.checkbox({
|
|
1548
|
+
message: "Select optional body fields to include:",
|
|
1549
|
+
pageSize: 20,
|
|
1550
|
+
choices: unset.body.map((f) => ({
|
|
1551
|
+
name: `${import_chalk3.default.cyan(f.name)}${f.type ? ` ${formatTypeHint(f.type)}` : ""}${formatDescription(f.description)}`,
|
|
1552
|
+
value: f.name
|
|
1553
|
+
}))
|
|
1554
|
+
});
|
|
1555
|
+
for (const fieldName of selected) {
|
|
1556
|
+
const field = unset.body.find((f) => f.name === fieldName);
|
|
1557
|
+
const value = await promptForBodyField(client, field, true);
|
|
1558
|
+
pos.push(`${field.name}=${value}`);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
return pos;
|
|
1562
|
+
}
|
|
1563
|
+
function printTagOperationResolveError(result, allEndpoints) {
|
|
1564
|
+
if (result.reason === "no_tag") {
|
|
1565
|
+
const tags = [...new Set(allEndpoints.flatMap((ep) => ep.tags || []))].sort();
|
|
1566
|
+
const preview = tags.slice(0, 25).join(", ");
|
|
1567
|
+
output_manager_default.error(
|
|
1568
|
+
`No operations use tag "${result.tag}".${tags.length > 0 ? ` Example tags: ${preview}${tags.length > 25 ? ", \u2026" : ""}.` : ""} Run \`vercel api ls --format json\` to inspect tags.`
|
|
1569
|
+
);
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
if (result.reason === "no_operation") {
|
|
1573
|
+
const ids = result.tagMatches.map((ep) => ep.operationId).filter(Boolean).sort();
|
|
1574
|
+
output_manager_default.error(
|
|
1575
|
+
`No operation matches "${result.operationHint}" under tag "${result.tag}".${ids.length > 0 ? ` Operations include: ${ids.slice(0, 20).join(", ")}${ids.length > 20 ? ", \u2026" : ""}.` : ""}`
|
|
1576
|
+
);
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
const lines = result.tagMatches.map(
|
|
1580
|
+
(ep) => ` ${ep.operationId} ${ep.method} ${ep.path}`
|
|
1581
|
+
);
|
|
1582
|
+
output_manager_default.error(
|
|
1583
|
+
`Multiple operations match "${result.operationHint}" under tag "${result.tag}":
|
|
1584
|
+
${lines.join("\n")}`
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
async function executeApiRequest(client, requestConfig, flags, displayColumns, options) {
|
|
1588
|
+
if (flags["--verbose"]) {
|
|
1589
|
+
output_manager_default.debug(`Request: ${requestConfig.method} ${requestConfig.url}`);
|
|
1590
|
+
if (Object.keys(requestConfig.headers).length > 0) {
|
|
1591
|
+
output_manager_default.debug(`Headers: ${JSON.stringify(requestConfig.headers)}`);
|
|
1592
|
+
}
|
|
1593
|
+
if (requestConfig.body) {
|
|
1594
|
+
output_manager_default.debug(
|
|
1595
|
+
`Body: ${typeof requestConfig.body === "string" ? requestConfig.body : JSON.stringify(requestConfig.body)}`
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
if (flags["--paginate"]) {
|
|
1600
|
+
return executePaginatedRequest(client, requestConfig, flags);
|
|
1601
|
+
}
|
|
1602
|
+
return executeSingleRequest(
|
|
1603
|
+
client,
|
|
1604
|
+
requestConfig,
|
|
1605
|
+
flags,
|
|
1606
|
+
displayColumns,
|
|
1607
|
+
options
|
|
1608
|
+
);
|
|
1609
|
+
}
|
|
1610
|
+
async function executeSingleRequest(client, config, flags, displayColumns, options) {
|
|
1611
|
+
try {
|
|
1612
|
+
const confirmed = await client.confirmMutatingOperation(
|
|
1613
|
+
config.url,
|
|
1614
|
+
config.method
|
|
1615
|
+
);
|
|
1616
|
+
if (!confirmed) {
|
|
1617
|
+
return 1;
|
|
1618
|
+
}
|
|
1619
|
+
const response = await client.fetch(config.url, {
|
|
1620
|
+
method: config.method,
|
|
1621
|
+
body: config.body,
|
|
1622
|
+
headers: config.headers,
|
|
1623
|
+
json: false
|
|
1624
|
+
});
|
|
1625
|
+
return handleResponse(
|
|
1626
|
+
client,
|
|
1627
|
+
response,
|
|
1628
|
+
flags,
|
|
1629
|
+
config.method,
|
|
1630
|
+
displayColumns,
|
|
1631
|
+
options
|
|
1632
|
+
);
|
|
1633
|
+
} catch (err) {
|
|
1634
|
+
output_manager_default.prettyError(err);
|
|
1635
|
+
return 1;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
async function executePaginatedRequest(client, config, flags) {
|
|
1639
|
+
const results = [];
|
|
1640
|
+
try {
|
|
1641
|
+
const confirmed = await client.confirmMutatingOperation(
|
|
1642
|
+
config.url,
|
|
1643
|
+
config.method
|
|
1644
|
+
);
|
|
1645
|
+
if (!confirmed) {
|
|
1646
|
+
return 1;
|
|
1647
|
+
}
|
|
1648
|
+
for await (const page of client.fetchPaginated(
|
|
1649
|
+
config.url,
|
|
1650
|
+
{
|
|
1651
|
+
method: config.method,
|
|
1652
|
+
body: config.body,
|
|
1653
|
+
headers: config.headers
|
|
1654
|
+
}
|
|
1655
|
+
)) {
|
|
1656
|
+
const data = extractPaginatedData(page);
|
|
1657
|
+
results.push(...data);
|
|
1658
|
+
}
|
|
1659
|
+
return outputResults(client, results, flags);
|
|
1660
|
+
} catch (err) {
|
|
1661
|
+
output_manager_default.prettyError(err);
|
|
1662
|
+
return 1;
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
function extractPaginatedData(page) {
|
|
1666
|
+
for (const [key, value] of Object.entries(page)) {
|
|
1667
|
+
if (key !== "pagination" && Array.isArray(value)) {
|
|
1668
|
+
return value;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
const { pagination, ...rest } = page;
|
|
1672
|
+
return [rest];
|
|
1673
|
+
}
|
|
1674
|
+
async function handleResponse(client, response, flags, method, displayColumns, options) {
|
|
1675
|
+
if (flags["--include"]) {
|
|
1676
|
+
outputHeaders(client, response);
|
|
1677
|
+
}
|
|
1678
|
+
if (flags["--silent"]) {
|
|
1679
|
+
return response.ok ? 0 : 1;
|
|
1680
|
+
}
|
|
1681
|
+
const contentType = response.headers.get("content-type") || "";
|
|
1682
|
+
const isMutation = options?.tagOperation && method !== "GET";
|
|
1683
|
+
if (contentType.includes("application/json")) {
|
|
1684
|
+
const json = await response.json();
|
|
1685
|
+
if (flags["--verbose"]) {
|
|
1686
|
+
output_manager_default.debug(
|
|
1687
|
+
`Response status: ${response.status} ${response.statusText}`
|
|
1688
|
+
);
|
|
1689
|
+
}
|
|
1690
|
+
if (displayColumns && response.ok && !flags["--raw"]) {
|
|
1691
|
+
return outputWithDisplayColumns(client, json, displayColumns);
|
|
1692
|
+
}
|
|
1693
|
+
if (isMutation && !flags["--raw"]) {
|
|
1694
|
+
if (!response.ok) {
|
|
1695
|
+
return outputMutationResult(client, response, method, json);
|
|
1696
|
+
}
|
|
1697
|
+
return outputMutationResult(client, response, method);
|
|
1698
|
+
}
|
|
1699
|
+
return outputResults(client, json, flags);
|
|
1700
|
+
}
|
|
1701
|
+
const text = await response.text();
|
|
1702
|
+
if (isMutation && !flags["--raw"]) {
|
|
1703
|
+
return outputMutationResult(
|
|
1704
|
+
client,
|
|
1705
|
+
response,
|
|
1706
|
+
method,
|
|
1707
|
+
response.ok ? void 0 : text
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
client.stdout.write(text);
|
|
1711
|
+
return response.ok ? 0 : 1;
|
|
1712
|
+
}
|
|
1713
|
+
function outputHeaders(client, response) {
|
|
1714
|
+
client.stdout.write(`HTTP ${response.status} ${response.statusText}
|
|
1715
|
+
`);
|
|
1716
|
+
response.headers.forEach((value, key) => {
|
|
1717
|
+
client.stdout.write(`${key}: ${value}
|
|
1718
|
+
`);
|
|
1719
|
+
});
|
|
1720
|
+
client.stdout.write("\n");
|
|
1721
|
+
}
|
|
1722
|
+
function outputWithDisplayColumns(client, data, columns) {
|
|
1723
|
+
const parsed = parseArrayColumns(data, columns);
|
|
1724
|
+
if (parsed) {
|
|
1725
|
+
client.stdout.write(renderTable(parsed.rows, parsed.rowColumns) + "\n");
|
|
1726
|
+
return 0;
|
|
1727
|
+
}
|
|
1728
|
+
if (Array.isArray(data)) {
|
|
1729
|
+
client.stdout.write(renderTable(data, columns) + "\n");
|
|
1730
|
+
} else if (data && typeof data === "object") {
|
|
1731
|
+
client.stdout.write(renderCard(data, columns) + "\n");
|
|
1732
|
+
} else {
|
|
1733
|
+
client.stdout.write(formatOutput(data, {}) + "\n");
|
|
1734
|
+
}
|
|
1735
|
+
return 0;
|
|
1736
|
+
}
|
|
1737
|
+
function outputMutationResult(client, response, method, errorBody) {
|
|
1738
|
+
const verb = method === "POST" ? "Created" : method === "PATCH" || method === "PUT" ? "Updated" : method === "DELETE" ? "Deleted" : "Done";
|
|
1739
|
+
if (response.ok) {
|
|
1740
|
+
client.stdout.write(
|
|
1741
|
+
`${import_chalk3.default.green("Success")} ${verb} ${import_chalk3.default.dim(`(${response.status})`)}
|
|
1742
|
+
`
|
|
1743
|
+
);
|
|
1744
|
+
return 0;
|
|
1745
|
+
}
|
|
1746
|
+
const errorMessage = extractErrorMessage(errorBody);
|
|
1747
|
+
const statusLine = `${import_chalk3.default.red("Error")} ${response.status} ${response.statusText}`;
|
|
1748
|
+
client.stdout.write(
|
|
1749
|
+
errorMessage ? `${statusLine}
|
|
1750
|
+
${import_chalk3.default.dim(errorMessage)}
|
|
1751
|
+
` : `${statusLine}
|
|
1752
|
+
`
|
|
1753
|
+
);
|
|
1754
|
+
return 1;
|
|
1755
|
+
}
|
|
1756
|
+
function extractErrorMessage(body) {
|
|
1757
|
+
if (!body)
|
|
1758
|
+
return null;
|
|
1759
|
+
if (typeof body === "string")
|
|
1760
|
+
return body;
|
|
1761
|
+
if (typeof body === "object" && body !== null) {
|
|
1762
|
+
const obj = body;
|
|
1763
|
+
if (typeof obj.message === "string")
|
|
1764
|
+
return obj.message;
|
|
1765
|
+
const err = obj.error;
|
|
1766
|
+
if (err && typeof err.message === "string")
|
|
1767
|
+
return err.message;
|
|
1768
|
+
}
|
|
1769
|
+
return null;
|
|
1770
|
+
}
|
|
1771
|
+
function outputResults(client, data, flags) {
|
|
1772
|
+
const formatted = formatOutput(data, {
|
|
1773
|
+
raw: flags["--raw"]
|
|
1774
|
+
});
|
|
1775
|
+
client.stdout.write(formatted + "\n");
|
|
1776
|
+
return 0;
|
|
1777
|
+
}
|
|
1778
|
+
async function promptEndpointSelection(client, forceRefresh) {
|
|
1779
|
+
try {
|
|
1780
|
+
const openApi = new OpenApiCache();
|
|
1781
|
+
const success = await openApi.loadWithSpinner(forceRefresh);
|
|
1782
|
+
if (!success) {
|
|
1783
|
+
output_manager_default.error("Could not load API specification for endpoint selection");
|
|
1784
|
+
return null;
|
|
1785
|
+
}
|
|
1786
|
+
const endpoints = openApi.getEndpoints();
|
|
1787
|
+
const selectedEndpoint = await promptForEndpoint(client, endpoints);
|
|
1788
|
+
const bodyFieldsSpec = openApi.getBodyFields(selectedEndpoint);
|
|
1789
|
+
const { finalUrl, bodyFields } = await promptForParameters(
|
|
1790
|
+
client,
|
|
1791
|
+
selectedEndpoint.path,
|
|
1792
|
+
selectedEndpoint.parameters,
|
|
1793
|
+
bodyFieldsSpec
|
|
1794
|
+
);
|
|
1795
|
+
return {
|
|
1796
|
+
path: selectedEndpoint.path,
|
|
1797
|
+
method: selectedEndpoint.method,
|
|
1798
|
+
finalUrl,
|
|
1799
|
+
bodyFields
|
|
1800
|
+
};
|
|
1801
|
+
} catch (err) {
|
|
1802
|
+
output_manager_default.stopSpinner();
|
|
1803
|
+
output_manager_default.debug(`Endpoint selection failed: ${err}`);
|
|
1804
|
+
return null;
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
async function promptForEndpoint(client, endpoints) {
|
|
1808
|
+
const allChoices = endpoints.map((ep) => ({
|
|
1809
|
+
name: `${colorizeMethodPadded(ep.method)} ${ep.path}`,
|
|
1810
|
+
value: ep,
|
|
1811
|
+
// Show full description if available, otherwise show summary
|
|
1812
|
+
description: ep.description || ep.summary || void 0,
|
|
1813
|
+
// Include summary in searchable metadata
|
|
1814
|
+
summary: ep.summary,
|
|
1815
|
+
tags: ep.tags
|
|
1816
|
+
}));
|
|
1817
|
+
const total = allChoices.length;
|
|
1818
|
+
return client.input.search({
|
|
1819
|
+
message: `Search for an API endpoint (${total} available):`,
|
|
1820
|
+
source: async (term) => {
|
|
1821
|
+
if (!term) {
|
|
1822
|
+
return allChoices;
|
|
1823
|
+
}
|
|
1824
|
+
const lowerTerm = term.toLowerCase();
|
|
1825
|
+
return allChoices.filter((choice) => {
|
|
1826
|
+
const searchableText = [
|
|
1827
|
+
choice.name,
|
|
1828
|
+
choice.summary || "",
|
|
1829
|
+
choice.description || "",
|
|
1830
|
+
...choice.tags || []
|
|
1831
|
+
].join(" ").toLowerCase();
|
|
1832
|
+
return searchableText.includes(lowerTerm);
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
async function listEndpoints(client, forceRefresh, format) {
|
|
1838
|
+
const openApi = new OpenApiCache();
|
|
1839
|
+
const success = await openApi.loadWithSpinner(forceRefresh);
|
|
1840
|
+
if (!success) {
|
|
1841
|
+
output_manager_default.error("Could not load API specification");
|
|
1842
|
+
return 1;
|
|
1843
|
+
}
|
|
1844
|
+
const endpoints = openApi.getEndpoints();
|
|
1845
|
+
if (format === "json") {
|
|
1846
|
+
return outputEndpointsAsJson(client, endpoints);
|
|
1847
|
+
}
|
|
1848
|
+
return outputEndpointsAsTable(endpoints);
|
|
1849
|
+
}
|
|
1850
|
+
function outputEndpointsAsJson(client, endpoints) {
|
|
1851
|
+
const jsonOutput = endpoints.map((ep) => ({
|
|
1852
|
+
method: ep.method,
|
|
1853
|
+
path: ep.path,
|
|
1854
|
+
summary: ep.summary || null,
|
|
1855
|
+
description: ep.description || null,
|
|
1856
|
+
operationId: ep.operationId || null,
|
|
1857
|
+
tags: ep.tags
|
|
1858
|
+
}));
|
|
1859
|
+
client.stdout.write(JSON.stringify(jsonOutput, null, 2) + "\n");
|
|
1860
|
+
return 0;
|
|
1861
|
+
}
|
|
1862
|
+
function groupEndpointsByPath(endpoints) {
|
|
1863
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
1864
|
+
for (const ep of endpoints) {
|
|
1865
|
+
const existing = grouped.get(ep.path) || [];
|
|
1866
|
+
existing.push({ method: ep.method, summary: ep.summary });
|
|
1867
|
+
grouped.set(ep.path, existing);
|
|
1868
|
+
}
|
|
1869
|
+
const methodOrder = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
1870
|
+
for (const [path, methods] of grouped) {
|
|
1871
|
+
methods.sort(
|
|
1872
|
+
(a, b) => methodOrder.indexOf(a.method) - methodOrder.indexOf(b.method)
|
|
1873
|
+
);
|
|
1874
|
+
grouped.set(path, methods);
|
|
1875
|
+
}
|
|
1876
|
+
return grouped;
|
|
1877
|
+
}
|
|
1878
|
+
function outputEndpointsAsTable(endpoints) {
|
|
1879
|
+
const grouped = groupEndpointsByPath(endpoints);
|
|
1880
|
+
const methodWidth = 7;
|
|
1881
|
+
output_manager_default.log("");
|
|
1882
|
+
for (const [path, methods] of grouped) {
|
|
1883
|
+
output_manager_default.log(import_chalk3.default.bold(path));
|
|
1884
|
+
for (const { method, summary } of methods) {
|
|
1885
|
+
const coloredMethod = colorizeMethod(method);
|
|
1886
|
+
const paddedMethod = method.padEnd(methodWidth);
|
|
1887
|
+
const methodDisplay = coloredMethod + paddedMethod.slice(method.length);
|
|
1888
|
+
output_manager_default.log(` ${methodDisplay} ${import_chalk3.default.gray(summary || "")}`);
|
|
1889
|
+
}
|
|
1890
|
+
output_manager_default.log("");
|
|
1891
|
+
}
|
|
1892
|
+
output_manager_default.log(
|
|
1893
|
+
`${import_chalk3.default.bold(grouped.size.toString())} routes, ${import_chalk3.default.bold(endpoints.length.toString())} endpoints`
|
|
1894
|
+
);
|
|
1895
|
+
return 0;
|
|
1896
|
+
}
|
|
1897
|
+
function createRequiredValidator(fieldName) {
|
|
1898
|
+
return (input) => {
|
|
1899
|
+
if (!input.trim()) {
|
|
1900
|
+
return `${fieldName} is required`;
|
|
1901
|
+
}
|
|
1902
|
+
return true;
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1905
|
+
function buildQueryString(params) {
|
|
1906
|
+
return Object.entries(params).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
|
|
1907
|
+
}
|
|
1908
|
+
async function promptForParameters(client, path, parameters, bodyFieldsSpec) {
|
|
1909
|
+
const globalParams = /* @__PURE__ */ new Set(["teamId", "slug"]);
|
|
1910
|
+
const pathParams = parameters.filter((p) => p.in === "path");
|
|
1911
|
+
const requiredQueryParams = parameters.filter(
|
|
1912
|
+
(p) => p.in === "query" && p.required && !globalParams.has(p.name)
|
|
1913
|
+
);
|
|
1914
|
+
const optionalQueryParams = parameters.filter(
|
|
1915
|
+
(p) => p.in === "query" && !p.required && !globalParams.has(p.name)
|
|
1916
|
+
);
|
|
1917
|
+
const requiredBodyFields = bodyFieldsSpec.filter((f) => f.required);
|
|
1918
|
+
const optionalBodyFields = bodyFieldsSpec.filter((f) => !f.required);
|
|
1919
|
+
let finalPath = path;
|
|
1920
|
+
for (const param of pathParams) {
|
|
1921
|
+
const value = await client.input.text({
|
|
1922
|
+
message: `Enter value for ${formatPathParam(param.name)}${formatDescription(param.description)}:`,
|
|
1923
|
+
validate: createRequiredValidator(param.name)
|
|
1924
|
+
});
|
|
1925
|
+
finalPath = finalPath.replace(`{${param.name}}`, encodeURIComponent(value));
|
|
1926
|
+
}
|
|
1927
|
+
const queryValues = {};
|
|
1928
|
+
for (const param of requiredQueryParams) {
|
|
1929
|
+
queryValues[param.name] = await client.input.text({
|
|
1930
|
+
message: `Enter value for ${import_chalk3.default.cyan(param.name)}${formatDescription(param.description)}:`,
|
|
1931
|
+
validate: createRequiredValidator(param.name)
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1934
|
+
if (optionalQueryParams.length > 0) {
|
|
1935
|
+
const selectedOptionalParams = await client.input.checkbox({
|
|
1936
|
+
message: "Select optional query parameters to include:",
|
|
1937
|
+
pageSize: 20,
|
|
1938
|
+
choices: optionalQueryParams.map((p) => ({
|
|
1939
|
+
name: `${import_chalk3.default.cyan(p.name)}${formatDescription(p.description)}`,
|
|
1940
|
+
value: p.name
|
|
1941
|
+
}))
|
|
1942
|
+
});
|
|
1943
|
+
for (const paramName of selectedOptionalParams) {
|
|
1944
|
+
const param = optionalQueryParams.find((p) => p.name === paramName);
|
|
1945
|
+
queryValues[param.name] = await client.input.text({
|
|
1946
|
+
message: `Enter value for ${import_chalk3.default.cyan(param.name)}${formatDescription(param.description)}:`,
|
|
1947
|
+
validate: createRequiredValidator(param.name)
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
const bodyFieldValues = [];
|
|
1952
|
+
for (const field of requiredBodyFields) {
|
|
1953
|
+
const value = await promptForBodyField(client, field, true);
|
|
1954
|
+
bodyFieldValues.push(`${field.name}=${value}`);
|
|
1955
|
+
}
|
|
1956
|
+
if (optionalBodyFields.length > 0) {
|
|
1957
|
+
const selectedOptionalFields = await client.input.checkbox({
|
|
1958
|
+
message: "Select optional body fields to include:",
|
|
1959
|
+
pageSize: 20,
|
|
1960
|
+
choices: optionalBodyFields.map((f) => ({
|
|
1961
|
+
name: `${import_chalk3.default.cyan(f.name)}${f.type ? ` ${formatTypeHint(f.type)}` : ""}${formatDescription(f.description)}`,
|
|
1962
|
+
value: f.name
|
|
1963
|
+
}))
|
|
1964
|
+
});
|
|
1965
|
+
for (const fieldName of selectedOptionalFields) {
|
|
1966
|
+
const field = optionalBodyFields.find((f) => f.name === fieldName);
|
|
1967
|
+
const value = await promptForBodyField(client, field, true);
|
|
1968
|
+
bodyFieldValues.push(`${field.name}=${value}`);
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
const queryString = buildQueryString(queryValues);
|
|
1972
|
+
if (queryString) {
|
|
1973
|
+
finalPath += `?${queryString}`;
|
|
1974
|
+
}
|
|
1975
|
+
return { finalUrl: finalPath, bodyFields: bodyFieldValues };
|
|
1976
|
+
}
|
|
1977
|
+
async function promptForBodyField(client, field, required) {
|
|
1978
|
+
const description = formatDescription(field.description);
|
|
1979
|
+
const optionalHint = required ? "" : import_chalk3.default.dim(" (optional)");
|
|
1980
|
+
if (field.type === "array" && field.enumValues && field.enumValues.length > 0) {
|
|
1981
|
+
const choices = field.enumValues.map((v) => ({
|
|
1982
|
+
name: String(v),
|
|
1983
|
+
value: String(v)
|
|
1984
|
+
}));
|
|
1985
|
+
const selected = await client.input.checkbox({
|
|
1986
|
+
message: `Select values for ${import_chalk3.default.cyan(field.name)}${optionalHint}${description}:`,
|
|
1987
|
+
choices,
|
|
1988
|
+
required
|
|
1989
|
+
});
|
|
1990
|
+
return JSON.stringify(selected);
|
|
1991
|
+
}
|
|
1992
|
+
if (field.enumValues && field.enumValues.length > 0) {
|
|
1993
|
+
const choices = field.enumValues.map((v) => ({
|
|
1994
|
+
name: String(v),
|
|
1995
|
+
value: String(v)
|
|
1996
|
+
}));
|
|
1997
|
+
if (!required) {
|
|
1998
|
+
choices.unshift({ name: import_chalk3.default.dim("(skip)"), value: "" });
|
|
1999
|
+
}
|
|
2000
|
+
return client.input.select({
|
|
2001
|
+
message: `Select value for ${import_chalk3.default.cyan(field.name)}${optionalHint}${description}:`,
|
|
2002
|
+
choices
|
|
2003
|
+
});
|
|
2004
|
+
}
|
|
2005
|
+
const typeHint = field.type ? ` ${formatTypeHint(field.type)}` : "";
|
|
2006
|
+
return client.input.text({
|
|
2007
|
+
message: `Enter value for ${import_chalk3.default.cyan(field.name)}${optionalHint}${typeHint}${description}:`,
|
|
2008
|
+
validate: required ? createRequiredValidator(field.name) : void 0
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
async function runTagOperation(client, options) {
|
|
2012
|
+
const { tag, operationId, flags, positionalOperationFields } = options;
|
|
2013
|
+
const telemetryClient = new ApiTelemetryClient({
|
|
2014
|
+
opts: { store: client.telemetryEventStore }
|
|
2015
|
+
});
|
|
2016
|
+
const finalFlags = { ...flags };
|
|
2017
|
+
const openApi = new OpenApiCache();
|
|
2018
|
+
const loaded = await openApi.loadWithSpinner(
|
|
2019
|
+
finalFlags["--refresh"] ?? false
|
|
2020
|
+
);
|
|
2021
|
+
if (!loaded) {
|
|
2022
|
+
output_manager_default.error("Could not load API specification");
|
|
2023
|
+
return 1;
|
|
2024
|
+
}
|
|
2025
|
+
const allEndpoints = openApi.getEndpoints();
|
|
2026
|
+
const resolved = resolveEndpointByTagAndOperationId(
|
|
2027
|
+
allEndpoints,
|
|
2028
|
+
tag,
|
|
2029
|
+
operationId
|
|
2030
|
+
);
|
|
2031
|
+
if (!resolved.ok) {
|
|
2032
|
+
printTagOperationResolveError(resolved, allEndpoints);
|
|
2033
|
+
return 1;
|
|
2034
|
+
}
|
|
2035
|
+
const bodyFields = openApi.getBodyFields(resolved.endpoint);
|
|
2036
|
+
const displayColumns = openApi.getDisplayColumns(resolved.endpoint);
|
|
2037
|
+
let tagOperationPositional = positionalOperationFields;
|
|
2038
|
+
if (client.stdin.isTTY) {
|
|
2039
|
+
const prompted = await promptMissingParamsForTagOperation(
|
|
2040
|
+
client,
|
|
2041
|
+
resolved.endpoint,
|
|
2042
|
+
bodyFields,
|
|
2043
|
+
finalFlags,
|
|
2044
|
+
tagOperationPositional
|
|
2045
|
+
);
|
|
2046
|
+
if (prompted === null) {
|
|
2047
|
+
return 1;
|
|
2048
|
+
}
|
|
2049
|
+
tagOperationPositional = prompted;
|
|
2050
|
+
} else {
|
|
2051
|
+
try {
|
|
2052
|
+
const parsed = await parseOperationKeyValuePairs(
|
|
2053
|
+
resolved.endpoint,
|
|
2054
|
+
bodyFields,
|
|
2055
|
+
finalFlags,
|
|
2056
|
+
tagOperationPositional
|
|
2057
|
+
);
|
|
2058
|
+
const missing = getMissingRequiredOperationParams(
|
|
2059
|
+
resolved.endpoint,
|
|
2060
|
+
bodyFields,
|
|
2061
|
+
parsed,
|
|
2062
|
+
finalFlags
|
|
2063
|
+
);
|
|
2064
|
+
if (missing.path.length > 0 || missing.query.length > 0 || missing.header.length > 0 || missing.body.length > 0) {
|
|
2065
|
+
printMissingOperationParamsHelp(resolved.endpoint, missing);
|
|
2066
|
+
return 1;
|
|
2067
|
+
}
|
|
2068
|
+
} catch (err) {
|
|
2069
|
+
printError(err);
|
|
2070
|
+
return 1;
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
let requestConfig;
|
|
2074
|
+
try {
|
|
2075
|
+
requestConfig = await buildRequestForResolvedOperation(
|
|
2076
|
+
resolved.endpoint,
|
|
2077
|
+
bodyFields,
|
|
2078
|
+
finalFlags,
|
|
2079
|
+
tagOperationPositional
|
|
2080
|
+
);
|
|
2081
|
+
} catch (err) {
|
|
2082
|
+
printError(err);
|
|
2083
|
+
return 1;
|
|
2084
|
+
}
|
|
2085
|
+
telemetryClient.trackCliArgumentEndpoint(tag);
|
|
2086
|
+
telemetryClient.trackCliArgumentOperationId(operationId);
|
|
2087
|
+
telemetryClient.trackCliOptionMethod(finalFlags["--method"]);
|
|
2088
|
+
telemetryClient.trackCliOptionHeader(finalFlags["--header"]);
|
|
2089
|
+
telemetryClient.trackCliOptionInput(finalFlags["--input"]);
|
|
2090
|
+
if (finalFlags["--paginate"])
|
|
2091
|
+
telemetryClient.trackCliFlagPaginate(true);
|
|
2092
|
+
if (finalFlags["--include"])
|
|
2093
|
+
telemetryClient.trackCliFlagInclude(true);
|
|
2094
|
+
if (finalFlags["--silent"])
|
|
2095
|
+
telemetryClient.trackCliFlagSilent(true);
|
|
2096
|
+
if (finalFlags["--verbose"])
|
|
2097
|
+
telemetryClient.trackCliFlagVerbose(true);
|
|
2098
|
+
if (finalFlags["--raw"])
|
|
2099
|
+
telemetryClient.trackCliFlagRaw(true);
|
|
2100
|
+
if (finalFlags["--refresh"])
|
|
2101
|
+
telemetryClient.trackCliFlagRefresh(true);
|
|
2102
|
+
if (finalFlags["--generate"])
|
|
2103
|
+
telemetryClient.trackCliOptionGenerate(finalFlags["--generate"]);
|
|
2104
|
+
if (finalFlags["--dangerously-skip-permissions"])
|
|
2105
|
+
telemetryClient.trackCliFlagDangerouslySkipPermissions(true);
|
|
2106
|
+
if (finalFlags["--generate"] === "curl") {
|
|
2107
|
+
const curlCmd = generateCurlCommand(
|
|
2108
|
+
requestConfig,
|
|
2109
|
+
"https://api.vercel.com"
|
|
2110
|
+
);
|
|
2111
|
+
output_manager_default.log("");
|
|
2112
|
+
output_manager_default.log("Replace <TOKEN> with your auth token:");
|
|
2113
|
+
output_manager_default.log("");
|
|
2114
|
+
client.stdout.write(curlCmd + "\n");
|
|
2115
|
+
return 0;
|
|
2116
|
+
}
|
|
2117
|
+
return executeApiRequest(client, requestConfig, finalFlags, displayColumns, {
|
|
2118
|
+
tagOperation: true
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
// src/util/upgrade.ts
|
|
2123
|
+
import { spawn } from "child_process";
|
|
2124
|
+
async function executeUpgrade() {
|
|
2125
|
+
const updateCommand = await getUpdateCommand();
|
|
2126
|
+
const [command, ...args] = updateCommand.split(" ");
|
|
2127
|
+
output_manager_default.log(`Upgrading Vercel CLI...`);
|
|
2128
|
+
output_manager_default.debug(`Executing: ${updateCommand}`);
|
|
2129
|
+
return new Promise((resolve3) => {
|
|
2130
|
+
const stdout = [];
|
|
2131
|
+
const stderr = [];
|
|
2132
|
+
const upgradeProcess = spawn(command, args, {
|
|
2133
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
2134
|
+
shell: false
|
|
2135
|
+
});
|
|
2136
|
+
upgradeProcess.stdout?.on("data", (data) => {
|
|
2137
|
+
stdout.push(data);
|
|
2138
|
+
});
|
|
2139
|
+
upgradeProcess.stderr?.on("data", (data) => {
|
|
2140
|
+
stderr.push(data);
|
|
2141
|
+
});
|
|
2142
|
+
upgradeProcess.on("error", (err) => {
|
|
2143
|
+
output_manager_default.error(`Failed to execute upgrade command: ${err.message}`);
|
|
2144
|
+
output_manager_default.log(`You can try running the command manually: ${updateCommand}`);
|
|
2145
|
+
resolve3(1);
|
|
2146
|
+
});
|
|
2147
|
+
upgradeProcess.on("close", (code) => {
|
|
2148
|
+
if (code === 0) {
|
|
2149
|
+
output_manager_default.success("Vercel CLI has been upgraded successfully!");
|
|
2150
|
+
} else {
|
|
2151
|
+
const stdoutStr = Buffer.concat(stdout).toString();
|
|
2152
|
+
const stderrStr = Buffer.concat(stderr).toString();
|
|
2153
|
+
if (stdoutStr) {
|
|
2154
|
+
output_manager_default.print(stdoutStr);
|
|
2155
|
+
}
|
|
2156
|
+
if (stderrStr) {
|
|
2157
|
+
output_manager_default.print(stderrStr);
|
|
2158
|
+
}
|
|
2159
|
+
output_manager_default.error(`Upgrade failed with exit code ${code ?? "unknown"}`);
|
|
2160
|
+
output_manager_default.log(
|
|
2161
|
+
`You can try running the command manually: ${updateCommand}`
|
|
2162
|
+
);
|
|
2163
|
+
}
|
|
2164
|
+
resolve3(code ?? 1);
|
|
2165
|
+
});
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
// src/commands/login/index.ts
|
|
2170
|
+
var import_chalk4 = __toESM(require_source(), 1);
|
|
2171
|
+
|
|
2172
|
+
// src/util/telemetry/commands/login/index.ts
|
|
2173
|
+
var LoginTelemetryClient = class extends TelemetryClient {
|
|
2174
|
+
/**
|
|
2175
|
+
* Tracks the state of the login process.
|
|
2176
|
+
* - `started` when the user initiates the login process.
|
|
2177
|
+
* - `canceled` when the user cancels the login process.
|
|
2178
|
+
* - `error` when the user encounters an error during the login process.
|
|
2179
|
+
* - `success` when the user successfully logs in.
|
|
2180
|
+
*/
|
|
2181
|
+
trackState(...args) {
|
|
2182
|
+
this.trackLoginState(...args);
|
|
2183
|
+
}
|
|
2184
|
+
};
|
|
2185
|
+
|
|
2186
|
+
// src/commands/login/index.ts
|
|
2187
|
+
async function login2(client, options) {
|
|
2188
|
+
let parsedArgs = null;
|
|
2189
|
+
const flagsSpecification = getFlagsSpecification(loginCommand.options);
|
|
2190
|
+
const telemetry = new LoginTelemetryClient({
|
|
2191
|
+
opts: {
|
|
2192
|
+
store: client.telemetryEventStore
|
|
2193
|
+
}
|
|
2194
|
+
});
|
|
2195
|
+
try {
|
|
2196
|
+
if (options.shouldParseArgs) {
|
|
2197
|
+
parsedArgs = parseArguments(client.argv.slice(2), flagsSpecification);
|
|
2198
|
+
}
|
|
2199
|
+
} catch (error) {
|
|
2200
|
+
printError(error);
|
|
2201
|
+
return 1;
|
|
2202
|
+
}
|
|
2203
|
+
if (parsedArgs?.flags["--help"]) {
|
|
2204
|
+
telemetry.trackCliFlagHelp("login");
|
|
2205
|
+
output_manager_default.print(help(loginCommand, { columns: client.stderr.columns }));
|
|
2206
|
+
return 0;
|
|
2207
|
+
}
|
|
2208
|
+
if (parsedArgs?.flags["--token"]) {
|
|
2209
|
+
output_manager_default.error('`--token` may not be used with the "login" command');
|
|
2210
|
+
return 2;
|
|
2211
|
+
}
|
|
2212
|
+
if (options.shouldParseArgs && parsedArgs) {
|
|
2213
|
+
const obsoleteFlags = Object.keys(parsedArgs.flags).filter((flag) => {
|
|
2214
|
+
const flagKey = flag.replace("--", "");
|
|
2215
|
+
const option = loginCommand.options.find((o) => o.name === flagKey);
|
|
2216
|
+
if (!option || typeof option === "number")
|
|
2217
|
+
return;
|
|
2218
|
+
return "deprecated" in option && option.deprecated;
|
|
2219
|
+
});
|
|
2220
|
+
if (obsoleteFlags.length) {
|
|
2221
|
+
const flags = obsoleteFlags.map((f) => import_chalk4.default.bold(f)).join(", ");
|
|
2222
|
+
output_manager_default.warn(`The following flags are deprecated: ${flags}`);
|
|
2223
|
+
}
|
|
2224
|
+
const obsoleteArguments = parsedArgs.args.slice(1);
|
|
2225
|
+
if (obsoleteArguments.length) {
|
|
2226
|
+
const args = obsoleteArguments.map((a) => import_chalk4.default.bold(a)).join(", ");
|
|
2227
|
+
output_manager_default.warn(`The following arguments are deprecated: ${args}`);
|
|
2228
|
+
}
|
|
2229
|
+
if (obsoleteArguments.length || obsoleteFlags.length) {
|
|
2230
|
+
output_manager_default.print(
|
|
2231
|
+
`Read more in our ${output_manager_default.link("changelog", "https://vercel.com/changelog/new-vercel-cli-login-flow")}.
|
|
2232
|
+
`
|
|
2233
|
+
);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
telemetry.trackState("started");
|
|
2237
|
+
return await login(client, telemetry);
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
// src/util/output/box.ts
|
|
2241
|
+
var import_chalk5 = __toESM(require_source(), 1);
|
|
2242
|
+
var import_strip_ansi = __toESM(require_strip_ansi(), 1);
|
|
2243
|
+
var border = ["\u2500", "\u256D", "\u256E", "\u2502", "\u2502", "\u2570", "\u256F"];
|
|
2244
|
+
var nothing = ["\u2500", "", "", "", "", "", ""];
|
|
2245
|
+
function box(message, {
|
|
2246
|
+
borderColor,
|
|
2247
|
+
padding = 1,
|
|
2248
|
+
textAlignment = "center",
|
|
2249
|
+
terminalColumns: cols = process.stdout.columns || process.env.COLUMNS && parseInt(process.env.COLUMNS, 10) || 80
|
|
2250
|
+
} = {}) {
|
|
2251
|
+
const lines = message.split(/\r?\n/).map((line) => [line, (0, import_strip_ansi.default)(line).length]);
|
|
2252
|
+
const maxLine = lines.reduce((p, [, len]) => Math.max(p, len), 0);
|
|
2253
|
+
const borderColorFn = borderColor && import_chalk5.default[borderColor] || import_chalk5.default.yellow;
|
|
2254
|
+
const clampedSidePadding = Math.max(1, padding * 3);
|
|
2255
|
+
const narrowMode = maxLine + 2 + clampedSidePadding * 2 > cols;
|
|
2256
|
+
const sidePadding = narrowMode ? 0 : clampedSidePadding;
|
|
2257
|
+
const innerWidth = Math.min(maxLine + sidePadding * 2, cols);
|
|
2258
|
+
const [hr, topLeft, topRight, left, right, bottomLeft, bottomRight] = narrowMode ? nothing : border;
|
|
2259
|
+
const spacerRow = narrowMode ? "\n".repeat(padding) : `${borderColorFn(`${left}${" ".repeat(innerWidth)}${right}`)}
|
|
2260
|
+
`.repeat(
|
|
2261
|
+
padding
|
|
2262
|
+
);
|
|
2263
|
+
const renderLine = ([line, len]) => {
|
|
2264
|
+
let leftPadding = 0;
|
|
2265
|
+
let rightPadding = 0;
|
|
2266
|
+
if (!narrowMode) {
|
|
2267
|
+
leftPadding = sidePadding;
|
|
2268
|
+
rightPadding = sidePadding;
|
|
2269
|
+
if (textAlignment === "center") {
|
|
2270
|
+
leftPadding += Math.floor((maxLine - len) / 2);
|
|
2271
|
+
rightPadding += maxLine - len - leftPadding + sidePadding;
|
|
2272
|
+
} else if (textAlignment === "right") {
|
|
2273
|
+
leftPadding += maxLine - len;
|
|
2274
|
+
} else if (textAlignment === "left") {
|
|
2275
|
+
rightPadding += maxLine - len;
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
return borderColorFn(left) + " ".repeat(leftPadding) + line + " ".repeat(rightPadding) + borderColorFn(right);
|
|
2279
|
+
};
|
|
2280
|
+
return borderColorFn(`${topLeft}${hr.repeat(innerWidth)}${topRight}`) + "\n" + spacerRow + lines.map(renderLine).join("\n") + "\n" + spacerRow + borderColorFn(`${bottomLeft}${hr.repeat(innerWidth)}${bottomRight}`);
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
// src/util/did-you-mean.ts
|
|
2284
|
+
var import_jaro_winkler = __toESM(require_jaro_winkler(), 1);
|
|
2285
|
+
var did_you_mean_default = didYouMean;
|
|
2286
|
+
function didYouMean(input, list, threshold = 0.5) {
|
|
2287
|
+
const rated = list.map((item) => [dashAwareDistance(input, item), item]);
|
|
2288
|
+
const found = rated.filter((item) => item[0] > threshold);
|
|
2289
|
+
if (found.length) {
|
|
2290
|
+
const highestRated = found.reduce((accu, curr) => {
|
|
2291
|
+
return accu[0] > curr[0] ? accu : curr;
|
|
2292
|
+
});
|
|
2293
|
+
return highestRated[1];
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
function dashAwareDistance(word, dashWord) {
|
|
2297
|
+
const fullDistance = (0, import_jaro_winkler.default)(word, dashWord);
|
|
2298
|
+
const distances = dashWord.split("-").map((w) => (0, import_jaro_winkler.default)(w, word));
|
|
2299
|
+
const meanDistance = distances.reduce((accu, curr) => accu + curr) / distances.length;
|
|
2300
|
+
return fullDistance > meanDistance ? fullDistance : meanDistance;
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
export {
|
|
2304
|
+
did_you_mean_default,
|
|
2305
|
+
OpenApiCache,
|
|
2306
|
+
matchesCliApiTag,
|
|
2307
|
+
resolveOpenApiTagForProjectsCli,
|
|
2308
|
+
resolveOpenApiTagForTeamsCli,
|
|
2309
|
+
api,
|
|
2310
|
+
tryOpenApiFallback,
|
|
2311
|
+
executeUpgrade,
|
|
2312
|
+
login2 as login,
|
|
2313
|
+
box
|
|
2314
|
+
};
|