mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 12:57:46 +00:00
Compare commits
13 Commits
@vercel/py
...
@vercel/ro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b211f28df | ||
|
|
c2d0887b94 | ||
|
|
fbb8bba4cf | ||
|
|
56cc87fe9d | ||
|
|
0027ffa65b | ||
|
|
0964be1710 | ||
|
|
9618ffe05f | ||
|
|
832ba3fe23 | ||
|
|
253b4fd1d2 | ||
|
|
9e5f17b3c6 | ||
|
|
39d0f8dbfc | ||
|
|
a567d047d1 | ||
|
|
fdfb3a385e |
@@ -16,7 +16,7 @@
|
||||
"unzip-stream": "0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "13.1.4",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/node-fetch": "2.5.4",
|
||||
"@vercel/node": "1.9.0",
|
||||
"typescript": "3.9.6"
|
||||
|
||||
3
examples/nextjs/.eslintrc.json
Normal file
3
examples/nextjs/.eslintrc.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
||||
4358
examples/nextjs/package-lock.json
generated
4358
examples/nextjs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,9 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "13.0.1",
|
||||
"eslint": "8.26.0",
|
||||
"eslint-config-next": "13.0.2",
|
||||
"next": "13.0.2",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "5.5.6",
|
||||
"version": "5.5.7",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "28.4.13",
|
||||
"version": "28.4.17",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -41,16 +41,16 @@
|
||||
"node": ">= 14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "5.5.6",
|
||||
"@vercel/go": "2.2.14",
|
||||
"@vercel/hydrogen": "0.0.27",
|
||||
"@vercel/next": "3.2.7",
|
||||
"@vercel/node": "2.6.0",
|
||||
"@vercel/python": "3.1.23",
|
||||
"@vercel/redwood": "1.0.32",
|
||||
"@vercel/remix": "1.0.33",
|
||||
"@vercel/ruby": "1.3.40",
|
||||
"@vercel/static-build": "1.0.33",
|
||||
"@vercel/build-utils": "5.5.7",
|
||||
"@vercel/go": "2.2.15",
|
||||
"@vercel/hydrogen": "0.0.29",
|
||||
"@vercel/next": "3.2.11",
|
||||
"@vercel/node": "2.6.2",
|
||||
"@vercel/python": "3.1.24",
|
||||
"@vercel/redwood": "1.0.35",
|
||||
"@vercel/remix": "1.0.35",
|
||||
"@vercel/ruby": "1.3.41",
|
||||
"@vercel/static-build": "1.0.36",
|
||||
"update-notifier": "5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -81,7 +81,7 @@
|
||||
"@types/minimatch": "3.0.3",
|
||||
"@types/mri": "1.1.0",
|
||||
"@types/ms": "0.7.30",
|
||||
"@types/node": "11.11.0",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/node-fetch": "2.5.10",
|
||||
"@types/npm-package-arg": "6.1.0",
|
||||
"@types/pluralize": "0.0.29",
|
||||
@@ -95,10 +95,10 @@
|
||||
"@types/which": "1.3.2",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@types/yauzl-promise": "2.1.0",
|
||||
"@vercel/client": "12.2.14",
|
||||
"@vercel/error-utils": "1.0.1",
|
||||
"@vercel/frameworks": "1.1.9",
|
||||
"@vercel/fs-detectors": "3.4.6",
|
||||
"@vercel/client": "12.2.17",
|
||||
"@vercel/error-utils": "1.0.3",
|
||||
"@vercel/frameworks": "1.1.12",
|
||||
"@vercel/fs-detectors": "3.4.9",
|
||||
"@vercel/fun": "1.0.4",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@zeit/source-map-support": "0.6.2",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { bold } from 'chalk';
|
||||
import inquirer from 'inquirer';
|
||||
import { EventEmitter } from 'events';
|
||||
import { URLSearchParams } from 'url';
|
||||
import { parse as parseUrl } from 'url';
|
||||
import { URL } from 'url';
|
||||
import { VercelConfig } from '@vercel/client';
|
||||
import retry, { RetryFunction, Options as RetryOptions } from 'async-retry';
|
||||
import fetch, { BodyInit, Headers, RequestInit, Response } from 'node-fetch';
|
||||
@@ -87,25 +86,18 @@ export default class Client extends EventEmitter implements Stdio {
|
||||
}
|
||||
|
||||
private _fetch(_url: string, opts: FetchOptions = {}) {
|
||||
const parsedUrl = parseUrl(_url, true);
|
||||
const apiUrl = parsedUrl.host
|
||||
? `${parsedUrl.protocol}//${parsedUrl.host}`
|
||||
: '';
|
||||
const url = new URL(_url, this.apiUrl);
|
||||
|
||||
if (opts.accountId || opts.useCurrentTeam !== false) {
|
||||
const query = new URLSearchParams(parsedUrl.query);
|
||||
|
||||
if (opts.accountId) {
|
||||
if (opts.accountId.startsWith('team_')) {
|
||||
query.set('teamId', opts.accountId);
|
||||
url.searchParams.set('teamId', opts.accountId);
|
||||
} else {
|
||||
query.delete('teamId');
|
||||
url.searchParams.delete('teamId');
|
||||
}
|
||||
} else if (opts.useCurrentTeam !== false && this.config.currentTeam) {
|
||||
query.set('teamId', this.config.currentTeam);
|
||||
url.searchParams.set('teamId', this.config.currentTeam);
|
||||
}
|
||||
|
||||
_url = `${apiUrl}${parsedUrl.pathname}?${query}`;
|
||||
}
|
||||
|
||||
const headers = new Headers(opts.headers);
|
||||
@@ -122,7 +114,6 @@ export default class Client extends EventEmitter implements Stdio {
|
||||
body = opts.body;
|
||||
}
|
||||
|
||||
const url = `${apiUrl ? '' : this.apiUrl}${_url}`;
|
||||
const requestId = this.requestIdCounter++;
|
||||
return this.output.time(res => {
|
||||
if (res) {
|
||||
@@ -130,7 +121,7 @@ export default class Client extends EventEmitter implements Stdio {
|
||||
res.statusText
|
||||
}: ${res.headers.get('x-vercel-id')}`;
|
||||
} else {
|
||||
return `#${requestId} → ${opts.method || 'GET'} ${url}`;
|
||||
return `#${requestId} → ${opts.method || 'GET'} ${url.href}`;
|
||||
}
|
||||
}, fetch(url, { ...opts, headers, body }));
|
||||
}
|
||||
|
||||
@@ -87,8 +87,12 @@ async function createBuildProcess(
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// The first message that the builder process sends is the `ready` event
|
||||
buildProcess.once('message', ({ type }) => {
|
||||
if (type !== 'ready') {
|
||||
buildProcess.once('message', data => {
|
||||
if (
|
||||
data !== null &&
|
||||
typeof data === 'object' &&
|
||||
(data as { type: string }).type !== 'ready'
|
||||
) {
|
||||
reject(new Error('Did not get "ready" event from builder'));
|
||||
} else {
|
||||
resolve(buildProcess);
|
||||
|
||||
@@ -31,11 +31,11 @@ export function parseListen(str: string, defaultPort = 3000): ListenSpec {
|
||||
return [url.pathname];
|
||||
case 'tcp:':
|
||||
url.port = url.port || String(defaultPort);
|
||||
return [parseInt(url.port, 10), url.hostname];
|
||||
return [parseInt(url.port, 10), url.hostname ?? undefined];
|
||||
default:
|
||||
if (!url.slashes) {
|
||||
if (url.protocol === null) {
|
||||
return [defaultPort, url.pathname];
|
||||
return [defaultPort, url.pathname ?? undefined];
|
||||
}
|
||||
port = Number(url.hostname);
|
||||
if (url.protocol && !isNaN(port)) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @param querystring - The querystring to parse, also known as the "search" string.
|
||||
*/
|
||||
export function parseQueryString(
|
||||
querystring?: string
|
||||
querystring?: string | null
|
||||
): Record<string, string[]> {
|
||||
const query: Record<string, string[]> = Object.create(null);
|
||||
if (!querystring || !querystring.startsWith('?') || querystring === '?') {
|
||||
@@ -38,9 +38,9 @@ export function parseQueryString(
|
||||
*/
|
||||
export function formatQueryString(
|
||||
query: Record<string, string[]> | undefined
|
||||
): string | undefined {
|
||||
): string | null {
|
||||
if (!query) {
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
let s = '';
|
||||
let prefix = '?';
|
||||
@@ -55,5 +55,5 @@ export function formatQueryString(
|
||||
prefix = '&';
|
||||
}
|
||||
}
|
||||
return s || undefined;
|
||||
return s || null;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,8 @@ export async function devRouter(
|
||||
phase?: HandleValue | null
|
||||
): Promise<RouteResult> {
|
||||
let result: RouteResult | undefined;
|
||||
let { pathname: reqPathname = '/', search: reqSearch } = url.parse(reqUrl);
|
||||
let { pathname: reqPathname, search: reqSearch } = url.parse(reqUrl);
|
||||
reqPathname ??= '/';
|
||||
const reqQuery = parseQueryString(reqSearch);
|
||||
const combinedHeaders: HttpHeadersConfig = { ...previousHeaders };
|
||||
let status: number | undefined;
|
||||
@@ -130,7 +131,8 @@ export async function devRouter(
|
||||
phase !== 'hit' &&
|
||||
!isDestUrl
|
||||
) {
|
||||
const { pathname = '/' } = url.parse(destPath);
|
||||
let { pathname } = url.parse(destPath);
|
||||
pathname ??= '/';
|
||||
const hasDestFile = await devServer.hasFilesystem(
|
||||
pathname,
|
||||
vercelConfig
|
||||
@@ -186,8 +188,9 @@ export async function devRouter(
|
||||
if (!destPath.startsWith('/')) {
|
||||
destPath = `/${destPath}`;
|
||||
}
|
||||
const { pathname: destPathname = '/', search: destSearch } =
|
||||
let { pathname: destPathname, search: destSearch } =
|
||||
url.parse(destPath);
|
||||
destPathname ??= '/';
|
||||
const destQuery = parseQueryString(destSearch);
|
||||
Object.assign(destQuery, reqQuery);
|
||||
result = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Client from '../client';
|
||||
import type Client from '../client';
|
||||
|
||||
export default async function confirm(
|
||||
client: Client,
|
||||
|
||||
@@ -34,7 +34,10 @@ export async function ensureLink(
|
||||
): Promise<LinkResult | number> {
|
||||
let link = await getLinkedProject(client, cwd);
|
||||
|
||||
if (link.status === 'not_linked') {
|
||||
if (
|
||||
(link.status === 'linked' && opts.forceDelete) ||
|
||||
link.status === 'not_linked'
|
||||
) {
|
||||
link = await setupAndLink(client, cwd, opts);
|
||||
|
||||
if (link.status === 'not_linked') {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
const { exec } = require('exeggcute');
|
||||
const path = require('path');
|
||||
const { existsSync, writeFileSync } = require('fs');
|
||||
|
||||
const a = require('./a');
|
||||
const b = require('./b');
|
||||
@@ -8,8 +10,14 @@ b();
|
||||
|
||||
exec('mkdir public', __dirname)
|
||||
.then(() => {
|
||||
exec('echo "Hello, World!" > public/index.html', __dirname).then(() => {
|
||||
const cacheFile = path.join(__dirname, 'node_modules/.was-cached');
|
||||
const cacheExists = existsSync(cacheFile);
|
||||
exec(
|
||||
`echo ${cacheExists ? 'cache exists' : 'no cache'} > public/index.html`,
|
||||
__dirname
|
||||
).then(() => {
|
||||
console.log('Success');
|
||||
writeFileSync(cacheFile, '1');
|
||||
});
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
15
packages/cli/test/integration.js
vendored
15
packages/cli/test/integration.js
vendored
@@ -3446,23 +3446,20 @@ test('deploy pnpm twice using pnp and symlink=false', async t => {
|
||||
]);
|
||||
}
|
||||
|
||||
function logs(deploymentUrl) {
|
||||
return execa(binaryPath, ['logs', deploymentUrl, ...defaultArgs]);
|
||||
}
|
||||
|
||||
let { exitCode, stderr, stdout } = await deploy();
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
|
||||
let { stdout: logsOutput } = await logs(stdout);
|
||||
|
||||
t.regex(logsOutput, /Build Cache not found/m);
|
||||
let page = await fetch(stdout);
|
||||
let text = await page.text();
|
||||
t.is(text, 'no cache\n');
|
||||
|
||||
({ exitCode, stderr, stdout } = await deploy());
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
|
||||
({ stdout: logsOutput } = await logs(stdout));
|
||||
page = await fetch(stdout);
|
||||
text = await page.text();
|
||||
|
||||
t.regex(logsOutput, /Build cache downloaded/m);
|
||||
t.is(text, 'cache exists\n');
|
||||
});
|
||||
|
||||
test('reject deploying with wrong team .vercel config', async t => {
|
||||
|
||||
@@ -23,7 +23,7 @@ class MockStream extends PassThrough {
|
||||
this.isTTY = true;
|
||||
}
|
||||
|
||||
// These is for the `ora` module
|
||||
// These are for the `ora` module
|
||||
clearLine() {}
|
||||
cursorTo() {}
|
||||
}
|
||||
|
||||
125
packages/cli/test/unit/commands/link.test.ts
Normal file
125
packages/cli/test/unit/commands/link.test.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { basename, join } from 'path';
|
||||
import { mkdtemp, readJSON, remove } from 'fs-extra';
|
||||
import link from '../../../src/commands/link';
|
||||
import { client } from '../../mocks/client';
|
||||
import { useUser } from '../../mocks/user';
|
||||
import { useTeams } from '../../mocks/team';
|
||||
import {
|
||||
defaultProject,
|
||||
useProject,
|
||||
useUnknownProject,
|
||||
} from '../../mocks/project';
|
||||
import { tmpdir } from 'os';
|
||||
|
||||
describe('link', () => {
|
||||
const origCwd = process.cwd();
|
||||
|
||||
it('should prompt for link', async () => {
|
||||
const cwd = await mkdtemp(join(tmpdir(), 'cli-'));
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
const user = useUser();
|
||||
useTeams('team_dummy');
|
||||
const { project } = useProject({
|
||||
...defaultProject,
|
||||
id: basename(cwd),
|
||||
name: basename(cwd),
|
||||
});
|
||||
useUnknownProject();
|
||||
|
||||
const exitCodePromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
'Which scope should contain your project?'
|
||||
);
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput('Link to it?');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
`Linked to ${user.username}/${project.name} (created .vercel and added it to .gitignore)`
|
||||
);
|
||||
|
||||
await expect(exitCodePromise).resolves.toEqual(0);
|
||||
|
||||
const projectJson = await readJSON(join(cwd, '.vercel/project.json'));
|
||||
expect(projectJson.orgId).toEqual(user.id);
|
||||
expect(projectJson.projectId).toEqual(project.id);
|
||||
} finally {
|
||||
process.chdir(origCwd);
|
||||
await remove(cwd);
|
||||
}
|
||||
});
|
||||
|
||||
it('should allow specifying `--project` flag', async () => {
|
||||
const cwd = await mkdtemp(join(tmpdir(), 'cli-'));
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
const user = useUser();
|
||||
useTeams('team_dummy');
|
||||
const { project } = useProject({
|
||||
...defaultProject,
|
||||
id: basename(cwd),
|
||||
name: basename(cwd),
|
||||
});
|
||||
useUnknownProject();
|
||||
|
||||
client.setArgv('--project', project.name!, '--yes');
|
||||
const exitCodePromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
`Linked to ${user.username}/${project.name} (created .vercel and added it to .gitignore)`
|
||||
);
|
||||
|
||||
await expect(exitCodePromise).resolves.toEqual(0);
|
||||
|
||||
const projectJson = await readJSON(join(cwd, '.vercel/project.json'));
|
||||
expect(projectJson.orgId).toEqual(user.id);
|
||||
expect(projectJson.projectId).toEqual(project.id);
|
||||
} finally {
|
||||
process.chdir(origCwd);
|
||||
await remove(cwd);
|
||||
}
|
||||
});
|
||||
|
||||
it('should allow overwriting existing link', async () => {
|
||||
const cwd = await mkdtemp(join(tmpdir(), 'cli-'));
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
const user = useUser();
|
||||
useTeams('team_dummy');
|
||||
const { project: proj1 } = useProject({
|
||||
...defaultProject,
|
||||
id: 'one',
|
||||
name: 'one',
|
||||
});
|
||||
const { project: proj2 } = useProject({
|
||||
...defaultProject,
|
||||
id: 'two',
|
||||
name: 'two',
|
||||
});
|
||||
useUnknownProject();
|
||||
|
||||
client.setArgv('--project', proj1.name!, '--yes');
|
||||
await expect(link(client)).resolves.toEqual(0);
|
||||
|
||||
let projectJson = await readJSON(join(cwd, '.vercel/project.json'));
|
||||
expect(projectJson.orgId).toEqual(user.id);
|
||||
expect(projectJson.projectId).toEqual(proj1.id);
|
||||
|
||||
client.setArgv('--project', proj2.name!, '--yes');
|
||||
await expect(link(client)).resolves.toEqual(0);
|
||||
|
||||
projectJson = await readJSON(join(cwd, '.vercel/project.json'));
|
||||
expect(projectJson.orgId).toEqual(user.id);
|
||||
expect(projectJson.projectId).toEqual(proj2.id);
|
||||
} finally {
|
||||
process.chdir(origCwd);
|
||||
await remove(cwd);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -23,24 +23,24 @@ describe('parseQueryString', () => {
|
||||
const parsed = parseQueryString('');
|
||||
expect(parsed).toEqual({});
|
||||
const format = formatQueryString(parsed);
|
||||
expect(format).toEqual(undefined);
|
||||
expect(format).toEqual(null);
|
||||
});
|
||||
it('should work with question mark', async () => {
|
||||
const parsed = parseQueryString('?');
|
||||
expect(parsed).toEqual({});
|
||||
const format = formatQueryString(parsed);
|
||||
expect(format).toEqual(undefined);
|
||||
expect(format).toEqual(null);
|
||||
});
|
||||
it('should work without question mark', async () => {
|
||||
const parsed = parseQueryString('blarg');
|
||||
expect(parsed).toEqual({});
|
||||
const format = formatQueryString(parsed);
|
||||
expect(format).toEqual(undefined);
|
||||
expect(format).toEqual(null);
|
||||
});
|
||||
it('should work with undefined', async () => {
|
||||
const parsed = parseQueryString(undefined);
|
||||
expect(parsed).toEqual({});
|
||||
const format = formatQueryString(parsed);
|
||||
expect(format).toEqual(undefined);
|
||||
expect(format).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "12.2.14",
|
||||
"version": "12.2.17",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -28,7 +28,7 @@
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/minimatch": "3.0.5",
|
||||
"@types/ms": "0.7.30",
|
||||
"@types/node": "12.0.4",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/node-fetch": "2.5.4",
|
||||
"@types/recursive-readdir": "2.2.0",
|
||||
"@types/tar-fs": "1.16.1",
|
||||
@@ -43,8 +43,8 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "5.5.6",
|
||||
"@vercel/routing-utils": "2.1.0",
|
||||
"@vercel/build-utils": "5.5.7",
|
||||
"@vercel/routing-utils": "2.1.3",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/edge",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.mjs",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/error-utils",
|
||||
"version": "1.0.1",
|
||||
"private": true,
|
||||
"version": "1.0.3",
|
||||
"description": "A collection of error utilities for vercel/vercel",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@@ -18,7 +17,7 @@
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/jest": "29.2.1",
|
||||
"@types/node": "16.11.7",
|
||||
"@types/node": "14.18.33",
|
||||
"jest": "29.2.2",
|
||||
"ts-jest": "29.0.3",
|
||||
"typescript": "^4.8.4"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/frameworks",
|
||||
"version": "1.1.9",
|
||||
"version": "1.1.12",
|
||||
"main": "./dist/frameworks.js",
|
||||
"types": "./dist/frameworks.d.ts",
|
||||
"files": [
|
||||
@@ -19,9 +19,9 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/js-yaml": "3.12.1",
|
||||
"@types/node": "12.0.4",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/node-fetch": "2.5.8",
|
||||
"@vercel/routing-utils": "2.1.0",
|
||||
"@vercel/routing-utils": "2.1.3",
|
||||
"ajv": "6.12.2",
|
||||
"typescript": "4.3.4"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/fs-detectors",
|
||||
"version": "3.4.6",
|
||||
"version": "3.4.9",
|
||||
"description": "Vercel filesystem detectors",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -19,8 +19,8 @@
|
||||
"test-unit": "yarn test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/frameworks": "1.1.9",
|
||||
"@vercel/routing-utils": "2.1.0",
|
||||
"@vercel/frameworks": "1.1.12",
|
||||
"@vercel/routing-utils": "2.1.3",
|
||||
"glob": "8.0.3",
|
||||
"js-yaml": "4.1.0",
|
||||
"json5": "2.2.1",
|
||||
@@ -32,7 +32,7 @@
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/js-yaml": "4.0.5",
|
||||
"@types/minimatch": "3.0.5",
|
||||
"@types/node": "12.12.20",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/semver": "7.3.10",
|
||||
"@vercel/build-utils": "4.2.0",
|
||||
"typescript": "4.3.4"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/go",
|
||||
"version": "2.2.14",
|
||||
"version": "2.2.15",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||
@@ -35,7 +35,7 @@
|
||||
"@types/jest": "28.1.6",
|
||||
"@types/node-fetch": "^2.3.0",
|
||||
"@types/tar": "^4.0.0",
|
||||
"@vercel/build-utils": "5.5.6",
|
||||
"@vercel/build-utils": "5.5.7",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"async-retry": "1.3.1",
|
||||
"execa": "^1.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/hydrogen",
|
||||
"version": "0.0.27",
|
||||
"version": "0.0.29",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -20,9 +20,9 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "*",
|
||||
"@vercel/build-utils": "5.5.6",
|
||||
"@vercel/static-config": "2.0.4",
|
||||
"@types/node": "14.18.33",
|
||||
"@vercel/build-utils": "5.5.7",
|
||||
"@vercel/static-config": "2.0.6",
|
||||
"typescript": "4.6.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/next",
|
||||
"version": "3.2.7",
|
||||
"version": "3.2.11",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||
@@ -39,14 +39,14 @@
|
||||
"@types/fs-extra": "8.0.0",
|
||||
"@types/glob": "7.1.3",
|
||||
"@types/next-server": "8.0.0",
|
||||
"@types/node": "14.17.27",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/resolve-from": "5.0.1",
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/text-table": "0.2.1",
|
||||
"@types/webpack-sources": "3.2.0",
|
||||
"@vercel/build-utils": "5.5.6",
|
||||
"@vercel/build-utils": "5.5.7",
|
||||
"@vercel/nft": "0.22.1",
|
||||
"@vercel/routing-utils": "2.1.0",
|
||||
"@vercel/routing-utils": "2.1.3",
|
||||
"async-sema": "3.0.1",
|
||||
"buffer-crc32": "0.2.13",
|
||||
"cheerio": "1.0.0-rc.10",
|
||||
|
||||
@@ -1137,6 +1137,25 @@ export async function serverBuild({
|
||||
}
|
||||
}
|
||||
|
||||
const rscHeader = routesManifest.rsc?.header?.toLowerCase() || '__rsc__';
|
||||
const completeDynamicRoutes: typeof dynamicRoutes = [];
|
||||
|
||||
if (appDir) {
|
||||
for (const route of dynamicRoutes) {
|
||||
completeDynamicRoutes.push(route);
|
||||
completeDynamicRoutes.push({
|
||||
...route,
|
||||
src: route.src.replace(
|
||||
new RegExp(escapeStringRegexp('(?:/)?$')),
|
||||
'(?:\\.rsc)?(?:/)?$'
|
||||
),
|
||||
dest: route.dest?.replace(/($|\?)/, '.rsc$1'),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
completeDynamicRoutes.push(...dynamicRoutes);
|
||||
}
|
||||
|
||||
return {
|
||||
wildcard: wildcardConfig,
|
||||
images:
|
||||
@@ -1311,8 +1330,16 @@ export async function serverBuild({
|
||||
|
||||
// middleware comes directly after redirects but before
|
||||
// beforeFiles rewrites as middleware is not a "file" route
|
||||
...(routesManifest?.skipMiddlewareUrlNormalize
|
||||
? denormalizeNextDataRoute(true)
|
||||
: []),
|
||||
|
||||
...(isCorrectMiddlewareOrder ? middleware.staticRoutes : []),
|
||||
|
||||
...(routesManifest?.skipMiddlewareUrlNormalize
|
||||
? normalizeNextDataRoute(true)
|
||||
: []),
|
||||
|
||||
...beforeFilesRewrites,
|
||||
|
||||
// Make sure to 404 for the /404 path itself
|
||||
@@ -1390,7 +1417,7 @@ export async function serverBuild({
|
||||
has: [
|
||||
{
|
||||
type: 'header',
|
||||
key: '__rsc__',
|
||||
key: rscHeader,
|
||||
},
|
||||
],
|
||||
dest: path.posix.join('/', entryDirectory, '/index.rsc'),
|
||||
@@ -1401,7 +1428,7 @@ export async function serverBuild({
|
||||
has: [
|
||||
{
|
||||
type: 'header',
|
||||
key: '__rsc__',
|
||||
key: rscHeader,
|
||||
},
|
||||
],
|
||||
dest: path.posix.join('/', entryDirectory, '/$1.rsc'),
|
||||
@@ -1502,7 +1529,7 @@ export async function serverBuild({
|
||||
? // when resolving data routes for middleware we need to include
|
||||
// all dynamic routes including non-SSG/SSP so that the priority
|
||||
// is correct
|
||||
dynamicRoutes
|
||||
completeDynamicRoutes
|
||||
.map(route => {
|
||||
route = Object.assign({}, route);
|
||||
let normalizedSrc = route.src;
|
||||
@@ -1577,7 +1604,7 @@ export async function serverBuild({
|
||||
|
||||
// Dynamic routes (must come after dataRoutes as dataRoutes are more
|
||||
// specific)
|
||||
...dynamicRoutes,
|
||||
...completeDynamicRoutes,
|
||||
|
||||
...(isNextDataServerResolving
|
||||
? [
|
||||
|
||||
@@ -209,6 +209,11 @@ type RoutesManifestOld = {
|
||||
defaultLocale: string;
|
||||
}>;
|
||||
};
|
||||
rsc?: {
|
||||
header: string;
|
||||
varyHeader: string;
|
||||
};
|
||||
skipMiddlewareUrlNormalize?: boolean;
|
||||
};
|
||||
|
||||
type RoutesManifestV4 = Omit<RoutesManifestOld, 'dynamicRoutes' | 'version'> & {
|
||||
@@ -1991,6 +1996,9 @@ export const onPrerenderRoute =
|
||||
allowQuery = [];
|
||||
}
|
||||
}
|
||||
const rscVaryHeader =
|
||||
routesManifest?.rsc?.varyHeader ||
|
||||
'__rsc__, __next_router_state_tree__, __next_router_prefetch__';
|
||||
|
||||
prerenders[outputPathPage] = new Prerender({
|
||||
expiration: initialRevalidate,
|
||||
@@ -2008,7 +2016,7 @@ export const onPrerenderRoute =
|
||||
...(isAppPathRoute
|
||||
? {
|
||||
initialHeaders: {
|
||||
vary: '__rsc__, __next_router_state_tree__, __next_router_prefetch__',
|
||||
vary: rscVaryHeader,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
@@ -2031,7 +2039,7 @@ export const onPrerenderRoute =
|
||||
? {
|
||||
initialHeaders: {
|
||||
'content-type': 'application/octet-stream',
|
||||
vary: '__rsc__, __next_router_state_tree__, __next_router_prefetch__',
|
||||
vary: rscVaryHeader,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
@@ -2270,6 +2278,7 @@ interface EdgeFunctionInfoV2 extends BaseEdgeFunctionInfo {
|
||||
interface EdgeFunctionMatcher {
|
||||
regexp: string;
|
||||
has?: HasField;
|
||||
missing?: HasField;
|
||||
}
|
||||
|
||||
export async function getMiddlewareBundle({
|
||||
@@ -2471,6 +2480,7 @@ export async function getMiddlewareBundle({
|
||||
key: 'x-prerender-revalidate',
|
||||
value: prerenderBypassToken,
|
||||
},
|
||||
...(matcher.missing || []),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -2601,6 +2611,9 @@ function getRouteMatchers(
|
||||
if (matcher.has) {
|
||||
m.has = normalizeHas(matcher.has);
|
||||
}
|
||||
if (matcher.missing) {
|
||||
m.missing = normalizeHas(matcher.missing);
|
||||
}
|
||||
return m;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,8 +2,5 @@ module.exports = {
|
||||
experimental: {
|
||||
appDir: true,
|
||||
runtime: 'experimental-edge',
|
||||
serverComponents: true,
|
||||
legacyBrowsers: false,
|
||||
browsersListForSwc: true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"path": "/edge",
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"__rsc__": "1"
|
||||
"RSC": "1"
|
||||
},
|
||||
"mustContain": "M1:{",
|
||||
"mustNotContain": "<html"
|
||||
@@ -24,7 +24,7 @@
|
||||
"path": "/edge",
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"__rsc__": "1"
|
||||
"RSC": "1"
|
||||
},
|
||||
"responseHeaders": {
|
||||
"content-type": "application/octet-stream"
|
||||
@@ -39,7 +39,7 @@
|
||||
"path": "/",
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"__rsc__": "1"
|
||||
"RSC": "1"
|
||||
},
|
||||
"mustContain": "M1:{",
|
||||
"mustNotContain": "<html"
|
||||
@@ -48,7 +48,7 @@
|
||||
"path": "/",
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"__rsc__": "1"
|
||||
"RSC": "1"
|
||||
},
|
||||
"responseHeaders": {
|
||||
"content-type": "application/octet-stream"
|
||||
|
||||
@@ -2,9 +2,6 @@ module.exports = {
|
||||
experimental: {
|
||||
appDir: true,
|
||||
runtime: 'nodejs',
|
||||
serverComponents: true,
|
||||
legacyBrowsers: false,
|
||||
browsersListForSwc: true,
|
||||
},
|
||||
rewrites: async () => {
|
||||
return [
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
"status": 200,
|
||||
"mustContain": "hello from app/dashboard",
|
||||
"responseHeaders": {
|
||||
"vary": "__rsc__, __next_router_state_tree__, __next_router_prefetch__"
|
||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/dashboard",
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"__rsc__": "1"
|
||||
"RSC": "1"
|
||||
},
|
||||
"mustContain": "M1:{",
|
||||
"mustNotContain": "<html"
|
||||
@@ -27,11 +27,11 @@
|
||||
"path": "/dashboard",
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"__rsc__": "1"
|
||||
"RSC": "1"
|
||||
},
|
||||
"responseHeaders": {
|
||||
"content-type": "application/octet-stream",
|
||||
"vary": "__rsc__, __next_router_state_tree__, __next_router_prefetch__"
|
||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -63,7 +63,7 @@
|
||||
"path": "/",
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"__rsc__": "1"
|
||||
"RSC": "1"
|
||||
},
|
||||
"mustContain": "M1:{",
|
||||
"mustNotContain": "<html"
|
||||
|
||||
10
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/[id]/settings/page.js
vendored
Normal file
10
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/[id]/settings/page.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function DeploymentsPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
hello from app/dashboard/deployments/[id]/settings. ID is:{' '}
|
||||
{props.params.id}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export default function Page() {
|
||||
return <p>catchall</p>;
|
||||
}
|
||||
@@ -2,9 +2,6 @@ module.exports = {
|
||||
experimental: {
|
||||
appDir: true,
|
||||
runtime: 'nodejs',
|
||||
serverComponents: true,
|
||||
legacyBrowsers: false,
|
||||
browsersListForSwc: true,
|
||||
},
|
||||
rewrites: async () => {
|
||||
return [
|
||||
|
||||
@@ -6,19 +6,59 @@
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/dashboard/deployments/123/settings",
|
||||
"status": 200,
|
||||
"mustContain": "hello from app/dashboard/deployments/[id]/settings",
|
||||
"responseHeaders": {
|
||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/dashboard/deployments/123/settings",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||
},
|
||||
"headers": {
|
||||
"RSC": "1"
|
||||
},
|
||||
"mustContain": "M1:{",
|
||||
"mustNotContain": "<html"
|
||||
},
|
||||
{
|
||||
"path": "/dashboard/deployments/catchall/something",
|
||||
"status": 200,
|
||||
"mustContain": "catchall",
|
||||
"responseHeaders": {
|
||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/dashboard/deployments/catchall/something",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||
},
|
||||
"headers": {
|
||||
"RSC": "1"
|
||||
},
|
||||
"mustContain": "M1:{",
|
||||
"mustNotContain": "<html"
|
||||
},
|
||||
{
|
||||
"path": "/dashboard",
|
||||
"status": 200,
|
||||
"mustContain": "hello from app/dashboard",
|
||||
"responseHeaders": {
|
||||
"vary": "__rsc__, __next_router_state_tree__, __next_router_prefetch__"
|
||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/dashboard",
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"__rsc__": "1"
|
||||
"RSC": "1"
|
||||
},
|
||||
"mustContain": "M1:{",
|
||||
"mustNotContain": "<html"
|
||||
@@ -27,11 +67,11 @@
|
||||
"path": "/dashboard",
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"__rsc__": "1"
|
||||
"RSC": "1"
|
||||
},
|
||||
"responseHeaders": {
|
||||
"content-type": "application/octet-stream",
|
||||
"vary": "__rsc__, __next_router_state_tree__, __next_router_prefetch__"
|
||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -68,7 +108,7 @@
|
||||
"path": "/",
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"__rsc__": "1"
|
||||
"RSC": "1"
|
||||
},
|
||||
"mustContain": "M1:{",
|
||||
"mustNotContain": "<html"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/node-bridge",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.2",
|
||||
"license": "MIT",
|
||||
"main": "./index.js",
|
||||
"repository": {
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/aws-lambda": "8.10.19",
|
||||
"@types/node": "*",
|
||||
"@types/node": "14.18.33",
|
||||
"jsonlines": "0.1.1",
|
||||
"test-listen": "1.1.0",
|
||||
"typescript": "4.3.4"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/node",
|
||||
"version": "2.6.0",
|
||||
"version": "2.6.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
||||
@@ -30,10 +30,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@edge-runtime/vm": "2.0.0",
|
||||
"@types/node": "*",
|
||||
"@vercel/build-utils": "5.5.6",
|
||||
"@vercel/node-bridge": "3.1.0",
|
||||
"@vercel/static-config": "2.0.4",
|
||||
"@types/node": "14.18.33",
|
||||
"@vercel/build-utils": "5.5.7",
|
||||
"@vercel/node-bridge": "3.1.2",
|
||||
"@vercel/static-config": "2.0.6",
|
||||
"edge-runtime": "2.0.0",
|
||||
"esbuild": "0.14.47",
|
||||
"exit-hook": "2.2.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/python",
|
||||
"version": "3.1.23",
|
||||
"version": "3.1.24",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
||||
@@ -22,7 +22,7 @@
|
||||
"devDependencies": {
|
||||
"@types/execa": "^0.9.0",
|
||||
"@types/jest": "27.4.1",
|
||||
"@vercel/build-utils": "5.5.6",
|
||||
"@vercel/build-utils": "5.5.7",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"execa": "^1.0.0",
|
||||
"typescript": "4.3.4"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/redwood",
|
||||
"version": "1.0.32",
|
||||
"version": "1.0.35",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -20,13 +20,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/nft": "0.22.1",
|
||||
"@vercel/routing-utils": "2.1.0",
|
||||
"@vercel/routing-utils": "2.1.3",
|
||||
"semver": "6.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/aws-lambda": "8.10.19",
|
||||
"@types/node": "*",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/semver": "6.0.0",
|
||||
"@vercel/build-utils": "5.5.6"
|
||||
"@vercel/build-utils": "5.5.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/remix",
|
||||
"version": "1.0.33",
|
||||
"version": "1.0.35",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -24,8 +24,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "*",
|
||||
"@vercel/build-utils": "5.5.6",
|
||||
"@types/node": "14.18.33",
|
||||
"@vercel/build-utils": "5.5.7",
|
||||
"typescript": "4.6.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/routing-utils",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.3",
|
||||
"description": "Vercel routing utilities",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/node": "12.12.20",
|
||||
"@types/node": "14.18.33",
|
||||
"ajv": "^6.0.0",
|
||||
"typescript": "4.3.4"
|
||||
},
|
||||
|
||||
@@ -51,6 +51,9 @@ export function convertRedirects(
|
||||
return redirects.map(r => {
|
||||
const { src, segments } = sourceToRegex(r.source);
|
||||
const hasSegments = collectHasSegments(r.has);
|
||||
normalizeHasKeys(r.has);
|
||||
normalizeHasKeys(r.missing);
|
||||
|
||||
try {
|
||||
const loc = replaceSegments(segments, hasSegments, r.destination, true);
|
||||
let status: number;
|
||||
@@ -70,6 +73,9 @@ export function convertRedirects(
|
||||
if (r.has) {
|
||||
route.has = r.has;
|
||||
}
|
||||
if (r.missing) {
|
||||
route.missing = r.missing;
|
||||
}
|
||||
return route;
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to parse redirect: ${JSON.stringify(r)}`);
|
||||
@@ -84,6 +90,9 @@ export function convertRewrites(
|
||||
return rewrites.map(r => {
|
||||
const { src, segments } = sourceToRegex(r.source);
|
||||
const hasSegments = collectHasSegments(r.has);
|
||||
normalizeHasKeys(r.has);
|
||||
normalizeHasKeys(r.missing);
|
||||
|
||||
try {
|
||||
const dest = replaceSegments(
|
||||
segments,
|
||||
@@ -97,6 +106,9 @@ export function convertRewrites(
|
||||
if (r.has) {
|
||||
route.has = r.has;
|
||||
}
|
||||
if (r.missing) {
|
||||
route.missing = r.missing;
|
||||
}
|
||||
return route;
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to parse rewrite: ${JSON.stringify(r)}`);
|
||||
@@ -109,6 +121,9 @@ export function convertHeaders(headers: Header[]): Route[] {
|
||||
const obj: { [key: string]: string } = {};
|
||||
const { src, segments } = sourceToRegex(h.source);
|
||||
const hasSegments = collectHasSegments(h.has);
|
||||
normalizeHasKeys(h.has);
|
||||
normalizeHasKeys(h.missing);
|
||||
|
||||
const namedSegments = segments.filter(name => name !== UN_NAMED_SEGMENT);
|
||||
const indexes: { [k: string]: string } = {};
|
||||
|
||||
@@ -140,6 +155,9 @@ export function convertHeaders(headers: Header[]): Route[] {
|
||||
if (h.has) {
|
||||
route.has = h.has;
|
||||
}
|
||||
if (h.missing) {
|
||||
route.missing = h.missing;
|
||||
}
|
||||
return route;
|
||||
});
|
||||
}
|
||||
@@ -193,14 +211,19 @@ export function sourceToRegex(source: string): {
|
||||
|
||||
const namedGroupsRegex = /\(\?<([a-zA-Z][a-zA-Z0-9]*)>/g;
|
||||
|
||||
const normalizeHasKeys = (hasItems: HasField = []) => {
|
||||
for (const hasItem of hasItems) {
|
||||
if ('key' in hasItem && hasItem.type === 'header') {
|
||||
hasItem.key = hasItem.key.toLowerCase();
|
||||
}
|
||||
}
|
||||
return hasItems;
|
||||
};
|
||||
|
||||
export function collectHasSegments(has?: HasField) {
|
||||
const hasSegments = new Set<string>();
|
||||
|
||||
for (const hasItem of has || []) {
|
||||
if ('key' in hasItem && hasItem.type === 'header') {
|
||||
hasItem.key = hasItem.key.toLowerCase();
|
||||
}
|
||||
|
||||
if (!hasItem.value && 'key' in hasItem) {
|
||||
hasSegments.add(hasItem.key);
|
||||
}
|
||||
@@ -297,7 +320,12 @@ function replaceSegments(
|
||||
safelyCompile(unescapeSegments(str), indexes, true)
|
||||
);
|
||||
} else {
|
||||
query[key] = safelyCompile(unescapeSegments(strOrArray), indexes, true);
|
||||
// TODO: handle strOrArray is undefined
|
||||
query[key] = safelyCompile(
|
||||
unescapeSegments(strOrArray as string),
|
||||
indexes,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
148
packages/routing-utils/test/superstatic.spec.ts
vendored
148
packages/routing-utils/test/superstatic.spec.ts
vendored
@@ -224,6 +224,17 @@ test('convertRedirects', () => {
|
||||
],
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
source: '/hello/:first',
|
||||
destination: '/another',
|
||||
missing: [
|
||||
{
|
||||
type: 'host',
|
||||
value: '(?<a>.*)\\.(?<b>.*)',
|
||||
},
|
||||
],
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
source: '/hello/:first',
|
||||
destination:
|
||||
@@ -384,6 +395,19 @@ test('convertRedirects', () => {
|
||||
src: '^\\/hello(?:\\/([^\\/]+?))$',
|
||||
status: 307,
|
||||
},
|
||||
{
|
||||
missing: [
|
||||
{
|
||||
type: 'host',
|
||||
value: '(?<a>.*)\\.(?<b>.*)',
|
||||
},
|
||||
],
|
||||
headers: {
|
||||
Location: '/another',
|
||||
},
|
||||
src: '^\\/hello(?:\\/([^\\/]+?))$',
|
||||
status: 307,
|
||||
},
|
||||
{
|
||||
has: [
|
||||
{
|
||||
@@ -453,6 +477,7 @@ test('convertRedirects', () => {
|
||||
['/hello/world', '/hello/again'],
|
||||
['/hello/world'],
|
||||
['/hello/world'],
|
||||
['/hello/world'],
|
||||
];
|
||||
|
||||
const mustNotMatch = [
|
||||
@@ -474,6 +499,7 @@ test('convertRedirects', () => {
|
||||
['/feature/first', '/feature'],
|
||||
['/hello', '/hello/another/one'],
|
||||
['/hellooo'],
|
||||
['/hellooo'],
|
||||
['/helloooo'],
|
||||
];
|
||||
|
||||
@@ -586,6 +612,48 @@ test('convertRewrites', () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
source: '/hello/:first',
|
||||
destination: '/another',
|
||||
missing: [
|
||||
{
|
||||
type: 'header',
|
||||
key: 'x-rewrite',
|
||||
},
|
||||
{
|
||||
type: 'cookie',
|
||||
key: 'loggedIn',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
type: 'host',
|
||||
value: 'vercel.com',
|
||||
},
|
||||
{
|
||||
type: 'host',
|
||||
value: '(?<a>.*)\\.(?<b>.*)',
|
||||
},
|
||||
{
|
||||
type: 'header',
|
||||
key: 'host',
|
||||
value: '(?<c>.*)\\.(?<d>.*)',
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
key: 'username',
|
||||
},
|
||||
{
|
||||
type: 'header',
|
||||
key: 'x-pathname',
|
||||
value: '(?<pathname>.*)',
|
||||
},
|
||||
{
|
||||
type: 'header',
|
||||
key: 'X-Pathname',
|
||||
value: '(?<another>hello|world)',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
source: '/array-query-string/:id/:name',
|
||||
destination: 'https://example.com/?tag=1&tag=2',
|
||||
@@ -740,6 +808,49 @@ test('convertRewrites', () => {
|
||||
],
|
||||
src: '^\\/hello(?:\\/([^\\/]+?))$',
|
||||
},
|
||||
{
|
||||
check: true,
|
||||
dest: '/another?first=$1',
|
||||
missing: [
|
||||
{
|
||||
key: 'x-rewrite',
|
||||
type: 'header',
|
||||
},
|
||||
{
|
||||
key: 'loggedIn',
|
||||
type: 'cookie',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
type: 'host',
|
||||
value: 'vercel.com',
|
||||
},
|
||||
{
|
||||
type: 'host',
|
||||
value: '(?<a>.*)\\.(?<b>.*)',
|
||||
},
|
||||
{
|
||||
key: 'host',
|
||||
type: 'header',
|
||||
value: '(?<c>.*)\\.(?<d>.*)',
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
key: 'username',
|
||||
},
|
||||
{
|
||||
type: 'header',
|
||||
key: 'x-pathname',
|
||||
value: '(?<pathname>.*)',
|
||||
},
|
||||
{
|
||||
type: 'header',
|
||||
key: 'x-pathname',
|
||||
value: '(?<another>hello|world)',
|
||||
},
|
||||
],
|
||||
src: '^\\/hello(?:\\/([^\\/]+?))$',
|
||||
},
|
||||
{
|
||||
src: '^\\/array-query-string(?:\\/([^\\/]+?))(?:\\/([^\\/]+?))$',
|
||||
dest: 'https://example.com/?tag=1&tag=2&id=$1&name=$2',
|
||||
@@ -776,6 +887,7 @@ test('convertRewrites', () => {
|
||||
['/hello/world', '/hello/again'],
|
||||
['/hello/world'],
|
||||
['/hello/world'],
|
||||
['/hello/world'],
|
||||
['/array-query-string/10/email'],
|
||||
['/en/hello'],
|
||||
];
|
||||
@@ -802,6 +914,7 @@ test('convertRewrites', () => {
|
||||
['/hello', '/hello/another/one'],
|
||||
['/hllooo'],
|
||||
['/hllooo'],
|
||||
['/hllooo'],
|
||||
['/array-query-string/10'],
|
||||
['/en/hello/world', '/en/hello/'],
|
||||
];
|
||||
@@ -919,6 +1032,25 @@ test('convertHeaders', () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
source: '/hello/:first',
|
||||
missing: [
|
||||
{
|
||||
type: 'host',
|
||||
value: '(?<a>.*)\\.(?<b>.*)',
|
||||
},
|
||||
],
|
||||
headers: [
|
||||
{
|
||||
key: 'x-a',
|
||||
value: 'a',
|
||||
},
|
||||
{
|
||||
key: 'x-b',
|
||||
value: 'b',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
source: '/hello/:first',
|
||||
has: [
|
||||
@@ -1057,6 +1189,20 @@ test('convertHeaders', () => {
|
||||
},
|
||||
src: '^\\/hello(?:\\/([^\\/]+?))$',
|
||||
},
|
||||
{
|
||||
continue: true,
|
||||
missing: [
|
||||
{
|
||||
type: 'host',
|
||||
value: '(?<a>.*)\\.(?<b>.*)',
|
||||
},
|
||||
],
|
||||
headers: {
|
||||
'x-a': 'a',
|
||||
'x-b': 'b',
|
||||
},
|
||||
src: '^\\/hello(?:\\/([^\\/]+?))$',
|
||||
},
|
||||
{
|
||||
continue: true,
|
||||
has: [
|
||||
@@ -1133,6 +1279,7 @@ test('convertHeaders', () => {
|
||||
['/like/params/first', '/like/params/second'],
|
||||
['/hello/world'],
|
||||
['/hello/world'],
|
||||
['/hello/world'],
|
||||
['/hello'],
|
||||
];
|
||||
|
||||
@@ -1143,6 +1290,7 @@ test('convertHeaders', () => {
|
||||
['/non-match', '/like/params', '/like/params/'],
|
||||
['/hellooo'],
|
||||
['/hellooo'],
|
||||
['/hellooo'],
|
||||
[],
|
||||
];
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@vercel/ruby",
|
||||
"author": "Nathan Cahill <nathan@nathancahill.com>",
|
||||
"version": "1.3.40",
|
||||
"version": "1.3.41",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
|
||||
@@ -22,7 +22,7 @@
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "8.0.0",
|
||||
"@types/semver": "6.0.0",
|
||||
"@vercel/build-utils": "5.5.6",
|
||||
"@vercel/build-utils": "5.5.7",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"execa": "2.0.4",
|
||||
"fs-extra": "^7.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/static-build",
|
||||
"version": "1.0.33",
|
||||
"version": "1.0.36",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/build-step",
|
||||
@@ -36,11 +36,11 @@
|
||||
"@types/ms": "0.7.31",
|
||||
"@types/node-fetch": "2.5.4",
|
||||
"@types/promise-timeout": "1.3.0",
|
||||
"@vercel/build-utils": "5.5.6",
|
||||
"@vercel/frameworks": "1.1.9",
|
||||
"@vercel/build-utils": "5.5.7",
|
||||
"@vercel/frameworks": "1.1.12",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/routing-utils": "2.1.0",
|
||||
"@vercel/static-config": "2.0.4",
|
||||
"@vercel/routing-utils": "2.1.3",
|
||||
"@vercel/static-config": "2.0.6",
|
||||
"fs-extra": "10.0.0",
|
||||
"get-port": "5.0.0",
|
||||
"is-port-reachable": "2.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/static-config",
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.6",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"repository": {
|
||||
@@ -24,7 +24,7 @@
|
||||
"devDependencies": {
|
||||
"@swc/core": "1.2.182",
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/node": "*"
|
||||
"@types/node": "14.18.33"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "ts-jest",
|
||||
|
||||
28
yarn.lock
28
yarn.lock
@@ -3033,30 +3033,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
|
||||
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
|
||||
|
||||
"@types/node@11.11.0":
|
||||
version "11.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.0.tgz#070e9ce7c90e727aca0e0c14e470f9a93ffe9390"
|
||||
integrity sha512-D5Rt+HXgEywr3RQJcGlZUCTCx1qVbCZpVk3/tOOA6spLNZdGm8BU+zRgdRYDoF1pO3RuXLxADzMrF903JlQXqg==
|
||||
|
||||
"@types/node@12.0.4":
|
||||
version "12.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.4.tgz#46832183115c904410c275e34cf9403992999c32"
|
||||
integrity sha512-j8YL2C0fXq7IONwl/Ud5Kt0PeXw22zGERt+HSSnwbKOJVsAGkEz3sFCYwaF9IOuoG1HOtE0vKCj6sXF7Q0+Vaw==
|
||||
|
||||
"@types/node@12.12.20":
|
||||
version "12.12.20"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.20.tgz#7b693038ce661fe57a7ffa4679440b5e7c5e8b99"
|
||||
integrity sha512-VAe+DiwpnC/g448uN+/3gRl4th0BTdrR9gSLIOHA+SUQskaYZQDOHG7xmjiE7JUhjbXnbXytf6Ih+/pA6CtMFQ==
|
||||
|
||||
"@types/node@14.17.27":
|
||||
version "14.17.27"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.27.tgz#5054610d37bb5f6e21342d0e6d24c494231f3b85"
|
||||
integrity sha512-94+Ahf9IcaDuJTle/2b+wzvjmutxXAEXU6O81JHblYXUg2BDG+dnBy7VxIPHKAyEEDHzCMQydTJuWvrE+Aanzw==
|
||||
|
||||
"@types/node@16.11.7":
|
||||
version "16.11.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42"
|
||||
integrity sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==
|
||||
"@types/node@14.18.33":
|
||||
version "14.18.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.33.tgz#8c29a0036771569662e4635790ffa9e057db379b"
|
||||
integrity sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==
|
||||
|
||||
"@types/normalize-package-data@^2.4.0":
|
||||
version "2.4.0"
|
||||
|
||||
Reference in New Issue
Block a user