Compare commits

...

128 Commits

Author SHA1 Message Date
Igor Klopov
77d445af71 Publish
- @now/bash@0.1.1
 - @now/build-utils@0.4.32
 - @now/cgi@0.0.15
 - @now/go@0.2.12
 - @now/html-minifier@1.0.7
 - @now/lambda@0.4.9
 - @now/md@0.4.9
 - @now/mdx-deck@0.4.18
 - @now/next@0.0.84
 - @now/node-bridge@0.1.10
 - @now/node-server@0.4.26
 - @now/node@0.4.28
 - @now/optipng@0.4.8
 - @now/php-bridge@0.4.13
 - @now/php@0.4.13
 - @now/static-build@0.4.17
 - @now/wordpress@0.4.14
2019-01-20 01:14:09 +03:00
Igor Klopov
79251ad180 [lerna] trying to set the order of package to publish 2019-01-20 00:01:16 +03:00
Igor Klopov
a215dc9103 [node-server] update tests for latest ncc 2019-01-19 23:23:44 +03:00
Nathan Rajlich
ea7d8f0f6c Update @zeit/ncc to v0.11.0 (#172) 2019-01-19 19:30:20 +03:00
Igor Klopov
2232efc984 fix misleading 'running npm install' messages in logs 2019-01-15 00:54:24 +03:00
Igor Klopov
b64ce0f3c0 [now-node] fix test for content-length 2019-01-14 03:27:15 +03:00
Igor Klopov
74233d50ad now/node: bump ncc 2019-01-12 05:20:37 +03:00
Nathan Rajlich
8aebec9fc3 Publish
- @now/bash@0.1.0
2019-01-10 12:27:59 -08:00
Igor Klopov
54584b7763 [tests] support NOW_TOKEN env var 2019-01-09 20:44:20 +03:00
Igor Klopov
d163fcbd71 [now-node-server] test for default content-type 2019-01-09 20:16:58 +03:00
Tim Neutkens
04c2996c76 [now-next] Add test for monorepo 2019-01-09 15:07:54 +01:00
Igor Klopov
2b69b898ed Publish
- @now/build-utils@0.4.32-canary.6
 - @now/node-bridge@0.1.10-canary.2
 - @now/node-server@0.4.26-canary.7
 - @now/node@0.4.28-canary.6
2019-01-08 01:42:13 +03:00
Igor Klopov
846aa11d6a now/node-bridge: postpone rejecting, let express print the error 2019-01-08 01:22:01 +03:00
Nathan Rajlich
a314a74479 Publish
- @now/bash@0.0.4-canary.2
2019-01-04 18:34:29 -08:00
Nathan Rajlich
40f029a72c [now-bash] Pipe response to jq stdin and use long options
Otherwise `jq` errors out with "arguments too long" when the response
body base64 is too large.

The long options are just for maintainability.
2019-01-04 18:33:56 -08:00
Nathan Rajlich
493d8a778f [now-bash] Update static-binaries to v1.0.0 2019-01-04 18:33:56 -08:00
Nathan Rajlich
cb5dcb658f [now-bash] Remove final build tree output
It's not necessary and can be too noisey if the lambda has a lot of files.
2019-01-04 18:33:56 -08:00
Nathan Rajlich
d77287d07b [now-bash] Add .editorconfig file 2019-01-04 18:33:56 -08:00
Igor Klopov
61d66bd957 Publish
- @now/build-utils@0.4.32-canary.5
 - @now/next@0.0.84-canary.0
2019-01-03 16:52:48 +03:00
Igor Klopov
ae73df9e3c build-utils: account google cloud functions 2019-01-03 16:29:55 +03:00
Tim Neutkens
cb09ae5bbf Publish
- @now/next@0.0.83
2019-01-03 11:56:29 +01:00
Tim Neutkens
a28eeacdaa Publish
- @now/build-utils@0.4.32-canary.4
 - @now/cgi@0.0.15-canary.0
 - @now/go@0.2.12-canary.0
 - @now/html-minifier@1.0.7-canary.0
 - @now/lambda@0.4.9-canary.0
 - @now/md@0.4.9-canary.0
 - @now/mdx-deck@0.4.18-canary.1
 - @now/next@0.0.83-canary.0
 - @now/node-bridge@0.1.10-canary.1
 - @now/node-server@0.4.26-canary.6
 - @now/node@0.4.28-canary.5
 - @now/optipng@0.4.8-canary.0
 - @now/php-bridge@0.4.13-canary.1
 - @now/php@0.4.13-canary.2
 - @now/static-build@0.4.17-canary.0
 - @now/wordpress@0.4.14-canary.1
2019-01-02 17:48:58 +01:00
Tim Neutkens
dd9d46d555 Add Next.js serverless target instead of lambdas build (#150)
* Give test more time

* Implement legacy flag

* Move tests

* Add test for new builder

* Add serverless target flow

* Remove prepareCache

* Add semver check

* Upgrade for latest Next.js canary
2019-01-02 17:48:01 +01:00
Igor Klopov
4472331ee0 tests: use token factory endpoint 2019-01-01 03:17:27 +03:00
Tim Neutkens
ac69836b44 Publish
- @now/next@0.0.82
2018-12-27 13:28:44 +01:00
Steven
15949a4ab4 Add missing license to package.json (#147) 2018-12-27 13:13:49 +01:00
Igor Klopov
697ada9d73 now-node: tests for content-length 2018-12-24 07:51:18 +03:00
Igor Klopov
cafbe30fa3 Publish
- @now/next@0.0.82-canary.1
 - @now/node-bridge@0.1.10-canary.0
 - @now/node-server@0.4.26-canary.5
 - @now/node@0.4.28-canary.4
2018-12-24 07:21:38 +03:00
Igor Klopov
583ebcc526 node-bridge: set content-length in response if user sets it 2018-12-24 06:57:17 +03:00
Connor Davis
52d1bd410c Lock Next.js Version (#145)
* Update utils.js

* Update utils.test.js

* Update utils.test.js

* Temp Commit

* Revert Temp Commit
2018-12-23 11:19:37 +01:00
Nathan Rajlich
11d0753bc1 Publish
- @now/bash@0.0.4-canary.1
 - @now/build-utils@0.4.32-canary.3
2018-12-21 13:46:41 -08:00
Nathan Rajlich
538710fe56 [now-bash] make the curl calls to AWS API silent (#142)
* [now-bash] make the `curl` calls to AWS API silent

Also log the exit status of the `handler` function.

* Remove `echo Request-Id`
2018-12-21 13:44:57 -08:00
Nathan Rajlich
2828c89e8d [now-bash] add stdio: inherit to builder.sh script (#143)
So that the build logs of the bash script are sent to the deployment
logs.
2018-12-21 13:44:42 -08:00
Igor Klopov
e40b45a939 tests: Accept = application/json for all api calls 2018-12-21 03:07:33 +03:00
Igor Klopov
38ba8a36fc Publish
- @now/build-utils@0.4.32-canary.2
 - @now/wordpress@0.4.14-canary.0
2018-12-21 00:59:08 +03:00
Igor Klopov
0323c505a3 now/build-utils: fix cross-install inssue in yarn in-memory cache 2018-12-20 09:03:52 +03:00
Igor Klopov
17ee07f4f6 now/build-utils: add cross-install test 2018-12-20 08:53:29 +03:00
Igor Klopov
0a6ada77ac now/wordpress: support non-root placement (monorepo) 2018-12-19 14:38:42 +03:00
Igor Klopov
4d817dd67d update yarn.lock file to avoid 'lerna ERR! EUNCOMMIT' 2018-12-19 01:55:54 +03:00
Igor Klopov
9682a7cc0b now/wordpress: release 0.4.13 manually 2018-12-18 10:25:24 +03:00
Igor Klopov
3456f23b3e now/wordpress: make latest.zip the default 2018-12-18 10:24:16 +03:00
Igor Klopov
800ca2cb0e Publish
- @now/php@0.4.13-canary.1
 - @now/wordpress@0.4.13-canary.1
2018-12-18 10:09:34 +03:00
Igor Klopov
ba54b4d706 now/wordpress: don't test it yet 2018-12-18 10:09:16 +03:00
Igor Klopov
e9482d66a9 now/php: dummy changes 2018-12-18 10:00:49 +03:00
Igor Klopov
401b669363 Publish
- @now/node-server@0.4.26-canary.4
 - @now/node@0.4.28-canary.3
 - @now/php-bridge@0.4.13-canary.0
 - @now/php@0.4.13-canary.0
 - @now/wordpress@0.4.13-canary.0
2018-12-18 09:51:38 +03:00
Igor Klopov
a2a0ede1f6 now/php-bridge: minor improvements 2018-12-18 09:49:19 +03:00
Igor Klopov
3c9fcff743 now/wordpress (#136)
* now/wordpress copied from new now/php

* download, decompress and merge release url

* static files

* require entrypoint be named 'wp-config.php'

* patch wp-db.php to use persistent connections

* "/wp-admin/index.php" rule is not needed

* emit lambda with name 'index.php'

* more staticRegexps

* make patchForPersistentConnections opt-in

* remove one more extra route

* update they way secrets are passed

* update route regexp a little
2018-12-18 09:47:07 +03:00
Igor Klopov
e5aa526583 now/php: update to use php-fpm 2018-12-18 04:24:08 +03:00
Igor Klopov
822b0ee3de now/node-server: yodasay.umd -> yodasay + pin 2018-12-18 03:21:45 +03:00
Igor Klopov
d612e46233 Publish
- @now/node-server@0.4.26-canary.3
 - @now/node@0.4.28-canary.2
2018-12-17 09:13:13 +03:00
Igor Klopov
77ee10cead now/node: bump ncc 2018-12-17 09:07:45 +03:00
Tim Neutkens
fb2029c464 Publish
- @now/build-utils@0.4.32-canary.1
 - @now/next@0.0.82-canary.0
 - @now/node-server@0.4.26-canary.2
 - @now/node@0.4.28-canary.1
 - @now/php@0.4.13-canary.1
2018-12-17 00:11:08 +01:00
Tim Neutkens
3b15755054 Add heap increase to now/next (#134) 2018-12-17 00:05:41 +01:00
Igor Klopov
4f65cc3aa8 now/build-utils: catch per-file stream errors 2018-12-16 03:17:04 +03:00
Igor Klopov
9936e35280 tests: retry on ETIMEDOUT 2018-12-15 21:55:55 +03:00
Igor Klopov
a04fd242b8 Revert "now/php: create php engine outside of request handling"
This reverts commit a7c2d9648a.
2018-12-12 01:09:12 +03:00
Igor Klopov
17bc6174a9 now/php: a regression test for engine reusage 2018-12-12 00:49:38 +03:00
Igor Klopov
a7c2d9648a now/php: create php engine outside of request handling 2018-12-11 23:04:47 +03:00
Igor Klopov
faa5ea9e21 now/php: fix $HTTP_RAW_POST_DATA 2018-12-11 08:49:45 +03:00
Igor Klopov
c52f30c898 now/php: fix $_SERVER['HTTP_HEADER'] 2018-12-11 07:53:46 +03:00
Igor Klopov
d675edf1dc this fixes several-values-per-header-name issue + test (#129) 2018-12-11 03:12:43 +03:00
Anthony Mittaz
f85c4f496f Bump ncc to v0.5.3 (#128)
* Bump `ncc` to v0.5.3

* Also bump `ncc` to v0.5.3 in now-node
2018-12-10 14:11:23 -08:00
Nathan Rajlich
d52d7904c2 Publish
- @now/bash@0.0.4-canary.0
2018-12-10 11:07:34 -08:00
Nathan Rajlich
79232024bd [now-bash] Rename serve function to handler (#125)
This is more consistent with what you would expect for a lambda
function, and we should maintain that convention.

For example: https://github.com/gkrizek/bash-lambda-layer
2018-12-10 10:55:38 -08:00
Igor Klopov
660b787bc3 tests: print headers in deploymentPost too 2018-12-10 06:34:21 +03:00
Igor Klopov
2dbf983ddb tests: account API_HOST in fetchApi, not in fetchWithAuth 2018-12-10 06:19:42 +03:00
Igor Klopov
0866ba9391 tests: export fetchApi and fetchWithAuth 2018-12-10 05:45:46 +03:00
Igor Klopov
d259a722a0 [test] print resp.headers on filePost failure 2018-12-10 05:10:32 +03:00
Igor Klopov
bf77c51f64 tests: retry on some network failures 2018-12-10 03:59:13 +03:00
Igor Klopov
062b78130c Publish
- @now/build-utils@0.4.32-canary.0
 - @now/mdx-deck@0.4.18-canary.0
 - @now/node-server@0.4.26-canary.1
 - @now/php@0.4.13-canary.0
2018-12-10 02:38:22 +03:00
Igor Klopov
fa70bc50cb sema around await streamToBuffer(zipFile.outputStream) (#124)
* sema around await streamToBuffer(zipFile.outputStream)

* lint fixes

* fix looking for 'undefined' scriptName
2018-12-10 02:30:16 +03:00
Igor Klopov
08e22b35d1 now/node-server: an improvement for 09-no-bundle 2018-12-09 00:32:15 +03:00
Igor Klopov
9d8f3315a1 now/php: partially revert set-cookie commit 2018-12-09 00:31:29 +03:00
Igor Klopov
a737a99a9d now/php: new test for setcookie + fix for bridge.go 2018-12-09 00:08:54 +03:00
Igor Klopov
ee92d92c9f now/php: fixed $_REQUEST 2018-12-08 07:58:08 +03:00
Igor Klopov
34d3ebd289 now/php: fix $_SERVER['SERVER_PROTOCOL'] 2018-12-08 06:35:46 +03:00
Igor Klopov
785f187e5d now/php: unescape cookie values 2018-12-08 06:25:39 +03:00
Igor Klopov
44449f474e now/php: fixed $_COOKIE 2018-12-08 01:03:18 +03:00
Igor Klopov
f44dae7f39 now/php: lint fixes 2018-12-07 23:06:45 +03:00
Igor Klopov
06f973f641 now/php: fixed $_SERVER['REQUEST_METHOD'] 2018-12-07 23:04:47 +03:00
Igor Klopov
47bb47804e now/php: fixed $_POST 2018-12-07 22:52:11 +03:00
António Nuno Monteiro
5df692979a Provide a complete implementation for @now/mdx-deck's analyze function (#97)
* Provide a complete implementation for `@now/mdx-deck`'s analyze function

Fixes #93

* Delete the analyze step
2018-12-07 03:44:56 +03:00
Igor Klopov
cd02d5390f now/php: simplify test.go and test.php 2018-12-07 03:37:25 +03:00
Igor Klopov
c93fd416c4 tests: pass 'env' from now.json to nowDeploy 2018-12-07 02:45:12 +03:00
Igor Klopov
431db7a62d bridge.go: remove duplicating 'host' header check 2018-12-07 02:40:09 +03:00
Igor Klopov
6f86c70313 now/php: use v[len(v) - 1] instead of iterating 2018-12-07 02:13:28 +03:00
Igor Klopov
0923fc9200 now/php: better parsing of _GET 2018-12-07 02:05:25 +03:00
Igor Klopov
787675f462 probe.js for more complex tests. probe.js for now/php globals 2018-12-06 20:53:41 +03:00
Igor Klopov
977615720a improvements and a test for now/php 2018-12-06 08:23:12 +03:00
Igor Klopov
1a4e64cd27 Publish
- @now/node-server@0.4.26-canary.0
 - @now/node@0.4.28-canary.0
2018-12-06 04:16:39 +03:00
Igor Klopov
c9fc255002 don't force set NODE_ENV=production. default instead (#120) 2018-12-06 03:03:02 +03:00
Igor Klopov
e83d4d4249 Publish
- @now/bash@0.0.3
 - @now/build-utils@0.4.31
 - @now/cgi@0.0.14
 - @now/go@0.2.11
 - @now/lambda@0.4.8
 - @now/md@0.4.8
 - @now/mdx-deck@0.4.17
 - @now/next@0.0.81
 - @now/node-server@0.4.25
 - @now/node@0.4.27
 - @now/php@0.4.12
 - @now/static-build@0.4.16
2018-12-06 01:54:09 +03:00
Igor Klopov
d2ca763079 update yarn.lock 2018-12-06 01:52:54 +03:00
Nathan Rajlich
2a95388f89 Publish
- @now/bash@0.0.3-canary.0
 - @now/build-utils@0.4.31-canary.2
 - @now/cgi@0.0.14-canary.0
 - @now/go@0.2.11-canary.1
 - @now/lambda@0.4.8-canary.1
 - @now/md@0.4.8-canary.2
 - @now/mdx-deck@0.4.17-canary.3
 - @now/node-server@0.4.25-canary.3
 - @now/node@0.4.27-canary.3
 - @now/php@0.4.12-canary.3
 - @now/static-build@0.4.16-canary.2
2018-12-04 17:40:38 -08:00
Nathan Rajlich
be9fedfdc4 Bump ncc to v0.4.1 (#117) 2018-12-04 17:38:41 -08:00
Igor Klopov
f0dee65f69 fixes for now/php 2018-12-05 00:46:59 +03:00
Daniel Levine
5514753c07 Update index.js (#115)
quick typo fix
2018-12-04 13:12:58 -08:00
Nathan Rajlich
7028556919 Add @now/bash builder (#114)
This builder expects a `.sh` shell script entrypoint file, and implements
a custom Lambda runtime written in bash.

* The entrypoint must define a `serve()` function which is executed for every
  HTTP request.
* The entrypoint _may_ define a `build()` function only gets executed
  during the build, to retreive any additional artifacts that the lambda
  depends on.
* `jq` is available implicitly, since the runtime depends on it to parse the
  event and generate the response.
* Stdin is the HTTP request body
* Stdout is the HTTP response body
* Invoke `http_response_code` to set the response status code
* Invoke `http_response_header` to set a HTTP response header
* Parse the `$REQUEST` variable with `jq` to get context about the request
  (path, method, etc.)
* [`import`](https://import.pw) is available by default, and `import`
  calls at the top-level of your file will be cached inside the lambda at
  build-time
* Since the runtime itself is written in bash, every time `serve` is
  invoked, _it is the same process_. This means that you can use global
  state in your script, for example:

```bash
COUNT=0

serve() {
  COUNT="$(( COUNT + 1 ))"
  echo "Invoke count: $COUNT"
}
```
2018-12-04 22:50:11 +03:00
Nathan Rajlich
a1f24853fc Create go/bridge common logic package for Go lambda builders (#96)
* Create `go/bridge` common logic package for Go lambda builders

* gofmt

* Fill out more properties on the `http.Request`
2018-12-04 22:47:09 +03:00
Igor Klopov
9804e82f8f add top-level package.json dummy 'version' entry 2018-12-04 07:28:00 +03:00
Igor Klopov
e96596634b specify '@canary' explicitly as builderUrl or buildUtilsUrl 2018-12-04 02:52:05 +03:00
Igor Klopov
495c193a40 Publish
- @now/build-utils@0.4.31-canary.1
 - @now/lambda@0.4.8-canary.0
 - @now/md@0.4.8-canary.1
 - @now/mdx-deck@0.4.17-canary.2
 - @now/node-server@0.4.25-canary.2
 - @now/node@0.4.27-canary.2
 - @now/php@0.4.12-canary.2
 - @now/static-build@0.4.16-canary.1
2018-12-04 02:03:45 +03:00
Igor Klopov
9d77d89513 bump ncc to 0.3.0 (#113) 2018-12-04 02:00:33 +03:00
Igor Klopov
bcffe0db91 take random token from pool if CIRCLE_BUILD_NUM is absent 2018-12-04 01:02:21 +03:00
Igor Klopov
228892fe9f pass API_HOST from process.env, don't write auth.json 2018-12-04 00:29:46 +03:00
Igor Klopov
c7d434c81d More tests 4 (#112)
* replace RANDOMNESS_PLACEHOLDER in all files

* [wip] test for now/lambda

* fix for lambda test

* testDeployment to return { deploymentId, deploymentUrl }
2018-12-04 00:03:25 +03:00
Igor Klopov
66bf4aa25a Publish
- @now/md@0.4.8-canary.0
 - @now/mdx-deck@0.4.17-canary.1
 - @now/next@0.0.81-canary.1
 - @now/node-server@0.4.25-canary.1
 - @now/node@0.4.27-canary.1
 - @now/php@0.4.12-canary.1
 - @now/static-build@0.4.16-canary.0
2018-12-03 04:54:10 +03:00
Igor Klopov
f328a53a3f bump ncc to 0.2.0 (#110) 2018-12-03 04:51:20 +03:00
Tim Neutkens
168b4cf2bb Include /static directory for now/next (#109) 2018-12-02 18:40:13 +01:00
Thomas Lindstrøm
a91e3da7d8 Support default export from import/export syntax (#30)
Fix issue where files using new `import/export` syntax ran into 502 when also exporting other named exports.
https://spectrum.chat/thread/4322e805-b8ba-43d2-96e2-98b2497724e3

```
const data = {};

export default function handler(request, response) {
  response.end('hello');
}

export {data};
```
2018-11-30 08:17:07 +03:00
Igor Klopov
756c452203 bump ncc in node-server and node 2018-11-30 07:59:11 +03:00
Igor Klopov
80db1937f8 take pool position from CIRCLE_BUILD_NUM 2018-11-29 05:35:45 +03:00
Igor Klopov
d9df4b0929 pick auth token from pool 2018-11-29 05:10:47 +03:00
Igor Klopov
08c52ebbf2 More tests 3 (#101)
* test for now/md

* yarn.lock is not needed in apollo anymore

* test for now/mdx
2018-11-29 04:39:29 +03:00
Tim Neutkens
fe8ead391a Publish
- @now/next@0.0.81-canary.0
2018-11-28 19:21:44 +01:00
Tim Neutkens
5d45f2df31 @now/next Fix prepareCache (#98) 2018-11-28 19:19:01 +01:00
Nathan Rajlich
1385c1ca48 Add yarn.lock file to root 2018-11-27 16:10:36 -08:00
Nathan Rajlich
4c63009123 Add manual publish instructions to README 2018-11-27 16:10:18 -08:00
Nathan Rajlich
389c85cef5 Publish
- @now/go@0.2.11-canary.0
 - @now/mdx-deck@0.4.17-canary.0
2018-11-27 16:06:37 -08:00
Vince Picone
227c239bbc [now/mdx-deck] update mdx-deck to v1.7.15 (#86)
* Update mdx-deck dependancy

Builds failing due to a breaking change in babel-plugin-styled-components 1.9.0. Updates mdx-deck to a version with babel-plugin-styled-components pinned to 1.8.0.

https://github.com/jxnblk/mdx-deck/issues/228

Related: https://github.com/styled-components/babel-plugin-styled-components/issues/182

* Only changed version in one place.
2018-11-27 15:58:10 -08:00
Nathan Rajlich
b93736132a [now-go] always send the response as base64 (#85)
This is in-line with the CGI and PHP (#83) builders.

(Side note: we really need to make a common go import for this logic…)
2018-11-27 15:51:05 -08:00
Igor Klopov
26849422ff Publish
- @now/build-utils@0.4.31-canary.0
 - @now/node-server@0.4.25-canary.0
 - @now/node@0.4.27-canary.0
2018-11-28 02:18:45 +03:00
Igor Klopov
31dd1ca491 build-utils: inject memory-fs for yarn cache (#91)
* build-utils: inject memory-fs for yarn cache

* ditch shelljs dependency

* try to cover circle ci odd yarn installation

* Revert "try to cover circle ci odd yarn installation"

This reverts commit 751949a5dd209bab34934042eba3be1904a86ac9.

* use in-memory cache for aws only

* separate isInsideCachePath function

* print 'using memory-fs for yarn cache'

* wrong name. isInsideCachePath -> isOutsideCachePath
2018-11-27 22:12:37 +03:00
Igor Klopov
04a1ce89b3 bump ncc in node-server and node 2018-11-27 22:00:56 +03:00
Igor Klopov
3e247fd16d Tests for ncc assets (#82)
* [wip] added a test for ncc assets

* bump ncc, add 08-assets test to node-server as well

* builder-utils: don't run all fixtures, just some
2018-11-27 05:58:26 +03:00
Nathan Rajlich
9e127421ad Publish
- @now/php@0.4.12-canary.0
2018-11-26 16:51:13 -08:00
Nathan Rajlich
337d0cb1ed [now-php] set the proper response status code (#84)
1. The initial status code should be 200 (so that the first PHP call to `http_status_code` returns 200, as per the PHP documentation).
1. Extract the resulting status code and return it in the response.
2018-11-26 16:47:44 -08:00
Nathan Rajlich
ad3cdf46f4 [now-php] always send the response as base64 (#83)
This should address https://spectrum.chat/zeit/general/corrupted-image-using-php~9fbb8cc5-b210-49d1-8934-b393a628219f
2018-11-26 16:34:21 -08:00
189 changed files with 11742 additions and 1816 deletions

View File

@@ -19,3 +19,9 @@ For the canary channel use:
```
yarn publish-canary
```
CircleCI will take care of publishing the updated packages to npm from there.
If for some reason CircleCI fails to publish the npm package, you may do so
manually by running `npm publish` from the package directory. Make sure to
include the `--tag canary` parameter if you are publishing a canary release!

View File

@@ -2,7 +2,24 @@
"npmClient": "yarn",
"useWorkspaces": true,
"packages": [
"packages/*"
"packages/now-build-utils",
"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": {
"publish": {

View File

@@ -1,5 +1,6 @@
{
"name": "now-builders",
"version": "0.0.0",
"private": true,
"license": "MIT",
"dependencies": {
@@ -30,6 +31,8 @@
"@types/glob": "^7.1.1",
"@types/multistream": "^2.1.1",
"@types/node": "^10.12.8",
"async-retry": "1.2.3",
"buffer-replace": "^1.0.0",
"eslint": "^5.9.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-config-prettier": "^3.1.0",

View File

@@ -0,0 +1,32 @@
root = true
[*]
indent_style = tab
indent_size = 4
tab_width = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.json,*.json.example,*.gyp,*.yml}]
indent_style = space
indent_size = 2
[*.py]
indent_style = space
indent_size = 4
[*.md]
trim_trailing_whitespace = false
# Ideal settings - some plugins might support these.
[*.js]
quote_type = single
[{*.c,*.cc,*.h,*.hh,*.cpp,*.hpp,*.m,*.mm,*.mpp,*.js,*.java,*.go,*.rs,*.php,*.ng,*.jsx,*.ts,*.d,*.cs,*.swift}]
curly_bracket_next_line = false
spaces_around_operators = true
spaces_around_brackets = outside
# close enough to 1TB
indent_brace_style = K&R

2
packages/now-bash/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules
handler

14
packages/now-bash/bootstrap Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
set -euo pipefail
cd "$LAMBDA_TASK_ROOT"
# Configure `import`
export IMPORT_CACHE="$LAMBDA_TASK_ROOT/.import-cache"
export PATH="$IMPORT_CACHE/bin:$PATH"
# Load `import` and runtime
. "$(which import)"
. "$IMPORT_CACHE/runtime.sh"
# Load user code and process events in a loop forever
_lambda_runtime_init

40
packages/now-bash/builder.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
set -euo pipefail
# `import` debug logs are always enabled during build
export IMPORT_DEBUG=1
# Install `import`
IMPORT_BIN="$IMPORT_CACHE/bin/import"
mkdir -p "$(dirname "$IMPORT_BIN")"
curl -sfLS https://import.pw > "$IMPORT_BIN"
chmod +x "$IMPORT_BIN"
# For now only the entrypoint file is copied into the lambda
mkdir -p "$(dirname "$ENTRYPOINT")"
cp "$SRC/$ENTRYPOINT" "$ENTRYPOINT"
# Copy in the runtime
cp "$BUILDER/runtime.sh" "$IMPORT_CACHE"
cp "$BUILDER/bootstrap" .
# Load `import`
. "$(which import)"
# Cache runtime and user dependencies
echo "Caching imports in \"$ENTRYPOINT\"…"
. "$IMPORT_CACHE/runtime.sh"
. "$ENTRYPOINT"
echo "Done caching imports"
# Run user build script
if declare -f build > /dev/null; then
echo "Running \`build\` function in \"$ENTRYPOINT\"…"
build "$@"
fi
# Ensure the entrypoint defined a `handler` function
if ! declare -f handler > /dev/null; then
echo "ERROR: A \`handler\` function must be defined in \"$ENTRYPOINT\"!" >&2
exit 1
fi

View File

@@ -0,0 +1,56 @@
const execa = require('execa');
const { join } = require('path');
const snakeCase = require('snake-case');
const glob = require('@now/build-utils/fs/glob');
const download = require('@now/build-utils/fs/download');
const { createLambda } = require('@now/build-utils/lambda');
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory');
exports.config = {
maxLambdaSize: '10mb',
};
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
exports.build = async ({ files, entrypoint, config }) => {
const srcDir = await getWritableDirectory();
const workDir = await getWritableDirectory();
console.log('downloading files...');
await download(files, srcDir);
const configEnv = Object.keys(config).reduce((o, v) => {
o[`IMPORT_${snakeCase(v).toUpperCase()}`] = config[v]; // eslint-disable-line no-param-reassign
return o;
}, {});
const IMPORT_CACHE = `${workDir}/.import-cache`;
const env = Object.assign({}, process.env, configEnv, {
PATH: `${IMPORT_CACHE}/bin:${process.env.PATH}`,
IMPORT_CACHE,
SRC: srcDir,
BUILDER: __dirname,
ENTRYPOINT: entrypoint,
});
const builderPath = join(__dirname, 'builder.sh');
await execa(builderPath, [entrypoint], {
env,
cwd: workDir,
stdio: 'inherit',
});
const lambda = await createLambda({
files: await glob('**', workDir),
handler: entrypoint, // not actually used in `bootstrap`
runtime: 'provided',
environment: Object.assign({}, configEnv, {
SCRIPT_FILENAME: entrypoint,
}),
});
return {
[entrypoint]: lambda,
};
};

View File

@@ -0,0 +1,22 @@
{
"name": "@now/bash",
"version": "0.1.1",
"description": "Now 2.0 builder for HTTP endpoints written in Bash",
"main": "index.js",
"author": "Nathan Rajlich <nate@zeit.co>",
"license": "MIT",
"files": [
"builder.sh",
"runtime.sh",
"bootstrap",
"index.js",
"package.json"
],
"dependencies": {
"execa": "^1.0.0",
"snake-case": "^2.1.0"
},
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
}
}

View File

@@ -0,0 +1,111 @@
import "static-binaries@1.0.0"
static_binaries jq
# These get reset upon each request
_STATUS_CODE="$(mktemp)"
_HEADERS="$(mktemp)"
_lambda_runtime_api() {
local endpoint="$1"
shift
curl -sfLS "http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/$endpoint" "$@"
}
_lambda_runtime_init() {
# Initialize user code
. "$SCRIPT_FILENAME" || {
local exit_code="$?"
local error
error='{"exitCode":'"$exit_code"'}'
_lambda_runtime_api "init/error" -X POST -d "$error"
exit "$EXIT_CODE"
}
# Process events
while true; do _lambda_runtime_next; done
}
_lambda_runtime_next() {
echo 200 > "$_STATUS_CODE"
echo '{"content-type":"text/plain; charset=utf8"}' > "$_HEADERS"
local headers
headers="$(mktemp)"
# Get an event
local event
event="$(mktemp)"
_lambda_runtime_api invocation/next -D "$headers" | jq --raw-output --monochrome-output '.body' > "$event"
local request_id
request_id="$(grep -Fi Lambda-Runtime-Aws-Request-Id "$headers" | tr -d '[:space:]' | cut -d: -f2)"
rm -f "$headers"
# Execute the handler function from the script
local body
body="$(mktemp)"
local exit_code=0
REQUEST="$event"
# Stdin of the `handler` function is the HTTP request body.
# Need to use a fifo here instead of bash <() because Lambda
# errors with "/dev/fd/63 not found" for some reason :/
local stdin
stdin="$(mktemp --dry-run)"
mkfifo "$stdin"
_lambda_runtime_body "$event" > "$stdin" &
handler "$event" < "$stdin" > "$body" || exit_code="$?"
rm -f "$event" "$stdin"
if [ "$exit_code" -eq 0 ]; then
# Send the response
jq --raw-input --raw-output --compact-output --slurp --monochrome-output \
--arg statusCode "$(cat "$_STATUS_CODE")" \
--argjson headers "$(cat "$_HEADERS")" \
'{statusCode:$statusCode|tonumber, headers:$headers, encoding:"base64", body:.|@base64}' < "$body" \
| _lambda_runtime_api "invocation/$request_id/response" -X POST -d @- > /dev/null
rm -f "$body" "$_HEADERS"
else
echo "\`handler\` function return code: $exit_code"
_lambda_runtime_api "invocation/$request_id/error" -X POST -d @- > /dev/null <<< '{"exitCode":'"$exit_code"'}'
fi
}
_lambda_runtime_body() {
if [ "$(jq --raw-output '.body | type' < "$1")" = "string" ]; then
if [ "$(jq --raw-output '.encoding' < "$1")" = "base64" ]; then
jq --raw-output '.body' < "$1" | base64 -d
else
# assume plain-text body
jq --raw-output '.body' < "$1"
fi
fi
}
# Set the response status code.
http_response_code() {
echo "$1" > "$_STATUS_CODE"
}
# Sets a response header.
# Overrides existing header if it has already been set.
http_response_header() {
local name="$1"
local value="$2"
local tmp
tmp="$(mktemp)"
jq --arg name "$name" --arg value "$value" '.[$name] = $value' < "$_HEADERS" > "$tmp"
mv -f "$tmp" "$_HEADERS"
}
http_response_redirect() {
http_response_code "${2:-302}"
http_response_header "location" "$1"
}
http_response_json() {
http_response_header "content-type" "application/json; charset=utf8"
}

146
packages/now-bash/yarn.lock Normal file
View File

@@ -0,0 +1,146 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
cross-spawn@^6.0.0:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"
semver "^5.5.0"
shebang-command "^1.2.0"
which "^1.2.9"
end-of-stream@^1.1.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
dependencies:
once "^1.4.0"
execa@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
dependencies:
cross-spawn "^6.0.0"
get-stream "^4.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
get-stream@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
dependencies:
pump "^3.0.0"
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
lower-case@^1.1.1:
version "1.1.4"
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
no-case@^2.2.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
dependencies:
lower-case "^1.1.1"
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
dependencies:
path-key "^2.0.0"
once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
semver@^5.5.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
dependencies:
shebang-regex "^1.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
signal-exit@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
snake-case@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f"
integrity sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=
dependencies:
no-case "^2.2.0"
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=

View File

@@ -56,7 +56,7 @@ class FileRef {
const resp = await fetch(url);
if (!resp.ok) {
const error = new BailableError(
`${resp.status} ${resp.statusText}`,
`download: ${resp.status} ${resp.statusText} for ${url}`,
);
if (resp.status === 403) error.bail = true;
throw error;

View File

@@ -0,0 +1,94 @@
const MemoryFileSystem = require('memory-fs');
const fs = require('fs');
const path = require('path');
const { spawnSync } = require('child_process');
const yarnPath = spawnSync('which', ['yarn'])
.stdout.toString()
.trim();
const cachePath = spawnSync(yarnPath, ['cache', 'dir'])
.stdout.toString()
.trim();
spawnSync(yarnPath, ['cache', 'clean']);
const vfs = new MemoryFileSystem();
function isInsideCachePath(filename) {
const relative = path.relative(cachePath, filename);
return !relative.startsWith('..');
}
const saveCreateWriteStream = fs.createWriteStream;
fs.createWriteStream = (...args) => {
const filename = args[0];
if (!isInsideCachePath(filename)) {
return saveCreateWriteStream.call(fs, ...args);
}
vfs.mkdirpSync(path.dirname(filename));
fs.writeFileSync(filename, Buffer.alloc(0));
const stream = vfs.createWriteStream(...args);
stream.on('finish', () => {
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 saveCopyFile = fs.copyFile;
fs.copyFile = (...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);
vfs.mkdirpSync(path.dirname(dest));
fs.writeFileSync(dest, Buffer.alloc(0));
return vfs.writeFile(dest, buffer, callback);
}
return saveCopyFile.call(fs, ...args);
};
const saveWriteFile = fs.writeFile;
fs.writeFile = (...args) => {
const filename = args[0];
if (!isInsideCachePath(filename)) {
return saveWriteFile.call(fs, ...args);
}
vfs.mkdirpSync(path.dirname(filename));
fs.writeFileSync(filename, Buffer.alloc(0));
return vfs.writeFile(...args);
};
require(yarnPath);

View File

@@ -1,8 +1,8 @@
const path = require('path');
const fs = require('fs-extra');
const dev = !process.env.AWS_EXECUTION_ENV;
const TMP_PATH = dev ? path.join(process.cwd(), 'tmp') : '/tmp';
const prod = process.env.AWS_EXECUTION_ENV || process.env.X_GOOGLE_CODE_LOCATION;
const TMP_PATH = prod ? '/tmp' : path.join(__dirname, 'tmp');
module.exports = async function getWritableDirectory() {
const name = Math.floor(Math.random() * 0x7fffffff).toString(16);

View File

@@ -3,6 +3,9 @@ const fs = require('fs-extra');
const path = require('path');
const { spawn } = require('child_process');
const prod = process.env.AWS_EXECUTION_ENV
|| process.env.X_GOOGLE_CODE_LOCATION;
function spawnAsync(command, args, cwd) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, { stdio: 'inherit', cwd });
@@ -35,7 +38,7 @@ async function scanParentDirs(destPath, scriptName) {
// eslint-disable-next-line no-await-in-loop
const packageJson = JSON.parse(await fs.readFile(packageJsonPath));
hasScript = Boolean(
packageJson.scripts && packageJson.scripts[scriptName],
packageJson.scripts && scriptName && packageJson.scripts[scriptName],
);
// eslint-disable-next-line no-await-in-loop
hasPackageLockJson = await fs.exists(
@@ -52,7 +55,7 @@ async function scanParentDirs(destPath, scriptName) {
return { hasScript, hasPackageLockJson };
}
async function runNpmInstall(destPath, args = []) {
async function installDependencies(destPath, args = []) {
assert(path.isAbsolute(destPath));
let commandArgs = args;
@@ -63,6 +66,15 @@ async function runNpmInstall(destPath, args = []) {
commandArgs = args.filter(a => a !== '--prefer-offline');
await spawnAsync('npm', ['install'].concat(commandArgs), destPath);
await spawnAsync('npm', ['cache', 'clean', '--force'], destPath);
} else if (prod) {
console.log('using memory-fs for yarn cache');
await spawnAsync(
'node',
[path.join(__dirname, 'bootstrap-yarn.js'), '--cwd', destPath].concat(
commandArgs,
),
destPath,
);
} else {
await spawnAsync('yarn', ['--cwd', destPath].concat(commandArgs), destPath);
await spawnAsync('yarn', ['cache', 'clean'], destPath);
@@ -90,6 +102,7 @@ async function runPackageJsonScript(destPath, scriptName) {
module.exports = {
runShellScript,
runNpmInstall,
installDependencies,
runNpmInstall: installDependencies,
runPackageJsonScript,
};

View File

@@ -1,4 +1,5 @@
const assert = require('assert');
const Sema = require('async-sema');
const { ZipFile } = require('yazl');
const streamToBuffer = require('./fs/stream-to-buffer.js');
@@ -14,6 +15,7 @@ class Lambda {
}
}
const sema = new Sema(10);
const mtime = new Date(1540000000000);
async function createLambda({
@@ -23,24 +25,33 @@ async function createLambda({
assert(typeof handler === 'string', '"handler" is not a string');
assert(typeof runtime === 'string', '"runtime" is not a string');
assert(typeof environment === 'object', '"environment" is not an object');
const zipFile = new ZipFile();
await sema.acquire();
try {
const zipFile = new ZipFile();
const zipBuffer = await new Promise((resolve, reject) => {
Object.keys(files)
.sort()
.forEach((name) => {
const file = files[name];
const stream = file.toStream();
stream.on('error', reject);
zipFile.addReadStream(stream, name, { mode: file.mode, mtime });
});
zipFile.end();
const zipBuffer = await streamToBuffer(zipFile.outputStream);
streamToBuffer(zipFile.outputStream).then(resolve).catch(reject);
});
return new Lambda({
zipBuffer,
handler,
runtime,
environment,
});
} finally {
sema.release();
}
}
module.exports = {

View File

@@ -1,6 +1,7 @@
{
"name": "@now/build-utils",
"version": "0.4.30",
"version": "0.4.32",
"license": "MIT",
"dependencies": {
"async-retry": "1.2.3",
"async-sema": "2.1.4",
@@ -8,6 +9,7 @@
"fs-extra": "7.0.0",
"glob": "7.1.3",
"into-stream": "4.0.0",
"memory-fs": "0.4.1",
"multistream": "2.1.1",
"node-fetch": "2.2.0",
"yazl": "2.4.3"

View File

@@ -0,0 +1,5 @@
const cowsay = require('cowsay').say;
module.exports = (req, resp) => {
resp.end(cowsay({ text: 'cross-cow:RANDOMNESS_PLACEHOLDER' }));
};

View File

@@ -0,0 +1,5 @@
{
"dependencies": {
"lib": "../lib"
}
}

View File

@@ -0,0 +1,7 @@
{
"name": "lib",
"version": "0.0.1",
"dependencies": {
"cowsay": "*"
}
}

View File

@@ -0,0 +1,9 @@
{
"version": 2,
"builds": [
{ "src": "api/index.js", "use": "@now/node" }
],
"probes": [
{ "path": "/api/index.js", "mustContain": "cross-cow:RANDOMNESS_PLACEHOLDER" }
]
}

View File

@@ -8,6 +8,7 @@ const {
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(2 * 60 * 1000);
const builderUrl = '@canary';
let buildUtilsUrl;
beforeAll(async () => {
@@ -25,8 +26,11 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
// eslint-disable-next-line no-loop-func
it(`should build ${fixture}`, async () => {
await expect(
testDeployment({ buildUtilsUrl }, path.join(fixturesPath, fixture)),
).resolves.toBe(undefined);
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
).resolves.toBeDefined();
});
}
@@ -43,11 +47,17 @@ for (const builder of buildersToTestWith) {
// eslint-disable-next-line no-restricted-syntax
for (const fixture of fs.readdirSync(fixturesPath2)) {
// don't run all foreign fixtures, just some
if (['01-cowsay', '03-env-vars'].includes(fixture)) {
// eslint-disable-next-line no-loop-func
it(`should build ${builder}/${fixture}`, async () => {
await expect(
testDeployment({ buildUtilsUrl }, path.join(fixturesPath2, fixture)),
).resolves.toBe(undefined);
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath2, fixture),
),
).resolves.toBeDefined();
});
}
}
}

View File

@@ -1,152 +1,36 @@
package main
import (
"os"
"fmt"
"net"
"strings"
"io/ioutil"
now "../../utils/go/bridge"
"net/http"
"net/http/cgi"
"os"
"path/filepath"
"encoding/json"
b64 "encoding/base64"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
type Request struct {
Host string `json:"host"`
Path string `json:"path"`
Method string `json:"method"`
Headers map[string]string `json:"headers"`
Encoding string `json:"encoding,omitempty"`
Body string `json:"body"`
}
type Response struct {
StatusCode int `json:"statusCode"`
Headers map[string]string `json:"headers"`
Encoding string `json:"encoding,omitemtpy"`
Body string `json:"body"`
}
type ResponseError struct {
Code string `json:"code"`
Message string `json:"message"`
}
type ResponseErrorWrapper struct {
Error ResponseError `json:"error"`
}
type CgiHandler struct {
http.Handler
Dir string
Script string
}
func createErrorResponse(message string, code string, statusCode int) (Response, error) {
obj := ResponseErrorWrapper{
Error: ResponseError{
Code: code,
Message: message,
},
}
body, _ := json.Marshal(obj)
return Response{
StatusCode: statusCode,
Headers: map[string]string{
"Content-Type": "application/json",
},
Body: string(body),
}, nil
}
func (h *CgiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
cgih := cgi.Handler{
handler := cgi.Handler{
Path: h.Script,
Root: "/" + h.Script,
Dir: h.Dir,
Env: []string{"SERVER_PORT=443", "HTTPS=on", "SERVER_SOFTWARE=@now/cgi"},
Env: []string{
"HTTPS=on",
"SERVER_PORT=443",
"SERVER_SOFTWARE=@now/cgi",
},
}
cgih.ServeHTTP(w, r)
handler.ServeHTTP(w, r)
}
func main() {
l, err := net.Listen("tcp", ":0")
if err != nil {
panic(err)
}
workdir, _ := filepath.Abs(".")
script := os.Getenv("SCRIPT_FILENAME")
h := &CgiHandler{nil, workdir, script}
http.Handle("/", h)
go http.Serve(l, nil)
handler := func(_req events.APIGatewayProxyRequest) (Response, error) {
var req Request
err := json.Unmarshal([]byte(_req.Body), &req)
if err != nil {
fmt.Println(err)
return createErrorResponse("Invalid payload", "bad_request", 400)
}
if req.Encoding == "base64" {
decoded, _ := b64.StdEncoding.DecodeString(req.Body)
req.Body = string(decoded)
}
url := "http://" + l.Addr().String() + req.Path
internalReq, err := http.NewRequest(req.Method, url, strings.NewReader(req.Body))
if err != nil {
fmt.Println(err)
return createErrorResponse("Bad gateway internal req failed", "bad_gateway", 502)
}
for k, v := range req.Headers {
internalReq.Header.Add(k, v)
if strings.ToLower(k) == "host" {
internalReq.Host = v
}
}
client := &http.Client{}
internalRes, err := client.Do(internalReq)
if err != nil {
fmt.Println(err)
return createErrorResponse("Bad gateway internal req Do failed", "bad_gateway", 502)
}
defer internalRes.Body.Close()
resHeaders := make(map[string]string, len(internalRes.Header))
for k, v := range internalRes.Header {
// FIXME: support multiple values via concatenating with ','
// see RFC 7230, section 3.2.2
resHeaders[k] = v[0]
}
bodyBytes, err := ioutil.ReadAll(internalRes.Body)
if err != nil {
return createErrorResponse("Bad gateway ReadAll bytes from response failed", "bad_gateway", 502)
}
resBody := b64.StdEncoding.EncodeToString(bodyBytes)
return Response{
StatusCode: internalRes.StatusCode,
Headers: resHeaders,
Encoding: "base64",
Body: resBody,
}, nil
}
lambda.Start(handler)
handler := &CgiHandler{nil, workdir, script}
now.Start(handler)
}

View File

@@ -1,6 +1,7 @@
{
"name": "@now/cgi",
"version": "0.0.13",
"version": "0.0.15",
"license": "MIT",
"scripts": {
"test": "best -I test/*.js",
"prepublish": "./build.sh"

View File

@@ -1,3 +1,4 @@
node_modules
*.log
launcher
bin

View File

@@ -9,7 +9,7 @@ const downloadGit = require('lambda-git');
const glob = require('@now/build-utils/fs/glob.js');
const downloadGoBin = require('./download-go-bin');
// creates a `$GOPATH` direcotry tree, as per
// creates a `$GOPATH` directory tree, as per
// `go help gopath`'s instructions.
// without this, Go won't recognize the `$GOPATH`
async function createGoPathTree(goPath) {

View File

@@ -1,143 +1,10 @@
package main
import (
b64 "encoding/base64"
"encoding/json"
"fmt"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"io/ioutil"
"net"
now "../../utils/go/bridge"
"net/http"
"strings"
)
type Request struct {
Host string `json:"host"`
Path string `json:"path"`
Method string `json`
Headers map[string]string `json:"headers"`
Encoding string `json"encoding,omitempty"`
Body string `json:"body"`
}
type Response struct {
StatusCode int `json:"statusCode"`
Headers map[string]string `json:"headers"`
Encoding string `json:"encoding,omitemtpy"`
Body string `json:"body"`
}
type ResponseError struct {
Code string `json:"code"`
Message string `json:"message"`
}
type ResponseErrorWrapper struct {
Error ResponseError `json:"error"`
}
func createErrorResponse(message string, code string, statusCode int) (Response, error) {
obj := ResponseErrorWrapper{
Error: ResponseError{
Code: code,
Message: message,
},
}
body, _ := json.Marshal(obj)
return Response{
StatusCode: statusCode,
Headers: map[string]string{
"Content-Type": "application/json",
},
Body: string(body),
}, nil
}
func main() {
l, err := net.Listen("tcp", ":0")
if err != nil {
panic(err)
}
http.HandleFunc("/", __NOW_HANDLER_FUNC_NAME)
go http.Serve(l, nil)
handler := func(_req events.APIGatewayProxyRequest) (Response, error) {
var req Request
err := json.Unmarshal([]byte(_req.Body), &req)
if err != nil {
fmt.Println(err)
return createErrorResponse("Invalid payload", "bad_request", 400)
}
if req.Encoding == "base64" {
decoded, _ := b64.StdEncoding.DecodeString(req.Body)
req.Body = string(decoded)
}
url := "http://" + l.Addr().String() + req.Path
internalReq, err := http.NewRequest(req.Method, url, strings.NewReader(req.Body))
if err != nil {
fmt.Println(err)
return createErrorResponse("Bad gateway", "bad_gateway", 502)
}
for k, v := range req.Headers {
internalReq.Header.Add(k, v)
if strings.ToLower(k) == "host" {
// we need to set `Host` in the request
// because Go likes to ignore the `Host` header
// see https://github.com/golang/go/issues/7682
internalReq.Host = v
}
}
client := &http.Client{}
internalRes, err := client.Do(internalReq)
if err != nil {
fmt.Println(err)
return createErrorResponse("Bad gateway", "bad_gateway", 502)
}
defer internalRes.Body.Close()
resHeaders := make(map[string]string, len(internalRes.Header))
var resEncoding string
for k, v := range internalRes.Header {
// FIXME: support multiple values via concatenating with ','
// see RFC 7230, section 3.2.2
if strings.ToLower(k) == "x-now-response-encoding" {
// we don't want to send this header down
resEncoding = v[0]
} else {
resHeaders[k] = v[0]
}
}
bodyBytes, err := ioutil.ReadAll(internalRes.Body)
if err != nil {
return createErrorResponse("Bad gateway", "bad_gateway", 502)
}
var resBody string
if resEncoding == "base64" {
resBody = b64.StdEncoding.EncodeToString(bodyBytes)
} else {
resBody = string(bodyBytes)
}
return Response{
StatusCode: internalRes.StatusCode,
Headers: resHeaders,
Encoding: resEncoding,
Body: resBody,
}, nil
}
lambda.Start(handler)
now.Start(http.HandlerFunc(__NOW_HANDLER_FUNC_NAME))
}

View File

@@ -1,6 +1,7 @@
{
"name": "@now/go",
"version": "0.2.10",
"version": "0.2.12",
"license": "MIT",
"scripts": {
"test": "best -I test/*.js",
"prepublish": "./build.sh"

View File

@@ -1,6 +1,7 @@
{
"name": "@now/html-minifier",
"version": "1.0.6",
"version": "1.0.7",
"license": "MIT",
"dependencies": {
"html-minifier": "3.5.21"
},

View File

@@ -0,0 +1 @@
/test

View File

@@ -1,7 +1,11 @@
{
"name": "@now/lambda",
"version": "0.4.7",
"version": "0.4.9",
"license": "MIT",
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
},
"scripts": {
"test": "jest"
}
}

Binary file not shown.

View File

@@ -0,0 +1,11 @@
{
"version": 2,
"builds": [
{ "src": "index.zip", "use": "@now/lambda", "config": { "handler": "index.handler", "runtime": "nodejs8.10" } },
{ "src": "subdirectory/index.zip", "use": "@now/lambda", "config": { "handler": "index.handler", "runtime": "nodejs8.10" } }
],
"probes": [
{ "path": "/", "mustContain": "cow:NO_REPLACE_TO_AVOID_CRC_MISMATCH" },
{ "path": "/subdirectory/", "mustContain": "yoda:NO_REPLACE_TO_AVOID_CRC_MISMATCH" }
]
}

Binary file not shown.

View File

@@ -0,0 +1,33 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs');
const path = require('path');
const {
packAndDeploy,
testDeployment,
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(2 * 60 * 1000);
const buildUtilsUrl = '@canary';
let builderUrl;
beforeAll(async () => {
const builderPath = path.resolve(__dirname, '..');
builderUrl = await packAndDeploy(builderPath);
console.log('builderUrl', builderUrl);
});
const fixturesPath = path.resolve(__dirname, 'fixtures');
// eslint-disable-next-line no-restricted-syntax
for (const fixture of fs.readdirSync(fixturesPath)) {
// eslint-disable-next-line no-loop-func
it(`should build ${fixture}`, async () => {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
).resolves.toBeDefined();
});
}

View File

@@ -0,0 +1 @@
/test

View File

@@ -1,6 +1,7 @@
{
"name": "@now/md",
"version": "0.4.7",
"version": "0.4.9",
"license": "MIT",
"dependencies": {
"rehype-document": "^2.2.0",
"rehype-format": "^2.3.0",
@@ -12,5 +13,8 @@
},
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
},
"scripts": {
"test": "jest"
}
}

View File

@@ -0,0 +1,5 @@
# Testing Markdown
cow:RANDOMNESS_PLACEHOLDER
[Wow a link!](https://zeit.co)

View File

@@ -0,0 +1,11 @@
{
"version": 2,
"builds": [
{ "src": "index.md", "use": "@now/md" },
{ "src": "subdirectory/index.md", "use": "@now/md" }
],
"probes": [
{ "path": "/", "mustContain": "cow:RANDOMNESS_PLACEHOLDER" },
{ "path": "/subdirectory/", "mustContain": "yoda:RANDOMNESS_PLACEHOLDER" }
]
}

View File

@@ -0,0 +1,5 @@
# Testing Markdown
yoda:RANDOMNESS_PLACEHOLDER
[Wow a link!](https://zeit.co)

View File

@@ -0,0 +1,33 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs');
const path = require('path');
const {
packAndDeploy,
testDeployment,
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(2 * 60 * 1000);
const buildUtilsUrl = '@canary';
let builderUrl;
beforeAll(async () => {
const builderPath = path.resolve(__dirname, '..');
builderUrl = await packAndDeploy(builderPath);
console.log('builderUrl', builderUrl);
});
const fixturesPath = path.resolve(__dirname, 'fixtures');
// eslint-disable-next-line no-restricted-syntax
for (const fixture of fs.readdirSync(fixturesPath)) {
// eslint-disable-next-line no-loop-func
it(`should build ${fixture}`, async () => {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
).resolves.toBeDefined();
});
}

View File

@@ -0,0 +1 @@
/test

View File

@@ -6,18 +6,16 @@ const glob = require('@now/build-utils/fs/glob.js');
const path = require('path');
const { runNpmInstall } = require('@now/build-utils/fs/run-user-scripts.js');
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
const writeFile = promisify(fs.writeFile);
exports.build = async ({ files, entrypoint, workPath }) => {
console.log('downloading user files...');
const downloadedFiles = await download(files, workPath);
console.log('writing package.json...');
const packageJson = { dependencies: { 'mdx-deck': '1.7.7' } };
const packageJson = { dependencies: { 'mdx-deck': '1.7.15' } };
const packageJsonPath = path.join(workPath, 'package.json');
await writeFile(packageJsonPath, JSON.stringify(packageJson));
console.log('running npm install...');
console.log('installing dependencies...');
process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = '1'; // TODO opts argument for runNpmInstall
await runNpmInstall(path.dirname(packageJsonPath), [
'--prod',
@@ -47,7 +45,7 @@ exports.build = async ({ files, entrypoint, workPath }) => {
exports.prepareCache = async ({ cachePath }) => {
console.log('writing package.json...');
const packageJson = { dependencies: { 'mdx-deck': '1.7.7' } };
const packageJson = { dependencies: { 'mdx-deck': '1.7.15' } };
const packageJsonPath = path.join(cachePath, 'package.json');
await writeFile(packageJsonPath, JSON.stringify(packageJson));
console.log('running npm install...');

View File

@@ -1,7 +1,11 @@
{
"name": "@now/mdx-deck",
"version": "0.4.16",
"version": "0.4.18",
"license": "MIT",
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
},
"scripts": {
"test": "jest"
}
}

View File

@@ -0,0 +1,5 @@
# Testing Markdown
---
cow:RANDOMNESS_PLACEHOLDER
---
[Wow a link!](https://zeit.co)

View File

@@ -0,0 +1,11 @@
{
"version": 2,
"builds": [
{ "src": "index.mdx", "use": "@now/mdx-deck" },
{ "src": "subdirectory/index.mdx", "use": "@now/mdx-deck" }
],
"probes": [
{ "path": "/", "mustContain": "cow:RANDOMNESS_PLACEHOLDER" },
{ "path": "/subdirectory/", "mustContain": "yoda:RANDOMNESS_PLACEHOLDER" }
]
}

View File

@@ -0,0 +1,5 @@
# Testing Markdown
---
yoda:RANDOMNESS_PLACEHOLDER
---
[Wow a link!](https://zeit.co)

View File

@@ -0,0 +1,33 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs');
const path = require('path');
const {
packAndDeploy,
testDeployment,
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(2 * 60 * 1000);
const buildUtilsUrl = '@canary';
let builderUrl;
beforeAll(async () => {
const builderPath = path.resolve(__dirname, '..');
builderUrl = await packAndDeploy(builderPath);
console.log('builderUrl', builderUrl);
});
const fixturesPath = path.resolve(__dirname, 'fixtures');
// eslint-disable-next-line no-restricted-syntax
for (const fixture of fs.readdirSync(fixturesPath)) {
// eslint-disable-next-line no-loop-func
it(`should build ${fixture}`, async () => {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
).resolves.toBeDefined();
});
}

View File

@@ -9,14 +9,16 @@ const {
runPackageJsonScript,
} = require('@now/build-utils/fs/run-user-scripts.js');
const glob = require('@now/build-utils/fs/glob.js');
const semver = require('semver');
const nextLegacyVersions = require('./legacy-versions');
const {
excludeFiles,
validateEntrypoint,
includeOnlyEntryDirectory,
moveEntryDirectoryToRoot,
excludeLockFiles,
normalizePackageJson,
excludeStaticDirectory,
onlyStaticDirectory,
} = require('./utils');
/** @typedef { import('@now/build-utils/file-ref').Files } Files */
@@ -87,42 +89,111 @@ exports.build = async ({ files, workPath, entrypoint }) => {
filesOnlyEntryDirectory,
entryDirectory,
);
const filesWithoutLockfiles = excludeLockFiles(filesWithEntryDirectoryRoot);
const filesWithoutStaticDirectory = excludeStaticDirectory(
filesWithoutLockfiles,
filesWithEntryDirectoryRoot,
);
let downloadedFiles = await download(filesWithoutStaticDirectory, workPath);
const downloadedFiles = await download(filesWithoutStaticDirectory, workPath);
console.log('normalizing package.json');
const packageJson = normalizePackageJson(
await readPackageJson(downloadedFiles),
const pkg = await readPackageJson(downloadedFiles);
let nextVersion;
if (pkg.dependencies && pkg.dependencies.next) {
nextVersion = pkg.dependencies.next;
} else if (pkg.devDependencies && pkg.devDependencies.next) {
nextVersion = pkg.devDependencies.next;
}
if (!nextVersion) {
throw new Error(
'No Next.js version could be detected in "package.json". Make sure `"next"` is installed in "dependencies" or "devDependencies"',
);
}
const isLegacy = (() => {
// If version is using the dist-tag instead of a version range
if (nextVersion === 'canary' || nextVersion === 'latest') {
return false;
}
// If the version is an exact match with the legacy versions
if (nextLegacyVersions.indexOf(nextVersion) !== -1) {
return true;
}
const maxSatisfying = semver.maxSatisfying(nextLegacyVersions, nextVersion);
// When the version can't be matched with legacy versions, so it must be a newer version
if (maxSatisfying === null) {
return false;
}
return true;
})();
console.log(`MODE: ${isLegacy ? 'legacy' : 'serverless'}`);
if (isLegacy) {
try {
await unlink(path.join(workPath, 'yarn.lock'));
} catch (err) {
console.log('no yarn.lock removed');
}
try {
await unlink(path.join(workPath, 'package-lock.json'));
} catch (err) {
console.log('no package-lock.json removed');
}
console.warn(
"WARNING: your application is being deployed in @now/next's legacy mode.",
);
console.log('normalizing package.json');
const packageJson = normalizePackageJson(pkg);
console.log('normalized package.json result: ', packageJson);
await writePackageJson(workPath, packageJson);
} else if (!pkg.scripts || !pkg.scripts['now-build']) {
console.warn(
'WARNING: "now-build" script not found. Adding \'"now-build": "next build"\' to "package.json" automatically',
);
pkg.scripts = {
'now-build': 'next build',
...(pkg.scripts || {}),
};
console.log('normalized package.json result: ', pkg);
await writePackageJson(workPath, pkg);
}
if (process.env.NPM_AUTH_TOKEN) {
console.log('found NPM_AUTH_TOKEN in environment, creating .npmrc');
await writeNpmRc(workPath, process.env.NPM_AUTH_TOKEN);
}
downloadedFiles = await glob('**', workPath);
console.log('running npm install...');
console.log('installing dependencies...');
await runNpmInstall(workPath, ['--prefer-offline']);
console.log('running user script...');
await runPackageJsonScript(workPath, 'now-build');
if (isLegacy) {
console.log('running npm install --production...');
await runNpmInstall(workPath, ['--prefer-offline', '--production']);
}
if (process.env.NPM_AUTH_TOKEN) {
await unlink(path.join(workPath, '.npmrc'));
}
downloadedFiles = await glob('**', workPath);
const lambdas = {};
if (isLegacy) {
const filesAfterBuild = await glob('**', workPath);
console.log('preparing lambda files...');
let buildId;
try {
buildId = await readFile(path.join(workPath, '.next', 'BUILD_ID'), 'utf8');
buildId = await readFile(
path.join(workPath, '.next', 'BUILD_ID'),
'utf8',
);
} catch (err) {
console.error(
'BUILD_ID not found in ".next". The "package.json" "build" script did not run "next build"',
@@ -144,17 +215,16 @@ exports.build = async ({ files, workPath, entrypoint }) => {
...dotNextServerRootFiles,
...launcherFiles,
};
if (downloadedFiles['next.config.js']) {
nextFiles['next.config.js'] = downloadedFiles['next.config.js'];
if (filesAfterBuild['next.config.js']) {
nextFiles['next.config.js'] = filesAfterBuild['next.config.js'];
}
const pages = await glob(
'**/*.js',
path.join(workPath, '.next', 'server', 'static', buildId, 'pages'),
);
const launcherPath = path.join(__dirname, 'launcher.js');
const launcherPath = path.join(__dirname, 'legacy-launcher.js');
const launcherData = await readFile(launcherPath, 'utf8');
const lambdas = {};
await Promise.all(
Object.keys(pages).map(async (page) => {
// These default pages don't have to be handled as they'd always 404
@@ -169,16 +239,16 @@ exports.build = async ({ files, workPath, entrypoint }) => {
);
const pageFiles = {
[`.next/server/static/${buildId}/pages/_document.js`]: downloadedFiles[
[`.next/server/static/${buildId}/pages/_document.js`]: filesAfterBuild[
`.next/server/static/${buildId}/pages/_document.js`
],
[`.next/server/static/${buildId}/pages/_app.js`]: downloadedFiles[
[`.next/server/static/${buildId}/pages/_app.js`]: filesAfterBuild[
`.next/server/static/${buildId}/pages/_app.js`
],
[`.next/server/static/${buildId}/pages/_error.js`]: downloadedFiles[
[`.next/server/static/${buildId}/pages/_error.js`]: filesAfterBuild[
`.next/server/static/${buildId}/pages/_error.js`
],
[`.next/server/static/${buildId}/pages/${page}`]: downloadedFiles[
[`.next/server/static/${buildId}/pages/${page}`]: filesAfterBuild[
`.next/server/static/${buildId}/pages/${page}`
],
};
@@ -196,6 +266,49 @@ exports.build = async ({ files, workPath, entrypoint }) => {
console.log(`Created lambda for page: "${page}"`);
}),
);
} else {
console.log('preparing lambda files...');
const launcherFiles = {
'now__bridge.js': new FileFsRef({ fsPath: require('@now/node-bridge') }),
'now__launcher.js': new FileFsRef({
fsPath: path.join(__dirname, 'launcher.js'),
}),
};
const pages = await glob(
'**/*.js',
path.join(workPath, '.next', 'serverless', 'pages'),
);
const pageKeys = Object.keys(pages);
if (pageKeys.length === 0) {
throw new Error(
'No serverless pages were built. https://err.sh/zeit/now-builders/now-next-no-serverless-pages-built',
);
}
await Promise.all(
pageKeys.map(async (page) => {
// These default pages don't have to be handled as they'd always 404
if (['_app.js', '_error.js', '_document.js'].includes(page)) {
return;
}
const pathname = page.replace(/\.js$/, '');
console.log(`Creating lambda for page: "${page}"...`);
lambdas[path.join(entryDirectory, pathname)] = await createLambda({
files: {
...launcherFiles,
'page.js': pages[page],
},
handler: 'now__launcher.launcher',
runtime: 'nodejs8.10',
});
console.log(`Created lambda for page: "${page}"`);
}),
);
}
const nextStaticFiles = await glob(
'**',
@@ -209,28 +322,14 @@ exports.build = async ({ files, workPath, entrypoint }) => {
{},
);
return { ...lambdas, ...staticFiles };
};
exports.prepareCache = async ({ files, cachePath, workPath }) => {
console.log('downloading user files...');
await download(files, cachePath);
await download(await glob('.next/**', workPath), cachePath);
await download(await glob('node_modules/**', workPath), cachePath);
console.log('.next folder contents', await glob('.next/**', cachePath));
console.log(
'.cache folder contents',
await glob('node_modules/.cache/**', cachePath),
const nextStaticDirectory = onlyStaticDirectory(filesWithEntryDirectoryRoot);
const staticDirectoryFiles = Object.keys(nextStaticDirectory).reduce(
(mappedFiles, file) => ({
...mappedFiles,
[path.join(entryDirectory, file)]: nextStaticDirectory[file],
}),
{},
);
console.log('running npm install...');
await runNpmInstall(cachePath);
return {
...(await glob('.next/records.json', cachePath)),
...(await glob('.next/server/records.json', cachePath)),
...(await glob('node_modules/**', cachePath)),
...(await glob('yarn.lock', cachePath)),
};
return { ...lambdas, ...staticFiles, ...staticDirectoryFiles };
};

View File

@@ -1,19 +1,13 @@
process.env.NODE_ENV = 'production';
const { Server } = require('http');
const next = require('next-server');
const url = require('url');
const { Bridge } = require('./now__bridge.js');
const page = require('./page.js');
const bridge = new Bridge();
bridge.port = 3000;
process.env.NODE_ENV = 'production';
const app = next({});
const server = new Server((req, res) => {
const parsedUrl = url.parse(req.url, true);
app.render(req, res, 'PATHNAME_PLACEHOLDER', parsedUrl.query, parsedUrl);
});
const server = new Server(page.render);
server.listen(bridge.port);
exports.launcher = bridge.launcher;

View File

@@ -0,0 +1,19 @@
const { Server } = require('http');
const next = require('next-server');
const url = require('url');
const { Bridge } = require('./now__bridge.js');
const bridge = new Bridge();
bridge.port = 3000;
process.env.NODE_ENV = 'production';
const app = next({});
const server = new Server((req, res) => {
const parsedUrl = url.parse(req.url, true);
app.render(req, res, 'PATHNAME_PLACEHOLDER', parsedUrl.query, parsedUrl);
});
server.listen(bridge.port);
exports.launcher = bridge.launcher;

View File

@@ -0,0 +1,336 @@
module.exports = [
'0.1.0',
'0.1.1',
'0.2.0',
'0.2.1',
'0.2.2',
'0.2.3',
'0.2.4',
'0.2.5',
'0.2.6',
'0.2.7',
'0.2.8',
'0.2.9',
'0.2.10',
'0.2.11',
'0.2.12',
'0.2.13',
'0.2.14',
'0.3.0',
'0.3.1',
'0.3.2',
'0.3.3',
'0.4.0',
'0.4.1',
'0.9.9',
'0.9.10',
'0.9.11',
'1.0.0',
'1.0.1',
'1.0.2',
'1.1.0',
'1.1.1',
'1.1.2',
'1.2.0',
'1.2.1',
'1.2.2',
'1.2.3',
'2.0.0-beta.0',
'2.0.0-beta.1',
'2.0.0-beta.2',
'2.0.0-beta.3',
'2.0.0-beta.4',
'2.0.0-beta.5',
'2.0.0-beta.6',
'2.0.0-beta.7',
'2.0.0-beta.8',
'2.0.0-beta.9',
'2.0.0-beta.10',
'2.0.0-beta.11',
'2.0.0-beta.12',
'2.0.0-beta.13',
'2.0.0-beta.14',
'2.0.0-beta.15',
'2.0.0-beta.16',
'2.0.0-beta.17',
'2.0.0-beta.18',
'2.0.0-beta.19',
'2.0.0-beta.20',
'2.0.0-beta.21',
'2.0.0-beta.22',
'2.0.0-beta.23',
'2.0.0-beta.24',
'2.0.0-beta.25',
'2.0.0-beta.26',
'2.0.0-beta.27',
'2.0.0-beta.28',
'2.0.0-beta.29',
'2.0.0-beta.30',
'2.0.0-beta.31',
'2.0.0-beta.32',
'2.0.0-beta.33',
'2.0.0-beta.34',
'2.0.0-beta.35',
'2.0.0-beta.36',
'2.0.0-beta.37',
'2.0.0-beta.38',
'2.0.0-beta.39',
'2.0.0-beta.40',
'2.0.0-beta.41',
'2.0.0-beta.42',
'2.0.0',
'2.0.1',
'2.1.0',
'2.1.1',
'2.2.0',
'2.3.0-alpha1',
'2.3.0',
'2.3.1',
'2.4.0',
'2.4.1',
'2.4.2',
'2.4.3',
'2.4.4',
'2.4.5',
'2.4.6',
'2.4.7',
'2.4.8',
'2.4.9',
'3.0.0-beta1',
'3.0.0-beta10',
'3.0.0-beta11',
'3.0.0-beta12',
'3.0.0-beta13',
'3.0.0-beta14',
'3.0.0-beta15',
'3.0.0-beta16',
'3.0.0-beta2',
'3.0.0-beta3',
'3.0.0-beta4',
'3.0.0-beta5',
'3.0.0-beta6',
'3.0.0-beta7',
'3.0.0-beta8',
'3.0.0-beta9',
'3.0.1-beta.1',
'3.0.1-beta.2',
'3.0.1-beta.3',
'3.0.1-beta.4',
'3.0.1-beta.5',
'3.0.1-beta.6',
'3.0.1-beta.7',
'3.0.1-beta.8',
'3.0.1-beta.9',
'3.0.1-beta.10',
'3.0.1-beta.11',
'3.0.1-beta.12',
'3.0.1-beta.13',
'3.0.1-beta.14',
'3.0.1-beta.15',
'3.0.1-beta.16',
'3.0.1-beta.17',
'3.0.1-beta.18',
'3.0.1-beta.19',
'3.0.1-beta.20',
'3.0.1-beta.21',
'3.0.1',
'3.0.2',
'3.0.3',
'3.0.4',
'3.0.5',
'3.0.6',
'3.1.0',
'3.2.0',
'3.2.1',
'3.2.2',
'3.2.3',
'4.0.0-beta.1',
'4.0.0-beta.2',
'4.0.0-beta.3',
'4.0.0-beta.4',
'4.0.0-beta.5',
'4.0.0-beta.6',
'4.0.0',
'4.0.1',
'4.0.2',
'4.0.3',
'4.0.4',
'4.0.5',
'4.1.0',
'4.1.1',
'4.1.2',
'4.1.3',
'4.1.4-canary.1',
'4.1.4-canary.2',
'4.1.4',
'4.2.0-canary.1',
'4.2.0-zones.2',
'4.2.0',
'4.2.1',
'4.2.2',
'4.2.3',
'4.3.0-canary.1',
'4.3.0-universal-alpha.1',
'4.3.0-universal-alpha.2',
'4.3.0-universal-alpha.3',
'4.3.0-universal-alpha.4',
'4.3.0-zones.1',
'4.4.0-canary.2',
'4.4.0-canary.3',
'5.0.0-universal-alpha.1',
'5.0.0-universal-alpha.2',
'5.0.0-universal-alpha.3',
'5.0.0-universal-alpha.4',
'5.0.0-universal-alpha.5',
'5.0.0-universal-alpha.6',
'5.0.0-universal-alpha.7',
'5.0.0-universal-alpha.8',
'5.0.0-universal-alpha.9',
'5.0.0-universal-alpha.10',
'5.0.0-universal-alpha.11',
'5.0.0-universal-alpha.12',
'5.0.0-universal-alpha.13',
'5.0.0-universal-alpha.14',
'5.0.0-universal-alpha.15',
'5.0.0-universal-alpha.16',
'5.0.0-universal-alpha.17',
'5.0.0-universal-alpha.18',
'5.0.0-universal-alpha.19',
'5.0.0-universal-alpha.20',
'5.0.0-universal-alpha.21',
'5.0.0-universal-alpha.22',
'5.0.0-universal-alpha.23',
'5.0.0-zones.1',
'5.0.0',
'5.0.1-canary.1',
'5.0.1-canary.2',
'5.0.1-canary.3',
'5.0.1-canary.4',
'5.0.1-canary.5',
'5.0.1-canary.6',
'5.0.1-canary.7',
'5.0.1-canary.8',
'5.0.1-canary.9',
'5.0.1-canary.10',
'5.0.1-canary.11',
'5.0.1-canary.12',
'5.0.1-canary.13',
'5.0.1-canary.14',
'5.0.1-canary.15',
'5.0.1-canary.16',
'5.0.1-canary.17',
'5.1.0',
'6.0.0-canary.1',
'6.0.0-canary.2',
'6.0.0-canary.3',
'6.0.0-canary.4',
'6.0.0-canary.5',
'6.0.0-canary.6',
'6.0.0-canary.7',
'6.0.0',
'6.0.1-canary.0',
'6.0.1-canary.1',
'6.0.1-canary.2',
'6.0.1',
'6.0.2-canary.0',
'6.0.2',
'6.0.3-canary.0',
'6.0.3-canary.1',
'6.0.3',
'6.0.4-canary.0',
'6.0.4-canary.1',
'6.0.4-canary.2',
'6.0.4-canary.3',
'6.0.4-canary.4',
'6.0.4-canary.5',
'6.0.4-canary.6',
'6.0.4-canary.7',
'6.0.4-canary.8',
'6.0.4-canary.9',
'6.1.0-canary.0',
'6.1.0',
'6.1.1-canary.0',
'6.1.1-canary.1',
'6.1.1-canary.2',
'6.1.1-canary.3',
'6.1.1-canary.4',
'6.1.1-canary.5',
'6.1.1',
'6.1.2',
'7.0.0-canary.0',
'7.0.0-canary.1',
'7.0.0-canary.2',
'7.0.0-canary.3',
'7.0.0-canary.4',
'7.0.0-canary.5',
'7.0.0-canary.6',
'7.0.0-canary.7',
'7.0.0-canary.8',
'7.0.0-canary.9',
'7.0.0-canary.10',
'7.0.0-canary.11',
'7.0.0-canary.12',
'7.0.0-canary.13',
'7.0.0-canary.14',
'7.0.0-canary.15',
'7.0.0-canary.16',
'7.0.0-canary.18',
'7.0.0-canary.19',
'7.0.0-canary.20',
'7.0.0',
'7.0.1-canary.0',
'7.0.1-canary.1',
'7.0.1-canary.2',
'7.0.1-canary.3',
'7.0.1-canary.4',
'7.0.1-canary.5',
'7.0.1-canary.6',
'7.0.1',
'7.0.2-alpha.1',
'7.0.2-alpha.3',
'7.0.2-canary.5',
'7.0.2-canary.6',
'7.0.2-canary.7',
'7.0.2-canary.8',
'7.0.2-canary.9',
'7.0.2-canary.10',
'7.0.2-canary.11',
'7.0.2-canary.12',
'7.0.2-canary.13',
'7.0.2-canary.14',
'7.0.2-canary.15',
'7.0.2-canary.16',
'7.0.2-canary.17',
'7.0.2-canary.18',
'7.0.2-canary.19',
'7.0.2-canary.20',
'7.0.2-canary.21',
'7.0.2-canary.22',
'7.0.2-canary.23',
'7.0.2-canary.24',
'7.0.2-canary.25',
'7.0.2-canary.26',
'7.0.2-canary.27',
'7.0.2-canary.28',
'7.0.2-canary.29',
'7.0.2-canary.31',
'7.0.2-canary.33',
'7.0.2-canary.34',
'7.0.2-canary.35',
'7.0.2-canary.36',
'7.0.2-canary.37',
'7.0.2-canary.38',
'7.0.2-canary.39',
'7.0.2-canary.40',
'7.0.2-canary.41',
'7.0.2-canary.42',
'7.0.2-canary.43',
'7.0.2-canary.44',
'7.0.2-canary.45',
'7.0.2-canary.46',
'7.0.2-canary.47',
'7.0.2-canary.48',
'7.0.2-canary.49',
'7.0.2-canary.50',
'7.0.2',
];

View File

@@ -1,10 +1,12 @@
{
"name": "@now/next",
"version": "0.0.80",
"version": "0.0.84",
"license": "MIT",
"dependencies": {
"@now/node-bridge": "0.1.4",
"execa": "^1.0.0",
"fs.promised": "^3.0.0"
"fs.promised": "^3.0.0",
"semver": "^5.6.0"
},
"peerDependencies": {
"@now/build-utils": ">=0.0.1"

View File

@@ -111,6 +111,19 @@ function excludeStaticDirectory(files) {
return excludeFiles(files, matcher);
}
/**
* Exclude the static directory from files
* @param {Files} files
* @returns {Files}
*/
function onlyStaticDirectory(files) {
function matcher(filePath) {
return !filePath.startsWith('static');
}
return excludeFiles(files, matcher);
}
/**
* Enforce specific package.json configuration for smallest possible lambda
* @param {{dependencies?: any, devDependencies?: any, scripts?: any}} defaultPackageJson
@@ -140,18 +153,18 @@ function normalizePackageJson(defaultPackageJson = {}) {
'react-dom': 'latest',
...dependencies, // override react if user provided it
// next-server is forced to canary
'next-server': 'canary',
'next-server': 'v7.0.2-canary.49',
},
devDependencies: {
...devDependencies,
// next is forced to canary
next: 'canary',
next: 'v7.0.2-canary.49',
// next-server is a dependency here
'next-server': undefined,
},
scripts: {
...defaultPackageJson.scripts,
'now-build': 'next build --lambdas',
'now-build': 'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
},
};
}
@@ -164,4 +177,5 @@ module.exports = {
excludeLockFiles,
normalizePackageJson,
excludeStaticDirectory,
onlyStaticDirectory,
};

View File

@@ -1,7 +1,10 @@
const http = require('http');
function normalizeEvent(event) {
let isApiGateway = true;
if (event.Action === 'Invoke') {
isApiGateway = false;
const invokeEvent = JSON.parse(event.body);
const {
@@ -21,10 +24,7 @@ function normalizeEvent(event) {
}
return {
method,
path,
headers,
body,
isApiGateway, method, path, headers, body,
};
}
@@ -33,10 +33,7 @@ function normalizeEvent(event) {
} = event;
return {
method,
path,
headers,
body,
isApiGateway, method, path, headers, body,
};
}
@@ -58,7 +55,7 @@ class Bridge {
}
const {
method, path, headers, body,
isApiGateway, method, path, headers, body,
} = normalizeEvent(event);
const opts = {
@@ -73,20 +70,35 @@ class Bridge {
const response = res;
const respBodyChunks = [];
response.on('data', chunk => respBodyChunks.push(Buffer.from(chunk)));
response.on('error', error => reject(error));
response.on('error', reject);
response.on('end', () => {
const bodyBuffer = Buffer.concat(respBodyChunks);
delete response.headers.connection;
if (isApiGateway) {
delete response.headers['content-length'];
} else
if (response.headers['content-length']) {
response.headers['content-length'] = bodyBuffer.length;
}
resolve({
statusCode: response.statusCode,
headers: response.headers,
body: Buffer.concat(respBodyChunks).toString('base64'),
body: bodyBuffer.toString('base64'),
encoding: 'base64',
});
});
});
req.on('error', (error) => {
setTimeout(() => {
// this lets express print the true error of why the connection was closed.
// it is probably 'Cannot set headers after they are sent to the client'
reject(error);
}, 2);
});
if (body) req.write(body);
req.end();
});

View File

@@ -1,6 +1,7 @@
{
"name": "@now/node-bridge",
"version": "0.1.9",
"version": "0.1.10",
"license": "MIT",
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
}

View File

@@ -37,7 +37,7 @@ async function downloadInstallAndBundle(
console.log('downloading user files...');
const downloadedFiles = await download(files, userPath);
console.log('running npm install for user...');
console.log('installing dependencies for user\'s code...');
const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
await runNpmInstall(entrypointFsDirname, npmArguments);
@@ -47,7 +47,7 @@ async function downloadInstallAndBundle(
'package.json': new FileBlob({
data: JSON.stringify({
dependencies: {
'@zeit/ncc': '0.1.12',
'@zeit/ncc': '0.11.0',
},
}),
}),
@@ -55,7 +55,7 @@ async function downloadInstallAndBundle(
nccPath,
);
console.log('running npm install for ncc...');
console.log('installing dependencies for ncc...');
await runNpmInstall(nccPath, npmArguments);
return [downloadedFiles, userPath, nccPath, entrypointFsDirname];
}
@@ -71,7 +71,8 @@ async function compile(workNccPath, downloadedFiles, entrypoint) {
preparedFiles[path.join('user', entrypoint)] = blob;
// eslint-disable-next-line no-restricted-syntax
for (const assetName of Object.keys(assets)) {
const blob2 = new FileBlob({ data: assets[assetName] });
const { source: data, permissions: mode } = assets[assetName];
const blob2 = new FileBlob({ data, mode });
preparedFiles[
path.join('user', path.dirname(entrypoint), assetName)
] = blob2;

View File

@@ -12,7 +12,10 @@ Server.prototype.listen = function listen(...args) {
};
try {
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = 'production';
}
// PLACEHOLDER
} catch (error) {
console.error(error);

View File

@@ -1,8 +1,9 @@
{
"name": "@now/node-server",
"version": "0.4.24",
"version": "0.4.26",
"license": "MIT",
"dependencies": {
"@now/node-bridge": "^0.1.9",
"@now/node-bridge": "^0.1.10",
"fs-extra": "7.0.1"
},
"peerDependencies": {

View File

@@ -1,4 +1,4 @@
const cowsay = require('cowsay/build/cowsay.umd.js').say;
const cowsay = require('cowsay').say;
const http = require('http');
// test that process.env is not replaced by webpack

View File

@@ -6,6 +6,6 @@
],
"probes": [
{ "path": "/", "mustContain": "cow:RANDOMNESS_PLACEHOLDER" },
{ "path": "/subdirectory", "mustContain": "yoda:RANDOMNESS_PLACEHOLDER" }
{ "path": "/subdirectory/", "mustContain": "yoda:RANDOMNESS_PLACEHOLDER" }
]
}

View File

@@ -1,5 +1,5 @@
{
"dependencies": {
"cowsay": "^1.3.1"
"cowsay": "1.3.1"
}
}

View File

@@ -1,4 +1,4 @@
const yodasay = require('yodasay/build/yodasay.umd.js').say;
const yodasay = require('yodasay').say;
const http = require('http');
// test that process.env is not replaced by webpack

View File

@@ -1,5 +1,5 @@
{
"dependencies": {
"yodasay": "^1.1.6"
"yodasay": "1.1.9"
}
}

View File

@@ -0,0 +1,7 @@
const http = require('http');
const server = http.createServer((req, resp) => {
resp.end('RANDOMNESS_PLACEHOLDER');
});
server.listen();

View File

@@ -0,0 +1,6 @@
{
"version": 2,
"builds": [
{ "src": "index.js", "use": "@now/node-server" }
]
}

View File

@@ -0,0 +1,7 @@
const assert = require('assert');
module.exports = async ({ deploymentUrl, fetch, randomness }) => {
const resp = await fetch(`https://${deploymentUrl}/`);
assert.equal(resp.headers.get('content-type'), null);
assert.equal(await resp.text(), randomness);
};

View File

@@ -0,0 +1,15 @@
const fs = require('fs');
const http = require('http');
const path = require('path');
const server = http.createServer((req, resp) => {
const asset1 = fs.readFileSync(
path.join(__dirname, 'subdirectory1/asset.txt'),
);
const asset2 = fs.readFileSync(
path.join(__dirname, 'subdirectory2/asset.txt'),
);
resp.end(`${asset1},${asset2}`);
});
server.listen();

View File

@@ -0,0 +1,9 @@
{
"version": 2,
"builds": [
{ "src": "index.js", "use": "@now/node-server" }
],
"probes": [
{ "path": "/", "mustContain": "asset1:RANDOMNESS_PLACEHOLDER,asset2:RANDOMNESS_PLACEHOLDER" }
]
}

View File

@@ -0,0 +1 @@
asset1:RANDOMNESS_PLACEHOLDER

View File

@@ -0,0 +1 @@
asset2:RANDOMNESS_PLACEHOLDER

View File

@@ -5,7 +5,7 @@
{ "src": "without-bundle/index.js", "use": "@now/node-server", "config": { "bundle": false } }
],
"probes": [
{ "path": "/with-bundle", "mustContain": "RANDOMNESS_PLACEHOLDER" },
{ "path": "/without-bundle", "mustContain": "RANDOMNESS_PLACEHOLDER" }
{ "path": "/with-bundle", "mustContain": "RANDOMNESS_PLACEHOLDER:with-bundle" },
{ "path": "/without-bundle", "mustContain": "RANDOMNESS_PLACEHOLDER:without-bundle" }
]
}

View File

@@ -2,7 +2,7 @@ const http = require('http');
const isBundled = require('./is-bundled.js');
const server = http.createServer((req, resp) => {
resp.end(isBundled() ? 'RANDOMNESS_PLACEHOLDER' : '');
resp.end(isBundled() ? 'RANDOMNESS_PLACEHOLDER:with-bundle' : 'WITHOUT-BUNDLE-THAT-IS-WRONG');
});
server.listen();

View File

@@ -1,3 +1,4 @@
const path = require('path');
module.exports = () => path.basename(__filename) === 'index.js';
// eslint-disable-next-line no-eval
module.exports = () => path.basename(eval('__filename')) === 'index.js';

View File

@@ -2,7 +2,7 @@ const http = require('http');
const isBundled = require('./is-bundled.js');
const server = http.createServer((req, resp) => {
resp.end(isBundled() ? '' : 'RANDOMNESS_PLACEHOLDER');
resp.end(isBundled() ? 'WITH-BUNDLE-THAT-IS-WRONG' : 'RANDOMNESS_PLACEHOLDER:without-bundle');
});
server.listen();

View File

@@ -1,3 +1,4 @@
const path = require('path');
module.exports = () => path.basename(__filename) === 'index.js';
// eslint-disable-next-line no-eval
module.exports = () => path.basename(eval('__filename')) === 'index.js';

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@ const {
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(2 * 60 * 1000);
const buildUtilsUrl = '@canary';
let builderUrl;
beforeAll(async () => {
@@ -23,7 +24,10 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
// eslint-disable-next-line no-loop-func
it(`should build ${fixture}`, async () => {
await expect(
testDeployment({ builderUrl }, path.join(fixturesPath, fixture)),
).resolves.toBe(undefined);
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
).resolves.toBeDefined();
});
}

View File

@@ -35,7 +35,7 @@ async function downloadInstallAndBundle(
console.log('downloading user files...');
const downloadedFiles = await download(files, userPath);
console.log('running npm install for user...');
console.log('installing dependencies for user\'s code...');
const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
await runNpmInstall(entrypointFsDirname, npmArguments);
@@ -45,7 +45,7 @@ async function downloadInstallAndBundle(
'package.json': new FileBlob({
data: JSON.stringify({
dependencies: {
'@zeit/ncc': '0.1.12',
'@zeit/ncc': '0.11.0',
},
}),
}),
@@ -53,7 +53,7 @@ async function downloadInstallAndBundle(
nccPath,
);
console.log('running npm install for ncc...');
console.log('installing dependencies for ncc...');
await runNpmInstall(nccPath, npmArguments);
return [downloadedFiles, nccPath, entrypointFsDirname];
}
@@ -69,7 +69,8 @@ async function compile(workNccPath, downloadedFiles, entrypoint) {
preparedFiles[path.join('user', entrypoint)] = blob;
// eslint-disable-next-line no-restricted-syntax
for (const assetName of Object.keys(assets)) {
const blob2 = new FileBlob({ data: assets[assetName] });
const { source: data, permissions: mode } = assets[assetName];
const blob2 = new FileBlob({ data, mode });
preparedFiles[
path.join('user', path.dirname(entrypoint), assetName)
] = blob2;
@@ -109,6 +110,7 @@ exports.build = async ({ files, entrypoint, workPath }) => {
[
'process.chdir("./user");',
`listener = require("./${path.join('user', entrypoint)}");`,
'if (listener.default) listener = listener.default;',
].join(' '),
);

View File

@@ -6,7 +6,10 @@ bridge.port = 3000;
let listener;
try {
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = 'production';
}
// PLACEHOLDER
} catch (error) {
console.error(error);

View File

@@ -1,8 +1,9 @@
{
"name": "@now/node",
"version": "0.4.26",
"version": "0.4.28",
"license": "MIT",
"dependencies": {
"@now/node-bridge": "^0.1.9",
"@now/node-bridge": "^0.1.10",
"fs-extra": "7.0.1"
},
"peerDependencies": {

View File

@@ -1,4 +1,4 @@
const cowsay = require('cowsay/build/cowsay.umd.js').say;
const cowsay = require('cowsay').say;
// test that process.env is not replaced by webpack
process.env.NODE_ENV = 'development';

View File

@@ -6,6 +6,6 @@
],
"probes": [
{ "path": "/", "mustContain": "cow:RANDOMNESS_PLACEHOLDER" },
{ "path": "/subdirectory", "mustContain": "yoda:RANDOMNESS_PLACEHOLDER" }
{ "path": "/subdirectory/", "mustContain": "yoda:RANDOMNESS_PLACEHOLDER" }
]
}

View File

@@ -1,5 +1,5 @@
{
"dependencies": {
"cowsay": "^1.3.1"
"cowsay": "1.3.1"
}
}

View File

@@ -1,4 +1,4 @@
const yodasay = require('yodasay/build/yodasay.umd.js').say;
const yodasay = require('yodasay').say;
// test that process.env is not replaced by webpack
process.env.NODE_ENV = 'development';

View File

@@ -1,5 +1,5 @@
{
"dependencies": {
"yodasay": "^1.1.6"
"yodasay": "1.1.9"
}
}

View File

@@ -0,0 +1,8 @@
{
"version": 2,
"builds": [
{ "src": "test1.js", "use": "@now/node" },
{ "src": "test2.js", "use": "@now/node" },
{ "src": "test3.js", "use": "@now/node" }
]
}

View File

@@ -0,0 +1,31 @@
const assert = require('assert');
async function test1({ deploymentUrl, fetch, randomness }) {
const bodyMustBe = `${randomness}:content-length`;
const resp = await fetch(`https://${deploymentUrl}/test1.js`);
assert.equal(resp.status, 401);
assert.equal(await resp.text(), bodyMustBe);
assert.equal(resp.headers.get('content-length'), bodyMustBe.length);
}
async function test2({ deploymentUrl, fetch }) {
const bodyMustBe = '';
const resp = await fetch(`https://${deploymentUrl}/test2.js`);
assert.equal(resp.status, 401);
assert.equal(await resp.text(), bodyMustBe);
assert.equal(resp.headers.get('content-length'), bodyMustBe.length);
}
async function test3({ deploymentUrl, fetch, randomness }) {
const bodyMustBe = `${randomness}:content-length`;
const resp = await fetch(`https://${deploymentUrl}/test3.js`);
assert.equal(resp.status, 401);
assert.equal(await resp.text(), bodyMustBe);
assert.equal(resp.headers.get('content-length'), null);
}
module.exports = async ({ deploymentUrl, fetch, randomness }) => {
await test1({ deploymentUrl, fetch, randomness });
await test2({ deploymentUrl, fetch, randomness });
await test3({ deploymentUrl, fetch, randomness });
};

View File

@@ -0,0 +1,4 @@
module.exports = (_, resp) => {
resp.writeHead(401, { 'content-length': 4242 });
resp.end(`${process.env.RANDOMNESS_ENV_VAR}:content-length`);
};

View File

@@ -0,0 +1,4 @@
module.exports = (_, resp) => {
resp.writeHead(401, { 'content-length': 2 });
resp.end();
};

View File

@@ -0,0 +1,4 @@
module.exports = (_, resp) => {
resp.writeHead(401);
resp.end(`${process.env.RANDOMNESS_ENV_VAR}:content-length`);
};

View File

@@ -0,0 +1,12 @@
const fs = require('fs');
const path = require('path');
module.exports = (req, resp) => {
const asset1 = fs.readFileSync(
path.join(__dirname, 'subdirectory1/asset.txt'),
);
const asset2 = fs.readFileSync(
path.join(__dirname, 'subdirectory2/asset.txt'),
);
resp.end(`${asset1},${asset2}`);
};

View File

@@ -0,0 +1,9 @@
{
"version": 2,
"builds": [
{ "src": "index.js", "use": "@now/node" }
],
"probes": [
{ "path": "/", "mustContain": "asset1:RANDOMNESS_PLACEHOLDER,asset2:RANDOMNESS_PLACEHOLDER" }
]
}

View File

@@ -0,0 +1 @@
asset1:RANDOMNESS_PLACEHOLDER

View File

@@ -0,0 +1 @@
asset2:RANDOMNESS_PLACEHOLDER

View File

@@ -8,6 +8,7 @@ const {
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(2 * 60 * 1000);
const buildUtilsUrl = '@canary';
let builderUrl;
beforeAll(async () => {
@@ -23,7 +24,10 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
// eslint-disable-next-line no-loop-func
it(`should build ${fixture}`, async () => {
await expect(
testDeployment({ builderUrl }, path.join(fixturesPath, fixture)),
).resolves.toBe(undefined);
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
).resolves.toBeDefined();
});
}

View File

@@ -1,6 +1,7 @@
{
"name": "@now/optipng",
"version": "0.4.7",
"version": "0.4.8",
"license": "MIT",
"dependencies": {
"multipipe": "2.0.3",
"optipng": "1.1.0"

View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,20 @@
FROM library/centos:6.8
RUN yum -y install wget git
RUN rpm -Uvh https://mirror.webtatic.com/yum/el6/latest.rpm
RUN yum -y install php71w-cli php71w-fpm php71w-mbstring php71w-mysql php71w-opcache
RUN yum -y install epel-release
RUN yum -y install patchelf
RUN mkdir -p /root/app/public
WORKDIR /root/app
COPY ./php.ini /root/app/php.ini
COPY ./php-fpm.ini /root/app/php-fpm.ini
COPY ./test.php /root/app/test.php
COPY ./test.sh /root/app/test.sh
RUN patchelf --set-rpath '$ORIGIN' /usr/bin/php
RUN patchelf --set-rpath '$ORIGIN' /usr/sbin/php-fpm
RUN patchelf --set-rpath '$ORIGIN' /usr/lib64/php/modules/mysqli.so
CMD ["/bin/bash", "test.sh"]

View File

@@ -0,0 +1,15 @@
rm -rf ../native
mkdir -p ../native/modules
docker rmi now-php-docker-image --force
docker build . -t now-php-docker-image
docker run now-php-docker-image
docker run now-php-docker-image /bin/cat /usr/sbin/php-fpm > ../native/php-fpm
docker run now-php-docker-image /bin/cat /root/app/php.ini > ../native/php.ini
docker run now-php-docker-image /bin/cat /root/app/php-fpm.ini > ../native/php-fpm.ini
docker run now-php-docker-image /bin/cat /usr/lib64/php/modules/curl.so > ../native/modules/curl.so
docker run now-php-docker-image /bin/cat /usr/lib64/php/modules/json.so > ../native/modules/json.so
docker run now-php-docker-image /bin/cat /usr/lib64/php/modules/mbstring.so > ../native/modules/mbstring.so
docker run now-php-docker-image /bin/cat /usr/lib64/php/modules/mysqli.so > ../native/modules/mysqli.so
docker run now-php-docker-image /bin/cat /usr/lib64/mysql/libmysqlclient.so.16 > ../native/modules/libmysqlclient.so.16
docker run now-php-docker-image /bin/cat /usr/lib64/php/modules/opcache.so > ../native/modules/opcache.so
chmod +x ../native/php-fpm

Some files were not shown because too many files have changed in this diff Show More