mirror of
https://github.com/LukeHagar/vercel.git
synced 2026-01-01 20:29:12 +00:00
Compare commits
11 Commits
@vercel/ro
...
@vercel/ro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c80bb37e8d | ||
|
|
a7acd92ffd | ||
|
|
035720ca82 | ||
|
|
a6ae923a7a | ||
|
|
83c0711d6e | ||
|
|
231f18d56b | ||
|
|
9d73091d8c | ||
|
|
0ca3189f79 | ||
|
|
9ff5bb9cb3 | ||
|
|
45d05a603b | ||
|
|
6ef3b12fde |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/frameworks",
|
||||
"version": "0.0.15-canary.3",
|
||||
"version": "0.0.15-canary.4",
|
||||
"main": "frameworks.json",
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
@@ -12,6 +12,6 @@
|
||||
"ajv": "6.10.2",
|
||||
"jest": "24.9.0",
|
||||
"ts-jest": "24.1.0",
|
||||
"typescript": "3.5.2"
|
||||
"typescript": "3.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "2.3.2-canary.2",
|
||||
"version": "2.3.2-canary.3",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
@@ -45,7 +45,7 @@
|
||||
"node-fetch": "2.2.0",
|
||||
"semver": "6.1.1",
|
||||
"ts-jest": "24.1.0",
|
||||
"typescript": "3.5.2",
|
||||
"typescript": "3.9.3",
|
||||
"yazl": "2.4.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,6 +531,7 @@ describe('Test `detectBuilders`', () => {
|
||||
const files = ['api/user.php'];
|
||||
// @ts-ignore
|
||||
const { errors } = await detectBuilders(files, null, {
|
||||
// @ts-ignore
|
||||
functions,
|
||||
});
|
||||
|
||||
@@ -1530,6 +1531,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
|
||||
const files = ['api/user.php'];
|
||||
// @ts-ignore
|
||||
const { errors } = await detectBuilders(files, null, {
|
||||
// @ts-ignore
|
||||
functions,
|
||||
featHandleMiss,
|
||||
});
|
||||
@@ -1630,6 +1632,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
|
||||
|
||||
// @ts-ignore
|
||||
const { errors } = await detectBuilders(files, null, {
|
||||
// @ts-ignore
|
||||
functions,
|
||||
featHandleMiss,
|
||||
});
|
||||
@@ -1646,6 +1649,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
|
||||
|
||||
// @ts-ignore: Since we test an invalid type
|
||||
const { errors } = await detectBuilders(files, null, {
|
||||
// @ts-ignore
|
||||
functions,
|
||||
featHandleMiss,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "19.0.2-canary.9",
|
||||
"version": "19.0.2-canary.11",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Now",
|
||||
@@ -62,13 +62,13 @@
|
||||
"node": ">= 10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.3.2-canary.2",
|
||||
"@vercel/go": "1.1.2-canary.0",
|
||||
"@vercel/next": "2.6.3-canary.4",
|
||||
"@vercel/node": "1.6.2-canary.4",
|
||||
"@vercel/python": "1.2.2-canary.1",
|
||||
"@vercel/ruby": "1.2.2-canary.0",
|
||||
"@vercel/static-build": "0.17.2-canary.0"
|
||||
"@vercel/build-utils": "2.3.2-canary.3",
|
||||
"@vercel/go": "1.1.2-canary.1",
|
||||
"@vercel/next": "2.6.3-canary.5",
|
||||
"@vercel/node": "1.6.2-canary.5",
|
||||
"@vercel/python": "1.2.2-canary.2",
|
||||
"@vercel/ruby": "1.2.2-canary.1",
|
||||
"@vercel/static-build": "0.17.2-canary.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sentry/node": "5.5.0",
|
||||
@@ -182,7 +182,7 @@
|
||||
"tmp-promise": "1.0.3",
|
||||
"tree-kill": "1.2.1",
|
||||
"ts-node": "8.3.0",
|
||||
"typescript": "3.6.4",
|
||||
"typescript": "3.9.3",
|
||||
"universal-analytics": "0.4.20",
|
||||
"update-check": "1.5.3",
|
||||
"utility-types": "2.1.0",
|
||||
|
||||
@@ -75,6 +75,17 @@ async function main() {
|
||||
const dest = join(dirRoot, 'dist/runtimes');
|
||||
await cpy('**/*', dest, { parents: true, cwd: runtimes });
|
||||
|
||||
// Band-aid to delete stuff that `ncc` bundles, but it shouldn't:
|
||||
|
||||
// TypeScript definition files from `@vercel/build-utils`
|
||||
await remove(join(dirRoot, 'dist', 'dist'));
|
||||
|
||||
// The Readme and `package.json` from "config-chain" module
|
||||
await remove(join(dirRoot, 'dist', 'config-chain'));
|
||||
|
||||
// A bunch of source `.ts` files from CLI's `util` directory
|
||||
await remove(join(dirRoot, 'dist', 'util'));
|
||||
|
||||
console.log('Finished building `now-cli`');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import path from 'path';
|
||||
import mri from 'mri';
|
||||
import { InvalidLocalConfig } from '../errors';
|
||||
import { ConflictingConfigFiles } from '../errors-ts';
|
||||
import { existsSync } from 'fs';
|
||||
|
||||
export default function getLocalPathConfig(prefix: string) {
|
||||
@@ -11,20 +12,30 @@ export default function getLocalPathConfig(prefix: string) {
|
||||
},
|
||||
});
|
||||
|
||||
// If `--local-config` flag was specified, then that takes priority
|
||||
const customPath = args['local-config'];
|
||||
|
||||
if (customPath && typeof customPath !== 'string') {
|
||||
throw new InvalidLocalConfig(customPath);
|
||||
if (customPath) {
|
||||
if (typeof customPath !== 'string') {
|
||||
throw new InvalidLocalConfig(customPath);
|
||||
}
|
||||
return path.resolve(prefix, customPath);
|
||||
}
|
||||
|
||||
const possibleConfigFiles = [
|
||||
path.join(prefix, 'vercel.json'),
|
||||
path.join(prefix, 'now.json'),
|
||||
];
|
||||
// Otherwise check for either `vercel.json` or `now.json`.
|
||||
// Throw an error if both exist.
|
||||
const vercelConfigPath = path.join(prefix, 'vercel.json');
|
||||
const nowConfigPath = path.join(prefix, 'now.json');
|
||||
|
||||
return (
|
||||
(customPath && path.resolve(prefix, customPath)) ||
|
||||
possibleConfigFiles.find(configFile => existsSync(configFile)) ||
|
||||
possibleConfigFiles[0]
|
||||
);
|
||||
const vercelConfigExists = existsSync(vercelConfigPath);
|
||||
const nowConfigExists = existsSync(nowConfigPath);
|
||||
|
||||
if (nowConfigExists && vercelConfigExists) {
|
||||
throw new ConflictingConfigFiles([vercelConfigPath, nowConfigPath]);
|
||||
}
|
||||
|
||||
if (nowConfigExists) {
|
||||
return nowConfigPath;
|
||||
}
|
||||
|
||||
return vercelConfigPath;
|
||||
}
|
||||
|
||||
@@ -1603,7 +1603,6 @@ export default class DevServer {
|
||||
debug(`Skipping \`startDevServer()\` for ${match.entrypoint}`);
|
||||
}
|
||||
}
|
||||
|
||||
let foundAsset = findAsset(match, requestPath, nowConfig);
|
||||
|
||||
if (!foundAsset && callLevel === 0) {
|
||||
@@ -2014,12 +2013,24 @@ async function findBuildMatch(
|
||||
isFilesystem?: boolean
|
||||
): Promise<BuildMatch | null> {
|
||||
requestPath = requestPath.replace(/^\//, '');
|
||||
|
||||
let bestIndexMatch: undefined | BuildMatch;
|
||||
for (const match of matches.values()) {
|
||||
if (await shouldServe(match, files, requestPath, devServer, isFilesystem)) {
|
||||
return match;
|
||||
if (!isIndex(match.src)) {
|
||||
return match;
|
||||
} else {
|
||||
// if isIndex === true and ends in .html, we're done. Otherwise, keep searching
|
||||
bestIndexMatch = match;
|
||||
if (extname(match.src) === '.html') {
|
||||
return bestIndexMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
// return a non-.html index file or none are found
|
||||
return bestIndexMatch || null;
|
||||
}
|
||||
|
||||
async function shouldServe(
|
||||
|
||||
@@ -771,6 +771,20 @@ export class CantParseJSONFile extends NowError<
|
||||
}
|
||||
}
|
||||
|
||||
export class ConflictingConfigFiles extends NowError<
|
||||
'CONFLICTING_CONFIG_FILES',
|
||||
{ files: string[] }
|
||||
> {
|
||||
constructor(files: string[]) {
|
||||
super({
|
||||
code: 'CONFLICTING_CONFIG_FILES',
|
||||
meta: { files },
|
||||
message:
|
||||
'Cannot use both a `vercel.json` and `now.json` file. Please delete the `now.json` file.',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class CantFindConfig extends NowError<
|
||||
'CANT_FIND_CONFIG',
|
||||
{ paths: string[] }
|
||||
|
||||
@@ -3,6 +3,7 @@ import { fileNameSymbol } from '@vercel/client';
|
||||
import {
|
||||
CantParseJSONFile,
|
||||
CantFindConfig,
|
||||
ConflictingConfigFiles,
|
||||
WorkingDirectoryDoesNotExist,
|
||||
} from './errors-ts';
|
||||
import humanizePath from './humanize-path';
|
||||
@@ -49,28 +50,31 @@ export default async function getConfig(
|
||||
}
|
||||
}
|
||||
|
||||
// Then try with vercel.json in the same directory
|
||||
// Then try with `vercel.json` or `now.json` in the same directory
|
||||
const vercelFilePath = path.resolve(localPath, 'vercel.json');
|
||||
const vercelConfig = await readJSONFile(vercelFilePath);
|
||||
const nowFilePath = path.resolve(localPath, 'now.json');
|
||||
const [vercelConfig, nowConfig] = await Promise.all([
|
||||
readJSONFile(vercelFilePath),
|
||||
readJSONFile(nowFilePath),
|
||||
]);
|
||||
if (vercelConfig instanceof CantParseJSONFile) {
|
||||
return vercelConfig;
|
||||
}
|
||||
if (nowConfig instanceof CantParseJSONFile) {
|
||||
return nowConfig;
|
||||
}
|
||||
if (vercelConfig && nowConfig) {
|
||||
return new ConflictingConfigFiles([vercelFilePath, nowFilePath]);
|
||||
}
|
||||
if (vercelConfig !== null) {
|
||||
output.debug(`Found config in file ${vercelFilePath}`);
|
||||
output.debug(`Found config in file "${vercelFilePath}"`);
|
||||
config = vercelConfig as NowConfig;
|
||||
config[fileNameSymbol] = 'vercel.json';
|
||||
return config;
|
||||
}
|
||||
|
||||
// Then try with now.json in the same directory
|
||||
const nowFilePath = path.resolve(localPath, 'now.json');
|
||||
const mainConfig = await readJSONFile(nowFilePath);
|
||||
if (mainConfig instanceof CantParseJSONFile) {
|
||||
return mainConfig;
|
||||
}
|
||||
if (mainConfig !== null) {
|
||||
output.debug(`Found config in file ${nowFilePath}`);
|
||||
config = mainConfig as NowConfig;
|
||||
if (nowConfig !== null) {
|
||||
output.debug(`Found config in file "${nowFilePath}"`);
|
||||
config = nowConfig as NowConfig;
|
||||
config[fileNameSymbol] = 'now.json';
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -42,10 +42,18 @@ const linkSchema = {
|
||||
/**
|
||||
* Returns the `<cwd>/.vercel` directory for the current project
|
||||
* with a fallback to <cwd>/.now` if it exists.
|
||||
*
|
||||
* Throws an error if *both* `.vercel` and `.now` directories exist.
|
||||
*/
|
||||
export function getVercelDirectory(cwd: string = process.cwd()) {
|
||||
export function getVercelDirectory(cwd: string = process.cwd()): string {
|
||||
const possibleDirs = [join(cwd, VERCEL_DIR), join(cwd, VERCEL_DIR_FALLBACK)];
|
||||
return possibleDirs.find(d => isDirectory(d)) || possibleDirs[0];
|
||||
const existingDirs = possibleDirs.filter(d => isDirectory(d));
|
||||
if (existingDirs.length > 1) {
|
||||
throw new Error(
|
||||
'Both `.vercel` and `.now` directories exist. Please remove the `.now` directory.'
|
||||
);
|
||||
}
|
||||
return existingDirs[0] || possibleDirs[0];
|
||||
}
|
||||
|
||||
async function getLink(path?: string): Promise<ProjectLink | null> {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
This is index.css
|
||||
@@ -0,0 +1,2 @@
|
||||
This is index.html
|
||||
|
||||
1
packages/now-cli/test/dev/fixtures/nested-tsconfig/.gitignore
vendored
Normal file
1
packages/now-cli/test/dev/fixtures/nested-tsconfig/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.vercel
|
||||
@@ -0,0 +1,5 @@
|
||||
import { IncomingMessage, ServerResponse } from 'http';
|
||||
|
||||
export default function(req: IncomingMessage, res: ServerResponse) {
|
||||
res.end('Nested `tsconfig.json` API endpoint');
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "api",
|
||||
"devDependencies": {
|
||||
"@types/node": "12"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2015",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"strict": true,
|
||||
"module": "CommonJS",
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["**/*.ts"]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/node@12":
|
||||
version "12.12.43"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.43.tgz#b60ce047822e526e7a9252e50844eee79d5386ff"
|
||||
integrity sha512-KUyZdkGCnVPuXfsKmDUu2XLui65LZIJ2s0M57noy5e+ixUT2oK33ep7zlvgzI8LElcWqbf8AR+o/3GqAPac2zA==
|
||||
2
packages/now-cli/test/dev/fixtures/nested-tsconfig/next-env.d.ts
vendored
Normal file
2
packages/now-cli/test/dev/fixtures/nested-tsconfig/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "nested-tsconfig",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "^9.3.4",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "14.0.9",
|
||||
"@types/react": "^16.9.32",
|
||||
"typescript": "^3.8.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export default function () {
|
||||
return <div>Nested tsconfig.json test page</div>;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"target": "esnext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"paths": {
|
||||
"@components/*": ["components/*"],
|
||||
"@lib/*": ["lib/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "api"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
5633
packages/now-cli/test/dev/fixtures/nested-tsconfig/yarn.lock
Normal file
5633
packages/now-cli/test/dev/fixtures/nested-tsconfig/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1347,3 +1347,20 @@ test(
|
||||
await testPath(200, `/api/user.sh`, /Hello, from Bash!/m);
|
||||
})
|
||||
);
|
||||
|
||||
test(
|
||||
'[vercel dev] Should work with nested `tsconfig.json` files',
|
||||
testFixtureStdio('nested-tsconfig', async testPath => {
|
||||
await testPath(200, `/`, /Nested tsconfig.json test page/);
|
||||
await testPath(200, `/api`, 'Nested `tsconfig.json` API endpoint');
|
||||
})
|
||||
);
|
||||
|
||||
test(
|
||||
'[vercel dev] should prioritize index.html over other file named index.*',
|
||||
testFixtureStdio('index-html-priority', async testPath => {
|
||||
await testPath(200, '/', 'This is index.html');
|
||||
await testPath(200, '/index.css', 'This is index.css');
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
2
packages/now-cli/test/fixtures/unit/get-vercel-directory-error/.gitignore
vendored
Normal file
2
packages/now-cli/test/fixtures/unit/get-vercel-directory-error/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
!.vercel
|
||||
!.now
|
||||
0
packages/now-cli/test/fixtures/unit/get-vercel-directory-error/.now/.gitkeep
vendored
Normal file
0
packages/now-cli/test/fixtures/unit/get-vercel-directory-error/.now/.gitkeep
vendored
Normal file
0
packages/now-cli/test/fixtures/unit/get-vercel-directory-error/.vercel/.gitkeep
vendored
Normal file
0
packages/now-cli/test/fixtures/unit/get-vercel-directory-error/.vercel/.gitkeep
vendored
Normal file
1
packages/now-cli/test/fixtures/unit/get-vercel-directory-legacy/.gitignore
vendored
Normal file
1
packages/now-cli/test/fixtures/unit/get-vercel-directory-legacy/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!.now
|
||||
0
packages/now-cli/test/fixtures/unit/get-vercel-directory-legacy/.now/.gitkeep
vendored
Normal file
0
packages/now-cli/test/fixtures/unit/get-vercel-directory-legacy/.now/.gitkeep
vendored
Normal file
1
packages/now-cli/test/fixtures/unit/get-vercel-directory/.gitignore
vendored
Normal file
1
packages/now-cli/test/fixtures/unit/get-vercel-directory/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!.vercel
|
||||
0
packages/now-cli/test/fixtures/unit/get-vercel-directory/.vercel/.gitkeep
vendored
Normal file
0
packages/now-cli/test/fixtures/unit/get-vercel-directory/.vercel/.gitkeep
vendored
Normal file
@@ -514,6 +514,11 @@ CMD ["node", "index.js"]`,
|
||||
],
|
||||
}),
|
||||
},
|
||||
'conflicting-now-json-vercel-json': {
|
||||
'index.html': '<h1>I am a website.</h1>',
|
||||
'vercel.json': getConfigFile(true),
|
||||
'now.json': getConfigFile(true),
|
||||
},
|
||||
};
|
||||
|
||||
for (const typeName of Object.keys(spec)) {
|
||||
|
||||
21
packages/now-cli/test/integration.js
vendored
21
packages/now-cli/test/integration.js
vendored
@@ -2895,3 +2895,24 @@ test('deploys with only vercel.json and README.md', async t => {
|
||||
const text = await res.text();
|
||||
t.regex(text, /readme contents/);
|
||||
});
|
||||
|
||||
test('reject conflicting `vercel.json` and `now.json` files', async t => {
|
||||
const directory = fixture('conflicting-now-json-vercel-json');
|
||||
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
[...defaultArgs, '--confirm'],
|
||||
{
|
||||
cwd: directory,
|
||||
reject: false,
|
||||
}
|
||||
);
|
||||
|
||||
t.is(exitCode, 1, formatOutput({ stderr, stdout }));
|
||||
t.true(
|
||||
stderr.includes(
|
||||
'Cannot use both a `vercel.json` and `now.json` file. Please delete the `now.json` file.'
|
||||
),
|
||||
formatOutput({ stderr, stdout })
|
||||
);
|
||||
});
|
||||
|
||||
29
packages/now-cli/test/unit.js
vendored
29
packages/now-cli/test/unit.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { join, sep } from 'path';
|
||||
import { basename, join, sep } from 'path';
|
||||
import { send } from 'micro';
|
||||
import test from 'ava';
|
||||
import sinon from 'sinon';
|
||||
@@ -24,6 +24,7 @@ import { isValidName } from '../src/util/is-valid-name';
|
||||
import preferV2Deployment from '../src/util/prefer-v2-deployment';
|
||||
import getUpdateCommand from '../src/util/get-update-command';
|
||||
import { isCanary } from '../src/util/is-canary';
|
||||
import { getVercelDirectory } from '../src/util/projects/link';
|
||||
|
||||
const output = createOutput({ debug: false });
|
||||
const prefix = `${join(__dirname, 'fixtures', 'unit')}${sep}`;
|
||||
@@ -1091,3 +1092,29 @@ test('detect update command', async t => {
|
||||
const updateCommand = await getUpdateCommand();
|
||||
t.is(updateCommand, `yarn add vercel@${isCanary() ? 'canary' : 'latest'}`);
|
||||
});
|
||||
|
||||
test('`getVercelDirectory()` returns ".vercel"', t => {
|
||||
const cwd = fixture('get-vercel-directory');
|
||||
const dir = getVercelDirectory(cwd);
|
||||
t.is(basename(dir), '.vercel');
|
||||
});
|
||||
|
||||
test('`getVercelDirectory()` returns ".now"', t => {
|
||||
const cwd = fixture('get-vercel-directory-legacy');
|
||||
const dir = getVercelDirectory(cwd);
|
||||
t.is(basename(dir), '.now');
|
||||
});
|
||||
|
||||
test('`getVercelDirectory()` throws an error if ".vercel" and ".now" exist', t => {
|
||||
let err;
|
||||
const cwd = fixture('get-vercel-directory-error');
|
||||
try {
|
||||
getVercelDirectory(cwd);
|
||||
} catch (_err) {
|
||||
err = _err;
|
||||
}
|
||||
t.is(
|
||||
err.message,
|
||||
'Both `.vercel` and `.now` directories exist. Please remove the `.now` directory.'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "8.0.2-canary.1",
|
||||
"version": "8.0.2-canary.2",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -27,7 +27,7 @@
|
||||
"@types/node-fetch": "2.5.4",
|
||||
"@types/recursive-readdir": "2.2.0",
|
||||
"@zeit/ncc": "0.18.5",
|
||||
"typescript": "3.5.1"
|
||||
"typescript": "3.9.3"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "ts-jest",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { readdir as readRootFolder, lstatSync } from 'fs-extra';
|
||||
import { relative, isAbsolute, basename } from 'path';
|
||||
import hashes, { mapToObject } from './utils/hashes';
|
||||
import { upload } from './upload';
|
||||
import { buildFileTree, createDebug, parseNowJSON } from './utils';
|
||||
import { buildFileTree, createDebug, parseVercelConfig } from './utils';
|
||||
import { DeploymentError } from './errors';
|
||||
import {
|
||||
NowConfig,
|
||||
@@ -85,10 +85,24 @@ export default function buildCreateDeployment(version: number) {
|
||||
let configPath: string | undefined;
|
||||
if (!nowConfig) {
|
||||
// If the user did not provide a config file, use the one in the root directory.
|
||||
configPath = fileList
|
||||
.map(f => relative(cwd, f))
|
||||
.find(f => f === 'vercel.json' || f === 'now.json');
|
||||
nowConfig = await parseNowJSON(configPath);
|
||||
const relativePaths = fileList.map(f => relative(cwd, f));
|
||||
const hasVercelConfig = relativePaths.includes('vercel.json');
|
||||
const hasNowConfig = relativePaths.includes('now.json');
|
||||
|
||||
if (hasVercelConfig) {
|
||||
if (hasNowConfig) {
|
||||
throw new DeploymentError({
|
||||
code: 'conflicting_config',
|
||||
message:
|
||||
'Cannot use both a `vercel.json` and `now.json` file. Please delete the `now.json` file.',
|
||||
});
|
||||
}
|
||||
configPath = 'vercel.json';
|
||||
} else if (hasNowConfig) {
|
||||
configPath = 'now.json';
|
||||
}
|
||||
|
||||
nowConfig = await parseVercelConfig(configPath);
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
@@ -51,7 +51,7 @@ export function getApiDeploymentsUrl(
|
||||
return '/v12/now/deployments';
|
||||
}
|
||||
|
||||
export async function parseNowJSON(filePath?: string): Promise<NowConfig> {
|
||||
export async function parseVercelConfig(filePath?: string): Promise<NowConfig> {
|
||||
if (!filePath) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/go",
|
||||
"version": "1.1.2-canary.0",
|
||||
"version": "1.1.2-canary.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||
@@ -28,6 +28,6 @@
|
||||
"node-fetch": "^2.2.1",
|
||||
"string-argv": "0.3.1",
|
||||
"tar": "4.4.6",
|
||||
"typescript": "3.5.2"
|
||||
"typescript": "3.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/next",
|
||||
"version": "2.6.3-canary.4",
|
||||
"version": "2.6.3-canary.5",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||
@@ -34,7 +34,7 @@
|
||||
"get-port": "5.0.0",
|
||||
"resolve-from": "5.0.0",
|
||||
"semver": "6.1.1",
|
||||
"typescript": "3.5.2",
|
||||
"typescript": "3.9.3",
|
||||
"yazl": "https://github.com/ijjk/yazl#70949c55b482647669ce37023017b1514c42b33c"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/node-bridge",
|
||||
"version": "1.3.1-canary.1",
|
||||
"version": "1.3.1-canary.2",
|
||||
"license": "MIT",
|
||||
"main": "./index.js",
|
||||
"repository": {
|
||||
@@ -20,6 +20,6 @@
|
||||
"devDependencies": {
|
||||
"@types/aws-lambda": "8.10.19",
|
||||
"@types/node": "10.x",
|
||||
"typescript": "3.5.2"
|
||||
"typescript": "3.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/node",
|
||||
"version": "1.6.2-canary.4",
|
||||
"version": "1.6.2-canary.5",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
||||
@@ -21,7 +21,7 @@
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"ts-node": "8.9.1",
|
||||
"typescript": "3.8.3"
|
||||
"typescript": "3.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.5.0",
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
const entrypoint = process.env.NOW_DEV_ENTRYPOINT;
|
||||
delete process.env.NOW_DEV_ENTRYPOINT;
|
||||
|
||||
const tsconfig = process.env.NOW_DEV_TSCONFIG;
|
||||
delete process.env.NOW_DEV_TSCONFIG;
|
||||
|
||||
if (!entrypoint) {
|
||||
throw new Error('`NOW_DEV_ENTRYPOINT` must be defined');
|
||||
}
|
||||
|
||||
import { register } from 'ts-node';
|
||||
|
||||
// Use the project's version of TypeScript if available,
|
||||
@@ -18,6 +28,7 @@ register({
|
||||
esModuleInterop: true,
|
||||
jsx: 'react',
|
||||
},
|
||||
project: tsconfig || undefined, // Resolve `tsconfig.json` from entrypoint dir
|
||||
transpileOnly: true,
|
||||
});
|
||||
|
||||
@@ -38,13 +49,6 @@ function listen(server: Server, port: number, host: string): Promise<void> {
|
||||
let bridge: Bridge | undefined = undefined;
|
||||
|
||||
async function main() {
|
||||
const entrypoint = process.env.NOW_DEV_ENTRYPOINT;
|
||||
delete process.env.NOW_DEV_ENTRYPOINT;
|
||||
|
||||
if (!entrypoint) {
|
||||
throw new Error('`NOW_DEV_ENTRYPOINT` must be defined');
|
||||
}
|
||||
|
||||
const config = JSON.parse(process.env.NOW_DEV_CONFIG || '{}');
|
||||
delete process.env.NOW_DEV_CONFIG;
|
||||
|
||||
@@ -53,7 +57,7 @@ async function main() {
|
||||
);
|
||||
|
||||
bridge = getNowLauncher({
|
||||
entrypointPath: join(process.cwd(), entrypoint),
|
||||
entrypointPath: join(process.cwd(), entrypoint!),
|
||||
helpersPath: './helpers',
|
||||
shouldAddHelpers,
|
||||
bridgePath: 'not used',
|
||||
|
||||
@@ -430,6 +430,14 @@ export async function startDevServer(
|
||||
opts: StartDevServerOptions
|
||||
): Promise<StartDevServerResult> {
|
||||
const { entrypoint, workPath, config, meta = {} } = opts;
|
||||
|
||||
// Find the `tsconfig.json` file closest to the entrypoint file
|
||||
const projectTsConfig = await walkParentDirs({
|
||||
base: workPath,
|
||||
start: join(workPath, dirname(entrypoint)),
|
||||
filename: 'tsconfig.json',
|
||||
});
|
||||
|
||||
const devServerPath = join(__dirname, 'dev-server.js');
|
||||
const child = fork(devServerPath, [], {
|
||||
cwd: workPath,
|
||||
@@ -438,6 +446,7 @@ export async function startDevServer(
|
||||
...process.env,
|
||||
...meta.env,
|
||||
NOW_DEV_ENTRYPOINT: entrypoint,
|
||||
NOW_DEV_TSCONFIG: projectTsConfig || '',
|
||||
NOW_DEV_CONFIG: JSON.stringify(config),
|
||||
},
|
||||
});
|
||||
@@ -456,7 +465,7 @@ export async function startDevServer(
|
||||
if (ext === '.ts' || ext === '.tsx') {
|
||||
// Invoke `tsc --noEmit` asynchronously in the background, so
|
||||
// that the HTTP request is not blocked by the type checking.
|
||||
doTypeCheck(opts).catch((err: Error) => {
|
||||
doTypeCheck(opts, projectTsConfig).catch((err: Error) => {
|
||||
console.error('Type check for %j failed:', entrypoint, err);
|
||||
});
|
||||
}
|
||||
@@ -470,23 +479,17 @@ export async function startDevServer(
|
||||
}
|
||||
}
|
||||
|
||||
async function doTypeCheck({
|
||||
entrypoint,
|
||||
workPath,
|
||||
meta = {},
|
||||
}: StartDevServerOptions): Promise<void> {
|
||||
async function doTypeCheck(
|
||||
{ entrypoint, workPath, meta = {} }: StartDevServerOptions,
|
||||
projectTsConfig: string | null
|
||||
): Promise<void> {
|
||||
const { devCacheDir = join(workPath, '.now', 'cache') } = meta;
|
||||
const entrypointCacheDir = join(devCacheDir, 'node', entrypoint);
|
||||
|
||||
// In order to type-check a single file, a standalone tsconfig
|
||||
// file needs to be created that inherits from the base one :(
|
||||
// See: https://stackoverflow.com/a/44748041/376773
|
||||
const projectTsConfig = await walkParentDirs({
|
||||
base: workPath,
|
||||
start: join(workPath, dirname(entrypoint)),
|
||||
filename: 'tsconfig.json',
|
||||
});
|
||||
|
||||
//
|
||||
// A different filename needs to be used for different `extends` tsconfig.json
|
||||
const tsconfigName = projectTsConfig
|
||||
? `tsconfig-with-${relative(workPath, projectTsConfig).replace(
|
||||
|
||||
@@ -138,7 +138,7 @@ export function getAwsLauncher({
|
||||
const { query } = parse(path, true);
|
||||
const queryStringParameters: { [i: string]: string } = {};
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (!Array.isArray(value)) {
|
||||
if (typeof value === 'string') {
|
||||
queryStringParameters[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/python",
|
||||
"version": "1.2.2-canary.1",
|
||||
"version": "1.2.2-canary.2",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
||||
@@ -21,6 +21,6 @@
|
||||
"devDependencies": {
|
||||
"@types/execa": "^0.9.0",
|
||||
"execa": "^1.0.0",
|
||||
"typescript": "3.5.2"
|
||||
"typescript": "3.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/routing-utils",
|
||||
"version": "1.8.3-canary.2",
|
||||
"version": "1.8.3-canary.5",
|
||||
"description": "Vercel routing utilities",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -25,7 +25,7 @@
|
||||
"devDependencies": {
|
||||
"@types/node": "12.12.20",
|
||||
"ajv": "^6.0.0",
|
||||
"typescript": "3.5.2"
|
||||
"typescript": "3.9.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"ajv": "^6.0.0"
|
||||
|
||||
@@ -223,23 +223,18 @@ function checkRedirect(r: NowRedirect, index: number) {
|
||||
|
||||
function createError(
|
||||
code: string,
|
||||
errors: string | string[],
|
||||
allErrors: string | string[],
|
||||
link: string,
|
||||
action: string
|
||||
): RouteApiError | null {
|
||||
let message: string;
|
||||
let otherErrors: string[] = [];
|
||||
if (Array.isArray(errors)) {
|
||||
[message, ...otherErrors] = errors;
|
||||
} else {
|
||||
message = errors;
|
||||
}
|
||||
const errors = Array.isArray(allErrors) ? allErrors : [allErrors];
|
||||
const message = errors[0];
|
||||
const error: RouteApiError = {
|
||||
code,
|
||||
message,
|
||||
link,
|
||||
action,
|
||||
otherErrors,
|
||||
errors,
|
||||
};
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ export function convertHeaders(headers: NowHeader[]): Route[] {
|
||||
return headers.map(h => {
|
||||
const obj: { [key: string]: string } = {};
|
||||
const { src, segments } = sourceToRegex(h.source);
|
||||
const hasSegments = segments.length > 0;
|
||||
const namedSegments = segments.filter(name => name !== UN_NAMED_SEGMENT);
|
||||
const indexes: { [k: string]: string } = {};
|
||||
|
||||
segments.forEach((name, index) => {
|
||||
@@ -97,7 +97,7 @@ export function convertHeaders(headers: NowHeader[]): Route[] {
|
||||
});
|
||||
|
||||
h.headers.forEach(({ key, value }) => {
|
||||
if (hasSegments) {
|
||||
if (namedSegments.length > 0) {
|
||||
if (key.includes(':')) {
|
||||
key = safelyCompile(key, indexes);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ export type RouteApiError = {
|
||||
message: string;
|
||||
link?: string; // link to error message details
|
||||
action?: string; // label for error link
|
||||
otherErrors?: string[];
|
||||
errors?: string[]; // array of all error messages
|
||||
};
|
||||
|
||||
export type Source = {
|
||||
|
||||
61
packages/now-routing-utils/test/index.spec.js
vendored
61
packages/now-routing-utils/test/index.spec.js
vendored
@@ -915,4 +915,65 @@ describe('getTransformedRoutes', () => {
|
||||
actual.error.message
|
||||
);
|
||||
});
|
||||
|
||||
test('should work with content-security-policy header containing URL', () => {
|
||||
const nowConfig = {
|
||||
headers: [
|
||||
{
|
||||
source: '/(.*)',
|
||||
headers: [
|
||||
{
|
||||
key: 'content-security-policy',
|
||||
value:
|
||||
"default-src 'self'; script-src 'self'; img-src 'self' https://*.example.com; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.examplpe.com wss://gateway.example.com; form-action 'self'",
|
||||
},
|
||||
{
|
||||
key: 'feature-policy',
|
||||
value:
|
||||
"accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'",
|
||||
},
|
||||
{
|
||||
key: 'referrer-policy',
|
||||
value: 'strict-origin-when-cross-origin',
|
||||
},
|
||||
{
|
||||
key: 'strict-transport-security',
|
||||
value: 'max-age=31536000; includesubdomains; preload',
|
||||
},
|
||||
{
|
||||
key: 'x-content-type-options',
|
||||
value: 'nosniff',
|
||||
},
|
||||
{
|
||||
key: 'x-frame-options',
|
||||
value: 'sameorigin',
|
||||
},
|
||||
{
|
||||
key: 'x-xss-protection',
|
||||
value: '1; mode=block',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const actual = getTransformedRoutes({ nowConfig });
|
||||
assert.deepEqual(actual.routes, [
|
||||
{
|
||||
continue: true,
|
||||
headers: {
|
||||
'content-security-policy':
|
||||
"default-src 'self'; script-src 'self'; img-src 'self' https://*.example.com; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.examplpe.com wss://gateway.example.com; form-action 'self'",
|
||||
'feature-policy':
|
||||
"accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'",
|
||||
'referrer-policy': 'strict-origin-when-cross-origin',
|
||||
'strict-transport-security':
|
||||
'max-age=31536000; includesubdomains; preload',
|
||||
'x-content-type-options': 'nosniff',
|
||||
'x-frame-options': 'sameorigin',
|
||||
'x-xss-protection': '1; mode=block',
|
||||
},
|
||||
src: '^(?:/(.*))$',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@vercel/ruby",
|
||||
"author": "Nathan Cahill <nathan@nathancahill.com>",
|
||||
"version": "1.2.2-canary.0",
|
||||
"version": "1.2.2-canary.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
|
||||
@@ -25,6 +25,6 @@
|
||||
"execa": "2.0.4",
|
||||
"fs-extra": "^7.0.1",
|
||||
"semver": "6.1.1",
|
||||
"typescript": "3.5.2"
|
||||
"typescript": "3.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/static-build",
|
||||
"version": "0.17.2-canary.0",
|
||||
"version": "0.17.2-canary.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/static-builds",
|
||||
@@ -27,6 +27,6 @@
|
||||
"is-port-reachable": "2.0.1",
|
||||
"ms": "2.1.2",
|
||||
"node-fetch": "2.6.0",
|
||||
"typescript": "3.5.2"
|
||||
"typescript": "3.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user