Compare commits

...

33 Commits

Author SHA1 Message Date
Steven
89172a6e89 Publish
- @now/go@0.5.0
 - @now/next@0.4.0
 - @now/node-bridge@1.1.3
 - @now/node-server@0.7.3
 - @now/node@0.7.3
 - @now/python@0.2.4
 - @now/static-build@0.5.7
2019-05-24 12:29:57 -04:00
Steven
e8f1dbaa46 Empty commit to satisfy lerna 2019-05-24 12:27:37 -04:00
Sophearak Tha
16b5b6fdf3 Publish
- @now/python@0.2.4-canary.2
2019-05-24 20:59:19 +07:00
Sophearak Tha
3bab29ff76 Add custom path and proper check (#527)
* Add custom path and proper check

* Change route tests to use another name
2019-05-24 20:55:28 +07:00
Sophearak Tha
d675d2e668 Use unquote() for http handler (#525)
* Use unquote() for http handler

* Add tests for url params http handler
2019-05-24 20:27:44 +07:00
Joe Haddad
2dda88e676 Publish
- @now/next@0.3.4-canary.4
2019-05-23 15:32:28 -07:00
Joe Haddad
5a0090eb1f [now-next] Ensure route begins with a slash (#524)
* Ensure route begins with a slash

* Simplift

* Apply suggestions from code review

Co-Authored-By: Connor Davis <mail@connordav.is>

* Adjust spacing
2019-05-23 15:31:13 -07:00
Sophearak Tha
d438b4ec4e Publish
- @now/go@0.4.8-canary.1
 - @now/python@0.2.4-canary.1
2019-05-23 20:34:53 +07:00
Sophearak Tha
f8810fd7e6 [now-python] Make sure to pass decode url params (#496)
* Make sure to pass decode url params

* Add tests cover default and custom routes behaviour on url param

* Removed `unquote` since `urlparse` already return expected value

* Using unquote in both PATH_INFO and QUERY_STRING

* Better code structure now_init.py

* Better test
2019-05-23 09:27:44 -04:00
Sophearak Tha
a642cfea96 [now-go] Add option to use private Git for go get (#513)
* Add option to use private Git

* Update packages/now-go/index.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Fix import error

* Using `GIT_CREDENTIALS` over multiple env vars

* Ignore initialize Git credentials in `meta.isDev`
2019-05-23 11:39:36 +07:00
Joe Haddad
2daa20a9f2 Publish
- @now/next@0.3.4-canary.3
2019-05-22 18:36:15 -07:00
JJ Kasper
4d5c0c40f0 [now-next] Update to use routes for static pages (#521) 2019-05-22 20:25:10 -05:00
Joe Haddad
29051681df Publish
- @now/next@0.3.4-canary.2
2019-05-22 16:18:59 -07:00
JJ Kasper
96d5e81538 [now-next] Handle statically exported pages (#520)
* Add support for auto exported pages

* Add entryDirectory to staticPages mapping

* Map to FsFileRef instead of path
2019-05-22 16:14:24 -07:00
Steven
9ba9dd6949 Publish
- @now/go@0.4.8-canary.0
 - @now/next@0.3.4-canary.1
 - @now/node-bridge@1.1.3-canary.0
 - @now/node-server@0.7.3-canary.0
 - @now/node@0.7.3-canary.0
 - @now/python@0.2.4-canary.0
2019-05-22 15:11:27 -04:00
Steven
b362d57270 [now-node-bridge] Disable callbackWaitsForEmptyEventLoop (#505)
* [now-node] Disable callbackWaitsForEmptyEventLoop

* Fix unit tests
2019-05-22 15:06:02 -04:00
Nathan Rajlich
4ff95e1718 Publish
- @now/go@0.4.7
 - @now/python@0.2.3
2019-05-20 12:40:51 -07:00
Sophearak Tha
ef02bedd4d Publish
- @now/python@0.2.3-canary.0
2019-05-20 23:54:04 +07:00
Sophearak Tha
ed68a09c3e Make sure cwd user clean by using cwd/.now (#516) 2019-05-20 23:53:03 +07:00
Leo Lamprecht
ac7ae5fc5d Run only tests for packages that changed (#515) 2019-05-20 18:10:42 +02:00
Sophearak Tha
9727b1f020 Publish
- @now/go@0.4.7-canary.1
2019-05-20 21:30:41 +07:00
Sophearak Tha
2dc454f15f [now-go] Give user descriptive error message when Go Modules not available (#514)
* Give user descriptive error message when Go Modules not available

* Include go1.11 onward
2019-05-20 21:29:36 +07:00
Sophearak Tha
4463af5c7a Publish
- @now/go@0.4.7-canary.0
 - @now/next@0.3.4-canary.0
2019-05-20 18:56:19 +07:00
Sophearak Tha
c00fb37cf6 [now-go] Use meta in download() (#495)
* Use meta in `download()`

* better handling cwd

* Ignore .now in during parsing entrypoint

* Make re-built faster
2019-05-20 18:52:50 +07:00
Marcel Haupenthal
4deb426f9c [now-go] Ignore folders in analyze.go (#503)(#504) (#506)
* [now-go] Ignore folders in `analyze.go` (#503)(#504)

This commit adds some changes to the way the AST for the source is
built.

The `analyze.go` program now ignores every `vendor`, `.git` and
`testdata` folder. This improves performance, since `vendor` and `.git`
are usually large folders (#504).

By ignoring `testdata`, we mimick the behaviour of `go build` and avoid
failing the parsing because of invalid Go code inside of `testdata` (#503)

* [now-go] Don't ignore `.git` in analyze (#506)

If the user wants to ignore `.git`, he should put it into `.nowignore`
2019-05-17 13:02:20 +07:00
Nathan Rajlich
008b04413a Publish
- @now/next@0.3.3
2019-05-16 11:49:42 -07:00
Nathan Rajlich
f177ba46e9 Publish
- @now/next@0.3.3-canary.0
 - @now/static-build@0.5.7-canary.0
2019-05-16 10:46:18 -07:00
Nathan Rajlich
c030fce589 [now-next] Default NODE_ENV to "development" for dev server (#493) 2019-05-15 18:46:26 -07:00
Nathan Rajlich
50a5150bb5 Publish
- @now/static-build@0.5.6
2019-05-14 10:40:21 -07:00
Nathan Rajlich
0578ccf47e Publish
- @now/static-build@0.5.6-canary.1
2019-05-13 15:58:26 -07:00
Nathan Rajlich
e32cd36ded [now-static-build] Remove srcBase from the proxy pass destination (#499)
The `srcBase` (directory where the entrypoint is located) should not be
in the `dest` proxy pass URL.

Consider an entrypoint like `www/package.json`. The development server
will be running within the `www` directory. A request for `GET
/static/foo.js` comes in, so we want to proxy pass to
`http://localhost:12345/static/foo.js` rather than
`http://localhost:12345/www/static/foo.js` which would lead to a 404.
2019-05-13 15:58:01 -07:00
Nathan Rajlich
6ac0ab121c Publish
- @now/static-build@0.5.6-canary.0
2019-05-13 13:12:35 -07:00
Nathan Rajlich
05db2e6a73 [now-static-build] Add err.sh link when dev server detection fails (#498)
* [now-static-build] Add `err.sh` link when dev server detection fails

The error message alone doesn't explain how to fix it, so adding this
`err.sh` link to guide the user to instructions on how to fix it.

For example: https://github.com/zeit/now-cli/issues/2339

* Shorter title

* should -> must
2019-05-13 13:11:03 -07:00
25 changed files with 359 additions and 96 deletions

View File

@@ -0,0 +1,38 @@
# `@now/static-build` Failed to detect a server running
#### Why This Warning Occurred
When running `now dev`, the `@now/static-build` builder proxies relevant HTTP
requests to the server that is created by the `now-dev` script in the
`package.json` file.
In order for `now dev` to know which port the server is running on, the builder
is provided a `$PORT` environment variable that the server *must* bind to. The
error "Failed to detect a server running on port" is printed if the builder fails
to detect a server listening on that specific port within five minutes.
#### Possible Ways to Fix It
Please ensure that your `now-dev` script binds the spawned development server on
the provided `$PORT` that the builder expects the server to bind to.
For example, if you are using Gatsby, your `now-dev` script must use the `-p`
(port) option to bind to the `$PORT` specified from the builder:
```
{
...
"scripts": {
...
"now-dev": "gatsby develop -p $PORT"
}
}
```
Consult your static builder program's `--help` or documentation to figure out what
the command line flag to bind to a specific port is (in many cases, it is one of:
`-p` / `-P` / `--port`).
### Useful Links
- [`@now/static-build` Local Development Documentation](https://zeit.co/docs/v2/deployments/official-builders/static-build-now-static-build#local-development)

View File

@@ -1,5 +1,37 @@
const childProcess = require('child_process');
const path = require('path');
const command = 'git diff HEAD~1 --name-only';
const diff = childProcess.execSync(command).toString();
const changed = diff
.split('\n')
.filter(item => Boolean(item) && item.includes('packages/'))
.map(item => path.relative('packages', item).split('/')[0]);
const matches = [];
if (changed.length > 0) {
console.log('The following packages have changed:');
changed.map((item) => {
matches.push(item);
console.log(item);
return null;
});
} else {
matches.push('now-node');
console.log(`No packages changed, defaulting to ${matches[0]}`);
}
const testMatch = Array.from(new Set(matches)).map(
item => `**/${item}/**/?(*.)+(spec|test).[jt]s?(x)`,
);
module.exports = { module.exports = {
testEnvironment: 'node', testEnvironment: 'node',
testMatch,
collectCoverageFrom: [ collectCoverageFrom: [
'packages/(!test)/**/*.{js,jsx}', 'packages/(!test)/**/*.{js,jsx}',
'!**/node_modules/**', '!**/node_modules/**',

View File

@@ -125,7 +125,15 @@ export async function downloadGo(
// If we found GOPATH in ENV, or default `Go` path exists // If we found GOPATH in ENV, or default `Go` path exists
// asssume that user have `Go` installed // asssume that user have `Go` installed
if (isUserGo || process.env.GOPATH !== undefined) { if (isUserGo || process.env.GOPATH !== undefined) {
return createGo(dir, platform, arch); const { stdout } = await execa('go', ['version']);
if (parseInt(stdout.split('.')[1]) >= 11) {
return createGo(dir, platform, arch);
}
throw new Error(
`Your current ${stdout} doesn't support Go Modules. Please update.`
);
} else { } else {
// Check `Go` bin in builder CWD // Check `Go` bin in builder CWD
const isGoExist = await pathExists(join(dir, 'bin')); const isGoExist = await pathExists(join(dir, 'bin'));

View File

@@ -1,5 +1,7 @@
import { join, sep, dirname } from 'path'; import { join, sep, dirname, basename } from 'path';
import { readFile, writeFile, pathExists, move } from 'fs-extra'; import { readFile, writeFile, pathExists, move, copy } from 'fs-extra';
import { homedir } from 'os';
import execa from 'execa';
import { import {
glob, glob,
@@ -29,6 +31,18 @@ interface BuildParamsType extends BuildOptions {
meta: BuildParamsMeta; meta: BuildParamsMeta;
} }
// Initialize private git repo for Go Modules
async function initPrivateGit(credentials: string) {
await execa('git', [
'config',
'--global',
'credential.helper',
`store --file ${join(homedir(), '.git-credentials')}`,
]);
await writeFile(join(homedir(), '.git-credentials'), credentials);
}
export const version = 2; export const version = 2;
export const config = { export const config = {
@@ -39,8 +53,14 @@ export async function build({
files, files,
entrypoint, entrypoint,
config, config,
workPath,
meta = {} as BuildParamsMeta, meta = {} as BuildParamsMeta,
}: BuildParamsType) { }: BuildParamsType) {
if (process.env.GIT_CREDENTIALS && !meta.isDev) {
console.log('Initialize Git credentials...');
await initPrivateGit(process.env.GIT_CREDENTIALS);
}
console.log('Downloading user files...'); console.log('Downloading user files...');
const entrypointArr = entrypoint.split(sep); const entrypointArr = entrypoint.split(sep);
@@ -49,26 +69,12 @@ export async function build({
getWriteableDirectory(), getWriteableDirectory(),
]); ]);
if (meta.isDev) {
const devGoPath = `dev${entrypointArr[entrypointArr.length - 1]}`;
const goPathArr = goPath.split(sep);
goPathArr.pop();
goPathArr.push(devGoPath);
goPath = goPathArr.join(sep);
}
const srcPath = join(goPath, 'src', 'lambda'); const srcPath = join(goPath, 'src', 'lambda');
const downloadedFiles = await download(files, srcPath); let downloadedFiles;
const input = dirname(downloadedFiles[entrypoint].fsPath); if (meta.isDev) {
var includedFiles: Files = {}; downloadedFiles = await download(files, workPath, meta);
} else {
if (config && config.includeFiles) { downloadedFiles = await download(files, srcPath);
for (const pattern of config.includeFiles) {
const files = await glob(pattern, input);
for (const assetName of Object.keys(files)) {
includedFiles[assetName] = files[assetName];
}
}
} }
console.log(`Parsing AST for "${entrypoint}"`); console.log(`Parsing AST for "${entrypoint}"`);
@@ -90,18 +96,71 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
throw err; throw err;
} }
const entrypointDirnameDev = dirname(downloadedFiles[entrypoint].fsPath);
const parsedAnalyzed = JSON.parse(analyzed) as Analyzed; const parsedAnalyzed = JSON.parse(analyzed) as Analyzed;
if (meta.isDev) {
const base = dirname(downloadedFiles['now.json'].fsPath);
const destNow = join(
base,
'.now',
'cache',
basename(entrypoint, '.go'),
'src',
'lambda'
);
const goMod = await pathExists(join(entrypointDirnameDev, 'go.mod'));
// this will ensure Go rebuilt fast
goPath = join(base, '.now', 'cache', basename(entrypoint, '.go'));
for (const file of parsedAnalyzed.watch) {
if (entrypointArr.length > 0) {
await copy(
join(base, dirname(entrypoint), file),
join(destNow, dirname(entrypoint), file)
);
if (goMod) {
await copy(
join(entrypointDirnameDev, 'go.mod'),
join(destNow, dirname(entrypoint), 'go.mod')
);
}
} else {
await copy(join(base, file), join(destNow, file));
if (goMod) {
await copy(
join(entrypointDirnameDev, 'go.mod'),
join(destNow, 'go.mod')
);
}
}
}
downloadedFiles = await glob('**', destNow);
}
const entrypointDirname = dirname(downloadedFiles[entrypoint].fsPath);
const input = entrypointDirname;
var includedFiles: Files = {};
if (config && config.includeFiles) {
for (const pattern of config.includeFiles) {
const files = await glob(pattern, input);
for (const assetName of Object.keys(files)) {
includedFiles[assetName] = files[assetName];
}
}
}
const handlerFunctionName = parsedAnalyzed.functionName; const handlerFunctionName = parsedAnalyzed.functionName;
console.log( console.log(
`Found exported function "${handlerFunctionName}" in "${entrypoint}"` `Found exported function "${handlerFunctionName}" in "${entrypoint}"`
); );
// we need `main.go` in the same dir as the entrypoint,
// otherwise `go build` will refuse to build
const entrypointDirname = dirname(downloadedFiles[entrypoint].fsPath);
// check if package name other than main // check if package name other than main
// using `go.mod` way building the handler
const packageName = parsedAnalyzed.packageName; const packageName = parsedAnalyzed.packageName;
const isGoModExist = await pathExists(join(entrypointDirname, 'go.mod')); const isGoModExist = await pathExists(join(entrypointDirname, 'go.mod'));
if (packageName !== 'main') { if (packageName !== 'main') {
@@ -228,6 +287,9 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
); );
} }
} else { } else {
// legacy mode
// we need `main.go` in the same dir as the entrypoint,
// otherwise `go build` will refuse to build
const go = await createGo( const go = await createGo(
goPath, goPath,
process.platform, process.platform,

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/go", "name": "@now/go",
"version": "0.4.6", "version": "0.5.0",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -10,9 +10,22 @@ import (
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"strings" "strings"
) )
var ignoredFoldersRegex []*regexp.Regexp
func init() {
ignoredFolders := []string{"vendor", "testdata", ".now"}
// Build the regex that matches if a path contains the respective ignored folder
// The pattern will look like: (.*/)?vendor/.*, which matches every path that contains a vendor folder
for _, folder := range ignoredFolders {
ignoredFoldersRegex = append(ignoredFoldersRegex, regexp.MustCompile("(.*/)?"+folder+"/.*"))
}
}
type analyze struct { type analyze struct {
PackageName string `json:"packageName"` PackageName string `json:"packageName"`
FuncName string `json:"functionName"` FuncName string `json:"functionName"`
@@ -40,8 +53,9 @@ func visit(files *[]string) filepath.WalkFunc {
} }
// we don't need Dirs, or test files // we don't need Dirs, or test files
// we only want `.go` files // we only want `.go` files. Further, we ignore
if info.IsDir() || itf || filepath.Ext(path) != ".go" { // every file that is in one of the ignored folders.
if info.IsDir() || itf || filepath.Ext(path) != ".go" || isInIgnoredFolder(path) {
return nil return nil
} }
@@ -50,6 +64,19 @@ func visit(files *[]string) filepath.WalkFunc {
} }
} }
// isInIgnoredFolder checks if the given path is in one of the ignored folders.
func isInIgnoredFolder(path string) bool {
// Make sure the regex works for Windows paths
path = filepath.ToSlash(path)
for _, pattern := range ignoredFoldersRegex {
if pattern.MatchString(path) {
return true
}
}
return false
}
// return unique file // return unique file
func unique(files []string) []string { func unique(files []string) []string {
encountered := map[string]bool{} encountered := map[string]bool{}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/next", "name": "@now/next",
"version": "0.3.2", "version": "0.4.0",
"license": "MIT", "license": "MIT",
"main": "./dist/index", "main": "./dist/index",
"scripts": { "scripts": {
@@ -14,7 +14,7 @@
"directory": "packages/now-next" "directory": "packages/now-next"
}, },
"dependencies": { "dependencies": {
"@now/node-bridge": "^1.1.2", "@now/node-bridge": "^1.1.3",
"fs-extra": "^7.0.0", "fs-extra": "^7.0.0",
"get-port": "^5.0.0", "get-port": "^5.0.0",
"resolve-from": "^5.0.0", "resolve-from": "^5.0.0",

View File

@@ -155,14 +155,13 @@ export const build = async ({
entrypoint, entrypoint,
meta = {} as BuildParamsMeta, meta = {} as BuildParamsMeta,
}: BuildParamsType): Promise<{ }: BuildParamsType): Promise<{
routes?: any[]; routes?: { src: string; dest: string }[];
output: Files; output: Files;
watch?: string[]; watch?: string[];
childProcesses: ChildProcess[]; childProcesses: ChildProcess[];
}> => { }> => {
validateEntrypoint(entrypoint); validateEntrypoint(entrypoint);
const routes: any[] = [];
const entryDirectory = path.dirname(entrypoint); const entryDirectory = path.dirname(entrypoint);
const entryPath = path.join(workPath, entryDirectory); const entryPath = path.join(workPath, entryDirectory);
const dotNext = path.join(entryPath, '.next'); const dotNext = path.join(entryPath, '.next');
@@ -191,6 +190,10 @@ export const build = async ({
console.log(`${name} Installing dependencies...`); console.log(`${name} Installing dependencies...`);
await runNpmInstall(entryPath, ['--prefer-offline']); await runNpmInstall(entryPath, ['--prefer-offline']);
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = 'development';
}
// The runtime env vars consist of the base `process.env` vars, but with the // The runtime env vars consist of the base `process.env` vars, but with the
// build env vars removed, and the runtime env vars mixed in afterwards // build env vars removed, and the runtime env vars mixed in afterwards
const runtimeEnv: EnvConfig = Object.assign({}, process.env); const runtimeEnv: EnvConfig = Object.assign({}, process.env);
@@ -285,7 +288,9 @@ export const build = async ({
await unlinkFile(path.join(entryPath, '.npmrc')); await unlinkFile(path.join(entryPath, '.npmrc'));
} }
const routes: { src: string; dest: string }[] = [];
const lambdas: { [key: string]: Lambda } = {}; const lambdas: { [key: string]: Lambda } = {};
const staticPages: { [key: string]: FileFsRef } = {};
if (isLegacy) { if (isLegacy) {
const filesAfterBuild = await glob('**', entryPath); const filesAfterBuild = await glob('**', entryPath);
@@ -377,10 +382,21 @@ export const build = async ({
fsPath: path.join(__dirname, 'launcher.js'), fsPath: path.join(__dirname, 'launcher.js'),
}), }),
}; };
const pages = await glob( const pagesDir = path.join(entryPath, '.next', 'serverless', 'pages');
'**/*.js',
path.join(entryPath, '.next', 'serverless', 'pages') const pages = await glob('**/*.js', pagesDir);
); const staticPageFiles = await glob('**/*.html', pagesDir);
Object.keys(staticPageFiles).forEach((page: string) => {
const staticRoute = path.join(entryDirectory, page);
staticPages[staticRoute] = staticPageFiles[page];
const pathname = page.replace(/\.html$/, '');
routes.push({
src: `^${path.join('/', entryDirectory, pathname)}$`,
dest: path.join('/', staticRoute),
});
});
const pageKeys = Object.keys(pages); const pageKeys = Object.keys(pages);
@@ -469,10 +485,11 @@ export const build = async ({
output: { output: {
...publicFiles, ...publicFiles,
...lambdas, ...lambdas,
...staticPages,
...staticFiles, ...staticFiles,
...staticDirectoryFiles, ...staticDirectoryFiles,
}, },
routes: [], routes,
watch: [], watch: [],
childProcesses: [], childProcesses: [],
}; };

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/node-bridge", "name": "@now/node-bridge",
"version": "1.1.2", "version": "1.1.3",
"license": "MIT", "license": "MIT",
"main": "./index.js", "main": "./index.js",
"repository": { "repository": {

View File

@@ -1,10 +1,10 @@
import { AddressInfo } from 'net'; import { AddressInfo } from 'net';
import { APIGatewayProxyEvent } from 'aws-lambda'; import { APIGatewayProxyEvent, Context } from 'aws-lambda';
import { import {
Server, Server,
IncomingHttpHeaders, IncomingHttpHeaders,
OutgoingHttpHeaders, OutgoingHttpHeaders,
request request,
} from 'http'; } from 'http';
interface NowProxyEvent { interface NowProxyEvent {
@@ -133,25 +133,25 @@ export class Bridge {
return this.server.listen({ return this.server.listen({
host: '127.0.0.1', host: '127.0.0.1',
port: 0 port: 0,
}); });
} }
async launcher( async launcher(
event: NowProxyEvent | APIGatewayProxyEvent event: NowProxyEvent | APIGatewayProxyEvent,
context: Context
): Promise<NowProxyResponse> { ): Promise<NowProxyResponse> {
context.callbackWaitsForEmptyEventLoop = false;
const { port } = await this.listening; const { port } = await this.listening;
const { isApiGateway, method, path, headers, body } = normalizeEvent( const { isApiGateway, method, path, headers, body } = normalizeEvent(event);
event
);
const opts = { const opts = {
hostname: '127.0.0.1', hostname: '127.0.0.1',
port, port,
path, path,
method, method,
headers headers,
}; };
// eslint-disable-next-line consistent-return // eslint-disable-next-line consistent-return
@@ -175,7 +175,7 @@ export class Bridge {
statusCode: response.statusCode || 200, statusCode: response.statusCode || 200,
headers: response.headers, headers: response.headers,
body: bodyBuffer.toString('base64'), body: bodyBuffer.toString('base64'),
encoding: 'base64' encoding: 'base64',
}); });
}); });
}); });

View File

@@ -16,56 +16,70 @@ test('port binding', async () => {
}); });
test('`APIGatewayProxyEvent` normalizing', async () => { test('`APIGatewayProxyEvent` normalizing', async () => {
const server = new Server((req, res) => res.end( const server = new Server((req, res) =>
JSON.stringify({ res.end(
method: req.method, JSON.stringify({
path: req.url, method: req.method,
headers: req.headers, path: req.url,
}), headers: req.headers,
)); })
)
);
const bridge = new Bridge(server); const bridge = new Bridge(server);
bridge.listen(); bridge.listen();
const result = await bridge.launcher({ const context = {};
httpMethod: 'GET', const result = await bridge.launcher(
headers: { foo: 'bar' }, {
path: '/apigateway', httpMethod: 'GET',
body: null, headers: { foo: 'bar' },
}); path: '/apigateway',
body: null,
},
context
);
assert.equal(result.encoding, 'base64'); assert.equal(result.encoding, 'base64');
assert.equal(result.statusCode, 200); assert.equal(result.statusCode, 200);
const body = JSON.parse(Buffer.from(result.body, 'base64').toString()); const body = JSON.parse(Buffer.from(result.body, 'base64').toString());
assert.equal(body.method, 'GET'); assert.equal(body.method, 'GET');
assert.equal(body.path, '/apigateway'); assert.equal(body.path, '/apigateway');
assert.equal(body.headers.foo, 'bar'); assert.equal(body.headers.foo, 'bar');
assert.equal(context.callbackWaitsForEmptyEventLoop, false);
server.close(); server.close();
}); });
test('`NowProxyEvent` normalizing', async () => { test('`NowProxyEvent` normalizing', async () => {
const server = new Server((req, res) => res.end( const server = new Server((req, res) =>
JSON.stringify({ res.end(
method: req.method, JSON.stringify({
path: req.url, method: req.method,
headers: req.headers, path: req.url,
}), headers: req.headers,
)); })
)
);
const bridge = new Bridge(server); const bridge = new Bridge(server);
bridge.listen(); bridge.listen();
const result = await bridge.launcher({ const context = { callbackWaitsForEmptyEventLoop: true };
Action: 'Invoke', const result = await bridge.launcher(
body: JSON.stringify({ {
method: 'POST', Action: 'Invoke',
headers: { foo: 'baz' }, body: JSON.stringify({
path: '/nowproxy', method: 'POST',
body: 'body=1', headers: { foo: 'baz' },
}), path: '/nowproxy',
}); body: 'body=1',
}),
},
context
);
assert.equal(result.encoding, 'base64'); assert.equal(result.encoding, 'base64');
assert.equal(result.statusCode, 200); assert.equal(result.statusCode, 200);
const body = JSON.parse(Buffer.from(result.body, 'base64').toString()); const body = JSON.parse(Buffer.from(result.body, 'base64').toString());
assert.equal(body.method, 'POST'); assert.equal(body.method, 'POST');
assert.equal(body.path, '/nowproxy'); assert.equal(body.path, '/nowproxy');
assert.equal(body.headers.foo, 'baz'); assert.equal(body.headers.foo, 'baz');
assert.equal(context.callbackWaitsForEmptyEventLoop, false);
server.close(); server.close();
}); });

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/node-server", "name": "@now/node-server",
"version": "0.7.2", "version": "0.7.3",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -8,7 +8,7 @@
"directory": "packages/now-node-server" "directory": "packages/now-node-server"
}, },
"dependencies": { "dependencies": {
"@now/node-bridge": "^1.1.2", "@now/node-bridge": "^1.1.3",
"@zeit/ncc": "0.18.5", "@zeit/ncc": "0.18.5",
"fs-extra": "7.0.1" "fs-extra": "7.0.1"
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/node", "name": "@now/node",
"version": "0.7.2", "version": "0.7.3",
"license": "MIT", "license": "MIT",
"main": "./dist/index", "main": "./dist/index",
"repository": { "repository": {
@@ -9,7 +9,7 @@
"directory": "packages/now-node" "directory": "packages/now-node"
}, },
"dependencies": { "dependencies": {
"@now/node-bridge": "^1.1.2", "@now/node-bridge": "^1.1.3",
"@zeit/ncc": "0.18.5", "@zeit/ncc": "0.18.5",
"fs-extra": "7.0.1" "fs-extra": "7.0.1"
}, },

View File

@@ -1,4 +1,4 @@
import { join, dirname } from 'path'; import { join, dirname, basename } from 'path';
import execa from 'execa'; import execa from 'execa';
import fs from 'fs'; import fs from 'fs';
import { promisify } from 'util'; import { promisify } from 'util';
@@ -73,7 +73,16 @@ export const build = async ({
meta = {}, meta = {},
}: BuildOptions) => { }: BuildOptions) => {
console.log('downloading files...'); console.log('downloading files...');
const downloadedFiles = await download(originalFiles, workPath, meta); let downloadedFiles = await download(originalFiles, workPath, meta);
if (meta.isDev) {
const base = dirname(downloadedFiles['now.json'].fsPath);
const destNow = join(base, '.now', 'cache', basename(entrypoint, '.py'));
await download(downloadedFiles, destNow);
downloadedFiles = await glob('**', destNow);
workPath = destNow;
}
const foundLockFile = 'Pipfile.lock' in downloadedFiles; const foundLockFile = 'Pipfile.lock' in downloadedFiles;
const pyUserBase = await getWriteableDirectory(); const pyUserBase = await getWriteableDirectory();
process.env.PYTHONUSERBASE = pyUserBase; process.env.PYTHONUSERBASE = pyUserBase;

View File

@@ -22,6 +22,7 @@ _now_imported, _now_is_legacy = _now_get_import()
if _now_is_legacy: if _now_is_legacy:
print('using HTTP Handler') print('using HTTP Handler')
from http.server import HTTPServer from http.server import HTTPServer
from urllib.parse import unquote
import requests import requests
import _thread import _thread
server = HTTPServer(('', 0), _now_imported) server = HTTPServer(('', 0), _now_imported)
@@ -30,7 +31,7 @@ if _now_is_legacy:
_thread.start_new_thread(server.handle_request, ()) _thread.start_new_thread(server.handle_request, ())
payload = json.loads(event['body']) payload = json.loads(event['body'])
path = payload['path'] path = unquote(payload['path'])
headers = payload['headers'] headers = payload['headers']
method = payload['method'] method = payload['method']
encoding = payload.get('encoding') encoding = payload.get('encoding')
@@ -53,10 +54,7 @@ if _now_is_legacy:
else: else:
print('using Web Server Gateway Interface (WSGI)') print('using Web Server Gateway Interface (WSGI)')
import sys import sys
try: from urllib.parse import urlparse, unquote
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
from werkzeug._compat import BytesIO from werkzeug._compat import BytesIO
from werkzeug._compat import string_types from werkzeug._compat import string_types
from werkzeug._compat import to_bytes from werkzeug._compat import to_bytes
@@ -75,13 +73,14 @@ else:
if isinstance(body, string_types): if isinstance(body, string_types):
body = to_bytes(body, charset='utf-8') body = to_bytes(body, charset='utf-8')
urlinfo = urlparse(payload['path']) path = unquote(payload['path'])
query = urlparse(path).query
environ = { environ = {
'CONTENT_LENGTH': str(len(body)), 'CONTENT_LENGTH': str(len(body)),
'CONTENT_TYPE': headers.get('content-type', ''), 'CONTENT_TYPE': headers.get('content-type', ''),
'PATH_INFO': payload['path'], 'PATH_INFO': path,
'QUERY_STRING': urlinfo.query, 'QUERY_STRING': query,
'REMOTE_ADDR': headers.get( 'REMOTE_ADDR': headers.get(
'x-forwarded-for', headers.get( 'x-forwarded-for', headers.get(
'x-real-ip', payload.get( 'x-real-ip', payload.get(
@@ -102,7 +101,7 @@ else:
} }
for key, value in environ.items(): for key, value in environ.items():
if isinstance(value, string_types): if isinstance(value, string_types) and key != 'QUERY_STRING':
environ[key] = wsgi_encoding_dance(value) environ[key] = wsgi_encoding_dance(value)
for key, value in headers.items(): for key, value in headers.items():

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/python", "name": "@now/python",
"version": "0.2.2", "version": "0.2.4",
"main": "index.js", "main": "index.js",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -0,0 +1,7 @@
from flask import Flask, Response, __version__
app = Flask(__name__)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
return Response("path=%s" %(path), mimetype='text/html')

View File

@@ -0,0 +1,7 @@
from flask import Flask, Response, __version__
app = Flask(__name__)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
return Response("path=%s" %(path), mimetype='text/html')

View File

@@ -0,0 +1,13 @@
{
"version": 2,
"builds": [
{ "src": "*.py", "use": "@now/python" }
],
"routes": [
{ "src": "/another", "dest": "custom.py" }
],
"probes": [
{ "path": "/?hello=/", "mustContain": "path=?hello=/" },
{ "path": "/another?hello=/", "mustContain": "path=another?hello=/" }
]
}

View File

@@ -0,0 +1 @@
Flask==1.0.2

View File

@@ -0,0 +1,8 @@
from http.server import BaseHTTPRequestHandler
class handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(str("path=").encode()+self.path.encode())
return

View File

@@ -0,0 +1,8 @@
from http.server import BaseHTTPRequestHandler
class handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(str("path=").encode()+self.path.encode())
return

View File

@@ -0,0 +1,13 @@
{
"version": 2,
"builds": [
{ "src": "*.py", "use": "@now/python" }
],
"routes": [
{ "src": "/another", "dest": "custom.py" }
],
"probes": [
{ "path": "/?hello=/", "mustContain": "path=/?hello=/" },
{ "path": "/another?hello=/", "mustContain": "path=/another?hello=/" }
]
}

View File

@@ -88,7 +88,7 @@ exports.build = async ({
); );
} catch (err) { } catch (err) {
throw new Error( throw new Error(
`Failed to detect a server running on port ${devPort}`, `Failed to detect a server running on port ${devPort}.\nDetails: https://err.sh/zeit/now-builders/now-static-build-failed-to-detect-a-server`,
); );
} }
@@ -101,7 +101,7 @@ exports.build = async ({
} }
routes.push({ routes.push({
src: `${srcBase}/(.*)`, src: `${srcBase}/(.*)`,
dest: `http://localhost:${devPort}${srcBase}/$1`, dest: `http://localhost:${devPort}/$1`,
}); });
} else { } else {
if (meta.isDev) { if (meta.isDev) {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/static-build", "name": "@now/static-build",
"version": "0.5.5", "version": "0.5.7",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",