mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 12:57:46 +00:00
Compare commits
25 Commits
@vercel/bu
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf5cfa9a41 | ||
|
|
12121b7a71 | ||
|
|
baa56aed2c | ||
|
|
6f767367e4 | ||
|
|
0e4124f94c | ||
|
|
30503d0a3f | ||
|
|
6c9164f67d | ||
|
|
906b7a8f2c | ||
|
|
43499b13d8 | ||
|
|
7d6e56670f | ||
|
|
dba337f148 | ||
|
|
a825bc9540 | ||
|
|
f5486a8297 | ||
|
|
225e0a4de3 | ||
|
|
0ecfdc1325 | ||
|
|
628409d233 | ||
|
|
51d968314f | ||
|
|
b4e2cbc6e5 | ||
|
|
7323beea8e | ||
|
|
e4bb311144 | ||
|
|
288546659d | ||
|
|
822224e212 | ||
|
|
6b23950b65 | ||
|
|
1558f21e49 | ||
|
|
a6aee8b904 |
1
.github/workflows/publish.yml
vendored
1
.github/workflows/publish.yml
vendored
@@ -37,6 +37,7 @@ jobs:
|
|||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
|
timeout-minutes: 5 # See https://github.com/actions/cache/issues/810
|
||||||
with:
|
with:
|
||||||
node-version: 14
|
node-version: 14
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
5
.github/workflows/test-integration-cli.yml
vendored
5
.github/workflows/test-integration-cli.yml
vendored
@@ -31,6 +31,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: '1.13.15'
|
go-version: '1.13.15'
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
|
timeout-minutes: 5 # See https://github.com/actions/cache/issues/810
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -38,5 +39,5 @@ jobs:
|
|||||||
- run: yarn run build
|
- run: yarn run build
|
||||||
- run: yarn test-integration-cli
|
- run: yarn test-integration-cli
|
||||||
env:
|
env:
|
||||||
VERCEL_TEAM_TOKEN: ${{ secrets.VERCEL_TEAM_TOKEN }}
|
VERCEL_TEST_TOKEN: ${{ secrets.VERCEL_TEST_TOKEN }}
|
||||||
VERCEL_REGISTRATION_URL: ${{ secrets.VERCEL_REGISTRATION_URL }}
|
VERCEL_TEST_REGISTRATION_URL: ${{ secrets.VERCEL_TEST_REGISTRATION_URL }}
|
||||||
|
|||||||
1
.github/workflows/test-unit.yml
vendored
1
.github/workflows/test-unit.yml
vendored
@@ -31,6 +31,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
|
timeout-minutes: 5 # See https://github.com/actions/cache/issues/810
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@@ -29,6 +29,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: '1.13.15'
|
go-version: '1.13.15'
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
|
timeout-minutes: 5 # See https://github.com/actions/cache/issues/810
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -65,6 +66,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: '1.13.15'
|
go-version: '1.13.15'
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
|
timeout-minutes: 5 # See https://github.com/actions/cache/issues/810
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -84,8 +86,8 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
VERCEL_CLI_VERSION: ${{ needs.setup.outputs.dplUrl }}/tarballs/vercel.tgz
|
VERCEL_CLI_VERSION: ${{ needs.setup.outputs.dplUrl }}/tarballs/vercel.tgz
|
||||||
VERCEL_TEAM_TOKEN: ${{ secrets.VERCEL_TEAM_TOKEN }}
|
VERCEL_TEST_TOKEN: ${{ secrets.VERCEL_TEST_TOKEN }}
|
||||||
VERCEL_REGISTRATION_URL: ${{ secrets.VERCEL_REGISTRATION_URL }}
|
VERCEL_TEST_REGISTRATION_URL: ${{ secrets.VERCEL_TEST_REGISTRATION_URL }}
|
||||||
FORCE_COLOR: '1'
|
FORCE_COLOR: '1'
|
||||||
|
|
||||||
conclusion:
|
conclusion:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/build-utils",
|
"name": "@vercel/build-utils",
|
||||||
"version": "5.4.4",
|
"version": "5.5.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.js",
|
"types": "./dist/index.d.js",
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ export class EdgeFunction {
|
|||||||
*/
|
*/
|
||||||
assets?: { name: string; path: string }[];
|
assets?: { name: string; path: string }[];
|
||||||
|
|
||||||
|
/** The regions where the edge function will be executed on */
|
||||||
|
regions?: 'auto' | string[] | 'all' | 'default';
|
||||||
|
|
||||||
constructor(params: Omit<EdgeFunction, 'type'>) {
|
constructor(params: Omit<EdgeFunction, 'type'>) {
|
||||||
this.type = 'EdgeFunction';
|
this.type = 'EdgeFunction';
|
||||||
this.name = params.name;
|
this.name = params.name;
|
||||||
@@ -46,5 +49,6 @@ export class EdgeFunction {
|
|||||||
this.files = params.files;
|
this.files = params.files;
|
||||||
this.envVarsInUse = params.envVarsInUse;
|
this.envVarsInUse = params.envVarsInUse;
|
||||||
this.assets = params.assets;
|
this.assets = params.assets;
|
||||||
|
this.regions = params.regions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,14 +61,14 @@ export function getPrettyError(obj: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new NowBuildError({
|
return new NowBuildError({
|
||||||
code: 'DEV_VALIDATE_CONFIG',
|
code: 'INVALID_VERCEL_CONFIG',
|
||||||
message: message,
|
message: message,
|
||||||
link: prop ? `${docsUrl}#project/${prop.toLowerCase()}` : docsUrl,
|
link: prop ? `${docsUrl}#project/${prop.toLowerCase()}` : docsUrl,
|
||||||
action: 'View Documentation',
|
action: 'View Documentation',
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return new NowBuildError({
|
return new NowBuildError({
|
||||||
code: 'DEV_VALIDATE_CONFIG',
|
code: 'INVALID_VERCEL_CONFIG',
|
||||||
message: `Failed to validate configuration.`,
|
message: `Failed to validate configuration.`,
|
||||||
link: docsUrl,
|
link: docsUrl,
|
||||||
action: 'View Documentation',
|
action: 'View Documentation',
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const allOptions = [
|
|||||||
major: 12,
|
major: 12,
|
||||||
range: '12.x',
|
range: '12.x',
|
||||||
runtime: 'nodejs12.x',
|
runtime: 'nodejs12.x',
|
||||||
discontinueDate: new Date('2022-10-01'),
|
discontinueDate: new Date('2022-10-03'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
major: 10,
|
major: 10,
|
||||||
|
|||||||
4
packages/build-utils/test/unit.test.ts
vendored
4
packages/build-utils/test/unit.test.ts
vendored
@@ -434,8 +434,8 @@ it('should warn for deprecated versions, soon to be discontinued', async () => {
|
|||||||
expect(warningMessages).toStrictEqual([
|
expect(warningMessages).toStrictEqual([
|
||||||
'Error: Node.js version 10.x has reached End-of-Life. Deployments created on or after 2021-04-20 will fail to build. Please set "engines": { "node": "16.x" } in your `package.json` file to use Node.js 16.',
|
'Error: Node.js version 10.x has reached End-of-Life. Deployments created on or after 2021-04-20 will fail to build. Please set "engines": { "node": "16.x" } in your `package.json` file to use Node.js 16.',
|
||||||
'Error: Node.js version 10.x has reached End-of-Life. Deployments created on or after 2021-04-20 will fail to build. Please set Node.js Version to 16.x in your Project Settings to use Node.js 16.',
|
'Error: Node.js version 10.x has reached End-of-Life. Deployments created on or after 2021-04-20 will fail to build. Please set Node.js Version to 16.x in your Project Settings to use Node.js 16.',
|
||||||
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-10-01 will fail to build. Please set "engines": { "node": "16.x" } in your `package.json` file to use Node.js 16.',
|
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-10-03 will fail to build. Please set "engines": { "node": "16.x" } in your `package.json` file to use Node.js 16.',
|
||||||
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-10-01 will fail to build. Please set Node.js Version to 16.x in your Project Settings to use Node.js 16.',
|
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-10-03 will fail to build. Please set Node.js Version to 16.x in your Project Settings to use Node.js 16.',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
global.Date.now = realDateNow;
|
global.Date.now = realDateNow;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vercel",
|
"name": "vercel",
|
||||||
"version": "28.4.0",
|
"version": "28.4.3",
|
||||||
"preferGlobal": true,
|
"preferGlobal": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"description": "The command-line interface for Vercel",
|
"description": "The command-line interface for Vercel",
|
||||||
@@ -41,16 +41,16 @@
|
|||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "5.4.4",
|
"@vercel/build-utils": "5.5.1",
|
||||||
"@vercel/go": "2.2.7",
|
"@vercel/go": "2.2.9",
|
||||||
"@vercel/hydrogen": "0.0.20",
|
"@vercel/hydrogen": "0.0.22",
|
||||||
"@vercel/next": "3.1.27",
|
"@vercel/next": "3.1.30",
|
||||||
"@vercel/node": "2.5.16",
|
"@vercel/node": "2.5.19",
|
||||||
"@vercel/python": "3.1.16",
|
"@vercel/python": "3.1.18",
|
||||||
"@vercel/redwood": "1.0.25",
|
"@vercel/redwood": "1.0.27",
|
||||||
"@vercel/remix": "1.0.26",
|
"@vercel/remix": "1.0.28",
|
||||||
"@vercel/ruby": "1.3.33",
|
"@vercel/ruby": "1.3.35",
|
||||||
"@vercel/static-build": "1.0.25",
|
"@vercel/static-build": "1.0.27",
|
||||||
"update-notifier": "5.1.0"
|
"update-notifier": "5.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -95,9 +95,9 @@
|
|||||||
"@types/which": "1.3.2",
|
"@types/which": "1.3.2",
|
||||||
"@types/write-json-file": "2.2.1",
|
"@types/write-json-file": "2.2.1",
|
||||||
"@types/yauzl-promise": "2.1.0",
|
"@types/yauzl-promise": "2.1.0",
|
||||||
"@vercel/client": "12.2.6",
|
"@vercel/client": "12.2.8",
|
||||||
"@vercel/frameworks": "1.1.6",
|
"@vercel/frameworks": "1.1.6",
|
||||||
"@vercel/fs-detectors": "3.3.0",
|
"@vercel/fs-detectors": "3.4.0",
|
||||||
"@vercel/fun": "1.0.4",
|
"@vercel/fun": "1.0.4",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"@zeit/source-map-support": "0.6.2",
|
"@zeit/source-map-support": "0.6.2",
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import open from 'open';
|
|||||||
import boxen from 'boxen';
|
import boxen from 'boxen';
|
||||||
import execa from 'execa';
|
import execa from 'execa';
|
||||||
import plural from 'pluralize';
|
import plural from 'pluralize';
|
||||||
import inquirer from 'inquirer';
|
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import chalk, { Chalk } from 'chalk';
|
import chalk, { Chalk } from 'chalk';
|
||||||
import { URLSearchParams, parse } from 'url';
|
import { URLSearchParams, parse } from 'url';
|
||||||
@@ -150,7 +149,9 @@ export default async function main(client: Client): Promise<number> {
|
|||||||
|
|
||||||
if (badDeployment) {
|
if (badDeployment) {
|
||||||
if (badDeployment instanceof Error) {
|
if (badDeployment instanceof Error) {
|
||||||
badDeployment.message += ` "${bad}"`;
|
badDeployment.message += ` when requesting bad deployment "${normalizeURL(
|
||||||
|
bad
|
||||||
|
)}"`;
|
||||||
output.prettyError(badDeployment);
|
output.prettyError(badDeployment);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -165,7 +166,9 @@ export default async function main(client: Client): Promise<number> {
|
|||||||
|
|
||||||
if (goodDeployment) {
|
if (goodDeployment) {
|
||||||
if (goodDeployment instanceof Error) {
|
if (goodDeployment instanceof Error) {
|
||||||
goodDeployment.message += ` "${good}"`;
|
goodDeployment.message += ` when requesting good deployment "${normalizeURL(
|
||||||
|
good
|
||||||
|
)}"`;
|
||||||
output.prettyError(goodDeployment);
|
output.prettyError(goodDeployment);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -226,7 +229,8 @@ export default async function main(client: Client): Promise<number> {
|
|||||||
// If we have the "good" deployment in this chunk, then we're done
|
// If we have the "good" deployment in this chunk, then we're done
|
||||||
for (let i = 0; i < newDeployments.length; i++) {
|
for (let i = 0; i < newDeployments.length; i++) {
|
||||||
if (newDeployments[i].url === good) {
|
if (newDeployments[i].url === good) {
|
||||||
newDeployments = newDeployments.slice(0, i + 1);
|
// grab all deployments up until the good one
|
||||||
|
newDeployments = newDeployments.slice(0, i);
|
||||||
next = undefined;
|
next = undefined;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -316,7 +320,7 @@ export default async function main(client: Client): Promise<number> {
|
|||||||
if (openEnabled) {
|
if (openEnabled) {
|
||||||
await open(testUrl);
|
await open(testUrl);
|
||||||
}
|
}
|
||||||
const answer = await inquirer.prompt({
|
const answer = await client.prompt({
|
||||||
type: 'expand',
|
type: 'expand',
|
||||||
name: 'action',
|
name: 'action',
|
||||||
message: 'Select an action:',
|
message: 'Select an action:',
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
MergeRoutesProps,
|
MergeRoutesProps,
|
||||||
Route,
|
Route,
|
||||||
} from '@vercel/routing-utils';
|
} from '@vercel/routing-utils';
|
||||||
|
import { fileNameSymbol } from '@vercel/client';
|
||||||
import type { VercelConfig } from '@vercel/client';
|
import type { VercelConfig } from '@vercel/client';
|
||||||
|
|
||||||
import pull from './pull';
|
import pull from './pull';
|
||||||
@@ -54,6 +55,7 @@ import { importBuilders } from '../util/build/import-builders';
|
|||||||
import { initCorepack, cleanupCorepack } from '../util/build/corepack';
|
import { initCorepack, cleanupCorepack } from '../util/build/corepack';
|
||||||
import { sortBuilders } from '../util/build/sort-builders';
|
import { sortBuilders } from '../util/build/sort-builders';
|
||||||
import { toEnumerableError } from '../util/error';
|
import { toEnumerableError } from '../util/error';
|
||||||
|
import { validateConfig } from '../util/validate-config';
|
||||||
|
|
||||||
type BuildResult = BuildResultV2 | BuildResultV3;
|
type BuildResult = BuildResultV2 | BuildResultV3;
|
||||||
|
|
||||||
@@ -232,7 +234,8 @@ export default async function main(client: Client): Promise<number> {
|
|||||||
process.env.VERCEL = '1';
|
process.env.VERCEL = '1';
|
||||||
process.env.NOW_BUILDER = '1';
|
process.env.NOW_BUILDER = '1';
|
||||||
|
|
||||||
return await doBuild(client, project, buildsJson, cwd, outputDir);
|
await doBuild(client, project, buildsJson, cwd, outputDir);
|
||||||
|
return 0;
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
output.prettyError(err);
|
output.prettyError(err);
|
||||||
|
|
||||||
@@ -265,23 +268,36 @@ async function doBuild(
|
|||||||
buildsJson: BuildsManifest,
|
buildsJson: BuildsManifest,
|
||||||
cwd: string,
|
cwd: string,
|
||||||
outputDir: string
|
outputDir: string
|
||||||
): Promise<number> {
|
): Promise<void> {
|
||||||
const { output } = client;
|
const { output } = client;
|
||||||
const workPath = join(cwd, project.settings.rootDirectory || '.');
|
const workPath = join(cwd, project.settings.rootDirectory || '.');
|
||||||
|
|
||||||
// Load `package.json` and `vercel.json` files
|
const [pkg, vercelConfig, nowConfig] = await Promise.all([
|
||||||
const [pkg, vercelConfig] = await Promise.all([
|
|
||||||
readJSONFile<PackageJson>(join(workPath, 'package.json')),
|
readJSONFile<PackageJson>(join(workPath, 'package.json')),
|
||||||
readJSONFile<VercelConfig>(join(workPath, 'vercel.json')).then(
|
readJSONFile<VercelConfig>(join(workPath, 'vercel.json')),
|
||||||
config => config || readJSONFile<VercelConfig>(join(workPath, 'now.json'))
|
readJSONFile<VercelConfig>(join(workPath, 'now.json')),
|
||||||
),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (pkg instanceof CantParseJSONFile) throw pkg;
|
if (pkg instanceof CantParseJSONFile) throw pkg;
|
||||||
if (vercelConfig instanceof CantParseJSONFile) throw vercelConfig;
|
if (vercelConfig instanceof CantParseJSONFile) throw vercelConfig;
|
||||||
|
if (nowConfig instanceof CantParseJSONFile) throw nowConfig;
|
||||||
|
|
||||||
|
if (vercelConfig) {
|
||||||
|
vercelConfig[fileNameSymbol] = 'vercel.json';
|
||||||
|
} else if (nowConfig) {
|
||||||
|
nowConfig[fileNameSymbol] = 'now.json';
|
||||||
|
}
|
||||||
|
|
||||||
|
const localConfig = vercelConfig || nowConfig || {};
|
||||||
|
const validateError = validateConfig(localConfig);
|
||||||
|
|
||||||
|
if (validateError) {
|
||||||
|
throw validateError;
|
||||||
|
}
|
||||||
|
|
||||||
const projectSettings = {
|
const projectSettings = {
|
||||||
...project.settings,
|
...project.settings,
|
||||||
...pickOverrides(vercelConfig || {}),
|
...pickOverrides(localConfig),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get a list of source files
|
// Get a list of source files
|
||||||
@@ -289,12 +305,12 @@ async function doBuild(
|
|||||||
normalizePath(relative(workPath, f))
|
normalizePath(relative(workPath, f))
|
||||||
);
|
);
|
||||||
|
|
||||||
const routesResult = getTransformedRoutes(vercelConfig || {});
|
const routesResult = getTransformedRoutes(localConfig);
|
||||||
if (routesResult.error) {
|
if (routesResult.error) {
|
||||||
throw routesResult.error;
|
throw routesResult.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vercelConfig?.builds && vercelConfig.functions) {
|
if (localConfig.builds && localConfig.functions) {
|
||||||
throw new NowBuildError({
|
throw new NowBuildError({
|
||||||
code: 'bad_request',
|
code: 'bad_request',
|
||||||
message:
|
message:
|
||||||
@@ -303,7 +319,7 @@ async function doBuild(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let builds = vercelConfig?.builds || [];
|
let builds = localConfig.builds || [];
|
||||||
let zeroConfigRoutes: Route[] = [];
|
let zeroConfigRoutes: Route[] = [];
|
||||||
let isZeroConfig = false;
|
let isZeroConfig = false;
|
||||||
|
|
||||||
@@ -318,7 +334,7 @@ async function doBuild(
|
|||||||
|
|
||||||
// Detect the Vercel Builders that will need to be invoked
|
// Detect the Vercel Builders that will need to be invoked
|
||||||
const detectedBuilders = await detectBuilders(files, pkg, {
|
const detectedBuilders = await detectBuilders(files, pkg, {
|
||||||
...vercelConfig,
|
...localConfig,
|
||||||
projectSettings,
|
projectSettings,
|
||||||
ignoreBuildScript: true,
|
ignoreBuildScript: true,
|
||||||
featHandleMiss: true,
|
featHandleMiss: true,
|
||||||
@@ -395,13 +411,10 @@ async function doBuild(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
buildsJson.builds = Array.from(buildsJsonBuilds.values());
|
buildsJson.builds = Array.from(buildsJsonBuilds.values());
|
||||||
const buildsJsonPath = join(outputDir, 'builds.json');
|
await fs.writeJSON(join(outputDir, 'builds.json'), buildsJson, {
|
||||||
const writeBuildsJsonPromise = fs.writeJSON(buildsJsonPath, buildsJson, {
|
|
||||||
spaces: 2,
|
spaces: 2,
|
||||||
});
|
});
|
||||||
|
|
||||||
ops.push(writeBuildsJsonPromise);
|
|
||||||
|
|
||||||
// The `meta` config property is re-used for each Builder
|
// The `meta` config property is re-used for each Builder
|
||||||
// invocation so that Builders can share state between
|
// invocation so that Builders can share state between
|
||||||
// subsequent entrypoint builds.
|
// subsequent entrypoint builds.
|
||||||
@@ -466,7 +479,7 @@ async function doBuild(
|
|||||||
build,
|
build,
|
||||||
builder,
|
builder,
|
||||||
builderPkg,
|
builderPkg,
|
||||||
vercelConfig
|
localConfig
|
||||||
).then(
|
).then(
|
||||||
override => {
|
override => {
|
||||||
if (override) overrides.push(override);
|
if (override) overrides.push(override);
|
||||||
@@ -475,26 +488,11 @@ async function doBuild(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
output.prettyError(err);
|
|
||||||
|
|
||||||
const writeConfigJsonPromise = fs.writeJSON(
|
|
||||||
join(outputDir, 'config.json'),
|
|
||||||
{ version: 3 },
|
|
||||||
{ spaces: 2 }
|
|
||||||
);
|
|
||||||
|
|
||||||
await Promise.all([writeBuildsJsonPromise, writeConfigJsonPromise]);
|
|
||||||
|
|
||||||
const buildJsonBuild = buildsJsonBuilds.get(build);
|
const buildJsonBuild = buildsJsonBuilds.get(build);
|
||||||
if (buildJsonBuild) {
|
if (buildJsonBuild) {
|
||||||
buildJsonBuild.error = toEnumerableError(err);
|
buildJsonBuild.error = toEnumerableError(err);
|
||||||
|
|
||||||
await fs.writeJSON(buildsJsonPath, buildsJson, {
|
|
||||||
spaces: 2,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
throw err;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,150 +553,7 @@ async function doBuild(
|
|||||||
builds: builderRoutes,
|
builds: builderRoutes,
|
||||||
});
|
});
|
||||||
|
|
||||||
const images = vercelConfig?.images
|
const mergedImages = mergeImages(localConfig.images, buildResults.values());
|
||||||
if (images) {
|
|
||||||
if (typeof images !== 'object') {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images" should be an object received ${typeof images}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Array.isArray(images.domains)) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.domains" should be an Array received ${typeof images.domains}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (images.domains.length > 50) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.domains" exceeds length of 50 received length (${images.domains.length}).`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidImageDomains = images.domains.filter(
|
|
||||||
(d: unknown) => typeof d !== 'string'
|
|
||||||
);
|
|
||||||
if (invalidImageDomains.length > 0) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.domains" should be an Array of strings received invalid values (${invalidImageDomains.join(
|
|
||||||
', '
|
|
||||||
)}).`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (images.remotePatterns) {
|
|
||||||
if (!Array.isArray(images.remotePatterns)) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.remotePatterns" should be an Array received ${typeof images.remotePatterns}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (images.remotePatterns.length > 50) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.remotePatterns" exceeds length of 50, received length (${images.remotePatterns.length}).`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const validProps = new Set(['protocol', 'hostname', 'pathname', 'port']);
|
|
||||||
const requiredProps = ['hostname'];
|
|
||||||
const invalidPatterns = images.remotePatterns.filter(
|
|
||||||
(d: unknown) =>
|
|
||||||
!d ||
|
|
||||||
typeof d !== 'object' ||
|
|
||||||
Object.entries(d).some(
|
|
||||||
([k, v]) => !validProps.has(k) || typeof v !== 'string'
|
|
||||||
) ||
|
|
||||||
requiredProps.some(k => !(k in d))
|
|
||||||
);
|
|
||||||
if (invalidPatterns.length > 0) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.remotePatterns" received invalid values:\n${invalidPatterns
|
|
||||||
.map(item => JSON.stringify(item))
|
|
||||||
.join(
|
|
||||||
'\n'
|
|
||||||
)}\n\nremotePatterns value must follow format { protocol: 'https', hostname: 'example.com', port: '', pathname: '/imgs/**' }.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Array.isArray(images.sizes)) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.sizes" should be an Array received ${typeof images.sizes}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (images.sizes.length < 1 || images.sizes.length > 50) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.sizes" should be an Array of length between 1 to 50 received length (${images.sizes.length}).`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidImageSizes = images.sizes.filter((d: unknown) => {
|
|
||||||
return typeof d !== 'number' || d < 1 || d > 10000;
|
|
||||||
});
|
|
||||||
if (invalidImageSizes.length > 0) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.sizes" should be an Array of numbers that are between 1 and 10000, received invalid values (${invalidImageSizes.join(
|
|
||||||
', '
|
|
||||||
)}).`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (images.minimumCacheTTL) {
|
|
||||||
if (
|
|
||||||
!Number.isInteger(images.minimumCacheTTL) ||
|
|
||||||
images.minimumCacheTTL < 0
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.minimumCacheTTL" should be an integer 0 or more received (${images.minimumCacheTTL}).`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (images.formats) {
|
|
||||||
if (!Array.isArray(images.formats)) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.formats" should be an Array received ${typeof images.formats}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (images.formats.length < 1 || images.formats.length > 2) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.formats" must be length 1 or 2, received length (${images.formats.length}).`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalid = images.formats.filter(f => {
|
|
||||||
return f !== 'image/avif' && f !== 'image/webp';
|
|
||||||
});
|
|
||||||
if (invalid.length > 0) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.formats" should be an Array of mime type strings, received invalid values (${invalid.join(
|
|
||||||
', '
|
|
||||||
)}).`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
typeof images.dangerouslyAllowSVG !== 'undefined' &&
|
|
||||||
typeof images.dangerouslyAllowSVG !== 'boolean'
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.dangerouslyAllowSVG" should be a boolean received (${images.dangerouslyAllowSVG}).`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
typeof images.contentSecurityPolicy !== 'undefined' &&
|
|
||||||
typeof images.contentSecurityPolicy !== 'string'
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
`vercel.json "images.contentSecurityPolicy" should be a string received ${images.contentSecurityPolicy}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mergedImages = mergeImages(images, buildResults.values());
|
|
||||||
const mergedWildcard = mergeWildcard(buildResults.values());
|
const mergedWildcard = mergeWildcard(buildResults.values());
|
||||||
const mergedOverrides: Record<string, PathOverride> =
|
const mergedOverrides: Record<string, PathOverride> =
|
||||||
overrides.length > 0 ? Object.assign({}, ...overrides) : undefined;
|
overrides.length > 0 ? Object.assign({}, ...overrides) : undefined;
|
||||||
@@ -724,8 +579,6 @@ async function doBuild(
|
|||||||
emoji('success')
|
emoji('success')
|
||||||
)}\n`
|
)}\n`
|
||||||
);
|
);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function expandBuild(files: string[], build: Builder): Builder[] {
|
function expandBuild(files: string[], build: Builder): Builder[] {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import type {
|
|||||||
} from '../types';
|
} from '../types';
|
||||||
import { sharedPromise } from './promise';
|
import { sharedPromise } from './promise';
|
||||||
import { APIError } from './errors-ts';
|
import { APIError } from './errors-ts';
|
||||||
|
import { normalizeError } from './is-error';
|
||||||
|
|
||||||
const isSAMLError = (v: any): v is SAMLError => {
|
const isSAMLError = (v: any): v is SAMLError => {
|
||||||
return v && v.saml;
|
return v && v.saml;
|
||||||
@@ -146,10 +147,15 @@ export default class Client extends EventEmitter implements Stdio {
|
|||||||
const error = await responseError(res);
|
const error = await responseError(res);
|
||||||
|
|
||||||
if (isSAMLError(error)) {
|
if (isSAMLError(error)) {
|
||||||
// A SAML error means the token is expired, or is not
|
try {
|
||||||
// designated for the requested team, so the user needs
|
// A SAML error means the token is expired, or is not
|
||||||
// to re-authenticate
|
// designated for the requested team, so the user needs
|
||||||
await this.reauthenticate(error);
|
// to re-authenticate
|
||||||
|
await this.reauthenticate(error);
|
||||||
|
} catch (reauthError) {
|
||||||
|
// there's no sense in retrying
|
||||||
|
return bail(normalizeError(reauthError));
|
||||||
|
}
|
||||||
} else if (res.status >= 400 && res.status < 500) {
|
} else if (res.status >= 400 && res.status < 500) {
|
||||||
// Any other 4xx should bail without retrying
|
// Any other 4xx should bail without retrying
|
||||||
return bail(error);
|
return bail(error);
|
||||||
@@ -186,7 +192,7 @@ export default class Client extends EventEmitter implements Stdio {
|
|||||||
`Failed to re-authenticate for ${bold(error.scope)} scope`
|
`Failed to re-authenticate for ${bold(error.scope)} scope`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
process.exit(1);
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.authConfig.token = result.token;
|
this.authConfig.token = result.token;
|
||||||
|
|||||||
@@ -78,16 +78,23 @@ function getLastCommit(directory: string): Promise<git.Commit> {
|
|||||||
|
|
||||||
export function isDirty(directory: string, output: Output): Promise<boolean> {
|
export function isDirty(directory: string, output: Output): Promise<boolean> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
exec('git status -s', { cwd: directory }, function (err, stdout, stderr) {
|
// note: we specify the `--no-optional-locks` git flag so that `git status`
|
||||||
let debugMessage = `Failed to determine if Git repo has been modified:`;
|
// does not perform any "optional" operations such as optimizing the index
|
||||||
if (err || stderr) {
|
// in the background: https://git-scm.com/docs/git-status#_background_refresh
|
||||||
if (err) debugMessage += `\n${err}`;
|
exec(
|
||||||
if (stderr) debugMessage += `\n${stderr.trim()}`;
|
'git --no-optional-locks status -s',
|
||||||
output.debug(debugMessage);
|
{ cwd: directory },
|
||||||
return resolve(false);
|
function (err, stdout, stderr) {
|
||||||
|
let debugMessage = `Failed to determine if Git repo has been modified:`;
|
||||||
|
if (err || stderr) {
|
||||||
|
if (err) debugMessage += `\n${err}`;
|
||||||
|
if (stderr) debugMessage += `\n${stderr.trim()}`;
|
||||||
|
output.debug(debugMessage);
|
||||||
|
return resolve(false);
|
||||||
|
}
|
||||||
|
resolve(stdout.trim().length > 0);
|
||||||
}
|
}
|
||||||
resolve(stdout.trim().length > 0);
|
);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ import { MissingDotenvVarsError } from '../errors-ts';
|
|||||||
import cliPkg from '../pkg';
|
import cliPkg from '../pkg';
|
||||||
import { getVercelDirectory } from '../projects/link';
|
import { getVercelDirectory } from '../projects/link';
|
||||||
import { staticFiles as getFiles } from '../get-files';
|
import { staticFiles as getFiles } from '../get-files';
|
||||||
import { validateConfig } from './validate';
|
import { validateConfig } from '../validate-config';
|
||||||
import { devRouter, getRoutesTypes } from './router';
|
import { devRouter, getRoutesTypes } from './router';
|
||||||
import getMimeType from './mime-type';
|
import getMimeType from './mime-type';
|
||||||
import { executeBuild, getBuildMatches, shutdownBuilder } from './builder';
|
import { executeBuild, getBuildMatches, shutdownBuilder } from './builder';
|
||||||
|
|||||||
@@ -28,6 +28,16 @@ export async function writeProjectSettings(
|
|||||||
project: Project,
|
project: Project,
|
||||||
org: Org
|
org: Org
|
||||||
) {
|
) {
|
||||||
|
let analyticsId: string | undefined;
|
||||||
|
if (
|
||||||
|
project.analytics?.id &&
|
||||||
|
(!project.analytics.disabledAt ||
|
||||||
|
(project.analytics.enabledAt &&
|
||||||
|
project.analytics.enabledAt > project.analytics.disabledAt))
|
||||||
|
) {
|
||||||
|
analyticsId = project.analytics.id;
|
||||||
|
}
|
||||||
|
|
||||||
const projectLinkAndSettings: ProjectLinkAndSettings = {
|
const projectLinkAndSettings: ProjectLinkAndSettings = {
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
orgId: org.id,
|
orgId: org.id,
|
||||||
@@ -41,7 +51,7 @@ export async function writeProjectSettings(
|
|||||||
rootDirectory: project.rootDirectory,
|
rootDirectory: project.rootDirectory,
|
||||||
directoryListing: project.directoryListing,
|
directoryListing: project.directoryListing,
|
||||||
nodeVersion: project.nodeVersion,
|
nodeVersion: project.nodeVersion,
|
||||||
analyticsId: project.analytics?.id,
|
analyticsId,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const path = join(cwd, VERCEL_DIR, VERCEL_DIR_PROJECT);
|
const path = join(cwd, VERCEL_DIR, VERCEL_DIR_PROJECT);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
rewritesSchema,
|
rewritesSchema,
|
||||||
trailingSlashSchema,
|
trailingSlashSchema,
|
||||||
} from '@vercel/routing-utils';
|
} from '@vercel/routing-utils';
|
||||||
import { VercelConfig } from './types';
|
import { VercelConfig } from './dev/types';
|
||||||
import {
|
import {
|
||||||
functionsSchema,
|
functionsSchema,
|
||||||
buildsSchema,
|
buildsSchema,
|
||||||
@@ -16,6 +16,83 @@ import {
|
|||||||
} from '@vercel/build-utils';
|
} from '@vercel/build-utils';
|
||||||
import { fileNameSymbol } from '@vercel/client';
|
import { fileNameSymbol } from '@vercel/client';
|
||||||
|
|
||||||
|
const imagesSchema = {
|
||||||
|
type: 'object',
|
||||||
|
additionalProperties: false,
|
||||||
|
required: ['sizes'],
|
||||||
|
properties: {
|
||||||
|
contentSecurityPolicy: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 256,
|
||||||
|
},
|
||||||
|
dangerouslyAllowSVG: {
|
||||||
|
type: 'boolean',
|
||||||
|
},
|
||||||
|
domains: {
|
||||||
|
type: 'array',
|
||||||
|
minItems: 0,
|
||||||
|
maxItems: 50,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 256,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
formats: {
|
||||||
|
type: 'array',
|
||||||
|
minItems: 1,
|
||||||
|
maxItems: 4,
|
||||||
|
items: {
|
||||||
|
enum: ['image/avif', 'image/webp', 'image/jpeg', 'image/png'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
minimumCacheTTL: {
|
||||||
|
type: 'integer',
|
||||||
|
minimum: 1,
|
||||||
|
maximum: 315360000,
|
||||||
|
},
|
||||||
|
remotePatterns: {
|
||||||
|
type: 'array',
|
||||||
|
minItems: 0,
|
||||||
|
maxItems: 50,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
additionalProperties: false,
|
||||||
|
required: ['hostname'],
|
||||||
|
properties: {
|
||||||
|
protocol: {
|
||||||
|
enum: ['http', 'https'],
|
||||||
|
},
|
||||||
|
hostname: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 256,
|
||||||
|
},
|
||||||
|
port: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 5,
|
||||||
|
},
|
||||||
|
pathname: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 256,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sizes: {
|
||||||
|
type: 'array',
|
||||||
|
minItems: 1,
|
||||||
|
maxItems: 50,
|
||||||
|
items: {
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const vercelConfigSchema = {
|
const vercelConfigSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
// These are not all possibilities because `vc dev`
|
// These are not all possibilities because `vc dev`
|
||||||
@@ -30,6 +107,7 @@ const vercelConfigSchema = {
|
|||||||
rewrites: rewritesSchema,
|
rewrites: rewritesSchema,
|
||||||
trailingSlash: trailingSlashSchema,
|
trailingSlash: trailingSlashSchema,
|
||||||
functions: functionsSchema,
|
functions: functionsSchema,
|
||||||
|
images: imagesSchema,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import generateUUID from '../vendor/generate-uuid';
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
runtime: 'experimental-edge',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function edge(request, event) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
randomString: generateUUID(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
6
packages/cli/test/dev/fixtures/edge-function/vendor/generate-uuid/index-browser.js
vendored
Normal file
6
packages/cli/test/dev/fixtures/edge-function/vendor/generate-uuid/index-browser.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// This uses the `crypto` globaly,
|
||||||
|
// which will work fine in a browser or Edge Runtime environment
|
||||||
|
|
||||||
|
export default function generateUUID(message) {
|
||||||
|
return crypto.randomUUID();
|
||||||
|
}
|
||||||
8
packages/cli/test/dev/fixtures/edge-function/vendor/generate-uuid/index-node.js
vendored
Normal file
8
packages/cli/test/dev/fixtures/edge-function/vendor/generate-uuid/index-node.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
|
// this uses a core Node library,
|
||||||
|
// which will fail to execute in a browser or Edge Runtime context
|
||||||
|
|
||||||
|
export default function say(message) {
|
||||||
|
return crypto.generateUUID();
|
||||||
|
}
|
||||||
6
packages/cli/test/dev/fixtures/edge-function/vendor/generate-uuid/package.json
vendored
Normal file
6
packages/cli/test/dev/fixtures/edge-function/vendor/generate-uuid/package.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "generate-uuid",
|
||||||
|
"private": true,
|
||||||
|
"main": "index-node.js",
|
||||||
|
"browser": "index-browser.js"
|
||||||
|
}
|
||||||
@@ -86,6 +86,7 @@ test(
|
|||||||
testFixtureStdio('edge-function', async (testPath: any) => {
|
testFixtureStdio('edge-function', async (testPath: any) => {
|
||||||
await testPath(500, '/api/edge-500-response');
|
await testPath(500, '/api/edge-500-response');
|
||||||
await testPath(200, '/api/edge-success');
|
await testPath(200, '/api/edge-success');
|
||||||
|
await testPath(200, '/api/edge-import-browser');
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
"sizes": [256, 384, 600, 1000],
|
"sizes": [256, 384, 600, 1000],
|
||||||
"domains": [],
|
"domains": [],
|
||||||
"minimumCacheTTL": 60,
|
"minimumCacheTTL": 60,
|
||||||
"formats": ["image/webp", "image/avif"]
|
"formats": ["image/avif", "image/webp"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
packages/cli/test/fixtures/unit/commands/build/invalid-rewrites/.vercel/project.json
vendored
Normal file
7
packages/cli/test/fixtures/unit/commands/build/invalid-rewrites/.vercel/project.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"orgId": ".",
|
||||||
|
"projectId": ".",
|
||||||
|
"settings": {
|
||||||
|
"framework": null
|
||||||
|
}
|
||||||
|
}
|
||||||
1
packages/cli/test/fixtures/unit/commands/build/invalid-rewrites/index.html
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/build/invalid-rewrites/index.html
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<h1>Vercel</h1>
|
||||||
16
packages/cli/test/fixtures/unit/commands/build/invalid-rewrites/vercel.json
vendored
Normal file
16
packages/cli/test/fixtures/unit/commands/build/invalid-rewrites/vercel.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"rewrites": [
|
||||||
|
{
|
||||||
|
"source": "/one",
|
||||||
|
"destination": "/api/one"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "/two",
|
||||||
|
"destination": "/api/two"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/three",
|
||||||
|
"dest": "/api/three"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -3,20 +3,26 @@ import chance from 'chance';
|
|||||||
import { Deployment } from '@vercel/client';
|
import { Deployment } from '@vercel/client';
|
||||||
import { client } from './client';
|
import { client } from './client';
|
||||||
import { Build, User } from '../../src/types';
|
import { Build, User } from '../../src/types';
|
||||||
|
import type { Request, Response } from 'express';
|
||||||
|
|
||||||
let deployments = new Map<string, Deployment>();
|
let deployments = new Map<string, Deployment>();
|
||||||
let deploymentBuilds = new Map<Deployment, Build[]>();
|
let deploymentBuilds = new Map<Deployment, Build[]>();
|
||||||
|
let alreadySetupDeplomentEndpoints = false;
|
||||||
|
|
||||||
type State = Deployment['readyState'];
|
type State = Deployment['readyState'];
|
||||||
|
|
||||||
export function useDeployment({
|
export function useDeployment({
|
||||||
creator,
|
creator,
|
||||||
state = 'READY',
|
state = 'READY',
|
||||||
|
createdAt,
|
||||||
}: {
|
}: {
|
||||||
creator: Pick<User, 'id' | 'email' | 'name' | 'username'>;
|
creator: Pick<User, 'id' | 'email' | 'name' | 'username'>;
|
||||||
state?: State;
|
state?: State;
|
||||||
|
createdAt?: number;
|
||||||
}) {
|
}) {
|
||||||
const createdAt = Date.now();
|
setupDeploymentEndpoints();
|
||||||
|
|
||||||
|
createdAt = createdAt || Date.now();
|
||||||
const url = new URL(chance().url());
|
const url = new URL(chance().url());
|
||||||
const name = chance().name();
|
const name = chance().name();
|
||||||
const id = `dpl_${chance().guid()}`;
|
const id = `dpl_${chance().guid()}`;
|
||||||
@@ -99,6 +105,15 @@ export function useDeploymentMissingProjectSettings() {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
deployments = new Map();
|
deployments = new Map();
|
||||||
deploymentBuilds = new Map();
|
deploymentBuilds = new Map();
|
||||||
|
alreadySetupDeplomentEndpoints = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
function setupDeploymentEndpoints() {
|
||||||
|
if (alreadySetupDeplomentEndpoints) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
alreadySetupDeplomentEndpoints = true;
|
||||||
|
|
||||||
client.scenario.get('/:version/deployments/:id', (req, res) => {
|
client.scenario.get('/:version/deployments/:id', (req, res) => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
@@ -136,8 +151,21 @@ beforeEach(() => {
|
|||||||
res.json({ builds });
|
res.json({ builds });
|
||||||
});
|
});
|
||||||
|
|
||||||
client.scenario.get('/:version/now/deployments', (req, res) => {
|
function handleGetDeployments(req: Request, res: Response) {
|
||||||
const deploymentsList = Array.from(deployments.values());
|
const currentDeployments = Array.from(deployments.values()).sort(
|
||||||
res.json({ deployments: deploymentsList });
|
(a: Deployment, b: Deployment) => {
|
||||||
});
|
// sort in reverse chronological order
|
||||||
});
|
return b.createdAt - a.createdAt;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
pagination: {
|
||||||
|
count: currentDeployments.length,
|
||||||
|
},
|
||||||
|
deployments: currentDeployments,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
client.scenario.get('/:version/now/deployments', handleGetDeployments);
|
||||||
|
client.scenario.get('/:version/deployments', handleGetDeployments);
|
||||||
|
}
|
||||||
|
|||||||
55
packages/cli/test/unit/commands/bisect.test.ts
Normal file
55
packages/cli/test/unit/commands/bisect.test.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { client } from '../../mocks/client';
|
||||||
|
import { useUser } from '../../mocks/user';
|
||||||
|
import bisect from '../../../src/commands/bisect';
|
||||||
|
import { useDeployment } from '../../mocks/deployment';
|
||||||
|
|
||||||
|
describe('bisect', () => {
|
||||||
|
it('should find the bad deployment', async () => {
|
||||||
|
const user = useUser();
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const deployment1 = useDeployment({ creator: user, createdAt: now });
|
||||||
|
const deployment2 = useDeployment({
|
||||||
|
creator: user,
|
||||||
|
createdAt: now + 10000,
|
||||||
|
});
|
||||||
|
const deployment3 = useDeployment({
|
||||||
|
creator: user,
|
||||||
|
createdAt: now + 20000,
|
||||||
|
});
|
||||||
|
|
||||||
|
// also create an extra deployment before the known good deployment
|
||||||
|
// to make sure the bisect pool doesn't include it
|
||||||
|
useDeployment({
|
||||||
|
creator: user,
|
||||||
|
createdAt: now - 30000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const bisectPromise = bisect(client);
|
||||||
|
|
||||||
|
await expect(client.stderr).toOutput('Specify a URL where the bug occurs:');
|
||||||
|
client.stdin.write(`https://${deployment3.url}\n`);
|
||||||
|
|
||||||
|
await expect(client.stderr).toOutput(
|
||||||
|
'Specify a URL where the bug does not occur:'
|
||||||
|
);
|
||||||
|
client.stdin.write(`https://${deployment1.url}\n`);
|
||||||
|
|
||||||
|
await expect(client.stderr).toOutput(
|
||||||
|
'Specify the URL subpath where the bug occurs:'
|
||||||
|
);
|
||||||
|
client.stdin.write('/docs\n');
|
||||||
|
|
||||||
|
await expect(client.stderr).toOutput('Bisecting');
|
||||||
|
await expect(client.stderr).toOutput(
|
||||||
|
`Deployment URL: https://${deployment2.url}`
|
||||||
|
);
|
||||||
|
client.stdin.write('b\n');
|
||||||
|
|
||||||
|
await expect(client.stderr).toOutput(
|
||||||
|
`The first bad deployment is: https://${deployment2.url}`
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(bisectPromise).resolves.toEqual(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -750,11 +750,22 @@ describe('build', () => {
|
|||||||
const errorBuilds = builds.builds.filter((b: any) => 'error' in b);
|
const errorBuilds = builds.builds.filter((b: any) => 'error' in b);
|
||||||
expect(errorBuilds).toHaveLength(1);
|
expect(errorBuilds).toHaveLength(1);
|
||||||
|
|
||||||
expect(errorBuilds[0].error.name).toEqual('Error');
|
expect(errorBuilds[0].error).toEqual({
|
||||||
expect(errorBuilds[0].error.message).toMatch(`TS1005`);
|
name: 'Error',
|
||||||
expect(errorBuilds[0].error.message).toMatch(`',' expected.`);
|
message: expect.stringContaining('TS1005'),
|
||||||
expect(errorBuilds[0].error.hideStackTrace).toEqual(true);
|
stack: expect.stringContaining('api/typescript.ts'),
|
||||||
expect(errorBuilds[0].error.code).toEqual('NODE_TYPESCRIPT_ERROR');
|
hideStackTrace: true,
|
||||||
|
code: 'NODE_TYPESCRIPT_ERROR',
|
||||||
|
});
|
||||||
|
|
||||||
|
// top level "error" also contains the same error
|
||||||
|
expect(builds.error).toEqual({
|
||||||
|
name: 'Error',
|
||||||
|
message: expect.stringContaining('TS1005'),
|
||||||
|
stack: expect.stringContaining('api/typescript.ts'),
|
||||||
|
hideStackTrace: true,
|
||||||
|
code: 'NODE_TYPESCRIPT_ERROR',
|
||||||
|
});
|
||||||
|
|
||||||
// `config.json` contains `version`
|
// `config.json` contains `version`
|
||||||
const configJson = await fs.readJSON(join(output, 'config.json'));
|
const configJson = await fs.readJSON(join(output, 'config.json'));
|
||||||
@@ -920,7 +931,7 @@ describe('build', () => {
|
|||||||
delete process.env.__VERCEL_BUILD_RUNNING;
|
delete process.env.__VERCEL_BUILD_RUNNING;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should apply "images" configuration from `vercel.json`', async () => {
|
it('should apply "images" configuration from `vercel.json`', async () => {
|
||||||
const cwd = fixture('images');
|
const cwd = fixture('images');
|
||||||
const output = join(cwd, '.vercel/output');
|
const output = join(cwd, '.vercel/output');
|
||||||
@@ -936,7 +947,7 @@ describe('build', () => {
|
|||||||
sizes: [256, 384, 600, 1000],
|
sizes: [256, 384, 600, 1000],
|
||||||
domains: [],
|
domains: [],
|
||||||
minimumCacheTTL: 60,
|
minimumCacheTTL: 60,
|
||||||
formats: ['image/webp', 'image/avif'],
|
formats: ['image/avif', 'image/webp'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
@@ -945,6 +956,38 @@ describe('build', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fail with invalid "rewrites" configuration from `vercel.json`', async () => {
|
||||||
|
const cwd = fixture('invalid-rewrites');
|
||||||
|
const output = join(cwd, '.vercel/output');
|
||||||
|
try {
|
||||||
|
process.chdir(cwd);
|
||||||
|
const exitCode = await build(client);
|
||||||
|
expect(exitCode).toEqual(1);
|
||||||
|
await expect(client.stderr).toOutput(
|
||||||
|
'Error: Invalid vercel.json - `rewrites[2]` should NOT have additional property `src`. Did you mean `source`?' +
|
||||||
|
'\n' +
|
||||||
|
'View Documentation: https://vercel.com/docs/configuration#project/rewrites'
|
||||||
|
);
|
||||||
|
const builds = await fs.readJSON(join(output, 'builds.json'));
|
||||||
|
expect(builds.builds).toBeUndefined();
|
||||||
|
expect(builds.error).toEqual({
|
||||||
|
name: 'Error',
|
||||||
|
message:
|
||||||
|
'Invalid vercel.json - `rewrites[2]` should NOT have additional property `src`. Did you mean `source`?',
|
||||||
|
stack: expect.stringContaining('at validateConfig'),
|
||||||
|
hideStackTrace: true,
|
||||||
|
code: 'INVALID_VERCEL_CONFIG',
|
||||||
|
link: 'https://vercel.com/docs/configuration#project/rewrites',
|
||||||
|
action: 'View Documentation',
|
||||||
|
});
|
||||||
|
const configJson = await fs.readJSON(join(output, 'config.json'));
|
||||||
|
expect(configJson.version).toBe(3);
|
||||||
|
} finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
delete process.env.__VERCEL_BUILD_RUNNING;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
describe('should find packages with different main/module/browser keys', function () {
|
describe('should find packages with different main/module/browser keys', function () {
|
||||||
let output: string;
|
let output: string;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { validateConfig } from '../../../../src/util/dev/validate';
|
import { validateConfig } from '../../../../src/util/validate-config';
|
||||||
|
|
||||||
describe('validateConfig', () => {
|
describe('validateConfig', () => {
|
||||||
it('should not error with empty config', async () => {
|
it('should not error with empty config', async () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/client",
|
"name": "@vercel/client",
|
||||||
"version": "12.2.6",
|
"version": "12.2.8",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"homepage": "https://vercel.com",
|
"homepage": "https://vercel.com",
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "5.4.4",
|
"@vercel/build-utils": "5.5.1",
|
||||||
"@vercel/routing-utils": "2.0.2",
|
"@vercel/routing-utils": "2.0.2",
|
||||||
"@zeit/fetch": "5.2.0",
|
"@zeit/fetch": "5.2.0",
|
||||||
"async-retry": "1.2.3",
|
"async-retry": "1.2.3",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/fs-detectors",
|
"name": "@vercel/fs-detectors",
|
||||||
"version": "3.3.0",
|
"version": "3.4.0",
|
||||||
"description": "Vercel filesystem detectors",
|
"description": "Vercel filesystem detectors",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
|
|||||||
@@ -89,33 +89,34 @@ export abstract class DetectorFilesystem {
|
|||||||
if (!p) {
|
if (!p) {
|
||||||
p = this._readdir(dirPath);
|
p = this._readdir(dirPath);
|
||||||
this.readdirCache.set(dirPath, p);
|
this.readdirCache.set(dirPath, p);
|
||||||
|
}
|
||||||
|
|
||||||
const directoryContent = await p;
|
const directoryContent = await p;
|
||||||
const directoryFiles = new Set<string>();
|
const directoryFiles = new Set<string>();
|
||||||
|
|
||||||
for (const file of directoryContent) {
|
for (const file of directoryContent) {
|
||||||
if (file.type === 'file') {
|
if (file.type === 'file') {
|
||||||
// we know this file exists, mark it as so on the filesystem
|
// we know this file exists, mark it as so on the filesystem
|
||||||
this.fileCache.set(file.path, Promise.resolve(true));
|
this.fileCache.set(file.path, Promise.resolve(true));
|
||||||
this.pathCache.set(file.path, Promise.resolve(true));
|
this.pathCache.set(file.path, Promise.resolve(true));
|
||||||
directoryFiles.add(file.name);
|
directoryFiles.add(file.name);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options?.potentialFiles) {
|
|
||||||
// calculate the set of paths that truly do not exist
|
|
||||||
const filesThatDoNotExist = options.potentialFiles.filter(
|
|
||||||
path => !directoryFiles.has(path)
|
|
||||||
);
|
|
||||||
for (const filePath of filesThatDoNotExist) {
|
|
||||||
const fullFilePath =
|
|
||||||
dirPath === '/' ? filePath : posixPath.join(dirPath, filePath);
|
|
||||||
// we know this file does not exist, mark it as so on the filesystem
|
|
||||||
this.fileCache.set(fullFilePath, Promise.resolve(false));
|
|
||||||
this.pathCache.set(fullFilePath, Promise.resolve(false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options?.potentialFiles) {
|
||||||
|
// calculate the set of paths that truly do not exist
|
||||||
|
const filesThatDoNotExist = options.potentialFiles.filter(
|
||||||
|
path => !directoryFiles.has(path)
|
||||||
|
);
|
||||||
|
for (const filePath of filesThatDoNotExist) {
|
||||||
|
const fullFilePath =
|
||||||
|
dirPath === '/' ? filePath : posixPath.join(dirPath, filePath);
|
||||||
|
// we know this file does not exist, mark it as so on the filesystem
|
||||||
|
this.fileCache.set(fullFilePath, Promise.resolve(false));
|
||||||
|
this.pathCache.set(fullFilePath, Promise.resolve(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ export async function getWorkspacePackagePaths({
|
|||||||
case 'nx':
|
case 'nx':
|
||||||
results = await getNxWorkspacePackagePaths({ fs: workspaceFs });
|
results = await getNxWorkspacePackagePaths({ fs: workspaceFs });
|
||||||
break;
|
break;
|
||||||
|
case 'rush':
|
||||||
|
results = await getRushWorkspacePackagePaths({ fs: workspaceFs });
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unknown workspace implementation: ${type}`);
|
throw new Error(`Unknown workspace implementation: ${type}`);
|
||||||
}
|
}
|
||||||
@@ -58,6 +61,14 @@ type PnpmWorkspaces = {
|
|||||||
packages?: string[];
|
packages?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type RushWorkspaces = {
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
projectFolder: string;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
const isWin = process.platform === 'win32';
|
const isWin = process.platform === 'win32';
|
||||||
const normalizePath = (p: string) => (isWin ? p.replace(/\\/g, '/') : p);
|
const normalizePath = (p: string) => (isWin ? p.replace(/\\/g, '/') : p);
|
||||||
|
|
||||||
@@ -127,3 +138,23 @@ async function getPnpmWorkspacePackagePaths({
|
|||||||
|
|
||||||
return getPackagePaths(packages, fs);
|
return getPackagePaths(packages, fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getRushWorkspacePackagePaths({
|
||||||
|
fs,
|
||||||
|
}: GetPackagePathOptions): Promise<string[]> {
|
||||||
|
const rushWorkspaceAsBuffer = await fs.readFile('rush.json');
|
||||||
|
|
||||||
|
const { projects = [] } = JSON.parse(
|
||||||
|
rushWorkspaceAsBuffer.toString()
|
||||||
|
) as RushWorkspaces;
|
||||||
|
|
||||||
|
if (Array.isArray(projects)) {
|
||||||
|
const packages = projects
|
||||||
|
.filter(proj => proj.projectFolder)
|
||||||
|
.map(project => project.projectFolder);
|
||||||
|
|
||||||
|
return getPackagePaths(packages, fs);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export interface GetWorkspaceOptions {
|
|||||||
cwd?: string;
|
cwd?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WorkspaceType = 'yarn' | 'pnpm' | 'npm' | 'nx';
|
export type WorkspaceType = 'yarn' | 'pnpm' | 'npm' | 'nx' | 'rush';
|
||||||
|
|
||||||
export type Workspace = {
|
export type Workspace = {
|
||||||
type: WorkspaceType;
|
type: WorkspaceType;
|
||||||
|
|||||||
@@ -71,6 +71,17 @@ export const workspaceManagers: Array<
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'rush',
|
||||||
|
slug: 'rush',
|
||||||
|
detectors: {
|
||||||
|
every: [
|
||||||
|
{
|
||||||
|
path: 'rush.json',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'default',
|
name: 'default',
|
||||||
slug: 'yarn',
|
slug: 'yarn',
|
||||||
|
|||||||
15
packages/fs-detectors/test/fixtures/40-rush-monorepo/apps/my-app/package.json
vendored
Normal file
15
packages/fs-detectors/test/fixtures/40-rush-monorepo/apps/my-app/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "my-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
15
packages/fs-detectors/test/fixtures/40-rush-monorepo/apps/my-second-app/package.json
vendored
Normal file
15
packages/fs-detectors/test/fixtures/40-rush-monorepo/apps/my-second-app/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "my-second-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,5 +23,14 @@
|
|||||||
"postRushBuild": []
|
"postRushBuild": []
|
||||||
},
|
},
|
||||||
"variants": [],
|
"variants": [],
|
||||||
"projects": []
|
"projects": [
|
||||||
|
{
|
||||||
|
"packageName": "my-app",
|
||||||
|
"projectFolder": "apps/my-app"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "my-second-app",
|
||||||
|
"projectFolder": "apps/my-second-app"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "b",
|
"name": "app-one",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "b",
|
"name": "app-two",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
27
packages/fs-detectors/test/fixtures/41-rush-monorepo-empty/rush.json
vendored
Normal file
27
packages/fs-detectors/test/fixtures/41-rush-monorepo-empty/rush.json
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json",
|
||||||
|
|
||||||
|
"rushVersion": "5.76.1",
|
||||||
|
|
||||||
|
"pnpmVersion": "6.7.1",
|
||||||
|
|
||||||
|
"pnpmOptions": {
|
||||||
|
"useWorkspaces": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"nodeSupportedVersionRange": ">=12.13.0 <13.0.0 || >=14.15.0 <15.0.0 || >=16.13.0 <17.0.0",
|
||||||
|
|
||||||
|
"gitPolicy": {},
|
||||||
|
|
||||||
|
"repository": {},
|
||||||
|
"eventHooks": {
|
||||||
|
"preRushInstall": [],
|
||||||
|
|
||||||
|
"postRushInstall": [],
|
||||||
|
"preRushBuild": [],
|
||||||
|
|
||||||
|
"postRushBuild": []
|
||||||
|
},
|
||||||
|
"variants": [],
|
||||||
|
"projects": []
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "b",
|
"name": "app-one",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "b",
|
"name": "app-two",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
27
packages/fs-detectors/test/fixtures/42-rush-json-invalid/rush.json
vendored
Normal file
27
packages/fs-detectors/test/fixtures/42-rush-json-invalid/rush.json
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json",
|
||||||
|
|
||||||
|
"rushVersion": "5.76.1",
|
||||||
|
|
||||||
|
"pnpmVersion": "6.7.1",
|
||||||
|
|
||||||
|
"pnpmOptions": {
|
||||||
|
"useWorkspaces": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"nodeSupportedVersionRange": ">=12.13.0 <13.0.0 || >=14.15.0 <15.0.0 || >=16.13.0 <17.0.0",
|
||||||
|
|
||||||
|
"gitPolicy": {},
|
||||||
|
|
||||||
|
"repository": {},
|
||||||
|
"eventHooks": {
|
||||||
|
"preRushInstall": [],
|
||||||
|
|
||||||
|
"postRushInstall": [],
|
||||||
|
"preRushBuild": [],
|
||||||
|
|
||||||
|
"postRushBuild": []
|
||||||
|
},
|
||||||
|
"variants": [],
|
||||||
|
"projects": "projects"
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "b",
|
"name": "app-one",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "b",
|
"name": "app-two",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "b",
|
"name": "app-one",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "b",
|
"name": "app-two",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
15
packages/fs-detectors/test/fixtures/45-rush-no-project-folder/apps/my-app/package.json
vendored
Normal file
15
packages/fs-detectors/test/fixtures/45-rush-no-project-folder/apps/my-app/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "my-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
15
packages/fs-detectors/test/fixtures/45-rush-no-project-folder/apps/my-second-app/package.json
vendored
Normal file
15
packages/fs-detectors/test/fixtures/45-rush-no-project-folder/apps/my-second-app/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "my-second-app",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
35
packages/fs-detectors/test/fixtures/45-rush-no-project-folder/rush.json
vendored
Normal file
35
packages/fs-detectors/test/fixtures/45-rush-no-project-folder/rush.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json",
|
||||||
|
|
||||||
|
"rushVersion": "5.76.1",
|
||||||
|
|
||||||
|
"pnpmVersion": "6.7.1",
|
||||||
|
|
||||||
|
"pnpmOptions": {
|
||||||
|
"useWorkspaces": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"nodeSupportedVersionRange": ">=12.13.0 <13.0.0 || >=14.15.0 <15.0.0 || >=16.13.0 <17.0.0",
|
||||||
|
|
||||||
|
"gitPolicy": {},
|
||||||
|
|
||||||
|
"repository": {},
|
||||||
|
"eventHooks": {
|
||||||
|
"preRushInstall": [],
|
||||||
|
|
||||||
|
"postRushInstall": [],
|
||||||
|
"preRushBuild": [],
|
||||||
|
|
||||||
|
"postRushBuild": []
|
||||||
|
},
|
||||||
|
"variants": [],
|
||||||
|
"projects": [
|
||||||
|
{
|
||||||
|
"packageName": "my-app"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "my-second-app",
|
||||||
|
"projectFolder": "apps/my-second-app"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -172,6 +172,20 @@ describe('DetectorFilesystem', () => {
|
|||||||
hasPathSpy.mock.calls.length = 0;
|
hasPathSpy.mock.calls.length = 0;
|
||||||
expect(await fs.hasPath('packages/app1/package.json')).toBe(true);
|
expect(await fs.hasPath('packages/app1/package.json')).toBe(true);
|
||||||
expect(hasPathSpy).not.toHaveBeenCalled();
|
expect(hasPathSpy).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await fs.readdir('packages/app1', { potentialFiles: ['vercel.json'] })
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
name: 'package.json',
|
||||||
|
path: 'packages/app1/package.json',
|
||||||
|
type: 'file',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
hasPathSpy.mock.calls.length = 0;
|
||||||
|
expect(await fs.hasPath('packages/app1/vercel.json')).toBe(false);
|
||||||
|
expect(hasPathSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to write files', async () => {
|
it('should be able to write files', async () => {
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ describe.each<[string, string[]]>([
|
|||||||
['42-npm-workspace-with-nx', ['/apps/app-one', '/apps/app-two']],
|
['42-npm-workspace-with-nx', ['/apps/app-one', '/apps/app-two']],
|
||||||
['43-nx-json-misshaped', []],
|
['43-nx-json-misshaped', []],
|
||||||
['44-nx-json-string', []],
|
['44-nx-json-string', []],
|
||||||
])('`getWorkspacesPackagePaths()`', (fixturePath, packagePaths) => {
|
['40-rush-monorepo', ['/apps/my-app', '/apps/my-second-app']],
|
||||||
|
['41-rush-monorepo-empty', []],
|
||||||
|
['42-rush-json-invalid', []],
|
||||||
|
['45-rush-no-project-folder', ['/apps/my-second-app']],
|
||||||
|
])('`getWorkspacePackagePaths()`', (fixturePath, packagePaths) => {
|
||||||
const testName =
|
const testName =
|
||||||
packagePaths.length > 0
|
packagePaths.length > 0
|
||||||
? `should detect ${packagePaths.join()} package${
|
? `should detect ${packagePaths.join()} package${
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ interface Analyzed {
|
|||||||
found?: boolean;
|
found?: boolean;
|
||||||
packageName: string;
|
packageName: string;
|
||||||
functionName: string;
|
functionName: string;
|
||||||
watch: string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PortInfo {
|
interface PortInfo {
|
||||||
@@ -498,18 +497,8 @@ export async function build({
|
|||||||
environment: {},
|
environment: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
const watch = parsedAnalyzed.watch;
|
|
||||||
let watchSub: string[] = [];
|
|
||||||
// if `entrypoint` located in subdirectory
|
|
||||||
// we will need to concat it with return watch array
|
|
||||||
if (entrypointArr.length > 1) {
|
|
||||||
entrypointArr.pop();
|
|
||||||
watchSub = parsedAnalyzed.watch.map(file => join(...entrypointArr, file));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
output: lambda,
|
output: lambda,
|
||||||
watch: watch.concat(watchSub),
|
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
debug('Go Builder Error: ' + error);
|
debug('Go Builder Error: ' + error);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/go",
|
"name": "@vercel/go",
|
||||||
"version": "2.2.7",
|
"version": "2.2.9",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"@types/jest": "28.1.6",
|
"@types/jest": "28.1.6",
|
||||||
"@types/node-fetch": "^2.3.0",
|
"@types/node-fetch": "^2.3.0",
|
||||||
"@types/tar": "^4.0.0",
|
"@types/tar": "^4.0.0",
|
||||||
"@vercel/build-utils": "5.4.4",
|
"@vercel/build-utils": "5.5.1",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"async-retry": "1.3.1",
|
"async-retry": "1.3.1",
|
||||||
"execa": "^1.0.0",
|
"execa": "^1.0.0",
|
||||||
|
|||||||
10
packages/go/test/fixtures/25-other-func-conflict/api/one.go
vendored
Normal file
10
packages/go/test/fixtures/25-other-func-conflict/api/one.go
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Handler2(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, "from one.go")
|
||||||
|
}
|
||||||
10
packages/go/test/fixtures/25-other-func-conflict/api/two.go
vendored
Normal file
10
packages/go/test/fixtures/25-other-func-conflict/api/two.go
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, "from two.go")
|
||||||
|
}
|
||||||
3
packages/go/test/fixtures/25-other-func-conflict/go.mod
vendored
Normal file
3
packages/go/test/fixtures/25-other-func-conflict/go.mod
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module handler
|
||||||
|
|
||||||
|
go 1.16
|
||||||
12
packages/go/test/fixtures/25-other-func-conflict/probes.json
vendored
Normal file
12
packages/go/test/fixtures/25-other-func-conflict/probes.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"probes": [
|
||||||
|
{
|
||||||
|
"path": "/api/one",
|
||||||
|
"mustContain": "from one.go"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/api/two",
|
||||||
|
"mustContain": "from two.go"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
@@ -104,84 +103,6 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
se := string(rf)
|
|
||||||
|
|
||||||
var files []string
|
|
||||||
var relatedFiles []string
|
|
||||||
|
|
||||||
// Add entrypoint to watchlist
|
|
||||||
relFileName, err := filepath.Rel(filepath.Dir(fileName), fileName)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
relatedFiles = append(relatedFiles, relFileName)
|
|
||||||
|
|
||||||
// looking for all go files that have export func
|
|
||||||
// using in entrypoint
|
|
||||||
err = filepath.Walk(filepath.Dir(fileName), visit(&files))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// looking related packages
|
|
||||||
var modPath string
|
|
||||||
flag.StringVar(&modPath, "modpath", "", "module path")
|
|
||||||
flag.Parse()
|
|
||||||
if len(modPath) > 1 {
|
|
||||||
err = filepath.Walk(modPath, visit(&files))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range files {
|
|
||||||
absFileName, _ := filepath.Abs(fileName)
|
|
||||||
absFile, _ := filepath.Abs(file)
|
|
||||||
// if it isn't entrypoint
|
|
||||||
if absFileName != absFile {
|
|
||||||
// find all export structs and functions
|
|
||||||
pf := parse(file)
|
|
||||||
var exportedDecl []string
|
|
||||||
|
|
||||||
ast.Inspect(pf, func(n ast.Node) bool {
|
|
||||||
switch t := n.(type) {
|
|
||||||
case *ast.FuncDecl:
|
|
||||||
if t.Name.IsExported() {
|
|
||||||
exportedDecl = append(exportedDecl, t.Name.Name)
|
|
||||||
}
|
|
||||||
// find variable declarations
|
|
||||||
case *ast.TypeSpec:
|
|
||||||
// which are public
|
|
||||||
if t.Name.IsExported() {
|
|
||||||
switch t.Type.(type) {
|
|
||||||
// and are interfaces
|
|
||||||
case *ast.StructType:
|
|
||||||
exportedDecl = append(exportedDecl, t.Name.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, ed := range exportedDecl {
|
|
||||||
if strings.Contains(se, ed) {
|
|
||||||
// find relative path of related file
|
|
||||||
var basePath string
|
|
||||||
if modPath == "" {
|
|
||||||
basePath = filepath.Dir(fileName)
|
|
||||||
} else {
|
|
||||||
basePath = modPath
|
|
||||||
}
|
|
||||||
|
|
||||||
rel, err := filepath.Rel(basePath, file)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
relatedFiles = append(relatedFiles, rel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed := parse(fileName)
|
parsed := parse(fileName)
|
||||||
offset := parsed.Pos()
|
offset := parsed.Pos()
|
||||||
@@ -207,7 +128,6 @@ func main() {
|
|||||||
analyzed := analyze{
|
analyzed := analyze{
|
||||||
PackageName: parsed.Name.Name,
|
PackageName: parsed.Name.Name,
|
||||||
FuncName: fn.Name.Name,
|
FuncName: fn.Name.Name,
|
||||||
Watch: unique(relatedFiles),
|
|
||||||
}
|
}
|
||||||
analyzedJSON, _ := json.Marshal(analyzed)
|
analyzedJSON, _ := json.Marshal(analyzed)
|
||||||
fmt.Print(string(analyzedJSON))
|
fmt.Print(string(analyzedJSON))
|
||||||
@@ -229,7 +149,6 @@ func main() {
|
|||||||
analyzed := analyze{
|
analyzed := analyze{
|
||||||
PackageName: parsed.Name.Name,
|
PackageName: parsed.Name.Name,
|
||||||
FuncName: fn.Name.Name,
|
FuncName: fn.Name.Name,
|
||||||
Watch: unique(relatedFiles),
|
|
||||||
}
|
}
|
||||||
analyzedJSON, _ := json.Marshal(analyzed)
|
analyzedJSON, _ := json.Marshal(analyzed)
|
||||||
fmt.Print(string(analyzedJSON))
|
fmt.Print(string(analyzedJSON))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/hydrogen",
|
"name": "@vercel/hydrogen",
|
||||||
"version": "0.0.20",
|
"version": "0.0.22",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"homepage": "https://vercel.com/docs",
|
"homepage": "https://vercel.com/docs",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "27.5.1",
|
"@types/jest": "27.5.1",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@vercel/build-utils": "5.4.4",
|
"@vercel/build-utils": "5.5.1",
|
||||||
"typescript": "4.6.4"
|
"typescript": "4.6.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/next",
|
"name": "@vercel/next",
|
||||||
"version": "3.1.27",
|
"version": "3.1.30",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
"@types/semver": "6.0.0",
|
"@types/semver": "6.0.0",
|
||||||
"@types/text-table": "0.2.1",
|
"@types/text-table": "0.2.1",
|
||||||
"@types/webpack-sources": "3.2.0",
|
"@types/webpack-sources": "3.2.0",
|
||||||
"@vercel/build-utils": "5.4.4",
|
"@vercel/build-utils": "5.5.1",
|
||||||
"@vercel/nft": "0.22.1",
|
"@vercel/nft": "0.22.1",
|
||||||
"@vercel/routing-utils": "2.0.2",
|
"@vercel/routing-utils": "2.0.2",
|
||||||
"async-sema": "3.0.1",
|
"async-sema": "3.0.1",
|
||||||
|
|||||||
@@ -1088,10 +1088,15 @@ export const build: BuildV2 = async ({
|
|||||||
'pages'
|
'pages'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let appDir: string | null = null;
|
||||||
const appPathRoutesManifest = await readJSON(
|
const appPathRoutesManifest = await readJSON(
|
||||||
path.join(entryPath, outputDirectory, 'app-path-routes-manifest.json')
|
path.join(entryPath, outputDirectory, 'app-path-routes-manifest.json')
|
||||||
).catch(() => null);
|
).catch(() => null);
|
||||||
|
|
||||||
|
if (appPathRoutesManifest) {
|
||||||
|
appDir = path.join(pagesDir, '../app');
|
||||||
|
}
|
||||||
|
|
||||||
const { pages, appPaths: lambdaAppPaths } = await getServerlessPages({
|
const { pages, appPaths: lambdaAppPaths } = await getServerlessPages({
|
||||||
pagesDir,
|
pagesDir,
|
||||||
entryPath,
|
entryPath,
|
||||||
@@ -2032,9 +2037,10 @@ export const build: BuildV2 = async ({
|
|||||||
console.timeEnd(allLambdasLabel);
|
console.timeEnd(allLambdasLabel);
|
||||||
}
|
}
|
||||||
const prerenderRoute = onPrerenderRoute({
|
const prerenderRoute = onPrerenderRoute({
|
||||||
|
appDir,
|
||||||
|
pagesDir,
|
||||||
hasPages404,
|
hasPages404,
|
||||||
static404Page,
|
static404Page,
|
||||||
pagesDir,
|
|
||||||
pageLambdaMap,
|
pageLambdaMap,
|
||||||
lambdas,
|
lambdas,
|
||||||
isServerMode,
|
isServerMode,
|
||||||
@@ -2042,6 +2048,7 @@ export const build: BuildV2 = async ({
|
|||||||
entryDirectory,
|
entryDirectory,
|
||||||
routesManifest,
|
routesManifest,
|
||||||
prerenderManifest,
|
prerenderManifest,
|
||||||
|
appPathRoutesManifest,
|
||||||
isSharedLambdas,
|
isSharedLambdas,
|
||||||
canUsePreviewMode,
|
canUsePreviewMode,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -881,6 +881,7 @@ export async function serverBuild({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const prerenderRoute = onPrerenderRoute({
|
const prerenderRoute = onPrerenderRoute({
|
||||||
|
appDir,
|
||||||
pagesDir,
|
pagesDir,
|
||||||
pageLambdaMap: {},
|
pageLambdaMap: {},
|
||||||
lambdas,
|
lambdas,
|
||||||
@@ -888,6 +889,7 @@ export async function serverBuild({
|
|||||||
entryDirectory,
|
entryDirectory,
|
||||||
routesManifest,
|
routesManifest,
|
||||||
prerenderManifest,
|
prerenderManifest,
|
||||||
|
appPathRoutesManifest,
|
||||||
isServerMode: true,
|
isServerMode: true,
|
||||||
isSharedLambdas: false,
|
isSharedLambdas: false,
|
||||||
canUsePreviewMode,
|
canUsePreviewMode,
|
||||||
@@ -1005,7 +1007,7 @@ export async function serverBuild({
|
|||||||
currentRouteSrc.length - 1
|
currentRouteSrc.length - 1
|
||||||
)}${
|
)}${
|
||||||
currentRouteSrc[currentRouteSrc.length - 2] === '(' ? '' : '|'
|
currentRouteSrc[currentRouteSrc.length - 2] === '(' ? '' : '|'
|
||||||
}${route})`;
|
}${route}/?)`;
|
||||||
|
|
||||||
if (isLastRoute) {
|
if (isLastRoute) {
|
||||||
pushRoute(currentRouteSrc);
|
pushRoute(currentRouteSrc);
|
||||||
@@ -1129,6 +1131,23 @@ export async function serverBuild({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (appPathRoutesManifest) {
|
||||||
|
// create .rsc variant for app lambdas and edge functions
|
||||||
|
// to match prerenders so we can route the same when the
|
||||||
|
// __flight__ header is present
|
||||||
|
const edgeFunctions = middleware.edgeFunctions;
|
||||||
|
|
||||||
|
for (let route of Object.values(appPathRoutesManifest)) {
|
||||||
|
route = path.posix.join('./', route === '/' ? '/index' : route);
|
||||||
|
|
||||||
|
if (lambdas[route]) {
|
||||||
|
lambdas[`${route}.rsc`] = lambdas[route];
|
||||||
|
} else if (edgeFunctions[route]) {
|
||||||
|
edgeFunctions[`${route}.rsc`] = edgeFunctions[route];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
wildcard: wildcardConfig,
|
wildcard: wildcardConfig,
|
||||||
images:
|
images:
|
||||||
@@ -1367,6 +1386,22 @@ export async function serverBuild({
|
|||||||
// to prevent a local/deploy mismatch
|
// to prevent a local/deploy mismatch
|
||||||
...(!isCorrectMiddlewareOrder ? middleware.staticRoutes : []),
|
...(!isCorrectMiddlewareOrder ? middleware.staticRoutes : []),
|
||||||
|
|
||||||
|
...(appDir
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
src: `^${path.posix.join('/', entryDirectory, '/(.*)$')}`,
|
||||||
|
has: [
|
||||||
|
{
|
||||||
|
type: 'header',
|
||||||
|
key: '__flight__',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dest: path.posix.join('/', entryDirectory, '/$1.rsc'),
|
||||||
|
check: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
|
||||||
// Next.js page lambdas, `static/` folder, reserved assets, and `public/`
|
// Next.js page lambdas, `static/` folder, reserved assets, and `public/`
|
||||||
// folder
|
// folder
|
||||||
{ handle: 'filesystem' },
|
{ handle: 'filesystem' },
|
||||||
|
|||||||
@@ -1660,10 +1660,12 @@ export const onPrerenderRouteInitial = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
type OnPrerenderRouteArgs = {
|
type OnPrerenderRouteArgs = {
|
||||||
|
appDir: string | null;
|
||||||
pagesDir: string;
|
pagesDir: string;
|
||||||
static404Page?: string;
|
static404Page?: string;
|
||||||
hasPages404: boolean;
|
hasPages404: boolean;
|
||||||
entryDirectory: string;
|
entryDirectory: string;
|
||||||
|
appPathRoutesManifest?: Record<string, string>;
|
||||||
prerenderManifest: NextPrerenderedRoutes;
|
prerenderManifest: NextPrerenderedRoutes;
|
||||||
isSharedLambdas: boolean;
|
isSharedLambdas: boolean;
|
||||||
isServerMode: boolean;
|
isServerMode: boolean;
|
||||||
@@ -1694,6 +1696,7 @@ export const onPrerenderRoute =
|
|||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
|
appDir,
|
||||||
pagesDir,
|
pagesDir,
|
||||||
hasPages404,
|
hasPages404,
|
||||||
static404Page,
|
static404Page,
|
||||||
@@ -1760,44 +1763,6 @@ export const onPrerenderRoute =
|
|||||||
|
|
||||||
const isNotFound = prerenderManifest.notFoundRoutes.includes(routeKey);
|
const isNotFound = prerenderManifest.notFoundRoutes.includes(routeKey);
|
||||||
|
|
||||||
const htmlFsRef =
|
|
||||||
isBlocking || (isNotFound && !static404Page)
|
|
||||||
? // Blocking pages do not have an HTML fallback
|
|
||||||
null
|
|
||||||
: new FileFsRef({
|
|
||||||
fsPath: path.join(
|
|
||||||
pagesDir,
|
|
||||||
isFallback
|
|
||||||
? // Fallback pages have a special file.
|
|
||||||
addLocaleOrDefault(
|
|
||||||
prerenderManifest.fallbackRoutes[routeKey].fallback,
|
|
||||||
routesManifest,
|
|
||||||
locale
|
|
||||||
)
|
|
||||||
: // Otherwise, the route itself should exist as a static HTML
|
|
||||||
// file.
|
|
||||||
`${
|
|
||||||
isOmitted || isNotFound
|
|
||||||
? addLocaleOrDefault('/404', routesManifest, locale)
|
|
||||||
: routeFileNoExt
|
|
||||||
}.html`
|
|
||||||
),
|
|
||||||
});
|
|
||||||
const jsonFsRef =
|
|
||||||
// JSON data does not exist for fallback or blocking pages
|
|
||||||
isFallback || isBlocking || (isNotFound && !static404Page)
|
|
||||||
? null
|
|
||||||
: new FileFsRef({
|
|
||||||
fsPath: path.join(
|
|
||||||
pagesDir,
|
|
||||||
`${
|
|
||||||
isOmitted || isNotFound
|
|
||||||
? addLocaleOrDefault('/404.html', routesManifest, locale)
|
|
||||||
: routeFileNoExt + '.json'
|
|
||||||
}`
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
let initialRevalidate: false | number;
|
let initialRevalidate: false | number;
|
||||||
let srcRoute: string | null;
|
let srcRoute: string | null;
|
||||||
let dataRoute: string;
|
let dataRoute: string;
|
||||||
@@ -1826,6 +1791,52 @@ export const onPrerenderRoute =
|
|||||||
({ initialRevalidate, srcRoute, dataRoute } = pr);
|
({ initialRevalidate, srcRoute, dataRoute } = pr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isAppPathRoute = false;
|
||||||
|
// TODO: leverage manifest to determine app paths more accurately
|
||||||
|
if (appDir && srcRoute && dataRoute.endsWith('.rsc')) {
|
||||||
|
isAppPathRoute = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const htmlFsRef =
|
||||||
|
isBlocking || (isNotFound && !static404Page)
|
||||||
|
? // Blocking pages do not have an HTML fallback
|
||||||
|
null
|
||||||
|
: new FileFsRef({
|
||||||
|
fsPath: path.join(
|
||||||
|
isAppPathRoute && appDir ? appDir : pagesDir,
|
||||||
|
isFallback
|
||||||
|
? // Fallback pages have a special file.
|
||||||
|
addLocaleOrDefault(
|
||||||
|
prerenderManifest.fallbackRoutes[routeKey].fallback,
|
||||||
|
routesManifest,
|
||||||
|
locale
|
||||||
|
)
|
||||||
|
: // Otherwise, the route itself should exist as a static HTML
|
||||||
|
// file.
|
||||||
|
`${
|
||||||
|
isOmitted || isNotFound
|
||||||
|
? addLocaleOrDefault('/404', routesManifest, locale)
|
||||||
|
: routeFileNoExt
|
||||||
|
}.html`
|
||||||
|
),
|
||||||
|
});
|
||||||
|
const jsonFsRef =
|
||||||
|
// JSON data does not exist for fallback or blocking pages
|
||||||
|
isFallback || isBlocking || (isNotFound && !static404Page)
|
||||||
|
? null
|
||||||
|
: new FileFsRef({
|
||||||
|
fsPath: path.join(
|
||||||
|
isAppPathRoute && appDir ? appDir : pagesDir,
|
||||||
|
`${
|
||||||
|
isOmitted || isNotFound
|
||||||
|
? addLocaleOrDefault('/404.html', routesManifest, locale)
|
||||||
|
: isAppPathRoute
|
||||||
|
? dataRoute
|
||||||
|
: routeFileNoExt + '.json'
|
||||||
|
}`
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
const outputPathPage = normalizeIndexOutput(
|
const outputPathPage = normalizeIndexOutput(
|
||||||
path.posix.join(entryDirectory, routeFileNoExt),
|
path.posix.join(entryDirectory, routeFileNoExt),
|
||||||
isServerMode
|
isServerMode
|
||||||
@@ -2218,7 +2229,11 @@ export async function getMiddlewareBundle({
|
|||||||
prerenderBypassToken: string;
|
prerenderBypassToken: string;
|
||||||
routesManifest: RoutesManifest;
|
routesManifest: RoutesManifest;
|
||||||
isCorrectMiddlewareOrder: boolean;
|
isCorrectMiddlewareOrder: boolean;
|
||||||
}) {
|
}): Promise<{
|
||||||
|
staticRoutes: Route[];
|
||||||
|
dynamicRouteMap: Map<string, RouteWithSrc>;
|
||||||
|
edgeFunctions: Record<string, EdgeFunction>;
|
||||||
|
}> {
|
||||||
const middlewareManifest = await getMiddlewareManifest(
|
const middlewareManifest = await getMiddlewareManifest(
|
||||||
entryPath,
|
entryPath,
|
||||||
outputDirectory
|
outputDirectory
|
||||||
@@ -2409,7 +2424,6 @@ export async function getMiddlewareBundle({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,3 @@ export default function Root({ children }) {
|
|||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const config = {
|
|
||||||
revalidate: 0,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -11,16 +11,27 @@
|
|||||||
"status": 200,
|
"status": 200,
|
||||||
"mustContain": "hello from app/dashboard"
|
"mustContain": "hello from app/dashboard"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "/dashboard",
|
||||||
|
"status": 200,
|
||||||
|
"headers": {
|
||||||
|
"__flight__": "1"
|
||||||
|
},
|
||||||
|
"mustContain": "M1:{",
|
||||||
|
"mustNotContain": "<html"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "/dashboard/another",
|
"path": "/dashboard/another",
|
||||||
"status": 200,
|
"status": 200,
|
||||||
"mustContain": "hello from newroot/dashboard/another"
|
"mustContain": "hello from newroot/dashboard/another"
|
||||||
},
|
},
|
||||||
{
|
// TODO: uncomment after this is fixed upstream
|
||||||
"path": "/dashboard/deployments/123",
|
// x-ref: https://vercel.slack.com/archives/C035J346QQL/p1663820032810519?thread_ts=1663775935.504379&cid=C035J346QQL
|
||||||
"status": 200,
|
// {
|
||||||
"mustContain": "hello from app/dashboard/deployments/[id]. ID is: <!-- -->123"
|
// "path": "/dashboard/deployments/123",
|
||||||
},
|
// "status": 200,
|
||||||
|
// "mustContain": "hello from app/dashboard/deployments/[id]. ID is: <!-- -->123"
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
"path": "/",
|
"path": "/",
|
||||||
"status": 200,
|
"status": 200,
|
||||||
@@ -31,11 +42,12 @@
|
|||||||
"status": 200,
|
"status": 200,
|
||||||
"mustContain": "hello from pages/blog/[slug]"
|
"mustContain": "hello from pages/blog/[slug]"
|
||||||
},
|
},
|
||||||
{
|
// TODO: uncomment after this is fixed upstream
|
||||||
"path": "/dynamic/category-1/id-1",
|
// {
|
||||||
"status": 200,
|
// "path": "/dynamic/category-1/id-1",
|
||||||
"mustContain": "{"category":"category-1","id":"id-1"}"
|
// "status": 200,
|
||||||
},
|
// "mustContain": "{"category":"category-1","id":"id-1"}"
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
"path": "/dashboard/changelog",
|
"path": "/dashboard/changelog",
|
||||||
"status": 200,
|
"status": 200,
|
||||||
|
|||||||
21
packages/next/test/fixtures/00-trailing-slash-add/pages/ssg/[slug].js
vendored
Normal file
21
packages/next/test/fixtures/00-trailing-slash-add/pages/ssg/[slug].js
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export default function Page(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>/ssg/[slug]</p>
|
||||||
|
<p>{JSON.stringify(props)}</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStaticProps() {
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStaticPaths() {
|
||||||
|
return {
|
||||||
|
paths: ['/ssg/first', '/ssg/second'],
|
||||||
|
fallback: 'blocking',
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,7 +1,20 @@
|
|||||||
{
|
{
|
||||||
"version": 2,
|
|
||||||
"builds": [{ "src": "package.json", "use": "@vercel/next" }],
|
|
||||||
"probes": [
|
"probes": [
|
||||||
|
{
|
||||||
|
"path": "/ssg/first/",
|
||||||
|
"status": 404,
|
||||||
|
"mustContain": "This page could not be found"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/ssg/second/",
|
||||||
|
"status": 404,
|
||||||
|
"mustContain": "This page could not be found"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/ssg/third/",
|
||||||
|
"status": 404,
|
||||||
|
"mustContain": "This page could not be found"
|
||||||
|
},
|
||||||
{ "path": "/foo/", "status": 200, "mustContain": "foo page" },
|
{ "path": "/foo/", "status": 200, "mustContain": "foo page" },
|
||||||
{
|
{
|
||||||
"fetchOptions": { "redirect": "manual" },
|
"fetchOptions": { "redirect": "manual" },
|
||||||
@@ -24,6 +24,16 @@ it('should build with app-dir correctly', async () => {
|
|||||||
expect(buildResult.output['dashboard/another']).toBeDefined();
|
expect(buildResult.output['dashboard/another']).toBeDefined();
|
||||||
expect(buildResult.output['dashboard/changelog']).toBeDefined();
|
expect(buildResult.output['dashboard/changelog']).toBeDefined();
|
||||||
expect(buildResult.output['dashboard/deployments/[id]']).toBeDefined();
|
expect(buildResult.output['dashboard/deployments/[id]']).toBeDefined();
|
||||||
|
|
||||||
|
// prefixed static generation output with `/app` under dist server files
|
||||||
|
expect(buildResult.output['dashboard'].type).toBe('FileFsRef');
|
||||||
|
expect(buildResult.output['dashboard'].fsPath).toMatch(
|
||||||
|
/server\/app\/dashboard\.html$/
|
||||||
|
);
|
||||||
|
expect(buildResult.output['dashboard.rsc'].type).toBe('FileFsRef');
|
||||||
|
expect(buildResult.output['dashboard.rsc'].fsPath).toMatch(
|
||||||
|
/server\/app\/dashboard\.rsc$/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should build with app-dir in edg runtime correctly', async () => {
|
it('should build with app-dir in edg runtime correctly', async () => {
|
||||||
@@ -31,7 +41,6 @@ it('should build with app-dir in edg runtime correctly', async () => {
|
|||||||
path.join(__dirname, '../fixtures/00-app-dir-edge')
|
path.join(__dirname, '../fixtures/00-app-dir-edge')
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('buildResult', buildResult);
|
|
||||||
const edgeFunctions = new Set();
|
const edgeFunctions = new Set();
|
||||||
|
|
||||||
for (const key of Object.keys(buildResult.output)) {
|
for (const key of Object.keys(buildResult.output)) {
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ const { FileFsRef } = require('@vercel/build-utils');
|
|||||||
jest.setTimeout(ms('6m'));
|
jest.setTimeout(ms('6m'));
|
||||||
|
|
||||||
describe(`${__dirname.split(path.sep).pop()}`, () => {
|
describe(`${__dirname.split(path.sep).pop()}`, () => {
|
||||||
afterEach(() => fs.remove(path.join(__dirname, 'yarn.lock')));
|
|
||||||
|
|
||||||
it('should normalize routes in build results output', async () => {
|
it('should normalize routes in build results output', async () => {
|
||||||
const files = [
|
const files = [
|
||||||
'index.test.js',
|
'index.test.js',
|
||||||
@@ -24,7 +22,7 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
|
|||||||
return filesMap;
|
return filesMap;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const { output } = await build({
|
const { output, routes } = await build({
|
||||||
config: {},
|
config: {},
|
||||||
entrypoint: 'package.json',
|
entrypoint: 'package.json',
|
||||||
files,
|
files,
|
||||||
@@ -44,5 +42,16 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
|
|||||||
path.join(pagesDir, `${page}.html`)
|
path.join(pagesDir, `${page}.html`)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const route of routes) {
|
||||||
|
if (typeof route.src === 'string') {
|
||||||
|
// src must start with a forward slash (or caret if a regex)
|
||||||
|
expect(route.src).toMatch(/^[/^]/);
|
||||||
|
}
|
||||||
|
if (typeof route.dest === 'string') {
|
||||||
|
// dest can be `/400` or `/.*` or `$0`, but not start with \
|
||||||
|
expect(route.dest).not.toMatch(/^\\/);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
184
packages/next/test/unit/fixtures/01-normalize-paths/yarn.lock
Normal file
184
packages/next/test/unit/fixtures/01-normalize-paths/yarn.lock
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@next/env@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.3.1.tgz#18266bd92de3b4aa4037b1927aa59e6f11879260"
|
||||||
|
integrity sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==
|
||||||
|
|
||||||
|
"@next/swc-android-arm-eabi@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz#b15ce8ad376102a3b8c0f3c017dde050a22bb1a3"
|
||||||
|
integrity sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==
|
||||||
|
|
||||||
|
"@next/swc-android-arm64@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz#85d205f568a790a137cb3c3f720d961a2436ac9c"
|
||||||
|
integrity sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q==
|
||||||
|
|
||||||
|
"@next/swc-darwin-arm64@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz#b105457d6760a7916b27e46c97cb1a40547114ae"
|
||||||
|
integrity sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg==
|
||||||
|
|
||||||
|
"@next/swc-darwin-x64@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz#6947b39082271378896b095b6696a7791c6e32b1"
|
||||||
|
integrity sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA==
|
||||||
|
|
||||||
|
"@next/swc-freebsd-x64@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz#2b6c36a4d84aae8b0ea0e0da9bafc696ae27085a"
|
||||||
|
integrity sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q==
|
||||||
|
|
||||||
|
"@next/swc-linux-arm-gnueabihf@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz#6e421c44285cfedac1f4631d5de330dd60b86298"
|
||||||
|
integrity sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w==
|
||||||
|
|
||||||
|
"@next/swc-linux-arm64-gnu@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz#8863f08a81f422f910af126159d2cbb9552ef717"
|
||||||
|
integrity sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ==
|
||||||
|
|
||||||
|
"@next/swc-linux-arm64-musl@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz#0038f07cf0b259d70ae0c80890d826dfc775d9f3"
|
||||||
|
integrity sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg==
|
||||||
|
|
||||||
|
"@next/swc-linux-x64-gnu@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz#c66468f5e8181ffb096c537f0dbfb589baa6a9c1"
|
||||||
|
integrity sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA==
|
||||||
|
|
||||||
|
"@next/swc-linux-x64-musl@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz#c6269f3e96ac0395bc722ad97ce410ea5101d305"
|
||||||
|
integrity sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg==
|
||||||
|
|
||||||
|
"@next/swc-win32-arm64-msvc@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz#83c639ee969cee36ce247c3abd1d9df97b5ecade"
|
||||||
|
integrity sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw==
|
||||||
|
|
||||||
|
"@next/swc-win32-ia32-msvc@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz#52995748b92aa8ad053440301bc2c0d9fbcf27c2"
|
||||||
|
integrity sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA==
|
||||||
|
|
||||||
|
"@next/swc-win32-x64-msvc@12.3.1":
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz#27d71a95247a9eaee03d47adee7e3bd594514136"
|
||||||
|
integrity sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA==
|
||||||
|
|
||||||
|
"@swc/helpers@0.4.11":
|
||||||
|
version "0.4.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.11.tgz#db23a376761b3d31c26502122f349a21b592c8de"
|
||||||
|
integrity sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.4.0"
|
||||||
|
|
||||||
|
caniuse-lite@^1.0.30001406:
|
||||||
|
version "1.0.30001409"
|
||||||
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz#6135da9dcab34cd9761d9cdb12a68e6740c5e96e"
|
||||||
|
integrity sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ==
|
||||||
|
|
||||||
|
"js-tokens@^3.0.0 || ^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
|
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||||
|
|
||||||
|
loose-envify@^1.1.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
|
dependencies:
|
||||||
|
js-tokens "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
|
nanoid@^3.3.4:
|
||||||
|
version "3.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
||||||
|
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
|
||||||
|
|
||||||
|
next@latest:
|
||||||
|
version "12.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/next/-/next-12.3.1.tgz#127b825ad2207faf869b33393ec8c75fe61e50f1"
|
||||||
|
integrity sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==
|
||||||
|
dependencies:
|
||||||
|
"@next/env" "12.3.1"
|
||||||
|
"@swc/helpers" "0.4.11"
|
||||||
|
caniuse-lite "^1.0.30001406"
|
||||||
|
postcss "8.4.14"
|
||||||
|
styled-jsx "5.0.7"
|
||||||
|
use-sync-external-store "1.2.0"
|
||||||
|
optionalDependencies:
|
||||||
|
"@next/swc-android-arm-eabi" "12.3.1"
|
||||||
|
"@next/swc-android-arm64" "12.3.1"
|
||||||
|
"@next/swc-darwin-arm64" "12.3.1"
|
||||||
|
"@next/swc-darwin-x64" "12.3.1"
|
||||||
|
"@next/swc-freebsd-x64" "12.3.1"
|
||||||
|
"@next/swc-linux-arm-gnueabihf" "12.3.1"
|
||||||
|
"@next/swc-linux-arm64-gnu" "12.3.1"
|
||||||
|
"@next/swc-linux-arm64-musl" "12.3.1"
|
||||||
|
"@next/swc-linux-x64-gnu" "12.3.1"
|
||||||
|
"@next/swc-linux-x64-musl" "12.3.1"
|
||||||
|
"@next/swc-win32-arm64-msvc" "12.3.1"
|
||||||
|
"@next/swc-win32-ia32-msvc" "12.3.1"
|
||||||
|
"@next/swc-win32-x64-msvc" "12.3.1"
|
||||||
|
|
||||||
|
picocolors@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||||
|
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||||
|
|
||||||
|
postcss@8.4.14:
|
||||||
|
version "8.4.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
|
||||||
|
integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
|
||||||
|
dependencies:
|
||||||
|
nanoid "^3.3.4"
|
||||||
|
picocolors "^1.0.0"
|
||||||
|
source-map-js "^1.0.2"
|
||||||
|
|
||||||
|
react-dom@latest:
|
||||||
|
version "18.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
||||||
|
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
scheduler "^0.23.0"
|
||||||
|
|
||||||
|
react@latest:
|
||||||
|
version "18.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
||||||
|
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
|
||||||
|
scheduler@^0.23.0:
|
||||||
|
version "0.23.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
|
||||||
|
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
|
||||||
|
source-map-js@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||||
|
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||||
|
|
||||||
|
styled-jsx@5.0.7:
|
||||||
|
version "5.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.7.tgz#be44afc53771b983769ac654d355ca8d019dff48"
|
||||||
|
integrity sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==
|
||||||
|
|
||||||
|
tslib@^2.4.0:
|
||||||
|
version "2.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
|
||||||
|
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
|
||||||
|
|
||||||
|
use-sync-external-store@1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
|
||||||
|
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
|
||||||
@@ -3,6 +3,13 @@ const fs = require('fs-extra');
|
|||||||
const execa = require('execa');
|
const execa = require('execa');
|
||||||
const { join } = require('path');
|
const { join } = require('path');
|
||||||
|
|
||||||
|
async function copyToDist(sourcePath, outDir) {
|
||||||
|
return fs.copyFile(
|
||||||
|
join(__dirname, sourcePath),
|
||||||
|
join(outDir, 'edge-functions/edge-handler-template.js')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const srcDir = join(__dirname, 'src');
|
const srcDir = join(__dirname, 'src');
|
||||||
const outDir = join(__dirname, 'dist');
|
const outDir = join(__dirname, 'dist');
|
||||||
@@ -50,6 +57,8 @@ async function main() {
|
|||||||
join(outDir, 'index.d.ts'),
|
join(outDir, 'index.d.ts'),
|
||||||
join(__dirname, 'test/fixtures/15-helpers/ts/types.d.ts')
|
join(__dirname, 'test/fixtures/15-helpers/ts/types.d.ts')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await copyToDist('src/edge-functions/edge-handler-template.js', outDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(err => {
|
main().catch(err => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/node",
|
"name": "@vercel/node",
|
||||||
"version": "2.5.16",
|
"version": "2.5.19",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@edge-runtime/vm": "1.1.0-beta.32",
|
"@edge-runtime/vm": "1.1.0-beta.32",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@vercel/build-utils": "5.4.4",
|
"@vercel/build-utils": "5.5.1",
|
||||||
"@vercel/node-bridge": "3.0.0",
|
"@vercel/node-bridge": "3.0.0",
|
||||||
"@vercel/static-config": "2.0.3",
|
"@vercel/static-config": "2.0.3",
|
||||||
"edge-runtime": "1.1.0-beta.32",
|
"edge-runtime": "1.1.0-beta.32",
|
||||||
|
|||||||
@@ -70,30 +70,13 @@ if (!process.env.VERCEL_DEV_IS_ESM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
import { createServer, Server, IncomingMessage, ServerResponse } from 'http';
|
import { createServer, Server, IncomingMessage, ServerResponse } from 'http';
|
||||||
import { Readable } from 'stream';
|
|
||||||
import type { Bridge } from '@vercel/node-bridge/bridge';
|
|
||||||
import { getVercelLauncher } from '@vercel/node-bridge/launcher.js';
|
|
||||||
import { VercelProxyResponse } from '@vercel/node-bridge/types';
|
import { VercelProxyResponse } from '@vercel/node-bridge/types';
|
||||||
import { Config, streamToBuffer, debug } from '@vercel/build-utils';
|
import { Config } from '@vercel/build-utils';
|
||||||
import exitHook from 'exit-hook';
|
|
||||||
import { EdgeRuntime, runServer } from 'edge-runtime';
|
|
||||||
import type { EdgeContext } from '@edge-runtime/vm';
|
|
||||||
import { getConfig } from '@vercel/static-config';
|
import { getConfig } from '@vercel/static-config';
|
||||||
import { Project } from 'ts-morph';
|
import { Project } from 'ts-morph';
|
||||||
import esbuild from 'esbuild';
|
import { logError } from './utils';
|
||||||
import fetch from 'node-fetch';
|
import { createEdgeEventHandler } from './edge-functions/edge-handler';
|
||||||
import { createEdgeWasmPlugin, WasmAssets } from './edge-wasm-plugin';
|
import { createServerlessEventHandler } from './serverless-functions/serverless-handler';
|
||||||
|
|
||||||
function logError(error: Error) {
|
|
||||||
console.error(error.message);
|
|
||||||
if (error.stack) {
|
|
||||||
// only show the stack trace if debug is enabled
|
|
||||||
// because it points to internals, not user code
|
|
||||||
const errorPrefixLength = 'Error: '.length;
|
|
||||||
const errorMessageLength = errorPrefixLength + error.message.length;
|
|
||||||
debug(error.stack.substring(errorMessageLength + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function listen(server: Server, port: number, host: string): Promise<void> {
|
function listen(server: Server, port: number, host: string): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
@@ -103,241 +86,6 @@ function listen(server: Server, port: number, host: string): Promise<void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createServerlessEventHandler(
|
|
||||||
entrypoint: string,
|
|
||||||
options: { shouldAddHelpers: boolean }
|
|
||||||
): Promise<(request: IncomingMessage) => Promise<VercelProxyResponse>> {
|
|
||||||
const launcher = getVercelLauncher({
|
|
||||||
entrypointPath: entrypoint,
|
|
||||||
helpersPath: './helpers.js',
|
|
||||||
shouldAddHelpers: options.shouldAddHelpers,
|
|
||||||
useRequire,
|
|
||||||
|
|
||||||
// not used
|
|
||||||
bridgePath: '',
|
|
||||||
sourcemapSupportPath: '',
|
|
||||||
});
|
|
||||||
const bridge: Bridge = launcher();
|
|
||||||
|
|
||||||
return async function (request: IncomingMessage) {
|
|
||||||
const body = await rawBody(request);
|
|
||||||
const event = {
|
|
||||||
Action: 'Invoke',
|
|
||||||
body: JSON.stringify({
|
|
||||||
method: request.method,
|
|
||||||
path: request.url,
|
|
||||||
headers: request.headers,
|
|
||||||
encoding: 'base64',
|
|
||||||
body: body.toString('base64'),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
return bridge.launcher(event, {
|
|
||||||
callbackWaitsForEmptyEventLoop: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function serializeRequest(message: IncomingMessage) {
|
|
||||||
const bodyBuffer = await streamToBuffer(message);
|
|
||||||
const body = bodyBuffer.toString('base64');
|
|
||||||
return JSON.stringify({
|
|
||||||
url: message.url,
|
|
||||||
method: message.method,
|
|
||||||
headers: message.headers,
|
|
||||||
body,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function compileUserCode(
|
|
||||||
entrypointPath: string,
|
|
||||||
entrypointLabel: string,
|
|
||||||
isMiddleware: boolean
|
|
||||||
): Promise<undefined | { userCode: string; wasmAssets: WasmAssets }> {
|
|
||||||
const { wasmAssets, plugin: edgeWasmPlugin } = createEdgeWasmPlugin();
|
|
||||||
try {
|
|
||||||
const result = await esbuild.build({
|
|
||||||
platform: 'node',
|
|
||||||
target: 'node14',
|
|
||||||
sourcemap: 'inline',
|
|
||||||
bundle: true,
|
|
||||||
plugins: [edgeWasmPlugin],
|
|
||||||
entryPoints: [entrypointPath],
|
|
||||||
write: false, // operate in memory
|
|
||||||
format: 'cjs',
|
|
||||||
});
|
|
||||||
|
|
||||||
const compiledFile = result.outputFiles?.[0];
|
|
||||||
if (!compiledFile) {
|
|
||||||
throw new Error(
|
|
||||||
`Compilation of ${entrypointLabel} produced no output files.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const userCode = `
|
|
||||||
${compiledFile.text};
|
|
||||||
|
|
||||||
const isMiddleware = ${isMiddleware};
|
|
||||||
|
|
||||||
addEventListener('fetch', async (event) => {
|
|
||||||
try {
|
|
||||||
let serializedRequest = await event.request.text();
|
|
||||||
let requestDetails = JSON.parse(serializedRequest);
|
|
||||||
|
|
||||||
let body;
|
|
||||||
|
|
||||||
if (requestDetails.method !== 'GET' && requestDetails.method !== 'HEAD') {
|
|
||||||
body = Uint8Array.from(atob(requestDetails.body), c => c.charCodeAt(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
let requestUrl = requestDetails.headers['x-forwarded-proto'] + '://' + requestDetails.headers['x-forwarded-host'] + requestDetails.url;
|
|
||||||
|
|
||||||
let request = new Request(requestUrl, {
|
|
||||||
headers: requestDetails.headers,
|
|
||||||
method: requestDetails.method,
|
|
||||||
body: body
|
|
||||||
});
|
|
||||||
|
|
||||||
event.request = request;
|
|
||||||
|
|
||||||
let edgeHandler = module.exports.default;
|
|
||||||
if (!edgeHandler) {
|
|
||||||
throw new Error('No default export was found. Add a default export to handle requests. Learn more: https://vercel.link/creating-edge-middleware');
|
|
||||||
}
|
|
||||||
|
|
||||||
let response = await edgeHandler(event.request, event);
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
if (isMiddleware) {
|
|
||||||
// allow empty responses to pass through
|
|
||||||
response = new Response(null, {
|
|
||||||
headers: {
|
|
||||||
'x-middleware-next': '1',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw new Error('Edge Function "${entrypointLabel}" did not return a response.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return event.respondWith(response);
|
|
||||||
} catch (error) {
|
|
||||||
// we can't easily show a meaningful stack trace
|
|
||||||
// so, stick to just the error message for now
|
|
||||||
const msg = error.cause
|
|
||||||
? (error.message + ': ' + (error.cause.message || error.cause))
|
|
||||||
: error.message;
|
|
||||||
event.respondWith(new Response(msg, {
|
|
||||||
status: 500,
|
|
||||||
headers: {
|
|
||||||
'x-vercel-failed': 'edge-wrapper'
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
})`;
|
|
||||||
return { userCode, wasmAssets };
|
|
||||||
} catch (error) {
|
|
||||||
// We can't easily show a meaningful stack trace from ncc -> edge-runtime.
|
|
||||||
// So, stick with just the message for now.
|
|
||||||
console.error(`Failed to compile user code for edge runtime.`);
|
|
||||||
logError(error);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createEdgeRuntime(params?: {
|
|
||||||
userCode: string;
|
|
||||||
wasmAssets: WasmAssets;
|
|
||||||
}) {
|
|
||||||
try {
|
|
||||||
if (!params) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wasmBindings = await params.wasmAssets.getContext();
|
|
||||||
const edgeRuntime = new EdgeRuntime({
|
|
||||||
initialCode: params.userCode,
|
|
||||||
extend: (context: EdgeContext) => {
|
|
||||||
Object.assign(context, {
|
|
||||||
// This is required for esbuild wrapping logic to resolve
|
|
||||||
module: {},
|
|
||||||
|
|
||||||
// This is required for environment variable access.
|
|
||||||
// In production, env var access is provided by static analysis
|
|
||||||
// so that only the used values are available.
|
|
||||||
process: {
|
|
||||||
env: process.env,
|
|
||||||
},
|
|
||||||
|
|
||||||
// These are the global bindings for WebAssembly module
|
|
||||||
...wasmBindings,
|
|
||||||
});
|
|
||||||
|
|
||||||
return context;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const server = await runServer({ runtime: edgeRuntime });
|
|
||||||
exitHook(server.close);
|
|
||||||
|
|
||||||
return server;
|
|
||||||
} catch (error) {
|
|
||||||
// We can't easily show a meaningful stack trace from ncc -> edge-runtime.
|
|
||||||
// So, stick with just the message for now.
|
|
||||||
console.error('Failed to instantiate edge runtime.');
|
|
||||||
logError(error);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createEdgeEventHandler(
|
|
||||||
entrypointPath: string,
|
|
||||||
entrypointLabel: string,
|
|
||||||
isMiddleware: boolean
|
|
||||||
): Promise<(request: IncomingMessage) => Promise<VercelProxyResponse>> {
|
|
||||||
const userCode = await compileUserCode(
|
|
||||||
entrypointPath,
|
|
||||||
entrypointLabel,
|
|
||||||
isMiddleware
|
|
||||||
);
|
|
||||||
const server = await createEdgeRuntime(userCode);
|
|
||||||
|
|
||||||
return async function (request: IncomingMessage) {
|
|
||||||
if (!server) {
|
|
||||||
// this error state is already logged, but we have to wait until here to exit the process
|
|
||||||
// this matches the serverless function bridge launcher's behavior when
|
|
||||||
// an error is thrown in the function
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(server.url, {
|
|
||||||
redirect: 'manual',
|
|
||||||
method: 'post',
|
|
||||||
body: await serializeRequest(request),
|
|
||||||
});
|
|
||||||
|
|
||||||
const body = await response.text();
|
|
||||||
|
|
||||||
const isUserError =
|
|
||||||
response.headers.get('x-vercel-failed') === 'edge-wrapper';
|
|
||||||
if (isUserError && response.status >= 500) {
|
|
||||||
// this error was "unhandled" from the user code's perspective
|
|
||||||
console.log(`Unhandled rejection: ${body}`);
|
|
||||||
|
|
||||||
// this matches the serverless function bridge launcher's behavior when
|
|
||||||
// an error is thrown in the function
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
statusCode: response.status,
|
|
||||||
headers: response.headers.raw(),
|
|
||||||
body,
|
|
||||||
encoding: 'utf8',
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const validRuntimes = ['experimental-edge'];
|
const validRuntimes = ['experimental-edge'];
|
||||||
function parseRuntime(
|
function parseRuntime(
|
||||||
entrypoint: string,
|
entrypoint: string,
|
||||||
@@ -376,7 +124,10 @@ async function createEventHandler(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return createServerlessEventHandler(entrypointPath, options);
|
return createServerlessEventHandler(entrypointPath, {
|
||||||
|
shouldAddHelpers: options.shouldAddHelpers,
|
||||||
|
useRequire,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let handleEvent: (request: IncomingMessage) => Promise<VercelProxyResponse>;
|
let handleEvent: (request: IncomingMessage) => Promise<VercelProxyResponse>;
|
||||||
@@ -413,21 +164,6 @@ async function main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rawBody(readable: Readable): Promise<Buffer> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let bytes = 0;
|
|
||||||
const chunks: Buffer[] = [];
|
|
||||||
readable.on('error', reject);
|
|
||||||
readable.on('data', chunk => {
|
|
||||||
chunks.push(chunk);
|
|
||||||
bytes += chunk.length;
|
|
||||||
});
|
|
||||||
readable.on('end', () => {
|
|
||||||
resolve(Buffer.concat(chunks, bytes));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function onDevRequest(
|
export async function onDevRequest(
|
||||||
req: IncomingMessage,
|
req: IncomingMessage,
|
||||||
res: ServerResponse
|
res: ServerResponse
|
||||||
|
|||||||
73
packages/node/src/edge-functions/edge-handler-template.js
Normal file
73
packages/node/src/edge-functions/edge-handler-template.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// provided by the edge runtime:
|
||||||
|
/* global addEventListener Request Response atob */
|
||||||
|
|
||||||
|
// provided by our edge handler logic:
|
||||||
|
/* global IS_MIDDLEWARE ENTRYPOINT_LABEL */
|
||||||
|
|
||||||
|
function buildUrl(requestDetails) {
|
||||||
|
let proto = requestDetails.headers['x-forwarded-proto'];
|
||||||
|
let host = requestDetails.headers['x-forwarded-host'];
|
||||||
|
let path = requestDetails.url;
|
||||||
|
return `${proto}://${host}${path}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener('fetch', async event => {
|
||||||
|
try {
|
||||||
|
let serializedRequest = await event.request.text();
|
||||||
|
let requestDetails = JSON.parse(serializedRequest);
|
||||||
|
|
||||||
|
let body;
|
||||||
|
|
||||||
|
if (requestDetails.method !== 'GET' && requestDetails.method !== 'HEAD') {
|
||||||
|
body = Uint8Array.from(atob(requestDetails.body), c => c.charCodeAt(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
let request = new Request(buildUrl(requestDetails), {
|
||||||
|
headers: requestDetails.headers,
|
||||||
|
method: requestDetails.method,
|
||||||
|
body: body,
|
||||||
|
});
|
||||||
|
|
||||||
|
event.request = request;
|
||||||
|
|
||||||
|
let edgeHandler = module.exports.default;
|
||||||
|
if (!edgeHandler) {
|
||||||
|
throw new Error(
|
||||||
|
'No default export was found. Add a default export to handle requests. Learn more: https://vercel.link/creating-edge-middleware'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = await edgeHandler(event.request, event);
|
||||||
|
|
||||||
|
if (!response) {
|
||||||
|
if (IS_MIDDLEWARE) {
|
||||||
|
// allow empty responses to pass through
|
||||||
|
response = new Response(null, {
|
||||||
|
headers: {
|
||||||
|
'x-middleware-next': '1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Edge Function "${ENTRYPOINT_LABEL}" did not return a response.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return event.respondWith(response);
|
||||||
|
} catch (error) {
|
||||||
|
// we can't easily show a meaningful stack trace
|
||||||
|
// so, stick to just the error message for now
|
||||||
|
const msg = error.cause
|
||||||
|
? error.message + ': ' + (error.cause.message || error.cause)
|
||||||
|
: error.message;
|
||||||
|
event.respondWith(
|
||||||
|
new Response(msg, {
|
||||||
|
status: 500,
|
||||||
|
headers: {
|
||||||
|
'x-vercel-failed': 'edge-wrapper',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
182
packages/node/src/edge-functions/edge-handler.ts
Normal file
182
packages/node/src/edge-functions/edge-handler.ts
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
import { IncomingMessage } from 'http';
|
||||||
|
import { VercelProxyResponse } from '@vercel/node-bridge/types';
|
||||||
|
import { streamToBuffer } from '@vercel/build-utils';
|
||||||
|
import exitHook from 'exit-hook';
|
||||||
|
import { EdgeRuntime, runServer } from 'edge-runtime';
|
||||||
|
import type { EdgeContext } from '@edge-runtime/vm';
|
||||||
|
import esbuild from 'esbuild';
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
import { createEdgeWasmPlugin, WasmAssets } from './edge-wasm-plugin';
|
||||||
|
import { logError } from '../utils';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
|
||||||
|
const NODE_VERSION_MAJOR = process.version.match(/^v(\d+)\.\d+/)?.[1];
|
||||||
|
const NODE_VERSION_IDENTIFIER = `node${NODE_VERSION_MAJOR}`;
|
||||||
|
if (!NODE_VERSION_MAJOR) {
|
||||||
|
throw new Error(
|
||||||
|
`Unable to determine current node version: process.version=${process.version}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const edgeHandlerTemplate = readFileSync(
|
||||||
|
`${__dirname}/edge-handler-template.js`
|
||||||
|
);
|
||||||
|
|
||||||
|
async function serializeRequest(message: IncomingMessage) {
|
||||||
|
const bodyBuffer = await streamToBuffer(message);
|
||||||
|
const body = bodyBuffer.toString('base64');
|
||||||
|
return JSON.stringify({
|
||||||
|
url: message.url,
|
||||||
|
method: message.method,
|
||||||
|
headers: message.headers,
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function compileUserCode(
|
||||||
|
entrypointPath: string,
|
||||||
|
entrypointLabel: string,
|
||||||
|
isMiddleware: boolean
|
||||||
|
): Promise<undefined | { userCode: string; wasmAssets: WasmAssets }> {
|
||||||
|
const { wasmAssets, plugin: edgeWasmPlugin } = createEdgeWasmPlugin();
|
||||||
|
try {
|
||||||
|
const result = await esbuild.build({
|
||||||
|
// bundling behavior: use globals (like "browser") instead
|
||||||
|
// of "require" statements for core libraries (like "node")
|
||||||
|
platform: 'browser',
|
||||||
|
// target syntax: only use syntax available on the current
|
||||||
|
// version of node
|
||||||
|
target: NODE_VERSION_IDENTIFIER,
|
||||||
|
sourcemap: 'inline',
|
||||||
|
legalComments: 'none',
|
||||||
|
bundle: true,
|
||||||
|
plugins: [edgeWasmPlugin],
|
||||||
|
entryPoints: [entrypointPath],
|
||||||
|
write: false, // operate in memory
|
||||||
|
format: 'cjs',
|
||||||
|
});
|
||||||
|
|
||||||
|
const compiledFile = result.outputFiles?.[0];
|
||||||
|
if (!compiledFile) {
|
||||||
|
throw new Error(
|
||||||
|
`Compilation of ${entrypointLabel} produced no output files.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userCode = `
|
||||||
|
// strict mode
|
||||||
|
"use strict";var regeneratorRuntime;
|
||||||
|
|
||||||
|
// user code
|
||||||
|
${compiledFile.text};
|
||||||
|
|
||||||
|
// request metadata
|
||||||
|
const IS_MIDDLEWARE = ${isMiddleware};
|
||||||
|
const ENTRYPOINT_LABEL = '${entrypointLabel}';
|
||||||
|
|
||||||
|
// edge handler
|
||||||
|
${edgeHandlerTemplate}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return { userCode, wasmAssets };
|
||||||
|
} catch (error) {
|
||||||
|
// We can't easily show a meaningful stack trace from ncc -> edge-runtime.
|
||||||
|
// So, stick with just the message for now.
|
||||||
|
console.error(`Failed to compile user code for edge runtime.`);
|
||||||
|
logError(error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createEdgeRuntime(params?: {
|
||||||
|
userCode: string;
|
||||||
|
wasmAssets: WasmAssets;
|
||||||
|
}) {
|
||||||
|
try {
|
||||||
|
if (!params) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wasmBindings = await params.wasmAssets.getContext();
|
||||||
|
const edgeRuntime = new EdgeRuntime({
|
||||||
|
initialCode: params.userCode,
|
||||||
|
extend: (context: EdgeContext) => {
|
||||||
|
Object.assign(context, {
|
||||||
|
// This is required for esbuild wrapping logic to resolve
|
||||||
|
module: {},
|
||||||
|
|
||||||
|
// This is required for environment variable access.
|
||||||
|
// In production, env var access is provided by static analysis
|
||||||
|
// so that only the used values are available.
|
||||||
|
process: {
|
||||||
|
env: process.env,
|
||||||
|
},
|
||||||
|
|
||||||
|
// These are the global bindings for WebAssembly module
|
||||||
|
...wasmBindings,
|
||||||
|
});
|
||||||
|
|
||||||
|
return context;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const server = await runServer({ runtime: edgeRuntime });
|
||||||
|
exitHook(server.close);
|
||||||
|
|
||||||
|
return server;
|
||||||
|
} catch (error) {
|
||||||
|
// We can't easily show a meaningful stack trace from ncc -> edge-runtime.
|
||||||
|
// So, stick with just the message for now.
|
||||||
|
console.error('Failed to instantiate edge runtime.');
|
||||||
|
logError(error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createEdgeEventHandler(
|
||||||
|
entrypointPath: string,
|
||||||
|
entrypointLabel: string,
|
||||||
|
isMiddleware: boolean
|
||||||
|
): Promise<(request: IncomingMessage) => Promise<VercelProxyResponse>> {
|
||||||
|
const userCode = await compileUserCode(
|
||||||
|
entrypointPath,
|
||||||
|
entrypointLabel,
|
||||||
|
isMiddleware
|
||||||
|
);
|
||||||
|
const server = await createEdgeRuntime(userCode);
|
||||||
|
|
||||||
|
return async function (request: IncomingMessage) {
|
||||||
|
if (!server) {
|
||||||
|
// this error state is already logged, but we have to wait until here to exit the process
|
||||||
|
// this matches the serverless function bridge launcher's behavior when
|
||||||
|
// an error is thrown in the function
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(server.url, {
|
||||||
|
redirect: 'manual',
|
||||||
|
method: 'post',
|
||||||
|
body: await serializeRequest(request),
|
||||||
|
});
|
||||||
|
|
||||||
|
const body = await response.text();
|
||||||
|
|
||||||
|
const isUserError =
|
||||||
|
response.headers.get('x-vercel-failed') === 'edge-wrapper';
|
||||||
|
if (isUserError && response.status >= 500) {
|
||||||
|
// this error was "unhandled" from the user code's perspective
|
||||||
|
console.log(`Unhandled rejection: ${body}`);
|
||||||
|
|
||||||
|
// this matches the serverless function bridge launcher's behavior when
|
||||||
|
// an error is thrown in the function
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode: response.status,
|
||||||
|
headers: response.headers.raw(),
|
||||||
|
body,
|
||||||
|
encoding: 'utf8',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
58
packages/node/src/serverless-functions/serverless-handler.ts
Normal file
58
packages/node/src/serverless-functions/serverless-handler.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { IncomingMessage } from 'http';
|
||||||
|
import { Readable } from 'stream';
|
||||||
|
import type { Bridge } from '@vercel/node-bridge/bridge';
|
||||||
|
import { getVercelLauncher } from '@vercel/node-bridge/launcher.js';
|
||||||
|
import { VercelProxyResponse } from '@vercel/node-bridge/types';
|
||||||
|
|
||||||
|
function rawBody(readable: Readable): Promise<Buffer> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let bytes = 0;
|
||||||
|
const chunks: Buffer[] = [];
|
||||||
|
readable.on('error', reject);
|
||||||
|
readable.on('data', chunk => {
|
||||||
|
chunks.push(chunk);
|
||||||
|
bytes += chunk.length;
|
||||||
|
});
|
||||||
|
readable.on('end', () => {
|
||||||
|
resolve(Buffer.concat(chunks, bytes));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createServerlessEventHandler(
|
||||||
|
entrypoint: string,
|
||||||
|
options: {
|
||||||
|
shouldAddHelpers: boolean;
|
||||||
|
useRequire: boolean;
|
||||||
|
}
|
||||||
|
): Promise<(request: IncomingMessage) => Promise<VercelProxyResponse>> {
|
||||||
|
const launcher = getVercelLauncher({
|
||||||
|
entrypointPath: entrypoint,
|
||||||
|
helpersPath: './helpers.js',
|
||||||
|
shouldAddHelpers: options.shouldAddHelpers,
|
||||||
|
useRequire: options.useRequire,
|
||||||
|
|
||||||
|
// not used
|
||||||
|
bridgePath: '',
|
||||||
|
sourcemapSupportPath: '',
|
||||||
|
});
|
||||||
|
const bridge: Bridge = launcher();
|
||||||
|
|
||||||
|
return async function (request: IncomingMessage) {
|
||||||
|
const body = await rawBody(request);
|
||||||
|
const event = {
|
||||||
|
Action: 'Invoke',
|
||||||
|
body: JSON.stringify({
|
||||||
|
method: request.method,
|
||||||
|
path: request.url,
|
||||||
|
headers: request.headers,
|
||||||
|
encoding: 'base64',
|
||||||
|
body: body.toString('base64'),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
return bridge.launcher(event, {
|
||||||
|
callbackWaitsForEmptyEventLoop: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { extname } from 'path';
|
import { extname } from 'path';
|
||||||
import { pathToRegexp } from 'path-to-regexp';
|
import { pathToRegexp } from 'path-to-regexp';
|
||||||
|
import { debug } from '@vercel/build-utils';
|
||||||
|
|
||||||
export function getRegExpFromMatchers(matcherOrMatchers: unknown): string {
|
export function getRegExpFromMatchers(matcherOrMatchers: unknown): string {
|
||||||
if (!matcherOrMatchers) {
|
if (!matcherOrMatchers) {
|
||||||
@@ -55,3 +56,14 @@ export function entrypointToOutputPath(
|
|||||||
}
|
}
|
||||||
return entrypoint;
|
return entrypoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function logError(error: Error) {
|
||||||
|
console.error(error.message);
|
||||||
|
if (error.stack) {
|
||||||
|
// only show the stack trace if debug is enabled
|
||||||
|
// because it points to internals, not user code
|
||||||
|
const errorPrefixLength = 'Error: '.length;
|
||||||
|
const errorMessageLength = errorPrefixLength + error.message.length;
|
||||||
|
debug(error.stack.substring(errorMessageLength + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/python",
|
"name": "@vercel/python",
|
||||||
"version": "3.1.16",
|
"version": "3.1.18",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/execa": "^0.9.0",
|
"@types/execa": "^0.9.0",
|
||||||
"@types/jest": "27.4.1",
|
"@types/jest": "27.4.1",
|
||||||
"@vercel/build-utils": "5.4.4",
|
"@vercel/build-utils": "5.5.1",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"execa": "^1.0.0",
|
"execa": "^1.0.0",
|
||||||
"typescript": "4.3.4"
|
"typescript": "4.3.4"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/redwood",
|
"name": "@vercel/redwood",
|
||||||
"version": "1.0.25",
|
"version": "1.0.27",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://vercel.com/docs",
|
"homepage": "https://vercel.com/docs",
|
||||||
@@ -27,6 +27,6 @@
|
|||||||
"@types/aws-lambda": "8.10.19",
|
"@types/aws-lambda": "8.10.19",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@types/semver": "6.0.0",
|
"@types/semver": "6.0.0",
|
||||||
"@vercel/build-utils": "5.4.4"
|
"@vercel/build-utils": "5.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/remix",
|
"name": "@vercel/remix",
|
||||||
"version": "1.0.26",
|
"version": "1.0.28",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"homepage": "https://vercel.com/docs",
|
"homepage": "https://vercel.com/docs",
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "27.5.1",
|
"@types/jest": "27.5.1",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@vercel/build-utils": "5.4.4",
|
"@vercel/build-utils": "5.5.1",
|
||||||
"typescript": "4.6.4"
|
"typescript": "4.6.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/ruby",
|
"name": "@vercel/ruby",
|
||||||
"author": "Nathan Cahill <nathan@nathancahill.com>",
|
"author": "Nathan Cahill <nathan@nathancahill.com>",
|
||||||
"version": "1.3.33",
|
"version": "1.3.35",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/fs-extra": "8.0.0",
|
"@types/fs-extra": "8.0.0",
|
||||||
"@types/semver": "6.0.0",
|
"@types/semver": "6.0.0",
|
||||||
"@vercel/build-utils": "5.4.4",
|
"@vercel/build-utils": "5.5.1",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"execa": "2.0.4",
|
"execa": "2.0.4",
|
||||||
"fs-extra": "^7.0.1",
|
"fs-extra": "^7.0.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/static-build",
|
"name": "@vercel/static-build",
|
||||||
"version": "1.0.25",
|
"version": "1.0.27",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/build-step",
|
"homepage": "https://vercel.com/docs/build-step",
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"@types/ms": "0.7.31",
|
"@types/ms": "0.7.31",
|
||||||
"@types/node-fetch": "2.5.4",
|
"@types/node-fetch": "2.5.4",
|
||||||
"@types/promise-timeout": "1.3.0",
|
"@types/promise-timeout": "1.3.0",
|
||||||
"@vercel/build-utils": "5.4.4",
|
"@vercel/build-utils": "5.5.1",
|
||||||
"@vercel/frameworks": "1.1.6",
|
"@vercel/frameworks": "1.1.6",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"@vercel/routing-utils": "2.0.2",
|
"@vercel/routing-utils": "2.0.2",
|
||||||
|
|||||||
@@ -200,8 +200,8 @@ async function fetchTokenWithRetry(retries = 5) {
|
|||||||
NOW_TOKEN,
|
NOW_TOKEN,
|
||||||
TEMP_TOKEN,
|
TEMP_TOKEN,
|
||||||
VERCEL_TOKEN,
|
VERCEL_TOKEN,
|
||||||
VERCEL_TEAM_TOKEN,
|
VERCEL_TEST_TOKEN,
|
||||||
VERCEL_REGISTRATION_URL,
|
VERCEL_TEST_REGISTRATION_URL,
|
||||||
} = process.env;
|
} = process.env;
|
||||||
if (VERCEL_TOKEN || NOW_TOKEN || TEMP_TOKEN) {
|
if (VERCEL_TOKEN || NOW_TOKEN || TEMP_TOKEN) {
|
||||||
if (!TEMP_TOKEN) {
|
if (!TEMP_TOKEN) {
|
||||||
@@ -211,7 +211,7 @@ async function fetchTokenWithRetry(retries = 5) {
|
|||||||
}
|
}
|
||||||
return VERCEL_TOKEN || NOW_TOKEN || TEMP_TOKEN;
|
return VERCEL_TOKEN || NOW_TOKEN || TEMP_TOKEN;
|
||||||
}
|
}
|
||||||
if (!VERCEL_TEAM_TOKEN || !VERCEL_REGISTRATION_URL) {
|
if (!VERCEL_TEST_TOKEN || !VERCEL_TEST_REGISTRATION_URL) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
process.env.CI
|
process.env.CI
|
||||||
? 'Failed to create test deployment. This is expected for 3rd-party Pull Requests. Please run tests locally.'
|
? 'Failed to create test deployment. This is expected for 3rd-party Pull Requests. Please run tests locally.'
|
||||||
@@ -219,10 +219,10 @@ async function fetchTokenWithRetry(retries = 5) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const res = await _fetch(VERCEL_REGISTRATION_URL, {
|
const res = await _fetch(VERCEL_TEST_REGISTRATION_URL, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${VERCEL_TEAM_TOKEN}`,
|
Authorization: `Bearer ${VERCEL_TEST_TOKEN}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const os = require('os');
|
const os = require('os');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
const json5 = require('json5');
|
||||||
const { glob } = require('@vercel/build-utils');
|
const { glob } = require('@vercel/build-utils');
|
||||||
|
|
||||||
function runAnalyze(wrapper, context) {
|
function runAnalyze(wrapper, context) {
|
||||||
@@ -18,7 +19,7 @@ async function runBuildLambda(inputPath) {
|
|||||||
if (typeof expect !== 'undefined') {
|
if (typeof expect !== 'undefined') {
|
||||||
expect(nowJsonRef).toBeDefined();
|
expect(nowJsonRef).toBeDefined();
|
||||||
}
|
}
|
||||||
const nowJson = require(nowJsonRef.fsPath);
|
const nowJson = json5.parse(await fs.readFile(nowJsonRef.fsPath, 'utf8'));
|
||||||
const build = nowJson.builds[0];
|
const build = nowJson.builds[0];
|
||||||
|
|
||||||
if (typeof expect !== 'undefined') {
|
if (typeof expect !== 'undefined') {
|
||||||
|
|||||||
Reference in New Issue
Block a user