Compare commits

...

29 Commits

Author SHA1 Message Date
luc
0ee88366ff Publish Stable
- vercel@20.1.4
2020-11-12 17:16:29 +01:00
luc
9ae42c9e92 Publish Canary
- vercel@20.1.4-canary.1
2020-11-12 16:59:28 +01:00
Luc Leray
62b8df4a8d [cli] Fix vc env rm with advanced env variables (#5411) 2020-11-12 16:58:41 +01:00
luc
73ec7f3018 Publish Canary
- vercel@20.1.4-canary.0
2020-11-12 15:31:54 +01:00
Luc Leray
2d24a75ca6 Revert "[cli] (major) Update vercel env (#5372)" (#5410)
* Revert "[cli] (major) Update `vercel env` (#5372)"

This reverts commit 9a57cc72dd.

* fix test

* do not change prompt UI
2020-11-12 15:30:47 +01:00
Nathan Rajlich
3f92c42ad6 Publish Stable
- @vercel/frameworks@0.2.0
 - @vercel/build-utils@2.6.0
 - vercel@20.1.3
 - @vercel/client@9.0.4
 - @vercel/next@2.7.0
 - @vercel/node@1.8.5
 - @vercel/routing-utils@1.9.1
 - @vercel/static-build@0.18.0
 - @vercel/redwood@0.2.0
2020-11-11 16:01:46 -08:00
Andy Bitz
d824f79d5a Publish Canary
- @vercel/static-build@0.17.16-canary.1
2020-11-12 00:36:43 +01:00
Andy
eefbf3a52d [static-build] Fix order of applying routes (#5408)
* [static-build] Fix order of applying routes

* Add test

* Fix 11-svelte
2020-11-12 00:36:02 +01:00
Nathan Rajlich
dda793018b Publish Canary
- @vercel/build-utils@2.5.5-canary.4
 - vercel@20.1.3-canary.9
 - @vercel/client@9.0.4-canary.5
2020-11-11 14:30:14 -08:00
Nathan Rajlich
9e588068ea [build-utils] Include installCommand when empty string (#5406)
* [build-utils] Include `installCommand` when empty string

An empty string for the Project's `installCommand` setting has different
behavior than `null`, so properly provide the empty string to the
Runtime.

* Move tests to proper section
2020-11-11 14:14:57 -08:00
Chris Leishman
76a7a51bdc [docs] Add required information for pull requests (#5282) 2020-11-11 19:43:20 +00:00
Nathan Rajlich
5f5b5b0340 Publish Canary
- vercel@20.1.3-canary.8
 - @vercel/next@2.6.39-canary.1
 - @vercel/node@1.8.5-canary.0
 - @vercel/static-build@0.17.16-canary.0
 - @vercel/redwood@0.1.2-canary.3
2020-11-11 10:31:14 -08:00
Nathan Rajlich
a0ce373dc9 [static-build][next][node][redwood] Invoke installCommand from Project settings (#5393)
* [static-build] Invoke `installCommand` from Project settings

* [next] Invoke `installCommand` from Project settings

* [redwood] Invoke `installCommand` from Project settings

* [node] Remove `--prefer-offline` npm flag

* [static-build] Remove `--prefer-offline` npm flag

* [next] Remove extra console.log()

* Move `installTime` to inside else branch

* Use `as keyof Config`

* [static-build] Add `installCommand` integration test

* [next] Add `installCommand` integration test

* Use `.`

* [redwood] Add `installCommand` integration test

* Skip `installCommand` if string is empty

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-11-11 10:26:57 -08:00
Steven
049ffb268b [examples] Update svelte example with latest rollup (#5404)
Updated the template using `npx degit sveltejs/template my-svelte-project`

I also added a `yarn.lock` file so dependencies don't break for future deployments.

Related to https://github.com/Samuel-Martineau/generator-svelte/issues/7
2020-11-11 09:44:06 -05:00
Andy Bitz
94483c8b36 Publish Stable
- @vercel/static-build@0.17.15
2020-11-10 21:32:13 +01:00
Andy Bitz
078f9de44e Publish Canary
- @vercel/frameworks@0.1.2-canary.2
 - @vercel/build-utils@2.5.5-canary.3
 - vercel@20.1.3-canary.7
 - @vercel/client@9.0.4-canary.4
 - @vercel/static-build@0.17.15-canary.0
 - @vercel/redwood@0.1.2-canary.2
2020-11-10 21:18:48 +01:00
Andy
0ae41f97a4 [static-build] Ignore framework routes if config/routes.json is present (#5401) 2020-11-10 21:17:45 +01:00
Nathan Rajlich
9fb6a1ec4c [frameworks] Use "value" instead of "placeholder" for frameworks with known installCommand (#5400) 2020-11-10 11:25:16 -08:00
Andy Bitz
21be46c8bb Publish Stable
- @vercel/static-build@0.17.14
2020-11-10 18:51:06 +01:00
Andy
91942fc4d2 [static-build] Expect routes array directly (#5399) 2020-11-10 18:49:51 +01:00
Andy Bitz
8e02f2289f Publish Stable
- @vercel/static-build@0.17.13
2020-11-10 16:21:58 +01:00
Andy Bitz
4205d643a1 Publish Canary
- @vercel/next@2.6.39-canary.0
 - @vercel/static-build@0.17.13-canary.0
2020-11-10 16:19:08 +01:00
Andy
b2dda4dbb9 [static-build] Support static and config directory in .vercel_build_output (#5396)
* Handle routes and static files from the build output directory

* Add logging

* Move comment
2020-11-10 16:18:07 +01:00
Joe Haddad
f36eac3d0a [next] files within the buildId directory are immutable (#5386)
Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
2020-11-10 09:19:26 -05:00
Andy Bitz
a2c56425f4 Publish Stable
- @vercel/static-build@0.17.12
2020-11-10 00:43:05 +01:00
Andy Bitz
c759bfda9c Publish Canary
- @vercel/client@9.0.4-canary.3
 - @vercel/static-build@0.17.12-canary.0
2020-11-10 00:14:31 +01:00
Andy
57995001ac [static-build] Add directory for Serverless Functions (#5390)
* [@vercel/static-build] Add directory for Serverless Functions

* Update tests and only consider index.js files

* Import only once

* Only change for zeroConfig

* Update packages/now-static-build/src/utils/_shared.ts

Co-authored-by: Steven <steven@ceriously.com>

* Update packages/now-static-build/test/fixtures/62-function-output-directory-with-static/now.json

Co-authored-by: Steven <steven@ceriously.com>

* Update packages/now-static-build/test/fixtures/61-function-output-directory/now.json

Co-authored-by: Steven <steven@ceriously.com>

* Update build

* Fix type

* Remove line

* Add to .vercelignore

* Fix paths in test

* Move more files

* Remove special case for test

Co-authored-by: Steven <steven@ceriously.com>
2020-11-10 00:09:23 +01:00
Nathan Rajlich
e5553d8ec2 Publish Canary
- @vercel/build-utils@2.5.5-canary.2
 - vercel@20.1.3-canary.6
 - @vercel/client@9.0.4-canary.2
2020-11-09 15:02:17 -08:00
Nathan Rajlich
dcee5b16c7 [build-utils] Add installCommand to Config object (#5391) 2020-11-09 22:27:29 +00:00
91 changed files with 13479 additions and 518 deletions

20
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,20 @@
### Related Issues
> Fixes #1
> Related to #2
### 📋 Checklist
<!--
Please keep your PR as a Draft until the checklist is complete
-->
#### Tests
- [ ] The code changed/added as part of this PR has been covered with tests
- [ ] All tests pass locally with `yarn test-unit`
#### Code Review
- [ ] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR

View File

@@ -1,7 +1,7 @@
version = 1
[merge]
automerge_label = "automerge"
automerge_label = ["semver-major","semver-minor","semver-patch"]
blacklist_title_regex = "^WIP.*"
blacklist_labels = ["work in progress"]
method = "squash"

View File

@@ -1,5 +1,8 @@
/node_modules/
/public/build/
.DS_Store
node_modules
public/bundle.*
.env
.env.local
.env.build
.vercel

View File

@@ -1,2 +0,0 @@
yarn.lock
README.md

View File

@@ -1,24 +1,21 @@
{
"name": "svelte-app",
"version": "1.0.0",
"private": true,
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv public"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^13.0.0",
"@rollup/plugin-node-resolve": "^8.1.0",
"npm-run-all": "^4.1.5",
"rollup": "^2.18.0",
"rollup-plugin-livereload": "^1.0.0",
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-terser": "^6.1.0",
"@rollup/plugin-commonjs": "^14.0.0",
"@rollup/plugin-node-resolve": "^8.0.0",
"rollup": "^2.3.4",
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-svelte": "^6.0.0",
"rollup-plugin-terser": "^7.0.0",
"svelte": "^3.0.0"
},
"dependencies": {
"sirv-cli": "^1.0.1"
},
"scripts": {
"build": "rollup -c",
"autobuild": "rollup -c -w",
"dev": "run-p start:dev autobuild",
"start": "sirv public --single",
"start:dev": "sirv public --single --dev"
"sirv-cli": "^1.0.0"
}
}

View File

@@ -1,17 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8" />
<meta name="viewport" content="width=device-width" />
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte + Node.js API</title>
<title>Svelte + Node.js API</title>
<link rel="icon" type="image/png" href="/favicon.png" />
<link rel="stylesheet" href="/global.css" />
<link rel="stylesheet" href="/bundle.css" />
</head>
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel='stylesheet' href='/global.css'>
<link rel='stylesheet' href='/build/bundle.css'>
<body>
<script src="/bundle.js"></script>
</body>
<script defer src='/build/bundle.js'></script>
</head>
<body>
</body>
</html>

View File

@@ -6,42 +6,70 @@ import { terser } from 'rollup-plugin-terser';
const production = !process.env.ROLLUP_WATCH;
function serve() {
let server;
function toExit() {
if (server) server.kill(0);
}
return {
writeBundle() {
if (server) return;
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
process.on('SIGTERM', toExit);
process.on('exit', toExit);
}
};
}
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/bundle.js',
},
plugins: [
svelte({
// enable run-time checks when not in production
dev: !production,
// we'll extract any component CSS out into
// a separate file better for performance
css: css => {
css.write('public/bundle.css');
},
}),
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js'
},
plugins: [
svelte({
// enable run-time checks when not in production
dev: !production,
// we'll extract any component CSS out into
// a separate file - better for performance
css: css => {
css.write('bundle.css');
}
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration
// consult the documentation for details:
// https://github.com/rollup/rollup-plugin-commonjs
resolve({ browser: true }),
commonjs(),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte']
}),
commonjs(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser(),
],
watch: {
clearScreen: false,
},
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};

View File

@@ -0,0 +1,128 @@
// @ts-check
/** This script modifies the project to support TS code in .svelte files like:
<script lang="ts">
export let name: string;
</script>
As well as validating the code for CI.
*/
/** To work on this script:
rm -rf test-template template && git clone sveltejs/template test-template && node scripts/setupTypeScript.js test-template
*/
const fs = require("fs")
const path = require("path")
const { argv } = require("process")
const projectRoot = argv[2] || path.join(__dirname, "..")
// Add deps to pkg.json
const packageJSON = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf8"))
packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, {
"svelte-check": "^1.0.0",
"svelte-preprocess": "^4.0.0",
"@rollup/plugin-typescript": "^6.0.0",
"typescript": "^3.9.3",
"tslib": "^2.0.0",
"@tsconfig/svelte": "^1.0.0"
})
// Add script for checking
packageJSON.scripts = Object.assign(packageJSON.scripts, {
"validate": "svelte-check"
})
// Write the package JSON
fs.writeFileSync(path.join(projectRoot, "package.json"), JSON.stringify(packageJSON, null, " "))
// mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too
const beforeMainJSPath = path.join(projectRoot, "src", "main.js")
const afterMainTSPath = path.join(projectRoot, "src", "main.ts")
fs.renameSync(beforeMainJSPath, afterMainTSPath)
// Switch the app.svelte file to use TS
const appSveltePath = path.join(projectRoot, "src", "App.svelte")
let appFile = fs.readFileSync(appSveltePath, "utf8")
appFile = appFile.replace("<script>", '<script lang="ts">')
appFile = appFile.replace("export let name;", 'export let name: string;')
fs.writeFileSync(appSveltePath, appFile)
// Edit rollup config
const rollupConfigPath = path.join(projectRoot, "rollup.config.js")
let rollupConfig = fs.readFileSync(rollupConfigPath, "utf8")
// Edit imports
rollupConfig = rollupConfig.replace(`'rollup-plugin-terser';`, `'rollup-plugin-terser';
import sveltePreprocess from 'svelte-preprocess';
import typescript from '@rollup/plugin-typescript';`)
// Replace name of entry point
rollupConfig = rollupConfig.replace(`'src/main.js'`, `'src/main.ts'`)
// Add preprocess to the svelte config, this is tricky because there's no easy signifier.
// Instead we look for `css:` then the next `}` and add the preprocessor to that
let foundCSS = false
let match
// https://regex101.com/r/OtNjwo/1
const configEditor = new RegExp(/css:.|\n*}/gmi)
while (( match = configEditor.exec(rollupConfig)) != null) {
if (foundCSS) {
const endOfCSSIndex = match.index + 1
rollupConfig = rollupConfig.slice(0, endOfCSSIndex) + ",\n preprocess: sveltePreprocess()," + rollupConfig.slice(endOfCSSIndex);
break
}
if (match[0].includes("css:")) foundCSS = true
}
// Add TypeScript
rollupConfig = rollupConfig.replace(
'commonjs(),',
'commonjs(),\n\t\ttypescript({\n\t\t\tsourceMap: !production,\n\t\t\tinlineSources: !production\n\t\t}),'
);
fs.writeFileSync(rollupConfigPath, rollupConfig)
// Add TSConfig
const tsconfig = `{
"extends": "@tsconfig/svelte/tsconfig.json",
"include": ["src/**/*"],
"exclude": ["node_modules/*", "__sapper__/*", "public/*"]
}`
const tsconfigPath = path.join(projectRoot, "tsconfig.json")
fs.writeFileSync(tsconfigPath, tsconfig)
// Delete this script, but not during testing
if (!argv[2]) {
// Remove the script
fs.unlinkSync(path.join(__filename))
// Check for Mac's DS_store file, and if it's the only one left remove it
const remainingFiles = fs.readdirSync(path.join(__dirname))
if (remainingFiles.length === 1 && remainingFiles[0] === '.DS_store') {
fs.unlinkSync(path.join(__dirname, '.DS_store'))
}
// Check if the scripts folder is empty
if (fs.readdirSync(path.join(__dirname)).length === 0) {
// Remove the scripts folder
fs.rmdirSync(path.join(__dirname))
}
}
// Adds the extension recommendation
fs.mkdirSync(path.join(projectRoot, ".vscode"))
fs.writeFileSync(path.join(projectRoot, ".vscode", "extensions.json"), `{
"recommendations": ["svelte.svelte-vscode"]
}
`)
console.log("Converted to TypeScript.")
if (fs.existsSync(path.join(projectRoot, "node_modules"))) {
console.log("\nYou will need to re-run your dependency manager to get started.")
}

View File

@@ -1,10 +1,10 @@
import App from './App.svelte';
const app = new App({
target: document.body,
props: {
name: 'world',
},
target: document.body,
props: {
name: 'world'
}
});
export default app;
export default app;

635
examples/svelte/yarn.lock Normal file
View File

@@ -0,0 +1,635 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/code-frame@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
dependencies:
"@babel/highlight" "^7.10.4"
"@babel/helper-validator-identifier@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
"@babel/highlight@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
dependencies:
"@babel/helper-validator-identifier" "^7.10.4"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@polka/url@^1.0.0-next.9":
version "1.0.0-next.11"
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
integrity sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA==
"@rollup/plugin-commonjs@^14.0.0":
version "14.0.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-14.0.0.tgz#4285f9ec2db686a31129e5a2b415c94aa1f836f0"
integrity sha512-+PSmD9ePwTAeU106i9FRdc+Zb3XUWyW26mo5Atr2mk82hor8+nPwkztEjFo8/B1fJKfaQDg9aM2bzQkjhi7zOw==
dependencies:
"@rollup/pluginutils" "^3.0.8"
commondir "^1.0.1"
estree-walker "^1.0.1"
glob "^7.1.2"
is-reference "^1.1.2"
magic-string "^0.25.2"
resolve "^1.11.0"
"@rollup/plugin-node-resolve@^8.0.0":
version "8.4.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.4.0.tgz#261d79a680e9dc3d86761c14462f24126ba83575"
integrity sha512-LFqKdRLn0ShtQyf6SBYO69bGE1upV6wUhBX0vFOUnLAyzx5cwp8svA0eHUnu8+YU57XOkrMtfG63QOpQx25pHQ==
dependencies:
"@rollup/pluginutils" "^3.1.0"
"@types/resolve" "1.17.1"
builtin-modules "^3.1.0"
deep-freeze "^0.0.1"
deepmerge "^4.2.2"
is-module "^1.0.0"
resolve "^1.17.0"
"@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
dependencies:
"@types/estree" "0.0.39"
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@types/estree@*":
version "0.0.45"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884"
integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==
"@types/estree@0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
"@types/node@*":
version "14.14.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.7.tgz#8ea1e8f8eae2430cf440564b98c6dfce1ec5945d"
integrity sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==
"@types/resolve@1.17.1":
version "1.17.1"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
dependencies:
"@types/node" "*"
ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
anymatch@~3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"
async-limiter@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
binary-extensions@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
builtin-modules@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==
chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chokidar@^3.3.0:
version "3.4.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b"
integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==
dependencies:
anymatch "~3.1.1"
braces "~3.0.2"
glob-parent "~5.1.0"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.5.0"
optionalDependencies:
fsevents "~2.1.2"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
color-name "1.1.3"
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
console-clear@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/console-clear/-/console-clear-1.1.1.tgz#995e20cbfbf14dd792b672cde387bd128d674bf7"
integrity sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==
deep-freeze@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84"
integrity sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=
deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
estree-walker@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
estree-walker@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
fsevents@~2.1.2:
version "2.1.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
get-port@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc"
integrity sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=
glob-parent@~5.1.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
dependencies:
is-glob "^4.0.1"
glob@^7.1.2:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
dependencies:
binary-extensions "^2.0.0"
is-core-module@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.1.0.tgz#a4cc031d9b1aca63eecbd18a650e13cb4eeab946"
integrity sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==
dependencies:
has "^1.0.3"
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
dependencies:
is-extglob "^2.1.1"
is-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-reference@^1.1.2:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
dependencies:
"@types/estree" "*"
jest-worker@^26.2.1:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
supports-color "^7.0.0"
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
kleur@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
livereload-js@^3.1.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-3.3.1.tgz#61f887468086762e61fb2987412cf9d1dda99202"
integrity sha512-CBu1gTEfzVhlOK1WASKAAJ9Qx1fHECTq0SUB67sfxwQssopTyvzqTlgl+c0h9pZ6V+Fzd2rc510ppuNusg9teQ==
livereload@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/livereload/-/livereload-0.9.1.tgz#65125dabdf2db4fd3f1169e953fe56e3bcc6f477"
integrity sha512-9g7sua11kkyZNo2hLRCG3LuZZwqexoyEyecSlV8cAsfAVVCZqLzVir6XDqmH0r+Vzgnd5LrdHDMyjtFnJQLAYw==
dependencies:
chokidar "^3.3.0"
livereload-js "^3.1.0"
opts ">= 1.2.0"
ws "^6.2.1"
local-access@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/local-access/-/local-access-1.0.1.tgz#5121258146d64e869046c642ea4f1dd39ff942bb"
integrity sha512-ykt2pgN0aqIy6KQC1CqdWTWkmUwNgaOS6dcpHVjyBJONA+Xi7AtSB1vuxC/U/0tjIP3wcRudwQk1YYzUvzk2bA==
magic-string@^0.25.2:
version "0.25.7"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
dependencies:
sourcemap-codec "^1.4.4"
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
mime@^2.3.1:
version "2.4.6"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1"
integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"
mri@^1.1.0:
version "1.1.6"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.6.tgz#49952e1044db21dbf90f6cd92bc9c9a777d415a6"
integrity sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
"opts@>= 1.2.0":
version "2.0.2"
resolved "https://registry.yarnpkg.com/opts/-/opts-2.0.2.tgz#a17e189fbbfee171da559edd8a42423bc5993ce1"
integrity sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
dependencies:
safe-buffer "^5.1.0"
readdirp@~3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
dependencies:
picomatch "^2.2.1"
require-relative@^0.8.7:
version "0.8.7"
resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de"
integrity sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=
resolve@^1.11.0, resolve@^1.17.0:
version "1.19.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
dependencies:
is-core-module "^2.1.0"
path-parse "^1.0.6"
rollup-plugin-livereload@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.0.tgz#d3928d74e8cf2ae4286c5dd46b770fd3f3b82313"
integrity sha512-oC/8NqumGYuphkqrfszOHUUIwzKsaHBICw6QRwT5uD07gvePTS+HW+GFwu6f9K8W02CUuTvtIM9AWJrbj4wE1A==
dependencies:
livereload "^0.9.1"
rollup-plugin-svelte@^6.0.0:
version "6.1.1"
resolved "https://registry.yarnpkg.com/rollup-plugin-svelte/-/rollup-plugin-svelte-6.1.1.tgz#66362cf0500fb7a848283ebcf19d289a60ef0871"
integrity sha512-ijnm0pH1ScrY4uxwaNXBpNVejVzpL2769hIEbAlnqNUWZrffLspu5/k9/l/Wsj3NrEHLQ6wCKGagVJonyfN7ow==
dependencies:
require-relative "^0.8.7"
rollup-pluginutils "^2.8.2"
sourcemap-codec "^1.4.8"
rollup-plugin-terser@^7.0.0:
version "7.0.2"
resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==
dependencies:
"@babel/code-frame" "^7.10.4"
jest-worker "^26.2.1"
serialize-javascript "^4.0.0"
terser "^5.0.0"
rollup-pluginutils@^2.8.2:
version "2.8.2"
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e"
integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==
dependencies:
estree-walker "^0.6.1"
rollup@^2.3.4:
version "2.33.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.33.1.tgz#802795164164ee63cd47769d8879c33ec8ae0c40"
integrity sha512-uY4O/IoL9oNW8MMcbA5hcOaz6tZTMIh7qJHx/tzIJm+n1wLoY38BLn6fuy7DhR57oNFLMbDQtDeJoFURt5933w==
optionalDependencies:
fsevents "~2.1.2"
sade@^1.6.0:
version "1.7.4"
resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.4.tgz#ea681e0c65d248d2095c90578c03ca0bb1b54691"
integrity sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==
dependencies:
mri "^1.1.0"
safe-buffer@^5.1.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
semiver@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/semiver/-/semiver-1.1.0.tgz#9c97fb02c21c7ce4fcf1b73e2c7a24324bdddd5f"
integrity sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==
serialize-javascript@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
dependencies:
randombytes "^2.1.0"
sirv-cli@^1.0.0:
version "1.0.8"
resolved "https://registry.yarnpkg.com/sirv-cli/-/sirv-cli-1.0.8.tgz#150c3f62694203a86cf5d71ec60e6ff4c34064a9"
integrity sha512-bJI+kkzQvMKfAOfgLzv09kWsdymLm39LgKmGjacB19GHIAQLCvXXg8e8HzcofTjDZlA8zVv4dQjU9SWkNzkJhw==
dependencies:
console-clear "^1.1.0"
get-port "^3.2.0"
kleur "^3.0.0"
local-access "^1.0.1"
sade "^1.6.0"
semiver "^1.0.0"
sirv "^1.0.7"
tinydate "^1.0.0"
sirv@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.7.tgz#ad8ca1f84430777a59162592626c2b8e9b9f1384"
integrity sha512-QMT2OTD3CTr8de9VByPmvSEeyt6k8/Cxg0J2kQJ5HNhIWfhFg9ypcIWWzez9rPWnGj+WtJ7AZD/MdT/vdilV/A==
dependencies:
"@polka/url" "^1.0.0-next.9"
mime "^2.3.1"
totalist "^1.0.0"
source-map-support@~0.5.19:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@~0.7.2:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8:
version "1.4.8"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
supports-color@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
svelte@^3.0.0:
version "3.29.7"
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.29.7.tgz#e254eb2d0d609ce0fd60f052d444ac4a66d90f7d"
integrity sha512-rx0g311kBODvEWUU01DFBUl3MJuJven04bvTVFUG/w0On/wuj0PajQY/QlXcJndFxG+W1s8iXKaB418tdHWc3A==
terser@^5.0.0:
version "5.3.8"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.3.8.tgz#991ae8ba21a3d990579b54aa9af11586197a75dd"
integrity sha512-zVotuHoIfnYjtlurOouTazciEfL7V38QMAOhGqpXDEg6yT13cF4+fEP9b0rrCEQTn+tT46uxgFsTZzhygk+CzQ==
dependencies:
commander "^2.20.0"
source-map "~0.7.2"
source-map-support "~0.5.19"
tinydate@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/tinydate/-/tinydate-1.3.0.tgz#e6ca8e5a22b51bb4ea1c3a2a4fd1352dbd4c57fb"
integrity sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
totalist@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
dependencies:
async-limiter "~1.0.0"

View File

@@ -849,7 +849,7 @@
},
"settings": {
"installCommand": {
"placeholder": "`bundle install`"
"value": "bundle install"
},
"buildCommand": {
"placeholder": "`npm run build` or `jekyll build`"
@@ -909,7 +909,7 @@
},
"settings": {
"installCommand": {
"placeholder": "`bundle install`"
"value": "bundle install"
},
"buildCommand": {
"value": "`npm run build` or `bundle exec middleman build`"

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/frameworks",
"version": "0.1.2-canary.1",
"version": "0.2.0",
"main": "frameworks.json",
"license": "UNLICENSED",
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "2.5.5-canary.1",
"version": "2.6.0",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
@@ -29,7 +29,7 @@
"@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0",
"@types/yazl": "^2.4.1",
"@vercel/frameworks": "0.1.2-canary.1",
"@vercel/frameworks": "0.2.0",
"@vercel/ncc": "0.24.0",
"aggregate-error": "3.0.1",
"async-retry": "1.2.3",

View File

@@ -24,6 +24,7 @@ interface Options {
projectSettings?: {
framework?: string | null;
devCommand?: string | null;
installCommand?: string | null;
buildCommand?: string | null;
outputDirectory?: string | null;
createdAt?: number;
@@ -450,6 +451,10 @@ function detectFrontBuilder(
config.devCommand = projectSettings.devCommand;
}
if (typeof projectSettings.installCommand === 'string') {
config.installCommand = projectSettings.installCommand;
}
if (projectSettings.buildCommand) {
config.buildCommand = projectSettings.buildCommand;
}

View File

@@ -41,6 +41,7 @@ export interface Config {
import?: { [key: string]: string };
functions?: BuilderFunctions;
outputDirectory?: string;
installCommand?: string;
buildCommand?: string;
devCommand?: string;
framework?: string;

View File

@@ -833,6 +833,50 @@ describe('Test `detectBuilders`', () => {
describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
const featHandleMiss = true;
it('should select "installCommand"', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = ['package.json', 'pages/index.js', 'public/index.html'];
const { builders, errors } = await detectBuilders(files, pkg, {
featHandleMiss,
projectSettings: {
installCommand: 'npx pnpm install',
},
});
expect(errors).toBe(null);
expect(builders).toBeDefined();
expect(builders!.length).toStrictEqual(1);
expect(builders![0].src).toStrictEqual('package.json');
expect(builders![0].use).toStrictEqual('@vercel/next');
expect(builders![0].config!.zeroConfig).toStrictEqual(true);
expect(builders![0].config!.installCommand).toStrictEqual(
'npx pnpm install'
);
});
it('should select empty "installCommand"', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = ['package.json', 'pages/index.js', 'public/index.html'];
const { builders, errors } = await detectBuilders(files, pkg, {
featHandleMiss,
projectSettings: {
installCommand: '',
},
});
expect(errors).toBe(null);
expect(builders).toBeDefined();
expect(builders!.length).toStrictEqual(1);
expect(builders![0].src).toStrictEqual('package.json');
expect(builders![0].use).toStrictEqual('@vercel/next');
expect(builders![0].config!.zeroConfig).toStrictEqual(true);
expect(builders![0].config!.installCommand).toStrictEqual('');
});
it('should never select now.json src', async () => {
const files = ['docs/index.md', 'mkdocs.yml', 'now.json'];
const { builders, errors } = await detectBuilders(files, null, {

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "20.1.3-canary.5",
"version": "20.1.4",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -61,9 +61,9 @@
"node": ">= 10"
},
"dependencies": {
"@vercel/build-utils": "2.5.5-canary.1",
"@vercel/build-utils": "2.6.0",
"@vercel/go": "1.1.6",
"@vercel/node": "1.8.4",
"@vercel/node": "1.8.5",
"@vercel/python": "1.2.3",
"@vercel/ruby": "1.2.4",
"update-notifier": "4.1.0"
@@ -100,7 +100,7 @@
"@types/universal-analytics": "0.4.2",
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@vercel/frameworks": "0.1.2-canary.1",
"@vercel/frameworks": "0.2.0",
"@vercel/ncc": "0.24.0",
"@zeit/fun": "0.11.2",
"@zeit/source-map-support": "0.6.2",
@@ -146,6 +146,7 @@
"minimatch": "3.0.4",
"mri": "1.1.5",
"ms": "2.1.2",
"nanoid": "3.0.2",
"node-fetch": "2.6.1",
"npm-package-arg": "6.1.0",
"nyc": "13.2.0",

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk';
import inquirer from 'inquirer';
import { ProjectEnvTarget, Project, Secret, ProjectEnvType } from '../../types';
import { ProjectEnvTarget, Project } from '../../types';
import { Output } from '../../util/output';
import Client from '../../util/client';
import stamp from '../../util/output/stamp';
@@ -11,14 +11,12 @@ import {
getEnvTargetPlaceholder,
getEnvTargetChoices,
} from '../../util/env/env-target';
import { isValidEnvType, getEnvTypePlaceholder } from '../../util/env/env-type';
import readStandardInput from '../../util/input/read-standard-input';
import param from '../../util/output/param';
import withSpinner from '../../util/with-spinner';
import { emoji, prependEmoji } from '../../util/emoji';
import { isKnownError } from '../../util/env/known-error';
import { getCommandName } from '../../util/pkg-name';
import { SYSTEM_ENV_VALUES } from '../../util/env/system-env';
type Options = {
'--debug': boolean;
@@ -31,71 +29,38 @@ export default async function add(
args: string[],
output: Output
) {
// improve the way we show inquirer prompts
require('../../util/input/patch-inquirer');
const stdInput = await readStandardInput();
let [envTypeArg, envName, envTargetArg] = args;
let [envName, envTarget] = args;
if (args.length > 3) {
if (args.length > 2) {
output.error(
`Invalid number of arguments. Usage: ${getCommandName(
`env add ${getEnvTypePlaceholder()} <name> ${getEnvTargetPlaceholder()}`
`env add <name> ${getEnvTargetPlaceholder()}`
)}`
);
return 1;
}
if (stdInput && (!envTypeArg || !envName || !envTargetArg)) {
if (stdInput && (!envName || !envTarget)) {
output.error(
`Invalid number of arguments. Usage: ${getCommandName(
`env add ${getEnvTypePlaceholder()} <name> <target> < <file>`
`env add <name> <target> < <file>`
)}`
);
return 1;
}
let envTargets: ProjectEnvTarget[] = [];
if (envTargetArg) {
if (!isValidEnvTarget(envTargetArg)) {
if (envTarget) {
if (!isValidEnvTarget(envTarget)) {
output.error(
`The Environment ${param(
envTargetArg
envTarget
)} is invalid. It must be one of: ${getEnvTargetPlaceholder()}.`
);
return 1;
}
envTargets.push(envTargetArg);
}
let envType: ProjectEnvType;
if (envTypeArg) {
if (!isValidEnvType(envTypeArg)) {
output.error(
`The Environment Variable type ${param(
envTypeArg
)} is invalid. It must be one of: ${getEnvTypePlaceholder()}.`
);
return 1;
}
envType = envTypeArg;
} else {
const answers = (await inquirer.prompt({
name: 'inputEnvType',
type: 'list',
message: `Which type of Environment Variable do you want to add?`,
choices: [
{ name: 'Plaintext', value: ProjectEnvType.Plaintext },
{
name: `Secret (can be created using ${getCommandName('secret add')})`,
value: ProjectEnvType.Secret,
},
{ name: 'Provided by System', value: ProjectEnvType.System },
],
})) as { inputEnvType: ProjectEnvType };
envType = answers.inputEnvType;
envTargets.push(envTarget);
}
while (!envName) {
@@ -133,59 +98,15 @@ export default async function add(
if (stdInput) {
envValue = stdInput;
} else if (envType === ProjectEnvType.Plaintext) {
} else if (isSystemEnvVariable(envName)) {
envValue = '';
} else {
const { inputValue } = await inquirer.prompt({
type: 'input',
type: 'password',
name: 'inputValue',
message: `Whats the value of ${envName}?`,
});
envValue = inputValue || '';
} else if (envType === ProjectEnvType.Secret) {
let secretId: string | null = null;
while (!secretId) {
let { secretName } = await inquirer.prompt({
type: 'input',
name: 'secretName',
message: `Whats the value of ${envName}?`,
});
secretName = secretName || '';
if (secretName[0] === '@') {
secretName = secretName.slice(1);
}
try {
const secret = await client.fetch<Secret>(
`/v2/now/secrets/${encodeURIComponent(secretName)}`
);
secretId = secret.uid;
} catch (error) {
if (error.status === 404) {
output.error(
`Please enter the name of an existing Secret (can be created with ${getCommandName(
'secret add'
)}).`
);
} else {
throw error;
}
}
}
envValue = secretId;
} else {
const { systemEnvValue } = await inquirer.prompt({
name: 'systemEnvValue',
type: 'list',
message: `Whats the value of ${envName}?`,
choices: SYSTEM_ENV_VALUES.map(value => ({ name: value, value })),
});
envValue = systemEnvValue;
}
while (envTargets.length === 0) {
@@ -206,15 +127,7 @@ export default async function add(
const addStamp = stamp();
try {
await withSpinner('Saving', () =>
addEnvRecord(
output,
client,
project.id,
envType,
envName,
envValue,
envTargets
)
addEnvRecord(output, client, project.id, envName, envValue, envTargets)
);
} catch (error) {
if (isKnownError(error) && error.serverMessage) {
@@ -235,3 +148,7 @@ export default async function add(
return 0;
}
function isSystemEnvVariable(envName: string) {
return envName.startsWith('VERCEL_');
}

View File

@@ -6,7 +6,6 @@ import getArgs from '../../util/get-args';
import getSubcommand from '../../util/get-subcommand';
import getInvalidSubcommand from '../../util/get-invalid-subcommand';
import { getEnvTargetPlaceholder } from '../../util/env/env-target';
import { getEnvTypePlaceholder } from '../../util/env/env-type';
import { getLinkedProject } from '../../util/projects/link';
import Client from '../../util/client';
import handleError from '../../util/handle-error';
@@ -19,17 +18,16 @@ import ls from './ls';
import rm from './rm';
const help = () => {
const typePlaceholder = getEnvTypePlaceholder();
const targetPlaceholder = getEnvTargetPlaceholder();
const placeholder = getEnvTargetPlaceholder();
console.log(`
${chalk.bold(`${logo} ${getPkgName()} env`)} [options] <command>
${chalk.dim('Commands:')}
ls [environment] List all variables for the specified Environment
add [type] [name] [environment] Add an Environment Variable (see examples below)
rm [name] [environment] Remove an Environment Variable (see examples below)
pull [filename] Pull all Development Environment Variables from the cloud and write to a file [.env]
ls [environment] List all variables for the specified Environment
add [name] [environment] Add an Environment Variable (see examples below)
rm [name] [environment] Remove an Environment Variable (see examples below)
pull [filename] Pull all Development Environment Variables from the cloud and write to a file [.env]
${chalk.dim('Options:')}
@@ -49,27 +47,21 @@ const help = () => {
${chalk.gray('')} Add a new variable to multiple Environments
${chalk.cyan(`$ ${getPkgName()} env add ${typePlaceholder} <name>`)}
${chalk.cyan(`$ ${getPkgName()} env add secret API_TOKEN`)}
${chalk.cyan(`$ ${getPkgName()} env add <name>`)}
${chalk.cyan(`$ ${getPkgName()} env add API_TOKEN`)}
${chalk.gray('')} Add a new variable for a specific Environment
${chalk.cyan(
`$ ${getPkgName()} env add ${typePlaceholder} <name> ${targetPlaceholder}`
)}
${chalk.cyan(`$ ${getPkgName()} env add secret DB_PASS production`)}
${chalk.cyan(`$ ${getPkgName()} env add <name> ${placeholder}`)}
${chalk.cyan(`$ ${getPkgName()} env add DB_CONNECTION production`)}
${chalk.gray('')} Add a new Environment Variable from stdin
${chalk.cyan(
`$ cat <file> | ${getPkgName()} env add ${typePlaceholder} <name> ${targetPlaceholder}`
)}
${chalk.cyan(
`$ cat ~/.npmrc | ${getPkgName()} env add plain NPM_RC preview`
)}
${chalk.cyan(
`$ ${getPkgName()} env add plain API_URL production < url.txt`
`$ cat <file> | ${getPkgName()} env add <name> ${placeholder}`
)}
${chalk.cyan(`$ cat ~/.npmrc | ${getPkgName()} env add NPM_RC preview`)}
${chalk.cyan(`$ ${getPkgName()} env add DB_PASS production < secret.txt`)}
${chalk.gray('')} Remove an variable from multiple Environments
@@ -78,7 +70,7 @@ const help = () => {
${chalk.gray('')} Remove a variable from a specific Environment
${chalk.cyan(`$ ${getPkgName()} env rm <name> ${targetPlaceholder}`)}
${chalk.cyan(`$ ${getPkgName()} env rm <name> ${placeholder}`)}
${chalk.cyan(`$ ${getPkgName()} env rm NPM_RC preview`)}
`);
};

View File

@@ -1,12 +1,7 @@
import chalk from 'chalk';
import ms from 'ms';
import { Output } from '../../util/output';
import {
ProjectEnvTarget,
Project,
ProjectEnvVariable,
ProjectEnvType,
} from '../../types';
import { ProjectEnvTarget, Project, ProjectEnvVariableV5 } from '../../types';
import Client from '../../util/client';
import formatTable from '../../util/format-table';
import getEnvVariables from '../../util/env/get-env-records';
@@ -18,8 +13,6 @@ import stamp from '../../util/output/stamp';
import param from '../../util/output/param';
import { getCommandName } from '../../util/pkg-name';
import ellipsis from '../../util/output/ellipsis';
// @ts-ignore
import title from 'title';
type Options = {
'--debug': boolean;
@@ -54,7 +47,19 @@ export default async function ls(
const lsStamp = stamp();
const { envs } = await getEnvVariables(output, client, project.id, envTarget);
const data = await getEnvVariables(output, client, project.id, envTarget);
// we expand env vars with multiple targets
const envs: ProjectEnvVariableV5[] = [];
for (let env of data.envs) {
if (Array.isArray(env.target)) {
for (let target of env.target) {
envs.push({ ...env, target });
}
} else {
envs.push({ ...env, target: env.target });
}
}
output.log(
`${
@@ -66,9 +71,9 @@ export default async function ls(
return 0;
}
function getTable(records: ProjectEnvVariable[]) {
function getTable(records: ProjectEnvVariableV5[]) {
return formatTable(
['name', 'value', 'environments', 'created'],
['name', 'value', 'environment', 'created'],
['l', 'l', 'l', 'l', 'l'],
[
{
@@ -79,16 +84,16 @@ function getTable(records: ProjectEnvVariable[]) {
);
}
function getRow(env: ProjectEnvVariable) {
function getRow(env: ProjectEnvVariableV5) {
let value: string;
if (env.type === ProjectEnvType.Plaintext) {
if (env.type === 'plain') {
// replace space characters (line-break, etc.) with simple spaces
// to make sure the displayed value is a single line
const singleLineValue = env.value.replace(/\s/g, ' ');
value = chalk.gray(ellipsis(singleLineValue, 19));
} else if (env.type === ProjectEnvType.System) {
value = chalk.gray.italic(env.value);
} else if (env.type === 'system') {
value = chalk.gray.italic('Populated by System');
} else {
value = chalk.gray.italic('Encrypted');
}
@@ -97,9 +102,7 @@ function getRow(env: ProjectEnvVariable) {
return [
chalk.bold(env.key),
value,
(Array.isArray(env.target) ? env.target : [env.target || ''])
.map(title)
.join(', '),
env.target || '',
env.createdAt ? `${ms(now - env.createdAt)} ago` : '',
];
}

View File

@@ -30,9 +30,6 @@ export default async function rm(
args: string[],
output: Output
) {
// improve the way we show inquirer prompts
require('../../util/input/patch-inquirer');
if (args.length > 2) {
output.error(
`Invalid number of arguments. Usage: ${getCommandName(

View File

@@ -203,16 +203,12 @@ export enum ProjectEnvTarget {
Development = 'development',
}
export enum ProjectEnvType {
Plaintext = 'plain',
Secret = 'secret',
System = 'system',
}
export type ProjectEnvVariableType = 'system' | 'secret' | 'plain';
export interface ProjectEnvVariable {
key: string;
value: string;
type: ProjectEnvType;
type: ProjectEnvVariableType;
configurationId?: string | null;
createdAt?: number;
updatedAt?: number;

View File

@@ -1,39 +1,60 @@
import { Output } from '../output';
import Client from '../client';
import {
Secret,
ProjectEnvTarget,
ProjectEnvVariableV5,
ProjectEnvType,
} from '../../types';
import { Secret, ProjectEnvTarget, ProjectEnvVariableV5 } from '../../types';
import { customAlphabet } from 'nanoid';
import slugify from '@sindresorhus/slugify';
export default async function addEnvRecord(
output: Output,
client: Client,
projectId: string,
type: ProjectEnvType,
key: string,
envValue: string,
envName: string,
envValue: string | undefined,
targets: ProjectEnvTarget[]
): Promise<void> {
output.debug(
`Adding ${type} Environment Variable ${key} to ${targets.length} targets`
`Adding Environment Variable ${envName} to ${targets.length} targets`
);
let value = envValue;
let values: string[] | undefined;
if (type === ProjectEnvType.Secret) {
const secret = await client.fetch<Secret>(
`/v2/now/secrets/${encodeURIComponent(envValue)}`
if (envValue) {
const secrets = await Promise.all(
targets.map(target =>
client.fetch<Secret>('/v2/now/secrets', {
method: 'POST',
body: JSON.stringify({
name: generateSecretName(envName, target),
value: envValue,
projectId: projectId,
decryptable: target === ProjectEnvTarget.Development,
}),
})
)
);
value = secret.uid;
values = secrets.map(secret => secret.uid);
}
const body = { type, key, value, target: targets };
const body = targets.map((target, i) => ({
key: envName,
value: values ? values[i] : '',
target,
}));
const urlProject = `/v6/projects/${projectId}/env`;
const urlProject = `/v4/projects/${projectId}/env`;
await client.fetch<ProjectEnvVariableV5>(urlProject, {
method: 'POST',
body: JSON.stringify(body),
});
}
const randomSecretSuffix = customAlphabet(
'123456789abcdefghijklmnopqrstuvwxyz',
4
);
function generateSecretName(envName: string, target: ProjectEnvTarget) {
return `${
slugify(envName).substring(0, 80) // we truncate because the max secret length is 100
}-${target}-${randomSecretSuffix()}`;
}

View File

@@ -1,15 +0,0 @@
import { ProjectEnvType } from '../../types';
function envTypes(): string[] {
return Object.values(ProjectEnvType);
}
export function isValidEnvType(
type?: string
): type is ProjectEnvType | undefined {
return typeof type === 'undefined' || envTypes().includes(type);
}
export function getEnvTypePlaceholder() {
return `<${envTypes().join(' | ')}>`;
}

View File

@@ -1,32 +0,0 @@
export const SYSTEM_ENV_VALUES = [
'VERCEL_URL',
'VERCEL_GITHUB_COMMIT_ORG',
'VERCEL_GITHUB_COMMIT_REF',
'VERCEL_GITHUB_ORG',
'VERCEL_GITHUB_DEPLOYMENT',
'VERCEL_GITHUB_COMMIT_REPO',
'VERCEL_GITHUB_REPO',
'VERCEL_GITHUB_COMMIT_AUTHOR_LOGIN',
'VERCEL_GITHUB_COMMIT_AUTHOR_NAME',
'VERCEL_GITHUB_COMMIT_SHA',
'VERCEL_GITLAB_DEPLOYMENT',
'VERCEL_GITLAB_PROJECT_NAMESPACE',
'VERCEL_GITLAB_PROJECT_NAME',
'VERCEL_GITLAB_PROJECT_ID',
'VERCEL_GITLAB_PROJECT_PATH',
'VERCEL_GITLAB_COMMIT_REF',
'VERCEL_GITLAB_COMMIT_SHA',
'VERCEL_GITLAB_COMMIT_MESSAGE',
'VERCEL_GITLAB_COMMIT_AUTHOR_LOGIN',
'VERCEL_GITLAB_COMMIT_AUTHOR_NAME',
'VERCEL_BITBUCKET_DEPLOYMENT',
'VERCEL_BITBUCKET_REPO_OWNER',
'VERCEL_BITBUCKET_REPO_SLUG',
'VERCEL_BITBUCKET_REPO_NAME',
'VERCEL_BITBUCKET_COMMIT_REF',
'VERCEL_BITBUCKET_COMMIT_SHA',
'VERCEL_BITBUCKET_COMMIT_MESSAGE',
'VERCEL_BITBUCKET_COMMIT_AUTHOR_NAME',
'VERCEL_BITBUCKET_COMMIT_AUTHOR_URL',
'VERCEL_BITBUCKET_COMMIT_AUTHOR_AVATAR',
];

View File

@@ -2,7 +2,7 @@ import getEnvVariables from './env/get-env-records';
import getDecryptedSecret from './env/get-decrypted-secret';
import Client from './client';
import { Output } from './output/create-output';
import { ProjectEnvTarget, Project, ProjectEnvType } from '../types';
import { ProjectEnvTarget, Project } from '../types';
import { Env } from '@vercel/build-utils';
@@ -15,9 +15,9 @@ export default async function getDecryptedEnvRecords(
const { envs } = await getEnvVariables(output, client, project.id, target);
const decryptedValues = await Promise.all(
envs.map(async env => {
if (env.type === ProjectEnvType.System) {
if (env.type === 'system') {
return { value: '', found: true };
} else if (env.type === ProjectEnvType.Plaintext) {
} else if (env.type === 'plain') {
return { value: env.value, found: true };
}

View File

@@ -10,7 +10,7 @@ import chalk from 'chalk';
*/
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/base.js#L126
const getQuestion = function () {
const getQuestion = function() {
let message = `${chalk.gray('?')} ${this.opt.message} `;
if (this.opt.type === 'confirm') {
@@ -35,7 +35,7 @@ inquirer.prompt.prompts.input.prototype.getQuestion = getQuestion;
inquirer.prompt.prompts.confirm.prototype.getQuestion = getQuestion;
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/list.js#L80
inquirer.prompt.prompts.list.prototype.render = function () {
inquirer.prompt.prompts.list.prototype.render = function() {
// Render question
let message = this.getQuestion();
@@ -89,22 +89,11 @@ function listRender(choices, pointer) {
}
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/checkbox.js#L84
inquirer.prompt.prompts.checkbox.prototype.render = function (error) {
inquirer.prompt.prompts.checkbox.prototype.render = function(error) {
// Render question
let message = this.getQuestion();
let bottomContent = '';
if (!this.spaceKeyPressed) {
message +=
'(Press ' +
chalk.cyan.bold('<space>') +
' to select, ' +
chalk.cyan.bold('<a>') +
' to toggle all, ' +
chalk.cyan.bold('<i>') +
' to invert selection)';
}
// Render choices or answer depending on the state
if (this.status === 'answered') {
message += this.selection.length > 0 ? this.selection.join(', ') : 'None';
@@ -129,7 +118,7 @@ function renderChoices(choices, pointer) {
let output = '';
let separatorOffset = 0;
choices.forEach(function (choice, i) {
choices.forEach(function(choice, i) {
if (choice.type === 'separator') {
separatorOffset++;
output += '' + choice + '\n';
@@ -162,7 +151,7 @@ function renderChoices(choices, pointer) {
}
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/input.js#L44
inquirer.prompt.prompts.input.prototype.render = function (error) {
inquirer.prompt.prompts.input.prototype.render = function(error) {
let bottomContent = '';
let appendContent = '';
let message = this.getQuestion();
@@ -189,7 +178,7 @@ inquirer.prompt.prompts.input.prototype.render = function (error) {
};
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/confirm.js#L64
inquirer.prompt.prompts.confirm.prototype.render = function (answer) {
inquirer.prompt.prompts.confirm.prototype.render = function(answer) {
let message = this.getQuestion();
if (this.status === 'answered') {

View File

@@ -422,17 +422,32 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
}
async function createSecret() {
const name = `my-secret${Math.floor(Math.random() * 10000)}`;
function withPlainTextEnv(fn) {
return async function (...args) {
const link = require(path.join(target, '.vercel/project.json'));
const postRes = await apiFetch(`/v6/projects/${link.projectId}/env`, {
method: 'POST',
body: JSON.stringify({
type: 'plain',
key: 'MY_PLAIN_VAR',
value: 'hello',
target: ['development'],
}),
});
t.is(postRes.status, 200);
const res = await apiFetch('/v2/now/secrets', {
method: 'POST',
body: JSON.stringify({ name, value: 'my secret' }),
});
t.is(res.status, 200);
return name;
try {
return await fn(...args);
} finally {
const deleteRes = await apiFetch(
`/v4/projects/${link.projectId}/env/MY_PLAIN_VAR?target=development`,
{
method: 'DELETE',
}
);
t.is(deleteRes.status, 200);
}
};
}
async function nowEnvLsIsEmpty() {
@@ -449,34 +464,26 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.regex(stderr, /No Environment Variables found in Project/gm);
}
async function nowEnvAddPlaintext() {
async function nowEnvAdd() {
const now = execa(binaryPath, ['env', 'add', ...defaultArgs], {
reject: false,
cwd: target,
});
await waitForPrompt(now, chunk =>
chunk.includes('Which type of Environment Variable do you want to add?')
);
now.stdin.write('\n'); // select plaintext
await waitForPrompt(now, chunk =>
chunk.includes('Whats the name of the variable?')
);
now.stdin.write('MY_PLAINTEXT_ENV_VAR\n');
now.stdin.write('MY_ENV_VAR\n');
await waitForPrompt(
now,
chunk =>
chunk.includes('Whats the value of') &&
chunk.includes('MY_PLAINTEXT_ENV_VAR')
chunk.includes('Whats the value of') && chunk.includes('MY_ENV_VAR')
);
now.stdin.write('my plaintext value\n');
now.stdin.write('MY_VALUE\n');
await waitForPrompt(
now,
chunk =>
chunk.includes('which Environments') &&
chunk.includes('MY_PLAINTEXT_ENV_VAR')
chunk.includes('which Environments') && chunk.includes('MY_ENV_VAR')
);
now.stdin.write('a\n'); // select all
@@ -485,47 +492,10 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
}
async function nowEnvAddSecret(secretName) {
const now = execa(binaryPath, ['env', 'add', ...defaultArgs], {
reject: false,
cwd: target,
});
await waitForPrompt(now, chunk =>
chunk.includes('Which type of Environment Variable do you want to add?')
);
now.stdin.write('j\n'); // select secret
await waitForPrompt(now, chunk =>
chunk.includes('Whats the name of the variable?')
);
now.stdin.write('MY_SECRET_ENV_VAR\n');
await waitForPrompt(
now,
chunk =>
chunk.includes('Whats the value of') &&
chunk.includes('MY_SECRET_ENV_VAR')
);
now.stdin.write(`@${secretName}\n`);
await waitForPrompt(
now,
chunk =>
chunk.includes('which Environments') &&
chunk.includes('MY_SECRET_ENV_VAR')
);
now.stdin.write('j \n'); // select preview
const { exitCode, stderr, stdout } = await now;
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
}
async function nowEnvAddFromStdin() {
const now = execa(
binaryPath,
['env', 'add', 'plain', 'MY_STDIN_VAR', 'development', ...defaultArgs],
['env', 'add', 'MY_STDIN_VAR', 'development', ...defaultArgs],
{
reject: false,
cwd: target,
@@ -539,20 +509,13 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
async function nowEnvAddSystemEnv() {
const now = execa(
binaryPath,
['env', 'add', 'system', 'VERCEL_URL', ...defaultArgs],
['env', 'add', 'VERCEL_URL', ...defaultArgs],
{
reject: false,
cwd: target,
}
);
await waitForPrompt(
now,
chunk =>
chunk.includes('Whats the value of') && chunk.includes('VERCEL_URL')
);
now.stdin.write(`\n`); // select VERCEL_URL
await waitForPrompt(
now,
chunk =>
@@ -578,28 +541,28 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
t.regex(stderr, /Environment Variables found in Project/gm);
console.log(stdout);
const lines = stdout.split('\n');
const plaintextEnvs = lines.filter(line =>
line.includes('MY_PLAINTEXT_ENV_VAR')
);
t.is(plaintextEnvs.length, 1);
t.regex(plaintextEnvs[0], /Production, Preview, Development/gm);
const myEnvVars = lines.filter(line => line.includes('MY_ENV_VAR'));
t.is(myEnvVars.length, 3);
t.regex(myEnvVars.join('\n'), /development/gm);
t.regex(myEnvVars.join('\n'), /preview/gm);
t.regex(myEnvVars.join('\n'), /production/gm);
const secretEnvs = lines.filter(line => line.includes('MY_SECRET_ENV_VAR'));
t.is(secretEnvs.length, 1);
t.regex(secretEnvs[0], /Preview/gm);
const myStdinVars = lines.filter(line => line.includes('MY_STDIN_VAR'));
t.is(myStdinVars.length, 1);
t.regex(myStdinVars.join('\n'), /development/gm);
const stdinEnvs = lines.filter(line => line.includes('MY_STDIN_VAR'));
t.is(stdinEnvs.length, 1);
t.regex(stdinEnvs[0], /Development/gm);
const vercelVars = lines.filter(line => line.includes('VERCEL_URL'));
t.is(vercelVars.length, 3);
t.regex(vercelVars.join('\n'), /development/gm);
t.regex(vercelVars.join('\n'), /preview/gm);
t.regex(vercelVars.join('\n'), /production/gm);
const systemEnvs = lines.filter(line => line.includes('VERCEL_URL'));
t.is(systemEnvs.length, 1);
t.regex(systemEnvs[0], /VERCEL_URL/gm);
t.regex(systemEnvs[0], /Production, Preview, Development/gm);
const myPlainVars = lines.filter(line => line.includes('MY_PLAIN_VAR'));
t.is(myPlainVars.length, 1);
t.regex(myPlainVars.join('\n'), /development/gm);
t.regex(myPlainVars.join('\n'), /hello/gm);
}
async function nowEnvPull() {
@@ -619,9 +582,10 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.true(contents.startsWith('# Created by Vercel CLI\n'));
const lines = new Set(contents.split('\n'));
t.true(lines.has('MY_PLAINTEXT_ENV_VAR="my plaintext value"'));
t.true(lines.has('MY_ENV_VAR="MY_VALUE"'));
t.true(lines.has('MY_STDIN_VAR="{"expect":"quotes"}"'));
t.true(lines.has('VERCEL_URL=""'));
t.true(lines.has('MY_PLAIN_VAR="hello"'));
}
async function nowEnvPullOverwrite() {
@@ -673,8 +637,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
const apiRes = await fetch(apiUrl);
t.is(apiRes.status, 200, formatOutput({ stderr, stdout }));
const apiJson = await apiRes.json();
t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(apiJson['MY_SECRET_ENV_VAR'], 'my secret');
t.is(apiJson['MY_ENV_VAR'], 'MY_VALUE');
t.is(apiJson['VERCEL_URL'], host);
const homeUrl = `https://${host}`;
@@ -682,8 +645,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
const homeRes = await fetch(homeUrl);
t.is(homeRes.status, 200, formatOutput({ stderr, stdout }));
const homeJson = await homeRes.json();
t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(homeJson['MY_SECRET_ENV_VAR'], 'my secret');
t.is(homeJson['MY_ENV_VAR'], 'MY_VALUE');
t.is(homeJson['VERCEL_URL'], host);
}
@@ -711,14 +673,14 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
const apiJson = await apiRes.json();
t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(apiJson['MY_ENV_VAR'], 'MY_VALUE');
t.is(apiJson['VERCEL_URL'], localhostNoProtocol);
const homeUrl = localhost[0];
const homeRes = await fetch(homeUrl);
const homeJson = await homeRes.json();
t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(homeJson['MY_ENV_VAR'], 'MY_VALUE');
t.is(homeJson['VERCEL_URL'], localhostNoProtocol);
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });
@@ -752,15 +714,15 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
const apiJson = await apiRes.json();
t.is(apiJson['VERCEL_URL'], localhostNoProtocol);
t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(apiJson['MY_STDIN_VAR'], '{"expect":"quotes"}');
t.is(apiJson['MY_ENV_VAR'], 'MY_VALUE');
t.is(apiJson['MY_PLAIN_VAR'], 'hello');
const homeUrl = localhost[0];
const homeRes = await fetch(homeUrl);
const homeJson = await homeRes.json();
t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(homeJson['MY_ENV_VAR'], 'MY_VALUE');
t.is(homeJson['VERCEL_URL'], localhostNoProtocol);
t.is(homeJson['MY_STDIN_VAR'], '{"expect":"quotes"}');
t.is(homeJson['MY_PLAIN_VAR'], 'hello');
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });
@@ -776,14 +738,13 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
await waitForPrompt(now, chunk =>
chunk.includes('Whats the name of the variable?')
);
now.stdin.write('MY_PLAINTEXT_ENV_VAR\n');
now.stdin.write('MY_ENV_VAR\n');
// expect error if no environment is selected
await waitForPrompt(
now,
chunk =>
chunk.includes('which Environments') &&
chunk.includes('MY_PLAINTEXT_ENV_VAR')
chunk.includes('which Environments') && chunk.includes('MY_ENV_VAR')
);
now.stdin.write('\n'); // select none
await waitForPrompt(now, chunk =>
@@ -795,8 +756,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
await waitForPrompt(
now,
chunk =>
chunk.includes('which Environments') &&
chunk.includes('MY_PLAINTEXT_ENV_VAR')
chunk.includes('which Environments') && chunk.includes('MY_ENV_VAR')
);
now.stdin.write('a\n'); // select all
@@ -807,21 +767,6 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
async function nowEnvRemoveWithArgs() {
const { exitCode, stderr, stdout } = await execa(
binaryPath,
['env', 'rm', 'MY_SECRET_ENV_VAR', 'preview', '-y', ...defaultArgs],
{
reject: false,
cwd: target,
}
);
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
const {
exitCode: exitCode2,
stderr: stderr2,
stdout: stdout2,
} = await execa(
binaryPath,
['env', 'rm', 'MY_STDIN_VAR', 'development', '-y', ...defaultArgs],
{
@@ -830,7 +775,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
}
);
t.is(exitCode2, 0, formatOutput({ stderr2, stdout2 }));
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
}
async function nowEnvRemoveWithNameOnly() {
@@ -855,20 +800,18 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
}
await nowDeploy();
const secretName = await createSecret();
await nowEnvLsIsEmpty();
await nowEnvAddPlaintext();
await nowEnvAddSecret(secretName);
await nowEnvAdd();
await nowEnvAddFromStdin();
await nowEnvAddSystemEnv();
await nowEnvLsIncludesVar();
await nowEnvPull();
await withPlainTextEnv(nowEnvLsIncludesVar)();
await withPlainTextEnv(nowEnvPull)();
await nowEnvPullOverwrite();
await nowEnvPullConfirm();
await nowDeployWithVar();
await nowDevWithEnv();
fs.unlinkSync(path.join(target, '.env'));
await nowDevAndFetchCloudVars();
await withPlainTextEnv(nowDevAndFetchCloudVars)();
await nowEnvRemove();
await nowEnvRemoveWithArgs();
await nowEnvRemoveWithNameOnly();

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "9.0.4-canary.1",
"version": "9.0.4",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://vercel.com",
@@ -37,7 +37,7 @@
]
},
"dependencies": {
"@vercel/build-utils": "2.5.5-canary.1",
"@vercel/build-utils": "2.6.0",
"@zeit/fetch": "5.2.0",
"async-retry": "1.2.3",
"async-sema": "3.0.0",

View File

@@ -136,6 +136,7 @@ export async function getVercelIgnore(
'__pycache__',
'venv',
'CVS',
'.vercel_build_output',
];
const cwds = Array.isArray(cwd) ? cwd : [cwd];

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/next",
"version": "2.6.38",
"version": "2.7.0",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",

View File

@@ -214,7 +214,7 @@ function startDevServer(entryPath: string, runtimeEnv: EnvConfig) {
return { forked, getUrl };
}
export const build = async ({
export async function build({
files,
workPath,
repoRootPath,
@@ -231,7 +231,7 @@ export const build = async ({
}>;
watch?: string[];
childProcesses: ChildProcess[];
}> => {
}> {
validateEntrypoint(entrypoint);
// Limit for max size each lambda can be, 50 MB if no custom limit
@@ -352,7 +352,7 @@ export const build = async ({
'now-build',
'build',
]);
const { buildCommand } = config;
const { installCommand, buildCommand } = config;
if (!buildScriptName && !buildCommand) {
console.log(
@@ -376,8 +376,22 @@ export const build = async ({
await writeNpmRc(entryPath, process.env.NPM_AUTH_TOKEN);
}
console.log('Installing dependencies...');
await runNpmInstall(entryPath, [], spawnOpts, meta);
if (typeof installCommand === 'string') {
if (installCommand.trim()) {
console.log(`Running "install" command: \`${installCommand}\`...`);
await execCommand(installCommand, {
...spawnOpts,
cwd: entryPath,
});
} else {
console.log(`Skipping "install" command...`);
}
} else {
console.log('Installing dependencies...');
const installTime = Date.now();
await runNpmInstall(entryPath, [], spawnOpts, meta);
debug(`Install complete [${Date.now() - installTime}ms]`);
}
// Refetch Next version now that dependencies are installed.
// This will now resolve the actual installed Next version,
@@ -732,7 +746,7 @@ export const build = async ({
src: path.join(
'/',
entryDirectory,
'_next/static/(?:[^/]+/pages|pages|chunks|runtime|css|media)/.+'
`_next/static/(?:[^/]+/pages|pages|chunks|runtime|css|media|${escapedBuildId})/.+`
),
// Next.js assets contain a hash or entropy in their filenames, so they
// are guaranteed to be unique and cacheable indefinitely.
@@ -2296,7 +2310,7 @@ export const build = async ({
src: path.join(
'/',
entryDirectory,
'_next/static/(?:[^/]+/pages|pages|chunks|runtime|css|media)/.+'
`_next/static/(?:[^/]+/pages|pages|chunks|runtime|css|media|${escapedBuildId})/.+`
),
// Next.js assets contain a hash or entropy in their filenames, so they
// are guaranteed to be unique and cacheable indefinitely.
@@ -2372,7 +2386,7 @@ export const build = async ({
watch: [],
childProcesses: [],
};
};
}
export const prepareCache = async ({
workPath,

View File

@@ -8,6 +8,12 @@
"cache-control": "public,max-age=31536000,immutable"
}
},
{
"path": "/_next/static/testing-build-id/_buildManifest.js",
"responseHeaders": {
"cache-control": "public,max-age=31536000,immutable"
}
},
{
"path": "/_next/static/invalid-build-id/pages/non-existent.js",
"notResponseHeaders": {

View File

@@ -8,6 +8,12 @@
"cache-control": "public,max-age=31536000,immutable"
}
},
{
"path": "/_next/static/testing-build-id/_buildManifest.js",
"responseHeaders": {
"cache-control": "public,max-age=31536000,immutable"
}
},
{
"path": "/",
"mustContain": "nextExport\":true"

View File

@@ -0,0 +1 @@
install.txt

View File

@@ -0,0 +1,19 @@
const path = require('path');
const { promises: fs } = require('fs');
async function main() {
console.log('installCommand...');
await fs.writeFile(path.join(__dirname, 'install.txt'), `installCommand`);
console.log('Finished installing...');
}
main()
.then(() => {
process.exit(0);
})
.catch(error => {
console.error(error);
process.exit(1);
});

View File

@@ -0,0 +1,3 @@
module.exports = {
target: 'serverless',
};

View File

@@ -0,0 +1,10 @@
{
"scripts": {
"build": "next build"
},
"dependencies": {
"next": "canary",
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
}

View File

@@ -0,0 +1,15 @@
import path from 'path';
import { promises as fs } from 'fs';
export async function getStaticProps(context) {
console.log(process.cwd());
const installPath = path.join(process.cwd(), 'install.txt');
const install = await fs.readFile(installPath, 'utf8');
return {
props: { install },
};
}
export default function ({ install }) {
return <div>{install}</div>;
}

View File

@@ -0,0 +1,20 @@
{
"builds": [
{
"src": "package.json",
"use": "@vercel/next",
"config": {
"zeroConfig": true,
"installCommand": "node install.js && yarn",
"buildCommand": "next build"
}
}
],
"probes": [
{
"path": "/",
"status": 200,
"mustContain": "installCommand"
}
]
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node",
"version": "1.8.4",
"version": "1.8.5",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",

View File

@@ -104,12 +104,7 @@ async function downloadInstallAndBundle({
} else {
const installTime = Date.now();
console.log('Installing dependencies...');
await runNpmInstall(
entrypointFsDirname,
['--prefer-offline'],
spawnOpts,
meta
);
await runNpmInstall(entrypointFsDirname, [], spawnOpts, meta);
debug(`Install complete [${Date.now() - installTime}ms]`);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/routing-utils",
"version": "1.9.1-canary.1",
"version": "1.9.1",
"description": "Vercel routing utilities",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",

View File

@@ -3,3 +3,6 @@ dist/
# bypass all ignored files for the cache fixtures
# because they contain node_modules and package-lock.json files
!test/cache-fixtures/**
/src/bridge.ts
/src/launcher.ts

View File

@@ -1,8 +1,17 @@
#!/bin/bash
set -euo pipefail
# Copy shared dependencies
bridge_defs="$(dirname $(pwd))/now-node-bridge/src/bridge.ts"
launcher_defs="$(dirname $(pwd))/now-node/src/launcher.ts"
cp -v "$bridge_defs" src
cp -v "$launcher_defs" src
# Start fresh
rm -rf dist
tsc
# Build with `ncc`
ncc build src/index.ts -e @vercel/build-utils -e @now/build-utils -o dist

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/static-build",
"version": "0.17.11",
"version": "0.18.0",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/build-step",
@@ -19,6 +19,7 @@
"prepublishOnly": "./build.sh"
},
"devDependencies": {
"@types/aws-lambda": "8.10.64",
"@types/cross-spawn": "6.0.0",
"@types/ms": "0.7.31",
"@types/node-fetch": "2.5.4",

View File

@@ -33,6 +33,7 @@ const {
NowBuildError,
} = buildUtils;
import { Route, Source } from '@vercel/routing-utils';
import { readBuildOutputDirectory } from './utils/read-build-output';
import * as GatsbyUtils from './utils/gatsby';
const sleep = (n: number) => new Promise(resolve => setTimeout(resolve, n));
@@ -110,7 +111,7 @@ function getScriptName(pkg: PackageJson, cmd: string, { zeroConfig }: Config) {
}
function getCommand(
name: 'build' | 'dev',
name: 'install' | 'build' | 'dev',
pkg: PackageJson | null,
config: Config,
framework: Framework | undefined
@@ -119,7 +120,7 @@ function getCommand(
return null;
}
const propName = name === 'build' ? 'buildCommand' : 'devCommand';
const propName = `${name}Command` as keyof Config;
if (typeof config[propName] === 'string') {
return config[propName];
@@ -134,7 +135,7 @@ function getCommand(
}
if (framework) {
return framework[propName] || null;
return (framework as any)[propName] || null;
}
return null;
@@ -269,6 +270,7 @@ export async function build({
const devCommand = getCommand('dev', pkg, config, framework);
const buildCommand = getCommand('build', pkg, config, framework);
const installCommand = getCommand('install', pkg, config, framework);
if (pkg || buildCommand) {
const gemfilePath = path.join(workPath, 'Gemfile');
@@ -279,18 +281,20 @@ export async function build({
const routes: Route[] = [];
if (config.zeroConfig) {
if (existsSync(gemfilePath) && !meta.isDev) {
debug('Detected Gemfile, executing bundle install...');
await runBundleInstall(workPath, [], undefined, meta);
}
if (existsSync(requirementsPath) && !meta.isDev) {
debug('Detected requirements.txt, executing pip install...');
await runPipInstall(
workPath,
['-r', requirementsPath],
undefined,
meta
);
if (typeof installCommand !== 'string') {
if (existsSync(gemfilePath) && !meta.isDev) {
debug('Detected Gemfile, executing bundle install...');
await runBundleInstall(workPath, [], undefined, meta);
}
if (existsSync(requirementsPath) && !meta.isDev) {
debug('Detected requirements.txt, executing pip install...');
await runPipInstall(
workPath,
['-r', requirementsPath],
undefined,
meta
);
}
}
const { HUGO_VERSION, ZOLA_VERSION, GUTENBERG_VERSION } = process.env;
@@ -357,10 +361,22 @@ export async function build({
if (meta.isDev) {
debug('Skipping dependency installation because dev mode is enabled');
} else {
const installTime = Date.now();
console.log('Installing dependencies...');
await runNpmInstall(entrypointDir, ['--prefer-offline'], spawnOpts, meta);
debug(`Install complete [${Date.now() - installTime}ms]`);
if (typeof installCommand === 'string') {
if (installCommand.trim()) {
console.log(`Running "install" command: \`${installCommand}\`...`);
await execCommand(installCommand, {
...spawnOpts,
cwd: entrypointDir,
});
} else {
console.log(`Skipping "install" command...`);
}
} else {
console.log('Installing dependencies...');
const installTime = Date.now();
await runNpmInstall(entrypointDir, [], spawnOpts, meta);
debug(`Install complete [${Date.now() - installTime}ms]`);
}
}
if (pkg && (buildCommand || devCommand)) {
@@ -375,7 +391,7 @@ export async function build({
};
debug(
`Added "${nodeBinPath}" to PATH env because a package.json file was found.`
`Added "${nodeBinPath}" to PATH env because a package.json file was found`
);
}
@@ -441,7 +457,7 @@ export async function build({
);
} else {
if (meta.isDev) {
debug(`WARN: A dev script is missing.`);
debug(`WARN: A dev script is missing`);
}
if (buildCommand) {
@@ -489,31 +505,50 @@ export async function build({
}
}
validateDistDir(distPath);
const extraOutputs = await readBuildOutputDirectory({ workPath });
if (framework) {
const frameworkRoutes = await getFrameworkRoutes(
framework,
outputDirPrefix
if (extraOutputs.routes) {
routes.push(...extraOutputs.routes);
}
if (extraOutputs.staticFiles) {
output = Object.assign(
{},
extraOutputs.staticFiles,
extraOutputs.functions
);
routes.push(...frameworkRoutes);
}
} else {
// No need to verify the dist dir if there are other output files.
if (!extraOutputs.functions) {
validateDistDir(distPath);
}
let ignore: string[] = [];
if (config.zeroConfig && config.outputDirectory === '.') {
ignore = [
'.env',
'.env.*',
'.git/**',
'.vercel/**',
'node_modules/**',
'yarn.lock',
'package-lock.json',
'package.json',
];
debug(`Using ignore: ${JSON.stringify(ignore)}`);
if (framework && !extraOutputs.routes) {
const frameworkRoutes = await getFrameworkRoutes(
framework,
outputDirPrefix
);
routes.push(...frameworkRoutes);
}
let ignore: string[] = [];
if (config.zeroConfig && config.outputDirectory === '.') {
ignore = [
'.env',
'.env.*',
'.git/**',
'.vercel/**',
'node_modules/**',
'yarn.lock',
'package-lock.json',
'package.json',
'.vercel_build_output',
];
debug(`Using ignore: ${JSON.stringify(ignore)}`);
}
output = await glob('**', { cwd: distPath, ignore }, mountpoint);
Object.assign(output, extraOutputs.functions);
}
output = await glob('**', { cwd: distPath, ignore }, mountpoint);
}
const watch = [path.join(mountpoint.replace(/^\.\/?/, ''), '**/*')];

View File

@@ -1,6 +1,6 @@
import { PackageJson } from '@vercel/build-utils';
import { constants, PathLike, promises as fs } from 'fs';
import * as path from 'path';
import { PackageJson } from '@vercel/build-utils';
import path from 'path';
export type DeepWriteable<T> = {
-readonly [P in keyof T]: DeepWriteable<T[P]>;
@@ -38,3 +38,11 @@ export async function writePackageJson(
JSON.stringify(packageJson, null, 2)
);
}
export function isObjectEmpty(object: { [key: string]: unknown }) {
for (const _prop in object) {
return false;
}
return true;
}

View File

@@ -0,0 +1,157 @@
import { FileBlob, Files, Lambda } from '@vercel/build-utils';
import { isObjectEmpty } from './_shared';
import { makeNowLauncher } from '../launcher';
import { promises as fs } from 'fs';
import { Route } from '@vercel/routing-utils';
import buildUtils from '../build-utils';
import path from 'path';
const { createLambda, debug, getLatestNodeVersion, glob } = buildUtils;
/**
* Reads the .vercel_build_output directory and returns and object
* that should be merged with the build outputs.
*
* At the moment only `functions/node` is supported for functions.
*/
export async function readBuildOutputDirectory({
workPath,
}: {
workPath: string;
}) {
const functions: { [key: string]: Lambda } = {};
const functionsMountPath = path.join('.vercel', 'functions');
Object.assign(
functions,
await readNodeFunctions({ workPath, functionsMountPath })
);
const staticFiles = await readStaticFiles({ workPath });
const routes = await readRoutesConfig({ workPath });
const outputs = {
staticFiles: isObjectEmpty(staticFiles) ? null : staticFiles,
functions: isObjectEmpty(functions) ? null : functions,
routes: routes.length ? routes : null,
};
if (outputs.functions) {
console.log(
`Detected Serverless Functions in ".vercel_build_output/functions"`
);
}
if (outputs.staticFiles) {
console.log(`Detected Static Assets in ".vercel_build_output/static"`);
}
if (outputs.routes) {
console.log(`Detected Configuration in ".vercel_build_output/config"`);
}
return outputs;
}
async function readStaticFiles({
workPath,
}: {
workPath: string;
}): Promise<Files> {
const staticFilePath = path.join(workPath, '.vercel_build_output', 'static');
const staticFiles = await glob('**', {
cwd: staticFilePath,
});
return staticFiles;
}
async function readNodeFunctions({
workPath,
functionsMountPath,
}: {
workPath: string;
functionsMountPath: string;
}) {
const output: { [key: string]: Lambda } = {};
const nodeFunctionPath = path.join(
workPath,
'.vercel_build_output',
'functions',
'node'
);
const nodeFunctionFiles = await glob('*/index.js', {
cwd: nodeFunctionPath,
});
const nodeBridgeData = await fs.readFile(path.join(__dirname, 'bridge.js'));
for (const fileName of Object.keys(nodeFunctionFiles)) {
const launcherFileName = '___now_launcher';
const bridgeFileName = '___now_bridge';
const launcherFiles: Files = {
[`${launcherFileName}.js`]: new FileBlob({
data: makeNowLauncher({
entrypointPath: `./index.js`,
bridgePath: `./${bridgeFileName}`,
helpersPath: '',
sourcemapSupportPath: '',
shouldAddHelpers: false,
shouldAddSourcemapSupport: false,
}),
}),
[`${bridgeFileName}.js`]: new FileBlob({
data: nodeBridgeData,
}),
};
const requiredFiles = await glob('**', {
cwd: path.join(nodeFunctionPath, path.dirname(fileName)),
});
const lambda = await createLambda({
files: {
...requiredFiles,
...launcherFiles,
},
handler: `${launcherFileName}.launcher`,
runtime: getLatestNodeVersion().runtime,
});
const parsed = path.parse(fileName);
const newPath = path.join(functionsMountPath, parsed.dir, parsed.name);
output[newPath] = lambda;
debug(
`Created Lambda "${newPath}" from "${path.join(
nodeFunctionPath,
fileName
)}".`
);
}
return output;
}
async function readRoutesConfig({
workPath,
}: {
workPath: string;
}): Promise<Route[]> {
const routesConfigPath = path.join(
workPath,
'.vercel_build_output',
'config',
'routes.json'
);
try {
return JSON.parse(await fs.readFile(routesConfigPath, 'utf8')) || [];
} catch (error) {
if (error.code === 'ENOENT') {
return [];
}
throw error;
}
}

View File

@@ -0,0 +1,71 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# dotenv environment variable files
.env*
# gatsby files
.cache/
public
# Mac files
.DS_Store
# Yarn
yarn-error.log
.pnp/
.pnp.js
# Yarn Integrity file
.yarn-integrity
.vercel

View File

@@ -0,0 +1,17 @@
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`,
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
author: `@gatsbyjs`,
},
plugins: [
{
resolve: 'gatsby-plugin-zeit-now',
options: {
globalHeaders: {
'x-some-header': 'some-value',
},
},
},
],
};

View File

@@ -0,0 +1,20 @@
{
"name": "gatsby-starter-default",
"private": true,
"description": "A simple starter to get up and developing quickly with Gatsby",
"version": "0.1.0",
"dependencies": {
"gatsby": "^2.24.91",
"gatsby-plugin-zeit-now": "0.3.0",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-dom": "^16.12.0"
},
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean"
}
}

View File

@@ -0,0 +1,5 @@
import React from 'react';
const NotFoundPage = () => <h1>404: Not Found</h1>;
export default NotFoundPage;

View File

@@ -0,0 +1,5 @@
import React from 'react';
const IndexPage = () => <h1>Hello World people</h1>;
export default IndexPage;

View File

@@ -0,0 +1,13 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build",
"config": {
"zeroConfig": true,
"framework": "gatsby"
}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -217,3 +217,42 @@ it(
},
FOUR_MINUTES
);
it(
'Should build Gatsby with "gatsby-plugin-zeit-now" plugin',
async () => {
const { workPath } = await runBuildLambda(
path.join(__dirname, 'build-fixtures/07-gatsby-with-now-plugin')
);
const contents = await fs.readdir(workPath);
expect(contents.some(name => name === 'gatsby-config.js')).toBeTruthy();
expect(require(path.join(workPath, 'gatsby-config.js')))
.toMatchInlineSnapshot(`
Object {
"plugins": Array [
Object {
"options": Object {
"globalHeaders": Object {
"x-some-header": "some-value",
},
},
"resolve": "gatsby-plugin-zeit-now",
},
Object {
"options": Object {},
"resolve": "gatsby-plugin-vercel",
},
],
"siteMetadata": Object {
"author": "@gatsbyjs",
"description": "Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.",
"title": "Gatsby Default Starter",
},
}
`);
},
FOUR_MINUTES
);

View File

@@ -7,7 +7,7 @@
"rollup-plugin-commonjs": "^9.3.4",
"rollup-plugin-livereload": "^1.0.0",
"rollup-plugin-node-resolve": "^4.2.3",
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-svelte": "^6.1.1",
"rollup-plugin-terser": "^4.0.4",
"svelte": "^3.0.0"
},

View File

@@ -0,0 +1 @@
.vercel_build_output

View File

@@ -0,0 +1,10 @@
[
{
"src": "/",
"dest": "/.vercel/functions/root/"
},
{
"src": "/(.*)",
"dest": "/.vercel/functions/$1"
}
]

View File

@@ -0,0 +1,5 @@
const { getAbout } = require('./util');
module.exports = async function (req, res) {
return res.end(`Hello from /about/index.js on ${req.url} - ${getAbout()}`);
};

View File

@@ -0,0 +1,5 @@
module.exports = {
getAbout() {
return 'Milkshake';
},
};

View File

@@ -0,0 +1,7 @@
const { getInfo } = require('./info');
module.exports = async function (req, res) {
return res.end(
`Hello from /product/index.js on ${req.url} - ${await getInfo()}`
);
};

View File

@@ -0,0 +1,5 @@
module.exports = {
async getInfo() {
return 'Information about a Product.';
},
};

View File

@@ -0,0 +1,3 @@
module.exports = async function (req, res) {
return res.end(`Hello from /root/index.js on ${req.url}`);
};

View File

@@ -0,0 +1,37 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build",
"config": { "zeroConfig": true }
}
],
"probes": [
{
"path": "/.vercel/functions/root",
"mustContain": "Hello from /root/index.js on /.vercel/functions/root"
},
{ "path": "/", "mustContain": "Hello from /root/index.js on /" },
{
"path": "/.vercel/functions/about",
"mustContain": "Hello from /about/index.js on /.vercel/functions/about - Milkshake"
},
{
"path": "/about",
"mustContain": "Hello from /about/index.js on /about - Milkshake"
},
{ "path": "/.vercel/functions/about/util", "status": 404 },
{ "path": "/about/util", "status": 404 },
{
"path": "/.vercel/functions/product",
"mustContain": "Hello from /product/index.js on /.vercel/functions/product - Information about a Product"
},
{
"path": "/product",
"mustContain": "Hello from /product/index.js on /product - Information about a Product"
},
{ "path": "/.vercel/functions/product/info", "status": 404 },
{ "path": "/product/info", "status": 404 }
]
}

View File

@@ -0,0 +1,5 @@
{
"scripts": {
"build": "cp -r fake .vercel_build_output"
}
}

View File

@@ -0,0 +1 @@
.vercel_build_output

View File

@@ -0,0 +1,10 @@
[
{
"src": "/",
"dest": "/.vercel/functions/root/"
},
{
"src": "/(.*)",
"dest": "/.vercel/functions/$1"
}
]

View File

@@ -0,0 +1,5 @@
const { getAbout } = require('./util');
module.exports = async function (req, res) {
return res.end(`Hello from /about/index.js on ${req.url} - ${getAbout()}`);
};

View File

@@ -0,0 +1,5 @@
module.exports = {
getAbout() {
return 'Milkshake';
},
};

View File

@@ -0,0 +1,7 @@
const { getInfo } = require('./info');
module.exports = async function (req, res) {
return res.end(
`Hello from /product/index.js on ${req.url} - ${await getInfo()}`
);
};

View File

@@ -0,0 +1,5 @@
module.exports = {
async getInfo() {
return 'Information about a Product.';
},
};

View File

@@ -0,0 +1,3 @@
module.exports = async function (req, res) {
return res.end(`Hello from /root/index.js on ${req.url}`);
};

View File

@@ -0,0 +1,22 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build",
"config": { "zeroConfig": true }
}
],
"probes": [
{ "path": "/static.txt", "mustContain": "static" },
{ "path": "/", "mustContain": "Hello from /root/index.js on /" },
{
"path": "/about",
"mustContain": "Hello from /about/index.js on /about - Milkshake"
},
{
"path": "/product",
"mustContain": "Hello from /product/index.js on /product - Information about a Product"
}
]
}

View File

@@ -0,0 +1,5 @@
{
"scripts": {
"build": "mkdir -p public && echo static > public/static.txt && cp -r fake .vercel_build_output"
}
}

View File

@@ -0,0 +1 @@
.vercel_build_output

View File

@@ -0,0 +1,10 @@
[
{
"src": "/",
"dest": "/.vercel/functions/root/"
},
{
"src": "/(.*)",
"dest": "/.vercel/functions/$1"
}
]

View File

@@ -0,0 +1,11 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build",
"config": { "zeroConfig": true }
}
],
"probes": [{ "path": "/", "mustContain": "overwritten" }]
}

View File

@@ -0,0 +1,5 @@
{
"scripts": {
"build": "mkdir -p public && echo static > public/index.txt && cp -r fake .vercel_build_output"
}
}

View File

@@ -0,0 +1 @@
public

View File

@@ -0,0 +1,22 @@
const path = require('path');
const { promises: fs } = require('fs');
async function main() {
console.log('buildCommand...');
await fs.appendFile(
path.join(__dirname, 'public', 'index.txt'),
`buildCommand.`
);
console.log('Finished building...');
}
main()
.then(() => {
process.exit(0);
})
.catch(error => {
console.error(error);
process.exit(1);
});

View File

@@ -0,0 +1,23 @@
const path = require('path');
const { promises: fs } = require('fs');
async function main() {
console.log('installCommand...');
await fs.mkdir(path.join(__dirname, 'public'));
await fs.writeFile(
path.join(__dirname, 'public', 'index.txt'),
`installCommand.`
);
console.log('Finished installing...');
}
main()
.then(() => {
process.exit(0);
})
.catch(error => {
console.error(error);
process.exit(1);
});

View File

@@ -0,0 +1,14 @@
{
"builds": [
{
"src": "build.js",
"use": "@vercel/static-build",
"config": {
"zeroConfig": true,
"installCommand": "node install.js",
"buildCommand": "node build.js"
}
}
],
"probes": [{ "path": "/", "mustContain": "installCommand.buildCommand." }]
}

View File

@@ -15,7 +15,6 @@
"strict": true,
"target": "esnext"
},
"exclude": [
"test/fixtures"
]
"include": ["src/**/*"],
"exclude": ["test/fixtures"]
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/redwood",
"version": "0.1.2-canary.1",
"version": "0.2.0",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs",
@@ -19,7 +19,7 @@
},
"dependencies": {
"@netlify/zip-it-and-ship-it": "1.2.0",
"@vercel/frameworks": "0.1.2-canary.1"
"@vercel/frameworks": "0.2.0"
},
"devDependencies": {
"@types/aws-lambda": "8.10.19",

View File

@@ -50,6 +50,7 @@ export async function build({
}: BuildOptions) {
await download(files, workPath, meta);
const { installCommand, buildCommand } = config;
const mountpoint = dirname(entrypoint);
const entrypointFsDirname = join(workPath, mountpoint);
const nodeVersion = await getNodeVersion(
@@ -60,18 +61,27 @@ export async function build({
);
const spawnOpts = getSpawnOptions(meta, nodeVersion);
await runNpmInstall(
entrypointFsDirname,
['--prefer-offline'],
spawnOpts,
meta
);
if (typeof installCommand === 'string') {
if (installCommand.trim()) {
console.log(`Running "install" command: \`${installCommand}\`...`);
await execCommand(installCommand, {
...spawnOpts,
cwd: entrypointFsDirname,
});
} else {
console.log(`Skipping "install" command...`);
}
} else {
console.log('Installing dependencies...');
const installTime = Date.now();
await runNpmInstall(entrypointFsDirname, [], spawnOpts, meta);
debug(`Install complete [${Date.now() - installTime}ms]`);
}
if (meta.isDev) {
throw new Error('Detected `@vercel/redwood` dev but this is not supported');
}
const { buildCommand } = config;
const frmwrkCmd = frameworks.find(f => f.slug === 'redwoodjs')?.settings
.buildCommand;
const pkg = await readConfigFile<PackageJson>(join(workPath, 'package.json'));

View File

@@ -0,0 +1,22 @@
const path = require('path')
const { promises: fs } = require('fs')
async function main() {
console.log('installCommand...')
await fs.writeFile(
path.join(__dirname, 'web', 'public', 'install.txt'),
`installCommand.`
)
console.log('Finished installing...')
}
main()
.then(() => {
process.exit(0)
})
.catch((error) => {
console.error(error)
process.exit(1)
})

View File

@@ -1,6 +1,15 @@
{
"version": 2,
"builds": [{ "src": "package.json", "use": "@vercel/redwood" }],
"builds": [
{
"src": "package.json",
"use": "@vercel/redwood",
"config": {
"zeroConfig": true,
"installCommand": "node install.js && yarn"
}
}
],
"probes": [
{ "path": "/", "mustContain": "<div id=\"redwood-app\">" },
{
@@ -14,6 +23,7 @@
"headers": { "Accept": "application/json" },
"body": { "query": "{ redwood { version } }" },
"mustContain": "0.16.0"
}
},
{ "path": "/install.txt", "mustContain": "installCommand." }
]
}

View File

@@ -1607,6 +1607,11 @@
resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.19.tgz#913a8016a4599d262960d97cb11faf7e963ec0e1"
integrity sha512-dEhQow/1awGGIf/unEpb97vsTtnQ3qRPAhSmZZcXKzs4nOVbIuWo5LCCzOYdSIkGkkoFXVvc8pBaSVKRYIFUBA==
"@types/aws-lambda@8.10.64":
version "8.10.64"
resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.64.tgz#4bdcb725aef96bef0cb1decf19c7efff1df22fe7"
integrity sha512-LRKk2UQCSi7BsO5TlfSI8cTNpOGz+MH6+RXEWtuZmxJficQgxwEYJDiKVirzgyiHce0L0F4CqCVvKTwblAeOUw==
"@types/babel__core@^7.1.0":
version "7.1.8"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.8.tgz#057f725aca3641f49fc11c7a87a9de5ec588a5d7"
@@ -8252,6 +8257,11 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
nanoid@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.0.2.tgz#37e91e6f5277ce22335be473e2a5db1bd96dd026"
integrity sha512-WOjyy/xu3199NlQiQWlx7VbspSFlGtOxa1bRX9ebmXOnp1fje4bJfjPs1wLQ8jZbJUfD+yceJmw879ZSaVJkdQ==
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"