Compare commits

..

23 Commits

Author SHA1 Message Date
Nathan Rajlich
63cc9009c8 Publish Stable
- @vercel/frameworks@0.0.15
 - @vercel/build-utils@2.4.0
 - @vercel/cgi@1.0.6
 - vercel@19.1.0
 - @vercel/client@8.1.0
 - @vercel/go@1.1.2
 - @vercel/next@2.6.6
 - @vercel/node-bridge@1.3.1
 - @vercel/node@1.7.0
 - @vercel/python@1.2.2
 - @vercel/routing-utils@1.8.3
 - @vercel/ruby@1.2.2
 - @vercel/static-build@0.17.2
2020-06-11 16:30:31 -07:00
Nathan Rajlich
ccf6e3c432 Publish Canary
- vercel@19.0.2-canary.17
 - @vercel/client@8.0.2-canary.4
2020-06-11 15:17:05 -07:00
Steven
8d015e3138 [client] Fix .vercelignore override default ignore list (#4627)
- Fixes #3747 
- Related to #4325
- Related to [tweet](https://twitter.com/Rich_Harris/status/1270871878018699264) from @Rich-Harris
- Docs updated in https://github.com/vercel/docs/pull/1909

There was an issue that was likely introduced when we started using `@vercel/client`: the [default ignore list](https://vercel.com/docs/v2/build-step#ignored-files-and-folders) could not be overridden. This is because the default `ignores` array was always used instead of the combined `default ignore + user ignore`. The solution was to utilize [`recursive-readdir` ignore function](https://www.npmjs.com/package/recursive-readdir#usage) along with [`ig.ignores` function](https://www.npmjs.com/package/ignore#usage) so that the combined result is used for ignoring files while walking the file tree.

This ensures that the fix from PR #4325 is still effective and also fixes the longstanding bug from Issue #3747.
2020-06-11 18:15:16 -04:00
Nathan Rajlich
42f2fa1a20 [cli] Invalidate the configuration if vercel.json is deleted (#4629)
Before this, if the `vercel.json` file gets deleted while the dev server
is running, then it would still act like the file exists since it would
use the cached version.

Now it properly invalidates to an empty configuration if the
`vercel.json` file does not exist.
2020-06-11 22:06:44 +00:00
Steven
8397aac0e3 [github] Update codeowners (#4630)
* Update codeowners

* Make TooTallNate taller
2020-06-11 16:59:18 -04:00
Nathan Rajlich
7bcdc144eb [cli] Update "npm-install-error" link to "npm-install-failed-dev" (#4628)
Depends on https://github.com/vercel/docs/pull/1908.
2020-06-11 19:08:48 +00:00
Nathan Rajlich
624da9170d Publish Canary
- @vercel/frameworks@0.0.15-canary.5
 - @vercel/build-utils@2.3.2-canary.6
 - vercel@19.0.2-canary.16
 - @vercel/client@8.0.2-canary.3
 - @vercel/node@1.6.2-canary.6
2020-06-10 14:27:18 -07:00
Nathan Rajlich
fb5b013a03 [node] Force module: "commonjs" in startDevServer() (#4621)
This is a follow up to #4514 to handle the case where there is no
`tsconfig.json` closer to the entrypoint. This is likely the case when
`.js` files with ES Modules syntax are being used instead of `.ts`.
2020-06-10 14:26:28 -07:00
Mark Glagola
0a4bb53a58 [cli] Handle aliasWarning and bump to v13/now/deployments (#4605)
* Handle aliasWarning

* Pick best production project domain

* Fix currentTeam assignment

* Adds `https` url check to cli integration tests
2020-06-10 16:00:50 -05:00
Nathan Rajlich
2fbd9c78e3 [cli] Better errors for conflicting configuration files (#4612)
* [cli] Better errors for conflicting configuration files

Renders the link https://vercel.link/combining-old-and-new-config
for all conflicting config errors.

* Fix unit test

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-06-10 12:38:02 -07:00
Nathan Rajlich
1ed2b7a57d [cli] Update @vercel/next to v2.6.5 (#4611)
It got out of sync somehow in 55c60d30e6.
2020-06-10 03:37:58 +00:00
Nathan Rajlich
88cd9ca3c3 [cli] Invalidate build match for changes to config in builds (#4603)
* Fixes changing a `config` value in the `builds` array (such as `helpers: false` for `@vercel/node`) and having it be reflected in `vc dev` without restarting the dev server.
* Re-validates the env vars configuration when a `.env` file changes or the `env` object is changed in `vercel.json` (same for the builds equivalents).
* Ensures that the `NODEJS_HELPERS` build env var is being properly checked in `startDevServer()`.
* Regenerated the `yarn.lock` file because yarn was erroring when trying to add the `fast-deep-equal` dependency.
2020-06-09 19:56:55 +00:00
JJ Kasper
ecea2ca4a3 Publish Stable
- @vercel/next@2.6.5
2020-06-09 13:02:11 -05:00
JJ Kasper
3f132bc15b Publish Canary
- @vercel/build-utils@2.3.2-canary.5
 - vercel@19.0.2-canary.15
 - @vercel/next@2.6.5-canary.0
 - @vercel/routing-utils@1.8.3-canary.6
2020-06-09 11:47:51 -05:00
JJ Kasper
61d95094c0 [next] Re-disable shared lambdas by default (#4609)
As noticed, `now.json` and `vercel.json` files aren't available during the build currently which makes feature detecting and opting out when `routes` are used not work currently so this re-disables the shared lambdas optimization by default while we investigate detecting this
2020-06-09 16:24:21 +00:00
Steven
f7c47975e3 [tests] Add log for error response (#4601) 2020-06-08 17:51:31 -07:00
Nathan Rajlich
7c96f9f9a5 [cli] Show npm output when failing to install Runtimes in vc dev (#4598)
If `npm install` doesn't exit with 0, then log the output to the
termial.

This was already happening with `--debug` due to `stdio: "inherit"`
when debug is enabled, so this change is really only relevant for the
non-debug case.

### Before

```
$ vc dev
Vercel CLI 19.0.2-canary.13 dev (beta) — https://vercel.com/feedback
Error! Command failed with exit code 1: npm install --save-exact --no-package-lock --no-audit --no-progress @now/build-utils@canary @vercel/build-utils@canary now-php@0.0.0
```

### After

Bad dependency:

<img width="641" alt="Screen Shot 2020-06-08 at 12 22 00 PM" src="https://user-images.githubusercontent.com/71256/84071523-b07c4c00-a982-11ea-9200-f18498ae917c.png">

No `npm` installed:

<img width="672" alt="Screen Shot 2020-06-08 at 12 21 16 PM" src="https://user-images.githubusercontent.com/71256/84071456-95114100-a982-11ea-87cc-05ed7fb2cb80.png">
2020-06-08 22:36:47 +00:00
Nathan Rajlich
a5c805b6eb [cli] Use getArgs() instead of mri to parse arguments in vc projects (#4570)
* Ensures that `vc --debug projects ls` properly prints the Projects listing, rather than the usage help info.
 * `vc projects` (without a subcommand) shows the Projects listing (this is consistent with i.e. `vc domains`).
 * Returns with exit code `2` when the usage help info is printed (standard Unix convention).
2020-06-08 21:05:18 +00:00
JJ Kasper
ff2a22023d Publish Stable
- @vercel/next@2.6.4
2020-06-08 14:56:04 -05:00
JJ Kasper
c6efc028aa Publish Canary
- vercel@19.0.2-canary.14
 - @vercel/next@2.6.4-canary.0
2020-06-08 14:48:59 -05:00
JJ Kasper
96565da1cf [next] Add shared lambdas opt-out for functions config (#4596)
As discussed this adds opting out of the shared lambdas optimization when a user adds a functions config in `now.json` or `vercel.json` since this could potentially be a breaking change. We plan to add new handling to still allow customizing this config for the combined lambdas that are created
2020-06-08 19:40:48 +00:00
Steven
afb5e7fc85 [cli] Update tests for 404.html (#4597)
Now that we updated api-deployments, we can remove this TODO and run tests agains `vercel dev` and real deployments.
2020-06-08 18:42:45 +00:00
Nathan Rajlich
34cc987be8 [cli] Make proxyPass() return a 502 if the proxying fails (#4586)
This happens, for example, with a `startDevServer()` process that
crashes (i.e. a syntax error in a Node.js API endpoint) before
responding to the HTTP request.
2020-06-08 18:02:05 +00:00
65 changed files with 6447 additions and 449 deletions

28
.github/CODEOWNERS vendored
View File

@@ -1,27 +1,27 @@
# Documentation
# https://help.github.com/en/articles/about-code-owners
* @tootallnate
* @TooTallNate
/.github/workflows @AndyBitz @styfle
/packages/frameworks @AndyBitz
/packages/now-cli/src/commands/dev/ @tootallnate @styfle @AndyBitz
/packages/now-cli/src/util/dev/ @tootallnate @styfle @AndyBitz
/packages/now-cli/src/commands/domains/ @javivelasco @mglagola @anatrajkovska
/packages/now-cli/src/commands/certs/ @javivelasco @mglagola @anatrajkovska
/packages/now-cli/src/commands/dev @TooTallNate @styfle @AndyBitz
/packages/now-cli/src/util/dev @TooTallNate @styfle @AndyBitz
/packages/now-cli/src/commands/domains @javivelasco @mglagola @anatrajkovska
/packages/now-cli/src/commands/certs @javivelasco @mglagola @anatrajkovska
/packages/now-cli/src/commands/env @styfle @lucleray
/packages/now-client @rdev
/packages/now-build-utils @styfle @AndyBitz
/packages/now-node @styfle @tootallnate @lucleray
/packages/now-node-bridge @styfle @tootallnate @lucleray
/packages/now-client @rdev @styfle @TooTallNate
/packages/now-build-utils @styfle @AndyBitz @TooTallNate
/packages/now-node @styfle @TooTallNate @lucleray
/packages/now-node-bridge @styfle @TooTallNate @lucleray
/packages/now-next @Timer @ijjk
/packages/now-go @styfle @sophearak
/packages/now-python @styfle @sophearak
/packages/now-ruby @styfle @coetry @nathancahill
/packages/now-go @styfle @TooTallNate
/packages/now-python @styfle @TooTallNate
/packages/now-ruby @styfle @coetry @TooTallNate
/packages/now-static-build @styfle @AndyBitz
/packages/now-routing-utils @styfle @dav-is @ijjk
/examples @mcsdevv @timothyis
/examples/create-react-app @Timer
/examples/nextjs @timneutkens
/examples/nextjs @timneutkens @Timer
/examples/hugo @mcsdevv @timothyis @styfle
/examples/jekyll @mcsdevv @timothyis @sarupbanskota
/examples/jekyll @mcsdevv @timothyis @styfle
/examples/zola @mcsdevv @timothyis @styfle

View File

@@ -0,0 +1,14 @@
# `@vercel/next` Functions Config Optimized Lambdas Opt-out
#### Why This Warning Occurred
`@vercel/next` by default now bundles pages into optimized functions, minimizing bootup time and increasing overall application throughput.
When the `functions` config is added in `now.json` or `vercel.json`, it causes conflicts with this optimization, so it is opted-out.
#### Possible Ways to Fix It
Remove the `functions` config from your `now.json` or `vercel.json` to take advantage of this optimization.
### Useful Links
- [Functions Config Documentation](https://vercel.com/docs/configuration?query=functions#project/functions)

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/frameworks",
"version": "0.0.15-canary.4",
"version": "0.0.15",
"main": "frameworks.json",
"license": "UNLICENSED",
"scripts": {
@@ -9,7 +9,7 @@
"devDependencies": {
"@types/jest": "24.0.22",
"@types/node": "12.0.4",
"ajv": "6.10.2",
"ajv": "6.12.2",
"jest": "24.9.0",
"ts-jest": "24.1.0",
"typescript": "3.9.3"

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "2.3.2-canary.4",
"version": "2.4.0",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",

View File

@@ -7,11 +7,13 @@ export class NowBuildError extends Error {
public hideStackTrace = true;
public code: string;
public link?: string;
public action?: string;
constructor({ message, code, link }: Props) {
constructor({ message, code, link, action }: Props) {
super(message);
this.code = code;
this.link = link;
this.action = action;
}
}
@@ -31,4 +33,8 @@ interface Props {
* link to more information about this error.
*/
link?: string;
/**
* Optional "action" to display before the `link`, such as "More details".
*/
action?: string;
}

View File

@@ -27,6 +27,7 @@ import {
getLatestNodeVersion,
getDiscontinuedNodeVersions,
} from './fs/node-version';
import { NowBuildError } from './errors';
import streamToBuffer from './fs/stream-to-buffer';
import shouldServe from './should-serve';
import debug from './debug';
@@ -111,9 +112,11 @@ export const getPlatformEnv = (name: string): string | undefined => {
const n = process.env[nName];
if (typeof v === 'string') {
if (typeof n === 'string') {
throw new Error(
`Both "${vName}" and "${nName}" env vars are defined. Please only define the "${vName}" env var`
);
throw new NowBuildError({
code: 'CONFLICTING_ENV_VAR_NAMES',
message: `Both "${vName}" and "${nName}" env vars are defined. Please only define the "${vName}" env var.`,
link: 'https://vercel.link/combining-old-and-new-config',
});
}
return v;
}

View File

@@ -39,7 +39,7 @@ describe('Test `getPlatformEnv()`', () => {
assert(err);
assert.equal(
err!.message,
'Both "VERCEL_FOO" and "NOW_FOO" env vars are defined. Please only define the "VERCEL_FOO" env var'
'Both "VERCEL_FOO" and "NOW_FOO" env vars are defined. Please only define the "VERCEL_FOO" env var.'
);
});
});

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/cgi",
"version": "1.0.6-canary.0",
"version": "1.0.6",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "19.0.2-canary.13",
"version": "19.1.0",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Now",
@@ -62,13 +62,13 @@
"node": ">= 10"
},
"dependencies": {
"@vercel/build-utils": "2.3.2-canary.4",
"@vercel/go": "1.1.2-canary.2",
"@vercel/next": "2.6.3-canary.6",
"@vercel/node": "1.6.2-canary.5",
"@vercel/python": "1.2.2-canary.2",
"@vercel/ruby": "1.2.2-canary.1",
"@vercel/static-build": "0.17.2-canary.1"
"@vercel/build-utils": "2.4.0",
"@vercel/go": "1.1.2",
"@vercel/next": "2.6.6",
"@vercel/node": "1.7.0",
"@vercel/python": "1.2.2",
"@vercel/ruby": "1.2.2",
"@vercel/static-build": "0.17.2"
},
"devDependencies": {
"@sentry/node": "5.5.0",
@@ -106,7 +106,7 @@
"@zeit/fun": "0.11.2",
"@zeit/ncc": "0.18.5",
"@zeit/source-map-support": "0.6.2",
"ajv": "6.10.2",
"ajv": "6.12.2",
"alpha-sort": "2.0.1",
"ansi-escapes": "3.0.0",
"ansi-regex": "3.0.0",
@@ -136,6 +136,7 @@
"escape-html": "1.0.3",
"esm": "3.1.4",
"execa": "3.2.0",
"fast-deep-equal": "3.1.3",
"fs-extra": "7.0.1",
"get-port": "5.1.1",
"glob": "7.1.2",

View File

@@ -39,7 +39,6 @@ import {
} from '../../util/errors-ts';
import { SchemaValidationFailed } from '../../util/errors';
import purchaseDomainIfAvailable from '../../util/domains/purchase-domain-if-available';
import isWildcardAlias from '../../util/alias/is-wildcard-alias';
import confirm from '../../util/input/confirm';
import editProjectSettings from '../../util/input/edit-project-settings';
import {
@@ -56,6 +55,7 @@ import validatePaths, {
} from '../../util/validate-paths';
import { readLocalConfig } from '../../util/config/files';
import { getCommandName } from '../../util/pkg-name.ts';
import { getPreferredPreviewURL } from '../../util/deploy/get-preferred-preview-url.ts';
const addProcessEnv = async (log, env) => {
let val;
@@ -87,6 +87,7 @@ const addProcessEnv = async (log, env) => {
const printDeploymentStatus = async (
output,
client,
{
readyState,
alias: aliasList,
@@ -119,18 +120,14 @@ const printDeploymentStatus = async (
let previewUrl;
let isWildcard;
if (!isFile && Array.isArray(aliasList) && aliasList.length > 0) {
// search for a non now.sh/non wildcard domain
// but fallback to the first alias in the list
const mainAlias =
aliasList.find(
alias =>
!alias.endsWith('.now.sh') &&
!alias.endsWith('.vercel.app') &&
!isWildcardAlias(alias)
) || aliasList[0];
isWildcard = isWildcardAlias(mainAlias);
previewUrl = isWildcard ? mainAlias : `https://${mainAlias}`;
const previewUrlInfo = await getPreferredPreviewURL(client, aliasList);
if (previewUrlInfo) {
isWildcard = previewUrlInfo.isWildcard;
previewUrl = previewUrlInfo.previewUrl;
} else {
isWildcard = false;
previewUrl = `https://${deploymentUrl}`;
}
} else {
// fallback to deployment url
isWildcard = false;
@@ -706,6 +703,12 @@ export default async function main(
return printDeploymentStatus(
output,
new Client({
apiUrl: ctx.apiUrl,
token: ctx.authConfig.token,
currentTeam: org.type === 'team' ? org.id : null,
debug: debugEnabled,
}),
deployment,
deployStamp,
!argv['--no-clipboard'],

View File

@@ -119,7 +119,7 @@ export default async function main(ctx: NowContext) {
try {
return await dev(ctx, argv, args, output);
} catch (err) {
output.error(err.message);
output.prettyError(err);
output.debug(stringifyError(err));
return 1;
}

View File

@@ -1,8 +1,8 @@
import chalk from 'chalk';
import table from 'text-table';
import mri from 'mri';
import ms from 'ms';
import strlen from '../util/strlen';
import getArgs from '../util/get-args';
import { handleError, error } from '../util/error';
import exit from '../util/exit';
import Client from '../util/client.ts';
@@ -11,7 +11,6 @@ import getScope from '../util/get-scope';
import createOutput from '../util/output';
import getCommandFlags from '../util/get-command-flags';
import wait from '../util/output/wait';
import getPrefixedFlags from '../util/get-prefixed-flags';
import { getPkgName, getCommandName } from '../util/pkg-name.ts';
const e = encodeURIComponent;
@@ -56,23 +55,25 @@ let apiUrl;
let subcommand;
const main = async ctx => {
argv = mri(ctx.argv.slice(2), {
boolean: ['help'],
alias: {
help: 'h',
next: 'N',
},
});
try {
argv = getArgs(ctx.argv.slice(2), {
'--next': Number,
'-N': '--next',
});
} catch (error) {
handleError(error);
return exit(1);
}
argv._ = argv._.slice(1);
debug = argv.debug;
debug = argv['--debug'];
apiUrl = ctx.apiUrl;
subcommand = argv._[0];
subcommand = argv._[0] || 'list';
if (argv.help || !subcommand) {
if (argv['--help']) {
help();
await exit(0);
return exit(2);
}
const output = createOutput({ debug });
@@ -126,15 +127,16 @@ async function run({ client, contextName }) {
)}`
)
);
return exit(1);
return exit(2);
}
const stopSpinner = wait(`Fetching projects in ${chalk.bold(contextName)}`);
let projectsUrl = '/v4/projects/?limit=20';
if (argv.next) {
projectsUrl += `&until=${argv.next}`;
const next = argv['--next'];
if (next) {
projectsUrl += `&until=${next}`;
}
const { projects: list, pagination } = await client.fetch(projectsUrl, {
@@ -175,14 +177,7 @@ async function run({ client, contextName }) {
}
if (pagination && pagination.count === 20) {
const prefixedArgs = getPrefixedFlags(argv);
const flags = getCommandFlags(prefixedArgs, [
'_',
'--next',
'-N',
'-d',
'-y',
]);
const flags = getCommandFlags(argv, ['_', '--next', '-N', '-d', '-y']);
const nextCmd = `projects ls${flags} --next ${pagination.next}`;
console.log(`To display the next page run ${getCommandName(nextCmd)}`);
}
@@ -271,7 +266,7 @@ async function run({ client, contextName }) {
console.error(error('Please specify a valid subcommand: ls | add | rm'));
help();
exit(1);
exit(2);
}
process.on('uncaughtException', err => {

View File

@@ -24,6 +24,7 @@ import checkForUpdate from 'update-check';
import ms from 'ms';
import { URL } from 'url';
import * as Sentry from '@sentry/node';
import { NowBuildError } from '@vercel/build-utils';
import getGlobalPathConfig from './util/config/global-path';
import {
getDefaultConfig,
@@ -114,10 +115,10 @@ const main = async argv_ => {
}
if (
localConfig instanceof NowError &&
(localConfig instanceof NowError || localConfig instanceof NowBuildError) &&
!(localConfig instanceof ERRORS.CantFindConfig)
) {
output.error(`Failed to load local config file: ${localConfig.message}`);
output.prettyError(localConfig);
return 1;
}
@@ -644,27 +645,6 @@ const main = async argv_ => {
)} could not be resolved. Please verify your internet connectivity and DNS configuration.`
);
output.debug(err.stack);
return 1;
}
await reportError(Sentry, err, apiUrl, configFiles);
// If there is a code we should not consider the error unexpected
// but instead show the message. Any error that is handled by this should
// actually be handled in the sub command instead. Please make sure
// that happens for anything that lands here. It should NOT bubble up to here.
if (err.code) {
output.debug(err.stack);
output.error(err.message);
if (shouldCollectMetrics) {
metric
.event(eventCategory, '1', pkg.version)
.exception(err.message)
.send();
}
return 1;
}
@@ -675,9 +655,23 @@ const main = async argv_ => {
.send();
}
// Otherwise it is an unexpected error and we should show the trace
// and an unexpected error message
output.error(`An unexpected error occurred in ${subcommand}: ${err.stack}`);
// If there is a code we should not consider the error unexpected
// but instead show the message. Any error that is handled by this should
// actually be handled in the sub command instead. Please make sure
// that happens for anything that lands here. It should NOT bubble up to here.
if (err.code) {
output.debug(err.stack);
output.prettyError(err);
} else {
await reportError(Sentry, err, apiUrl, configFiles);
// Otherwise it is an unexpected error and we should show the trace
// and an unexpected error message
output.error(
`An unexpected error occurred in ${subcommand}: ${err.stack}`
);
}
return 1;
}
@@ -688,8 +682,6 @@ const main = async argv_ => {
return exitCode;
};
debug('start');
const handleRejection = async err => {
debug('handling rejection');

View File

@@ -0,0 +1,17 @@
import { stringify } from 'querystring';
import { Cert } from '../../types';
import Client from '../client';
/**
* Returns certs that contain @param cn.
*/
export async function getCertsForCn(
client: Client,
cn: string,
{ limit }: { limit?: number } = {}
) {
const { certs } = await client.fetch<{
certs: Cert[];
}>(`/v4/now/certs?${stringify({ cn, ...(limit ? { limit } : {}) })}`);
return certs;
}

View File

@@ -24,7 +24,7 @@ export default class Client extends EventEmitter {
_withCache: boolean;
_output: Output;
_token: string;
currentTeam?: string;
currentTeam?: string | null;
constructor({
apiUrl,
@@ -36,7 +36,7 @@ export default class Client extends EventEmitter {
}: {
apiUrl: string;
token: string;
currentTeam?: string;
currentTeam?: string | null;
forceNew?: boolean;
withCache?: boolean;
debug?: boolean;

View File

@@ -0,0 +1,48 @@
import isWildcardAlias from '../alias/is-wildcard-alias';
import { getCertsForCn } from '../certs/get-certs-for-cn';
import Client from '../client';
/**
* Tries to find the "best" alias url.
* @param aliasList
*/
export async function getPreferredPreviewURL(
client: Client,
aliasList: string[]
) {
if (aliasList.length === 0) {
return null;
}
/**
* First checks for non public aliases and non wildcard domains.
*/
const preferredAliases = aliasList.filter(
alias =>
!alias.endsWith('.now.sh') &&
!alias.endsWith('.vercel.app') &&
!isWildcardAlias(alias)
);
for (const alias of preferredAliases) {
const certs = await getCertsForCn(client, alias, { limit: 1 }).catch(() => {
return null;
});
if (certs && certs.length > 0) {
return { previewUrl: `https://${alias}`, isWildcard: false };
}
}
/**
* Fallback to first alias
*/
const [firstAlias] = aliasList;
if (isWildcardAlias(firstAlias)) {
return { previewUrl: firstAlias, isWildcard: true };
}
if (firstAlias.endsWith('.vercel.app') || firstAlias.endsWith('.now.sh')) {
return { previewUrl: `https://${firstAlias}`, isWildcard: false };
}
return { previewUrl: `http://${firstAlias}`, isWildcard: false };
}

View File

@@ -3,9 +3,9 @@ import semver from 'semver';
import npa from 'npm-package-arg';
import pluralize from 'pluralize';
import { basename, join } from 'path';
import { PackageJson } from '@vercel/build-utils';
import XDGAppPaths from 'xdg-app-paths';
import { mkdirp, readJSON, writeJSON } from 'fs-extra';
import { NowBuildError, PackageJson } from '@vercel/build-utils';
import cliPkg from '../pkg';
import { NoBuilderCacheError } from '../errors-ts';
@@ -232,21 +232,41 @@ async function npmInstall(
output.debug(`Running npm install in ${cwd}`);
try {
await execa(
'npm',
[
'install',
'--save-exact',
'--no-package-lock',
'--no-audit',
'--no-progress',
...sortedPackages,
],
{
cwd,
stdio: output.isDebugEnabled() ? 'inherit' : undefined,
const args = [
'install',
'--save-exact',
'--no-package-lock',
'--no-audit',
'--no-progress',
];
if (process.stderr.isTTY) {
// Force colors in the npm child process
// https://docs.npmjs.com/misc/config#color
args.push('--color=always');
}
args.push(...sortedPackages);
const result = await execa('npm', args, {
cwd,
reject: false,
stdio: output.isDebugEnabled() ? 'inherit' : 'pipe',
});
if (result.failed) {
stopSpinner();
if (result.stdout) {
console.log(result.stdout);
}
);
if (result.stderr) {
console.error(result.stderr);
}
throw new NowBuildError({
message:
(result as any).code === 'ENOENT'
? '`npm` is not installed'
: 'Failed to install `vercel dev` dependencies',
code: 'NPM_INSTALL_ERROR',
link: 'https://vercel.link/npm-install-failed-dev',
});
}
} finally {
stopSpinner();
}

View File

@@ -18,6 +18,7 @@ import directoryTemplate from 'serve-handler/src/directory';
import getPort from 'get-port';
import { ChildProcess } from 'child_process';
import isPortReachable from 'is-port-reachable';
import deepEqual from 'fast-deep-equal';
import which from 'which';
import { getVercelIgnore, fileNameSymbol } from '@vercel/client';
@@ -114,6 +115,7 @@ export default class DevServer {
public cwd: string;
public debug: boolean;
public output: Output;
public proxy: httpProxy;
public envConfigs: EnvConfigs;
public frameworkSlug: string | null;
public files: BuilderInputs;
@@ -124,7 +126,6 @@ export default class DevServer {
private caseSensitive: boolean;
private apiDir: string | null;
private apiExtensions: Set<string>;
private proxy: httpProxy;
private server: http.Server;
private stopping: boolean;
private buildMatches: Map<string, BuildMatch>;
@@ -234,8 +235,18 @@ export default class DevServer {
}
}
// Update the build matches in case an entrypoint was created or deleted
const nowConfig = await this.getNowConfig(false);
// Update the env vars configuration
const nowConfigBuild = nowConfig.build || {};
const [runEnv, buildEnv] = await Promise.all([
this.getLocalEnv('.env', nowConfig.env),
this.getLocalEnv('.env.build', nowConfigBuild.env),
]);
const allEnv = { ...buildEnv, ...runEnv };
this.envConfigs = { buildEnv, runEnv, allEnv };
// Update the build matches in case an entrypoint was created or deleted
await this.updateBuildMatches(nowConfig);
const filesChangedArray = [...filesChanged];
@@ -400,7 +411,7 @@ export default class DevServer {
const blockingBuilds: Promise<void>[] = [];
for (const match of matches) {
const currentMatch = this.buildMatches.get(match.src);
if (!currentMatch || currentMatch.use !== match.use) {
if (!buildMatchEquals(currentMatch, match)) {
this.output.debug(
`Adding build match for "${match.src}" with "${match.use}"`
);
@@ -522,18 +533,11 @@ export default class DevServer {
// The default empty `vercel.json` is used to serve all files as static
// when no `vercel.json` is present
let configPath = 'vercel.json';
let config: NowConfig = this.cachedNowConfig || {
let config: NowConfig = {
version: 2,
[fileNameSymbol]: configPath,
};
// We need to delete these properties for zero config to work
// with file changes
if (this.cachedNowConfig) {
delete this.cachedNowConfig.builds;
delete this.cachedNowConfig.routes;
}
try {
configPath = getNowConfigPath(this.cwd);
this.output.debug(`Reading ${configPath}`);
@@ -564,7 +568,7 @@ export default class DevServer {
nowConfig: config,
});
if (routeError) {
this.output.error(routeError.message, null, routeError.link);
this.output.prettyError(routeError);
await this.exit();
}
config.routes = maybeRoutes || [];
@@ -773,7 +777,6 @@ export default class DevServer {
this.getLocalEnv('.env.build', nowConfigBuild.env),
]);
const allEnv = { ...buildEnv, ...runEnv };
Object.assign(process.env, allEnv);
this.envConfigs = { buildEnv, runEnv, allEnv };
const opts = { output: this.output, isBuilds: true };
@@ -1367,7 +1370,7 @@ export default class DevServer {
debug(`ProxyPass: ${destUrl}`);
this.setResponseHeaders(res, nowRequestId);
return proxyPass(req, res, destUrl, this.proxy, this.output);
return proxyPass(req, res, destUrl, this, nowRequestId);
}
match = await findBuildMatch(
@@ -1506,8 +1509,8 @@ export default class DevServer {
req,
res,
`http://localhost:${this.devProcessPort}`,
this.proxy,
this.output,
this,
nowRequestId,
false
);
}
@@ -1626,8 +1629,8 @@ export default class DevServer {
req,
res,
`http://localhost:${port}`,
this.proxy,
this.output,
this,
nowRequestId,
false
);
} else {
@@ -1656,8 +1659,8 @@ export default class DevServer {
req,
res,
`http://localhost:${this.devProcessPort}`,
this.proxy,
this.output,
this,
nowRequestId,
false
);
}
@@ -1967,24 +1970,27 @@ function proxyPass(
req: http.IncomingMessage,
res: http.ServerResponse,
dest: string,
proxy: httpProxy,
output: Output,
devServer: DevServer,
nowRequestId: string,
ignorePath: boolean = true
): void {
return proxy.web(
return devServer.proxy.web(
req,
res,
{ target: dest, ignorePath },
(error: NodeJS.ErrnoException) => {
// If the client hangs up a socket, we do not
// want to do anything, as the client just expects
// the connection to be closed.
if (error.code === 'ECONNRESET') {
res.end();
return;
devServer.output.error(
`Failed to complete request to ${req.url}: ${error}`
);
if (!res.headersSent) {
devServer.sendError(
req,
res,
nowRequestId,
'NO_RESPONSE_FROM_FUNCTION',
502
);
}
output.error(`Failed to complete request to ${req.url}: ${error}`);
}
);
}
@@ -2258,3 +2264,11 @@ function hasNewRoutingProperties(nowConfig: NowConfig) {
typeof nowConfig.trailingSlash !== undefined
);
}
function buildMatchEquals(a?: BuildMatch, b?: BuildMatch): boolean {
if (!a || !b) return false;
if (a.src !== b.src) return false;
if (a.use !== b.use) return false;
if (!deepEqual(a.config || {}, b.config || {})) return false;
return true;
}

View File

@@ -1,5 +1,6 @@
import bytes from 'bytes';
import { Response } from 'node-fetch';
import { NowBuildError } from '@vercel/build-utils';
import { NowError } from './now-error';
import code from './output/code';
import { getCommandName } from './pkg-name';
@@ -771,17 +772,17 @@ export class CantParseJSONFile extends NowError<
}
}
export class ConflictingConfigFiles extends NowError<
'CONFLICTING_CONFIG_FILES',
{ files: string[] }
> {
export class ConflictingConfigFiles extends NowBuildError {
files: string[];
constructor(files: string[]) {
super({
code: 'CONFLICTING_CONFIG_FILES',
meta: { files },
message:
'Cannot use both a `vercel.json` and `now.json` file. Please delete the `now.json` file.',
link: 'https://vercel.link/combining-old-and-new-config',
});
this.files = files;
}
}

View File

@@ -2,6 +2,7 @@ import chalk from 'chalk';
import boxen from 'boxen';
import { format } from 'util';
import { Console } from 'console';
import renderLink from './link';
import wait from './wait';
export type Output = ReturnType<typeof createOutput>;
@@ -41,7 +42,7 @@ export default function createOutput({ debug: debugEnabled = false } = {}) {
boxen(
chalk.bold.yellow('WARN! ') +
str +
(details ? `\nMore details: ${details}` : ''),
(details ? `\nMore details: ${renderLink(details)}` : ''),
{
padding: {
top: 0,
@@ -64,17 +65,21 @@ export default function createOutput({ debug: debugEnabled = false } = {}) {
function error(
str: string,
slug: string | null = null,
link: string | null = null,
slug?: string,
link?: string,
action = 'More details'
) {
print(`${chalk.red(`Error!`)} ${str}\n`);
const details = slug ? `https://err.sh/now/${slug}` : link;
if (details) {
print(`${action}: ${details}\n`);
print(`${chalk.bold(action)}: ${renderLink(details)}\n`);
}
}
function prettyError(err: Error & { link?: string; action?: string }) {
return error(err.message, undefined, err.link, err.action);
}
function ready(str: string) {
print(`${chalk.cyan('> Ready!')} ${str}\n`);
}
@@ -107,8 +112,6 @@ export default function createOutput({ debug: debugEnabled = false } = {}) {
return wait(message, delay);
}
// This is pretty hacky, but since we control the version of Node.js
// being used because of `pkg` it's safe to do in this case.
const c = {
_times: new Map(),
log(a: string, ...args: string[]) {
@@ -135,6 +138,7 @@ export default function createOutput({ debug: debugEnabled = false } = {}) {
log,
warn,
error,
prettyError,
ready,
success,
debug,

View File

@@ -1,6 +1,7 @@
import chalk from 'chalk';
import { metrics, shouldCollectMetrics } from '../metrics';
import { APIError } from '../errors-ts';
import renderLink from './link';
const metric = metrics();
@@ -9,10 +10,9 @@ export default function error(...input: string[] | [APIError]) {
if (typeof input[0] === 'object') {
const { slug, message, link } = input[0];
messages = [message];
if (slug) {
messages.push(`> More details: https://err.sh/now/${slug}`);
} else if (link) {
messages.push(`> More details: ${link}`);
const details = slug ? `https://err.sh/now/${slug}` : link;
if (details) {
messages.push(`${chalk.bold('More details')}: ${renderLink(details)}`);
}
}

View File

@@ -14,7 +14,7 @@ import chalk from 'chalk';
import { prependEmoji, emoji } from '../emoji';
import AJV from 'ajv';
import { isDirectory } from '../config/global-path';
import { getPlatformEnv } from '@vercel/build-utils';
import { NowBuildError, getPlatformEnv } from '@vercel/build-utils';
const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);
@@ -49,9 +49,12 @@ export function getVercelDirectory(cwd: string = process.cwd()): string {
const possibleDirs = [join(cwd, VERCEL_DIR), join(cwd, VERCEL_DIR_FALLBACK)];
const existingDirs = possibleDirs.filter(d => isDirectory(d));
if (existingDirs.length > 1) {
throw new Error(
'Both `.vercel` and `.now` directories exist. Please remove the `.now` directory.'
);
throw new NowBuildError({
code: 'CONFLICTING_CONFIG_DIRECTORIES',
message:
'Both `.vercel` and `.now` directories exist. Please remove the `.now` directory.',
link: 'https://vercel.link/combining-old-and-new-config',
});
}
return existingDirs[0] || possibleDirs[0];
}

View File

@@ -0,0 +1 @@
.vercel

View File

@@ -0,0 +1,3 @@
export default function(req, res) {
res.end('Force "module: commonjs" JavaScript with ES Modules API endpoint');
}

View File

@@ -0,0 +1,5 @@
import { IncomingMessage, ServerResponse } from 'http';
export default function(req: IncomingMessage, res: ServerResponse) {
res.end('Force "module: commonjs" TypeScript API endpoint');
}

View File

@@ -0,0 +1,2 @@
/// <reference types="next" />
/// <reference types="next/types/global" />

View File

@@ -0,0 +1,19 @@
{
"name": "force-module-commonjs",
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "^9.3.4",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"@types/node": "14.0.9",
"@types/react": "^16.9.32",
"typescript": "^3.8.3"
}
}

View File

@@ -0,0 +1,3 @@
export default function () {
return <div>Force "module: commonjs" test page</div>;
}

View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"baseUrl": ".",
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"paths": {
"@components/*": ["components/*"],
"@lib/*": ["lib/*"]
}
},
"exclude": ["node_modules", "api"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
export default (req, res) => {
res.send(process.env);
};

View File

@@ -0,0 +1 @@
{ "env": { "FOO": "bar" } }

View File

@@ -0,0 +1,10 @@
export default (req, res) => {
const hasHelpers = typeof req.query !== 'undefined';
res.setHeader('Content-Type', 'application/json');
res.end(
JSON.stringify({
hasHelpers,
query: req.query,
})
);
};

View File

@@ -0,0 +1 @@
{ "builds": [{ "src": "index.js", "use": "@vercel/node@canary" }] }

View File

@@ -0,0 +1,3 @@
{
"builds": [{ "src": "*.js", "use": "@vercel/does-not-exist" }]
}

View File

@@ -161,7 +161,7 @@ async function testPath(
Object.entries(headers).forEach(([key, expectedValue]) => {
let actualValue = res.headers.get(key);
if (key.toLowerCase() === 'location' && actualValue === '//') {
// HACK: `node-fetch` has strang behavior for location header so fix it
// HACK: `node-fetch` has strange behavior for location header so fix it
// with `manual-dont-change` opt and convert double slash to single.
// See https://github.com/node-fetch/node-fetch/issues/417#issuecomment-587233352
actualValue = '/';
@@ -187,20 +187,29 @@ async function testFixture(directory, opts = {}, args = []) {
}
);
const stdoutList = [];
const stderrList = [];
let stdout = '';
let stderr = '';
const readyResolver = createResolver();
const exitResolver = createResolver();
dev.stderr.on('data', data => stderrList.push(Buffer.from(data)));
dev.stdout.on('data', data => stdoutList.push(Buffer.from(data)));
dev.stdout.setEncoding('utf8');
dev.stderr.setEncoding('utf8');
dev.stdout.on('data', data => {
stdout += data;
});
dev.stderr.on('data', data => {
stderr += data;
if (stderr.includes('Ready! Available at')) {
readyResolver.resolve();
}
});
let printedOutput = false;
dev.on('exit', () => {
if (!printedOutput) {
const stdout = Buffer.concat(stdoutList).toString();
const stderr = Buffer.concat(stderrList).toString();
printOutput(directory, stdout, stderr);
printedOutput = true;
}
@@ -209,8 +218,6 @@ async function testFixture(directory, opts = {}, args = []) {
dev.on('error', () => {
if (!printedOutput) {
const stdout = Buffer.concat(stdoutList).toString();
const stderr = Buffer.concat(stderrList).toString();
printOutput(directory, stdout, stderr);
printedOutput = true;
}
@@ -226,6 +233,7 @@ async function testFixture(directory, opts = {}, args = []) {
return {
dev,
port,
readyResolver,
};
}
@@ -267,14 +275,12 @@ function testFixtureStdio(
await runNpmInstall(cwd);
const stdoutList = [];
const stderrList = [];
let stdout = '';
let stderr = '';
const readyResolver = createResolver();
const exitResolver = createResolver();
try {
let stderr = '';
let printedOutput = false;
const env = skipDeploy
@@ -285,17 +291,19 @@ function testFixtureStdio(
env,
});
dev.stdout.setEncoding('utf8');
dev.stderr.setEncoding('utf8');
dev.stdout.pipe(process.stdout);
dev.stderr.pipe(process.stderr);
dev.stdout.on('data', data => {
stdoutList.push(data);
stdout += data;
});
dev.stderr.on('data', data => {
stderrList.push(data);
stderr += data;
stderr += data.toString();
if (stderr.includes('Ready! Available at')) {
readyResolver.resolve();
}
@@ -315,8 +323,6 @@ function testFixtureStdio(
dev.on('exit', () => {
if (!printedOutput) {
const stdout = Buffer.concat(stdoutList).toString();
const stderr = Buffer.concat(stderrList).toString();
printOutput(directory, stdout, stderr);
printedOutput = true;
}
@@ -325,8 +331,6 @@ function testFixtureStdio(
dev.on('error', () => {
if (!printedOutput) {
const stdout = Buffer.concat(stdoutList).toString();
const stderr = Buffer.concat(stderrList).toString();
printOutput(directory, stdout, stderr);
printedOutput = true;
}
@@ -375,6 +379,153 @@ test.afterEach(async () => {
);
});
test('[vercel dev] prints `npm install` errors', async t => {
const dir = fixture('runtime-not-installed');
const result = await exec(dir);
t.truthy(result.stderr.includes('npm ERR! 404'));
t.truthy(
result.stderr.includes('Failed to install `vercel dev` dependencies')
);
t.truthy(
result.stderr.includes('https://vercel.link/npm-install-failed-dev')
);
});
test('[vercel dev] `vercel.json` should be invalidated if deleted', async t => {
const dir = fixture('invalidate-vercel-config');
const configPath = join(dir, 'vercel.json');
const originalConfig = await fs.readJSON(configPath);
const { dev, port, readyResolver } = await testFixture(dir);
try {
await readyResolver;
{
// Env var should be set from `vercel.json`
const res = await fetch(`http://localhost:${port}/api`);
const body = await res.json();
t.is(body.FOO, 'bar');
}
{
// Env var should not be set after `vercel.json` is deleted
await fs.remove(configPath);
await sleep(1000);
const res = await fetch(`http://localhost:${port}/api`);
const body = await res.json();
t.is(body.FOO, undefined);
}
} finally {
await dev.kill('SIGTERM');
await fs.writeJSON(configPath, originalConfig);
}
});
test('[vercel dev] reflects changes to config and env without restart', async t => {
const dir = fixture('node-helpers');
const configPath = join(dir, 'vercel.json');
const originalConfig = await fs.readJSON(configPath);
const { dev, port, readyResolver } = await testFixture(dir);
try {
await readyResolver;
{
// Node.js helpers should be available by default
const res = await fetch(`http://localhost:${port}/?foo=bar`);
const body = await res.json();
t.is(body.hasHelpers, true);
t.is(body.query.foo, 'bar');
}
{
// Disable the helpers via `config.helpers = false`
const config = {
...originalConfig,
builds: [
{
...originalConfig.builds[0],
config: {
helpers: false,
},
},
],
};
await fs.writeJSON(configPath, config);
await sleep(1000);
const res = await fetch(`http://localhost:${port}/?foo=bar`);
const body = await res.json();
t.is(body.hasHelpers, false);
t.is(body.query, undefined);
}
{
// Enable the helpers via `config.helpers = true`
const config = {
...originalConfig,
builds: [
{
...originalConfig.builds[0],
config: {
helpers: true,
},
},
],
};
await fs.writeJSON(configPath, config);
await sleep(1000);
const res = await fetch(`http://localhost:${port}/?foo=baz`);
const body = await res.json();
t.is(body.hasHelpers, true);
t.is(body.query.foo, 'baz');
}
{
// Disable the helpers via `NODEJS_HELPERS = '0'`
const config = {
...originalConfig,
build: {
env: {
NODEJS_HELPERS: '0',
},
},
};
await fs.writeJSON(configPath, config);
await sleep(1000);
const res = await fetch(`http://localhost:${port}/?foo=baz`);
const body = await res.json();
t.is(body.hasHelpers, false);
t.is(body.query, undefined);
}
{
// Enable the helpers via `NODEJS_HELPERS = '1'`
const config = {
...originalConfig,
build: {
env: {
NODEJS_HELPERS: '1',
},
},
};
await fs.writeJSON(configPath, config);
await sleep(1000);
const res = await fetch(`http://localhost:${port}/?foo=boo`);
const body = await res.json();
t.is(body.hasHelpers, true);
t.is(body.query.foo, 'boo');
}
} finally {
await dev.kill('SIGTERM');
await fs.writeJSON(configPath, originalConfig);
}
});
test(
'[vercel dev] validate routes that use `check: true`',
testFixtureStdio('routes-check-true', async testPath => {
@@ -482,19 +633,15 @@ test(
test(
'[vercel dev] should serve the public directory and api functions',
testFixtureStdio(
'public-and-api',
async testPath => {
await testPath(200, '/', 'This is the home page');
await testPath(200, '/about.html', 'This is the about page');
await testPath(200, '/api/date', /current date/);
await testPath(200, '/api/rand', /random number/);
await testPath(200, '/api/rand.js', /random number/);
await testPath(404, '/api/api', /NOT_FOUND/m);
await testPath(404, '/nothing', /Custom 404 Page/);
},
{ skipDeploy: true /** TODO: remove after prod goes live */ }
)
testFixtureStdio('public-and-api', async testPath => {
await testPath(200, '/', 'This is the home page');
await testPath(200, '/about.html', 'This is the about page');
await testPath(200, '/api/date', /current date/);
await testPath(200, '/api/rand', /random number/);
await testPath(200, '/api/rand.js', /random number/);
await testPath(404, '/api/api', /NOT_FOUND/m);
await testPath(404, '/nothing', /Custom 404 Page/);
})
);
test(
@@ -694,17 +841,13 @@ test(
test(
'[vercel dev] should serve custom 404 when `cleanUrls: true`',
testFixtureStdio(
'test-clean-urls-custom-404',
async testPath => {
await testPath(200, '/', 'This is the home page');
await testPath(200, '/about', 'The about page');
await testPath(200, '/contact/me', 'Contact Me Subdirectory');
await testPath(404, '/nothing', 'Custom 404 Page');
await testPath(404, '/nothing/', 'Custom 404 Page');
},
{ skipDeploy: true /** TODO: remove after prod goes live */ }
)
testFixtureStdio('test-clean-urls-custom-404', async testPath => {
await testPath(200, '/', 'This is the home page');
await testPath(200, '/about', 'The about page');
await testPath(200, '/contact/me', 'Contact Me Subdirectory');
await testPath(404, '/nothing', 'Custom 404 Page');
await testPath(404, '/nothing/', 'Custom 404 Page');
})
);
test(
@@ -777,16 +920,12 @@ test(
test(
'[vercel dev] should serve custom 404 when `trailingSlash: true`',
testFixtureStdio(
'test-trailing-slash-custom-404',
async testPath => {
await testPath(200, '/', 'This is the home page');
await testPath(200, '/about.html', 'The about page');
await testPath(200, '/contact/', 'Contact Subdirectory');
await testPath(404, '/nothing/', 'Custom 404 Page');
},
{ skipDeploy: true /** TODO: remove after prod goes live */ }
)
testFixtureStdio('test-trailing-slash-custom-404', async testPath => {
await testPath(200, '/', 'This is the home page');
await testPath(200, '/about.html', 'The about page');
await testPath(200, '/contact/', 'Contact Subdirectory');
await testPath(404, '/nothing/', 'Custom 404 Page');
})
);
test(
@@ -1403,6 +1542,23 @@ test(
})
);
test(
'[vercel dev] Should force `tsc` option "module: commonjs" for `startDevServer()`',
testFixtureStdio('force-module-commonjs', async testPath => {
await testPath(200, `/`, /Force &quot;module: commonjs&quot; test page/);
await testPath(
200,
`/api`,
'Force "module: commonjs" JavaScript with ES Modules API endpoint'
);
await testPath(
200,
`/api/ts`,
'Force "module: commonjs" TypeScript API endpoint'
);
})
);
test(
'[vercel dev] should prioritize index.html over other file named index.*',
testFixtureStdio('index-html-priority', async testPath => {

View File

@@ -1589,7 +1589,7 @@ test('create a staging deployment', async t => {
/Setting target to staging/gm,
formatOutput(targetCall)
);
t.regex(targetCall.stdout, /https:\/\//gm);
t.is(targetCall.exitCode, 0, formatOutput(targetCall));
const { host } = new URL(targetCall.stdout);
@@ -1625,6 +1625,7 @@ test('create a production deployment', async t => {
/Setting target to production/gm,
formatOutput(targetCall)
);
t.regex(targetCall.stdout, /https:\/\//gm);
const { host: targetHost } = new URL(targetCall.stdout);
const targetDeployment = await apiFetch(
@@ -1648,6 +1649,7 @@ test('create a production deployment', async t => {
/Setting target to production/gm,
formatOutput(targetCall)
);
t.regex(call.stdout, /https:\/\//gm);
const { host } = new URL(call.stdout);
const deployment = await apiFetch(
@@ -2916,3 +2918,19 @@ test('reject conflicting `vercel.json` and `now.json` files', async t => {
formatOutput({ stderr, stdout })
);
});
test('`vc --debug project ls` should output the projects listing', async t => {
const { exitCode, stderr, stdout } = await execa(
binaryPath,
[...defaultArgs, '--debug', 'project', 'ls'],
{
reject: false,
}
);
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
t.true(
stdout.includes('> Projects found under'),
formatOutput({ stderr, stdout })
);
});

View File

@@ -3,4 +3,6 @@ lib
node_modules
*.log
!tests/fixtures/nowignore/node_modules
!tests/fixtures/nowignore/node_modules
!tests/fixtures/vercelignore-allow-nodemodules/node_modules
!tests/fixtures/vercelignore-allow-nodemodules/sub/node_modules

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "8.0.2-canary.2",
"version": "8.1.0",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://vercel.com",

View File

@@ -93,6 +93,16 @@ export async function* checkDeploymentStatus(
}
if (isAliasAssigned(deploymentUpdate)) {
if (
deploymentUpdate.aliasWarning &&
deploymentUpdate.aliasWarning.message
) {
yield {
type: 'warning',
payload: deploymentUpdate.aliasWarning.message,
};
}
debug('Deployment alias assigned');
return yield { type: 'alias-assigned', payload: deploymentUpdate };
}

View File

@@ -7,6 +7,7 @@ import qs from 'querystring';
import ignore from 'ignore';
type Ignore = ReturnType<typeof ignore>;
import { pkgVersion } from '../pkg';
import { NowBuildError } from '@vercel/build-utils';
import { NowClientOptions, DeploymentOptions, NowConfig } from '../types';
import { Sema } from 'async-sema';
import { readFile } from 'fs-extra';
@@ -48,7 +49,7 @@ export function getApiDeploymentsUrl(
return '/v10/now/deployments';
}
return '/v12/now/deployments';
return '/v13/now/deployments';
}
export async function parseVercelConfig(filePath?: string): Promise<NowConfig> {
@@ -76,43 +77,22 @@ const maybeRead = async function<T>(path: string, default_: T) {
}
};
export async function readdirRelative(
path: string,
ignores: string[],
cwd: string
): Promise<string[]> {
const preprocessedIgnores = ignores.map(ignore => {
if (ignore.endsWith('/')) {
return ignore.slice(0, -1);
}
return ignore;
});
const dirContents = await readdir(path, preprocessedIgnores);
return dirContents.map(filePath => relative(cwd, filePath));
}
export async function buildFileTree(
path: string | string[],
isDirectory: boolean,
debug: Debug
): Promise<string[]> {
// Get .nowignore
let { ig, ignores } = await getVercelIgnore(path);
debug(`Found ${ig.ignores.length} rules in .nowignore`);
let fileList: string[];
let { ig } = await getVercelIgnore(path);
debug(`Found ${ig.ignores.length} rules in .vercelignore`);
debug('Building file tree...');
if (isDirectory && !Array.isArray(path)) {
// Directory path
const cwd = process.cwd();
const relativeFileList = await readdirRelative(path, ignores, cwd);
fileList = ig
.filter(relativeFileList)
.map((relativePath: string) => join(cwd, relativePath));
const ignores = (absPath: string) => ig.ignores(relative(cwd, absPath));
fileList = await readdir(path, [ignores]);
debug(`Read ${fileList.length} files in the specified directory`);
} else if (Array.isArray(path)) {
// Array of file paths
@@ -166,9 +146,12 @@ export async function getVercelIgnore(
maybeRead(join(cwd, '.nowignore'), ''),
]);
if (vercelignore && nowignore) {
throw new Error(
'Cannot use both a `.vercelignore` and `.nowignore` file. Please delete the `.nowignore` file.'
);
throw new NowBuildError({
code: 'CONFLICTING_IGNORE_FILES',
message:
'Cannot use both a `.vercelignore` and `.nowignore` file. Please delete the `.nowignore` file.',
link: 'https://vercel.link/combining-old-and-new-config',
});
}
return vercelignore || nowignore;
})

View File

@@ -0,0 +1 @@
EXCLUDE="this file should be ignored"

View File

@@ -0,0 +1,6 @@
# literally dont ignore the node_modules directory
# so basically include the node_modules directory recursively
!node_modules/
# ignore this file in addition to the defaults
exclude.txt

View File

@@ -0,0 +1 @@
Should be ignored

View File

@@ -0,0 +1 @@
Hello World

View File

@@ -0,0 +1 @@
Should be included

View File

@@ -1,7 +1,8 @@
import path from 'path';
import { buildFileTree, getVercelIgnore, readdirRelative } from '../src/utils';
import { join, resolve } from 'path';
import { buildFileTree } from '../src/utils';
const ignoreFixturePath = path.resolve(__dirname, 'fixtures', 'nowignore');
const fixture = (name: string) => resolve(__dirname, 'fixtures', name);
const noop = () => {};
const normalizeWindowsPaths = (files: string[]) => {
if (process.platform === 'win32') {
@@ -10,34 +11,29 @@ const normalizeWindowsPaths = (files: string[]) => {
return files;
};
describe('buildFileTree', () => {
it('will include the correct files', async () => {
const expected = [
'tests/fixtures/nowignore/.nowignore',
'tests/fixtures/nowignore/index.txt',
].map(p => path.join(process.cwd(), p));
const actual = await buildFileTree(ignoreFixturePath, true, () => {});
expect(normalizeWindowsPaths(expected).sort()).toEqual(
normalizeWindowsPaths(actual).sort()
);
});
});
const toAbsolutePaths = (cwd: string, files: string[]) =>
files.map(p => join(cwd, p));
describe('readdirRelative', () => {
it('will ignore the hardcoded default ignores', async () => {
// most importantly, this method should not walk/include node_modules
const expected = [
'tests/fixtures/nowignore/.nowignore',
'tests/fixtures/nowignore/ignore.txt',
'tests/fixtures/nowignore/index.txt',
'tests/fixtures/nowignore/folder/ignore.txt',
];
const { ignores } = await getVercelIgnore(ignoreFixturePath);
const actual = await readdirRelative(
ignoreFixturePath,
ignores,
process.cwd()
describe('buildFileTree', () => {
it('should exclude files using `.nowignore` blocklist', async () => {
const cwd = fixture('nowignore');
const expected = toAbsolutePaths(cwd, ['.nowignore', 'index.txt']);
const actual = await buildFileTree(cwd, true, noop);
expect(normalizeWindowsPaths(expected).sort()).toEqual(
normalizeWindowsPaths(actual).sort()
);
});
it('should include the node_modules using `.vercelignore` allowlist', async () => {
const cwd = fixture('vercelignore-allow-nodemodules');
const expected = toAbsolutePaths(cwd, [
'node_modules/one.txt',
'sub/node_modules/two.txt',
'sub/include.txt',
'.vercelignore',
'hello.txt',
]);
const actual = await buildFileTree(cwd, true, noop);
expect(normalizeWindowsPaths(expected).sort()).toEqual(
normalizeWindowsPaths(actual).sort()
);

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/go",
"version": "1.1.2-canary.2",
"version": "1.1.2",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",

View File

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

View File

@@ -70,7 +70,7 @@ import {
syncEnvVars,
validateEntrypoint,
} from './utils';
import findUp from 'find-up';
// import findUp from 'find-up';
interface BuildParamsMeta {
isDev: boolean | undefined;
@@ -205,30 +205,6 @@ export const build = async ({
}> => {
validateEntrypoint(entrypoint);
const nowJsonPath = await findUp(['now.json', 'vercel.json'], {
type: 'file',
});
let hasLegacyRoutes = false;
if (nowJsonPath) {
const nowJsonData = JSON.parse(await readFile(nowJsonPath, 'utf8'));
if (Array.isArray(nowJsonData.routes) && nowJsonData.routes.length > 0) {
hasLegacyRoutes = true;
console.warn(
`WARNING: your application is being opted out of @vercel/next's optimized lambdas mode due to legacy routes in ${path.basename(
nowJsonPath
)}. http://err.sh/vercel/vercel/next-legacy-routes-optimized-lambdas`
);
}
}
// default to true but still allow opting out with the config
const isSharedLambdas =
!hasLegacyRoutes && typeof config.sharedLambdas === 'undefined'
? true
: !!config.sharedLambdas;
// Limit for max size each lambda can be, 50 MB if no custom limit
const lambdaCompressedByteLimit = config.maxLambdaSize || 50 * 1000 * 1000;
@@ -253,6 +229,48 @@ export const build = async ({
});
}
// let nowJsonPath = Object.keys(files).find(file => {
// return file.endsWith('now.json') || file.endsWith('vercel.json')
// })
// if (nowJsonPath) nowJsonPath = files[nowJsonPath].fsPath
// if (!nowJsonPath) {
// nowJsonPath = await findUp(['now.json', 'vercel.json'], {
// cwd: path.join(workPath, path.dirname(entrypoint))
// })
// }
// let hasLegacyRoutes = false;
// const hasFunctionsConfig = !!config.functions;
// if (nowJsonPath) {
// const nowJsonData = JSON.parse(await readFile(nowJsonPath, 'utf8'));
// if (Array.isArray(nowJsonData.routes) && nowJsonData.routes.length > 0) {
// hasLegacyRoutes = true;
// console.warn(
// `WARNING: your application is being opted out of @vercel/next's optimized lambdas mode due to legacy routes in ${path.basename(
// nowJsonPath
// )}. http://err.sh/vercel/vercel/next-legacy-routes-optimized-lambdas`
// );
// }
// }
// if (hasFunctionsConfig) {
// console.warn(
// `WARNING: Your application is being opted out of "@vercel/next" optimized lambdas mode due to \`functions\` config.\nMore info: http://err.sh/vercel/vercel/next-functions-config-optimized-lambdas`
// );
// }
// default to true but still allow opting out with the config
const isSharedLambdas = !!config.sharedLambdas;
// !hasLegacyRoutes &&
// !hasFunctionsConfig &&
// typeof config.sharedLambdas === 'undefined'
// ? true
// : !!config.sharedLambdas;
if (meta.isDev) {
let childProcess: ChildProcess | undefined;
@@ -1178,50 +1196,6 @@ export const build = async ({
);
if (isSharedLambdas) {
// since we combine the pages into lambda groups we need to merge
// the lambda options into one this means they should only configure
// lambda options for one page or one API as doing it for
// another will override it
const getMergedLambdaOptions = async (pageKeys: string[]) => {
if (pageKeys.length === 0) return {};
const lambdaOptions = await getLambdaOptionsFromFunction({
sourceFile: await getSourceFilePathFromPage({
workPath,
page: pageKeys[0],
}),
config,
});
for (const page of pageKeys) {
if (page === pageKeys[0]) continue;
const sourceFile = await getSourceFilePathFromPage({
workPath,
page,
});
const newOptions = await getLambdaOptionsFromFunction({
sourceFile,
config,
});
for (const key of Object.keys(newOptions)) {
// eslint-disable-next-line
if (typeof (newOptions as any)[key] !== 'undefined') {
// eslint-disable-next-line
(lambdaOptions as any)[key] = (newOptions as any)[key];
}
}
}
return lambdaOptions;
};
const mergedPageLambdaOptions = await getMergedLambdaOptions(
pageKeys.filter(page => !page.startsWith('api/'))
);
const mergedApiLambdaOptions = await getMergedLambdaOptions(
pageKeys.filter(page => page.startsWith('api/'))
);
const launcherPath = path.join(__dirname, 'templated-launcher-shared.js');
const launcherData = await readFile(launcherPath, 'utf8');
@@ -1337,9 +1311,6 @@ export const build = async ({
],
handler: 'now__launcher.launcher',
runtime: nodeVersion.runtime,
...(group.isApiLambda
? mergedApiLambdaOptions
: mergedPageLambdaOptions),
});
} else {
lambdas[
@@ -1352,9 +1323,6 @@ export const build = async ({
layers: pageLayers,
handler: 'now__launcher.launcher',
runtime: nodeVersion.runtime,
...(group.isApiLambda
? mergedApiLambdaOptions
: mergedPageLambdaOptions),
});
}
}

View File

@@ -15,8 +15,8 @@ it(
buildResult: { output },
} = await runBuildLambda(path.join(__dirname, 'standard'));
expect(output['index']).toBeDefined();
expect(output.goodbye).not.toBeDefined();
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
expect(output.goodbye).toBeDefined();
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath =>
filePath.match(/_error/)
@@ -34,6 +34,28 @@ it(
FOUR_MINUTES
);
// it(
// 'Should opt-out of shared lambdas when routes are detected',
// async () => {
// const {
// buildResult: { output },
// } = await runBuildLambda(path.join(__dirname, '../fixtures/26-mono-repo-404-lambda'));
// expect(output['packages/webapp/404']).toBeDefined();
// expect(output['packages/webapp/index']).toBeDefined();
// expect(output['packages/webapp/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
// const filePaths = Object.keys(output);
// const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
// filePath.match(/static.*\/pages\/_app\.js$/)
// );
// const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
// filePath.match(/static.*\/pages\/_error\.js$/)
// );
// expect(hasUnderScoreAppStaticFile).toBeTruthy();
// expect(hasUnderScoreErrorStaticFile).toBeTruthy();
// },
// FOUR_MINUTES
// );
it(
'Should build the monorepo example',
async () => {
@@ -41,8 +63,8 @@ it(
buildResult: { output },
} = await runBuildLambda(path.join(__dirname, 'monorepo'));
expect(output['www/index']).not.toBeDefined();
expect(output['www/__NEXT_PAGE_LAMBDA_0']).toBeDefined();
expect(output['www/index']).toBeDefined();
expect(output['www/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
expect(output['www/static/test.txt']).toBeDefined();
expect(output['www/data.txt']).toBeDefined();
const filePaths = Object.keys(output);
@@ -142,9 +164,9 @@ it(
buildResult: { output },
} = await runBuildLambda(path.join(__dirname, 'serverless-config'));
expect(output.index).not.toBeDefined();
expect(output.goodbye).not.toBeDefined();
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
expect(output.index).toBeDefined();
expect(output.goodbye).toBeDefined();
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath =>
filePath.match(/_error/)
@@ -179,9 +201,9 @@ it(
path.join(__dirname, 'serverless-config-monorepo-missing')
);
expect(output['nested/index']).not.toBeDefined();
expect(output['nested/goodbye']).not.toBeDefined();
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).toBeDefined();
expect(output['nested/index']).toBeDefined();
expect(output['nested/goodbye']).toBeDefined();
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath =>
filePath.match(/_error/)
@@ -213,9 +235,9 @@ it(
path.join(__dirname, 'serverless-config-monorepo-present')
);
expect(output['nested/index']).not.toBeDefined();
expect(output['nested/goodbye']).not.toBeDefined();
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).toBeDefined();
expect(output['nested/index']).toBeDefined();
expect(output['nested/goodbye']).toBeDefined();
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath =>
filePath.match(/_error/)
@@ -281,8 +303,8 @@ it(
} = await runBuildLambda(path.join(__dirname, 'serverless-config-object'));
expect(output['index']).toBeDefined();
expect(output.goodbye).not.toBeDefined();
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
expect(output.goodbye).toBeDefined();
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath =>
filePath.match(/_error/)
@@ -316,8 +338,8 @@ it(
} = await runBuildLambda(path.join(__dirname, 'serverless-no-config'));
expect(output['index']).toBeDefined();
expect(output.goodbye).not.toBeDefined();
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
expect(output.goodbye).toBeDefined();
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath =>
filePath.match(/_error/)

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node-bridge",
"version": "1.3.1-canary.2",
"version": "1.3.1",
"license": "MIT",
"main": "./index.js",
"repository": {

View File

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

View File

@@ -1,11 +1,11 @@
const entrypoint = process.env.NOW_DEV_ENTRYPOINT;
delete process.env.NOW_DEV_ENTRYPOINT;
const entrypoint = process.env.VERCEL_DEV_ENTRYPOINT;
delete process.env.VERCEL_DEV_ENTRYPOINT;
const tsconfig = process.env.NOW_DEV_TSCONFIG;
delete process.env.NOW_DEV_TSCONFIG;
const tsconfig = process.env.VERCEL_DEV_TSCONFIG;
delete process.env.VERCEL_DEV_TSCONFIG;
if (!entrypoint) {
throw new Error('`NOW_DEV_ENTRYPOINT` must be defined');
throw new Error('`VERCEL_DEV_ENTRYPOINT` must be defined');
}
import { register } from 'ts-node';
@@ -27,6 +27,7 @@ register({
allowJs: true,
esModuleInterop: true,
jsx: 'react',
module: 'commonjs',
},
project: tsconfig || undefined, // Resolve `tsconfig.json` from entrypoint dir
transpileOnly: true,
@@ -49,11 +50,14 @@ function listen(server: Server, port: number, host: string): Promise<void> {
let bridge: Bridge | undefined = undefined;
async function main() {
const config = JSON.parse(process.env.NOW_DEV_CONFIG || '{}');
delete process.env.NOW_DEV_CONFIG;
const config = JSON.parse(process.env.VERCEL_DEV_CONFIG || '{}');
delete process.env.VERCEL_DEV_CONFIG;
const buildEnv = JSON.parse(process.env.VERCEL_DEV_BUILD_ENV || '{}');
delete process.env.VERCEL_DEV_BUILD_ENV;
const shouldAddHelpers = !(
config.helpers === false || process.env.NODEJS_HELPERS === '0'
config.helpers === false || buildEnv.NODEJS_HELPERS === '0'
);
bridge = getNowLauncher({

View File

@@ -445,9 +445,10 @@ export async function startDevServer(
env: {
...process.env,
...meta.env,
NOW_DEV_ENTRYPOINT: entrypoint,
NOW_DEV_TSCONFIG: projectTsConfig || '',
NOW_DEV_CONFIG: JSON.stringify(config),
VERCEL_DEV_ENTRYPOINT: entrypoint,
VERCEL_DEV_TSCONFIG: projectTsConfig || '',
VERCEL_DEV_CONFIG: JSON.stringify(config),
VERCEL_DEV_BUILD_ENV: JSON.stringify(meta.buildEnv || {}),
},
});

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/python",
"version": "1.2.2-canary.2",
"version": "1.2.2",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",

View File

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

View File

@@ -230,6 +230,7 @@ function createError(
const errors = Array.isArray(allErrors) ? allErrors : [allErrors];
const message = errors[0];
const error: RouteApiError = {
name: 'RouteApiError',
code,
message,
link,

View File

@@ -1,6 +1,7 @@
import { HandleValue } from './index';
export type RouteApiError = {
name: string;
code: string;
message: string;
link?: string; // link to error message details

View File

@@ -1,7 +1,7 @@
{
"name": "@vercel/ruby",
"author": "Nathan Cahill <nathan@nathancahill.com>",
"version": "1.2.2-canary.1",
"version": "1.2.2",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/static-build",
"version": "0.17.2-canary.1",
"version": "0.17.2",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/static-builds",

View File

@@ -186,7 +186,10 @@ async function fetchTokenWithRetry(retries = 5) {
},
});
if (!res.ok) {
throw new Error(`Unexpected status from registration: ${res.status}`);
const text = await res.text();
throw new Error(
`Unexpected status (${res.status}) from registration: ${text}`
);
}
const data = await res.json();
if (!data) {

103
yarn.lock
View File

@@ -1402,9 +1402,9 @@
"@types/node" ">= 8"
"@octokit/types@^4.0.1":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-4.1.5.tgz#465872f9f5f5e6bb85c6ed763053486bba9b251b"
integrity sha512-/MKeipxtwMorckj1bfP+SKhbzKhqQimT5JuXKGtwnLazqDwj/noYYSPChpLzstVAwF8JVPygJ7L75cKCK47Ikg==
version "4.1.9"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-4.1.9.tgz#a3e1ff1a15637ab830fbab0268c2d7ca824bc969"
integrity sha512-hinM/BA2c1vebN2HSR3JtVdYtrSbmvn/doUBZXXuQuh/9o60hYwitQQAGTpJu+k6pjtjURskDHQxUFvqLvYCeA==
dependencies:
"@types/node" ">= 8"
@@ -1485,9 +1485,9 @@
escape-string-regexp "^2.0.0"
"@sindresorhus/transliterate@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/transliterate/-/transliterate-0.1.0.tgz#c063bfc4102783fb19c91c2f8c1efb3adfb754be"
integrity sha512-bO6v0M0EuJPjm5Ntfow4nk+r3EZQ41n0ahvAmh766FzPqlm6V/2uDc01vZI3gLeI/1lgV2BTMb6QvxOk9z73ng==
version "0.1.1"
resolved "https://registry.yarnpkg.com/@sindresorhus/transliterate/-/transliterate-0.1.1.tgz#779b31244781d3c898f185b61d58c89e7c782674"
integrity sha512-QSdIQ5keUFAZ3KLbfbsntW39ox0Ym8183RqTwBq/ZEFoN3NQAtGV+qWaNdzKpIDHgj9J2CQ2iNDRVU11Zyr7MQ==
dependencies:
escape-string-regexp "^2.0.0"
lodash.deburr "^4.1.0"
@@ -1731,7 +1731,7 @@
dependencies:
"@types/node" "*"
"@types/glob@7.1.1", "@types/glob@^7.1.1":
"@types/glob@7.1.1":
version "7.1.1"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
@@ -1740,6 +1740,14 @@
"@types/minimatch" "*"
"@types/node" "*"
"@types/glob@^7.1.1":
version "7.1.2"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.2.tgz#06ca26521353a545d94a0adc74f38a59d232c987"
integrity sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==
dependencies:
"@types/minimatch" "*"
"@types/node" "*"
"@types/http-proxy@1.16.2":
version "1.16.2"
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.16.2.tgz#16cb373b52fff2aa2f389d23d940ed4a642349e5"
@@ -1892,9 +1900,9 @@
form-data "^3.0.0"
"@types/node@*", "@types/node@>= 8":
version "14.0.9"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.9.tgz#43896ab87fc82bda1dfd600cdf44a0c8a64e11d2"
integrity sha512-0sCTiXKXELOBxvZLN4krQ0FPOAA7ij+6WwvD0k/PHd9/KAkr4dXel5J9fh6F4x1FwAQILqAWkmpeuS6mjf1iKA==
version "14.0.12"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.12.tgz#9c1d8ffb8084e8936603a6122a7649e40e68e04b"
integrity sha512-/sjzehvjkkpvLpYtN6/2dv5kg41otMGuHQUt9T2aiAuIfleCQRQHXXzF1eAw/qkZTj5Kcf4JSTf7EIizHocy6Q==
"@types/node@10.12.18":
version "10.12.18"
@@ -1902,9 +1910,9 @@
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
"@types/node@10.x":
version "10.17.24"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.24.tgz#c57511e3a19c4b5e9692bb2995c40a3a52167944"
integrity sha512-5SCfvCxV74kzR3uWgTYiGxrd69TbT1I6+cMx1A5kEly/IVveJBimtAMlXiEyVFn5DvUFewQWxOOiJhlxeQwxgA==
version "10.17.25"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.25.tgz#64f64cd3e8641e8163c81045e545d2825d300e37"
integrity sha512-EWPw3jDB0jip4HafDkoezNOwG00TtVZ1TOe74MaxIBWgpyM60UF/LXzFVx9+8AdSYNNOPgx7TuJoRmgnhHZ/7g==
"@types/node@11.11.0":
version "11.11.0"
@@ -2429,17 +2437,7 @@ aggregate-error@3.0.1, aggregate-error@^3.0.0:
clean-stack "^2.0.0"
indent-string "^4.0.0"
ajv@6.10.2:
version "6.10.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
dependencies:
fast-deep-equal "^2.0.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ajv@^6.0.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5:
ajv@6.12.2, ajv@^6.0.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5:
version "6.12.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==
@@ -4614,9 +4612,9 @@ escape-string-regexp@^2.0.0:
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
escodegen@^1.9.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457"
integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==
version "1.14.2"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.2.tgz#14ab71bf5026c2aa08173afba22c6f3173284a84"
integrity sha512-InuOIiKk8wwuOFg6x9BQXbzjrQhtyXh46K9bqVTPzSo2FnyMBaYGBMC6PhQy7yxxil9vIedFBweQBMK74/7o8A==
dependencies:
esprima "^4.0.1"
estraverse "^4.2.0"
@@ -4648,9 +4646,9 @@ eslint-scope@^4.0.0:
estraverse "^4.1.1"
eslint-scope@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9"
integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==
version "5.1.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5"
integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==
dependencies:
esrecurse "^4.1.0"
estraverse "^4.1.1"
@@ -4670,9 +4668,9 @@ eslint-utils@^2.0.0:
eslint-visitor-keys "^1.1.0"
eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
version "1.2.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz#74415ac884874495f78ec2a97349525344c981fa"
integrity sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ==
eslint@6.2.2:
version "6.2.2"
@@ -4995,15 +4993,10 @@ extsprintf@^1.2.0:
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
fast-deep-equal@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
fast-deep-equal@3.1.3, fast-deep-equal@^3.1.1:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-diff@^1.1.2:
version "1.2.0"
@@ -6506,11 +6499,11 @@ is-promise@^2.1.0:
integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
is-regex@^1.0.4, is-regex@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae"
integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff"
integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==
dependencies:
has "^1.0.3"
has-symbols "^1.0.1"
is-regexp@^1.0.0:
version "1.0.0"
@@ -7838,9 +7831,9 @@ merge-stream@^2.0.0:
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
merge2@^1.2.3, merge2@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81"
integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==
version "1.4.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
micro@9.1.2:
version "9.1.2"
@@ -9536,9 +9529,9 @@ regenerate-unicode-properties@^8.2.0:
regenerate "^1.4.0"
regenerate@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
version "1.4.1"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f"
integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==
regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
@@ -11522,9 +11515,9 @@ widest-line@^3.1.0:
string-width "^4.0.0"
windows-release@^3.1.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.0.tgz#dce167e9f8be733f21c849ebd4d03fe66b29b9f0"
integrity sha512-2HetyTg1Y+R+rUgrKeUEhAG/ZuOmTrI1NBb3ZyAGQMYmOJjBBPe4MTodghRkmLJZHwkuPi02anbeGP+Zf401LQ==
version "3.3.1"
resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.1.tgz#cb4e80385f8550f709727287bf71035e209c4ace"
integrity sha512-Pngk/RDCaI/DkuHPlGTdIkDiTAnAkyMjoQMZqRsxydNl1qGXNIoZrB7RK8g53F2tEgQBMqQJHQdYZuQEEAu54A==
dependencies:
execa "^1.0.0"