Compare commits

...

144 Commits

Author SHA1 Message Date
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
Igor Klopov
9a93713158 Publish
- @now/build-utils@0.4.30
 - @now/cgi@0.0.13
 - @now/go@0.2.10
 - @now/html-minifier@1.0.6
 - @now/lambda@0.4.7
 - @now/md@0.4.7
 - @now/mdx-deck@0.4.16
 - @now/next@0.0.80
 - @now/node-bridge@0.1.9
 - @now/node-server@0.4.24
 - @now/node@0.4.26
 - @now/optipng@0.4.7
 - @now/php@0.4.11
 - @now/python@0.0.40
 - @now/static-build@0.4.15
2018-11-26 04:16:16 +03:00
Igor Klopov
3392ef5636 [now-php] compile launcher binary 2018-11-26 03:48:52 +03:00
Igor Klopov
9236e2b584 Publish
- @now/build-utils@0.4.30-canary.6
 - @now/node-server@0.4.24-canary.8
 - @now/node@0.4.26-canary.8
 - @now/php@0.4.11-canary.7
 - @now/static-build@0.4.15-canary.7
2018-11-26 02:44:14 +03:00
Igor Klopov
ffc4686ab9 now/node-server: take assets from ncc into zip 2018-11-25 22:28:58 +03:00
Igor Klopov
1ff4b6bb4b now/node: take assets from ncc into zip 2018-11-25 22:15:07 +03:00
Igor Klopov
0e7d8c3ff1 node-server and node: bump ncc, yet without assets 2018-11-25 21:18:08 +03:00
Igor Klopov
86885b8c38 yarn/npm test for build-utils 2018-11-25 20:48:29 +03:00
Igor Klopov
8563f2b8b5 remove confusing now-build script not found from logs 2018-11-25 17:58:31 +03:00
Igor Klopov
c36938bd95 Tests for now/build-utils (#74)
* rearrange testDeployment arguments

* added tests for build-utils

* print what page failed probe check

* make opposing package be always at least canary
2018-11-25 05:16:17 +03:00
Igor Klopov
957ab6c4e3 Publish
- @now/cgi@0.0.13-canary.6
 - @now/go@0.2.10-canary.6
 - @now/node-server@0.4.24-canary.7
 - @now/node@0.4.26-canary.7
 - @now/php@0.4.11-canary.6
 - @now/static-build@0.4.15-canary.6
2018-11-24 02:35:01 +03:00
Nathan Rajlich
069e9b4052 [circle-ci] set GOPATH to ~/go (#72)
Attempting to fix this error:

```
> @now/cgi@0.0.13-canary.3 prepublish /home/circleci/repo/packages/now-cgi
> ./build.sh

main.go:14:2: cannot find package "github.com/aws/aws-lambda-go/events" in any of:
	/usr/lib/go/src/pkg/github.com/aws/aws-lambda-go/events (from $GOROOT)
	($GOPATH not set)
main.go:15:2: cannot find package "github.com/aws/aws-lambda-go/lambda" in any of:
	/usr/lib/go/src/pkg/github.com/aws/aws-lambda-go/lambda (from $GOROOT)
	($GOPATH not set)
```
2018-11-23 22:13:13 +01:00
Igor Klopov
0b06704be6 More tests 2 (#71)
* rename to let cowsays be together

* test for script.sh for static-build

* make env-vars 03 across builders

* 03-env-vars test for static-build
2018-11-23 17:44:07 +03:00
Igor Klopov
cf5a49e699 Node-server bundle=false (#70)
* copy node-server/index.js from node/index.js

* no need to promisify fs if we have fs-extra

* few renames to clarify what for they are

* node-server: config.bundle = false

* builder code fixes and tests

* fix maxLambdaSize back
2018-11-23 04:51:09 +03:00
Matheus Fernandes
b671b23d8d [now-go] Fix typo when setting the Host value (#66)
* `req.Host` -> `internalReq.Host`

* Add comments
2018-11-22 14:50:31 -08:00
Igor Klopov
fa44c23225 env vars test for now/php (#68) 2018-11-22 21:40:13 +03:00
Igor Klopov
ba9da3cec5 collect test fixtures via readdir 2018-11-22 17:27:17 +03:00
Igor Klopov
0909aaf2b3 Test env vars (#65)
* move 02-others to 10-others

* add 02-env-vars for node-server

* added 02-env-vars for now/node
2018-11-22 15:14:35 +03:00
Nathan Rajlich
e276342a6f [now-cgi] add HTTPS and SERVER_SOFTWARE env vars 2018-11-21 15:51:44 -08:00
Igor Klopov
f6e1bdf0a1 simple test for now/php 2018-11-22 02:29:50 +03:00
Igor Klopov
2c2189b661 add npmignore to prevent publishing 'test' directory 2018-11-22 01:43:29 +03:00
Igor Klopov
61522e2bc7 show deploymentUrl if state is ERROR. othw not clear from ci logs 2018-11-21 23:01:51 +03:00
Igor Klopov
a20f3a5920 test for static-build with 300 generated files 2018-11-21 22:40:23 +03:00
Igor Klopov
a5e58c2a8d bump to ncc 0.1.6 and enable apollo test 2018-11-21 22:26:41 +03:00
Igor Klopov
a58451548f simple tests for now/static-build 2018-11-21 19:11:52 +03:00
Igor Klopov
8e846c50b5 Pack testing 3 (#58)
* produce builder targz in jest.beforeAll

* improve fetchDeploymentUrl

* wait for deployment to become READY
2018-11-21 05:30:22 +03:00
Igor Klopov
7613dcf68b Pack testing 2 (#57)
* include new pack testing into 'yarn test'

* take now auth token from env var

* mkdirp(authJsonPath)
2018-11-21 00:21:03 +03:00
Nathan Rajlich
bea499cad3 [@now/php] remove unnecessary log line upon cold start (#44) 2018-11-20 11:46:28 -08:00
Igor Klopov
0f20a0dbbf [wip] Pack testing (#51)
* test.js packs and deploys static targz

* test.js deploys a fixture using the targz

* randomness, RANDOMNESS_PLACEHOLDER to prevent stale data

* test.js tests if randomness is present

* make test-deployment.js shared

* remove package.json.name

* nowDeploy: pass routes from now.json

* make apollo test work

* simplify test logs

* same page content that does not match a test. for inspection

* added cowsay to node-server

* distinguish mustContain values to prevent them intersect

* separate step packAndDeploy

* test for process.env.NODE_ENV replacement

* fetchBuilderUrl to wait for targz is deployed
2018-11-20 21:13:38 +03:00
Igor Klopov
1ea30588a3 Publish
- @now/node-server@0.4.24-canary.6
 - @now/node@0.4.26-canary.6
2018-11-20 19:20:22 +03:00
Igor Klopov
a3b670675a [node] bump zeit/ncc 2018-11-20 19:16:57 +03:00
Tim Neutkens
c4374fe5a8 Publish
- @now/next@0.0.80-canary.0
2018-11-20 00:05:45 +01:00
Tim Neutkens
c3983ba1c2 @now/next Use next build --lambdas to bundle node_modules (#54) 2018-11-19 17:00:47 -06:00
Tim Neutkens
ae1be4b243 @now/next Add maxLambdaSize 2018-11-19 12:15:31 +01:00
Tim Neutkens
b4b1131619 Publish
- @now/next@0.0.79-canary.7
2018-11-19 02:06:09 +01:00
Tim Neutkens
5fd923a7e7 Add stable publish script 2018-11-19 01:57:54 +01:00
Tim Neutkens
f4e95eb59c Publish
- @now/next@0.0.79-canary.7
2018-11-19 01:36:53 +01:00
Tim Neutkens
a6cdaccd34 @now/next add integration test for custom dependencies 2018-11-19 01:35:22 +01:00
Tim Neutkens
4f5fe8eba8 @now/next Fix normalizePackageJson types 2018-11-19 01:06:14 +01:00
Tim Neutkens
7239013989 Don’t run build on tags, only branches 2018-11-19 00:44:15 +01:00
Tim Neutkens
75000ee334 Publish
- @now/next@0.0.79-canary.6
2018-11-19 00:40:04 +01:00
Tim Neutkens
5319610d59 @now/next add normalized package.json logging 2018-11-19 00:39:37 +01:00
Tim Neutkens
6df0d69afa Add passing test for real world package.json 2018-11-19 00:28:48 +01:00
Tim Neutkens
65b191f6b9 Publish
- @now/build-utils@0.4.30-canary.5
 - @now/cgi@0.0.13-canary.5
 - @now/go@0.2.10-canary.5
 - @now/html-minifier@1.0.6-canary.5
 - @now/lambda@0.4.7-canary.5
 - @now/md@0.4.7-canary.5
 - @now/mdx-deck@0.4.16-canary.5
 - @now/next@0.0.79-canary.5
 - @now/node-bridge@0.1.9-canary.5
 - @now/node-server@0.4.24-canary.5
 - @now/node@0.4.26-canary.5
 - @now/optipng@0.4.7-canary.5
 - @now/php@0.4.11-canary.5
 - @now/python@0.0.40-canary.5
 - @now/static-build@0.4.15-canary.5
2018-11-18 17:04:46 +01:00
Tim Neutkens
115f62bbba Set gopath temporarily 2018-11-18 17:02:23 +01:00
Tim Neutkens
cdf6a98a18 Publish
- @now/build-utils@0.4.30-canary.4
 - @now/cgi@0.0.13-canary.4
 - @now/go@0.2.10-canary.4
 - @now/html-minifier@1.0.6-canary.4
 - @now/lambda@0.4.7-canary.4
 - @now/md@0.4.7-canary.4
 - @now/mdx-deck@0.4.16-canary.4
 - @now/next@0.0.79-canary.4
 - @now/node-bridge@0.1.9-canary.4
 - @now/node-server@0.4.24-canary.4
 - @now/node@0.4.26-canary.4
 - @now/optipng@0.4.7-canary.4
 - @now/php@0.4.11-canary.4
 - @now/python@0.0.40-canary.4
 - @now/static-build@0.4.15-canary.4
2018-11-18 16:50:10 +01:00
Tim Neutkens
bb75dfd993 Manually get dependencies 2018-11-18 16:48:57 +01:00
Tim Neutkens
b63062cfc5 Publish
- @now/build-utils@0.4.30-canary.3
 - @now/cgi@0.0.13-canary.3
 - @now/go@0.2.10-canary.3
 - @now/html-minifier@1.0.6-canary.3
 - @now/lambda@0.4.7-canary.3
 - @now/md@0.4.7-canary.3
 - @now/mdx-deck@0.4.16-canary.3
 - @now/next@0.0.79-canary.3
 - @now/node-bridge@0.1.9-canary.3
 - @now/node-server@0.4.24-canary.3
 - @now/node@0.4.26-canary.3
 - @now/optipng@0.4.7-canary.3
 - @now/php@0.4.11-canary.3
 - @now/python@0.0.40-canary.3
 - @now/static-build@0.4.15-canary.3
2018-11-18 16:23:55 +01:00
Tim Neutkens
5ad6dabd96 Use if/else so that build will fail when lerna fails 2018-11-18 16:23:10 +01:00
Tim Neutkens
30060bee07 Publish
- @now/build-utils@0.4.30-canary.2
 - @now/cgi@0.0.13-canary.2
 - @now/go@0.2.10-canary.2
 - @now/html-minifier@1.0.6-canary.2
 - @now/lambda@0.4.7-canary.2
 - @now/md@0.4.7-canary.2
 - @now/mdx-deck@0.4.16-canary.2
 - @now/next@0.0.79-canary.2
 - @now/node-bridge@0.1.9-canary.2
 - @now/node-server@0.4.24-canary.2
 - @now/node@0.4.26-canary.2
 - @now/optipng@0.4.7-canary.2
 - @now/php@0.4.11-canary.2
 - @now/python@0.0.40-canary.2
 - @now/static-build@0.4.15-canary.2
2018-11-18 16:14:10 +01:00
Tim Neutkens
dd48a1c6d3 Fall back to showing did not publish 2018-11-18 16:11:46 +01:00
Tim Neutkens
24d45736f1 If describe fails force null 2018-11-18 16:06:36 +01:00
Tim Neutkens
d839fdbe81 Only run on exact tag matches 2018-11-18 15:59:03 +01:00
Tim Neutkens
cfdcd2f8d0 Make git describe not fail on no tag 2018-11-18 15:53:20 +01:00
Tim Neutkens
b3cac2b372 Manually match tags and publish 2018-11-18 15:46:22 +01:00
Tim Neutkens
9d27d69656 Publish
- @now/build-utils@0.4.30-canary.1
 - @now/cgi@0.0.13-canary.1
 - @now/go@0.2.10-canary.1
 - @now/html-minifier@1.0.6-canary.1
 - @now/lambda@0.4.7-canary.1
 - @now/md@0.4.7-canary.1
 - @now/mdx-deck@0.4.16-canary.1
 - @now/next@0.0.79-canary.1
 - @now/node-bridge@0.1.9-canary.1
 - @now/node-server@0.4.24-canary.1
 - @now/node@0.4.26-canary.1
 - @now/optipng@0.4.7-canary.1
 - @now/php@0.4.11-canary.1
 - @now/python@0.0.40-canary.1
 - @now/static-build@0.4.15-canary.1
2018-11-18 14:55:52 +01:00
Tim Neutkens
04197b250c Run build for tags 2018-11-18 14:52:57 +01:00
Tim Neutkens
ce6f43eae7 Publish
- @now/build-utils@0.4.30-canary.0
 - @now/cgi@0.0.13-canary.0
 - @now/go@0.2.10-canary.0
 - @now/html-minifier@1.0.6-canary.0
 - @now/lambda@0.4.7-canary.0
 - @now/md@0.4.7-canary.0
 - @now/mdx-deck@0.4.16-canary.0
 - @now/next@0.0.79-canary.0
 - @now/node-bridge@0.1.9-canary.0
 - @now/node-server@0.4.24-canary.0
 - @now/node@0.4.26-canary.0
 - @now/optipng@0.4.7-canary.0
 - @now/php@0.4.11-canary.0
 - @now/python@0.0.40-canary.0
 - @now/static-build@0.4.15-canary.0
2018-11-18 14:49:58 +01:00
Tim Neutkens
2cfafe4054 Remove unused comment 2018-11-18 14:49:15 +01:00
Tim Neutkens
b195949881 Bring back canary publish job 2018-11-18 14:47:51 +01:00
Igor Klopov
b7c47fa587 Publish
- @now/build-utils@0.4.29
 - @now/cgi@0.0.12
 - @now/go@0.2.9
 - @now/html-minifier@1.0.5
 - @now/lambda@0.4.6
 - @now/md@0.4.6
 - @now/mdx-deck@0.4.15
 - @now/next@0.0.78
 - @now/node-bridge@0.1.8
 - @now/node-server@0.4.23
 - @now/node@0.4.25
 - @now/optipng@0.4.6
 - @now/php@0.4.10
 - @now/python@0.0.39
 - @now/static-build@0.4.14
2018-11-18 04:44:36 +03:00
Tim Neutkens
f3bcefe822 @now/next exclude package-lock.json / yarn.lock from entry directory (#39)
* @now/next exclude package-lock.json / yarn.lock

* Add typescript to now-next

* Add download and file-fs-ref types

* Add types for now-next

* Remove yarn.lock
2018-11-17 23:10:14 +01:00
Tim Neutkens
7a481c9515 Make PR builds reliable again (#45)
* Run yarn prettier --write --single-quote packages/**/*.js and yarn lint --fix

* Fix tsc error

* Try and make publish-stable only trigger on tag
2018-11-17 22:53:59 +01:00
Igor Klopov
af275c60bf Publish
- @now/node-server@0.4.23-canary.4
 - @now/node@0.4.25-canary.4
2018-11-17 02:37:03 +03:00
Igor Klopov
ded377dfc2 [node] bump ncc 2018-11-17 02:34:51 +03:00
Igor Klopov
0daaa1cf6a Publish
- @now/build-utils@0.4.29-canary.2
 - @now/cgi@0.0.12-canary.1
 - @now/go@0.2.9-canary.1
 - @now/html-minifier@1.0.5-canary.0
 - @now/lambda@0.4.6-canary.0
 - @now/md@0.4.6-canary.0
 - @now/mdx-deck@0.4.15-canary.0
 - @now/next@0.0.78-canary.1
 - @now/node-bridge@0.1.8-canary.1
 - @now/node-server@0.4.23-canary.3
 - @now/node@0.4.25-canary.3
 - @now/optipng@0.4.6-canary.0
 - @now/php@0.4.10-canary.1
 - @now/python@0.0.39-canary.1
 - @now/static-build@0.4.14-canary.0
2018-11-16 22:25:25 +03:00
Igor Klopov
6e928d1a68 run jest tests in parallel 2018-11-16 21:35:54 +03:00
Igor Klopov
791c26fdfe lint fixes to satisfy ci 2018-11-16 21:13:50 +03:00
Igor Klopov
c14451c2c5 Publish
- @now/build-utils@0.4.29-canary.1
 - @now/node-server@0.4.23-canary.2
 - @now/node@0.4.25-canary.2
2018-11-16 20:01:51 +03:00
Igor Klopov
846b229511 [build-utils] apply #38 manually 2018-11-16 19:50:04 +03:00
Igor Klopov
d832658226 [node] erase workPath in prepareCache + bugfix 2018-11-16 18:42:33 +03:00
Igor Klopov
2df09c7742 [node-server] erase workPath in prepareCache 2018-11-16 18:12:56 +03:00
Igor Klopov
e55b84b646 [build-utils] clear cache right away after npmInstall 2018-11-16 17:45:21 +03:00
Igor Klopov
265df1491e Publish
- @now/go@0.2.9-canary.0
 - @now/node-server@0.4.23-canary.1
 - @now/node@0.4.25-canary.1
 - @now/php@0.4.10-canary.0
 - @now/python@0.0.39-canary.0
2018-11-16 05:54:30 +03:00
Igor Klopov
f46c0dc747 [node-server] switch from rollup to ncc 2018-11-16 05:53:00 +03:00
Igor Klopov
1443e5435b [node] switch from rollup to ncc 2018-11-16 05:47:27 +03:00
Nathan Rajlich
b4fa4d35db Add builder config and default maxLambdaSize values (#36)
* Add builder `config` and default `maxLambdaSize` values

* 15mb max lambda zip for `@now/node-server`

* Fix merge weirdness
2018-11-15 17:56:28 -08:00
Igor Klopov
1f565c2570 Publish
- @now/build-utils@0.4.29-canary.0
 - @now/cgi@0.0.12-canary.0
 - @now/next@0.0.78-canary.0
 - @now/node-bridge@0.1.8-canary.0
 - @now/node-server@0.4.23-canary.0
 - @now/node@0.4.25-canary.0
2018-11-16 04:50:58 +03:00
Tim Neutkens
a2d95ae8ee Initial Typescript JSDoc integration (#33)
* Initial typescript jsdoc integration

* Fix trailing comma issue reported by @matheuss

* Add file-ref.js types

* Add BailableError

* Add typescript to lint command
2018-11-16 04:42:55 +03:00
Nathan Rajlich
fe15cc1b2c Add @now/cgi builder 2018-11-15 12:48:59 -08:00
Maarten Van Hoof
e8a9c49949 fix(Next): Fixed typo in environment (#34) 2018-11-15 17:59:42 +01:00
Tim Neutkens
f9233b2e24 Publish
- @now/build-utils@0.4.28
 - @now/go@0.2.8
 - @now/html-minifier@1.0.4
 - @now/lambda@0.4.5
 - @now/md@0.4.5
 - @now/mdx-deck@0.4.14
 - @now/next@0.0.77
 - @now/node-bridge@0.1.7
 - @now/node-server@0.4.22
 - @now/node@0.4.24
 - @now/optipng@0.4.5
 - @now/php@0.4.9
 - @now/python@0.0.38
 - @now/static-build@0.4.13
2018-11-14 16:16:43 +01:00
Tim Neutkens
bfa0c05e5d Install go before publishing 2018-11-14 16:16:06 +01:00
Tim Neutkens
6caba97183 Publish
- @now/build-utils@0.4.27
 - @now/go@0.2.7
 - @now/html-minifier@1.0.3
 - @now/lambda@0.4.4
 - @now/md@0.4.4
 - @now/mdx-deck@0.4.13
 - @now/next@0.0.76
 - @now/node-bridge@0.1.6
 - @now/node-server@0.4.21
 - @now/node@0.4.23
 - @now/optipng@0.4.4
 - @now/php@0.4.8
 - @now/python@0.0.37
 - @now/static-build@0.4.12
2018-11-14 16:09:42 +01:00
Tim Neutkens
5d35de8908 Temporarily disable publish-canary 2018-11-14 16:06:34 +01:00
Tim Neutkens
551a29dd13 Use build instead of upload 2018-11-14 15:54:19 +01:00
Tim Neutkens
f63f48e1e9 Revert "Publish"
This reverts commit 7d7f0adfb3.
2018-11-14 15:53:18 +01:00
Tim Neutkens
7d7f0adfb3 Publish
- @now/build-utils@0.4.27
 - @now/go@0.2.7
 - @now/html-minifier@1.0.3
 - @now/lambda@0.4.4
 - @now/md@0.4.4
 - @now/mdx-deck@0.4.13
 - @now/next@0.0.76
 - @now/node-bridge@0.1.6
 - @now/node-server@0.4.21
 - @now/node@0.4.23
 - @now/optipng@0.4.4
 - @now/php@0.4.8
 - @now/python@0.0.37
 - @now/static-build@0.4.12
2018-11-14 15:30:51 +01:00
Tim Neutkens
5538e97bb8 Add publish-stable script 2018-11-14 15:20:25 +01:00
Tim Neutkens
f8c260353c Add stable publish 2018-11-14 15:14:02 +01:00
Tim Neutkens
9123356d23 Publish
- @now/node-bridge@0.1.6-canary.6
 - @now/node-server@0.4.21-canary.6
 - @now/node@0.4.23-canary.6
2018-11-14 13:59:58 +01:00
Tim Neutkens
d85eee5571 Add publish-canary for tag releases 2018-11-14 13:58:32 +01:00
Tim Neutkens
0f59d568e5 Fix linting 2018-11-14 13:45:48 +01:00
Tim Neutkens
2d69514a37 Publish
- @now/lambda@0.4.4-canary.5
 - @now/next@0.0.76-canary.0
 - @now/node-bridge@0.1.6-canary.5
 - @now/node-server@0.4.21-canary.5
 - @now/node@0.4.23-canary.5
2018-11-14 13:40:41 +01:00
Tim Neutkens
7b690c742b Remove publishing from build step 2018-11-14 13:39:15 +01:00
Igor Klopov
fecbad7016 account a case with no encoding. fixes #5 (#32)
* account a case with no encoding. fixes #5

* replaced assert with throw
2018-11-14 02:32:39 +03:00
Igor Klopov
c8fce90612 [now/lambda] take handler and runtime from now.json's config 2018-11-13 23:42:59 +03:00
Igor Klopov
04803712af fix @now/lambda 2018-11-13 23:13:08 +03:00
Tim Neutkens
8a3913c5b5 Add tests for libraries breaking on now/node (#23)
* Add tests for libraries breaking on now/node

* Fix eslint errors

* Change order of extends
2018-11-12 19:07:41 +03:00
Tim Neutkens
8eb66c8c23 Publish
- @now/next@0.0.75
2018-11-11 22:55:43 +01:00
Tim Neutkens
24e10396c8 Publish
- @now/next@0.0.74-canary.6
2018-11-11 20:46:15 +01:00
Tim Neutkens
740118488c @now/next parse querystring 2018-11-11 20:43:56 +01:00
Tim Neutkens
2cf6769b93 Publish
- @now/next@0.0.74-canary.5
 - @now/static-build@0.4.12-canary.5
2018-11-11 18:22:35 +01:00
Tim Neutkens
4353614ae3 Fix linting for @now/next 2018-11-11 18:21:56 +01:00
Tim Neutkens
92f1515271 @now/next - don’t run path matching for lambdas (#13)
Fixes https://spectrum.chat/thread/5e7c14aa-752a-45c3-a744-89721ecf7ceb
2018-11-11 18:13:30 +01:00
Simon Hänisch
3c24ce4116 feat(now-static-build): add a distDir option (#20)
Adds an optional `distDir` config option to now-static-build.

To be used in `now.json` like

```json
{
  "builds": [
    {
      "src": "package.json",
      "use": "@now/static-build",
      "config": { "distDir": "www" }
    }
  ]
}
```

Closes #19
2018-11-11 18:12:46 +01:00
Tim Neutkens
863b8c8fe5 Add lint-staged precommit hooks + prettier (#18)
Runs both on pre-commit
2018-11-11 16:05:59 +01:00
Tim Neutkens
3e52eda3af Add tests (#17)
Add testing setup
2018-11-10 23:55:51 +01:00
194 changed files with 13946 additions and 698 deletions

View File

@@ -4,6 +4,8 @@ jobs:
docker: docker:
- image: circleci/node:10 - image: circleci/node:10
working_directory: ~/repo working_directory: ~/repo
environment:
GOPATH: $HOME/go
steps: steps:
- checkout - checkout
- run: - run:
@@ -19,44 +21,22 @@ jobs:
name: Bootstrapping name: Bootstrapping
command: yarn bootstrap command: yarn bootstrap
- run: - run:
name: Saving Authentication Information name: Linting
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc command: yarn lint
- run: - run:
name: Publishing to Canary Channel name: Tests
command: yarn run lerna publish from-git --npm-tag canary --yes command: yarn test
publish-canary:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- run: yarn install
- run: yarn bootstrap
- run: - run:
name: Saving Authentication Information name: Potentially save npm token
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc command: "([[ ! -z $NPM_TOKEN ]] && echo \"//registry.npmjs.org/:_authToken=$NPM_TOKEN\" >> ~/.npmrc) || echo \"Did not write npm token\""
- run: - run:
name: Publishing to Canary Channel name: Potentially publish canary release
command: yarn run lerna publish from-git --npm-tag canary --yes command: "if ls ~/.npmrc >/dev/null 2>&1 && [[ $(git describe --exact-match 2> /dev/null || :) =~ -canary ]]; then yarn run lerna publish from-git --npm-tag canary --yes; else echo \"Did not publish\"; fi"
- run:
name: Potentially publish stable release
command: "if ls ~/.npmrc >/dev/null 2>&1 && [[ ! $(git describe --exact-match 2> /dev/null || :) =~ -canary ]]; then yarn run lerna publish from-git --yes; else echo \"Did not publish\"; fi"
workflows: workflows:
version: 2 version: 2
unscheduled: build-and-deploy:
jobs: jobs:
- build: - build
filters:
tags:
only: /.*/
- publish-canary:
filters:
tags:
only: /.*/
branches:
ignore: /.*/
# - publish-stable:
# requires:
# - build
# filters:
# tags:
# only: /^(\d+\.)?(\d+\.)?(\*|\d+)$/
# branches:
# ignore: /.*/

View File

@@ -1,2 +1,3 @@
/tmp/*
/node_modules/* /node_modules/*
/**/node_modules/* /**/node_modules/*

View File

@@ -5,6 +5,20 @@
"import/no-unresolved": 0, "import/no-unresolved": 0,
"import/no-dynamic-require": 0, "import/no-dynamic-require": 0,
"global-require": 0 "global-require": 0
} },
"overrides": [
{
"files": ["test/**"],
"rules": {
"import/no-extraneous-dependencies": 0
},
"globals": {
"describe": true,
"it": true,
"test": true,
"expect": true
}
}
]
} }

1
.gitignore vendored
View File

@@ -1 +1,2 @@
node_modules node_modules
tmp

View File

@@ -19,3 +19,9 @@ For the canary channel use:
``` ```
yarn publish-canary 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!

4
jest.config.js Normal file
View File

@@ -0,0 +1,4 @@
module.exports = {
testEnvironment: 'node',
collectCoverageFrom: ['packages/**/*.{js,jsx}', '!**/node_modules/**'],
};

View File

@@ -1,5 +1,6 @@
{ {
"name": "now-builders", "name": "now-builders",
"version": "0.0.0",
"private": true, "private": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -11,13 +12,37 @@
"scripts": { "scripts": {
"lerna": "lerna", "lerna": "lerna",
"bootstrap": "lerna bootstrap", "bootstrap": "lerna bootstrap",
"publish-stable": "lerna version",
"publish-canary": "lerna version prerelease --preid canary", "publish-canary": "lerna version prerelease --preid canary",
"lint": "eslint ." "lint": "tsc && eslint .",
"test": "jest --runInBand",
"lint-staged": "lint-staged"
},
"pre-commit": "lint-staged",
"lint-staged": {
"*.js": [
"prettier --write --single-quote",
"eslint --fix",
"git add"
]
}, },
"devDependencies": { "devDependencies": {
"@types/fs-extra": "^5.0.4",
"@types/glob": "^7.1.1",
"@types/multistream": "^2.1.1",
"@types/node": "^10.12.8",
"buffer-replace": "^1.0.0",
"eslint": "^5.9.0", "eslint": "^5.9.0",
"eslint-config-airbnb-base": "^13.1.0", "eslint-config-airbnb-base": "^13.1.0",
"eslint-config-prettier": "^3.1.0", "eslint-config-prettier": "^3.1.0",
"eslint-plugin-import": "^2.14.0" "eslint-plugin-import": "^2.14.0",
"fs-extra": "^7.0.1",
"glob": "^7.1.3",
"jest": "^23.6.0",
"lint-staged": "^8.0.4",
"node-fetch": "^2.3.0",
"pre-commit": "^1.2.2",
"prettier": "^1.15.2",
"typescript": "^3.1.6"
} }
} }

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

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

@@ -0,0 +1,49 @@
#!/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 `serve` function
if ! declare -f serve > /dev/null; then
echo "ERROR: A \`serve\` function must be defined in \"$ENTRYPOINT\"!" >&2
exit 1
fi
# Show a tree of the final lambda build
show_tree() {
import "static-binaries@0.0.6"
static_binaries tree
echo "Final lambda file tree:"
tree -a .
}
IMPORT_DEBUG= IMPORT_CACHE="$(mktemp -d)" show_tree

View File

@@ -0,0 +1,55 @@
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,
});
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.0.3",
"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,115 @@
import "static-binaries@0.0.6"
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 -r '.body' > "$event"
local request_id
request_id="$(grep -Fi Lambda-Runtime-Aws-Request-Id "$headers" | tr -d '[:space:]' | cut -d: -f2)"
echo "Request-Id: $request_id" >&2
rm -f "$headers"
# Execute the handler function from the script
local body
body="$(mktemp)"
local exit_code=0
REQUEST="$event"
# Stdin of the `serve` 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" &
serve "$event" < "$stdin" > "$body" || exit_code="$?"
rm -f "$event" "$stdin"
if [ "$exit_code" -eq 0 ]; then
# Send the response
local response
response="$(jq -cnMr \
--arg statusCode "$(cat "$_STATUS_CODE")" \
--argjson headers "$(cat "$_HEADERS")" \
--arg body "$(base64 --wrap=0 < "$body")" \
'{statusCode:$statusCode|tonumber, headers:$headers, encoding:"base64", body:$body}')"
rm -f "$body" "$_HEADERS"
_lambda_runtime_api "invocation/$request_id/response" -X POST -d "$response"
else
local error
error='{"exitCode":'"$exit_code"'}'
_lambda_runtime_api "invocation/$request_id/error" -X POST -d "$error"
fi
}
_lambda_runtime_body() {
if [ "$(jq -r '.body | type' < "$1")" = "string" ]; then
if [ "$(jq -r '.encoding' < "$1")" = "base64" ]; then
jq -r '.body' < "$1" | base64 -d
else
# assume plain-text body
jq -r '.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

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

View File

@@ -1,20 +1,38 @@
const assert = require('assert'); const assert = require('assert');
const fs = require('fs-extra'); const fs = require('fs-extra');
const MultiStream = require('multistream'); const multiStream = require('multistream');
const path = require('path'); const path = require('path');
const Sema = require('async-sema'); const Sema = require('async-sema');
/** @typedef {{[filePath: string]: FileFsRef}} FsFiles */
const semaToPreventEMFILE = new Sema(30); const semaToPreventEMFILE = new Sema(30);
/**
* @constructor
* @argument {Object} options
* @argument {number} [options.mode=0o100644]
* @argument {string} options.fsPath
*/
class FileFsRef { class FileFsRef {
constructor({ mode = 0o100644, fsPath }) { constructor({ mode = 0o100644, fsPath }) {
assert(typeof mode === 'number'); assert(typeof mode === 'number');
assert(typeof fsPath === 'string'); assert(typeof fsPath === 'string');
/** @type {string} */
this.type = 'FileFsRef'; this.type = 'FileFsRef';
/** @type {number} */
this.mode = mode; this.mode = mode;
/** @type {string} */
this.fsPath = fsPath; this.fsPath = fsPath;
} }
/**
* @argument {Object} options
* @argument {number} [options.mode=0o100644]
* @argument {NodeJS.ReadableStream} options.stream
* @argument {string} options.fsPath
* @returns {Promise<FileFsRef>}
*/
static async fromStream({ mode = 0o100644, stream, fsPath }) { static async fromStream({ mode = 0o100644, stream, fsPath }) {
assert(typeof mode === 'number'); assert(typeof mode === 'number');
assert(typeof stream.pipe === 'function'); // is-stream assert(typeof stream.pipe === 'function'); // is-stream
@@ -24,37 +42,45 @@ class FileFsRef {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
const dest = fs.createWriteStream(fsPath); const dest = fs.createWriteStream(fsPath);
stream.pipe(dest); stream.pipe(dest);
stream.on('error', error => reject(error)); stream.on('error', reject);
dest.on('finish', () => resolve()); dest.on('finish', resolve);
dest.on('error', error => reject(error)); dest.on('error', reject);
}); });
await fs.chmod(fsPath, mode.toString(8).slice(-3)); await fs.chmod(fsPath, mode.toString(8).slice(-3));
return new FileFsRef({ mode, fsPath }); return new FileFsRef({ mode, fsPath });
} }
/**
* @returns {Promise<NodeJS.ReadableStream>}
*/
async toStreamAsync() { async toStreamAsync() {
await semaToPreventEMFILE.acquire(); await semaToPreventEMFILE.acquire();
const release = () => semaToPreventEMFILE.release(); const release = () => semaToPreventEMFILE.release();
const stream = fs.createReadStream(this.fsPath); const stream = fs.createReadStream(this.fsPath);
stream.on('end', release); stream.on('close', release);
stream.on('error', release); stream.on('error', release);
return stream; return stream;
} }
/**
* @returns {NodeJS.ReadableStream}
*/
toStream() { toStream() {
let flag; let flag;
// eslint-disable-next-line consistent-return // eslint-disable-next-line consistent-return
return new MultiStream((cb) => { return multiStream((cb) => {
if (flag) return cb(); if (flag) return cb(null, null);
flag = true; flag = true;
this.toStreamAsync().then((stream) => { this.toStreamAsync()
cb(undefined, stream); .then((stream) => {
}).catch((error) => { cb(null, stream);
cb(error); })
}); .catch((error) => {
cb(error, null);
});
}); });
} }
} }

View File

@@ -1,20 +1,42 @@
const assert = require('assert'); const assert = require('assert');
const fetch = require('node-fetch'); const fetch = require('node-fetch');
const MultiStream = require('multistream'); const multiStream = require('multistream');
const retry = require('async-retry'); const retry = require('async-retry');
const Sema = require('async-sema'); const Sema = require('async-sema');
/** @typedef {{[filePath: string]: FileRef}} Files */
const semaToDownloadFromS3 = new Sema(10); const semaToDownloadFromS3 = new Sema(10);
class BailableError extends Error {
constructor(...args) {
super(...args);
/** @type {boolean} */
this.bail = false;
}
}
/**
* @constructor
* @argument {Object} options
* @argument {number} [options.mode=0o100644]
* @argument {string} options.digest
*/
class FileRef { class FileRef {
constructor({ mode = 0o100644, digest }) { constructor({ mode = 0o100644, digest }) {
assert(typeof mode === 'number'); assert(typeof mode === 'number');
assert(typeof digest === 'string'); assert(typeof digest === 'string');
/** @type {string} */
this.type = 'FileRef'; this.type = 'FileRef';
/** @type {number} */
this.mode = mode; this.mode = mode;
/** @type {string} */
this.digest = digest; this.digest = digest;
} }
/**
* @returns {Promise<NodeJS.ReadableStream>}
*/
async toStreamAsync() { async toStreamAsync() {
let url; let url;
// sha:24be087eef9fac01d61b30a725c1a10d7b45a256 // sha:24be087eef9fac01d61b30a725c1a10d7b45a256
@@ -29,34 +51,44 @@ class FileRef {
await semaToDownloadFromS3.acquire(); await semaToDownloadFromS3.acquire();
console.time(`downloading ${url}`); console.time(`downloading ${url}`);
try { try {
return await retry(async () => { return await retry(
const resp = await fetch(url); async () => {
if (!resp.ok) { const resp = await fetch(url);
const error = new Error(`${resp.status} ${resp.statusText}`); if (!resp.ok) {
if (resp.status === 403) error.bail = true; const error = new BailableError(
throw error; `${resp.status} ${resp.statusText}`,
} );
return resp.body; if (resp.status === 403) error.bail = true;
}, { factor: 1, retries: 3 }); throw error;
}
return resp.body;
},
{ factor: 1, retries: 3 },
);
} finally { } finally {
console.timeEnd(`downloading ${url}`); console.timeEnd(`downloading ${url}`);
semaToDownloadFromS3.release(); semaToDownloadFromS3.release();
} }
} }
/**
* @returns {NodeJS.ReadableStream}
*/
toStream() { toStream() {
let flag; let flag;
// eslint-disable-next-line consistent-return // eslint-disable-next-line consistent-return
return new MultiStream((cb) => { return multiStream((cb) => {
if (flag) return cb(); if (flag) return cb(null, null);
flag = true; flag = true;
this.toStreamAsync().then((stream) => { this.toStreamAsync()
cb(undefined, stream); .then((stream) => {
}).catch((error) => { cb(null, stream);
cb(error); })
}); .catch((error) => {
cb(error, null);
});
}); });
} }
} }

View File

@@ -0,0 +1,83 @@
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 isOutsideCachePath(filename) {
const relative = path.relative(cachePath, filename);
return relative.startsWith('..');
}
const saveCreateWriteStream = fs.createWriteStream;
fs.createWriteStream = (...args) => {
const filename = args[0];
if (isOutsideCachePath(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 (isOutsideCachePath(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];
if (isOutsideCachePath(src)) {
return saveCopyFile.call(fs, ...args);
}
const dest = args[1];
const callback = args[args.length - 1];
const buffer = vfs.readFileSync(src);
return fs.writeFile(dest, buffer, callback);
};
const saveWriteFile = fs.writeFile;
fs.writeFile = (...args) => {
const filename = args[0];
if (isOutsideCachePath(filename)) {
return saveWriteFile.call(fs, ...args);
}
return vfs.writeFile(...args);
};
require(yarnPath);

View File

@@ -1,20 +1,38 @@
const path = require('path'); const path = require('path');
const FileFsRef = require('../file-fs-ref.js'); const FileFsRef = require('../file-fs-ref.js');
/** @typedef {import('../file-ref')} FileRef */
/** @typedef {import('../file-fs-ref')} FileFsRef */
/** @typedef {{[filePath: string]: FileRef|FileFsRef}} Files */
/** @typedef {{[filePath: string]: FileFsRef}|{}} DownloadedFiles */
/**
* @param {FileRef|FileFsRef} file
* @param {string} fsPath
* @returns {Promise<FileFsRef>}
*/
async function downloadFile(file, fsPath) { async function downloadFile(file, fsPath) {
const { mode } = file; const { mode } = file;
const stream = file.toStream(); const stream = file.toStream();
return FileFsRef.fromStream({ mode, stream, fsPath }); return FileFsRef.fromStream({ mode, stream, fsPath });
} }
/**
* Download files to disk
* @argument {Files} files
* @argument {string} basePath
* @returns {Promise<DownloadedFiles>}
*/
module.exports = async function download(files, basePath) { module.exports = async function download(files, basePath) {
const files2 = {}; const files2 = {};
await Promise.all(Object.keys(files).map(async (name) => { await Promise.all(
const file = files[name]; Object.keys(files).map(async (name) => {
const fsPath = path.join(basePath, name); const file = files[name];
files2[name] = await downloadFile(file, fsPath); const fsPath = path.join(basePath, name);
})); files2[name] = await downloadFile(file, fsPath);
}),
);
return files2; return files2;
}; };

View File

@@ -3,15 +3,30 @@ const path = require('path');
const vanillaGlob = require('glob'); const vanillaGlob = require('glob');
const FileFsRef = require('../file-fs-ref.js'); const FileFsRef = require('../file-fs-ref.js');
/** @typedef {import('fs').Stats} Stats */
/** @typedef {import('glob').IOptions} GlobOptions */
/** @typedef {import('../file-fs-ref').FsFiles|{}} GlobFiles */
/**
* @argument {string} pattern
* @argument {GlobOptions|string} opts
* @argument {string} [mountpoint]
* @returns {Promise<GlobFiles>}
*/
module.exports = function glob(pattern, opts = {}, mountpoint) { module.exports = function glob(pattern, opts = {}, mountpoint) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let options = opts; /** @type {GlobOptions} */
if (typeof options === 'string') { let options;
options = { cwd: options }; if (typeof opts === 'string') {
options = { cwd: opts };
} else {
options = opts;
} }
if (!options.cwd) { if (!options.cwd) {
throw new Error('Second argument (basePath) must be specified for names of resulting files'); throw new Error(
'Second argument (basePath) must be specified for names of resulting files',
);
} }
if (!path.isAbsolute(options.cwd)) { if (!path.isAbsolute(options.cwd)) {
@@ -26,21 +41,27 @@ module.exports = function glob(pattern, opts = {}, mountpoint) {
vanillaGlob(pattern, options, (error, files) => { vanillaGlob(pattern, options, (error, files) => {
if (error) return reject(error); if (error) return reject(error);
resolve(files.reduce((files2, relativePath) => { resolve(
const fsPath = path.join(options.cwd, relativePath); files.reduce((files2, relativePath) => {
const stat = options.statCache[fsPath]; const fsPath = path.join(options.cwd, relativePath);
assert(stat, `statCache does not contain value for ${relativePath} (resolved to ${fsPath})`); /** @type {Stats|any} */
if (stat.isFile()) { const stat = options.statCache[fsPath];
let finalPath = relativePath; assert(
if (mountpoint) finalPath = path.join(mountpoint, finalPath); stat,
return { `statCache does not contain value for ${relativePath} (resolved to ${fsPath})`,
...files2, );
[finalPath]: new FileFsRef({ mode: stat.mode, fsPath }), if (stat && stat.isFile()) {
}; let finalPath = relativePath;
} if (mountpoint) finalPath = path.join(mountpoint, finalPath);
return {
...files2,
[finalPath]: new FileFsRef({ mode: stat.mode, fsPath }),
};
}
return files2; return files2;
}, {})); }, {}),
);
}); });
}); });
}; };

View File

@@ -1,6 +1,25 @@
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
/** @typedef { import('@now/build-utils/file-fs-ref') } FileFsRef */
/** @typedef {{[filePath: string]: FileRef|FileFsRef}} Files */
/**
* @callback delegate
* @argument {string} name
* @returns {string}
*/
/**
* Rename files using delegate function
* @argument {Files} files
* @argument {delegate} delegate
* @returns {Files}
*/
module.exports = function rename(files, delegate) { module.exports = function rename(files, delegate) {
return Object.keys(files).reduce((newFiles, name) => ({ return Object.keys(files).reduce(
...newFiles, (newFiles, name) => ({
[delegate(name)]: files[name], ...newFiles,
}), {}); [delegate(name)]: files[name],
}),
{},
);
}; };

View File

@@ -1,3 +1,4 @@
const assert = require('assert');
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('path'); const path = require('path');
const { spawn } = require('child_process'); const { spawn } = require('child_process');
@@ -6,27 +7,41 @@ function spawnAsync(command, args, cwd) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const child = spawn(command, args, { stdio: 'inherit', cwd }); const child = spawn(command, args, { stdio: 'inherit', cwd });
child.on('error', reject); child.on('error', reject);
child.on('close', (code, signal) => (code !== 0 ? reject(new Error(`Exited with ${code || signal}`)) : resolve())); child.on('close', (code, signal) => (code !== 0
? reject(new Error(`Exited with ${code || signal}`))
: resolve()));
}); });
} }
async function runShellScript(fsPath) { async function runShellScript(fsPath) {
assert(path.isAbsolute(fsPath));
const destPath = path.dirname(fsPath); const destPath = path.dirname(fsPath);
await spawnAsync(`./${path.basename(fsPath)}`, [], destPath); await spawnAsync(`./${path.basename(fsPath)}`, [], destPath);
return true; return true;
} }
async function shouldUseNpm(destPath) { async function scanParentDirs(destPath, scriptName) {
assert(path.isAbsolute(destPath));
let hasScript = false;
let hasPackageLockJson = false;
let currentDestPath = destPath; let currentDestPath = destPath;
// eslint-disable-next-line no-constant-condition // eslint-disable-next-line no-constant-condition
while (true) { while (true) {
const packageJsonPath = path.join(currentDestPath, 'package.json');
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
if (await fs.exists(path.join(currentDestPath, 'package.json'))) { if (await fs.exists(packageJsonPath)) {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
if (await fs.exists(path.join(currentDestPath, 'package-lock.json'))) { const packageJson = JSON.parse(await fs.readFile(packageJsonPath));
return true; hasScript = Boolean(
} packageJson.scripts && packageJson.scripts[scriptName],
return false; );
// eslint-disable-next-line no-await-in-loop
hasPackageLockJson = await fs.exists(
path.join(currentDestPath, 'package-lock.json'),
);
break;
} }
const newDestPath = path.dirname(currentDestPath); const newDestPath = path.dirname(currentDestPath);
@@ -34,32 +49,49 @@ async function shouldUseNpm(destPath) {
currentDestPath = newDestPath; currentDestPath = newDestPath;
} }
return false; return { hasScript, hasPackageLockJson };
} }
async function runNpmInstall(destPath, args = []) { async function runNpmInstall(destPath, args = []) {
assert(path.isAbsolute(destPath));
let commandArgs = args; let commandArgs = args;
console.log(`installing to ${destPath}`); console.log(`installing to ${destPath}`);
if (await shouldUseNpm(destPath)) { const { hasPackageLockJson } = await scanParentDirs(destPath);
if (hasPackageLockJson) {
commandArgs = args.filter(a => a !== '--prefer-offline'); commandArgs = args.filter(a => a !== '--prefer-offline');
await spawnAsync('npm', ['install'].concat(commandArgs), destPath); await spawnAsync('npm', ['install'].concat(commandArgs), destPath);
await spawnAsync('npm', ['cache', 'clean', '--force'], destPath);
} else if (process.env.AWS_EXECUTION_ENV) {
console.log('using memory-fs for yarn cache');
await spawnAsync(
'node',
[path.join(__dirname, 'bootstrap-yarn.js'), '--cwd', destPath].concat(
commandArgs,
),
destPath,
);
} else { } else {
await spawnAsync('yarn', ['--cwd', destPath].concat(commandArgs), destPath); await spawnAsync('yarn', ['--cwd', destPath].concat(commandArgs), destPath);
await spawnAsync('yarn', ['cache', 'clean'], destPath);
} }
} }
async function runPackageJsonScript(destPath, scriptName) { async function runPackageJsonScript(destPath, scriptName) {
try { assert(path.isAbsolute(destPath));
if (await shouldUseNpm(destPath)) { const { hasScript, hasPackageLockJson } = await scanParentDirs(
console.log(`running "npm run ${scriptName}"`); destPath,
await spawnAsync('npm', ['run', scriptName], destPath); scriptName,
} else { );
console.log(`running "yarn run ${scriptName}"`); if (!hasScript) return false;
await spawnAsync('yarn', ['--cwd', destPath, 'run', scriptName], destPath);
} if (hasPackageLockJson) {
} catch (error) { console.log(`running "npm run ${scriptName}"`);
console.log(error.message); await spawnAsync('npm', ['run', scriptName], destPath);
return false; } else {
console.log(`running "yarn run ${scriptName}"`);
await spawnAsync('yarn', ['--cwd', destPath, 'run', scriptName], destPath);
} }
return true; return true;

View File

@@ -25,16 +25,21 @@ async function createLambda({
assert(typeof environment === 'object', '"environment" is not an object'); assert(typeof environment === 'object', '"environment" is not an object');
const zipFile = new ZipFile(); const zipFile = new ZipFile();
Object.keys(files).sort().forEach((name) => { Object.keys(files)
const file = files[name]; .sort()
const stream = file.toStream(); .forEach((name) => {
zipFile.addReadStream(stream, name, { mode: file.mode, mtime }); const file = files[name];
}); const stream = file.toStream();
zipFile.addReadStream(stream, name, { mode: file.mode, mtime });
});
zipFile.end(); zipFile.end();
const zipBuffer = await streamToBuffer(zipFile.outputStream); const zipBuffer = await streamToBuffer(zipFile.outputStream);
return new Lambda({ return new Lambda({
zipBuffer, handler, runtime, environment, zipBuffer,
handler,
runtime,
environment,
}); });
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/build-utils", "name": "@now/build-utils",
"version": "0.4.27-canary.4", "version": "0.4.31",
"dependencies": { "dependencies": {
"async-retry": "1.2.3", "async-retry": "1.2.3",
"async-sema": "2.1.4", "async-sema": "2.1.4",
@@ -8,8 +8,12 @@
"fs-extra": "7.0.0", "fs-extra": "7.0.0",
"glob": "7.1.3", "glob": "7.1.3",
"into-stream": "4.0.0", "into-stream": "4.0.0",
"memory-fs": "0.4.1",
"multistream": "2.1.1", "multistream": "2.1.1",
"node-fetch": "2.2.0", "node-fetch": "2.2.0",
"yazl": "2.4.3" "yazl": "2.4.3"
},
"scripts": {
"test": "jest"
} }
} }

View File

@@ -0,0 +1,11 @@
{
"version": 2,
"builds": [
{ "src": "with-npm/index.js", "use": "@now/node" },
{ "src": "with-yarn/index.js", "use": "@now/node" }
],
"probes": [
{ "path": "/with-npm", "mustContain": "npm:RANDOMNESS_PLACEHOLDER" },
{ "path": "/with-yarn", "mustContain": "yarn:RANDOMNESS_PLACEHOLDER" }
]
}

View File

@@ -0,0 +1,14 @@
const fs = require('fs');
const path = require('path');
const execpath = path.basename(process.env.npm_execpath);
console.log('execpath', execpath);
if (execpath === 'npm-cli.js') {
fs.writeFileSync(
'index.js',
'module.exports = (_, resp) => resp.end("npm:RANDOMNESS_PLACEHOLDER");',
);
} else {
throw new Error('npm is expected');
}

View File

@@ -0,0 +1,3 @@
{
"lockfileVersion": 1
}

View File

@@ -0,0 +1,5 @@
{
"scripts": {
"now-build": "node must-be-npm.js"
}
}

View File

@@ -0,0 +1,14 @@
const fs = require('fs');
const path = require('path');
const execpath = path.basename(process.env.npm_execpath);
console.log('execpath', execpath);
if (execpath === 'yarn.js' || execpath === 'yarn') {
fs.writeFileSync(
'index.js',
'module.exports = (_, resp) => resp.end("yarn:RANDOMNESS_PLACEHOLDER");',
);
} else {
throw new Error('yarn is expected');
}

View File

@@ -0,0 +1,5 @@
{
"scripts": {
"now-build": "node must-be-yarn.js"
}
}

View File

@@ -0,0 +1,63 @@
/* 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 builderUrl = '@canary';
let buildUtilsUrl;
beforeAll(async () => {
const buildUtilsPath = path.resolve(__dirname, '..');
buildUtilsUrl = await packAndDeploy(buildUtilsPath);
console.log('buildUtilsUrl', buildUtilsUrl);
});
// own fixtures
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();
});
}
// few foreign tests
const buildersToTestWith = ['now-node-server', 'now-static-build'];
// eslint-disable-next-line no-restricted-syntax
for (const builder of buildersToTestWith) {
const fixturesPath2 = path.resolve(
__dirname,
`../../${builder}/test/fixtures`,
);
// 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(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath2, fixture),
),
).resolves.toBeDefined();
});
}
}
}

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-cgi/.gitignore vendored Normal file
View File

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

7
packages/now-cgi/build.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
export GOOS=linux
export GOARCH=amd64
export GOPATH=$HOME/go
go get github.com/aws/aws-lambda-go/events
go get github.com/aws/aws-lambda-go/lambda
go build -o handler main.go

42
packages/now-cgi/index.js Normal file
View File

@@ -0,0 +1,42 @@
const path = require('path');
const { mkdirp, copyFile } = require('fs-extra');
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.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
exports.build = async ({ files, entrypoint }) => {
console.log('downloading files...');
const srcDir = await getWritableDirectory();
const outDir = await getWritableDirectory();
await download(files, srcDir);
const handlerPath = path.join(__dirname, 'handler');
await copyFile(handlerPath, path.join(outDir, 'handler'));
const entrypointOutDir = path.join(outDir, path.dirname(entrypoint));
await mkdirp(entrypointOutDir);
// For now only the entrypoint file is copied into the lambda
await copyFile(
path.join(srcDir, entrypoint),
path.join(outDir, entrypoint),
);
const lambda = await createLambda({
files: await glob('**', outDir),
handler: 'handler',
runtime: 'go1.x',
environment: {
SCRIPT_FILENAME: entrypoint,
},
});
return {
[entrypoint]: lambda,
};
};

36
packages/now-cgi/main.go Normal file
View File

@@ -0,0 +1,36 @@
package main
import (
now "../../utils/go/bridge"
"net/http"
"net/http/cgi"
"os"
"path/filepath"
)
type CgiHandler struct {
http.Handler
Dir string
Script string
}
func (h *CgiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
handler := cgi.Handler{
Path: h.Script,
Root: "/" + h.Script,
Dir: h.Dir,
Env: []string{
"HTTPS=on",
"SERVER_PORT=443",
"SERVER_SOFTWARE=@now/cgi",
},
}
handler.ServeHTTP(w, r)
}
func main() {
workdir, _ := filepath.Abs(".")
script := os.Getenv("SCRIPT_FILENAME")
handler := &CgiHandler{nil, workdir, script}
now.Start(handler)
}

View File

@@ -0,0 +1,22 @@
{
"name": "@now/cgi",
"version": "0.0.14",
"scripts": {
"test": "best -I test/*.js",
"prepublish": "./build.sh"
},
"files": [
"index.js",
"handler"
],
"dependencies": {
"fs-extra": "7.0.0"
},
"devDependencies": {
"@zeit/best": "0.4.3",
"rmfr": "2.0.0"
},
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
}
}

862
packages/now-cgi/yarn.lock Normal file
View File

@@ -0,0 +1,862 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
dependencies:
call-me-maybe "^1.0.1"
glob-to-regexp "^0.3.0"
"@nodelib/fs.stat@^1.0.1":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
"@zeit/best@0.4.3":
version "0.4.3"
resolved "http://registry.npmjs.org/@zeit/best/-/best-0.4.3.tgz#eaebdfa8b24121a97b1753501ea8c9330d549b30"
dependencies:
arg "1.0.0"
chalk "2.3.1"
diff "3.5.0"
globby "8.0.0"
signal-exit "3.0.2"
ansi-styles@^3.2.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
dependencies:
color-convert "^1.9.0"
append-type@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/append-type/-/append-type-1.0.1.tgz#e29a6eb22cec0c0b9b93063b3cf6b10d9e0c60f4"
arg@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/arg/-/arg-1.0.0.tgz#444d885a4e25b121640b55155ef7cd03975d6050"
arr-diff@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
arr-flatten@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
arr-union@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
array-to-sentence@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc"
array-union@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
dependencies:
array-uniq "^1.0.1"
array-uniq@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
array-unique@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
assert-valid-glob-opts@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-valid-glob-opts/-/assert-valid-glob-opts-1.0.0.tgz#ab9b5438ec5e929f5bb08201819affb1227f730a"
dependencies:
glob-option-error "^1.0.0"
validate-glob-opts "^1.0.0"
assign-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
atob@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
base@^0.11.1:
version "0.11.2"
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
dependencies:
cache-base "^1.0.1"
class-utils "^0.3.5"
component-emitter "^1.2.1"
define-property "^1.0.0"
isobject "^3.0.1"
mixin-deep "^1.2.0"
pascalcase "^0.1.1"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@^2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
dependencies:
arr-flatten "^1.1.0"
array-unique "^0.3.2"
extend-shallow "^2.0.1"
fill-range "^4.0.0"
isobject "^3.0.1"
repeat-element "^1.1.2"
snapdragon "^0.8.1"
snapdragon-node "^2.0.1"
split-string "^3.0.2"
to-regex "^3.0.1"
cache-base@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
dependencies:
collection-visit "^1.0.0"
component-emitter "^1.2.1"
get-value "^2.0.6"
has-value "^1.0.0"
isobject "^3.0.1"
set-value "^2.0.0"
to-object-path "^0.3.0"
union-value "^1.0.0"
unset-value "^1.0.0"
call-me-maybe@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
chalk@2.3.1:
version "2.3.1"
resolved "http://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
dependencies:
ansi-styles "^3.2.0"
escape-string-regexp "^1.0.5"
supports-color "^5.2.0"
class-utils@^0.3.5:
version "0.3.6"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
dependencies:
arr-union "^3.1.0"
define-property "^0.2.5"
isobject "^3.0.0"
static-extend "^0.1.1"
collection-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
dependencies:
map-visit "^1.0.0"
object-visit "^1.0.0"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
dependencies:
color-name "1.1.3"
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
component-emitter@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
dependencies:
ms "2.0.0"
decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
define-property@^0.2.5:
version "0.2.5"
resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
dependencies:
is-descriptor "^0.1.0"
define-property@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
dependencies:
is-descriptor "^1.0.0"
define-property@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
dependencies:
is-descriptor "^1.0.2"
isobject "^3.0.1"
diff@3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
dir-glob@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
dependencies:
arrify "^1.0.1"
path-type "^3.0.0"
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
expand-brackets@^2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
dependencies:
debug "^2.3.3"
define-property "^0.2.5"
extend-shallow "^2.0.1"
posix-character-classes "^0.1.0"
regex-not "^1.0.0"
snapdragon "^0.8.1"
to-regex "^3.0.1"
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
dependencies:
is-extendable "^0.1.0"
extend-shallow@^3.0.0, extend-shallow@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
dependencies:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
extglob@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
dependencies:
array-unique "^0.3.2"
define-property "^1.0.0"
expand-brackets "^2.1.4"
extend-shallow "^2.0.1"
fragment-cache "^0.2.1"
regex-not "^1.0.0"
snapdragon "^0.8.1"
to-regex "^3.0.1"
fast-glob@^2.0.2:
version "2.2.3"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.3.tgz#d09d378e9ef6b0076a0fa1ba7519d9d4d9699c28"
dependencies:
"@mrmlnc/readdir-enhanced" "^2.2.1"
"@nodelib/fs.stat" "^1.0.1"
glob-parent "^3.1.0"
is-glob "^4.0.0"
merge2 "^1.2.1"
micromatch "^3.1.10"
fill-range@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
dependencies:
extend-shallow "^2.0.1"
is-number "^3.0.0"
repeat-string "^1.6.1"
to-regex-range "^2.1.0"
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
fragment-cache@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
dependencies:
map-cache "^0.2.2"
fs-extra@7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
glob-option-error@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/glob-option-error/-/glob-option-error-1.0.0.tgz#57cc65def9c7d5c1461baf13129bb5403cff6176"
glob-parent@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
dependencies:
is-glob "^3.1.0"
path-dirname "^1.0.0"
glob-to-regexp@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
glob@^7.0.5, glob@^7.1.2:
version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
globby@8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.0.tgz#e6f8340ead9a52fa417ec0e75ae664ae0026f5c6"
dependencies:
array-union "^1.0.1"
dir-glob "^2.0.0"
fast-glob "^2.0.2"
glob "^7.1.2"
ignore "^3.3.5"
pify "^3.0.0"
slash "^1.0.0"
graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
version "4.1.14"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.14.tgz#1b6e8362ef8c5ecb5da799901f39297e3054773a"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
has-value@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
dependencies:
get-value "^2.0.3"
has-values "^0.1.4"
isobject "^2.0.0"
has-value@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
dependencies:
get-value "^2.0.6"
has-values "^1.0.0"
isobject "^3.0.0"
has-values@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
has-values@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
dependencies:
is-number "^3.0.0"
kind-of "^4.0.0"
ignore@^3.3.5:
version "3.3.10"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
indexed-filter@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/indexed-filter/-/indexed-filter-1.0.3.tgz#7911439191cac588188464640a8db4f6b324973d"
dependencies:
append-type "^1.0.1"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
inspect-with-kind@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/inspect-with-kind/-/inspect-with-kind-1.0.5.tgz#fce151d4ce89722c82ca8e9860bb96f9167c316c"
dependencies:
kind-of "^6.0.2"
is-accessor-descriptor@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
dependencies:
kind-of "^3.0.2"
is-accessor-descriptor@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
dependencies:
kind-of "^6.0.0"
is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
is-data-descriptor@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
dependencies:
kind-of "^3.0.2"
is-data-descriptor@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
dependencies:
kind-of "^6.0.0"
is-descriptor@^0.1.0:
version "0.1.6"
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
dependencies:
is-accessor-descriptor "^0.1.6"
is-data-descriptor "^0.1.4"
kind-of "^5.0.0"
is-descriptor@^1.0.0, is-descriptor@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
dependencies:
is-accessor-descriptor "^1.0.0"
is-data-descriptor "^1.0.0"
kind-of "^6.0.2"
is-extendable@^0.1.0, is-extendable@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
is-extendable@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
dependencies:
is-plain-object "^2.0.4"
is-extglob@^2.1.0, is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
is-glob@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
dependencies:
is-extglob "^2.1.0"
is-glob@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
dependencies:
is-extglob "^2.1.1"
is-number@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
dependencies:
kind-of "^3.0.2"
is-plain-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
dependencies:
isobject "^3.0.1"
is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
isarray@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isobject@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
dependencies:
isarray "1.0.0"
isobject@^3.0.0, isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
optionalDependencies:
graceful-fs "^4.1.6"
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
dependencies:
is-buffer "^1.1.5"
kind-of@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
dependencies:
is-buffer "^1.1.5"
kind-of@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
kind-of@^6.0.0, kind-of@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
map-cache@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
map-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
dependencies:
object-visit "^1.0.0"
merge2@^1.2.1:
version "1.2.3"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
micromatch@^3.1.10:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
dependencies:
arr-diff "^4.0.0"
array-unique "^0.3.2"
braces "^2.3.1"
define-property "^2.0.2"
extend-shallow "^3.0.2"
extglob "^2.0.4"
fragment-cache "^0.2.1"
kind-of "^6.0.2"
nanomatch "^1.2.9"
object.pick "^1.3.0"
regex-not "^1.0.0"
snapdragon "^0.8.1"
to-regex "^3.0.2"
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
brace-expansion "^1.1.7"
mixin-deep@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
dependencies:
for-in "^1.0.2"
is-extendable "^1.0.1"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
dependencies:
arr-diff "^4.0.0"
array-unique "^0.3.2"
define-property "^2.0.2"
extend-shallow "^3.0.2"
fragment-cache "^0.2.1"
is-windows "^1.0.2"
kind-of "^6.0.2"
object.pick "^1.3.0"
regex-not "^1.0.0"
snapdragon "^0.8.1"
to-regex "^3.0.1"
object-copy@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
dependencies:
copy-descriptor "^0.1.0"
define-property "^0.2.5"
kind-of "^3.0.3"
object-visit@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
dependencies:
isobject "^3.0.0"
object.pick@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
dependencies:
isobject "^3.0.1"
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
wrappy "1"
pascalcase@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
path-dirname@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
path-type@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
dependencies:
pify "^3.0.0"
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
posix-character-classes@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
dependencies:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
repeat-element@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
repeat-string@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
rimraf@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies:
glob "^7.0.5"
rmfr@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/rmfr/-/rmfr-2.0.0.tgz#8a42e81332550b3f0019b8fb8ab245bea81b6d1c"
dependencies:
assert-valid-glob-opts "^1.0.0"
glob "^7.1.2"
graceful-fs "^4.1.11"
inspect-with-kind "^1.0.4"
rimraf "^2.6.2"
safe-regex@^1.1.0:
version "1.1.0"
resolved "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
dependencies:
ret "~0.1.10"
set-value@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
dependencies:
extend-shallow "^2.0.1"
is-extendable "^0.1.1"
is-plain-object "^2.0.1"
to-object-path "^0.3.0"
set-value@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
dependencies:
extend-shallow "^2.0.1"
is-extendable "^0.1.1"
is-plain-object "^2.0.3"
split-string "^3.0.1"
signal-exit@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
slash@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
snapdragon-node@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
dependencies:
define-property "^1.0.0"
isobject "^3.0.0"
snapdragon-util "^3.0.1"
snapdragon-util@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
dependencies:
kind-of "^3.2.0"
snapdragon@^0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
dependencies:
base "^0.11.1"
debug "^2.2.0"
define-property "^0.2.5"
extend-shallow "^2.0.1"
map-cache "^0.2.2"
source-map "^0.5.6"
source-map-resolve "^0.5.0"
use "^3.1.0"
source-map-resolve@^0.5.0:
version "0.5.2"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
dependencies:
atob "^2.1.1"
decode-uri-component "^0.2.0"
resolve-url "^0.2.1"
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
source-map@^0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
dependencies:
extend-shallow "^3.0.0"
static-extend@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
dependencies:
define-property "^0.2.5"
object-copy "^0.1.0"
supports-color@^5.2.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
dependencies:
has-flag "^3.0.0"
to-object-path@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
dependencies:
kind-of "^3.0.2"
to-regex-range@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
dependencies:
is-number "^3.0.0"
repeat-string "^1.6.1"
to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
dependencies:
define-property "^2.0.2"
extend-shallow "^3.0.2"
regex-not "^1.0.2"
safe-regex "^1.1.0"
union-value@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
dependencies:
arr-union "^3.1.0"
get-value "^2.0.6"
is-extendable "^0.1.1"
set-value "^0.4.3"
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
unset-value@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
dependencies:
has-value "^0.3.1"
isobject "^3.0.0"
urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
validate-glob-opts@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/validate-glob-opts/-/validate-glob-opts-1.0.2.tgz#ef9f98977d965537ea4f51fa7d5799e9c6ebca91"
dependencies:
array-to-sentence "^1.1.0"
indexed-filter "^1.0.0"
inspect-with-kind "^1.0.4"
is-plain-obj "^1.1.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"

View File

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

View File

@@ -9,7 +9,7 @@ const downloadGit = require('lambda-git');
const glob = require('@now/build-utils/fs/glob.js'); const glob = require('@now/build-utils/fs/glob.js');
const downloadGoBin = require('./download-go-bin'); 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. // `go help gopath`'s instructions.
// without this, Go won't recognize the `$GOPATH` // without this, Go won't recognize the `$GOPATH`
async function createGoPathTree(goPath) { async function createGoPathTree(goPath) {
@@ -17,6 +17,10 @@ async function createGoPathTree(goPath) {
await mkdirp(path.join(goPath, 'pkg', 'linux_amd64')); await mkdirp(path.join(goPath, 'pkg', 'linux_amd64'));
} }
exports.config = {
maxLambdaSize: '10mb',
};
exports.build = async ({ files, entrypoint }) => { exports.build = async ({ files, entrypoint }) => {
console.log('downloading files...'); console.log('downloading files...');
@@ -57,15 +61,25 @@ exports.build = async ({ files, entrypoint }) => {
} }
if (handlerFunctionName === '') { if (handlerFunctionName === '') {
const e = new Error(`Could not find an exported function on "${entrypoint}"`); const e = new Error(
`Could not find an exported function on "${entrypoint}"`,
);
console.log(e.message); console.log(e.message);
throw e; throw e;
} }
console.log(`Found exported function "${handlerFunctionName}" on "${entrypoint}"`); console.log(
`Found exported function "${handlerFunctionName}" on "${entrypoint}"`,
);
const origianlMainGoContents = await readFile(path.join(__dirname, 'main.go'), 'utf8'); const origianlMainGoContents = await readFile(
const mainGoContents = origianlMainGoContents.replace('__NOW_HANDLER_FUNC_NAME', handlerFunctionName); path.join(__dirname, 'main.go'),
'utf8',
);
const mainGoContents = origianlMainGoContents.replace(
'__NOW_HANDLER_FUNC_NAME',
handlerFunctionName,
);
// in order to allow the user to have `main.go`, we need our `main.go` to be called something else // in order to allow the user to have `main.go`, we need our `main.go` to be called something else
const mainGoFileName = 'main__now__go__.go'; const mainGoFileName = 'main__now__go__.go';
@@ -77,12 +91,15 @@ exports.build = async ({ files, entrypoint }) => {
// so now we place `main.go` together with the user code // so now we place `main.go` together with the user code
await writeFile(path.join(entrypointDirname, mainGoFileName), mainGoContents); await writeFile(path.join(entrypointDirname, mainGoFileName), mainGoContents);
console.log('installing dependencies'); console.log('installing dependencies');
// `go get` will look at `*.go` (note we set `cwd`), parse // `go get` will look at `*.go` (note we set `cwd`), parse
// the `import`s and download any packages that aren't part of the stdlib // the `import`s and download any packages that aren't part of the stdlib
try { try {
await execa(goBin, ['get'], { env: goEnv, cwd: entrypointDirname, stdio: 'inherit' }); await execa(goBin, ['get'], {
env: goEnv,
cwd: entrypointDirname,
stdio: 'inherit',
});
} catch (err) { } catch (err) {
console.log('failed to `go get`'); console.log('failed to `go get`');
throw err; throw err;
@@ -90,11 +107,17 @@ exports.build = async ({ files, entrypoint }) => {
console.log('running go build...'); console.log('running go build...');
try { try {
await execa(goBin, [ await execa(
'build', goBin,
'-o', path.join(outDir, 'handler'), [
path.join(entrypointDirname, mainGoFileName), downloadedFiles[entrypoint].fsPath, 'build',
], { env: goEnv, cwd: entrypointDirname, stdio: 'inherit' }); '-o',
path.join(outDir, 'handler'),
path.join(entrypointDirname, mainGoFileName),
downloadedFiles[entrypoint].fsPath,
],
{ env: goEnv, cwd: entrypointDirname, stdio: 'inherit' },
);
} catch (err) { } catch (err) {
console.log('failed to `go build`'); console.log('failed to `go build`');
throw err; throw err;

View File

@@ -1,140 +1,10 @@
package main package main
import ( import (
b64 "encoding/base64" now "../../utils/go/bridge"
"encoding/json"
"fmt"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"io/ioutil"
"net"
"net/http" "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() { func main() {
l, err := net.Listen("tcp", ":0") now.Start(http.HandlerFunc(__NOW_HANDLER_FUNC_NAME))
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" {
req.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)
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/go", "name": "@now/go",
"version": "0.2.7-canary.4", "version": "0.2.11",
"scripts": { "scripts": {
"test": "best -I test/*.js", "test": "best -I test/*.js",
"prepublish": "./build.sh" "prepublish": "./build.sh"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/html-minifier", "name": "@now/html-minifier",
"version": "1.0.3-canary.4", "version": "1.0.6",
"dependencies": { "dependencies": {
"html-minifier": "3.5.21" "html-minifier": "3.5.21"
}, },

View File

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

View File

@@ -1,25 +1,12 @@
const { Lambda } = require('@now/build-utils/lambda.js'); const { Lambda } = require('@now/build-utils/lambda.js');
const path = require('path'); const streamToBuffer = require('@now/build-utils/fs/stream-to-buffer.js');
exports.build = async ({ files, entrypoint }) => { exports.build = async ({ files, entrypoint, config }) => {
if (!files[entrypoint]) throw new Error('Entrypoint not found in files'); if (!files[entrypoint]) throw new Error('Entrypoint not found in files');
const { handler, runtime } = config;
// handler=launcher.main!runtime=nodejs8.10!name.zip if (!handler) throw new Error('Handler not found in config');
const config = path.basename(entrypoint).split('!').reduce((a, c) => { if (!runtime) throw new Error('Runtime not found in config');
const [k, v] = c.split('='); const zipBuffer = await streamToBuffer(files[entrypoint].toStream());
// eslint-disable-next-line no-param-reassign const lambda = new Lambda({ zipBuffer, handler, runtime });
if (v) a[k] = v;
return a;
}, {});
if (!config.handler) throw new Error('Handler not found in config');
if (!config.runtime) throw new Error('Runtime not found in config');
const lambda = new Lambda({
zipStream: files[entrypoint].toStream(), // TODO zipBuffer
handler: config.handler,
runtime: config.runtime,
});
return { [entrypoint]: lambda }; return { [entrypoint]: lambda };
}; };

View File

@@ -1,7 +1,10 @@
{ {
"name": "@now/lambda", "name": "@now/lambda",
"version": "0.4.4-canary.4", "version": "0.4.8",
"peerDependencies": { "peerDependencies": {
"@now/build-utils": ">=0.0.1" "@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

@@ -22,12 +22,17 @@ exports.build = async ({ files, entrypoint, config }) => {
.use(markdown) .use(markdown)
.use(remark2rehype) .use(remark2rehype)
.use(doc, { .use(doc, {
title, language, meta, css, title,
language,
meta,
css,
}) })
.use(format) .use(format)
.use(html); .use(html);
const result = await FileBlob.fromStream({ stream: stream.pipe(unifiedStream(processor)) }); const result = await FileBlob.fromStream({
stream: stream.pipe(unifiedStream(processor)),
});
console.log(result.data.toString()); console.log(result.data.toString());

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/md", "name": "@now/md",
"version": "0.4.4-canary.4", "version": "0.4.8",
"dependencies": { "dependencies": {
"rehype-document": "^2.2.0", "rehype-document": "^2.2.0",
"rehype-format": "^2.3.0", "rehype-format": "^2.3.0",
@@ -12,5 +12,8 @@
}, },
"peerDependencies": { "peerDependencies": {
"@now/build-utils": ">=0.0.1" "@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

@@ -14,18 +14,24 @@ exports.build = async ({ files, entrypoint, workPath }) => {
console.log('downloading user files...'); console.log('downloading user files...');
const downloadedFiles = await download(files, workPath); const downloadedFiles = await download(files, workPath);
console.log('writing package.json...'); 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'); const packageJsonPath = path.join(workPath, 'package.json');
await writeFile(packageJsonPath, JSON.stringify(packageJson)); await writeFile(packageJsonPath, JSON.stringify(packageJson));
console.log('running npm install...'); console.log('running npm install...');
process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = '1'; // TODO opts argument for runNpmInstall process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = '1'; // TODO opts argument for runNpmInstall
await runNpmInstall(path.dirname(packageJsonPath), ['--prod', '--prefer-offline']); await runNpmInstall(path.dirname(packageJsonPath), [
'--prod',
'--prefer-offline',
]);
console.log('building...'); console.log('building...');
const outDir = await getWritableDirectory(); const outDir = await getWritableDirectory();
const entrypointFsPath = downloadedFiles[entrypoint].fsPath; const entrypointFsPath = downloadedFiles[entrypoint].fsPath;
const mountpoint = path.dirname(entrypoint); const mountpoint = path.dirname(entrypoint);
const build = require(path.join(workPath, 'node_modules/mdx-deck/lib/build.js')); const build = require(path.join(
workPath,
'node_modules/mdx-deck/lib/build.js',
));
await build({ await build({
html: true, html: true,
@@ -41,15 +47,15 @@ exports.build = async ({ files, entrypoint, workPath }) => {
exports.prepareCache = async ({ cachePath }) => { exports.prepareCache = async ({ cachePath }) => {
console.log('writing package.json...'); 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'); const packageJsonPath = path.join(cachePath, 'package.json');
await writeFile(packageJsonPath, JSON.stringify(packageJson)); await writeFile(packageJsonPath, JSON.stringify(packageJson));
console.log('running npm install...'); console.log('running npm install...');
await runNpmInstall(path.dirname(packageJsonPath), ['--prod']); await runNpmInstall(path.dirname(packageJsonPath), ['--prod']);
return { return {
...await glob('node_modules/**', cachePath), ...(await glob('node_modules/**', cachePath)),
...await glob('package-lock.json', cachePath), ...(await glob('package-lock.json', cachePath)),
...await glob('yarn.lock', cachePath), ...(await glob('yarn.lock', cachePath)),
}; };
}; };

View File

@@ -1,7 +1,10 @@
{ {
"name": "@now/mdx-deck", "name": "@now/mdx-deck",
"version": "0.4.13-canary.4", "version": "0.4.17",
"peerDependencies": { "peerDependencies": {
"@now/build-utils": ">=0.0.1" "@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

@@ -1,107 +1,110 @@
const { createLambda } = require('@now/build-utils/lambda.js'); const { createLambda } = require('@now/build-utils/lambda.js');
const download = require('@now/build-utils/fs/download.js'); const download = require('@now/build-utils/fs/download.js');
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); const FileFsRef = require('@now/build-utils/file-fs-ref.js');
const FileBlob = require('@now/build-utils/file-blob');
const path = require('path'); const path = require('path');
const { readFile, writeFile, unlink } = require('fs.promised'); const { readFile, writeFile, unlink } = require('fs.promised');
const rename = require('@now/build-utils/fs/rename.js'); const {
const { runNpmInstall, runPackageJsonScript } = require('@now/build-utils/fs/run-user-scripts.js'); runNpmInstall,
runPackageJsonScript,
} = require('@now/build-utils/fs/run-user-scripts.js');
const glob = require('@now/build-utils/fs/glob.js'); const glob = require('@now/build-utils/fs/glob.js');
const {
excludeFiles,
validateEntrypoint,
includeOnlyEntryDirectory,
moveEntryDirectoryToRoot,
excludeLockFiles,
normalizePackageJson,
excludeStaticDirectory,
onlyStaticDirectory,
} = require('./utils');
// Exclude certain files from the files object /** @typedef { import('@now/build-utils/file-ref').Files } Files */
function excludeFiles(files, matchFn) { /** @typedef { import('@now/build-utils/fs/download').DownloadedFiles } DownloadedFiles */
return Object.keys(files).reduce((newFiles, fileName) => {
if (matchFn(fileName)) {
return newFiles;
}
return {
...newFiles,
[fileName]: files[fileName],
};
}, {});
}
function shouldExcludeFile(entryDirectory) { /**
return (file) => { * @typedef {Object} BuildParamsType
// If the file is not in the entry directory * @property {Files} files - Files object
if (entryDirectory !== '.' && !file.startsWith(entryDirectory)) { * @property {string} entrypoint - Entrypoint specified for the builder
return true; * @property {string} workPath - Working directory for this build
} */
// Exclude static directory /**
if (file.startsWith(path.join(entryDirectory, 'static'))) { * Read package.json from files
return true; * @param {DownloadedFiles} files
} */
async function readPackageJson(files) {
if (file === 'package-lock.json') { if (!files['package.json']) {
return true; return {};
}
if (file === 'yarn.lock') {
return true;
}
return false;
};
}
exports.build = async ({ files, workPath, entrypoint }) => {
if (!/package\.json$/.exec(entrypoint) && !/next\.config\.js$/.exec(entrypoint)) {
throw new Error('Specified "src" for "@now/next" has to be "package.json" or "next.config.js"');
} }
const packageJsonPath = files['package.json'].fsPath;
return JSON.parse(await readFile(packageJsonPath, 'utf8'));
}
/**
* Write package.json
* @param {string} workPath
* @param {Object} packageJson
*/
async function writePackageJson(workPath, packageJson) {
await writeFile(
path.join(workPath, 'package.json'),
JSON.stringify(packageJson, null, 2),
);
}
/**
* Write .npmrc with npm auth token
* @param {string} workPath
* @param {string} token
*/
async function writeNpmRc(workPath, token) {
await writeFile(
path.join(workPath, '.npmrc'),
`//registry.npmjs.org/:_authToken=${token}`,
);
}
exports.config = {
maxLambdaSize: '5mb',
};
/**
* @param {BuildParamsType} buildParams
* @returns {Promise<Files>}
*/
exports.build = async ({ files, workPath, entrypoint }) => {
validateEntrypoint(entrypoint);
console.log('downloading user files...'); console.log('downloading user files...');
const entryDirectory = path.dirname(entrypoint); const entryDirectory = path.dirname(entrypoint);
const filesToDownload = excludeFiles(files, shouldExcludeFile(entryDirectory)); const filesOnlyEntryDirectory = includeOnlyEntryDirectory(
const entrypointHandledFilesToDownload = rename(filesToDownload, (file) => { files,
if (entryDirectory !== '.') { entryDirectory,
return file.replace(new RegExp(`^${entryDirectory}/`), ''); );
} const filesWithEntryDirectoryRoot = moveEntryDirectoryToRoot(
return file; filesOnlyEntryDirectory,
}); entryDirectory,
let downloadedFiles = await download(entrypointHandledFilesToDownload, workPath); );
const filesWithoutLockfiles = excludeLockFiles(filesWithEntryDirectoryRoot);
const filesWithoutStaticDirectory = excludeStaticDirectory(
filesWithoutLockfiles,
);
const downloadedFiles = await download(filesWithoutStaticDirectory, workPath);
let packageJson = {}; console.log('normalizing package.json');
if (downloadedFiles['package.json']) { const packageJson = normalizePackageJson(
console.log('found package.json, overwriting'); await readPackageJson(downloadedFiles),
const packageJsonPath = downloadedFiles['package.json'].fsPath; );
packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')); console.log('normalized package.json result: ', packageJson);
} await writePackageJson(workPath, packageJson);
packageJson = {
...packageJson,
dependencies: {
...packageJson.dependencies,
'next-server': 'canary',
},
devDependencies: {
...packageJson.devDependencies,
next: 'canary',
},
scripts: {
...packageJson.scripts,
'now-build': 'next build',
},
};
if (!packageJson.dependencies.react) {
console.log('"react" not found in dependencies, adding to "package.json" "dependencies"');
packageJson.dependencies.react = 'latest';
}
if (!packageJson.dependencies['react-dom']) {
console.log('"react-dom" not found in dependencies, adding to "package.json" "dependencies"');
packageJson.dependencies['react-dom'] = 'latest';
}
// in case the user has `next` on their `dependencies`, we remove it
delete packageJson.dependencies.next;
await writeFile(path.join(workPath, 'package.json'), JSON.stringify(packageJson, null, 2));
if (process.env.NPM_AUTH_TOKEN) { if (process.env.NPM_AUTH_TOKEN) {
console.log('found NPM_AUTH_TOKEN in environement, creating .npmrc'); console.log('found NPM_AUTH_TOKEN in environment, creating .npmrc');
await writeFile(path.join(workPath, '.npmrc'), `//registry.npmjs.org/:_authToken=${process.env.NPM_AUTH_TOKEN}`); await writeNpmRc(workPath, process.env.NPM_AUTH_TOKEN);
} }
downloadedFiles = await glob('**', workPath);
console.log('running npm install...'); console.log('running npm install...');
await runNpmInstall(workPath, ['--prefer-offline']); await runNpmInstall(workPath, ['--prefer-offline']);
@@ -112,78 +115,145 @@ exports.build = async ({ files, workPath, entrypoint }) => {
if (process.env.NPM_AUTH_TOKEN) { if (process.env.NPM_AUTH_TOKEN) {
await unlink(path.join(workPath, '.npmrc')); await unlink(path.join(workPath, '.npmrc'));
} }
downloadedFiles = await glob('**', workPath);
const filesAfterBuild = await glob('**', workPath);
console.log('preparing lambda files...'); console.log('preparing lambda files...');
let buildId; let buildId;
try { try {
buildId = await readFile(path.join(workPath, '.next', 'BUILD_ID'), 'utf8'); buildId = await readFile(path.join(workPath, '.next', 'BUILD_ID'), 'utf8');
} catch (err) { } catch (err) {
console.error('BUILD_ID not found in ".next". The "package.json" "build" script did not run "next build"'); console.error(
'BUILD_ID not found in ".next". The "package.json" "build" script did not run "next build"',
);
throw new Error('Missing BUILD_ID'); throw new Error('Missing BUILD_ID');
} }
const dotNextRootFiles = await glob('.next/*', workPath); const dotNextRootFiles = await glob('.next/*', workPath);
const dotNextServerRootFiles = await glob('.next/server/*', workPath); const dotNextServerRootFiles = await glob('.next/server/*', workPath);
const nodeModules = excludeFiles(await glob('node_modules/**', workPath), file => file.startsWith('node_modules/.cache')); const nodeModules = excludeFiles(
await glob('node_modules/**', workPath),
file => file.startsWith('node_modules/.cache'),
);
const launcherFiles = { const launcherFiles = {
'now__launcher.js': new FileFsRef({ fsPath: path.join(__dirname, 'launcher.js') }),
'now__bridge.js': new FileFsRef({ fsPath: require('@now/node-bridge') }), 'now__bridge.js': new FileFsRef({ fsPath: require('@now/node-bridge') }),
}; };
const nextFiles = { const nextFiles = {
...nodeModules, ...dotNextRootFiles, ...dotNextServerRootFiles, ...launcherFiles, ...nodeModules,
...dotNextRootFiles,
...dotNextServerRootFiles,
...launcherFiles,
}; };
if (downloadedFiles['next.config.js']) { if (filesAfterBuild['next.config.js']) {
nextFiles['next.config.js'] = downloadedFiles['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 pages = await glob(
'**/*.js',
path.join(workPath, '.next', 'server', 'static', buildId, 'pages'),
);
const launcherPath = path.join(__dirname, 'launcher.js');
const launcherData = await readFile(launcherPath, 'utf8');
const lambdas = {}; const lambdas = {};
await Promise.all(Object.keys(pages).map(async (page) => { await Promise.all(
// These default pages don't have to be handled as they'd always 404 Object.keys(pages).map(async (page) => {
if (['_app.js', '_error.js', '_document.js'].includes(page)) { // These default pages don't have to be handled as they'd always 404
return; if (['_app.js', '_error.js', '_document.js'].includes(page)) {
} return;
}
const pageFiles = { const pathname = page.replace(/\.js$/, '');
[`.next/server/static/${buildId}/pages/_document.js`]: downloadedFiles[`.next/server/static/${buildId}/pages/_document.js`], const launcher = launcherData.replace(
[`.next/server/static/${buildId}/pages/_app.js`]: downloadedFiles[`.next/server/static/${buildId}/pages/_app.js`], 'PATHNAME_PLACEHOLDER',
[`.next/server/static/${buildId}/pages/_error.js`]: downloadedFiles[`.next/server/static/${buildId}/pages/_error.js`], `/${pathname.replace(/(^|\/)index$/, '')}`,
[`.next/server/static/${buildId}/pages/${page}`]: downloadedFiles[`.next/server/static/${buildId}/pages/${page}`], );
};
lambdas[path.join(entryDirectory, page.replace(/\.js$/, ''))] = await createLambda({ const pageFiles = {
files: { ...nextFiles, ...pageFiles }, [`.next/server/static/${buildId}/pages/_document.js`]: filesAfterBuild[
handler: 'now__launcher.launcher', `.next/server/static/${buildId}/pages/_document.js`
runtime: 'nodejs8.10', ],
}); [`.next/server/static/${buildId}/pages/_app.js`]: filesAfterBuild[
})); `.next/server/static/${buildId}/pages/_app.js`
],
[`.next/server/static/${buildId}/pages/_error.js`]: filesAfterBuild[
`.next/server/static/${buildId}/pages/_error.js`
],
[`.next/server/static/${buildId}/pages/${page}`]: filesAfterBuild[
`.next/server/static/${buildId}/pages/${page}`
],
};
const nextStaticFiles = await glob('**', path.join(workPath, '.next', 'static')); console.log(`Creating lambda for page: "${page}"...`);
const staticFiles = Object.keys(nextStaticFiles).reduce((mappedFiles, file) => ({ lambdas[path.join(entryDirectory, pathname)] = await createLambda({
...mappedFiles, files: {
[path.join(entryDirectory, `_next/static/${file}`)]: nextStaticFiles[file], ...nextFiles,
}), {}); ...pageFiles,
'now__launcher.js': new FileBlob({ data: launcher }),
},
handler: 'now__launcher.launcher',
runtime: 'nodejs8.10',
});
console.log(`Created lambda for page: "${page}"`);
}),
);
return { ...lambdas, ...staticFiles }; const nextStaticFiles = await glob(
'**',
path.join(workPath, '.next', 'static'),
);
const staticFiles = Object.keys(nextStaticFiles).reduce(
(mappedFiles, file) => ({
...mappedFiles,
[path.join(entryDirectory, `_next/static/${file}`)]: nextStaticFiles[file],
}),
{},
);
const nextStaticDirectory = onlyStaticDirectory(filesWithoutLockfiles);
const staticDirectoryFiles = Object.keys(nextStaticDirectory).reduce(
(mappedFiles, file) => ({
...mappedFiles,
[path.join(entryDirectory, file)]: nextStaticDirectory[file],
}),
{},
);
return { ...lambdas, ...staticFiles, ...staticDirectoryFiles };
}; };
exports.prepareCache = async ({ files, cachePath, workPath }) => { exports.prepareCache = async ({
files, entrypoint, cachePath, workPath,
}) => {
console.log('downloading user files...'); console.log('downloading user files...');
await download(files, cachePath); const entryDirectory = path.dirname(entrypoint);
const filesOnlyEntryDirectory = includeOnlyEntryDirectory(
files,
entryDirectory,
);
const filesWithEntryDirectoryRoot = moveEntryDirectoryToRoot(
filesOnlyEntryDirectory,
entryDirectory,
);
const filesWithoutLockfiles = excludeLockFiles(filesWithEntryDirectoryRoot);
const filesWithoutStaticDirectory = excludeStaticDirectory(
filesWithoutLockfiles,
);
await download(filesWithoutStaticDirectory, workPath);
await download(await glob('.next/**', workPath), cachePath); await download(await glob('.next/**', workPath), cachePath);
await download(await glob('node_modules/**', workPath), cachePath); await download(await glob('node_modules/**', workPath), cachePath);
console.log('.next folder contents', await glob('.next/**', cachePath)); console.log('.next folder contents', await glob('.next/**', cachePath));
console.log('.cache folder contents', await glob('node_modules/.cache/**', cachePath)); console.log(
'.cache folder contents',
await glob('node_modules/.cache/**', cachePath),
);
console.log('running npm install...'); console.log('running npm install...');
await runNpmInstall(cachePath); await runNpmInstall(cachePath);
return { return {
...await glob('.next/records.json', cachePath), ...(await glob('.next/records.json', cachePath)),
...await glob('.next/server/records.json', cachePath), ...(await glob('.next/server/records.json', cachePath)),
...await glob('node_modules/**', cachePath), ...(await glob('node_modules/**', cachePath)),
...await glob('yarn.lock', cachePath), ...(await glob('yarn.lock', cachePath)),
}; };
}; };

View File

@@ -1,5 +1,6 @@
const { Server } = require('http'); const { Server } = require('http');
const next = require('next-server'); const next = require('next-server');
const url = require('url');
const { Bridge } = require('./now__bridge.js'); const { Bridge } = require('./now__bridge.js');
const bridge = new Bridge(); const bridge = new Bridge();
@@ -8,9 +9,11 @@ bridge.port = 3000;
process.env.NODE_ENV = 'production'; process.env.NODE_ENV = 'production';
const app = next({}); const app = next({});
const handler = app.getRequestHandler();
const server = new Server(handler); 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); server.listen(bridge.port);
exports.launcher = bridge.launcher; exports.launcher = bridge.launcher;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/next", "name": "@now/next",
"version": "0.0.74-canary.4", "version": "0.0.81",
"dependencies": { "dependencies": {
"@now/node-bridge": "0.1.4", "@now/node-bridge": "0.1.4",
"execa": "^1.0.0", "execa": "^1.0.0",

181
packages/now-next/utils.js Normal file
View File

@@ -0,0 +1,181 @@
const rename = require('@now/build-utils/fs/rename.js');
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
/** @typedef { import('@now/build-utils/file-fs-ref') } FileFsRef */
/** @typedef {{[filePath: string]: FileRef|FileFsRef}} Files */
/**
* Validate if the entrypoint is allowed to be used
* @param {string} entrypoint
* @throws {Error}
*/
function validateEntrypoint(entrypoint) {
if (
!/package\.json$/.exec(entrypoint)
&& !/next\.config\.js$/.exec(entrypoint)
) {
throw new Error(
'Specified "src" for "@now/next" has to be "package.json" or "next.config.js"',
);
}
}
/**
* This callback type is called `requestCallback` and is displayed as a global symbol.
*
* @callback matcher
* @param {string} filePath
* @returns {boolean}
*/
/**
* Exclude certain files from the files object
* @param {Files} files
* @param {matcher} matcher
* @returns {Files}
*/
function excludeFiles(files, matcher) {
return Object.keys(files).reduce((newFiles, filePath) => {
if (matcher(filePath)) {
return newFiles;
}
return {
...newFiles,
[filePath]: files[filePath],
};
}, {});
}
/**
* Creates a new Files object holding only the entrypoint files
* @param {Files} files
* @param {string} entryDirectory
* @returns {Files}
*/
function includeOnlyEntryDirectory(files, entryDirectory) {
if (entryDirectory === '.') {
return files;
}
function matcher(filePath) {
return !filePath.startsWith(entryDirectory);
}
return excludeFiles(files, matcher);
}
/**
* Moves all files under the entry directory to the root directory
* @param {Files} files
* @param {string} entryDirectory
* @returns {Files}
*/
function moveEntryDirectoryToRoot(files, entryDirectory) {
if (entryDirectory === '.') {
return files;
}
function delegate(filePath) {
return filePath.replace(new RegExp(`^${entryDirectory}/`), '');
}
return rename(files, delegate);
}
/**
* Exclude package manager lockfiles from files
* @param {Files} files
* @returns {Files}
*/
function excludeLockFiles(files) {
const newFiles = files;
if (newFiles['package-lock.json']) {
delete newFiles['package-lock.json'];
}
if (newFiles['yarn.lock']) {
delete newFiles['yarn.lock'];
}
return files;
}
/**
* Exclude the static directory from files
* @param {Files} files
* @returns {Files}
*/
function excludeStaticDirectory(files) {
function matcher(filePath) {
return filePath.startsWith('static');
}
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
*/
function normalizePackageJson(defaultPackageJson = {}) {
const dependencies = {};
const devDependencies = {
...defaultPackageJson.dependencies,
...defaultPackageJson.devDependencies,
};
if (devDependencies.react) {
dependencies.react = devDependencies.react;
delete devDependencies.react;
}
if (devDependencies['react-dom']) {
dependencies['react-dom'] = devDependencies['react-dom'];
delete devDependencies['react-dom'];
}
return {
...defaultPackageJson,
dependencies: {
// react and react-dom can be overwritten
react: 'latest',
'react-dom': 'latest',
...dependencies, // override react if user provided it
// next-server is forced to canary
'next-server': 'canary',
},
devDependencies: {
...devDependencies,
// next is forced to canary
next: 'canary',
// next-server is a dependency here
'next-server': undefined,
},
scripts: {
...defaultPackageJson.scripts,
'now-build': 'next build --lambdas',
},
};
}
module.exports = {
excludeFiles,
validateEntrypoint,
includeOnlyEntryDirectory,
moveEntryDirectoryToRoot,
excludeLockFiles,
normalizePackageJson,
excludeStaticDirectory,
onlyStaticDirectory,
};

View File

@@ -1,16 +1,23 @@
const assert = require('assert');
const http = require('http'); const http = require('http');
function normalizeEvent(event) { function normalizeEvent(event) {
if (event.Action === 'Invoke') { if (event.Action === 'Invoke') {
const invokeEvent = JSON.parse(event.body); const invokeEvent = JSON.parse(event.body);
const { const {
method, path, headers, encoding, method, path, headers, encoding,
} = invokeEvent; } = invokeEvent;
let { body } = invokeEvent; let { body } = invokeEvent;
if (body) { if (body) {
assert(encoding === 'base64', JSON.stringify(event)); // do we support anything else? if (encoding === 'base64') {
body = Buffer.from(body, encoding); body = Buffer.from(body, encoding);
} else if (encoding === undefined) {
body = Buffer.from(body);
} else {
throw new Error(`Unsupported encoding: ${encoding}`);
}
} }
return { return {
@@ -22,10 +29,7 @@ function normalizeEvent(event) {
} }
const { const {
httpMethod: method, httpMethod: method, path, headers, body,
path,
headers,
body,
} = event; } = event;
return { return {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/node-bridge", "name": "@now/node-bridge",
"version": "0.1.6-canary.4", "version": "0.1.9",
"peerDependencies": { "peerDependencies": {
"@now/build-utils": ">=0.0.1" "@now/build-utils": ">=0.0.1"
} }

View File

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

View File

@@ -2,113 +2,129 @@ const { createLambda } = require('@now/build-utils/lambda.js');
const download = require('@now/build-utils/fs/download.js'); const download = require('@now/build-utils/fs/download.js');
const FileBlob = require('@now/build-utils/file-blob.js'); const FileBlob = require('@now/build-utils/file-blob.js');
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); const FileFsRef = require('@now/build-utils/file-fs-ref.js');
const fs = require('fs'); const fs = require('fs-extra');
const glob = require('@now/build-utils/fs/glob.js'); const glob = require('@now/build-utils/fs/glob.js');
const path = require('path'); const path = require('path');
const { promisify } = require('util'); const rename = require('@now/build-utils/fs/rename.js');
const { runNpmInstall, runPackageJsonScript } = require('@now/build-utils/fs/run-user-scripts.js'); const {
runNpmInstall,
runPackageJsonScript,
} = require('@now/build-utils/fs/run-user-scripts.js');
const fsp = { /** @typedef { import('@now/build-utils/file-ref') } FileRef */
readFile: promisify(fs.readFile), /** @typedef {{[filePath: string]: FileRef}} Files */
};
async function commonForTwo({ /**
files, entrypoint, workPath, cachePath, * @typedef {Object} BuildParamsType
}) { * @property {Files} files - Files object
const xPath = workPath || cachePath; * @property {string} entrypoint - Entrypoint specified for the builder
const preferOfflineArgument = workPath ? ['--prefer-offline'] : []; * @property {Object} config - User-passed config from now.json
* @property {string} workPath - Working directory for this build
*/
const xUserPath = path.join(xPath, 'user'); /**
const xRollupPath = path.join(xPath, 'rollup'); * @param {BuildParamsType} buildParams
* @param {Object} [options]
* @param {string[]} [options.npmArguments]
*/
async function downloadInstallAndBundle(
{ files, entrypoint, workPath },
{ npmArguments = [] } = {},
) {
const userPath = path.join(workPath, 'user');
const nccPath = path.join(workPath, 'ncc');
console.log('downloading user files...'); console.log('downloading user files...');
const filesOnDisk = await download(files, xUserPath); const downloadedFiles = await download(files, userPath);
console.log('running npm install for user...'); console.log('running npm install for user...');
const entrypointFsDirname = path.join(xUserPath, path.dirname(entrypoint)); const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
await runNpmInstall(entrypointFsDirname, preferOfflineArgument); await runNpmInstall(entrypointFsDirname, npmArguments);
console.log('writing rollup package.json...'); console.log('writing ncc package.json...');
await download({ await download(
'package.json': new FileBlob({ {
data: JSON.stringify({ 'package.json': new FileBlob({
dependencies: { data: JSON.stringify({
builtins: '2.0.0', dependencies: {
rollup: '0.67.0', '@zeit/ncc': '0.4.1',
'rollup-plugin-commonjs': '9.2.0', },
'rollup-plugin-json': '3.1.0', }),
'rollup-plugin-node-resolve': '3.4.0',
'rollup-plugin-terser': '3.0.0',
},
}), }),
}),
}, xRollupPath);
console.log('running npm install for rollup...');
await runNpmInstall(xRollupPath, preferOfflineArgument);
return [filesOnDisk, xRollupPath, entrypointFsDirname];
}
async function compile(workRollupPath, input) {
const rollup = require(path.join(workRollupPath, 'node_modules/rollup'));
const nodeResolve = require(path.join(workRollupPath, 'node_modules/rollup-plugin-node-resolve'));
const commonjs = require(path.join(workRollupPath, 'node_modules/rollup-plugin-commonjs'));
const json = require(path.join(workRollupPath, 'node_modules/rollup-plugin-json'));
const { terser } = require(path.join(workRollupPath, 'node_modules/rollup-plugin-terser'));
const builtins = require(path.join(workRollupPath, 'node_modules/builtins'))();
const bundle = await rollup.rollup({
input,
plugins: [
nodeResolve({
module: false,
jsnext: false,
browser: false,
preferBuiltins: true,
}),
json(),
commonjs(),
terser(),
],
onwarn(error) {
if (/external dependency/.test(error.message)) {
const mod = error.message.split('\'')[1];
// ignore rollup warnings about known node.js modules
if (builtins.indexOf(mod) > -1) return;
}
console.error(error.message);
}, },
}); nccPath,
);
return (await bundle.generate({ console.log('running npm install for ncc...');
format: 'cjs', await runNpmInstall(nccPath, npmArguments);
})).code; return [downloadedFiles, userPath, nccPath, entrypointFsDirname];
} }
exports.build = async ({ files, entrypoint, workPath }) => { async function compile(workNccPath, downloadedFiles, entrypoint) {
const input = downloadedFiles[entrypoint].fsPath;
const ncc = require(path.join(workNccPath, 'node_modules/@zeit/ncc'));
const { code, assets } = await ncc(input);
const preparedFiles = {};
const blob = new FileBlob({ data: code });
// move all user code to 'user' subdirectory
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] });
preparedFiles[
path.join('user', path.dirname(entrypoint), assetName)
] = blob2;
}
return preparedFiles;
}
exports.config = {
maxLambdaSize: '15mb',
};
/**
* @param {BuildParamsType} buildParams
* @returns {Promise<Files>}
*/
exports.build = async ({
files, entrypoint, config, workPath,
}) => {
const [ const [
filesOnDisk, downloadedFiles,
workRollupPath, workUserPath,
workNccPath,
entrypointFsDirname, entrypointFsDirname,
] = await commonForTwo({ files, entrypoint, workPath }); ] = await downloadInstallAndBundle(
{ files, entrypoint, workPath },
{ npmArguments: ['--prefer-offline'] },
);
console.log('running user script...'); console.log('running user script...');
await runPackageJsonScript(entrypointFsDirname, 'now-build'); await runPackageJsonScript(entrypointFsDirname, 'now-build');
console.log('compiling entrypoint with rollup...');
const data = await compile(workRollupPath, filesOnDisk[entrypoint].fsPath);
const blob = new FileBlob({ data });
console.log('preparing lambda files...'); console.log('preparing lambda files...');
// move all user code to 'user' subdirectory let preparedFiles;
const compiledFiles = { [path.join('user', entrypoint)]: blob };
const launcherPath = path.join(__dirname, 'launcher.js');
let launcherData = await fsp.readFile(launcherPath, 'utf8');
launcherData = launcherData.replace('// PLACEHOLDER', [ if (config && config.bundle === false) {
'process.chdir("./user");', // move all user code to 'user' subdirectory
`require("./${path.join('user', entrypoint)}");`, preparedFiles = await glob('**', workUserPath);
].join(' ')); preparedFiles = rename(preparedFiles, name => path.join('user', name));
} else {
console.log('compiling entrypoint with ncc...');
preparedFiles = await compile(workNccPath, downloadedFiles, entrypoint);
}
const launcherPath = path.join(__dirname, 'launcher.js');
let launcherData = await fs.readFile(launcherPath, 'utf8');
launcherData = launcherData.replace(
'// PLACEHOLDER',
[
'process.chdir("./user");',
`require("./${path.join('user', entrypoint)}");`,
].join(' '),
);
const launcherFiles = { const launcherFiles = {
'launcher.js': new FileBlob({ data: launcherData }), 'launcher.js': new FileBlob({ data: launcherData }),
@@ -116,7 +132,7 @@ exports.build = async ({ files, entrypoint, workPath }) => {
}; };
const lambda = await createLambda({ const lambda = await createLambda({
files: { ...compiledFiles, ...launcherFiles }, files: { ...preparedFiles, ...launcherFiles },
handler: 'launcher.launcher', handler: 'launcher.launcher',
runtime: 'nodejs8.10', runtime: 'nodejs8.10',
}); });
@@ -124,15 +140,18 @@ exports.build = async ({ files, entrypoint, workPath }) => {
return { [entrypoint]: lambda }; return { [entrypoint]: lambda };
}; };
exports.prepareCache = async ({ files, entrypoint, cachePath }) => { exports.prepareCache = async ({
await commonForTwo({ files, entrypoint, cachePath }); files, entrypoint, workPath, cachePath,
}) => {
await fs.remove(workPath);
await downloadInstallAndBundle({ files, entrypoint, workPath: cachePath });
return { return {
...await glob('user/node_modules/**', cachePath), ...(await glob('user/node_modules/**', cachePath)),
...await glob('user/package-lock.json', cachePath), ...(await glob('user/package-lock.json', cachePath)),
...await glob('user/yarn.lock', cachePath), ...(await glob('user/yarn.lock', cachePath)),
...await glob('rollup/node_modules/**', cachePath), ...(await glob('ncc/node_modules/**', cachePath)),
...await glob('rollup/package-lock.json', cachePath), ...(await glob('ncc/package-lock.json', cachePath)),
...await glob('rollup/yarn.lock', cachePath), ...(await glob('ncc/yarn.lock', cachePath)),
}; };
}; };

View File

@@ -1,10 +1,14 @@
{ {
"name": "@now/node-server", "name": "@now/node-server",
"version": "0.4.21-canary.4", "version": "0.4.25",
"dependencies": { "dependencies": {
"@now/node-bridge": "^0.1.6-canary.4" "@now/node-bridge": "^0.1.9",
"fs-extra": "7.0.1"
}, },
"peerDependencies": { "peerDependencies": {
"@now/build-utils": ">=0.0.1" "@now/build-utils": ">=0.0.1"
},
"scripts": {
"test": "jest"
} }
} }

View File

@@ -0,0 +1,11 @@
const cowsay = require('cowsay/build/cowsay.umd.js').say;
const http = require('http');
// test that process.env is not replaced by webpack
process.env.NODE_ENV = 'development';
const server = http.createServer((req, resp) => {
resp.end(cowsay({ text: 'cow:RANDOMNESS_PLACEHOLDER' }));
});
server.listen();

View File

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

View File

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

View File

@@ -0,0 +1,11 @@
const yodasay = require('yodasay/build/yodasay.umd.js').say;
const http = require('http');
// test that process.env is not replaced by webpack
process.env.NODE_ENV = 'development';
const server = http.createServer((req, resp) => {
resp.end(yodasay({ text: 'yoda:RANDOMNESS_PLACEHOLDER' }));
});
server.listen();

View File

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

View File

@@ -0,0 +1,10 @@
const assert = require('assert');
const http = require('http');
const server = http.createServer((req, resp) => {
assert(!process.env.RANDOMNESS_BUILD_ENV_VAR);
assert(process.env.RANDOMNESS_ENV_VAR);
resp.end('BUILD_TIME_PLACEHOLDER:build-env');
});
server.listen();

View File

@@ -0,0 +1,12 @@
const assert = require('assert');
const fs = require('fs');
assert(process.env.RANDOMNESS_BUILD_ENV_VAR);
assert(!process.env.RANDOMNESS_ENV_VAR);
fs.writeFileSync(
'index.js',
fs
.readFileSync('index.js', 'utf8')
.replace('BUILD_TIME_PLACEHOLDER', process.env.RANDOMNESS_BUILD_ENV_VAR),
);

View File

@@ -0,0 +1,5 @@
{
"scripts": {
"now-build": "node now-build.js"
}
}

View File

@@ -0,0 +1,10 @@
const assert = require('assert');
const http = require('http');
const server = http.createServer((req, resp) => {
assert(!process.env.RANDOMNESS_BUILD_ENV_VAR);
assert(process.env.RANDOMNESS_ENV_VAR);
resp.end(`${process.env.RANDOMNESS_ENV_VAR}:env`);
});
server.listen();

View File

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

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

@@ -0,0 +1,11 @@
{
"version": 2,
"builds": [
{ "src": "with-bundle/index.js", "use": "@now/node-server" },
{ "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" }
]
}

View File

@@ -0,0 +1,8 @@
const http = require('http');
const isBundled = require('./is-bundled.js');
const server = http.createServer((req, resp) => {
resp.end(isBundled() ? 'RANDOMNESS_PLACEHOLDER' : '');
});
server.listen();

View File

@@ -0,0 +1,3 @@
const path = require('path');
module.exports = () => path.basename(__filename) === 'index.js';

View File

@@ -0,0 +1,8 @@
const http = require('http');
const isBundled = require('./is-bundled.js');
const server = http.createServer((req, resp) => {
resp.end(isBundled() ? '' : 'RANDOMNESS_PLACEHOLDER');
});
server.listen();

View File

@@ -0,0 +1,3 @@
const path = require('path');
module.exports = () => path.basename(__filename) === 'index.js';

View File

@@ -0,0 +1,24 @@
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');
const typeDefs = gql`
type Query {
hello: String
}
`;
const resolvers = {
Query: {
hello: () => 'apollo:RANDOMNESS_PLACEHOLDER',
},
};
const server = new ApolloServer({ typeDefs, resolvers, introspection: true });
const app = express();
server.applyMiddleware({ app });
app.get('/', (req, resp) => {
resp.redirect('/graphql');
});
app.listen({ port: 4000 });

View File

@@ -0,0 +1,7 @@
{
"dependencies": {
"apollo-server-express": "^2.2.2",
"express": "^4.16.4",
"graphql": "^14.0.2"
}
}

View File

@@ -0,0 +1,12 @@
{
"version": 2,
"builds": [
{ "src": "apollo/index.js", "use": "@now/node-server" }
],
"routes": [
{ "src": "/.*", "dest": "apollo/index.js" }
],
"probes": [
{ "path": "/graphql", "method": "POST", "body": { "query": "{hello}" }, "mustContain": "apollo:RANDOMNESS_PLACEHOLDER" }
]
}

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

@@ -2,113 +2,116 @@ const { createLambda } = require('@now/build-utils/lambda.js');
const download = require('@now/build-utils/fs/download.js'); const download = require('@now/build-utils/fs/download.js');
const FileBlob = require('@now/build-utils/file-blob.js'); const FileBlob = require('@now/build-utils/file-blob.js');
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); const FileFsRef = require('@now/build-utils/file-fs-ref.js');
const fs = require('fs'); const fs = require('fs-extra');
const glob = require('@now/build-utils/fs/glob.js'); const glob = require('@now/build-utils/fs/glob.js');
const path = require('path'); const path = require('path');
const { promisify } = require('util'); const {
const { runNpmInstall, runPackageJsonScript } = require('@now/build-utils/fs/run-user-scripts.js'); runNpmInstall,
runPackageJsonScript,
} = require('@now/build-utils/fs/run-user-scripts.js');
const fsp = { /** @typedef { import('@now/build-utils/file-ref') } FileRef */
readFile: promisify(fs.readFile), /** @typedef {{[filePath: string]: FileRef}} Files */
};
async function commonForTwo({ /**
files, entrypoint, workPath, cachePath, * @typedef {Object} BuildParamsType
}) { * @property {Files} files - Files object
const xPath = workPath || cachePath; * @property {string} entrypoint - Entrypoint specified for the builder
const preferOfflineArgument = workPath ? ['--prefer-offline'] : []; * @property {string} workPath - Working directory for this build
*/
const xUserPath = path.join(xPath, 'user'); /**
const xRollupPath = path.join(xPath, 'rollup'); * @param {BuildParamsType} buildParams
* @param {Object} [options]
* @param {string[]} [options.npmArguments]
*/
async function downloadInstallAndBundle(
{ files, entrypoint, workPath },
{ npmArguments = [] } = {},
) {
const userPath = path.join(workPath, 'user');
const nccPath = path.join(workPath, 'ncc');
console.log('downloading user files...'); console.log('downloading user files...');
const filesOnDisk = await download(files, xUserPath); const downloadedFiles = await download(files, userPath);
console.log('running npm install for user...'); console.log('running npm install for user...');
const entrypointFsDirname = path.join(xUserPath, path.dirname(entrypoint)); const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
await runNpmInstall(entrypointFsDirname, preferOfflineArgument); await runNpmInstall(entrypointFsDirname, npmArguments);
console.log('writing rollup package.json...'); console.log('writing ncc package.json...');
await download({ await download(
'package.json': new FileBlob({ {
data: JSON.stringify({ 'package.json': new FileBlob({
dependencies: { data: JSON.stringify({
builtins: '2.0.0', dependencies: {
rollup: '0.67.0', '@zeit/ncc': '0.4.1',
'rollup-plugin-commonjs': '9.2.0', },
'rollup-plugin-json': '3.1.0', }),
'rollup-plugin-node-resolve': '3.4.0',
'rollup-plugin-terser': '3.0.0',
},
}), }),
}),
}, xRollupPath);
console.log('running npm install for rollup...');
await runNpmInstall(xRollupPath, preferOfflineArgument);
return [filesOnDisk, xRollupPath, entrypointFsDirname];
}
async function compile(workRollupPath, input) {
const rollup = require(path.join(workRollupPath, 'node_modules/rollup'));
const nodeResolve = require(path.join(workRollupPath, 'node_modules/rollup-plugin-node-resolve'));
const commonjs = require(path.join(workRollupPath, 'node_modules/rollup-plugin-commonjs'));
const json = require(path.join(workRollupPath, 'node_modules/rollup-plugin-json'));
const { terser } = require(path.join(workRollupPath, 'node_modules/rollup-plugin-terser'));
const builtins = require(path.join(workRollupPath, 'node_modules/builtins'))();
const bundle = await rollup.rollup({
input,
plugins: [
nodeResolve({
module: false,
jsnext: false,
browser: false,
preferBuiltins: true,
}),
json(),
commonjs(),
terser(),
],
onwarn(error) {
if (/external dependency/.test(error.message)) {
const mod = error.message.split('\'')[1];
// ignore rollup warnings about known node.js modules
if (builtins.indexOf(mod) > -1) return;
}
console.error(error.message);
}, },
}); nccPath,
);
return (await bundle.generate({ console.log('running npm install for ncc...');
format: 'cjs', await runNpmInstall(nccPath, npmArguments);
})).code; return [downloadedFiles, nccPath, entrypointFsDirname];
} }
async function compile(workNccPath, downloadedFiles, entrypoint) {
const input = downloadedFiles[entrypoint].fsPath;
const ncc = require(path.join(workNccPath, 'node_modules/@zeit/ncc'));
const { code, assets } = await ncc(input);
const preparedFiles = {};
const blob = new FileBlob({ data: code });
// move all user code to 'user' subdirectory
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] });
preparedFiles[
path.join('user', path.dirname(entrypoint), assetName)
] = blob2;
}
return preparedFiles;
}
exports.config = {
maxLambdaSize: '5mb',
};
/**
* @param {BuildParamsType} buildParams
* @returns {Promise<Files>}
*/
exports.build = async ({ files, entrypoint, workPath }) => { exports.build = async ({ files, entrypoint, workPath }) => {
const [ const [
filesOnDisk, downloadedFiles,
workRollupPath, workNccPath,
entrypointFsDirname, entrypointFsDirname,
] = await commonForTwo({ files, entrypoint, workPath }); ] = await downloadInstallAndBundle(
{ files, entrypoint, workPath },
{ npmArguments: ['--prefer-offline'] },
);
console.log('running user script...'); console.log('running user script...');
await runPackageJsonScript(entrypointFsDirname, 'now-build'); await runPackageJsonScript(entrypointFsDirname, 'now-build');
console.log('compiling entrypoint with rollup...'); console.log('compiling entrypoint with ncc...');
const data = await compile(workRollupPath, filesOnDisk[entrypoint].fsPath); const preparedFiles = await compile(workNccPath, downloadedFiles, entrypoint);
const blob = new FileBlob({ data });
console.log('preparing lambda files...');
// move all user code to 'user' subdirectory
const compiledFiles = { [path.join('user', entrypoint)]: blob };
const launcherPath = path.join(__dirname, 'launcher.js'); const launcherPath = path.join(__dirname, 'launcher.js');
let launcherData = await fsp.readFile(launcherPath, 'utf8'); let launcherData = await fs.readFile(launcherPath, 'utf8');
launcherData = launcherData.replace('// PLACEHOLDER', [ launcherData = launcherData.replace(
'process.chdir("./user");', '// PLACEHOLDER',
`listener = require("./${path.join('user', entrypoint)}");`, [
].join(' ')); 'process.chdir("./user");',
`listener = require("./${path.join('user', entrypoint)}");`,
'if (listener.default) listener = listener.default;',
].join(' '),
);
const launcherFiles = { const launcherFiles = {
'launcher.js': new FileBlob({ data: launcherData }), 'launcher.js': new FileBlob({ data: launcherData }),
@@ -116,7 +119,7 @@ exports.build = async ({ files, entrypoint, workPath }) => {
}; };
const lambda = await createLambda({ const lambda = await createLambda({
files: { ...compiledFiles, ...launcherFiles }, files: { ...preparedFiles, ...launcherFiles },
handler: 'launcher.launcher', handler: 'launcher.launcher',
runtime: 'nodejs8.10', runtime: 'nodejs8.10',
}); });
@@ -124,15 +127,18 @@ exports.build = async ({ files, entrypoint, workPath }) => {
return { [entrypoint]: lambda }; return { [entrypoint]: lambda };
}; };
exports.prepareCache = async ({ files, entrypoint, cachePath }) => { exports.prepareCache = async ({
await commonForTwo({ files, entrypoint, cachePath }); files, entrypoint, workPath, cachePath,
}) => {
await fs.remove(workPath);
await downloadInstallAndBundle({ files, entrypoint, workPath: cachePath });
return { return {
...await glob('user/node_modules/**', cachePath), ...(await glob('user/node_modules/**', cachePath)),
...await glob('user/package-lock.json', cachePath), ...(await glob('user/package-lock.json', cachePath)),
...await glob('user/yarn.lock', cachePath), ...(await glob('user/yarn.lock', cachePath)),
...await glob('rollup/node_modules/**', cachePath), ...(await glob('ncc/node_modules/**', cachePath)),
...await glob('rollup/package-lock.json', cachePath), ...(await glob('ncc/package-lock.json', cachePath)),
...await glob('rollup/yarn.lock', cachePath), ...(await glob('ncc/yarn.lock', cachePath)),
}; };
}; };

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