Compare commits

...

205 Commits

Author SHA1 Message Date
Nathan Rajlich
0b60467d2f Publish Stable
- @vercel/build-utils@2.7.0
 - vercel@21.1.0
 - @vercel/client@9.0.5
 - @vercel/go@1.1.7
 - @vercel/node-bridge@1.3.2
 - @vercel/node@1.9.0
 - @vercel/python@1.2.4
 - @vercel/routing-utils@1.9.2
 - @vercel/ruby@1.2.5
2021-01-13 17:18:43 -08:00
Nathan Rajlich
4384a6104f Publish Canary
- vercel@21.0.2-canary.10
2021-01-13 11:42:54 -08:00
Nathan Rajlich
f40f95ff37 [cli] Respect the directoryListing Project setting in vc dev (#5690)
Implements the ["Directory Listing" Project setting](https://vercel.com/changelog/listing-the-content-of-directories-can-now-be-toggled) in `vercel dev`.

The Dev integration test file has been updated to allow specifying custom Project settings that will be `PATCH`'d to the project document before running `vc deploy` / `vc dev`.
2021-01-13 15:36:12 +00:00
Nathan Rajlich
90c05250b0 Publish Canary
- vercel@21.0.2-canary.9
 - @vercel/go@1.1.7-canary.1
 - @vercel/node@1.8.6-canary.5
2021-01-12 17:47:24 -08:00
Nathan Rajlich
030880fe74 [node][go] Fix order of exit code in startDevServer() error reason (#5688) 2021-01-12 17:02:55 -08:00
Nathan Rajlich
02bc88f33b [cli] Use cmd() formatting for "npm not installed" message (#5687)
* [cli] Use `cmd()` formatting for "npm not installed" message

* Fix build
2021-01-12 17:02:36 -08:00
Nathan Rajlich
38ff557cad [cli] Skip "00-list-directory" and "temporary directory listing" tests temporarily (#5689)
* [cli] Skip "now-dev-directory-listing" test temporarily

* Disable correct tests

* Fix `vc env` test
2021-01-12 17:01:56 -08:00
Nathan Rajlich
47c34842d5 Publish Canary
- vercel@21.0.2-canary.8
 - @vercel/go@1.1.7-canary.0
 - @vercel/node@1.8.6-canary.4
 - @vercel/python@1.2.4-canary.0
 - @vercel/ruby@1.2.5-canary.0
2021-01-12 14:51:30 -08:00
Nathan Rajlich
d21b215ad0 [cli] Add error link when startDevServer() throws, and make npm not installed formatting consistent (#5684) 2021-01-12 14:47:11 -08:00
Nathan Rajlich
5827737fd5 [node][go] Better startDevServer() error message (#5674)
* [go] Better `startDevServer()` error message

* [node] Better `startDevServer()` error message

Co-authored-by: Steven <steven@ceriously.com>
2021-01-11 15:55:58 -08:00
Steven
a9e078d410 [all] Rename init files to vc_ prefix (#5675)
These files show up in error logs, so its confusing to see the [legacy now terminology](https://vercel.com/blog/zeit-is-now-vercel).
2021-01-11 20:38:03 +00:00
Lee Robinson
b4d9b17fb8 Update to latest Create Next App example. (#5655) 2021-01-10 19:52:18 -06:00
Steven
02c55bf634 [cli] Remove legacy example from vc ls --help (#5651)
`vc ls --help` was still listing an example using `--all` which was removed with Now 1.0 in PR #5011.

This PR removes that legacy example.
2021-01-07 20:28:48 +00:00
Nathan Rajlich
08af15055f Publish Canary
- vercel@21.0.2-canary.7
2021-01-06 18:33:16 -08:00
Nathan Rajlich
0597aaa5e4 [cli] Print better message upon ENOENT error when invoking startDevServer() (#5643)
When `spawn()` emits an "ENOENT" error, meaning that the command was not
found, the error would only be visible if `--debug` was enabled for vc
dev.

Now we will always render any error from `startDevServer()`, as well as
special-case the "ENOENT" error informing the user to double check their
installation of the command.
2021-01-06 13:48:55 -08:00
Nathan Rajlich
176856a1ea Stop publishing legacy @now scoped packages (#5641)
These `@now` scoped packages have been published and deprecated with the following warning since May 2020:

```
DEPRECATED ⚠️  - "@now/node" is deprecated and will stop receiving updates on December 31, 2020. Please use "@vercel/node" instead.
```

Since it is now 2021, the time has come to stop publishing.

### Related Issues

[[ch3378]]
2021-01-06 01:59:25 +00:00
Nathan Rajlich
375a55ebed [next][redwood][static-build] Remove frontend runtimes (#5640) 2021-01-05 14:11:55 -08:00
JJ Kasper
7d33a05581 Publish Stable
- @vercel/next@2.7.8
2021-01-05 09:58:19 -06:00
JJ Kasper
0377c8b737 [next] Add tests for optional catch-all fallback true page params (#5247)
This adds tests for optional catch-all `fallback: true` pages to ensure the params are normalized correctly. These should be failing initially until the PR with the normalizing fix in Next.js is released to canary. 

x-ref: https://github.com/vercel/next.js/issues/17220
2021-01-05 04:59:16 +00:00
Nathan Rajlich
662d546388 Publish Canary
- @vercel/node-bridge@1.3.2-canary.1
2021-01-04 16:37:52 -08:00
Nathan Rajlich
8c514b5608 [node-bridge] Publish launcher.* files to npm (#5636) 2021-01-04 16:37:22 -08:00
Nathan Rajlich
a6ec53d9d3 Publish Canary
- vercel@21.0.2-canary.6
 - @vercel/node-bridge@1.3.2-canary.0
 - @vercel/node@1.8.6-canary.3
 - @vercel/static-build@0.18.1-canary.1
 - @vercel/redwood@0.2.1-canary.0
2021-01-04 16:27:14 -08:00
Nathan Rajlich
3ad5903f70 [node-bridge] Move launcher.ts to @vercel/node-bridge (#5634)
The `launcher.ts` file is more closely aligned to the node bridge package, as it's used by other runtimes as well.
2021-01-04 16:25:27 -08:00
Nathan Rajlich
3cf155e999 [tests] Retry fetch upon "ECONNREFUSED" (#5635)
CI failed due to this error code, which can be retried.
2021-01-04 16:06:28 -08:00
JJ Kasper
d9a298d97c Publish Canary
- @vercel/next@2.7.8-canary.0
2021-01-04 15:15:21 -06:00
JJ Kasper
487d3c8554 [next] Ensure 404 route is correct for GSP/GIP 404 (#5632)
This is a follow-up to https://github.com/vercel/vercel/pull/5618 ensuring the 404 route is pointing to the static 404 output correctly when `_app.gip` and getStaticProps in `/404.js` is used

### Related Issues

Fixes: https://github.com/vercel/next.js/issues/19849

#### Tests

- [ ] The code changed/added as part of this PR has been covered with tests
- [ ] All tests pass locally with `yarn test-unit`

#### Code Review

- [ ] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR
2021-01-04 20:53:29 +00:00
JJ Kasper
9d0bfd3656 Publish Stable
- @vercel/next@2.7.7
2021-01-02 12:24:18 -06:00
JJ Kasper
ec75333569 [next] Fix next test files lint (#5619) 2020-12-31 17:10:52 -06:00
JJ Kasper
51aab912a2 Publish Canary
- @vercel/next@2.7.7-canary.2
2020-12-31 16:01:02 -06:00
JJ Kasper
670b2653c0 [next] Ensure 404 is static with _app.GIP and 404 GSP (#5618) 2020-12-31 15:47:18 -06:00
JJ Kasper
f71686fdad Publish Canary
- vercel@21.0.2-canary.5
 - @vercel/next@2.7.7-canary.1
 - @vercel/node@1.8.6-canary.2
2020-12-29 18:26:39 -06:00
Joe Haddad
ec9c8ce150 [next] share cache between nft runs (#5614)
This should result in faster Lambda tracing, as it avoids duplicate work.
2020-12-29 19:04:47 -05:00
Steven
a2048fc6d3 [node][next] Bump nft to 0.9.5 (#5581)
This PR bumps nft from version 0.9.4 to [0.9.5](https://github.com/vercel/nft/releases/tag/0.9.5).
2020-12-28 12:23:03 -05:00
Steven
09ff9cda9f [docs] Fix error message when credentials are missing (#5590) 2020-12-21 12:12:32 -08:00
Nathan Rajlich
3a4d6f7848 Publish Canary
- vercel@21.0.2-canary.4
 - @vercel/node@1.8.6-canary.1
2020-12-21 10:11:14 -08:00
Andy
9a0d676c0d Remove "Add a new framework" CONTRIBUTING.md (#5583) 2020-12-18 12:34:50 -08:00
Nathan Rajlich
25cd7b9e6e [cli] Fix vc logs -o raw and add test (#5571)
There are events (i.e. with `type: "deployment-event"`) that do not
contain a `text` property, so check that it's a string before invoking
`.replace()` on it.

Fixes this stack trace:

```
Error! An unexpected error occurred in logs: TypeError: Cannot read property 'replace' of undefined
    at Object.printLogRaw [as raw] (/home/me/nextjs-site/node_modules/vercel/dist/index.js:203803:10)
    at printEvent (/home/me/nextjs-site/node_modules/vercel/dist/index.js:203688:35)
    at Array.forEach (<anonymous>)
    at main (/home/me/nextjs-site/node_modules/vercel/dist/index.js:203690:31)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at main (/home/me/nextjs-site/node_modules/vercel/dist/index.js:207173:16)
```
2020-12-16 16:16:36 -08:00
Steven
f926d5516c [examples] Update gatsby to use @vercel/node (#5567)
[`@now/node`](https://www.npmjs.com/package/@now/node) is deprecated in favor of [`@vercel/node`](https://www.npmjs.com/package/@vercel/node)
2020-12-14 18:29:10 -05:00
Nathan Rajlich
4603383850 [node] Add Vercel prefixed TypeScript types (#5568)
The `Now` prefixed types remain as aliases for backwards-compat purposes.

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit`

#### Code Review

- [x] This PR has a concise title and thorough description useful to a reviewer
2020-12-14 18:26:22 -05:00
Nathan Rajlich
c0c57889c8 Publish Canary
- @vercel/build-utils@2.6.1-canary.2
 - vercel@21.0.2-canary.3
 - @vercel/client@9.0.5-canary.2
 - @vercel/next@2.7.7-canary.0
 - @vercel/static-build@0.18.1-canary.0
2020-12-14 09:59:43 -08:00
Nathan Rajlich
85908a0524 [build-utils][static-build][next] Force YARN_NODE_LINKER="node-modules" env var when executing yarn (#5552)
### Related Issues

* https://vercel.com/knowledge/does-vercel-support-yarn-2
* https://github.com/vercel/vercel/discussions/4223
* https://github.com/vercel/vercel/discussions/4910
* https://github.com/vercel/vercel/issues/5136
* https://github.com/vercel/vercel/issues/5280

### 📋 Checklist

<!--
  Please keep your PR as a Draft until the checklist is complete
-->

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit`

#### Code Review

- [ ] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR
2020-12-14 04:27:59 +00:00
Andy Bitz
503b9a2429 Publish Canary
- @vercel/build-utils@2.6.1-canary.1
 - vercel@21.0.2-canary.2
 - @vercel/client@9.0.5-canary.1
2020-12-11 19:02:19 +01:00
Andy
eac8f32ae7 [cli][build-utils] Change type to handle builds without a src property (#5553)
* [cli][build-utils] Change type to handle builds without a `src` property

* Add test

* Update unit tests

* Update test

* Undo test changes
2020-12-11 19:00:49 +01:00
dependabot[bot]
3f76fefde6 Bump ini from 1.3.5 to 1.3.7 (#5550)
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7.
<details>
<summary>Commits</summary>
<ul>
<li><a href="c74c8af35f"><code>c74c8af</code></a> 1.3.7</li>
<li><a href="024b8b55ac"><code>024b8b5</code></a> update deps, add linting</li>
<li><a href="032fbaf5f0"><code>032fbaf</code></a> Use Object.create(null) to avoid default object property hazards</li>
<li><a href="2da90391ef"><code>2da9039</code></a> 1.3.6</li>
<li><a href="cfea636f53"><code>cfea636</code></a> better git push script, before publish instead of after</li>
<li><a href="56d2805e07"><code>56d2805</code></a> do not allow invalid hazardous string as section name</li>
<li>See full diff in <a href="https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7">compare view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a href="https://www.npmjs.com/~isaacs">isaacs</a>, a new releaser for ini since your current version.</p>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ini&package-manager=npm_and_yarn&previous-version=1.3.5&new-version=1.3.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/vercel/vercel/network/alerts).

</details>
2020-12-10 22:09:11 +00:00
Steven
79ddc5746b Publish Canary
- @vercel/routing-utils@1.9.2-canary.4
2020-12-10 15:14:12 -05:00
Javi Velasco
9a14615b43 [routing-utils] More accurate schema (#5477)
This PR completes the routes schema to be more accurate for the provided type.
This will allow us to generate the type dynamically from the JSON Schema
2020-12-10 20:10:57 +00:00
JJ Kasper
6d6ccbdc25 [tests] Add retrying for GitHub actions connection error (#5533)
Follow-up to https://github.com/vercel/vercel/pull/5526 this also adds retrying for fetch connection issues in GitHub Actions to prevent false test failures.

x-ref: https://github.com/vercel/vercel/runs/1518604380
2020-12-09 21:11:01 +00:00
JJ Kasper
704424ec58 Publish Stable
- @vercel/next@2.7.6
2020-12-08 10:49:48 -06:00
JJ Kasper
c471127c69 Publish Canary
- @vercel/next@2.7.6-canary.1
2020-12-08 10:33:13 -06:00
JJ Kasper
c02dc9ac49 [next] Add public dir check and update tests (#5526)
* Add public dir check and update tests

* De-dupe test checks a bit
2020-12-08 10:25:55 -05:00
JJ Kasper
dd10e8cc77 Publish Canary
- @vercel/next@2.7.6-canary.0
 - @vercel/routing-utils@1.9.2-canary.3
2020-12-01 16:11:08 -06:00
Connor Davis
cf69c2398c [next] Add Important Headers to Avoid Users Overriding Cache Headers (#5452)
We want to ensure users cannot override Next.js' cache-control headers

### Related Issues

https://app.clubhouse.io/vercel/story/14921/add-important-headers-to-routes
https://app.clubhouse.io/vercel/story/15528/add-important-to-cache-control-headers-in-next-js

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit`

#### Code Review

- [x] This PR has a concise title and thorough description useful to a reviewer
- [x] Issue from task tracker has a link to this PR


Fixes: https://github.com/vercel/vercel/pull/5452
2020-12-01 22:08:50 +00:00
JJ Kasper
e48707571f Publish Stable
- @vercel/next@2.7.5
2020-11-30 11:06:59 -06:00
JJ Kasper
6051fe6f0c Publish Canary
- @vercel/next@2.7.5-canary.1
2020-11-30 11:00:43 -06:00
JJ Kasper
2b3ba8a14f [next] Make sure to use outputDirectory when loading prerenderManifest (#5487)
* Make sure to use outputDirectory when loading prerenderManifest

* Add test case
2020-11-30 10:57:56 -06:00
Steven
25bea3f83e Publish Canary
- vercel@21.0.2-canary.1
 - @vercel/next@2.7.5-canary.0
 - @vercel/node@1.8.6-canary.0
2020-11-24 15:24:52 -05:00
Steven
b3e1828ebe [node][next] Bump nft to 0.9.4 (#5455)
This PR bumps nft to [0.9.4](https://github.com/vercel/nft/releases/tag/0.9.4)
2020-11-24 14:32:46 -05:00
Andy Bitz
e0e2a8e87e Publish Canary
- @vercel/routing-utils@1.9.2-canary.2
2020-11-24 19:52:19 +01:00
Andy
37ec89796d [routing-utils] Handle null phase at the beginning (#5470)
* [routing-utils] Handle `null` phase at the beginning

* Add fixed list

* Add tests

* Change hit and miss order

* Put null at the start

* Undo order changes

Co-authored-by: Steven <steven@ceriously.com>
2020-11-24 19:51:06 +01:00
JJ Kasper
d3e2a4c4db Publish Stable
- @vercel/next@2.7.4
2020-11-24 11:14:03 -06:00
JJ Kasper
ece3645914 Publish Canary
- vercel@21.0.2-canary.0
 - @vercel/next@2.7.4-canary.0
2020-11-24 10:53:50 -06:00
JJ Kasper
fee386493b [next] Add handle: resource to ensure 404 page (#5454)
This adds `handle: resource` to ensure the 404 page is shown instead of a directory listing when there isn't an index route for an output directory. This also removes the `.well-known` route added in https://github.com/vercel/vercel/pull/5447 in favor of adding it in Next.js itself here https://github.com/vercel/next.js/pull/19364 and revalidate tests wait times are increased in this PR due to [this thread](https://vercel.slack.com/archives/C9MMK4674/p1605821738156200)

x-ref: https://github.com/vercel/next.js/pull/19364
Fixes: https://github.com/vercel/next.js/issues/16555
2020-11-24 16:38:43 +00:00
Luc Leray
d95ed184ab [tests] Add test for secrets decryption in vc env pull and vc dev (#5461)
* add test for env with decryptable secret

* Apply suggestions from code review

Co-authored-by: Nathan Rajlich <nathan@tootallnate.net>

Co-authored-by: Nathan Rajlich <nathan@tootallnate.net>
2020-11-23 10:38:29 +01:00
luc
aef8e6388e Publish Stable
- vercel@21.0.1
2020-11-23 00:48:10 +01:00
luc
ba43e88603 Publish Canary
- vercel@21.0.1-canary.0
2020-11-23 00:39:59 +01:00
Igor Klopov
e61f9740c4 [cli] Fix secrets decryption when running vc env pull and vc dev (#5460) 2020-11-23 00:39:17 +01:00
luc
c4b010fe8b Publish Stable
- vercel@21.0.0
2020-11-20 23:10:15 +01:00
luc
db18eb091f Publish Canary
- vercel@20.1.5-canary.6
2020-11-20 17:33:55 +01:00
Luc Leray
360e62d172 [cli] Download automatically exposed System Environment Variables when running vercel env pull (#5451)
* fix VERCEL_REGION and NOW_REGION

* remove VERCEL_REGION from exposeSystemEnvs

* refactor exposeSystemEnvs

* refactor getDecryptedEnvRecords

* consider project envs in exposeSystemEnvs

* simplify exposeSystemEnvs

* correctly set value of VERCEL_URL system envs

* make exposeSystemEnvs return all envs object

* parse url in server

* simplify

* refactor getDecryptedEnvRecords

* add comment

* remove unnecessary code

* add test

* fix test

* fix dev server unit tests

* always expose NOW_REGION

* fix dev test

* fix dev test

* only retrieve system env values when autoExposeSystemEnvs is true
2020-11-20 17:33:16 +01:00
JJ Kasper
8c3cd0332d Publish Stable
- @vercel/next@2.7.3
2020-11-19 14:47:12 -06:00
JJ Kasper
f5f276021e Publish Canary
- @vercel/next@2.7.3-canary.0
2020-11-19 14:30:56 -06:00
JJ Kasper
9fbec823f3 [next] Ensure public files are matched with i18n domains (#5447)
This makes sure we strip all locales during the `handle: 'miss'` phase to allow locale domains to match public files correctly. This also updates the trailing slash redirect handling to match the behavior for `.well-known` added in https://github.com/vercel/vercel/pull/5407

We aren't able to add tests for locale domains with the current test flow yet since they require domains be assigned although the changes in this PR was tested manually against http://i18n-support.vercel.app/ with `@ijjk/now-next@0.1.3-i18n`

x-ref: https://github.com/vercel/vercel/pull/5407
Fixes: https://github.com/vercel/next.js/issues/19324
2020-11-19 20:24:46 +00:00
luc
18c3dd3a63 Publish Canary
- vercel@20.1.5-canary.5
2020-11-19 16:01:27 +01:00
Ana Trajkovska
5a4a20b33f Remove code which removes auto-generated secrets (#5440) 2020-11-19 16:00:57 +01:00
luc
4489ed0c85 Publish Canary
- vercel@20.1.5-canary.4
2020-11-18 16:11:28 +01:00
Luc Leray
359f23daf1 [cli] Expose VERCEL_REGION when autoExposeSystemEnvs is true (#5437)
* auto expose VERCEL_REGION

* add test
2020-11-18 16:00:20 +01:00
luc
4ef92e85db Publish Canary
- vercel@20.1.5-canary.3
2020-11-18 00:27:15 +01:00
Naoyuki Kanezawa
659c4d6ccd [cli] Expose system envs when autoExposeSystemEnvs is enabled on vc dev (#5434)
Ref: https://app.clubhouse.io/vercel/story/15112

We added a property called `autoExposeSystemEnvs` to projects. If that property is `true`, we automatically expose system env variables such as `VERCEL=1`, `VERCEL_ENV=<production | preview>`, ... to the runtime and build time.

This PR makes sure we mirror this behavior when running `vc dev` locally.

### 📋 Checklist

<!--
  Please keep your PR as a Draft until the checklist is complete
-->

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit`

#### Code Review

- [x] This PR has a concise title and thorough description useful to a reviewer
- [x] Issue from task tracker has a link to this PR
2020-11-17 23:21:40 +00:00
JJ Kasper
e93d477df8 Publish Stable
- @vercel/next@2.7.2
2020-11-17 14:49:04 -06:00
JJ Kasper
f64625655b Publish Canary
- @vercel/next@2.7.2-canary.0
2020-11-17 14:11:32 -06:00
JJ Kasper
25a8189997 [next] Correct non-dynamic index SSG data route output (#5435)
Co-authored-by: Joe Haddad <joe.haddad@zeit.co>
2020-11-17 15:09:56 -05:00
Andy Bitz
25c3e627cf Publish Canary
- @vercel/build-utils@2.6.1-canary.0
 - vercel@20.1.5-canary.2
 - @vercel/client@9.0.5-canary.0
2020-11-17 18:13:30 +01:00
Andy
1d6d8b530f [build-utils] Remove continue: true from 404 route (#5432)
* [build-utils] Remove `continue: true` from 404 route

* Update tests
2020-11-17 18:08:29 +01:00
Steven
e821cc0ae7 [cli] Add tests to compare dev/prd image optimization (#5428)
Add E2E test for to test image optimization against `vc dev` as well as a prod deployment.

### 📋 Checklist

<!--
  Please keep your PR as a Draft until the checklist is complete
-->

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit`

#### Code Review

- [x] This PR has a concise title and thorough description useful to a reviewer
- [x] Issue from task tracker has a link to this PR (CH13104)
2020-11-16 20:20:27 +00:00
JJ Kasper
8ecbdc5d03 Publish Stable
- @vercel/next@2.7.1
2020-11-14 16:48:35 -06:00
JJ Kasper
895224985b Publish Canary
- @vercel/next@2.7.1-canary.0
2020-11-14 16:23:24 -06:00
JJ Kasper
0f42a63c03 [next] Ensure correct route order for i18n + custom-routes (#5421)
Co-authored-by: Steven <steven@ceriously.com>
2020-11-14 17:13:08 -05:00
dav-is
81e4c9e6fe Publish Canary
- @vercel/routing-utils@1.9.2-canary.1
2020-11-13 13:48:28 -05:00
Connor Davis
a0a29dc836 [routing-utils] Exclude /.well-known from trailing slash redirect (#5407)
`/.well-known` files shouldn't have trailing slashes added as these clients likely do not follow redirects

Specifically, `/.well-known/apple-developer-merchantid-domain-association` cannot have trailing slash.

### Related Issues

https://vercel.slack.com/archives/CLDDX2Y0G/p1605127589058800

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit`

#### Code Review

- [x] This PR has a concise title and thorough description useful to a reviewer
- [x] Issue from task tracker has a link to this PR
2020-11-12 22:38:01 +00:00
luc
c1f9d51d7a Publish Canary
- vercel@20.1.5-canary.1
2020-11-12 22:06:16 +01:00
Luc Leray
422f0558c1 [cli] Rename "Provided by system" to "Reference ..." (#5415)
* Revert "Revert "[cli] (major) Update `vercel env` (#5372)" (#5410)"

This reverts commit 2d24a75ca6.

* fetch system env values from dedicated endpoint

* rename "Provided by System"
2020-11-12 22:05:24 +01:00
luc
f064ae2908 Publish Canary
- vercel@20.1.5-canary.0
 - @vercel/routing-utils@1.9.2-canary.0
2020-11-12 21:07:28 +01:00
Luc Leray
58c3e636f0 [cli] (Major) Update vc env (#5413)
* Revert "Revert "[cli] (major) Update `vercel env` (#5372)" (#5410)"

This reverts commit 2d24a75ca6.

* fetch system env values from dedicated endpoint
2020-11-12 21:06:25 +01:00
Connor Davis
d5081367f3 [routing-utils] Add important headers to disallow users from overriding (#5409)
If a builder wants to set a header that isn't allowed to be overridden by users, it should use `important: true`

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit`

#### Code Review

- [x] This PR has a concise title and thorough description useful to a reviewer
- [x] Issue from task tracker has a link to this PR: CH-14921
2020-11-12 17:45:33 +00:00
luc
0ee88366ff Publish Stable
- vercel@20.1.4
2020-11-12 17:16:29 +01:00
luc
9ae42c9e92 Publish Canary
- vercel@20.1.4-canary.1
2020-11-12 16:59:28 +01:00
Luc Leray
62b8df4a8d [cli] Fix vc env rm with advanced env variables (#5411) 2020-11-12 16:58:41 +01:00
luc
73ec7f3018 Publish Canary
- vercel@20.1.4-canary.0
2020-11-12 15:31:54 +01:00
Luc Leray
2d24a75ca6 Revert "[cli] (major) Update vercel env (#5372)" (#5410)
* Revert "[cli] (major) Update `vercel env` (#5372)"

This reverts commit 9a57cc72dd.

* fix test

* do not change prompt UI
2020-11-12 15:30:47 +01:00
Nathan Rajlich
3f92c42ad6 Publish Stable
- @vercel/frameworks@0.2.0
 - @vercel/build-utils@2.6.0
 - vercel@20.1.3
 - @vercel/client@9.0.4
 - @vercel/next@2.7.0
 - @vercel/node@1.8.5
 - @vercel/routing-utils@1.9.1
 - @vercel/static-build@0.18.0
 - @vercel/redwood@0.2.0
2020-11-11 16:01:46 -08:00
Andy Bitz
d824f79d5a Publish Canary
- @vercel/static-build@0.17.16-canary.1
2020-11-12 00:36:43 +01:00
Andy
eefbf3a52d [static-build] Fix order of applying routes (#5408)
* [static-build] Fix order of applying routes

* Add test

* Fix 11-svelte
2020-11-12 00:36:02 +01:00
Nathan Rajlich
dda793018b Publish Canary
- @vercel/build-utils@2.5.5-canary.4
 - vercel@20.1.3-canary.9
 - @vercel/client@9.0.4-canary.5
2020-11-11 14:30:14 -08:00
Nathan Rajlich
9e588068ea [build-utils] Include installCommand when empty string (#5406)
* [build-utils] Include `installCommand` when empty string

An empty string for the Project's `installCommand` setting has different
behavior than `null`, so properly provide the empty string to the
Runtime.

* Move tests to proper section
2020-11-11 14:14:57 -08:00
Chris Leishman
76a7a51bdc [docs] Add required information for pull requests (#5282) 2020-11-11 19:43:20 +00:00
Nathan Rajlich
5f5b5b0340 Publish Canary
- vercel@20.1.3-canary.8
 - @vercel/next@2.6.39-canary.1
 - @vercel/node@1.8.5-canary.0
 - @vercel/static-build@0.17.16-canary.0
 - @vercel/redwood@0.1.2-canary.3
2020-11-11 10:31:14 -08:00
Nathan Rajlich
a0ce373dc9 [static-build][next][node][redwood] Invoke installCommand from Project settings (#5393)
* [static-build] Invoke `installCommand` from Project settings

* [next] Invoke `installCommand` from Project settings

* [redwood] Invoke `installCommand` from Project settings

* [node] Remove `--prefer-offline` npm flag

* [static-build] Remove `--prefer-offline` npm flag

* [next] Remove extra console.log()

* Move `installTime` to inside else branch

* Use `as keyof Config`

* [static-build] Add `installCommand` integration test

* [next] Add `installCommand` integration test

* Use `.`

* [redwood] Add `installCommand` integration test

* Skip `installCommand` if string is empty

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-11-11 10:26:57 -08:00
Steven
049ffb268b [examples] Update svelte example with latest rollup (#5404)
Updated the template using `npx degit sveltejs/template my-svelte-project`

I also added a `yarn.lock` file so dependencies don't break for future deployments.

Related to https://github.com/Samuel-Martineau/generator-svelte/issues/7
2020-11-11 09:44:06 -05:00
Andy Bitz
94483c8b36 Publish Stable
- @vercel/static-build@0.17.15
2020-11-10 21:32:13 +01:00
Andy Bitz
078f9de44e Publish Canary
- @vercel/frameworks@0.1.2-canary.2
 - @vercel/build-utils@2.5.5-canary.3
 - vercel@20.1.3-canary.7
 - @vercel/client@9.0.4-canary.4
 - @vercel/static-build@0.17.15-canary.0
 - @vercel/redwood@0.1.2-canary.2
2020-11-10 21:18:48 +01:00
Andy
0ae41f97a4 [static-build] Ignore framework routes if config/routes.json is present (#5401) 2020-11-10 21:17:45 +01:00
Nathan Rajlich
9fb6a1ec4c [frameworks] Use "value" instead of "placeholder" for frameworks with known installCommand (#5400) 2020-11-10 11:25:16 -08:00
Andy Bitz
21be46c8bb Publish Stable
- @vercel/static-build@0.17.14
2020-11-10 18:51:06 +01:00
Andy
91942fc4d2 [static-build] Expect routes array directly (#5399) 2020-11-10 18:49:51 +01:00
Andy Bitz
8e02f2289f Publish Stable
- @vercel/static-build@0.17.13
2020-11-10 16:21:58 +01:00
Andy Bitz
4205d643a1 Publish Canary
- @vercel/next@2.6.39-canary.0
 - @vercel/static-build@0.17.13-canary.0
2020-11-10 16:19:08 +01:00
Andy
b2dda4dbb9 [static-build] Support static and config directory in .vercel_build_output (#5396)
* Handle routes and static files from the build output directory

* Add logging

* Move comment
2020-11-10 16:18:07 +01:00
Joe Haddad
f36eac3d0a [next] files within the buildId directory are immutable (#5386)
Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
2020-11-10 09:19:26 -05:00
Andy Bitz
a2c56425f4 Publish Stable
- @vercel/static-build@0.17.12
2020-11-10 00:43:05 +01:00
Andy Bitz
c759bfda9c Publish Canary
- @vercel/client@9.0.4-canary.3
 - @vercel/static-build@0.17.12-canary.0
2020-11-10 00:14:31 +01:00
Andy
57995001ac [static-build] Add directory for Serverless Functions (#5390)
* [@vercel/static-build] Add directory for Serverless Functions

* Update tests and only consider index.js files

* Import only once

* Only change for zeroConfig

* Update packages/now-static-build/src/utils/_shared.ts

Co-authored-by: Steven <steven@ceriously.com>

* Update packages/now-static-build/test/fixtures/62-function-output-directory-with-static/now.json

Co-authored-by: Steven <steven@ceriously.com>

* Update packages/now-static-build/test/fixtures/61-function-output-directory/now.json

Co-authored-by: Steven <steven@ceriously.com>

* Update build

* Fix type

* Remove line

* Add to .vercelignore

* Fix paths in test

* Move more files

* Remove special case for test

Co-authored-by: Steven <steven@ceriously.com>
2020-11-10 00:09:23 +01:00
Nathan Rajlich
e5553d8ec2 Publish Canary
- @vercel/build-utils@2.5.5-canary.2
 - vercel@20.1.3-canary.6
 - @vercel/client@9.0.4-canary.2
2020-11-09 15:02:17 -08:00
Nathan Rajlich
dcee5b16c7 [build-utils] Add installCommand to Config object (#5391) 2020-11-09 22:27:29 +00:00
JJ Kasper
b190f2e118 Publish Stable
- @vercel/next@2.6.38
2020-11-07 12:11:05 -06:00
JJ Kasper
2389d3e936 Publish Canary
- @vercel/next@2.6.38-canary.0
2020-11-07 11:55:08 -06:00
JJ Kasper
0f4ed1965a [next] Correct data routes with basePath (#5381) 2020-11-06 23:40:32 -05:00
luc
e1e38ee536 Publish Canary
- vercel@20.1.3-canary.5
2020-11-06 16:50:13 +01:00
Luc Leray
dc1ff00610 [cli] Show error when removing env variable from no target environment (#5378)
* error if no env target is selected

* improve prompt ui

* add test
2020-11-06 16:49:34 +01:00
luc
5f31736603 Publish Canary
- vercel@20.1.3-canary.4
2020-11-05 23:17:08 +01:00
Luc Leray
9a57cc72dd [cli] (major) Update vercel env (#5372)
* prompt to select env type

* improve copy

* create env variable with type

* remove nanoid dependency

* use encodeURIComponent

* refactor envType -> type

* refactor envName -> key

* do not hide value input

* adjust value prompt depending on type

* handle std input for plaintext env variables

* show custom error when secret is not found

* handle secret name input starting with `@`

* fix system env value question

* improve ui of prompts

* expand env list in vc rm

* adjust tests

* environment -> environments

* list multiple targets in vc env ls

* show value for system env vars

* adjust tests

* capitalize targets

* add <type> to arguments

* always use stdInput for envValue

* fix number of arguments error

* adjust tests

* refactor ProjectEnvType

* refactor SYSTEM_ENV_VALUES

* fix typo for typePlaceholder

* use getCommandName

* use title

* remove @ts-ignore

* improve types

* show key controls for checkbox prompt
2020-11-05 22:58:58 +01:00
JJ Kasper
9d9c5f3753 Publish Stable
- @vercel/next@2.6.37
2020-11-05 12:44:43 -06:00
JJ Kasper
deeefc0c93 Publish Canary
- @vercel/next@2.6.37-canary.0
2020-11-05 11:50:05 -06:00
JJ Kasper
5c23b08bc1 Ensure auto-export dynamic routes are routed properly (#5377) 2020-11-05 11:48:29 -06:00
dependabot[bot]
7c4e25ccce Bump bl from 1.2.2 to 1.2.3 (#5363)
Bumps [bl](https://github.com/rvagg/bl) from 1.2.2 to 1.2.3.
- [Release notes](https://github.com/rvagg/bl/releases)
- [Commits](https://github.com/rvagg/bl/compare/v1.2.2...v1.2.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-05 10:24:17 -05:00
Joe Haddad
1bfa310945 Publish Stable
- @vercel/static-build@0.17.11
2020-11-04 23:29:30 -05:00
Joe Haddad
c96062266b Publish Canary
- @vercel/frameworks@0.1.2-canary.1
 - @vercel/build-utils@2.5.5-canary.1
 - vercel@20.1.3-canary.3
 - @vercel/client@9.0.4-canary.1
 - @vercel/static-build@0.17.11-canary.0
 - @vercel/redwood@0.1.2-canary.1
2020-11-04 23:12:46 -05:00
Joe Haddad
5bea99c1d9 [static-build] zero-config gatsby should support export default (#5375) 2020-11-04 23:11:40 -05:00
Luc Leray
358be773a2 [tests] Cleanup fixture folder before running CLI test (#5374) 2020-11-05 02:09:36 +01:00
Nathan Rajlich
9ebf4e531d [frameworks] Add installCommand placeholders (#5373) 2020-11-04 16:24:06 -08:00
Joe Haddad
71e79258b7 Publish Stable
- @vercel/next@2.6.36
 - @vercel/static-build@0.17.10
2020-11-03 10:49:41 -05:00
Joe Haddad
1dfafe7040 Publish Canary
- @vercel/next@2.6.36-canary.0
2020-11-03 10:40:07 -05:00
JJ Kasper
78ed452a99 [next] Ensure localeDetection: false is honored (#5365)
This disables adding the locale redirects when `localeDetection` is set to `false` 

x-ref: https://github.com/vercel/next.js/issues/18482
2020-11-03 01:58:40 +00:00
Joe Haddad
d408e2ef1a Publish Canary
- @vercel/static-build@0.17.10-canary.0
2020-11-02 15:04:48 -05:00
Joe Haddad
8ebb1fd9ce [static-build] add Vercel Analytics Support for Gatsby (#5366) 2020-11-02 15:03:45 -05:00
JJ Kasper
4eb5ad625c Publish Stable
- @vercel/next@2.6.35
2020-11-02 10:26:52 -06:00
luc
7164f6e58e Publish Canary
- vercel@20.1.3-canary.2
2020-11-02 15:43:54 +01:00
Naoyuki Kanezawa
a36d084b3e [cli] Add support for plaintext env variables (#5345)
* fix plain envs can not be retrieved

* add test

* add test for `vc dev`

* use v6 to retrieve env variables

* fix v6 return type

* use v6 to display env vars

* add test for vc env ls

* expand env vars with multiple targets

* minor type fixes

* always use v6 for getEnvVariables

Co-authored-by: luc <luc.leray@gmail.com>
2020-11-02 15:42:28 +01:00
JJ Kasper
8a16447fed Publish Canary
- vercel@20.1.3-canary.1
 - @vercel/next@2.6.35-canary.1
2020-11-01 12:24:51 -06:00
Leo Lamprecht
efda4ab6b9 Updated Next.js Template to use latest version of Next.js and React (#5358) 2020-11-01 17:13:16 +01:00
JJ Kasper
16060a71a9 [next] Add additional tests for i18n revalidate params (#5356) 2020-11-01 15:15:20 +01:00
Luc Leray
b18e0a7415 [cli] Replace util/prompt-bool by util/input/confirm (#5359) 2020-10-31 22:07:35 +01:00
JJ Kasper
1251f11a97 Publish Canary
- @vercel/next@2.6.35-canary.0
2020-10-31 00:34:03 -05:00
JJ Kasper
07235e22f6 [next] Fix root-most optional-catchall with i18n (#5354)
* Fix root-most optional-catchall with i18n

* Ensure dynamic prerenders revalidation

* Add test delay
2020-10-30 17:40:39 -05:00
JJ Kasper
81011df816 Publish Stable
- @vercel/next@2.6.34
2020-10-30 10:50:03 -05:00
JJ Kasper
c8d31bdcf7 Publish Canary
- @vercel/next@2.6.34-canary.0
2020-10-30 10:16:20 -05:00
JJ Kasper
5e7f1158ad [next] Ensure revalidation works with i18n (#5350)
This corrects some i18n pages being considered staticPages instead of prerender items which was breaking revalidate behavior. This also adds more verbose tests for i18n ensuring revalidation is working correctly

x-ref: https://github.com/vercel/next.js/discussions/18443
Fixes: https://github.com/vercel/next.js/issues/18503
2020-10-30 14:59:47 +00:00
JJ Kasper
df5aa1f10d Publish Stable
- @vercel/next@2.6.33
2020-10-27 13:41:00 -05:00
JJ Kasper
eb1ba97309 Publish Canary
- @vercel/next@2.6.33-canary.0
2020-10-27 13:33:33 -05:00
JJ Kasper
8047d6de49 [next] Fix index data path for non-locale path (#5339)
* Fix index data path for non-locale path

* Add index SSG test

* Update tests for canary

* Correct logic check to handle default locale
2020-10-27 13:33:02 -05:00
JJ Kasper
7470ff3724 Publish Stable
- @vercel/next@2.6.32
2020-10-27 09:30:43 -05:00
JJ Kasper
8340d9327c Publish Canary
- @vercel/next@2.6.32-canary.1
2020-10-27 09:11:04 -05:00
JJ Kasper
d278425810 Update tests for stabilized field (#5337) 2020-10-27 09:05:39 -05:00
JJ Kasper
8b26bbe643 [next] Add redirecting domain specific locales (#5333)
Co-authored-by: Joe Haddad <joe.haddad@zeit.co>
2020-10-27 11:32:08 +01:00
JJ Kasper
fa8e1e73c8 Ensure index GSP data is available at correct path (#5336) 2020-10-27 01:51:58 -05:00
JJ Kasper
f8abcbcd9f Remove unstable_ prefix from unstable_blocking (#5334) 2020-10-27 00:42:11 -05:00
Andy Bitz
e18ff683b2 Publish Canary
- @vercel/frameworks@0.1.2-canary.0
 - @vercel/build-utils@2.5.5-canary.0
 - vercel@20.1.3-canary.0
 - @vercel/client@9.0.4-canary.0
 - @vercel/redwood@0.1.2-canary.0
2020-10-26 16:22:53 +01:00
Andy
f28293a5a8 [frameworks] Add recommended integrations and related dependencies (#5330)
Adds the `recommendedIntegrations` property to the frameworks list with related dependencies.

Story https://app.clubhouse.io/vercel/story/13391
2020-10-26 15:10:40 +00:00
Steven
a4963a89c7 Publish Canary
- @vercel/next@2.6.32-canary.0
2020-10-25 16:58:01 -04:00
Steven
21df39fe8c [next] Image Optimization for default loader (#5321)
We currently pass through `images` whenever its defined, but this is enabling Image Optimization in the Proxy for every Next.js project.

Instead, we should check to see if the default loader is used (the same use for `next dev`) as a signal to enable this feature in the deployment.

Related to https://github.com/vercel/next.js/issues/18122
2020-10-24 12:55:53 +00:00
JJ Kasper
5ad9d61451 Publish Stable
- @vercel/next@2.6.31
2020-10-23 15:48:21 -05:00
JJ Kasper
8b5a2aa44f Publish Canary
- @vercel/next@2.6.31-canary.0
2020-10-23 15:17:30 -05:00
JJ Kasper
d0da1ce195 [next] Add handling for not found routes with i18n (#5313)
* Add handling for not found routes with i18n

* Update prerender lambda check
2020-10-23 14:34:17 -05:00
JJ Kasper
fd5d3b2921 Publish Stable
- @vercel/next@2.6.30
2020-10-20 13:11:20 -05:00
JJ Kasper
d22bdeb8d0 Publish Canary
- @vercel/next@2.6.30-canary.0
2020-10-20 12:59:12 -05:00
JJ Kasper
c120fd82f9 [next] Ensure root-most index GSP page is located correctly (#5309) 2020-10-20 19:58:18 +02:00
JJ Kasper
2474a80ff1 Correct i18n trailing slash redirect priority (#5306) 2020-10-20 11:01:31 -05:00
JJ Kasper
cc1cdbe610 Publish Stable
- @vercel/next@2.6.29
2020-10-20 06:15:03 -05:00
JJ Kasper
0b92f8ceee Publish Canary
- @vercel/next@2.6.29-canary.0
 - @vercel/routing-utils@1.9.1-canary.1
2020-10-20 05:08:26 -05:00
JJ Kasper
be82a88d1a [next] Add i18n support handling (#5298)
* Add initial locale output mapping

* Add additional probes

* Add locale specific 404 handling

* Add locale specific 404s, locale redirects, and more tests

* Update wildcard value

* Fix wildcard handling and update route type

* Update addLocale util

* Apply suggestions from code review

Co-authored-by: Steven <steven@ceriously.com>

* Remove redundant console.error

Co-authored-by: Steven <steven@ceriously.com>
Co-authored-by: Leo Lamprecht <leo@zeit.co>
2020-10-20 12:05:06 +02:00
JJ Kasper
64da08f0f2 Publish Stable
- @vercel/next@2.6.28
2020-10-20 05:00:10 -05:00
Steven
2e957fce55 Publish Canary
- @vercel/next@2.6.28-canary.0
2020-10-16 18:19:07 -04:00
Steven
c7ead151f5 [next] Add support for Image Optimization (#5296)
This PR sends the results of the image optimization config from next.config.js to the build output.

x-ref: https://github.com/vercel/next.js/pull/17749
2020-10-16 17:56:14 -04:00
dav-is
e2baf9b00f Publish Canary
- @vercel/routing-utils@1.9.1-canary.0
2020-10-14 16:48:04 -04:00
Connor Davis
ba8ef7bc98 Add custom locale cookie (#5293) 2020-10-14 16:46:40 -04:00
JJ Kasper
c5d04e0d4f Publish Stable
- @vercel/next@2.6.27
2020-10-13 14:40:53 -05:00
JJ Kasper
b4f849418d Publish Canary
- @vercel/next@2.6.27-canary.0
2020-10-13 00:17:38 -05:00
JJ Kasper
b37c4f211e [next] Update next.config backup name to be deterministic (#5288) 2020-10-13 01:13:40 -04:00
Daniel Roe
f06efe167c [docs] Update contributing example of @vercel/nft (#5284) 2020-10-12 15:01:27 -04:00
dependabot[bot]
296d8da676 Bump next from 9.5.1 to 9.5.4 in /examples/nextjs (#5278)
Bumps [next](https://github.com/vercel/next.js) from 9.5.1 to 9.5.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/vercel/next.js/releases">next's releases</a>.</em></p>
<blockquote>
<h2>v9.5.4</h2>
<p><strong>This upgrade is <em>completely backwards compatible and recommended for all users on versions below 9.5.4.</em> For future security related communications of our OSS projects, please <a href="https://vercel.com/security">join this mailing list</a>.</strong></p>
<p>A security team from one of our partners noticed an issue in Next.js that allowed for open redirects to occur.</p>
<p>Specially encoded paths could be used with the trailing slash redirect to allow an open redirect to occur to an external site.</p>
<p>In general, this redirect does not directly harm users although can allow for phishing attacks by redirecting to an attackers domain from a trusted domain.</p>
<p>We recommend upgrading to the latest version of Next.js to improve the overall security of your application.</p>
<h2>How to Upgrade</h2>
<ul>
<li>We have released patch versions for both the stable and canary channels of Next.js.</li>
<li>To upgrade run <code>npm install next@latest --save</code></li>
</ul>
<h2>Impact</h2>
<ul>
<li><strong>Affected</strong>: Users of Next.js between 9.5.0 and 9.5.3</li>
<li><strong>Not affected</strong>: Deployments on Vercel (<a href="https://vercel.com">https://vercel.com</a>) are not affected</li>
<li><strong>Not affected</strong>: Deployments using <code>next export</code></li>
</ul>
<p>We recommend everyone to upgrade regardless of whether you can reproduce the issue or not.</p>
<h3>How to Assess Impact</h3>
<p>If you think users could have been affected, you can filter logs of affected sites by <code>%2F</code> with a 308 response.</p>
<h2>What is Being Done</h2>
<p>As Next.js has grown in popularity, it has received the attention of security teams and auditors. We are thankful to those that reached out for their investigation and discovery of the original bug and subsequent responsible disclosure.</p>
<p>We've landed a patch that ensures encoding is handled properly for these types of redirects so the open redirect can no longer occur.</p>
<p>Regression tests for this attack were added to the <a href="https://github.com/vercel/next.js/blob/canary/test/integration/production/test/security.js">security</a> integration test suite.</p>
<ul>
<li>We have notified known Next.js users in advance of this publication.</li>
<li>A public CVE was released.</li>
<li>If you want to stay on top of our security related news impacting Next.js or other Vercel projects, please <a href="https://zeit.co/security">join this mailing list</a>.</li>
<li>We encourage responsible disclosure of future issues. Please email us at <strong><a href="https://github.com/vercel/next.js/blob/HEAD/mailto:security@zeit.co">security@vercel.com</a>.</strong> We are actively monitoring this mailbox.</li>
</ul>
<hr />
<h3>Core Changes</h3>
<ul>
<li>Make the image post-processor ignore SVG images: <a href="https://github-redirect.dependabot.com/vercel/next.js/issues/16732">#16732</a></li>
<li>Only update lookups for dev overlay if mounted: <a href="https://github-redirect.dependabot.com/vercel/next.js/issues/16776">#16776</a></li>
<li>Ensure interpolating dynamic href values works correctly: <a href="https://github-redirect.dependabot.com/vercel/next.js/issues/16774">#16774</a></li>
<li>Add automatic reloading when editing GS(S)P methods: <a href="https://github-redirect.dependabot.com/vercel/next.js/issues/16744">#16744</a></li>
<li>Update to show build indicator while re-fetching GS(S)P data in dev: <a href="https://github-redirect.dependabot.com/vercel/next.js/issues/16789">#16789</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="6588108150"><code>6588108</code></a> v9.5.4</li>
<li><a href="7108567b06"><code>7108567</code></a> v9.5.4-canary.25</li>
<li><a href="5d79a8c0c4"><code>5d79a8c</code></a> Update workflow step to restore cache (<a href="https://github-redirect.dependabot.com/vercel/next.js/issues/17656">#17656</a>)</li>
<li><a href="4c38e3ed8e"><code>4c38e3e</code></a> fix typo (<a href="https://github-redirect.dependabot.com/vercel/next.js/issues/17653">#17653</a>)</li>
<li><a href="241f38eaa8"><code>241f38e</code></a> v9.5.4-canary.24</li>
<li><a href="7dec91175c"><code>7dec911</code></a> change anonymous functions to named in docs examples (<a href="https://github-redirect.dependabot.com/vercel/next.js/issues/17510">#17510</a>)</li>
<li><a href="1659e4da61"><code>1659e4d</code></a> Update migrating from Gatsby docs. (<a href="https://github-redirect.dependabot.com/vercel/next.js/issues/17636">#17636</a>)</li>
<li><a href="06a8b1ad67"><code>06a8b1a</code></a> Add docs on how to migrate from Gatsby. (<a href="https://github-redirect.dependabot.com/vercel/next.js/issues/17491">#17491</a>)</li>
<li><a href="04234cc312"><code>04234cc</code></a> Update to use hasNextSupport for custom-routes in next export check (<a href="https://github-redirect.dependabot.com/vercel/next.js/issues/17630">#17630</a>)</li>
<li><a href="742f5d9a46"><code>742f5d9</code></a> test(create-next-app): increase coverage (<a href="https://github-redirect.dependabot.com/vercel/next.js/issues/17507">#17507</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/vercel/next.js/compare/v9.5.1...v9.5.4">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=next&package-manager=npm_and_yarn&previous-version=9.5.1&new-version=9.5.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/configuring-github-dependabot-security-updates)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/vercel/vercel/network/alerts).

</details>
2020-10-09 14:32:15 +00:00
Steven
981e4183c6 Publish Stable
- @vercel/build-utils@2.5.4
 - vercel@20.1.2
 - @vercel/client@9.0.3
 - @vercel/node@1.8.4
 - @vercel/routing-utils@1.9.0
2020-10-08 09:10:16 -04:00
Steven
1706a00cb9 Publish Canary
- @vercel/build-utils@2.5.4-canary.0
 - vercel@20.1.2-canary.5
 - @vercel/client@9.0.3-canary.0
2020-10-06 09:10:41 -04:00
Steven
d7bd03cf1d [build-utils] Fix framework "CRA" when Next.js is dependency (#5246)
Fixes https://github.com/vercel/vercel/discussions/4288#discussioncomment-88998

This was fixed when "Framework: Other" in #5009 but this PR fixes it when "Framework: CRA" or any framework selection.
2020-10-06 13:09:02 +00:00
dav-is
e27ff8d2e0 Publish Canary
- vercel@20.1.2-canary.4
2020-10-05 18:14:54 -04:00
RAJPRAKASH
bc6da39cc2 [examples] Fix link to gatsby live example (#5205)
Fixes the link in the gatsby example back to the repo.

Co-authored-by: Steven <steven@ceriously.com>
2020-10-05 18:08:29 -04:00
dav-is
727109c64a Publish Canary
- @vercel/routing-utils@1.8.5-canary.0
2020-10-05 18:03:21 -04:00
Connor Davis
817410a8e2 [routing-utils] Add locale to routes schema (#5259)
We need to add a `locale` property to `routes`: CH-12345, CH-12349
2020-10-05 21:25:21 +00:00
Steven
e022e7b79c Publish Canary
- vercel@20.1.2-canary.3
2020-10-05 15:20:29 -04:00
Steven
dda6c24a3d [cli] Fix progress bar completion (#5260)
In some rare cases, the progress bar will still be in progress when the deployment completes, which causes the  "Inspect" URL to print on the same line as the progress bar instead of a new line.

This PR fixes that corner case.
2020-10-05 19:10:20 +00:00
Steven
7c922a4092 [cli] Remove 1.0 path alias rules (#5258)
We don't support routing path aliases anymore, now that we've completely shut down the ZEIT Now 1.0 infrastructure. This PR removes path alias rules from Vercel CLI.
2020-10-05 17:48:37 +00:00
Steven
376dec8f33 Publish Canary
- vercel@20.1.2-canary.2
2020-10-02 19:18:35 -04:00
Steven
16e101d262 [cli] Fix dev routing when using routes with a frontend framework (#5253)
There was a regression when introducing multiple phases such as `hit` and `miss` which caused `routes` to stop working because the transition from `null` phase to the `filesystem` phase resets any dest rewrites.

The workaround is to detect when we don't have a `filesystem` phase and exit early.
2020-10-02 22:46:53 +00:00
Nathan Rajlich
41ce1a4291 Publish Canary
- vercel@20.1.2-canary.1
 - @vercel/node@1.8.4-canary.0
2020-09-25 10:00:24 -07:00
Nathan Rajlich
449f35cf33 [node] Only use the project's local "typescript" when it has compatible ScriptTarget (#5220)
https://app.clubhouse.io/vercel/story/8304
2020-09-24 15:18:09 -07:00
Nathan Rajlich
d683402bba Publish Canary
- vercel@20.1.2-canary.0
2020-09-23 13:23:44 -07:00
Nathan Rajlich
2051a1cd9b [cli] Ensure the devProcessPort is set during "upgrade" events (#5226)
Related to: https://twitter.com/raymondcamden/status/1308838251902521348
2020-09-23 20:16:51 +00:00
1849 changed files with 3590 additions and 231987 deletions

View File

@@ -34,6 +34,7 @@ packages/now-node-bridge/bridge.*
# now-static-build # now-static-build
packages/now-static-build/test/fixtures packages/now-static-build/test/fixtures
packages/now-static-build/test/build-fixtures
# redwood # redwood
packages/redwood/test/fixtures packages/redwood/test/fixtures

View File

@@ -73,8 +73,8 @@ The logs of this deployment will contain the actual error which may help you to
Some of the Builders use `@vercel/nft` to tree-shake files before deployment. If you suspect an error with this tree-shaking mechanism, you can create the following script in your project: Some of the Builders use `@vercel/nft` to tree-shake files before deployment. If you suspect an error with this tree-shaking mechanism, you can create the following script in your project:
```js ```js
const trace = require('@vercel/nft'); const { nodeFileTrace } = require('@vercel/nft');
trace(['path/to/entrypoint.js'], { nodeFileTrace(['path/to/entrypoint.js'], {
ts: true, ts: true,
mixedModules: true, mixedModules: true,
}) })
@@ -94,12 +94,3 @@ Sometimes you want to test changes to a Builder against an existing project, may
4. Run `vercel *.tgz` to upload the tarball file and get a URL 4. Run `vercel *.tgz` to upload the tarball file and get a URL
5. Edit any existing `vercel.json` project and replace `use` with the URL 5. Edit any existing `vercel.json` project and replace `use` with the URL
6. Run `vercel` or `vercel dev` to deploy with the experimental Builder 6. Run `vercel` or `vercel dev` to deploy with the experimental Builder
## Add a New Framework
You can add support for a new Framework by creating a Pull Request for this repository and following the steps below:
1. Add the Framework to the `@vercel/frameworks` package: The file is located in `./packages/frameworks/frameworks.json`. You can copy the structure of an existing one and adjust the required fields. Note that the `settings` property either contains a `value` or a `placeholder`. The `value` property is used when something is not configurable, the `placeholder` is used when something is configurable and can be changed with configuration. An example would be the Output Directory for Hugo, it's `public` by default but can be changed through its config file, so we use `placeholder` with an explanation of what can be used.
2. Add an example to the `./examples` directory: The name of the directory should equal the slug of the framework used in `@vercel/frameworks`. The `.github/EXAMPLE_README_TEMPLATE.md` file can be used to create a `README.md` file for the example.
3. Update the `@vercel/static-build` package: The file `./packages/now-static-build/src/frameworks.ts` has to be extended. You can add default routes that will always be applied to projects that use this Framework or specify some paths that will be cached to speed up the build process.
4. After your Pull Request has been merged and released, other users can select the example on the Vercel dashboard and deploy it.

20
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,20 @@
### Related Issues
> Fixes #1
> Related to #2
### 📋 Checklist
<!--
Please keep your PR as a Draft until the checklist is complete
-->
#### Tests
- [ ] The code changed/added as part of this PR has been covered with tests
- [ ] All tests pass locally with `yarn test-unit`
#### Code Review
- [ ] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR

View File

@@ -1,7 +1,7 @@
version = 1 version = 1
[merge] [merge]
automerge_label = "automerge" automerge_label = ["semver-major","semver-minor","semver-patch"]
blacklist_title_regex = "^WIP.*" blacklist_title_regex = "^WIP.*"
blacklist_labels = ["work in progress"] blacklist_labels = ["work in progress"]
method = "squash" method = "squash"

View File

@@ -6,5 +6,5 @@ You're running Vercel CLI in a non-terminal context and there are no credentials
#### Possible Ways to Fix It #### Possible Ways to Fix It
- Specify a value for the `--token` flag (this needs to be the token of the user account as which you'd like to act). You can either get the token from the `./vercel/auth.json` file located in your user directory or [from the dashboard](https://vercel.com/account/tokens). - Specify a value for the `--token` flag (this needs to be the token of the user account as which you'd like to act). You can create a new token on your [Settings page](https://vercel.com/account/tokens).
- Ensure that both `~/vercel/auth.json` and `~/vercel/config.json` exist - Run `vercel login` to sign in and generate a new token

View File

@@ -1,4 +1,4 @@
import { NowRequest, NowResponse } from '@now/node'; import { NowRequest, NowResponse } from '@vercel/node';
export default (_req: NowRequest, res: NowResponse) => { export default (_req: NowRequest, res: NowResponse) => {
const date = new Date().toString(); const date = new Date().toString();

View File

@@ -12,7 +12,7 @@
"react-helmet": "^5.2.0" "react-helmet": "^5.2.0"
}, },
"devDependencies": { "devDependencies": {
"@now/node": "^1.3.0" "@vercel/node": "1.8.5"
}, },
"scripts": { "scripts": {
"dev": "gatsby develop", "dev": "gatsby develop",

View File

@@ -31,7 +31,7 @@ function Index() {
</h2> </h2>
<p> <p>
<a <a
href="https://github.com/vercel/vercel/blob/master/gatsby" href="https://github.com/vercel/vercel/tree/master/examples/gatsby"
target="_blank" target="_blank"
rel="noreferrer noopener" rel="noreferrer noopener"
> >

View File

@@ -1107,15 +1107,6 @@
"@nodelib/fs.scandir" "2.1.3" "@nodelib/fs.scandir" "2.1.3"
fastq "^1.6.0" fastq "^1.6.0"
"@now/node@^1.3.0":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@now/node/-/node-1.7.1.tgz#764a0c6bcb24967f8014c4f73ad238c292996fe3"
integrity sha512-+srVKopsVTPDR3u9eOjJryZroLTrPp8XEOuIDGBdfFcJuS7qpAomctSbfyA7WNyjC0ExtUxELqBg5sAedG5+2g==
dependencies:
"@types/node" "*"
ts-node "8.9.1"
typescript "3.9.3"
"@pieh/friendly-errors-webpack-plugin@1.7.0-chalk-2": "@pieh/friendly-errors-webpack-plugin@1.7.0-chalk-2":
version "1.7.0-chalk-2" version "1.7.0-chalk-2"
resolved "https://registry.yarnpkg.com/@pieh/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.0-chalk-2.tgz#2e9da9d3ade9d18d013333eb408c457d04eabac0" resolved "https://registry.yarnpkg.com/@pieh/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.0-chalk-2.tgz#2e9da9d3ade9d18d013333eb408c457d04eabac0"
@@ -1409,6 +1400,15 @@
dependencies: dependencies:
wonka "^4.0.14" wonka "^4.0.14"
"@vercel/node@1.8.5":
version "1.8.5"
resolved "https://registry.yarnpkg.com/@vercel/node/-/node-1.8.5.tgz#2c8b9532f1bb25734a9964c52973386ed78022d4"
integrity sha512-1iw7FSR8Oau6vZB1MWfBnA5q2a/IqRHiSZSbt8lz0dyTF599q8pc5GcSv/TvmrYaEGzh3+N0S4cbmuMCqVlwJg==
dependencies:
"@types/node" "*"
ts-node "8.9.1"
typescript "3.9.3"
"@webassemblyjs/ast@1.9.0": "@webassemblyjs/ast@1.9.0":
version "1.9.0" version "1.9.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"

View File

@@ -14,6 +14,10 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
## Learn More ## Learn More
To learn more about Next.js, take a look at the following resources: To learn more about Next.js, take a look at the following resources:

View File

@@ -8,8 +8,8 @@
"start": "next start" "start": "next start"
}, },
"dependencies": { "dependencies": {
"next": "9.5.1", "next": "10.0.5",
"react": "16.13.1", "react": "17.0.1",
"react-dom": "16.13.1" "react-dom": "17.0.1"
} }
} }

View File

@@ -76,7 +76,6 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
max-width: 800px; max-width: 800px;
margin-top: 3rem; margin-top: 3rem;
} }

View File

@@ -1,5 +1,8 @@
/node_modules/
/public/build/
.DS_Store .DS_Store
node_modules
public/bundle.*
.env .env
.env.local
.env.build .env.build
.vercel

View File

@@ -1,2 +0,0 @@
yarn.lock
README.md

View File

@@ -1,24 +1,21 @@
{ {
"name": "svelte-app", "name": "svelte-app",
"version": "1.0.0", "private": true,
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv public"
},
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "^13.0.0", "@rollup/plugin-commonjs": "^14.0.0",
"@rollup/plugin-node-resolve": "^8.1.0", "@rollup/plugin-node-resolve": "^8.0.0",
"npm-run-all": "^4.1.5", "rollup": "^2.3.4",
"rollup": "^2.18.0", "rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-livereload": "^1.0.0", "rollup-plugin-svelte": "^6.0.0",
"rollup-plugin-svelte": "^5.0.3", "rollup-plugin-terser": "^7.0.0",
"rollup-plugin-terser": "^6.1.0",
"svelte": "^3.0.0" "svelte": "^3.0.0"
}, },
"dependencies": { "dependencies": {
"sirv-cli": "^1.0.1" "sirv-cli": "^1.0.0"
},
"scripts": {
"build": "rollup -c",
"autobuild": "rollup -c -w",
"dev": "run-p start:dev autobuild",
"start": "sirv public --single",
"start:dev": "sirv public --single --dev"
} }
} }

View File

@@ -1,17 +1,18 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf8" /> <meta charset='utf-8'>
<meta name="viewport" content="width=device-width" /> <meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte + Node.js API</title> <title>Svelte + Node.js API</title>
<link rel="icon" type="image/png" href="/favicon.png" /> <link rel='icon' type='image/png' href='/favicon.png'>
<link rel="stylesheet" href="/global.css" /> <link rel='stylesheet' href='/global.css'>
<link rel="stylesheet" href="/bundle.css" /> <link rel='stylesheet' href='/build/bundle.css'>
</head>
<body> <script defer src='/build/bundle.js'></script>
<script src="/bundle.js"></script> </head>
</body>
<body>
</body>
</html> </html>

View File

@@ -6,42 +6,70 @@ import { terser } from 'rollup-plugin-terser';
const production = !process.env.ROLLUP_WATCH; const production = !process.env.ROLLUP_WATCH;
function serve() {
let server;
function toExit() {
if (server) server.kill(0);
}
return {
writeBundle() {
if (server) return;
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
process.on('SIGTERM', toExit);
process.on('exit', toExit);
}
};
}
export default { export default {
input: 'src/main.js', input: 'src/main.js',
output: { output: {
sourcemap: true, sourcemap: true,
format: 'iife', format: 'iife',
name: 'app', name: 'app',
file: 'public/bundle.js', file: 'public/build/bundle.js'
}, },
plugins: [ plugins: [
svelte({ svelte({
// enable run-time checks when not in production // enable run-time checks when not in production
dev: !production, dev: !production,
// we'll extract any component CSS out into // we'll extract any component CSS out into
// a separate file better for performance // a separate file - better for performance
css: css => { css: css => {
css.write('public/bundle.css'); css.write('bundle.css');
}, }
}), }),
// If you have external dependencies installed from // If you have external dependencies installed from
// npm, you'll most likely need these plugins. In // npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration // some cases you'll need additional configuration -
// consult the documentation for details: // consult the documentation for details:
// https://github.com/rollup/rollup-plugin-commonjs // https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({ browser: true }), resolve({
commonjs(), browser: true,
dedupe: ['svelte']
}),
commonjs(),
// Watch the `public` directory and refresh the // In dev mode, call `npm run start` once
// browser on changes when not in production // the bundle has been generated
!production && livereload('public'), !production && serve(),
// If we're building for production (npm run build // Watch the `public` directory and refresh the
// instead of npm run dev), minify // browser on changes when not in production
production && terser(), !production && livereload('public'),
],
watch: { // If we're building for production (npm run build
clearScreen: false, // instead of npm run dev), minify
}, production && terser()
],
watch: {
clearScreen: false
}
}; };

View File

@@ -0,0 +1,128 @@
// @ts-check
/** This script modifies the project to support TS code in .svelte files like:
<script lang="ts">
export let name: string;
</script>
As well as validating the code for CI.
*/
/** To work on this script:
rm -rf test-template template && git clone sveltejs/template test-template && node scripts/setupTypeScript.js test-template
*/
const fs = require("fs")
const path = require("path")
const { argv } = require("process")
const projectRoot = argv[2] || path.join(__dirname, "..")
// Add deps to pkg.json
const packageJSON = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf8"))
packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, {
"svelte-check": "^1.0.0",
"svelte-preprocess": "^4.0.0",
"@rollup/plugin-typescript": "^6.0.0",
"typescript": "^3.9.3",
"tslib": "^2.0.0",
"@tsconfig/svelte": "^1.0.0"
})
// Add script for checking
packageJSON.scripts = Object.assign(packageJSON.scripts, {
"validate": "svelte-check"
})
// Write the package JSON
fs.writeFileSync(path.join(projectRoot, "package.json"), JSON.stringify(packageJSON, null, " "))
// mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too
const beforeMainJSPath = path.join(projectRoot, "src", "main.js")
const afterMainTSPath = path.join(projectRoot, "src", "main.ts")
fs.renameSync(beforeMainJSPath, afterMainTSPath)
// Switch the app.svelte file to use TS
const appSveltePath = path.join(projectRoot, "src", "App.svelte")
let appFile = fs.readFileSync(appSveltePath, "utf8")
appFile = appFile.replace("<script>", '<script lang="ts">')
appFile = appFile.replace("export let name;", 'export let name: string;')
fs.writeFileSync(appSveltePath, appFile)
// Edit rollup config
const rollupConfigPath = path.join(projectRoot, "rollup.config.js")
let rollupConfig = fs.readFileSync(rollupConfigPath, "utf8")
// Edit imports
rollupConfig = rollupConfig.replace(`'rollup-plugin-terser';`, `'rollup-plugin-terser';
import sveltePreprocess from 'svelte-preprocess';
import typescript from '@rollup/plugin-typescript';`)
// Replace name of entry point
rollupConfig = rollupConfig.replace(`'src/main.js'`, `'src/main.ts'`)
// Add preprocess to the svelte config, this is tricky because there's no easy signifier.
// Instead we look for `css:` then the next `}` and add the preprocessor to that
let foundCSS = false
let match
// https://regex101.com/r/OtNjwo/1
const configEditor = new RegExp(/css:.|\n*}/gmi)
while (( match = configEditor.exec(rollupConfig)) != null) {
if (foundCSS) {
const endOfCSSIndex = match.index + 1
rollupConfig = rollupConfig.slice(0, endOfCSSIndex) + ",\n preprocess: sveltePreprocess()," + rollupConfig.slice(endOfCSSIndex);
break
}
if (match[0].includes("css:")) foundCSS = true
}
// Add TypeScript
rollupConfig = rollupConfig.replace(
'commonjs(),',
'commonjs(),\n\t\ttypescript({\n\t\t\tsourceMap: !production,\n\t\t\tinlineSources: !production\n\t\t}),'
);
fs.writeFileSync(rollupConfigPath, rollupConfig)
// Add TSConfig
const tsconfig = `{
"extends": "@tsconfig/svelte/tsconfig.json",
"include": ["src/**/*"],
"exclude": ["node_modules/*", "__sapper__/*", "public/*"]
}`
const tsconfigPath = path.join(projectRoot, "tsconfig.json")
fs.writeFileSync(tsconfigPath, tsconfig)
// Delete this script, but not during testing
if (!argv[2]) {
// Remove the script
fs.unlinkSync(path.join(__filename))
// Check for Mac's DS_store file, and if it's the only one left remove it
const remainingFiles = fs.readdirSync(path.join(__dirname))
if (remainingFiles.length === 1 && remainingFiles[0] === '.DS_store') {
fs.unlinkSync(path.join(__dirname, '.DS_store'))
}
// Check if the scripts folder is empty
if (fs.readdirSync(path.join(__dirname)).length === 0) {
// Remove the scripts folder
fs.rmdirSync(path.join(__dirname))
}
}
// Adds the extension recommendation
fs.mkdirSync(path.join(projectRoot, ".vscode"))
fs.writeFileSync(path.join(projectRoot, ".vscode", "extensions.json"), `{
"recommendations": ["svelte.svelte-vscode"]
}
`)
console.log("Converted to TypeScript.")
if (fs.existsSync(path.join(projectRoot, "node_modules"))) {
console.log("\nYou will need to re-run your dependency manager to get started.")
}

View File

@@ -1,10 +1,10 @@
import App from './App.svelte'; import App from './App.svelte';
const app = new App({ const app = new App({
target: document.body, target: document.body,
props: { props: {
name: 'world', name: 'world'
}, }
}); });
export default app; export default app;

635
examples/svelte/yarn.lock Normal file
View File

@@ -0,0 +1,635 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/code-frame@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
dependencies:
"@babel/highlight" "^7.10.4"
"@babel/helper-validator-identifier@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
"@babel/highlight@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
dependencies:
"@babel/helper-validator-identifier" "^7.10.4"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@polka/url@^1.0.0-next.9":
version "1.0.0-next.11"
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
integrity sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA==
"@rollup/plugin-commonjs@^14.0.0":
version "14.0.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-14.0.0.tgz#4285f9ec2db686a31129e5a2b415c94aa1f836f0"
integrity sha512-+PSmD9ePwTAeU106i9FRdc+Zb3XUWyW26mo5Atr2mk82hor8+nPwkztEjFo8/B1fJKfaQDg9aM2bzQkjhi7zOw==
dependencies:
"@rollup/pluginutils" "^3.0.8"
commondir "^1.0.1"
estree-walker "^1.0.1"
glob "^7.1.2"
is-reference "^1.1.2"
magic-string "^0.25.2"
resolve "^1.11.0"
"@rollup/plugin-node-resolve@^8.0.0":
version "8.4.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.4.0.tgz#261d79a680e9dc3d86761c14462f24126ba83575"
integrity sha512-LFqKdRLn0ShtQyf6SBYO69bGE1upV6wUhBX0vFOUnLAyzx5cwp8svA0eHUnu8+YU57XOkrMtfG63QOpQx25pHQ==
dependencies:
"@rollup/pluginutils" "^3.1.0"
"@types/resolve" "1.17.1"
builtin-modules "^3.1.0"
deep-freeze "^0.0.1"
deepmerge "^4.2.2"
is-module "^1.0.0"
resolve "^1.17.0"
"@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
dependencies:
"@types/estree" "0.0.39"
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@types/estree@*":
version "0.0.45"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884"
integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==
"@types/estree@0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
"@types/node@*":
version "14.14.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.7.tgz#8ea1e8f8eae2430cf440564b98c6dfce1ec5945d"
integrity sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==
"@types/resolve@1.17.1":
version "1.17.1"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
dependencies:
"@types/node" "*"
ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
anymatch@~3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"
async-limiter@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
binary-extensions@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
builtin-modules@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==
chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chokidar@^3.3.0:
version "3.4.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b"
integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==
dependencies:
anymatch "~3.1.1"
braces "~3.0.2"
glob-parent "~5.1.0"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.5.0"
optionalDependencies:
fsevents "~2.1.2"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
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"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
console-clear@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/console-clear/-/console-clear-1.1.1.tgz#995e20cbfbf14dd792b672cde387bd128d674bf7"
integrity sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==
deep-freeze@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84"
integrity sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=
deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
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"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
estree-walker@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
estree-walker@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
fsevents@~2.1.2:
version "2.1.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
get-port@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc"
integrity sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=
glob-parent@~5.1.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
dependencies:
is-glob "^4.0.1"
glob@^7.1.2:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
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"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
dependencies:
binary-extensions "^2.0.0"
is-core-module@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.1.0.tgz#a4cc031d9b1aca63eecbd18a650e13cb4eeab946"
integrity sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==
dependencies:
has "^1.0.3"
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
dependencies:
is-extglob "^2.1.1"
is-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-reference@^1.1.2:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
dependencies:
"@types/estree" "*"
jest-worker@^26.2.1:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
supports-color "^7.0.0"
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
kleur@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
livereload-js@^3.1.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-3.3.1.tgz#61f887468086762e61fb2987412cf9d1dda99202"
integrity sha512-CBu1gTEfzVhlOK1WASKAAJ9Qx1fHECTq0SUB67sfxwQssopTyvzqTlgl+c0h9pZ6V+Fzd2rc510ppuNusg9teQ==
livereload@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/livereload/-/livereload-0.9.1.tgz#65125dabdf2db4fd3f1169e953fe56e3bcc6f477"
integrity sha512-9g7sua11kkyZNo2hLRCG3LuZZwqexoyEyecSlV8cAsfAVVCZqLzVir6XDqmH0r+Vzgnd5LrdHDMyjtFnJQLAYw==
dependencies:
chokidar "^3.3.0"
livereload-js "^3.1.0"
opts ">= 1.2.0"
ws "^6.2.1"
local-access@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/local-access/-/local-access-1.0.1.tgz#5121258146d64e869046c642ea4f1dd39ff942bb"
integrity sha512-ykt2pgN0aqIy6KQC1CqdWTWkmUwNgaOS6dcpHVjyBJONA+Xi7AtSB1vuxC/U/0tjIP3wcRudwQk1YYzUvzk2bA==
magic-string@^0.25.2:
version "0.25.7"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
dependencies:
sourcemap-codec "^1.4.4"
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
mime@^2.3.1:
version "2.4.6"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1"
integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"
mri@^1.1.0:
version "1.1.6"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.6.tgz#49952e1044db21dbf90f6cd92bc9c9a777d415a6"
integrity sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
"opts@>= 1.2.0":
version "2.0.2"
resolved "https://registry.yarnpkg.com/opts/-/opts-2.0.2.tgz#a17e189fbbfee171da559edd8a42423bc5993ce1"
integrity sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==
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"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
dependencies:
safe-buffer "^5.1.0"
readdirp@~3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
dependencies:
picomatch "^2.2.1"
require-relative@^0.8.7:
version "0.8.7"
resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de"
integrity sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=
resolve@^1.11.0, resolve@^1.17.0:
version "1.19.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
dependencies:
is-core-module "^2.1.0"
path-parse "^1.0.6"
rollup-plugin-livereload@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.0.tgz#d3928d74e8cf2ae4286c5dd46b770fd3f3b82313"
integrity sha512-oC/8NqumGYuphkqrfszOHUUIwzKsaHBICw6QRwT5uD07gvePTS+HW+GFwu6f9K8W02CUuTvtIM9AWJrbj4wE1A==
dependencies:
livereload "^0.9.1"
rollup-plugin-svelte@^6.0.0:
version "6.1.1"
resolved "https://registry.yarnpkg.com/rollup-plugin-svelte/-/rollup-plugin-svelte-6.1.1.tgz#66362cf0500fb7a848283ebcf19d289a60ef0871"
integrity sha512-ijnm0pH1ScrY4uxwaNXBpNVejVzpL2769hIEbAlnqNUWZrffLspu5/k9/l/Wsj3NrEHLQ6wCKGagVJonyfN7ow==
dependencies:
require-relative "^0.8.7"
rollup-pluginutils "^2.8.2"
sourcemap-codec "^1.4.8"
rollup-plugin-terser@^7.0.0:
version "7.0.2"
resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==
dependencies:
"@babel/code-frame" "^7.10.4"
jest-worker "^26.2.1"
serialize-javascript "^4.0.0"
terser "^5.0.0"
rollup-pluginutils@^2.8.2:
version "2.8.2"
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e"
integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==
dependencies:
estree-walker "^0.6.1"
rollup@^2.3.4:
version "2.33.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.33.1.tgz#802795164164ee63cd47769d8879c33ec8ae0c40"
integrity sha512-uY4O/IoL9oNW8MMcbA5hcOaz6tZTMIh7qJHx/tzIJm+n1wLoY38BLn6fuy7DhR57oNFLMbDQtDeJoFURt5933w==
optionalDependencies:
fsevents "~2.1.2"
sade@^1.6.0:
version "1.7.4"
resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.4.tgz#ea681e0c65d248d2095c90578c03ca0bb1b54691"
integrity sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==
dependencies:
mri "^1.1.0"
safe-buffer@^5.1.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
semiver@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/semiver/-/semiver-1.1.0.tgz#9c97fb02c21c7ce4fcf1b73e2c7a24324bdddd5f"
integrity sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==
serialize-javascript@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
dependencies:
randombytes "^2.1.0"
sirv-cli@^1.0.0:
version "1.0.8"
resolved "https://registry.yarnpkg.com/sirv-cli/-/sirv-cli-1.0.8.tgz#150c3f62694203a86cf5d71ec60e6ff4c34064a9"
integrity sha512-bJI+kkzQvMKfAOfgLzv09kWsdymLm39LgKmGjacB19GHIAQLCvXXg8e8HzcofTjDZlA8zVv4dQjU9SWkNzkJhw==
dependencies:
console-clear "^1.1.0"
get-port "^3.2.0"
kleur "^3.0.0"
local-access "^1.0.1"
sade "^1.6.0"
semiver "^1.0.0"
sirv "^1.0.7"
tinydate "^1.0.0"
sirv@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.7.tgz#ad8ca1f84430777a59162592626c2b8e9b9f1384"
integrity sha512-QMT2OTD3CTr8de9VByPmvSEeyt6k8/Cxg0J2kQJ5HNhIWfhFg9ypcIWWzez9rPWnGj+WtJ7AZD/MdT/vdilV/A==
dependencies:
"@polka/url" "^1.0.0-next.9"
mime "^2.3.1"
totalist "^1.0.0"
source-map-support@~0.5.19:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@~0.7.2:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8:
version "1.4.8"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
supports-color@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
svelte@^3.0.0:
version "3.29.7"
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.29.7.tgz#e254eb2d0d609ce0fd60f052d444ac4a66d90f7d"
integrity sha512-rx0g311kBODvEWUU01DFBUl3MJuJven04bvTVFUG/w0On/wuj0PajQY/QlXcJndFxG+W1s8iXKaB418tdHWc3A==
terser@^5.0.0:
version "5.3.8"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.3.8.tgz#991ae8ba21a3d990579b54aa9af11586197a75dd"
integrity sha512-zVotuHoIfnYjtlurOouTazciEfL7V38QMAOhGqpXDEg6yT13cF4+fEP9b0rrCEQTn+tT46uxgFsTZzhygk+CzQ==
dependencies:
commander "^2.20.0"
source-map "~0.7.2"
source-map-support "~0.5.19"
tinydate@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/tinydate/-/tinydate-1.3.0.tgz#e6ca8e5a22b51bb4ea1c3a2a4fd1352dbd4c57fb"
integrity sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
totalist@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
dependencies:
async-limiter "~1.0.0"

View File

@@ -17,6 +17,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `blitz build`" "placeholder": "`npm run build` or `blitz build`"
}, },
@@ -47,6 +50,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `next build`" "placeholder": "`npm run build` or `next build`"
}, },
@@ -56,7 +62,13 @@
"outputDirectory": { "outputDirectory": {
"placeholder": "Next.js default" "placeholder": "Next.js default"
} }
} },
"recommendedIntegrations": [
{
"id": "oac_5lUsiANun1DEzgLg0NZx5Es3",
"dependencies": ["next-plugin-sentry", "next-sentry-source-maps"]
}
]
}, },
{ {
"name": "Gatsby.js", "name": "Gatsby.js",
@@ -76,6 +88,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `gatsby build`" "placeholder": "`npm run build` or `gatsby build`"
}, },
@@ -105,6 +120,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `hexo generate`" "placeholder": "`npm run build` or `hexo generate`"
}, },
@@ -134,6 +152,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `npx @11ty/eleventy`" "placeholder": "`npm run build` or `npx @11ty/eleventy`"
}, },
@@ -162,6 +183,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `docusaurus build`" "placeholder": "`npm run build` or `docusaurus build`"
}, },
@@ -190,6 +214,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `docusaurus-build`" "placeholder": "`npm run build` or `docusaurus-build`"
}, },
@@ -218,6 +245,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `preact build`" "placeholder": "`npm run build` or `preact build`"
}, },
@@ -249,6 +279,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `dojo build`" "placeholder": "`npm run build` or `dojo build`"
}, },
@@ -277,6 +310,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `ember build`" "placeholder": "`npm run build` or `ember build`"
}, },
@@ -305,6 +341,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `vue-cli-service build`" "placeholder": "`npm run build` or `vue-cli-service build`"
}, },
@@ -333,6 +372,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `ng build && scully`" "placeholder": "`npm run build` or `ng build && scully`"
}, },
@@ -361,6 +403,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `ng build`" "placeholder": "`npm run build` or `ng build`"
}, },
@@ -389,6 +434,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `ng build`" "placeholder": "`npm run build` or `ng build`"
}, },
@@ -417,6 +465,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `polymer build`" "placeholder": "`npm run build` or `polymer build`"
}, },
@@ -445,6 +496,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `rollup -c`" "placeholder": "`npm run build` or `rollup -c`"
}, },
@@ -473,6 +527,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `react-scripts build`" "placeholder": "`npm run build` or `react-scripts build`"
}, },
@@ -505,6 +562,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `react-scripts build`" "placeholder": "`npm run build` or `react-scripts build`"
}, },
@@ -533,6 +593,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `gridsome build`" "placeholder": "`npm run build` or `gridsome build`"
}, },
@@ -561,6 +624,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `umi build`" "placeholder": "`npm run build` or `umi build`"
}, },
@@ -589,6 +655,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `sapper export`" "placeholder": "`npm run build` or `sapper export`"
}, },
@@ -617,6 +686,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `saber build`" "placeholder": "`npm run build` or `saber build`"
}, },
@@ -645,6 +717,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `stencil build`" "placeholder": "`npm run build` or `stencil build`"
}, },
@@ -673,6 +748,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `nuxt generate`" "placeholder": "`npm run build` or `nuxt generate`"
}, },
@@ -703,6 +781,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"value": "yarn rw build && yarn rw db up --no-db-client --auto-approve && yarn rw dataMigrate up" "value": "yarn rw build && yarn rw db up --no-db-client --auto-approve && yarn rw dataMigrate up"
}, },
@@ -737,6 +818,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "None"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `hugo -D --gc`" "placeholder": "`npm run build` or `hugo -D --gc`"
}, },
@@ -764,6 +848,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"value": "bundle install"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `jekyll build`" "placeholder": "`npm run build` or `jekyll build`"
}, },
@@ -791,6 +878,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run build` or `brunch build --production`" "placeholder": "`npm run build` or `brunch build --production`"
}, },
@@ -818,6 +908,9 @@
] ]
}, },
"settings": { "settings": {
"installCommand": {
"value": "bundle install"
},
"buildCommand": { "buildCommand": {
"value": "`npm run build` or `bundle exec middleman build`" "value": "`npm run build` or `bundle exec middleman build`"
}, },
@@ -835,6 +928,9 @@
"logo": "https://raw.githubusercontent.com/vercel/vercel/master/packages/frameworks/logos/other.svg", "logo": "https://raw.githubusercontent.com/vercel/vercel/master/packages/frameworks/logos/other.svg",
"description": "No framework or a unoptimized framework.", "description": "No framework or a unoptimized framework.",
"settings": { "settings": {
"installCommand": {
"placeholder": "`yarn install` or `npm install`"
},
"buildCommand": { "buildCommand": {
"placeholder": "`npm run vercel-build` or `npm run build`" "placeholder": "`npm run vercel-build` or `npm run build`"
}, },

View File

@@ -31,4 +31,8 @@ export interface Framework {
devCommand: Setting; devCommand: Setting;
outputDirectory: Setting; outputDirectory: Setting;
}; };
recommendedIntegrations?: {
id: string;
dependencies: string[];
}[];
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/frameworks", "name": "@vercel/frameworks",
"version": "0.1.1", "version": "0.2.0",
"main": "frameworks.json", "main": "frameworks.json",
"license": "UNLICENSED", "license": "UNLICENSED",
"scripts": { "scripts": {

View File

@@ -89,14 +89,39 @@ const Schema = {
}, },
settings: { settings: {
type: 'object', type: 'object',
required: ['buildCommand', 'devCommand', 'outputDirectory'], required: [
'installCommand',
'buildCommand',
'devCommand',
'outputDirectory',
],
additionalProperties: false, additionalProperties: false,
properties: { properties: {
installCommand: SchemaSettings,
buildCommand: SchemaSettings, buildCommand: SchemaSettings,
devCommand: SchemaSettings, devCommand: SchemaSettings,
outputDirectory: SchemaSettings, outputDirectory: SchemaSettings,
}, },
}, },
recommendedIntegrations: {
type: 'array',
items: {
type: 'object',
required: ['id', 'dependencies'],
additionalProperties: false,
properties: {
id: {
type: 'string',
},
dependencies: {
type: 'array',
items: {
type: 'string',
},
},
},
},
},
}, },
}, },
}; };

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/build-utils", "name": "@vercel/build-utils",
"version": "2.5.3", "version": "2.7.0",
"license": "MIT", "license": "MIT",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.js", "types": "./dist/index.d.js",
@@ -29,7 +29,7 @@
"@types/node-fetch": "^2.1.6", "@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0", "@types/semver": "6.0.0",
"@types/yazl": "^2.4.1", "@types/yazl": "^2.4.1",
"@vercel/frameworks": "0.1.1", "@vercel/frameworks": "0.2.0",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"aggregate-error": "3.0.1", "aggregate-error": "3.0.1",
"async-retry": "1.2.3", "async-retry": "1.2.3",

View File

@@ -24,6 +24,7 @@ interface Options {
projectSettings?: { projectSettings?: {
framework?: string | null; framework?: string | null;
devCommand?: string | null; devCommand?: string | null;
installCommand?: string | null;
buildCommand?: string | null; buildCommand?: string | null;
outputDirectory?: string | null; outputDirectory?: string | null;
createdAt?: number; createdAt?: number;
@@ -42,9 +43,8 @@ export function sortFiles(fileA: string, fileB: string) {
export function detectApiExtensions(builders: Builder[]): Set<string> { export function detectApiExtensions(builders: Builder[]): Set<string> {
return new Set<string>( return new Set<string>(
builders builders
.filter( .filter((b): b is Builder & { src: string } =>
b => Boolean(b.config && b.config.zeroConfig && b.src?.startsWith('api/'))
b.config && b.config.zeroConfig && b.src && b.src.startsWith('api/')
) )
.map(b => extname(b.src)) .map(b => extname(b.src))
.filter(Boolean) .filter(Boolean)
@@ -55,22 +55,28 @@ export function detectApiDirectory(builders: Builder[]): string | null {
// TODO: We eventually want to save the api directory to // TODO: We eventually want to save the api directory to
// builder.config.apiDirectory so it is only detected once // builder.config.apiDirectory so it is only detected once
const found = builders.some( const found = builders.some(
b => b.config && b.config.zeroConfig && b.src.startsWith('api/') b => b.config && b.config.zeroConfig && b.src?.startsWith('api/')
); );
return found ? 'api' : null; return found ? 'api' : null;
} }
// TODO: Replace this function with `config.outputDirectory` // TODO: Replace this function with `config.outputDirectory`
function getPublicBuilder(builders: Builder[]): Builder | null { function getPublicBuilder(
const builder = builders.find( builders: Builder[]
builder => ): (Builder & { src: string }) | null {
for (const builder of builders) {
if (
typeof builder.src === 'string' &&
isOfficialRuntime('static', builder.use) && isOfficialRuntime('static', builder.use) &&
/^.*\/\*\*\/\*$/.test(builder.src) && /^.*\/\*\*\/\*$/.test(builder.src) &&
builder.config && builder.config &&
builder.config.zeroConfig === true builder.config.zeroConfig === true
); ) {
return builder as Builder & { src: string };
}
}
return builder || null; return null;
} }
export function detectOutputDirectory(builders: Builder[]): string | null { export function detectOutputDirectory(builders: Builder[]): string | null {
// TODO: We eventually want to save the output directory to // TODO: We eventually want to save the output directory to
@@ -360,7 +366,7 @@ function maybeGetApiBuilder(
return null; return null;
} }
const match = apiMatches.find(({ src }) => { const match = apiMatches.find(({ src = '**' }) => {
return src === fileName || minimatch(fileName, src); return src === fileName || minimatch(fileName, src);
}); });
@@ -450,6 +456,10 @@ function detectFrontBuilder(
config.devCommand = projectSettings.devCommand; config.devCommand = projectSettings.devCommand;
} }
if (typeof projectSettings.installCommand === 'string') {
config.installCommand = projectSettings.installCommand;
}
if (projectSettings.buildCommand) { if (projectSettings.buildCommand) {
config.buildCommand = projectSettings.buildCommand; config.buildCommand = projectSettings.buildCommand;
} }
@@ -458,7 +468,10 @@ function detectFrontBuilder(
config.outputDirectory = projectSettings.outputDirectory; config.outputDirectory = projectSettings.outputDirectory;
} }
if (pkg && (framework !== null || createdAt < Date.parse('2020-03-01'))) { if (
pkg &&
(framework === undefined || createdAt < Date.parse('2020-03-01'))
) {
const deps: PackageJson['dependencies'] = { const deps: PackageJson['dependencies'] = {
...pkg.dependencies, ...pkg.dependencies,
...pkg.devDependencies, ...pkg.devDependencies,
@@ -981,7 +994,6 @@ function getRouteResult(
rewriteRoutes.push({ rewriteRoutes.push({
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
status: 404, status: 404,
continue: true,
}); });
} }
} else { } else {

View File

@@ -292,6 +292,11 @@ export async function runNpmInstall(
opts.prettyCommand = 'yarn install'; opts.prettyCommand = 'yarn install';
command = 'yarn'; command = 'yarn';
commandArgs = ['install', ...args]; commandArgs = ['install', ...args];
// Yarn v2 PnP mode may be activated, so force "node-modules" linker style
if (!env.YARN_NODE_LINKER) {
env.YARN_NODE_LINKER = 'node-modules';
}
} }
if (process.env.NPM_ONLY_PRODUCTION) { if (process.env.NPM_ONLY_PRODUCTION) {
@@ -388,10 +393,17 @@ export async function runPackageJsonScript(
prettyCommand, prettyCommand,
}); });
} else { } else {
// Yarn v2 PnP mode may be activated, so force "node-modules" linker style
const env: typeof process.env = { ...spawnOpts?.env };
if (!env.YARN_NODE_LINKER) {
env.YARN_NODE_LINKER = 'node-modules';
}
const prettyCommand = `yarn run ${scriptName}`; const prettyCommand = `yarn run ${scriptName}`;
console.log(`Running "${prettyCommand}"`); console.log(`Running "${prettyCommand}"`);
await spawnAsync('yarn', ['run', scriptName], { await spawnAsync('yarn', ['run', scriptName], {
...spawnOpts, ...spawnOpts,
env,
cwd: destPath, cwd: destPath,
prettyCommand, prettyCommand,
}); });

View File

@@ -41,6 +41,7 @@ export interface Config {
import?: { [key: string]: string }; import?: { [key: string]: string };
functions?: BuilderFunctions; functions?: BuilderFunctions;
outputDirectory?: string; outputDirectory?: string;
installCommand?: string;
buildCommand?: string; buildCommand?: string;
devCommand?: string; devCommand?: string;
framework?: string; framework?: string;
@@ -335,7 +336,7 @@ export interface NodeVersion {
export interface Builder { export interface Builder {
use: string; use: string;
src: string; src?: string;
config?: Config; config?: Config;
} }

View File

@@ -0,0 +1,5 @@
const { camelCase } = require('camel-case');
module.exports = (req, res) => {
res.end(camelCase('camel-case module is working'));
};

View File

@@ -1,5 +0,0 @@
{
"version": 2,
"builds": [{ "src": "package.json", "use": "@vercel/static-build" }],
"probes": [{ "path": "/", "mustContain": "Svelte app" }]
}

View File

@@ -16,6 +16,7 @@
"svelte": "^3.0.0" "svelte": "^3.0.0"
}, },
"dependencies": { "dependencies": {
"camel-case": "^4.1.2",
"sirv-cli": "^0.4.4" "sirv-cli": "^0.4.4"
} }
} }

View File

@@ -0,0 +1,11 @@
{
"version": 2,
"builds": [
{ "src": "package.json", "use": "@vercel/static-build" },
{ "src": "api/index.js", "use": "@vercel/node" }
],
"probes": [
{ "path": "/", "mustContain": "Svelte app" },
{ "path": "/api", "mustContain": "camelCaseModuleIsWorking" }
]
}

View File

@@ -270,6 +270,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"camel-case@npm:^4.1.2":
version: 4.1.2
resolution: "camel-case@npm:4.1.2"
dependencies:
pascal-case: ^3.1.2
tslib: ^2.0.3
checksum: 3/0b8dcfb424c9497e45984b88ef005c66bdf8e877e36365aedfc3cf73182684fde5a14cf2c526579c0351a5f27dc39a00f1edecc25d43606075fea948c504e37f
languageName: node
linkType: hard
"caseless@npm:~0.12.0": "caseless@npm:~0.12.0":
version: 0.12.0 version: 0.12.0
resolution: "caseless@npm:0.12.0" resolution: "caseless@npm:0.12.0"
@@ -850,6 +860,15 @@ fsevents@~2.1.2:
languageName: node languageName: node
linkType: hard linkType: hard
"lower-case@npm:^2.0.2":
version: 2.0.2
resolution: "lower-case@npm:2.0.2"
dependencies:
tslib: ^2.0.3
checksum: 3/aabaca9cef65f7564a1005b625664527e4d169e363101e65773f8f6ff2fdcf09884a3bc02990cd7a62cf05f3538114af25ee7bef553f1ca3208c8a77ac75cbfa
languageName: node
linkType: hard
"magic-string@npm:^0.25.2": "magic-string@npm:^0.25.2":
version: 0.25.7 version: 0.25.7
resolution: "magic-string@npm:0.25.7" resolution: "magic-string@npm:0.25.7"
@@ -944,6 +963,16 @@ fsevents@~2.1.2:
languageName: node languageName: node
linkType: hard linkType: hard
"no-case@npm:^3.0.4":
version: 3.0.4
resolution: "no-case@npm:3.0.4"
dependencies:
lower-case: ^2.0.2
tslib: ^2.0.3
checksum: 3/84db4909caec37504c6655f995a004067f8733be8cd8d849f1578661b60a1685e086325fa4e1a5e8ce94e7416c1d0f037e2a00f635a14457183de80ab4fc7612
languageName: node
linkType: hard
"node-gyp@npm:latest": "node-gyp@npm:latest":
version: 6.1.0 version: 6.1.0
resolution: "node-gyp@npm:6.1.0" resolution: "node-gyp@npm:6.1.0"
@@ -1057,6 +1086,16 @@ fsevents@~2.1.2:
languageName: node languageName: node
linkType: hard linkType: hard
"pascal-case@npm:^3.1.2":
version: 3.1.2
resolution: "pascal-case@npm:3.1.2"
dependencies:
no-case: ^3.0.4
tslib: ^2.0.3
checksum: 3/31708cecab221482edc81e2bd9b9d8282d72d4f1443b31f39725aa23768c5e42d93c4c014f1bc90f7f074e2a70d5091e4892ea370e550affc9ccf1d33c900bcd
languageName: node
linkType: hard
"path-is-absolute@npm:^1.0.0": "path-is-absolute@npm:^1.0.0":
version: 1.0.1 version: 1.0.1
resolution: "path-is-absolute@npm:1.0.1" resolution: "path-is-absolute@npm:1.0.1"
@@ -1447,6 +1486,7 @@ fsevents@~2.1.2:
dependencies: dependencies:
"@rollup/plugin-commonjs": ^12.0.0 "@rollup/plugin-commonjs": ^12.0.0
"@rollup/plugin-node-resolve": ^8.0.0 "@rollup/plugin-node-resolve": ^8.0.0
camel-case: ^4.1.2
rollup: ^2.3.4 rollup: ^2.3.4
rollup-plugin-livereload: ^1.0.0 rollup-plugin-livereload: ^1.0.0
rollup-plugin-svelte: ^5.0.3 rollup-plugin-svelte: ^5.0.3
@@ -1517,6 +1557,13 @@ fsevents@~2.1.2:
languageName: node languageName: node
linkType: hard linkType: hard
"tslib@npm:^2.0.3":
version: 2.0.3
resolution: "tslib@npm:2.0.3"
checksum: 3/447bfca5deaa157806c3f77eaba74d05dd0b38b014e47ce79d98b5c77ce7d91b00a687ba13ca1b5a74d35ca1098ac7a072c0a97fad06f0266612f2a03a6c8e8f
languageName: node
linkType: hard
"tunnel-agent@npm:^0.6.0": "tunnel-agent@npm:^0.6.0":
version: 0.6.0 version: 0.6.0
resolution: "tunnel-agent@npm:0.6.0" resolution: "tunnel-agent@npm:0.6.0"

View File

@@ -182,7 +182,7 @@ describe('Test `detectBuilders`', () => {
const { builders } = await detectBuilders(files); const { builders } = await detectBuilders(files);
expect(builders!.length).toBe(7); expect(builders!.length).toBe(7);
expect(builders!.some(b => b.src.endsWith('_test.go'))).toBe(false); expect(builders!.some(b => b.src!.endsWith('_test.go'))).toBe(false);
}); });
it('just public', async () => { it('just public', async () => {
@@ -833,6 +833,50 @@ describe('Test `detectBuilders`', () => {
describe('Test `detectBuilders` with `featHandleMiss=true`', () => { describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
const featHandleMiss = true; const featHandleMiss = true;
it('should select "installCommand"', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = ['package.json', 'pages/index.js', 'public/index.html'];
const { builders, errors } = await detectBuilders(files, pkg, {
featHandleMiss,
projectSettings: {
installCommand: 'npx pnpm install',
},
});
expect(errors).toBe(null);
expect(builders).toBeDefined();
expect(builders!.length).toStrictEqual(1);
expect(builders![0].src).toStrictEqual('package.json');
expect(builders![0].use).toStrictEqual('@vercel/next');
expect(builders![0].config!.zeroConfig).toStrictEqual(true);
expect(builders![0].config!.installCommand).toStrictEqual(
'npx pnpm install'
);
});
it('should select empty "installCommand"', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = ['package.json', 'pages/index.js', 'public/index.html'];
const { builders, errors } = await detectBuilders(files, pkg, {
featHandleMiss,
projectSettings: {
installCommand: '',
},
});
expect(errors).toBe(null);
expect(builders).toBeDefined();
expect(builders!.length).toStrictEqual(1);
expect(builders![0].src).toStrictEqual('package.json');
expect(builders![0].use).toStrictEqual('@vercel/next');
expect(builders![0].config!.zeroConfig).toStrictEqual(true);
expect(builders![0].config!.installCommand).toStrictEqual('');
});
it('should never select now.json src', async () => { it('should never select now.json src', async () => {
const files = ['docs/index.md', 'mkdocs.yml', 'now.json']; const files = ['docs/index.md', 'mkdocs.yml', 'now.json'];
const { builders, errors } = await detectBuilders(files, null, { const { builders, errors } = await detectBuilders(files, null, {
@@ -1080,6 +1124,46 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
expect(errorRoutes).toStrictEqual([]); expect(errorRoutes).toStrictEqual([]);
}); });
it('Using "Create React App" framework with `next` in dependencies should NOT autodetect Next.js for new projects', async () => {
const pkg = {
scripts: {
dev: 'react-scripts start',
build: 'react-scripts build',
},
dependencies: {
next: '9.3.5',
react: '16.13.1',
'react-dom': '16.13.1',
'react-scripts': '2.1.1',
},
};
const files = ['package.json', 'src/index.js', 'public/favicon.ico'];
const projectSettings = {
framework: 'create-react-app',
buildCommand: 'react-scripts build',
createdAt: Date.parse('2020-07-01'),
};
const { builders, errorRoutes } = await detectBuilders(files, pkg, {
projectSettings,
featHandleMiss,
});
expect(builders).toEqual([
{
use: '@vercel/static-build',
src: 'package.json',
config: {
zeroConfig: true,
framework: projectSettings.framework,
buildCommand: projectSettings.buildCommand,
},
},
]);
expect(errorRoutes!.length).toBe(1);
expect((errorRoutes![0] as Source).status).toBe(404);
});
it('Using "Other" framework with Storybook should NOT autodetect Next.js for new projects', async () => { it('Using "Other" framework with Storybook should NOT autodetect Next.js for new projects', async () => {
const pkg = { const pkg = {
scripts: { scripts: {
@@ -1257,7 +1341,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
featHandleMiss, featHandleMiss,
}); });
expect(builders!.length).toBe(7); expect(builders!.length).toBe(7);
expect(builders!.some(b => b.src.endsWith('_test.go'))).toBe(false); expect(builders!.some(b => b.src!.endsWith('_test.go'))).toBe(false);
expect(errorRoutes!.length).toBe(1); expect(errorRoutes!.length).toBe(1);
expect((errorRoutes![0] as Source).status).toBe(404); expect((errorRoutes![0] as Source).status).toBe(404);
}); });
@@ -2309,7 +2393,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
expect(errorRoutes).toStrictEqual([ expect(errorRoutes).toStrictEqual([
@@ -2411,7 +2494,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2449,7 +2531,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2487,7 +2568,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2520,7 +2600,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2548,7 +2627,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2579,7 +2657,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2606,7 +2683,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2641,7 +2717,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
expect(errorRoutes).toStrictEqual([ expect(errorRoutes).toStrictEqual([
@@ -2736,7 +2811,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2769,7 +2843,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2803,7 +2876,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2829,7 +2901,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2853,7 +2924,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2878,7 +2948,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2899,7 +2968,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -2934,7 +3002,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
@@ -2992,7 +3059,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -3025,7 +3091,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -3059,7 +3124,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -3078,7 +3142,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -3102,7 +3165,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -3127,7 +3189,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }
@@ -3148,7 +3209,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
{ {
status: 404, status: 404,
src: '^/api(/.*)?$', src: '^/api(/.*)?$',
continue: true,
}, },
]); ]);
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "vercel", "name": "vercel",
"version": "20.1.1", "version": "21.1.0",
"preferGlobal": true, "preferGlobal": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "The command-line interface for Vercel", "description": "The command-line interface for Vercel",
@@ -13,7 +13,7 @@
"scripts": { "scripts": {
"preinstall": "node ./scripts/preinstall.js", "preinstall": "node ./scripts/preinstall.js",
"test-unit": "nyc ava test/unit.js test/dev-builder.unit.js test/dev-router.unit.js test/dev-server.unit.js test/dev-validate.unit.js --serial --fail-fast --verbose", "test-unit": "nyc ava test/unit.js test/dev-builder.unit.js test/dev-router.unit.js test/dev-server.unit.js test/dev-validate.unit.js --serial --fail-fast --verbose",
"test-integration-cli": "ava test/integration.js --serial --fail-fast --verbose", "test-integration-cli": "rimraf test/fixtures/integration && ava test/integration.js --serial --fail-fast --verbose",
"test-integration-dev": "ava test/dev/integration.js --serial --fail-fast --verbose", "test-integration-dev": "ava test/dev/integration.js --serial --fail-fast --verbose",
"prepublishOnly": "yarn build", "prepublishOnly": "yarn build",
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov", "coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
@@ -61,11 +61,11 @@
"node": ">= 10" "node": ">= 10"
}, },
"dependencies": { "dependencies": {
"@vercel/build-utils": "2.5.3", "@vercel/build-utils": "2.7.0",
"@vercel/go": "1.1.6", "@vercel/go": "1.1.7",
"@vercel/node": "1.8.3", "@vercel/node": "1.9.0",
"@vercel/python": "1.2.3", "@vercel/python": "1.2.4",
"@vercel/ruby": "1.2.4", "@vercel/ruby": "1.2.5",
"update-notifier": "4.1.0" "update-notifier": "4.1.0"
}, },
"devDependencies": { "devDependencies": {
@@ -100,7 +100,7 @@
"@types/universal-analytics": "0.4.2", "@types/universal-analytics": "0.4.2",
"@types/which": "1.3.2", "@types/which": "1.3.2",
"@types/write-json-file": "2.2.1", "@types/write-json-file": "2.2.1",
"@vercel/frameworks": "0.1.1", "@vercel/frameworks": "0.2.0",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"@zeit/fun": "0.11.2", "@zeit/fun": "0.11.2",
"@zeit/source-map-support": "0.6.2", "@zeit/source-map-support": "0.6.2",
@@ -146,7 +146,6 @@
"minimatch": "3.0.4", "minimatch": "3.0.4",
"mri": "1.1.5", "mri": "1.1.5",
"ms": "2.1.2", "ms": "2.1.2",
"nanoid": "3.0.2",
"node-fetch": "2.6.1", "node-fetch": "2.6.1",
"npm-package-arg": "6.1.0", "npm-package-arg": "6.1.0",
"nyc": "13.2.0", "nyc": "13.2.0",
@@ -158,6 +157,7 @@
"psl": "1.1.31", "psl": "1.1.31",
"qr-image": "3.2.0", "qr-image": "3.2.0",
"raw-body": "2.4.1", "raw-body": "2.4.1",
"rimraf": "3.0.2",
"semver": "5.5.0", "semver": "5.5.0",
"serve-handler": "6.1.1", "serve-handler": "6.1.1",
"sinon": "4.4.2", "sinon": "4.4.2",

View File

@@ -18,7 +18,7 @@ const help = () => {
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
ls [app] Show all aliases (or per app name) ls Show all aliases
set <deployment> <alias> Create a new alias set <deployment> <alias> Create a new alias
rm <alias> Remove an alias using its hostname rm <alias> Remove an alias using its hostname
@@ -39,19 +39,19 @@ const help = () => {
-N, --next Show next page of results -N, --next Show next page of results
${chalk.dim('Examples:')} ${chalk.dim('Examples:')}
${chalk.gray('')} Add a new alias to ${chalk.underline('my-api.now.sh')} ${chalk.gray('')} Add a new alias to ${chalk.underline('my-api.vercel.app')}
${chalk.cyan( ${chalk.cyan(
`$ ${getPkgName()} alias set ${chalk.underline( `$ ${getPkgName()} alias set ${chalk.underline(
'api-ownv3nc9f8.now.sh' 'api-ownv3nc9f8.vercel.app'
)} ${chalk.underline('my-api.now.sh')}` )} ${chalk.underline('my-api.vercel.app')}`
)} )}
Custom domains work as alias targets Custom domains work as alias targets
${chalk.cyan( ${chalk.cyan(
`$ ${getPkgName()} alias set ${chalk.underline( `$ ${getPkgName()} alias set ${chalk.underline(
'api-ownv3nc9f8.now.sh' 'api-ownv3nc9f8.vercel.app'
)} ${chalk.underline('my-api.com')}` )} ${chalk.underline('my-api.com')}`
)} )}

View File

@@ -1,6 +1,5 @@
import chalk from 'chalk'; import chalk from 'chalk';
import ms from 'ms'; import ms from 'ms';
import plural from 'pluralize';
import table from 'text-table'; import table from 'text-table';
import Now from '../../util'; import Now from '../../util';
import Client from '../../util/client.ts'; import Client from '../../util/client.ts';
@@ -52,21 +51,17 @@ export default async function ls(ctx, opts, args, output) {
const lsStamp = stamp(); const lsStamp = stamp();
let cancelWait; let cancelWait;
if (args.length > 1) { if (args.length > 0) {
output.error( output.error(
`Invalid number of arguments. Usage: ${chalk.cyan( `Invalid number of arguments. Usage: ${chalk.cyan(
`${getCommandName('alias ls [alias]')}` `${getCommandName('alias ls')}`
)}` )}`
); );
return 1; return 1;
} }
cancelWait = output.spinner( cancelWait = output.spinner(
args[0] `Fetching aliases under ${chalk.bold(contextName)}`
? `Fetching alias details for "${args[0]}" under ${chalk.bold(
contextName
)}`
: `Fetching aliases under ${chalk.bold(contextName)}`
); );
const { aliases, pagination } = await getAliases( const { aliases, pagination } = await getAliases(
@@ -76,32 +71,8 @@ export default async function ls(ctx, opts, args, output) {
); );
if (cancelWait) cancelWait(); if (cancelWait) cancelWait();
if (args[0]) { output.log(`aliases found under ${chalk.bold(contextName)} ${lsStamp()}`);
const alias = aliases.find( console.log(printAliasTable(aliases));
item => item.uid === args[0] || item.alias === args[0]
);
if (!alias) {
output.error(`Could not match path alias for: ${args[0]}`);
now.close();
return 1;
}
if (opts['--json']) {
console.log(JSON.stringify({ rules: alias.rules }, null, 2));
} else {
const rules = alias.rules || [];
output.log(
`${rules.length} path alias ${plural(
'rule',
rules.length
)} found under ${chalk.bold(contextName)} ${lsStamp()}`
);
output.print(`${printPathAliasTable(rules)}\n`);
}
} else {
output.log(`aliases found under ${chalk.bold(contextName)} ${lsStamp()}`);
console.log(printAliasTable(aliases));
}
if (pagination && pagination.count === 20) { if (pagination && pagination.count === 20) {
const flags = getCommandFlags(opts, ['_', '--next']); const flags = getCommandFlags(opts, ['_', '--next']);
@@ -121,14 +92,10 @@ function printAliasTable(aliases) {
[ [
['source', 'url', 'age'].map(h => chalk.gray(h)), ['source', 'url', 'age'].map(h => chalk.gray(h)),
...aliases.map(a => [ ...aliases.map(a => [
a.rules && a.rules.length // for legacy reasons, we might have situations
? chalk.cyan(`[${plural('rule', a.rules.length, true)}]`) // where the deployment was deleted and the alias
: // for legacy reasons, we might have situations // not collected appropriately, and we need to handle it
// where the deployment was deleted and the alias a.deployment && a.deployment.url ? a.deployment.url : chalk.gray(''),
// not collected appropriately, and we need to handle it
a.deployment && a.deployment.url
? a.deployment.url
: chalk.gray(''),
a.alias, a.alias,
ms(Date.now() - new Date(a.createdAt)), ms(Date.now() - new Date(a.createdAt)),
]), ]),
@@ -140,21 +107,3 @@ function printAliasTable(aliases) {
} }
).replace(/^/gm, ' ')}\n\n`; ).replace(/^/gm, ' ')}\n\n`;
} }
function printPathAliasTable(rules) {
const header = [['pathname', 'method', 'dest'].map(s => chalk.gray(s))];
return `${table(
header.concat(
rules.map(rule => [
rule.pathname ? rule.pathname : chalk.cyan('[fallthrough]'),
rule.method ? rule.method : '*',
rule.dest,
])
),
{
align: ['l', 'l', 'l', 'l'],
hsep: ' '.repeat(6),
stringLength: strlen,
}
).replace(/^(.*)/gm, ' $1')}\n`;
}

View File

@@ -7,7 +7,7 @@ import getScope from '../../util/get-scope.ts';
import removeAliasById from '../../util/alias/remove-alias-by-id'; import removeAliasById from '../../util/alias/remove-alias-by-id';
import stamp from '../../util/output/stamp.ts'; import stamp from '../../util/output/stamp.ts';
import strlen from '../../util/strlen.ts'; import strlen from '../../util/strlen.ts';
import promptBool from '../../util/prompt-bool'; import confirm from '../../util/input/confirm';
import { isValidName } from '../../util/is-valid-name'; import { isValidName } from '../../util/is-valid-name';
import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id'; import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id';
import { getCommandName } from '../../util/pkg-name.ts'; import { getCommandName } from '../../util/pkg-name.ts';
@@ -108,5 +108,5 @@ async function confirmAliasRemove(output, alias) {
output.log(`The following alias will be removed permanently`); output.log(`The following alias will be removed permanently`);
output.print(` ${tbl}\n`); output.print(` ${tbl}\n`);
return promptBool(output, chalk.red('Are you sure?')); return confirm(chalk.red('Are you sure?'), false);
} }

View File

@@ -388,7 +388,7 @@ function handleCreateAliasError<T>(
} }
if (error instanceof ERRORS.InvalidAlias) { if (error instanceof ERRORS.InvalidAlias) {
output.error( output.error(
`Invalid alias. Please confirm that the alias you provided is a valid hostname. Note: For \`now.sh\`, only sub and sub-sub domains are supported.` `Invalid alias. Please confirm that the alias you provided is a valid hostname. Note: For \`vercel.app\`, only sub and sub-sub domains are supported.`
); );
return 1; return 1;
} }

View File

@@ -3,15 +3,15 @@ import { resolve, join } from 'path';
import DevServer from '../../util/dev/server'; import DevServer from '../../util/dev/server';
import parseListen from '../../util/dev/parse-listen'; import parseListen from '../../util/dev/parse-listen';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import { NowContext } from '../../types'; import { NowContext, ProjectEnvVariable } from '../../types';
import Client from '../../util/client'; import Client from '../../util/client';
import { getLinkedProject } from '../../util/projects/link'; import { getLinkedProject } from '../../util/projects/link';
import { getFrameworks } from '../../util/get-frameworks'; import { getFrameworks } from '../../util/get-frameworks';
import { isSettingValue } from '../../util/is-setting-value'; import { isSettingValue } from '../../util/is-setting-value';
import { ProjectSettings, ProjectEnvTarget } from '../../types'; import { ProjectSettings } from '../../types';
import getDecryptedEnvRecords from '../../util/get-decrypted-env-records'; import getDecryptedEnvRecords from '../../util/get-decrypted-env-records';
import { Env } from '@vercel/build-utils';
import setupAndLink from '../../util/link/setup-and-link'; import setupAndLink from '../../util/link/setup-and-link';
import getSystemEnvValues from '../../util/env/get-system-env-values';
type Options = { type Options = {
'--debug'?: boolean; '--debug'?: boolean;
@@ -70,7 +70,8 @@ export default async function dev(
let devCommand: string | undefined; let devCommand: string | undefined;
let frameworkSlug: string | undefined; let frameworkSlug: string | undefined;
let projectSettings: ProjectSettings | undefined; let projectSettings: ProjectSettings | undefined;
let environmentVars: Env | undefined; let projectEnvs: ProjectEnvVariable[] = [];
let systemEnvValues: string[] = [];
if (link.status === 'linked') { if (link.status === 'linked') {
const { project, org } = link; const { project, org } = link;
client.currentTeam = org.type === 'team' ? org.id : undefined; client.currentTeam = org.type === 'team' ? org.id : undefined;
@@ -98,12 +99,12 @@ export default async function dev(
cwd = join(cwd, project.rootDirectory); cwd = join(cwd, project.rootDirectory);
} }
environmentVars = await getDecryptedEnvRecords( [{ envs: projectEnvs }, { systemEnvValues }] = await Promise.all([
output, getDecryptedEnvRecords(output, client, project.id),
client, project.autoExposeSystemEnvs
project, ? getSystemEnvValues(output, client, project.id)
ProjectEnvTarget.Development : { systemEnvValues: [] },
); ]);
} }
const devServer = new DevServer(cwd, { const devServer = new DevServer(cwd, {
@@ -112,7 +113,8 @@ export default async function dev(
devCommand, devCommand,
frameworkSlug, frameworkSlug,
projectSettings, projectSettings,
environmentVars, projectEnvs,
systemEnvValues,
}); });
process.once('SIGINT', () => devServer.stop()); process.once('SIGINT', () => devServer.stop());

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk'; import chalk from 'chalk';
import inquirer from 'inquirer'; import inquirer from 'inquirer';
import { ProjectEnvTarget, Project } from '../../types'; import { ProjectEnvTarget, Project, Secret, ProjectEnvType } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import Client from '../../util/client'; import Client from '../../util/client';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
@@ -11,12 +11,14 @@ import {
getEnvTargetPlaceholder, getEnvTargetPlaceholder,
getEnvTargetChoices, getEnvTargetChoices,
} from '../../util/env/env-target'; } from '../../util/env/env-target';
import { isValidEnvType, getEnvTypePlaceholder } from '../../util/env/env-type';
import readStandardInput from '../../util/input/read-standard-input'; import readStandardInput from '../../util/input/read-standard-input';
import param from '../../util/output/param'; import param from '../../util/output/param';
import withSpinner from '../../util/with-spinner'; import withSpinner from '../../util/with-spinner';
import { emoji, prependEmoji } from '../../util/emoji'; import { emoji, prependEmoji } from '../../util/emoji';
import { isKnownError } from '../../util/env/known-error'; import { isKnownError } from '../../util/env/known-error';
import { getCommandName } from '../../util/pkg-name'; import { getCommandName } from '../../util/pkg-name';
import getSystemEnvValues from '../../util/env/get-system-env-values';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
@@ -29,38 +31,74 @@ export default async function add(
args: string[], args: string[],
output: Output output: Output
) { ) {
const stdInput = await readStandardInput(); // improve the way we show inquirer prompts
let [envName, envTarget] = args; require('../../util/input/patch-inquirer');
if (args.length > 2) { const stdInput = await readStandardInput();
let [envTypeArg, envName, envTargetArg] = args;
if (args.length > 3) {
output.error( output.error(
`Invalid number of arguments. Usage: ${getCommandName( `Invalid number of arguments. Usage: ${getCommandName(
`env add <name> ${getEnvTargetPlaceholder()}` `env add ${getEnvTypePlaceholder()} <name> ${getEnvTargetPlaceholder()}`
)}` )}`
); );
return 1; return 1;
} }
if (stdInput && (!envName || !envTarget)) { if (stdInput && (!envTypeArg || !envName || !envTargetArg)) {
output.error( output.error(
`Invalid number of arguments. Usage: ${getCommandName( `Invalid number of arguments. Usage: ${getCommandName(
`env add <name> <target> < <file>` `env add ${getEnvTypePlaceholder()} <name> <target> < <file>`
)}` )}`
); );
return 1; return 1;
} }
let envTargets: ProjectEnvTarget[] = []; let envTargets: ProjectEnvTarget[] = [];
if (envTarget) { if (envTargetArg) {
if (!isValidEnvTarget(envTarget)) { if (!isValidEnvTarget(envTargetArg)) {
output.error( output.error(
`The Environment ${param( `The Environment ${param(
envTarget envTargetArg
)} is invalid. It must be one of: ${getEnvTargetPlaceholder()}.` )} is invalid. It must be one of: ${getEnvTargetPlaceholder()}.`
); );
return 1; return 1;
} }
envTargets.push(envTarget); envTargets.push(envTargetArg);
}
let envType: ProjectEnvType;
if (envTypeArg) {
if (!isValidEnvType(envTypeArg)) {
output.error(
`The Environment Variable type ${param(
envTypeArg
)} is invalid. It must be one of: ${getEnvTypePlaceholder()}.`
);
return 1;
}
envType = envTypeArg;
} else {
const answers = (await inquirer.prompt({
name: 'inputEnvType',
type: 'list',
message: `Which type of Environment Variable do you want to add?`,
choices: [
{ name: 'Plaintext', value: ProjectEnvType.Plaintext },
{
name: `Secret (can be created using ${getCommandName('secret add')})`,
value: ProjectEnvType.Secret,
},
{
name: 'Reference to System Environment Variable',
value: ProjectEnvType.System,
},
],
})) as { inputEnvType: ProjectEnvType };
envType = answers.inputEnvType;
} }
while (!envName) { while (!envName) {
@@ -77,7 +115,10 @@ export default async function add(
} }
} }
const envs = await getEnvVariables(output, client, project.id, 4); const [{ envs }, { systemEnvValues }] = await Promise.all([
getEnvVariables(output, client, project.id),
getSystemEnvValues(output, client, project.id),
]);
const existing = new Set( const existing = new Set(
envs.filter(r => r.key === envName).map(r => r.target) envs.filter(r => r.key === envName).map(r => r.target)
); );
@@ -98,15 +139,59 @@ export default async function add(
if (stdInput) { if (stdInput) {
envValue = stdInput; envValue = stdInput;
} else if (isSystemEnvVariable(envName)) { } else if (envType === ProjectEnvType.Plaintext) {
envValue = '';
} else {
const { inputValue } = await inquirer.prompt({ const { inputValue } = await inquirer.prompt({
type: 'password', type: 'input',
name: 'inputValue', name: 'inputValue',
message: `Whats the value of ${envName}?`, message: `Whats the value of ${envName}?`,
}); });
envValue = inputValue || ''; envValue = inputValue || '';
} else if (envType === ProjectEnvType.Secret) {
let secretId: string | null = null;
while (!secretId) {
let { secretName } = await inquirer.prompt({
type: 'input',
name: 'secretName',
message: `Whats the value of ${envName}?`,
});
secretName = secretName || '';
if (secretName[0] === '@') {
secretName = secretName.slice(1);
}
try {
const secret = await client.fetch<Secret>(
`/v2/now/secrets/${encodeURIComponent(secretName)}`
);
secretId = secret.uid;
} catch (error) {
if (error.status === 404) {
output.error(
`Please enter the name of an existing Secret (can be created with ${getCommandName(
'secret add'
)}).`
);
} else {
throw error;
}
}
}
envValue = secretId;
} else {
const { systemEnvValue } = await inquirer.prompt({
name: 'systemEnvValue',
type: 'list',
message: `Whats the value of ${envName}?`,
choices: systemEnvValues.map(value => ({ name: value, value })),
});
envValue = systemEnvValue;
} }
while (envTargets.length === 0) { while (envTargets.length === 0) {
@@ -127,7 +212,15 @@ export default async function add(
const addStamp = stamp(); const addStamp = stamp();
try { try {
await withSpinner('Saving', () => await withSpinner('Saving', () =>
addEnvRecord(output, client, project.id, envName, envValue, envTargets) addEnvRecord(
output,
client,
project.id,
envType,
envName,
envValue,
envTargets
)
); );
} catch (error) { } catch (error) {
if (isKnownError(error) && error.serverMessage) { if (isKnownError(error) && error.serverMessage) {
@@ -148,7 +241,3 @@ export default async function add(
return 0; return 0;
} }
function isSystemEnvVariable(envName: string) {
return envName.startsWith('VERCEL_');
}

View File

@@ -6,6 +6,7 @@ import getArgs from '../../util/get-args';
import getSubcommand from '../../util/get-subcommand'; import getSubcommand from '../../util/get-subcommand';
import getInvalidSubcommand from '../../util/get-invalid-subcommand'; import getInvalidSubcommand from '../../util/get-invalid-subcommand';
import { getEnvTargetPlaceholder } from '../../util/env/env-target'; import { getEnvTargetPlaceholder } from '../../util/env/env-target';
import { getEnvTypePlaceholder } from '../../util/env/env-type';
import { getLinkedProject } from '../../util/projects/link'; import { getLinkedProject } from '../../util/projects/link';
import Client from '../../util/client'; import Client from '../../util/client';
import handleError from '../../util/handle-error'; import handleError from '../../util/handle-error';
@@ -18,16 +19,17 @@ import ls from './ls';
import rm from './rm'; import rm from './rm';
const help = () => { const help = () => {
const placeholder = getEnvTargetPlaceholder(); const typePlaceholder = getEnvTypePlaceholder();
const targetPlaceholder = getEnvTargetPlaceholder();
console.log(` console.log(`
${chalk.bold(`${logo} ${getPkgName()} env`)} [options] <command> ${chalk.bold(`${logo} ${getPkgName()} env`)} [options] <command>
${chalk.dim('Commands:')} ${chalk.dim('Commands:')}
ls [environment] List all variables for the specified Environment ls [environment] List all variables for the specified Environment
add [name] [environment] Add an Environment Variable (see examples below) add [type] [name] [environment] Add an Environment Variable (see examples below)
rm [name] [environment] Remove an Environment Variable (see examples below) rm [name] [environment] Remove an Environment Variable (see examples below)
pull [filename] Pull all Development Environment Variables from the cloud and write to a file [.env] pull [filename] Pull all Development Environment Variables from the cloud and write to a file [.env]
${chalk.dim('Options:')} ${chalk.dim('Options:')}
@@ -42,27 +44,32 @@ const help = () => {
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline( -t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
'TOKEN' 'TOKEN'
)} Login token )} Login token
-N, --next Show next page of results
${chalk.dim('Examples:')} ${chalk.dim('Examples:')}
${chalk.gray('')} Add a new variable to multiple Environments ${chalk.gray('')} Add a new variable to multiple Environments
${chalk.cyan(`$ ${getPkgName()} env add <name>`)} ${chalk.cyan(`$ ${getPkgName()} env add ${typePlaceholder} <name>`)}
${chalk.cyan(`$ ${getPkgName()} env add API_TOKEN`)} ${chalk.cyan(`$ ${getPkgName()} env add secret API_TOKEN`)}
${chalk.gray('')} Add a new variable for a specific Environment ${chalk.gray('')} Add a new variable for a specific Environment
${chalk.cyan(`$ ${getPkgName()} env add <name> ${placeholder}`)} ${chalk.cyan(
${chalk.cyan(`$ ${getPkgName()} env add DB_CONNECTION production`)} `$ ${getPkgName()} env add ${typePlaceholder} <name> ${targetPlaceholder}`
)}
${chalk.cyan(`$ ${getPkgName()} env add secret DB_PASS production`)}
${chalk.gray('')} Add a new Environment Variable from stdin ${chalk.gray('')} Add a new Environment Variable from stdin
${chalk.cyan( ${chalk.cyan(
`$ cat <file> | ${getPkgName()} env add <name> ${placeholder}` `$ cat <file> | ${getPkgName()} env add ${typePlaceholder} <name> ${targetPlaceholder}`
)}
${chalk.cyan(
`$ cat ~/.npmrc | ${getPkgName()} env add plain NPM_RC preview`
)}
${chalk.cyan(
`$ ${getPkgName()} env add plain API_URL production < url.txt`
)} )}
${chalk.cyan(`$ cat ~/.npmrc | ${getPkgName()} env add NPM_RC preview`)}
${chalk.cyan(`$ ${getPkgName()} env add DB_PASS production < secret.txt`)}
${chalk.gray('')} Remove an variable from multiple Environments ${chalk.gray('')} Remove an variable from multiple Environments
@@ -71,14 +78,8 @@ const help = () => {
${chalk.gray('')} Remove a variable from a specific Environment ${chalk.gray('')} Remove a variable from a specific Environment
${chalk.cyan(`$ ${getPkgName()} env rm <name> ${placeholder}`)} ${chalk.cyan(`$ ${getPkgName()} env rm <name> ${targetPlaceholder}`)}
${chalk.cyan(`$ ${getPkgName()} env rm NPM_RC preview`)} ${chalk.cyan(`$ ${getPkgName()} env rm NPM_RC preview`)}
${chalk.gray('')} Paginate results, where ${chalk.dim(
'`1584722256178`'
)} is the time in milliseconds since the UNIX epoch.
${chalk.cyan(`$ ${getPkgName()} env ls --next 1584722256178`)}
`); `);
}; };
@@ -96,8 +97,6 @@ export default async function main(ctx: NowContext) {
argv = getArgs(ctx.argv.slice(2), { argv = getArgs(ctx.argv.slice(2), {
'--yes': Boolean, '--yes': Boolean,
'-y': '--yes', '-y': '--yes',
'--next': Number,
'-N': '--next',
}); });
} catch (error) { } catch (error) {
handleError(error); handleError(error);

View File

@@ -1,7 +1,12 @@
import chalk from 'chalk'; import chalk from 'chalk';
import ms from 'ms'; import ms from 'ms';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import { ProjectEnvVariable, ProjectEnvTarget, Project } from '../../types'; import {
ProjectEnvTarget,
Project,
ProjectEnvVariable,
ProjectEnvType,
} from '../../types';
import Client from '../../util/client'; import Client from '../../util/client';
import formatTable from '../../util/format-table'; import formatTable from '../../util/format-table';
import getEnvVariables from '../../util/env/get-env-records'; import getEnvVariables from '../../util/env/get-env-records';
@@ -11,12 +16,13 @@ import {
} from '../../util/env/env-target'; } from '../../util/env/env-target';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import param from '../../util/output/param'; import param from '../../util/output/param';
import getCommandFlags from '../../util/get-command-flags';
import { getCommandName } from '../../util/pkg-name'; import { getCommandName } from '../../util/pkg-name';
import ellipsis from '../../util/output/ellipsis';
// @ts-ignore
import title from 'title';
type Options = { type Options = {
'--debug': boolean; '--debug': boolean;
'--next'?: number;
}; };
export default async function ls( export default async function ls(
@@ -26,8 +32,6 @@ export default async function ls(
args: string[], args: string[],
output: Output output: Output
) { ) {
const { '--next': nextTimestamp } = opts;
if (args.length > 1) { if (args.length > 1) {
output.error( output.error(
`Invalid number of arguments. Usage: ${getCommandName( `Invalid number of arguments. Usage: ${getCommandName(
@@ -50,42 +54,21 @@ export default async function ls(
const lsStamp = stamp(); const lsStamp = stamp();
if (typeof nextTimestamp !== 'undefined' && Number.isNaN(nextTimestamp)) { const { envs } = await getEnvVariables(output, client, project.id, envTarget);
output.error('Please provide a number for flag --next');
return 1;
}
const data = await getEnvVariables(
output,
client,
project.id,
5,
envTarget,
nextTimestamp
);
const { envs: records, pagination } = data;
output.log( output.log(
`${ `${
records.length > 0 ? 'Environment Variables' : 'No Environment Variables' envs.length > 0 ? 'Environment Variables' : 'No Environment Variables'
} found in Project ${chalk.bold(project.name)} ${chalk.gray(lsStamp())}` } found in Project ${chalk.bold(project.name)} ${chalk.gray(lsStamp())}`
); );
console.log(getTable(records)); console.log(getTable(envs));
if (pagination && pagination.count === 20) {
const flags = getCommandFlags(opts, ['_', '--next']);
output.log(
`To display the next page run ${getCommandName(
`env ls${flags} --next ${pagination.next}`
)}`
);
}
return 0; return 0;
} }
function getTable(records: ProjectEnvVariable[]) { function getTable(records: ProjectEnvVariable[]) {
return formatTable( return formatTable(
['name', 'value', 'environment', 'created'], ['name', 'value', 'environments', 'created'],
['l', 'l', 'l', 'l', 'l'], ['l', 'l', 'l', 'l', 'l'],
[ [
{ {
@@ -96,17 +79,27 @@ function getTable(records: ProjectEnvVariable[]) {
); );
} }
function getRow({ function getRow(env: ProjectEnvVariable) {
key, let value: string;
system = false, if (env.type === ProjectEnvType.Plaintext) {
target, // replace space characters (line-break, etc.) with simple spaces
createdAt = 0, // to make sure the displayed value is a single line
}: ProjectEnvVariable) { const singleLineValue = env.value.replace(/\s/g, ' ');
value = chalk.gray(ellipsis(singleLineValue, 19));
} else if (env.type === ProjectEnvType.System) {
value = chalk.gray.italic(env.value);
} else {
value = chalk.gray.italic('Encrypted');
}
const now = Date.now(); const now = Date.now();
return [ return [
chalk.bold(key), chalk.bold(env.key),
chalk.gray(chalk.italic(system ? 'Populated by System' : 'Encrypted')), value,
target || '', (Array.isArray(env.target) ? env.target : [env.target || ''])
`${ms(now - createdAt)} ago`, .map(title)
.join(', '),
env.createdAt ? `${ms(now - env.createdAt)} ago` : '',
]; ];
} }

View File

@@ -1,7 +1,7 @@
import chalk from 'chalk'; import chalk from 'chalk';
import { ProjectEnvTarget, Project } from '../../types'; import { Project } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import promptBool from '../../util/prompt-bool'; import confirm from '../../util/input/confirm';
import Client from '../../util/client'; import Client from '../../util/client';
import stamp from '../../util/output/stamp'; import stamp from '../../util/output/stamp';
import getDecryptedEnvRecords from '../../util/get-decrypted-env-records'; import getDecryptedEnvRecords from '../../util/get-decrypted-env-records';
@@ -12,7 +12,8 @@ import { promises, openSync, closeSync, readSync } from 'fs';
import { emoji, prependEmoji } from '../../util/emoji'; import { emoji, prependEmoji } from '../../util/emoji';
import { getCommandName } from '../../util/pkg-name'; import { getCommandName } from '../../util/pkg-name';
const { writeFile } = promises; const { writeFile } = promises;
import { Env } from '@vercel/build-utils'; import exposeSystemEnvs from '../../util/dev/expose-system-envs';
import getSystemEnvValues from '../../util/env/get-system-env-values';
const CONTENTS_PREFIX = '# Created by Vercel CLI\n'; const CONTENTS_PREFIX = '# Created by Vercel CLI\n';
@@ -68,9 +69,9 @@ export default async function pull(
} else if ( } else if (
exists && exists &&
!skipConfirmation && !skipConfirmation &&
!(await promptBool( !(await confirm(
output, `Found existing file ${param(filename)}. Do you want to overwrite?`,
`Found existing file ${param(filename)}. Do you want to overwrite?` false
)) ))
) { ) {
output.log('Aborted'); output.log('Aborted');
@@ -84,15 +85,22 @@ export default async function pull(
); );
const pullStamp = stamp(); const pullStamp = stamp();
const records: Env = await withSpinner( const [
'Downloading', { envs: projectEnvs },
async () => { systemEnvValues },
await getDecryptedEnvRecords( ] = await withSpinner('Downloading', () =>
output, Promise.all([
client, getDecryptedEnvRecords(output, client, project.id),
project, project.autoExposeSystemEnvs
ProjectEnvTarget.Development ? getSystemEnvValues(output, client, project.id)
) : { systemEnvValues: [] },
])
);
const records = exposeSystemEnvs(
projectEnvs,
systemEnvValues,
project.autoExposeSystemEnvs
); );
const contents = const contents =

View File

@@ -1,8 +1,8 @@
import chalk from 'chalk'; import chalk from 'chalk';
import inquirer from 'inquirer'; import inquirer from 'inquirer';
import { ProjectEnvTarget, Project } from '../../types'; import { ProjectEnvTarget, Project, ProjectEnvVariableV5 } from '../../types';
import { Output } from '../../util/output'; import { Output } from '../../util/output';
import promptBool from '../../util/prompt-bool'; import confirm from '../../util/input/confirm';
import removeEnvRecord from '../../util/env/remove-env-record'; import removeEnvRecord from '../../util/env/remove-env-record';
import getEnvVariables from '../../util/env/get-env-records'; import getEnvVariables from '../../util/env/get-env-records';
import { import {
@@ -30,6 +30,9 @@ export default async function rm(
args: string[], args: string[],
output: Output output: Output
) { ) {
// improve the way we show inquirer prompts
require('../../util/input/patch-inquirer');
if (args.length > 2) { if (args.length > 2) {
output.error( output.error(
`Invalid number of arguments. Usage: ${getCommandName( `Invalid number of arguments. Usage: ${getCommandName(
@@ -69,7 +72,20 @@ export default async function rm(
envName = inputName; envName = inputName;
} }
const envs = await getEnvVariables(output, client, project.id, 4); const data = await getEnvVariables(output, client, project.id);
// we expand env vars with multiple targets
const envs: ProjectEnvVariableV5[] = [];
for (let env of data.envs) {
if (Array.isArray(env.target)) {
for (let target of env.target) {
envs.push({ ...env, target });
}
} else {
envs.push({ ...env, target: env.target });
}
}
const existing = new Set( const existing = new Set(
envs.filter(r => r.key === envName).map(r => r.target) envs.filter(r => r.key === envName).map(r => r.target)
); );
@@ -79,7 +95,7 @@ export default async function rm(
return 1; return 1;
} }
if (envTargets.length === 0) { while (envTargets.length === 0) {
const choices = getEnvTargetChoices().filter(c => existing.has(c.value)); const choices = getEnvTargetChoices().filter(c => existing.has(c.value));
if (choices.length === 0) { if (choices.length === 0) {
output.error( output.error(
@@ -97,6 +113,13 @@ export default async function rm(
message: `Remove ${envName} from which Environments (select multiple)?`, message: `Remove ${envName} from which Environments (select multiple)?`,
choices, choices,
}); });
if (inputTargets.length === 0) {
output.error(
'Please select an Environment to remove the Environment Variable from.'
);
}
envTargets = inputTargets; envTargets = inputTargets;
} }
} }
@@ -104,11 +127,11 @@ export default async function rm(
const skipConfirmation = opts['--yes']; const skipConfirmation = opts['--yes'];
if ( if (
!skipConfirmation && !skipConfirmation &&
!(await promptBool( !(await confirm(
output,
`Removing Environment Variable ${param( `Removing Environment Variable ${param(
envName envName
)} from Project ${chalk.bold(project.name)}. Are you sure?` )} from Project ${chalk.bold(project.name)}. Are you sure?`,
false
)) ))
) { ) {
output.log('Aborted'); output.log('Aborted');

View File

@@ -51,12 +51,6 @@ const help = () => {
${chalk.cyan(`$ ${getPkgName()} ls my-app`)} ${chalk.cyan(`$ ${getPkgName()} ls my-app`)}
${chalk.gray(
''
)} List all deployments and all instances for the app ${chalk.dim('`my-app`')}
${chalk.cyan(`$ ${getPkgName()} ls my-app --all`)}
${chalk.gray('')} Filter deployments by metadata ${chalk.gray('')} Filter deployments by metadata
${chalk.cyan(`$ ${getPkgName()} ls -m key1=value1 -m key2=value2`)} ${chalk.cyan(`$ ${getPkgName()} ls -m key1=value1 -m key2=value2`)}

View File

@@ -324,7 +324,7 @@ function printLogRaw(log) {
if (log.object) { if (log.object) {
console.log(log.object); console.log(log.object);
} else { } else if (typeof log.text === 'string') {
console.log( console.log(
log.text log.text
.replace(/\n$/, '') .replace(/\n$/, '')

View File

@@ -117,12 +117,6 @@ export type Deployment = {
creator: { uid: string }; creator: { uid: string };
}; };
type PathAliasRule = {
pathname: string;
method: Array<'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'>;
dest: string;
};
export type Alias = { export type Alias = {
uid: string; uid: string;
alias: string; alias: string;
@@ -137,13 +131,6 @@ export type Alias = {
email: string; email: string;
}; };
deploymentId?: string; deploymentId?: string;
rules?: PathAliasRule[];
};
export type PathRule = {
dest: string;
pathname?: string;
method?: Array<string>;
}; };
export type DNSRecord = { export type DNSRecord = {
@@ -216,12 +203,23 @@ export enum ProjectEnvTarget {
Development = 'development', Development = 'development',
} }
export enum ProjectEnvType {
Plaintext = 'plain',
Secret = 'secret',
System = 'system',
}
export interface ProjectEnvVariable { export interface ProjectEnvVariable {
key: string; key: string;
value: string; value: string;
type: ProjectEnvType;
configurationId?: string | null; configurationId?: string | null;
createdAt?: number; createdAt?: number;
updatedAt?: number; updatedAt?: number;
target?: ProjectEnvTarget | ProjectEnvTarget[];
}
export interface ProjectEnvVariableV5 extends ProjectEnvVariable {
target?: ProjectEnvTarget; target?: ProjectEnvTarget;
system?: boolean; system?: boolean;
} }
@@ -232,6 +230,8 @@ export interface ProjectSettings {
buildCommand?: string | null; buildCommand?: string | null;
outputDirectory?: string | null; outputDirectory?: string | null;
rootDirectory?: string | null; rootDirectory?: string | null;
autoExposeSystemEnvs?: boolean;
directoryListing?: boolean;
} }
export interface Project extends ProjectSettings { export interface Project extends ProjectSettings {
@@ -245,6 +245,7 @@ export interface Project extends ProjectSettings {
framework?: string | null; framework?: string | null;
rootDirectory?: string | null; rootDirectory?: string | null;
latestDeployments?: Partial<Deployment>[]; latestDeployments?: Partial<Deployment>[];
autoExposeSystemEnvs?: boolean;
} }
export interface Org { export interface Org {

View File

@@ -172,6 +172,10 @@ export default async function processDeployment({
if (event.type === 'created') { if (event.type === 'created') {
deployingSpinner(); deployingSpinner();
if (bar && !bar.complete) {
bar.tick(bar.total + 1);
}
now._host = event.payload.url; now._host = event.payload.url;
await linkFolderToProject( await linkFolderToProject(

View File

@@ -1,3 +1,4 @@
import chalk from 'chalk';
import execa from 'execa'; import execa from 'execa';
import semver from 'semver'; import semver from 'semver';
import npa from 'npm-package-arg'; import npa from 'npm-package-arg';
@@ -8,9 +9,10 @@ import { mkdirp, readJSON, writeJSON } from 'fs-extra';
import { NowBuildError, PackageJson } from '@vercel/build-utils'; import { NowBuildError, PackageJson } from '@vercel/build-utils';
import cliPkg from '../pkg'; import cliPkg from '../pkg';
import { NoBuilderCacheError } from '../errors-ts'; import cmd from '../output/cmd';
import { Output } from '../output'; import { Output } from '../output';
import { getDistTag } from '../get-dist-tag'; import { getDistTag } from '../get-dist-tag';
import { NoBuilderCacheError } from '../errors-ts';
import * as staticBuilder from './static-builder'; import * as staticBuilder from './static-builder';
import { BuilderWithPackage } from './types'; import { BuilderWithPackage } from './types';
@@ -261,7 +263,9 @@ async function npmInstall(
throw new NowBuildError({ throw new NowBuildError({
message: message:
(result as any).code === 'ENOENT' (result as any).code === 'ENOENT'
? '`npm` is not installed' ? `Command not found: ${chalk.cyan(
'npm'
)}\nPlease ensure that ${cmd('npm')} is properly installed`
: 'Failed to install `vercel dev` dependencies', : 'Failed to install `vercel dev` dependencies',
code: 'NPM_INSTALL_ERROR', code: 'NPM_INSTALL_ERROR',
link: 'https://vercel.link/npm-install-failed-dev', link: 'https://vercel.link/npm-install-failed-dev',

View File

@@ -149,8 +149,8 @@ export async function executeBuild(
filesRemoved, filesRemoved,
// This env distiniction is only necessary to maintain // This env distiniction is only necessary to maintain
// backwards compatibility with the `@vercel/next` builder. // backwards compatibility with the `@vercel/next` builder.
env: envConfigs.runEnv, env: { ...envConfigs.runEnv },
buildEnv: envConfigs.buildEnv, buildEnv: { ...envConfigs.buildEnv },
}, },
}; };
@@ -402,7 +402,7 @@ export async function getBuildMatches(
const builds = nowConfig.builds || [{ src: '**', use: '@vercel/static' }]; const builds = nowConfig.builds || [{ src: '**', use: '@vercel/static' }];
for (const buildConfig of builds) { for (const buildConfig of builds) {
let { src, use } = buildConfig; let { src = '**', use } = buildConfig;
if (!use) { if (!use) {
continue; continue;

View File

@@ -0,0 +1,41 @@
import { ProjectEnvType, ProjectEnvVariable } from '../../types';
import { Env } from '@vercel/build-utils';
function getSystemEnvValue(
systemEnvRef: string,
{ vercelUrl }: { vercelUrl?: string }
) {
if (systemEnvRef === 'VERCEL_URL') {
return vercelUrl || '';
}
return '';
}
export default function exposeSystemEnvs(
projectEnvs: ProjectEnvVariable[],
systemEnvValues: string[],
autoExposeSystemEnvs: boolean | undefined,
vercelUrl?: string
) {
const envs: Env = {};
if (autoExposeSystemEnvs) {
envs['VERCEL'] = '1';
envs['VERCEL_ENV'] = 'development';
for (const key of systemEnvValues) {
envs[key] = getSystemEnvValue(key, { vercelUrl });
}
}
for (let env of projectEnvs) {
if (env.type === ProjectEnvType.System) {
envs[env.key] = getSystemEnvValue(env.value, { vercelUrl });
} else {
envs[env.key] = env.value;
}
}
return envs;
}

View File

@@ -43,6 +43,7 @@ import {
} from '@vercel/build-utils'; } from '@vercel/build-utils';
import _frameworks, { Framework } from '@vercel/frameworks'; import _frameworks, { Framework } from '@vercel/frameworks';
import cmd from '../output/cmd';
import link from '../output/link'; import link from '../output/link';
import { Output } from '../output'; import { Output } from '../output';
import { relative } from '../path-helpers'; import { relative } from '../path-helpers';
@@ -85,7 +86,8 @@ import {
HttpHeadersConfig, HttpHeadersConfig,
EnvConfigs, EnvConfigs,
} from './types'; } from './types';
import { ProjectSettings } from '../../types'; import { ProjectEnvVariable, ProjectSettings } from '../../types';
import exposeSystemEnvs from './expose-system-envs';
const frameworkList = _frameworks as Framework[]; const frameworkList = _frameworks as Framework[];
const frontendRuntimeSet = new Set( const frontendRuntimeSet = new Set(
@@ -149,14 +151,16 @@ export default class DevServer {
private updateBuildersTimeout: NodeJS.Timeout | undefined; private updateBuildersTimeout: NodeJS.Timeout | undefined;
private startPromise: Promise<void> | null; private startPromise: Promise<void> | null;
private environmentVars: Env | undefined; private systemEnvValues: string[];
private projectEnvs: ProjectEnvVariable[];
constructor(cwd: string, options: DevServerOptions) { constructor(cwd: string, options: DevServerOptions) {
this.cwd = cwd; this.cwd = cwd;
this.debug = options.debug; this.debug = options.debug;
this.output = options.output; this.output = options.output;
this.envConfigs = { buildEnv: {}, runEnv: {}, allEnv: {} }; this.envConfigs = { buildEnv: {}, runEnv: {}, allEnv: {} };
this.environmentVars = options.environmentVars; this.systemEnvValues = options.systemEnvValues || [];
this.projectEnvs = options.projectEnvs || [];
this.files = {}; this.files = {};
this.address = ''; this.address = '';
this.devCommand = options.devCommand; this.devCommand = options.devCommand;
@@ -491,7 +495,7 @@ export default class DevServer {
const dotenv = await fs.readFile(filePath, 'utf8'); const dotenv = await fs.readFile(filePath, 'utf8');
this.output.debug(`Using local env: ${filePath}`); this.output.debug(`Using local env: ${filePath}`);
env = parseDotenv(dotenv); env = parseDotenv(dotenv);
env = this.populateVercelEnvVars(env); env = this.injectSystemValuesInDotenv(env);
} catch (err) { } catch (err) {
if (err.code !== 'ENOENT') { if (err.code !== 'ENOENT') {
throw err; throw err;
@@ -642,10 +646,30 @@ export default class DevServer {
let allEnv = { ...buildEnv, ...runEnv }; let allEnv = { ...buildEnv, ...runEnv };
// If no .env/.build.env is present, fetch and use cloud environment variables // If no .env/.build.env is present, use cloud environment variables
if (Object.keys(allEnv).length === 0) { if (Object.keys(allEnv).length === 0) {
const cloudEnv = this.populateVercelEnvVars(this.environmentVars); const cloudEnv = exposeSystemEnvs(
allEnv = runEnv = buildEnv = cloudEnv; this.projectEnvs || [],
this.systemEnvValues || [],
this.projectSettings?.autoExposeSystemEnvs,
new URL(this.address).host
);
allEnv = { ...cloudEnv };
runEnv = { ...cloudEnv };
buildEnv = { ...cloudEnv };
}
// legacy NOW_REGION env variable
runEnv['NOW_REGION'] = 'dev1';
buildEnv['NOW_REGION'] = 'dev1';
allEnv['NOW_REGION'] = 'dev1';
// mirror how VERCEL_REGION is injected in prod/preview
// only inject in `runEnvs`, because `allEnvs` is exposed to dev command
// and should not contain VERCEL_REGION
if (this.projectSettings?.autoExposeSystemEnvs) {
runEnv['VERCEL_REGION'] = 'dev1';
} }
this.envConfigs = { buildEnv, runEnv, allEnv }; this.envConfigs = { buildEnv, runEnv, allEnv };
@@ -753,23 +777,15 @@ export default class DevServer {
return merged; return merged;
} }
populateVercelEnvVars(env: Env | undefined): Env { injectSystemValuesInDotenv(env: Env): Env {
if (!env) {
return {};
}
for (const name of Object.keys(env)) { for (const name of Object.keys(env)) {
if (name === 'VERCEL_URL') { if (name === 'VERCEL_URL') {
const host = new URL(this.address).host; env['VERCEL_URL'] = new URL(this.address).host;
env['VERCEL_URL'] = host;
} else if (name === 'VERCEL_REGION') { } else if (name === 'VERCEL_REGION') {
env['VERCEL_REGION'] = 'dev1'; env['VERCEL_REGION'] = 'dev1';
} }
} }
// Always set NOW_REGION to match production
env['NOW_REGION'] = 'dev1';
return env; return env;
} }
@@ -871,7 +887,7 @@ export default class DevServer {
}) })
.catch(err => { .catch(err => {
this.updateBuildersPromise = null; this.updateBuildersPromise = null;
this.output.error(`Failed to update builders: ${err.message}`); this.output.prettyError(err);
this.output.debug(err.stack); this.output.debug(err.stack);
}); });
}, ms('30s')); }, ms('30s'));
@@ -923,9 +939,17 @@ export default class DevServer {
await once(this.watcher, 'ready'); await once(this.watcher, 'ready');
// Configure the server to forward WebSocket "upgrade" events to the proxy. // Configure the server to forward WebSocket "upgrade" events to the proxy.
this.server.on('upgrade', (req, socket, head) => { this.server.on('upgrade', async (req, socket, head) => {
await this.startPromise;
if (!this.devProcessPort) {
this.output.debug(
`Detected "upgrade" event, but closing socket because no frontend dev server is running`
);
socket.destroy();
return;
}
const target = `http://localhost:${this.devProcessPort}`; const target = `http://localhost:${this.devProcessPort}`;
this.output.debug(`Detected upgrade event, proxying to ${target}`); this.output.debug(`Detected "upgrade" event, proxying to ${target}`);
this.proxy.ws(req, socket, head, { target }); this.proxy.ws(req, socket, head, { target });
}); });
@@ -1364,6 +1388,7 @@ export default class DevServer {
const missRoutes = handleMap.get('miss') || []; const missRoutes = handleMap.get('miss') || [];
const hitRoutes = handleMap.get('hit') || []; const hitRoutes = handleMap.get('hit') || [];
const errorRoutes = handleMap.get('error') || []; const errorRoutes = handleMap.get('error') || [];
const filesystemRoutes = handleMap.get('filesystem') || [];
const phases: (HandleValue | null)[] = [null, 'filesystem']; const phases: (HandleValue | null)[] = [null, 'filesystem'];
let routeResult: RouteResult | null = null; let routeResult: RouteResult | null = null;
@@ -1481,6 +1506,11 @@ export default class DevServer {
// end the phase // end the phase
break; break;
} }
if (phase === null && filesystemRoutes.length === 0) {
// hack to skip the reset from null to filesystem
break;
}
} }
if (!match && routeResult && errorRoutes.length > 0) { if (!match && routeResult && errorRoutes.length > 0) {
@@ -1644,15 +1674,24 @@ export default class DevServer {
isDev: true, isDev: true,
requestPath, requestPath,
devCacheDir, devCacheDir,
env: envConfigs.runEnv, env: { ...envConfigs.runEnv },
buildEnv: envConfigs.buildEnv, buildEnv: { ...envConfigs.buildEnv },
}, },
}); });
} catch (err) { } catch (err) {
// `startDevServer()` threw an error. Most likely this means the dev // `startDevServer()` threw an error. Most likely this means the dev
// server process exited before sending the port information message // server process exited before sending the port information message
// (missing dependency at runtime, for example). // (missing dependency at runtime, for example).
debug(`Error starting "${builderPkg.name}" dev server: ${err}`); if (err.code === 'ENOENT') {
err.message = `Command not found: ${chalk.cyan(
err.path,
...err.spawnargs
)}\nPlease ensure that ${cmd(err.path)} is properly installed`;
err.link = 'https://vercel.link/command-not-found';
}
this.output.prettyError(err);
await this.sendError( await this.sendError(
req, req,
res, res,
@@ -1865,6 +1904,12 @@ export default class DevServer {
requestPath: string, requestPath: string,
nowRequestId: string nowRequestId: string
): boolean { ): boolean {
// If the "directory listing" feature is disabled in the
// Project's settings, then don't render the directory listing
if (this.projectSettings?.directoryListing === false) {
return false;
}
let prefix = requestPath; let prefix = requestPath;
if (prefix.length > 0 && !prefix.endsWith('/')) { if (prefix.length > 0 && !prefix.endsWith('/')) {
prefix += '/'; prefix += '/';

View File

@@ -17,7 +17,7 @@ import {
import { NowConfig } from '@vercel/client'; import { NowConfig } from '@vercel/client';
import { HandleValue, Route } from '@vercel/routing-utils'; import { HandleValue, Route } from '@vercel/routing-utils';
import { Output } from '../output'; import { Output } from '../output';
import { ProjectSettings } from '../../types'; import { ProjectEnvVariable, ProjectSettings } from '../../types';
export { NowConfig }; export { NowConfig };
@@ -27,7 +27,8 @@ export interface DevServerOptions {
devCommand?: string; devCommand?: string;
frameworkSlug?: string; frameworkSlug?: string;
projectSettings?: ProjectSettings; projectSettings?: ProjectSettings;
environmentVars?: Env; systemEnvValues?: string[];
projectEnvs?: ProjectEnvVariable[];
} }
export interface EnvConfigs { export interface EnvConfigs {
@@ -49,6 +50,7 @@ export interface EnvConfigs {
export interface BuildMatch extends BuildConfig { export interface BuildMatch extends BuildConfig {
entrypoint: string; entrypoint: string;
src: string;
builderWithPkg: BuilderWithPackage; builderWithPkg: BuilderWithPackage;
buildOutput: BuilderOutputs; buildOutput: BuilderOutputs;
buildResults: Map<string | null, BuildResult>; buildResults: Map<string | null, BuildResult>;

View File

@@ -1,60 +1,39 @@
import { Output } from '../output'; import { Output } from '../output';
import Client from '../client'; import Client from '../client';
import { Secret, ProjectEnvTarget, ProjectEnvVariable } from '../../types'; import {
import { customAlphabet } from 'nanoid'; Secret,
import slugify from '@sindresorhus/slugify'; ProjectEnvTarget,
ProjectEnvVariableV5,
ProjectEnvType,
} from '../../types';
export default async function addEnvRecord( export default async function addEnvRecord(
output: Output, output: Output,
client: Client, client: Client,
projectId: string, projectId: string,
envName: string, type: ProjectEnvType,
envValue: string | undefined, key: string,
envValue: string,
targets: ProjectEnvTarget[] targets: ProjectEnvTarget[]
): Promise<void> { ): Promise<void> {
output.debug( output.debug(
`Adding Environment Variable ${envName} to ${targets.length} targets` `Adding ${type} Environment Variable ${key} to ${targets.length} targets`
); );
let values: string[] | undefined; let value = envValue;
if (envValue) { if (type === ProjectEnvType.Secret) {
const secrets = await Promise.all( const secret = await client.fetch<Secret>(
targets.map(target => `/v2/now/secrets/${encodeURIComponent(envValue)}`
client.fetch<Secret>('/v2/now/secrets', {
method: 'POST',
body: JSON.stringify({
name: generateSecretName(envName, target),
value: envValue,
projectId: projectId,
decryptable: target === ProjectEnvTarget.Development,
}),
})
)
); );
values = secrets.map(secret => secret.uid); value = secret.uid;
} }
const body = targets.map((target, i) => ({ const body = { type, key, value, target: targets };
key: envName,
value: values ? values[i] : '',
target,
}));
const urlProject = `/v4/projects/${projectId}/env`; const urlProject = `/v6/projects/${projectId}/env`;
await client.fetch<ProjectEnvVariable>(urlProject, { await client.fetch<ProjectEnvVariableV5>(urlProject, {
method: 'POST', method: 'POST',
body: JSON.stringify(body), body: JSON.stringify(body),
}); });
} }
const randomSecretSuffix = customAlphabet(
'123456789abcdefghijklmnopqrstuvwxyz',
4
);
function generateSecretName(envName: string, target: ProjectEnvTarget) {
return `${
slugify(envName).substring(0, 80) // we truncate because the max secret length is 100
}-${target}-${randomSecretSuffix()}`;
}

View File

@@ -0,0 +1,15 @@
import { ProjectEnvType } from '../../types';
function envTypes(): string[] {
return Object.values(ProjectEnvType);
}
export function isValidEnvType(
type?: string
): type is ProjectEnvType | undefined {
return typeof type === 'undefined' || envTypes().includes(type);
}
export function getEnvTypePlaceholder() {
return `<${envTypes().join(' | ')}>`;
}

View File

@@ -1,17 +0,0 @@
import { Output } from '../output';
import Client from '../client';
import { Secret } from '../../types';
export default async function getDecryptedSecret(
output: Output,
client: Client,
secretId: string
): Promise<string> {
if (!secretId) {
return '';
}
output.debug(`Fetching decrypted secret ${secretId}`);
const url = `/v2/now/secrets/${secretId}?decrypt=true`;
const secret = await client.fetch<Secret>(url);
return secret.value;
}

View File

@@ -1,69 +1,24 @@
import { Output } from '../output'; import { Output } from '../output';
import Client from '../client'; import Client from '../client';
import { import { ProjectEnvVariable, ProjectEnvTarget } from '../../types';
ProjectEnvVariable,
ProjectEnvTarget,
PaginationOptions,
} from '../../types';
import { URLSearchParams } from 'url'; import { URLSearchParams } from 'url';
type ApiVersion = 4 | 5;
type APIV4Response = ProjectEnvVariable[];
interface APIV5Response {
pagination: PaginationOptions;
envs: ProjectEnvVariable[];
}
export default async function getEnvVariables( export default async function getEnvVariables(
output: Output, output: Output,
client: Client, client: Client,
projectId: string, projectId: string,
apiVersion: 4,
target?: ProjectEnvTarget target?: ProjectEnvTarget
): Promise<APIV4Response>;
export default async function getEnvVariables(
output: Output,
client: Client,
projectId: string,
apiVersion: 5,
target?: ProjectEnvTarget,
next?: number
): Promise<APIV5Response>;
export default async function getEnvVariables<V extends ApiVersion>(
output: Output,
client: Client,
projectId: string,
apiVersion: V,
target?: ProjectEnvTarget,
next?: number
) { ) {
output.debug( output.debug(
`Fetching Environment Variables of project ${projectId} and target ${target}` `Fetching Environment Variables of project ${projectId} and target ${target}`
); );
const query = new URLSearchParams(); const query = new URLSearchParams();
if (apiVersion >= 5) {
query.set('limit', String(20));
}
if (target) { if (target) {
query.set('target', target); query.set('target', target);
} }
if (next) { const url = `/v6/projects/${projectId}/env?${query}`;
query.set('until', String(next));
}
const url = `/v${apiVersion}/projects/${projectId}/env?${query}`; return client.fetch<{ envs: ProjectEnvVariable[] }>(url);
if (apiVersion === 5) {
return client.fetch<APIV5Response>(url);
} else if (apiVersion === 4) {
return client.fetch<APIV4Response>(url);
} else {
throw new Error('Unknown version: ' + apiVersion);
}
} }

View File

@@ -0,0 +1,12 @@
import { Output } from '../output';
import Client from '../client';
export default async function getSystemEnvValues(
output: Output,
client: Client,
projectId: string
) {
output.debug(`Fetching System Environment Values of project ${projectId}`);
const url = `/v6/projects/${projectId}/system-env-values`;
return client.fetch<{ systemEnvValues: string[] }>(url);
}

View File

@@ -1,6 +1,6 @@
import { Output } from '../output'; import { Output } from '../output';
import Client from '../client'; import Client from '../client';
import { ProjectEnvTarget, Secret, ProjectEnvVariable } from '../../types'; import { ProjectEnvTarget, ProjectEnvVariableV5 } from '../../types';
export default async function removeEnvRecord( export default async function removeEnvRecord(
output: Output, output: Output,
@@ -18,32 +18,7 @@ export default async function removeEnvRecord(
envName envName
)}${qs}`; )}${qs}`;
const env = await client.fetch<ProjectEnvVariable>(urlProject, { await client.fetch<ProjectEnvVariableV5>(urlProject, {
method: 'DELETE', method: 'DELETE',
}); });
if (env && env.value) {
const idOrName = env.value.startsWith('@') ? env.value.slice(1) : env.value;
const urlSecret = `/v2/now/secrets/${idOrName}`;
let secret: Secret | undefined;
try {
secret = await client.fetch<Secret>(urlSecret);
} catch (error) {
if (error && error.status === 404) {
// User likely deleted the secret before the env var, so we can still report success
output.debug(
`Skipped ${env.key} because secret ${idOrName} was already deleted`
);
return;
}
throw error;
}
// Since integrations add global secrets, we must only delete if the secret was
// specifically added to this project
if (secret && secret.projectId === projectId) {
await client.fetch<Secret>(urlSecret, { method: 'DELETE' });
}
}
} }

View File

@@ -1,46 +1,65 @@
import getEnvVariables from './env/get-env-records';
import getDecryptedSecret from './env/get-decrypted-secret';
import Client from './client'; import Client from './client';
import { Output } from './output/create-output'; import { Output } from './output/create-output';
import { ProjectEnvTarget, Project } from '../types'; import {
ProjectEnvTarget,
import { Env } from '@vercel/build-utils'; ProjectEnvType,
ProjectEnvVariable,
Secret,
} from '../types';
import getEnvRecords from './env/get-env-records';
export default async function getDecryptedEnvRecords( export default async function getDecryptedEnvRecords(
output: Output, output: Output,
client: Client, client: Client,
project: Project, projectId: string
target: ProjectEnvTarget ): Promise<{ envs: ProjectEnvVariable[] }> {
): Promise<Env> { const { envs } = await getEnvRecords(
const envs = await getEnvVariables(output, client, project.id, 4, target); output,
const decryptedValues = await Promise.all( client,
envs.map(async env => { projectId,
try { ProjectEnvTarget.Development
const value = await getDecryptedSecret(output, client, env.value); );
return { value, found: true };
} catch (error) { const envsWithDecryptedSecrets = await Promise.all(
if (error && error.status === 404) { envs.map(async ({ type, key, value }) => {
return { value: '', found: false }; // it's not possible to create secret env variables for development
// anymore but we keep this because legacy env variables with "decryptable"
// secret values still exit in our system
if (type === ProjectEnvType.Secret) {
try {
const secretIdOrName = value;
if (!secretIdOrName) {
return { type, key, value: '', found: true };
}
output.debug(`Fetching decrypted secret ${secretIdOrName}`);
const secret = await client.fetch<Secret>(
`/v2/now/secrets/${secretIdOrName}?decrypt=true`
);
return { type, key, value: secret.value, found: true };
} catch (error) {
if (error && error.status === 404) {
return { type, key, value: '', found: false };
}
throw error;
} }
throw error;
} }
return { type, key, value, found: true };
}) })
); );
const results: Env = {}; for (let env of envsWithDecryptedSecrets) {
for (let i = 0; i < decryptedValues.length; i++) { if (!env.found) {
const { key } = envs[i];
const { value, found } = decryptedValues[i];
if (!found) {
output.print(''); output.print('');
output.warn( output.warn(
`Unable to download variable ${key} because associated secret was deleted` `Unable to download variable ${env.key} because associated secret was deleted`
); );
continue;
} }
results[key] = value ? value : '';
} }
return results;
return { envs: envsWithDecryptedSecrets };
} }

View File

@@ -10,7 +10,7 @@ import chalk from 'chalk';
*/ */
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/base.js#L126 // adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/base.js#L126
const getQuestion = function() { const getQuestion = function () {
let message = `${chalk.gray('?')} ${this.opt.message} `; let message = `${chalk.gray('?')} ${this.opt.message} `;
if (this.opt.type === 'confirm') { if (this.opt.type === 'confirm') {
@@ -35,7 +35,7 @@ inquirer.prompt.prompts.input.prototype.getQuestion = getQuestion;
inquirer.prompt.prompts.confirm.prototype.getQuestion = getQuestion; inquirer.prompt.prompts.confirm.prototype.getQuestion = getQuestion;
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/list.js#L80 // adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/list.js#L80
inquirer.prompt.prompts.list.prototype.render = function() { inquirer.prompt.prompts.list.prototype.render = function () {
// Render question // Render question
let message = this.getQuestion(); let message = this.getQuestion();
@@ -89,11 +89,22 @@ function listRender(choices, pointer) {
} }
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/checkbox.js#L84 // adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/checkbox.js#L84
inquirer.prompt.prompts.checkbox.prototype.render = function(error) { inquirer.prompt.prompts.checkbox.prototype.render = function (error) {
// Render question // Render question
let message = this.getQuestion(); let message = this.getQuestion();
let bottomContent = ''; let bottomContent = '';
if (!this.spaceKeyPressed) {
message +=
'(Press ' +
chalk.cyan.bold('<space>') +
' to select, ' +
chalk.cyan.bold('<a>') +
' to toggle all, ' +
chalk.cyan.bold('<i>') +
' to invert selection)';
}
// Render choices or answer depending on the state // Render choices or answer depending on the state
if (this.status === 'answered') { if (this.status === 'answered') {
message += this.selection.length > 0 ? this.selection.join(', ') : 'None'; message += this.selection.length > 0 ? this.selection.join(', ') : 'None';
@@ -118,7 +129,7 @@ function renderChoices(choices, pointer) {
let output = ''; let output = '';
let separatorOffset = 0; let separatorOffset = 0;
choices.forEach(function(choice, i) { choices.forEach(function (choice, i) {
if (choice.type === 'separator') { if (choice.type === 'separator') {
separatorOffset++; separatorOffset++;
output += '' + choice + '\n'; output += '' + choice + '\n';
@@ -151,7 +162,7 @@ function renderChoices(choices, pointer) {
} }
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/input.js#L44 // adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/input.js#L44
inquirer.prompt.prompts.input.prototype.render = function(error) { inquirer.prompt.prompts.input.prototype.render = function (error) {
let bottomContent = ''; let bottomContent = '';
let appendContent = ''; let appendContent = '';
let message = this.getQuestion(); let message = this.getQuestion();
@@ -178,7 +189,7 @@ inquirer.prompt.prompts.input.prototype.render = function(error) {
}; };
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/confirm.js#L64 // adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/confirm.js#L64
inquirer.prompt.prompts.confirm.prototype.render = function(answer) { inquirer.prompt.prompts.confirm.prototype.render = function (answer) {
let message = this.getQuestion(); let message = this.getQuestion();
if (this.status === 'answered') { if (this.status === 'answered') {

View File

@@ -0,0 +1,3 @@
export default function ellipsis(str: string, length: number) {
return str.length > length ? `${str.slice(0, length - 1)}` : str;
}

View File

@@ -1,21 +0,0 @@
import chalk from 'chalk';
import { Output } from './output';
async function promptBool(output: Output, message: string): Promise<boolean> {
return new Promise<boolean>(resolve => {
output.print(`${chalk.gray('>')} ${message} ${chalk.gray('[y/N] ')}`);
process.stdin
.on('data', d => {
process.stdin.pause();
resolve(
d
.toString()
.trim()
.toLowerCase() === 'y'
);
})
.resume();
});
}
export default promptBool;

View File

@@ -0,0 +1,3 @@
node_modules
.next
.vercel

View File

@@ -1,10 +1,7 @@
{ {
"private": true, "private": true,
"workspaces": [
"packages/*"
],
"dependencies": { "dependencies": {
"next": "9.5.1", "next": "9.5.3",
"react": "16.13.1", "react": "16.13.1",
"react-dom": "16.13.1" "react-dom": "16.13.1"
} }

View File

@@ -0,0 +1,3 @@
module.exports = (_req, res) => {
res.end('Hello Routes');
};

View File

@@ -0,0 +1,10 @@
function Index() {
return (
<main>
<h1>Next.js with routes</h1>
<a href="/hello">/hello</a>
</main>
);
}
export default Index;

View File

@@ -0,0 +1,3 @@
{
"routes": [{ "src": "/hello", "dest": "/api/hello" }]
}

View File

@@ -0,0 +1,4 @@
.next
!public
yarn.lock
.vercel

View File

@@ -1,10 +1,12 @@
{ {
"private": true,
"scripts": { "scripts": {
"dev": "next dev",
"build": "next build" "build": "next build"
}, },
"dependencies": { "dependencies": {
"next": "canary", "next": "canary",
"react": "^16.8.6", "react": "^17.0.0",
"react-dom": "^16.8.6" "react-dom": "^17.0.0"
} }
} }

View File

@@ -0,0 +1,15 @@
import Image from 'next/image';
export default function Home() {
return (
<>
<h1>Home Page</h1>
<hr />
<h2>Optimized</h2>
<Image src="/test.png" width="400" height="400" />
<hr />
<h2>Original</h2>
<img src="/test.png" width="400" height="400" />
</>
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="400.000000pt" height="400.000000pt" viewBox="0 0 400.000000 400.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,400.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M0 2000 l0 -2000 2000 0 2000 0 0 2000 0 2000 -2000 0 -2000 0 0
-2000z m2401 118 l396 -693 -398 -3 c-220 -1 -578 -1 -798 0 l-398 3 396 693
c217 380 398 692 401 692 3 0 184 -312 401 -692z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 635 B

View File

@@ -0,0 +1,8 @@
{
"version": 2,
"build": {
"env": {
"FORCE_BUILDER_TAG": "canary"
}
}
}

View File

@@ -0,0 +1,4 @@
package.json
yarn.lock
.now
.vercel

View File

@@ -0,0 +1 @@
hello:index.txt

View File

@@ -0,0 +1,7 @@
{
"builds": [
{
"use": "@vercel/static"
}
]
}

View File

@@ -128,14 +128,13 @@ async function testPath(
status, status,
path, path,
expectedText, expectedText,
headers = {}, expectedHeaders = {},
method = 'GET', fetchOpts = {}
body = undefined
) { ) {
const opts = { redirect: 'manual-dont-change', method, body }; const opts = { ...fetchOpts, redirect: 'manual-dont-change' };
const url = `${origin}${path}`; const url = `${origin}${path}`;
const res = await fetch(url, opts); const res = await fetch(url, opts);
const msg = `Testing response from ${method} ${url}`; const msg = `Testing response from ${fetchOpts.method || 'GET'} ${url}`;
console.log(msg); console.log(msg);
t.is(res.status, status, msg); t.is(res.status, status, msg);
validateResponseHeaders(t, res); validateResponseHeaders(t, res);
@@ -150,8 +149,8 @@ async function testPath(
expectedText.lastIndex = 0; // reset since we test twice expectedText.lastIndex = 0; // reset since we test twice
t.regex(actualText, expectedText); t.regex(actualText, expectedText);
} }
if (headers) { if (expectedHeaders) {
Object.entries(headers).forEach(([key, expectedValue]) => { Object.entries(expectedHeaders).forEach(([key, expectedValue]) => {
let actualValue = res.headers.get(key); let actualValue = res.headers.get(key);
if (key.toLowerCase() === 'location' && actualValue === '//') { if (key.toLowerCase() === 'location' && actualValue === '//') {
// HACK: `node-fetch` has strange behavior for location header so fix it // HACK: `node-fetch` has strange behavior for location header so fix it
@@ -233,7 +232,7 @@ async function testFixture(directory, opts = {}, args = []) {
function testFixtureStdio( function testFixtureStdio(
directory, directory,
fn, fn,
{ expectedCode = 0, skipDeploy, isExample } = {} { expectedCode = 0, skipDeploy, isExample, projectSettings } = {}
) { ) {
return async t => { return async t => {
const nodeMajor = Number(process.versions.node.split('.')[0]); const nodeMajor = Number(process.versions.node.split('.')[0]);
@@ -250,24 +249,51 @@ function testFixtureStdio(
// Deploy fixture and link project // Deploy fixture and link project
if (!skipDeploy) { if (!skipDeploy) {
const project = join(cwd, '.vercel', 'project.json'); const projectJsonPath = join(cwd, '.vercel', 'project.json');
if (await fs.exists(project)) { await fs.remove(projectJsonPath);
await fs.unlink(project);
}
const gitignore = join(cwd, '.gitignore'); const gitignore = join(cwd, '.gitignore');
const gitignoreOrig = await fs.exists(gitignore); const hasGitignore = await fs.exists(gitignore);
let { stdout, stderr, exitCode } = await execa(
binaryPath, try {
['-t', token, '--confirm', '--public', '--no-clipboard', '--debug'], // Run `vc link`
{ cwd, reject: false } const { exitCode: linkExitCode } = await execa(
); binaryPath,
console.log({ stdout, stderr, exitCode }); ['-t', token, 'link', '--confirm'],
if (!gitignoreOrig && (await fs.exists(gitignore))) { { cwd, stdio: 'inherit', reject: false }
await fs.unlink(gitignore); );
} t.is(linkExitCode, 0);
t.is(exitCode, expectedCode);
if (expectedCode === 0) { // Patch the project with any non-default properties
deploymentUrl = new URL(stdout).host; if (projectSettings) {
const { projectId } = await fs.readJson(projectJsonPath);
const res = await fetch(
`https://api.vercel.com/v2/projects/${projectId}`,
{
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(projectSettings),
}
);
t.is(res.status, 200);
}
// Run `vc deploy`
let { exitCode, stdout } = await execa(
binaryPath,
['-t', token, 'deploy', '--public', '--no-clipboard', '--debug'],
{ cwd, stdio: ['ignore', 'pipe', 'inherit'], reject: false }
);
console.log({ exitCode, stdout });
t.is(exitCode, expectedCode);
if (expectedCode === 0) {
deploymentUrl = new URL(stdout).host;
}
} finally {
if (!hasGitignore) {
await fs.remove(gitignore);
}
} }
} }
@@ -387,9 +413,12 @@ test(
async testPath => { async testPath => {
await testPath(200, '/', /<div id="redwood-app">/m); await testPath(200, '/', /<div id="redwood-app">/m);
await testPath(200, '/about', /<div id="redwood-app">/m); await testPath(200, '/about', /<div id="redwood-app">/m);
const reqBody = '{"query":"{redwood{version}}"}'; const fetchOpts = {
method: 'POST',
body: '{"query":"{redwood{version}}"}',
};
const resBody = '{"data":{"redwood":{"version":"0.15.0"}}}'; const resBody = '{"data":{"redwood":{"version":"0.15.0"}}}';
await testPath(200, '/api/graphql', resBody, {}, 'POST', reqBody); await testPath(200, '/api/graphql', resBody, {}, fetchOpts);
}, },
{ isExample: true } { isExample: true }
) )
@@ -620,14 +649,6 @@ test(
}); });
}) })
); );
/*
test(
'[vercel dev] displays directory listing after miss',
testFixtureStdio('handle-miss-display-dir-list', async (testPath) => {
await testPath(404, '/post', /one.html/m);
})
);
*/
test( test(
'[vercel dev] does not display directory listing after 404', '[vercel dev] does not display directory listing after 404',
@@ -945,12 +966,16 @@ test(
'Access-Control-Allow-Methods': 'Access-Control-Allow-Methods':
'GET, POST, OPTIONS, HEAD, PATCH, PUT, DELETE', 'GET, POST, OPTIONS, HEAD, PATCH, PUT, DELETE',
}; };
await testPath(200, '/', 'status api', headers, 'GET'); await testPath(200, '/', 'status api', headers, { method: 'GET' });
await testPath(200, '/', 'status api', headers, 'POST'); await testPath(200, '/', 'status api', headers, { method: 'POST' });
await testPath(200, '/api/status.js', 'status api', headers, 'GET'); await testPath(200, '/api/status.js', 'status api', headers, {
await testPath(200, '/api/status.js', 'status api', headers, 'POST'); method: 'GET',
await testPath(204, '/', '', headers, 'OPTIONS'); });
await testPath(204, '/api/status.js', '', headers, 'OPTIONS'); await testPath(200, '/api/status.js', 'status api', headers, {
method: 'POST',
});
await testPath(204, '/', '', headers, { method: 'OPTIONS' });
await testPath(204, '/api/status.js', '', headers, { method: 'OPTIONS' });
}) })
); );
@@ -1050,12 +1075,16 @@ test(
test( test(
'[vercel dev] 00-list-directory', '[vercel dev] 00-list-directory',
testFixtureStdio('00-list-directory', async testPath => { testFixtureStdio(
await testPath(200, '/', /Files within/m); '00-list-directory',
await testPath(200, '/', /test[0-3]\.txt/m); async testPath => {
await testPath(200, '/', /\.well-known/m); await testPath(200, '/', /Files within/m);
await testPath(200, '/.well-known/keybase.txt', 'proof goes here'); await testPath(200, '/', /test[0-3]\.txt/m);
}) await testPath(200, '/', /\.well-known/m);
await testPath(200, '/.well-known/keybase.txt', 'proof goes here');
},
{ projectSettings: { directoryListing: true } }
)
); );
test( test(
@@ -1180,6 +1209,14 @@ test(
}) })
); );
test(
'[vercel dev] 10a-nextjs-routes',
testFixtureStdio('10a-nextjs-routes', async testPath => {
await testPath(200, '/', /Next.js with routes/m);
await testPath(200, '/hello', /Hello Routes/m);
})
);
test( test(
'[vercel dev] 12-polymer-node', '[vercel dev] 12-polymer-node',
testFixtureStdio( testFixtureStdio(
@@ -1587,6 +1624,61 @@ test(
}) })
); );
test(
'[vercel dev] 30-next-image-optimization',
testFixtureStdio('30-next-image-optimization', async testPath => {
const toUrl = (url, w, q) => {
const query = new URLSearchParams();
query.append('url', url);
query.append('w', w);
query.append('q', q);
return `/_next/image?${query}`;
};
const expectHeader = accept => ({
'content-type': accept,
'cache-control': 'public, max-age=0, must-revalidate',
});
const fetchOpts = accept => ({ method: 'GET', headers: { accept } });
await testPath(200, '/', /Home Page/m);
await testPath(
200,
toUrl('/test.jpg', 64, 100),
null,
expectHeader('image/webp'),
fetchOpts('image/webp')
);
await testPath(
200,
toUrl('/test.png', 64, 90),
null,
expectHeader('image/webp'),
fetchOpts('image/webp')
);
await testPath(
200,
toUrl('/test.gif', 64, 80),
null,
expectHeader('image/webp'),
fetchOpts('image/webp')
);
await testPath(
200,
toUrl('/test.svg', 64, 70),
null,
expectHeader('image/svg+xml'),
fetchOpts('image/webp')
);
await testPath(
200,
toUrl('/animated.gif', 64, 60),
null,
expectHeader('image/gif'),
fetchOpts('image/gif')
);
})
);
test( test(
'[vercel dev] Use `@vercel/python` with Flask requirements.txt', '[vercel dev] Use `@vercel/python` with Flask requirements.txt',
testFixtureStdio('python-flask', async testPath => { testFixtureStdio('python-flask', async testPath => {
@@ -1687,3 +1779,11 @@ test(
}); });
}) })
); );
test(
'[vercel dev] Do not fail if `src` is missing',
testFixtureStdio('missing-src-property', async testPath => {
await testPath(200, '/', /hello:index.txt/m);
await testPath(404, '/i-do-not-exist');
})
);

View File

@@ -28,9 +28,6 @@ module.exports = async function prepare(session) {
'first.png': getImageFile(session, { size: 30 }), 'first.png': getImageFile(session, { size: 30 }),
'second.png': getImageFile(session, { size: 20 }), 'second.png': getImageFile(session, { size: 20 }),
}, },
'single-dotfile': {
'.testing': 'i am a dotfile',
},
'empty-directory': {}, 'empty-directory': {},
'config-scope-property-email': { 'config-scope-property-email': {
'now.json': `{ "scope": "${session}@zeit.pub", "builds": [ { "src": "*.html", "use": "@now/static" } ] }`, 'now.json': `{ "scope": "${session}@zeit.pub", "builds": [ { "src": "*.html", "use": "@now/static" } ] }`,
@@ -207,23 +204,6 @@ module.exports = async function prepare(session) {
}, },
}), }),
}, },
'alias-rules': {
'rules.json': JSON.stringify({
rules: [
// for example:
// { pathname: '/', dest: '' },
// { pathname: '/', dest: '', method: 'GET' }
// Will be generated by the actual test
],
}),
'invalid-rules.json': JSON.stringify({
what: { what: 0 },
}),
'invalid-type-rules.json': JSON.stringify({
rules: { what: 0 },
}),
'invalid-json-rules.json': '==ok',
},
'zero-config-next-js': { 'zero-config-next-js': {
'pages/index.js': 'pages/index.js':
'export default () => <div><h1>Now CLI test</h1><p>Zero-config + Next.js</p></div>', 'export default () => <div><h1>Now CLI test</h1><p>Zero-config + Next.js</p></div>',

View File

@@ -422,6 +422,19 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.is(exitCode, 0, formatOutput({ stderr, stdout })); t.is(exitCode, 0, formatOutput({ stderr, stdout }));
} }
async function createSecret() {
const name = `my-secret${Math.floor(Math.random() * 10000)}`;
const res = await apiFetch('/v2/now/secrets', {
method: 'POST',
body: JSON.stringify({ name, value: 'my secret' }),
});
t.is(res.status, 200);
return name;
}
async function nowEnvLsIsEmpty() { async function nowEnvLsIsEmpty() {
const { exitCode, stderr, stdout } = await execa( const { exitCode, stderr, stdout } = await execa(
binaryPath, binaryPath,
@@ -436,26 +449,34 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.regex(stderr, /No Environment Variables found in Project/gm); t.regex(stderr, /No Environment Variables found in Project/gm);
} }
async function nowEnvAdd() { async function nowEnvAddPlaintext() {
const now = execa(binaryPath, ['env', 'add', ...defaultArgs], { const now = execa(binaryPath, ['env', 'add', ...defaultArgs], {
reject: false, reject: false,
cwd: target, cwd: target,
}); });
await waitForPrompt(now, chunk =>
chunk.includes('Which type of Environment Variable do you want to add?')
);
now.stdin.write('\n'); // select plaintext
await waitForPrompt(now, chunk => await waitForPrompt(now, chunk =>
chunk.includes('Whats the name of the variable?') chunk.includes('Whats the name of the variable?')
); );
now.stdin.write('MY_ENV_VAR\n'); now.stdin.write('MY_PLAINTEXT_ENV_VAR\n');
await waitForPrompt( await waitForPrompt(
now, now,
chunk => chunk =>
chunk.includes('Whats the value of') && chunk.includes('MY_ENV_VAR') chunk.includes('Whats the value of') &&
chunk.includes('MY_PLAINTEXT_ENV_VAR')
); );
now.stdin.write('MY_VALUE\n'); now.stdin.write('my plaintext value\n');
await waitForPrompt( await waitForPrompt(
now, now,
chunk => chunk =>
chunk.includes('which Environments') && chunk.includes('MY_ENV_VAR') chunk.includes('which Environments') &&
chunk.includes('MY_PLAINTEXT_ENV_VAR')
); );
now.stdin.write('a\n'); // select all now.stdin.write('a\n'); // select all
@@ -464,10 +485,47 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.is(exitCode, 0, formatOutput({ stderr, stdout })); t.is(exitCode, 0, formatOutput({ stderr, stdout }));
} }
async function nowEnvAddSecret(secretName) {
const now = execa(binaryPath, ['env', 'add', ...defaultArgs], {
reject: false,
cwd: target,
});
await waitForPrompt(now, chunk =>
chunk.includes('Which type of Environment Variable do you want to add?')
);
now.stdin.write('j\n'); // select secret
await waitForPrompt(now, chunk =>
chunk.includes('Whats the name of the variable?')
);
now.stdin.write('MY_SECRET_ENV_VAR\n');
await waitForPrompt(
now,
chunk =>
chunk.includes('Whats the value of') &&
chunk.includes('MY_SECRET_ENV_VAR')
);
now.stdin.write(`@${secretName}\n`);
await waitForPrompt(
now,
chunk =>
chunk.includes('which Environments') &&
chunk.includes('MY_SECRET_ENV_VAR')
);
now.stdin.write('j \n'); // select preview
const { exitCode, stderr, stdout } = await now;
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
}
async function nowEnvAddFromStdin() { async function nowEnvAddFromStdin() {
const now = execa( const now = execa(
binaryPath, binaryPath,
['env', 'add', 'MY_STDIN_VAR', 'development', ...defaultArgs], ['env', 'add', 'plain', 'MY_STDIN_VAR', 'development', ...defaultArgs],
{ {
reject: false, reject: false,
cwd: target, cwd: target,
@@ -481,13 +539,20 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
async function nowEnvAddSystemEnv() { async function nowEnvAddSystemEnv() {
const now = execa( const now = execa(
binaryPath, binaryPath,
['env', 'add', 'VERCEL_URL', ...defaultArgs], ['env', 'add', 'system', 'NEXT_PUBLIC_VERCEL_URL', ...defaultArgs],
{ {
reject: false, reject: false,
cwd: target, cwd: target,
} }
); );
await waitForPrompt(
now,
chunk =>
chunk.includes('Whats the value of') && chunk.includes('VERCEL_URL')
);
now.stdin.write(`\n`); // select VERCEL_URL
await waitForPrompt( await waitForPrompt(
now, now,
chunk => chunk =>
@@ -513,23 +578,63 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.is(exitCode, 0, formatOutput({ stderr, stdout })); t.is(exitCode, 0, formatOutput({ stderr, stdout }));
t.regex(stderr, /Environment Variables found in Project/gm); t.regex(stderr, /Environment Variables found in Project/gm);
console.log(stdout);
const lines = stdout.split('\n'); const lines = stdout.split('\n');
const myEnvVars = lines.filter(line => line.includes('MY_ENV_VAR')); const plaintextEnvs = lines.filter(line =>
t.is(myEnvVars.length, 3); line.includes('MY_PLAINTEXT_ENV_VAR')
t.regex(myEnvVars.join('\n'), /development/gm); );
t.regex(myEnvVars.join('\n'), /preview/gm); t.is(plaintextEnvs.length, 1);
t.regex(myEnvVars.join('\n'), /production/gm); t.regex(plaintextEnvs[0], /Production, Preview, Development/gm);
const myStdinVars = lines.filter(line => line.includes('MY_STDIN_VAR')); const secretEnvs = lines.filter(line => line.includes('MY_SECRET_ENV_VAR'));
t.is(myStdinVars.length, 1); t.is(secretEnvs.length, 1);
t.regex(myStdinVars.join('\n'), /development/gm); t.regex(secretEnvs[0], /Preview/gm);
const vercelVars = lines.filter(line => line.includes('VERCEL_URL')); const stdinEnvs = lines.filter(line => line.includes('MY_STDIN_VAR'));
t.is(vercelVars.length, 3); t.is(stdinEnvs.length, 1);
t.regex(vercelVars.join('\n'), /development/gm); t.regex(stdinEnvs[0], /Development/gm);
t.regex(vercelVars.join('\n'), /preview/gm);
t.regex(vercelVars.join('\n'), /production/gm); const systemEnvs = lines.filter(line => line.includes('VERCEL_URL'));
t.is(systemEnvs.length, 1);
t.regex(systemEnvs[0], /VERCEL_URL/gm);
t.regex(systemEnvs[0], /Production, Preview, Development/gm);
}
// we create a "legacy" env variable that contains a decryptable secret
// to check that vc env pull and vc dev work correctly with decryptable secrets
async function createEnvWithDecryptableSecret() {
console.log('creating an env variable with a decryptable secret');
const name = `my-secret${Math.floor(Math.random() * 10000)}`;
const res = await apiFetch('/v2/now/secrets', {
method: 'POST',
body: JSON.stringify({
name,
value: 'decryptable value',
decryptable: true,
}),
});
t.is(res.status, 200);
const json = await res.json();
const link = require(path.join(target, '.vercel/project.json'));
const resEnv = await apiFetch(`/v4/projects/${link.projectId}/env`, {
method: 'POST',
body: JSON.stringify({
key: 'MY_DECRYPTABLE_SECRET_ENV',
value: json.uid,
target: ['development'],
type: 'secret',
}),
});
t.is(resEnv.status, 200);
} }
async function nowEnvPull() { async function nowEnvPull() {
@@ -549,9 +654,10 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.true(contents.startsWith('# Created by Vercel CLI\n')); t.true(contents.startsWith('# Created by Vercel CLI\n'));
const lines = new Set(contents.split('\n')); const lines = new Set(contents.split('\n'));
t.true(lines.has('MY_ENV_VAR="MY_VALUE"')); t.true(lines.has('MY_PLAINTEXT_ENV_VAR="my plaintext value"'));
t.true(lines.has('MY_STDIN_VAR="{"expect":"quotes"}"')); t.true(lines.has('MY_STDIN_VAR="{"expect":"quotes"}"'));
t.true(lines.has('VERCEL_URL=""')); t.true(lines.has('NEXT_PUBLIC_VERCEL_URL=""'));
t.true(lines.has('MY_DECRYPTABLE_SECRET_ENV="decryptable value"'));
} }
async function nowEnvPullOverwrite() { async function nowEnvPullOverwrite() {
@@ -603,16 +709,18 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
const apiRes = await fetch(apiUrl); const apiRes = await fetch(apiUrl);
t.is(apiRes.status, 200, formatOutput({ stderr, stdout })); t.is(apiRes.status, 200, formatOutput({ stderr, stdout }));
const apiJson = await apiRes.json(); const apiJson = await apiRes.json();
t.is(apiJson['MY_ENV_VAR'], 'MY_VALUE'); t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(apiJson['VERCEL_URL'], host); t.is(apiJson['MY_SECRET_ENV_VAR'], 'my secret');
t.is(apiJson['NEXT_PUBLIC_VERCEL_URL'], host);
const homeUrl = `https://${host}`; const homeUrl = `https://${host}`;
console.log({ homeUrl }); console.log({ homeUrl });
const homeRes = await fetch(homeUrl); const homeRes = await fetch(homeUrl);
t.is(homeRes.status, 200, formatOutput({ stderr, stdout })); t.is(homeRes.status, 200, formatOutput({ stderr, stdout }));
const homeJson = await homeRes.json(); const homeJson = await homeRes.json();
t.is(homeJson['MY_ENV_VAR'], 'MY_VALUE'); t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(homeJson['VERCEL_URL'], host); t.is(homeJson['MY_SECRET_ENV_VAR'], 'my secret');
t.is(homeJson['NEXT_PUBLIC_VERCEL_URL'], host);
} }
async function nowDevWithEnv() { async function nowDevWithEnv() {
@@ -630,8 +738,6 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
return false; return false;
}); });
const localhostNoProtocol = localhost[0].slice('http://'.length);
const apiUrl = `${localhost[0]}/api/get-env`; const apiUrl = `${localhost[0]}/api/get-env`;
const apiRes = await fetch(apiUrl); const apiRes = await fetch(apiUrl);
@@ -639,15 +745,17 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
const apiJson = await apiRes.json(); const apiJson = await apiRes.json();
t.is(apiJson['MY_ENV_VAR'], 'MY_VALUE'); t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(apiJson['VERCEL_URL'], localhostNoProtocol); t.is(apiJson['NEXT_PUBLIC_VERCEL_URL'], '');
t.is(apiJson['MY_DECRYPTABLE_SECRET_ENV'], 'decryptable value');
const homeUrl = localhost[0]; const homeUrl = localhost[0];
const homeRes = await fetch(homeUrl); const homeRes = await fetch(homeUrl);
const homeJson = await homeRes.json(); const homeJson = await homeRes.json();
t.is(homeJson['MY_ENV_VAR'], 'MY_VALUE'); t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(homeJson['VERCEL_URL'], localhostNoProtocol); t.is(homeJson['NEXT_PUBLIC_VERCEL_URL'], '');
t.is(homeJson['MY_DECRYPTABLE_SECRET_ENV'], 'decryptable value');
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 }); vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });
@@ -679,14 +787,105 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
const apiJson = await apiRes.json(); const apiJson = await apiRes.json();
t.is(apiJson['VERCEL_URL'], localhostNoProtocol); t.is(apiJson['NEXT_PUBLIC_VERCEL_URL'], localhostNoProtocol);
t.is(apiJson['MY_ENV_VAR'], 'MY_VALUE'); t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(apiJson['MY_STDIN_VAR'], '{"expect":"quotes"}');
t.is(apiJson['MY_DECRYPTABLE_SECRET_ENV'], 'decryptable value');
const homeUrl = localhost[0]; const homeUrl = localhost[0];
const homeRes = await fetch(homeUrl); const homeRes = await fetch(homeUrl);
const homeJson = await homeRes.json(); const homeJson = await homeRes.json();
t.is(homeJson['MY_ENV_VAR'], 'MY_VALUE'); t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
t.is(homeJson['NEXT_PUBLIC_VERCEL_URL'], localhostNoProtocol);
t.is(homeJson['MY_STDIN_VAR'], '{"expect":"quotes"}');
t.is(homeJson['MY_DECRYPTABLE_SECRET_ENV'], 'decryptable value');
// system env vars are automatically exposed
t.is(apiJson['VERCEL'], '1');
t.is(homeJson['VERCEL'], '1');
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });
const { exitCode, stderr, stdout } = await vc;
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
}
async function enableAutoExposeSystemEnvs() {
const link = require(path.join(target, '.vercel/project.json'));
const res = await apiFetch(`/v2/projects/${link.projectId}`, {
method: 'PATCH',
body: JSON.stringify({ autoExposeSystemEnvs: true }),
});
t.is(res.status, 200);
if (res.status === 200) {
console.log(
`Set autoExposeSystemEnvs=true for project ${link.projectId}`
);
}
}
async function nowEnvPullFetchSystemVars() {
const { exitCode, stderr, stdout } = await execa(
binaryPath,
['env', 'pull', '-y', ...defaultArgs],
{
reject: false,
cwd: target,
}
);
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
const contents = fs.readFileSync(path.join(target, '.env'), 'utf8');
const lines = new Set(contents.split('\n'));
t.true(lines.has('VERCEL="1"'));
t.true(lines.has('VERCEL_URL=""'));
t.true(lines.has('NEXT_PUBLIC_VERCEL_URL=""'));
t.true(lines.has('VERCEL_ENV="development"'));
t.true(lines.has('VERCEL_GIT_PROVIDER=""'));
t.true(lines.has('VERCEL_GIT_REPO_SLUG=""'));
}
async function nowDevAndFetchSystemVars() {
const vc = execa(binaryPath, ['dev', ...defaultArgs], {
reject: false,
cwd: target,
});
let localhost = undefined;
await waitForPrompt(vc, chunk => {
if (chunk.includes('Ready! Available at')) {
localhost = /(https?:[^\s]+)/g.exec(chunk);
return true;
}
return false;
});
const apiUrl = `${localhost[0]}/api/get-env`;
const apiRes = await fetch(apiUrl);
const localhostNoProtocol = localhost[0].slice('http://'.length);
const apiJson = await apiRes.json();
t.is(apiJson['VERCEL'], '1');
t.is(apiJson['VERCEL_URL'], localhostNoProtocol);
t.is(apiJson['VERCEL_ENV'], 'development');
t.is(apiJson['VERCEL_REGION'], 'dev1');
t.is(apiJson['VERCEL_GIT_PROVIDER'], '');
t.is(apiJson['VERCEL_GIT_REPO_SLUG'], '');
const homeUrl = localhost[0];
const homeRes = await fetch(homeUrl);
const homeJson = await homeRes.json();
t.is(homeJson['VERCEL'], '1');
t.is(homeJson['VERCEL_URL'], localhostNoProtocol); t.is(homeJson['VERCEL_URL'], localhostNoProtocol);
t.is(homeJson['VERCEL_ENV'], 'development');
t.is(homeJson['VERCEL_REGION'], undefined);
t.is(homeJson['VERCEL_GIT_PROVIDER'], '');
t.is(homeJson['VERCEL_GIT_REPO_SLUG'], '');
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 }); vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });
@@ -702,12 +901,27 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
await waitForPrompt(now, chunk => await waitForPrompt(now, chunk =>
chunk.includes('Whats the name of the variable?') chunk.includes('Whats the name of the variable?')
); );
now.stdin.write('MY_ENV_VAR\n'); now.stdin.write('MY_PLAINTEXT_ENV_VAR\n');
// expect error if no environment is selected
await waitForPrompt(
now,
chunk =>
chunk.includes('which Environments') &&
chunk.includes('MY_PLAINTEXT_ENV_VAR')
);
now.stdin.write('\n'); // select none
await waitForPrompt(now, chunk =>
chunk.includes(
'Please select an Environment to remove the Environment Variable from.'
)
);
await waitForPrompt( await waitForPrompt(
now, now,
chunk => chunk =>
chunk.includes('which Environments') && chunk.includes('MY_ENV_VAR') chunk.includes('which Environments') &&
chunk.includes('MY_PLAINTEXT_ENV_VAR')
); );
now.stdin.write('a\n'); // select all now.stdin.write('a\n'); // select all
@@ -719,7 +933,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
async function nowEnvRemoveWithArgs() { async function nowEnvRemoveWithArgs() {
const { exitCode, stderr, stdout } = await execa( const { exitCode, stderr, stdout } = await execa(
binaryPath, binaryPath,
['env', 'rm', 'MY_STDIN_VAR', 'development', '-y', ...defaultArgs], ['env', 'rm', 'MY_SECRET_ENV_VAR', 'preview', '-y', ...defaultArgs],
{ {
reject: false, reject: false,
cwd: target, cwd: target,
@@ -727,12 +941,49 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
); );
t.is(exitCode, 0, formatOutput({ stderr, stdout })); t.is(exitCode, 0, formatOutput({ stderr, stdout }));
const {
exitCode: exitCode2,
stderr: stderr2,
stdout: stdout2,
} = await execa(
binaryPath,
['env', 'rm', 'MY_STDIN_VAR', 'development', '-y', ...defaultArgs],
{
reject: false,
cwd: target,
}
);
t.is(exitCode2, 0, formatOutput({ stderr2, stdout2 }));
const {
exitCode: exitCode3,
stderr: stderr3,
stdout: stdout3,
} = await execa(
binaryPath,
[
'env',
'rm',
'MY_DECRYPTABLE_SECRET_ENV',
'development',
'-y',
...defaultArgs,
],
{
reject: false,
cwd: target,
}
);
t.is(exitCode3, 0, formatOutput({ stderr3, stdout3 }));
} }
async function nowEnvRemoveWithNameOnly() { async function nowEnvRemoveWithNameOnly() {
const vc = execa( const vc = execa(
binaryPath, binaryPath,
['env', 'rm', 'VERCEL_URL', '-y', ...defaultArgs], ['env', 'rm', 'NEXT_PUBLIC_VERCEL_URL', '-y', ...defaultArgs],
{ {
reject: false, reject: false,
cwd: target, cwd: target,
@@ -742,7 +993,8 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
await waitForPrompt( await waitForPrompt(
vc, vc,
chunk => chunk =>
chunk.includes('which Environments') && chunk.includes('VERCEL_URL') chunk.includes('which Environments') &&
chunk.includes('NEXT_PUBLIC_VERCEL_URL')
); );
vc.stdin.write('a\n'); // select all vc.stdin.write('a\n'); // select all
@@ -751,11 +1003,14 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
} }
await nowDeploy(); await nowDeploy();
const secretName = await createSecret();
await nowEnvLsIsEmpty(); await nowEnvLsIsEmpty();
await nowEnvAdd(); await nowEnvAddPlaintext();
await nowEnvAddSecret(secretName);
await nowEnvAddFromStdin(); await nowEnvAddFromStdin();
await nowEnvAddSystemEnv(); await nowEnvAddSystemEnv();
await nowEnvLsIncludesVar(); await nowEnvLsIncludesVar();
await createEnvWithDecryptableSecret();
await nowEnvPull(); await nowEnvPull();
await nowEnvPullOverwrite(); await nowEnvPullOverwrite();
await nowEnvPullConfirm(); await nowEnvPullConfirm();
@@ -763,6 +1018,10 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
await nowDevWithEnv(); await nowDevWithEnv();
fs.unlinkSync(path.join(target, '.env')); fs.unlinkSync(path.join(target, '.env'));
await nowDevAndFetchCloudVars(); await nowDevAndFetchCloudVars();
await enableAutoExposeSystemEnvs();
await nowEnvPullFetchSystemVars();
fs.unlinkSync(path.join(target, '.env'));
await nowDevAndFetchSystemVars();
await nowEnvRemove(); await nowEnvRemove();
await nowEnvRemoveWithArgs(); await nowEnvRemoveWithArgs();
await nowEnvRemoveWithNameOnly(); await nowEnvRemoveWithNameOnly();
@@ -1307,7 +1566,7 @@ test('ensure we render a warning for deployments with no files', async t => {
t.is(res.status, 404); t.is(res.status, 404);
}); });
test('output logs of a 2.0 deployment', async t => { test('output logs with "short" output', async t => {
const { stderr, stdout, exitCode } = await execa( const { stderr, stdout, exitCode } = await execa(
binaryPath, binaryPath,
['logs', context.deployment, ...defaultArgs], ['logs', context.deployment, ...defaultArgs],
@@ -1324,13 +1583,21 @@ test('output logs of a 2.0 deployment', async t => {
stderr.includes(`Fetched deployment "${context.deployment}"`), stderr.includes(`Fetched deployment "${context.deployment}"`),
formatOutput({ stderr, stdout }) formatOutput({ stderr, stdout })
); );
// "short" format includes timestamps
t.truthy(
stdout.match(
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/
)
);
t.is(exitCode, 0); t.is(exitCode, 0);
}); });
test('output logs of a 2.0 deployment without annotate', async t => { test('output logs with "raw" output', async t => {
const { stderr, stdout, exitCode } = await execa( const { stderr, stdout, exitCode } = await execa(
binaryPath, binaryPath,
['logs', context.deployment, ...defaultArgs], ['logs', context.deployment, ...defaultArgs, '--output', 'raw'],
{ {
reject: false, reject: false,
} }
@@ -1340,12 +1607,19 @@ test('output logs of a 2.0 deployment without annotate', async t => {
console.log(stdout); console.log(stdout);
console.log(exitCode); console.log(exitCode);
t.true(!stderr.includes('[now-builder-debug]')); t.true(
t.true(!stderr.includes('START RequestId')); stderr.includes(`Fetched deployment "${context.deployment}"`),
t.true(!stderr.includes('END RequestId')); formatOutput({ stderr, stdout })
t.true(!stderr.includes('REPORT RequestId')); );
t.true(!stderr.includes('Init Duration'));
t.true(!stderr.includes('XRAY TraceId')); // "raw" format does not include timestamps
t.is(
null,
stdout.match(
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/
)
);
t.is(exitCode, 0); t.is(exitCode, 0);
}); });

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/client", "name": "@vercel/client",
"version": "9.0.2", "version": "9.0.5",
"main": "dist/index.js", "main": "dist/index.js",
"typings": "dist/index.d.ts", "typings": "dist/index.d.ts",
"homepage": "https://vercel.com", "homepage": "https://vercel.com",
@@ -37,7 +37,7 @@
] ]
}, },
"dependencies": { "dependencies": {
"@vercel/build-utils": "2.5.3", "@vercel/build-utils": "2.7.0",
"@zeit/fetch": "5.2.0", "@zeit/fetch": "5.2.0",
"async-retry": "1.2.3", "async-retry": "1.2.3",
"async-sema": "3.0.0", "async-sema": "3.0.0",

View File

@@ -136,6 +136,7 @@ export async function getVercelIgnore(
'__pycache__', '__pycache__',
'venv', 'venv',
'CVS', 'CVS',
'.vercel_build_output',
]; ];
const cwds = Array.isArray(cwd) ? cwd : [cwd]; const cwds = Array.isArray(cwd) ? cwd : [cwd];

View File

@@ -285,8 +285,8 @@ Learn more: https://vercel.com/docs/runtimes#official-runtimes/go
} }
const mainModGoContents = modMainGoContents const mainModGoContents = modMainGoContents
.replace('__NOW_HANDLER_PACKAGE_NAME', goPackageName) .replace('__VC_HANDLER_PACKAGE_NAME', goPackageName)
.replace('__NOW_HANDLER_FUNC_NAME', goFuncName); .replace('__VC_HANDLER_FUNC_NAME', goFuncName);
if (isGoModExist && isGoModInRootDir) { if (isGoModExist && isGoModInRootDir) {
debug('[mod-root] Write main file to ' + downloadPath); debug('[mod-root] Write main file to ' + downloadPath);
@@ -405,13 +405,13 @@ Learn more: https://vercel.com/docs/runtimes#official-runtimes/go
'utf8' 'utf8'
); );
const mainGoContents = origianlMainGoContents.replace( const mainGoContents = origianlMainGoContents.replace(
'__NOW_HANDLER_FUNC_NAME', '__VC_HANDLER_FUNC_NAME',
handlerFunctionName handlerFunctionName
); );
// in order to allow the user to have `main.go`, // in order to allow the user to have `main.go`,
// we need our `main.go` to be called something else // we need our `main.go` to be called something else
const mainGoFileName = 'main__now__go__.go'; const mainGoFileName = 'main__vc__go__.go';
// Go doesn't like to build files in different directories, // Go doesn't like to build files in different directories,
// so now we place `main.go` together with the user code // so now we place `main.go` together with the user code
@@ -580,9 +580,9 @@ Learn more: https://vercel.com/docs/runtimes#official-runtimes/go`
}; };
} else if (Array.isArray(result)) { } else if (Array.isArray(result)) {
// Got "exit" event from child process // Got "exit" event from child process
throw new Error( const [exitCode, signal] = result;
`Failed to start dev server for "${entrypointWithExt}" (code=${result[0]}, signal=${result[1]})` const reason = signal ? `"${signal}" signal` : `exit code ${exitCode}`;
); throw new Error(`\`go run ${entrypointWithExt}\` failed with ${reason}`);
} else { } else {
throw new Error(`Unexpected result type: ${typeof result}`); throw new Error(`Unexpected result type: ${typeof result}`);
} }

View File

@@ -6,5 +6,5 @@ import (
) )
func main() { func main() {
vc.Start(http.HandlerFunc(__NOW_HANDLER_FUNC_NAME)) vc.Start(http.HandlerFunc(__VC_HANDLER_FUNC_NAME))
} }

View File

@@ -1,12 +1,12 @@
package main package main
import ( import (
"__NOW_HANDLER_PACKAGE_NAME" "__VC_HANDLER_PACKAGE_NAME"
"net/http" "net/http"
vc "github.com/vercel/go-bridge/go/bridge" vc "github.com/vercel/go-bridge/go/bridge"
) )
func main() { func main() {
vc.Start(http.HandlerFunc(__NOW_HANDLER_FUNC_NAME)) vc.Start(http.HandlerFunc(__VC_HANDLER_FUNC_NAME))
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/go", "name": "@vercel/go",
"version": "1.1.6", "version": "1.1.7",
"license": "MIT", "license": "MIT",
"main": "./dist/index", "main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go", "homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",

View File

@@ -1,2 +0,0 @@
/dist
/src/now__bridge.ts

View File

@@ -1,16 +0,0 @@
#!/bin/bash
set -euo pipefail
bridge_defs="$(dirname $(pwd))/now-node-bridge/src/bridge.ts"
cp -v "$bridge_defs" src/now__bridge.ts
tsc
ncc build src/dev-server.ts -e @vercel/build-utils -e @now/build-utils -o dist/dev
mv dist/dev/index.js dist/dev-server.js
rm -rf dist/dev
ncc build src/index.ts -e @vercel/build-utils -e @now/build-utils -o dist/main
mv dist/main/index.js dist/index.js
rm -rf dist/main

View File

@@ -1,43 +0,0 @@
{
"name": "@vercel/next",
"version": "2.6.26",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
"scripts": {
"build": "./build.sh",
"test-integration-once": "jest --env node --verbose --runInBand --bail",
"prepublishOnly": "./build.sh"
},
"repository": {
"type": "git",
"url": "https://github.com/vercel/vercel.git",
"directory": "packages/now-next"
},
"files": [
"dist"
],
"devDependencies": {
"@types/aws-lambda": "8.10.19",
"@types/buffer-crc32": "0.2.0",
"@types/find-up": "4.0.0",
"@types/fs-extra": "8.0.0",
"@types/next-server": "8.0.0",
"@types/resolve-from": "5.0.1",
"@types/semver": "6.0.0",
"@types/yazl": "2.4.1",
"@vercel/nft": "0.9.2",
"async-sema": "3.0.1",
"buffer-crc32": "0.2.13",
"escape-string-regexp": "3.0.0",
"execa": "2.0.4",
"find-up": "4.1.0",
"fs-extra": "7.0.0",
"get-port": "5.0.0",
"resolve-from": "5.0.0",
"semver": "6.1.1",
"set-cookie-parser": "2.4.6",
"typescript": "3.9.3",
"yazl": "https://github.com/ijjk/yazl#70949c55b482647669ce37023017b1514c42b33c"
}
}

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