mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-24 03:39:11 +00:00
Compare commits
43 Commits
@now/node@
...
@now/node@
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdd25ac727 | ||
|
|
3a27328828 | ||
|
|
c076a5620f | ||
|
|
2bd8ef9eed | ||
|
|
500014f2fc | ||
|
|
17687e9bcd | ||
|
|
90354e9fe7 | ||
|
|
6236631beb | ||
|
|
75aefdddd6 | ||
|
|
566d82e873 | ||
|
|
44ae0b654e | ||
|
|
d8cfaae596 | ||
|
|
a40e0f21ee | ||
|
|
ac1f506c98 | ||
|
|
68d5bdcf3d | ||
|
|
beb51f8c67 | ||
|
|
b881cb7111 | ||
|
|
d83bc59257 | ||
|
|
5be9f297de | ||
|
|
51d440431e | ||
|
|
7cf061122c | ||
|
|
1254368505 | ||
|
|
9d4b830c5f | ||
|
|
37401b4363 | ||
|
|
10fe08e14f | ||
|
|
0ecdb35d50 | ||
|
|
caee8fe9ef | ||
|
|
7d92c27b2d | ||
|
|
701eabbaba | ||
|
|
e74a1b2d1a | ||
|
|
e087b02333 | ||
|
|
eea7f902b5 | ||
|
|
db7583201b | ||
|
|
023001a8b1 | ||
|
|
4ff8ab2435 | ||
|
|
d2cccbfce6 | ||
|
|
970e6c400c | ||
|
|
b4cb7345a1 | ||
|
|
7e75d8c1a3 | ||
|
|
a4ea551160 | ||
|
|
f56ad447a0 | ||
|
|
7656422057 | ||
|
|
afa2231add |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
node_modules
|
||||
package-lock.json
|
||||
dist
|
||||
.vscode
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
.nyc_output
|
||||
|
||||
@@ -285,14 +285,13 @@ This is an abstract enumeration type that is implemented by one of the following
|
||||
|
||||
- `nodejs12.x`
|
||||
- `nodejs10.x`
|
||||
- `nodejs8.10`
|
||||
- `go1.x`
|
||||
- `java-1.8.0-openjdk`
|
||||
- `java11`
|
||||
- `python3.8`
|
||||
- `python3.6`
|
||||
- `python2.7`
|
||||
- `dotnetcore2.1`
|
||||
- `dotnetcore2.0`
|
||||
- `dotnetcore1.0`
|
||||
- `ruby2.5`
|
||||
- `provided`
|
||||
|
||||
## JavaScript API
|
||||
|
||||
|
||||
31
changelog.js
31
changelog.js
@@ -12,12 +12,31 @@ if (!commit) {
|
||||
throw new Error('Unable to find last publish commit');
|
||||
}
|
||||
|
||||
const log = execSync(`git log --pretty=format:"- %s [%an]" ${commit}...HEAD`)
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(line => !line.startsWith('- Publish Canary '))
|
||||
.join('\n');
|
||||
const log =
|
||||
execSync(`git log --pretty=format:"- %s [%an]" ${commit}...HEAD`)
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(line => !line.startsWith('- Publish Canary '))
|
||||
.join('\n') || 'NO CHANGES DETECTED';
|
||||
|
||||
console.log(`Changes since the last Stable release (${commit.slice(0, 7)}):`);
|
||||
console.log(`\n${log}\n`);
|
||||
|
||||
const pkgs =
|
||||
Array.from(
|
||||
new Set(
|
||||
execSync(`git diff --name-only ${commit}...HEAD`)
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(line => line.startsWith('packages/'))
|
||||
.map(line => line.split('/')[1])
|
||||
.map(pkgName => require(`./packages/${pkgName}/package.json`).name)
|
||||
)
|
||||
).join(',') || 'now';
|
||||
|
||||
console.log('To publish a stable release, execute the following:');
|
||||
console.log(
|
||||
`\ngit pull && lerna version --message 'Publish Stable' --exact --force-publish=${pkgs}\n`
|
||||
);
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"scripts": {
|
||||
"lerna": "lerna",
|
||||
"bootstrap": "lerna bootstrap",
|
||||
"publish-stable": "git pull && lerna version --message 'Publish Stable' --exact",
|
||||
"publish-stable": "echo 'Run `yarn changelog` for instructions'",
|
||||
"publish-canary": "git pull && lerna version prerelease --preid canary --message 'Publish Canary' --exact",
|
||||
"publish-from-github": "./.circleci/publish.sh",
|
||||
"changelog": "node changelog.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/build-utils",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.2-canary.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
@@ -32,6 +32,7 @@
|
||||
"aggregate-error": "3.0.1",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "2.1.4",
|
||||
"boxen": "4.2.0",
|
||||
"cross-spawn": "6.0.5",
|
||||
"end-of-stream": "1.4.1",
|
||||
"execa": "^1.0.0",
|
||||
|
||||
@@ -18,7 +18,7 @@ const config: Config = { zeroConfig: true };
|
||||
const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = {
|
||||
code: 'missing_build_script',
|
||||
message:
|
||||
'Your `package.json` file is missing a `build` property inside the `script` property.' +
|
||||
'Your `package.json` file is missing a `build` property inside the `scripts` property.' +
|
||||
'\nMore details: https://zeit.co/docs/v2/platform/frequently-asked-questions#missing-build-script',
|
||||
};
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ export default async function detectAngular({
|
||||
const hasAngular = await hasDependency('@angular/cli');
|
||||
if (!hasAngular) return false;
|
||||
return {
|
||||
buildCommand: ['ng', 'build'],
|
||||
buildCommand: 'ng build',
|
||||
buildDirectory: 'dist',
|
||||
devCommand: ['ng', 'serve', '--port', '$PORT'],
|
||||
devCommand: 'ng serve --port $PORT',
|
||||
minNodeRange: '10.x',
|
||||
routes: [
|
||||
{
|
||||
|
||||
@@ -10,8 +10,8 @@ export default async function detectBrunch({
|
||||
if (!hasConfig) return false;
|
||||
|
||||
return {
|
||||
buildCommand: ['brunch', 'build', '--production'],
|
||||
buildCommand: 'brunch build --production',
|
||||
buildDirectory: 'public',
|
||||
devCommand: ['brunch', 'watch', '--server', '--port', '$PORT'],
|
||||
devCommand: 'brunch watch --server --port $PORT',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ export default async function detectCreateReactAppEjected({
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: ['node', 'scripts/build.js'],
|
||||
buildCommand: 'node scripts/build.js',
|
||||
buildDirectory: 'build',
|
||||
devCommand: ['node', 'scripts/start.js'],
|
||||
devEnv: { BROWSER: 'none' },
|
||||
devCommand: 'node scripts/start.js',
|
||||
devVariables: { BROWSER: 'none' },
|
||||
routes: [
|
||||
{
|
||||
src: '/static/(.*)',
|
||||
|
||||
@@ -8,10 +8,10 @@ export default async function detectCreateReactApp({
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: ['react-scripts', 'build'],
|
||||
buildCommand: 'react-scripts build',
|
||||
buildDirectory: 'build',
|
||||
devCommand: ['react-scripts', 'start'],
|
||||
devEnv: { BROWSER: 'none' },
|
||||
devCommand: 'react-scripts start',
|
||||
devVariables: { BROWSER: 'none' },
|
||||
routes: [
|
||||
{
|
||||
src: '/static/(.*)',
|
||||
|
||||
@@ -6,8 +6,8 @@ export default async function detectDocusaurus({
|
||||
const hasDocusaurus = await hasDependency('docusaurus');
|
||||
if (!hasDocusaurus) return false;
|
||||
return {
|
||||
buildCommand: ['docusaurus-build'],
|
||||
buildCommand: 'docusaurus-build',
|
||||
buildDirectory: 'build',
|
||||
devCommand: ['docusaurus-start', '--port', '$PORT'],
|
||||
devCommand: 'docusaurus-start --port $PORT',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,15 +6,8 @@ export default async function detectEleventy({
|
||||
const hasEleventy = await hasDependency('@11ty/eleventy');
|
||||
if (!hasEleventy) return false;
|
||||
return {
|
||||
buildCommand: ['npx', '@11ty/eleventy'],
|
||||
buildCommand: 'npx @11ty/eleventy',
|
||||
buildDirectory: '_site',
|
||||
devCommand: [
|
||||
'npx',
|
||||
'@11ty/eleventy',
|
||||
'--serve',
|
||||
'--watch',
|
||||
'--port',
|
||||
'$PORT',
|
||||
],
|
||||
devCommand: 'npx @11ty/eleventy --serve --watch --port $PORT',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ export default async function detectEmber({
|
||||
const hasEmber = await hasDependency('ember-cli');
|
||||
if (!hasEmber) return false;
|
||||
return {
|
||||
buildCommand: ['ember', 'build'],
|
||||
buildCommand: 'ember build',
|
||||
buildDirectory: 'dist',
|
||||
devCommand: ['ember', 'serve', '--port', '$PORT'],
|
||||
devCommand: 'ember serve --port $PORT',
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
|
||||
@@ -8,9 +8,9 @@ export default async function detectGatsby({
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: ['gatsby', 'build'],
|
||||
buildCommand: 'gatsby build',
|
||||
buildDirectory: 'public',
|
||||
devCommand: ['gatsby', 'develop', '-p', '$PORT'],
|
||||
devCommand: 'gatsby develop -p $PORT',
|
||||
cachePattern: '.cache/**',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ export default async function detectGridsome({
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: ['gridsome', 'build'],
|
||||
buildCommand: 'gridsome build',
|
||||
buildDirectory: 'dist',
|
||||
devCommand: ['gridsome', 'develop', '-p', '$PORT'],
|
||||
devCommand: 'gridsome develop -p $PORT',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ export default async function detectHexo({
|
||||
const hasHexo = await hasDependency('hexo');
|
||||
if (!hasHexo) return false;
|
||||
return {
|
||||
buildCommand: ['hexo', 'generate'],
|
||||
buildCommand: 'hexo generate',
|
||||
buildDirectory: 'public',
|
||||
devCommand: ['hexo', 'server', '--port', '$PORT'],
|
||||
devCommand: 'hexo server --port $PORT',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ export default async function detectHugo({
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: ['hugo'],
|
||||
buildCommand: 'hugo',
|
||||
buildDirectory: config.publishDir || 'public',
|
||||
devCommand: ['hugo', 'server', '-D', '-w', '-p', '$PORT'],
|
||||
devCommand: 'hugo server -D -w -p $PORT',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,16 +15,8 @@ export default async function detectJekyll({
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
buildCommand: ['jekyll', 'build'],
|
||||
buildCommand: 'jekyll build',
|
||||
buildDirectory: config.destination || '_site',
|
||||
devCommand: [
|
||||
'bundle',
|
||||
'exec',
|
||||
'jekyll',
|
||||
'serve',
|
||||
'--watch',
|
||||
'--port',
|
||||
'$PORT',
|
||||
],
|
||||
devCommand: 'bundle exec jekyll serve --watch --port $PORT',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ export default async function detectMiddleman({
|
||||
if (!hasConfig) return false;
|
||||
|
||||
return {
|
||||
buildCommand: ['bundle', 'exec', 'middleman', 'build'],
|
||||
buildCommand: 'bundle exec middleman build',
|
||||
buildDirectory: 'build',
|
||||
devCommand: ['bundle', 'exec', 'middleman', 'server', '-p', '$PORT'],
|
||||
devCommand: 'bundle exec middleman server -p $PORT',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ export default async function detectNext({
|
||||
const hasNext = await hasDependency('next');
|
||||
if (!hasNext) return false;
|
||||
return {
|
||||
buildCommand: ['next', 'build'],
|
||||
buildCommand: 'next build',
|
||||
buildDirectory: 'build',
|
||||
devCommand: ['next', '-p', '$PORT'],
|
||||
devCommand: 'next -p $PORT',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ export default async function detectPolymer({
|
||||
const hasPolymer = await hasDependency('polymer-cli');
|
||||
if (!hasPolymer) return false;
|
||||
return {
|
||||
buildCommand: ['polymer', 'build'],
|
||||
buildCommand: 'polymer build',
|
||||
buildDirectory: 'build',
|
||||
devCommand: ['polymer', 'serve', '--port', '$PORT'],
|
||||
devCommand: 'polymer serve --port $PORT',
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
|
||||
@@ -6,9 +6,9 @@ export default async function detectPreact({
|
||||
const hasPreact = await hasDependency('preact-cli');
|
||||
if (!hasPreact) return false;
|
||||
return {
|
||||
buildCommand: ['preact', 'build'],
|
||||
buildCommand: 'preact build',
|
||||
buildDirectory: 'build',
|
||||
devCommand: ['preact', 'watch', '--port', '$PORT'],
|
||||
devCommand: 'preact watch --port $PORT',
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
|
||||
@@ -6,9 +6,9 @@ export default async function detectSaber({
|
||||
const hasSaber = await hasDependency('saber');
|
||||
if (!hasSaber) return false;
|
||||
return {
|
||||
buildCommand: ['saber', 'build'],
|
||||
buildCommand: 'saber build',
|
||||
buildDirectory: 'public',
|
||||
devCommand: ['saber', '--port', '$PORT'],
|
||||
devCommand: 'saber --port $PORT',
|
||||
routes: [
|
||||
{
|
||||
src: '/_saber/.*',
|
||||
|
||||
@@ -6,8 +6,8 @@ export default async function detectSapper({
|
||||
const hasSapper = await hasDependency('sapper');
|
||||
if (!hasSapper) return false;
|
||||
return {
|
||||
buildCommand: ['sapper', 'export'],
|
||||
buildCommand: 'sapper export',
|
||||
buildDirectory: '__sapper__/export',
|
||||
devCommand: ['sapper', 'dev', '--port', '$PORT'],
|
||||
devCommand: 'sapper dev --port $PORT',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,17 +6,9 @@ export default async function detectStencil({
|
||||
const hasStencil = await hasDependency('@stencil/core');
|
||||
if (!hasStencil) return false;
|
||||
return {
|
||||
buildCommand: ['stencil', 'build'],
|
||||
buildCommand: 'stencil build',
|
||||
buildDirectory: 'www',
|
||||
devCommand: [
|
||||
'stencil',
|
||||
'build',
|
||||
'--dev',
|
||||
'--watch',
|
||||
'--serve',
|
||||
'--port',
|
||||
'$PORT',
|
||||
],
|
||||
devCommand: 'stencil build --dev --watch --serve --port $PORT',
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
|
||||
@@ -6,9 +6,9 @@ export default async function detectSvelte({
|
||||
const hasSvelte = await hasDependency('sirv-cli');
|
||||
if (!hasSvelte) return false;
|
||||
return {
|
||||
buildCommand: ['rollup', '-c'],
|
||||
buildCommand: 'rollup -c',
|
||||
buildDirectory: 'public',
|
||||
devCommand: ['sirv', 'public', '--single', '--dev', ' --port', '$PORT'],
|
||||
devCommand: 'sirv public --single --dev --port $PORT',
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
|
||||
@@ -6,9 +6,9 @@ export default async function detectUmiJS({
|
||||
const hasUmi = await hasDependency('umi');
|
||||
if (!hasUmi) return false;
|
||||
return {
|
||||
buildCommand: ['umi', 'build'],
|
||||
buildCommand: 'umi build',
|
||||
buildDirectory: 'dist',
|
||||
devCommand: ['umi', 'dev', '--port', '$PORT'],
|
||||
devCommand: 'umi dev --port $PORT',
|
||||
routes: [
|
||||
{
|
||||
handle: 'filesystem',
|
||||
|
||||
@@ -6,9 +6,9 @@ export default async function detectVue({
|
||||
const hasVue = await hasDependency('@vue/cli-service');
|
||||
if (!hasVue) return false;
|
||||
return {
|
||||
buildCommand: ['vue-cli-service', 'build'],
|
||||
buildCommand: 'vue-cli-service build',
|
||||
buildDirectory: 'dist',
|
||||
devCommand: ['vue-cli-service', 'serve', '--port', '$PORT'],
|
||||
devCommand: 'vue-cli-service serve --port $PORT',
|
||||
routes: [
|
||||
{
|
||||
src: '^/[^/]*\\.(js|txt|ico|json)',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import path from 'path';
|
||||
import debug from '../debug';
|
||||
import FileFsRef from '../file-fs-ref';
|
||||
import { File, Files, Meta } from '../types';
|
||||
import { remove, mkdirp, readlink, symlink } from 'fs-extra';
|
||||
@@ -39,8 +40,12 @@ export default async function download(
|
||||
basePath: string,
|
||||
meta?: Meta
|
||||
): Promise<DownloadedFiles> {
|
||||
const { isDev = false, skipDownload = false, filesChanged = null, filesRemoved = null } =
|
||||
meta || {};
|
||||
const {
|
||||
isDev = false,
|
||||
skipDownload = false,
|
||||
filesChanged = null,
|
||||
filesRemoved = null,
|
||||
} = meta || {};
|
||||
|
||||
if (isDev || skipDownload) {
|
||||
// In `now dev`, the `download()` function is a no-op because
|
||||
@@ -48,11 +53,14 @@ export default async function download(
|
||||
// source files are already available.
|
||||
return files as DownloadedFiles;
|
||||
}
|
||||
debug('Downloading deployment source files...');
|
||||
|
||||
const start = Date.now();
|
||||
const files2: DownloadedFiles = {};
|
||||
const filenames = Object.keys(files);
|
||||
|
||||
await Promise.all(
|
||||
Object.keys(files).map(async name => {
|
||||
filenames.map(async name => {
|
||||
// If the file does not exist anymore, remove it.
|
||||
if (Array.isArray(filesRemoved) && filesRemoved.includes(name)) {
|
||||
await removeFile(basePath, name);
|
||||
@@ -71,5 +79,8 @@ export default async function download(
|
||||
})
|
||||
);
|
||||
|
||||
const duration = Date.now() - start;
|
||||
debug(`Downloaded ${filenames.length} source files: ${duration}ms`);
|
||||
|
||||
return files2;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
import { intersects } from 'semver';
|
||||
import boxen from 'boxen';
|
||||
import { NodeVersion } from '../types';
|
||||
import debug from '../debug';
|
||||
|
||||
const supportedOptions: NodeVersion[] = [
|
||||
const allOptions: NodeVersion[] = [
|
||||
{ major: 12, range: '12.x', runtime: 'nodejs12.x' },
|
||||
{ major: 10, range: '10.x', runtime: 'nodejs10.x' },
|
||||
{ major: 8, range: '8.10.x', runtime: 'nodejs8.10' },
|
||||
{
|
||||
major: 8,
|
||||
range: '8.10.x',
|
||||
runtime: 'nodejs8.10',
|
||||
discontinueDate: new Date('2020-01-06'),
|
||||
},
|
||||
];
|
||||
|
||||
const supportedOptions = allOptions.filter(o => !isDiscontinued(o));
|
||||
|
||||
// This version should match Fargate's default in the PATH
|
||||
// Today that is Node 8
|
||||
export const defaultSelection = supportedOptions.find(
|
||||
@@ -28,13 +36,14 @@ export async function getSupportedNodeVersion(
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const found = supportedOptions.some(o => {
|
||||
const found = allOptions.some(o => {
|
||||
// the array is already in order so return the first
|
||||
// match which will be the newest version of node
|
||||
selection = o;
|
||||
return intersects(o.range, engineRange);
|
||||
});
|
||||
if (found) {
|
||||
const discontinued = isDiscontinued(selection);
|
||||
if (found && !discontinued) {
|
||||
if (!silent) {
|
||||
debug(
|
||||
'Found `engines` in `package.json`, selecting range: ' +
|
||||
@@ -42,15 +51,44 @@ export async function getSupportedNodeVersion(
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!silent) {
|
||||
throw new Error(
|
||||
'Found `engines` in `package.json` with an unsupported node range: ' +
|
||||
engineRange +
|
||||
'\nPlease use one of the following supported ranges: ' +
|
||||
JSON.stringify(supportedOptions.map(o => o.range))
|
||||
);
|
||||
}
|
||||
throw new Error(
|
||||
'Found `engines` in `package.json` with an unsupported Node.js version range: ' +
|
||||
engineRange +
|
||||
'\nPlease use one of the following supported ranges: ' +
|
||||
JSON.stringify(supportedOptions.map(o => o.range)) +
|
||||
(discontinued
|
||||
? '\nThis change is the result of a decision made by an upstream infrastructure provider (AWS).' +
|
||||
'\nRead more: https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html'
|
||||
: '')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const { range, discontinueDate } = selection;
|
||||
if (discontinueDate && !isDiscontinued(selection)) {
|
||||
const d = discontinueDate.toISOString().split('T')[0];
|
||||
const validRanges = supportedOptions
|
||||
.filter(o => !o.discontinueDate)
|
||||
.map(o => o.range);
|
||||
console.warn(
|
||||
boxen(
|
||||
'WARNING' +
|
||||
'\n' +
|
||||
`\nNode.js ${range} will be discontinued on ${d}.` +
|
||||
`\nDeployments created on or after ${d} will fail to build.` +
|
||||
'\nPlease use one of the following supported `engines` in `package.json`: ' +
|
||||
JSON.stringify(validRanges) +
|
||||
'\nThis change is the result of a decision made by an upstream infrastructure provider (AWS).' +
|
||||
'\nRead more: https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html',
|
||||
{ padding: 1 }
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
function isDiscontinued({ discontinueDate }: NodeVersion): boolean {
|
||||
const today = new Date();
|
||||
return discontinueDate !== undefined && discontinueDate <= today;
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ export async function runNpmInstall(
|
||||
commandArgs = args.filter(a => a !== '--prefer-offline');
|
||||
await spawnAsync(
|
||||
'npm',
|
||||
commandArgs.concat(['install', '--unsafe-perm']),
|
||||
commandArgs.concat(['install', '--no-audit', '--unsafe-perm']),
|
||||
opts
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -3,7 +3,7 @@ import FileFsRef from './file-fs-ref';
|
||||
import FileRef from './file-ref';
|
||||
import { Lambda, createLambda, getLambdaOptionsFromFunction } from './lambda';
|
||||
import { Prerender } from './prerender';
|
||||
import download, { DownloadedFiles } from './fs/download';
|
||||
import download, { DownloadedFiles, isSymbolicLink } from './fs/download';
|
||||
import getWriteableDirectory from './fs/get-writable-directory';
|
||||
import glob from './fs/glob';
|
||||
import rename from './fs/rename';
|
||||
@@ -52,6 +52,7 @@ export {
|
||||
detectBuilders,
|
||||
detectRoutes,
|
||||
debug,
|
||||
isSymbolicLink,
|
||||
getLambdaOptionsFromFunction,
|
||||
};
|
||||
|
||||
|
||||
@@ -304,6 +304,7 @@ export interface NodeVersion {
|
||||
major: number;
|
||||
range: string;
|
||||
runtime: string;
|
||||
discontinueDate?: Date;
|
||||
}
|
||||
|
||||
export interface Builder {
|
||||
@@ -352,11 +353,11 @@ export interface DetectorParameters {
|
||||
}
|
||||
|
||||
export interface DetectorOutput {
|
||||
buildCommand: string[];
|
||||
buildCommand: string;
|
||||
buildDirectory: string;
|
||||
buildEnv?: Env;
|
||||
devCommand?: string[];
|
||||
devEnv?: Env;
|
||||
buildVariables?: Env;
|
||||
devCommand?: string;
|
||||
devVariables?: Env;
|
||||
minNodeRange?: string;
|
||||
cachePattern?: string;
|
||||
routes?: Route[];
|
||||
|
||||
@@ -68,7 +68,7 @@ test('detectDefaults() - angular', async () => {
|
||||
const result = await detectDefaults({ fs });
|
||||
if (!result) throw new Error('Expected result');
|
||||
assert.equal(result.buildDirectory, 'dist');
|
||||
assert.deepEqual(result.buildCommand, ['ng', 'build']);
|
||||
assert.deepEqual(result.buildCommand, 'ng build');
|
||||
});
|
||||
|
||||
test('detectDefaults() - brunch', async () => {
|
||||
@@ -77,7 +77,7 @@ test('detectDefaults() - brunch', async () => {
|
||||
const result = await detectDefaults({ fs });
|
||||
if (!result) throw new Error('Expected result');
|
||||
assert.equal(result.buildDirectory, 'public');
|
||||
assert.deepEqual(result.buildCommand, ['brunch', 'build', '--production']);
|
||||
assert.deepEqual(result.buildCommand, 'brunch build --production');
|
||||
});
|
||||
|
||||
test('detectDefaults() - hugo', async () => {
|
||||
@@ -86,7 +86,7 @@ test('detectDefaults() - hugo', async () => {
|
||||
const result = await detectDefaults({ fs });
|
||||
if (!result) throw new Error('Expected result');
|
||||
assert.equal(result.buildDirectory, 'public');
|
||||
assert.deepEqual(result.buildCommand, ['hugo']);
|
||||
assert.deepEqual(result.buildCommand, 'hugo');
|
||||
});
|
||||
|
||||
test('detectDefaults() - jekyll', async () => {
|
||||
@@ -95,7 +95,7 @@ test('detectDefaults() - jekyll', async () => {
|
||||
const result = await detectDefaults({ fs });
|
||||
if (!result) throw new Error('Expected result');
|
||||
assert.equal(result.buildDirectory, '_site');
|
||||
assert.deepEqual(result.buildCommand, ['jekyll', 'build']);
|
||||
assert.deepEqual(result.buildCommand, 'jekyll build');
|
||||
});
|
||||
|
||||
test('detectDefaults() - middleman', async () => {
|
||||
@@ -104,10 +104,5 @@ test('detectDefaults() - middleman', async () => {
|
||||
const result = await detectDefaults({ fs });
|
||||
if (!result) throw new Error('Expected result');
|
||||
assert.equal(result.buildDirectory, 'build');
|
||||
assert.deepEqual(result.buildCommand, [
|
||||
'bundle',
|
||||
'exec',
|
||||
'middleman',
|
||||
'build',
|
||||
]);
|
||||
assert.deepEqual(result.buildCommand, 'bundle exec middleman build');
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ const { mkdirp, copyFile } = require('fs-extra');
|
||||
|
||||
const {
|
||||
glob,
|
||||
debug,
|
||||
download,
|
||||
shouldServe,
|
||||
createLambda,
|
||||
@@ -14,7 +15,6 @@ exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
|
||||
exports.version = 3;
|
||||
|
||||
exports.build = async ({ workPath, files, entrypoint, meta, config }) => {
|
||||
console.log('downloading files...');
|
||||
const outDir = await getWritableDirectory();
|
||||
|
||||
await download(files, workPath, meta);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/cgi",
|
||||
"version": "1.0.1-canary.0",
|
||||
"version": "1.0.1-canary.1",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "now",
|
||||
"version": "16.6.0",
|
||||
"version": "16.6.4-canary.0",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Now",
|
||||
@@ -146,7 +146,6 @@
|
||||
"ora": "3.4.0",
|
||||
"pcre-to-regexp": "1.0.0",
|
||||
"pluralize": "7.0.0",
|
||||
"pre-commit": "1.2.2",
|
||||
"printf": "0.2.5",
|
||||
"progress": "2.0.3",
|
||||
"promisepipe": "3.0.0",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
const fs = require('fs');
|
||||
const { promisify } = require('util');
|
||||
const { join, delimiter } = require('path');
|
||||
const { homedir } = require('os');
|
||||
|
||||
const stat = promisify(fs.stat);
|
||||
const unlink = promisify(fs.unlink);
|
||||
@@ -39,7 +40,16 @@ function isGlobal() {
|
||||
// See: https://git.io/fj4jD
|
||||
function getNowPath() {
|
||||
if (process.platform === 'win32') {
|
||||
const path = join(process.env.LOCALAPPDATA, 'now-cli', 'now.exe');
|
||||
const { LOCALAPPDATA, USERPROFILE, HOMEPATH } = process.env;
|
||||
const home = homedir() || USERPROFILE || HOMEPATH;
|
||||
let path;
|
||||
if (LOCALAPPDATA) {
|
||||
path = join(LOCALAPPDATA, 'now-cli', 'now.exe');
|
||||
} else if (home) {
|
||||
path = join(home, 'AppData', 'Local', 'now-cli', 'now.exe');
|
||||
} else {
|
||||
path = '';
|
||||
}
|
||||
return fs.existsSync(path) ? path : null;
|
||||
}
|
||||
|
||||
@@ -48,7 +58,7 @@ function getNowPath() {
|
||||
const paths = [
|
||||
join(process.env.HOME || '/', 'bin'),
|
||||
'/usr/local/bin',
|
||||
'/usr/bin'
|
||||
'/usr/bin',
|
||||
];
|
||||
|
||||
for (const basePath of paths) {
|
||||
|
||||
@@ -294,15 +294,11 @@ export default async function main(
|
||||
parseEnv(argv['--env'])
|
||||
);
|
||||
|
||||
// Enable debug mode for builders
|
||||
const buildDebugEnv = debugEnabled ? { NOW_BUILDER_DEBUG: '1' } : {};
|
||||
|
||||
// Merge build env out of `build.env` from now.json, and `--build-env` args
|
||||
const deploymentBuildEnv = Object.assign(
|
||||
{},
|
||||
parseEnv(localConfig.build && localConfig.build.env),
|
||||
parseEnv(argv['--build-env']),
|
||||
buildDebugEnv
|
||||
parseEnv(argv['--build-env'])
|
||||
);
|
||||
|
||||
// If there's any undefined values, then inherit them from this process
|
||||
|
||||
@@ -18,7 +18,7 @@ export default async function dev(
|
||||
output: Output
|
||||
) {
|
||||
output.dim(
|
||||
`Now CLI ${pkg.version} dev (beta) — https://zeit.co/feedback/dev`
|
||||
`Now CLI ${pkg.version} dev (beta) — https://zeit.co/feedback`
|
||||
);
|
||||
|
||||
const [dir = '.'] = args;
|
||||
|
||||
@@ -2,13 +2,7 @@ import { NowConfig } from './util/dev/types';
|
||||
|
||||
export type ThenArg<T> = T extends Promise<infer U> ? U : T;
|
||||
|
||||
export interface Config extends NowConfig {
|
||||
alias?: string[] | string;
|
||||
aliases?: string[] | string;
|
||||
name?: string;
|
||||
type?: string;
|
||||
scope?: string;
|
||||
}
|
||||
export type Config = NowConfig;
|
||||
|
||||
export interface NowContext {
|
||||
argv: string[];
|
||||
|
||||
@@ -6,12 +6,14 @@ import {
|
||||
createDeployment,
|
||||
createLegacyDeployment,
|
||||
DeploymentOptions,
|
||||
} from 'now-client/dist';
|
||||
NowClientOptions,
|
||||
} from 'now-client';
|
||||
import wait from '../output/wait';
|
||||
import { Output } from '../output';
|
||||
// @ts-ignore
|
||||
import Now from '../../util';
|
||||
import { NowConfig } from '../dev/types';
|
||||
import ua from '../ua';
|
||||
|
||||
export default async function processDeployment({
|
||||
now,
|
||||
@@ -21,9 +23,9 @@ export default async function processDeployment({
|
||||
requestBody,
|
||||
uploadStamp,
|
||||
deployStamp,
|
||||
legacy,
|
||||
env,
|
||||
isLegacy,
|
||||
quiet,
|
||||
force,
|
||||
nowConfig,
|
||||
}: {
|
||||
now: Now;
|
||||
@@ -33,27 +35,36 @@ export default async function processDeployment({
|
||||
requestBody: DeploymentOptions;
|
||||
uploadStamp: () => number;
|
||||
deployStamp: () => number;
|
||||
legacy: boolean;
|
||||
env: any;
|
||||
isLegacy: boolean;
|
||||
quiet: boolean;
|
||||
nowConfig?: NowConfig;
|
||||
force?: boolean;
|
||||
}) {
|
||||
const { warn, log, debug, note } = output;
|
||||
let bar: Progress | null = null;
|
||||
|
||||
const path0 = paths[0];
|
||||
const opts: DeploymentOptions = {
|
||||
...requestBody,
|
||||
debug: now._debug,
|
||||
const { env = {} } = requestBody;
|
||||
|
||||
const nowClientOptions: NowClientOptions = {
|
||||
teamId: now.currentTeam,
|
||||
apiUrl: now._apiUrl,
|
||||
token: now._token,
|
||||
debug: now._debug,
|
||||
userAgent: ua,
|
||||
path: paths[0],
|
||||
force,
|
||||
};
|
||||
|
||||
if (!legacy) {
|
||||
if (!isLegacy) {
|
||||
let queuedSpinner = null;
|
||||
let buildSpinner = null;
|
||||
let deploySpinner = null;
|
||||
|
||||
for await (const event of createDeployment(path0, opts, nowConfig)) {
|
||||
for await (const event of createDeployment(
|
||||
nowClientOptions,
|
||||
requestBody,
|
||||
nowConfig
|
||||
)) {
|
||||
if (event.type === 'hashes-calculated') {
|
||||
hashes = event.payload;
|
||||
}
|
||||
@@ -110,7 +121,7 @@ export default async function processDeployment({
|
||||
now._host = event.payload.url;
|
||||
|
||||
if (!quiet) {
|
||||
const version = legacy ? `${chalk.grey('[v1]')} ` : '';
|
||||
const version = isLegacy ? `${chalk.grey('[v1]')} ` : '';
|
||||
log(`https://${event.payload.url} ${version}${deployStamp()}`);
|
||||
} else {
|
||||
process.stdout.write(`https://${event.payload.url}`);
|
||||
@@ -176,7 +187,11 @@ export default async function processDeployment({
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for await (const event of createLegacyDeployment(path0, opts, nowConfig)) {
|
||||
for await (const event of createLegacyDeployment(
|
||||
nowClientOptions,
|
||||
requestBody,
|
||||
nowConfig
|
||||
)) {
|
||||
if (event.type === 'hashes-calculated') {
|
||||
hashes = event.payload;
|
||||
}
|
||||
@@ -224,7 +239,7 @@ export default async function processDeployment({
|
||||
now._host = event.payload.url;
|
||||
|
||||
if (!quiet) {
|
||||
const version = legacy ? `${chalk.grey('[v1]')} ` : '';
|
||||
const version = isLegacy ? `${chalk.grey('[v1]')} ` : '';
|
||||
log(`${event.payload.url} ${version}${deployStamp()}`);
|
||||
} else {
|
||||
process.stdout.write(`https://${event.payload.url}`);
|
||||
|
||||
@@ -158,6 +158,14 @@ export function getBuildUtils(packages: string[]): string {
|
||||
return `@now/build-utils@${version}`;
|
||||
}
|
||||
|
||||
function parseVersionSafe(rawSpec: string) {
|
||||
try {
|
||||
return semver.parse(rawSpec);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function filterPackage(
|
||||
builderSpec: string,
|
||||
distTag: string,
|
||||
@@ -165,6 +173,17 @@ export function filterPackage(
|
||||
) {
|
||||
if (builderSpec in localBuilders) return false;
|
||||
const parsed = npa(builderSpec);
|
||||
const parsedVersion = parseVersionSafe(parsed.rawSpec);
|
||||
// skip install of already installed runtime
|
||||
if (
|
||||
parsed.name &&
|
||||
parsed.type === 'version' &&
|
||||
parsedVersion &&
|
||||
buildersPkg.dependencies &&
|
||||
parsedVersion.version == buildersPkg.dependencies[parsed.name]
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
parsed.name &&
|
||||
parsed.type === 'tag' &&
|
||||
|
||||
@@ -83,12 +83,6 @@ async function createBuildProcess(
|
||||
NOW_REGION: 'dev1',
|
||||
};
|
||||
|
||||
// Builders won't show debug logs by default.
|
||||
// The `NOW_BUILDER_DEBUG` env variable enables them.
|
||||
if (debugEnabled) {
|
||||
env.NOW_BUILDER_DEBUG = '1';
|
||||
}
|
||||
|
||||
const buildProcess = fork(modulePath, [], {
|
||||
cwd: workPath,
|
||||
env,
|
||||
|
||||
@@ -88,6 +88,17 @@ export default async function(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (routeConfig.check && devServer) {
|
||||
const { pathname = '/' } = url.parse(destPath);
|
||||
const hasDestFile = await devServer.hasFilesystem(pathname);
|
||||
if (!hasDestFile) {
|
||||
// If the file is not found, `check: true` will
|
||||
// behave the same as `continue: true`
|
||||
reqPathname = destPath;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isURL(destPath)) {
|
||||
found = {
|
||||
found: true,
|
||||
|
||||
@@ -9,9 +9,12 @@ import {
|
||||
PackageJson,
|
||||
BuilderFunctions,
|
||||
} from '@now/build-utils';
|
||||
import { NowConfig } from 'now-client';
|
||||
import { NowRedirect, NowRewrite, NowHeader, Route } from '@now/routing-utils';
|
||||
import { Output } from '../output';
|
||||
|
||||
export { NowConfig };
|
||||
|
||||
export interface DevServerOptions {
|
||||
output: Output;
|
||||
debug: boolean;
|
||||
@@ -31,24 +34,6 @@ export interface BuildMatch extends BuildConfig {
|
||||
|
||||
export type RouteConfig = Route;
|
||||
|
||||
export interface NowConfig {
|
||||
name?: string;
|
||||
version?: number;
|
||||
env?: EnvConfig;
|
||||
build?: {
|
||||
env?: EnvConfig;
|
||||
};
|
||||
builds?: BuildConfig[];
|
||||
routes?: RouteConfig[];
|
||||
files?: string[];
|
||||
cleanUrls?: boolean;
|
||||
rewrites?: NowRewrite[];
|
||||
redirects?: NowRedirect[];
|
||||
headers?: NowHeader[];
|
||||
trailingSlash?: boolean;
|
||||
functions?: BuilderFunctions;
|
||||
}
|
||||
|
||||
export interface HttpHandler {
|
||||
(req: http.IncomingMessage, res: http.ServerResponse): void;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ export default class Now extends EventEmitter {
|
||||
nowConfig = {},
|
||||
hasNowJson = false,
|
||||
sessionAffinity = 'random',
|
||||
atlas = false,
|
||||
|
||||
// Latest
|
||||
name,
|
||||
@@ -71,39 +70,21 @@ export default class Now extends EventEmitter {
|
||||
) {
|
||||
const opts = { output: this._output, hasNowJson };
|
||||
const { log, warn, debug } = this._output;
|
||||
const isBuilds = type === null;
|
||||
const isLegacy = type !== null;
|
||||
|
||||
let files = [];
|
||||
let hashes = {};
|
||||
const relatives = {};
|
||||
let engines;
|
||||
let deployment;
|
||||
let requestBody = {};
|
||||
|
||||
if (isBuilds) {
|
||||
requestBody = {
|
||||
token: this._token,
|
||||
teamId: this.currentTeam,
|
||||
env,
|
||||
build,
|
||||
public: wantsPublic || nowConfig.public,
|
||||
name,
|
||||
project,
|
||||
meta,
|
||||
regions,
|
||||
force: forceNew,
|
||||
};
|
||||
|
||||
if (target) {
|
||||
requestBody.target = target;
|
||||
}
|
||||
} else if (type === 'npm') {
|
||||
if (type === 'npm') {
|
||||
files = await getNpmFiles(paths[0], pkg, nowConfig, opts);
|
||||
|
||||
// A `start` or `now-start` npm script, or a `server.js` file
|
||||
// in the root directory of the deployment are required
|
||||
if (
|
||||
!isBuilds &&
|
||||
isLegacy &&
|
||||
!hasNpmStart(pkg) &&
|
||||
!hasFile(paths[0], files, 'server.js')
|
||||
) {
|
||||
@@ -139,30 +120,30 @@ export default class Now extends EventEmitter {
|
||||
|
||||
const uploadStamp = stamp();
|
||||
|
||||
if (isBuilds) {
|
||||
deployment = await processDeployment({
|
||||
now: this,
|
||||
output: this._output,
|
||||
hashes,
|
||||
paths,
|
||||
requestBody,
|
||||
uploadStamp,
|
||||
deployStamp,
|
||||
quiet,
|
||||
nowConfig,
|
||||
});
|
||||
} else {
|
||||
// Read `registry.npmjs.org` authToken from .npmrc
|
||||
let authToken;
|
||||
let requestBody = {
|
||||
...nowConfig,
|
||||
env,
|
||||
build,
|
||||
public: wantsPublic || nowConfig.public,
|
||||
name,
|
||||
project,
|
||||
meta,
|
||||
regions,
|
||||
target: target || undefined,
|
||||
};
|
||||
|
||||
if (type === 'npm' && forwardNpm) {
|
||||
authToken =
|
||||
(await readAuthToken(paths[0])) || (await readAuthToken(homedir()));
|
||||
}
|
||||
// Ignore specific items from Now.json
|
||||
delete requestBody.scope;
|
||||
delete requestBody.github;
|
||||
|
||||
if (isLegacy) {
|
||||
// Read `registry.npmjs.org` authToken from .npmrc
|
||||
const registryAuthToken =
|
||||
type === 'npm' && forwardNpm
|
||||
? (await readAuthToken(paths[0])) || (await readAuthToken(homedir()))
|
||||
: undefined;
|
||||
|
||||
requestBody = {
|
||||
token: this._token,
|
||||
teamId: this.currentTeam,
|
||||
env,
|
||||
build,
|
||||
meta,
|
||||
@@ -172,31 +153,29 @@ export default class Now extends EventEmitter {
|
||||
project,
|
||||
description,
|
||||
deploymentType: type,
|
||||
registryAuthToken: authToken,
|
||||
registryAuthToken,
|
||||
engines,
|
||||
scale,
|
||||
sessionAffinity,
|
||||
limits: nowConfig.limits,
|
||||
atlas,
|
||||
config: nowConfig,
|
||||
functions: nowConfig.functions,
|
||||
};
|
||||
|
||||
deployment = await processDeployment({
|
||||
legacy: true,
|
||||
now: this,
|
||||
output: this._output,
|
||||
hashes,
|
||||
paths,
|
||||
requestBody,
|
||||
uploadStamp,
|
||||
deployStamp,
|
||||
quiet,
|
||||
env,
|
||||
nowConfig,
|
||||
});
|
||||
}
|
||||
|
||||
deployment = await processDeployment({
|
||||
isLegacy,
|
||||
now: this,
|
||||
output: this._output,
|
||||
hashes,
|
||||
paths,
|
||||
requestBody,
|
||||
uploadStamp,
|
||||
deployStamp,
|
||||
quiet,
|
||||
nowConfig,
|
||||
force: forceNew,
|
||||
});
|
||||
|
||||
// We report about files whose sizes are too big
|
||||
let missingVersion = false;
|
||||
|
||||
@@ -228,7 +207,7 @@ export default class Now extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
if (!isBuilds && !quiet && type === 'npm' && deployment.nodeVersion) {
|
||||
if (isLegacy && !quiet && type === 'npm' && deployment.nodeVersion) {
|
||||
if (engines && engines.node && !missingVersion) {
|
||||
log(
|
||||
chalk`Using Node.js {bold ${deployment.nodeVersion}} (requested: {dim \`${engines.node}\`})`
|
||||
|
||||
72
packages/now-cli/test/dev-builder.unit.js
vendored
72
packages/now-cli/test/dev-builder.unit.js
vendored
@@ -4,8 +4,8 @@ import { filterPackage } from '../src/util/dev/builder-cache';
|
||||
test('[dev-builder] filter install "latest", cached canary', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'@now/build-utils': '0.0.1-canary.0'
|
||||
}
|
||||
'@now/build-utils': '0.0.1-canary.0',
|
||||
},
|
||||
};
|
||||
const result = filterPackage('@now/build-utils', 'canary', buildersPkg);
|
||||
t.is(result, true);
|
||||
@@ -14,8 +14,8 @@ test('[dev-builder] filter install "latest", cached canary', async t => {
|
||||
test('[dev-builder] filter install "canary", cached stable', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'@now/build-utils': '0.0.1'
|
||||
}
|
||||
'@now/build-utils': '0.0.1',
|
||||
},
|
||||
};
|
||||
const result = filterPackage(
|
||||
'@now/build-utils@canary',
|
||||
@@ -28,8 +28,8 @@ test('[dev-builder] filter install "canary", cached stable', async t => {
|
||||
test('[dev-builder] filter install "latest", cached stable', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'@now/build-utils': '0.0.1'
|
||||
}
|
||||
'@now/build-utils': '0.0.1',
|
||||
},
|
||||
};
|
||||
const result = filterPackage('@now/build-utils', 'latest', buildersPkg);
|
||||
t.is(result, false);
|
||||
@@ -38,8 +38,8 @@ test('[dev-builder] filter install "latest", cached stable', async t => {
|
||||
test('[dev-builder] filter install "canary", cached canary', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'@now/build-utils': '0.0.1-canary.0'
|
||||
}
|
||||
'@now/build-utils': '0.0.1-canary.0',
|
||||
},
|
||||
};
|
||||
const result = filterPackage(
|
||||
'@now/build-utils@canary',
|
||||
@@ -52,8 +52,8 @@ test('[dev-builder] filter install "canary", cached canary', async t => {
|
||||
test('[dev-builder] filter install URL, cached stable', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'@now/build-utils': '0.0.1'
|
||||
}
|
||||
'@now/build-utils': '0.0.1',
|
||||
},
|
||||
};
|
||||
const result = filterPackage('https://tarball.now.sh', 'latest', buildersPkg);
|
||||
t.is(result, true);
|
||||
@@ -62,8 +62,8 @@ test('[dev-builder] filter install URL, cached stable', async t => {
|
||||
test('[dev-builder] filter install URL, cached canary', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'@now/build-utils': '0.0.1-canary.0'
|
||||
}
|
||||
'@now/build-utils': '0.0.1-canary.0',
|
||||
},
|
||||
};
|
||||
const result = filterPackage('https://tarball.now.sh', 'canary', buildersPkg);
|
||||
t.is(result, true);
|
||||
@@ -72,8 +72,8 @@ test('[dev-builder] filter install URL, cached canary', async t => {
|
||||
test('[dev-builder] filter install "latest", cached URL - stable', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'@now/build-utils': 'https://tarball.now.sh'
|
||||
}
|
||||
'@now/build-utils': 'https://tarball.now.sh',
|
||||
},
|
||||
};
|
||||
const result = filterPackage('@now/build-utils', 'latest', buildersPkg);
|
||||
t.is(result, true);
|
||||
@@ -82,9 +82,49 @@ test('[dev-builder] filter install "latest", cached URL - stable', async t => {
|
||||
test('[dev-builder] filter install "latest", cached URL - canary', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'@now/build-utils': 'https://tarball.now.sh'
|
||||
}
|
||||
'@now/build-utils': 'https://tarball.now.sh',
|
||||
},
|
||||
};
|
||||
const result = filterPackage('@now/build-utils', 'canary', buildersPkg);
|
||||
t.is(result, true);
|
||||
});
|
||||
|
||||
test('[dev-builder] filter install not bundled version, cached same version', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'not-bundled-package': '0.0.1',
|
||||
},
|
||||
};
|
||||
const result = filterPackage('not-bundled-package@0.0.1', '_', buildersPkg);
|
||||
t.is(result, false);
|
||||
});
|
||||
|
||||
test('[dev-builder] filter install not bundled version, cached different version', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'not-bundled-package': '0.0.9',
|
||||
},
|
||||
};
|
||||
const result = filterPackage('not-bundled-package@0.0.1', '_', buildersPkg);
|
||||
t.is(result, true);
|
||||
});
|
||||
|
||||
test('[dev-builder] filter install not bundled stable, cached version', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'not-bundled-package': '0.0.1',
|
||||
},
|
||||
};
|
||||
const result = filterPackage('not-bundled-package', '_', buildersPkg);
|
||||
t.is(result, true);
|
||||
});
|
||||
|
||||
test('[dev-builder] filter install not bundled tagged, cached tagged', async t => {
|
||||
const buildersPkg = {
|
||||
dependencies: {
|
||||
'not-bundled-package': '16.9.0-alpha.0',
|
||||
},
|
||||
};
|
||||
const result = filterPackage('not-bundled-package@alpha', '_', buildersPkg);
|
||||
t.is(result, true);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"routes": [
|
||||
{
|
||||
"src": "/blog/(.*)",
|
||||
"check": true,
|
||||
"dest": "/blog?post=$1"
|
||||
},
|
||||
{
|
||||
"src": "/(.*)",
|
||||
"check": true,
|
||||
"dest": "/src/$1"
|
||||
},
|
||||
{
|
||||
"src": "/(.*)",
|
||||
"check": true,
|
||||
"dest": "/fake/$1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Blog Home
|
||||
@@ -154,6 +154,22 @@ function testFixtureStdio(directory, fn) {
|
||||
};
|
||||
}
|
||||
|
||||
test(
|
||||
'[now dev] validate routes that use `check: true`',
|
||||
testFixtureStdio('routes-check-true', async (t, port) => {
|
||||
const result = await fetchWithRetry(
|
||||
`http://localhost:${port}/blog/post`,
|
||||
3
|
||||
);
|
||||
const response = await result;
|
||||
|
||||
validateResponseHeaders(t, response);
|
||||
|
||||
const body = await response.text();
|
||||
t.regex(body, /Blog Home/gm);
|
||||
})
|
||||
);
|
||||
|
||||
test('[now dev] validate builds', async t => {
|
||||
const directory = fixture('invalid-builds');
|
||||
const output = await exec(directory);
|
||||
@@ -291,10 +307,10 @@ test(
|
||||
await testPath(200, '/sub', 'Sub Index Page');
|
||||
await testPath(200, '/sub/another', 'Sub Another Page');
|
||||
await testPath(200, '/style.css', 'body { color: green }');
|
||||
await testPath(301, '/index.html', '', { Location: '/' });
|
||||
await testPath(301, '/about.html', '', { Location: '/about' });
|
||||
await testPath(301, '/sub/index.html', '', { Location: '/sub' });
|
||||
await testPath(301, '/sub/another.html', '', { Location: '/sub/another' });
|
||||
await testPath(308, '/index.html', '', { Location: '/' });
|
||||
await testPath(308, '/about.html', '', { Location: '/about' });
|
||||
await testPath(308, '/sub/index.html', '', { Location: '/sub' });
|
||||
await testPath(308, '/sub/another.html', '', { Location: '/sub/another' });
|
||||
})
|
||||
);
|
||||
|
||||
@@ -308,10 +324,10 @@ test(
|
||||
await testPath(200, '/sub/', 'Sub Index Page');
|
||||
await testPath(200, '/sub/another/', 'Sub Another Page');
|
||||
await testPath(200, '/style.css/', 'body { color: green }');
|
||||
await testPath(301, '/index.html', '', { Location: '/' });
|
||||
await testPath(301, '/about.html', '', { Location: '/about/' });
|
||||
await testPath(301, '/sub/index.html', '', { Location: '/sub/' });
|
||||
await testPath(301, '/sub/another.html', '', {
|
||||
await testPath(308, '/index.html', '', { Location: '/' });
|
||||
await testPath(308, '/about.html', '', { Location: '/about/' });
|
||||
await testPath(308, '/sub/index.html', '', { Location: '/sub/' });
|
||||
await testPath(308, '/sub/another.html', '', {
|
||||
Location: '/sub/another/',
|
||||
});
|
||||
}
|
||||
@@ -328,9 +344,9 @@ test(
|
||||
await testPath(200, '/sub/index.html/', 'Sub Index Page');
|
||||
await testPath(200, '/sub/another.html/', 'Sub Another Page');
|
||||
await testPath(200, '/style.css/', 'body { color: green }');
|
||||
await testPath(307, '/about.html', '', { Location: '/about.html/' });
|
||||
await testPath(307, '/sub', '', { Location: '/sub/' });
|
||||
await testPath(307, '/sub/another.html', '', {
|
||||
await testPath(308, '/about.html', '', { Location: '/about.html/' });
|
||||
await testPath(308, '/sub', '', { Location: '/sub/' });
|
||||
await testPath(308, '/sub/another.html', '', {
|
||||
Location: '/sub/another.html/',
|
||||
});
|
||||
})
|
||||
@@ -346,9 +362,9 @@ test(
|
||||
await testPath(200, '/sub/index.html', 'Sub Index Page');
|
||||
await testPath(200, '/sub/another.html', 'Sub Another Page');
|
||||
await testPath(200, '/style.css', 'body { color: green }');
|
||||
await testPath(307, '/about.html/', '', { Location: '/about.html' });
|
||||
await testPath(307, '/sub/', '', { Location: '/sub' });
|
||||
await testPath(307, '/sub/another.html/', '', {
|
||||
await testPath(308, '/about.html/', '', { Location: '/about.html' });
|
||||
await testPath(308, '/sub/', '', { Location: '/sub' });
|
||||
await testPath(308, '/sub/another.html/', '', {
|
||||
Location: '/sub/another.html',
|
||||
});
|
||||
})
|
||||
|
||||
@@ -122,11 +122,6 @@ module.exports = async session => {
|
||||
'single-dotfile': {
|
||||
'.testing': 'i am a dotfile',
|
||||
},
|
||||
'config-alias-property': {
|
||||
'now.json':
|
||||
'{ "alias": "test.now.sh", "builds": [ { "src": "*.html", "use": "@now/static" } ] }',
|
||||
'index.html': '<span>test alias</span',
|
||||
},
|
||||
'config-scope-property-email': {
|
||||
'now.json': `{ "scope": "${session}@zeit.pub", "builds": [ { "src": "*.html", "use": "@now/static" } ], "version": 2 }`,
|
||||
'index.html': '<span>test scope email</span',
|
||||
@@ -204,7 +199,7 @@ fs.writeFileSync(
|
||||
'index.js',
|
||||
fs
|
||||
.readFileSync('index.js', 'utf8')
|
||||
.replace('BUILD_ENV_DEBUG', process.env.NOW_BUILDER_DEBUG),
|
||||
.replace('BUILD_ENV_DEBUG', process.env.NOW_BUILDER_DEBUG ? 'on' : 'off'),
|
||||
);
|
||||
`,
|
||||
'index.js': `
|
||||
@@ -463,6 +458,18 @@ CMD ["node", "index.js"]`,
|
||||
},
|
||||
}),
|
||||
},
|
||||
'github-and-scope-config': {
|
||||
'index.txt': 'I Am a Website!',
|
||||
'now.json': JSON.stringify({
|
||||
scope: 'i-do-not-exist',
|
||||
github: {
|
||||
autoAlias: true,
|
||||
autoJobCancelation: true,
|
||||
enabled: true,
|
||||
silent: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
for (const typeName of Object.keys(spec)) {
|
||||
|
||||
31
packages/now-cli/test/integration-v1.js
vendored
31
packages/now-cli/test/integration-v1.js
vendored
@@ -1427,35 +1427,6 @@ test('ensure we render a prompt when deploying home directory', async t => {
|
||||
t.true(stderr.includes('> Aborted'));
|
||||
});
|
||||
|
||||
test('ensure the `alias` property is not sent to the API', async t => {
|
||||
const directory = fixture('config-alias-property');
|
||||
|
||||
const { stdout, stderr, exitCode } = await execa(
|
||||
binaryPath,
|
||||
[directory, '--public', '--name', session, ...defaultArgs, '--force'],
|
||||
{
|
||||
reject: false,
|
||||
}
|
||||
);
|
||||
|
||||
console.log(stderr);
|
||||
console.log(stdout);
|
||||
console.log(exitCode);
|
||||
|
||||
// Ensure the exit code is right
|
||||
t.is(exitCode, 0);
|
||||
|
||||
// Test if the output is really a URL
|
||||
const { href, host } = new URL(stdout);
|
||||
t.is(host.split('-')[0], session);
|
||||
|
||||
// Send a test request to the deployment
|
||||
const response = await fetch(href);
|
||||
const contentType = response.headers.get('content-type');
|
||||
|
||||
t.is(contentType, 'text/html; charset=utf-8');
|
||||
});
|
||||
|
||||
test('ensure the `scope` property works with email', async t => {
|
||||
const directory = fixture('config-scope-property-email');
|
||||
|
||||
@@ -1995,7 +1966,7 @@ test('use `--debug` CLI flag', async t => {
|
||||
// get the content
|
||||
const response = await fetch(href);
|
||||
const content = await response.text();
|
||||
t.is(content.trim(), '1');
|
||||
t.is(content.trim(), 'off');
|
||||
});
|
||||
|
||||
test('try to deploy non-existing path', async t => {
|
||||
|
||||
39
packages/now-cli/test/integration.js
vendored
39
packages/now-cli/test/integration.js
vendored
@@ -919,35 +919,6 @@ test('ensure we render a prompt when deploying home directory', async t => {
|
||||
t.true(stderr.includes('> Aborted'));
|
||||
});
|
||||
|
||||
test('ensure the `alias` property is not sent to the API', async t => {
|
||||
const directory = fixture('config-alias-property');
|
||||
|
||||
const { stdout, stderr, exitCode } = await execa(
|
||||
binaryPath,
|
||||
[directory, '--public', '--name', session, ...defaultArgs, '--force'],
|
||||
{
|
||||
reject: false,
|
||||
}
|
||||
);
|
||||
|
||||
console.log(stderr);
|
||||
console.log(stdout);
|
||||
console.log(exitCode);
|
||||
|
||||
// Ensure the exit code is right
|
||||
t.is(exitCode, 0);
|
||||
|
||||
// Test if the output is really a URL
|
||||
const { href, host } = new URL(stdout);
|
||||
t.is(host.split('-')[0], session);
|
||||
|
||||
// Send a test request to the deployment
|
||||
const response = await fetch(href);
|
||||
const contentType = response.headers.get('content-type');
|
||||
|
||||
t.is(contentType, 'text/html; charset=utf-8');
|
||||
});
|
||||
|
||||
test('ensure the `scope` property works with email', async t => {
|
||||
const directory = fixture('config-scope-property-email');
|
||||
|
||||
@@ -1456,7 +1427,7 @@ test('use `--debug` CLI flag', async t => {
|
||||
// get the content
|
||||
const response = await fetch(href);
|
||||
const content = await response.text();
|
||||
t.is(content.trim(), '1');
|
||||
t.is(content.trim(), 'off');
|
||||
});
|
||||
|
||||
test('try to deploy non-existing path', async t => {
|
||||
@@ -2056,7 +2027,6 @@ test('deploy a Lambda with a specific runtime', async t => {
|
||||
t.is(build.use, 'now-php@0.0.7', JSON.stringify(build, null, 2));
|
||||
});
|
||||
|
||||
// We need to skip this test until `now-php` supports Runtime version 3
|
||||
test('fail to deploy a Lambda with a specific runtime but without a locked version', async t => {
|
||||
const directory = fixture('lambda-with-invalid-runtime');
|
||||
const output = await execute([directory]);
|
||||
@@ -2069,6 +2039,13 @@ test('fail to deploy a Lambda with a specific runtime but without a locked versi
|
||||
);
|
||||
});
|
||||
|
||||
test('ensure `github` and `scope` are not sent to the API', async t => {
|
||||
const directory = fixture('github-and-scope-config');
|
||||
const output = await execute([directory]);
|
||||
|
||||
t.is(output.exitCode, 0, formatOutput(output));
|
||||
});
|
||||
|
||||
test.after.always(async () => {
|
||||
// Make sure the token gets revoked
|
||||
await execa(binaryPath, ['logout', ...defaultArgs]);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "now-client",
|
||||
"version": "5.2.4",
|
||||
"main": "dist/src/index.js",
|
||||
"typings": "dist/src/index.d.ts",
|
||||
"version": "6.0.0",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://zeit.co",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
|
||||
@@ -8,7 +8,13 @@ import {
|
||||
isAliasAssigned,
|
||||
isAliasError,
|
||||
} from './utils/ready-state';
|
||||
import { Deployment, DeploymentBuild } from './types';
|
||||
import { createDebug } from './utils';
|
||||
import {
|
||||
Dictionary,
|
||||
Deployment,
|
||||
NowClientOptions,
|
||||
DeploymentBuild,
|
||||
} from './types';
|
||||
|
||||
interface DeploymentStatus {
|
||||
type: string;
|
||||
@@ -16,22 +22,22 @@ interface DeploymentStatus {
|
||||
}
|
||||
|
||||
/* eslint-disable */
|
||||
export default async function* checkDeploymentStatus(
|
||||
export async function* checkDeploymentStatus(
|
||||
deployment: Deployment,
|
||||
token: string,
|
||||
version: number | undefined,
|
||||
teamId: string | undefined,
|
||||
debug: Function,
|
||||
apiUrl?: string
|
||||
clientOptions: NowClientOptions
|
||||
): AsyncIterableIterator<DeploymentStatus> {
|
||||
const { version } = deployment;
|
||||
const { token, teamId, apiUrl, userAgent } = clientOptions;
|
||||
const debug = createDebug(clientOptions.debug);
|
||||
|
||||
let deploymentState = deployment;
|
||||
let allBuildsCompleted = false;
|
||||
const buildsState: { [key: string]: DeploymentBuild } = {};
|
||||
const buildsState: Dictionary<DeploymentBuild> = {};
|
||||
|
||||
const apiDeployments = getApiDeploymentsUrl({
|
||||
version,
|
||||
builds: deployment.builds,
|
||||
functions: deployment.functions
|
||||
functions: deployment.functions,
|
||||
});
|
||||
|
||||
debug(`Using ${version ? `${version}.0` : '2.0'} API for status checks`);
|
||||
@@ -54,7 +60,7 @@ export default async function* checkDeploymentStatus(
|
||||
teamId ? `?teamId=${teamId}` : ''
|
||||
}`,
|
||||
token,
|
||||
{ apiUrl }
|
||||
{ apiUrl, userAgent }
|
||||
);
|
||||
|
||||
const data = await buildsData.json();
|
||||
@@ -91,7 +97,8 @@ export default async function* checkDeploymentStatus(
|
||||
`${apiDeployments}/${deployment.id || deployment.deploymentId}${
|
||||
teamId ? `?teamId=${teamId}` : ''
|
||||
}`,
|
||||
token
|
||||
token,
|
||||
{ apiUrl, userAgent }
|
||||
);
|
||||
const deploymentUpdate = await deploymentData.json();
|
||||
|
||||
@@ -3,26 +3,22 @@ import { readdir as readRootFolder, lstatSync } from 'fs-extra';
|
||||
import readdir from 'recursive-readdir';
|
||||
import { relative, join, isAbsolute } from 'path';
|
||||
import hashes, { mapToObject } from './utils/hashes';
|
||||
import uploadAndDeploy from './upload';
|
||||
import { upload } from './upload';
|
||||
import { getNowIgnore, createDebug, parseNowJSON } from './utils';
|
||||
import { DeploymentError } from './errors';
|
||||
import {
|
||||
CreateDeploymentFunction,
|
||||
DeploymentOptions,
|
||||
NowJsonOptions,
|
||||
} from './types';
|
||||
import { NowConfig, NowClientOptions, DeploymentOptions } from './types';
|
||||
|
||||
export { EVENTS } from './utils';
|
||||
|
||||
export default function buildCreateDeployment(
|
||||
version: number
|
||||
): CreateDeploymentFunction {
|
||||
export default function buildCreateDeployment(version: number) {
|
||||
return async function* createDeployment(
|
||||
path: string | string[],
|
||||
options: DeploymentOptions = {},
|
||||
nowConfig?: NowJsonOptions
|
||||
clientOptions: NowClientOptions,
|
||||
deploymentOptions: DeploymentOptions,
|
||||
nowConfig: NowConfig = {}
|
||||
): AsyncIterableIterator<any> {
|
||||
const debug = createDebug(options.debug);
|
||||
const { path } = clientOptions;
|
||||
|
||||
const debug = createDebug(clientOptions.debug);
|
||||
const cwd = process.cwd();
|
||||
|
||||
debug('Creating deployment...');
|
||||
@@ -38,9 +34,9 @@ export default function buildCreateDeployment(
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof options.token !== 'string') {
|
||||
if (typeof clientOptions.token !== 'string') {
|
||||
debug(
|
||||
`Error: 'token' is expected to be a string. Received ${typeof options.token}`
|
||||
`Error: 'token' is expected to be a string. Received ${typeof clientOptions.token}`
|
||||
);
|
||||
|
||||
throw new DeploymentError({
|
||||
@@ -49,7 +45,8 @@ export default function buildCreateDeployment(
|
||||
});
|
||||
}
|
||||
|
||||
const isDirectory = !Array.isArray(path) && lstatSync(path).isDirectory();
|
||||
clientOptions.isDirectory =
|
||||
!Array.isArray(path) && lstatSync(path).isDirectory();
|
||||
|
||||
let rootFiles: string[];
|
||||
|
||||
@@ -69,7 +66,7 @@ export default function buildCreateDeployment(
|
||||
});
|
||||
}
|
||||
|
||||
if (isDirectory && !Array.isArray(path)) {
|
||||
if (clientOptions.isDirectory && !Array.isArray(path)) {
|
||||
debug(`Provided 'path' is a directory. Reading subpaths... `);
|
||||
rootFiles = await readRootFolder(path);
|
||||
debug(`Read ${rootFiles.length} subpaths`);
|
||||
@@ -90,7 +87,7 @@ export default function buildCreateDeployment(
|
||||
|
||||
debug('Building file tree...');
|
||||
|
||||
if (isDirectory && !Array.isArray(path)) {
|
||||
if (clientOptions.isDirectory && !Array.isArray(path)) {
|
||||
// Directory path
|
||||
const dirContents = await readdir(path, ignores);
|
||||
const relativeFileList = dirContents.map(filePath =>
|
||||
@@ -156,15 +153,14 @@ export default function buildCreateDeployment(
|
||||
// from getting confused about a deployment that renders 404.
|
||||
if (
|
||||
fileList.length === 0 ||
|
||||
fileList.every((item): boolean => {
|
||||
if (!item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const segments = item.split('/');
|
||||
|
||||
return segments[segments.length - 1].startsWith('.');
|
||||
})
|
||||
fileList.every(item =>
|
||||
item
|
||||
? item
|
||||
.split('/')
|
||||
.pop()!
|
||||
.startsWith('.')
|
||||
: true
|
||||
)
|
||||
) {
|
||||
debug(
|
||||
`Deployment path has no files (or only dotfiles). Yielding a warning event`
|
||||
@@ -181,39 +177,24 @@ export default function buildCreateDeployment(
|
||||
debug(`Yielding a 'hashes-calculated' event with ${files.size} hashes`);
|
||||
yield { type: 'hashes-calculated', payload: mapToObject(files) };
|
||||
|
||||
const {
|
||||
token,
|
||||
teamId,
|
||||
force,
|
||||
defaultName,
|
||||
debug: debug_,
|
||||
apiUrl,
|
||||
...metadata
|
||||
} = options;
|
||||
if (clientOptions.apiUrl) {
|
||||
debug(`Using provided API URL: ${clientOptions.apiUrl}`);
|
||||
}
|
||||
|
||||
if (apiUrl) {
|
||||
debug(`Using provided API URL: ${apiUrl}`);
|
||||
if (clientOptions.userAgent) {
|
||||
debug(`Using provided user agent: ${clientOptions.userAgent}`);
|
||||
}
|
||||
|
||||
debug(`Setting platform version to ${version}`);
|
||||
metadata.version = version;
|
||||
|
||||
const deploymentOpts = {
|
||||
debug: debug_,
|
||||
totalFiles: files.size,
|
||||
nowConfig,
|
||||
token,
|
||||
isDirectory,
|
||||
path,
|
||||
teamId,
|
||||
force,
|
||||
defaultName,
|
||||
metadata,
|
||||
apiUrl,
|
||||
};
|
||||
deploymentOptions.version = version;
|
||||
|
||||
debug(`Creating the deployment and starting upload...`);
|
||||
for await (const event of uploadAndDeploy(files, deploymentOpts)) {
|
||||
for await (const event of upload(
|
||||
files,
|
||||
nowConfig,
|
||||
clientOptions,
|
||||
deploymentOptions
|
||||
)) {
|
||||
debug(`Yielding a '${event.type}' event`);
|
||||
yield event;
|
||||
}
|
||||
|
||||
@@ -5,51 +5,41 @@ import {
|
||||
createDebug,
|
||||
getApiDeploymentsUrl,
|
||||
} from './utils';
|
||||
import checkDeploymentStatus from './deployment-status';
|
||||
import { checkDeploymentStatus } from './check-deployment-status';
|
||||
import { generateQueryString } from './utils/query-string';
|
||||
import { Deployment, DeploymentOptions, NowJsonOptions } from './types';
|
||||
import { isReady, isAliasAssigned } from './utils/ready-state';
|
||||
|
||||
export interface Options {
|
||||
metadata: DeploymentOptions;
|
||||
totalFiles: number;
|
||||
path: string | string[];
|
||||
token: string;
|
||||
teamId?: string;
|
||||
force?: boolean;
|
||||
isDirectory?: boolean;
|
||||
defaultName?: string;
|
||||
preflight?: boolean;
|
||||
debug?: boolean;
|
||||
nowConfig?: NowJsonOptions;
|
||||
apiUrl?: string;
|
||||
}
|
||||
import {
|
||||
Deployment,
|
||||
DeploymentOptions,
|
||||
NowConfig,
|
||||
NowClientOptions,
|
||||
} from './types';
|
||||
|
||||
async function* createDeployment(
|
||||
metadata: DeploymentOptions,
|
||||
files: Map<string, DeploymentFile>,
|
||||
options: Options,
|
||||
debug: Function
|
||||
clientOptions: NowClientOptions,
|
||||
deploymentOptions: DeploymentOptions
|
||||
): AsyncIterableIterator<{ type: string; payload: any }> {
|
||||
const preparedFiles = prepareFiles(files, options);
|
||||
|
||||
const apiDeployments = getApiDeploymentsUrl(metadata);
|
||||
const debug = createDebug(clientOptions.debug);
|
||||
const preparedFiles = prepareFiles(files, clientOptions);
|
||||
const apiDeployments = getApiDeploymentsUrl(deploymentOptions);
|
||||
|
||||
debug('Sending deployment creation API request');
|
||||
try {
|
||||
const dpl = await fetch(
|
||||
`${apiDeployments}${generateQueryString(options)}`,
|
||||
options.token,
|
||||
`${apiDeployments}${generateQueryString(clientOptions)}`,
|
||||
clientOptions.token,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
...metadata,
|
||||
...deploymentOptions,
|
||||
files: preparedFiles,
|
||||
}),
|
||||
apiUrl: options.apiUrl,
|
||||
apiUrl: clientOptions.apiUrl,
|
||||
userAgent: clientOptions.userAgent,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -85,87 +75,88 @@ async function* createDeployment(
|
||||
}
|
||||
}
|
||||
|
||||
const getDefaultName = (
|
||||
path: string | string[] | undefined,
|
||||
isDirectory: boolean | undefined,
|
||||
function getDefaultName(
|
||||
files: Map<string, DeploymentFile>,
|
||||
debug: Function
|
||||
): string => {
|
||||
clientOptions: NowClientOptions
|
||||
): string {
|
||||
const debug = createDebug(clientOptions.debug);
|
||||
const { isDirectory, path } = clientOptions;
|
||||
|
||||
if (isDirectory && typeof path === 'string') {
|
||||
debug('Provided path is a directory. Using last segment as default name');
|
||||
const segments = path.split('/');
|
||||
|
||||
return segments[segments.length - 1];
|
||||
return path.split('/').pop()!;
|
||||
} else {
|
||||
debug(
|
||||
'Provided path is not a directory. Using last segment of the first file as default name'
|
||||
);
|
||||
const filePath = Array.from(files.values())[0].names[0];
|
||||
const segments = filePath.split('/');
|
||||
|
||||
return segments[segments.length - 1];
|
||||
return filePath.split('/').pop()!;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default async function* deploy(
|
||||
export async function* deploy(
|
||||
files: Map<string, DeploymentFile>,
|
||||
options: Options
|
||||
nowConfig: NowConfig,
|
||||
clientOptions: NowClientOptions,
|
||||
deploymentOptions: DeploymentOptions
|
||||
): AsyncIterableIterator<{ type: string; payload: any }> {
|
||||
const debug = createDebug(options.debug);
|
||||
const nowJsonMetadata = options.nowConfig || {};
|
||||
delete nowJsonMetadata.github;
|
||||
delete nowJsonMetadata.scope;
|
||||
|
||||
const meta = options.metadata || {};
|
||||
const metadata = { ...nowJsonMetadata, ...meta };
|
||||
const debug = createDebug(clientOptions.debug);
|
||||
|
||||
// Check if we should default to a static deployment
|
||||
if (!metadata.version && !metadata.name) {
|
||||
metadata.version = 2;
|
||||
metadata.name =
|
||||
options.totalFiles === 1
|
||||
? 'file'
|
||||
: getDefaultName(options.path, options.isDirectory, files, debug);
|
||||
if (!deploymentOptions.version && !deploymentOptions.name) {
|
||||
deploymentOptions.version = 2;
|
||||
deploymentOptions.name =
|
||||
files.size === 1 ? 'file' : getDefaultName(files, clientOptions);
|
||||
|
||||
if (metadata.name === 'file') {
|
||||
if (deploymentOptions.name === 'file') {
|
||||
debug('Setting deployment name to "file" for single-file deployment');
|
||||
}
|
||||
}
|
||||
|
||||
if (options.totalFiles === 1 && !metadata.builds && !metadata.routes) {
|
||||
if (
|
||||
files.size === 1 &&
|
||||
!deploymentOptions.builds &&
|
||||
!deploymentOptions.routes
|
||||
) {
|
||||
debug(`Assigning '/' route for single file deployment`);
|
||||
const filePath = Array.from(files.values())[0].names[0];
|
||||
const segments = filePath.split('/');
|
||||
|
||||
metadata.routes = [
|
||||
deploymentOptions.routes = [
|
||||
{
|
||||
src: '/',
|
||||
dest: `/${segments[segments.length - 1]}`,
|
||||
dest: `/${filePath.split('/').pop()}`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (!metadata.name) {
|
||||
metadata.name =
|
||||
options.defaultName ||
|
||||
getDefaultName(options.path, options.isDirectory, files, debug);
|
||||
debug('No name provided. Defaulting to', metadata.name);
|
||||
if (!deploymentOptions.name) {
|
||||
deploymentOptions.name =
|
||||
clientOptions.defaultName || getDefaultName(files, clientOptions);
|
||||
debug('No name provided. Defaulting to', deploymentOptions.name);
|
||||
}
|
||||
|
||||
if (metadata.version === 1 && !metadata.deploymentType) {
|
||||
debug(`Setting 'type' for 1.0 deployment to '${nowJsonMetadata.type}'`);
|
||||
metadata.deploymentType = nowJsonMetadata.type;
|
||||
if (
|
||||
deploymentOptions.version === 1 &&
|
||||
!deploymentOptions.deploymentType &&
|
||||
nowConfig.type
|
||||
) {
|
||||
debug(`Setting 'type' for 1.0 deployment to '${nowConfig.type}'`);
|
||||
deploymentOptions.deploymentType = nowConfig.type.toUpperCase() as DeploymentOptions['deploymentType'];
|
||||
}
|
||||
|
||||
if (metadata.version === 1) {
|
||||
if (deploymentOptions.version === 1 && !deploymentOptions.config) {
|
||||
debug(`Writing 'config' values for 1.0 deployment`);
|
||||
const nowConfig = { ...nowJsonMetadata };
|
||||
delete nowConfig.version;
|
||||
deploymentOptions.config = { ...nowConfig };
|
||||
delete deploymentOptions.config.version;
|
||||
}
|
||||
|
||||
metadata.config = {
|
||||
...nowConfig,
|
||||
...metadata.config,
|
||||
};
|
||||
if (
|
||||
deploymentOptions.version === 1 &&
|
||||
!deploymentOptions.forceNew &&
|
||||
clientOptions.force
|
||||
) {
|
||||
debug(`Setting 'forceNew' for 1.0 deployment`);
|
||||
deploymentOptions.forceNew = clientOptions.force;
|
||||
}
|
||||
|
||||
let deployment: Deployment | undefined;
|
||||
@@ -173,10 +164,9 @@ export default async function* deploy(
|
||||
try {
|
||||
debug('Creating deployment');
|
||||
for await (const event of createDeployment(
|
||||
metadata,
|
||||
files,
|
||||
options,
|
||||
debug
|
||||
clientOptions,
|
||||
deploymentOptions
|
||||
)) {
|
||||
if (event.type === 'created') {
|
||||
debug('Deployment created');
|
||||
@@ -203,11 +193,7 @@ export default async function* deploy(
|
||||
debug('Waiting for deployment to be ready...');
|
||||
for await (const event of checkDeploymentStatus(
|
||||
deployment,
|
||||
options.token,
|
||||
metadata.version,
|
||||
options.teamId,
|
||||
debug,
|
||||
options.apiUrl
|
||||
clientOptions
|
||||
)) {
|
||||
yield event;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
import { BuilderFunctions } from '@now/build-utils';
|
||||
import { Builder, BuilderFunctions } from '@now/build-utils';
|
||||
import { NowHeader, Route, NowRedirect, NowRewrite } from '@now/routing-utils';
|
||||
|
||||
export interface Route {
|
||||
src: string;
|
||||
dest: string;
|
||||
headers?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
status?: number;
|
||||
methods?: string[];
|
||||
export interface Dictionary<T> {
|
||||
[key: string]: T;
|
||||
}
|
||||
|
||||
export interface Build {
|
||||
src: string;
|
||||
use: string;
|
||||
/**
|
||||
* Options for `now-client` or
|
||||
* properties that should not
|
||||
* be part of the payload.
|
||||
*/
|
||||
export interface NowClientOptions {
|
||||
token: string;
|
||||
path: string | string[];
|
||||
debug?: boolean;
|
||||
teamId?: string;
|
||||
apiUrl?: string;
|
||||
force?: boolean;
|
||||
userAgent?: string;
|
||||
defaultName?: string;
|
||||
isDirectory?: boolean;
|
||||
}
|
||||
|
||||
export interface Deployment {
|
||||
@@ -20,13 +27,11 @@ export interface Deployment {
|
||||
deploymentId?: string;
|
||||
url: string;
|
||||
name: string;
|
||||
meta: {
|
||||
[key: string]: string | number | boolean;
|
||||
};
|
||||
meta: Dictionary<string | number | boolean>;
|
||||
version: number;
|
||||
regions: string[];
|
||||
routes: Route[];
|
||||
builds?: Build[];
|
||||
builds?: Builder[];
|
||||
functions?: BuilderFunctions;
|
||||
plan: string;
|
||||
public: boolean;
|
||||
@@ -47,13 +52,9 @@ export interface Deployment {
|
||||
| 'ERROR';
|
||||
createdAt: string;
|
||||
createdIn: string;
|
||||
env: {
|
||||
[key: string]: string;
|
||||
};
|
||||
env: Dictionary<string>;
|
||||
build: {
|
||||
env: {
|
||||
[key: string]: string;
|
||||
};
|
||||
env: Dictionary<string>;
|
||||
};
|
||||
target: string;
|
||||
alias: string[];
|
||||
@@ -91,51 +92,69 @@ export interface DeploymentGithubData {
|
||||
autoJobCancelation: boolean;
|
||||
}
|
||||
|
||||
export interface DeploymentOptions {
|
||||
interface LegacyNowConfig {
|
||||
type?: string;
|
||||
aliases?: string | string[];
|
||||
}
|
||||
|
||||
export interface NowConfig extends LegacyNowConfig {
|
||||
name?: string;
|
||||
version?: number;
|
||||
env?: Dictionary<string>;
|
||||
build?: {
|
||||
env?: Dictionary<string>;
|
||||
};
|
||||
builds?: Builder[];
|
||||
routes?: Route[];
|
||||
files?: string[];
|
||||
cleanUrls?: boolean;
|
||||
rewrites?: NowRewrite[];
|
||||
redirects?: NowRedirect[];
|
||||
headers?: NowHeader[];
|
||||
trailingSlash?: boolean;
|
||||
functions?: BuilderFunctions;
|
||||
github?: DeploymentGithubData;
|
||||
scope?: string;
|
||||
alias?: string | string[];
|
||||
}
|
||||
|
||||
interface LegacyDeploymentOptions {
|
||||
project?: string;
|
||||
forceNew?: boolean;
|
||||
description?: string;
|
||||
registryAuthToken?: string;
|
||||
engines?: Dictionary<string>;
|
||||
sessionAffinity?: 'ip' | 'key' | 'random';
|
||||
deploymentType?: 'NPM' | 'STATIC' | 'DOCKER';
|
||||
scale?: Dictionary<{
|
||||
min?: number;
|
||||
max?: number | 'auto';
|
||||
}>;
|
||||
limits?: {
|
||||
duration?: number;
|
||||
maxConcurrentReqs?: number;
|
||||
timeout?: number;
|
||||
};
|
||||
// Can't be NowConfig, since we don't
|
||||
// include all legacy types here
|
||||
config?: Dictionary<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options that will be sent to the API.
|
||||
*/
|
||||
export interface DeploymentOptions extends LegacyDeploymentOptions {
|
||||
version?: number;
|
||||
regions?: string[];
|
||||
routes?: Route[];
|
||||
builds?: Build[];
|
||||
builds?: Builder[];
|
||||
functions?: BuilderFunctions;
|
||||
env?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
env?: Dictionary<string>;
|
||||
build?: {
|
||||
env: {
|
||||
[key: string]: string;
|
||||
};
|
||||
env: Dictionary<string>;
|
||||
};
|
||||
target?: string;
|
||||
token?: string | null;
|
||||
teamId?: string;
|
||||
force?: boolean;
|
||||
name?: string;
|
||||
defaultName?: string;
|
||||
isDirectory?: boolean;
|
||||
path?: string | string[];
|
||||
github?: DeploymentGithubData;
|
||||
scope?: string;
|
||||
public?: boolean;
|
||||
forceNew?: boolean;
|
||||
deploymentType?: 'NPM' | 'STATIC' | 'DOCKER';
|
||||
registryAuthToken?: string;
|
||||
engines?: { [key: string]: string };
|
||||
sessionAffinity?: 'ip' | 'random';
|
||||
config?: { [key: string]: any };
|
||||
debug?: boolean;
|
||||
apiUrl?: string;
|
||||
meta?: Dictionary<string>;
|
||||
}
|
||||
|
||||
export interface NowJsonOptions {
|
||||
github?: DeploymentGithubData;
|
||||
scope?: string;
|
||||
type?: 'NPM' | 'STATIC' | 'DOCKER';
|
||||
version?: number;
|
||||
files?: string[];
|
||||
}
|
||||
|
||||
export type CreateDeploymentFunction = (
|
||||
path: string | string[],
|
||||
options?: DeploymentOptions,
|
||||
nowConfig?: NowJsonOptions
|
||||
) => AsyncIterableIterator<any>;
|
||||
|
||||
@@ -4,8 +4,9 @@ import retry from 'async-retry';
|
||||
import { Sema } from 'async-sema';
|
||||
import { DeploymentFile } from './utils/hashes';
|
||||
import { fetch, API_FILES, createDebug } from './utils';
|
||||
import { DeploymentError } from '.';
|
||||
import deploy, { Options } from './deploy';
|
||||
import { DeploymentError } from './errors';
|
||||
import { deploy } from './deploy';
|
||||
import { NowConfig, NowClientOptions, DeploymentOptions } from './types';
|
||||
|
||||
const isClientNetworkError = (err: Error | DeploymentError) => {
|
||||
if (err.message) {
|
||||
@@ -24,12 +25,14 @@ const isClientNetworkError = (err: Error | DeploymentError) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
export default async function* upload(
|
||||
export async function* upload(
|
||||
files: Map<string, DeploymentFile>,
|
||||
options: Options
|
||||
nowConfig: NowConfig,
|
||||
clientOptions: NowClientOptions,
|
||||
deploymentOptions: DeploymentOptions
|
||||
): AsyncIterableIterator<any> {
|
||||
const { token, teamId, debug: isDebug, apiUrl } = options;
|
||||
const debug = createDebug(isDebug);
|
||||
const { token, teamId, apiUrl, userAgent } = clientOptions;
|
||||
const debug = createDebug(clientOptions.debug);
|
||||
|
||||
if (!files && !token && !teamId) {
|
||||
debug(`Neither 'files', 'token' nor 'teamId are present. Exiting`);
|
||||
@@ -40,7 +43,12 @@ export default async function* upload(
|
||||
|
||||
debug('Determining necessary files for upload...');
|
||||
|
||||
for await (const event of deploy(files, options)) {
|
||||
for await (const event of deploy(
|
||||
files,
|
||||
nowConfig,
|
||||
clientOptions,
|
||||
deploymentOptions
|
||||
)) {
|
||||
if (event.type === 'error') {
|
||||
if (event.payload.code === 'missing_files') {
|
||||
missingFiles = event.payload.missing;
|
||||
@@ -105,8 +113,9 @@ export default async function* upload(
|
||||
body: stream,
|
||||
teamId,
|
||||
apiUrl,
|
||||
userAgent,
|
||||
},
|
||||
isDebug
|
||||
clientOptions.debug
|
||||
);
|
||||
|
||||
if (res.status === 200) {
|
||||
@@ -185,7 +194,12 @@ export default async function* upload(
|
||||
|
||||
try {
|
||||
debug('Starting deployment creation');
|
||||
for await (const event of deploy(files, options)) {
|
||||
for await (const event of deploy(
|
||||
files,
|
||||
nowConfig,
|
||||
clientOptions,
|
||||
deploymentOptions
|
||||
)) {
|
||||
if (event.type === 'alias-assigned') {
|
||||
debug('Deployment is ready');
|
||||
return yield event;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { DeploymentFile } from './hashes';
|
||||
import { parse as parseUrl } from 'url';
|
||||
import fetch_ from 'node-fetch';
|
||||
import fetch_, { RequestInit } from 'node-fetch';
|
||||
import { join, sep } from 'path';
|
||||
import qs from 'querystring';
|
||||
import ignore from 'ignore';
|
||||
import { pkgVersion } from '../pkg';
|
||||
import { Options } from '../deploy';
|
||||
import { NowJsonOptions, DeploymentOptions } from '../types';
|
||||
import { NowClientOptions, DeploymentOptions, NowConfig } from '../types';
|
||||
import { Sema } from 'async-sema';
|
||||
import { readFile } from 'fs-extra';
|
||||
const semaphore = new Sema(10);
|
||||
@@ -44,7 +43,7 @@ export function getApiDeploymentsUrl(
|
||||
return '/v11/now/deployments';
|
||||
}
|
||||
|
||||
export async function parseNowJSON(filePath?: string): Promise<NowJsonOptions> {
|
||||
export async function parseNowJSON(filePath?: string): Promise<NowConfig> {
|
||||
if (!filePath) {
|
||||
return {};
|
||||
}
|
||||
@@ -111,10 +110,18 @@ export async function getNowIgnore(path: string | string[]): Promise<any> {
|
||||
return { ig, ignores };
|
||||
}
|
||||
|
||||
interface FetchOpts extends RequestInit {
|
||||
apiUrl?: string;
|
||||
method?: string;
|
||||
teamId?: string;
|
||||
headers?: { [key: string]: any };
|
||||
userAgent?: string;
|
||||
}
|
||||
|
||||
export const fetch = async (
|
||||
url: string,
|
||||
token: string,
|
||||
opts: any = {},
|
||||
opts: FetchOpts = {},
|
||||
debugEnabled?: boolean
|
||||
): Promise<any> => {
|
||||
semaphore.acquire();
|
||||
@@ -133,11 +140,14 @@ export const fetch = async (
|
||||
delete opts.teamId;
|
||||
}
|
||||
|
||||
const userAgent = opts.userAgent || `now-client-v${pkgVersion}`;
|
||||
delete opts.userAgent;
|
||||
|
||||
opts.headers = {
|
||||
...opts.headers,
|
||||
authorization: `Bearer ${token}`,
|
||||
accept: 'application/json',
|
||||
'user-agent': `now-client-v${pkgVersion}`,
|
||||
'user-agent': userAgent,
|
||||
};
|
||||
|
||||
debug(`${opts.method || 'GET'} ${url}`);
|
||||
@@ -160,7 +170,7 @@ const isWin = process.platform.includes('win');
|
||||
|
||||
export const prepareFiles = (
|
||||
files: Map<string, DeploymentFile>,
|
||||
options: Options
|
||||
clientOptions: NowClientOptions
|
||||
): PreparedFile[] => {
|
||||
const preparedFiles = [...files.keys()].reduce(
|
||||
(acc: PreparedFile[], sha: string): PreparedFile[] => {
|
||||
@@ -171,10 +181,10 @@ export const prepareFiles = (
|
||||
for (const name of file.names) {
|
||||
let fileName: string;
|
||||
|
||||
if (options.isDirectory) {
|
||||
if (clientOptions.isDirectory) {
|
||||
// Directory
|
||||
fileName = options.path
|
||||
? name.substring(options.path.length + 1)
|
||||
fileName = clientOptions.path
|
||||
? name.substring(clientOptions.path.length + 1)
|
||||
: name;
|
||||
} else {
|
||||
// Array of files or single file
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { Options } from '../deploy';
|
||||
import { URLSearchParams } from 'url';
|
||||
import { NowClientOptions } from '../types';
|
||||
|
||||
export const generateQueryString = (options: Options): string => {
|
||||
if (options.force && options.teamId) {
|
||||
return `?teamId=${options.teamId}&forceNew=1`;
|
||||
} else if (options.teamId) {
|
||||
return `?teamId=${options.teamId}`;
|
||||
} else if (options.force) {
|
||||
return `?forceNew=1`;
|
||||
export function generateQueryString(clientOptions: NowClientOptions): string {
|
||||
const options = new URLSearchParams();
|
||||
|
||||
if (clientOptions.teamId) {
|
||||
options.set('teamId', clientOptions.teamId);
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
if (clientOptions.force) {
|
||||
options.set('forceNew', '1');
|
||||
}
|
||||
|
||||
return Array.from(options.entries()).length ? `?${options.toString()}` : '';
|
||||
}
|
||||
|
||||
@@ -28,10 +28,12 @@ describe('create v2 deployment', () => {
|
||||
|
||||
it('will display an empty deployment warning', async () => {
|
||||
for await (const event of createDeployment(
|
||||
path.resolve(__dirname, 'fixtures', 'v2'),
|
||||
{
|
||||
token,
|
||||
name: 'now-client-tests-v2',
|
||||
path: path.resolve(__dirname, 'fixtures', 'v2'),
|
||||
},
|
||||
{
|
||||
name: 'now-clien-tests-v2',
|
||||
}
|
||||
)) {
|
||||
if (event.type === 'warning') {
|
||||
@@ -47,9 +49,11 @@ describe('create v2 deployment', () => {
|
||||
|
||||
it('will report correct file count event', async () => {
|
||||
for await (const event of createDeployment(
|
||||
path.resolve(__dirname, 'fixtures', 'v2'),
|
||||
{
|
||||
token,
|
||||
path: path.resolve(__dirname, 'fixtures', 'v2'),
|
||||
},
|
||||
{
|
||||
name: 'now-client-tests-v2',
|
||||
}
|
||||
)) {
|
||||
@@ -66,9 +70,11 @@ describe('create v2 deployment', () => {
|
||||
|
||||
it('will create a v2 deployment', async () => {
|
||||
for await (const event of createDeployment(
|
||||
path.resolve(__dirname, 'fixtures', 'v2'),
|
||||
{
|
||||
token,
|
||||
path: path.resolve(__dirname, 'fixtures', 'v2'),
|
||||
},
|
||||
{
|
||||
name: 'now-client-tests-v2',
|
||||
}
|
||||
)) {
|
||||
@@ -82,9 +88,11 @@ describe('create v2 deployment', () => {
|
||||
|
||||
it('will create a v2 deployment with correct file permissions', async () => {
|
||||
for await (const event of createDeployment(
|
||||
path.resolve(__dirname, 'fixtures', 'v2-file-permissions'),
|
||||
{
|
||||
token,
|
||||
path: path.resolve(__dirname, 'fixtures', 'v2-file-permissions'),
|
||||
},
|
||||
{
|
||||
name: 'now-client-tests-v2',
|
||||
}
|
||||
)) {
|
||||
@@ -104,10 +112,12 @@ describe('create v2 deployment', () => {
|
||||
|
||||
it('will create a v2 deployment and ignore files specified in .nowignore', async () => {
|
||||
for await (const event of createDeployment(
|
||||
path.resolve(__dirname, 'fixtures', 'nowignore'),
|
||||
{
|
||||
token,
|
||||
name: 'now-client-tests-v2-ignore',
|
||||
path: path.resolve(__dirname, 'fixtures', 'nowignore'),
|
||||
},
|
||||
{
|
||||
name: 'now-client-tests-v2',
|
||||
}
|
||||
)) {
|
||||
if (event.type === 'ready') {
|
||||
|
||||
@@ -29,9 +29,11 @@ describe('create v1 deployment', () => {
|
||||
|
||||
it('will create a v1 static deployment', async () => {
|
||||
for await (const event of createLegacyDeployment(
|
||||
path.resolve(__dirname, 'fixtures', 'v1', 'static'),
|
||||
{
|
||||
token,
|
||||
path: path.resolve(__dirname, 'fixtures', 'v1', 'static'),
|
||||
},
|
||||
{
|
||||
name: 'now-client-tests-v1-static',
|
||||
}
|
||||
)) {
|
||||
@@ -47,9 +49,11 @@ describe('create v1 deployment', () => {
|
||||
|
||||
it('will create a v1 npm deployment', async () => {
|
||||
for await (const event of createLegacyDeployment(
|
||||
path.resolve(__dirname, 'fixtures', 'v1', 'npm'),
|
||||
{
|
||||
token,
|
||||
path: path.resolve(__dirname, 'fixtures', 'v1', 'npm'),
|
||||
},
|
||||
{
|
||||
name: 'now-client-tests-v1-npm',
|
||||
}
|
||||
)) {
|
||||
@@ -65,9 +69,11 @@ describe('create v1 deployment', () => {
|
||||
|
||||
it('will create a v1 Docker deployment', async () => {
|
||||
for await (const event of createLegacyDeployment(
|
||||
path.resolve(__dirname, 'fixtures', 'v1', 'docker'),
|
||||
{
|
||||
token,
|
||||
path: path.resolve(__dirname, 'fixtures', 'v1', 'docker'),
|
||||
},
|
||||
{
|
||||
name: 'now-client-tests-v1-docker',
|
||||
}
|
||||
)) {
|
||||
|
||||
@@ -10,10 +10,15 @@ describe('path handling', () => {
|
||||
|
||||
it('will fali with a relative path', async () => {
|
||||
try {
|
||||
await createDeployment('./fixtures/v2/now.json', {
|
||||
token,
|
||||
name: 'now-client-tests-v2',
|
||||
});
|
||||
await createDeployment(
|
||||
{
|
||||
token,
|
||||
path: './fixtures/v2/now.json',
|
||||
},
|
||||
{
|
||||
name: 'now-client-tests-v2',
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.code).toEqual('invalid_path');
|
||||
}
|
||||
@@ -21,10 +26,15 @@ describe('path handling', () => {
|
||||
|
||||
it('will fali with an array of relative paths', async () => {
|
||||
try {
|
||||
await createDeployment(['./fixtures/v2/now.json'], {
|
||||
token,
|
||||
name: 'now-client-tests-v2',
|
||||
});
|
||||
await createDeployment(
|
||||
{
|
||||
token,
|
||||
path: ['./fixtures/v2/now.json'],
|
||||
},
|
||||
{
|
||||
name: 'now-client-tests-v2',
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
expect(e.code).toEqual('invalid_path');
|
||||
}
|
||||
|
||||
@@ -70,7 +70,6 @@ Learn more: https://github.com/golang/go/wiki/Modules
|
||||
`);
|
||||
}
|
||||
|
||||
debug('Downloading user files...');
|
||||
const entrypointArr = entrypoint.split(sep);
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/go",
|
||||
"version": "1.0.1-canary.0",
|
||||
"version": "1.0.1-canary.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://zeit.co/docs/runtimes#official-runtimes/go",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/next",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.2-canary.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://zeit.co/docs/runtimes#official-runtimes/next-js",
|
||||
|
||||
@@ -10,25 +10,15 @@ process.on('unhandledRejection', err => {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
async function main(cwd: string) {
|
||||
const next = require(resolveFrom(cwd, 'next'));
|
||||
const app = next({ dev: true, dir: cwd });
|
||||
process.once('message', async ({ dir, runtimeEnv }) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const next = require(resolveFrom(dir, 'next'));
|
||||
const app = next({ dev: true, dir });
|
||||
const handler = app.getRequestHandler();
|
||||
|
||||
const openPort = await getPort({
|
||||
port: [5000, 4000],
|
||||
});
|
||||
|
||||
const [openPort] = await Promise.all([getPort(), app.prepare()]);
|
||||
const url = `http://localhost:${openPort}`;
|
||||
|
||||
// Prepare for incoming requests
|
||||
await app.prepare();
|
||||
|
||||
// The runtime env vars are passed in to `argv[2]`
|
||||
// as a base64-encoded JSON string
|
||||
const runtimeEnv = JSON.parse(
|
||||
Buffer.from(process.argv[2], 'base64').toString()
|
||||
);
|
||||
syncEnvVars(process.env, process.env, runtimeEnv);
|
||||
|
||||
createServer((req, res) => {
|
||||
@@ -39,6 +29,4 @@ async function main(cwd: string) {
|
||||
process.send(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
main(process.cwd());
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { ChildProcess, fork } from 'child_process';
|
||||
import url from 'url'
|
||||
import {
|
||||
pathExists,
|
||||
readFile,
|
||||
unlink as unlinkFile,
|
||||
writeFile,
|
||||
lstatSync,
|
||||
} from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
@@ -60,8 +60,8 @@ import {
|
||||
|
||||
import {
|
||||
convertRedirects,
|
||||
convertRewrites
|
||||
} from '@now/routing-utils/dist/superstatic'
|
||||
convertRewrites,
|
||||
} from '@now/routing-utils/dist/superstatic';
|
||||
|
||||
interface BuildParamsMeta {
|
||||
isDev: boolean | undefined;
|
||||
@@ -77,7 +77,7 @@ interface BuildParamsType extends BuildOptions {
|
||||
}
|
||||
|
||||
export const version = 2;
|
||||
|
||||
const htmlContentType = 'text/html; charset=utf-8';
|
||||
const nowDevChildProcesses = new Set<ChildProcess>();
|
||||
|
||||
['SIGINT', 'SIGTERM'].forEach(signal => {
|
||||
@@ -163,24 +163,20 @@ const name = '[@now/next]';
|
||||
const urls: stringMap = {};
|
||||
|
||||
function startDevServer(entryPath: string, runtimeEnv: EnvConfig) {
|
||||
// The runtime env vars are encoded and passed in as `argv[2]`, so that the
|
||||
// dev-server process can replace them onto `process.env` after the Next.js
|
||||
// "prepare" step
|
||||
const encodedEnv = Buffer.from(JSON.stringify(runtimeEnv)).toString('base64');
|
||||
|
||||
// `env` is omitted since that
|
||||
// makes it default to `process.env`
|
||||
const forked = fork(path.join(__dirname, 'dev-server.js'), [encodedEnv], {
|
||||
// `env` is omitted since that makes it default to `process.env`
|
||||
const forked = fork(path.join(__dirname, 'dev-server.js'), [], {
|
||||
cwd: entryPath,
|
||||
execArgv: [],
|
||||
});
|
||||
|
||||
const getUrl = () =>
|
||||
new Promise<string>((resolve, reject) => {
|
||||
forked.on('message', resolve);
|
||||
forked.on('error', reject);
|
||||
forked.once('message', resolve);
|
||||
forked.once('error', reject);
|
||||
});
|
||||
|
||||
forked.send({ dir: entryPath, runtimeEnv });
|
||||
|
||||
return { forked, getUrl };
|
||||
}
|
||||
|
||||
@@ -202,7 +198,6 @@ export const build = async ({
|
||||
const entryPath = path.join(workPath, entryDirectory);
|
||||
const dotNextStatic = path.join(entryPath, '.next/static');
|
||||
|
||||
debug(`${name} Downloading user files...`);
|
||||
await download(files, workPath, meta);
|
||||
|
||||
const pkg = await readPackageJson(entryPath);
|
||||
@@ -353,7 +348,6 @@ export const build = async ({
|
||||
await unlinkFile(path.join(entryPath, '.npmrc'));
|
||||
}
|
||||
|
||||
const exportedPageRoutes: Route[] = [];
|
||||
const lambdas: { [key: string]: Lambda } = {};
|
||||
const prerenders: { [key: string]: Prerender | FileFsRef } = {};
|
||||
const staticPages: { [key: string]: FileFsRef } = {};
|
||||
@@ -484,18 +478,14 @@ export const build = async ({
|
||||
return;
|
||||
}
|
||||
|
||||
const staticRoute = path.join(entryDirectory, page);
|
||||
const staticRoute = path.join(entryDirectory, pathname);
|
||||
staticPages[staticRoute] = staticPageFiles[page];
|
||||
staticPages[staticRoute].contentType = htmlContentType;
|
||||
|
||||
if (isDynamicRoute(pathname)) {
|
||||
dynamicPages.push(routeName);
|
||||
return;
|
||||
}
|
||||
|
||||
exportedPageRoutes.push({
|
||||
src: `^${path.join('/', entryDirectory, pathname)}$`,
|
||||
dest: path.join('/', staticRoute),
|
||||
});
|
||||
});
|
||||
|
||||
const pageKeys = Object.keys(pages);
|
||||
@@ -589,9 +579,11 @@ export const build = async ({
|
||||
// Initial files are manually added to the lambda later
|
||||
return;
|
||||
}
|
||||
const { mode } = lstatSync(path.join(workPath, file));
|
||||
|
||||
files[file] = new FileFsRef({
|
||||
fsPath: path.join(workPath, file),
|
||||
mode,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -743,14 +735,9 @@ export const build = async ({
|
||||
if (htmlFsRef == null || jsonFsRef == null) {
|
||||
throw new Error('invariant: htmlFsRef != null && jsonFsRef != null');
|
||||
}
|
||||
|
||||
const outputPathPageHtml = outputPathPage.concat('.html');
|
||||
prerenders[outputPathPageHtml] = htmlFsRef;
|
||||
htmlFsRef.contentType = htmlContentType;
|
||||
prerenders[outputPathPage] = htmlFsRef;
|
||||
prerenders[outputPathData] = jsonFsRef;
|
||||
exportedPageRoutes.push({
|
||||
src: path.posix.join('/', outputPathPage),
|
||||
dest: outputPathPageHtml,
|
||||
});
|
||||
} else {
|
||||
const lambda = lambdas[outputSrcPathPage];
|
||||
if (lambda == null) {
|
||||
@@ -832,7 +819,7 @@ export const build = async ({
|
||||
let dynamicPrefix = path.join('/', entryDirectory);
|
||||
dynamicPrefix = dynamicPrefix === '/' ? '' : dynamicPrefix;
|
||||
|
||||
const routesManifest = await getRoutesManifest(entryPath, realNextVersion)
|
||||
const routesManifest = await getRoutesManifest(entryPath, realNextVersion);
|
||||
|
||||
const dynamicRoutes = await getDynamicRoutes(
|
||||
entryPath,
|
||||
@@ -842,25 +829,20 @@ export const build = async ({
|
||||
routesManifest
|
||||
).then(arr =>
|
||||
arr.map(route => {
|
||||
// make sure .html is added to dest for now until
|
||||
// outputting static files to clean routes is available
|
||||
if (staticPages[`${route.dest}.html`.substr(1)]) {
|
||||
route.dest = `${route.dest}.html`;
|
||||
}
|
||||
route.src = route.src.replace('^', `^${dynamicPrefix}`);
|
||||
return route;
|
||||
})
|
||||
);
|
||||
|
||||
const rewrites: Route[] = []
|
||||
const redirects: Route[] = []
|
||||
const rewrites: Route[] = [];
|
||||
const redirects: Route[] = [];
|
||||
|
||||
if (routesManifest) {
|
||||
switch(routesManifest.version) {
|
||||
switch (routesManifest.version) {
|
||||
case 1: {
|
||||
redirects.push(...convertRedirects(routesManifest.redirects))
|
||||
rewrites.push(...convertRewrites(routesManifest.rewrites))
|
||||
break
|
||||
redirects.push(...convertRedirects(routesManifest.redirects));
|
||||
rewrites.push(...convertRewrites(routesManifest.rewrites));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// update MIN_ROUTES_MANIFEST_VERSION in ./utils.ts
|
||||
@@ -872,24 +854,6 @@ export const build = async ({
|
||||
}
|
||||
}
|
||||
|
||||
const topRoutes = [
|
||||
// Before we handle static files we need to set proper caching headers
|
||||
{
|
||||
// This ensures we only match known emitted-by-Next.js files and not
|
||||
// user-emitted files which may be missing a hash in their filename.
|
||||
src: path.join(
|
||||
'/',
|
||||
entryDirectory,
|
||||
'_next/static/(?:[^/]+/pages|chunks|runtime|css|media)/.+'
|
||||
),
|
||||
// Next.js assets contain a hash or entropy in their filenames, so they
|
||||
// are guaranteed to be unique and cacheable indefinitely.
|
||||
headers: { 'cache-control': 'public,max-age=31536000,immutable' },
|
||||
continue: true,
|
||||
},
|
||||
{ src: path.join('/', entryDirectory, '_next(?!/data(?:/|$))(?:/.*)?') },
|
||||
]
|
||||
|
||||
return {
|
||||
output: {
|
||||
...publicDirectoryFiles,
|
||||
@@ -901,17 +865,27 @@ export const build = async ({
|
||||
...staticDirectoryFiles,
|
||||
},
|
||||
routes: [
|
||||
...topRoutes,
|
||||
// redirects take the highest priority
|
||||
...redirects,
|
||||
...rewrites,
|
||||
// we need to re-apply the routes above rewrites in-case the are
|
||||
// rewriting to one of those routes
|
||||
...topRoutes,
|
||||
// Static exported pages (.html rewrites)
|
||||
...exportedPageRoutes,
|
||||
// Before we handle static files we need to set proper caching headers
|
||||
{
|
||||
// This ensures we only match known emitted-by-Next.js files and not
|
||||
// user-emitted files which may be missing a hash in their filename.
|
||||
src: path.join(
|
||||
'/',
|
||||
entryDirectory,
|
||||
'_next/static/(?:[^/]+/pages|chunks|runtime|css|media)/.+'
|
||||
),
|
||||
// Next.js assets contain a hash or entropy in their filenames, so they
|
||||
// are guaranteed to be unique and cacheable indefinitely.
|
||||
headers: { 'cache-control': 'public,max-age=31536000,immutable' },
|
||||
continue: true,
|
||||
},
|
||||
{ src: path.join('/', entryDirectory, '_next(?!/data(?:/|$))(?:/.*)?') },
|
||||
// Next.js page lambdas, `static/` folder, reserved assets, and `public/`
|
||||
// folder
|
||||
{ handle: 'filesystem' },
|
||||
...rewrites,
|
||||
// Dynamic routes
|
||||
...dynamicRoutes,
|
||||
...dynamicDataRoutes,
|
||||
@@ -934,7 +908,7 @@ export const build = async ({
|
||||
export const prepareCache = async ({
|
||||
workPath,
|
||||
entrypoint,
|
||||
}: PrepareCacheOptions) => {
|
||||
}: PrepareCacheOptions): Promise<Files> => {
|
||||
debug('Preparing cache...');
|
||||
const entryDirectory = path.dirname(entrypoint);
|
||||
const entryPath = path.join(workPath, entryDirectory);
|
||||
@@ -954,8 +928,6 @@ export const prepareCache = async ({
|
||||
const cache = {
|
||||
...(await glob(path.join(cacheEntrypoint, 'node_modules/**'), workPath)),
|
||||
...(await glob(path.join(cacheEntrypoint, '.next/cache/**'), workPath)),
|
||||
...(await glob(path.join(cacheEntrypoint, 'package-lock.json'), workPath)),
|
||||
...(await glob(path.join(cacheEntrypoint, 'yarn.lock'), workPath)),
|
||||
};
|
||||
debug('Cache file manifest produced');
|
||||
return cache;
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
streamToBuffer,
|
||||
Lambda,
|
||||
Route,
|
||||
isSymbolicLink,
|
||||
} from '@now/build-utils';
|
||||
|
||||
type stringMap = { [key: string]: string };
|
||||
@@ -293,37 +294,36 @@ async function getRoutes(
|
||||
}
|
||||
|
||||
export type Rewrite = {
|
||||
source: string,
|
||||
destination: string,
|
||||
}
|
||||
source: string;
|
||||
destination: string;
|
||||
};
|
||||
|
||||
export type Redirect = Rewrite & {
|
||||
statusCode?: number
|
||||
}
|
||||
statusCode?: number;
|
||||
};
|
||||
|
||||
type RoutesManifestRegex = {
|
||||
regex: string,
|
||||
regexKeys: string[]
|
||||
}
|
||||
regex: string;
|
||||
regexKeys: string[];
|
||||
};
|
||||
|
||||
export type RoutesManifest = {
|
||||
redirects: (Redirect & RoutesManifestRegex)[],
|
||||
rewrites: (Rewrite & RoutesManifestRegex)[],
|
||||
redirects: (Redirect & RoutesManifestRegex)[];
|
||||
rewrites: (Rewrite & RoutesManifestRegex)[];
|
||||
dynamicRoutes: {
|
||||
page: string,
|
||||
regex: string,
|
||||
}[],
|
||||
version: number
|
||||
}
|
||||
page: string;
|
||||
regex: string;
|
||||
}[];
|
||||
version: number;
|
||||
};
|
||||
|
||||
export async function getRoutesManifest(
|
||||
entryPath: string,
|
||||
nextVersion?: string,
|
||||
): Promise< RoutesManifest | undefined> {
|
||||
const shouldHaveManifest = (
|
||||
nextVersion && semver.gte(nextVersion, '9.1.4-canary.0')
|
||||
)
|
||||
if (!shouldHaveManifest) return
|
||||
nextVersion?: string
|
||||
): Promise<RoutesManifest | undefined> {
|
||||
const shouldHaveManifest =
|
||||
nextVersion && semver.gte(nextVersion, '9.1.4-canary.0');
|
||||
if (!shouldHaveManifest) return;
|
||||
|
||||
const pathRoutesManifest = path.join(
|
||||
entryPath,
|
||||
@@ -338,12 +338,13 @@ export async function getRoutesManifest(
|
||||
if (shouldHaveManifest && !hasRoutesManifest) {
|
||||
throw new Error(
|
||||
`A routes-manifest.json couldn't be found. This could be due to a failure during the build`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const routesManifest: RoutesManifest = require(pathRoutesManifest)
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const routesManifest: RoutesManifest = require(pathRoutesManifest);
|
||||
|
||||
return routesManifest
|
||||
return routesManifest;
|
||||
}
|
||||
|
||||
export async function getDynamicRoutes(
|
||||
@@ -455,11 +456,20 @@ function syncEnvVars(base: EnvConfig, removeEnv: EnvConfig, addEnv: EnvConfig) {
|
||||
export const ExperimentalTraceVersion = `9.0.4-canary.1`;
|
||||
|
||||
export type PseudoLayer = {
|
||||
[fileName: string]: {
|
||||
crc32: number;
|
||||
compBuffer: Buffer;
|
||||
uncompressedSize: number;
|
||||
};
|
||||
[fileName: string]: PseudoFile | PseudoSymbolicLink;
|
||||
};
|
||||
|
||||
export type PseudoFile = {
|
||||
isSymlink: false;
|
||||
crc32: number;
|
||||
compBuffer: Buffer;
|
||||
uncompressedSize: number;
|
||||
};
|
||||
|
||||
export type PseudoSymbolicLink = {
|
||||
isSymlink: true;
|
||||
file: FileFsRef;
|
||||
symlinkTarget: string;
|
||||
};
|
||||
|
||||
const compressBuffer = (buf: Buffer): Promise<Buffer> => {
|
||||
@@ -482,13 +492,22 @@ export async function createPseudoLayer(files: {
|
||||
|
||||
for (const fileName of Object.keys(files)) {
|
||||
const file = files[fileName];
|
||||
const origBuffer = await streamToBuffer(file.toStream());
|
||||
const compBuffer = await compressBuffer(origBuffer);
|
||||
pseudoLayer[fileName] = {
|
||||
compBuffer,
|
||||
crc32: crc32.unsigned(origBuffer),
|
||||
uncompressedSize: origBuffer.byteLength,
|
||||
};
|
||||
|
||||
if (isSymbolicLink(file.mode)) {
|
||||
pseudoLayer[fileName] = {
|
||||
file,
|
||||
isSymlink: true,
|
||||
symlinkTarget: await fs.readlink(file.fsPath),
|
||||
} as PseudoSymbolicLink;
|
||||
} else {
|
||||
const origBuffer = await streamToBuffer(file.toStream());
|
||||
const compBuffer = await compressBuffer(origBuffer);
|
||||
pseudoLayer[fileName] = {
|
||||
compBuffer,
|
||||
crc32: crc32.unsigned(origBuffer),
|
||||
uncompressedSize: origBuffer.byteLength,
|
||||
} as PseudoFile;
|
||||
}
|
||||
}
|
||||
|
||||
return pseudoLayer;
|
||||
@@ -521,10 +540,31 @@ export async function createLambdaFromPseudoLayers({
|
||||
const zipFile = new ZipFile();
|
||||
const addedFiles = new Set();
|
||||
|
||||
const names = Object.keys(files).sort();
|
||||
const symlinkTargets = new Map<string, string>();
|
||||
|
||||
for (const name of names) {
|
||||
const file = files[name];
|
||||
if (file.mode && isSymbolicLink(file.mode) && file.type === 'FileFsRef') {
|
||||
const symlinkTarget = await fs.readlink((file as FileFsRef).fsPath);
|
||||
symlinkTargets.set(name, symlinkTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// apply pseudo layers (already compressed objects)
|
||||
for (const layer of layers) {
|
||||
for (const seedKey of Object.keys(layer)) {
|
||||
const { compBuffer, crc32, uncompressedSize } = layer[seedKey];
|
||||
const item = layer[seedKey];
|
||||
|
||||
if (item.isSymlink) {
|
||||
const { symlinkTarget, file } = item;
|
||||
|
||||
zipFile.addBuffer(Buffer.from(symlinkTarget, 'utf8'), seedKey, {
|
||||
mode: file.mode,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const { compBuffer, crc32, uncompressedSize } = item;
|
||||
|
||||
// @ts-ignore: `addDeflatedBuffer` is a valid function, but missing on the type
|
||||
zipFile.addDeflatedBuffer(compBuffer, seedKey, {
|
||||
@@ -540,8 +580,16 @@ export async function createLambdaFromPseudoLayers({
|
||||
// was already added in a pseudo layer
|
||||
if (addedFiles.has(fileName)) continue;
|
||||
const file = files[fileName];
|
||||
const fileBuffer = await streamToBuffer(file.toStream());
|
||||
zipFile.addBuffer(fileBuffer, fileName);
|
||||
const symlinkTarget = symlinkTargets.get(fileName);
|
||||
|
||||
if (typeof symlinkTarget === 'string') {
|
||||
zipFile.addBuffer(Buffer.from(symlinkTarget, 'utf8'), fileName, {
|
||||
mode: file.mode,
|
||||
});
|
||||
} else {
|
||||
const fileBuffer = await streamToBuffer(file.toStream());
|
||||
zipFile.addBuffer(fileBuffer, fileName);
|
||||
}
|
||||
}
|
||||
zipFile.end();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "^9.1.2-canary.8",
|
||||
"next": "^9.1.6-canary.1",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function unstable_getStaticParams() {
|
||||
export async function unstable_getStaticPaths () {
|
||||
return [
|
||||
'/blog/post-1/comment-1',
|
||||
{ post: 'post-2', comment: 'comment-2' },
|
||||
{ params: { post: 'post-2', comment: 'comment-2' } },
|
||||
'/blog/post-1337/comment-1337',
|
||||
];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function unstable_getStaticProps({ params }) {
|
||||
export async function unstable_getStaticProps ({ params }) {
|
||||
return {
|
||||
props: {
|
||||
post: params.post,
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import React from 'react'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function unstable_getStaticParams () {
|
||||
export async function unstable_getStaticPaths () {
|
||||
return [
|
||||
'/blog/post-1',
|
||||
{ post: 'post-2' },
|
||||
{ params: { post: 'post-2' } },
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function unstable_getStaticProps ({ params }) {
|
||||
if (params.post === 'post-10') {
|
||||
|
||||
6
packages/now-next/test/fixtures/09-yarn-workspaces/.gitignore
vendored
Normal file
6
packages/now-next/test/fixtures/09-yarn-workspaces/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
.next
|
||||
.env
|
||||
tsconfig.tsbuildinfo
|
||||
.DS_Store
|
||||
*.log
|
||||
5
packages/now-next/test/fixtures/09-yarn-workspaces/lerna.json
vendored
Normal file
5
packages/now-next/test/fixtures/09-yarn-workspaces/lerna.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"packages": ["packages/*"],
|
||||
"npmClient": "yarn",
|
||||
"version": "0.0.0"
|
||||
}
|
||||
11
packages/now-next/test/fixtures/09-yarn-workspaces/now.json
vendored
Normal file
11
packages/now-next/test/fixtures/09-yarn-workspaces/now.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "packages/web/next.config.js", "use": "@now/next" }],
|
||||
"routes": [{ "src": "/(.*)", "dest": "/packages/web/$1", "continue": true }],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/",
|
||||
"mustContain": "hello world <!-- -->6"
|
||||
}
|
||||
]
|
||||
}
|
||||
14
packages/now-next/test/fixtures/09-yarn-workspaces/package.json
vendored
Normal file
14
packages/now-next/test/fixtures/09-yarn-workspaces/package.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"packages/*"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "lerna run build --scope=@jimmy/common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lerna": "^3.19.0"
|
||||
}
|
||||
}
|
||||
1
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/dist/index.d.ts
vendored
Normal file
1
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/dist/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const add: (a: number, b: number) => number;
|
||||
6
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/dist/index.js
vendored
Normal file
6
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/dist/index.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
exports.add = (a, b) => {
|
||||
return a + b;
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/dist/index.js.map
vendored
Normal file
1
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/dist/index.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAa,QAAA,GAAG,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE;IAC1C,OAAO,CAAC,GAAG,CAAC,CAAC;AACf,CAAC,CAAC"}
|
||||
14
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/package.json
vendored
Normal file
14
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/package.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "@jimmy/common",
|
||||
"version": "1.0.64",
|
||||
"types": "dist/index.d.ts",
|
||||
"main": "dist/index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"build": "tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^3.7.3"
|
||||
}
|
||||
}
|
||||
3
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/src/index.ts
vendored
Normal file
3
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/src/index.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export const add = (a: number, b: number) => {
|
||||
return a + b;
|
||||
};
|
||||
32
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/tsconfig.json
vendored
Normal file
32
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/tsconfig.json
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"sourceMap": true,
|
||||
"removeComments": true,
|
||||
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"alwaysStrict": true,
|
||||
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
|
||||
"composite": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"lib": ["dom", "es2017", "esnext.asynciterable", "es2017.object"],
|
||||
"declaration": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.json"],
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
2029
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/tsconfig.tsbuildinfo
vendored
Normal file
2029
packages/now-next/test/fixtures/09-yarn-workspaces/packages/common/tsconfig.tsbuildinfo
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/next-env.d.ts
vendored
Normal file
2
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
1
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/next.config.js
vendored
Normal file
1
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/next.config.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = {};
|
||||
24
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/package.json
vendored
Normal file
24
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/package.json
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@jimmy/web",
|
||||
"version": "1.0.67",
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jimmy/common": "^1.0.64",
|
||||
"next": "^9.1.4",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-syntax-class-properties": "^7.7.4",
|
||||
"@types/next": "^9.0.0",
|
||||
"@types/node": "^12.12.14",
|
||||
"@types/react": "^16.9.15",
|
||||
"@types/react-dom": "16.9.4",
|
||||
"typescript": "3.7.3"
|
||||
},
|
||||
"license": "ISC"
|
||||
}
|
||||
58
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/pages/_app.tsx
vendored
Normal file
58
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/pages/_app.tsx
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import App from "next/app";
|
||||
import React from "react";
|
||||
|
||||
class MyApp extends App<any> {
|
||||
static async getInitialProps() {
|
||||
console.log("i am props");
|
||||
return { q: 5, pageProps: {} };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { Component, pageProps } = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>yo</div>
|
||||
<Component {...pageProps} />
|
||||
<style jsx global>
|
||||
{`
|
||||
html {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
body,
|
||||
body > div {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
div,
|
||||
input,
|
||||
form,
|
||||
li,
|
||||
ul {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MyApp;
|
||||
5
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/pages/index.tsx
vendored
Normal file
5
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/pages/index.tsx
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import { add } from "@jimmy/common";
|
||||
|
||||
export default () => {
|
||||
return <div>hello world {add(1, 5)}</div>;
|
||||
};
|
||||
26
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/tsconfig.json
vendored
Normal file
26
packages/now-next/test/fixtures/09-yarn-workspaces/packages/web/tsconfig.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"jsx": "preserve",
|
||||
"lib": ["dom", "es2017"],
|
||||
"baseUrl": ".",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"isolatedModules": true,
|
||||
"removeComments": false,
|
||||
"preserveConstEnums": true,
|
||||
"sourceMap": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"exclude": ["dist", ".next", "out", "next.config.js"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
8464
packages/now-next/test/fixtures/09-yarn-workspaces/yarn.lock
vendored
Normal file
8464
packages/now-next/test/fixtures/09-yarn-workspaces/yarn.lock
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ const FOUR_MINUTES = 240000;
|
||||
|
||||
beforeAll(() => {
|
||||
process.env.NEXT_TELEMETRY_DISABLED = '1';
|
||||
})
|
||||
});
|
||||
|
||||
it(
|
||||
'Should build the standard example',
|
||||
@@ -14,7 +14,7 @@ it(
|
||||
const {
|
||||
buildResult: { output },
|
||||
} = await runBuildLambda(path.join(__dirname, 'standard'));
|
||||
expect(output['index.html']).toBeDefined();
|
||||
expect(output['index']).toBeDefined();
|
||||
expect(output.goodbye).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const serverlessError = filePaths.some(filePath =>
|
||||
@@ -274,7 +274,7 @@ it(
|
||||
buildResult: { output },
|
||||
} = await runBuildLambda(path.join(__dirname, 'serverless-config-object'));
|
||||
|
||||
expect(output['index.html']).toBeDefined();
|
||||
expect(output['index']).toBeDefined();
|
||||
expect(output.goodbye).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const serverlessError = filePaths.some(filePath =>
|
||||
@@ -308,7 +308,7 @@ it(
|
||||
buildResult: { output },
|
||||
} = await runBuildLambda(path.join(__dirname, 'serverless-no-config'));
|
||||
|
||||
expect(output['index.html']).toBeDefined();
|
||||
expect(output['index']).toBeDefined();
|
||||
expect(output.goodbye).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const serverlessError = filePaths.some(filePath =>
|
||||
@@ -344,7 +344,7 @@ it(
|
||||
path.join(__dirname, 'serverless-no-config-build')
|
||||
);
|
||||
|
||||
expect(output['index.html']).toBeDefined();
|
||||
expect(output['index']).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const serverlessError = filePaths.some(filePath =>
|
||||
filePath.match(/_error/)
|
||||
|
||||
@@ -8,7 +8,7 @@ jest.setTimeout(45000);
|
||||
|
||||
beforeAll(() => {
|
||||
process.env.NEXT_TELEMETRY_DISABLED = '1';
|
||||
})
|
||||
});
|
||||
|
||||
describe('build meta dev', () => {
|
||||
const files = {
|
||||
@@ -18,40 +18,40 @@ describe('build meta dev', () => {
|
||||
module.exports = {
|
||||
target: 'serverless'
|
||||
}
|
||||
`
|
||||
`,
|
||||
}),
|
||||
'pages/index.js': new FileBlob({
|
||||
mode: 0o777,
|
||||
data: `
|
||||
export default () => 'Index page'
|
||||
`
|
||||
`,
|
||||
}),
|
||||
'pages/nested/[param].js': new FileBlob({
|
||||
mode: 0o777,
|
||||
data: `
|
||||
export default () => 'Dynamic page'
|
||||
`
|
||||
`,
|
||||
}),
|
||||
'pages/nested/page.tsx': new FileBlob({
|
||||
mode: 0o777,
|
||||
data: `
|
||||
export default () => 'Nested page'
|
||||
`
|
||||
`,
|
||||
}),
|
||||
'pages/api/test.js': new FileBlob({
|
||||
mode: 0o777,
|
||||
data: `
|
||||
export default (req, res) => res.status(200).end('API Route')
|
||||
`
|
||||
`,
|
||||
}),
|
||||
// This file should be omitted because `pages/index.js` will use the same route
|
||||
'public/index': new FileBlob({
|
||||
mode: 0o777,
|
||||
data: 'text'
|
||||
data: 'text',
|
||||
}),
|
||||
'public/data.txt': new FileBlob({
|
||||
mode: 0o777,
|
||||
data: 'data'
|
||||
data: 'data',
|
||||
}),
|
||||
'package.json': new FileBlob({
|
||||
mode: 0o777,
|
||||
@@ -71,8 +71,8 @@ describe('build meta dev', () => {
|
||||
"typescript": "3"
|
||||
}
|
||||
}
|
||||
`
|
||||
})
|
||||
`,
|
||||
}),
|
||||
};
|
||||
const entrypoint = 'next.config.js';
|
||||
const workPath = path.join(
|
||||
@@ -92,7 +92,7 @@ describe('build meta dev', () => {
|
||||
await execa('yarn', ['install'], {
|
||||
cwd: workPath,
|
||||
env: process.env,
|
||||
reject: true
|
||||
reject: true,
|
||||
});
|
||||
|
||||
const meta = { isDev: true, requestPath: null };
|
||||
@@ -100,11 +100,11 @@ describe('build meta dev', () => {
|
||||
files,
|
||||
workPath,
|
||||
entrypoint,
|
||||
meta
|
||||
meta,
|
||||
});
|
||||
routes.forEach(route => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
route.dest = route.dest.replace(':4000', ':5000');
|
||||
route.dest = route.dest.replace(/:\d+/, ':5000');
|
||||
});
|
||||
expect(output).toEqual({});
|
||||
expect(routes).toEqual([
|
||||
@@ -116,9 +116,9 @@ describe('build meta dev', () => {
|
||||
{ src: '/api/test', dest: 'http://localhost:5000/api/test' },
|
||||
{
|
||||
src: '^/(nested\\/([^\\/]+?)(?:\\/)?)$',
|
||||
dest: 'http://localhost:5000/$1'
|
||||
dest: 'http://localhost:5000/$1',
|
||||
},
|
||||
{ src: '/data.txt', dest: 'http://localhost:5000/data.txt' }
|
||||
{ src: '/data.txt', dest: 'http://localhost:5000/data.txt' },
|
||||
]);
|
||||
expect(watch).toEqual([
|
||||
'next.config.js',
|
||||
@@ -128,7 +128,7 @@ describe('build meta dev', () => {
|
||||
'pages/api/test.js',
|
||||
'public/index',
|
||||
'public/data.txt',
|
||||
'package.json'
|
||||
'package.json',
|
||||
]);
|
||||
childProcesses.forEach(cp => cp.kill());
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/node",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.2-canary.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://zeit.co/docs/runtimes#official-runtimes/node-js",
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
shouldServe,
|
||||
Config,
|
||||
debug,
|
||||
isSymbolicLink,
|
||||
} from '@now/build-utils';
|
||||
export { shouldServe };
|
||||
export { NowRequest, NowResponse } from './types';
|
||||
@@ -55,13 +56,6 @@ const BRIDGE_FILENAME = '___now_bridge';
|
||||
const HELPERS_FILENAME = '___now_helpers';
|
||||
const SOURCEMAP_SUPPORT_FILENAME = '__sourcemap_support';
|
||||
|
||||
const S_IFMT = 61440; /* 0170000 type of file */
|
||||
const S_IFLNK = 40960; /* 0120000 symbolic link */
|
||||
|
||||
function isSymbolicLink(mode: number): boolean {
|
||||
return (mode & S_IFMT) === S_IFLNK;
|
||||
}
|
||||
|
||||
async function downloadInstallAndBundle({
|
||||
files,
|
||||
entrypoint,
|
||||
@@ -69,10 +63,7 @@ async function downloadInstallAndBundle({
|
||||
config,
|
||||
meta,
|
||||
}: DownloadOptions) {
|
||||
debug('Downloading user files...');
|
||||
const downloadTime = Date.now();
|
||||
const downloadedFiles = await download(files, workPath, meta);
|
||||
debug(`download complete [${Date.now() - downloadTime}ms]`);
|
||||
|
||||
console.log('Installing dependencies...');
|
||||
const installTime = Date.now();
|
||||
@@ -393,10 +384,9 @@ export async function build({
|
||||
return { output: lambda, watch };
|
||||
}
|
||||
|
||||
export async function prepareCache({ workPath }: PrepareCacheOptions) {
|
||||
return {
|
||||
...(await glob('node_modules/**', workPath)),
|
||||
...(await glob('package-lock.json', workPath)),
|
||||
...(await glob('yarn.lock', workPath)),
|
||||
};
|
||||
export async function prepareCache({
|
||||
workPath,
|
||||
}: PrepareCacheOptions): Promise<Files> {
|
||||
const cache = await glob('node_modules/**', workPath);
|
||||
return cache;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/python",
|
||||
"version": "1.0.1-canary.0",
|
||||
"version": "1.0.1-canary.1",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://zeit.co/docs/runtimes#official-runtimes/python",
|
||||
|
||||
@@ -77,7 +77,6 @@ export const build = async ({
|
||||
meta = {},
|
||||
config,
|
||||
}: BuildOptions) => {
|
||||
debug('Downloading user files...');
|
||||
let downloadedFiles = await download(originalFiles, workPath, meta);
|
||||
|
||||
if (meta.isDev) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/routing-utils",
|
||||
"version": "1.3.4-canary.2",
|
||||
"version": "1.4.0",
|
||||
"description": "ZEIT Now routing utilities",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -20,7 +20,7 @@
|
||||
"test-unit": "jest --env node --verbose --runInBand"
|
||||
},
|
||||
"dependencies": {
|
||||
"path-to-regexp": "3.1.0"
|
||||
"path-to-regexp": "6.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ajv": "^6.0.0",
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
} from './superstatic';
|
||||
|
||||
export { getCleanUrls } from './superstatic';
|
||||
export { mergeRoutes } from './merge';
|
||||
|
||||
export function isHandler(route: Route): route is Handler {
|
||||
return typeof (route as Handler).handle !== 'undefined';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user