mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-12 21:07:46 +00:00
Compare commits
30 Commits
@vercel/py
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ad27eefb0 | ||
|
|
578fe8a930 | ||
|
|
04ea3bb88d | ||
|
|
46116022b7 | ||
|
|
f80539df82 | ||
|
|
daf06307b4 | ||
|
|
0bd028cd84 | ||
|
|
1c48030e1e | ||
|
|
1dc05428d7 | ||
|
|
288dca045c | ||
|
|
8c5bc04fde | ||
|
|
a07e6fc103 | ||
|
|
9af3054d41 | ||
|
|
9fb254e14a | ||
|
|
3616bdf17a | ||
|
|
52a89fd4b7 | ||
|
|
d4db6635f1 | ||
|
|
f1009a80cd | ||
|
|
2756d1e323 | ||
|
|
5b61b16bd1 | ||
|
|
41c61f8f8b | ||
|
|
6c52e1fad7 | ||
|
|
d2e82fdc3a | ||
|
|
a60b1b225b | ||
|
|
18bec983ae | ||
|
|
e6fb2ffe05 | ||
|
|
0533cfd566 | ||
|
|
3db8618885 | ||
|
|
4722ea5ad6 | ||
|
|
c7bd6f3266 |
@@ -11,7 +11,11 @@
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Vercel is the optimal workflow for frontend teams. All-in-one: Static and Jamstack deployment, Serverless Functions, and Global CDN.
|
Vercel is a platform for **static sites and frontend frameworks**, built to integrate with your headless content, commerce, or database.
|
||||||
|
|
||||||
|
We provide a **frictionless developer experience** to take care of the hard things: deploy instantly, scale automatically, and serve personalized content around the globe.
|
||||||
|
|
||||||
|
We make it easy for frontend teams to **develop, preview, and ship** delightful user experiences, where performance is the default.
|
||||||
|
|
||||||
Get started by [Importing a Git Project](https://vercel.com/new) and use `git push` to deploy. Alternatively, you can [install Vercel CLI](https://vercel.com/cli).
|
Get started by [Importing a Git Project](https://vercel.com/new) and use `git push` to deploy. Alternatively, you can [install Vercel CLI](https://vercel.com/cli).
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,19 @@
|
|||||||
* Get example list from extracted folder
|
* Get example list from extracted folder
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { join } from 'path';
|
|
||||||
import { lstatSync, existsSync, readdirSync } from 'fs';
|
import { lstatSync, existsSync, readdirSync } from 'fs';
|
||||||
|
|
||||||
const exists = (path: string) => existsSync(path);
|
const exists = (path: string) => existsSync(path);
|
||||||
const isDotFile = (name: string) => name.startsWith('.');
|
const isDotFile = (name: string) => name.startsWith('.');
|
||||||
const isDirectory = (path: string) => lstatSync(path).isDirectory();
|
const isDirectory = (path: string) => lstatSync(path).isDirectory();
|
||||||
|
|
||||||
export function summary(source: string) {
|
export function summary(source: string): string[] {
|
||||||
if (!exists(source) || !isDirectory(source)) {
|
if (!exists(source) || !isDirectory(source)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return readdirSync(source)
|
return readdirSync(source, { withFileTypes: true })
|
||||||
.filter(name => !isDotFile(name))
|
.filter(d => !isDotFile(d.name))
|
||||||
.filter(name => isDirectory(join(source, name)));
|
.filter(d => d.isDirectory())
|
||||||
|
.map(d => d.name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^16.6.1",
|
"react": "^16.6.1",
|
||||||
"react-dom": "^16.6.1",
|
"react-dom": "^16.6.1",
|
||||||
"react-scripts": "2.1.1"
|
"react-scripts": "^4.0.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "BROWSER=none react-scripts start",
|
"dev": "BROWSER=none react-scripts start",
|
||||||
|
|||||||
3
examples/nextjs/.eslintrc.json
Normal file
3
examples/nextjs/.eslintrc.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "next/core-web-vitals"
|
||||||
|
}
|
||||||
@@ -29,6 +29,6 @@ You can check out [the Next.js GitHub repository](https://github.com/vercel/next
|
|||||||
|
|
||||||
## Deploy on Vercel
|
## Deploy on Vercel
|
||||||
|
|
||||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||||
|
|||||||
3
examples/nextjs/next.config.js
Normal file
3
examples/nextjs/next.config.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
reactStrictMode: true,
|
||||||
|
}
|
||||||
@@ -5,11 +5,16 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start"
|
"start": "next start",
|
||||||
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "10.x",
|
"next": "11.1.0",
|
||||||
"react": "17.x",
|
"react": "17.0.2",
|
||||||
"react-dom": "17.x"
|
"react-dom": "17.0.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "7.32.0",
|
||||||
|
"eslint-config-next": "11.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||||
|
|
||||||
export default (req, res) => {
|
export default function handler(req, res) {
|
||||||
res.statusCode = 200
|
res.status(200).json({ name: 'John Doe' })
|
||||||
res.json({ name: 'John Doe' })
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
|
import Image from 'next/image'
|
||||||
import styles from '../styles/Home.module.css'
|
import styles from '../styles/Home.module.css'
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
@@ -6,6 +7,7 @@ export default function Home() {
|
|||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Create Next App</title>
|
<title>Create Next App</title>
|
||||||
|
<meta name="description" content="Generated by create next app" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
@@ -21,12 +23,12 @@ export default function Home() {
|
|||||||
|
|
||||||
<div className={styles.grid}>
|
<div className={styles.grid}>
|
||||||
<a href="https://nextjs.org/docs" className={styles.card}>
|
<a href="https://nextjs.org/docs" className={styles.card}>
|
||||||
<h3>Documentation →</h3>
|
<h2>Documentation →</h2>
|
||||||
<p>Find in-depth information about Next.js features and API.</p>
|
<p>Find in-depth information about Next.js features and API.</p>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="https://nextjs.org/learn" className={styles.card}>
|
<a href="https://nextjs.org/learn" className={styles.card}>
|
||||||
<h3>Learn →</h3>
|
<h2>Learn →</h2>
|
||||||
<p>Learn about Next.js in an interactive course with quizzes!</p>
|
<p>Learn about Next.js in an interactive course with quizzes!</p>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
@@ -34,15 +36,15 @@ export default function Home() {
|
|||||||
href="https://github.com/vercel/next.js/tree/master/examples"
|
href="https://github.com/vercel/next.js/tree/master/examples"
|
||||||
className={styles.card}
|
className={styles.card}
|
||||||
>
|
>
|
||||||
<h3>Examples →</h3>
|
<h2>Examples →</h2>
|
||||||
<p>Discover and deploy boilerplate example Next.js projects.</p>
|
<p>Discover and deploy boilerplate example Next.js projects.</p>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="https://vercel.com/import?filter=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||||
className={styles.card}
|
className={styles.card}
|
||||||
>
|
>
|
||||||
<h3>Deploy →</h3>
|
<h2>Deploy →</h2>
|
||||||
<p>
|
<p>
|
||||||
Instantly deploy your Next.js site to a public URL with Vercel.
|
Instantly deploy your Next.js site to a public URL with Vercel.
|
||||||
</p>
|
</p>
|
||||||
@@ -57,7 +59,9 @@ export default function Home() {
|
|||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
Powered by{' '}
|
Powered by{' '}
|
||||||
<img src="/vercel.svg" alt="Vercel Logo" className={styles.logo} />
|
<span className={styles.logo}>
|
||||||
|
<Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
@@ -25,14 +26,11 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer img {
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer a {
|
.footer a {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title a {
|
.title a {
|
||||||
@@ -82,7 +80,6 @@
|
|||||||
|
|
||||||
.card {
|
.card {
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
flex-basis: 45%;
|
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@@ -90,6 +87,7 @@
|
|||||||
border: 1px solid #eaeaea;
|
border: 1px solid #eaeaea;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
transition: color 0.15s ease, border-color 0.15s ease;
|
transition: color 0.15s ease, border-color 0.15s ease;
|
||||||
|
width: 45%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:hover,
|
.card:hover,
|
||||||
@@ -99,7 +97,7 @@
|
|||||||
border-color: #0070f3;
|
border-color: #0070f3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card h3 {
|
.card h2 {
|
||||||
margin: 0 0 1rem 0;
|
margin: 0 0 1rem 0;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
@@ -112,6 +110,7 @@
|
|||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
height: 1em;
|
height: 1em;
|
||||||
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -25,17 +25,19 @@
|
|||||||
"eslint-config-prettier": "8.3.0",
|
"eslint-config-prettier": "8.3.0",
|
||||||
"eslint-plugin-jest": "24.3.6",
|
"eslint-plugin-jest": "24.3.6",
|
||||||
"husky": "6.0.0",
|
"husky": "6.0.0",
|
||||||
|
"jest": "27.0.6",
|
||||||
"json5": "2.1.1",
|
"json5": "2.1.1",
|
||||||
"lint-staged": "9.2.5",
|
"lint-staged": "9.2.5",
|
||||||
"node-fetch": "2.6.1",
|
"node-fetch": "2.6.1",
|
||||||
"npm-package-arg": "6.1.0",
|
"npm-package-arg": "6.1.0",
|
||||||
"prettier": "2.3.1"
|
"prettier": "2.3.1",
|
||||||
|
"ts-jest": "27.0.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lerna": "lerna",
|
"lerna": "lerna",
|
||||||
"bootstrap": "lerna bootstrap",
|
"bootstrap": "lerna bootstrap",
|
||||||
"publish-stable": "echo 'Run `yarn changelog` for instructions'",
|
"publish-stable": "echo 'Run `yarn changelog` for instructions'",
|
||||||
"publish-canary": "git checkout main && git pull && lerna version prerelease --preid canary --message 'Publish Canary' --exact",
|
"publish-canary": "git checkout main && git pull && lerna version prerelease --preid canary --message \"Publish Canary\" --exact",
|
||||||
"publish-from-github": "./utils/publish.sh",
|
"publish-from-github": "./utils/publish.sh",
|
||||||
"changelog": "node utils/changelog.js",
|
"changelog": "node utils/changelog.js",
|
||||||
"build": "node utils/run.js build all",
|
"build": "node utils/run.js build all",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/build-utils",
|
"name": "@vercel/build-utils",
|
||||||
"version": "2.12.0",
|
"version": "2.12.3-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.js",
|
"types": "./dist/index.d.js",
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
"@types/node-fetch": "^2.1.6",
|
"@types/node-fetch": "^2.1.6",
|
||||||
"@types/semver": "6.0.0",
|
"@types/semver": "6.0.0",
|
||||||
"@types/yazl": "^2.4.1",
|
"@types/yazl": "^2.4.1",
|
||||||
"@vercel/frameworks": "0.5.0",
|
"@vercel/frameworks": "0.5.1-canary.1",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"aggregate-error": "3.0.1",
|
"aggregate-error": "3.0.1",
|
||||||
"async-retry": "1.2.3",
|
"async-retry": "1.2.3",
|
||||||
@@ -41,13 +41,11 @@
|
|||||||
"fs-extra": "7.0.0",
|
"fs-extra": "7.0.0",
|
||||||
"glob": "7.1.3",
|
"glob": "7.1.3",
|
||||||
"into-stream": "5.0.0",
|
"into-stream": "5.0.0",
|
||||||
"jest": "27.0.6",
|
|
||||||
"js-yaml": "3.13.1",
|
"js-yaml": "3.13.1",
|
||||||
"minimatch": "3.0.4",
|
"minimatch": "3.0.4",
|
||||||
"multistream": "2.1.1",
|
"multistream": "2.1.1",
|
||||||
"node-fetch": "2.6.1",
|
"node-fetch": "2.6.1",
|
||||||
"semver": "6.1.1",
|
"semver": "6.1.1",
|
||||||
"ts-jest": "27.0.4",
|
|
||||||
"typescript": "4.3.4",
|
"typescript": "4.3.4",
|
||||||
"yazl": "2.4.3"
|
"yazl": "2.4.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -244,10 +244,13 @@ export async function scanParentDirs(
|
|||||||
const packageJsonPath = path.join(currentDestPath, 'package.json');
|
const packageJsonPath = path.join(currentDestPath, 'package.json');
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
if (await fs.pathExists(packageJsonPath)) {
|
if (await fs.pathExists(packageJsonPath)) {
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// Only read the contents of the *first* `package.json` file found,
|
||||||
if (readPackageJson) {
|
// since that's the one related to this installation.
|
||||||
|
if (readPackageJson && !packageJson) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
const [packageLockJson, hasYarnLock] = await Promise.all([
|
const [packageLockJson, hasYarnLock] = await Promise.all([
|
||||||
fs
|
fs
|
||||||
@@ -256,9 +259,8 @@ export async function scanParentDirs(
|
|||||||
// If the file doesn't exist, fail gracefully otherwise error
|
// If the file doesn't exist, fail gracefully otherwise error
|
||||||
if (error.code === 'ENOENT') {
|
if (error.code === 'ENOENT') {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
throw error;
|
||||||
}),
|
}),
|
||||||
fs.pathExists(path.join(currentDestPath, 'yarn.lock')),
|
fs.pathExists(path.join(currentDestPath, 'yarn.lock')),
|
||||||
]);
|
]);
|
||||||
@@ -267,7 +269,13 @@ export async function scanParentDirs(
|
|||||||
cliType = 'npm';
|
cliType = 'npm';
|
||||||
lockfileVersion = packageLockJson.lockfileVersion;
|
lockfileVersion = packageLockJson.lockfileVersion;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
// Only stop iterating if a lockfile was found, because it's possible
|
||||||
|
// that the lockfile is in a higher path than where the `package.json`
|
||||||
|
// file was found.
|
||||||
|
if (packageLockJson || hasYarnLock) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const newDestPath = path.dirname(currentDestPath);
|
const newDestPath = path.dirname(currentDestPath);
|
||||||
@@ -305,7 +313,8 @@ export async function runNpmInstall(
|
|||||||
destPath: string,
|
destPath: string,
|
||||||
args: string[] = [],
|
args: string[] = [],
|
||||||
spawnOpts?: SpawnOptions,
|
spawnOpts?: SpawnOptions,
|
||||||
meta?: Meta
|
meta?: Meta,
|
||||||
|
nodeVersion?: NodeVersion
|
||||||
) {
|
) {
|
||||||
if (meta?.isDev) {
|
if (meta?.isDev) {
|
||||||
debug('Skipping dependency installation because dev mode is enabled');
|
debug('Skipping dependency installation because dev mode is enabled');
|
||||||
@@ -329,7 +338,12 @@ export async function runNpmInstall(
|
|||||||
.filter(a => a !== '--prefer-offline')
|
.filter(a => a !== '--prefer-offline')
|
||||||
.concat(['install', '--no-audit', '--unsafe-perm']);
|
.concat(['install', '--no-audit', '--unsafe-perm']);
|
||||||
|
|
||||||
if (typeof lockfileVersion === 'number' && lockfileVersion >= 2) {
|
// If the lockfile version is 2 or greater and the node version is less than 16 than we will force npm7 to be used
|
||||||
|
if (
|
||||||
|
typeof lockfileVersion === 'number' &&
|
||||||
|
lockfileVersion >= 2 &&
|
||||||
|
(nodeVersion?.major || 0) < 16
|
||||||
|
) {
|
||||||
// Ensure that npm 7 is at the beginning of the `$PATH`
|
// Ensure that npm 7 is at the beginning of the `$PATH`
|
||||||
env.PATH = `/node16/bin-npm7:${env.PATH}`;
|
env.PATH = `/node16/bin-npm7:${env.PATH}`;
|
||||||
console.log('Detected `package-lock.json` generated by npm 7...');
|
console.log('Detected `package-lock.json` generated by npm 7...');
|
||||||
|
|||||||
15
packages/build-utils/test/fixtures/21-npm-workspaces/a/package.json
vendored
Normal file
15
packages/build-utils/test/fixtures/21-npm-workspaces/a/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "a",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
15
packages/build-utils/test/fixtures/21-npm-workspaces/b/package.json
vendored
Normal file
15
packages/build-utils/test/fixtures/21-npm-workspaces/b/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "b",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"cowsay": "^1.5.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
782
packages/build-utils/test/fixtures/21-npm-workspaces/package-lock.json
generated
vendored
Normal file
782
packages/build-utils/test/fixtures/21-npm-workspaces/package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,782 @@
|
|||||||
|
{
|
||||||
|
"name": "21-npm-workspaces",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"workspaces": [
|
||||||
|
"a",
|
||||||
|
"b"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"a": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"b": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"cowsay": "^1.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/a": {
|
||||||
|
"resolved": "a",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/ansi-regex": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/b": {
|
||||||
|
"resolved": "b",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/camelcase": {
|
||||||
|
"version": "5.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||||
|
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cliui": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"strip-ansi": "^6.0.0",
|
||||||
|
"wrap-ansi": "^6.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cliui/node_modules/ansi-regex": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cliui/node_modules/is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cliui/node_modules/string-width": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||||
|
"dependencies": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cliui/node_modules/strip-ansi": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||||
|
},
|
||||||
|
"node_modules/cowsay": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cowsay/-/cowsay-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-8Ipzr54Z8zROr/62C8f0PdhQcDusS05gKTS87xxdji8VbWefWly0k8BwGK7+VqamOrkv3eGsCkPtvlHzrhWsCA==",
|
||||||
|
"dependencies": {
|
||||||
|
"get-stdin": "8.0.0",
|
||||||
|
"string-width": "~2.1.1",
|
||||||
|
"strip-final-newline": "2.0.0",
|
||||||
|
"yargs": "15.4.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"cowsay": "cli.js",
|
||||||
|
"cowthink": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/debug": {
|
||||||
|
"version": "4.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||||
|
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/decamelize": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||||
|
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||||
|
},
|
||||||
|
"node_modules/find-up": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||||
|
"dependencies": {
|
||||||
|
"locate-path": "^5.0.0",
|
||||||
|
"path-exists": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/get-caller-file": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||||
|
"engines": {
|
||||||
|
"node": "6.* || 8.* || >= 10.*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/get-stdin": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-fullwidth-code-point": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/locate-path": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||||
|
"dependencies": {
|
||||||
|
"p-locate": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
},
|
||||||
|
"node_modules/p-limit": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"p-try": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-locate": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||||
|
"dependencies": {
|
||||||
|
"p-limit": "^2.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-try": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/path-exists": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/require-directory": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
|
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/require-main-filename": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||||
|
},
|
||||||
|
"node_modules/set-blocking": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
||||||
|
},
|
||||||
|
"node_modules/string-width": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-fullwidth-code-point": "^2.0.0",
|
||||||
|
"strip-ansi": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strip-ansi": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strip-final-newline": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/which-module": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"string-width": "^4.1.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi/node_modules/ansi-regex": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi/node_modules/string-width": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||||
|
"dependencies": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi/node_modules/strip-ansi": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/y18n": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
|
||||||
|
},
|
||||||
|
"node_modules/yargs": {
|
||||||
|
"version": "15.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
||||||
|
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
|
||||||
|
"dependencies": {
|
||||||
|
"cliui": "^6.0.0",
|
||||||
|
"decamelize": "^1.2.0",
|
||||||
|
"find-up": "^4.1.0",
|
||||||
|
"get-caller-file": "^2.0.1",
|
||||||
|
"require-directory": "^2.1.1",
|
||||||
|
"require-main-filename": "^2.0.0",
|
||||||
|
"set-blocking": "^2.0.0",
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"which-module": "^2.0.0",
|
||||||
|
"y18n": "^4.0.0",
|
||||||
|
"yargs-parser": "^18.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs-parser": {
|
||||||
|
"version": "18.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||||
|
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"camelcase": "^5.0.0",
|
||||||
|
"decamelize": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs/node_modules/ansi-regex": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs/node_modules/is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs/node_modules/string-width": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||||
|
"dependencies": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs/node_modules/strip-ansi": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"a": {
|
||||||
|
"version": "file:a",
|
||||||
|
"requires": {
|
||||||
|
"debug": "^4.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
|
||||||
|
},
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"requires": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"b": {
|
||||||
|
"version": "file:b",
|
||||||
|
"requires": {
|
||||||
|
"cowsay": "^1.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"camelcase": {
|
||||||
|
"version": "5.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||||
|
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
|
||||||
|
},
|
||||||
|
"cliui": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
|
||||||
|
"requires": {
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"strip-ansi": "^6.0.0",
|
||||||
|
"wrap-ansi": "^6.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
|
||||||
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||||
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||||
|
"requires": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"requires": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||||
|
},
|
||||||
|
"cowsay": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cowsay/-/cowsay-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-8Ipzr54Z8zROr/62C8f0PdhQcDusS05gKTS87xxdji8VbWefWly0k8BwGK7+VqamOrkv3eGsCkPtvlHzrhWsCA==",
|
||||||
|
"requires": {
|
||||||
|
"get-stdin": "8.0.0",
|
||||||
|
"string-width": "~2.1.1",
|
||||||
|
"strip-final-newline": "2.0.0",
|
||||||
|
"yargs": "15.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"version": "4.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||||
|
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"decamelize": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||||
|
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||||
|
},
|
||||||
|
"emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||||
|
},
|
||||||
|
"find-up": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||||
|
"requires": {
|
||||||
|
"locate-path": "^5.0.0",
|
||||||
|
"path-exists": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"get-caller-file": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||||
|
},
|
||||||
|
"get-stdin": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg=="
|
||||||
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
|
||||||
|
},
|
||||||
|
"locate-path": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||||
|
"requires": {
|
||||||
|
"p-locate": "^4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
},
|
||||||
|
"p-limit": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||||
|
"requires": {
|
||||||
|
"p-try": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-locate": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||||
|
"requires": {
|
||||||
|
"p-limit": "^2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-try": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
|
||||||
|
},
|
||||||
|
"path-exists": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
|
||||||
|
},
|
||||||
|
"require-directory": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
|
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
|
||||||
|
},
|
||||||
|
"require-main-filename": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||||
|
},
|
||||||
|
"set-blocking": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
||||||
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||||
|
"requires": {
|
||||||
|
"is-fullwidth-code-point": "^2.0.0",
|
||||||
|
"strip-ansi": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-final-newline": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="
|
||||||
|
},
|
||||||
|
"which-module": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
||||||
|
},
|
||||||
|
"wrap-ansi": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"string-width": "^4.1.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
|
||||||
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||||
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||||
|
"requires": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"y18n": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
|
||||||
|
},
|
||||||
|
"yargs": {
|
||||||
|
"version": "15.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
||||||
|
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
|
||||||
|
"requires": {
|
||||||
|
"cliui": "^6.0.0",
|
||||||
|
"decamelize": "^1.2.0",
|
||||||
|
"find-up": "^4.1.0",
|
||||||
|
"get-caller-file": "^2.0.1",
|
||||||
|
"require-directory": "^2.1.1",
|
||||||
|
"require-main-filename": "^2.0.0",
|
||||||
|
"set-blocking": "^2.0.0",
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"which-module": "^2.0.0",
|
||||||
|
"y18n": "^4.0.0",
|
||||||
|
"yargs-parser": "^18.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
|
||||||
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||||
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||||
|
"requires": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"yargs-parser": {
|
||||||
|
"version": "18.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||||
|
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
|
||||||
|
"requires": {
|
||||||
|
"camelcase": "^5.0.0",
|
||||||
|
"decamelize": "^1.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
packages/build-utils/test/fixtures/21-npm-workspaces/package.json
vendored
Normal file
8
packages/build-utils/test/fixtures/21-npm-workspaces/package.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "21-npm-workspaces",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"workspaces": [
|
||||||
|
"a",
|
||||||
|
"b"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ const skipFixtures: string[] = [
|
|||||||
'06-zero-config-hugo',
|
'06-zero-config-hugo',
|
||||||
'07-zero-config-jekyll',
|
'07-zero-config-jekyll',
|
||||||
'08-zero-config-middleman',
|
'08-zero-config-middleman',
|
||||||
|
'21-npm-workspaces',
|
||||||
];
|
];
|
||||||
|
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
|||||||
26
packages/build-utils/test/unit.test.ts
vendored
26
packages/build-utils/test/unit.test.ts
vendored
@@ -298,23 +298,29 @@ it(
|
|||||||
);
|
);
|
||||||
|
|
||||||
it('should return lockfileVersion 2 with npm7', async () => {
|
it('should return lockfileVersion 2 with npm7', async () => {
|
||||||
const packageLockJsonPath = path.join(__dirname, 'fixtures', '20-npm-7');
|
const fixture = path.join(__dirname, 'fixtures', '20-npm-7');
|
||||||
const result = await scanParentDirs(packageLockJsonPath);
|
const result = await scanParentDirs(fixture);
|
||||||
|
expect(result.cliType).toEqual('npm');
|
||||||
expect(result.lockfileVersion).toEqual(2);
|
expect(result.lockfileVersion).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not return lockfileVersion with yarn', async () => {
|
it('should not return lockfileVersion with yarn', async () => {
|
||||||
const packageLockJsonPath = path.join(__dirname, 'fixtures', '19-yarn-v2');
|
const fixture = path.join(__dirname, 'fixtures', '19-yarn-v2');
|
||||||
const result = await scanParentDirs(packageLockJsonPath);
|
const result = await scanParentDirs(fixture);
|
||||||
|
expect(result.cliType).toEqual('yarn');
|
||||||
expect(result.lockfileVersion).toEqual(undefined);
|
expect(result.lockfileVersion).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return lockfileVersion 1 with older versions of npm', async () => {
|
it('should return lockfileVersion 1 with older versions of npm', async () => {
|
||||||
const packageLockJsonPath = path.join(
|
const fixture = path.join(__dirname, 'fixtures', '08-yarn-npm/with-npm');
|
||||||
__dirname,
|
const result = await scanParentDirs(fixture);
|
||||||
'fixtures',
|
expect(result.cliType).toEqual('npm');
|
||||||
'08-yarn-npm/with-npm'
|
|
||||||
);
|
|
||||||
const result = await scanParentDirs(packageLockJsonPath);
|
|
||||||
expect(result.lockfileVersion).toEqual(1);
|
expect(result.lockfileVersion).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should detect npm Workspaces', async () => {
|
||||||
|
const fixture = path.join(__dirname, 'fixtures', '21-npm-workspaces/a');
|
||||||
|
const result = await scanParentDirs(fixture);
|
||||||
|
expect(result.cliType).toEqual('npm');
|
||||||
|
expect(result.lockfileVersion).toEqual(2);
|
||||||
|
});
|
||||||
|
|||||||
@@ -10,9 +10,13 @@
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Vercel is the optimal workflow for frontend teams. All-in-one: Static and Jamstack deployment, Serverless Functions, and Global CDN.
|
Vercel is a platform for **static sites and frontend frameworks**, built to integrate with your headless content, commerce, or database.
|
||||||
|
|
||||||
To install the latest version of Vercel CLI, visit [vercel.com/download](https://vercel.com/download) or run this command:
|
We provide a **frictionless developer experience** to take care of the hard things: deploy instantly, scale automatically, and serve personalized content around the globe.
|
||||||
|
|
||||||
|
We make it easy for frontend teams to **develop, preview, and ship** delightful user experiences, where performance is the default.
|
||||||
|
|
||||||
|
To install the latest version of Vercel CLI, run this command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm i -g vercel
|
npm i -g vercel
|
||||||
@@ -26,6 +30,8 @@ cd <PROJECT> # Change directory to the new project
|
|||||||
vercel # Deploy to the cloud
|
vercel # Deploy to the cloud
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Finally, [connect your Git repository to Vercel](https://vercel.com/docs/git) and deploy with `git push`.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
For details on how to use Vercel CLI, check out our [documentation](https://vercel.com/docs).
|
For details on how to use Vercel CLI, check out our [documentation](https://vercel.com/docs).
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vercel",
|
"name": "vercel",
|
||||||
"version": "23.1.0",
|
"version": "23.1.3-canary.0",
|
||||||
"preferGlobal": true,
|
"preferGlobal": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"description": "The command-line interface for Vercel",
|
"description": "The command-line interface for Vercel",
|
||||||
@@ -61,11 +61,11 @@
|
|||||||
"node": ">= 12"
|
"node": ">= 12"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "2.12.0",
|
"@vercel/build-utils": "2.12.3-canary.0",
|
||||||
"@vercel/go": "1.2.3",
|
"@vercel/go": "1.2.4-canary.0",
|
||||||
"@vercel/node": "1.12.0",
|
"@vercel/node": "1.12.2-canary.0",
|
||||||
"@vercel/python": "2.0.5",
|
"@vercel/python": "2.0.6-canary.0",
|
||||||
"@vercel/ruby": "1.2.7",
|
"@vercel/ruby": "1.2.8-canary.0",
|
||||||
"update-notifier": "4.1.0"
|
"update-notifier": "4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -97,10 +97,11 @@
|
|||||||
"@types/semver": "6.0.1",
|
"@types/semver": "6.0.1",
|
||||||
"@types/tar-fs": "1.16.1",
|
"@types/tar-fs": "1.16.1",
|
||||||
"@types/text-table": "0.2.0",
|
"@types/text-table": "0.2.0",
|
||||||
|
"@types/title": "3.4.1",
|
||||||
"@types/universal-analytics": "0.4.2",
|
"@types/universal-analytics": "0.4.2",
|
||||||
"@types/which": "1.3.2",
|
"@types/which": "1.3.2",
|
||||||
"@types/write-json-file": "2.2.1",
|
"@types/write-json-file": "2.2.1",
|
||||||
"@vercel/frameworks": "0.5.0",
|
"@vercel/frameworks": "0.5.1-canary.1",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"@zeit/fun": "0.11.2",
|
"@zeit/fun": "0.11.2",
|
||||||
"@zeit/source-map-support": "0.6.2",
|
"@zeit/source-map-support": "0.6.2",
|
||||||
|
|||||||
@@ -6,12 +6,11 @@ import cardBrands from '../../util/billing/card-brands';
|
|||||||
import success from '../../util/output/success';
|
import success from '../../util/output/success';
|
||||||
import wait from '../../util/output/wait';
|
import wait from '../../util/output/wait';
|
||||||
import chars from '../../util/output/chars';
|
import chars from '../../util/output/chars';
|
||||||
import rightPad from '../../util/output/right-pad';
|
|
||||||
import error from '../../util/output/error';
|
import error from '../../util/output/error';
|
||||||
|
|
||||||
const expDateMiddleware = data => data;
|
const expDateMiddleware = data => data;
|
||||||
|
|
||||||
export default async function({ creditCards, clear = false, contextName }) {
|
export default async function ({ creditCards, clear = false, contextName }) {
|
||||||
const state = {
|
const state = {
|
||||||
error: undefined,
|
error: undefined,
|
||||||
cardGroupLabel: `> ${chalk.bold(
|
cardGroupLabel: `> ${chalk.bold(
|
||||||
@@ -19,13 +18,13 @@ export default async function({ creditCards, clear = false, contextName }) {
|
|||||||
)}`,
|
)}`,
|
||||||
|
|
||||||
name: {
|
name: {
|
||||||
label: rightPad('Full Name', 12),
|
label: 'Full Name'.padEnd(12),
|
||||||
placeholder: 'John Appleseed',
|
placeholder: 'John Appleseed',
|
||||||
validateValue: data => data.trim().length > 0,
|
validateValue: data => data.trim().length > 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
cardNumber: {
|
cardNumber: {
|
||||||
label: rightPad('Number', 12),
|
label: 'Number'.padEnd(12),
|
||||||
mask: 'cc',
|
mask: 'cc',
|
||||||
placeholder: '#### #### #### ####',
|
placeholder: '#### #### #### ####',
|
||||||
validateKeypress: (data, value) => /\d/.test(data) && value.length < 19,
|
validateKeypress: (data, value) => /\d/.test(data) && value.length < 19,
|
||||||
@@ -40,7 +39,7 @@ export default async function({ creditCards, clear = false, contextName }) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
ccv: {
|
ccv: {
|
||||||
label: rightPad('CCV', 12),
|
label: 'CCV'.padEnd(12),
|
||||||
mask: 'ccv',
|
mask: 'ccv',
|
||||||
placeholder: '###',
|
placeholder: '###',
|
||||||
validateValue: data => {
|
validateValue: data => {
|
||||||
@@ -50,7 +49,7 @@ export default async function({ creditCards, clear = false, contextName }) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
expDate: {
|
expDate: {
|
||||||
label: rightPad('Exp. Date', 12),
|
label: 'Exp. Date'.padEnd(12),
|
||||||
mask: 'expDate',
|
mask: 'expDate',
|
||||||
placeholder: 'mm / yyyy',
|
placeholder: 'mm / yyyy',
|
||||||
middleware: expDateMiddleware,
|
middleware: expDateMiddleware,
|
||||||
@@ -147,9 +146,9 @@ export default async function({ creditCards, clear = false, contextName }) {
|
|||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
success(
|
success(
|
||||||
`${state.cardNumber.brand ||
|
`${state.cardNumber.brand || state.cardNumber.card.brand} ending in ${
|
||||||
state.cardNumber.card.brand} ending in ${res.last4 ||
|
res.last4 || res.card.last4
|
||||||
res.card.last4} was added to ${chalk.bold(contextName)}`
|
} was added to ${chalk.bold(contextName)}`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import ms from 'ms';
|
|||||||
import plural from 'pluralize';
|
import plural from 'pluralize';
|
||||||
import { error } from '../../util/error';
|
import { error } from '../../util/error';
|
||||||
import NowCreditCards from '../../util/credit-cards';
|
import NowCreditCards from '../../util/credit-cards';
|
||||||
import indent from '../../util/indent';
|
import indent from '../../util/output/indent';
|
||||||
import listInput from '../../util/input/list';
|
import listInput from '../../util/input/list';
|
||||||
import success from '../../util/output/success';
|
import success from '../../util/output/success';
|
||||||
import promptBool from '../../util/input/prompt-bool';
|
import promptBool from '../../util/input/prompt-bool';
|
||||||
|
|||||||
@@ -1,17 +1,72 @@
|
|||||||
|
import ms from 'ms';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import { resolve, basename } from 'path';
|
import bytes from 'bytes';
|
||||||
import { VercelConfig, fileNameSymbol } from '@vercel/client';
|
import chalk from 'chalk';
|
||||||
|
import { join, resolve, basename } from 'path';
|
||||||
|
import { Dictionary, fileNameSymbol, VercelConfig } from '@vercel/client';
|
||||||
import code from '../../util/output/code';
|
import code from '../../util/output/code';
|
||||||
import highlight from '../../util/output/highlight';
|
import highlight from '../../util/output/highlight';
|
||||||
import { readLocalConfig } from '../../util/config/files';
|
import { readLocalConfig } from '../../util/config/files';
|
||||||
import getArgs from '../../util/get-args';
|
import getArgs from '../../util/get-args';
|
||||||
import { handleError } from '../../util/error';
|
import { handleError } from '../../util/error';
|
||||||
import { help } from './args';
|
|
||||||
import deploy from './latest';
|
|
||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
|
import { write as copy } from 'clipboardy';
|
||||||
|
import { getPrettyError } from '@vercel/build-utils';
|
||||||
|
import toHumanPath from '../../util/humanize-path';
|
||||||
|
import Now from '../../util';
|
||||||
|
import stamp from '../../util/output/stamp';
|
||||||
|
import createDeploy from '../../util/deploy/create-deploy';
|
||||||
|
import getDeploymentByIdOrHost from '../../util/deploy/get-deployment-by-id-or-host';
|
||||||
|
import parseMeta from '../../util/parse-meta';
|
||||||
|
import linkStyle from '../../util/output/link';
|
||||||
|
import param from '../../util/output/param';
|
||||||
|
import {
|
||||||
|
BuildsRateLimited,
|
||||||
|
DeploymentNotFound,
|
||||||
|
DeploymentPermissionDenied,
|
||||||
|
InvalidDeploymentId,
|
||||||
|
DomainNotFound,
|
||||||
|
DomainNotVerified,
|
||||||
|
DomainPermissionDenied,
|
||||||
|
DomainVerificationFailed,
|
||||||
|
InvalidDomain,
|
||||||
|
TooManyRequests,
|
||||||
|
UserAborted,
|
||||||
|
DeploymentsRateLimited,
|
||||||
|
AliasDomainConfigured,
|
||||||
|
MissingBuildScript,
|
||||||
|
ConflictingFilePath,
|
||||||
|
ConflictingPathSegment,
|
||||||
|
BuildError,
|
||||||
|
NotDomainOwner,
|
||||||
|
} from '../../util/errors-ts';
|
||||||
|
import { SchemaValidationFailed } from '../../util/errors';
|
||||||
|
import purchaseDomainIfAvailable from '../../util/domains/purchase-domain-if-available';
|
||||||
|
import confirm from '../../util/input/confirm';
|
||||||
|
import editProjectSettings from '../../util/input/edit-project-settings';
|
||||||
|
import {
|
||||||
|
getLinkedProject,
|
||||||
|
linkFolderToProject,
|
||||||
|
} from '../../util/projects/link';
|
||||||
|
import getProjectName from '../../util/get-project-name';
|
||||||
|
import selectOrg from '../../util/input/select-org';
|
||||||
|
import inputProject from '../../util/input/input-project';
|
||||||
|
import { prependEmoji, emoji } from '../../util/emoji';
|
||||||
|
import { inputRootDirectory } from '../../util/input/input-root-directory';
|
||||||
|
import validatePaths, {
|
||||||
|
validateRootDirectory,
|
||||||
|
} from '../../util/validate-paths';
|
||||||
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
|
import { getPreferredPreviewURL } from '../../util/deploy/get-preferred-preview-url';
|
||||||
|
import { Output } from '../../util/output';
|
||||||
|
import { help } from './args';
|
||||||
|
|
||||||
export default async (client: Client) => {
|
export default async (client: Client) => {
|
||||||
const { output } = client;
|
const {
|
||||||
|
apiUrl,
|
||||||
|
output,
|
||||||
|
authConfig: { token },
|
||||||
|
} = client;
|
||||||
|
|
||||||
let argv = null;
|
let argv = null;
|
||||||
|
|
||||||
@@ -105,5 +160,739 @@ export default async (client: Client) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return deploy(client, paths, localConfig, argv);
|
const { log, debug, error, warn } = output;
|
||||||
|
const debugEnabled = argv['--debug'];
|
||||||
|
|
||||||
|
const { isTTY } = process.stdout;
|
||||||
|
const quiet = !isTTY;
|
||||||
|
|
||||||
|
// check paths
|
||||||
|
const pathValidation = await validatePaths(output, paths);
|
||||||
|
|
||||||
|
if (!pathValidation.valid) {
|
||||||
|
return pathValidation.exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { isFile, path } = pathValidation;
|
||||||
|
const autoConfirm = argv['--confirm'] || isFile;
|
||||||
|
|
||||||
|
// deprecate --name
|
||||||
|
if (argv['--name']) {
|
||||||
|
output.print(
|
||||||
|
`${prependEmoji(
|
||||||
|
`The ${param(
|
||||||
|
'--name'
|
||||||
|
)} option is deprecated (https://vercel.link/name-flag)`,
|
||||||
|
emoji('warning')
|
||||||
|
)}\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve `project` and `org` from .vercel
|
||||||
|
const link = await getLinkedProject(client, path);
|
||||||
|
|
||||||
|
if (link.status === 'error') {
|
||||||
|
return link.exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { org, project, status } = link;
|
||||||
|
|
||||||
|
let newProjectName = null;
|
||||||
|
let rootDirectory = project ? project.rootDirectory : null;
|
||||||
|
let sourceFilesOutsideRootDirectory = true;
|
||||||
|
|
||||||
|
if (status === 'not_linked') {
|
||||||
|
const shouldStartSetup =
|
||||||
|
autoConfirm ||
|
||||||
|
(await confirm(
|
||||||
|
`Set up and deploy ${chalk.cyan(`“${toHumanPath(path)}”`)}?`,
|
||||||
|
true
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!shouldStartSetup) {
|
||||||
|
output.print(`Aborted. Project not set up.\n`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
org = await selectOrg(
|
||||||
|
client,
|
||||||
|
'Which scope do you want to deploy to?',
|
||||||
|
autoConfirm
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED') {
|
||||||
|
output.error(err.message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use `localConfig` here to read the name
|
||||||
|
// even though the `vercel.json` file can change
|
||||||
|
// afterwards, this is fine since the property
|
||||||
|
// will be deprecated and can be replaced with
|
||||||
|
// user input.
|
||||||
|
const detectedProjectName = getProjectName({
|
||||||
|
argv,
|
||||||
|
nowConfig: localConfig || {},
|
||||||
|
isFile,
|
||||||
|
paths,
|
||||||
|
});
|
||||||
|
|
||||||
|
const projectOrNewProjectName = await inputProject(
|
||||||
|
client,
|
||||||
|
org,
|
||||||
|
detectedProjectName,
|
||||||
|
autoConfirm
|
||||||
|
);
|
||||||
|
|
||||||
|
if (typeof projectOrNewProjectName === 'string') {
|
||||||
|
newProjectName = projectOrNewProjectName;
|
||||||
|
rootDirectory = await inputRootDirectory(path, output, autoConfirm);
|
||||||
|
} else {
|
||||||
|
project = projectOrNewProjectName;
|
||||||
|
rootDirectory = project.rootDirectory;
|
||||||
|
sourceFilesOutsideRootDirectory = project.sourceFilesOutsideRootDirectory;
|
||||||
|
|
||||||
|
// we can already link the project
|
||||||
|
await linkFolderToProject(
|
||||||
|
output,
|
||||||
|
path,
|
||||||
|
{
|
||||||
|
projectId: project.id,
|
||||||
|
orgId: org.id,
|
||||||
|
},
|
||||||
|
project.name,
|
||||||
|
org.slug
|
||||||
|
);
|
||||||
|
status = 'linked';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point `org` should be populated
|
||||||
|
if (!org) {
|
||||||
|
throw new Error(`"org" is not defined`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the `contextName` and `currentTeam` as specified by the
|
||||||
|
// Project Settings, so that API calls happen with the proper scope
|
||||||
|
const contextName = org.slug;
|
||||||
|
client.config.currentTeam = org.type === 'team' ? org.id : undefined;
|
||||||
|
|
||||||
|
// if we have `sourceFilesOutsideRootDirectory` set to `true`, we use the current path
|
||||||
|
// and upload the entire directory.
|
||||||
|
const sourcePath =
|
||||||
|
rootDirectory && !sourceFilesOutsideRootDirectory
|
||||||
|
? join(path, rootDirectory)
|
||||||
|
: path;
|
||||||
|
|
||||||
|
if (
|
||||||
|
rootDirectory &&
|
||||||
|
(await validateRootDirectory(
|
||||||
|
output,
|
||||||
|
path,
|
||||||
|
sourcePath,
|
||||||
|
project
|
||||||
|
? `To change your Project Settings, go to https://vercel.com/${org?.slug}/${project.name}/settings`
|
||||||
|
: ''
|
||||||
|
)) === false
|
||||||
|
) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If Root Directory is used we'll try to read the config
|
||||||
|
// from there instead and use it if it exists.
|
||||||
|
if (rootDirectory) {
|
||||||
|
const rootDirectoryConfig = readLocalConfig(join(path, rootDirectory));
|
||||||
|
|
||||||
|
if (rootDirectoryConfig) {
|
||||||
|
debug(`Read local config from root directory (${rootDirectory})`);
|
||||||
|
localConfig = rootDirectoryConfig;
|
||||||
|
} else if (localConfig) {
|
||||||
|
output.print(
|
||||||
|
`${prependEmoji(
|
||||||
|
`The ${highlight(
|
||||||
|
localConfig[fileNameSymbol]!
|
||||||
|
)} file should be inside of the provided root directory.`,
|
||||||
|
emoji('warning')
|
||||||
|
)}\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localConfig = localConfig || {};
|
||||||
|
|
||||||
|
if (localConfig.name) {
|
||||||
|
output.print(
|
||||||
|
`${prependEmoji(
|
||||||
|
`The ${code('name')} property in ${highlight(
|
||||||
|
localConfig[fileNameSymbol]!
|
||||||
|
)} is deprecated (https://vercel.link/name-prop)`,
|
||||||
|
emoji('warning')
|
||||||
|
)}\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build `env`
|
||||||
|
const isObject = (item: any) =>
|
||||||
|
Object.prototype.toString.call(item) === '[object Object]';
|
||||||
|
|
||||||
|
// This validation needs to happen on the client side because
|
||||||
|
// the data is merged with other data before it is passed to the API (which
|
||||||
|
// also does schema validation).
|
||||||
|
if (typeof localConfig.env !== 'undefined' && !isObject(localConfig.env)) {
|
||||||
|
error(
|
||||||
|
`The ${code('env')} property in ${highlight(
|
||||||
|
localConfig[fileNameSymbol]!
|
||||||
|
)} needs to be an object`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof localConfig.build !== 'undefined') {
|
||||||
|
if (!isObject(localConfig.build)) {
|
||||||
|
error(
|
||||||
|
`The ${code('build')} property in ${highlight(
|
||||||
|
localConfig[fileNameSymbol]!
|
||||||
|
)} needs to be an object`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof localConfig.build.env !== 'undefined' &&
|
||||||
|
!isObject(localConfig.build.env)
|
||||||
|
) {
|
||||||
|
error(
|
||||||
|
`The ${code('build.env')} property in ${highlight(
|
||||||
|
localConfig[fileNameSymbol]!
|
||||||
|
)} needs to be an object`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build `meta`
|
||||||
|
const meta = Object.assign(
|
||||||
|
{},
|
||||||
|
parseMeta(localConfig.meta),
|
||||||
|
parseMeta(argv['--meta'])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Merge dotenv config, `env` from vercel.json, and `--env` / `-e` arguments
|
||||||
|
const deploymentEnv = Object.assign(
|
||||||
|
{},
|
||||||
|
parseEnv(localConfig.env),
|
||||||
|
parseEnv(argv['--env'])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Merge build env out of `build.env` from vercel.json, and `--build-env` args
|
||||||
|
const deploymentBuildEnv = Object.assign(
|
||||||
|
{},
|
||||||
|
parseEnv(localConfig.build && localConfig.build.env),
|
||||||
|
parseEnv(argv['--build-env'])
|
||||||
|
);
|
||||||
|
|
||||||
|
// If there's any undefined values, then inherit them from this process
|
||||||
|
try {
|
||||||
|
await addProcessEnv(log, deploymentEnv);
|
||||||
|
await addProcessEnv(log, deploymentBuildEnv);
|
||||||
|
} catch (err) {
|
||||||
|
error(err.message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build `regions`
|
||||||
|
const regionFlag = (argv['--regions'] || '')
|
||||||
|
.split(',')
|
||||||
|
.map((s: string) => s.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
const regions = regionFlag.length > 0 ? regionFlag : localConfig.regions;
|
||||||
|
|
||||||
|
// build `target`
|
||||||
|
let target;
|
||||||
|
if (argv['--target']) {
|
||||||
|
const deprecatedTarget = argv['--target'];
|
||||||
|
|
||||||
|
if (!['staging', 'production'].includes(deprecatedTarget)) {
|
||||||
|
error(
|
||||||
|
`The specified ${param('--target')} ${code(
|
||||||
|
deprecatedTarget
|
||||||
|
)} is not valid`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deprecatedTarget === 'production') {
|
||||||
|
warn(
|
||||||
|
'We recommend using the much shorter `--prod` option instead of `--target production` (deprecated)'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.debug(`Setting target to ${deprecatedTarget}`);
|
||||||
|
target = deprecatedTarget;
|
||||||
|
} else if (argv['--prod']) {
|
||||||
|
output.debug('Setting target to production');
|
||||||
|
target = 'production';
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTeam = org?.type === 'team' ? org.id : undefined;
|
||||||
|
const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam });
|
||||||
|
let deployStamp = stamp();
|
||||||
|
let deployment = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const createArgs: any = {
|
||||||
|
name: project ? project.name : newProjectName,
|
||||||
|
env: deploymentEnv,
|
||||||
|
build: { env: deploymentBuildEnv },
|
||||||
|
forceNew: argv['--force'],
|
||||||
|
withCache: argv['--with-cache'],
|
||||||
|
quiet,
|
||||||
|
wantsPublic: argv['--public'] || localConfig.public,
|
||||||
|
isFile,
|
||||||
|
type: null,
|
||||||
|
nowConfig: localConfig,
|
||||||
|
regions,
|
||||||
|
meta,
|
||||||
|
deployStamp,
|
||||||
|
target,
|
||||||
|
skipAutoDetectionConfirmation: autoConfirm,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!localConfig.builds || localConfig.builds.length === 0) {
|
||||||
|
// Only add projectSettings for zero config deployments
|
||||||
|
createArgs.projectSettings = { sourceFilesOutsideRootDirectory };
|
||||||
|
}
|
||||||
|
|
||||||
|
deployment = await createDeploy(
|
||||||
|
client,
|
||||||
|
now,
|
||||||
|
contextName,
|
||||||
|
[sourcePath],
|
||||||
|
createArgs,
|
||||||
|
org,
|
||||||
|
!project && !isFile,
|
||||||
|
path
|
||||||
|
);
|
||||||
|
|
||||||
|
if (deployment.code === 'missing_project_settings') {
|
||||||
|
let { projectSettings, framework } = deployment;
|
||||||
|
if (rootDirectory) {
|
||||||
|
projectSettings.rootDirectory = rootDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof sourceFilesOutsideRootDirectory !== 'undefined') {
|
||||||
|
projectSettings.sourceFilesOutsideRootDirectory =
|
||||||
|
sourceFilesOutsideRootDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = await editProjectSettings(
|
||||||
|
output,
|
||||||
|
projectSettings,
|
||||||
|
framework
|
||||||
|
);
|
||||||
|
|
||||||
|
// deploy again, but send projectSettings this time
|
||||||
|
createArgs.projectSettings = settings;
|
||||||
|
|
||||||
|
deployStamp = stamp();
|
||||||
|
createArgs.deployStamp = deployStamp;
|
||||||
|
deployment = await createDeploy(
|
||||||
|
client,
|
||||||
|
now,
|
||||||
|
contextName,
|
||||||
|
[sourcePath],
|
||||||
|
createArgs,
|
||||||
|
org,
|
||||||
|
false,
|
||||||
|
path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deployment instanceof NotDomainOwner) {
|
||||||
|
output.error(deployment.message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deployment instanceof Error) {
|
||||||
|
output.error(
|
||||||
|
deployment.message ||
|
||||||
|
'An unexpected error occurred while deploying your project',
|
||||||
|
undefined,
|
||||||
|
'https://vercel.link/help',
|
||||||
|
'Contact Support'
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deployment.readyState === 'CANCELED') {
|
||||||
|
output.print('The deployment has been canceled.\n');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deploymentResponse = await getDeploymentByIdOrHost(
|
||||||
|
client,
|
||||||
|
contextName,
|
||||||
|
deployment.id,
|
||||||
|
'v10'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
deploymentResponse instanceof DeploymentNotFound ||
|
||||||
|
deploymentResponse instanceof DeploymentPermissionDenied ||
|
||||||
|
deploymentResponse instanceof InvalidDeploymentId
|
||||||
|
) {
|
||||||
|
output.error(deploymentResponse.message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deployment === null) {
|
||||||
|
error('Uploading failed. Please try again.');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
debug(`Error: ${err}\n${err.stack}`);
|
||||||
|
|
||||||
|
if (err instanceof NotDomainOwner) {
|
||||||
|
output.error(err.message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err instanceof DomainNotFound && err.meta && err.meta.domain) {
|
||||||
|
output.debug(
|
||||||
|
`The domain ${err.meta.domain} was not found, trying to purchase it`
|
||||||
|
);
|
||||||
|
|
||||||
|
const purchase = await purchaseDomainIfAvailable(
|
||||||
|
output,
|
||||||
|
client,
|
||||||
|
err.meta.domain,
|
||||||
|
contextName
|
||||||
|
);
|
||||||
|
|
||||||
|
if (purchase === true) {
|
||||||
|
output.success(`Successfully purchased the domain ${err.meta.domain}!`);
|
||||||
|
|
||||||
|
// We exit if the purchase is completed since
|
||||||
|
// the domain verification can take some time
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (purchase === false || purchase instanceof UserAborted) {
|
||||||
|
handleCreateDeployError(output, deployment, localConfig);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCreateDeployError(output, purchase, localConfig);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
err instanceof DomainNotFound ||
|
||||||
|
err instanceof DomainNotVerified ||
|
||||||
|
err instanceof NotDomainOwner ||
|
||||||
|
err instanceof DomainPermissionDenied ||
|
||||||
|
err instanceof DomainVerificationFailed ||
|
||||||
|
err instanceof SchemaValidationFailed ||
|
||||||
|
err instanceof InvalidDomain ||
|
||||||
|
err instanceof DeploymentNotFound ||
|
||||||
|
err instanceof BuildsRateLimited ||
|
||||||
|
err instanceof DeploymentsRateLimited ||
|
||||||
|
err instanceof AliasDomainConfigured ||
|
||||||
|
err instanceof MissingBuildScript ||
|
||||||
|
err instanceof ConflictingFilePath ||
|
||||||
|
err instanceof ConflictingPathSegment
|
||||||
|
) {
|
||||||
|
handleCreateDeployError(output, err, localConfig);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err instanceof BuildError) {
|
||||||
|
output.error(err.message || 'Build failed');
|
||||||
|
output.error(
|
||||||
|
`Check your logs at https://${now.url}/_logs or run ${getCommandName(
|
||||||
|
`logs ${now.url}`
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err.keyword === 'additionalProperties' && err.dataPath === '.scale') {
|
||||||
|
const { additionalProperty = '' } = err.params || {};
|
||||||
|
const message = `Invalid DC name for the scale option: ${additionalProperty}`;
|
||||||
|
error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err.code === 'size_limit_exceeded') {
|
||||||
|
const { sizeLimit = 0 } = err;
|
||||||
|
const message = `File size limit exceeded (${bytes(sizeLimit)})`;
|
||||||
|
error(message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return printDeploymentStatus(
|
||||||
|
output,
|
||||||
|
client,
|
||||||
|
deployment,
|
||||||
|
deployStamp,
|
||||||
|
!argv['--no-clipboard'],
|
||||||
|
isFile
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleCreateDeployError(
|
||||||
|
output: Output,
|
||||||
|
error: Error,
|
||||||
|
localConfig: VercelConfig
|
||||||
|
) {
|
||||||
|
if (error instanceof InvalidDomain) {
|
||||||
|
output.error(`The domain ${error.meta.domain} is not valid`);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (error instanceof DomainVerificationFailed) {
|
||||||
|
output.error(
|
||||||
|
`The domain used as a suffix ${chalk.underline(
|
||||||
|
error.meta.domain
|
||||||
|
)} is not verified and can't be used as custom suffix.`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (error instanceof DomainPermissionDenied) {
|
||||||
|
output.error(
|
||||||
|
`You don't have permissions to access the domain used as a suffix ${chalk.underline(
|
||||||
|
error.meta.domain
|
||||||
|
)}.`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (error instanceof SchemaValidationFailed) {
|
||||||
|
const niceError = getPrettyError(error.meta);
|
||||||
|
const fileName = localConfig[fileNameSymbol] || 'vercel.json';
|
||||||
|
niceError.message = `Invalid ${fileName} - ${niceError.message}`;
|
||||||
|
output.prettyError(niceError);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (error instanceof TooManyRequests) {
|
||||||
|
output.error(
|
||||||
|
`Too many requests detected for ${error.meta.api} API. Try again in ${ms(
|
||||||
|
error.meta.retryAfter * 1000,
|
||||||
|
{
|
||||||
|
long: true,
|
||||||
|
}
|
||||||
|
)}.`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (error instanceof DomainNotVerified) {
|
||||||
|
output.error(
|
||||||
|
`The domain used as an alias ${chalk.underline(
|
||||||
|
error.meta.domain
|
||||||
|
)} is not verified yet. Please verify it.`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (error instanceof BuildsRateLimited) {
|
||||||
|
output.error(error.message);
|
||||||
|
output.note(
|
||||||
|
`Run ${getCommandName('upgrade')} to increase your builds limit.`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
error instanceof DeploymentNotFound ||
|
||||||
|
error instanceof NotDomainOwner ||
|
||||||
|
error instanceof DeploymentsRateLimited ||
|
||||||
|
error instanceof AliasDomainConfigured ||
|
||||||
|
error instanceof MissingBuildScript ||
|
||||||
|
error instanceof ConflictingFilePath ||
|
||||||
|
error instanceof ConflictingPathSegment
|
||||||
|
) {
|
||||||
|
output.error(error.message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const addProcessEnv = async (
|
||||||
|
log: (str: string) => void,
|
||||||
|
env: typeof process.env
|
||||||
|
) => {
|
||||||
|
let val;
|
||||||
|
|
||||||
|
for (const key of Object.keys(env)) {
|
||||||
|
if (typeof env[key] !== 'undefined') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = process.env[key];
|
||||||
|
|
||||||
|
if (typeof val === 'string') {
|
||||||
|
log(
|
||||||
|
`Reading ${chalk.bold(
|
||||||
|
`"${chalk.bold(key)}"`
|
||||||
|
)} from your env (as no value was specified)`
|
||||||
|
);
|
||||||
|
// Escape value if it begins with @
|
||||||
|
env[key] = val.replace(/^@/, '\\@');
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`No value specified for env ${chalk.bold(
|
||||||
|
`"${chalk.bold(key)}"`
|
||||||
|
)} and it was not found in your env.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const printDeploymentStatus = async (
|
||||||
|
output: Output,
|
||||||
|
client: Client,
|
||||||
|
{
|
||||||
|
readyState,
|
||||||
|
alias: aliasList,
|
||||||
|
aliasError,
|
||||||
|
target,
|
||||||
|
indications,
|
||||||
|
url: deploymentUrl,
|
||||||
|
aliasWarning,
|
||||||
|
}: {
|
||||||
|
readyState: string;
|
||||||
|
alias: string[];
|
||||||
|
aliasError: Error;
|
||||||
|
target: string;
|
||||||
|
indications: any;
|
||||||
|
url: string;
|
||||||
|
aliasWarning?: {
|
||||||
|
code: string;
|
||||||
|
message: string;
|
||||||
|
link?: string;
|
||||||
|
action?: string;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
deployStamp: () => string,
|
||||||
|
isClipboardEnabled: boolean,
|
||||||
|
isFile: boolean
|
||||||
|
) => {
|
||||||
|
indications = indications || [];
|
||||||
|
const isProdDeployment = target === 'production';
|
||||||
|
|
||||||
|
if (readyState !== 'READY') {
|
||||||
|
output.error(
|
||||||
|
`Your deployment failed. Please retry later. More: https://err.sh/vercel/deployment-error`
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aliasError) {
|
||||||
|
output.warn(
|
||||||
|
`Failed to assign aliases${
|
||||||
|
aliasError.message ? `: ${aliasError.message}` : ''
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// print preview/production url
|
||||||
|
let previewUrl: string;
|
||||||
|
let isWildcard: boolean;
|
||||||
|
if (!isFile && Array.isArray(aliasList) && aliasList.length > 0) {
|
||||||
|
const previewUrlInfo = await getPreferredPreviewURL(client, aliasList);
|
||||||
|
if (previewUrlInfo) {
|
||||||
|
isWildcard = previewUrlInfo.isWildcard;
|
||||||
|
previewUrl = previewUrlInfo.previewUrl;
|
||||||
|
} else {
|
||||||
|
isWildcard = false;
|
||||||
|
previewUrl = `https://${deploymentUrl}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// fallback to deployment url
|
||||||
|
isWildcard = false;
|
||||||
|
previewUrl = `https://${deploymentUrl}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy to clipboard
|
||||||
|
let isCopiedToClipboard = false;
|
||||||
|
if (isClipboardEnabled && !isWildcard) {
|
||||||
|
try {
|
||||||
|
await copy(previewUrl);
|
||||||
|
isCopiedToClipboard = true;
|
||||||
|
} catch (err) {
|
||||||
|
output.debug(`Error copyind to clipboard: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output.print(
|
||||||
|
prependEmoji(
|
||||||
|
`${isProdDeployment ? 'Production' : 'Preview'}: ${chalk.bold(
|
||||||
|
previewUrl
|
||||||
|
)}${
|
||||||
|
isCopiedToClipboard ? chalk.gray(` [copied to clipboard]`) : ''
|
||||||
|
} ${deployStamp()}`,
|
||||||
|
emoji('success')
|
||||||
|
) + `\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aliasWarning?.message) {
|
||||||
|
indications.push({
|
||||||
|
type: 'warning',
|
||||||
|
payload: aliasWarning.message,
|
||||||
|
link: aliasWarning.link,
|
||||||
|
action: aliasWarning.action,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const newline = '\n';
|
||||||
|
for (let indication of indications) {
|
||||||
|
const message =
|
||||||
|
prependEmoji(chalk.dim(indication.payload), emoji(indication.type)) +
|
||||||
|
newline;
|
||||||
|
let link = '';
|
||||||
|
if (indication.link)
|
||||||
|
link =
|
||||||
|
chalk.dim(
|
||||||
|
`${indication.action || 'Learn More'}: ${linkStyle(indication.link)}`
|
||||||
|
) + newline;
|
||||||
|
output.print(message + link);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Converts `env` Arrays, Strings and Objects into env Objects.
|
||||||
|
const parseEnv = (env?: string[] | Dictionary<string>) => {
|
||||||
|
if (!env) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof env === 'string') {
|
||||||
|
// a single `--env` arg comes in as a String
|
||||||
|
env = [env];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(env)) {
|
||||||
|
return env.reduce((o, e) => {
|
||||||
|
let key;
|
||||||
|
let value;
|
||||||
|
const equalsSign = e.indexOf('=');
|
||||||
|
|
||||||
|
if (equalsSign === -1) {
|
||||||
|
key = e;
|
||||||
|
} else {
|
||||||
|
key = e.substr(0, equalsSign);
|
||||||
|
value = e.substr(equalsSign + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
o[key] = value;
|
||||||
|
return o;
|
||||||
|
}, {} as Dictionary<string | undefined>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume it's already an Object
|
||||||
|
return env;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,808 +0,0 @@
|
|||||||
import ms from 'ms';
|
|
||||||
import bytes from 'bytes';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { write as copy } from 'clipboardy';
|
|
||||||
import chalk from 'chalk';
|
|
||||||
import { Dictionary, fileNameSymbol, VercelConfig } from '@vercel/client';
|
|
||||||
import { getPrettyError } from '@vercel/build-utils';
|
|
||||||
import { handleError } from '../../util/error';
|
|
||||||
import toHumanPath from '../../util/humanize-path';
|
|
||||||
import Now from '../../util';
|
|
||||||
import stamp from '../../util/output/stamp';
|
|
||||||
import createDeploy from '../../util/deploy/create-deploy';
|
|
||||||
import getDeploymentByIdOrHost from '../../util/deploy/get-deployment-by-id-or-host';
|
|
||||||
import parseMeta from '../../util/parse-meta';
|
|
||||||
import code from '../../util/output/code';
|
|
||||||
import linkStyle from '../../util/output/link';
|
|
||||||
import param from '../../util/output/param';
|
|
||||||
import highlight from '../../util/output/highlight';
|
|
||||||
import {
|
|
||||||
BuildsRateLimited,
|
|
||||||
DeploymentNotFound,
|
|
||||||
DeploymentPermissionDenied,
|
|
||||||
InvalidDeploymentId,
|
|
||||||
DomainNotFound,
|
|
||||||
DomainNotVerified,
|
|
||||||
DomainPermissionDenied,
|
|
||||||
DomainVerificationFailed,
|
|
||||||
InvalidDomain,
|
|
||||||
TooManyRequests,
|
|
||||||
UserAborted,
|
|
||||||
DeploymentsRateLimited,
|
|
||||||
AliasDomainConfigured,
|
|
||||||
MissingBuildScript,
|
|
||||||
ConflictingFilePath,
|
|
||||||
ConflictingPathSegment,
|
|
||||||
BuildError,
|
|
||||||
NotDomainOwner,
|
|
||||||
} from '../../util/errors-ts';
|
|
||||||
import { SchemaValidationFailed } from '../../util/errors';
|
|
||||||
import purchaseDomainIfAvailable from '../../util/domains/purchase-domain-if-available';
|
|
||||||
import confirm from '../../util/input/confirm';
|
|
||||||
import editProjectSettings from '../../util/input/edit-project-settings';
|
|
||||||
import {
|
|
||||||
getLinkedProject,
|
|
||||||
linkFolderToProject,
|
|
||||||
} from '../../util/projects/link';
|
|
||||||
import getProjectName from '../../util/get-project-name';
|
|
||||||
import selectOrg from '../../util/input/select-org';
|
|
||||||
import inputProject from '../../util/input/input-project';
|
|
||||||
import { prependEmoji, emoji } from '../../util/emoji';
|
|
||||||
import { inputRootDirectory } from '../../util/input/input-root-directory';
|
|
||||||
import validatePaths, {
|
|
||||||
validateRootDirectory,
|
|
||||||
} from '../../util/validate-paths';
|
|
||||||
import { readLocalConfig } from '../../util/config/files';
|
|
||||||
import { getCommandName } from '../../util/pkg-name';
|
|
||||||
import { getPreferredPreviewURL } from '../../util/deploy/get-preferred-preview-url';
|
|
||||||
import { Output } from '../../util/output';
|
|
||||||
import Client from '../../util/client';
|
|
||||||
|
|
||||||
const addProcessEnv = async (
|
|
||||||
log: (str: string) => void,
|
|
||||||
env: typeof process.env
|
|
||||||
) => {
|
|
||||||
let val;
|
|
||||||
|
|
||||||
for (const key of Object.keys(env)) {
|
|
||||||
if (typeof env[key] !== 'undefined') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
val = process.env[key];
|
|
||||||
|
|
||||||
if (typeof val === 'string') {
|
|
||||||
log(
|
|
||||||
`Reading ${chalk.bold(
|
|
||||||
`"${chalk.bold(key)}"`
|
|
||||||
)} from your env (as no value was specified)`
|
|
||||||
);
|
|
||||||
// Escape value if it begins with @
|
|
||||||
env[key] = val.replace(/^@/, '\\@');
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
`No value specified for env ${chalk.bold(
|
|
||||||
`"${chalk.bold(key)}"`
|
|
||||||
)} and it was not found in your env.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const printDeploymentStatus = async (
|
|
||||||
output: Output,
|
|
||||||
client: Client,
|
|
||||||
{
|
|
||||||
readyState,
|
|
||||||
alias: aliasList,
|
|
||||||
aliasError,
|
|
||||||
target,
|
|
||||||
indications,
|
|
||||||
url: deploymentUrl,
|
|
||||||
aliasWarning,
|
|
||||||
}: {
|
|
||||||
readyState: string;
|
|
||||||
alias: string[];
|
|
||||||
aliasError: Error;
|
|
||||||
target: string;
|
|
||||||
indications: any;
|
|
||||||
url: string;
|
|
||||||
aliasWarning?: {
|
|
||||||
code: string;
|
|
||||||
message: string;
|
|
||||||
link?: string;
|
|
||||||
action?: string;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
deployStamp: () => string,
|
|
||||||
isClipboardEnabled: boolean,
|
|
||||||
isFile: boolean
|
|
||||||
) => {
|
|
||||||
indications = indications || [];
|
|
||||||
const isProdDeployment = target === 'production';
|
|
||||||
|
|
||||||
if (readyState !== 'READY') {
|
|
||||||
output.error(
|
|
||||||
`Your deployment failed. Please retry later. More: https://err.sh/vercel/deployment-error`
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aliasError) {
|
|
||||||
output.warn(
|
|
||||||
`Failed to assign aliases${
|
|
||||||
aliasError.message ? `: ${aliasError.message}` : ''
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// print preview/production url
|
|
||||||
let previewUrl: string;
|
|
||||||
let isWildcard: boolean;
|
|
||||||
if (!isFile && Array.isArray(aliasList) && aliasList.length > 0) {
|
|
||||||
const previewUrlInfo = await getPreferredPreviewURL(client, aliasList);
|
|
||||||
if (previewUrlInfo) {
|
|
||||||
isWildcard = previewUrlInfo.isWildcard;
|
|
||||||
previewUrl = previewUrlInfo.previewUrl;
|
|
||||||
} else {
|
|
||||||
isWildcard = false;
|
|
||||||
previewUrl = `https://${deploymentUrl}`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// fallback to deployment url
|
|
||||||
isWildcard = false;
|
|
||||||
previewUrl = `https://${deploymentUrl}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy to clipboard
|
|
||||||
let isCopiedToClipboard = false;
|
|
||||||
if (isClipboardEnabled && !isWildcard) {
|
|
||||||
try {
|
|
||||||
await copy(previewUrl);
|
|
||||||
isCopiedToClipboard = true;
|
|
||||||
} catch (err) {
|
|
||||||
output.debug(`Error copyind to clipboard: ${err}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output.print(
|
|
||||||
prependEmoji(
|
|
||||||
`${isProdDeployment ? 'Production' : 'Preview'}: ${chalk.bold(
|
|
||||||
previewUrl
|
|
||||||
)}${
|
|
||||||
isCopiedToClipboard ? chalk.gray(` [copied to clipboard]`) : ''
|
|
||||||
} ${deployStamp()}`,
|
|
||||||
emoji('success')
|
|
||||||
) + `\n`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aliasWarning?.message) {
|
|
||||||
indications.push({
|
|
||||||
type: 'warning',
|
|
||||||
payload: aliasWarning.message,
|
|
||||||
link: aliasWarning.link,
|
|
||||||
action: aliasWarning.action,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const newline = '\n';
|
|
||||||
for (let indication of indications) {
|
|
||||||
const message =
|
|
||||||
prependEmoji(chalk.dim(indication.payload), emoji(indication.type)) +
|
|
||||||
newline;
|
|
||||||
let link = '';
|
|
||||||
if (indication.link)
|
|
||||||
link =
|
|
||||||
chalk.dim(
|
|
||||||
`${indication.action || 'Learn More'}: ${linkStyle(indication.link)}`
|
|
||||||
) + newline;
|
|
||||||
output.print(message + link);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Converts `env` Arrays, Strings and Objects into env Objects.
|
|
||||||
const parseEnv = (env?: string[] | Dictionary<string>) => {
|
|
||||||
if (!env) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof env === 'string') {
|
|
||||||
// a single `--env` arg comes in as a String
|
|
||||||
env = [env];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(env)) {
|
|
||||||
return env.reduce((o, e) => {
|
|
||||||
let key;
|
|
||||||
let value;
|
|
||||||
const equalsSign = e.indexOf('=');
|
|
||||||
|
|
||||||
if (equalsSign === -1) {
|
|
||||||
key = e;
|
|
||||||
} else {
|
|
||||||
key = e.substr(0, equalsSign);
|
|
||||||
value = e.substr(equalsSign + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
o[key] = value;
|
|
||||||
return o;
|
|
||||||
}, {} as Dictionary<string | undefined>);
|
|
||||||
}
|
|
||||||
|
|
||||||
// assume it's already an Object
|
|
||||||
return env;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function main(
|
|
||||||
client: Client,
|
|
||||||
paths: string[],
|
|
||||||
localConfig: VercelConfig | null,
|
|
||||||
argv: any
|
|
||||||
) {
|
|
||||||
const {
|
|
||||||
apiUrl,
|
|
||||||
output,
|
|
||||||
authConfig: { token },
|
|
||||||
} = client;
|
|
||||||
const { log, debug, error, warn } = output;
|
|
||||||
const debugEnabled = argv['--debug'];
|
|
||||||
|
|
||||||
const { isTTY } = process.stdout;
|
|
||||||
const quiet = !isTTY;
|
|
||||||
|
|
||||||
// check paths
|
|
||||||
const pathValidation = await validatePaths(output, paths);
|
|
||||||
|
|
||||||
if (!pathValidation.valid) {
|
|
||||||
return pathValidation.exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { isFile, path } = pathValidation;
|
|
||||||
const autoConfirm = argv['--confirm'] || isFile;
|
|
||||||
|
|
||||||
// deprecate --name
|
|
||||||
if (argv['--name']) {
|
|
||||||
output.print(
|
|
||||||
`${prependEmoji(
|
|
||||||
`The ${param(
|
|
||||||
'--name'
|
|
||||||
)} option is deprecated (https://vercel.link/name-flag)`,
|
|
||||||
emoji('warning')
|
|
||||||
)}\n`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieve `project` and `org` from .vercel
|
|
||||||
const link = await getLinkedProject(client, path);
|
|
||||||
|
|
||||||
if (link.status === 'error') {
|
|
||||||
return link.exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { org, project, status } = link;
|
|
||||||
|
|
||||||
let newProjectName = null;
|
|
||||||
let rootDirectory = project ? project.rootDirectory : null;
|
|
||||||
let sourceFilesOutsideRootDirectory = true;
|
|
||||||
|
|
||||||
if (status === 'not_linked') {
|
|
||||||
const shouldStartSetup =
|
|
||||||
autoConfirm ||
|
|
||||||
(await confirm(
|
|
||||||
`Set up and deploy ${chalk.cyan(`“${toHumanPath(path)}”`)}?`,
|
|
||||||
true
|
|
||||||
));
|
|
||||||
|
|
||||||
if (!shouldStartSetup) {
|
|
||||||
output.print(`Aborted. Project not set up.\n`);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
org = await selectOrg(
|
|
||||||
client,
|
|
||||||
'Which scope do you want to deploy to?',
|
|
||||||
autoConfirm
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
if (err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED') {
|
|
||||||
output.error(err.message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use `localConfig` here to read the name
|
|
||||||
// even though the `vercel.json` file can change
|
|
||||||
// afterwards, this is fine since the property
|
|
||||||
// will be deprecated and can be replaced with
|
|
||||||
// user input.
|
|
||||||
const detectedProjectName = getProjectName({
|
|
||||||
argv,
|
|
||||||
nowConfig: localConfig || {},
|
|
||||||
isFile,
|
|
||||||
paths,
|
|
||||||
});
|
|
||||||
|
|
||||||
const projectOrNewProjectName = await inputProject(
|
|
||||||
output,
|
|
||||||
client,
|
|
||||||
org,
|
|
||||||
detectedProjectName,
|
|
||||||
autoConfirm
|
|
||||||
);
|
|
||||||
|
|
||||||
if (typeof projectOrNewProjectName === 'string') {
|
|
||||||
newProjectName = projectOrNewProjectName;
|
|
||||||
rootDirectory = await inputRootDirectory(path, output, autoConfirm);
|
|
||||||
} else {
|
|
||||||
project = projectOrNewProjectName;
|
|
||||||
rootDirectory = project.rootDirectory;
|
|
||||||
sourceFilesOutsideRootDirectory = project.sourceFilesOutsideRootDirectory;
|
|
||||||
|
|
||||||
// we can already link the project
|
|
||||||
await linkFolderToProject(
|
|
||||||
output,
|
|
||||||
path,
|
|
||||||
{
|
|
||||||
projectId: project.id,
|
|
||||||
orgId: org.id,
|
|
||||||
},
|
|
||||||
project.name,
|
|
||||||
org.slug
|
|
||||||
);
|
|
||||||
status = 'linked';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point `org` should be populated
|
|
||||||
if (!org) {
|
|
||||||
throw new Error(`"org" is not defined`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the `contextName` and `currentTeam` as specified by the
|
|
||||||
// Project Settings, so that API calls happen with the proper scope
|
|
||||||
const contextName = org.slug;
|
|
||||||
client.config.currentTeam = org.type === 'team' ? org.id : undefined;
|
|
||||||
|
|
||||||
// if we have `sourceFilesOutsideRootDirectory` set to `true`, we use the current path
|
|
||||||
// and upload the entire directory.
|
|
||||||
const sourcePath =
|
|
||||||
rootDirectory && !sourceFilesOutsideRootDirectory
|
|
||||||
? join(path, rootDirectory)
|
|
||||||
: path;
|
|
||||||
|
|
||||||
if (
|
|
||||||
rootDirectory &&
|
|
||||||
(await validateRootDirectory(
|
|
||||||
output,
|
|
||||||
path,
|
|
||||||
sourcePath,
|
|
||||||
project
|
|
||||||
? `To change your Project Settings, go to https://vercel.com/${org?.slug}/${project.name}/settings`
|
|
||||||
: ''
|
|
||||||
)) === false
|
|
||||||
) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If Root Directory is used we'll try to read the config
|
|
||||||
// from there instead and use it if it exists.
|
|
||||||
if (rootDirectory) {
|
|
||||||
const rootDirectoryConfig = readLocalConfig(join(path, rootDirectory));
|
|
||||||
|
|
||||||
if (rootDirectoryConfig) {
|
|
||||||
debug(`Read local config from root directory (${rootDirectory})`);
|
|
||||||
localConfig = rootDirectoryConfig;
|
|
||||||
} else if (localConfig) {
|
|
||||||
output.print(
|
|
||||||
`${prependEmoji(
|
|
||||||
`The ${highlight(
|
|
||||||
localConfig[fileNameSymbol]!
|
|
||||||
)} file should be inside of the provided root directory.`,
|
|
||||||
emoji('warning')
|
|
||||||
)}\n`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
localConfig = localConfig || {};
|
|
||||||
|
|
||||||
if (localConfig.name) {
|
|
||||||
output.print(
|
|
||||||
`${prependEmoji(
|
|
||||||
`The ${code('name')} property in ${highlight(
|
|
||||||
localConfig[fileNameSymbol]!
|
|
||||||
)} is deprecated (https://vercel.link/name-prop)`,
|
|
||||||
emoji('warning')
|
|
||||||
)}\n`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// build `env`
|
|
||||||
const isObject = (item: any) =>
|
|
||||||
Object.prototype.toString.call(item) === '[object Object]';
|
|
||||||
|
|
||||||
// This validation needs to happen on the client side because
|
|
||||||
// the data is merged with other data before it is passed to the API (which
|
|
||||||
// also does schema validation).
|
|
||||||
if (typeof localConfig.env !== 'undefined' && !isObject(localConfig.env)) {
|
|
||||||
error(
|
|
||||||
`The ${code('env')} property in ${highlight(
|
|
||||||
localConfig[fileNameSymbol]!
|
|
||||||
)} needs to be an object`
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof localConfig.build !== 'undefined') {
|
|
||||||
if (!isObject(localConfig.build)) {
|
|
||||||
error(
|
|
||||||
`The ${code('build')} property in ${highlight(
|
|
||||||
localConfig[fileNameSymbol]!
|
|
||||||
)} needs to be an object`
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
typeof localConfig.build.env !== 'undefined' &&
|
|
||||||
!isObject(localConfig.build.env)
|
|
||||||
) {
|
|
||||||
error(
|
|
||||||
`The ${code('build.env')} property in ${highlight(
|
|
||||||
localConfig[fileNameSymbol]!
|
|
||||||
)} needs to be an object`
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// build `meta`
|
|
||||||
const meta = Object.assign(
|
|
||||||
{},
|
|
||||||
parseMeta(localConfig.meta),
|
|
||||||
parseMeta(argv['--meta'])
|
|
||||||
);
|
|
||||||
|
|
||||||
// Merge dotenv config, `env` from vercel.json, and `--env` / `-e` arguments
|
|
||||||
const deploymentEnv = Object.assign(
|
|
||||||
{},
|
|
||||||
parseEnv(localConfig.env),
|
|
||||||
parseEnv(argv['--env'])
|
|
||||||
);
|
|
||||||
|
|
||||||
// Merge build env out of `build.env` from vercel.json, and `--build-env` args
|
|
||||||
const deploymentBuildEnv = Object.assign(
|
|
||||||
{},
|
|
||||||
parseEnv(localConfig.build && localConfig.build.env),
|
|
||||||
parseEnv(argv['--build-env'])
|
|
||||||
);
|
|
||||||
|
|
||||||
// If there's any undefined values, then inherit them from this process
|
|
||||||
try {
|
|
||||||
await addProcessEnv(log, deploymentEnv);
|
|
||||||
await addProcessEnv(log, deploymentBuildEnv);
|
|
||||||
} catch (err) {
|
|
||||||
error(err.message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// build `regions`
|
|
||||||
const regionFlag = (argv['--regions'] || '')
|
|
||||||
.split(',')
|
|
||||||
.map((s: string) => s.trim())
|
|
||||||
.filter(Boolean);
|
|
||||||
const regions = regionFlag.length > 0 ? regionFlag : localConfig.regions;
|
|
||||||
|
|
||||||
// build `target`
|
|
||||||
let target;
|
|
||||||
if (argv['--target']) {
|
|
||||||
const deprecatedTarget = argv['--target'];
|
|
||||||
|
|
||||||
if (!['staging', 'production'].includes(deprecatedTarget)) {
|
|
||||||
error(
|
|
||||||
`The specified ${param('--target')} ${code(
|
|
||||||
deprecatedTarget
|
|
||||||
)} is not valid`
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deprecatedTarget === 'production') {
|
|
||||||
warn(
|
|
||||||
'We recommend using the much shorter `--prod` option instead of `--target production` (deprecated)'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
output.debug(`Setting target to ${deprecatedTarget}`);
|
|
||||||
target = deprecatedTarget;
|
|
||||||
} else if (argv['--prod']) {
|
|
||||||
output.debug('Setting target to production');
|
|
||||||
target = 'production';
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentTeam = org?.type === 'team' ? org.id : undefined;
|
|
||||||
const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam });
|
|
||||||
let deployStamp = stamp();
|
|
||||||
let deployment = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const createArgs: any = {
|
|
||||||
name: project ? project.name : newProjectName,
|
|
||||||
env: deploymentEnv,
|
|
||||||
build: { env: deploymentBuildEnv },
|
|
||||||
forceNew: argv['--force'],
|
|
||||||
withCache: argv['--with-cache'],
|
|
||||||
quiet,
|
|
||||||
wantsPublic: argv['--public'] || localConfig.public,
|
|
||||||
isFile,
|
|
||||||
type: null,
|
|
||||||
nowConfig: localConfig,
|
|
||||||
regions,
|
|
||||||
meta,
|
|
||||||
deployStamp,
|
|
||||||
target,
|
|
||||||
skipAutoDetectionConfirmation: autoConfirm,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!localConfig.builds || localConfig.builds.length === 0) {
|
|
||||||
// Only add projectSettings for zero config deployments
|
|
||||||
createArgs.projectSettings = { sourceFilesOutsideRootDirectory };
|
|
||||||
}
|
|
||||||
|
|
||||||
deployment = await createDeploy(
|
|
||||||
client,
|
|
||||||
now,
|
|
||||||
contextName,
|
|
||||||
[sourcePath],
|
|
||||||
createArgs,
|
|
||||||
org,
|
|
||||||
!project && !isFile,
|
|
||||||
path
|
|
||||||
);
|
|
||||||
|
|
||||||
if (deployment.code === 'missing_project_settings') {
|
|
||||||
let { projectSettings, framework } = deployment;
|
|
||||||
if (rootDirectory) {
|
|
||||||
projectSettings.rootDirectory = rootDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof sourceFilesOutsideRootDirectory !== 'undefined') {
|
|
||||||
projectSettings.sourceFilesOutsideRootDirectory =
|
|
||||||
sourceFilesOutsideRootDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
const settings = await editProjectSettings(
|
|
||||||
output,
|
|
||||||
projectSettings,
|
|
||||||
framework
|
|
||||||
);
|
|
||||||
|
|
||||||
// deploy again, but send projectSettings this time
|
|
||||||
createArgs.projectSettings = settings;
|
|
||||||
|
|
||||||
deployStamp = stamp();
|
|
||||||
createArgs.deployStamp = deployStamp;
|
|
||||||
deployment = await createDeploy(
|
|
||||||
client,
|
|
||||||
now,
|
|
||||||
contextName,
|
|
||||||
[sourcePath],
|
|
||||||
createArgs,
|
|
||||||
org,
|
|
||||||
false,
|
|
||||||
path
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deployment instanceof NotDomainOwner) {
|
|
||||||
output.error(deployment.message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deployment instanceof Error) {
|
|
||||||
output.error(
|
|
||||||
deployment.message ||
|
|
||||||
'An unexpected error occurred while deploying your project',
|
|
||||||
undefined,
|
|
||||||
'https://vercel.link/help',
|
|
||||||
'Contact Support'
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deployment.readyState === 'CANCELED') {
|
|
||||||
output.print('The deployment has been canceled.\n');
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const deploymentResponse = await getDeploymentByIdOrHost(
|
|
||||||
client,
|
|
||||||
contextName,
|
|
||||||
deployment.id,
|
|
||||||
'v10'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
deploymentResponse instanceof DeploymentNotFound ||
|
|
||||||
deploymentResponse instanceof DeploymentPermissionDenied ||
|
|
||||||
deploymentResponse instanceof InvalidDeploymentId
|
|
||||||
) {
|
|
||||||
output.error(deploymentResponse.message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deployment === null) {
|
|
||||||
error('Uploading failed. Please try again.');
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
debug(`Error: ${err}\n${err.stack}`);
|
|
||||||
|
|
||||||
if (err instanceof NotDomainOwner) {
|
|
||||||
output.error(err.message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err instanceof DomainNotFound && err.meta && err.meta.domain) {
|
|
||||||
output.debug(
|
|
||||||
`The domain ${err.meta.domain} was not found, trying to purchase it`
|
|
||||||
);
|
|
||||||
|
|
||||||
const purchase = await purchaseDomainIfAvailable(
|
|
||||||
output,
|
|
||||||
client,
|
|
||||||
err.meta.domain,
|
|
||||||
contextName
|
|
||||||
);
|
|
||||||
|
|
||||||
if (purchase === true) {
|
|
||||||
output.success(`Successfully purchased the domain ${err.meta.domain}!`);
|
|
||||||
|
|
||||||
// We exit if the purchase is completed since
|
|
||||||
// the domain verification can take some time
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (purchase === false || purchase instanceof UserAborted) {
|
|
||||||
handleCreateDeployError(output, deployment, localConfig);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCreateDeployError(output, purchase, localConfig);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
err instanceof DomainNotFound ||
|
|
||||||
err instanceof DomainNotVerified ||
|
|
||||||
err instanceof NotDomainOwner ||
|
|
||||||
err instanceof DomainPermissionDenied ||
|
|
||||||
err instanceof DomainVerificationFailed ||
|
|
||||||
err instanceof SchemaValidationFailed ||
|
|
||||||
err instanceof InvalidDomain ||
|
|
||||||
err instanceof DeploymentNotFound ||
|
|
||||||
err instanceof BuildsRateLimited ||
|
|
||||||
err instanceof DeploymentsRateLimited ||
|
|
||||||
err instanceof AliasDomainConfigured ||
|
|
||||||
err instanceof MissingBuildScript ||
|
|
||||||
err instanceof ConflictingFilePath ||
|
|
||||||
err instanceof ConflictingPathSegment
|
|
||||||
) {
|
|
||||||
handleCreateDeployError(output, err, localConfig);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err instanceof BuildError) {
|
|
||||||
output.error(err.message || 'Build failed');
|
|
||||||
output.error(
|
|
||||||
`Check your logs at https://${now.url}/_logs or run ${getCommandName(
|
|
||||||
`logs ${now.url}`
|
|
||||||
)}`
|
|
||||||
);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err.keyword === 'additionalProperties' && err.dataPath === '.scale') {
|
|
||||||
const { additionalProperty = '' } = err.params || {};
|
|
||||||
const message = `Invalid DC name for the scale option: ${additionalProperty}`;
|
|
||||||
error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err.code === 'size_limit_exceeded') {
|
|
||||||
const { sizeLimit = 0 } = err;
|
|
||||||
const message = `File size limit exceeded (${bytes(sizeLimit)})`;
|
|
||||||
error(message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleError(err);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return printDeploymentStatus(
|
|
||||||
output,
|
|
||||||
client,
|
|
||||||
deployment,
|
|
||||||
deployStamp,
|
|
||||||
!argv['--no-clipboard'],
|
|
||||||
isFile
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCreateDeployError(
|
|
||||||
output: Output,
|
|
||||||
error: Error,
|
|
||||||
localConfig: VercelConfig
|
|
||||||
) {
|
|
||||||
if (error instanceof InvalidDomain) {
|
|
||||||
output.error(`The domain ${error.meta.domain} is not valid`);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (error instanceof DomainVerificationFailed) {
|
|
||||||
output.error(
|
|
||||||
`The domain used as a suffix ${chalk.underline(
|
|
||||||
error.meta.domain
|
|
||||||
)} is not verified and can't be used as custom suffix.`
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (error instanceof DomainPermissionDenied) {
|
|
||||||
output.error(
|
|
||||||
`You don't have permissions to access the domain used as a suffix ${chalk.underline(
|
|
||||||
error.meta.domain
|
|
||||||
)}.`
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (error instanceof SchemaValidationFailed) {
|
|
||||||
const niceError = getPrettyError(error.meta);
|
|
||||||
const fileName = localConfig[fileNameSymbol] || 'vercel.json';
|
|
||||||
niceError.message = `Invalid ${fileName} - ${niceError.message}`;
|
|
||||||
output.prettyError(niceError);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (error instanceof TooManyRequests) {
|
|
||||||
output.error(
|
|
||||||
`Too many requests detected for ${error.meta.api} API. Try again in ${ms(
|
|
||||||
error.meta.retryAfter * 1000,
|
|
||||||
{
|
|
||||||
long: true,
|
|
||||||
}
|
|
||||||
)}.`
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (error instanceof DomainNotVerified) {
|
|
||||||
output.error(
|
|
||||||
`The domain used as an alias ${chalk.underline(
|
|
||||||
error.meta.domain
|
|
||||||
)} is not verified yet. Please verify it.`
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (error instanceof BuildsRateLimited) {
|
|
||||||
output.error(error.message);
|
|
||||||
output.note(
|
|
||||||
`Run ${getCommandName('upgrade')} to increase your builds limit.`
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
error instanceof DeploymentNotFound ||
|
|
||||||
error instanceof NotDomainOwner ||
|
|
||||||
error instanceof DeploymentsRateLimited ||
|
|
||||||
error instanceof AliasDomainConfigured ||
|
|
||||||
error instanceof MissingBuildScript ||
|
|
||||||
error instanceof ConflictingFilePath ||
|
|
||||||
error instanceof ConflictingPathSegment
|
|
||||||
) {
|
|
||||||
output.error(error.message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
@@ -36,17 +36,11 @@ export default async function dev(
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (link.status === 'not_linked' && !process.env.__VERCEL_SKIP_DEV_CMD) {
|
if (link.status === 'not_linked' && !process.env.__VERCEL_SKIP_DEV_CMD) {
|
||||||
const autoConfirm = opts['--confirm'] || false;
|
link = await setupAndLink(client, cwd, {
|
||||||
const forceDelete = false;
|
autoConfirm: opts['--confirm'],
|
||||||
|
successEmoji: 'link',
|
||||||
link = await setupAndLink(
|
setupMsg: 'Set up and develop',
|
||||||
client,
|
});
|
||||||
cwd,
|
|
||||||
forceDelete,
|
|
||||||
autoConfirm,
|
|
||||||
'link',
|
|
||||||
'Set up and develop'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (link.status === 'not_linked') {
|
if (link.status === 'not_linked') {
|
||||||
// User aborted project linking questions
|
// User aborted project linking questions
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { User, Team } from '../../types';
|
|||||||
import * as ERRORS from '../../util/errors-ts';
|
import * as ERRORS from '../../util/errors-ts';
|
||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import getScope from '../../util/get-scope';
|
import getScope from '../../util/get-scope';
|
||||||
import withSpinner from '../../util/with-spinner';
|
|
||||||
import moveOutDomain from '../../util/domains/move-out-domain';
|
import moveOutDomain from '../../util/domains/move-out-domain';
|
||||||
import isRootDomain from '../../util/is-root-domain';
|
import isRootDomain from '../../util/is-root-domain';
|
||||||
import textInput from '../../util/input/text';
|
import textInput from '../../util/input/text';
|
||||||
@@ -106,9 +105,14 @@ export default async function move(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const context = contextName;
|
const context = contextName;
|
||||||
const moveTokenResult = await withSpinner('Moving', () => {
|
output.spinner('Moving');
|
||||||
return moveOutDomain(client, context, domainName, matchId || destination);
|
const moveTokenResult = await moveOutDomain(
|
||||||
});
|
client,
|
||||||
|
context,
|
||||||
|
domainName,
|
||||||
|
matchId || destination
|
||||||
|
);
|
||||||
|
|
||||||
if (moveTokenResult instanceof ERRORS.DomainMoveConflict) {
|
if (moveTokenResult instanceof ERRORS.DomainMoveConflict) {
|
||||||
const { suffix, pendingAsyncPurchase } = moveTokenResult.meta;
|
const { suffix, pendingAsyncPurchase } = moveTokenResult.meta;
|
||||||
if (suffix) {
|
if (suffix) {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import param from '../../util/output/param';
|
|||||||
import transferInDomain from '../../util/domains/transfer-in-domain';
|
import transferInDomain from '../../util/domains/transfer-in-domain';
|
||||||
import stamp from '../../util/output/stamp';
|
import stamp from '../../util/output/stamp';
|
||||||
import getAuthCode from '../../util/domains/get-auth-code';
|
import getAuthCode from '../../util/domains/get-auth-code';
|
||||||
import withSpinner from '../../util/with-spinner';
|
|
||||||
import getDomainPrice from '../../util/domains/get-domain-price';
|
import getDomainPrice from '../../util/domains/get-domain-price';
|
||||||
import checkTransfer from '../../util/domains/check-transfer';
|
import checkTransfer from '../../util/domains/check-transfer';
|
||||||
import promptBool from '../../util/input/prompt-bool';
|
import promptBool from '../../util/input/prompt-bool';
|
||||||
@@ -89,9 +88,13 @@ export default async function transferIn(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const transferStamp = stamp();
|
const transferStamp = stamp();
|
||||||
const transferInResult = await withSpinner(
|
output.spinner(`Initiating transfer for domain ${domainName}`);
|
||||||
`Initiating transfer for domain ${domainName}`,
|
|
||||||
() => transferInDomain(client, domainName, authCode, price)
|
const transferInResult = await transferInDomain(
|
||||||
|
client,
|
||||||
|
domainName,
|
||||||
|
authCode,
|
||||||
|
price
|
||||||
);
|
);
|
||||||
|
|
||||||
if (transferInResult instanceof ERRORS.InvalidDomain) {
|
if (transferInResult instanceof ERRORS.InvalidDomain) {
|
||||||
|
|||||||
22
packages/cli/src/commands/env/add.ts
vendored
22
packages/cli/src/commands/env/add.ts
vendored
@@ -13,7 +13,6 @@ import {
|
|||||||
} from '../../util/env/env-target';
|
} from '../../util/env/env-target';
|
||||||
import readStandardInput from '../../util/input/read-standard-input';
|
import readStandardInput from '../../util/input/read-standard-input';
|
||||||
import param from '../../util/output/param';
|
import param from '../../util/output/param';
|
||||||
import withSpinner from '../../util/with-spinner';
|
|
||||||
import { emoji, prependEmoji } from '../../util/emoji';
|
import { emoji, prependEmoji } from '../../util/emoji';
|
||||||
import { isKnownError } from '../../util/env/known-error';
|
import { isKnownError } from '../../util/env/known-error';
|
||||||
import { getCommandName } from '../../util/pkg-name';
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
@@ -142,17 +141,16 @@ export default async function add(
|
|||||||
|
|
||||||
const addStamp = stamp();
|
const addStamp = stamp();
|
||||||
try {
|
try {
|
||||||
await withSpinner('Saving', () =>
|
output.spinner('Saving');
|
||||||
addEnvRecord(
|
await addEnvRecord(
|
||||||
output,
|
output,
|
||||||
client,
|
client,
|
||||||
project.id,
|
project.id,
|
||||||
ProjectEnvType.Encrypted,
|
ProjectEnvType.Encrypted,
|
||||||
envName,
|
envName,
|
||||||
envValue,
|
envValue,
|
||||||
envTargets,
|
envTargets,
|
||||||
envGitBranch
|
envGitBranch
|
||||||
)
|
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (isKnownError(error) && error.serverMessage) {
|
if (isKnownError(error) && error.serverMessage) {
|
||||||
|
|||||||
23
packages/cli/src/commands/env/pull.ts
vendored
23
packages/cli/src/commands/env/pull.ts
vendored
@@ -6,7 +6,6 @@ import Client from '../../util/client';
|
|||||||
import stamp from '../../util/output/stamp';
|
import stamp from '../../util/output/stamp';
|
||||||
import getDecryptedEnvRecords from '../../util/get-decrypted-env-records';
|
import getDecryptedEnvRecords from '../../util/get-decrypted-env-records';
|
||||||
import param from '../../util/output/param';
|
import param from '../../util/output/param';
|
||||||
import withSpinner from '../../util/with-spinner';
|
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { promises, openSync, closeSync, readSync } from 'fs';
|
import { promises, openSync, closeSync, readSync } from 'fs';
|
||||||
import { emoji, prependEmoji } from '../../util/emoji';
|
import { emoji, prependEmoji } from '../../util/emoji';
|
||||||
@@ -83,19 +82,16 @@ export default async function pull(
|
|||||||
project.name
|
project.name
|
||||||
)}\n`
|
)}\n`
|
||||||
);
|
);
|
||||||
const pullStamp = stamp();
|
|
||||||
|
|
||||||
const [
|
const pullStamp = stamp();
|
||||||
{ envs: projectEnvs },
|
output.spinner('Downloading');
|
||||||
{ systemEnvValues },
|
|
||||||
] = await withSpinner('Downloading', () =>
|
const [{ envs: projectEnvs }, { systemEnvValues }] = await Promise.all([
|
||||||
Promise.all([
|
getDecryptedEnvRecords(output, client, project.id),
|
||||||
getDecryptedEnvRecords(output, client, project.id),
|
project.autoExposeSystemEnvs
|
||||||
project.autoExposeSystemEnvs
|
? getSystemEnvValues(output, client, project.id)
|
||||||
? getSystemEnvValues(output, client, project.id)
|
: { systemEnvValues: [] },
|
||||||
: { systemEnvValues: [] },
|
]);
|
||||||
])
|
|
||||||
);
|
|
||||||
|
|
||||||
const records = exposeSystemEnvs(
|
const records = exposeSystemEnvs(
|
||||||
projectEnvs,
|
projectEnvs,
|
||||||
@@ -120,6 +116,7 @@ export default async function pull(
|
|||||||
emoji('success')
|
emoji('success')
|
||||||
)}\n`
|
)}\n`
|
||||||
);
|
);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
packages/cli/src/commands/env/rm.ts
vendored
6
packages/cli/src/commands/env/rm.ts
vendored
@@ -13,7 +13,6 @@ import {
|
|||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import stamp from '../../util/output/stamp';
|
import stamp from '../../util/output/stamp';
|
||||||
import param from '../../util/output/param';
|
import param from '../../util/output/param';
|
||||||
import withSpinner from '../../util/with-spinner';
|
|
||||||
import { emoji, prependEmoji } from '../../util/emoji';
|
import { emoji, prependEmoji } from '../../util/emoji';
|
||||||
import { isKnownError } from '../../util/env/known-error';
|
import { isKnownError } from '../../util/env/known-error';
|
||||||
import { getCommandName } from '../../util/pkg-name';
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
@@ -112,9 +111,8 @@ export default async function rm(
|
|||||||
const rmStamp = stamp();
|
const rmStamp = stamp();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await withSpinner('Removing', async () => {
|
output.spinner('Removing');
|
||||||
await removeEnvRecord(output, client, project.id, env);
|
await removeEnvRecord(output, client, project.id, env);
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (isKnownError(error) && error.serverMessage) {
|
if (isKnownError(error) && error.serverMessage) {
|
||||||
output.error(error.serverMessage);
|
output.error(error.serverMessage);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import getSubcommand from '../../util/get-subcommand';
|
|||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import handleError from '../../util/handle-error';
|
import handleError from '../../util/handle-error';
|
||||||
import logo from '../../util/output/logo';
|
import logo from '../../util/output/logo';
|
||||||
import error from '../../util/output/error';
|
|
||||||
import init from './init';
|
import init from './init';
|
||||||
import { getPkgName } from '../../util/pkg-name';
|
import { getPkgName } from '../../util/pkg-name';
|
||||||
|
|
||||||
@@ -44,6 +43,7 @@ const help = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function main(client: Client) {
|
export default async function main(client: Client) {
|
||||||
|
const { output } = client;
|
||||||
let argv;
|
let argv;
|
||||||
let args;
|
let args;
|
||||||
|
|
||||||
@@ -64,15 +64,15 @@ export default async function main(client: Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (argv._.length > 3) {
|
if (argv._.length > 3) {
|
||||||
client.output.error('Too much arguments.');
|
output.error('Too much arguments.');
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await init(client, argv, args);
|
return await init(client, argv, args);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(error(err.message));
|
output.prettyError(err);
|
||||||
client.output.debug(err.stack);
|
output.debug(err.stack);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,16 +2,13 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import tar from 'tar-fs';
|
import tar from 'tar-fs';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import fetch from 'node-fetch';
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import listInput from '../../util/input/list';
|
import listInput from '../../util/input/list';
|
||||||
import listItem from '../../util/output/list-item';
|
import listItem from '../../util/output/list-item';
|
||||||
import promptBool from '../../util/input/prompt-bool';
|
import promptBool from '../../util/input/prompt-bool';
|
||||||
import toHumanPath from '../../util/humanize-path';
|
import toHumanPath from '../../util/humanize-path';
|
||||||
import { Output } from '../../util/output';
|
|
||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import success from '../../util/output/success';
|
|
||||||
import info from '../../util/output/info';
|
import info from '../../util/output/info';
|
||||||
import cmd from '../../util/output/cmd';
|
import cmd from '../../util/output/cmd';
|
||||||
import didYouMean from '../../util/init/did-you-mean';
|
import didYouMean from '../../util/init/did-you-mean';
|
||||||
@@ -40,7 +37,7 @@ export default async function init(
|
|||||||
const [name, dir] = args;
|
const [name, dir] = args;
|
||||||
const force = opts['-f'] || opts['--force'];
|
const force = opts['-f'] || opts['--force'];
|
||||||
|
|
||||||
const examples = await fetchExampleList(output);
|
const examples = await fetchExampleList(client);
|
||||||
|
|
||||||
if (!examples) {
|
if (!examples) {
|
||||||
throw new Error(`Could not fetch example list.`);
|
throw new Error(`Could not fetch example list.`);
|
||||||
@@ -56,47 +53,37 @@ export default async function init(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return extractExample(output, chosen, dir, force);
|
return extractExample(client, chosen, dir, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exampleList.includes(name)) {
|
if (exampleList.includes(name)) {
|
||||||
return extractExample(output, name, dir, force);
|
return extractExample(client, name, dir, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldExample = examples.find(x => !x.visible && x.name === name);
|
const oldExample = examples.find(x => !x.visible && x.name === name);
|
||||||
if (oldExample) {
|
if (oldExample) {
|
||||||
return extractExample(output, name, dir, force, 'v1');
|
return extractExample(client, name, dir, force, 'v1');
|
||||||
}
|
}
|
||||||
|
|
||||||
const found = await guess(exampleList, name);
|
const found = await guess(exampleList, name);
|
||||||
|
|
||||||
if (typeof found === 'string') {
|
if (typeof found === 'string') {
|
||||||
return extractExample(output, found, dir, force);
|
return extractExample(client, found, dir, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(info('No changes made.'));
|
output.log(info('No changes made.'));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch example list json
|
* Fetch example list json
|
||||||
*/
|
*/
|
||||||
async function fetchExampleList(output: Output) {
|
async function fetchExampleList(client: Client) {
|
||||||
output.spinner('Fetching examples');
|
client.output.spinner('Fetching examples');
|
||||||
const url = `${EXAMPLE_API}/v2/list.json`;
|
const url = `${EXAMPLE_API}/v2/list.json`;
|
||||||
|
|
||||||
try {
|
const body = await client.fetch<Example[]>(url);
|
||||||
const resp = await fetch(url);
|
return body;
|
||||||
output.stopSpinner();
|
|
||||||
|
|
||||||
if (resp.status !== 200) {
|
|
||||||
throw new Error(`Failed fetching list.json (${resp.statusText}).`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (await resp.json()) as Example[];
|
|
||||||
} catch (e) {
|
|
||||||
output.stopSpinner();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,31 +106,33 @@ async function chooseFromDropdown(message: string, exampleList: string[]) {
|
|||||||
* Extract example to directory
|
* Extract example to directory
|
||||||
*/
|
*/
|
||||||
async function extractExample(
|
async function extractExample(
|
||||||
output: Output,
|
client: Client,
|
||||||
name: string,
|
name: string,
|
||||||
dir: string,
|
dir: string,
|
||||||
force?: boolean,
|
force?: boolean,
|
||||||
ver: string = 'v2'
|
ver: string = 'v2'
|
||||||
) {
|
) {
|
||||||
|
const { output } = client;
|
||||||
const folder = prepareFolder(process.cwd(), dir || name, force);
|
const folder = prepareFolder(process.cwd(), dir || name, force);
|
||||||
output.spinner(`Fetching ${name}`);
|
output.spinner(`Fetching ${name}`);
|
||||||
|
|
||||||
const url = `${EXAMPLE_API}/${ver}/download/${name}.tar.gz`;
|
const url = `${EXAMPLE_API}/${ver}/download/${name}.tar.gz`;
|
||||||
|
|
||||||
return fetch(url)
|
return client
|
||||||
.then(async resp => {
|
.fetch(url, { json: false })
|
||||||
|
.then(async res => {
|
||||||
output.stopSpinner();
|
output.stopSpinner();
|
||||||
|
|
||||||
if (resp.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error(`Could not get ${name}.tar.gz`);
|
throw new Error(`Could not get ${name}.tar.gz`);
|
||||||
}
|
}
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const extractor = tar.extract(folder);
|
const extractor = tar.extract(folder);
|
||||||
resp.body.on('error', reject);
|
res.body.on('error', reject);
|
||||||
extractor.on('error', reject);
|
extractor.on('error', reject);
|
||||||
extractor.on('finish', resolve);
|
extractor.on('finish', resolve);
|
||||||
resp.body.pipe(extractor);
|
res.body.pipe(extractor);
|
||||||
});
|
});
|
||||||
|
|
||||||
const successLog = `Initialized "${chalk.bold(
|
const successLog = `Initialized "${chalk.bold(
|
||||||
@@ -158,7 +147,7 @@ async function extractExample(
|
|||||||
`cd ${folderRel}`
|
`cd ${folderRel}`
|
||||||
)} and run ${getCommandName()}.`
|
)} and run ${getCommandName()}.`
|
||||||
);
|
);
|
||||||
console.log(success(`${successLog}\n${deployHint}`));
|
output.success(`${successLog}\n${deployHint}`);
|
||||||
return 0;
|
return 0;
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { getPkgName, getCommandName } from '../util/pkg-name';
|
|||||||
import Client from '../util/client';
|
import Client from '../util/client';
|
||||||
import { getDeployment } from '../util/get-deployment';
|
import { getDeployment } from '../util/get-deployment';
|
||||||
import { Deployment } from '@vercel/client';
|
import { Deployment } from '@vercel/client';
|
||||||
|
import { Build } from '../types';
|
||||||
|
|
||||||
const help = () => {
|
const help = () => {
|
||||||
console.log(`
|
console.log(`
|
||||||
@@ -116,7 +117,9 @@ export default async function main(client: Client) {
|
|||||||
|
|
||||||
const { builds } =
|
const { builds } =
|
||||||
deployment.version === 2
|
deployment.version === 2
|
||||||
? await client.fetch(`/v1/now/deployments/${id}/builds`)
|
? await client.fetch<{ builds: Build[] }>(
|
||||||
|
`/v1/now/deployments/${id}/builds`
|
||||||
|
)
|
||||||
: { builds: [] };
|
: { builds: [] };
|
||||||
|
|
||||||
log(
|
log(
|
||||||
@@ -146,7 +149,8 @@ export default async function main(client: Client) {
|
|||||||
|
|
||||||
for (const build of builds) {
|
for (const build of builds) {
|
||||||
const { id, createdAt, readyStateAt } = build;
|
const { id, createdAt, readyStateAt } = build;
|
||||||
times[id] = createdAt ? elapsed(readyStateAt - createdAt) : null;
|
times[id] =
|
||||||
|
createdAt && readyStateAt ? elapsed(readyStateAt - createdAt) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
print(chalk.bold(' Builds\n\n'));
|
print(chalk.bold(' Builds\n\n'));
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import getArgs from '../../util/get-args';
|
import getArgs from '../../util/get-args';
|
||||||
import getSubcommand from '../../util/get-subcommand';
|
|
||||||
import handleError from '../../util/handle-error';
|
|
||||||
import logo from '../../util/output/logo';
|
import logo from '../../util/output/logo';
|
||||||
import { getPkgName } from '../../util/pkg-name';
|
import { getPkgName } from '../../util/pkg-name';
|
||||||
import setupAndLink from '../../util/link/setup-and-link';
|
import setupAndLink from '../../util/link/setup-and-link';
|
||||||
@@ -24,6 +22,9 @@ const help = () => {
|
|||||||
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
|
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
|
||||||
'TOKEN'
|
'TOKEN'
|
||||||
)} Login token
|
)} Login token
|
||||||
|
-p ${chalk.bold.underline('NAME')}, --project=${chalk.bold.underline(
|
||||||
|
'NAME'
|
||||||
|
)} Project name
|
||||||
--confirm Confirm default options and skip questions
|
--confirm Confirm default options and skip questions
|
||||||
|
|
||||||
${chalk.dim('Examples:')}
|
${chalk.dim('Examples:')}
|
||||||
@@ -44,40 +45,26 @@ const help = () => {
|
|||||||
`);
|
`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const COMMAND_CONFIG = {
|
|
||||||
// No subcommands yet
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function main(client: Client) {
|
export default async function main(client: Client) {
|
||||||
let argv;
|
const argv = getArgs(client.argv.slice(2), {
|
||||||
|
'--confirm': Boolean,
|
||||||
try {
|
'--project': String,
|
||||||
argv = getArgs(client.argv.slice(2), {
|
'-p': '--project',
|
||||||
'--confirm': Boolean,
|
});
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
handleError(error);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argv['--help']) {
|
if (argv['--help']) {
|
||||||
help();
|
help();
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { args } = getSubcommand(argv._.slice(1), COMMAND_CONFIG);
|
const cwd = argv._[1] || process.cwd();
|
||||||
const path = args[0] || process.cwd();
|
const link = await setupAndLink(client, cwd, {
|
||||||
const autoConfirm = argv['--confirm'] || false;
|
forceDelete: true,
|
||||||
const forceDelete = true;
|
autoConfirm: argv['--confirm'],
|
||||||
|
projectName: argv['--project'],
|
||||||
const link = await setupAndLink(
|
successEmoji: 'success',
|
||||||
client,
|
setupMsg: 'Set up',
|
||||||
path,
|
});
|
||||||
forceDelete,
|
|
||||||
autoConfirm,
|
|
||||||
'success',
|
|
||||||
'Set up'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (link.status === 'error') {
|
if (link.status === 'error') {
|
||||||
return link.exitCode;
|
return link.exitCode;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import stamp from '../../util/output/stamp.ts';
|
import stamp from '../../util/output/stamp.ts';
|
||||||
import info from '../../util/output/info';
|
import info from '../../util/output/info';
|
||||||
import rightPad from '../../util/output/right-pad';
|
|
||||||
import eraseLines from '../../util/output/erase-lines';
|
import eraseLines from '../../util/output/erase-lines';
|
||||||
import chars from '../../util/output/chars';
|
import chars from '../../util/output/chars';
|
||||||
import note from '../../util/output/note';
|
import note from '../../util/output/note';
|
||||||
@@ -30,8 +29,8 @@ const gracefulExit = () => {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const teamUrlPrefix = rightPad('Team URL', 14) + chalk.gray('vercel.com/');
|
const teamUrlPrefix = 'Team URL'.padEnd(14) + chalk.gray('vercel.com/');
|
||||||
const teamNamePrefix = rightPad('Team Name', 14);
|
const teamNamePrefix = 'Team Name'.padEnd(14);
|
||||||
|
|
||||||
export default async function add(client, teams) {
|
export default async function add(client, teams) {
|
||||||
let slug;
|
let slug;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import cmd from '../../util/output/cmd.ts';
|
|||||||
import stamp from '../../util/output/stamp.ts';
|
import stamp from '../../util/output/stamp.ts';
|
||||||
import param from '../../util/output/param.ts';
|
import param from '../../util/output/param.ts';
|
||||||
import chars from '../../util/output/chars';
|
import chars from '../../util/output/chars';
|
||||||
import rightPad from '../../util/output/right-pad';
|
|
||||||
import textInput from '../../util/input/text';
|
import textInput from '../../util/input/text';
|
||||||
import eraseLines from '../../util/output/erase-lines';
|
import eraseLines from '../../util/output/erase-lines';
|
||||||
import getUser from '../../util/get-user.ts';
|
import getUser from '../../util/get-user.ts';
|
||||||
@@ -126,8 +125,8 @@ export default async function invite(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const inviteUserPrefix = rightPad('Invite User', 14);
|
const inviteUserPrefix = 'Invite User'.padEnd(14);
|
||||||
const sentEmailPrefix = rightPad('Sent Email', 14);
|
const sentEmailPrefix = 'Sent Email'.padEnd(14);
|
||||||
const emails = [];
|
const emails = [];
|
||||||
let hasError = false;
|
let hasError = false;
|
||||||
let email;
|
let email;
|
||||||
|
|||||||
@@ -430,12 +430,16 @@ const main = async () => {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.teamId) {
|
||||||
|
// SSO login, so set the current scope to the appropriate Team
|
||||||
|
client.config.currentTeam = result.teamId;
|
||||||
|
} else {
|
||||||
|
delete client.config.currentTeam;
|
||||||
|
}
|
||||||
|
|
||||||
// When `result` is a string it's the user's authentication token.
|
// When `result` is a string it's the user's authentication token.
|
||||||
// It needs to be saved to the configuration file.
|
// It needs to be saved to the configuration file.
|
||||||
client.authConfig.token = result;
|
client.authConfig.token = result.token;
|
||||||
|
|
||||||
// New user, so we can't keep the team
|
|
||||||
delete client.config.currentTeam;
|
|
||||||
|
|
||||||
configFiles.writeToAuthConfigFile(client.authConfig);
|
configFiles.writeToAuthConfigFile(client.authConfig);
|
||||||
configFiles.writeToConfigFile(client.config);
|
configFiles.writeToConfigFile(client.config);
|
||||||
|
|||||||
@@ -16,11 +16,13 @@ export interface JSONObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthConfig {
|
export interface AuthConfig {
|
||||||
|
_: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
skipWrite?: boolean;
|
skipWrite?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GlobalConfig {
|
export interface GlobalConfig {
|
||||||
|
_: string;
|
||||||
currentTeam?: string;
|
currentTeam?: string;
|
||||||
includeScheme?: string;
|
includeScheme?: string;
|
||||||
collectMetrics?: boolean;
|
collectMetrics?: boolean;
|
||||||
@@ -306,3 +308,141 @@ export interface Token {
|
|||||||
createdAt: number;
|
createdAt: number;
|
||||||
teamId?: string;
|
teamId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object representing a Build on Vercel
|
||||||
|
*/
|
||||||
|
export interface Build {
|
||||||
|
/**
|
||||||
|
* The unique identifier of the Build
|
||||||
|
* @example "bld_q5fj68jh7eewfe8"
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier of the deployment
|
||||||
|
* @example "dpl_BRGyoU2Jzzwx7myBnqv3xjRDD2GnHTwUWyFybnrUvjDD"
|
||||||
|
*/
|
||||||
|
deploymentId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entrypoint of the deployment
|
||||||
|
* @example "api/index.js"
|
||||||
|
*/
|
||||||
|
entrypoint: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state of the deployment depending on the process of deploying,
|
||||||
|
* or if it is ready or in an error state
|
||||||
|
* @example "READY"
|
||||||
|
*/
|
||||||
|
readyState:
|
||||||
|
| 'INITIALIZING'
|
||||||
|
| 'BUILDING'
|
||||||
|
| 'UPLOADING'
|
||||||
|
| 'DEPLOYING'
|
||||||
|
| 'READY'
|
||||||
|
| 'ARCHIVED'
|
||||||
|
| 'ERROR'
|
||||||
|
| 'QUEUED'
|
||||||
|
| 'CANCELED';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time at which the Build state was last modified
|
||||||
|
* @example 1567024758130
|
||||||
|
*/
|
||||||
|
readyStateAt?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time at which the Build was scheduled to be built
|
||||||
|
* @example 1567024756543
|
||||||
|
*/
|
||||||
|
scheduledAt?: number | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time at which the Build was created
|
||||||
|
* @example 1567071524208
|
||||||
|
*/
|
||||||
|
createdAt?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time at which the Build was deployed
|
||||||
|
* @example 1567071598563
|
||||||
|
*/
|
||||||
|
deployedAt?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The region where the Build was first created
|
||||||
|
* @example "sfo1"
|
||||||
|
*/
|
||||||
|
createdIn?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Runtime the Build used to generate the output
|
||||||
|
* @example "@vercel/node"
|
||||||
|
*/
|
||||||
|
use?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object that contains the Build's configuration
|
||||||
|
* @example {"zeroConfig": true}
|
||||||
|
*/
|
||||||
|
config?: {
|
||||||
|
distDir?: string | undefined;
|
||||||
|
forceBuildIn?: string | undefined;
|
||||||
|
reuseWorkPathFrom?: string | undefined;
|
||||||
|
zeroConfig?: boolean | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of outputs for the Build that can be either Serverless Functions or static files
|
||||||
|
*/
|
||||||
|
output: BuildOutput[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the Build uses the `@vercel/static` Runtime, it contains a hashed string of all outputs
|
||||||
|
* @example null
|
||||||
|
*/
|
||||||
|
fingerprint?: string | null;
|
||||||
|
|
||||||
|
copiedFrom?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BuildOutput {
|
||||||
|
/**
|
||||||
|
* The type of the output
|
||||||
|
*/
|
||||||
|
type?: 'lambda' | 'file';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The absolute path of the file or Serverless Function
|
||||||
|
*/
|
||||||
|
path: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SHA1 of the file
|
||||||
|
*/
|
||||||
|
digest: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The POSIX file permissions
|
||||||
|
*/
|
||||||
|
mode: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the file in bytes
|
||||||
|
*/
|
||||||
|
size?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the output is a Serverless Function, an object
|
||||||
|
* containing the name, location and memory size of the function
|
||||||
|
*/
|
||||||
|
lambda?: {
|
||||||
|
functionName: string;
|
||||||
|
deployedTo: string[];
|
||||||
|
memorySize?: number;
|
||||||
|
timeout?: number;
|
||||||
|
layers?: string[];
|
||||||
|
} | null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
export const isReady = ({ readyState }) => readyState === 'READY';
|
|
||||||
export const isFailed = ({ readyState }) =>
|
|
||||||
readyState.endsWith('_ERROR') || readyState === 'ERROR';
|
|
||||||
export const isDone = ({ readyState }) =>
|
|
||||||
isReady({ readyState }) || isFailed({ readyState });
|
|
||||||
7
packages/cli/src/util/build-state.ts
Normal file
7
packages/cli/src/util/build-state.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { Build } from '../types';
|
||||||
|
|
||||||
|
export const isReady = ({ readyState }: Pick<Build, 'readyState'>) =>
|
||||||
|
readyState === 'READY';
|
||||||
|
|
||||||
|
export const isFailed = ({ readyState }: Pick<Build, 'readyState'>) =>
|
||||||
|
readyState.endsWith('_ERROR') || readyState === 'ERROR';
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
export const getDefaultConfig = async existingCopy => {
|
import { AuthConfig, GlobalConfig } from '../../types';
|
||||||
|
|
||||||
|
export const getDefaultConfig = async (existingCopy: GlobalConfig) => {
|
||||||
let migrated = false;
|
let migrated = false;
|
||||||
|
|
||||||
const config = {
|
const config: GlobalConfig = {
|
||||||
_:
|
_: 'This is your Vercel config file. For more information see the global configuration documentation: https://vercel.com/docs/configuration#global',
|
||||||
'This is your Vercel config file. For more information see the global configuration documentation: https://vercel.com/docs/configuration#global',
|
|
||||||
collectMetrics: true,
|
collectMetrics: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -16,44 +17,33 @@ export const getDefaultConfig = async existingCopy => {
|
|||||||
'collectMetrics',
|
'collectMetrics',
|
||||||
'api',
|
'api',
|
||||||
// This is deleted later in the code
|
// This is deleted later in the code
|
||||||
'shownTips',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const existing = Object.assign({}, existingCopy);
|
const existing = Object.assign({}, existingCopy);
|
||||||
|
// @ts-ignore
|
||||||
const sh = Object.assign({}, existing.sh || {});
|
const sh = Object.assign({}, existing.sh || {});
|
||||||
|
|
||||||
Object.assign(config, existing, sh);
|
Object.assign(config, existing, sh);
|
||||||
|
|
||||||
for (const key of Object.keys(config)) {
|
for (const key of Object.keys(config)) {
|
||||||
if (!keep.includes(key)) {
|
if (!keep.includes(key)) {
|
||||||
|
// @ts-ignore
|
||||||
delete config[key];
|
delete config[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof config.currentTeam === 'object') {
|
if (typeof config.currentTeam === 'object') {
|
||||||
|
// @ts-ignore
|
||||||
config.currentTeam = config.currentTeam.id;
|
config.currentTeam = config.currentTeam.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
if (typeof config.user === 'object') {
|
if (typeof config.user === 'object') {
|
||||||
|
// @ts-ignore
|
||||||
config.user = config.user.uid || config.user.id;
|
config.user = config.user.uid || config.user.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure Now Desktop users don't see any tips
|
|
||||||
// again that they already dismissed
|
|
||||||
if (config.shownTips) {
|
|
||||||
if (config.desktop) {
|
|
||||||
config.desktop.shownTips = config.shownTips;
|
|
||||||
} else {
|
|
||||||
config.desktop = {
|
|
||||||
shownTips: config.shownTips,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up the old property
|
|
||||||
delete config.shownTips;
|
|
||||||
}
|
|
||||||
|
|
||||||
migrated = true;
|
migrated = true;
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
@@ -61,16 +51,16 @@ export const getDefaultConfig = async existingCopy => {
|
|||||||
return { config, migrated };
|
return { config, migrated };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDefaultAuthConfig = async existing => {
|
export const getDefaultAuthConfig = async (existing?: AuthConfig) => {
|
||||||
let migrated = false;
|
let migrated = false;
|
||||||
|
|
||||||
const config = {
|
const config: AuthConfig = {
|
||||||
_:
|
_: 'This is your Vercel credentials file. DO NOT SHARE! More: https://vercel.com/docs/configuration#global',
|
||||||
'This is your Vercel credentials file. DO NOT SHARE! More: https://vercel.com/docs/configuration#global',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
try {
|
try {
|
||||||
|
// @ts-ignore
|
||||||
const sh = existing.credentials.find(item => item.provider === 'sh');
|
const sh = existing.credentials.find(item => item.provider === 'sh');
|
||||||
|
|
||||||
if (sh) {
|
if (sh) {
|
||||||
@@ -82,14 +82,14 @@ function getNpmVersion(use = ''): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBuildUtils(packages: string[], org: string): string {
|
export function getBuildUtils(packages: string[]): string {
|
||||||
const version = packages
|
const version = packages
|
||||||
.map(getNpmVersion)
|
.map(getNpmVersion)
|
||||||
.some(ver => ver.includes('canary'))
|
.some(ver => ver.includes('canary'))
|
||||||
? 'canary'
|
? 'canary'
|
||||||
: 'latest';
|
: 'latest';
|
||||||
|
|
||||||
return `@${org}/build-utils@${version}`;
|
return `@vercel/build-utils@${version}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseVersionSafe(rawSpec: string) {
|
function parseVersionSafe(rawSpec: string) {
|
||||||
@@ -191,10 +191,7 @@ export async function installBuilders(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
packagesToInstall.push(
|
packagesToInstall.push(getBuildUtils(packages));
|
||||||
getBuildUtils(packages, 'vercel'),
|
|
||||||
getBuildUtils(packages, 'now')
|
|
||||||
);
|
|
||||||
|
|
||||||
await npmInstall(builderDir, output, packagesToInstall, false);
|
await npmInstall(builderDir, output, packagesToInstall, false);
|
||||||
|
|
||||||
@@ -307,10 +304,7 @@ export async function updateBuilders(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (packagesToUpdate.length > 0) {
|
if (packagesToUpdate.length > 0) {
|
||||||
packagesToUpdate.push(
|
packagesToUpdate.push(getBuildUtils(packages));
|
||||||
getBuildUtils(packages, 'vercel'),
|
|
||||||
getBuildUtils(packages, 'now')
|
|
||||||
);
|
|
||||||
|
|
||||||
await npmInstall(builderDir, output, packagesToUpdate, true);
|
await npmInstall(builderDir, output, packagesToUpdate, true);
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
//@ts-ignore Missing types for 'title'
|
|
||||||
import title from 'title';
|
import title from 'title';
|
||||||
import { ProjectEnvVariable } from '../../types';
|
import { ProjectEnvVariable } from '../../types';
|
||||||
|
|
||||||
export default function formatEnvTarget(env: ProjectEnvVariable): string {
|
export default function formatEnvTarget(env: ProjectEnvVariable): string {
|
||||||
const target = (Array.isArray(env.target) ? env.target : [env.target || ''])
|
const target = (Array.isArray(env.target) ? env.target : [env.target || ''])
|
||||||
.map(title)
|
.map(t => title(t))
|
||||||
.join(', ');
|
.join(', ');
|
||||||
|
|
||||||
return env.gitBranch ? `${target} (${env.gitBranch})` : target;
|
return env.gitBranch ? `${target} (${env.gitBranch})` : target;
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { basename } from 'path';
|
|
||||||
|
|
||||||
export default function getProjectName({ argv, nowConfig, isFile, paths }) {
|
|
||||||
const nameCli = argv['--name'] || argv.name;
|
|
||||||
|
|
||||||
if (nameCli) {
|
|
||||||
return nameCli;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nowConfig.name) {
|
|
||||||
return nowConfig.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isFile || paths.length > 1) {
|
|
||||||
return 'files';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise let's send the name of the directory
|
|
||||||
return basename(paths[0]);
|
|
||||||
}
|
|
||||||
34
packages/cli/src/util/get-project-name.ts
Normal file
34
packages/cli/src/util/get-project-name.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import arg from 'arg';
|
||||||
|
import { basename } from 'path';
|
||||||
|
import { VercelConfig } from '@vercel/client';
|
||||||
|
|
||||||
|
export interface GetProjectNameOptions {
|
||||||
|
argv: arg.Result<{ '--name': StringConstructor }>;
|
||||||
|
nowConfig?: VercelConfig;
|
||||||
|
isFile: boolean;
|
||||||
|
paths: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getProjectName({
|
||||||
|
argv,
|
||||||
|
nowConfig = {},
|
||||||
|
isFile,
|
||||||
|
paths = [],
|
||||||
|
}: GetProjectNameOptions) {
|
||||||
|
const nameCli = argv['--name'];
|
||||||
|
|
||||||
|
if (nameCli) {
|
||||||
|
return nameCli;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nowConfig.name) {
|
||||||
|
return nowConfig.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFile || paths.length > 1) {
|
||||||
|
return 'files';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, use the name of the directory
|
||||||
|
return basename(paths[0] || '');
|
||||||
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
function indent(text, n) {
|
|
||||||
return text
|
|
||||||
.split('\n')
|
|
||||||
.map(l => ' '.repeat(n) + l)
|
|
||||||
.join('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
export default indent;
|
|
||||||
@@ -217,7 +217,10 @@ export default class Now extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error.errorCode && error.errorCode === 'BUILD_FAILED') {
|
if (
|
||||||
|
error.errorCode === 'BUILD_FAILED' ||
|
||||||
|
error.errorCode === 'UNEXPECTED_ERROR'
|
||||||
|
) {
|
||||||
return new BuildError({
|
return new BuildError({
|
||||||
message: error.errorMessage,
|
message: error.errorMessage,
|
||||||
meta: {},
|
meta: {},
|
||||||
|
|||||||
@@ -4,17 +4,16 @@ import confirm from './confirm';
|
|||||||
import getProjectByIdOrName from '../projects/get-project-by-id-or-name';
|
import getProjectByIdOrName from '../projects/get-project-by-id-or-name';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { ProjectNotFound } from '../../util/errors-ts';
|
import { ProjectNotFound } from '../../util/errors-ts';
|
||||||
import { Output } from '../output';
|
|
||||||
import { Project, Org } from '../../types';
|
import { Project, Org } from '../../types';
|
||||||
import slugify from '@sindresorhus/slugify';
|
import slugify from '@sindresorhus/slugify';
|
||||||
|
|
||||||
export default async function inputProject(
|
export default async function inputProject(
|
||||||
output: Output,
|
|
||||||
client: Client,
|
client: Client,
|
||||||
org: Org,
|
org: Org,
|
||||||
detectedProjectName: string,
|
detectedProjectName: string,
|
||||||
autoConfirm: boolean
|
autoConfirm: boolean
|
||||||
): Promise<Project | string> {
|
): Promise<Project | string> {
|
||||||
|
const { output } = client;
|
||||||
const slugifiedName = slugify(detectedProjectName);
|
const slugifiedName = slugify(detectedProjectName);
|
||||||
|
|
||||||
// attempt to auto-detect a project to link
|
// attempt to auto-detect a project to link
|
||||||
|
|||||||
@@ -25,13 +25,24 @@ import { EmojiLabel } from '../emoji';
|
|||||||
import createDeploy from '../deploy/create-deploy';
|
import createDeploy from '../deploy/create-deploy';
|
||||||
import Now from '../index';
|
import Now from '../index';
|
||||||
|
|
||||||
|
export interface SetupAndLinkOptions {
|
||||||
|
forceDelete?: boolean;
|
||||||
|
autoConfirm?: boolean;
|
||||||
|
successEmoji: EmojiLabel;
|
||||||
|
setupMsg: string;
|
||||||
|
projectName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export default async function setupAndLink(
|
export default async function setupAndLink(
|
||||||
client: Client,
|
client: Client,
|
||||||
path: string,
|
path: string,
|
||||||
forceDelete: boolean,
|
{
|
||||||
autoConfirm: boolean,
|
forceDelete = false,
|
||||||
successEmoji: EmojiLabel,
|
autoConfirm = false,
|
||||||
setupMsg: string
|
successEmoji,
|
||||||
|
setupMsg,
|
||||||
|
projectName,
|
||||||
|
}: SetupAndLinkOptions
|
||||||
): Promise<ProjectLinkResult> {
|
): Promise<ProjectLinkResult> {
|
||||||
const {
|
const {
|
||||||
authConfig: { token },
|
authConfig: { token },
|
||||||
@@ -90,10 +101,9 @@ export default async function setupAndLink(
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
const detectedProjectName = basename(path);
|
const detectedProjectName = projectName || basename(path);
|
||||||
|
|
||||||
const projectOrNewProjectName = await inputProject(
|
const projectOrNewProjectName = await inputProject(
|
||||||
output,
|
|
||||||
client,
|
client,
|
||||||
org,
|
org,
|
||||||
detectedProjectName,
|
detectedProjectName,
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ import chalk from 'chalk';
|
|||||||
import title from 'title';
|
import title from 'title';
|
||||||
import bytes from 'bytes';
|
import bytes from 'bytes';
|
||||||
import { isReady, isFailed } from '../build-state';
|
import { isReady, isFailed } from '../build-state';
|
||||||
|
import { Build, BuildOutput } from '../../types';
|
||||||
|
|
||||||
|
export interface Times {
|
||||||
|
[id: string]: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
// That's how long the word "Initializing" is
|
// That's how long the word "Initializing" is
|
||||||
const longestState = 12;
|
const longestState = 12;
|
||||||
@@ -13,21 +18,24 @@ const padding = 8;
|
|||||||
const MAX_BUILD_GROUPS = 5;
|
const MAX_BUILD_GROUPS = 5;
|
||||||
const MAX_OUTPUTS_PER_GROUP = 5;
|
const MAX_OUTPUTS_PER_GROUP = 5;
|
||||||
|
|
||||||
const prepareState = state => title(state.replace('_', ' '));
|
const prepareState = (state: string) => title(state.replace('_', ' '));
|
||||||
|
|
||||||
|
const hasOutput = (b: Build) => Array.isArray(b.output) && b.output.length > 0;
|
||||||
|
|
||||||
// Get the common path out of multiple builds
|
// Get the common path out of multiple builds
|
||||||
const getCommonPath = (buildGroup) => {
|
const getCommonPath = (buildGroup: Build[]) => {
|
||||||
const commonPath = [];
|
const commonPath = [];
|
||||||
const splits = buildGroup.map((build) => getDirPath(build.entrypoint).split('/'));
|
const splits = buildGroup.map(build =>
|
||||||
const shortest = splits.reduce((prevValue, currentValue) =>
|
getDirPath(build.entrypoint).split('/')
|
||||||
prevValue.length < currentValue.length
|
);
|
||||||
? prevValue.length
|
const shortest = splits.reduce(
|
||||||
: currentValue.length
|
(prevValue, currentValue) => Math.min(prevValue, currentValue.length),
|
||||||
|
Infinity
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let i = 0; i <= shortest; i++) {
|
for (let i = 0; i <= shortest; i++) {
|
||||||
const first = splits[0][i];
|
const first = splits[0][i];
|
||||||
if (splits.every((pathParts) => pathParts[i] === first)) {
|
if (splits.every(pathParts => pathParts[i] === first)) {
|
||||||
commonPath.push(first);
|
commonPath.push(first);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -38,58 +46,63 @@ const getCommonPath = (buildGroup) => {
|
|||||||
return commonPath.join('/') || '/';
|
return commonPath.join('/') || '/';
|
||||||
};
|
};
|
||||||
|
|
||||||
const styleBuild = (build, times, longestSource) => {
|
const styleBuild = (build: Build, times: Times, longestSource: number) => {
|
||||||
const { entrypoint, readyState, id, hasOutput } = build;
|
const { entrypoint, readyState, id } = build;
|
||||||
const state = prepareState(readyState).padEnd(longestState + padding);
|
const state = prepareState(readyState).padEnd(longestState + padding);
|
||||||
const time = typeof times[id] === 'string' ? times[id] : '';
|
const time = typeof times[id] === 'string' ? times[id] : '';
|
||||||
|
|
||||||
let stateColor = chalk.grey;
|
let stateColor = chalk.grey;
|
||||||
let pathColor = chalk.cyan;
|
let pathColor = chalk.cyan;
|
||||||
|
|
||||||
if (isReady({ readyState })) {
|
if (isReady(build)) {
|
||||||
stateColor = item => item;
|
stateColor = chalk;
|
||||||
} else if (isFailed({ readyState })) {
|
} else if (isFailed(build)) {
|
||||||
stateColor = chalk.red;
|
stateColor = chalk.red;
|
||||||
pathColor = chalk.red;
|
pathColor = chalk.red;
|
||||||
}
|
}
|
||||||
|
|
||||||
const entry = entrypoint.padEnd(longestSource + padding);
|
const entry = entrypoint.padEnd(longestSource + padding);
|
||||||
const prefix = hasOutput ? '┌' : '╶';
|
const prefix = hasOutput(build) ? '┌' : '╶';
|
||||||
|
|
||||||
return `${chalk.grey(prefix)} ${pathColor(entry)}${stateColor(state)}${time}`;
|
return `${chalk.grey(prefix)} ${pathColor(entry)}${stateColor(state)}${time}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const styleHiddenBuilds = (commonPath, buildGroup, times, longestSource, isHidden = false) => {
|
const styleHiddenBuilds = (
|
||||||
|
commonPath: string,
|
||||||
|
buildGroup: Build[],
|
||||||
|
times: Times,
|
||||||
|
longestSource: number,
|
||||||
|
isHidden = false
|
||||||
|
) => {
|
||||||
const { id } = buildGroup[0];
|
const { id } = buildGroup[0];
|
||||||
const entry = commonPath.padEnd(longestSource + padding);
|
const entry = commonPath.padEnd(longestSource + padding);
|
||||||
const time = typeof times[id] === 'string' ? times[id] : '';
|
const time = typeof times[id] === 'string' ? times[id] : '';
|
||||||
const prefix = isHidden === false && buildGroup.some((build) => build.hasOutput) ? '┌' : '╶';
|
const prefix = isHidden === false && buildGroup.some(hasOutput) ? '┌' : '╶';
|
||||||
|
|
||||||
// Set the defaults so that they will be sorted
|
// Set the defaults so that they will be sorted
|
||||||
const stateMap = {
|
const stateMap: { [readyState: string]: number } = {
|
||||||
READY: 0,
|
READY: 0,
|
||||||
ERROR: 0,
|
ERROR: 0,
|
||||||
BUILDING: 0
|
BUILDING: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
buildGroup.map(({ readyState }) => {
|
for (const { readyState } of buildGroup) {
|
||||||
stateMap[readyState] = stateMap[readyState]
|
stateMap[readyState]++;
|
||||||
? stateMap[readyState] + 1
|
}
|
||||||
: 1;
|
|
||||||
|
|
||||||
return readyState;
|
let state = Object.keys(stateMap)
|
||||||
});
|
.map(readyState => {
|
||||||
|
const counter = stateMap[readyState];
|
||||||
|
const name = prepareState(readyState);
|
||||||
|
|
||||||
let state = Object.keys(stateMap).map((readyState) => {
|
if (!counter) {
|
||||||
const counter = stateMap[readyState];
|
return null;
|
||||||
const name = prepareState(readyState);
|
}
|
||||||
|
|
||||||
if (!counter) {
|
return `${counter > 9 ? '9+' : counter} ${name}`;
|
||||||
return null;
|
})
|
||||||
}
|
.filter(s => s)
|
||||||
|
.join(', ');
|
||||||
return `${counter > 9 ? '9+' : counter} ${name}`;
|
|
||||||
}).filter(s => s).join(', ')
|
|
||||||
|
|
||||||
// Since the longestState might still be shorter
|
// Since the longestState might still be shorter
|
||||||
// than multiple states we still want to ensure
|
// than multiple states we still want to ensure
|
||||||
@@ -100,7 +113,7 @@ const styleHiddenBuilds = (commonPath, buildGroup, times, longestSource, isHidd
|
|||||||
let stateColor = chalk.grey;
|
let stateColor = chalk.grey;
|
||||||
|
|
||||||
if (buildGroup.every(isReady)) {
|
if (buildGroup.every(isReady)) {
|
||||||
stateColor = item => item;
|
stateColor = chalk;
|
||||||
} else if (buildGroup.every(isFailed)) {
|
} else if (buildGroup.every(isFailed)) {
|
||||||
stateColor = chalk.red;
|
stateColor = chalk.red;
|
||||||
pathColor = chalk.red;
|
pathColor = chalk.red;
|
||||||
@@ -113,8 +126,12 @@ const styleHiddenBuilds = (commonPath, buildGroup, times, longestSource, isHidd
|
|||||||
return `${chalk.grey(prefix)} ${pathColor(entry)}${stateColor(state)}${time}`;
|
return `${chalk.grey(prefix)} ${pathColor(entry)}${stateColor(state)}${time}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const styleOutput = (output) => {
|
const styleOutput = (
|
||||||
const { type, path, readyState, size, isLast, lambda } = output;
|
output: BuildOutput,
|
||||||
|
readyState: Build['readyState'],
|
||||||
|
isLast: boolean
|
||||||
|
) => {
|
||||||
|
const { type, path, size, lambda } = output;
|
||||||
const prefix = type === 'lambda' ? 'λ ' : '';
|
const prefix = type === 'lambda' ? 'λ ' : '';
|
||||||
const finalSize = size ? ` ${chalk.grey(`(${bytes(size)})`)}` : '';
|
const finalSize = size ? ` ${chalk.grey(`(${bytes(size)})`)}` : '';
|
||||||
|
|
||||||
@@ -122,7 +139,7 @@ const styleOutput = (output) => {
|
|||||||
let finalRegion = '';
|
let finalRegion = '';
|
||||||
|
|
||||||
if (isReady({ readyState })) {
|
if (isReady({ readyState })) {
|
||||||
color = item => item;
|
color = chalk;
|
||||||
} else if (isFailed({ readyState })) {
|
} else if (isFailed({ readyState })) {
|
||||||
color = chalk.red;
|
color = chalk.red;
|
||||||
}
|
}
|
||||||
@@ -141,7 +158,11 @@ const styleOutput = (output) => {
|
|||||||
return `${chalk.grey(corner)} ${color(main)}`;
|
return `${chalk.grey(corner)} ${color(main)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDirPath = (path, level = 0, highestLevel = null) => {
|
const getDirPath = (
|
||||||
|
path: string,
|
||||||
|
level = 0,
|
||||||
|
highestLevel: number | null = null
|
||||||
|
) => {
|
||||||
const parts = path.split('/').slice(0, -1);
|
const parts = path.split('/').slice(0, -1);
|
||||||
|
|
||||||
if (highestLevel === null || level === 0) {
|
if (highestLevel === null || level === 0) {
|
||||||
@@ -152,7 +173,7 @@ const getDirPath = (path, level = 0, highestLevel = null) => {
|
|||||||
return parts.slice(0, reverseLevel).join('/');
|
return parts.slice(0, reverseLevel).join('/');
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortByEntrypoint = (a, b) => {
|
const sortByEntrypoint = (a: Build, b: Build) => {
|
||||||
const aPath = getDirPath(a.entrypoint);
|
const aPath = getDirPath(a.entrypoint);
|
||||||
const bPath = getDirPath(b.entrypoint);
|
const bPath = getDirPath(b.entrypoint);
|
||||||
|
|
||||||
@@ -175,22 +196,30 @@ const sortByEntrypoint = (a, b) => {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const groupBuilds = (buildList, highestLevel, counter) => {
|
const groupBuilds = (
|
||||||
const currentIndex = counter % (buildList.length);
|
buildList: Build[][],
|
||||||
|
highestLevel: number,
|
||||||
|
counter: number
|
||||||
|
) => {
|
||||||
|
const currentIndex = counter % buildList.length;
|
||||||
const __level = Math.ceil(counter / buildList.length);
|
const __level = Math.ceil(counter / buildList.length);
|
||||||
const _level = (__level === 0 ? 1 : __level) - 1;
|
const _level = (__level === 0 ? 1 : __level) - 1;
|
||||||
const level = _level > highestLevel ? highestLevel : _level;
|
const level = _level > highestLevel ? highestLevel : _level;
|
||||||
const currentPath = getDirPath(buildList[currentIndex][0].entrypoint, level, highestLevel);
|
const currentPath = getDirPath(
|
||||||
|
buildList[currentIndex][0].entrypoint,
|
||||||
|
level,
|
||||||
|
highestLevel
|
||||||
|
);
|
||||||
|
|
||||||
const nextList = [];
|
const nextList = [];
|
||||||
let currentGroup = [];
|
const currentGroup = [];
|
||||||
|
|
||||||
for (let i = 0; i < buildList.length; i++) {
|
for (let i = 0; i < buildList.length; i++) {
|
||||||
const group = buildList[i];
|
const group = buildList[i];
|
||||||
const path = getDirPath(group[0].entrypoint, level, highestLevel);
|
const path = getDirPath(group[0].entrypoint, level, highestLevel);
|
||||||
|
|
||||||
if (path === currentPath) {
|
if (path === currentPath) {
|
||||||
currentGroup = currentGroup.concat(group);
|
currentGroup.push(...group);
|
||||||
} else {
|
} else {
|
||||||
nextList.push(group);
|
nextList.push(group);
|
||||||
}
|
}
|
||||||
@@ -205,26 +234,10 @@ const groupBuilds = (buildList, highestLevel, counter) => {
|
|||||||
return nextList;
|
return nextList;
|
||||||
};
|
};
|
||||||
|
|
||||||
const prepareBuild = (build) => {
|
export default (builds: Build[], times: Times) => {
|
||||||
build.hasOutput = Array.isArray(build.output) && build.output.length > 0;
|
|
||||||
|
|
||||||
if (build.hasOutput) {
|
|
||||||
build.output = build.output.map((item) => {
|
|
||||||
item.readyState = build.readyState;
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return build;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default (builds, times) => {
|
|
||||||
// Sort the builds by path
|
// Sort the builds by path
|
||||||
// so that the grouping will be easier
|
// so that the grouping will be easier
|
||||||
let path = builds
|
let path = builds.sort(sortByEntrypoint).map(build => [build]);
|
||||||
.map(prepareBuild)
|
|
||||||
.sort(sortByEntrypoint)
|
|
||||||
.map(build => [build]);
|
|
||||||
|
|
||||||
const highestLevel = builds.reduce((prev, curr) => {
|
const highestLevel = builds.reduce((prev, curr) => {
|
||||||
const partCounter = curr.entrypoint.split('/').length - 1;
|
const partCounter = curr.entrypoint.split('/').length - 1;
|
||||||
@@ -251,28 +264,28 @@ export default (builds, times) => {
|
|||||||
const final = [];
|
const final = [];
|
||||||
let finalBuildsLength = path.length;
|
let finalBuildsLength = path.length;
|
||||||
let lengthWithoutRootPaths = path.length;
|
let lengthWithoutRootPaths = path.length;
|
||||||
let hiddenBuildGroup = [];
|
let hiddenBuildGroup: Build[] = [];
|
||||||
|
|
||||||
// Ungroup the root files
|
// Ungroup the root files
|
||||||
path = (() => {
|
path = (() => {
|
||||||
const nextList = [];
|
const nextList = [];
|
||||||
const rootList = [];
|
const rootList: Build[][] = [];
|
||||||
|
|
||||||
for (const group of path) {
|
for (const group of path) {
|
||||||
if (getCommonPath(group) === '/') {
|
if (getCommonPath(group) === '/') {
|
||||||
group.map((item) => rootList.push([item]));
|
group.map(item => rootList.push([item]));
|
||||||
} else {
|
} else {
|
||||||
nextList.push(group);
|
nextList.push(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lengthWithoutRootPaths = nextList.length;
|
lengthWithoutRootPaths = nextList.length;
|
||||||
rootList.map((group) => nextList.push(group));
|
rootList.map(group => nextList.push(group));
|
||||||
|
|
||||||
return nextList;
|
return nextList;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
path.map((buildGroup) => {
|
for (const buildGroup of path) {
|
||||||
const commonPath = getCommonPath(buildGroup);
|
const commonPath = getCommonPath(buildGroup);
|
||||||
|
|
||||||
// All items with the common path / are a single group
|
// All items with the common path / are a single group
|
||||||
@@ -286,51 +299,63 @@ export default (builds, times) => {
|
|||||||
finalBuildsLength++;
|
finalBuildsLength++;
|
||||||
} else {
|
} else {
|
||||||
hiddenBuildGroup.push(buildGroup[0]);
|
hiddenBuildGroup.push(buildGroup[0]);
|
||||||
return buildGroup;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (buildGroup.length === 1) {
|
} else if (buildGroup.length === 1) {
|
||||||
const item = buildGroup[0];
|
const item = buildGroup[0];
|
||||||
final.push(`${styleBuild(item, times, longestSource)}\n`);
|
final.push(`${styleBuild(item, times, longestSource)}\n`);
|
||||||
finalBuildsLength++;
|
finalBuildsLength++;
|
||||||
} else {
|
} else {
|
||||||
final.push(`${styleHiddenBuilds(`${commonPath}/*`, buildGroup, times, longestSource)}\n`);
|
final.push(
|
||||||
|
`${styleHiddenBuilds(
|
||||||
|
`${commonPath}/*`,
|
||||||
|
buildGroup,
|
||||||
|
times,
|
||||||
|
longestSource
|
||||||
|
)}\n`
|
||||||
|
);
|
||||||
finalBuildsLength++;
|
finalBuildsLength++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the first five outputs when the deployment is ready
|
// Get the first five outputs when the deployment is ready
|
||||||
const outputs = buildGroup.reduce((prevValue, currentValue) => (
|
const outputs: BuildOutput[] = [];
|
||||||
prevValue.concat(Array.isArray(currentValue.output)
|
for (const build of buildGroup) {
|
||||||
? currentValue.output
|
if (Array.isArray(build.output)) {
|
||||||
: []
|
outputs.push(...build.output);
|
||||||
)
|
}
|
||||||
), []);
|
|
||||||
|
|
||||||
outputs.slice(0, MAX_OUTPUTS_PER_GROUP).map((output, index) => (
|
|
||||||
final.push(`${styleOutput({
|
|
||||||
...output,
|
|
||||||
isLast: outputs.length === (index + 1)
|
|
||||||
})}\n`)
|
|
||||||
));
|
|
||||||
|
|
||||||
if (outputs.length > MAX_OUTPUTS_PER_GROUP) {
|
|
||||||
final.push(chalk.grey(`└── ${outputs.length - MAX_OUTPUTS_PER_GROUP} output items hidden\n`));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildGroup;
|
outputs
|
||||||
});
|
.slice(0, MAX_OUTPUTS_PER_GROUP)
|
||||||
|
.forEach((output, index) =>
|
||||||
|
final.push(
|
||||||
|
`${styleOutput(output, 'READY', outputs.length === index + 1)}\n`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (outputs.length > MAX_OUTPUTS_PER_GROUP) {
|
||||||
|
final.push(
|
||||||
|
chalk.grey(
|
||||||
|
`└── ${outputs.length - MAX_OUTPUTS_PER_GROUP} output items hidden\n`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hiddenBuildGroup.length) {
|
if (hiddenBuildGroup.length) {
|
||||||
final.push(`${styleHiddenBuilds(
|
final.push(
|
||||||
`${hiddenBuildGroup.length} builds hidden`,
|
`${styleHiddenBuilds(
|
||||||
hiddenBuildGroup,
|
`${hiddenBuildGroup.length} builds hidden`,
|
||||||
times,
|
hiddenBuildGroup,
|
||||||
longestSource,
|
times,
|
||||||
true
|
longestSource,
|
||||||
)}\n`);
|
true
|
||||||
|
)}\n`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lines: final.length + 1,
|
lines: final.length + 1,
|
||||||
toPrint: `${final.join('')}`
|
toPrint: `${final.join('')}`,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import { gray } from 'chalk';
|
|
||||||
|
|
||||||
const effect = msg => `${gray(`+ ${msg}`)}`;
|
|
||||||
|
|
||||||
export default effect;
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
//
|
|
||||||
import formatLogText from './format-log-text';
|
|
||||||
|
|
||||||
export default function formatLogCmd(text) {
|
|
||||||
return `▲ ${formatLogText(text)}`;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
//
|
|
||||||
import formatLogText from './format-log-text';
|
|
||||||
|
|
||||||
export default function formatLogOutput(text, prefix = '') {
|
|
||||||
return formatLogText(text)
|
|
||||||
.split('\n')
|
|
||||||
.map(textItem => `${prefix}${textItem.replace(/^> /, '')}`);
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
//
|
|
||||||
export default function formatLogText(text) {
|
|
||||||
return text.replace(/\n$/, '').replace(/^\n/, '');
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export default (input, level) => {
|
export default (input: string, level: number) => {
|
||||||
const fill = ' '.repeat(level);
|
const fill = ' '.repeat(level);
|
||||||
return `${fill}${input.replace(/\n/g, `\n${fill}`)}`;
|
return `${fill}${input.replace(/\n/g, `\n${fill}`)}`;
|
||||||
};
|
};
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import { yellow } from 'chalk';
|
|
||||||
|
|
||||||
const note = msg => `${yellow('> NOTE:')} ${msg}`;
|
|
||||||
|
|
||||||
export default note;
|
|
||||||
3
packages/cli/src/util/output/note.ts
Normal file
3
packages/cli/src/util/output/note.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { yellow } from 'chalk';
|
||||||
|
|
||||||
|
export default (msg: string) => `${yellow('> NOTE:')} ${msg}`;
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import { cyan } from 'chalk';
|
|
||||||
|
|
||||||
const ready = msg => `${cyan('> Ready!')} ${msg}`;
|
|
||||||
|
|
||||||
export default ready;
|
|
||||||
3
packages/cli/src/util/output/ready.ts
Normal file
3
packages/cli/src/util/output/ready.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { cyan } from 'chalk';
|
||||||
|
|
||||||
|
export default (msg: string) => `${cyan('> Ready!')} ${msg}`;
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export default (string, n = 0) => {
|
|
||||||
n -= string.length;
|
|
||||||
return string + ' '.repeat(n > -1 ? n : 0);
|
|
||||||
};
|
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
import { Route } from '@vercel/routing-utils';
|
||||||
|
|
||||||
const longestProperty = (routes, name) => {
|
const longestProperty = (routes: Route[], name: keyof Route): number => {
|
||||||
const longestItem = routes.sort((a, b) => {
|
const longestItem = routes.sort((a, b) => {
|
||||||
const firstItem = a[name] ? a[name].length : 0;
|
const aName = a[name];
|
||||||
const secondItem = b[name] ? b[name].length : 0;
|
const bName = b[name];
|
||||||
|
const firstItem = typeof aName === 'string' ? aName.length : 0;
|
||||||
|
const secondItem = typeof bName === 'string' ? bName.length : 0;
|
||||||
|
|
||||||
return secondItem - firstItem
|
return secondItem - firstItem;
|
||||||
})[0];
|
})[0];
|
||||||
|
|
||||||
if (!longestItem[name]) {
|
const val = longestItem[name];
|
||||||
return null;
|
return typeof val === 'string' ? val.length : 0;
|
||||||
}
|
|
||||||
|
|
||||||
return longestItem[name].length;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default routes => {
|
export default function routes(routes: Route[]) {
|
||||||
let toPrint = '';
|
let toPrint = '';
|
||||||
|
|
||||||
const longestSrc = longestProperty(routes, 'src');
|
const longestSrc = longestProperty(routes, 'src');
|
||||||
@@ -24,20 +24,22 @@ export default routes => {
|
|||||||
const padding = 6;
|
const padding = 6;
|
||||||
const space = ' '.repeat(padding);
|
const space = ' '.repeat(padding);
|
||||||
const destSpace = ' '.repeat(longestDest || 10);
|
const destSpace = ' '.repeat(longestDest || 10);
|
||||||
const arrow = chalk.grey('->')
|
const arrow = chalk.grey('->');
|
||||||
|
|
||||||
for (const item of routes) {
|
for (const item of routes) {
|
||||||
if (item.handle) {
|
if ('handle' in item) {
|
||||||
toPrint += `${chalk.grey('╶')} ${chalk.cyan(item.handle)}`;
|
toPrint += `${chalk.grey('╶')} ${chalk.cyan(item.handle)}`;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { src, dest, status, headers } = item;
|
const { src, dest, status, headers } = item;
|
||||||
const last = routes.indexOf(item) === (routes.length - 1);
|
const last = routes.indexOf(item) === routes.length - 1;
|
||||||
const suffix = last ? '' : `\n`;
|
const suffix = last ? '' : `\n`;
|
||||||
|
|
||||||
const finalSrc = chalk.cyan(src.padEnd(longestSrc + padding));
|
const finalSrc = chalk.cyan(src.padEnd(longestSrc + padding));
|
||||||
const finalDest = dest ? `${arrow}${space}${dest}` : ` ${space}${destSpace}`;
|
const finalDest = dest
|
||||||
|
? `${arrow}${space}${dest}`
|
||||||
|
: ` ${space}${destSpace}`;
|
||||||
const finalStatus = status ? chalk.grey(`[${status}]`) : '';
|
const finalStatus = status ? chalk.grey(`[${status}]`) : '';
|
||||||
|
|
||||||
let finalHeaders = null;
|
let finalHeaders = null;
|
||||||
@@ -49,7 +51,7 @@ export default routes => {
|
|||||||
|
|
||||||
for (const header of headerKeys) {
|
for (const header of headerKeys) {
|
||||||
const value = headers[header];
|
const value = headers[header];
|
||||||
const last = headerKeys.indexOf(header) === (headerKeys.length - 1);
|
const last = headerKeys.indexOf(header) === headerKeys.length - 1;
|
||||||
const suffix = last ? '' : `\n`;
|
const suffix = last ? '' : `\n`;
|
||||||
const prefix = chalk.grey(last ? '└──' : '├──');
|
const prefix = chalk.grey(last ? '└──' : '├──');
|
||||||
|
|
||||||
@@ -64,4 +66,4 @@ export default routes => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return toPrint;
|
return toPrint;
|
||||||
};
|
}
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
|
||||||
const printLine = (data, sizes) =>
|
const printLine = (data: string[], sizes: number[]) =>
|
||||||
data.reduce((line, col, i) => line + col.padEnd(sizes[i]), '');
|
data.reduce((line, col, i) => line + col.padEnd(sizes[i]), '');
|
||||||
|
|
||||||
// Print a table
|
/**
|
||||||
export default (fieldNames = [], data = [], margins = []) => {
|
* Print a table.
|
||||||
|
*/
|
||||||
|
export default function table(
|
||||||
|
fieldNames: string[] = [],
|
||||||
|
data: string[][] = [],
|
||||||
|
margins: number[] = []
|
||||||
|
) {
|
||||||
// Compute size of each column
|
// Compute size of each column
|
||||||
const sizes = data
|
const sizes = data
|
||||||
.reduce(
|
.reduce(
|
||||||
@@ -21,6 +27,9 @@ export default (fieldNames = [], data = [], margins = []) => {
|
|||||||
|
|
||||||
// Print header
|
// Print header
|
||||||
console.log(chalk.grey(printLine(fieldNames, sizes)));
|
console.log(chalk.grey(printLine(fieldNames, sizes)));
|
||||||
|
|
||||||
// Print content
|
// Print content
|
||||||
data.forEach(row => console.log(printLine(row, sizes)));
|
for (const row of data) {
|
||||||
};
|
console.log(printLine(row, sizes));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,4 +2,4 @@ import chalk from 'chalk';
|
|||||||
|
|
||||||
// Used for including uids in the output
|
// Used for including uids in the output
|
||||||
// example: `(dom_ji13dj2fih4fi2hf)`
|
// example: `(dom_ji13dj2fih4fi2hf)`
|
||||||
export default id => chalk.gray(`(${id})`);
|
export default (id: string) => chalk.gray(`(${id})`);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export default function parseMeta(meta) {
|
export default function parseMeta(meta?: string | string[]) {
|
||||||
if (!meta) {
|
if (!meta) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -7,12 +7,12 @@ export default function parseMeta(meta) {
|
|||||||
meta = [meta];
|
meta = [meta];
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsed = {};
|
const parsed: { [k: string]: string } = {};
|
||||||
|
|
||||||
meta.forEach(item => {
|
for (const item of meta) {
|
||||||
const [key, ...rest] = item.split('=');
|
const [key, ...rest] = item.split('=');
|
||||||
parsed[key] = rest.join('=');
|
parsed[key] = rest.join('=');
|
||||||
});
|
}
|
||||||
|
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
// @ts-ignore
|
|
||||||
import title from 'title';
|
import title from 'title';
|
||||||
|
|
||||||
import pkg from './pkg';
|
import pkg from './pkg';
|
||||||
import cmd from './output/cmd';
|
import cmd from './output/cmd';
|
||||||
|
|
||||||
@@ -8,9 +6,6 @@ import cmd from './output/cmd';
|
|||||||
* Returns the package name such as `vercel` or `now`.
|
* Returns the package name such as `vercel` or `now`.
|
||||||
*/
|
*/
|
||||||
export function getPkgName(): string {
|
export function getPkgName(): string {
|
||||||
if (!pkg.name) {
|
|
||||||
throw new Error('Expected `package.json` to have a `name` property.');
|
|
||||||
}
|
|
||||||
return pkg.name;
|
return pkg.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
import chalk from 'chalk';
|
|
||||||
|
|
||||||
export default promptOptions;
|
|
||||||
|
|
||||||
function promptOptions(opts) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
opts.forEach(([, text], i) => {
|
|
||||||
console.log(`${chalk.gray('>')} [${chalk.bold(i + 1)}] ${text}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
const ondata = v => {
|
|
||||||
const s = v.toString();
|
|
||||||
|
|
||||||
const cleanup = () => {
|
|
||||||
if (process.stdin) {
|
|
||||||
if (process.stdin.setRawMode) {
|
|
||||||
process.stdin.setRawMode(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdin.removeListener('data', ondata);
|
|
||||||
process.stdin.pause();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ctrl + C
|
|
||||||
if (s === '\u0003') {
|
|
||||||
cleanup();
|
|
||||||
const err = new Error('Aborted');
|
|
||||||
err.code = 'USER_ABORT';
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
const n = Number(s);
|
|
||||||
|
|
||||||
if (opts[n - 1]) {
|
|
||||||
cleanup();
|
|
||||||
resolve(opts[n - 1][0]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.stdin) {
|
|
||||||
if (process.stdin.setRawMode) {
|
|
||||||
process.stdin.setRawMode(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdin.resume();
|
|
||||||
process.stdin.on('data', ondata);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
export const maybeURL = id =>
|
export const maybeURL = (id: string): boolean =>
|
||||||
// E.g, "appname-asdf"
|
// E.g, "appname-asdf"
|
||||||
id.includes('-');
|
id.includes('-');
|
||||||
|
|
||||||
export const normalizeURL = u => {
|
export const normalizeURL = (u: string): string => {
|
||||||
// Normalize URL by removing slash from the end
|
// Normalize URL by removing slash from the end
|
||||||
if (u.slice(-1) === '/') {
|
if (u.slice(-1) === '/') {
|
||||||
u = u.slice(0, -1);
|
u = u.slice(0, -1);
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import wait from './output/wait';
|
|
||||||
|
|
||||||
export default async function withSpinner<T>(msg: string, f: () => Promise<T>) {
|
|
||||||
const stopSpinner = wait(msg);
|
|
||||||
try {
|
|
||||||
const res = await f();
|
|
||||||
stopSpinner();
|
|
||||||
return res;
|
|
||||||
} catch (error) {
|
|
||||||
stopSpinner();
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"builds": [
|
"builds": [
|
||||||
{
|
{
|
||||||
"src": "index.html",
|
"src": "index.html",
|
||||||
"use": "https://files-1bsmqkkol.now.sh"
|
"use": "https://files-17f5npcdc-testuser.vercel.app"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ function testFixtureStdio(
|
|||||||
const projectJsonPath = join(cwd, '.vercel', 'project.json');
|
const projectJsonPath = join(cwd, '.vercel', 'project.json');
|
||||||
await fs.remove(projectJsonPath);
|
await fs.remove(projectJsonPath);
|
||||||
const gitignore = join(cwd, '.gitignore');
|
const gitignore = join(cwd, '.gitignore');
|
||||||
const hasGitignore = await fs.exists(gitignore);
|
const hasGitignore = await fs.pathExists(gitignore);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Run `vc link`
|
// Run `vc link`
|
||||||
@@ -469,7 +469,7 @@ test('[vercel dev] `vercel.json` should be invalidated if deleted', async t => {
|
|||||||
t.is(body.FOO, undefined);
|
t.is(body.FOO, undefined);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
await dev.kill('SIGTERM');
|
dev.kill('SIGTERM');
|
||||||
await fs.writeJSON(configPath, originalConfig);
|
await fs.writeJSON(configPath, originalConfig);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -569,7 +569,7 @@ test('[vercel dev] reflects changes to config and env without restart', async t
|
|||||||
t.is(body.query.foo, 'boo');
|
t.is(body.query.foo, 'boo');
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
await dev.kill('SIGTERM');
|
dev.kill('SIGTERM');
|
||||||
await fs.writeJSON(configPath, originalConfig);
|
await fs.writeJSON(configPath, originalConfig);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -598,7 +598,7 @@ test('[vercel dev] `@vercel/node` TypeScript should be resolved by default', asy
|
|||||||
const body = await res.text();
|
const body = await res.text();
|
||||||
t.is(body, 'world');
|
t.is(body, 'world');
|
||||||
} finally {
|
} finally {
|
||||||
await dev.kill('SIGTERM');
|
dev.kill('SIGTERM');
|
||||||
await fs.remove(dir);
|
await fs.remove(dir);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -848,7 +848,7 @@ test('[vercel dev] validate env var names', async t => {
|
|||||||
|
|
||||||
t.pass();
|
t.pass();
|
||||||
} finally {
|
} finally {
|
||||||
await dev.kill('SIGTERM');
|
dev.kill('SIGTERM');
|
||||||
}
|
}
|
||||||
|
|
||||||
t.pass();
|
t.pass();
|
||||||
@@ -1431,7 +1431,7 @@ test(
|
|||||||
test('[vercel dev] 24-ember', async t => {
|
test('[vercel dev] 24-ember', async t => {
|
||||||
if (shouldSkip(t, '24-ember', '>^6.14.0 || ^8.10.0 || >=9.10.0')) return;
|
if (shouldSkip(t, '24-ember', '>^6.14.0 || ^8.10.0 || >=9.10.0')) return;
|
||||||
|
|
||||||
const tester = await testFixtureStdio(
|
const tester = testFixtureStdio(
|
||||||
'24-ember',
|
'24-ember',
|
||||||
async testPath => {
|
async testPath => {
|
||||||
await testPath(200, '/', /HelloWorld/m);
|
await testPath(200, '/', /HelloWorld/m);
|
||||||
@@ -1539,7 +1539,7 @@ test('[vercel dev] no build matches warning', async t => {
|
|||||||
|
|
||||||
t.pass();
|
t.pass();
|
||||||
} finally {
|
} finally {
|
||||||
await dev.kill('SIGTERM');
|
dev.kill('SIGTERM');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1577,7 +1577,7 @@ test('[vercel dev] render warning for empty cwd dir', async t => {
|
|||||||
validateResponseHeaders(t, response);
|
validateResponseHeaders(t, response);
|
||||||
t.is(response.status, 404);
|
t.is(response.status, 404);
|
||||||
} finally {
|
} finally {
|
||||||
await dev.kill('SIGTERM');
|
dev.kill('SIGTERM');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1617,7 +1617,7 @@ test('[vercel dev] do not rebuild for changes in the output directory', async t
|
|||||||
const text2 = await resp2.text();
|
const text2 = await resp2.text();
|
||||||
t.is(text2.trim(), 'hello second', stderr.join(''));
|
t.is(text2.trim(), 'hello second', stderr.join(''));
|
||||||
} finally {
|
} finally {
|
||||||
await dev.kill('SIGTERM');
|
dev.kill('SIGTERM');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
122
packages/cli/test/integration.js
vendored
122
packages/cli/test/integration.js
vendored
@@ -2030,12 +2030,8 @@ test('initialize example "angular"', async t => {
|
|||||||
cwd,
|
cwd,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(stderr);
|
|
||||||
console.log(stdout);
|
|
||||||
console.log(exitCode);
|
|
||||||
|
|
||||||
t.is(exitCode, 0, formatOutput({ stdout, stderr }));
|
t.is(exitCode, 0, formatOutput({ stdout, stderr }));
|
||||||
t.true(stdout.includes(goal), formatOutput({ stdout, stderr }));
|
t.true(stderr.includes(goal), formatOutput({ stdout, stderr }));
|
||||||
t.true(
|
t.true(
|
||||||
verifyExampleAngular(cwd, 'angular'),
|
verifyExampleAngular(cwd, 'angular'),
|
||||||
formatOutput({ stdout, stderr })
|
formatOutput({ stdout, stderr })
|
||||||
@@ -2054,13 +2050,9 @@ test('initialize example ("angular") to specified directory', async t => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(stderr);
|
t.is(exitCode, 0, formatOutput({ stdout, stderr }));
|
||||||
console.log(stdout);
|
t.true(stderr.includes(goal), formatOutput({ stdout, stderr }));
|
||||||
console.log(exitCode);
|
t.true(verifyExampleAngular(cwd, 'ang'), formatOutput({ stdout, stderr }));
|
||||||
|
|
||||||
t.is(exitCode, 0);
|
|
||||||
t.true(stdout.includes(goal));
|
|
||||||
t.true(verifyExampleAngular(cwd, 'ang'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('initialize selected example ("amp")', async t => {
|
test('initialize selected example ("amp")', async t => {
|
||||||
@@ -2073,12 +2065,8 @@ test('initialize selected example ("amp")', async t => {
|
|||||||
input: '\n',
|
input: '\n',
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(stderr);
|
|
||||||
console.log(stdout);
|
|
||||||
console.log(exitCode);
|
|
||||||
|
|
||||||
t.is(exitCode, 0, formatOutput({ stdout, stderr }));
|
t.is(exitCode, 0, formatOutput({ stdout, stderr }));
|
||||||
t.true(stdout.includes(goal), formatOutput({ stdout, stderr }));
|
t.true(stderr.includes(goal), formatOutput({ stdout, stderr }));
|
||||||
t.true(verifyExampleAmp(cwd, 'amp'), formatOutput({ stdout, stderr }));
|
t.true(verifyExampleAmp(cwd, 'amp'), formatOutput({ stdout, stderr }));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2096,13 +2084,12 @@ test('initialize example to existing directory with "-f"', async t => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(stderr);
|
t.is(exitCode, 0, formatOutput({ stdout, stderr }));
|
||||||
console.log(stdout);
|
t.true(stderr.includes(goal), formatOutput({ stdout, stderr }));
|
||||||
console.log(exitCode);
|
t.true(
|
||||||
|
verifyExampleAngular(cwd, 'angular'),
|
||||||
t.is(exitCode, 0);
|
formatOutput({ stdout, stderr })
|
||||||
t.true(stdout.includes(goal), formatOutput({ stdout, stderr }));
|
);
|
||||||
t.true(verifyExampleAngular(cwd, 'angular'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('try to initialize example to existing directory', async t => {
|
test('try to initialize example to existing directory', async t => {
|
||||||
@@ -2118,12 +2105,8 @@ test('try to initialize example to existing directory', async t => {
|
|||||||
input: '\n',
|
input: '\n',
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(stderr);
|
t.is(exitCode, 1, formatOutput({ stdout, stderr }));
|
||||||
console.log(stdout);
|
t.true(stderr.includes(goal), formatOutput({ stdout, stderr }));
|
||||||
console.log(exitCode);
|
|
||||||
|
|
||||||
t.is(exitCode, 1);
|
|
||||||
t.true(stdout.includes(goal), formatOutput({ stdout, stderr }));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('try to initialize misspelled example (noce) in non-tty', async t => {
|
test('try to initialize misspelled example (noce) in non-tty', async t => {
|
||||||
@@ -2138,8 +2121,8 @@ test('try to initialize misspelled example (noce) in non-tty', async t => {
|
|||||||
console.log(stdout);
|
console.log(stdout);
|
||||||
console.log(exitCode);
|
console.log(exitCode);
|
||||||
|
|
||||||
t.is(exitCode, 1);
|
t.is(exitCode, 1, formatOutput({ stdout, stderr }));
|
||||||
t.true(stdout.includes(goal), formatOutput({ stdout, stderr }));
|
t.true(stderr.includes(goal), formatOutput({ stdout, stderr }));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('try to initialize example "example-404"', async t => {
|
test('try to initialize example "example-404"', async t => {
|
||||||
@@ -2152,12 +2135,8 @@ test('try to initialize example "example-404"', async t => {
|
|||||||
cwd,
|
cwd,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(stderr);
|
t.is(exitCode, 1, formatOutput({ stdout, stderr }));
|
||||||
console.log(stdout);
|
t.true(stderr.includes(goal), formatOutput({ stdout, stderr }));
|
||||||
console.log(exitCode);
|
|
||||||
|
|
||||||
t.is(exitCode, 1);
|
|
||||||
t.true(stdout.includes(goal), formatOutput({ stdout, stderr }));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('try to revert a deployment and assign the automatic aliases', async t => {
|
test('try to revert a deployment and assign the automatic aliases', async t => {
|
||||||
@@ -2170,10 +2149,11 @@ test('try to revert a deployment and assign the automatic aliases', async t => {
|
|||||||
const url = `https://${name}.user.vercel.app`;
|
const url = `https://${name}.user.vercel.app`;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { stdout: deploymentUrl, stderr, exitCode } = await execute([
|
const {
|
||||||
firstDeployment,
|
stdout: deploymentUrl,
|
||||||
'--confirm',
|
stderr,
|
||||||
]);
|
exitCode,
|
||||||
|
} = await execute([firstDeployment, '--confirm']);
|
||||||
|
|
||||||
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
||||||
|
|
||||||
@@ -2190,10 +2170,11 @@ test('try to revert a deployment and assign the automatic aliases', async t => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const { stdout: deploymentUrl, stderr, exitCode } = await execute([
|
const {
|
||||||
secondDeployment,
|
stdout: deploymentUrl,
|
||||||
'--confirm',
|
stderr,
|
||||||
]);
|
exitCode,
|
||||||
|
} = await execute([secondDeployment, '--confirm']);
|
||||||
|
|
||||||
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
||||||
|
|
||||||
@@ -2212,10 +2193,11 @@ test('try to revert a deployment and assign the automatic aliases', async t => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const { stdout: deploymentUrl, stderr, exitCode } = await execute([
|
const {
|
||||||
firstDeployment,
|
stdout: deploymentUrl,
|
||||||
'--confirm',
|
stderr,
|
||||||
]);
|
exitCode,
|
||||||
|
} = await execute([firstDeployment, '--confirm']);
|
||||||
|
|
||||||
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
t.is(exitCode, 0, formatOutput({ stderr, stdout: deploymentUrl }));
|
||||||
|
|
||||||
@@ -2559,15 +2541,25 @@ test('deploy a Lambda with 3 seconds of maxDuration', async t => {
|
|||||||
|
|
||||||
t.is(output.exitCode, 0, formatOutput(output));
|
t.is(output.exitCode, 0, formatOutput(output));
|
||||||
|
|
||||||
const { host: url } = new URL(output.stdout);
|
const url = new URL(output.stdout);
|
||||||
|
|
||||||
const [response1, response2] = await Promise.all([
|
// Should time out
|
||||||
fetch('https://' + url + '/api/wait-for/2'),
|
url.pathname = '/api/wait-for/4';
|
||||||
fetch('https://' + url + '/api/wait-for/4'),
|
const response1 = await fetch(url.href);
|
||||||
]);
|
t.is(
|
||||||
|
response1.status,
|
||||||
|
504,
|
||||||
|
`Expected 504 status, got ${response1.status}: ${url}`
|
||||||
|
);
|
||||||
|
|
||||||
t.is(response1.status, 200, url);
|
// Should not time out
|
||||||
t.is(response2.status, 504, url);
|
url.pathname = '/api/wait-for/2';
|
||||||
|
const response2 = await fetch(url.href);
|
||||||
|
t.is(
|
||||||
|
response2.status,
|
||||||
|
200,
|
||||||
|
`Expected 200 status, got ${response1.status}: ${url}`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('fail to deploy a Lambda with an incorrect value for maxDuration', async t => {
|
test('fail to deploy a Lambda with an incorrect value for maxDuration', async t => {
|
||||||
@@ -3651,3 +3643,19 @@ test('[vc dev] should send the platform proxy request headers to frontend dev se
|
|||||||
process.kill(dev.pid, 'SIGTERM');
|
process.kill(dev.pid, 'SIGTERM');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('[vc link] should support the `--project` flag', async t => {
|
||||||
|
const projectName = 'link-project-flag';
|
||||||
|
const directory = fixture('static-deployment');
|
||||||
|
|
||||||
|
const [user, output] = await Promise.all([
|
||||||
|
fetchTokenInformation(token),
|
||||||
|
execute(['link', '--confirm', '--project', projectName, directory]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
t.is(output.exitCode, 0, formatOutput(output));
|
||||||
|
t.true(
|
||||||
|
output.stderr.includes(`Linked to ${user.username}/${projectName}`),
|
||||||
|
formatOutput(output)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
11
packages/cli/test/unit.js
vendored
11
packages/cli/test/unit.js
vendored
@@ -245,16 +245,7 @@ test('5xx response error with random JSON', async t => {
|
|||||||
t.is(formatted.message, 'Failed to process data (500)');
|
t.is(formatted.message, 'Failed to process data (500)');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getProjectName with argv - option 1', t => {
|
test('getProjectName with argv', t => {
|
||||||
const project = getProjectName({
|
|
||||||
argv: {
|
|
||||||
name: 'abc',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
t.is(project, 'abc');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('getProjectName with argv - option 2', t => {
|
|
||||||
const project = getProjectName({
|
const project = getProjectName({
|
||||||
argv: {
|
argv: {
|
||||||
'--name': 'abc',
|
'--name': 'abc',
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"lib": ["esnext"],
|
"lib": ["esnext"],
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
"typeRoots": ["./@types", "./node_modules/@types"]
|
"typeRoots": ["./@types", "./node_modules/@types"]
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"]
|
"include": ["src/**/*"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/client",
|
"name": "@vercel/client",
|
||||||
"version": "10.2.0",
|
"version": "10.2.3-canary.0",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"homepage": "https://vercel.com",
|
"homepage": "https://vercel.com",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "2.12.0",
|
"@vercel/build-utils": "2.12.3-canary.0",
|
||||||
"@zeit/fetch": "5.2.0",
|
"@zeit/fetch": "5.2.0",
|
||||||
"async-retry": "1.2.3",
|
"async-retry": "1.2.3",
|
||||||
"async-sema": "3.0.0",
|
"async-sema": "3.0.0",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { readdir as readRootFolder, lstatSync } from 'fs-extra';
|
import { lstatSync } from 'fs-extra';
|
||||||
|
|
||||||
import { relative, isAbsolute } from 'path';
|
import { relative, isAbsolute } from 'path';
|
||||||
import hashes, { mapToObject } from './utils/hashes';
|
import hashes, { mapToObject } from './utils/hashes';
|
||||||
@@ -50,8 +50,6 @@ export default function buildCreateDeployment() {
|
|||||||
clientOptions.isDirectory =
|
clientOptions.isDirectory =
|
||||||
!Array.isArray(path) && lstatSync(path).isDirectory();
|
!Array.isArray(path) && lstatSync(path).isDirectory();
|
||||||
|
|
||||||
let rootFiles: string[];
|
|
||||||
|
|
||||||
if (Array.isArray(path)) {
|
if (Array.isArray(path)) {
|
||||||
for (const filePath of path) {
|
for (const filePath of path) {
|
||||||
if (!isAbsolute(filePath)) {
|
if (!isAbsolute(filePath)) {
|
||||||
@@ -69,15 +67,11 @@ export default function buildCreateDeployment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (clientOptions.isDirectory && !Array.isArray(path)) {
|
if (clientOptions.isDirectory && !Array.isArray(path)) {
|
||||||
debug(`Provided 'path' is a directory. Reading subpaths... `);
|
debug(`Provided 'path' is a directory.`);
|
||||||
rootFiles = await readRootFolder(path);
|
|
||||||
debug(`Read ${rootFiles.length} subpaths`);
|
|
||||||
} else if (Array.isArray(path)) {
|
} else if (Array.isArray(path)) {
|
||||||
debug(`Provided 'path' is an array of file paths`);
|
debug(`Provided 'path' is an array of file paths`);
|
||||||
rootFiles = path;
|
|
||||||
} else {
|
} else {
|
||||||
debug(`Provided 'path' is a single file`);
|
debug(`Provided 'path' is a single file`);
|
||||||
rootFiles = [path];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let { fileList } = await buildFileTree(
|
let { fileList } = await buildFileTree(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/frameworks",
|
"name": "@vercel/frameworks",
|
||||||
"version": "0.5.0",
|
"version": "0.5.1-canary.1",
|
||||||
"main": "./dist/frameworks.js",
|
"main": "./dist/frameworks.js",
|
||||||
"types": "./dist/frameworks.d.ts",
|
"types": "./dist/frameworks.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -22,8 +22,6 @@
|
|||||||
"@types/node-fetch": "2.5.8",
|
"@types/node-fetch": "2.5.8",
|
||||||
"@vercel/routing-utils": "1.11.3",
|
"@vercel/routing-utils": "1.11.3",
|
||||||
"ajv": "6.12.2",
|
"ajv": "6.12.2",
|
||||||
"jest": "24.9.0",
|
|
||||||
"ts-jest": "24.1.0",
|
|
||||||
"typescript": "4.3.4"
|
"typescript": "4.3.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import { readConfigFile } from './read-config-file';
|
|||||||
|
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|
||||||
const { readdir, stat, readFile, unlink } = promises;
|
const { readdir, readFile, unlink } = promises;
|
||||||
const isDir = async (file: string): Promise<boolean> =>
|
|
||||||
(await stat(file)).isDirectory();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Please note that is extremely important that the `dependency` property needs
|
* Please note that is extremely important that the `dependency` property needs
|
||||||
@@ -313,11 +311,11 @@ export const frameworks = [
|
|||||||
const base = 'build';
|
const base = 'build';
|
||||||
try {
|
try {
|
||||||
const location = join(dirPrefix, base);
|
const location = join(dirPrefix, base);
|
||||||
const content = await readdir(location);
|
const content = await readdir(location, { withFileTypes: true });
|
||||||
|
|
||||||
// If there is only one file in it that is a dir we'll use it as dist dir
|
// If there is only one file in it that is a dir we'll use it as dist dir
|
||||||
if (content.length === 1 && (await isDir(join(location, content[0])))) {
|
if (content.length === 1 && content[0].isDirectory()) {
|
||||||
return join(base, content[0]);
|
return join(base, content[0].name);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error detecting output directory: `, error);
|
console.error(`Error detecting output directory: `, error);
|
||||||
@@ -402,11 +400,11 @@ export const frameworks = [
|
|||||||
const base = 'build';
|
const base = 'build';
|
||||||
try {
|
try {
|
||||||
const location = join(dirPrefix, base);
|
const location = join(dirPrefix, base);
|
||||||
const content = await readdir(location);
|
const content = await readdir(location, { withFileTypes: true });
|
||||||
|
|
||||||
// If there is only one file in it that is a dir we'll use it as dist dir
|
// If there is only one file in it that is a dir we'll use it as dist dir
|
||||||
if (content.length === 1 && (await isDir(join(location, content[0])))) {
|
if (content.length === 1 && content[0].isDirectory()) {
|
||||||
return join(base, content[0]);
|
return join(base, content[0].name);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error detecting output directory: `, error);
|
console.error(`Error detecting output directory: `, error);
|
||||||
@@ -744,11 +742,11 @@ export const frameworks = [
|
|||||||
const base = 'dist';
|
const base = 'dist';
|
||||||
try {
|
try {
|
||||||
const location = join(dirPrefix, base);
|
const location = join(dirPrefix, base);
|
||||||
const content = await readdir(location);
|
const content = await readdir(location, { withFileTypes: true });
|
||||||
|
|
||||||
// If there is only one file in it that is a dir we'll use it as dist dir
|
// If there is only one file in it that is a dir we'll use it as dist dir
|
||||||
if (content.length === 1 && (await isDir(join(location, content[0])))) {
|
if (content.length === 1 && content[0].isDirectory()) {
|
||||||
return join(base, content[0]);
|
return join(base, content[0].name);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error detecting output directory: `, error);
|
console.error(`Error detecting output directory: `, error);
|
||||||
@@ -830,8 +828,7 @@ export const frameworks = [
|
|||||||
logo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/svelte.svg',
|
logo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/svelte.svg',
|
||||||
tagline:
|
tagline:
|
||||||
'Svelte lets you write high performance reactive apps with significantly less boilerplate.',
|
'Svelte lets you write high performance reactive apps with significantly less boilerplate.',
|
||||||
description:
|
description: 'A basic Svelte app using the default template.',
|
||||||
'A basic Svelte app using the default template.',
|
|
||||||
website: 'https://svelte.dev',
|
website: 'https://svelte.dev',
|
||||||
detectors: {
|
detectors: {
|
||||||
every: [
|
every: [
|
||||||
@@ -882,8 +879,7 @@ export const frameworks = [
|
|||||||
logo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/svelte.svg',
|
logo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/svelte.svg',
|
||||||
tagline:
|
tagline:
|
||||||
'SvelteKit is a framework for building web applications of all sizes.',
|
'SvelteKit is a framework for building web applications of all sizes.',
|
||||||
description:
|
description: 'A SvelteKit app optimized to work for serverless.',
|
||||||
'A SvelteKit app optimized to work for serverless.',
|
|
||||||
website: 'https://kit.svelte.dev',
|
website: 'https://kit.svelte.dev',
|
||||||
detectors: {
|
detectors: {
|
||||||
every: [
|
every: [
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
let buildUtils: typeof import('@vercel/build-utils');
|
|
||||||
|
|
||||||
try {
|
|
||||||
buildUtils = require('@vercel/build-utils');
|
|
||||||
} catch (e) {
|
|
||||||
// Fallback for older CLI versions
|
|
||||||
buildUtils = require('@now/build-utils');
|
|
||||||
}
|
|
||||||
|
|
||||||
export default buildUtils;
|
|
||||||
@@ -12,16 +12,7 @@ async function main() {
|
|||||||
// Build with `ncc`
|
// Build with `ncc`
|
||||||
await execa(
|
await execa(
|
||||||
'ncc',
|
'ncc',
|
||||||
[
|
['build', 'index.ts', '-e', '@vercel/build-utils', '-o', outDir],
|
||||||
'build',
|
|
||||||
'index.ts',
|
|
||||||
'-e',
|
|
||||||
'@vercel/build-utils',
|
|
||||||
'-e',
|
|
||||||
'@now/build-utils',
|
|
||||||
'-o',
|
|
||||||
outDir,
|
|
||||||
],
|
|
||||||
{
|
{
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ import execa from 'execa';
|
|||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { mkdirp, pathExists, readFile } from 'fs-extra';
|
import { mkdirp, pathExists, readFile } from 'fs-extra';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import buildUtils from './build-utils';
|
|
||||||
import stringArgv from 'string-argv';
|
import stringArgv from 'string-argv';
|
||||||
const { debug } = buildUtils;
|
import { debug } from '@vercel/build-utils';
|
||||||
const versionMap = new Map([
|
const versionMap = new Map([
|
||||||
['1.16', '1.16'],
|
['1.16', '1.16'],
|
||||||
['1.15', '1.15.8'],
|
['1.15', '1.15.8'],
|
||||||
|
|||||||
@@ -20,17 +20,13 @@ import {
|
|||||||
PrepareCacheOptions,
|
PrepareCacheOptions,
|
||||||
StartDevServerOptions,
|
StartDevServerOptions,
|
||||||
StartDevServerResult,
|
StartDevServerResult,
|
||||||
} from '@vercel/build-utils';
|
|
||||||
import buildUtils from './build-utils';
|
|
||||||
|
|
||||||
const {
|
|
||||||
glob,
|
glob,
|
||||||
download,
|
download,
|
||||||
createLambda,
|
createLambda,
|
||||||
getWriteableDirectory,
|
getWriteableDirectory,
|
||||||
shouldServe,
|
shouldServe,
|
||||||
debug,
|
debug,
|
||||||
} = buildUtils;
|
} from '@vercel/build-utils';
|
||||||
|
|
||||||
const TMP = tmpdir();
|
const TMP = tmpdir();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/go",
|
"name": "@vercel/go",
|
||||||
"version": "1.2.3",
|
"version": "1.2.4-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||||
|
|||||||
@@ -155,7 +155,8 @@ class Bridge {
|
|||||||
const { port } = await this.listening;
|
const { port } = await this.listening;
|
||||||
|
|
||||||
const normalizedEvent = normalizeEvent(event);
|
const normalizedEvent = normalizeEvent(event);
|
||||||
const { isApiGateway, method, path, headers, body } = normalizedEvent;
|
const { isApiGateway, method, headers, body } = normalizedEvent;
|
||||||
|
let { path } = normalizedEvent;
|
||||||
|
|
||||||
if (this.shouldStoreEvents) {
|
if (this.shouldStoreEvents) {
|
||||||
const reqId = `${this.reqIdSeed++}`;
|
const reqId = `${this.reqIdSeed++}`;
|
||||||
@@ -165,6 +166,12 @@ class Bridge {
|
|||||||
|
|
||||||
// eslint-disable-next-line consistent-return
|
// eslint-disable-next-line consistent-return
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
// if the path is improperly encoded we need to encode it or
|
||||||
|
// http.request will throw an error (related check: https://github.com/nodejs/node/blob/4ece669c6205ec78abfdadfe78869bbb8411463e/lib/_http_client.js#L84)
|
||||||
|
if (path && /[^\u0021-\u00ff]/.test(path)) {
|
||||||
|
path = encodeURI(path);
|
||||||
|
}
|
||||||
|
|
||||||
const opts = { hostname: '127.0.0.1', port, path, method };
|
const opts = { hostname: '127.0.0.1', port, path, method };
|
||||||
const req = request(opts, res => {
|
const req = request(opts, res => {
|
||||||
const response = res;
|
const response = res;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/node-bridge",
|
"name": "@vercel/node-bridge",
|
||||||
"version": "2.1.0",
|
"version": "2.1.1-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./index.js",
|
"main": "./index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
38
packages/node-bridge/test/bridge.test.js
vendored
38
packages/node-bridge/test/bridge.test.js
vendored
@@ -122,6 +122,44 @@ test('consumeEvent', async () => {
|
|||||||
server.close();
|
server.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('consumeEvent and handle decoded path', async () => {
|
||||||
|
const mockListener = jest.fn((req, res) => {
|
||||||
|
res.end('hello');
|
||||||
|
});
|
||||||
|
|
||||||
|
const server = new Server(mockListener);
|
||||||
|
const bridge = new Bridge(server, true);
|
||||||
|
bridge.listen();
|
||||||
|
|
||||||
|
const context = { callbackWaitsForEmptyEventLoop: true };
|
||||||
|
await bridge.launcher(
|
||||||
|
{
|
||||||
|
Action: 'Invoke',
|
||||||
|
body: JSON.stringify({
|
||||||
|
method: 'POST',
|
||||||
|
headers: { foo: 'baz' },
|
||||||
|
path: '/now proxy',
|
||||||
|
body: 'body=1',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
const headers = mockListener.mock.calls[0][0].headers;
|
||||||
|
const reqId = headers['x-now-bridge-request-id'];
|
||||||
|
|
||||||
|
expect(reqId).toBeTruthy();
|
||||||
|
|
||||||
|
const event = bridge.consumeEvent(reqId);
|
||||||
|
expect(event.body.toString()).toBe('body=1');
|
||||||
|
|
||||||
|
// an event can't be consumed multiple times
|
||||||
|
// to avoid memory leaks
|
||||||
|
expect(bridge.consumeEvent(reqId)).toBeUndefined();
|
||||||
|
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
|
||||||
test('invalid request headers', async () => {
|
test('invalid request headers', async () => {
|
||||||
const server = new Server((req, res) =>
|
const server = new Server((req, res) =>
|
||||||
res.end(
|
res.end(
|
||||||
|
|||||||
@@ -53,8 +53,6 @@ async function main() {
|
|||||||
'@vercel/node-bridge',
|
'@vercel/node-bridge',
|
||||||
'-e',
|
'-e',
|
||||||
'@vercel/build-utils',
|
'@vercel/build-utils',
|
||||||
'-e',
|
|
||||||
'@now/build-utils',
|
|
||||||
'-o',
|
'-o',
|
||||||
helpersDir,
|
helpersDir,
|
||||||
],
|
],
|
||||||
@@ -74,8 +72,6 @@ async function main() {
|
|||||||
'@vercel/node-bridge',
|
'@vercel/node-bridge',
|
||||||
'-e',
|
'-e',
|
||||||
'@vercel/build-utils',
|
'@vercel/build-utils',
|
||||||
'-e',
|
|
||||||
'@now/build-utils',
|
|
||||||
'-o',
|
'-o',
|
||||||
sourceMapSupportDir,
|
sourceMapSupportDir,
|
||||||
],
|
],
|
||||||
@@ -98,8 +94,6 @@ async function main() {
|
|||||||
'-e',
|
'-e',
|
||||||
'@vercel/build-utils',
|
'@vercel/build-utils',
|
||||||
'-e',
|
'-e',
|
||||||
'@now/build-utils',
|
|
||||||
'-e',
|
|
||||||
'typescript',
|
'typescript',
|
||||||
'-o',
|
'-o',
|
||||||
mainDir,
|
mainDir,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/node",
|
"name": "@vercel/node",
|
||||||
"version": "1.12.0",
|
"version": "1.12.2-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
"@types/test-listen": "1.1.0",
|
"@types/test-listen": "1.1.0",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"@vercel/nft": "0.13.1",
|
"@vercel/nft": "0.13.1",
|
||||||
"@vercel/node-bridge": "2.1.0",
|
"@vercel/node-bridge": "2.1.1-canary.0",
|
||||||
"content-type": "1.0.4",
|
"content-type": "1.0.4",
|
||||||
"cookie": "0.4.0",
|
"cookie": "0.4.0",
|
||||||
"etag": "1.8.1",
|
"etag": "1.8.1",
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
let buildUtils: typeof import('@vercel/build-utils');
|
|
||||||
|
|
||||||
try {
|
|
||||||
buildUtils = require('@vercel/build-utils');
|
|
||||||
} catch (e) {
|
|
||||||
// Fallback for older CLI versions
|
|
||||||
buildUtils = require('@now/build-utils');
|
|
||||||
}
|
|
||||||
|
|
||||||
export default buildUtils;
|
|
||||||
@@ -20,7 +20,6 @@ import {
|
|||||||
import mkdirp from 'mkdirp-promise';
|
import mkdirp from 'mkdirp-promise';
|
||||||
import once from '@tootallnate/once';
|
import once from '@tootallnate/once';
|
||||||
import { nodeFileTrace } from '@vercel/nft';
|
import { nodeFileTrace } from '@vercel/nft';
|
||||||
import buildUtils from './build-utils';
|
|
||||||
import {
|
import {
|
||||||
File,
|
File,
|
||||||
Files,
|
Files,
|
||||||
@@ -30,8 +29,6 @@ import {
|
|||||||
Config,
|
Config,
|
||||||
StartDevServerOptions,
|
StartDevServerOptions,
|
||||||
StartDevServerResult,
|
StartDevServerResult,
|
||||||
} from '@vercel/build-utils';
|
|
||||||
const {
|
|
||||||
glob,
|
glob,
|
||||||
download,
|
download,
|
||||||
FileBlob,
|
FileBlob,
|
||||||
@@ -45,7 +42,7 @@ const {
|
|||||||
debug,
|
debug,
|
||||||
isSymbolicLink,
|
isSymbolicLink,
|
||||||
walkParentDirs,
|
walkParentDirs,
|
||||||
} = buildUtils;
|
} from '@vercel/build-utils';
|
||||||
|
|
||||||
// @ts-ignore - copied to the `dist` output as-is
|
// @ts-ignore - copied to the `dist` output as-is
|
||||||
import { makeVercelLauncher, makeAwsLauncher } from './launcher.js';
|
import { makeVercelLauncher, makeAwsLauncher } from './launcher.js';
|
||||||
@@ -112,7 +109,7 @@ async function downloadInstallAndBundle({
|
|||||||
} else {
|
} else {
|
||||||
const installTime = Date.now();
|
const installTime = Date.now();
|
||||||
console.log('Installing dependencies...');
|
console.log('Installing dependencies...');
|
||||||
await runNpmInstall(entrypointFsDirname, [], spawnOpts, meta);
|
await runNpmInstall(entrypointFsDirname, [], spawnOpts, meta, nodeVersion);
|
||||||
debug(`Install complete [${Date.now() - installTime}ms]`);
|
debug(`Install complete [${Date.now() - installTime}ms]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,18 +357,14 @@ export async function build({
|
|||||||
const baseDir = repoRootPath || workPath;
|
const baseDir = repoRootPath || workPath;
|
||||||
const awsLambdaHandler = getAWSLambdaHandler(entrypoint, config);
|
const awsLambdaHandler = getAWSLambdaHandler(entrypoint, config);
|
||||||
|
|
||||||
const {
|
const { entrypointPath, entrypointFsDirname, nodeVersion, spawnOpts } =
|
||||||
entrypointPath,
|
await downloadInstallAndBundle({
|
||||||
entrypointFsDirname,
|
files,
|
||||||
nodeVersion,
|
entrypoint,
|
||||||
spawnOpts,
|
workPath,
|
||||||
} = await downloadInstallAndBundle({
|
config,
|
||||||
files,
|
meta,
|
||||||
entrypoint,
|
});
|
||||||
workPath,
|
|
||||||
config,
|
|
||||||
meta,
|
|
||||||
});
|
|
||||||
|
|
||||||
await runPackageJsonScript(
|
await runPackageJsonScript(
|
||||||
entrypointFsDirname,
|
entrypointFsDirname,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export type NowRequestCookies = VercelRequestCookies;
|
|||||||
/** @deprecated Use VercelRequestQuery instead. */
|
/** @deprecated Use VercelRequestQuery instead. */
|
||||||
export type NowRequestQuery = VercelRequestQuery;
|
export type NowRequestQuery = VercelRequestQuery;
|
||||||
|
|
||||||
/** @deprecated Use `any` instead. */
|
/** @deprecated Use VercelRequestBody instead. */
|
||||||
export type NowRequestBody = any;
|
export type NowRequestBody = any;
|
||||||
|
|
||||||
/** @deprecated Use VercelRequest instead. */
|
/** @deprecated Use VercelRequest instead. */
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { relative, basename, resolve, dirname } from 'path';
|
|
||||||
import _ts from 'typescript';
|
import _ts from 'typescript';
|
||||||
import buildUtils from './build-utils';
|
import { NowBuildError } from '@vercel/build-utils';
|
||||||
const { NowBuildError } = buildUtils;
|
import { relative, basename, resolve, dirname } from 'path';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fork of TS-Node - https://github.com/TypeStrong/ts-node
|
* Fork of TS-Node - https://github.com/TypeStrong/ts-node
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ async function main() {
|
|||||||
join(__dirname, 'src/index.ts'),
|
join(__dirname, 'src/index.ts'),
|
||||||
'-e',
|
'-e',
|
||||||
'@vercel/build-utils',
|
'@vercel/build-utils',
|
||||||
'-e',
|
|
||||||
'@now/build-utils',
|
|
||||||
'-o',
|
'-o',
|
||||||
outDir,
|
outDir,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/python",
|
"name": "@vercel/python",
|
||||||
"version": "2.0.5",
|
"version": "2.0.6-canary.0",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
let buildUtils: typeof import('@vercel/build-utils');
|
|
||||||
|
|
||||||
try {
|
|
||||||
buildUtils = require('@vercel/build-utils');
|
|
||||||
} catch (e) {
|
|
||||||
// Fallback for older CLI versions
|
|
||||||
buildUtils = require('@now/build-utils');
|
|
||||||
}
|
|
||||||
|
|
||||||
export default buildUtils;
|
|
||||||
@@ -4,16 +4,16 @@ import fs from 'fs';
|
|||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
const readFile = promisify(fs.readFile);
|
const readFile = promisify(fs.readFile);
|
||||||
const writeFile = promisify(fs.writeFile);
|
const writeFile = promisify(fs.writeFile);
|
||||||
import buildUtils from './build-utils';
|
import {
|
||||||
import { GlobOptions, BuildOptions } from '@vercel/build-utils';
|
GlobOptions,
|
||||||
const {
|
BuildOptions,
|
||||||
getWriteableDirectory,
|
getWriteableDirectory,
|
||||||
download,
|
download,
|
||||||
glob,
|
glob,
|
||||||
createLambda,
|
createLambda,
|
||||||
shouldServe,
|
shouldServe,
|
||||||
debug,
|
debug,
|
||||||
} = buildUtils;
|
} from '@vercel/build-utils';
|
||||||
import { installRequirement, installRequirementsFile } from './install';
|
import { installRequirement, installRequirementsFile } from './install';
|
||||||
|
|
||||||
async function pipenvConvert(cmd: string, srcDir: string) {
|
async function pipenvConvert(cmd: string, srcDir: string) {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import execa from 'execa';
|
import execa from 'execa';
|
||||||
import { Meta } from '@vercel/build-utils';
|
import { Meta, debug } from '@vercel/build-utils';
|
||||||
import buildUtils from './build-utils';
|
|
||||||
const { debug } = buildUtils;
|
|
||||||
const pipPath = 'pip3';
|
const pipPath = 'pip3';
|
||||||
|
|
||||||
const makeDependencyCheckCode = (dependency: string) => `
|
const makeDependencyCheckCode = (dependency: string) => `
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
let buildUtils: typeof import('@vercel/build-utils');
|
|
||||||
|
|
||||||
try {
|
|
||||||
buildUtils = require('@vercel/build-utils');
|
|
||||||
} catch (e) {
|
|
||||||
// Fallback for older CLI versions
|
|
||||||
buildUtils = require('@now/build-utils');
|
|
||||||
}
|
|
||||||
|
|
||||||
export default buildUtils;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user