mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 12:57:46 +00:00
Compare commits
22 Commits
@now/php-b
...
@now/pytho
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e1d577fc0 | ||
|
|
cf2f542c71 | ||
|
|
e608861e4e | ||
|
|
a99b999209 | ||
|
|
fd9c6e7847 | ||
|
|
b2ad3a6147 | ||
|
|
997d3c2a30 | ||
|
|
ca575bf0a6 | ||
|
|
4c2e93ccef | ||
|
|
4d6437d235 | ||
|
|
0d8058d062 | ||
|
|
2b5cdfc0a7 | ||
|
|
69a41f78fb | ||
|
|
a013d59d62 | ||
|
|
173a29cfdb | ||
|
|
3f73451311 | ||
|
|
2fc706be43 | ||
|
|
0fb7eb6093 | ||
|
|
aa43c0bc87 | ||
|
|
3c5925a6e3 | ||
|
|
9fc7b047f5 | ||
|
|
ecae29457f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
node_modules
|
node_modules
|
||||||
tmp
|
tmp
|
||||||
|
target/
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
This is the full list of official Builders provided by the ZEIT team.
|
This is the full list of official Builders provided by the ZEIT team.
|
||||||
|
|
||||||
More details here: http://zeit.co/docs
|
More details here: https://zeit.co/docs/v2/deployments/builders/overview/
|
||||||
|
|
||||||
### Publishing to npm
|
### Publishing to npm
|
||||||
|
|
||||||
|
|||||||
73
errors/now-next-legacy-mode.md
Normal file
73
errors/now-next-legacy-mode.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# `@now/next` Legacy Mode
|
||||||
|
|
||||||
|
#### Why This Warning Occurred
|
||||||
|
|
||||||
|
`@now/next` has two modes: `legacy` and `serverless`. You will always want to use the `serverless` mode. `legacy` is to provide backwards compatibility with previous `@now/next` versions.
|
||||||
|
|
||||||
|
The differences:
|
||||||
|
|
||||||
|
Legacy:
|
||||||
|
|
||||||
|
- Minimal lambda size of `2.2Mb` (approximately)
|
||||||
|
- Forces `next@v7.0.2-canary.49` and `next-server@v7.0.2-canary.49`
|
||||||
|
- Forces all `dependencies` to be `devDependencies`
|
||||||
|
- Loads `next.config.js` on bootup, breaking sometimes when users didn't use `phases` to load files
|
||||||
|
- Used `next-server` which is the full Next.js server with routing etc.
|
||||||
|
- Runs `npm install`
|
||||||
|
- Runs `npm run now-build`
|
||||||
|
- Runs `npm install --production` after build
|
||||||
|
|
||||||
|
Serverless:
|
||||||
|
|
||||||
|
- Minimal lambda size of `49Kb` (approximately)
|
||||||
|
- Uses Next.js build targets (`target: 'serverless'`) in `next.config.js`. [documentation](https://github.com/zeit/next.js#summary)
|
||||||
|
- Does not make changes to your application dependencies
|
||||||
|
- Does not load `next.config.js` ([as per the serverless target documentation](https://github.com/zeit/next.js#summary))
|
||||||
|
- Runs `npm install`
|
||||||
|
- Runs `npm run now-build`
|
||||||
|
- Does not run `npm install --production` as the output from the build is all that's needed to bundle lambdas.
|
||||||
|
- No runtime dependencies, meaning smaller lambda functions
|
||||||
|
- Optimized for fast [cold start](https://zeit.co/blog/serverless-ssr#cold-start)
|
||||||
|
|
||||||
|
|
||||||
|
#### Possible Ways to Fix It
|
||||||
|
|
||||||
|
In order to create the smallest possible lambdas Next.js has to be configured to build for the `serverless` target.
|
||||||
|
|
||||||
|
1. Serverless Next.js requires Next.js 8 or later, currently this version is out on the `canary` release channel:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install next@canary
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add the `now-build` script to your `package.json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"now-build": "next build"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Add `target: 'serverless'` to `next.config.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = {
|
||||||
|
target: 'serverless'
|
||||||
|
// Other options are still valid
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Optionally make sure the `"src"` in `"builds"` points to your application `package.json`
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"builds": [{ "src": "package.json", "use": "@now/next" }]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Useful Links
|
||||||
|
|
||||||
|
- [Serverless target implementation](https://github.com/zeit/now-builders/pull/150)
|
||||||
43
errors/now-next-no-serverless-pages-built.md
Normal file
43
errors/now-next-no-serverless-pages-built.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# `@now/next` No Serverless Pages Built
|
||||||
|
|
||||||
|
#### Why This Error Occurred
|
||||||
|
|
||||||
|
This error occurs when you have your application is not configured for Serverless Next.js build output.
|
||||||
|
|
||||||
|
#### Possible Ways to Fix It
|
||||||
|
|
||||||
|
In order to create the smallest possible lambdas Next.js has to be configured to build for the `serverless` target.
|
||||||
|
|
||||||
|
1. Serverless Next.js requires Next.js 8 or later, currently this version is out on the `canary` release channel:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install next@canary
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add the `now-build` script to your `package.json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"now-build": "next build"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Add `target: 'serverless'` to `next.config.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = {
|
||||||
|
target: 'serverless'
|
||||||
|
// Other options are still valid
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Optionally make sure the `"src"` in `"builds"` points to your application `package.json`
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"builds": [{ "src": "package.json", "use": "@now/next" }]
|
||||||
|
}
|
||||||
|
```
|
||||||
19
lerna.json
19
lerna.json
@@ -2,24 +2,7 @@
|
|||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"useWorkspaces": true,
|
"useWorkspaces": true,
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/now-build-utils",
|
"packages/*"
|
||||||
"packages/now-node-bridge",
|
|
||||||
"packages/now-php-bridge",
|
|
||||||
"packages/now-bash",
|
|
||||||
"packages/now-cgi",
|
|
||||||
"packages/now-go",
|
|
||||||
"packages/now-html-minifier",
|
|
||||||
"packages/now-lambda",
|
|
||||||
"packages/now-md",
|
|
||||||
"packages/now-mdx-deck",
|
|
||||||
"packages/now-next",
|
|
||||||
"packages/now-node",
|
|
||||||
"packages/now-node-server",
|
|
||||||
"packages/now-optipng",
|
|
||||||
"packages/now-php",
|
|
||||||
"packages/now-python",
|
|
||||||
"packages/now-static-build",
|
|
||||||
"packages/now-wordpress"
|
|
||||||
],
|
],
|
||||||
"command": {
|
"command": {
|
||||||
"publish": {
|
"publish": {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
const execa = require('execa');
|
const execa = require('execa');
|
||||||
const { join } = require('path');
|
const { join } = require('path');
|
||||||
const snakeCase = require('snake-case');
|
const snakeCase = require('snake-case');
|
||||||
const glob = require('@now/build-utils/fs/glob');
|
const glob = require('@now/build-utils/fs/glob'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const download = require('@now/build-utils/fs/download');
|
const download = require('@now/build-utils/fs/download'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const { createLambda } = require('@now/build-utils/lambda');
|
const { createLambda } = require('@now/build-utils/lambda'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory');
|
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
exports.config = {
|
exports.config = {
|
||||||
maxLambdaSize: '10mb',
|
maxLambdaSize: '10mb',
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/bash",
|
"name": "@now/bash",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2-canary.0",
|
||||||
"description": "Now 2.0 builder for HTTP endpoints written in Bash",
|
"description": "Now 2.0 builder for HTTP endpoints written in Bash",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"author": "Nathan Rajlich <nate@zeit.co>",
|
"author": "Nathan Rajlich <nate@zeit.co>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-bash"
|
||||||
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"builder.sh",
|
"builder.sh",
|
||||||
"runtime.sh",
|
"runtime.sh",
|
||||||
@@ -15,8 +20,5 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"execa": "^1.0.0",
|
"execa": "^1.0.0",
|
||||||
"snake-case": "^2.1.0"
|
"snake-case": "^2.1.0"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@now/build-utils": ">=0.0.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class FileRef {
|
|||||||
assert(url);
|
assert(url);
|
||||||
|
|
||||||
await semaToDownloadFromS3.acquire();
|
await semaToDownloadFromS3.acquire();
|
||||||
console.time(`downloading ${url}`);
|
// console.time(`downloading ${url}`);
|
||||||
try {
|
try {
|
||||||
return await retry(
|
return await retry(
|
||||||
async () => {
|
async () => {
|
||||||
@@ -66,7 +66,7 @@ class FileRef {
|
|||||||
{ factor: 1, retries: 3 },
|
{ factor: 1, retries: 3 },
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
console.timeEnd(`downloading ${url}`);
|
// console.timeEnd(`downloading ${url}`);
|
||||||
semaToDownloadFromS3.release();
|
semaToDownloadFromS3.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
270
packages/now-build-utils/fs/bootstrap-yarn.js
vendored
270
packages/now-build-utils/fs/bootstrap-yarn.js
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable arrow-body-style,no-multi-assign,no-param-reassign */
|
||||||
|
|
||||||
const MemoryFileSystem = require('memory-fs');
|
const MemoryFileSystem = require('memory-fs');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
@@ -19,76 +21,222 @@ function isInsideCachePath(filename) {
|
|||||||
return !relative.startsWith('..');
|
return !relative.startsWith('..');
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveCreateWriteStream = fs.createWriteStream;
|
function replaceFn(name, newFnFactory) {
|
||||||
fs.createWriteStream = (...args) => {
|
const prevFn = fs[name];
|
||||||
const filename = args[0];
|
fs[name] = newFnFactory(prevFn);
|
||||||
if (!isInsideCachePath(filename)) {
|
}
|
||||||
return saveCreateWriteStream.call(fs, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfs.mkdirpSync(path.dirname(filename));
|
replaceFn('createWriteStream', (prevFn) => {
|
||||||
fs.writeFileSync(filename, Buffer.alloc(0));
|
return (...args) => {
|
||||||
const stream = vfs.createWriteStream(...args);
|
const filename = args[0];
|
||||||
|
if (!isInsideCachePath(filename)) {
|
||||||
stream.on('finish', () => {
|
return prevFn.call(fs, ...args);
|
||||||
setTimeout(() => {
|
|
||||||
stream.emit('close');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveReadFile = fs.readFile;
|
|
||||||
fs.readFile = (...args) => {
|
|
||||||
const filename = args[0];
|
|
||||||
if (!isInsideCachePath(filename)) {
|
|
||||||
return saveReadFile.call(fs, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
const callback = args[args.length - 1];
|
|
||||||
return vfs.readFile(...args.slice(0, -1), (error, result) => {
|
|
||||||
if (error) {
|
|
||||||
saveReadFile.call(fs, ...args);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(error, result);
|
const stream = vfs.createWriteStream(...args);
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveCopyFile = fs.copyFile;
|
stream.on('finish', () => {
|
||||||
fs.copyFile = (...args) => {
|
setTimeout(() => {
|
||||||
const src = args[0];
|
stream.emit('close');
|
||||||
const dest = args[1];
|
});
|
||||||
const callback = args[args.length - 1];
|
});
|
||||||
|
|
||||||
if (isInsideCachePath(src) && !isInsideCachePath(dest)) {
|
setTimeout(() => {
|
||||||
const buffer = vfs.readFileSync(src);
|
stream.emit('open');
|
||||||
return fs.writeFile(dest, buffer, callback);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (!isInsideCachePath(src) && isInsideCachePath(dest)) {
|
return stream;
|
||||||
const buffer = fs.readFileSync(src);
|
};
|
||||||
|
});
|
||||||
|
|
||||||
vfs.mkdirpSync(path.dirname(dest));
|
replaceFn('readFile', (prevFn) => {
|
||||||
fs.writeFileSync(dest, Buffer.alloc(0));
|
return (...args) => {
|
||||||
return vfs.writeFile(dest, buffer, callback);
|
const filename = args[0];
|
||||||
}
|
if (!isInsideCachePath(filename)) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
return saveCopyFile.call(fs, ...args);
|
const callback = args[args.length - 1];
|
||||||
};
|
return vfs.readFile(...args.slice(0, -1), (error, result) => {
|
||||||
|
if (error) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
const saveWriteFile = fs.writeFile;
|
return callback(error, result);
|
||||||
fs.writeFile = (...args) => {
|
});
|
||||||
const filename = args[0];
|
};
|
||||||
if (!isInsideCachePath(filename)) {
|
});
|
||||||
return saveWriteFile.call(fs, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfs.mkdirpSync(path.dirname(filename));
|
replaceFn('readdir', (prevFn) => {
|
||||||
fs.writeFileSync(filename, Buffer.alloc(0));
|
return (...args) => {
|
||||||
return vfs.writeFile(...args);
|
const dirname = args[0];
|
||||||
};
|
if (!isInsideCachePath(dirname)) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = args[args.length - 1];
|
||||||
|
return prevFn.call(fs, dirname, (error, results) => {
|
||||||
|
if (error) {
|
||||||
|
results = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return vfs.readdir(dirname, (error2, results2) => {
|
||||||
|
if (error2) {
|
||||||
|
return callback(error2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
for (const result2 of results2) {
|
||||||
|
if (!results.includes(result2)) {
|
||||||
|
results.push(result2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback(error2, results);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
replaceFn('stat', (prevFn) => {
|
||||||
|
return (...args) => {
|
||||||
|
const filename = args[0];
|
||||||
|
if (!isInsideCachePath(filename)) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = args[args.length - 1];
|
||||||
|
return vfs.stat(...args.slice(0, -1), (error, result) => {
|
||||||
|
if (error) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.atime = result.mtime = new Date();
|
||||||
|
return callback(error, result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
replaceFn('lstat', (prevFn) => {
|
||||||
|
return (...args) => {
|
||||||
|
const filename = args[0];
|
||||||
|
if (!isInsideCachePath(filename)) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = args[args.length - 1];
|
||||||
|
return vfs.stat(...args.slice(0, -1), (error, result) => {
|
||||||
|
if (error) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.atime = result.mtime = new Date();
|
||||||
|
return callback(error, result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
replaceFn('exists', (prevFn) => {
|
||||||
|
return (...args) => {
|
||||||
|
const filename = args[0];
|
||||||
|
if (!isInsideCachePath(filename)) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = args[args.length - 1];
|
||||||
|
return vfs.exists(...args.slice(0, -1), (result) => {
|
||||||
|
if (!result) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback(result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
replaceFn('copyFile', (prevFn) => {
|
||||||
|
return (...args) => {
|
||||||
|
const src = args[0];
|
||||||
|
const dest = args[1];
|
||||||
|
const callback = args[args.length - 1];
|
||||||
|
|
||||||
|
if (isInsideCachePath(src) && !isInsideCachePath(dest)) {
|
||||||
|
const buffer = vfs.readFileSync(src);
|
||||||
|
return fs.writeFile(dest, buffer, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isInsideCachePath(src) && isInsideCachePath(dest)) {
|
||||||
|
const buffer = fs.readFileSync(src);
|
||||||
|
return vfs.writeFile(dest, buffer, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
replaceFn('writeFile', (prevFn) => {
|
||||||
|
return (...args) => {
|
||||||
|
const filename = args[0];
|
||||||
|
if (!isInsideCachePath(filename)) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vfs.writeFile(...args);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
replaceFn('mkdir', (prevFn) => {
|
||||||
|
return (...args) => {
|
||||||
|
const dirname = args[0];
|
||||||
|
if (!isInsideCachePath(dirname)) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = args[args.length - 1];
|
||||||
|
return prevFn.call(fs, dirname, (error) => {
|
||||||
|
if (error) {
|
||||||
|
return callback(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vfs.mkdirp(dirname, callback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
replaceFn('utimes', (prevFn) => {
|
||||||
|
return (...args) => {
|
||||||
|
const filename = args[0];
|
||||||
|
if (!isInsideCachePath(filename)) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = args[args.length - 1];
|
||||||
|
return setTimeout(callback, 0);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
replaceFn('chmod', (prevFn) => {
|
||||||
|
return (...args) => {
|
||||||
|
const filename = args[0];
|
||||||
|
if (!isInsideCachePath(filename)) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = args[args.length - 1];
|
||||||
|
return setTimeout(callback, 0);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
replaceFn('chown', (prevFn) => {
|
||||||
|
return (...args) => {
|
||||||
|
const filename = args[0];
|
||||||
|
if (!isInsideCachePath(filename)) {
|
||||||
|
return prevFn.call(fs, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const callback = args[args.length - 1];
|
||||||
|
return setTimeout(callback, 0);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
require(yarnPath);
|
require(yarnPath);
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/build-utils",
|
"name": "@now/build-utils",
|
||||||
"version": "0.4.32",
|
"version": "0.4.33-canary.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-build-utils"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async-retry": "1.2.3",
|
"async-retry": "1.2.3",
|
||||||
"async-sema": "2.1.4",
|
"async-sema": "2.1.4",
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { mkdirp, copyFile } = require('fs-extra');
|
const { mkdirp, copyFile } = require('fs-extra');
|
||||||
|
|
||||||
const glob = require('@now/build-utils/fs/glob');
|
const glob = require('@now/build-utils/fs/glob'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const download = require('@now/build-utils/fs/download');
|
const download = require('@now/build-utils/fs/download'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const { createLambda } = require('@now/build-utils/lambda');
|
const { createLambda } = require('@now/build-utils/lambda'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory');
|
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
|
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/cgi",
|
"name": "@now/cgi",
|
||||||
"version": "0.0.15",
|
"version": "0.0.16-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-cgi"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "best -I test/*.js",
|
"test": "best -I test/*.js",
|
||||||
"prepublish": "./build.sh"
|
"prepublish": "./build.sh"
|
||||||
@@ -16,8 +21,5 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@zeit/best": "0.4.3",
|
"@zeit/best": "0.4.3",
|
||||||
"rmfr": "2.0.0"
|
"rmfr": "2.0.0"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@now/build-utils": ">=0.0.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const path = require('path');
|
|||||||
|
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
const tar = require('tar');
|
const tar = require('tar');
|
||||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js');
|
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
const url = 'https://dl.google.com/go/go1.11.1.linux-amd64.tar.gz';
|
const url = 'https://dl.google.com/go/go1.11.1.linux-amd64.tar.gz';
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ const path = require('path');
|
|||||||
const { mkdirp, readFile, writeFile } = require('fs-extra');
|
const { mkdirp, readFile, writeFile } = require('fs-extra');
|
||||||
|
|
||||||
const execa = require('execa');
|
const execa = require('execa');
|
||||||
const { createLambda } = require('@now/build-utils/lambda.js');
|
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js');
|
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const download = require('@now/build-utils/fs/download.js');
|
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const downloadGit = require('lambda-git');
|
const downloadGit = require('lambda-git');
|
||||||
const glob = require('@now/build-utils/fs/glob.js');
|
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const downloadGoBin = require('./download-go-bin');
|
const downloadGoBin = require('./download-go-bin');
|
||||||
|
|
||||||
// creates a `$GOPATH` directory tree, as per
|
// creates a `$GOPATH` directory tree, as per
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/go",
|
"name": "@now/go",
|
||||||
"version": "0.2.12",
|
"version": "0.2.13-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-go"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "best -I test/*.js",
|
"test": "best -I test/*.js",
|
||||||
"prepublish": "./build.sh"
|
"prepublish": "./build.sh"
|
||||||
@@ -23,8 +28,5 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@zeit/best": "0.4.3",
|
"@zeit/best": "0.4.3",
|
||||||
"rmfr": "2.0.0"
|
"rmfr": "2.0.0"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@now/build-utils": ">=0.0.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const FileBlob = require('@now/build-utils/file-blob.js');
|
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const { minify } = require('html-minifier');
|
const { minify } = require('html-minifier');
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/html-minifier",
|
"name": "@now/html-minifier",
|
||||||
"version": "1.0.7",
|
"version": "1.0.8-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-html-minifier"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"html-minifier": "3.5.21"
|
"html-minifier": "3.5.21"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@now/build-utils": ">=0.0.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const { Lambda } = require('@now/build-utils/lambda.js');
|
const { Lambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const streamToBuffer = require('@now/build-utils/fs/stream-to-buffer.js');
|
const streamToBuffer = require('@now/build-utils/fs/stream-to-buffer.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
exports.build = async ({ files, entrypoint, config }) => {
|
exports.build = async ({ files, entrypoint, config }) => {
|
||||||
if (!files[entrypoint]) throw new Error('Entrypoint not found in files');
|
if (!files[entrypoint]) throw new Error('Entrypoint not found in files');
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/lambda",
|
"name": "@now/lambda",
|
||||||
"version": "0.4.9",
|
"version": "0.4.10-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"repository": {
|
||||||
"@now/build-utils": ">=0.0.1"
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-lambda"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const FileBlob = require('@now/build-utils/file-blob.js');
|
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const unified = require('unified');
|
const unified = require('unified');
|
||||||
const unifiedStream = require('unified-stream');
|
const unifiedStream = require('unified-stream');
|
||||||
const markdown = require('remark-parse');
|
const markdown = require('remark-parse');
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/md",
|
"name": "@now/md",
|
||||||
"version": "0.4.9",
|
"version": "0.4.10-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-md"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"rehype-document": "^2.2.0",
|
"rehype-document": "^2.2.0",
|
||||||
"rehype-format": "^2.3.0",
|
"rehype-format": "^2.3.0",
|
||||||
@@ -11,9 +16,6 @@
|
|||||||
"unified": "^7.0.0",
|
"unified": "^7.0.0",
|
||||||
"unified-stream": "^1.0.2"
|
"unified-stream": "^1.0.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
|
||||||
"@now/build-utils": ">=0.0.1"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
const download = require('@now/build-utils/fs/download.js');
|
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { promisify } = require('util');
|
const { promisify } = require('util');
|
||||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js');
|
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const glob = require('@now/build-utils/fs/glob.js');
|
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { runNpmInstall } = require('@now/build-utils/fs/run-user-scripts.js');
|
const { runNpmInstall } = require('@now/build-utils/fs/run-user-scripts.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
const writeFile = promisify(fs.writeFile);
|
const writeFile = promisify(fs.writeFile);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/mdx-deck",
|
"name": "@now/mdx-deck",
|
||||||
"version": "0.4.18",
|
"version": "0.4.19-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"repository": {
|
||||||
"@now/build-utils": ">=0.0.1"
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-mdx-deck"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
const { createLambda } = require('@now/build-utils/lambda.js');
|
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const download = require('@now/build-utils/fs/download.js');
|
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const FileFsRef = require('@now/build-utils/file-fs-ref.js');
|
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const FileBlob = require('@now/build-utils/file-blob');
|
const FileBlob = require('@now/build-utils/file-blob'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { readFile, writeFile, unlink } = require('fs.promised');
|
const { readFile, writeFile, unlink } = require('fs.promised');
|
||||||
const {
|
const {
|
||||||
runNpmInstall,
|
runNpmInstall,
|
||||||
runPackageJsonScript,
|
runPackageJsonScript,
|
||||||
} = require('@now/build-utils/fs/run-user-scripts.js');
|
} = require('@now/build-utils/fs/run-user-scripts.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const glob = require('@now/build-utils/fs/glob.js');
|
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const semver = require('semver');
|
const semver = require('semver');
|
||||||
const nextLegacyVersions = require('./legacy-versions');
|
const nextLegacyVersions = require('./legacy-versions');
|
||||||
const {
|
const {
|
||||||
@@ -145,8 +145,9 @@ exports.build = async ({ files, workPath, entrypoint }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.warn(
|
console.warn(
|
||||||
"WARNING: your application is being deployed in @now/next's legacy mode.",
|
"WARNING: your application is being deployed in @now/next's legacy mode. http://err.sh/zeit/now-builders/now-next-legacy-mode",
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('normalizing package.json');
|
console.log('normalizing package.json');
|
||||||
const packageJson = normalizePackageJson(pkg);
|
const packageJson = normalizePackageJson(pkg);
|
||||||
console.log('normalized package.json result: ', packageJson);
|
console.log('normalized package.json result: ', packageJson);
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/next",
|
"name": "@now/next",
|
||||||
"version": "0.0.84",
|
"version": "0.0.85-canary.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-next"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@now/node-bridge": "0.1.4",
|
"@now/node-bridge": "0.1.4",
|
||||||
"execa": "^1.0.0",
|
"execa": "^1.0.0",
|
||||||
"fs.promised": "^3.0.0",
|
"fs.promised": "^3.0.0",
|
||||||
"semver": "^5.6.0"
|
"semver": "^5.6.0"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@now/build-utils": ">=0.0.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const rename = require('@now/build-utils/fs/rename.js');
|
const rename = require('@now/build-utils/fs/rename.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
|
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
|
||||||
/** @typedef { import('@now/build-utils/file-fs-ref') } FileFsRef */
|
/** @typedef { import('@now/build-utils/file-fs-ref') } FileFsRef */
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/node-bridge",
|
"name": "@now/node-bridge",
|
||||||
"version": "0.1.10",
|
"version": "0.1.11-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"repository": {
|
||||||
"@now/build-utils": ">=0.0.1"
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-node-bridge"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
const { createLambda } = require('@now/build-utils/lambda.js');
|
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const download = require('@now/build-utils/fs/download.js');
|
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const FileBlob = require('@now/build-utils/file-blob.js');
|
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const FileFsRef = require('@now/build-utils/file-fs-ref.js');
|
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const glob = require('@now/build-utils/fs/glob.js');
|
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const rename = require('@now/build-utils/fs/rename.js');
|
const rename = require('@now/build-utils/fs/rename.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const {
|
const {
|
||||||
runNpmInstall,
|
runNpmInstall,
|
||||||
runPackageJsonScript,
|
runPackageJsonScript,
|
||||||
} = require('@now/build-utils/fs/run-user-scripts.js');
|
} = require('@now/build-utils/fs/run-user-scripts.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
|
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
|
||||||
/** @typedef {{[filePath: string]: FileRef}} Files */
|
/** @typedef {{[filePath: string]: FileRef}} Files */
|
||||||
@@ -37,7 +37,7 @@ async function downloadInstallAndBundle(
|
|||||||
console.log('downloading user files...');
|
console.log('downloading user files...');
|
||||||
const downloadedFiles = await download(files, userPath);
|
const downloadedFiles = await download(files, userPath);
|
||||||
|
|
||||||
console.log('installing dependencies for user\'s code...');
|
console.log("installing dependencies for user's code...");
|
||||||
const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
|
const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
|
||||||
await runNpmInstall(entrypointFsDirname, npmArguments);
|
await runNpmInstall(entrypointFsDirname, npmArguments);
|
||||||
|
|
||||||
@@ -46,8 +46,9 @@ async function downloadInstallAndBundle(
|
|||||||
{
|
{
|
||||||
'package.json': new FileBlob({
|
'package.json': new FileBlob({
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
|
license: 'UNLICENSED',
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@zeit/ncc': '0.11.0',
|
'@zeit/ncc': '0.13.2',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/node-server",
|
"name": "@now/node-server",
|
||||||
"version": "0.4.26",
|
"version": "0.4.27-canary.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"repository": {
|
||||||
"@now/node-bridge": "^0.1.10",
|
"type": "git",
|
||||||
"fs-extra": "7.0.1"
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-node-server"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"dependencies": {
|
||||||
"@now/build-utils": ">=0.0.1"
|
"@now/node-bridge": "^0.1.11-canary.0",
|
||||||
|
"fs-extra": "7.0.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
const { createLambda } = require('@now/build-utils/lambda.js');
|
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const download = require('@now/build-utils/fs/download.js');
|
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const FileBlob = require('@now/build-utils/file-blob.js');
|
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const FileFsRef = require('@now/build-utils/file-fs-ref.js');
|
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const glob = require('@now/build-utils/fs/glob.js');
|
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const {
|
const {
|
||||||
runNpmInstall,
|
runNpmInstall,
|
||||||
runPackageJsonScript,
|
runPackageJsonScript,
|
||||||
} = require('@now/build-utils/fs/run-user-scripts.js');
|
} = require('@now/build-utils/fs/run-user-scripts.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
|
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
|
||||||
/** @typedef {{[filePath: string]: FileRef}} Files */
|
/** @typedef {{[filePath: string]: FileRef}} Files */
|
||||||
@@ -35,7 +35,7 @@ async function downloadInstallAndBundle(
|
|||||||
console.log('downloading user files...');
|
console.log('downloading user files...');
|
||||||
const downloadedFiles = await download(files, userPath);
|
const downloadedFiles = await download(files, userPath);
|
||||||
|
|
||||||
console.log('installing dependencies for user\'s code...');
|
console.log("installing dependencies for user's code...");
|
||||||
const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
|
const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
|
||||||
await runNpmInstall(entrypointFsDirname, npmArguments);
|
await runNpmInstall(entrypointFsDirname, npmArguments);
|
||||||
|
|
||||||
@@ -44,8 +44,9 @@ async function downloadInstallAndBundle(
|
|||||||
{
|
{
|
||||||
'package.json': new FileBlob({
|
'package.json': new FileBlob({
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
|
license: 'UNLICENSED',
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@zeit/ncc': '0.11.0',
|
'@zeit/ncc': '0.13.2',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/node",
|
"name": "@now/node",
|
||||||
"version": "0.4.28",
|
"version": "0.4.29-canary.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"repository": {
|
||||||
"@now/node-bridge": "^0.1.10",
|
"type": "git",
|
||||||
"fs-extra": "7.0.1"
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-node"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"dependencies": {
|
||||||
"@now/build-utils": ">=0.0.1"
|
"@now/node-bridge": "^0.1.11-canary.0",
|
||||||
|
"fs-extra": "7.0.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const FileBlob = require('@now/build-utils/file-blob.js');
|
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const OptiPng = require('optipng');
|
const OptiPng = require('optipng');
|
||||||
const pipe = require('multipipe');
|
const pipe = require('multipipe');
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/optipng",
|
"name": "@now/optipng",
|
||||||
"version": "0.4.8",
|
"version": "0.4.9-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-optipng"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"multipipe": "2.0.3",
|
"multipipe": "2.0.3",
|
||||||
"optipng": "1.1.0"
|
"optipng": "1.1.0"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@now/build-utils": ">=0.0.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,38 @@
|
|||||||
const FileBlob = require('@now/build-utils/file-blob.js');
|
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const FileFsRef = require('@now/build-utils/file-fs-ref.js');
|
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const glob = require('@now/build-utils/fs/glob.js');
|
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
async function getFiles() {
|
async function getFiles() {
|
||||||
const files = await glob('native/**', __dirname);
|
const files = await glob('native/**', __dirname);
|
||||||
|
|
||||||
const phpConfig = await FileBlob.fromStream({ stream: files['native/php.ini'].toStream() });
|
const phpConfig = await FileBlob.fromStream({
|
||||||
phpConfig.data = phpConfig.data.toString()
|
stream: files['native/php.ini'].toStream(),
|
||||||
|
});
|
||||||
|
phpConfig.data = phpConfig.data
|
||||||
|
.toString()
|
||||||
.replace(/\/root\/app\/modules/g, '/var/task/native/modules');
|
.replace(/\/root\/app\/modules/g, '/var/task/native/modules');
|
||||||
files['native/php.ini'] = phpConfig;
|
files['native/php.ini'] = phpConfig;
|
||||||
|
|
||||||
Object.assign(files, {
|
Object.assign(files, {
|
||||||
'fastcgi/connection.js': new FileFsRef({ fsPath: require.resolve('fastcgi-client/lib/connection.js') }),
|
'fastcgi/connection.js': new FileFsRef({
|
||||||
'fastcgi/consts.js': new FileFsRef({ fsPath: require.resolve('fastcgi-client/lib/consts.js') }),
|
fsPath: require.resolve('fastcgi-client/lib/connection.js'),
|
||||||
'fastcgi/stringifykv.js': new FileFsRef({ fsPath: require.resolve('fastcgi-client/lib/stringifykv.js') }),
|
}),
|
||||||
'fastcgi/index.js': new FileFsRef({ fsPath: path.join(__dirname, 'fastcgi/index.js') }),
|
'fastcgi/consts.js': new FileFsRef({
|
||||||
'fastcgi/port.js': new FileFsRef({ fsPath: path.join(__dirname, 'fastcgi/port.js') }),
|
fsPath: require.resolve('fastcgi-client/lib/consts.js'),
|
||||||
'launcher.js': new FileFsRef({ fsPath: path.join(__dirname, 'launcher.js') }),
|
}),
|
||||||
|
'fastcgi/stringifykv.js': new FileFsRef({
|
||||||
|
fsPath: require.resolve('fastcgi-client/lib/stringifykv.js'),
|
||||||
|
}),
|
||||||
|
'fastcgi/index.js': new FileFsRef({
|
||||||
|
fsPath: path.join(__dirname, 'fastcgi/index.js'),
|
||||||
|
}),
|
||||||
|
'fastcgi/port.js': new FileFsRef({
|
||||||
|
fsPath: path.join(__dirname, 'fastcgi/port.js'),
|
||||||
|
}),
|
||||||
|
'launcher.js': new FileFsRef({
|
||||||
|
fsPath: path.join(__dirname, 'launcher.js'),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/php-bridge",
|
"name": "@now/php-bridge",
|
||||||
"version": "0.4.13",
|
"version": "0.4.14-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-php-bridge"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fastcgi-client": "0.0.1"
|
"fastcgi-client": "0.0.1"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@now/build-utils": ">=0.0.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const { createLambda } = require('@now/build-utils/lambda.js');
|
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const rename = require('@now/build-utils/fs/rename.js');
|
const rename = require('@now/build-utils/fs/rename.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const { getFiles } = require('@now/php-bridge');
|
const { getFiles } = require('@now/php-bridge');
|
||||||
|
|
||||||
exports.config = {
|
exports.config = {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/php",
|
"name": "@now/php",
|
||||||
"version": "0.4.13",
|
"version": "0.4.14-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"repository": {
|
||||||
"@now/php-bridge": "^0.4.13"
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-php"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"dependencies": {
|
||||||
"@now/build-utils": ">=0.0.1"
|
"@now/php-bridge": "^0.4.14-canary.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const fetch = require('node-fetch');
|
|||||||
const execa = require('execa');
|
const execa = require('execa');
|
||||||
const { createWriteStream } = require('fs');
|
const { createWriteStream } = require('fs');
|
||||||
|
|
||||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js');
|
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
const url = 'https://bootstrap.pypa.io/get-pip.py';
|
const url = 'https://bootstrap.pypa.io/get-pip.py';
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const execa = require('execa');
|
const execa = require('execa');
|
||||||
const { readFile, writeFile } = require('fs.promised');
|
const { readFile, writeFile } = require('fs.promised');
|
||||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js');
|
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const download = require('@now/build-utils/fs/download.js');
|
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const glob = require('@now/build-utils/fs/glob.js');
|
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const { createLambda } = require('@now/build-utils/lambda.js');
|
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const downloadAndInstallPip = require('./download-and-install-pip');
|
const downloadAndInstallPip = require('./download-and-install-pip');
|
||||||
|
|
||||||
async function pipInstall(pipPath, srcDir, ...args) {
|
async function pipInstall(pipPath, srcDir, ...args) {
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/python",
|
"name": "@now/python",
|
||||||
"version": "0.0.40",
|
"version": "0.0.41-canary.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-python"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"execa": "^1.0.0",
|
"execa": "^1.0.0",
|
||||||
"fs.promised": "^3.0.0",
|
"fs.promised": "^3.0.0",
|
||||||
"node-fetch": "^2.2.0"
|
"node-fetch": "^2.2.0"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@now/build-utils": ">=0.0.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1101
packages/now-rust/Cargo.lock
generated
Normal file
1101
packages/now-rust/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
15
packages/now-rust/Cargo.toml
Normal file
15
packages/now-rust/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "now_lambda"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Antonio Nuno Monteiro <anmonteiro@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = "^1"
|
||||||
|
serde_json = "^1"
|
||||||
|
serde_derive = "^1"
|
||||||
|
http = "0.1"
|
||||||
|
tokio = "^0.1"
|
||||||
|
base64 = "0.10"
|
||||||
|
log = "^0.4"
|
||||||
|
lambda_runtime = "0.2.0"
|
||||||
62
packages/now-rust/download-install-rust-toolchain.js
Normal file
62
packages/now-rust/download-install-rust-toolchain.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
const tar = require('tar');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
|
const rustUrl = 'https://dmmcy0pwk6bqi.cloudfront.net/rust.tar.gz';
|
||||||
|
const ccUrl = 'https://dmmcy0pwk6bqi.cloudfront.net/gcc-4.8.5.tgz';
|
||||||
|
|
||||||
|
async function downloadRustToolchain() {
|
||||||
|
console.log('downloading the rust toolchain');
|
||||||
|
const res = await fetch(rustUrl);
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`Failed to download: ${rustUrl}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { HOME } = process.env;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
res.body
|
||||||
|
.on('error', reject)
|
||||||
|
.pipe(tar.extract({ gzip: true, cwd: HOME }))
|
||||||
|
.on('finish', () => resolve());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function downloadGCC() {
|
||||||
|
console.log('downloading GCC');
|
||||||
|
const res = await fetch(ccUrl);
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`Failed to download: ${ccUrl}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
res.body
|
||||||
|
.on('error', reject)
|
||||||
|
// NOTE(anmonteiro): We pipe GCC into `/tmp` instead of getting a writable
|
||||||
|
// directory from `@now/build-utils` because the GCC distribution that we
|
||||||
|
// use is specifically packaged for AWS Lambda (where `/tmp` is writable)
|
||||||
|
// and contains several hardcoded symlinks to paths in `/tmp`.
|
||||||
|
.pipe(tar.extract({ gzip: true, cwd: '/tmp' }))
|
||||||
|
.on('finish', async () => {
|
||||||
|
const { LD_LIBRARY_PATH } = process.env;
|
||||||
|
// Set the environment variables as per
|
||||||
|
// https://github.com/lambci/lambci/blob/e6c9c7/home/init/gcc#L14-L17
|
||||||
|
const newEnv = {
|
||||||
|
PATH: '/tmp/bin:/tmp/sbin',
|
||||||
|
LD_LIBRARY_PATH: `/tmp/lib:/tmp/lib64:${LD_LIBRARY_PATH}`,
|
||||||
|
CPATH: '/tmp/include',
|
||||||
|
LIBRARY_PATH: '/tmp/lib',
|
||||||
|
};
|
||||||
|
|
||||||
|
return resolve(newEnv);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = async () => {
|
||||||
|
await downloadRustToolchain();
|
||||||
|
|
||||||
|
const newEnv = await downloadGCC();
|
||||||
|
|
||||||
|
return newEnv;
|
||||||
|
};
|
||||||
90
packages/now-rust/index.js
Normal file
90
packages/now-rust/index.js
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const concat = require('concat-stream');
|
||||||
|
const execa = require('execa');
|
||||||
|
const toml = require('toml');
|
||||||
|
const rimraf = require('rimraf');
|
||||||
|
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
const installRustAndGCC = require('./download-install-rust-toolchain.js');
|
||||||
|
const inferCargoBinaries = require('./inferCargoBinaries.js');
|
||||||
|
|
||||||
|
exports.config = {
|
||||||
|
maxLambdaSize: '25mb',
|
||||||
|
};
|
||||||
|
|
||||||
|
async function parseTOMLStream(stream) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
stream.pipe(concat(data => resolve(toml.parse(data))));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.build = async ({ files, entrypoint, workPath }) => {
|
||||||
|
console.log('downloading files');
|
||||||
|
const downloadedFiles = await download(files, workPath);
|
||||||
|
|
||||||
|
const { PATH: toolchainPath, ...otherEnv } = await installRustAndGCC();
|
||||||
|
const { PATH, HOME } = process.env;
|
||||||
|
const rustEnv = {
|
||||||
|
...process.env,
|
||||||
|
...otherEnv,
|
||||||
|
PATH: `${path.join(HOME, '.cargo/bin')}:${toolchainPath}:${PATH}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
let cargoToml;
|
||||||
|
try {
|
||||||
|
cargoToml = await parseTOMLStream(files[entrypoint].toStream());
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to parse TOML from entrypoint:', entrypoint);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
const entrypointDirname = path.dirname(downloadedFiles[entrypoint].fsPath);
|
||||||
|
console.log('running `cargo build --release`...');
|
||||||
|
try {
|
||||||
|
await execa('cargo', ['build', '--release'], {
|
||||||
|
env: rustEnv,
|
||||||
|
cwd: entrypointDirname,
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error('failed to `cargo build --release`');
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetPath = path.join(workPath, 'target', 'release');
|
||||||
|
const binaries = await inferCargoBinaries(
|
||||||
|
cargoToml,
|
||||||
|
path.join(workPath, 'src'),
|
||||||
|
);
|
||||||
|
|
||||||
|
const lambdas = {};
|
||||||
|
await Promise.all(
|
||||||
|
binaries.map(async (binary) => {
|
||||||
|
const fsPath = path.join(targetPath, binary);
|
||||||
|
const lambda = await createLambda({
|
||||||
|
files: {
|
||||||
|
bootstrap: new FileFsRef({ mode: 0o755, fsPath }),
|
||||||
|
},
|
||||||
|
handler: 'bootstrap',
|
||||||
|
runtime: 'provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
lambdas[binary] = lambda;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return lambdas;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.prepareCache = async ({ cachePath, workPath }) => {
|
||||||
|
console.log('preparing cache...');
|
||||||
|
rimraf.sync(path.join(cachePath, 'target'));
|
||||||
|
fs.renameSync(path.join(workPath, 'target'), path.join(cachePath, 'target'));
|
||||||
|
|
||||||
|
return {
|
||||||
|
...(await glob('target/**', path.join(cachePath))),
|
||||||
|
};
|
||||||
|
};
|
||||||
73
packages/now-rust/inferCargoBinaries.js
Normal file
73
packages/now-rust/inferCargoBinaries.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
function readdir(dir) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fs.readdir(dir, (err, files) => {
|
||||||
|
if (err != null) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(files);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function exists(p) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fs.exists(p, (err, res) => {
|
||||||
|
if (err != null) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function stat(p) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fs.stat(p, (err, stats) => {
|
||||||
|
if (err != null) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(stats);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function inferCargoBinaries(cargoToml, srcDir) {
|
||||||
|
const { package: pkg, bin } = cargoToml;
|
||||||
|
const binaries = [];
|
||||||
|
const hasMain = (await readdir(srcDir)).includes('main.rs');
|
||||||
|
|
||||||
|
if (hasMain) {
|
||||||
|
binaries.push(pkg.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From: https://doc.rust-lang.org/cargo/reference/manifest.html#the-project-layout
|
||||||
|
// Do note, however, once you add a [[bin]] section (see below), Cargo will
|
||||||
|
// no longer automatically build files located in src/bin/*.rs. Instead you
|
||||||
|
// must create a [[bin]] section for each file you want to build.
|
||||||
|
if (Array.isArray(bin)) {
|
||||||
|
bin.forEach((binary) => {
|
||||||
|
binaries.push(binary.name);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const binDir = path.join(srcDir, 'bin');
|
||||||
|
const filesInSrcBin = (await exists(binDir)) && (await stat(binDir)).isDirectory()
|
||||||
|
? await readdir(binDir)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
filesInSrcBin.forEach((file) => {
|
||||||
|
if (file.endsWith('.rs')) {
|
||||||
|
binaries.push(file.slice(0, -3));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return binaries;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = inferCargoBinaries;
|
||||||
23
packages/now-rust/package.json
Normal file
23
packages/now-rust/package.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "@now/rust",
|
||||||
|
"version": "0.0.2-canary.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-rust"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"index.js",
|
||||||
|
"download-install-rust-toolchain.js",
|
||||||
|
"inferCargoBinaries.js"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"concat-stream": "^2.0.0",
|
||||||
|
"execa": "^1.0.0",
|
||||||
|
"node-fetch": "^2.3.0",
|
||||||
|
"rimraf": "^2.6.3",
|
||||||
|
"tar": "^4.4.8",
|
||||||
|
"toml": "^2.3.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
157
packages/now-rust/src/body.rs
Normal file
157
packages/now-rust/src/body.rs
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
//! Provides a Now Lambda oriented request and response body entity interface
|
||||||
|
|
||||||
|
use std::{borrow::Cow, ops::Deref};
|
||||||
|
|
||||||
|
use base64::display::Base64Display;
|
||||||
|
use serde::ser::{Error as SerError, Serialize, Serializer};
|
||||||
|
|
||||||
|
/// Representation of http request and response bodies as supported
|
||||||
|
/// by Zeit Now v2.
|
||||||
|
///
|
||||||
|
/// These come in three flavors
|
||||||
|
/// * `Empty` ( no body )
|
||||||
|
/// * `Text` ( text data )
|
||||||
|
/// * `Binary` ( binary data )
|
||||||
|
///
|
||||||
|
/// Body types can be `Deref` and `AsRef`'d into `[u8]` types much like the `hyper` crate
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Body types are inferred with `From` implementations.
|
||||||
|
///
|
||||||
|
/// ## Text
|
||||||
|
///
|
||||||
|
/// Types like `String`, `str` whose type reflects
|
||||||
|
/// text produce `Body::Text` variants
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// assert!(match now_lambda::Body::from("text") {
|
||||||
|
/// now_lambda::Body::Text(_) => true,
|
||||||
|
/// _ => false
|
||||||
|
/// })
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Binary
|
||||||
|
///
|
||||||
|
/// Types like `Vec<u8>` and `&[u8]` whose types reflect raw bytes produce `Body::Binary` variants
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// assert!(match now_lambda::Body::from("text".as_bytes()) {
|
||||||
|
/// now_lambda::Body::Binary(_) => true,
|
||||||
|
/// _ => false
|
||||||
|
/// })
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// `Binary` responses bodies will automatically get base64 encoded.
|
||||||
|
///
|
||||||
|
/// ## Empty
|
||||||
|
///
|
||||||
|
/// The unit type ( `()` ) whose type represents an empty value produces `Body::Empty` variants
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// assert!(match now_lambda::Body::from(()) {
|
||||||
|
/// now_lambda::Body::Empty => true,
|
||||||
|
/// _ => false
|
||||||
|
/// })
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Body {
|
||||||
|
/// An empty body
|
||||||
|
Empty,
|
||||||
|
/// A body containing string data
|
||||||
|
Text(String),
|
||||||
|
/// A body containing binary data
|
||||||
|
Binary(Vec<u8>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Body {
|
||||||
|
fn default() -> Self {
|
||||||
|
Body::Empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<()> for Body {
|
||||||
|
fn from(_: ()) -> Self {
|
||||||
|
Body::Empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for Body {
|
||||||
|
fn from(s: &'a str) -> Self {
|
||||||
|
Body::Text(s.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Body {
|
||||||
|
fn from(b: String) -> Self {
|
||||||
|
Body::Text(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Cow<'static, str>> for Body {
|
||||||
|
#[inline]
|
||||||
|
fn from(cow: Cow<'static, str>) -> Body {
|
||||||
|
match cow {
|
||||||
|
Cow::Borrowed(b) => Body::from(b.to_owned()),
|
||||||
|
Cow::Owned(o) => Body::from(o),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Cow<'static, [u8]>> for Body {
|
||||||
|
#[inline]
|
||||||
|
fn from(cow: Cow<'static, [u8]>) -> Body {
|
||||||
|
match cow {
|
||||||
|
Cow::Borrowed(b) => Body::from(b),
|
||||||
|
Cow::Owned(o) => Body::from(o),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<u8>> for Body {
|
||||||
|
fn from(b: Vec<u8>) -> Self {
|
||||||
|
Body::Binary(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a [u8]> for Body {
|
||||||
|
fn from(b: &'a [u8]) -> Self {
|
||||||
|
Body::Binary(b.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Body {
|
||||||
|
type Target = [u8];
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for Body {
|
||||||
|
#[inline]
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
match self {
|
||||||
|
Body::Empty => &[],
|
||||||
|
Body::Text(ref bytes) => bytes.as_ref(),
|
||||||
|
Body::Binary(ref bytes) => bytes.as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Serialize for Body {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Body::Text(data) => serializer
|
||||||
|
.serialize_str(::std::str::from_utf8(data.as_ref()).map_err(S::Error::custom)?),
|
||||||
|
Body::Binary(data) => {
|
||||||
|
serializer.collect_str(&Base64Display::with_config(data, base64::STANDARD))
|
||||||
|
}
|
||||||
|
Body::Empty => serializer.serialize_unit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
packages/now-rust/src/error.rs
Normal file
35
packages/now-rust/src/error.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use lambda_runtime::error::LambdaErrorExt;
|
||||||
|
use std::{error::Error, fmt};
|
||||||
|
|
||||||
|
/// This module implements a custom error currently over the AWS Lambda runtime,
|
||||||
|
/// which can be extended later to support more service providers.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NowError {
|
||||||
|
msg: String,
|
||||||
|
}
|
||||||
|
impl NowError {
|
||||||
|
pub fn new(message: &str) -> NowError {
|
||||||
|
NowError {
|
||||||
|
msg: message.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl fmt::Display for NowError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Error for NowError {}
|
||||||
|
impl From<std::num::ParseIntError> for NowError {
|
||||||
|
fn from(i: std::num::ParseIntError) -> Self {
|
||||||
|
NowError::new(&format!("{}", i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the value returned by the error_type function is included as the
|
||||||
|
// `errorType` in the AWS Lambda response
|
||||||
|
impl LambdaErrorExt for NowError {
|
||||||
|
fn error_type(&self) -> &str {
|
||||||
|
"NowError"
|
||||||
|
}
|
||||||
|
}
|
||||||
87
packages/now-rust/src/lib.rs
Normal file
87
packages/now-rust/src/lib.rs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
pub use http::{self, Response};
|
||||||
|
use lambda_runtime::{self as lambda, Context};
|
||||||
|
use log::{self, debug, error};
|
||||||
|
use serde_json::Error;
|
||||||
|
use tokio::runtime::Runtime as TokioRuntime;
|
||||||
|
|
||||||
|
mod body;
|
||||||
|
pub mod error;
|
||||||
|
pub mod request;
|
||||||
|
mod response;
|
||||||
|
mod strmap;
|
||||||
|
|
||||||
|
pub use crate::{body::Body, response::IntoResponse, strmap::StrMap};
|
||||||
|
use crate::{
|
||||||
|
error::NowError,
|
||||||
|
request::{NowEvent, NowRequest},
|
||||||
|
response::NowResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Type alias for `http::Request`s with a fixed `now_lambda::Body` body
|
||||||
|
pub type Request = http::Request<Body>;
|
||||||
|
|
||||||
|
/// Functions acting as Now Lambda handlers must conform to this type.
|
||||||
|
pub trait Handler<R> {
|
||||||
|
/// Method to execute the handler function
|
||||||
|
fn run(&mut self, event: Request) -> Result<R, NowError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Function, R> Handler<R> for Function
|
||||||
|
where
|
||||||
|
Function: FnMut(Request) -> Result<R, NowError>,
|
||||||
|
{
|
||||||
|
fn run(&mut self, event: Request) -> Result<R, NowError> {
|
||||||
|
(*self)(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new `lambda_runtime::Runtime` and begins polling for Now Lambda events
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `f` A type that conforms to the `Handler` interface.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// The function panics if the Lambda environment variables are not set.
|
||||||
|
pub fn start<R>(f: impl Handler<R>, runtime: Option<TokioRuntime>)
|
||||||
|
where
|
||||||
|
R: IntoResponse,
|
||||||
|
{
|
||||||
|
// handler requires a mutable ref
|
||||||
|
let mut func = f;
|
||||||
|
lambda::start(
|
||||||
|
|e: NowEvent, _ctx: Context| {
|
||||||
|
let req_str = e.body;
|
||||||
|
let parse_result: Result<NowRequest, Error> = serde_json::from_str(&req_str);
|
||||||
|
match parse_result {
|
||||||
|
Ok(req) => {
|
||||||
|
debug!("Deserialized Now proxy request successfully");
|
||||||
|
func.run(req.into())
|
||||||
|
.map(|resp| NowResponse::from(resp.into_response()))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Could not deserialize event body to NowRequest {}", e);
|
||||||
|
panic!("Could not deserialize event body to NowRequest {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
runtime,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A macro for starting new handler's poll for Now Lambda events
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! lambda {
|
||||||
|
($handler:expr) => {
|
||||||
|
$crate::start($handler, None)
|
||||||
|
};
|
||||||
|
($handler:expr, $runtime:expr) => {
|
||||||
|
$crate::start($handler, Some($runtime))
|
||||||
|
};
|
||||||
|
($handler:ident) => {
|
||||||
|
$crate::start($handler, None)
|
||||||
|
};
|
||||||
|
($handler:ident, $runtime:expr) => {
|
||||||
|
$crate::start($handler, Some($runtime))
|
||||||
|
};
|
||||||
|
}
|
||||||
139
packages/now-rust/src/request.rs
Normal file
139
packages/now-rust/src/request.rs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
use std::{borrow::Cow, fmt, mem};
|
||||||
|
|
||||||
|
use http::{self, header::HeaderValue, HeaderMap, Method, Request as HttpRequest};
|
||||||
|
use serde::{
|
||||||
|
de::{Error as DeError, MapAccess, Visitor},
|
||||||
|
Deserialize, Deserializer,
|
||||||
|
};
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use crate::body::Body;
|
||||||
|
|
||||||
|
/// Representation of a Now Lambda proxy event data
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Deserialize, Debug, Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub(crate) struct NowRequest<'a> {
|
||||||
|
pub(crate) host: Cow<'a, str>,
|
||||||
|
pub(crate) path: Cow<'a, str>,
|
||||||
|
#[serde(deserialize_with = "deserialize_method")]
|
||||||
|
pub(crate) method: Method,
|
||||||
|
#[serde(deserialize_with = "deserialize_headers")]
|
||||||
|
pub(crate) headers: HeaderMap<HeaderValue>,
|
||||||
|
pub(crate) body: Option<Cow<'a, str>>,
|
||||||
|
pub(crate) encoding: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Deserialize, Debug, Default)]
|
||||||
|
pub(crate) struct NowEvent<'a> {
|
||||||
|
#[serde(rename = "Action")]
|
||||||
|
action: Cow<'a, str>,
|
||||||
|
pub(crate) body: Cow<'a, str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_method<'de, D>(deserializer: D) -> Result<Method, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct MethodVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for MethodVisitor {
|
||||||
|
type Value = Method;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(formatter, "a Method")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: DeError,
|
||||||
|
{
|
||||||
|
v.parse().map_err(E::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(MethodVisitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_headers<'de, D>(deserializer: D) -> Result<HeaderMap<HeaderValue>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct HeaderVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for HeaderVisitor {
|
||||||
|
type Value = HeaderMap<HeaderValue>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(formatter, "a HeaderMap<HeaderValue>")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut headers = http::HeaderMap::new();
|
||||||
|
while let Some((key, value)) = map.next_entry::<Cow<'_, str>, Cow<'_, str>>()? {
|
||||||
|
let header_name = key
|
||||||
|
.parse::<http::header::HeaderName>()
|
||||||
|
.map_err(A::Error::custom)?;
|
||||||
|
let header_value =
|
||||||
|
http::header::HeaderValue::from_shared(value.into_owned().into())
|
||||||
|
.map_err(A::Error::custom)?;
|
||||||
|
headers.append(header_name, header_value);
|
||||||
|
}
|
||||||
|
Ok(headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_map(HeaderVisitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// deserializes (json) null values to their default values
|
||||||
|
// https://github.com/serde-rs/serde/issues/1098
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn nullable_default<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
T: Default + Deserialize<'de>,
|
||||||
|
{
|
||||||
|
let opt = Option::deserialize(deserializer)?;
|
||||||
|
Ok(opt.unwrap_or_else(T::default))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<NowRequest<'a>> for HttpRequest<Body> {
|
||||||
|
fn from(value: NowRequest<'_>) -> Self {
|
||||||
|
let NowRequest {
|
||||||
|
host,
|
||||||
|
path,
|
||||||
|
method,
|
||||||
|
headers,
|
||||||
|
body,
|
||||||
|
encoding,
|
||||||
|
} = value;
|
||||||
|
|
||||||
|
// build an http::Request<now_lambda::Body> from a now_lambda::NowRequest
|
||||||
|
let mut builder = HttpRequest::builder();
|
||||||
|
builder.method(method);
|
||||||
|
builder.uri({ format!("https://{}{}", host, path) });
|
||||||
|
|
||||||
|
let mut req = builder
|
||||||
|
.body(match (body, encoding) {
|
||||||
|
(Some(ref b), Some(ref encoding)) if encoding == "base64" => {
|
||||||
|
// todo: document failure behavior
|
||||||
|
Body::from(::base64::decode(b.as_ref()).unwrap_or_default())
|
||||||
|
}
|
||||||
|
(Some(b), Some(_)) => Body::from(b.into_owned()),
|
||||||
|
_ => Body::from(()),
|
||||||
|
})
|
||||||
|
.expect("failed to build request");
|
||||||
|
|
||||||
|
// no builder method that sets headers in batch
|
||||||
|
mem::replace(req.headers_mut(), headers);
|
||||||
|
|
||||||
|
req
|
||||||
|
}
|
||||||
|
}
|
||||||
125
packages/now-rust/src/response.rs
Normal file
125
packages/now-rust/src/response.rs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
//! Response types
|
||||||
|
|
||||||
|
use http::{
|
||||||
|
header::{HeaderMap, HeaderValue},
|
||||||
|
Response,
|
||||||
|
};
|
||||||
|
use serde::{
|
||||||
|
ser::{Error as SerError, SerializeMap},
|
||||||
|
Serializer,
|
||||||
|
};
|
||||||
|
use serde_derive::Serialize;
|
||||||
|
|
||||||
|
use crate::body::Body;
|
||||||
|
|
||||||
|
/// Representation of a Now Lambda response
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub(crate) struct NowResponse {
|
||||||
|
pub status_code: u16,
|
||||||
|
#[serde(
|
||||||
|
skip_serializing_if = "HeaderMap::is_empty",
|
||||||
|
serialize_with = "serialize_headers"
|
||||||
|
)]
|
||||||
|
pub headers: HeaderMap<HeaderValue>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub body: Option<Body>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub encoding: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for NowResponse {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
status_code: 200,
|
||||||
|
headers: Default::default(),
|
||||||
|
body: Default::default(),
|
||||||
|
encoding: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_headers<S>(headers: &HeaderMap<HeaderValue>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let mut map = serializer.serialize_map(Some(headers.keys_len()))?;
|
||||||
|
for key in headers.keys() {
|
||||||
|
let map_value = headers[key].to_str().map_err(S::Error::custom)?;
|
||||||
|
map.serialize_entry(key.as_str(), map_value)?;
|
||||||
|
}
|
||||||
|
map.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Response<T>> for NowResponse
|
||||||
|
where
|
||||||
|
T: Into<Body>,
|
||||||
|
{
|
||||||
|
fn from(value: Response<T>) -> Self {
|
||||||
|
let (parts, bod) = value.into_parts();
|
||||||
|
let (encoding, body) = match bod.into() {
|
||||||
|
Body::Empty => (None, None),
|
||||||
|
b @ Body::Text(_) => (None, Some(b)),
|
||||||
|
b @ Body::Binary(_) => (Some("base64".to_string()), Some(b)),
|
||||||
|
};
|
||||||
|
NowResponse {
|
||||||
|
status_code: parts.status.as_u16(),
|
||||||
|
body,
|
||||||
|
headers: parts.headers,
|
||||||
|
encoding,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A conversion of self into a `Response`
|
||||||
|
///
|
||||||
|
/// Implementations for `Response<B> where B: Into<Body>`,
|
||||||
|
/// `B where B: Into<Body>` and `serde_json::Value` are provided
|
||||||
|
/// by default
|
||||||
|
///
|
||||||
|
/// # example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use now_lambda::{Body, IntoResponse, Response};
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// "hello".into_response().body(),
|
||||||
|
/// Response::new(Body::from("hello")).body()
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
pub trait IntoResponse {
|
||||||
|
/// Return a translation of `self` into a `Response<Body>`
|
||||||
|
fn into_response(self) -> Response<Body>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B> IntoResponse for Response<B>
|
||||||
|
where
|
||||||
|
B: Into<Body>,
|
||||||
|
{
|
||||||
|
fn into_response(self) -> Response<Body> {
|
||||||
|
let (parts, body) = self.into_parts();
|
||||||
|
Response::from_parts(parts, body.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B> IntoResponse for B
|
||||||
|
where
|
||||||
|
B: Into<Body>,
|
||||||
|
{
|
||||||
|
fn into_response(self) -> Response<Body> {
|
||||||
|
Response::new(self.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoResponse for serde_json::Value {
|
||||||
|
fn into_response(self) -> Response<Body> {
|
||||||
|
Response::builder()
|
||||||
|
.header(http::header::CONTENT_TYPE, "application/json")
|
||||||
|
.body(
|
||||||
|
serde_json::to_string(&self)
|
||||||
|
.expect("unable to serialize serde_json::Value")
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.expect("unable to build http::Response")
|
||||||
|
}
|
||||||
|
}
|
||||||
93
packages/now-rust/src/strmap.rs
Normal file
93
packages/now-rust/src/strmap.rs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
use std::{
|
||||||
|
collections::{hash_map::Keys, HashMap},
|
||||||
|
fmt,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serde::{
|
||||||
|
de::{MapAccess, Visitor},
|
||||||
|
Deserialize, Deserializer,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A read-only view into a map of string data
|
||||||
|
#[derive(Default, Debug, PartialEq)]
|
||||||
|
pub struct StrMap(pub(crate) Arc<HashMap<String, String>>);
|
||||||
|
|
||||||
|
impl StrMap {
|
||||||
|
/// Return a named value where available
|
||||||
|
pub fn get(&self, key: &str) -> Option<&str> {
|
||||||
|
self.0.get(key).map(|value| value.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true if the underlying map is empty
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return an iterator over keys and values
|
||||||
|
pub fn iter(&self) -> StrMapIter<'_> {
|
||||||
|
StrMapIter {
|
||||||
|
data: self,
|
||||||
|
keys: self.0.keys(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for StrMap {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
// only clone the inner data
|
||||||
|
StrMap(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<HashMap<String, String>> for StrMap {
|
||||||
|
fn from(inner: HashMap<String, String>) -> Self {
|
||||||
|
StrMap(Arc::new(inner))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A read only reference to `StrMap` key and value slice pairings
|
||||||
|
pub struct StrMapIter<'a> {
|
||||||
|
data: &'a StrMap,
|
||||||
|
keys: Keys<'a, String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for StrMapIter<'a> {
|
||||||
|
type Item = (&'a str, &'a str);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<(&'a str, &'a str)> {
|
||||||
|
self.keys
|
||||||
|
.next()
|
||||||
|
.and_then(|k| self.data.get(k).map(|v| (k.as_str(), v)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for StrMap {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<StrMap, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct StrMapVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for StrMapVisitor {
|
||||||
|
type Value = StrMap;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(formatter, "a StrMap")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut inner = HashMap::new();
|
||||||
|
while let Some((key, value)) = map.next_entry()? {
|
||||||
|
inner.insert(key, value);
|
||||||
|
}
|
||||||
|
Ok(StrMap(Arc::new(inner)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_map(StrMapVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
154
packages/now-rust/test/test.js
Normal file
154
packages/now-rust/test/test.js
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
/* global afterAll, beforeAll, describe, expect, it, jest */
|
||||||
|
const fs = require('fs');
|
||||||
|
const inferCargoBinaries = require('../inferCargoBinaries');
|
||||||
|
|
||||||
|
const { exists, readdir, stat } = fs;
|
||||||
|
const isDir = fs.Stats.prototype.isDirectory;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
fs.exists = jest.fn((p, cb) => cb(null, false));
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
fs.readdir = readdir;
|
||||||
|
fs.stat = stat;
|
||||||
|
fs.Stats.prototype.isDirectory = isDir;
|
||||||
|
fs.exists = exists;
|
||||||
|
});
|
||||||
|
|
||||||
|
// src/
|
||||||
|
// |- main.rs
|
||||||
|
describe('one binary, src/main.rs', async () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
fs.readdir = jest.fn((p, cb) => cb(null, ['main.rs']));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('infers only one binary', async () => {
|
||||||
|
const toml = {
|
||||||
|
package: {
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(inferCargoBinaries(toml, '/path/to/src')).resolves.toEqual(['foo']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// [[bin]] sections in `Cargo.toml`
|
||||||
|
// `main.rs` -> `package.name`
|
||||||
|
// `bar.rs` -> `bin.name`
|
||||||
|
// src/
|
||||||
|
// |- bar.rs
|
||||||
|
// |- main.rs
|
||||||
|
describe('two binaries, src/main.rs, src/bar.rs', async () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
fs.readdir = jest.fn((p, cb) => cb(null, ['main.rs', 'bar.rs']));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('infers two binaries', async () => {
|
||||||
|
const toml = {
|
||||||
|
package: {
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
bin: [{ name: 'bar', path: 'src/bar.rs' }],
|
||||||
|
};
|
||||||
|
expect((await inferCargoBinaries(toml, '/path/to/src')).sort()).toEqual([
|
||||||
|
'bar',
|
||||||
|
'foo',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// no main.rs
|
||||||
|
// src/
|
||||||
|
// |- foo.rs
|
||||||
|
describe('one named binary, no main.rs', async () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
fs.readdir = jest.fn((p, cb) => cb(null, ['bar.rs']));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('infers only one binary', async () => {
|
||||||
|
const toml = {
|
||||||
|
package: {
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
bin: [{ name: 'bar', path: 'src/bar.rs' }],
|
||||||
|
};
|
||||||
|
expect((await inferCargoBinaries(toml, '/path/to/src')).sort()).toEqual([
|
||||||
|
'bar',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// `src/bin` folder
|
||||||
|
// src/
|
||||||
|
// |- bin/
|
||||||
|
// | |- bar.rs
|
||||||
|
// | |- baz.rs
|
||||||
|
// |- main.rs
|
||||||
|
describe('multiple binaries in bin/, no [[bin]] section', async () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
fs.readdir = jest.fn((p, cb) => {
|
||||||
|
if (p === '/path/to/src') {
|
||||||
|
return cb(null, ['bin', 'main.rs']);
|
||||||
|
}
|
||||||
|
if (p === '/path/to/src/bin') {
|
||||||
|
return cb(null, ['bar.rs', 'baz.rs']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cb('some error');
|
||||||
|
});
|
||||||
|
fs.exists = jest.fn((p, cb) => cb(null, p.endsWith('bin')));
|
||||||
|
fs.stat = jest.fn((_, cb) => cb(null, new fs.Stats()));
|
||||||
|
fs.Stats.prototype.isDirectory = jest.fn(() => true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('infers three binaries', async () => {
|
||||||
|
const toml = {
|
||||||
|
package: {
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect((await inferCargoBinaries(toml, '/path/to/src')).sort()).toEqual([
|
||||||
|
'bar',
|
||||||
|
'baz',
|
||||||
|
'foo',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// `src/bin` folder, bin sections ignore baz.rs
|
||||||
|
// src/
|
||||||
|
// |- bin/
|
||||||
|
// | |- bar.rs
|
||||||
|
// | |- baz.rs
|
||||||
|
// |- main.rs
|
||||||
|
describe('src/bin exists but one binary is ignored', async () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
fs.readdir = jest.fn((p, cb) => {
|
||||||
|
if (p === '/path/to/src') {
|
||||||
|
return cb(null, ['bin', 'main.rs']);
|
||||||
|
}
|
||||||
|
if (p === '/path/to/src/bin') {
|
||||||
|
return cb(null, ['bar.rs', 'baz.rs']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cb('some error');
|
||||||
|
});
|
||||||
|
fs.exists = jest.fn((p, cb) => cb(null, p.endsWith('bin')));
|
||||||
|
fs.stat = jest.fn((_, cb) => cb(null, new fs.Stats()));
|
||||||
|
fs.Stats.prototype.isDirectory = jest.fn(() => true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('infers only one binary', async () => {
|
||||||
|
const toml = {
|
||||||
|
package: {
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
bin: [{ name: 'bar', path: 'src/bar.rs' }],
|
||||||
|
};
|
||||||
|
expect((await inferCargoBinaries(toml, '/path/to/src')).sort()).toEqual([
|
||||||
|
'bar',
|
||||||
|
'foo',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
const download = require('@now/build-utils/fs/download.js');
|
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const glob = require('@now/build-utils/fs/glob.js');
|
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const {
|
const {
|
||||||
runNpmInstall,
|
runNpmInstall,
|
||||||
runPackageJsonScript,
|
runPackageJsonScript,
|
||||||
runShellScript,
|
runShellScript,
|
||||||
} = require('@now/build-utils/fs/run-user-scripts.js');
|
} = require('@now/build-utils/fs/run-user-scripts.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
exports.build = async ({
|
exports.build = async ({
|
||||||
files, entrypoint, workPath, config,
|
files, entrypoint, workPath, config,
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/static-build",
|
"name": "@now/static-build",
|
||||||
"version": "0.4.17",
|
"version": "0.4.18-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"repository": {
|
||||||
"@now/build-utils": ">=0.0.1"
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-static-build"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const { createLambda } = require('@now/build-utils/lambda.js');
|
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
const FileBlob = require('@now/build-utils/file-blob.js');
|
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const { getFiles } = require('@now/php-bridge');
|
const { getFiles } = require('@now/php-bridge');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const rename = require('@now/build-utils/fs/rename.js');
|
const rename = require('@now/build-utils/fs/rename.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const streamToBuffer = require('@now/build-utils/fs/stream-to-buffer.js');
|
const streamToBuffer = require('@now/build-utils/fs/stream-to-buffer.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
const yauzl = require('yauzl');
|
const yauzl = require('yauzl');
|
||||||
|
|
||||||
exports.config = {
|
exports.config = {
|
||||||
@@ -16,7 +16,9 @@ async function readReleaseUrl(releaseUrl) {
|
|||||||
const resp = await fetch(releaseUrl);
|
const resp = await fetch(releaseUrl);
|
||||||
|
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
throw new Error(`Failed to download ${releaseUrl}. Status code is ${resp.status}`);
|
throw new Error(
|
||||||
|
`Failed to download ${releaseUrl}. Status code is ${resp.status}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.buffer();
|
return resp.buffer();
|
||||||
@@ -49,13 +51,15 @@ function decompressBuffer(buffer, mountpoint) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
streamToBuffer(readStream).then((data) => {
|
streamToBuffer(readStream)
|
||||||
assert(prefixRegexp.test(fileName), fileName);
|
.then((data) => {
|
||||||
const fileName2 = fileName.replace(prefixRegexp, '');
|
assert(prefixRegexp.test(fileName), fileName);
|
||||||
const fileName3 = path.join(mountpoint, fileName2);
|
const fileName2 = fileName.replace(prefixRegexp, '');
|
||||||
files[fileName3] = new FileBlob({ data });
|
const fileName3 = path.join(mountpoint, fileName2);
|
||||||
zipfile.readEntry();
|
files[fileName3] = new FileBlob({ data });
|
||||||
}).catch(reject);
|
zipfile.readEntry();
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -65,12 +69,22 @@ function decompressBuffer(buffer, mountpoint) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const staticRegexps = [
|
const staticRegexps = [
|
||||||
/\.css$/, /\.gif$/, /\.ico$/, /\.js$/, /\.jpg$/, /\.png$/, /\.svg$/, /\.woff$/, /\.woff2$/,
|
/\.css$/,
|
||||||
|
/\.gif$/,
|
||||||
|
/\.ico$/,
|
||||||
|
/\.js$/,
|
||||||
|
/\.jpg$/,
|
||||||
|
/\.png$/,
|
||||||
|
/\.svg$/,
|
||||||
|
/\.woff$/,
|
||||||
|
/\.woff2$/,
|
||||||
];
|
];
|
||||||
|
|
||||||
exports.build = async ({ files, entrypoint, config }) => {
|
exports.build = async ({ files, entrypoint, config }) => {
|
||||||
if (path.basename(entrypoint) !== 'wp-config.php') {
|
if (path.basename(entrypoint) !== 'wp-config.php') {
|
||||||
throw new Error(`Entrypoint file name must be "wp-config.php". Currently it is ${entrypoint}`);
|
throw new Error(
|
||||||
|
`Entrypoint file name must be "wp-config.php". Currently it is ${entrypoint}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { releaseUrl = 'https://wordpress.org/latest.zip' } = config;
|
const { releaseUrl = 'https://wordpress.org/latest.zip' } = config;
|
||||||
@@ -84,9 +98,12 @@ exports.build = async ({ files, entrypoint, config }) => {
|
|||||||
if (config.patchForPersistentConnections) {
|
if (config.patchForPersistentConnections) {
|
||||||
const wpDbPhp = path.join(mountpoint, 'wp-includes/wp-db.php');
|
const wpDbPhp = path.join(mountpoint, 'wp-includes/wp-db.php');
|
||||||
const wpDbPhpBlob = mergedFiles[wpDbPhp];
|
const wpDbPhpBlob = mergedFiles[wpDbPhp];
|
||||||
wpDbPhpBlob.data = wpDbPhpBlob.data.toString()
|
wpDbPhpBlob.data = wpDbPhpBlob.data
|
||||||
.replace(/mysqli_real_connect\( \$this->dbh, \$host,/g,
|
.toString()
|
||||||
'mysqli_real_connect( $this->dbh, \'p:\' . $host,');
|
.replace(
|
||||||
|
/mysqli_real_connect\( \$this->dbh, \$host,/g,
|
||||||
|
"mysqli_real_connect( $this->dbh, 'p:' . $host,",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const staticFiles = {};
|
const staticFiles = {};
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/wordpress",
|
"name": "@now/wordpress",
|
||||||
"version": "0.4.14",
|
"version": "0.4.15-canary.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now-builders.git",
|
||||||
|
"directory": "packages/now-wordpress"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@now/php-bridge": "^0.4.13",
|
"@now/php-bridge": "^0.4.14-canary.0",
|
||||||
"node-fetch": "2.3.0",
|
"node-fetch": "2.3.0",
|
||||||
"yauzl": "2.10.0"
|
"yauzl": "2.10.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
|
||||||
"@now/build-utils": ">=0.0.1"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ async function packAndDeploy (builderPath) {
|
|||||||
|
|
||||||
const RANDOMNESS_PLACEHOLDER_STRING = 'RANDOMNESS_PLACEHOLDER';
|
const RANDOMNESS_PLACEHOLDER_STRING = 'RANDOMNESS_PLACEHOLDER';
|
||||||
|
|
||||||
async function testDeployment ({ builderUrl, buildUtilsUrl }, fixturePath) {
|
async function testDeployment ({ builderUrl, buildUtilsUrl }, fixturePath, buildDelegate) {
|
||||||
console.log('testDeployment', fixturePath);
|
console.log('testDeployment', fixturePath);
|
||||||
const globResult = await glob(`${fixturePath}/**`, { nodir: true });
|
const globResult = await glob(`${fixturePath}/**`, { nodir: true });
|
||||||
const bodies = globResult.reduce((b, f) => {
|
const bodies = globResult.reduce((b, f) => {
|
||||||
@@ -63,6 +63,10 @@ async function testDeployment ({ builderUrl, buildUtilsUrl }, fixturePath) {
|
|||||||
config.useBuildUtils = `https://${buildUtilsUrl}`;
|
config.useBuildUtils = `https://${buildUtilsUrl}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buildDelegate) {
|
||||||
|
buildDelegate(build);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bodies['now.json'] = Buffer.from(JSON.stringify(nowJson));
|
bodies['now.json'] = Buffer.from(JSON.stringify(nowJson));
|
||||||
@@ -84,7 +88,8 @@ async function testDeployment ({ builderUrl, buildUtilsUrl }, fixturePath) {
|
|||||||
if (!text.includes(probe.mustContain)) {
|
if (!text.includes(probe.mustContain)) {
|
||||||
await fs.writeFile(path.join(__dirname, 'failed-page.txt'), text);
|
await fs.writeFile(path.join(__dirname, 'failed-page.txt'), text);
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Fetched page ${probeUrl} does not contain ${probe.mustContain}`
|
`Fetched page ${probeUrl} does not contain ${probe.mustContain}.`
|
||||||
|
+ ` Instead it contains ${text.slice(0, 60)}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -113,7 +118,8 @@ async function fetchDeploymentUrl (url, opts) {
|
|||||||
for (let i = 0; i < 500; i += 1) {
|
for (let i = 0; i < 500; i += 1) {
|
||||||
const resp = await fetch(url, opts);
|
const resp = await fetch(url, opts);
|
||||||
const text = await resp.text();
|
const text = await resp.text();
|
||||||
if (text && !text.includes('Join Free')) {
|
if (text && !text.includes('Join Free')
|
||||||
|
&& !text.includes('The page could not be found')) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const {
|
|||||||
excludeStaticDirectory,
|
excludeStaticDirectory,
|
||||||
onlyStaticDirectory,
|
onlyStaticDirectory,
|
||||||
} = require('@now/next/utils');
|
} = require('@now/next/utils');
|
||||||
const FileRef = require('@now/build-utils/file-ref');
|
const FileRef = require('@now/build-utils/file-ref'); // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
|
||||||
describe('excludeFiles', () => {
|
describe('excludeFiles', () => {
|
||||||
it('should exclude files', () => {
|
it('should exclude files', () => {
|
||||||
|
|||||||
42
yarn.lock
42
yarn.lock
@@ -1780,6 +1780,16 @@ concat-stream@^1.4.6, concat-stream@^1.4.7, concat-stream@^1.5.0, concat-stream@
|
|||||||
readable-stream "^2.2.2"
|
readable-stream "^2.2.2"
|
||||||
typedarray "^0.0.6"
|
typedarray "^0.0.6"
|
||||||
|
|
||||||
|
concat-stream@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1"
|
||||||
|
integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==
|
||||||
|
dependencies:
|
||||||
|
buffer-from "^1.0.0"
|
||||||
|
inherits "^2.0.3"
|
||||||
|
readable-stream "^3.0.2"
|
||||||
|
typedarray "^0.0.6"
|
||||||
|
|
||||||
config-chain@^1.1.11:
|
config-chain@^1.1.11:
|
||||||
version "1.1.12"
|
version "1.1.12"
|
||||||
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa"
|
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa"
|
||||||
@@ -6741,6 +6751,15 @@ read@1, read@~1.0.1:
|
|||||||
isarray "0.0.1"
|
isarray "0.0.1"
|
||||||
string_decoder "~0.10.x"
|
string_decoder "~0.10.x"
|
||||||
|
|
||||||
|
readable-stream@^3.0.2:
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06"
|
||||||
|
integrity sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==
|
||||||
|
dependencies:
|
||||||
|
inherits "^2.0.3"
|
||||||
|
string_decoder "^1.1.1"
|
||||||
|
util-deprecate "^1.0.1"
|
||||||
|
|
||||||
readable-stream@~1.1.9:
|
readable-stream@~1.1.9:
|
||||||
version "1.1.14"
|
version "1.1.14"
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
|
||||||
@@ -7046,6 +7065,13 @@ rimraf@2, rimraf@^2.2.6, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.
|
|||||||
dependencies:
|
dependencies:
|
||||||
glob "^7.0.5"
|
glob "^7.0.5"
|
||||||
|
|
||||||
|
rimraf@^2.6.3:
|
||||||
|
version "2.6.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
|
||||||
|
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
|
||||||
|
dependencies:
|
||||||
|
glob "^7.1.3"
|
||||||
|
|
||||||
rmfr@2.0.0:
|
rmfr@2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/rmfr/-/rmfr-2.0.0.tgz#8a42e81332550b3f0019b8fb8ab245bea81b6d1c"
|
resolved "https://registry.yarnpkg.com/rmfr/-/rmfr-2.0.0.tgz#8a42e81332550b3f0019b8fb8ab245bea81b6d1c"
|
||||||
@@ -7539,6 +7565,13 @@ string-width@^1.0.1:
|
|||||||
is-fullwidth-code-point "^2.0.0"
|
is-fullwidth-code-point "^2.0.0"
|
||||||
strip-ansi "^4.0.0"
|
strip-ansi "^4.0.0"
|
||||||
|
|
||||||
|
string_decoder@^1.1.1:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
|
||||||
|
integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
|
||||||
|
dependencies:
|
||||||
|
safe-buffer "~5.1.0"
|
||||||
|
|
||||||
string_decoder@~0.10.x:
|
string_decoder@~0.10.x:
|
||||||
version "0.10.31"
|
version "0.10.31"
|
||||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
||||||
@@ -7746,7 +7779,7 @@ tar@^2.0.0:
|
|||||||
fstream "^1.0.2"
|
fstream "^1.0.2"
|
||||||
inherits "2"
|
inherits "2"
|
||||||
|
|
||||||
tar@^4, tar@^4.4.6:
|
tar@^4, tar@^4.4.6, tar@^4.4.8:
|
||||||
version "4.4.8"
|
version "4.4.8"
|
||||||
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
|
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
|
||||||
integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
|
integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
|
||||||
@@ -7903,6 +7936,11 @@ to-regex@^3.0.1, to-regex@^3.0.2:
|
|||||||
regex-not "^1.0.2"
|
regex-not "^1.0.2"
|
||||||
safe-regex "^1.1.0"
|
safe-regex "^1.1.0"
|
||||||
|
|
||||||
|
toml@^2.3.3:
|
||||||
|
version "2.3.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/toml/-/toml-2.3.6.tgz#25b0866483a9722474895559088b436fd11f861b"
|
||||||
|
integrity sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ==
|
||||||
|
|
||||||
tough-cookie@>=2.3.3, tough-cookie@^2.3.4:
|
tough-cookie@>=2.3.3, tough-cookie@^2.3.4:
|
||||||
version "2.5.0"
|
version "2.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||||
@@ -8198,7 +8236,7 @@ use@^3.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
|
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
|
||||||
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
|
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
|
||||||
|
|
||||||
util-deprecate@~1.0.1:
|
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||||
|
|||||||
Reference in New Issue
Block a user