vercel 59.0.0 → 59.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{add-SQ6ERCFZ.js → add-CUGPQYFW.js} +8 -8
- package/dist/chunks/{add-QZUQNL2C.js → add-PP3PJPJV.js} +5 -5
- package/dist/chunks/{add-3LO3UMYC.js → add-PRG4KKYH.js} +9 -11
- package/dist/chunks/{build-WMUKZEFH.js → build-T22GMLY6.js} +8 -8
- package/dist/chunks/{chunk-ELA5VN3A.js → chunk-2MF3ZAVW.js} +13 -4
- package/dist/chunks/{chunk-ZFTRB6AB.js → chunk-43DD2KNM.js} +1 -1
- package/dist/chunks/{chunk-N5DK7EMY.js → chunk-4HI7G6KG.js} +1 -1
- package/dist/chunks/{chunk-DQDJVHA5.js → chunk-4JKZ7SRX.js} +4 -4
- package/dist/chunks/{chunk-ZRWSSPW5.js → chunk-57G6HBJ4.js} +2 -2
- package/dist/chunks/{chunk-RWRSUGXY.js → chunk-5DVMXOFT.js} +2 -2
- package/dist/chunks/{chunk-SHR6DYA5.js → chunk-7NQLRE5V.js} +1 -1
- package/dist/chunks/{chunk-JLWQWYKO.js → chunk-BBSS3XIW.js} +2 -4
- package/dist/chunks/{chunk-V42UVZDX.js → chunk-BCZFZETZ.js} +5 -5
- package/dist/chunks/{chunk-MZ3L3SGZ.js → chunk-DAWJOQF6.js} +4 -6
- package/dist/chunks/{chunk-W34XLJ44.js → chunk-DEB45ND4.js} +3 -3
- package/dist/chunks/{chunk-QGQX7BYN.js → chunk-DOMLWKKZ.js} +38 -15
- package/dist/chunks/{chunk-TEQKKTJQ.js → chunk-F7OXZLY2.js} +2 -2
- package/dist/chunks/{chunk-J6LK45HT.js → chunk-GFCTRJI5.js} +16 -2
- package/dist/chunks/{chunk-O26N2UPI.js → chunk-GGPE5377.js} +1 -1
- package/dist/chunks/{chunk-4LDQIDRM.js → chunk-GMWRTZVZ.js} +9 -1
- package/dist/chunks/{chunk-LT5UQNTC.js → chunk-IKKUCZE7.js} +3 -3
- package/dist/chunks/{chunk-XIG4GH62.js → chunk-JYEO6OJS.js} +188 -102
- package/dist/chunks/{chunk-DMLU5KQE.js → chunk-KTLFN5FV.js} +1 -1
- package/dist/chunks/{chunk-L6NIIAB7.js → chunk-LNVZ3T7X.js} +6 -8
- package/dist/chunks/{chunk-UQVOFOP2.js → chunk-M34ZRNDQ.js} +1 -1
- package/dist/chunks/{chunk-2SFMOCWR.js → chunk-PD7ZUXE7.js} +1 -1
- package/dist/chunks/chunk-QCVKGY2A.js +151 -0
- package/dist/chunks/{chunk-S3H7ITUR.js → chunk-QD5NX7RG.js} +1 -1
- package/dist/chunks/{chunk-4N7XLXM2.js → chunk-QQ6PH4RY.js} +1 -0
- package/dist/chunks/{chunk-A5KP5HAI.js → chunk-RIB4S2IB.js} +10 -1
- package/dist/chunks/{chunk-ZX2FSPWV.js → chunk-SJQEGGH7.js} +4 -4
- package/dist/chunks/{chunk-5KI3SUJI.js → chunk-SOKQBFF7.js} +609 -73
- package/dist/chunks/{chunk-PSZQNYEV.js → chunk-SQGMTRZD.js} +91 -43
- package/dist/chunks/{chunk-TJJ562C5.js → chunk-TJLBCLEX.js} +15 -0
- package/dist/chunks/{chunk-WE3TFESA.js → chunk-TM3F7PLR.js} +2 -2
- package/dist/chunks/{chunk-SD2QZHZA.js → chunk-TNKRSTMB.js} +1 -1
- package/dist/chunks/{chunk-KT4XXKJK.js → chunk-VAFU7DXZ.js} +195 -3
- package/dist/chunks/{chunk-RQ7H43CJ.js → chunk-VDJN4WKH.js} +1 -1
- package/dist/chunks/{chunk-3R5JGMHV.js → chunk-VE545BR3.js} +4473 -2796
- package/dist/chunks/{chunk-B3JTF4CF.js → chunk-WC7IINFV.js} +10 -1
- package/dist/chunks/{chunk-SQAQED4U.js → chunk-XZLI27ES.js} +2 -2
- package/dist/chunks/{chunk-CMR5KQVR.js → chunk-ZUVJISHS.js} +3 -3
- package/dist/chunks/{clear-W2B4CHTP.js → clear-Z4IKUIN7.js} +5 -5
- package/dist/chunks/{compile-vercel-config-HTWOS7DZ.js → compile-vercel-config-PSVXFAZW.js} +3 -3
- package/dist/chunks/{config-EGJY4UUE.js → config-M5GMZ2X5.js} +8 -8
- package/dist/chunks/{constants-WEQVJSYS.js → constants-YMCRE6IG.js} +1 -1
- package/dist/chunks/{delete-BVMID4W2.js → delete-5GRRDJSF.js} +4 -4
- package/dist/chunks/{delete-6I7V5AGV.js → delete-P4XIBY7T.js} +5 -5
- package/dist/chunks/{disable-I54JNXJE.js → disable-NT5NYVO7.js} +4 -4
- package/dist/chunks/{discard-6TSJJCUQ.js → discard-TBNIEAJZ.js} +4 -4
- package/dist/chunks/{edit-YS2SWHFJ.js → edit-DJ6MT6HA.js} +5 -5
- package/dist/chunks/{edit-KCWYQ2YT.js → edit-UF3D2CCH.js} +5 -5
- package/dist/chunks/{enable-RYXRIGQN.js → enable-JTQBQMBO.js} +4 -4
- package/dist/chunks/{export-G3NYOADE.js → export-OKMRGRVM.js} +4 -4
- package/dist/chunks/{image-RJBLSUES.js → image-ARUJH4H5.js} +4 -4
- package/dist/chunks/{import-builders-M6F3F4DH.js → import-builders-3NTMZM64.js} +6 -4
- package/dist/chunks/{inspect-YTCVTZHY.js → inspect-5NETOGAI.js} +6 -7
- package/dist/chunks/{inspect-AE4YIJYS.js → inspect-CHFKZKKP.js} +5 -5
- package/dist/chunks/{inspect-Z74NZZ2A.js → inspect-FXZTQY62.js} +6 -6
- package/dist/chunks/{inspect-E7TBGK7D.js → inspect-PTXIBSYW.js} +8 -8
- package/dist/chunks/{inspect-7XUEVBDM.js → inspect-UXP2HDES.js} +5 -5
- package/dist/chunks/{list-SGPLL4KJ.js → list-2WMIVJ2R.js} +15 -10
- package/dist/chunks/{list-KJNC3NOE.js → list-ADI55WKW.js} +6 -7
- package/dist/chunks/{list-WXS2AFQD.js → list-DYCZA2VX.js} +3 -3
- package/dist/chunks/{login-XD3CFPBF.js → login-YCSIQG6B.js} +8 -8
- package/dist/chunks/{ls-5DSOTTYX.js → ls-2TKUIUK4.js} +11 -12
- package/dist/chunks/{ls-KE5I7BZO.js → ls-EOMIQLRH.js} +11 -12
- package/dist/chunks/{ls-SVSO3677.js → ls-PQFDGOJL.js} +7 -8
- package/dist/chunks/{ls-5A4327XJ.js → ls-RZVTIP5U.js} +11 -12
- package/dist/chunks/{ls-NBKSDTWX.js → ls-VIOMDUGW.js} +14 -15
- package/dist/chunks/{open-M2MOAE2K.js → open-JYPWOXQD.js} +5 -5
- package/dist/chunks/{permissions-ADPY554K.js → permissions-SGJWGEVD.js} +6 -6
- package/dist/chunks/{publish-OBIOOL7T.js → publish-ZUQHJAXL.js} +4 -4
- package/dist/chunks/{push-5237XBTO.js → push-XMVKG5A5.js} +8 -8
- package/dist/chunks/{query-ILL74HIA.js → query-ZLJZEGZB.js} +237 -49
- package/dist/chunks/{reorder-GAUAO4LW.js → reorder-NVHDWMRU.js} +4 -4
- package/dist/chunks/{reply-IZJHEULD.js → reply-PUUPUQ3V.js} +5 -5
- package/dist/chunks/{resolve-HTIT7CGL.js → resolve-5U2LJVE6.js} +5 -5
- package/dist/chunks/{restore-IKL74HSE.js → restore-OXIUY2UI.js} +4 -4
- package/dist/chunks/{rm-QAVNP5KX.js → rm-3IOCBNPE.js} +5 -5
- package/dist/chunks/{rm-5Y6BL47T.js → rm-BZNKJRXU.js} +5 -5
- package/dist/chunks/{rm-C37ZORQV.js → rm-OUI4ZB5R.js} +5 -5
- package/dist/chunks/{rm-XJU5SBGH.js → rm-Z2KYJ7XT.js} +8 -8
- package/dist/chunks/{rule-inspect-DYHWWROS.js → rule-inspect-ZBJJCDQV.js} +7 -8
- package/dist/chunks/{rules-M6EJ2Y6S.js → rules-HEGAXXUN.js} +8 -8
- package/dist/chunks/{schema-LLBDZNIC.js → schema-7GVL3BNP.js} +63 -31
- package/dist/chunks/{schema-ZNPIMQL5.js → schema-ZYIJYA2E.js} +2 -3
- package/dist/chunks/{tags-HR5RVQFA.js → tags-3SCWCMNQ.js} +3 -3
- package/dist/chunks/{types-UWI4HETD.js → types-AJHILHO5.js} +2 -4
- package/dist/chunks/{update-6A5V6HBH.js → update-YR2GCCJN.js} +7 -8
- package/dist/commands/build/index.js +10 -15
- package/dist/commands/deploy/index.js +310 -302
- package/dist/commands/dev/index.js +254 -181
- package/dist/commands/env/index.js +15 -16
- package/dist/commands/link/index.js +14 -20
- package/dist/commands/list/index.js +7 -9
- package/dist/commands-bulk.js +4408 -1246
- package/dist/help.js +1 -1
- package/dist/index.js +30 -22
- package/dist/version.mjs +1 -1
- package/package.json +41 -40
- package/dist/chunks/chunk-BGILSKZ5.js +0 -85
- package/dist/chunks/chunk-GFG6QDIE.js +0 -101
- package/dist/chunks/chunk-KBEX5MYS.js +0 -208
- package/dist/chunks/chunk-PBECT5BN.js +0 -107
- package/dist/chunks/chunk-PVCJIMVY.js +0 -1552
- /package/dist/{commands/dev/next-dev-websocket-shim-preload.cjs → runtime-assets/node-preloads/next-dev-websocket.cjs} +0 -0
|
@@ -1,1552 +0,0 @@
|
|
|
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
|
-
getLocalPathConfig,
|
|
9
|
-
isPromptBackError,
|
|
10
|
-
isPromptCanceledError
|
|
11
|
-
} from "./chunk-BGILSKZ5.js";
|
|
12
|
-
import {
|
|
13
|
-
table
|
|
14
|
-
} from "./chunk-KT4XXKJK.js";
|
|
15
|
-
import {
|
|
16
|
-
Separator,
|
|
17
|
-
VERCEL_DIR_PROJECT,
|
|
18
|
-
VERCEL_DIR_README,
|
|
19
|
-
checkExistsAndConnect,
|
|
20
|
-
compileVercelConfig,
|
|
21
|
-
createDetectEntrypoint,
|
|
22
|
-
createProject,
|
|
23
|
-
detectProjects,
|
|
24
|
-
fetchProjectsForRepoUrl,
|
|
25
|
-
findProjectsFromPath,
|
|
26
|
-
findRepoRoot,
|
|
27
|
-
findSourceVercelConfigFile,
|
|
28
|
-
getGitConfigPath,
|
|
29
|
-
getLinkedProject,
|
|
30
|
-
getProjectByNameOrId,
|
|
31
|
-
getRemoteUrls,
|
|
32
|
-
getServicesConfigWriteBlocker,
|
|
33
|
-
getVercelDirectory,
|
|
34
|
-
humanizePath,
|
|
35
|
-
isDirectory,
|
|
36
|
-
linkFolderToProject,
|
|
37
|
-
linkRepoProject,
|
|
38
|
-
parseGitConfig,
|
|
39
|
-
parseRepoUrl,
|
|
40
|
-
pluckRemoteUrls,
|
|
41
|
-
printAlignedLabel,
|
|
42
|
-
pull,
|
|
43
|
-
readJSONFile,
|
|
44
|
-
require_dist3 as require_dist,
|
|
45
|
-
require_frameworks,
|
|
46
|
-
require_lib,
|
|
47
|
-
require_slugify,
|
|
48
|
-
resolveGitRemote,
|
|
49
|
-
selectAndParseRemoteUrl,
|
|
50
|
-
selectOrg,
|
|
51
|
-
writeServicesConfig
|
|
52
|
-
} from "./chunk-3R5JGMHV.js";
|
|
53
|
-
import {
|
|
54
|
-
printError
|
|
55
|
-
} from "./chunk-KBEX5MYS.js";
|
|
56
|
-
import {
|
|
57
|
-
CantParseJSONFile,
|
|
58
|
-
ProjectNotFound,
|
|
59
|
-
isAPIError
|
|
60
|
-
} from "./chunk-SOFC4MLS.js";
|
|
61
|
-
import {
|
|
62
|
-
output_manager_default
|
|
63
|
-
} from "./chunk-OX7KI3LF.js";
|
|
64
|
-
import {
|
|
65
|
-
require_source
|
|
66
|
-
} from "./chunk-S7KYDPEM.js";
|
|
67
|
-
import {
|
|
68
|
-
__toESM
|
|
69
|
-
} from "./chunk-TZ2YI2VH.js";
|
|
70
|
-
|
|
71
|
-
// src/util/validate-paths.ts
|
|
72
|
-
var import_fs_extra = __toESM(require_lib(), 1);
|
|
73
|
-
var import_chalk = __toESM(require_source(), 1);
|
|
74
|
-
import { homedir } from "os";
|
|
75
|
-
import { resolve, sep } from "path";
|
|
76
|
-
async function validateRootDirectory(cwd, path2, errorSuffix = "") {
|
|
77
|
-
const pathStat = await (0, import_fs_extra.lstat)(path2).catch(() => null);
|
|
78
|
-
const suffix = errorSuffix ? ` ${errorSuffix}` : "";
|
|
79
|
-
if (!pathStat) {
|
|
80
|
-
output_manager_default.error(
|
|
81
|
-
`The provided path ${import_chalk.default.cyan(
|
|
82
|
-
`\u201C${humanizePath(path2)}\u201D`
|
|
83
|
-
)} does not exist.${suffix}`
|
|
84
|
-
);
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
if (!pathStat.isDirectory()) {
|
|
88
|
-
output_manager_default.error(
|
|
89
|
-
`The provided path ${import_chalk.default.cyan(
|
|
90
|
-
`\u201C${humanizePath(path2)}\u201D`
|
|
91
|
-
)} is a file, but expected a directory.${suffix}`
|
|
92
|
-
);
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
const base = resolve(cwd);
|
|
96
|
-
const target = resolve(path2);
|
|
97
|
-
if (target !== base && !target.startsWith(base + sep)) {
|
|
98
|
-
output_manager_default.error(
|
|
99
|
-
`The provided path ${import_chalk.default.cyan(
|
|
100
|
-
`\u201C${humanizePath(path2)}\u201D`
|
|
101
|
-
)} is outside of the project.${suffix}`
|
|
102
|
-
);
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
async function validatePaths(client, paths) {
|
|
108
|
-
if (paths.length > 1) {
|
|
109
|
-
output_manager_default.error(`Can't deploy more than one path.`);
|
|
110
|
-
return { valid: false, exitCode: 1 };
|
|
111
|
-
}
|
|
112
|
-
const path2 = paths[0];
|
|
113
|
-
const pathStat = await (0, import_fs_extra.lstat)(path2).catch(() => null);
|
|
114
|
-
if (!pathStat) {
|
|
115
|
-
output_manager_default.error(`Could not find ${import_chalk.default.cyan(`\u201C${humanizePath(path2)}\u201D`)}`);
|
|
116
|
-
return { valid: false, exitCode: 1 };
|
|
117
|
-
}
|
|
118
|
-
if (!pathStat.isDirectory()) {
|
|
119
|
-
output_manager_default.prettyError({
|
|
120
|
-
message: "Support for single file deployments has been removed.",
|
|
121
|
-
link: "https://vercel.link/no-single-file-deployments"
|
|
122
|
-
});
|
|
123
|
-
return { valid: false, exitCode: 1 };
|
|
124
|
-
}
|
|
125
|
-
if (path2 === homedir()) {
|
|
126
|
-
const shouldDeployHomeDirectory = await client.input.confirm(
|
|
127
|
-
`You are deploying your home directory. Do you want to continue?`,
|
|
128
|
-
false
|
|
129
|
-
);
|
|
130
|
-
if (!shouldDeployHomeDirectory) {
|
|
131
|
-
output_manager_default.print(`Canceled
|
|
132
|
-
`);
|
|
133
|
-
return { valid: false, exitCode: 0 };
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return { valid: true, path: path2 };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// src/util/config/read-config.ts
|
|
140
|
-
async function readConfig(dir) {
|
|
141
|
-
let pkgFilePath;
|
|
142
|
-
try {
|
|
143
|
-
const compileResult = await compileVercelConfig(dir);
|
|
144
|
-
pkgFilePath = compileResult.configPath || getLocalPathConfig(dir);
|
|
145
|
-
} catch (err) {
|
|
146
|
-
if (err instanceof Error) {
|
|
147
|
-
return err;
|
|
148
|
-
}
|
|
149
|
-
throw err;
|
|
150
|
-
}
|
|
151
|
-
const result = await readJSONFile(pkgFilePath);
|
|
152
|
-
if (result instanceof CantParseJSONFile) {
|
|
153
|
-
return result;
|
|
154
|
-
}
|
|
155
|
-
if (result) {
|
|
156
|
-
return result;
|
|
157
|
-
}
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// src/util/input/display-services.ts
|
|
162
|
-
var import_frameworks = __toESM(require_frameworks(), 1);
|
|
163
|
-
import {
|
|
164
|
-
getServiceQueueTopics,
|
|
165
|
-
isExperimentalServiceV2,
|
|
166
|
-
isQueueTriggeredService,
|
|
167
|
-
isScheduleTriggeredService,
|
|
168
|
-
isWorkflowTriggeredService
|
|
169
|
-
} from "@vercel/build-utils";
|
|
170
|
-
var chalk2 = require_source();
|
|
171
|
-
var frameworksBySlug = new Map(import_frameworks.frameworkList.map((f) => [f.slug, f]));
|
|
172
|
-
var frameworkColors = {
|
|
173
|
-
// JavaScript/TypeScript frameworks
|
|
174
|
-
nextjs: chalk2.white,
|
|
175
|
-
vite: chalk2.magenta,
|
|
176
|
-
nuxtjs: chalk2.green,
|
|
177
|
-
remix: chalk2.cyan,
|
|
178
|
-
astro: chalk2.magenta,
|
|
179
|
-
gatsby: chalk2.magenta,
|
|
180
|
-
svelte: chalk2.red,
|
|
181
|
-
sveltekit: chalk2.red,
|
|
182
|
-
solidstart: chalk2.blue,
|
|
183
|
-
angular: chalk2.red,
|
|
184
|
-
vue: chalk2.green,
|
|
185
|
-
ember: chalk2.red,
|
|
186
|
-
preact: chalk2.magenta,
|
|
187
|
-
// Python frameworks
|
|
188
|
-
fastapi: chalk2.green,
|
|
189
|
-
flask: chalk2.cyan,
|
|
190
|
-
// Node frameworks
|
|
191
|
-
express: chalk2.yellow,
|
|
192
|
-
nest: chalk2.red,
|
|
193
|
-
hono: chalk2.yellowBright
|
|
194
|
-
};
|
|
195
|
-
var runtimeColors = {
|
|
196
|
-
node: chalk2.green,
|
|
197
|
-
python: chalk2.blue,
|
|
198
|
-
go: chalk2.cyan,
|
|
199
|
-
ruby: chalk2.red,
|
|
200
|
-
rust: chalk2.yellowBright
|
|
201
|
-
};
|
|
202
|
-
function getFrameworkName(slug) {
|
|
203
|
-
if (!slug)
|
|
204
|
-
return void 0;
|
|
205
|
-
return frameworksBySlug.get(slug)?.name;
|
|
206
|
-
}
|
|
207
|
-
function formatRoutePrefix(routePrefix) {
|
|
208
|
-
if (routePrefix === "/") {
|
|
209
|
-
return "/";
|
|
210
|
-
}
|
|
211
|
-
const normalized = routePrefix.startsWith("/") ? routePrefix : `/${routePrefix}`;
|
|
212
|
-
return `${normalized}/*`;
|
|
213
|
-
}
|
|
214
|
-
var jobTriggerLabels = {
|
|
215
|
-
queue: "Job/Queue",
|
|
216
|
-
schedule: "Job/Schedule",
|
|
217
|
-
workflow: "Job/Workflow"
|
|
218
|
-
};
|
|
219
|
-
function getServiceDescriptionInfo(service) {
|
|
220
|
-
if (service.type === "worker" || service.type === "job" || service.type === "cron") {
|
|
221
|
-
const typeLabel = service.type === "worker" ? "Worker" : jobTriggerLabels[service.trigger ?? ""] ?? "Job";
|
|
222
|
-
const typeColorFn = service.type === "worker" ? chalk2.magenta : chalk2.cyan;
|
|
223
|
-
if (service.runtime) {
|
|
224
|
-
const runtimeName = service.runtime.charAt(0).toUpperCase() + service.runtime.slice(1);
|
|
225
|
-
const runtimeColorFn = runtimeColors[service.runtime] || chalk2.yellow;
|
|
226
|
-
const label = `${typeLabel}${chalk2.white("/")}${runtimeColorFn(runtimeName)}`;
|
|
227
|
-
return { label, colorFn: typeColorFn };
|
|
228
|
-
}
|
|
229
|
-
return { label: typeLabel, colorFn: typeColorFn };
|
|
230
|
-
}
|
|
231
|
-
return getFrameworkRuntimeBuilderInfo(service);
|
|
232
|
-
}
|
|
233
|
-
function getFrameworkRuntimeBuilderInfo(service) {
|
|
234
|
-
const frameworkName = getFrameworkName(service.framework);
|
|
235
|
-
if (frameworkName && service.framework) {
|
|
236
|
-
const colorFn = frameworkColors[service.framework] || chalk2.cyan;
|
|
237
|
-
return { label: frameworkName, colorFn };
|
|
238
|
-
} else if (service.runtime) {
|
|
239
|
-
const normalizedRuntime = service.runtime.toLowerCase().replace(/@.*$/, "");
|
|
240
|
-
const colorFn = runtimeColors[normalizedRuntime] || chalk2.yellow;
|
|
241
|
-
return { label: service.runtime, colorFn };
|
|
242
|
-
} else if (service.builder?.use) {
|
|
243
|
-
return { label: service.builder.use, colorFn: chalk2.magenta };
|
|
244
|
-
}
|
|
245
|
-
return { label: "unknown", colorFn: chalk2.dim };
|
|
246
|
-
}
|
|
247
|
-
function getServiceTarget(service) {
|
|
248
|
-
if (isScheduleTriggeredService(service)) {
|
|
249
|
-
return `schedule: ${service.schedule ?? "none"}`;
|
|
250
|
-
}
|
|
251
|
-
if (isQueueTriggeredService(service)) {
|
|
252
|
-
const topics = getServiceQueueTopics(service);
|
|
253
|
-
return `topics: ${topics.join(", ")}`;
|
|
254
|
-
}
|
|
255
|
-
if (isWorkflowTriggeredService(service)) {
|
|
256
|
-
return "workflow";
|
|
257
|
-
}
|
|
258
|
-
return service.routePrefix ? formatRoutePrefix(service.routePrefix) : "no route";
|
|
259
|
-
}
|
|
260
|
-
function displayDetectedServices(services) {
|
|
261
|
-
output_manager_default.print(`Detected services:
|
|
262
|
-
`);
|
|
263
|
-
const rows = services.some(isExperimentalServiceV2) ? buildServiceRowsV2(services.filter(isExperimentalServiceV2)) : buildServiceRowsV1(services);
|
|
264
|
-
const tableOutput = table(rows, { align: ["l", "l", "l", "l"], hsep: 2 });
|
|
265
|
-
output_manager_default.print(`${tableOutput}
|
|
266
|
-
`);
|
|
267
|
-
}
|
|
268
|
-
function buildServiceRowsV1(services) {
|
|
269
|
-
const outputOrder = {
|
|
270
|
-
web: 0,
|
|
271
|
-
cron: 1,
|
|
272
|
-
job: 1,
|
|
273
|
-
worker: 2
|
|
274
|
-
};
|
|
275
|
-
const sorted = [...services].sort(
|
|
276
|
-
(a, b) => (outputOrder[a.type] ?? 3) - (outputOrder[b.type] ?? 3)
|
|
277
|
-
);
|
|
278
|
-
return sorted.map((service) => {
|
|
279
|
-
const descInfo = getServiceDescriptionInfo(service);
|
|
280
|
-
const target = getServiceTarget(service);
|
|
281
|
-
return [
|
|
282
|
-
`\u2022 ${service.name}`,
|
|
283
|
-
descInfo.colorFn(`[${descInfo.label}]`),
|
|
284
|
-
chalk2.dim("\u2192"),
|
|
285
|
-
target
|
|
286
|
-
];
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
function buildServiceRowsV2(services) {
|
|
290
|
-
return services.map((service) => {
|
|
291
|
-
const descInfo = getFrameworkRuntimeBuilderInfo(service);
|
|
292
|
-
return [`\u2022 ${service.name}`, descInfo.colorFn(`[${descInfo.label}]`)];
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
function displayServicesConfigNote(configFileName = "vercel.json") {
|
|
296
|
-
output_manager_default.print(
|
|
297
|
-
`
|
|
298
|
-
${chalk2.dim(`Services are configured via ${configFileName}.`)}
|
|
299
|
-
`
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
function displayServiceErrors(errors) {
|
|
303
|
-
for (const error of errors) {
|
|
304
|
-
output_manager_default.warn(error.message);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// src/util/link/setup-and-link.ts
|
|
309
|
-
var import_fs_extra2 = __toESM(require_lib(), 1);
|
|
310
|
-
var import_fs_detectors2 = __toESM(require_dist(), 1);
|
|
311
|
-
import { join as join3, basename } from "path";
|
|
312
|
-
import { getPlatformEnv } from "@vercel/build-utils";
|
|
313
|
-
|
|
314
|
-
// src/util/input/input-project.ts
|
|
315
|
-
var import_chalk2 = __toESM(require_source(), 1);
|
|
316
|
-
var import_slugify = __toESM(require_slugify(), 1);
|
|
317
|
-
var SEARCH_ALL_PROJECTS = "search-all-projects";
|
|
318
|
-
var CREATE_NEW_PROJECT = "create-new-project";
|
|
319
|
-
var BACK_TO_PROJECT_SELECTION = Symbol("back-to-project-selection");
|
|
320
|
-
var BACK_TO_TEAM_SELECTION = Symbol("back-to-team-selection");
|
|
321
|
-
var SWITCH_GIT_REMOTE = Symbol("switch-git-remote");
|
|
322
|
-
var NO_EXISTING_PROJECTS = Symbol("no-existing-projects");
|
|
323
|
-
async function inputProjectDecision(client, defaultDecision) {
|
|
324
|
-
const createChoice = {
|
|
325
|
-
name: "Create new project",
|
|
326
|
-
value: "create"
|
|
327
|
-
};
|
|
328
|
-
const existingChoice = {
|
|
329
|
-
name: "Link existing project",
|
|
330
|
-
value: "existing"
|
|
331
|
-
};
|
|
332
|
-
return await client.input.select({
|
|
333
|
-
message: "Project?",
|
|
334
|
-
choices: defaultDecision === "existing" ? [existingChoice, createChoice] : [createChoice, existingChoice]
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
function randomNameSuffix() {
|
|
338
|
-
return Math.random().toString(36).slice(2, 6).padEnd(4, "0");
|
|
339
|
-
}
|
|
340
|
-
async function suggestNewProjectName(client, org, slugifiedName, knownTaken) {
|
|
341
|
-
let taken = knownTaken;
|
|
342
|
-
if (!taken) {
|
|
343
|
-
try {
|
|
344
|
-
const existing = await getProjectByNameOrId(
|
|
345
|
-
client,
|
|
346
|
-
slugifiedName,
|
|
347
|
-
org.id
|
|
348
|
-
);
|
|
349
|
-
taken = !(existing instanceof ProjectNotFound);
|
|
350
|
-
} catch {
|
|
351
|
-
taken = false;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
return taken ? `${slugifiedName}-${randomNameSuffix()}` : slugifiedName;
|
|
355
|
-
}
|
|
356
|
-
function promptForProjectName(client, org, defaultName, message = "Name?") {
|
|
357
|
-
return client.input.text({
|
|
358
|
-
message,
|
|
359
|
-
default: defaultName,
|
|
360
|
-
validate: async (val) => {
|
|
361
|
-
if (!val) {
|
|
362
|
-
return "Project name cannot be empty";
|
|
363
|
-
}
|
|
364
|
-
const project = await getProjectByNameOrId(client, val, org.id);
|
|
365
|
-
if (!(project instanceof ProjectNotFound)) {
|
|
366
|
-
return "Project already exists";
|
|
367
|
-
}
|
|
368
|
-
return true;
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
async function promptForProjectNameWithBack(client, org, defaultName) {
|
|
373
|
-
try {
|
|
374
|
-
return await client.withPromptBackNavigation(
|
|
375
|
-
() => promptForProjectName(
|
|
376
|
-
client,
|
|
377
|
-
org,
|
|
378
|
-
defaultName,
|
|
379
|
-
`Name? ${import_chalk2.default.dim("Press \u2191 to return to project options")}`
|
|
380
|
-
)
|
|
381
|
-
);
|
|
382
|
-
} catch (error) {
|
|
383
|
-
if (isPromptBackError(error)) {
|
|
384
|
-
return BACK_TO_PROJECT_SELECTION;
|
|
385
|
-
}
|
|
386
|
-
throw error;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
async function searchExistingProjects(client, org, allowBack) {
|
|
390
|
-
const firstPage = await client.fetch(`/v9/projects?limit=100`, { accountId: org.id });
|
|
391
|
-
const projects = firstPage.projects;
|
|
392
|
-
const hasMoreProjects = firstPage.pagination.next != null;
|
|
393
|
-
if (projects.length === 0) {
|
|
394
|
-
output_manager_default.log(
|
|
395
|
-
`No existing projects found under ${import_chalk2.default.bold(org.slug)}. Creating new project.`
|
|
396
|
-
);
|
|
397
|
-
return NO_EXISTING_PROJECTS;
|
|
398
|
-
}
|
|
399
|
-
const pageSize = 15;
|
|
400
|
-
const countHint = projects.length > pageSize ? ` ${import_chalk2.default.dim(
|
|
401
|
-
`(${hasMoreProjects ? "100+" : projects.length} projects)`
|
|
402
|
-
)}` : "";
|
|
403
|
-
return await client.input.search({
|
|
404
|
-
message: `Which project?${countHint}`,
|
|
405
|
-
pageSize,
|
|
406
|
-
source: async (term, { signal }) => {
|
|
407
|
-
const searchTerm = term?.trim();
|
|
408
|
-
let matchingProjects = projects;
|
|
409
|
-
if (searchTerm) {
|
|
410
|
-
if (hasMoreProjects) {
|
|
411
|
-
matchingProjects = (await client.fetch(
|
|
412
|
-
`/v9/projects?search=${encodeURIComponent(searchTerm)}&limit=20`,
|
|
413
|
-
{
|
|
414
|
-
accountId: org.id,
|
|
415
|
-
signal
|
|
416
|
-
}
|
|
417
|
-
)).projects;
|
|
418
|
-
} else {
|
|
419
|
-
const normalizedSearchTerm = searchTerm.toLowerCase();
|
|
420
|
-
matchingProjects = projects.filter(
|
|
421
|
-
(project) => project.name.toLowerCase().includes(normalizedSearchTerm) || project.id === searchTerm
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
const choices = matchingProjects.slice().sort((a, b) => b.updatedAt - a.updatedAt).map((project) => ({
|
|
426
|
-
name: project.name,
|
|
427
|
-
value: project
|
|
428
|
-
}));
|
|
429
|
-
if (!allowBack) {
|
|
430
|
-
return choices;
|
|
431
|
-
}
|
|
432
|
-
const backChoice = {
|
|
433
|
-
name: "Back to project options",
|
|
434
|
-
value: BACK_TO_PROJECT_SELECTION
|
|
435
|
-
};
|
|
436
|
-
if (choices.length === 0) {
|
|
437
|
-
return [backChoice];
|
|
438
|
-
}
|
|
439
|
-
if (searchTerm) {
|
|
440
|
-
return choices;
|
|
441
|
-
}
|
|
442
|
-
return [...choices, new Separator(), backChoice];
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
async function inputProject(client, org, detectedProjectName, autoConfirm = false, skipAutoDetect = false, showProjectSuggestions = false, allowTeamSelectionBack = false, repoMatches = [], gitRemoteOptions) {
|
|
447
|
-
const slugifiedName = (0, import_slugify.default)(detectedProjectName);
|
|
448
|
-
const canSwitchGitRemote = (gitRemoteOptions?.remoteNames.length ?? 0) > 1;
|
|
449
|
-
let detectedProject = null;
|
|
450
|
-
if (!skipAutoDetect && repoMatches.length === 0) {
|
|
451
|
-
output_manager_default.spinner("Searching for existing projects\u2026", 1e3);
|
|
452
|
-
const [project, slugifiedProject] = await Promise.all([
|
|
453
|
-
getProjectByNameOrId(client, detectedProjectName, org.id),
|
|
454
|
-
slugifiedName !== detectedProjectName ? getProjectByNameOrId(client, slugifiedName, org.id) : null
|
|
455
|
-
]);
|
|
456
|
-
detectedProject = !(project instanceof ProjectNotFound) ? project : !(slugifiedProject instanceof ProjectNotFound) ? slugifiedProject : null;
|
|
457
|
-
if (detectedProject && !detectedProject.id) {
|
|
458
|
-
throw new Error(`Detected linked project does not have "id".`);
|
|
459
|
-
}
|
|
460
|
-
output_manager_default.stopSpinner();
|
|
461
|
-
}
|
|
462
|
-
if (autoConfirm) {
|
|
463
|
-
if (repoMatches.length === 1) {
|
|
464
|
-
return repoMatches[0];
|
|
465
|
-
}
|
|
466
|
-
return detectedProject || detectedProjectName;
|
|
467
|
-
}
|
|
468
|
-
if (client.nonInteractive) {
|
|
469
|
-
if (detectedProject) {
|
|
470
|
-
return detectedProject;
|
|
471
|
-
}
|
|
472
|
-
const err = new Error("Confirmation required");
|
|
473
|
-
err.code = "HEADLESS";
|
|
474
|
-
throw err;
|
|
475
|
-
}
|
|
476
|
-
const slugifiedNameKnownFree = !skipAutoDetect && repoMatches.length === 0 && !detectedProject;
|
|
477
|
-
let memoizedDefaultName;
|
|
478
|
-
async function defaultNewProjectName() {
|
|
479
|
-
if (memoizedDefaultName === void 0) {
|
|
480
|
-
memoizedDefaultName = slugifiedNameKnownFree ? slugifiedName : await suggestNewProjectName(
|
|
481
|
-
client,
|
|
482
|
-
org,
|
|
483
|
-
slugifiedName,
|
|
484
|
-
detectedProject?.name === slugifiedName
|
|
485
|
-
);
|
|
486
|
-
}
|
|
487
|
-
return memoizedDefaultName;
|
|
488
|
-
}
|
|
489
|
-
let shouldLinkProject;
|
|
490
|
-
if (showProjectSuggestions && !skipAutoDetect) {
|
|
491
|
-
for (; ; ) {
|
|
492
|
-
const choices = [];
|
|
493
|
-
if (repoMatches.length > 0) {
|
|
494
|
-
choices.push(
|
|
495
|
-
...repoMatches.map((match) => ({
|
|
496
|
-
name: `${match.project.name} ${import_chalk2.default.gray("(linked by git)")}`,
|
|
497
|
-
value: match
|
|
498
|
-
})),
|
|
499
|
-
new Separator()
|
|
500
|
-
);
|
|
501
|
-
} else if (detectedProject) {
|
|
502
|
-
choices.push(
|
|
503
|
-
{
|
|
504
|
-
name: `${detectedProject.name} ${import_chalk2.default.gray("(folder name)")}`,
|
|
505
|
-
value: detectedProject
|
|
506
|
-
},
|
|
507
|
-
new Separator()
|
|
508
|
-
);
|
|
509
|
-
}
|
|
510
|
-
choices.push(
|
|
511
|
-
{
|
|
512
|
-
name: "Search all projects",
|
|
513
|
-
value: SEARCH_ALL_PROJECTS,
|
|
514
|
-
description: "Browse or search every project in this team"
|
|
515
|
-
},
|
|
516
|
-
{
|
|
517
|
-
name: "Create a new project",
|
|
518
|
-
value: CREATE_NEW_PROJECT,
|
|
519
|
-
description: `Create it under ${org.slug}`
|
|
520
|
-
}
|
|
521
|
-
);
|
|
522
|
-
if (canSwitchGitRemote) {
|
|
523
|
-
const current = gitRemoteOptions?.currentRemoteName;
|
|
524
|
-
choices.push({
|
|
525
|
-
name: "Switch Git remote",
|
|
526
|
-
value: SWITCH_GIT_REMOTE,
|
|
527
|
-
description: current ? `Suggestions are from ${current}` : "Search projects linked to a different remote"
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
if (allowTeamSelectionBack) {
|
|
531
|
-
choices.push({
|
|
532
|
-
name: "Choose a different team",
|
|
533
|
-
value: BACK_TO_TEAM_SELECTION,
|
|
534
|
-
description: "Return to team selection"
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
const selected = await client.input.select({
|
|
538
|
-
message: "Which project?",
|
|
539
|
-
choices
|
|
540
|
-
});
|
|
541
|
-
if (selected === BACK_TO_TEAM_SELECTION) {
|
|
542
|
-
return BACK_TO_TEAM_SELECTION;
|
|
543
|
-
}
|
|
544
|
-
if (selected === SWITCH_GIT_REMOTE) {
|
|
545
|
-
return SWITCH_GIT_REMOTE;
|
|
546
|
-
}
|
|
547
|
-
if (selected === CREATE_NEW_PROJECT) {
|
|
548
|
-
const projectName = await promptForProjectNameWithBack(
|
|
549
|
-
client,
|
|
550
|
-
org,
|
|
551
|
-
await defaultNewProjectName()
|
|
552
|
-
);
|
|
553
|
-
if (projectName === BACK_TO_PROJECT_SELECTION) {
|
|
554
|
-
continue;
|
|
555
|
-
}
|
|
556
|
-
return projectName;
|
|
557
|
-
}
|
|
558
|
-
if (selected !== SEARCH_ALL_PROJECTS) {
|
|
559
|
-
return selected;
|
|
560
|
-
}
|
|
561
|
-
const existingProject = await searchExistingProjects(client, org, true);
|
|
562
|
-
if (existingProject === BACK_TO_PROJECT_SELECTION) {
|
|
563
|
-
continue;
|
|
564
|
-
}
|
|
565
|
-
if (existingProject === NO_EXISTING_PROJECTS) {
|
|
566
|
-
const projectName = await promptForProjectNameWithBack(
|
|
567
|
-
client,
|
|
568
|
-
org,
|
|
569
|
-
slugifiedName
|
|
570
|
-
);
|
|
571
|
-
if (projectName === BACK_TO_PROJECT_SELECTION) {
|
|
572
|
-
continue;
|
|
573
|
-
}
|
|
574
|
-
return projectName;
|
|
575
|
-
}
|
|
576
|
-
return existingProject;
|
|
577
|
-
}
|
|
578
|
-
} else if (!detectedProject) {
|
|
579
|
-
const decision = await inputProjectDecision(
|
|
580
|
-
client,
|
|
581
|
-
skipAutoDetect ? "existing" : "create"
|
|
582
|
-
);
|
|
583
|
-
shouldLinkProject = decision === "existing";
|
|
584
|
-
} else {
|
|
585
|
-
output_manager_default.print(` ${import_chalk2.default.bold("Found existing project")}
|
|
586
|
-
`);
|
|
587
|
-
printAlignedLabel("Project", `${org.slug}/${detectedProject.name}`);
|
|
588
|
-
if (await client.input.confirm(`Link directory to project?`, true)) {
|
|
589
|
-
return detectedProject;
|
|
590
|
-
}
|
|
591
|
-
const decision = await inputProjectDecision(client, "existing");
|
|
592
|
-
shouldLinkProject = decision === "existing";
|
|
593
|
-
}
|
|
594
|
-
if (shouldLinkProject) {
|
|
595
|
-
const existingProject = await searchExistingProjects(client, org, false);
|
|
596
|
-
if (existingProject !== NO_EXISTING_PROJECTS && existingProject !== BACK_TO_PROJECT_SELECTION) {
|
|
597
|
-
return existingProject;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
return await promptForProjectName(client, org, await defaultNewProjectName());
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
// src/util/input/input-root-directory.ts
|
|
604
|
-
var import_chalk3 = __toESM(require_source(), 1);
|
|
605
|
-
import { normalizePath } from "@vercel/build-utils";
|
|
606
|
-
import path from "path";
|
|
607
|
-
async function inputRootDirectory(client, cwd, autoConfirm = false) {
|
|
608
|
-
if (autoConfirm) {
|
|
609
|
-
return null;
|
|
610
|
-
}
|
|
611
|
-
while (true) {
|
|
612
|
-
const rootDirectory = await client.input.text({
|
|
613
|
-
message: `Code directory?`,
|
|
614
|
-
transformer: (input) => {
|
|
615
|
-
return `${import_chalk3.default.dim(`./`)}${input}`;
|
|
616
|
-
}
|
|
617
|
-
});
|
|
618
|
-
if (!rootDirectory) {
|
|
619
|
-
return null;
|
|
620
|
-
}
|
|
621
|
-
const normal = path.normalize(rootDirectory);
|
|
622
|
-
if (normal === "." || normal === "./") {
|
|
623
|
-
return null;
|
|
624
|
-
}
|
|
625
|
-
const fullPath = path.join(cwd, normal);
|
|
626
|
-
if (await validateRootDirectory(
|
|
627
|
-
cwd,
|
|
628
|
-
fullPath,
|
|
629
|
-
"Please choose a different one."
|
|
630
|
-
) === false) {
|
|
631
|
-
continue;
|
|
632
|
-
}
|
|
633
|
-
return normalizePath(normal);
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
// src/util/input/edit-project-settings.ts
|
|
638
|
-
var import_chalk4 = __toESM(require_source(), 1);
|
|
639
|
-
var import_frameworks2 = __toESM(require_frameworks(), 1);
|
|
640
|
-
|
|
641
|
-
// src/util/is-setting-value.ts
|
|
642
|
-
function isSettingValue(setting) {
|
|
643
|
-
return setting && typeof setting.value === "string";
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
// src/util/input/edit-project-settings.ts
|
|
647
|
-
var settingMap = {
|
|
648
|
-
buildCommand: "Build Command",
|
|
649
|
-
devCommand: "Development Command",
|
|
650
|
-
commandForIgnoringBuildStep: "Ignore Command",
|
|
651
|
-
installCommand: "Install Command",
|
|
652
|
-
outputDirectory: "Output Directory",
|
|
653
|
-
framework: "Framework"
|
|
654
|
-
};
|
|
655
|
-
var settingKeys = Object.keys(settingMap).sort();
|
|
656
|
-
async function editProjectSettings(client, projectSettings, framework, autoConfirm, localConfigurationOverrides, configFileName = "vercel.json") {
|
|
657
|
-
const settings = Object.assign(
|
|
658
|
-
{
|
|
659
|
-
buildCommand: null,
|
|
660
|
-
devCommand: null,
|
|
661
|
-
framework: null,
|
|
662
|
-
commandForIgnoringBuildStep: null,
|
|
663
|
-
installCommand: null,
|
|
664
|
-
outputDirectory: null
|
|
665
|
-
},
|
|
666
|
-
projectSettings
|
|
667
|
-
);
|
|
668
|
-
const hasLocalConfigurationOverrides = localConfigurationOverrides && Object.values(localConfigurationOverrides ?? {}).some(Boolean);
|
|
669
|
-
if (hasLocalConfigurationOverrides) {
|
|
670
|
-
for (const setting of settingKeys) {
|
|
671
|
-
const localConfigValue = localConfigurationOverrides[setting];
|
|
672
|
-
if (localConfigValue)
|
|
673
|
-
settings[setting] = localConfigValue;
|
|
674
|
-
}
|
|
675
|
-
output_manager_default.print(` Local settings detected in ${configFileName}:
|
|
676
|
-
`);
|
|
677
|
-
for (const setting of settingKeys) {
|
|
678
|
-
const override = localConfigurationOverrides[setting];
|
|
679
|
-
if (override) {
|
|
680
|
-
output_manager_default.print(
|
|
681
|
-
` ${import_chalk4.default.dim(
|
|
682
|
-
`${import_chalk4.default.bold(`${settingMap[setting]}:`)} ${override}`
|
|
683
|
-
)}
|
|
684
|
-
`
|
|
685
|
-
);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
if (localConfigurationOverrides.framework) {
|
|
689
|
-
const overrideFramework = import_frameworks2.frameworkList.find(
|
|
690
|
-
(f) => f.slug === localConfigurationOverrides.framework
|
|
691
|
-
);
|
|
692
|
-
if (overrideFramework) {
|
|
693
|
-
framework = overrideFramework;
|
|
694
|
-
output_manager_default.print(
|
|
695
|
-
` Merging default Project Settings for ${framework.name}. Previously listed overrides are prioritized.
|
|
696
|
-
`
|
|
697
|
-
);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
if (!framework) {
|
|
702
|
-
settings.framework = null;
|
|
703
|
-
return settings;
|
|
704
|
-
}
|
|
705
|
-
output_manager_default.print("\n");
|
|
706
|
-
if (!framework.slug) {
|
|
707
|
-
output_manager_default.print(` No framework detected. Default Project Settings:
|
|
708
|
-
`);
|
|
709
|
-
} else {
|
|
710
|
-
const buildCmd = framework.settings.buildCommand?.value ?? null;
|
|
711
|
-
const outputSetting = framework.settings.outputDirectory;
|
|
712
|
-
const outputDir = outputSetting ? isSettingValue(outputSetting) ? outputSetting.value : outputSetting.placeholder : null;
|
|
713
|
-
const inline = [
|
|
714
|
-
buildCmd ? `${settingMap.buildCommand}: ${buildCmd}` : null,
|
|
715
|
-
outputDir ? `${settingMap.outputDirectory}: ${outputDir}` : null
|
|
716
|
-
].filter(Boolean);
|
|
717
|
-
const detail = inline.length ? import_chalk4.default.dim(` (${inline.join(", ")})`) : "";
|
|
718
|
-
output_manager_default.print(` ${import_chalk4.default.bold("Detected")} ${framework.name}${detail}
|
|
719
|
-
`);
|
|
720
|
-
}
|
|
721
|
-
settings.framework = framework.slug;
|
|
722
|
-
if (!framework.slug) {
|
|
723
|
-
for (const setting of settingKeys) {
|
|
724
|
-
if (setting === "framework" || setting === "commandForIgnoringBuildStep") {
|
|
725
|
-
continue;
|
|
726
|
-
}
|
|
727
|
-
const defaultSetting = framework.settings[setting];
|
|
728
|
-
const override = localConfigurationOverrides?.[setting];
|
|
729
|
-
if (!override && defaultSetting) {
|
|
730
|
-
output_manager_default.print(
|
|
731
|
-
` ${import_chalk4.default.dim(
|
|
732
|
-
`${import_chalk4.default.bold(`${settingMap[setting]}:`)} ${isSettingValue(defaultSetting) ? defaultSetting.value : import_chalk4.default.italic(`${defaultSetting.placeholder}`)}`
|
|
733
|
-
)}
|
|
734
|
-
`
|
|
735
|
-
);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
if (autoConfirm || !await client.input.confirm("Customize settings?", false)) {
|
|
740
|
-
return settings;
|
|
741
|
-
}
|
|
742
|
-
const choices = settingKeys.reduce(
|
|
743
|
-
(acc, setting) => {
|
|
744
|
-
const skip = setting === "framework" || setting === "commandForIgnoringBuildStep" || setting === "installCommand" || localConfigurationOverrides?.[setting];
|
|
745
|
-
if (skip)
|
|
746
|
-
return acc;
|
|
747
|
-
return [...acc, { name: settingMap[setting], value: setting }];
|
|
748
|
-
},
|
|
749
|
-
[]
|
|
750
|
-
);
|
|
751
|
-
const settingFields = await client.input.checkbox({
|
|
752
|
-
message: "Which settings would you like to overwrite (select multiple)?",
|
|
753
|
-
choices
|
|
754
|
-
});
|
|
755
|
-
for (const setting of settingFields) {
|
|
756
|
-
const field = settingMap[setting];
|
|
757
|
-
settings[setting] = await client.input.text({
|
|
758
|
-
message: `${import_chalk4.default.bold(field)}?`
|
|
759
|
-
});
|
|
760
|
-
}
|
|
761
|
-
return settings;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
// src/util/link/setup-and-link.ts
|
|
765
|
-
var import_frameworks3 = __toESM(require_frameworks(), 1);
|
|
766
|
-
|
|
767
|
-
// src/util/input/vercel-auth.ts
|
|
768
|
-
var import_chalk5 = __toESM(require_source(), 1);
|
|
769
|
-
var DEFAULT_VERCEL_AUTH_SETTING = "standard";
|
|
770
|
-
var OPTIONS = {
|
|
771
|
-
message: `What setting do you want to use for Vercel Authentication?`,
|
|
772
|
-
default: DEFAULT_VERCEL_AUTH_SETTING,
|
|
773
|
-
choices: [
|
|
774
|
-
{
|
|
775
|
-
description: "Standard Protection (recommended)",
|
|
776
|
-
name: "standard",
|
|
777
|
-
value: "standard"
|
|
778
|
-
},
|
|
779
|
-
{
|
|
780
|
-
description: "No Protection (all deployments will be public)",
|
|
781
|
-
name: "none",
|
|
782
|
-
value: "none"
|
|
783
|
-
}
|
|
784
|
-
]
|
|
785
|
-
};
|
|
786
|
-
async function vercelAuth(client, {
|
|
787
|
-
autoConfirm = false
|
|
788
|
-
}) {
|
|
789
|
-
if (autoConfirm || await client.input.confirm(
|
|
790
|
-
`Want to use the default Deployment Protection settings? ${import_chalk5.default.dim(`(Vercel Authentication: Standard Protection)`)}`,
|
|
791
|
-
true
|
|
792
|
-
)) {
|
|
793
|
-
return DEFAULT_VERCEL_AUTH_SETTING;
|
|
794
|
-
}
|
|
795
|
-
const vercelAuth2 = await client.input.select(OPTIONS);
|
|
796
|
-
return vercelAuth2;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
// src/util/link/services-setup.ts
|
|
800
|
-
var import_fs_detectors = __toESM(require_dist(), 1);
|
|
801
|
-
import { normalizePath as normalizePath2 } from "@vercel/build-utils";
|
|
802
|
-
import { join, relative } from "path";
|
|
803
|
-
var SERVICES_DOCS_URL = "https://vercel.com/docs/services";
|
|
804
|
-
var INFERRED_SERVICES_PROMPT = "Multiple services were detected. How would you like to set up this project?";
|
|
805
|
-
async function getServicesSetupState(workPath) {
|
|
806
|
-
const detectServicesResult = await (0, import_fs_detectors.detectServices)({
|
|
807
|
-
fs: new import_fs_detectors.LocalFileSystemDetector(workPath),
|
|
808
|
-
detectEntrypoint: createDetectEntrypoint(workPath)
|
|
809
|
-
});
|
|
810
|
-
const hasConfiguredServices = detectServicesResult.resolved?.source === "configured";
|
|
811
|
-
const inferredServices = hasConfiguredServices ? null : detectServicesResult.inferred;
|
|
812
|
-
const inferredServicesWriteBlocker = inferredServices ? await getServicesConfigWriteBlocker(workPath, inferredServices.config) : null;
|
|
813
|
-
return {
|
|
814
|
-
detectServicesResult,
|
|
815
|
-
hasConfiguredServices,
|
|
816
|
-
inferredServices,
|
|
817
|
-
inferredServicesWriteBlocker
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
function displayConfiguredServicesSetup(detectServicesResult, configFileName = "vercel.json") {
|
|
821
|
-
const v1Services = detectServicesResult.services.filter(
|
|
822
|
-
import_fs_detectors.isExperimentalService
|
|
823
|
-
);
|
|
824
|
-
if (v1Services.length > 0) {
|
|
825
|
-
displayDetectedServices(v1Services);
|
|
826
|
-
}
|
|
827
|
-
if (detectServicesResult.errors.length > 0) {
|
|
828
|
-
displayServiceErrors(detectServicesResult.errors);
|
|
829
|
-
}
|
|
830
|
-
displayServicesConfigNote(configFileName);
|
|
831
|
-
}
|
|
832
|
-
function formatDetectedServicesSummary(services) {
|
|
833
|
-
if (services.length === 0) {
|
|
834
|
-
return "";
|
|
835
|
-
}
|
|
836
|
-
if (services.length === 1) {
|
|
837
|
-
return `"${services[0].name}"`;
|
|
838
|
-
}
|
|
839
|
-
if (services.length === 2) {
|
|
840
|
-
return `"${services[0].name}" + "${services[1].name}"`;
|
|
841
|
-
}
|
|
842
|
-
const othersCount = services.length - 2;
|
|
843
|
-
return `"${services[0].name}" + "${services[1].name}" + ${othersCount} ${othersCount === 1 ? "other" : "others"}`;
|
|
844
|
-
}
|
|
845
|
-
function toProjectRootDirectory(projectPath, selectedPath) {
|
|
846
|
-
const rootDirectory = normalizePath2(relative(projectPath, selectedPath));
|
|
847
|
-
return rootDirectory === "" ? null : rootDirectory;
|
|
848
|
-
}
|
|
849
|
-
async function promptForInferredServicesSetup({
|
|
850
|
-
client,
|
|
851
|
-
autoConfirm,
|
|
852
|
-
nonInteractive,
|
|
853
|
-
workPath,
|
|
854
|
-
inferred,
|
|
855
|
-
inferredWriteBlocker,
|
|
856
|
-
allowChooseDifferentProjectDirectory = false
|
|
857
|
-
}) {
|
|
858
|
-
if (!inferred) {
|
|
859
|
-
return null;
|
|
860
|
-
}
|
|
861
|
-
if (inferredWriteBlocker) {
|
|
862
|
-
output_manager_default.warn(
|
|
863
|
-
`Multiple services were detected, but your existing project config uses \`${inferredWriteBlocker}\`. To deploy multiple services in one project, see ${output_manager_default.link("Services", SERVICES_DOCS_URL)}.`
|
|
864
|
-
);
|
|
865
|
-
return null;
|
|
866
|
-
}
|
|
867
|
-
displayDetectedServices(inferred.services);
|
|
868
|
-
let choice = null;
|
|
869
|
-
if (autoConfirm) {
|
|
870
|
-
choice = { type: "services" };
|
|
871
|
-
} else if (!nonInteractive) {
|
|
872
|
-
const webServices = inferred.services.filter(
|
|
873
|
-
(service) => (0, import_fs_detectors.isExperimentalService)(service) ? service.type === "web" : true
|
|
874
|
-
);
|
|
875
|
-
const choices = [
|
|
876
|
-
{
|
|
877
|
-
name: `Set up project with all detected services: ${formatDetectedServicesSummary(
|
|
878
|
-
inferred.services
|
|
879
|
-
)}`,
|
|
880
|
-
value: "services"
|
|
881
|
-
},
|
|
882
|
-
...webServices.map((service, index) => ({
|
|
883
|
-
name: `Set up project with "${service.name}"`,
|
|
884
|
-
value: `single-app:${index}`
|
|
885
|
-
})),
|
|
886
|
-
...allowChooseDifferentProjectDirectory ? [
|
|
887
|
-
{
|
|
888
|
-
name: "Choose a different root directory",
|
|
889
|
-
value: "project-directory"
|
|
890
|
-
}
|
|
891
|
-
] : []
|
|
892
|
-
];
|
|
893
|
-
const selected = await client.input.select({
|
|
894
|
-
message: INFERRED_SERVICES_PROMPT,
|
|
895
|
-
choices
|
|
896
|
-
});
|
|
897
|
-
if (selected === "services") {
|
|
898
|
-
choice = { type: "services" };
|
|
899
|
-
} else if (selected === "project-directory") {
|
|
900
|
-
choice = { type: "project-directory" };
|
|
901
|
-
} else if (typeof selected === "string" && selected.startsWith("single-app:")) {
|
|
902
|
-
const index = Number.parseInt(selected.slice("single-app:".length), 10);
|
|
903
|
-
const service = webServices[index];
|
|
904
|
-
if (service) {
|
|
905
|
-
const serviceRoot = (0, import_fs_detectors.isExperimentalServiceV2)(service) ? service.root : service.workspace;
|
|
906
|
-
choice = {
|
|
907
|
-
type: "single-app",
|
|
908
|
-
selectedPath: serviceRoot === "." ? workPath : join(workPath, serviceRoot)
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
if (choice?.type !== "services") {
|
|
914
|
-
return choice;
|
|
915
|
-
}
|
|
916
|
-
const { configFileName } = await writeServicesConfig(
|
|
917
|
-
workPath,
|
|
918
|
-
inferred.config
|
|
919
|
-
);
|
|
920
|
-
output_manager_default.print(` Added services configuration to ${configFileName}.
|
|
921
|
-
`);
|
|
922
|
-
return { type: "services" };
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
// src/util/projects/search-project-across-teams.ts
|
|
926
|
-
var import_slugify2 = __toESM(require_slugify(), 1);
|
|
927
|
-
import { join as join2, relative as relative2 } from "path";
|
|
928
|
-
async function searchProjectsByRepoRoot({
|
|
929
|
-
client,
|
|
930
|
-
cwd,
|
|
931
|
-
gitProjectName,
|
|
932
|
-
orgs,
|
|
933
|
-
remoteName
|
|
934
|
-
}) {
|
|
935
|
-
const empty = { matches: [], remoteNames: [] };
|
|
936
|
-
const rootPath = await findRepoRoot(cwd);
|
|
937
|
-
if (!rootPath) {
|
|
938
|
-
return empty;
|
|
939
|
-
}
|
|
940
|
-
const gitConfigPath = getGitConfigPath({ cwd: rootPath }) ?? join2(rootPath, ".git/config");
|
|
941
|
-
const remoteUrls = await getRemoteUrls(gitConfigPath);
|
|
942
|
-
const remoteNames = remoteUrls ? Object.keys(remoteUrls).sort() : [];
|
|
943
|
-
let remote;
|
|
944
|
-
try {
|
|
945
|
-
remote = await resolveGitRemote(client, rootPath, {
|
|
946
|
-
yes: true,
|
|
947
|
-
existingRemoteName: remoteName
|
|
948
|
-
});
|
|
949
|
-
} catch (error) {
|
|
950
|
-
if (isPromptCanceledError(error)) {
|
|
951
|
-
throw error;
|
|
952
|
-
}
|
|
953
|
-
output_manager_default.debug(`Failed to resolve Git remote for project search: ${error}`);
|
|
954
|
-
return { matches: [], remoteNames };
|
|
955
|
-
}
|
|
956
|
-
if (!remote) {
|
|
957
|
-
return { matches: [], remoteNames };
|
|
958
|
-
}
|
|
959
|
-
const relativePath = relative2(rootPath, cwd);
|
|
960
|
-
const results = await Promise.all(
|
|
961
|
-
orgs.map(async (org) => {
|
|
962
|
-
try {
|
|
963
|
-
const projects = await fetchProjectsForRepoUrl(
|
|
964
|
-
client,
|
|
965
|
-
remote.repoUrl,
|
|
966
|
-
org.id
|
|
967
|
-
);
|
|
968
|
-
const repoProjectConfigs = projects.filter(
|
|
969
|
-
(project) => !gitProjectName || project.id === gitProjectName || project.name === gitProjectName
|
|
970
|
-
).map((project) => ({
|
|
971
|
-
id: project.id,
|
|
972
|
-
name: project.name,
|
|
973
|
-
directory: project.rootDirectory || ".",
|
|
974
|
-
orgId: org.id
|
|
975
|
-
}));
|
|
976
|
-
const matchingProjects = findProjectsFromPath(
|
|
977
|
-
repoProjectConfigs,
|
|
978
|
-
relativePath
|
|
979
|
-
);
|
|
980
|
-
return matchingProjects.map((match) => {
|
|
981
|
-
const project = projects.find((p) => p.id === match.id);
|
|
982
|
-
if (!project) {
|
|
983
|
-
return null;
|
|
984
|
-
}
|
|
985
|
-
return {
|
|
986
|
-
project,
|
|
987
|
-
org,
|
|
988
|
-
reason: "repo-root",
|
|
989
|
-
repo: {
|
|
990
|
-
...remote,
|
|
991
|
-
directory: match.directory
|
|
992
|
-
}
|
|
993
|
-
};
|
|
994
|
-
}).filter(Boolean);
|
|
995
|
-
} catch (error) {
|
|
996
|
-
if (isPromptCanceledError(error)) {
|
|
997
|
-
throw error;
|
|
998
|
-
}
|
|
999
|
-
output_manager_default.debug(
|
|
1000
|
-
`Failed to search Git-linked projects under ${org.slug}: ${error}`
|
|
1001
|
-
);
|
|
1002
|
-
return [];
|
|
1003
|
-
}
|
|
1004
|
-
})
|
|
1005
|
-
);
|
|
1006
|
-
return {
|
|
1007
|
-
matches: results.flat(),
|
|
1008
|
-
remote,
|
|
1009
|
-
remoteNames
|
|
1010
|
-
};
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
// src/util/link/setup-and-link.ts
|
|
1014
|
-
function isCrossTeamMatch(value) {
|
|
1015
|
-
return typeof value === "object" && value !== null && "project" in value && "org" in value && "reason" in value;
|
|
1016
|
-
}
|
|
1017
|
-
async function selectOrgForLink(client, autoConfirm, searchable = false, meta) {
|
|
1018
|
-
try {
|
|
1019
|
-
return await selectOrg(
|
|
1020
|
-
client,
|
|
1021
|
-
"Which team?",
|
|
1022
|
-
autoConfirm,
|
|
1023
|
-
searchable,
|
|
1024
|
-
meta
|
|
1025
|
-
);
|
|
1026
|
-
} catch (err) {
|
|
1027
|
-
if (isAPIError(err)) {
|
|
1028
|
-
if (err.code === "NOT_AUTHORIZED") {
|
|
1029
|
-
output_manager_default.prettyError(err);
|
|
1030
|
-
return { status: "error", exitCode: 1, reason: "NOT_AUTHORIZED" };
|
|
1031
|
-
}
|
|
1032
|
-
if (err.code === "TEAM_DELETED") {
|
|
1033
|
-
output_manager_default.prettyError(err);
|
|
1034
|
-
return { status: "error", exitCode: 1, reason: "TEAM_DELETED" };
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
throw err;
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
function isErrnoException(err) {
|
|
1041
|
-
return err instanceof Error && typeof err.code === "string";
|
|
1042
|
-
}
|
|
1043
|
-
async function hasWorkspaces(cwd) {
|
|
1044
|
-
try {
|
|
1045
|
-
const fs = new import_fs_detectors2.LocalFileSystemDetector(cwd);
|
|
1046
|
-
const workspaces = await (0, import_fs_detectors2.getWorkspaces)({ fs });
|
|
1047
|
-
return workspaces.length > 0;
|
|
1048
|
-
} catch (err) {
|
|
1049
|
-
if (isErrnoException(err) && err.code && ["ENOENT", "EACCES", "ENOTDIR"].includes(err.code)) {
|
|
1050
|
-
output_manager_default.debug(`getWorkspaces failed for ${cwd}: ${err}`);
|
|
1051
|
-
return false;
|
|
1052
|
-
}
|
|
1053
|
-
throw err;
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
async function shouldPromptForRootDirectory(opts) {
|
|
1057
|
-
if (opts.servicesChoice?.type === "project-directory") {
|
|
1058
|
-
return true;
|
|
1059
|
-
}
|
|
1060
|
-
if (await hasWorkspaces(opts.path)) {
|
|
1061
|
-
return true;
|
|
1062
|
-
}
|
|
1063
|
-
try {
|
|
1064
|
-
const detected = await detectProjects(opts.path);
|
|
1065
|
-
const frameworksAtRoot = detected.get("") ?? [];
|
|
1066
|
-
return frameworksAtRoot.length === 0;
|
|
1067
|
-
} catch (err) {
|
|
1068
|
-
output_manager_default.debug(`detectProjects failed at root: ${err}`);
|
|
1069
|
-
return true;
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
async function maybePullEnvAfterLink(client, path2, autoConfirm, pullEnv) {
|
|
1073
|
-
if (!pullEnv || !client.stdin.isTTY || client.nonInteractive) {
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
output_manager_default.print("\n");
|
|
1077
|
-
const pullEnvConfirmed = autoConfirm || await client.input.confirm(
|
|
1078
|
-
"Pull development environment variables into .env.local?",
|
|
1079
|
-
true
|
|
1080
|
-
);
|
|
1081
|
-
if (!pullEnvConfirmed) {
|
|
1082
|
-
return;
|
|
1083
|
-
}
|
|
1084
|
-
const originalCwd = client.cwd;
|
|
1085
|
-
try {
|
|
1086
|
-
client.cwd = path2;
|
|
1087
|
-
const args = autoConfirm ? ["--yes"] : [];
|
|
1088
|
-
const exitCode = await pull(client, args, "vercel-cli:link");
|
|
1089
|
-
if (exitCode !== 0) {
|
|
1090
|
-
output_manager_default.error(
|
|
1091
|
-
"Failed to pull environment variables. You can run `vc env pull` manually."
|
|
1092
|
-
);
|
|
1093
|
-
}
|
|
1094
|
-
} catch (_error) {
|
|
1095
|
-
output_manager_default.error(
|
|
1096
|
-
"Failed to pull environment variables. You can run `vc env pull` manually."
|
|
1097
|
-
);
|
|
1098
|
-
} finally {
|
|
1099
|
-
client.cwd = originalCwd;
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
async function linkCrossTeamMatch({
|
|
1103
|
-
client,
|
|
1104
|
-
path: path2,
|
|
1105
|
-
match,
|
|
1106
|
-
successEmoji,
|
|
1107
|
-
autoConfirm,
|
|
1108
|
-
pullEnv
|
|
1109
|
-
}) {
|
|
1110
|
-
client.config.currentTeam = match.org.type === "team" ? match.org.id : void 0;
|
|
1111
|
-
if (match.reason === "repo-root" && match.repo) {
|
|
1112
|
-
await linkRepoProject(client, path2, {
|
|
1113
|
-
project: match.project,
|
|
1114
|
-
orgId: match.org.id,
|
|
1115
|
-
orgSlug: match.org.slug,
|
|
1116
|
-
remoteName: match.repo.remoteName,
|
|
1117
|
-
successEmoji
|
|
1118
|
-
});
|
|
1119
|
-
await maybePullEnvAfterLink(client, path2, autoConfirm, pullEnv);
|
|
1120
|
-
return {
|
|
1121
|
-
status: "linked",
|
|
1122
|
-
org: match.org,
|
|
1123
|
-
project: match.project,
|
|
1124
|
-
repoRoot: match.repo.rootPath
|
|
1125
|
-
};
|
|
1126
|
-
}
|
|
1127
|
-
await linkFolderToProject(
|
|
1128
|
-
client,
|
|
1129
|
-
path2,
|
|
1130
|
-
{ projectId: match.project.id, orgId: match.org.id },
|
|
1131
|
-
match.project.name,
|
|
1132
|
-
match.org.slug,
|
|
1133
|
-
successEmoji,
|
|
1134
|
-
autoConfirm,
|
|
1135
|
-
pullEnv
|
|
1136
|
-
);
|
|
1137
|
-
return { status: "linked", org: match.org, project: match.project };
|
|
1138
|
-
}
|
|
1139
|
-
async function setupAndLink(client, path2, {
|
|
1140
|
-
autoConfirm = false,
|
|
1141
|
-
forceDelete = false,
|
|
1142
|
-
link,
|
|
1143
|
-
selectedOrg,
|
|
1144
|
-
successEmoji = "link",
|
|
1145
|
-
projectName,
|
|
1146
|
-
nonInteractive = false,
|
|
1147
|
-
pullEnv = true,
|
|
1148
|
-
v0
|
|
1149
|
-
}) {
|
|
1150
|
-
const { config } = client;
|
|
1151
|
-
const gitProjectName = projectName;
|
|
1152
|
-
projectName = projectName ?? basename(path2);
|
|
1153
|
-
if (!isDirectory(path2)) {
|
|
1154
|
-
output_manager_default.error(`Expected directory but found file: ${path2}`);
|
|
1155
|
-
return { status: "error", exitCode: 1, reason: "PATH_IS_FILE" };
|
|
1156
|
-
}
|
|
1157
|
-
if (!link) {
|
|
1158
|
-
link = await getLinkedProject(client, { cwd: path2 });
|
|
1159
|
-
}
|
|
1160
|
-
const isTTY = client.stdin.isTTY;
|
|
1161
|
-
let rootDirectory = null;
|
|
1162
|
-
let newProjectName;
|
|
1163
|
-
let org = selectedOrg;
|
|
1164
|
-
if (!forceDelete && link.status === "linked") {
|
|
1165
|
-
return link;
|
|
1166
|
-
}
|
|
1167
|
-
if (getPlatformEnv("ORG_ID") && getPlatformEnv("PROJECT_ID")) {
|
|
1168
|
-
const envLink = await getLinkedProject(client, { cwd: path2 });
|
|
1169
|
-
if (envLink.status === "error") {
|
|
1170
|
-
return envLink;
|
|
1171
|
-
}
|
|
1172
|
-
if (envLink.status === "linked") {
|
|
1173
|
-
config.currentTeam = envLink.org.type === "team" ? envLink.org.id : void 0;
|
|
1174
|
-
output_manager_default.print("\n");
|
|
1175
|
-
printAlignedLabel("Directory", humanizePath(path2));
|
|
1176
|
-
printAlignedLabel("Source", "VERCEL_ORG_ID and VERCEL_PROJECT_ID");
|
|
1177
|
-
output_manager_default.print("\n");
|
|
1178
|
-
printAlignedLabel(
|
|
1179
|
-
"Linked",
|
|
1180
|
-
`${envLink.org.slug}/${envLink.project.name}`,
|
|
1181
|
-
{ gutter: "\u2713" }
|
|
1182
|
-
);
|
|
1183
|
-
return envLink;
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
if (!isTTY && !autoConfirm && !nonInteractive) {
|
|
1187
|
-
return { status: "error", exitCode: 1, reason: "HEADLESS" };
|
|
1188
|
-
}
|
|
1189
|
-
if (!org && (nonInteractive || !isTTY)) {
|
|
1190
|
-
const resolved = await selectOrgForLink(client, autoConfirm);
|
|
1191
|
-
if ("status" in resolved) {
|
|
1192
|
-
return resolved;
|
|
1193
|
-
}
|
|
1194
|
-
org = resolved;
|
|
1195
|
-
}
|
|
1196
|
-
if (forceDelete) {
|
|
1197
|
-
const vercelDir = getVercelDirectory(path2);
|
|
1198
|
-
(0, import_fs_extra2.remove)(join3(vercelDir, VERCEL_DIR_README));
|
|
1199
|
-
(0, import_fs_extra2.remove)(join3(vercelDir, VERCEL_DIR_PROJECT));
|
|
1200
|
-
}
|
|
1201
|
-
output_manager_default.print("\n");
|
|
1202
|
-
printAlignedLabel("Directory", humanizePath(path2));
|
|
1203
|
-
output_manager_default.print("\n");
|
|
1204
|
-
const interactive = isTTY && !nonInteractive;
|
|
1205
|
-
const searchableTeamPicker = interactive;
|
|
1206
|
-
const showProjectSuggestions = interactive && !gitProjectName;
|
|
1207
|
-
let projectOrNewProjectName;
|
|
1208
|
-
let teamAutoSelected = false;
|
|
1209
|
-
let selectedGitRemoteName;
|
|
1210
|
-
for (; ; ) {
|
|
1211
|
-
if (!org) {
|
|
1212
|
-
const orgMeta = {};
|
|
1213
|
-
const resolved = await selectOrgForLink(
|
|
1214
|
-
client,
|
|
1215
|
-
autoConfirm,
|
|
1216
|
-
searchableTeamPicker,
|
|
1217
|
-
orgMeta
|
|
1218
|
-
);
|
|
1219
|
-
if ("status" in resolved) {
|
|
1220
|
-
return resolved;
|
|
1221
|
-
}
|
|
1222
|
-
org = resolved;
|
|
1223
|
-
teamAutoSelected = orgMeta.choiceCount === 1;
|
|
1224
|
-
}
|
|
1225
|
-
let repoMatches = [];
|
|
1226
|
-
let gitRemoteNames = [];
|
|
1227
|
-
let currentGitRemoteName;
|
|
1228
|
-
if (showProjectSuggestions) {
|
|
1229
|
-
output_manager_default.spinner("Searching for existing projects\u2026", 1e3);
|
|
1230
|
-
try {
|
|
1231
|
-
const repoSearch = await searchProjectsByRepoRoot({
|
|
1232
|
-
client,
|
|
1233
|
-
cwd: path2,
|
|
1234
|
-
gitProjectName,
|
|
1235
|
-
orgs: [org],
|
|
1236
|
-
remoteName: selectedGitRemoteName
|
|
1237
|
-
});
|
|
1238
|
-
repoMatches = repoSearch.matches;
|
|
1239
|
-
gitRemoteNames = repoSearch.remoteNames;
|
|
1240
|
-
currentGitRemoteName = repoSearch.remote?.remoteName;
|
|
1241
|
-
} catch (err) {
|
|
1242
|
-
if (isPromptCanceledError(err)) {
|
|
1243
|
-
throw err;
|
|
1244
|
-
}
|
|
1245
|
-
output_manager_default.debug(`Git-linked project search failed: ${err}`);
|
|
1246
|
-
} finally {
|
|
1247
|
-
output_manager_default.stopSpinner();
|
|
1248
|
-
}
|
|
1249
|
-
}
|
|
1250
|
-
try {
|
|
1251
|
-
projectOrNewProjectName = await inputProject(
|
|
1252
|
-
client,
|
|
1253
|
-
org,
|
|
1254
|
-
projectName,
|
|
1255
|
-
autoConfirm,
|
|
1256
|
-
false,
|
|
1257
|
-
showProjectSuggestions,
|
|
1258
|
-
searchableTeamPicker && !selectedOrg && !teamAutoSelected,
|
|
1259
|
-
repoMatches,
|
|
1260
|
-
{
|
|
1261
|
-
remoteNames: gitRemoteNames,
|
|
1262
|
-
currentRemoteName: currentGitRemoteName
|
|
1263
|
-
}
|
|
1264
|
-
);
|
|
1265
|
-
} catch (err) {
|
|
1266
|
-
if (err instanceof Error && err.code === "HEADLESS") {
|
|
1267
|
-
return { status: "error", exitCode: 1, reason: "HEADLESS" };
|
|
1268
|
-
}
|
|
1269
|
-
throw err;
|
|
1270
|
-
}
|
|
1271
|
-
if (projectOrNewProjectName === BACK_TO_TEAM_SELECTION) {
|
|
1272
|
-
org = void 0;
|
|
1273
|
-
selectedGitRemoteName = void 0;
|
|
1274
|
-
continue;
|
|
1275
|
-
}
|
|
1276
|
-
if (projectOrNewProjectName === SWITCH_GIT_REMOTE) {
|
|
1277
|
-
const rootPath = await findRepoRoot(path2);
|
|
1278
|
-
if (!rootPath) {
|
|
1279
|
-
continue;
|
|
1280
|
-
}
|
|
1281
|
-
try {
|
|
1282
|
-
const remote = await resolveGitRemote(client, rootPath, {
|
|
1283
|
-
yes: false
|
|
1284
|
-
});
|
|
1285
|
-
selectedGitRemoteName = remote?.remoteName;
|
|
1286
|
-
} catch (err) {
|
|
1287
|
-
if (isPromptCanceledError(err)) {
|
|
1288
|
-
throw err;
|
|
1289
|
-
}
|
|
1290
|
-
output_manager_default.debug(`Failed to switch Git remote: ${err}`);
|
|
1291
|
-
}
|
|
1292
|
-
continue;
|
|
1293
|
-
}
|
|
1294
|
-
break;
|
|
1295
|
-
}
|
|
1296
|
-
if (typeof projectOrNewProjectName === "string") {
|
|
1297
|
-
newProjectName = projectOrNewProjectName;
|
|
1298
|
-
} else if (isCrossTeamMatch(projectOrNewProjectName)) {
|
|
1299
|
-
return await linkCrossTeamMatch({
|
|
1300
|
-
client,
|
|
1301
|
-
path: path2,
|
|
1302
|
-
match: projectOrNewProjectName,
|
|
1303
|
-
successEmoji,
|
|
1304
|
-
autoConfirm,
|
|
1305
|
-
pullEnv
|
|
1306
|
-
});
|
|
1307
|
-
} else {
|
|
1308
|
-
const project = projectOrNewProjectName;
|
|
1309
|
-
await linkFolderToProject(
|
|
1310
|
-
client,
|
|
1311
|
-
path2,
|
|
1312
|
-
{
|
|
1313
|
-
projectId: project.id,
|
|
1314
|
-
orgId: org.id
|
|
1315
|
-
},
|
|
1316
|
-
project.name,
|
|
1317
|
-
org.slug,
|
|
1318
|
-
successEmoji,
|
|
1319
|
-
autoConfirm,
|
|
1320
|
-
pullEnv
|
|
1321
|
-
);
|
|
1322
|
-
return { status: "linked", org, project };
|
|
1323
|
-
}
|
|
1324
|
-
config.currentTeam = org.type === "team" ? org.id : void 0;
|
|
1325
|
-
const gitConnectIntent = await resolveGitConnectIntent(
|
|
1326
|
-
client,
|
|
1327
|
-
path2,
|
|
1328
|
-
autoConfirm
|
|
1329
|
-
);
|
|
1330
|
-
const rootServicesSetup = await getServicesSetupState(path2);
|
|
1331
|
-
const configFileName = await findSourceVercelConfigFile(path2) ?? "vercel.json";
|
|
1332
|
-
try {
|
|
1333
|
-
let settings = {};
|
|
1334
|
-
let pathWithRootDirectory = path2;
|
|
1335
|
-
let rootInferredServicesChoice = null;
|
|
1336
|
-
if (!rootServicesSetup.hasConfiguredServices) {
|
|
1337
|
-
rootInferredServicesChoice = await promptForInferredServicesSetup({
|
|
1338
|
-
client,
|
|
1339
|
-
autoConfirm,
|
|
1340
|
-
nonInteractive,
|
|
1341
|
-
workPath: path2,
|
|
1342
|
-
inferred: rootServicesSetup.inferredServices,
|
|
1343
|
-
inferredWriteBlocker: rootServicesSetup.inferredServicesWriteBlocker,
|
|
1344
|
-
allowChooseDifferentProjectDirectory: true
|
|
1345
|
-
});
|
|
1346
|
-
}
|
|
1347
|
-
if (rootServicesSetup.hasConfiguredServices) {
|
|
1348
|
-
displayConfiguredServicesSetup(
|
|
1349
|
-
rootServicesSetup.detectServicesResult,
|
|
1350
|
-
configFileName
|
|
1351
|
-
);
|
|
1352
|
-
settings.framework = "services";
|
|
1353
|
-
} else if (rootInferredServicesChoice?.type === "services") {
|
|
1354
|
-
settings.framework = "services";
|
|
1355
|
-
} else {
|
|
1356
|
-
const skipSelectedRootInferredServicesPrompt = rootInferredServicesChoice?.type === "single-app";
|
|
1357
|
-
if (rootInferredServicesChoice?.type === "single-app") {
|
|
1358
|
-
rootDirectory = toProjectRootDirectory(
|
|
1359
|
-
path2,
|
|
1360
|
-
rootInferredServicesChoice.selectedPath
|
|
1361
|
-
);
|
|
1362
|
-
} else {
|
|
1363
|
-
const shouldPromptRoot = await shouldPromptForRootDirectory({
|
|
1364
|
-
path: path2,
|
|
1365
|
-
servicesChoice: rootInferredServicesChoice
|
|
1366
|
-
});
|
|
1367
|
-
if (shouldPromptRoot) {
|
|
1368
|
-
rootDirectory = await inputRootDirectory(client, path2, autoConfirm);
|
|
1369
|
-
if (rootDirectory && !await validateRootDirectory(path2, join3(path2, rootDirectory))) {
|
|
1370
|
-
return {
|
|
1371
|
-
status: "error",
|
|
1372
|
-
exitCode: 1,
|
|
1373
|
-
reason: "INVALID_ROOT_DIRECTORY"
|
|
1374
|
-
};
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
pathWithRootDirectory = rootDirectory ? join3(path2, rootDirectory) : path2;
|
|
1379
|
-
const selectedRootServicesSetup = pathWithRootDirectory === path2 ? null : await getServicesSetupState(pathWithRootDirectory);
|
|
1380
|
-
let selectedRootInferredServicesChoice = null;
|
|
1381
|
-
if (!skipSelectedRootInferredServicesPrompt) {
|
|
1382
|
-
selectedRootInferredServicesChoice = await promptForInferredServicesSetup({
|
|
1383
|
-
client,
|
|
1384
|
-
autoConfirm,
|
|
1385
|
-
nonInteractive,
|
|
1386
|
-
workPath: pathWithRootDirectory,
|
|
1387
|
-
inferred: selectedRootServicesSetup?.inferredServices ?? null,
|
|
1388
|
-
inferredWriteBlocker: selectedRootServicesSetup?.inferredServicesWriteBlocker ?? null
|
|
1389
|
-
});
|
|
1390
|
-
}
|
|
1391
|
-
if (selectedRootServicesSetup?.hasConfiguredServices) {
|
|
1392
|
-
displayConfiguredServicesSetup(
|
|
1393
|
-
selectedRootServicesSetup.detectServicesResult,
|
|
1394
|
-
configFileName
|
|
1395
|
-
);
|
|
1396
|
-
settings.framework = "services";
|
|
1397
|
-
} else if (selectedRootInferredServicesChoice?.type === "services") {
|
|
1398
|
-
settings.framework = "services";
|
|
1399
|
-
} else {
|
|
1400
|
-
if (selectedRootInferredServicesChoice?.type === "single-app") {
|
|
1401
|
-
rootDirectory = toProjectRootDirectory(
|
|
1402
|
-
path2,
|
|
1403
|
-
selectedRootInferredServicesChoice.selectedPath
|
|
1404
|
-
);
|
|
1405
|
-
pathWithRootDirectory = rootDirectory ? join3(path2, rootDirectory) : path2;
|
|
1406
|
-
}
|
|
1407
|
-
const localConfig = await readConfig(pathWithRootDirectory);
|
|
1408
|
-
if (localConfig instanceof CantParseJSONFile) {
|
|
1409
|
-
output_manager_default.prettyError(localConfig);
|
|
1410
|
-
return { status: "error", exitCode: 1 };
|
|
1411
|
-
}
|
|
1412
|
-
const isZeroConfig = !localConfig || !localConfig.builds || localConfig.builds.length === 0;
|
|
1413
|
-
if (isZeroConfig) {
|
|
1414
|
-
const localConfigurationOverrides = {
|
|
1415
|
-
buildCommand: localConfig?.buildCommand,
|
|
1416
|
-
devCommand: localConfig?.devCommand,
|
|
1417
|
-
framework: localConfig?.framework,
|
|
1418
|
-
commandForIgnoringBuildStep: localConfig?.ignoreCommand,
|
|
1419
|
-
installCommand: localConfig?.installCommand,
|
|
1420
|
-
outputDirectory: localConfig?.outputDirectory
|
|
1421
|
-
};
|
|
1422
|
-
const detectedProjectsForWorkspace = await detectProjects(
|
|
1423
|
-
pathWithRootDirectory
|
|
1424
|
-
);
|
|
1425
|
-
const detectedProjects = detectedProjectsForWorkspace.get("") || [];
|
|
1426
|
-
const framework = detectedProjects[0] ?? import_frameworks3.frameworkList.find((f) => f.slug === null);
|
|
1427
|
-
settings = await editProjectSettings(
|
|
1428
|
-
client,
|
|
1429
|
-
{},
|
|
1430
|
-
framework,
|
|
1431
|
-
autoConfirm,
|
|
1432
|
-
localConfigurationOverrides,
|
|
1433
|
-
configFileName
|
|
1434
|
-
);
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
const changeAdditionalSettings = false;
|
|
1439
|
-
let vercelAuthSetting = DEFAULT_VERCEL_AUTH_SETTING;
|
|
1440
|
-
if (changeAdditionalSettings) {
|
|
1441
|
-
vercelAuthSetting = await vercelAuth(client, {
|
|
1442
|
-
autoConfirm
|
|
1443
|
-
});
|
|
1444
|
-
}
|
|
1445
|
-
if (rootDirectory) {
|
|
1446
|
-
settings.rootDirectory = rootDirectory;
|
|
1447
|
-
}
|
|
1448
|
-
const project = await createProject(client, {
|
|
1449
|
-
...settings,
|
|
1450
|
-
name: newProjectName,
|
|
1451
|
-
vercelAuth: vercelAuthSetting,
|
|
1452
|
-
v0
|
|
1453
|
-
});
|
|
1454
|
-
await linkFolderToProject(
|
|
1455
|
-
client,
|
|
1456
|
-
path2,
|
|
1457
|
-
{
|
|
1458
|
-
projectId: project.id,
|
|
1459
|
-
orgId: org.id
|
|
1460
|
-
},
|
|
1461
|
-
project.name,
|
|
1462
|
-
org.slug,
|
|
1463
|
-
successEmoji,
|
|
1464
|
-
autoConfirm,
|
|
1465
|
-
false,
|
|
1466
|
-
// don't prompt to pull env for newly created projects
|
|
1467
|
-
"Created"
|
|
1468
|
-
);
|
|
1469
|
-
await applyGitConnectIntent(
|
|
1470
|
-
client,
|
|
1471
|
-
gitConnectIntent,
|
|
1472
|
-
project,
|
|
1473
|
-
autoConfirm,
|
|
1474
|
-
org
|
|
1475
|
-
);
|
|
1476
|
-
return { status: "linked", org, project };
|
|
1477
|
-
} catch (err) {
|
|
1478
|
-
if (isPromptCanceledError(err)) {
|
|
1479
|
-
throw err;
|
|
1480
|
-
}
|
|
1481
|
-
if (isAPIError(err) && err.code === "too_many_projects") {
|
|
1482
|
-
output_manager_default.prettyError(err);
|
|
1483
|
-
return { status: "error", exitCode: 1, reason: "TOO_MANY_PROJECTS" };
|
|
1484
|
-
}
|
|
1485
|
-
if (err instanceof Error && err.code === "HEADLESS") {
|
|
1486
|
-
return { status: "error", exitCode: 1, reason: "HEADLESS" };
|
|
1487
|
-
}
|
|
1488
|
-
printError(err);
|
|
1489
|
-
return { status: "error", exitCode: 1 };
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
async function resolveGitConnectIntent(client, path2, autoConfirm) {
|
|
1493
|
-
try {
|
|
1494
|
-
const gitConfig = await parseGitConfig(join3(path2, ".git/config"));
|
|
1495
|
-
if (!gitConfig) {
|
|
1496
|
-
return null;
|
|
1497
|
-
}
|
|
1498
|
-
const remoteUrls = pluckRemoteUrls(gitConfig);
|
|
1499
|
-
if (!remoteUrls || Object.keys(remoteUrls).length === 0) {
|
|
1500
|
-
return null;
|
|
1501
|
-
}
|
|
1502
|
-
const skipPrompts = autoConfirm || client.nonInteractive;
|
|
1503
|
-
const shouldConnect = skipPrompts || await client.input.confirm(`Connect detected Git repository?`, false);
|
|
1504
|
-
if (!shouldConnect) {
|
|
1505
|
-
return null;
|
|
1506
|
-
}
|
|
1507
|
-
const repoInfo = skipPrompts ? parseRepoUrl(remoteUrls.origin ?? Object.values(remoteUrls)[0]) : await selectAndParseRemoteUrl(client, remoteUrls);
|
|
1508
|
-
if (!repoInfo) {
|
|
1509
|
-
return null;
|
|
1510
|
-
}
|
|
1511
|
-
return { repoInfo };
|
|
1512
|
-
} catch (error) {
|
|
1513
|
-
if (isPromptCanceledError(error)) {
|
|
1514
|
-
throw error;
|
|
1515
|
-
}
|
|
1516
|
-
output_manager_default.debug(`Failed to detect git repository: ${error}`);
|
|
1517
|
-
return null;
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
async function applyGitConnectIntent(client, intent, project, autoConfirm, org) {
|
|
1521
|
-
if (!intent) {
|
|
1522
|
-
return;
|
|
1523
|
-
}
|
|
1524
|
-
const { repoInfo } = intent;
|
|
1525
|
-
try {
|
|
1526
|
-
await checkExistsAndConnect({
|
|
1527
|
-
client,
|
|
1528
|
-
confirm: autoConfirm,
|
|
1529
|
-
gitProviderLink: project.link,
|
|
1530
|
-
org,
|
|
1531
|
-
gitOrg: repoInfo.org,
|
|
1532
|
-
project,
|
|
1533
|
-
// Type assertion since we only need the id
|
|
1534
|
-
provider: repoInfo.provider,
|
|
1535
|
-
repo: repoInfo.repo,
|
|
1536
|
-
repoPath: `${repoInfo.org}/${repoInfo.repo}`
|
|
1537
|
-
});
|
|
1538
|
-
} catch (error) {
|
|
1539
|
-
if (isPromptCanceledError(error)) {
|
|
1540
|
-
return;
|
|
1541
|
-
}
|
|
1542
|
-
output_manager_default.debug(`Failed to connect git repository: ${error}`);
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
export {
|
|
1547
|
-
validateRootDirectory,
|
|
1548
|
-
validatePaths,
|
|
1549
|
-
readConfig,
|
|
1550
|
-
displayDetectedServices,
|
|
1551
|
-
setupAndLink
|
|
1552
|
-
};
|