Compare commits

..

17 Commits

Author SHA1 Message Date
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
47 changed files with 6343 additions and 361 deletions

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-canary.5",
"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.3.2-canary.6",
"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",
"version": "19.0.2-canary.13",
"version": "19.0.2-canary.16",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Now",
@@ -62,10 +62,10 @@
"node": ">= 10"
},
"dependencies": {
"@vercel/build-utils": "2.3.2-canary.4",
"@vercel/build-utils": "2.3.2-canary.6",
"@vercel/go": "1.1.2-canary.2",
"@vercel/next": "2.6.3-canary.6",
"@vercel/node": "1.6.2-canary.5",
"@vercel/next": "2.6.5",
"@vercel/node": "1.6.2-canary.6",
"@vercel/python": "1.2.2-canary.2",
"@vercel/ruby": "1.2.2-canary.1",
"@vercel/static-build": "0.17.2-canary.1"
@@ -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-error',
});
}
} 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}"`
);
@@ -564,7 +575,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 || [];
@@ -1367,7 +1378,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 +1517,8 @@ export default class DevServer {
req,
res,
`http://localhost:${this.devProcessPort}`,
this.proxy,
this.output,
this,
nowRequestId,
false
);
}
@@ -1626,8 +1637,8 @@ export default class DevServer {
req,
res,
`http://localhost:${port}`,
this.proxy,
this.output,
this,
nowRequestId,
false
);
} else {
@@ -1656,8 +1667,8 @@ export default class DevServer {
req,
res,
`http://localhost:${this.devProcessPort}`,
this.proxy,
this.output,
this,
nowRequestId,
false
);
}
@@ -1967,24 +1978,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 +2272,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,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,120 @@ 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-error'));
});
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 +600,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 +808,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 +887,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 +1509,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

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "8.0.2-canary.2",
"version": "8.0.2-canary.3",
"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> {
@@ -166,9 +167,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

@@ -1,6 +1,6 @@
{
"name": "@vercel/next",
"version": "2.6.3",
"version": "2.6.5",
"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",
"version": "1.6.2-canary.5",
"version": "1.6.2-canary.6",
"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/routing-utils",
"version": "1.8.3-canary.5",
"version": "1.8.3-canary.6",
"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

@@ -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"