mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-12 12:57:47 +00:00
Compare commits
66 Commits
@vercel/ru
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a567d047d1 | ||
|
|
fdfb3a385e | ||
|
|
a630e19896 | ||
|
|
00430eeabf | ||
|
|
49f453742b | ||
|
|
bcb8d4f812 | ||
|
|
d42a8a6588 | ||
|
|
301bcf58fb | ||
|
|
11d0091393 | ||
|
|
6405fb51a1 | ||
|
|
edd477e602 | ||
|
|
4f8f8a5b98 | ||
|
|
a8e66eef41 | ||
|
|
23dd29e269 | ||
|
|
4eb4d2b355 | ||
|
|
3590ea06a4 | ||
|
|
314a97b318 | ||
|
|
d41d9e7374 | ||
|
|
80b211fb4a | ||
|
|
ffaf5c9143 | ||
|
|
ba1c2a7e54 | ||
|
|
30a9183836 | ||
|
|
df9accfd6c | ||
|
|
b388357c0b | ||
|
|
90291525c2 | ||
|
|
812dd43b6a | ||
|
|
9e97e0fd58 | ||
|
|
74528c2160 | ||
|
|
82fd2b8068 | ||
|
|
dd94dcab32 | ||
|
|
300e6c6ebb | ||
|
|
cfe6550ac8 | ||
|
|
dfe009ffe2 | ||
|
|
40f38948a0 | ||
|
|
87eba56063 | ||
|
|
d0a5676c26 | ||
|
|
da9fa997ed | ||
|
|
3d79a9d4d4 | ||
|
|
ae13c5ee92 | ||
|
|
ad654139df | ||
|
|
74f8414e12 | ||
|
|
65c2860e14 | ||
|
|
3b5b397b35 | ||
|
|
051e061176 | ||
|
|
30d46321cc | ||
|
|
c2563535ea | ||
|
|
5f2bed4f24 | ||
|
|
cfb7946f4b | ||
|
|
05c5b3a80d | ||
|
|
45bd855250 | ||
|
|
49de8ad9a0 | ||
|
|
a1ea56fd67 | ||
|
|
e88addc9ed | ||
|
|
5d50013f93 | ||
|
|
44e1eb3983 | ||
|
|
f8af013349 | ||
|
|
972cc495ec | ||
|
|
1c580da3d8 | ||
|
|
244554ab1b | ||
|
|
053c185481 | ||
|
|
8805b586ea | ||
|
|
681070ffa0 | ||
|
|
362b17d60a | ||
|
|
c7c9b1a791 | ||
|
|
c42f309463 | ||
|
|
a0ead28369 |
1
.github/CONTRIBUTING.md
vendored
1
.github/CONTRIBUTING.md
vendored
@@ -13,6 +13,7 @@ To get started, execute the following:
|
|||||||
```
|
```
|
||||||
git clone https://github.com/vercel/vercel
|
git clone https://github.com/vercel/vercel
|
||||||
cd vercel
|
cd vercel
|
||||||
|
corepack enable
|
||||||
yarn install
|
yarn install
|
||||||
yarn bootstrap
|
yarn bootstrap
|
||||||
yarn build
|
yarn build
|
||||||
|
|||||||
17
.github/workflows/cancel.yml
vendored
17
.github/workflows/cancel.yml
vendored
@@ -1,17 +0,0 @@
|
|||||||
name: Cancel
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
- '!main'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cancel:
|
|
||||||
name: 'Cancel Previous Runs'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 2
|
|
||||||
steps:
|
|
||||||
- uses: styfle/cancel-workflow-action@0.9.1
|
|
||||||
with:
|
|
||||||
workflow_id: test.yml, test-integration-cli.yml, test-unit.yml
|
|
||||||
access_token: ${{ github.token }}
|
|
||||||
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
@@ -18,7 +18,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
- name: Check Release
|
- name: Check Release
|
||||||
id: check-release
|
id: check-release
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
12
.github/workflows/required-pr-label.yml
vendored
12
.github/workflows/required-pr-label.yml
vendored
@@ -10,13 +10,17 @@ jobs:
|
|||||||
uses: actions/github-script@v6
|
uses: actions/github-script@v6
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
|
let missing = false;
|
||||||
const labels = context.payload.pull_request.labels.map(l => l.name);
|
const labels = context.payload.pull_request.labels.map(l => l.name);
|
||||||
if (labels.filter(l => l.startsWith('area:')).length === 0) {
|
if (labels.filter(l => l.startsWith('area:')).length === 0) {
|
||||||
console.error('\u001b[31mMissing label: Please add at least one "area" label.');
|
console.error('::error::Missing label: Please add at least one "area" label.');
|
||||||
process.exit(1);
|
missing = true;
|
||||||
}
|
}
|
||||||
if (labels.filter(l => l.startsWith('semver:')).length !== 1) {
|
if (labels.filter(l => l.startsWith('semver:')).length !== 1) {
|
||||||
console.error('\u001b[31mMissing label: Please add exactly one "semver" label.');
|
console.error('::error::Missing label: Please add exactly one "semver" label.');
|
||||||
|
missing = true;
|
||||||
|
}
|
||||||
|
if (missing) {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
console.log('\u001b[32mSuccess: This pull request has correct labels, thanks!');
|
console.log('::notice::Success: This pull request has correct labels, thanks!');
|
||||||
|
|||||||
4
.github/workflows/test-integration-cli.yml
vendored
4
.github/workflows/test-integration-cli.yml
vendored
@@ -13,6 +13,10 @@ env:
|
|||||||
TURBO_TEAM: 'vercel'
|
TURBO_TEAM: 'vercel'
|
||||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
name: CLI
|
name: CLI
|
||||||
|
|||||||
4
.github/workflows/test-unit.yml
vendored
4
.github/workflows/test-unit.yml
vendored
@@ -13,6 +13,10 @@ env:
|
|||||||
TURBO_TEAM: 'vercel'
|
TURBO_TEAM: 'vercel'
|
||||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
name: Unit
|
name: Unit
|
||||||
|
|||||||
8
.github/workflows/test.yml
vendored
8
.github/workflows/test.yml
vendored
@@ -14,6 +14,10 @@ env:
|
|||||||
TURBO_TEAM: 'vercel'
|
TURBO_TEAM: 'vercel'
|
||||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
setup:
|
||||||
name: Find Changes
|
name: Find Changes
|
||||||
@@ -78,11 +82,11 @@ jobs:
|
|||||||
- run: yarn install --network-timeout 1000000
|
- run: yarn install --network-timeout 1000000
|
||||||
|
|
||||||
- name: Build ${{matrix.packageName}} and all its dependencies
|
- name: Build ${{matrix.packageName}} and all its dependencies
|
||||||
run: node_modules/.bin/turbo run build --cache-dir=".turbo" --scope=${{matrix.packageName}} --include-dependencies --no-deps
|
run: node utils/gen.js && node_modules/.bin/turbo run build --cache-dir=".turbo" --scope=${{matrix.packageName}} --include-dependencies --no-deps
|
||||||
env:
|
env:
|
||||||
FORCE_COLOR: '1'
|
FORCE_COLOR: '1'
|
||||||
- name: Test ${{matrix.packageName}}
|
- name: Test ${{matrix.packageName}}
|
||||||
run: node_modules/.bin/turbo run test --cache-dir=".turbo" --scope=${{matrix.packageName}} --no-deps -- ${{ join(matrix.testPaths, ' ') }}
|
run: node utils/gen.js && node_modules/.bin/turbo run test --cache-dir=".turbo" --scope=${{matrix.packageName}} --no-deps -- ${{ join(matrix.testPaths, ' ') }}
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
VERCEL_CLI_VERSION: ${{ needs.setup.outputs.dplUrl }}/tarballs/vercel.tgz
|
VERCEL_CLI_VERSION: ${{ needs.setup.outputs.dplUrl }}/tarballs/vercel.tgz
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,3 +28,4 @@ test/lib/deployment/failed-page.txt
|
|||||||
__pycache__
|
__pycache__
|
||||||
.vercel
|
.vercel
|
||||||
.turbo
|
.turbo
|
||||||
|
turbo-cache-key.json
|
||||||
|
|||||||
@@ -380,8 +380,8 @@ This is a [class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refere
|
|||||||
|
|
||||||
This is an abstract enumeration type that is implemented by one of the following possible `String` values:
|
This is an abstract enumeration type that is implemented by one of the following possible `String` values:
|
||||||
|
|
||||||
|
- `nodejs16.x`
|
||||||
- `nodejs14.x`
|
- `nodejs14.x`
|
||||||
- `nodejs12.x`
|
|
||||||
- `go1.x`
|
- `go1.x`
|
||||||
- `java11`
|
- `java11`
|
||||||
- `python3.9`
|
- `python3.9`
|
||||||
|
|||||||
@@ -19,11 +19,9 @@
|
|||||||
|
|
||||||
## Vercel
|
## Vercel
|
||||||
|
|
||||||
Vercel is a platform for **static sites and frontend frameworks**, built to integrate with your headless content, commerce, or database.
|
Vercel is the platform for frontend developers, providing the speed and reliability innovators need to create at the moment of inspiration.
|
||||||
|
|
||||||
We provide a **frictionless developer experience** to take care of the hard things: deploy instantly, scale automatically, and serve personalized content around the globe.
|
We enable teams to iterate quickly and develop, preview, and ship delightful user experiences. Vercel has zero-configuration support for 35+ frontend frameworks and integrates with your headless content, commerce, or database of choice.
|
||||||
|
|
||||||
We make it easy for frontend teams to **develop, preview, and ship** delightful user experiences, where performance is the default.
|
|
||||||
|
|
||||||
## Deploy
|
## Deploy
|
||||||
|
|
||||||
@@ -37,4 +35,4 @@ For details on how to use Vercel, check out our [documentation](https://vercel.c
|
|||||||
|
|
||||||
- [Code of Conduct](./.github/CODE_OF_CONDUCT.md)
|
- [Code of Conduct](./.github/CODE_OF_CONDUCT.md)
|
||||||
- [Contributing Guidelines](./.github/CONTRIBUTING.md)
|
- [Contributing Guidelines](./.github/CONTRIBUTING.md)
|
||||||
- [MIT License](./LICENSE)
|
- [Apache 2.0 License](./LICENSE)
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ async function main() {
|
|||||||
{ recursive: true, force: true }
|
{ recursive: true, force: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await fs.cp(
|
||||||
|
join(repoRoot, 'packages', 'fs-detectors', 'logos'),
|
||||||
|
join(pubDir, 'monorepo-logos'),
|
||||||
|
{ recursive: true, force: true }
|
||||||
|
);
|
||||||
|
|
||||||
const examples = await getExampleList();
|
const examples = await getExampleList();
|
||||||
const pathListAll = join(pubDir, 'list-all.json');
|
const pathListAll = join(pubDir, 'list-all.json');
|
||||||
await fs.writeFile(pathListAll, JSON.stringify(examples));
|
await fs.writeFile(pathListAll, JSON.stringify(examples));
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "next/core-web-vitals"
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
swcMinify: true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = nextConfig
|
module.exports = nextConfig
|
||||||
|
|||||||
637
examples/nextjs/package-lock.json
generated
Normal file
637
examples/nextjs/package-lock.json
generated
Normal file
@@ -0,0 +1,637 @@
|
|||||||
|
{
|
||||||
|
"name": "nextjs",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "nextjs",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"next": "13.0.1",
|
||||||
|
"react": "18.2.0",
|
||||||
|
"react-dom": "18.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/env": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-gK60YoFae3s8qi5UgIzbvxOhsh5gKyEaiKH5+kLBUYXLlrPyWJR2xKBj2WqvHkO7wDX7/Hed3DAqjSpU4ijIvQ=="
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-android-arm-eabi": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-M28QSbohZlNXNn//HY6lV2T3YaMzG58Jwr0YwOdVmOQv6i+7lu6xe3GqQu4kdqInqhLrBXnL+nabFuGTVSHtTg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-android-arm64": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-szmO/i6GoHcPXcbhUKhwBMETWHNXH3ITz9wfxwOOFBNKdDU8pjKsHL88lg28aOiQYZSU1sxu1v1p9KY5kJIZCg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-darwin-arm64": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-O1RxCaiDNOjGZmdAp6SQoHUITt9aVDQXoR3lZ/TloI/NKRAyAV4u0KUUofK+KaZeHOmVTnPUaQuCyZSc3i1x5Q==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-darwin-x64": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-8E6BY/VO+QqQkthhoWgB8mJMw1NcN9Vhl2OwEwxv8jy2r3zjeU+WNRxz4y8RLbcY0R1h+vHlXuP0mLnuac84tQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-freebsd-x64": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-ocwoOxm2KVwF50RyoAT+2RQPLlkyoF7sAqzMUVgj+S6+DTkY3iwH+Zpo0XAk2pnqT9qguOrKnEpq9EIx//+K7Q==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-linux-arm-gnueabihf": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-yO7e3zITfGol/N6lPQnmIRi0WyuILBMXrvH6EdmWzzqMDJFfTCII6l+B6gMO5WVDCTQUGQlQRNZ7sFqWR4I71g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-OEs6WDPDI8RyM8SjOqTDMqMBfOlU97VnW6ZMXUvzUTyH0K9c7NF+cn7UMu+I4tKFN0uJ9WQs/6TYaFBGkgoVVA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-linux-arm64-musl": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-y5ypFK0Y3urZSFoQxbtDqvKsBx026sz+Fm+xHlPWlGHNZrbs3Q812iONjcZTo09QwRMk5X86iMWBRxV18xMhaw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-linux-x64-gnu": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-XDIHEE6SU8VCF+dUVntD6PDv6RK31N0forx9kucZBYirbe8vCZ+Yx8hYgvtIaGrTcWtGxibxmND0pIuHDq8H5g==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-linux-x64-musl": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-yxIOuuz5EOx0F1FDtsyzaLgnDym0Ysxv8CWeJyDTKKmt9BVyITg6q/cD+RP9bEkT1TQi+PYXIMATSz675Q82xw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-+ucLe2qgQzP+FM94jD4ns6LDGyMFaX9k3lVHqu/tsQCy2giMymbport4y4p77mYcXEMlDaHMzlHgOQyHRniWFA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-win32-ia32-msvc": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-Krr/qGN7OB35oZuvMAZKoXDt2IapynIWLh5A5rz6AODb7f/ZJqyAuZSK12vOa2zKdobS36Qm4IlxxBqn9c00MA==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-win32-x64-msvc": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-t/0G33t/6VGWZUGCOT7rG42qqvf/x+MrFp1CU+8CN6PrjSSL57R5bqkXfubV9t4eCEnUxVP+5Hn3MoEXEebtEw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/helpers": {
|
||||||
|
"version": "0.4.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz",
|
||||||
|
"integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/caniuse-lite": {
|
||||||
|
"version": "1.0.30001427",
|
||||||
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001427.tgz",
|
||||||
|
"integrity": "sha512-lfXQ73oB9c8DP5Suxaszm+Ta2sr/4tf8+381GkIm1MLj/YdLf+rEDyDSRCzeltuyTVGm+/s18gdZ0q+Wmp8VsQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/browserslist"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/client-only": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
|
||||||
|
},
|
||||||
|
"node_modules/js-tokens": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||||
|
},
|
||||||
|
"node_modules/loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"loose-envify": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||||
|
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/next": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/next/-/next-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-ErCNBPIeZMKFn6hX+ZBSlqZVgJIeitEqhGTuQUNmYXJ07/A71DZ7AJI8eyHYUdBb686LUpV1/oBdTq9RpzRVPg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@next/env": "13.0.1",
|
||||||
|
"@swc/helpers": "0.4.11",
|
||||||
|
"caniuse-lite": "^1.0.30001406",
|
||||||
|
"postcss": "8.4.14",
|
||||||
|
"styled-jsx": "5.1.0",
|
||||||
|
"use-sync-external-store": "1.2.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"next": "dist/bin/next"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.6.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@next/swc-android-arm-eabi": "13.0.1",
|
||||||
|
"@next/swc-android-arm64": "13.0.1",
|
||||||
|
"@next/swc-darwin-arm64": "13.0.1",
|
||||||
|
"@next/swc-darwin-x64": "13.0.1",
|
||||||
|
"@next/swc-freebsd-x64": "13.0.1",
|
||||||
|
"@next/swc-linux-arm-gnueabihf": "13.0.1",
|
||||||
|
"@next/swc-linux-arm64-gnu": "13.0.1",
|
||||||
|
"@next/swc-linux-arm64-musl": "13.0.1",
|
||||||
|
"@next/swc-linux-x64-gnu": "13.0.1",
|
||||||
|
"@next/swc-linux-x64-musl": "13.0.1",
|
||||||
|
"@next/swc-win32-arm64-msvc": "13.0.1",
|
||||||
|
"@next/swc-win32-ia32-msvc": "13.0.1",
|
||||||
|
"@next/swc-win32-x64-msvc": "13.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"fibers": ">= 3.1.0",
|
||||||
|
"node-sass": "^6.0.0 || ^7.0.0",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"sass": "^1.3.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"fibers": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node-sass": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.4.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
|
||||||
|
"integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.4",
|
||||||
|
"picocolors": "^1.0.0",
|
||||||
|
"source-map-js": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react": {
|
||||||
|
"version": "18.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||||
|
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-dom": {
|
||||||
|
"version": "18.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||||
|
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.1.0",
|
||||||
|
"scheduler": "^0.23.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/scheduler": {
|
||||||
|
"version": "0.23.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||||
|
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/styled-jsx": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-/iHaRJt9U7T+5tp6TRelLnqBqiaIT0HsO0+vgyj8hK2KUk7aejFqRrumqPUlAqDwAj8IbS/1hk3IhBAAK/FCUQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"client-only": "0.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@babel/core": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"babel-plugin-macros": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
|
||||||
|
},
|
||||||
|
"node_modules/use-sync-external-store": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@next/env": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-gK60YoFae3s8qi5UgIzbvxOhsh5gKyEaiKH5+kLBUYXLlrPyWJR2xKBj2WqvHkO7wDX7/Hed3DAqjSpU4ijIvQ=="
|
||||||
|
},
|
||||||
|
"@next/swc-android-arm-eabi": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-M28QSbohZlNXNn//HY6lV2T3YaMzG58Jwr0YwOdVmOQv6i+7lu6xe3GqQu4kdqInqhLrBXnL+nabFuGTVSHtTg==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-android-arm64": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-szmO/i6GoHcPXcbhUKhwBMETWHNXH3ITz9wfxwOOFBNKdDU8pjKsHL88lg28aOiQYZSU1sxu1v1p9KY5kJIZCg==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-darwin-arm64": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-O1RxCaiDNOjGZmdAp6SQoHUITt9aVDQXoR3lZ/TloI/NKRAyAV4u0KUUofK+KaZeHOmVTnPUaQuCyZSc3i1x5Q==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-darwin-x64": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-8E6BY/VO+QqQkthhoWgB8mJMw1NcN9Vhl2OwEwxv8jy2r3zjeU+WNRxz4y8RLbcY0R1h+vHlXuP0mLnuac84tQ==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-freebsd-x64": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-ocwoOxm2KVwF50RyoAT+2RQPLlkyoF7sAqzMUVgj+S6+DTkY3iwH+Zpo0XAk2pnqT9qguOrKnEpq9EIx//+K7Q==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-linux-arm-gnueabihf": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-yO7e3zITfGol/N6lPQnmIRi0WyuILBMXrvH6EdmWzzqMDJFfTCII6l+B6gMO5WVDCTQUGQlQRNZ7sFqWR4I71g==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-linux-arm64-gnu": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-OEs6WDPDI8RyM8SjOqTDMqMBfOlU97VnW6ZMXUvzUTyH0K9c7NF+cn7UMu+I4tKFN0uJ9WQs/6TYaFBGkgoVVA==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-linux-arm64-musl": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-y5ypFK0Y3urZSFoQxbtDqvKsBx026sz+Fm+xHlPWlGHNZrbs3Q812iONjcZTo09QwRMk5X86iMWBRxV18xMhaw==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-linux-x64-gnu": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-XDIHEE6SU8VCF+dUVntD6PDv6RK31N0forx9kucZBYirbe8vCZ+Yx8hYgvtIaGrTcWtGxibxmND0pIuHDq8H5g==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-linux-x64-musl": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-yxIOuuz5EOx0F1FDtsyzaLgnDym0Ysxv8CWeJyDTKKmt9BVyITg6q/cD+RP9bEkT1TQi+PYXIMATSz675Q82xw==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-win32-arm64-msvc": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-+ucLe2qgQzP+FM94jD4ns6LDGyMFaX9k3lVHqu/tsQCy2giMymbport4y4p77mYcXEMlDaHMzlHgOQyHRniWFA==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-win32-ia32-msvc": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-Krr/qGN7OB35oZuvMAZKoXDt2IapynIWLh5A5rz6AODb7f/ZJqyAuZSK12vOa2zKdobS36Qm4IlxxBqn9c00MA==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@next/swc-win32-x64-msvc": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-t/0G33t/6VGWZUGCOT7rG42qqvf/x+MrFp1CU+8CN6PrjSSL57R5bqkXfubV9t4eCEnUxVP+5Hn3MoEXEebtEw==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@swc/helpers": {
|
||||||
|
"version": "0.4.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz",
|
||||||
|
"integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"caniuse-lite": {
|
||||||
|
"version": "1.0.30001427",
|
||||||
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001427.tgz",
|
||||||
|
"integrity": "sha512-lfXQ73oB9c8DP5Suxaszm+Ta2sr/4tf8+381GkIm1MLj/YdLf+rEDyDSRCzeltuyTVGm+/s18gdZ0q+Wmp8VsQ=="
|
||||||
|
},
|
||||||
|
"client-only": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
|
||||||
|
},
|
||||||
|
"js-tokens": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||||
|
},
|
||||||
|
"loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"requires": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nanoid": {
|
||||||
|
"version": "3.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||||
|
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
|
||||||
|
},
|
||||||
|
"next": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/next/-/next-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-ErCNBPIeZMKFn6hX+ZBSlqZVgJIeitEqhGTuQUNmYXJ07/A71DZ7AJI8eyHYUdBb686LUpV1/oBdTq9RpzRVPg==",
|
||||||
|
"requires": {
|
||||||
|
"@next/env": "13.0.1",
|
||||||
|
"@next/swc-android-arm-eabi": "13.0.1",
|
||||||
|
"@next/swc-android-arm64": "13.0.1",
|
||||||
|
"@next/swc-darwin-arm64": "13.0.1",
|
||||||
|
"@next/swc-darwin-x64": "13.0.1",
|
||||||
|
"@next/swc-freebsd-x64": "13.0.1",
|
||||||
|
"@next/swc-linux-arm-gnueabihf": "13.0.1",
|
||||||
|
"@next/swc-linux-arm64-gnu": "13.0.1",
|
||||||
|
"@next/swc-linux-arm64-musl": "13.0.1",
|
||||||
|
"@next/swc-linux-x64-gnu": "13.0.1",
|
||||||
|
"@next/swc-linux-x64-musl": "13.0.1",
|
||||||
|
"@next/swc-win32-arm64-msvc": "13.0.1",
|
||||||
|
"@next/swc-win32-ia32-msvc": "13.0.1",
|
||||||
|
"@next/swc-win32-x64-msvc": "13.0.1",
|
||||||
|
"@swc/helpers": "0.4.11",
|
||||||
|
"caniuse-lite": "^1.0.30001406",
|
||||||
|
"postcss": "8.4.14",
|
||||||
|
"styled-jsx": "5.1.0",
|
||||||
|
"use-sync-external-store": "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"picocolors": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
|
||||||
|
},
|
||||||
|
"postcss": {
|
||||||
|
"version": "8.4.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
|
||||||
|
"integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
|
||||||
|
"requires": {
|
||||||
|
"nanoid": "^3.3.4",
|
||||||
|
"picocolors": "^1.0.0",
|
||||||
|
"source-map-js": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"version": "18.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||||
|
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-dom": {
|
||||||
|
"version": "18.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||||
|
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.1.0",
|
||||||
|
"scheduler": "^0.23.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scheduler": {
|
||||||
|
"version": "0.23.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||||
|
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"source-map-js": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
|
||||||
|
},
|
||||||
|
"styled-jsx": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-/iHaRJt9U7T+5tp6TRelLnqBqiaIT0HsO0+vgyj8hK2KUk7aejFqRrumqPUlAqDwAj8IbS/1hk3IhBAAK/FCUQ==",
|
||||||
|
"requires": {
|
||||||
|
"client-only": "0.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tslib": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
|
||||||
|
},
|
||||||
|
"use-sync-external-store": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
|
||||||
|
"requires": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,12 +9,8 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "12.3.1",
|
"next": "13.0.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"eslint": "8.23.1",
|
|
||||||
"eslint-config-next": "12.3.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ export default function Home() {
|
|||||||
|
|
||||||
<a
|
<a
|
||||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
className={styles.card}
|
className={styles.card}
|
||||||
>
|
>
|
||||||
<h2>Deploy →</h2>
|
<h2>Deploy →</h2>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@@ -3,6 +3,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"packageManager": "yarn@1.22.19",
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
@@ -43,14 +44,14 @@
|
|||||||
"publish-canary": "git checkout main && git pull && lerna version prerelease --preid canary --message \"Publish Canary\" --exact",
|
"publish-canary": "git checkout main && git pull && lerna version prerelease --preid canary --message \"Publish Canary\" --exact",
|
||||||
"publish-from-github": "./utils/publish.sh",
|
"publish-from-github": "./utils/publish.sh",
|
||||||
"changelog": "node utils/changelog.js",
|
"changelog": "node utils/changelog.js",
|
||||||
"build": "turbo run build",
|
"build": "node utils/gen.js && turbo run build",
|
||||||
"vercel-build": "yarn build && yarn run pack && cd api && node -r ts-eager/register ./_lib/script/build.ts",
|
"vercel-build": "yarn build && yarn run pack && cd api && node -r ts-eager/register ./_lib/script/build.ts",
|
||||||
"pre-commit": "lint-staged",
|
"pre-commit": "lint-staged",
|
||||||
"test": "jest --rootDir=\"test\" --testPathPattern=\"\\.test.js\"",
|
"test": "jest --rootDir=\"test\" --testPathPattern=\"\\.test.js\"",
|
||||||
"test-unit": "yarn test && turbo run test-unit",
|
"test-unit": "yarn test && node utils/gen.js && turbo run test-unit",
|
||||||
"test-integration-cli": "turbo run test-integration-cli",
|
"test-integration-cli": "node utils/gen.js && turbo run test-integration-cli",
|
||||||
"test-integration-once": "turbo run test-integration-once",
|
"test-integration-once": "node utils/gen.js && turbo run test-integration-once",
|
||||||
"test-integration-dev": "turbo run test-integration-dev",
|
"test-integration-dev": "node utils/gen.js && turbo run test-integration-dev",
|
||||||
"lint": "eslint . --ext .ts,.js",
|
"lint": "eslint . --ext .ts,.js",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"pack": "cd utils && node -r ts-eager/register ./pack.ts"
|
"pack": "cd utils && node -r ts-eager/register ./pack.ts"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/build-utils",
|
"name": "@vercel/build-utils",
|
||||||
"version": "5.5.3",
|
"version": "5.5.7",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.js",
|
"types": "./dist/index.d.js",
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export class EdgeFunction {
|
|||||||
assets?: { name: string; path: string }[];
|
assets?: { name: string; path: string }[];
|
||||||
|
|
||||||
/** The regions where the edge function will be executed on */
|
/** The regions where the edge function will be executed on */
|
||||||
regions?: 'auto' | string[] | 'all' | 'default';
|
regions?: string | string[];
|
||||||
|
|
||||||
constructor(params: Omit<EdgeFunction, 'type'>) {
|
constructor(params: Omit<EdgeFunction, 'type'>) {
|
||||||
this.type = 'EdgeFunction';
|
this.type = 'EdgeFunction';
|
||||||
|
|||||||
@@ -5,7 +5,13 @@ import path from 'path';
|
|||||||
import Sema from 'async-sema';
|
import Sema from 'async-sema';
|
||||||
import { FileBase } from './types';
|
import { FileBase } from './types';
|
||||||
|
|
||||||
const semaToPreventEMFILE = new Sema(20);
|
const DEFAULT_SEMA = 20;
|
||||||
|
const semaToPreventEMFILE = new Sema(
|
||||||
|
parseInt(
|
||||||
|
process.env.VERCEL_INTERNAL_FILE_FS_REF_SEMA || String(DEFAULT_SEMA),
|
||||||
|
10
|
||||||
|
) || DEFAULT_SEMA
|
||||||
|
);
|
||||||
|
|
||||||
interface FileFsRefOptions {
|
interface FileFsRefOptions {
|
||||||
mode?: number;
|
mode?: number;
|
||||||
|
|||||||
@@ -12,7 +12,13 @@ interface FileRefOptions {
|
|||||||
mutable?: boolean;
|
mutable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const semaToDownloadFromS3 = new Sema(5);
|
const DEFAULT_SEMA = 5;
|
||||||
|
const semaToDownloadFromS3 = new Sema(
|
||||||
|
parseInt(
|
||||||
|
process.env.VERCEL_INTERNAL_FILE_REF_SEMA || String(DEFAULT_SEMA),
|
||||||
|
10
|
||||||
|
) || DEFAULT_SEMA
|
||||||
|
);
|
||||||
|
|
||||||
class BailableError extends Error {
|
class BailableError extends Error {
|
||||||
public bail: boolean;
|
public bail: boolean;
|
||||||
|
|||||||
@@ -3,28 +3,37 @@ import { NodeVersion } from '../types';
|
|||||||
import { NowBuildError } from '../errors';
|
import { NowBuildError } from '../errors';
|
||||||
import debug from '../debug';
|
import debug from '../debug';
|
||||||
|
|
||||||
const allOptions = [
|
function getOptions() {
|
||||||
{ major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
const options = [
|
||||||
{ major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
{ major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
{
|
{ major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
||||||
major: 12,
|
{
|
||||||
range: '12.x',
|
major: 12,
|
||||||
runtime: 'nodejs12.x',
|
range: '12.x',
|
||||||
discontinueDate: new Date('2022-10-03'),
|
runtime: 'nodejs12.x',
|
||||||
},
|
discontinueDate: new Date('2022-10-03'),
|
||||||
{
|
},
|
||||||
major: 10,
|
{
|
||||||
range: '10.x',
|
major: 10,
|
||||||
runtime: 'nodejs10.x',
|
range: '10.x',
|
||||||
discontinueDate: new Date('2021-04-20'),
|
runtime: 'nodejs10.x',
|
||||||
},
|
discontinueDate: new Date('2021-04-20'),
|
||||||
{
|
},
|
||||||
major: 8,
|
{
|
||||||
range: '8.10.x',
|
major: 8,
|
||||||
runtime: 'nodejs8.10',
|
range: '8.10.x',
|
||||||
discontinueDate: new Date('2020-01-06'),
|
runtime: 'nodejs8.10',
|
||||||
},
|
discontinueDate: new Date('2020-01-06'),
|
||||||
] as const;
|
},
|
||||||
|
] as const;
|
||||||
|
if (process.env.VERCEL_ALLOW_NODEJS18 === '1') {
|
||||||
|
return [
|
||||||
|
{ major: 18, range: '18.x', runtime: 'nodejs18.x' },
|
||||||
|
...options,
|
||||||
|
] as const;
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
function getHint(isAuto = false) {
|
function getHint(isAuto = false) {
|
||||||
const { major, range } = getLatestNodeVersion();
|
const { major, range } = getLatestNodeVersion();
|
||||||
@@ -34,11 +43,11 @@ function getHint(isAuto = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getLatestNodeVersion() {
|
export function getLatestNodeVersion() {
|
||||||
return allOptions[0];
|
return getOptions()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDiscontinuedNodeVersions(): NodeVersion[] {
|
export function getDiscontinuedNodeVersions(): NodeVersion[] {
|
||||||
return allOptions.filter(isDiscontinued);
|
return getOptions().filter(isDiscontinued);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSupportedNodeVersion(
|
export async function getSupportedNodeVersion(
|
||||||
@@ -50,7 +59,7 @@ export async function getSupportedNodeVersion(
|
|||||||
if (engineRange) {
|
if (engineRange) {
|
||||||
const found =
|
const found =
|
||||||
validRange(engineRange) &&
|
validRange(engineRange) &&
|
||||||
allOptions.some(o => {
|
getOptions().some(o => {
|
||||||
// the array is already in order so return the first
|
// the array is already in order so return the first
|
||||||
// match which will be the newest version of node
|
// match which will be the newest version of node
|
||||||
selection = o;
|
selection = o;
|
||||||
|
|||||||
@@ -251,33 +251,24 @@ export async function getNodeVersion(
|
|||||||
meta: Meta = {}
|
meta: Meta = {}
|
||||||
): Promise<NodeVersion> {
|
): Promise<NodeVersion> {
|
||||||
const latest = getLatestNodeVersion();
|
const latest = getLatestNodeVersion();
|
||||||
if (meta && meta.isDev) {
|
if (meta.isDev) {
|
||||||
// Use the system-installed version of `node` in PATH for `vercel dev`
|
// Use the system-installed version of `node` in PATH for `vercel dev`
|
||||||
return { ...latest, runtime: 'nodejs' };
|
return { ...latest, runtime: 'nodejs' };
|
||||||
}
|
}
|
||||||
const { packageJson } = await scanParentDirs(destPath, true);
|
const { packageJson } = await scanParentDirs(destPath, true);
|
||||||
let { nodeVersion } = config;
|
let { nodeVersion } = config;
|
||||||
let isAuto = true;
|
let isAuto = true;
|
||||||
if (packageJson && packageJson.engines && packageJson.engines.node) {
|
if (packageJson?.engines?.node) {
|
||||||
const { node } = packageJson.engines;
|
const { node } = packageJson.engines;
|
||||||
if (
|
if (nodeVersion && validRange(node) && !intersects(nodeVersion, node)) {
|
||||||
nodeVersion &&
|
|
||||||
validRange(node) &&
|
|
||||||
!intersects(nodeVersion, node) &&
|
|
||||||
!meta.isDev
|
|
||||||
) {
|
|
||||||
console.warn(
|
console.warn(
|
||||||
`Warning: Due to "engines": { "node": "${node}" } in your \`package.json\` file, the Node.js Version defined in your Project Settings ("${nodeVersion}") will not apply. Learn More: http://vercel.link/node-version`
|
`Warning: Due to "engines": { "node": "${node}" } in your \`package.json\` file, the Node.js Version defined in your Project Settings ("${nodeVersion}") will not apply. Learn More: http://vercel.link/node-version`
|
||||||
);
|
);
|
||||||
} else if (coerce(node)?.raw === node && !meta.isDev) {
|
} else if (coerce(node)?.raw === node) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Warning: Detected "engines": { "node": "${node}" } in your \`package.json\` with major.minor.patch, but only major Node.js Version can be selected. Learn More: http://vercel.link/node-version`
|
`Warning: Detected "engines": { "node": "${node}" } in your \`package.json\` with major.minor.patch, but only major Node.js Version can be selected. Learn More: http://vercel.link/node-version`
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (validRange(node) && intersects(`${latest.major + 1}.x`, node)) {
|
||||||
validRange(node) &&
|
|
||||||
intersects(`${latest.major + 1}.x`, node) &&
|
|
||||||
!meta.isDev
|
|
||||||
) {
|
|
||||||
console.warn(
|
console.warn(
|
||||||
`Warning: Detected "engines": { "node": "${node}" } in your \`package.json\` that will automatically upgrade when a new major Node.js Version is released. Learn More: http://vercel.link/node-version`
|
`Warning: Detected "engines": { "node": "${node}" } in your \`package.json\` that will automatically upgrade when a new major Node.js Version is released. Learn More: http://vercel.link/node-version`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export interface LambdaOptionsBase {
|
|||||||
regions?: string[];
|
regions?: string[];
|
||||||
supportsMultiPayloads?: boolean;
|
supportsMultiPayloads?: boolean;
|
||||||
supportsWrapper?: boolean;
|
supportsWrapper?: boolean;
|
||||||
|
experimentalResponseStreaming?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LambdaOptionsWithFiles extends LambdaOptionsBase {
|
export interface LambdaOptionsWithFiles extends LambdaOptionsBase {
|
||||||
@@ -60,6 +61,7 @@ export class Lambda {
|
|||||||
zipBuffer?: Buffer;
|
zipBuffer?: Buffer;
|
||||||
supportsMultiPayloads?: boolean;
|
supportsMultiPayloads?: boolean;
|
||||||
supportsWrapper?: boolean;
|
supportsWrapper?: boolean;
|
||||||
|
experimentalResponseStreaming?: boolean;
|
||||||
|
|
||||||
constructor(opts: LambdaOptions) {
|
constructor(opts: LambdaOptions) {
|
||||||
const {
|
const {
|
||||||
@@ -72,6 +74,7 @@ export class Lambda {
|
|||||||
regions,
|
regions,
|
||||||
supportsMultiPayloads,
|
supportsMultiPayloads,
|
||||||
supportsWrapper,
|
supportsWrapper,
|
||||||
|
experimentalResponseStreaming,
|
||||||
} = opts;
|
} = opts;
|
||||||
if ('files' in opts) {
|
if ('files' in opts) {
|
||||||
assert(typeof opts.files === 'object', '"files" must be an object');
|
assert(typeof opts.files === 'object', '"files" must be an object');
|
||||||
@@ -132,6 +135,7 @@ export class Lambda {
|
|||||||
this.zipBuffer = 'zipBuffer' in opts ? opts.zipBuffer : undefined;
|
this.zipBuffer = 'zipBuffer' in opts ? opts.zipBuffer : undefined;
|
||||||
this.supportsMultiPayloads = supportsMultiPayloads;
|
this.supportsMultiPayloads = supportsMultiPayloads;
|
||||||
this.supportsWrapper = supportsWrapper;
|
this.supportsWrapper = supportsWrapper;
|
||||||
|
this.experimentalResponseStreaming = experimentalResponseStreaming;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createZip(): Promise<Buffer> {
|
async createZip(): Promise<Buffer> {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ interface PrerenderOptions {
|
|||||||
group?: number;
|
group?: number;
|
||||||
bypassToken?: string | null /* optional to be non-breaking change */;
|
bypassToken?: string | null /* optional to be non-breaking change */;
|
||||||
allowQuery?: string[];
|
allowQuery?: string[];
|
||||||
|
initialHeaders?: Record<string, string>;
|
||||||
|
initialStatus?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Prerender {
|
export class Prerender {
|
||||||
@@ -18,6 +20,8 @@ export class Prerender {
|
|||||||
public group?: number;
|
public group?: number;
|
||||||
public bypassToken: string | null;
|
public bypassToken: string | null;
|
||||||
public allowQuery?: string[];
|
public allowQuery?: string[];
|
||||||
|
public initialHeaders?: Record<string, string>;
|
||||||
|
public initialStatus?: number;
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
expiration,
|
expiration,
|
||||||
@@ -26,6 +30,8 @@ export class Prerender {
|
|||||||
group,
|
group,
|
||||||
bypassToken,
|
bypassToken,
|
||||||
allowQuery,
|
allowQuery,
|
||||||
|
initialHeaders,
|
||||||
|
initialStatus,
|
||||||
}: PrerenderOptions) {
|
}: PrerenderOptions) {
|
||||||
this.type = 'Prerender';
|
this.type = 'Prerender';
|
||||||
this.expiration = expiration;
|
this.expiration = expiration;
|
||||||
@@ -64,6 +70,30 @@ export class Prerender {
|
|||||||
}
|
}
|
||||||
this.fallback = fallback;
|
this.fallback = fallback;
|
||||||
|
|
||||||
|
if (initialHeaders !== undefined) {
|
||||||
|
if (
|
||||||
|
!initialHeaders ||
|
||||||
|
typeof initialHeaders !== 'object' ||
|
||||||
|
Object.entries(initialHeaders).some(
|
||||||
|
([key, value]) => typeof key !== 'string' || typeof value !== 'string'
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`The \`initialHeaders\` argument for \`Prerender\` must be an object with string key/values`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.initialHeaders = initialHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialStatus !== undefined) {
|
||||||
|
if (initialStatus <= 0 || !Number.isInteger(initialStatus)) {
|
||||||
|
throw new Error(
|
||||||
|
`The \`initialStatus\` argument for \`Prerender\` must be a natural number.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.initialStatus = initialStatus;
|
||||||
|
}
|
||||||
|
|
||||||
if (allowQuery !== undefined) {
|
if (allowQuery !== undefined) {
|
||||||
if (!Array.isArray(allowQuery)) {
|
if (!Array.isArray(allowQuery)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
79
packages/build-utils/test/unit.test.ts
vendored
79
packages/build-utils/test/unit.test.ts
vendored
@@ -216,10 +216,6 @@ it('should download symlinks even with incorrect file', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should only match supported node versions, otherwise throw an error', async () => {
|
it('should only match supported node versions, otherwise throw an error', async () => {
|
||||||
expect(await getSupportedNodeVersion('12.x', false)).toHaveProperty(
|
|
||||||
'major',
|
|
||||||
12
|
|
||||||
);
|
|
||||||
expect(await getSupportedNodeVersion('14.x', false)).toHaveProperty(
|
expect(await getSupportedNodeVersion('14.x', false)).toHaveProperty(
|
||||||
'major',
|
'major',
|
||||||
14
|
14
|
||||||
@@ -240,10 +236,6 @@ it('should only match supported node versions, otherwise throw an error', async
|
|||||||
await expectBuilderError(getSupportedNodeVersion('foo', true), autoMessage);
|
await expectBuilderError(getSupportedNodeVersion('foo', true), autoMessage);
|
||||||
await expectBuilderError(getSupportedNodeVersion('=> 10', true), autoMessage);
|
await expectBuilderError(getSupportedNodeVersion('=> 10', true), autoMessage);
|
||||||
|
|
||||||
expect(await getSupportedNodeVersion('12.x', true)).toHaveProperty(
|
|
||||||
'major',
|
|
||||||
12
|
|
||||||
);
|
|
||||||
expect(await getSupportedNodeVersion('14.x', true)).toHaveProperty(
|
expect(await getSupportedNodeVersion('14.x', true)).toHaveProperty(
|
||||||
'major',
|
'major',
|
||||||
14
|
14
|
||||||
@@ -273,24 +265,41 @@ it('should only match supported node versions, otherwise throw an error', async
|
|||||||
|
|
||||||
it('should match all semver ranges', async () => {
|
it('should match all semver ranges', async () => {
|
||||||
// See https://docs.npmjs.com/files/package.json#engines
|
// See https://docs.npmjs.com/files/package.json#engines
|
||||||
expect(await getSupportedNodeVersion('12.0.0')).toHaveProperty('major', 12);
|
expect(await getSupportedNodeVersion('14.0.0')).toHaveProperty('major', 14);
|
||||||
expect(await getSupportedNodeVersion('12.x')).toHaveProperty('major', 12);
|
expect(await getSupportedNodeVersion('14.x')).toHaveProperty('major', 14);
|
||||||
expect(await getSupportedNodeVersion('>=10')).toHaveProperty('major', 16);
|
expect(await getSupportedNodeVersion('>=10')).toHaveProperty('major', 16);
|
||||||
expect(await getSupportedNodeVersion('>=10.3.0')).toHaveProperty('major', 16);
|
expect(await getSupportedNodeVersion('>=10.3.0')).toHaveProperty('major', 16);
|
||||||
expect(await getSupportedNodeVersion('11.5.0 - 12.5.0')).toHaveProperty(
|
expect(await getSupportedNodeVersion('16.5.0 - 16.9.0')).toHaveProperty(
|
||||||
'major',
|
'major',
|
||||||
12
|
16
|
||||||
);
|
);
|
||||||
expect(await getSupportedNodeVersion('>=9.5.0 <=12.5.0')).toHaveProperty(
|
expect(await getSupportedNodeVersion('>=9.5.0 <=14.5.0')).toHaveProperty(
|
||||||
'major',
|
|
||||||
12
|
|
||||||
);
|
|
||||||
expect(await getSupportedNodeVersion('~12.5.0')).toHaveProperty('major', 12);
|
|
||||||
expect(await getSupportedNodeVersion('^12.5.0')).toHaveProperty('major', 12);
|
|
||||||
expect(await getSupportedNodeVersion('12.5.0 - 14.5.0')).toHaveProperty(
|
|
||||||
'major',
|
'major',
|
||||||
14
|
14
|
||||||
);
|
);
|
||||||
|
expect(await getSupportedNodeVersion('~14.5.0')).toHaveProperty('major', 14);
|
||||||
|
expect(await getSupportedNodeVersion('^14.5.0')).toHaveProperty('major', 14);
|
||||||
|
expect(await getSupportedNodeVersion('14.5.0 - 14.20.0')).toHaveProperty(
|
||||||
|
'major',
|
||||||
|
14
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only allow nodejs18.x when env var is set', async () => {
|
||||||
|
try {
|
||||||
|
expect(getLatestNodeVersion()).toHaveProperty('major', 16);
|
||||||
|
expect(getSupportedNodeVersion('18.x')).rejects.toThrow();
|
||||||
|
|
||||||
|
process.env.VERCEL_ALLOW_NODEJS18 = '1';
|
||||||
|
|
||||||
|
expect(getLatestNodeVersion()).toHaveProperty('major', 18);
|
||||||
|
expect(await getSupportedNodeVersion('18.x')).toHaveProperty('major', 18);
|
||||||
|
expect(await getSupportedNodeVersion('18')).toHaveProperty('major', 18);
|
||||||
|
expect(await getSupportedNodeVersion('18.1.0')).toHaveProperty('major', 18);
|
||||||
|
expect(await getSupportedNodeVersion('>=16')).toHaveProperty('major', 18);
|
||||||
|
} finally {
|
||||||
|
delete process.env.VERCEL_ALLOW_NODEJS18;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore node version in vercel dev getNodeVersion()', async () => {
|
it('should ignore node version in vercel dev getNodeVersion()', async () => {
|
||||||
@@ -441,6 +450,38 @@ it('should warn for deprecated versions, soon to be discontinued', async () => {
|
|||||||
global.Date.now = realDateNow;
|
global.Date.now = realDateNow;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support initialHeaders and initialStatus correctly', async () => {
|
||||||
|
const { Prerender } = require('@vercel/build-utils/dist/prerender.js');
|
||||||
|
new Prerender({
|
||||||
|
expiration: 1,
|
||||||
|
fallback: null,
|
||||||
|
group: 1,
|
||||||
|
bypassToken: 'some-long-bypass-token-to-make-it-work',
|
||||||
|
initialHeaders: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
'x-initial': 'true',
|
||||||
|
},
|
||||||
|
initialStatus: 308,
|
||||||
|
});
|
||||||
|
new Prerender({
|
||||||
|
expiration: 1,
|
||||||
|
fallback: null,
|
||||||
|
group: 1,
|
||||||
|
bypassToken: 'some-long-bypass-token-to-make-it-work',
|
||||||
|
initialStatus: 308,
|
||||||
|
});
|
||||||
|
new Prerender({
|
||||||
|
expiration: 1,
|
||||||
|
fallback: null,
|
||||||
|
group: 1,
|
||||||
|
bypassToken: 'some-long-bypass-token-to-make-it-work',
|
||||||
|
initialHeaders: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
'x-initial': 'true',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should support require by path for legacy builders', () => {
|
it('should support require by path for legacy builders', () => {
|
||||||
const index = require('@vercel/build-utils');
|
const index = require('@vercel/build-utils');
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,9 @@
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Vercel is a platform for **static sites and frontend frameworks**, built to integrate with your headless content, commerce, or database.
|
Vercel is the platform for frontend developers, providing the speed and reliability innovators need to create at the moment of inspiration.
|
||||||
|
|
||||||
We provide a **frictionless developer experience** to take care of the hard things: deploy instantly, scale automatically, and serve personalized content around the globe.
|
We enable teams to iterate quickly and develop, preview, and ship delightful user experiences. Vercel has zero-configuration support for 35+ frontend frameworks and integrates with your headless content, commerce, or database of choice.
|
||||||
|
|
||||||
We make it easy for frontend teams to **develop, preview, and ship** delightful user experiences, where performance is the default.
|
|
||||||
|
|
||||||
To install the latest version of Vercel CLI, run this command:
|
To install the latest version of Vercel CLI, run this command:
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vercel",
|
"name": "vercel",
|
||||||
"version": "28.4.5",
|
"version": "28.4.14",
|
||||||
"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",
|
||||||
@@ -41,16 +41,16 @@
|
|||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "5.5.3",
|
"@vercel/build-utils": "5.5.7",
|
||||||
"@vercel/go": "2.2.11",
|
"@vercel/go": "2.2.15",
|
||||||
"@vercel/hydrogen": "0.0.24",
|
"@vercel/hydrogen": "0.0.28",
|
||||||
"@vercel/next": "3.2.1",
|
"@vercel/next": "3.2.8",
|
||||||
"@vercel/node": "2.5.21",
|
"@vercel/node": "2.6.1",
|
||||||
"@vercel/python": "3.1.20",
|
"@vercel/python": "3.1.24",
|
||||||
"@vercel/redwood": "1.0.29",
|
"@vercel/redwood": "1.0.33",
|
||||||
"@vercel/remix": "1.0.30",
|
"@vercel/remix": "1.0.34",
|
||||||
"@vercel/ruby": "1.3.37",
|
"@vercel/ruby": "1.3.41",
|
||||||
"@vercel/static-build": "1.0.29",
|
"@vercel/static-build": "1.0.34",
|
||||||
"update-notifier": "5.1.0"
|
"update-notifier": "5.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -95,9 +95,10 @@
|
|||||||
"@types/which": "1.3.2",
|
"@types/which": "1.3.2",
|
||||||
"@types/write-json-file": "2.2.1",
|
"@types/write-json-file": "2.2.1",
|
||||||
"@types/yauzl-promise": "2.1.0",
|
"@types/yauzl-promise": "2.1.0",
|
||||||
"@vercel/client": "12.2.10",
|
"@vercel/client": "12.2.15",
|
||||||
"@vercel/frameworks": "1.1.6",
|
"@vercel/error-utils": "1.0.2",
|
||||||
"@vercel/fs-detectors": "3.4.1",
|
"@vercel/frameworks": "1.1.10",
|
||||||
|
"@vercel/fs-detectors": "3.4.7",
|
||||||
"@vercel/fun": "1.0.4",
|
"@vercel/fun": "1.0.4",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"@zeit/source-map-support": "0.6.2",
|
"@zeit/source-map-support": "0.6.2",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import chalk from 'chalk';
|
|||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import { join, normalize, relative, resolve } from 'path';
|
import { join, normalize, relative, resolve } from 'path';
|
||||||
import {
|
import {
|
||||||
|
getDiscontinuedNodeVersions,
|
||||||
normalizePath,
|
normalizePath,
|
||||||
Files,
|
Files,
|
||||||
FileFsRef,
|
FileFsRef,
|
||||||
@@ -467,6 +468,25 @@ async function doBuild(
|
|||||||
);
|
);
|
||||||
const buildResult = await builder.build(buildOptions);
|
const buildResult = await builder.build(buildOptions);
|
||||||
|
|
||||||
|
if (
|
||||||
|
buildResult &&
|
||||||
|
'output' in buildResult &&
|
||||||
|
'runtime' in buildResult.output &&
|
||||||
|
'type' in buildResult.output &&
|
||||||
|
buildResult.output.type === 'Lambda'
|
||||||
|
) {
|
||||||
|
const lambdaRuntime = buildResult.output.runtime;
|
||||||
|
if (
|
||||||
|
getDiscontinuedNodeVersions().some(o => o.runtime === lambdaRuntime)
|
||||||
|
) {
|
||||||
|
throw new NowBuildError({
|
||||||
|
code: 'NODEJS_DISCONTINUED_VERSION',
|
||||||
|
message: `The Runtime "${build.use}" is using "${lambdaRuntime}", which is discontinued. Please upgrade your Runtime to a more recent version or consult the author for more details.`,
|
||||||
|
link: 'https://github.com/vercel/vercel/blob/main/DEVELOPING_A_RUNTIME.md#lambdaruntime',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Store the build result to generate the final `config.json` after
|
// Store the build result to generate the final `config.json` after
|
||||||
// all builds have completed
|
// all builds have completed
|
||||||
buildResults.set(build, buildResult);
|
buildResults.set(build, buildResult);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ import getPrebuiltJson from '../../util/deploy/get-prebuilt-json';
|
|||||||
import { createGitMeta } from '../../util/create-git-meta';
|
import { createGitMeta } from '../../util/create-git-meta';
|
||||||
import { isValidArchive } from '../../util/deploy/validate-archive-format';
|
import { isValidArchive } from '../../util/deploy/validate-archive-format';
|
||||||
import { parseEnv } from '../../util/parse-env';
|
import { parseEnv } from '../../util/parse-env';
|
||||||
import { errorToString, isErrnoException, isError } from '../../util/is-error';
|
import { errorToString, isErrnoException, isError } from '@vercel/error-utils';
|
||||||
import { pickOverrides } from '../../util/projects/project-settings';
|
import { pickOverrides } from '../../util/projects/project-settings';
|
||||||
|
|
||||||
export default async (client: Client): Promise<number> => {
|
export default async (client: Client): Promise<number> => {
|
||||||
|
|||||||
@@ -3,16 +3,14 @@ import fs from 'fs-extra';
|
|||||||
|
|
||||||
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 { 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 { ProjectSettings } from '../../types';
|
import { ProjectSettings } from '../../types';
|
||||||
import getDecryptedEnvRecords from '../../util/get-decrypted-env-records';
|
|
||||||
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';
|
|
||||||
import { getCommandName } from '../../util/pkg-name';
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
import param from '../../util/output/param';
|
import param from '../../util/output/param';
|
||||||
import { OUTPUT_DIR } from '../../util/build/write-build-result';
|
import { OUTPUT_DIR } from '../../util/build/write-build-result';
|
||||||
|
import { pullEnvRecords } from '../../util/env/get-env-records';
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
'--listen': string;
|
'--listen': string;
|
||||||
@@ -57,8 +55,7 @@ export default async function dev(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let projectSettings: ProjectSettings | undefined;
|
let projectSettings: ProjectSettings | undefined;
|
||||||
let projectEnvs: ProjectEnvVariable[] = [];
|
let envValues: Record<string, string> = {};
|
||||||
let systemEnvValues: string[] = [];
|
|
||||||
if (link.status === 'linked') {
|
if (link.status === 'linked') {
|
||||||
const { project, org } = link;
|
const { project, org } = link;
|
||||||
client.config.currentTeam = org.type === 'team' ? org.id : undefined;
|
client.config.currentTeam = org.type === 'team' ? org.id : undefined;
|
||||||
@@ -69,19 +66,15 @@ export default async function dev(
|
|||||||
cwd = join(cwd, project.rootDirectory);
|
cwd = join(cwd, project.rootDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
[{ envs: projectEnvs }, { systemEnvValues }] = await Promise.all([
|
envValues = (
|
||||||
getDecryptedEnvRecords(output, client, project.id, 'vercel-cli:dev'),
|
await pullEnvRecords(output, client, project.id, 'vercel-cli:dev')
|
||||||
project.autoExposeSystemEnvs
|
).env;
|
||||||
? getSystemEnvValues(output, client, project.id)
|
|
||||||
: { systemEnvValues: [] },
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const devServer = new DevServer(cwd, {
|
const devServer = new DevServer(cwd, {
|
||||||
output,
|
output,
|
||||||
projectSettings,
|
projectSettings,
|
||||||
projectEnvs,
|
envValues,
|
||||||
systemEnvValues,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// If there is no Development Command, we must delete the
|
// If there is no Development Command, we must delete the
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import readConfig from '../../util/config/read-config';
|
|||||||
import readJSONFile from '../../util/read-json-file';
|
import readJSONFile from '../../util/read-json-file';
|
||||||
import { getPkgName, getCommandName } from '../../util/pkg-name';
|
import { getPkgName, getCommandName } from '../../util/pkg-name';
|
||||||
import { CantParseJSONFile } from '../../util/errors-ts';
|
import { CantParseJSONFile } from '../../util/errors-ts';
|
||||||
import { isErrnoException } from '../../util/is-error';
|
import { isErrnoException } from '@vercel/error-utils';
|
||||||
|
|
||||||
const COMMAND_CONFIG = {
|
const COMMAND_CONFIG = {
|
||||||
dev: ['dev'],
|
dev: ['dev'],
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import promptBool from '../../util/input/prompt-bool';
|
|||||||
import purchaseDomain from '../../util/domains/purchase-domain';
|
import purchaseDomain from '../../util/domains/purchase-domain';
|
||||||
import stamp from '../../util/output/stamp';
|
import stamp from '../../util/output/stamp';
|
||||||
import { getCommandName } from '../../util/pkg-name';
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
import { errorToString } from '../../util/is-error';
|
import { errorToString } from '@vercel/error-utils';
|
||||||
|
|
||||||
type Options = {};
|
type Options = {};
|
||||||
|
|
||||||
|
|||||||
29
packages/cli/src/commands/env/pull.ts
vendored
29
packages/cli/src/commands/env/pull.ts
vendored
@@ -4,21 +4,21 @@ import { closeSync, openSync, readSync } from 'fs';
|
|||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import { Project, ProjectEnvTarget } from '../../types';
|
import { Project, ProjectEnvTarget } from '../../types';
|
||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import exposeSystemEnvs from '../../util/dev/expose-system-envs';
|
|
||||||
import { emoji, prependEmoji } from '../../util/emoji';
|
import { emoji, prependEmoji } from '../../util/emoji';
|
||||||
import getSystemEnvValues from '../../util/env/get-system-env-values';
|
|
||||||
import getDecryptedEnvRecords from '../../util/get-decrypted-env-records';
|
|
||||||
import confirm from '../../util/input/confirm';
|
import confirm from '../../util/input/confirm';
|
||||||
import { Output } from '../../util/output';
|
import { Output } from '../../util/output';
|
||||||
import param from '../../util/output/param';
|
import param from '../../util/output/param';
|
||||||
import stamp from '../../util/output/stamp';
|
import stamp from '../../util/output/stamp';
|
||||||
import { getCommandName } from '../../util/pkg-name';
|
import { getCommandName } from '../../util/pkg-name';
|
||||||
import { EnvRecordsSource } from '../../util/env/get-env-records';
|
import {
|
||||||
|
EnvRecordsSource,
|
||||||
|
pullEnvRecords,
|
||||||
|
} from '../../util/env/get-env-records';
|
||||||
import {
|
import {
|
||||||
buildDeltaString,
|
buildDeltaString,
|
||||||
createEnvObject,
|
createEnvObject,
|
||||||
} from '../../util/env/diff-env-files';
|
} from '../../util/env/diff-env-files';
|
||||||
import { isErrnoException } from '../../util/is-error';
|
import { isErrnoException } from '@vercel/error-utils';
|
||||||
|
|
||||||
const CONTENTS_PREFIX = '# Created by Vercel CLI\n';
|
const CONTENTS_PREFIX = '# Created by Vercel CLI\n';
|
||||||
|
|
||||||
@@ -97,20 +97,11 @@ export default async function pull(
|
|||||||
const pullStamp = stamp();
|
const pullStamp = stamp();
|
||||||
output.spinner('Downloading');
|
output.spinner('Downloading');
|
||||||
|
|
||||||
const [{ envs: projectEnvs }, { systemEnvValues }] = await Promise.all([
|
const records = (
|
||||||
getDecryptedEnvRecords(output, client, project.id, source, environment),
|
await pullEnvRecords(output, client, project.id, source, {
|
||||||
project.autoExposeSystemEnvs
|
target: environment || ProjectEnvTarget.Development,
|
||||||
? getSystemEnvValues(output, client, project.id)
|
})
|
||||||
: { systemEnvValues: [] },
|
).env;
|
||||||
]);
|
|
||||||
|
|
||||||
const records = exposeSystemEnvs(
|
|
||||||
projectEnvs,
|
|
||||||
systemEnvValues,
|
|
||||||
project.autoExposeSystemEnvs,
|
|
||||||
undefined,
|
|
||||||
environment
|
|
||||||
);
|
|
||||||
|
|
||||||
let deltaString = '';
|
let deltaString = '';
|
||||||
let oldEnv;
|
let oldEnv;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import { ensureLink } from '../../util/ensure-link';
|
import { ensureLink } from '../../util/link/ensure-link';
|
||||||
import getArgs from '../../util/get-args';
|
import getArgs from '../../util/get-args';
|
||||||
import getInvalidSubcommand from '../../util/get-invalid-subcommand';
|
import getInvalidSubcommand from '../../util/get-invalid-subcommand';
|
||||||
import handleError from '../../util/handle-error';
|
import handleError from '../../util/handle-error';
|
||||||
@@ -80,7 +80,7 @@ export default async function main(client: Client) {
|
|||||||
argv._ = argv._.slice(1);
|
argv._ = argv._.slice(1);
|
||||||
subcommand = argv._[0];
|
subcommand = argv._[0];
|
||||||
const args = argv._.slice(1);
|
const args = argv._.slice(1);
|
||||||
const confirm = Boolean(argv['--yes']);
|
const autoConfirm = Boolean(argv['--yes']);
|
||||||
const { output } = client;
|
const { output } = client;
|
||||||
|
|
||||||
let paths = [process.cwd()];
|
let paths = [process.cwd()];
|
||||||
@@ -90,7 +90,7 @@ export default async function main(client: Client) {
|
|||||||
}
|
}
|
||||||
const { path } = pathValidation;
|
const { path } = pathValidation;
|
||||||
|
|
||||||
const linkedProject = await ensureLink('git', client, path, confirm);
|
const linkedProject = await ensureLink('git', client, path, { autoConfirm });
|
||||||
if (typeof linkedProject === 'number') {
|
if (typeof linkedProject === 'number') {
|
||||||
return linkedProject;
|
return linkedProject;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import handleError from '../../util/handle-error';
|
|||||||
import logo from '../../util/output/logo';
|
import logo from '../../util/output/logo';
|
||||||
import init from './init';
|
import init from './init';
|
||||||
import { getPkgName } from '../../util/pkg-name';
|
import { getPkgName } from '../../util/pkg-name';
|
||||||
import { isError } from '../../util/is-error';
|
import { isError } from '@vercel/error-utils';
|
||||||
|
|
||||||
const COMMAND_CONFIG = {
|
const COMMAND_CONFIG = {
|
||||||
init: ['init'],
|
init: ['init'],
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { getDeployment } from '../util/get-deployment';
|
|||||||
import { Deployment } from '@vercel/client';
|
import { Deployment } from '@vercel/client';
|
||||||
import { Build } from '../types';
|
import { Build } from '../types';
|
||||||
import title from 'title';
|
import title from 'title';
|
||||||
import { isErrnoException } from '../util/is-error';
|
import { isErrnoException } from '@vercel/error-utils';
|
||||||
import { isAPIError } from '../util/errors-ts';
|
import { isAPIError } from '../util/errors-ts';
|
||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ import Client from '../../util/client';
|
|||||||
import getArgs from '../../util/get-args';
|
import getArgs from '../../util/get-args';
|
||||||
import logo from '../../util/output/logo';
|
import logo from '../../util/output/logo';
|
||||||
import { getPkgName } from '../../util/pkg-name';
|
import { getPkgName } from '../../util/pkg-name';
|
||||||
import setupAndLink from '../../util/link/setup-and-link';
|
import { ensureLink } from '../../util/link/ensure-link';
|
||||||
import { getCommandName } from '../../util/pkg-name';
|
|
||||||
import param from '../../util/output/param';
|
|
||||||
|
|
||||||
const help = () => {
|
const help = () => {
|
||||||
console.log(`
|
console.log(`
|
||||||
@@ -70,31 +68,16 @@ export default async function main(client: Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cwd = argv._[1] || process.cwd();
|
const cwd = argv._[1] || process.cwd();
|
||||||
const link = await setupAndLink(client, cwd, {
|
|
||||||
|
const link = await ensureLink('link', client, cwd, {
|
||||||
|
autoConfirm: !!argv['--yes'],
|
||||||
forceDelete: true,
|
forceDelete: true,
|
||||||
autoConfirm: argv['--yes'],
|
|
||||||
projectName: argv['--project'],
|
projectName: argv['--project'],
|
||||||
successEmoji: 'success',
|
successEmoji: 'success',
|
||||||
setupMsg: 'Set up',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (link.status === 'error') {
|
if (typeof link === 'number') {
|
||||||
if (link.reason === 'HEADLESS') {
|
return link;
|
||||||
client.output.error(
|
|
||||||
`Command ${getCommandName(
|
|
||||||
'link'
|
|
||||||
)} requires confirmation. Use option ${param('--yes')} to confirm.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return link.exitCode;
|
|
||||||
} else if (link.status === 'not_linked') {
|
|
||||||
// User aborted project linking questions
|
|
||||||
return 0;
|
|
||||||
} else if (link.status === 'linked') {
|
|
||||||
// Successfully linked
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
const err: never = link;
|
|
||||||
throw new Error('Unknown link status: ' + err);
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ import Client from '../util/client';
|
|||||||
import { Deployment } from '@vercel/client';
|
import { Deployment } from '@vercel/client';
|
||||||
import validatePaths from '../util/validate-paths';
|
import validatePaths from '../util/validate-paths';
|
||||||
import { getLinkedProject } from '../util/projects/link';
|
import { getLinkedProject } from '../util/projects/link';
|
||||||
import { ensureLink } from '../util/ensure-link';
|
import { ensureLink } from '../util/link/ensure-link';
|
||||||
import getScope from '../util/get-scope';
|
import getScope from '../util/get-scope';
|
||||||
import { isAPIError } from '../util/errors-ts';
|
import { isAPIError } from '../util/errors-ts';
|
||||||
import { isErrnoException } from '../util/is-error';
|
import { isErrnoException } from '@vercel/error-utils';
|
||||||
|
|
||||||
const help = () => {
|
const help = () => {
|
||||||
console.log(`
|
console.log(`
|
||||||
@@ -56,7 +56,7 @@ const help = () => {
|
|||||||
${chalk.gray('–')} List all deployments for the project ${chalk.dim(
|
${chalk.gray('–')} List all deployments for the project ${chalk.dim(
|
||||||
'`my-app`'
|
'`my-app`'
|
||||||
)} in the team of the currently linked project
|
)} in the team of the currently linked project
|
||||||
|
|
||||||
${chalk.cyan(`$ ${getPkgName()} ls my-app`)}
|
${chalk.cyan(`$ ${getPkgName()} ls my-app`)}
|
||||||
|
|
||||||
${chalk.gray('–')} Filter deployments by metadata
|
${chalk.gray('–')} Filter deployments by metadata
|
||||||
@@ -112,7 +112,7 @@ export default async function main(client: Client) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const yes = !!argv['--yes'];
|
const autoConfirm = !!argv['--yes'];
|
||||||
const prod = argv['--prod'] || false;
|
const prod = argv['--prod'] || false;
|
||||||
|
|
||||||
const meta = parseMeta(argv['--meta']);
|
const meta = parseMeta(argv['--meta']);
|
||||||
@@ -145,7 +145,9 @@ export default async function main(client: Client) {
|
|||||||
// If there's no linked project and user doesn't pass `app` arg,
|
// If there's no linked project and user doesn't pass `app` arg,
|
||||||
// prompt to link their current directory.
|
// prompt to link their current directory.
|
||||||
if (status === 'not_linked' && !app) {
|
if (status === 'not_linked' && !app) {
|
||||||
const linkedProject = await ensureLink('list', client, path, yes);
|
const linkedProject = await ensureLink('list', client, path, {
|
||||||
|
autoConfirm,
|
||||||
|
});
|
||||||
if (typeof linkedProject === 'number') {
|
if (typeof linkedProject === 'number') {
|
||||||
return linkedProject;
|
return linkedProject;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import getArgs from '../util/get-args';
|
|||||||
import Client from '../util/client';
|
import Client from '../util/client';
|
||||||
import { getCommandName, getPkgName } from '../util/pkg-name';
|
import { getCommandName, getPkgName } from '../util/pkg-name';
|
||||||
import { isAPIError } from '../util/errors-ts';
|
import { isAPIError } from '../util/errors-ts';
|
||||||
import { errorToString } from '../util/is-error';
|
import { errorToString } from '@vercel/error-utils';
|
||||||
|
|
||||||
const help = () => {
|
const help = () => {
|
||||||
console.log(`
|
console.log(`
|
||||||
|
|||||||
@@ -4,24 +4,18 @@ import Client from '../util/client';
|
|||||||
import { ProjectEnvTarget } from '../types';
|
import { ProjectEnvTarget } from '../types';
|
||||||
import { emoji, prependEmoji } from '../util/emoji';
|
import { emoji, prependEmoji } from '../util/emoji';
|
||||||
import getArgs from '../util/get-args';
|
import getArgs from '../util/get-args';
|
||||||
import setupAndLink from '../util/link/setup-and-link';
|
|
||||||
import logo from '../util/output/logo';
|
import logo from '../util/output/logo';
|
||||||
import stamp from '../util/output/stamp';
|
import stamp from '../util/output/stamp';
|
||||||
import { getPkgName } from '../util/pkg-name';
|
import { getPkgName } from '../util/pkg-name';
|
||||||
import {
|
import { VERCEL_DIR, VERCEL_DIR_PROJECT } from '../util/projects/link';
|
||||||
getLinkedProject,
|
|
||||||
VERCEL_DIR,
|
|
||||||
VERCEL_DIR_PROJECT,
|
|
||||||
} from '../util/projects/link';
|
|
||||||
import { writeProjectSettings } from '../util/projects/project-settings';
|
import { writeProjectSettings } from '../util/projects/project-settings';
|
||||||
import envPull from './env/pull';
|
import envPull from './env/pull';
|
||||||
import { getCommandName } from '../util/pkg-name';
|
import type { Project } from '../types';
|
||||||
import param from '../util/output/param';
|
|
||||||
import type { Project, Org } from '../types';
|
|
||||||
import {
|
import {
|
||||||
isValidEnvTarget,
|
isValidEnvTarget,
|
||||||
getEnvTargetPlaceholder,
|
getEnvTargetPlaceholder,
|
||||||
} from '../util/env/env-target';
|
} from '../util/env/env-target';
|
||||||
|
import { ensureLink } from '../util/link/ensure-link';
|
||||||
|
|
||||||
const help = () => {
|
const help = () => {
|
||||||
return console.log(`
|
return console.log(`
|
||||||
@@ -83,43 +77,6 @@ function parseArgs(client: Client) {
|
|||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
type LinkResult = {
|
|
||||||
org: Org;
|
|
||||||
project: Project;
|
|
||||||
};
|
|
||||||
async function ensureLink(
|
|
||||||
client: Client,
|
|
||||||
cwd: string,
|
|
||||||
yes: boolean
|
|
||||||
): Promise<LinkResult | number> {
|
|
||||||
let link = await getLinkedProject(client, cwd);
|
|
||||||
if (link.status === 'not_linked') {
|
|
||||||
link = await setupAndLink(client, cwd, {
|
|
||||||
autoConfirm: yes,
|
|
||||||
successEmoji: 'link',
|
|
||||||
setupMsg: 'Set up',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (link.status === 'not_linked') {
|
|
||||||
// User aborted project linking questions
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (link.status === 'error') {
|
|
||||||
if (link.reason === 'HEADLESS') {
|
|
||||||
client.output.error(
|
|
||||||
`Command ${getCommandName(
|
|
||||||
'pull'
|
|
||||||
)} requires confirmation. Use option ${param('--yes')} to confirm.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return link.exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { org: link.org, project: link.project };
|
|
||||||
}
|
|
||||||
|
|
||||||
async function pullAllEnvFiles(
|
async function pullAllEnvFiles(
|
||||||
environment: ProjectEnvTarget,
|
environment: ProjectEnvTarget,
|
||||||
client: Client,
|
client: Client,
|
||||||
@@ -140,7 +97,9 @@ async function pullAllEnvFiles(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseEnvironment(environment = 'development'): ProjectEnvTarget {
|
export function parseEnvironment(
|
||||||
|
environment = 'development'
|
||||||
|
): ProjectEnvTarget {
|
||||||
if (!isValidEnvTarget(environment)) {
|
if (!isValidEnvTarget(environment)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`environment "${environment}" not supported; must be one of ${getEnvTargetPlaceholder()}`
|
`environment "${environment}" not supported; must be one of ${getEnvTargetPlaceholder()}`
|
||||||
@@ -156,10 +115,10 @@ export default async function main(client: Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cwd = argv._[1] || process.cwd();
|
const cwd = argv._[1] || process.cwd();
|
||||||
const yes = Boolean(argv['--yes']);
|
const autoConfirm = Boolean(argv['--yes']);
|
||||||
const environment = parseEnvironment(argv['--environment'] || undefined);
|
const environment = parseEnvironment(argv['--environment'] || undefined);
|
||||||
|
|
||||||
const link = await ensureLink(client, cwd, yes);
|
const link = await ensureLink('pull', client, cwd, { autoConfirm });
|
||||||
if (typeof link === 'number') {
|
if (typeof link === 'number') {
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { getPkgName, getCommandName } from '../../util/pkg-name';
|
|||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import createTeam from '../../util/teams/create-team';
|
import createTeam from '../../util/teams/create-team';
|
||||||
import patchTeam from '../../util/teams/patch-team';
|
import patchTeam from '../../util/teams/patch-team';
|
||||||
import { errorToString, isError } from '../../util/is-error';
|
import { errorToString, isError } from '@vercel/error-utils';
|
||||||
|
|
||||||
const validateSlugKeypress = (data: string, value: string) =>
|
const validateSlugKeypress = (data: string, value: string) =>
|
||||||
// TODO: the `value` here should contain the current value + the keypress
|
// TODO: the `value` here should contain the current value + the keypress
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { email as regexEmail } from '../../util/input/regexes';
|
|||||||
import getTeams from '../../util/teams/get-teams';
|
import getTeams from '../../util/teams/get-teams';
|
||||||
import inviteUserToTeam from '../../util/teams/invite-user-to-team';
|
import inviteUserToTeam from '../../util/teams/invite-user-to-team';
|
||||||
import { isAPIError } from '../../util/errors-ts';
|
import { isAPIError } from '../../util/errors-ts';
|
||||||
import { errorToString, isError } from '../../util/is-error';
|
import { errorToString, isError } from '@vercel/error-utils';
|
||||||
|
|
||||||
const validateEmail = (data: string) =>
|
const validateEmail = (data: string) =>
|
||||||
regexEmail.test(data.trim()) || data.length === 0;
|
regexEmail.test(data.trim()) || data.length === 0;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import { isErrnoException, isError, errorToString } from './util/is-error';
|
import { isErrnoException, isError, errorToString } from '@vercel/error-utils';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Test to see if cwd has been deleted before
|
// Test to see if cwd has been deleted before
|
||||||
@@ -610,6 +610,21 @@ const main = async () => {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isErrnoException(err) && err.code === 'ECONNRESET') {
|
||||||
|
// Error message will look like the following:
|
||||||
|
// request to https://api.vercel.com/v2/user failed, reason: socket hang up
|
||||||
|
const matches = /request to https:\/\/(.*?)\//.exec(err.message || '');
|
||||||
|
const hostname = matches?.[1];
|
||||||
|
if (hostname) {
|
||||||
|
output.error(
|
||||||
|
`Connection to ${highlight(
|
||||||
|
hostname
|
||||||
|
)} interrupted. Please verify your internet connectivity and DNS configuration.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isErrnoException(err) &&
|
isErrnoException(err) &&
|
||||||
(err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED')
|
(err.code === 'NOT_AUTHORIZED' || err.code === 'TEAM_DELETED')
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { VERCEL_DIR } from '../projects/link';
|
|||||||
import { Output } from '../output';
|
import { Output } from '../output';
|
||||||
import readJSONFile from '../read-json-file';
|
import readJSONFile from '../read-json-file';
|
||||||
import { CantParseJSONFile } from '../errors-ts';
|
import { CantParseJSONFile } from '../errors-ts';
|
||||||
import { errorToString, isErrnoException, isError } from '../is-error';
|
import { errorToString, isErrnoException, isError } from '@vercel/error-utils';
|
||||||
import cmd from '../output/cmd';
|
import cmd from '../output/cmd';
|
||||||
import code from '../output/code';
|
import code from '../output/code';
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { readFileSync } from 'fs';
|
|||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import Client from '../client';
|
import Client from '../client';
|
||||||
import { Cert } from '../../types';
|
import { Cert } from '../../types';
|
||||||
import { isErrnoException } from '../is-error';
|
import { isErrnoException } from '@vercel/error-utils';
|
||||||
import { isAPIError } from '../errors-ts';
|
import { isAPIError } from '../errors-ts';
|
||||||
|
|
||||||
export default async function createCertFromFile(
|
export default async function createCertFromFile(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import retry from 'async-retry';
|
|||||||
import { Cert } from '../../types';
|
import { Cert } from '../../types';
|
||||||
import Client from '../client';
|
import Client from '../client';
|
||||||
import { isAPIError } from '../errors-ts';
|
import { isAPIError } from '../errors-ts';
|
||||||
import { isError } from '../is-error';
|
import { isError } from '@vercel/error-utils';
|
||||||
|
|
||||||
// When it's a configuration error we should retry because of the DNS propagation
|
// When it's a configuration error we should retry because of the DNS propagation
|
||||||
// otherwise we bail to handle the error in the upper level
|
// otherwise we bail to handle the error in the upper level
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import type {
|
|||||||
} from '../types';
|
} from '../types';
|
||||||
import { sharedPromise } from './promise';
|
import { sharedPromise } from './promise';
|
||||||
import { APIError } from './errors-ts';
|
import { APIError } from './errors-ts';
|
||||||
import { normalizeError } from './is-error';
|
import { normalizeError } from '@vercel/error-utils';
|
||||||
|
|
||||||
const isSAMLError = (v: any): v is SAMLError => {
|
const isSAMLError = (v: any): v is SAMLError => {
|
||||||
return v && v.saml;
|
return v && v.saml;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import error from '../output/error';
|
|||||||
import highlight from '../output/highlight';
|
import highlight from '../output/highlight';
|
||||||
import { VercelConfig } from '../dev/types';
|
import { VercelConfig } from '../dev/types';
|
||||||
import { AuthConfig, GlobalConfig } from '../../types';
|
import { AuthConfig, GlobalConfig } from '../../types';
|
||||||
import { isErrnoException, isError } from '../is-error';
|
import { isErrnoException, isError } from '@vercel/error-utils';
|
||||||
|
|
||||||
const VERCEL_DIR = getGlobalPathConfig();
|
const VERCEL_DIR = getGlobalPathConfig();
|
||||||
const CONFIG_FILE_PATH = join(VERCEL_DIR, 'config.json');
|
const CONFIG_FILE_PATH = join(VERCEL_DIR, 'config.json');
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import git from 'git-last-commit';
|
|||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
import { GitMetadata, Project } from '../types';
|
import { GitMetadata, Project } from '../types';
|
||||||
import { Output } from './output';
|
import { Output } from './output';
|
||||||
import { errorToString } from './is-error';
|
import { errorToString } from '@vercel/error-utils';
|
||||||
|
|
||||||
export async function createGitMeta(
|
export async function createGitMeta(
|
||||||
directory: string,
|
directory: string,
|
||||||
|
|||||||
@@ -115,29 +115,39 @@ export default async function processDeployment({
|
|||||||
.reduce((a: number, b: number) => a + b, 0);
|
.reduce((a: number, b: number) => a + b, 0);
|
||||||
const totalSizeHuman = bytes.format(missingSize, { decimalPlaces: 1 });
|
const totalSizeHuman = bytes.format(missingSize, { decimalPlaces: 1 });
|
||||||
|
|
||||||
uploads.forEach((e: any) =>
|
// When stderr is not a TTY then we only want to
|
||||||
e.on('progress', () => {
|
// print upload progress in 25% increments
|
||||||
const uploadedBytes = uploads.reduce((acc: number, e: any) => {
|
let nextStep = 0;
|
||||||
return acc + e.bytesUploaded;
|
const stepSize = now._client.stderr.isTTY ? 0 : 0.25;
|
||||||
}, 0);
|
|
||||||
|
|
||||||
const bar = progress(uploadedBytes, missingSize);
|
const updateProgress = () => {
|
||||||
if (!bar || uploadedBytes === missingSize) {
|
const uploadedBytes = uploads.reduce((acc: number, e: any) => {
|
||||||
output.spinner(deployingSpinnerVal, 0);
|
return acc + e.bytesUploaded;
|
||||||
} else {
|
}, 0);
|
||||||
const uploadedHuman = bytes.format(uploadedBytes, {
|
|
||||||
decimalPlaces: 1,
|
const bar = progress(uploadedBytes, missingSize);
|
||||||
fixedDecimals: true,
|
if (!bar) {
|
||||||
});
|
output.spinner(deployingSpinnerVal, 0);
|
||||||
|
} else {
|
||||||
|
const uploadedHuman = bytes.format(uploadedBytes, {
|
||||||
|
decimalPlaces: 1,
|
||||||
|
fixedDecimals: true,
|
||||||
|
});
|
||||||
|
const percent = uploadedBytes / missingSize;
|
||||||
|
if (percent >= nextStep) {
|
||||||
output.spinner(
|
output.spinner(
|
||||||
`Uploading ${chalk.reset(
|
`Uploading ${chalk.reset(
|
||||||
`[${bar}] (${uploadedHuman}/${totalSizeHuman})`
|
`[${bar}] (${uploadedHuman}/${totalSizeHuman})`
|
||||||
)}`,
|
)}`,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
nextStep += stepSize;
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
);
|
};
|
||||||
|
|
||||||
|
uploads.forEach((e: any) => e.on('progress', updateProgress));
|
||||||
|
updateProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === 'file-uploaded') {
|
if (event.type === 'file-uploaded') {
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
import {
|
|
||||||
ProjectEnvType,
|
|
||||||
ProjectEnvVariable,
|
|
||||||
ProjectEnvTarget,
|
|
||||||
} 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,
|
|
||||||
target?: ProjectEnvTarget
|
|
||||||
) {
|
|
||||||
const envs: Env = {};
|
|
||||||
|
|
||||||
if (autoExposeSystemEnvs) {
|
|
||||||
envs['VERCEL'] = '1';
|
|
||||||
envs['VERCEL_ENV'] = target || '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;
|
|
||||||
}
|
|
||||||
@@ -16,3 +16,75 @@ export function nodeHeadersToFetchHeaders(
|
|||||||
}
|
}
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request headers that are not allowed to be overridden by a middleware.
|
||||||
|
*/
|
||||||
|
const NONOVERRIDABLE_HEADERS: Set<string> = new Set([
|
||||||
|
'host',
|
||||||
|
'connection',
|
||||||
|
'content-length',
|
||||||
|
'transfer-encoding',
|
||||||
|
'keep-alive',
|
||||||
|
'transfer-encoding',
|
||||||
|
'te',
|
||||||
|
'upgrade',
|
||||||
|
'trailer',
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds/Updates/Deletes headers in `reqHeaders` based on the response headers
|
||||||
|
* from a middleware (`respHeaders`).
|
||||||
|
*
|
||||||
|
* `x-middleware-override-headers` is a comma-separated list of *all* header
|
||||||
|
* names that should appear in new request headers. Names not in this list
|
||||||
|
* will be deleted.
|
||||||
|
*
|
||||||
|
* `x-middleware-request-*` is the new value for each header. This can't be
|
||||||
|
* omitted, even if the header is not being modified.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function applyOverriddenHeaders(
|
||||||
|
reqHeaders: { [k: string]: string | string[] | undefined },
|
||||||
|
respHeaders: Headers
|
||||||
|
) {
|
||||||
|
const overriddenHeaders = respHeaders.get('x-middleware-override-headers');
|
||||||
|
if (!overriddenHeaders) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const overriddenKeys: Set<string> = new Set();
|
||||||
|
for (const key of overriddenHeaders.split(',')) {
|
||||||
|
overriddenKeys.add(key.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
respHeaders.delete('x-middleware-override-headers');
|
||||||
|
|
||||||
|
// Delete headers.
|
||||||
|
for (const key of Object.keys(reqHeaders)) {
|
||||||
|
if (!NONOVERRIDABLE_HEADERS.has(key) && !overriddenKeys.has(key)) {
|
||||||
|
delete reqHeaders[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update or add headers.
|
||||||
|
for (const key of overriddenKeys.keys()) {
|
||||||
|
if (NONOVERRIDABLE_HEADERS.has(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueKey = 'x-middleware-request-' + key;
|
||||||
|
const newValue = respHeaders.get(valueKey);
|
||||||
|
const oldValue = reqHeaders[key];
|
||||||
|
|
||||||
|
if (oldValue !== newValue) {
|
||||||
|
if (newValue) {
|
||||||
|
reqHeaders[key] = newValue;
|
||||||
|
} else {
|
||||||
|
delete reqHeaders[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
respHeaders.delete(valueKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -85,17 +85,16 @@ import {
|
|||||||
HttpHeadersConfig,
|
HttpHeadersConfig,
|
||||||
EnvConfigs,
|
EnvConfigs,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { ProjectEnvVariable, ProjectSettings } from '../../types';
|
import { ProjectSettings } from '../../types';
|
||||||
import exposeSystemEnvs from './expose-system-envs';
|
|
||||||
import { treeKill } from '../tree-kill';
|
import { treeKill } from '../tree-kill';
|
||||||
import { nodeHeadersToFetchHeaders } from './headers';
|
import { applyOverriddenHeaders, nodeHeadersToFetchHeaders } from './headers';
|
||||||
import { formatQueryString, parseQueryString } from './parse-query-string';
|
import { formatQueryString, parseQueryString } from './parse-query-string';
|
||||||
import {
|
import {
|
||||||
errorToString,
|
errorToString,
|
||||||
isErrnoException,
|
isErrnoException,
|
||||||
isError,
|
isError,
|
||||||
isSpawnError,
|
isSpawnError,
|
||||||
} from '../is-error';
|
} from '@vercel/error-utils';
|
||||||
import isURL from './is-url';
|
import isURL from './is-url';
|
||||||
import { pickOverrides } from '../projects/project-settings';
|
import { pickOverrides } from '../projects/project-settings';
|
||||||
import { replaceLocalhost } from './parse-listen';
|
import { replaceLocalhost } from './parse-listen';
|
||||||
@@ -168,15 +167,13 @@ export default class DevServer {
|
|||||||
private blockingBuildsPromise: Promise<void> | null;
|
private blockingBuildsPromise: Promise<void> | null;
|
||||||
private startPromise: Promise<void> | null;
|
private startPromise: Promise<void> | null;
|
||||||
|
|
||||||
private systemEnvValues: string[];
|
private envValues: Record<string, string>;
|
||||||
private projectEnvs: ProjectEnvVariable[];
|
|
||||||
|
|
||||||
constructor(cwd: string, options: DevServerOptions) {
|
constructor(cwd: string, options: DevServerOptions) {
|
||||||
this.cwd = cwd;
|
this.cwd = cwd;
|
||||||
this.output = options.output;
|
this.output = options.output;
|
||||||
this.envConfigs = { buildEnv: {}, runEnv: {}, allEnv: {} };
|
this.envConfigs = { buildEnv: {}, runEnv: {}, allEnv: {} };
|
||||||
this.systemEnvValues = options.systemEnvValues || [];
|
this.envValues = options.envValues || {};
|
||||||
this.projectEnvs = options.projectEnvs || [];
|
|
||||||
this.files = {};
|
this.files = {};
|
||||||
this.originalProjectSettings = options.projectSettings;
|
this.originalProjectSettings = options.projectSettings;
|
||||||
this.projectSettings = options.projectSettings;
|
this.projectSettings = options.projectSettings;
|
||||||
@@ -684,16 +681,13 @@ export default class DevServer {
|
|||||||
|
|
||||||
// If no .env/.build.env is present, 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 = exposeSystemEnvs(
|
const envValues = { ...this.envValues };
|
||||||
this.projectEnvs || [],
|
if (this.address.host) {
|
||||||
this.systemEnvValues || [],
|
envValues['VERCEL_URL'] = this.address.host;
|
||||||
this.projectSettings?.autoExposeSystemEnvs,
|
}
|
||||||
this.address.host
|
allEnv = { ...envValues };
|
||||||
);
|
runEnv = { ...envValues };
|
||||||
|
buildEnv = { ...envValues };
|
||||||
allEnv = { ...cloudEnv };
|
|
||||||
runEnv = { ...cloudEnv };
|
|
||||||
buildEnv = { ...cloudEnv };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// legacy NOW_REGION env variable
|
// legacy NOW_REGION env variable
|
||||||
@@ -1454,7 +1448,9 @@ export default class DevServer {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (middlewareRes.status === 500) {
|
const middlewareBody = await middlewareRes.buffer();
|
||||||
|
|
||||||
|
if (middlewareRes.status === 500 && middlewareBody.byteLength === 0) {
|
||||||
await this.sendError(
|
await this.sendError(
|
||||||
req,
|
req,
|
||||||
res,
|
res,
|
||||||
@@ -1478,6 +1474,9 @@ export default class DevServer {
|
|||||||
'content-length',
|
'content-length',
|
||||||
'transfer-encoding',
|
'transfer-encoding',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
applyOverriddenHeaders(req.headers, middlewareRes.headers);
|
||||||
|
|
||||||
for (const [name, value] of middlewareRes.headers) {
|
for (const [name, value] of middlewareRes.headers) {
|
||||||
if (name === 'x-middleware-next') {
|
if (name === 'x-middleware-next') {
|
||||||
shouldContinue = value === '1';
|
shouldContinue = value === '1';
|
||||||
@@ -1496,7 +1495,6 @@ export default class DevServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldContinue) {
|
if (!shouldContinue) {
|
||||||
const middlewareBody = await middlewareRes.buffer();
|
|
||||||
this.setResponseHeaders(res, requestId);
|
this.setResponseHeaders(res, requestId);
|
||||||
if (middlewareBody.length > 0) {
|
if (middlewareBody.length > 0) {
|
||||||
res.setHeader('content-length', middlewareBody.length);
|
res.setHeader('content-length', middlewareBody.length);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
import { VercelConfig } from '@vercel/client';
|
import { VercelConfig } 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 { ProjectEnvVariable, ProjectSettings } from '../../types';
|
import { ProjectSettings } from '../../types';
|
||||||
import { BuilderWithPkg } from '../build/import-builders';
|
import { BuilderWithPkg } from '../build/import-builders';
|
||||||
|
|
||||||
export { VercelConfig };
|
export { VercelConfig };
|
||||||
@@ -24,8 +24,7 @@ export { VercelConfig };
|
|||||||
export interface DevServerOptions {
|
export interface DevServerOptions {
|
||||||
output: Output;
|
output: Output;
|
||||||
projectSettings?: ProjectSettings;
|
projectSettings?: ProjectSettings;
|
||||||
systemEnvValues?: string[];
|
envValues?: Record<string, string>;
|
||||||
projectEnvs?: ProjectEnvVariable[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EnvConfigs {
|
export interface EnvConfigs {
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
import { Org, Project } from '../types';
|
|
||||||
import Client from './client';
|
|
||||||
import setupAndLink from './link/setup-and-link';
|
|
||||||
import param from './output/param';
|
|
||||||
import { getCommandName } from './pkg-name';
|
|
||||||
import { getLinkedProject } from './projects/link';
|
|
||||||
|
|
||||||
type LinkResult = {
|
|
||||||
org: Org;
|
|
||||||
project: Project;
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function ensureLink(
|
|
||||||
commandName: string,
|
|
||||||
client: Client,
|
|
||||||
cwd: string,
|
|
||||||
yes: boolean
|
|
||||||
): Promise<LinkResult | number> {
|
|
||||||
let link = await getLinkedProject(client, cwd);
|
|
||||||
if (link.status === 'not_linked') {
|
|
||||||
link = await setupAndLink(client, cwd, {
|
|
||||||
autoConfirm: yes,
|
|
||||||
successEmoji: 'link',
|
|
||||||
setupMsg: 'Set up',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (link.status === 'not_linked') {
|
|
||||||
// User aborted project linking questions
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (link.status === 'error') {
|
|
||||||
if (link.reason === 'HEADLESS') {
|
|
||||||
client.output.error(
|
|
||||||
`Command ${getCommandName(
|
|
||||||
commandName
|
|
||||||
)} requires confirmation. Use option ${param('--yes')} to confirm.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return link.exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { org: link.org, project: link.project };
|
|
||||||
}
|
|
||||||
38
packages/cli/src/util/env/get-env-records.ts
vendored
38
packages/cli/src/util/env/get-env-records.ts
vendored
@@ -2,6 +2,7 @@ import { Output } from '../output';
|
|||||||
import Client from '../client';
|
import Client from '../client';
|
||||||
import { ProjectEnvVariable, ProjectEnvTarget } from '../../types';
|
import { ProjectEnvVariable, ProjectEnvTarget } from '../../types';
|
||||||
import { URLSearchParams } from 'url';
|
import { URLSearchParams } from 'url';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
/** The CLI command that was used that needs the environment variables. */
|
/** The CLI command that was used that needs the environment variables. */
|
||||||
export type EnvRecordsSource =
|
export type EnvRecordsSource =
|
||||||
@@ -49,3 +50,40 @@ export default async function getEnvRecords(
|
|||||||
|
|
||||||
return client.fetch<{ envs: ProjectEnvVariable[] }>(url);
|
return client.fetch<{ envs: ProjectEnvVariable[] }>(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PullEnvOptions {
|
||||||
|
target?: ProjectEnvTarget | string;
|
||||||
|
gitBranch?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function pullEnvRecords(
|
||||||
|
output: Output,
|
||||||
|
client: Client,
|
||||||
|
projectId: string,
|
||||||
|
source: EnvRecordsSource,
|
||||||
|
{ target, gitBranch }: PullEnvOptions = {}
|
||||||
|
) {
|
||||||
|
output.debug(
|
||||||
|
`Fetching Environment Variables of project ${projectId} and target ${target}`
|
||||||
|
);
|
||||||
|
const query = new URLSearchParams();
|
||||||
|
|
||||||
|
let url = `/v1/env/pull/${projectId}`;
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
url = path.join(url, target, gitBranch ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source) {
|
||||||
|
query.set('source', source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.from(query).length > 0) {
|
||||||
|
url += `?${query}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.fetch<{
|
||||||
|
env: Record<string, string>;
|
||||||
|
buildEnv: Record<string, string>;
|
||||||
|
}>(url);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
2
packages/cli/src/util/env/known-error.ts
vendored
2
packages/cli/src/util/env/known-error.ts
vendored
@@ -1,4 +1,4 @@
|
|||||||
import { isErrnoException } from '../is-error';
|
import { isErrnoException } from '@vercel/error-utils';
|
||||||
|
|
||||||
const knownErrorsCodes = new Set([
|
const knownErrorsCodes = new Set([
|
||||||
'PAYMENT_REQUIRED',
|
'PAYMENT_REQUIRED',
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { NowError } from './now-error';
|
|||||||
import code from './output/code';
|
import code from './output/code';
|
||||||
import { getCommandName } from './pkg-name';
|
import { getCommandName } from './pkg-name';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { isError } from './is-error';
|
import { isError } from '@vercel/error-utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This error is thrown when there is an API error with a payload. The error
|
* This error is thrown when there is an API error with a payload. The error
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import humanizePath from './humanize-path';
|
|||||||
import readJSONFile from './read-json-file';
|
import readJSONFile from './read-json-file';
|
||||||
import { VercelConfig } from './dev/types';
|
import { VercelConfig } from './dev/types';
|
||||||
import { Output } from './output';
|
import { Output } from './output';
|
||||||
import { isErrnoException } from './is-error';
|
import { isErrnoException } from '@vercel/error-utils';
|
||||||
|
|
||||||
let config: VercelConfig;
|
let config: VercelConfig;
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
import Client from './client';
|
|
||||||
import { Output } from './output/create-output';
|
|
||||||
import {
|
|
||||||
ProjectEnvTarget,
|
|
||||||
ProjectEnvType,
|
|
||||||
ProjectEnvVariable,
|
|
||||||
Secret,
|
|
||||||
} from '../types';
|
|
||||||
import getEnvRecords, { EnvRecordsSource } from './env/get-env-records';
|
|
||||||
import { isAPIError } from './errors-ts';
|
|
||||||
|
|
||||||
export default async function getDecryptedEnvRecords(
|
|
||||||
output: Output,
|
|
||||||
client: Client,
|
|
||||||
projectId: string,
|
|
||||||
source: EnvRecordsSource,
|
|
||||||
target?: ProjectEnvTarget
|
|
||||||
): Promise<{ envs: ProjectEnvVariable[] }> {
|
|
||||||
const { envs } = await getEnvRecords(output, client, projectId, source, {
|
|
||||||
target: target || ProjectEnvTarget.Development,
|
|
||||||
decrypt: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const envsWithDecryptedSecrets = await Promise.all(
|
|
||||||
envs.map(async ({ id, type, key, value }) => {
|
|
||||||
// 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 { id, type, key, value: '', found: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
output.debug(`Fetching decrypted secret ${secretIdOrName}`);
|
|
||||||
const secret = await client.fetch<Secret>(
|
|
||||||
`/v2/now/secrets/${secretIdOrName}?decrypt=true`
|
|
||||||
);
|
|
||||||
|
|
||||||
return { id, type, key, value: secret.value, found: true };
|
|
||||||
} catch (err: unknown) {
|
|
||||||
if (isAPIError(err) && err.status === 404) {
|
|
||||||
return { id, type, key, value: '', found: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { id, type, key, value, found: true };
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let env of envsWithDecryptedSecrets) {
|
|
||||||
if (!env.found) {
|
|
||||||
output.print('');
|
|
||||||
output.warn(
|
|
||||||
`Unable to download variable ${env.key} because associated secret was deleted`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { envs: envsWithDecryptedSecrets };
|
|
||||||
}
|
|
||||||
58
packages/cli/src/util/link/ensure-link.ts
Normal file
58
packages/cli/src/util/link/ensure-link.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { Org, Project } from '../../types';
|
||||||
|
import Client from '../client';
|
||||||
|
import setupAndLink from '../link/setup-and-link';
|
||||||
|
import param from '../output/param';
|
||||||
|
import { getCommandName } from '../pkg-name';
|
||||||
|
import { getLinkedProject } from '../projects/link';
|
||||||
|
import type { SetupAndLinkOptions } from '../link/setup-and-link';
|
||||||
|
|
||||||
|
type LinkResult = {
|
||||||
|
org: Org;
|
||||||
|
project: Project;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a project is already linked and if not, links the project and
|
||||||
|
* validates the link response.
|
||||||
|
*
|
||||||
|
* @param commandName - The name of the current command to print in the
|
||||||
|
* event of an error
|
||||||
|
* @param client - The Vercel Node.js client instance
|
||||||
|
* @param cwd - The current working directory
|
||||||
|
* @param opts.forceDelete - When `true`, deletes the project's `.vercel`
|
||||||
|
* directory
|
||||||
|
* @param opts.projectName - The project name to use when linking, otherwise
|
||||||
|
* the current directory
|
||||||
|
* @returns {Promise<LinkResult|number>} Returns a numeric exit code when aborted or
|
||||||
|
* error, otherwise an object containing the org an project
|
||||||
|
*/
|
||||||
|
export async function ensureLink(
|
||||||
|
commandName: string,
|
||||||
|
client: Client,
|
||||||
|
cwd: string,
|
||||||
|
opts: SetupAndLinkOptions
|
||||||
|
): Promise<LinkResult | number> {
|
||||||
|
let link = await getLinkedProject(client, cwd);
|
||||||
|
|
||||||
|
if (link.status === 'not_linked') {
|
||||||
|
link = await setupAndLink(client, cwd, opts);
|
||||||
|
|
||||||
|
if (link.status === 'not_linked') {
|
||||||
|
// User aborted project linking questions
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (link.status === 'error') {
|
||||||
|
if (link.reason === 'HEADLESS') {
|
||||||
|
client.output.error(
|
||||||
|
`Command ${getCommandName(
|
||||||
|
commandName
|
||||||
|
)} requires confirmation. Use option ${param('--yes')} to confirm.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return link.exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { org: link.org, project: link.project };
|
||||||
|
}
|
||||||
@@ -32,8 +32,8 @@ import { isAPIError } from '../errors-ts';
|
|||||||
export interface SetupAndLinkOptions {
|
export interface SetupAndLinkOptions {
|
||||||
forceDelete?: boolean;
|
forceDelete?: boolean;
|
||||||
autoConfirm?: boolean;
|
autoConfirm?: boolean;
|
||||||
successEmoji: EmojiLabel;
|
successEmoji?: EmojiLabel;
|
||||||
setupMsg: string;
|
setupMsg?: string;
|
||||||
projectName?: string;
|
projectName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,8 +43,8 @@ export default async function setupAndLink(
|
|||||||
{
|
{
|
||||||
forceDelete = false,
|
forceDelete = false,
|
||||||
autoConfirm = false,
|
autoConfirm = false,
|
||||||
successEmoji,
|
successEmoji = 'link',
|
||||||
setupMsg,
|
setupMsg = 'Set up',
|
||||||
projectName,
|
projectName,
|
||||||
}: SetupAndLinkOptions
|
}: SetupAndLinkOptions
|
||||||
): Promise<ProjectLinkResult> {
|
): Promise<ProjectLinkResult> {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import executeLogin from './login';
|
|||||||
import Client from '../client';
|
import Client from '../client';
|
||||||
import { LoginResult } from './types';
|
import { LoginResult } from './types';
|
||||||
import { isAPIError } from '../errors-ts';
|
import { isAPIError } from '../errors-ts';
|
||||||
import { errorToString } from '../is-error';
|
import { errorToString } from '@vercel/error-utils';
|
||||||
|
|
||||||
export default async function doEmailLogin(
|
export default async function doEmailLogin(
|
||||||
client: Client,
|
client: Client,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Client from '../client';
|
import Client from '../client';
|
||||||
import { InvalidEmail, AccountNotFound, isAPIError } from '../errors-ts';
|
import { InvalidEmail, AccountNotFound, isAPIError } from '../errors-ts';
|
||||||
import { errorToString } from '../is-error';
|
import { errorToString } from '@vercel/error-utils';
|
||||||
import { LoginData } from './types';
|
import { LoginData } from './types';
|
||||||
|
|
||||||
export default async function login(
|
export default async function login(
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import chalk from 'chalk';
|
|||||||
import renderLink from './link';
|
import renderLink from './link';
|
||||||
import wait, { StopSpinner } from './wait';
|
import wait, { StopSpinner } from './wait';
|
||||||
import type { WritableTTY } from '../../types';
|
import type { WritableTTY } from '../../types';
|
||||||
import { errorToString } from '../is-error';
|
import { errorToString } from '@vercel/error-utils';
|
||||||
|
|
||||||
|
const IS_TEST = process.env.NODE_ENV === 'test';
|
||||||
|
|
||||||
export interface OutputOptions {
|
export interface OutputOptions {
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
@@ -108,12 +110,15 @@ export class Output {
|
|||||||
};
|
};
|
||||||
|
|
||||||
spinner = (message: string, delay: number = 300): void => {
|
spinner = (message: string, delay: number = 300): void => {
|
||||||
this.spinnerMessage = message;
|
|
||||||
if (this.debugEnabled) {
|
if (this.debugEnabled) {
|
||||||
this.debug(`Spinner invoked (${message}) with a ${delay}ms delay`);
|
this.debug(`Spinner invoked (${message}) with a ${delay}ms delay`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.stream.isTTY) {
|
if (IS_TEST || !this.stream.isTTY) {
|
||||||
|
this.print(`${message}\n`);
|
||||||
|
} else {
|
||||||
|
this.spinnerMessage = message;
|
||||||
|
|
||||||
if (this._spinner) {
|
if (this._spinner) {
|
||||||
this._spinner.text = message;
|
this._spinner.text = message;
|
||||||
} else {
|
} else {
|
||||||
@@ -125,8 +130,6 @@ export class Output {
|
|||||||
delay
|
delay
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.print(`${message}\n`);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { prependEmoji, emoji, EmojiLabel } from '../emoji';
|
|||||||
import { isDirectory } from '../config/global-path';
|
import { isDirectory } from '../config/global-path';
|
||||||
import { NowBuildError, getPlatformEnv } from '@vercel/build-utils';
|
import { NowBuildError, getPlatformEnv } from '@vercel/build-utils';
|
||||||
import outputCode from '../output/code';
|
import outputCode from '../output/code';
|
||||||
import { isErrnoException, isError } from '../is-error';
|
import { isErrnoException, isError } from '@vercel/error-utils';
|
||||||
|
|
||||||
const readFile = promisify(fs.readFile);
|
const readFile = promisify(fs.readFile);
|
||||||
const writeFile = promisify(fs.writeFile);
|
const writeFile = promisify(fs.writeFile);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Client from './client';
|
import Client from './client';
|
||||||
import getScope from './get-scope';
|
import getScope from './get-scope';
|
||||||
import getArgs from './get-args';
|
import getArgs from './get-args';
|
||||||
import { isError } from './is-error';
|
import { isError } from '@vercel/error-utils';
|
||||||
import type { Team, User } from '../types';
|
import type { Team, User } from '../types';
|
||||||
|
|
||||||
export default async function reportError(
|
export default async function reportError(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "latest",
|
"next": "latest",
|
||||||
"react": "^17.0.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^17.0.0"
|
"react-dom": "^18.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export default () => new Response(null, { status: 500 });
|
export default () => new Response('Example Error', { status: 500 });
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export default (req, res) => {
|
||||||
|
res.json(req.headers);
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
export default () => {
|
||||||
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
'x-middleware-next': '1',
|
||||||
|
'x-middleware-override-headers':
|
||||||
|
'x-from-client-a,x-from-client-b,x-from-middleware-a,x-from-middleware-b,transfer-encoding',
|
||||||
|
// Headers to be preserved.
|
||||||
|
'x-middleware-request-x-from-client-a': 'hello from client',
|
||||||
|
// Headers to be modified by the middleware.
|
||||||
|
'x-middleware-request-x-from-client-b': 'hello from middleware',
|
||||||
|
// Headers to be added by the middleware.
|
||||||
|
'x-middleware-request-x-from-middleware-a': 'hello a!',
|
||||||
|
'x-middleware-request-x-from-middleware-b': 'hello b!',
|
||||||
|
// Headers not allowed by the dev server: will be ignored.
|
||||||
|
'transfer-encoding': 'gzip, chunked',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@ import ms from 'ms';
|
|||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import { isIP } from 'net';
|
import { isIP } from 'net';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import { Response } from 'node-fetch';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
fetch,
|
fetch,
|
||||||
@@ -550,7 +551,7 @@ test(
|
|||||||
test(
|
test(
|
||||||
'[vercel dev] Middleware with an explicit 500 response',
|
'[vercel dev] Middleware with an explicit 500 response',
|
||||||
testFixtureStdio('middleware-500-response', async (testPath: any) => {
|
testFixtureStdio('middleware-500-response', async (testPath: any) => {
|
||||||
await testPath(500, '/', /EDGE_FUNCTION_INVOCATION_FAILED/);
|
await testPath(500, '/', 'Example Error');
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -613,3 +614,72 @@ test(
|
|||||||
{ skipDeploy: true }
|
{ skipDeploy: true }
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'[vercel dev] Middleware can override request headers',
|
||||||
|
testFixtureStdio(
|
||||||
|
'middleware-request-headers-override',
|
||||||
|
async (testPath: any) => {
|
||||||
|
await testPath(
|
||||||
|
200,
|
||||||
|
'/api/dump-headers',
|
||||||
|
(actual: string, res: Response) => {
|
||||||
|
// Headers sent to the API route.
|
||||||
|
const headers = JSON.parse(actual);
|
||||||
|
|
||||||
|
// Preserved headers.
|
||||||
|
expect(headers).toHaveProperty(
|
||||||
|
'x-from-client-a',
|
||||||
|
'hello from client'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Headers added/modified by the middleware.
|
||||||
|
expect(headers).toHaveProperty(
|
||||||
|
'x-from-client-b',
|
||||||
|
'hello from middleware'
|
||||||
|
);
|
||||||
|
expect(headers).toHaveProperty('x-from-middleware-a', 'hello a!');
|
||||||
|
expect(headers).toHaveProperty('x-from-middleware-b', 'hello b!');
|
||||||
|
|
||||||
|
// Headers deleted by the middleware.
|
||||||
|
expect(headers).not.toHaveProperty('x-from-client-c');
|
||||||
|
|
||||||
|
// Internal headers should not be visible from API routes.
|
||||||
|
expect(headers).not.toHaveProperty('x-middleware-override-headers');
|
||||||
|
expect(headers).not.toHaveProperty(
|
||||||
|
'x-middleware-request-from-middleware-a'
|
||||||
|
);
|
||||||
|
expect(headers).not.toHaveProperty(
|
||||||
|
'x-middleware-request-from-middleware-b'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Request headers should not be visible from clients.
|
||||||
|
const respHeaders = Object.fromEntries(res.headers.entries());
|
||||||
|
expect(respHeaders).not.toHaveProperty(
|
||||||
|
'x-middleware-override-headers'
|
||||||
|
);
|
||||||
|
expect(respHeaders).not.toHaveProperty(
|
||||||
|
'x-middleware-request-from-middleware-a'
|
||||||
|
);
|
||||||
|
expect(respHeaders).not.toHaveProperty(
|
||||||
|
'x-middleware-request-from-middleware-b'
|
||||||
|
);
|
||||||
|
expect(respHeaders).not.toHaveProperty('from-middleware-a');
|
||||||
|
expect(respHeaders).not.toHaveProperty('from-middleware-b');
|
||||||
|
expect(respHeaders).not.toHaveProperty('x-from-client-a');
|
||||||
|
expect(respHeaders).not.toHaveProperty('x-from-client-b');
|
||||||
|
expect(respHeaders).not.toHaveProperty('x-from-client-c');
|
||||||
|
},
|
||||||
|
/*expectedHeaders=*/ {},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'x-from-client-a': 'hello from client',
|
||||||
|
'x-from-client-b': 'hello from client',
|
||||||
|
'x-from-client-c': 'hello from client',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ skipDeploy: true }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|||||||
2
packages/cli/test/fixtures/unit/commands/build/discontinued-nodejs12.x/.gitignore
vendored
Normal file
2
packages/cli/test/fixtures/unit/commands/build/discontinued-nodejs12.x/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.vercel/builders
|
||||||
|
.vercel/output
|
||||||
7
packages/cli/test/fixtures/unit/commands/build/discontinued-nodejs12.x/.vercel/project.json
vendored
Normal file
7
packages/cli/test/fixtures/unit/commands/build/discontinued-nodejs12.x/.vercel/project.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"orgId": ".",
|
||||||
|
"projectId": ".",
|
||||||
|
"settings": {
|
||||||
|
"framework": null
|
||||||
|
}
|
||||||
|
}
|
||||||
1
packages/cli/test/fixtures/unit/commands/build/discontinued-nodejs12.x/api/index.php
vendored
Normal file
1
packages/cli/test/fixtures/unit/commands/build/discontinued-nodejs12.x/api/index.php
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?php echo 'This version of vercel-php uses the nodejs12.x Lambda Runtime'; ?>
|
||||||
8
packages/cli/test/fixtures/unit/commands/build/discontinued-nodejs12.x/vercel.json
vendored
Normal file
8
packages/cli/test/fixtures/unit/commands/build/discontinued-nodejs12.x/vercel.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://openapi.vercel.sh/vercel.json",
|
||||||
|
"functions": {
|
||||||
|
"api/index.php": {
|
||||||
|
"runtime": "vercel-php@0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -326,7 +326,7 @@ module.exports = async function prepare(session, binaryPath, tmpFixturesDir) {
|
|||||||
'vercel.json': JSON.stringify({
|
'vercel.json': JSON.stringify({
|
||||||
functions: {
|
functions: {
|
||||||
'api/**/*.php': {
|
'api/**/*.php': {
|
||||||
runtime: 'vercel-php@0.1.0',
|
runtime: 'vercel-php@0.5.2',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,37 +1,44 @@
|
|||||||
import { client } from './client';
|
import { client } from './client';
|
||||||
import { Project } from '../../src/types';
|
import {
|
||||||
|
Project,
|
||||||
|
ProjectEnvTarget,
|
||||||
|
ProjectEnvType,
|
||||||
|
ProjectEnvVariable,
|
||||||
|
} from '../../src/types';
|
||||||
import { formatProvider } from '../../src/util/git/connect-git-provider';
|
import { formatProvider } from '../../src/util/git/connect-git-provider';
|
||||||
|
import { parseEnvironment } from '../../src/commands/pull';
|
||||||
|
import { Env } from '@vercel/build-utils/dist';
|
||||||
|
|
||||||
const envs = [
|
const envs: ProjectEnvVariable[] = [
|
||||||
{
|
{
|
||||||
type: 'encrypted',
|
type: ProjectEnvType.Encrypted,
|
||||||
id: '781dt89g8r2h789g',
|
id: '781dt89g8r2h789g',
|
||||||
key: 'REDIS_CONNECTION_STRING',
|
key: 'REDIS_CONNECTION_STRING',
|
||||||
value: 'redis://abc123@redis.example.com:6379',
|
value: 'redis://abc123@redis.example.com:6379',
|
||||||
target: ['production', 'preview'],
|
target: [ProjectEnvTarget.Production, ProjectEnvTarget.Preview],
|
||||||
gitBranch: null,
|
gitBranch: undefined,
|
||||||
configurationId: null,
|
configurationId: null,
|
||||||
updatedAt: 1557241361455,
|
updatedAt: 1557241361455,
|
||||||
createdAt: 1557241361455,
|
createdAt: 1557241361455,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'encrypted',
|
type: ProjectEnvType.Encrypted,
|
||||||
id: 'r124t6frtu25df16',
|
id: 'r124t6frtu25df16',
|
||||||
key: 'SQL_CONNECTION_STRING',
|
key: 'SQL_CONNECTION_STRING',
|
||||||
value: 'Server=sql.example.com;Database=app;Uid=root;Pwd=P455W0RD;',
|
value: 'Server=sql.example.com;Database=app;Uid=root;Pwd=P455W0RD;',
|
||||||
target: ['production'],
|
target: [ProjectEnvTarget.Production],
|
||||||
gitBranch: null,
|
gitBranch: undefined,
|
||||||
configurationId: null,
|
configurationId: null,
|
||||||
updatedAt: 1557241361445,
|
updatedAt: 1557241361445,
|
||||||
createdAt: 1557241361445,
|
createdAt: 1557241361445,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'encrypted',
|
type: ProjectEnvType.Encrypted,
|
||||||
id: 'a235l6frtu25df32',
|
id: 'a235l6frtu25df32',
|
||||||
key: 'SPECIAL_FLAG',
|
key: 'SPECIAL_FLAG',
|
||||||
value: '1',
|
value: '1',
|
||||||
target: ['development'],
|
target: [ProjectEnvTarget.Development],
|
||||||
gitBranch: null,
|
gitBranch: undefined,
|
||||||
configurationId: null,
|
configurationId: null,
|
||||||
updatedAt: 1557241361445,
|
updatedAt: 1557241361445,
|
||||||
createdAt: 1557241361445,
|
createdAt: 1557241361445,
|
||||||
@@ -206,6 +213,43 @@ export function useProject(project: Partial<Project> = defaultProject) {
|
|||||||
Object.assign(project, req.body);
|
Object.assign(project, req.body);
|
||||||
res.json(project);
|
res.json(project);
|
||||||
});
|
});
|
||||||
|
client.scenario.get(
|
||||||
|
`/v1/env/pull/${project.id}/:target?/:gitBranch?`,
|
||||||
|
(req, res) => {
|
||||||
|
const target: ProjectEnvTarget | undefined =
|
||||||
|
typeof req.params.target === 'string'
|
||||||
|
? parseEnvironment(req.params.target)
|
||||||
|
: undefined;
|
||||||
|
let projectEnvs = envs;
|
||||||
|
if (target) {
|
||||||
|
projectEnvs = projectEnvs.filter(env => {
|
||||||
|
if (typeof env.target === 'string') {
|
||||||
|
return env.target === target;
|
||||||
|
}
|
||||||
|
if (Array.isArray(env.target)) {
|
||||||
|
return env.target.includes(target);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const allEnvs = Object.entries(
|
||||||
|
exposeSystemEnvs(
|
||||||
|
projectEnvs,
|
||||||
|
systemEnvs.map(env => env.key),
|
||||||
|
project.autoExposeSystemEnvs,
|
||||||
|
undefined,
|
||||||
|
target
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const env: Record<string, string> = {};
|
||||||
|
|
||||||
|
allEnvs.forEach(([k, v]) => {
|
||||||
|
env[k] = v ?? '';
|
||||||
|
});
|
||||||
|
res.json({ env: env });
|
||||||
|
}
|
||||||
|
);
|
||||||
client.scenario.get(
|
client.scenario.get(
|
||||||
`/v6/projects/${project.id}/system-env-values`,
|
`/v6/projects/${project.id}/system-env-values`,
|
||||||
(_req, res) => {
|
(_req, res) => {
|
||||||
@@ -222,15 +266,26 @@ export function useProject(project: Partial<Project> = defaultProject) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
client.scenario.get(`/v8/projects/${project.id}/env`, (_req, res) => {
|
client.scenario.get(`/v8/projects/${project.id}/env`, (req, res) => {
|
||||||
const target = _req.query.target;
|
const target: ProjectEnvTarget | undefined =
|
||||||
if (typeof target === 'string') {
|
typeof req.query.target === 'string'
|
||||||
const targetEnvs = envs.filter(env => env.target.includes(target));
|
? parseEnvironment(req.query.target)
|
||||||
res.json({ envs: targetEnvs });
|
: undefined;
|
||||||
return;
|
|
||||||
|
let targetEnvs = envs;
|
||||||
|
if (target) {
|
||||||
|
targetEnvs = targetEnvs.filter(env => {
|
||||||
|
if (typeof env.target === 'string') {
|
||||||
|
return env.target === target;
|
||||||
|
}
|
||||||
|
if (Array.isArray(env.target)) {
|
||||||
|
return env.target.includes(target);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({ envs });
|
res.json({ envs: targetEnvs });
|
||||||
});
|
});
|
||||||
client.scenario.post(`/v8/projects/${project.id}/env`, (req, res) => {
|
client.scenario.post(`/v8/projects/${project.id}/env`, (req, res) => {
|
||||||
const envObj = req.body;
|
const envObj = req.body;
|
||||||
@@ -310,3 +365,43 @@ export function useProject(project: Partial<Project> = defaultProject) {
|
|||||||
|
|
||||||
return { project, envs };
|
return { project, envs };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSystemEnvValue(
|
||||||
|
systemEnvRef: string,
|
||||||
|
{ vercelUrl }: { vercelUrl?: string }
|
||||||
|
) {
|
||||||
|
if (systemEnvRef === 'VERCEL_URL') {
|
||||||
|
return vercelUrl || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function exposeSystemEnvs(
|
||||||
|
projectEnvs: ProjectEnvVariable[],
|
||||||
|
systemEnvValues: string[],
|
||||||
|
autoExposeSystemEnvs: boolean | undefined,
|
||||||
|
vercelUrl?: string,
|
||||||
|
target?: ProjectEnvTarget
|
||||||
|
) {
|
||||||
|
const envs: Env = {};
|
||||||
|
|
||||||
|
if (autoExposeSystemEnvs) {
|
||||||
|
envs['VERCEL'] = '1';
|
||||||
|
envs['VERCEL_ENV'] = target || '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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -776,6 +776,55 @@ describe('build', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should error when "functions" has runtime that emits discontinued "nodejs12.x"', async () => {
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
console.log('Skipping test on Windows');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cwd = fixture('discontinued-nodejs12.x');
|
||||||
|
const output = join(cwd, '.vercel/output');
|
||||||
|
try {
|
||||||
|
process.chdir(cwd);
|
||||||
|
const exitCode = await build(client);
|
||||||
|
expect(exitCode).toEqual(1);
|
||||||
|
|
||||||
|
// Error gets printed to the terminal
|
||||||
|
await expect(client.stderr).toOutput(
|
||||||
|
'The Runtime "vercel-php@0.1.0" is using "nodejs12.x", which is discontinued. Please upgrade your Runtime to a more recent version or consult the author for more details.'
|
||||||
|
);
|
||||||
|
|
||||||
|
// `builds.json` contains "error" build
|
||||||
|
const builds = await fs.readJSON(join(output, 'builds.json'));
|
||||||
|
const errorBuilds = builds.builds.filter((b: any) => 'error' in b);
|
||||||
|
expect(errorBuilds).toHaveLength(1);
|
||||||
|
expect(errorBuilds[0].error).toEqual({
|
||||||
|
name: 'Error',
|
||||||
|
message: expect.stringContaining('Please upgrade your Runtime'),
|
||||||
|
stack: expect.stringContaining('Please upgrade your Runtime'),
|
||||||
|
hideStackTrace: true,
|
||||||
|
code: 'NODEJS_DISCONTINUED_VERSION',
|
||||||
|
link: 'https://github.com/vercel/vercel/blob/main/DEVELOPING_A_RUNTIME.md#lambdaruntime',
|
||||||
|
});
|
||||||
|
|
||||||
|
// top level "error" also contains the same error
|
||||||
|
expect(builds.error).toEqual({
|
||||||
|
name: 'Error',
|
||||||
|
message: expect.stringContaining('Please upgrade your Runtime'),
|
||||||
|
stack: expect.stringContaining('Please upgrade your Runtime'),
|
||||||
|
hideStackTrace: true,
|
||||||
|
code: 'NODEJS_DISCONTINUED_VERSION',
|
||||||
|
link: 'https://github.com/vercel/vercel/blob/main/DEVELOPING_A_RUNTIME.md#lambdaruntime',
|
||||||
|
});
|
||||||
|
|
||||||
|
// `config.json` contains `version`
|
||||||
|
const configJson = await fs.readJSON(join(output, 'config.json'));
|
||||||
|
expect(configJson.version).toBe(3);
|
||||||
|
} finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
delete process.env.__VERCEL_BUILD_RUNNING;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('should allow for missing "build" script', async () => {
|
it('should allow for missing "build" script', async () => {
|
||||||
const cwd = fixture('static-with-pkg');
|
const cwd = fixture('static-with-pkg');
|
||||||
const output = join(cwd, '.vercel/output');
|
const output = join(cwd, '.vercel/output');
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import bytes from 'bytes';
|
||||||
|
import fs from 'fs-extra';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import { randomBytes } from 'crypto';
|
||||||
import { fileNameSymbol } from '@vercel/client';
|
import { fileNameSymbol } from '@vercel/client';
|
||||||
import { client } from '../../mocks/client';
|
import { client } from '../../mocks/client';
|
||||||
import deploy from '../../../src/commands/deploy';
|
import deploy from '../../../src/commands/deploy';
|
||||||
@@ -199,4 +202,119 @@ describe('deploy', () => {
|
|||||||
process.chdir(originalCwd);
|
process.chdir(originalCwd);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should upload missing files', async () => {
|
||||||
|
const cwd = setupFixture('commands/deploy/archive');
|
||||||
|
const originalCwd = process.cwd();
|
||||||
|
|
||||||
|
// Add random 1mb file
|
||||||
|
await fs.writeFile(join(cwd, 'data'), randomBytes(bytes('1mb')));
|
||||||
|
|
||||||
|
try {
|
||||||
|
process.chdir(cwd);
|
||||||
|
|
||||||
|
const user = useUser();
|
||||||
|
useTeams('team_dummy');
|
||||||
|
useProject({
|
||||||
|
...defaultProject,
|
||||||
|
name: 'archive',
|
||||||
|
id: 'archive',
|
||||||
|
});
|
||||||
|
|
||||||
|
let body: any;
|
||||||
|
let fileUploaded = false;
|
||||||
|
client.scenario.post(`/v13/deployments`, (req, res) => {
|
||||||
|
if (fileUploaded) {
|
||||||
|
body = req.body;
|
||||||
|
res.json({
|
||||||
|
creator: {
|
||||||
|
uid: user.id,
|
||||||
|
username: user.username,
|
||||||
|
},
|
||||||
|
id: 'dpl_archive_test',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const sha = req.body.files[0].sha;
|
||||||
|
res.status(400).json({
|
||||||
|
error: {
|
||||||
|
code: 'missing_files',
|
||||||
|
message: 'Missing files',
|
||||||
|
missing: [sha],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
client.scenario.post('/v2/files', (req, res) => {
|
||||||
|
// Wait for file to be finished uploading
|
||||||
|
req.on('data', () => {
|
||||||
|
// Noop
|
||||||
|
});
|
||||||
|
req.on('end', () => {
|
||||||
|
fileUploaded = true;
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
client.scenario.get(`/v13/deployments/dpl_archive_test`, (req, res) => {
|
||||||
|
res.json({
|
||||||
|
creator: {
|
||||||
|
uid: user.id,
|
||||||
|
username: user.username,
|
||||||
|
},
|
||||||
|
id: 'dpl_archive_test',
|
||||||
|
readyState: 'READY',
|
||||||
|
aliasAssigned: true,
|
||||||
|
alias: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
client.scenario.get(
|
||||||
|
`/v10/now/deployments/dpl_archive_test`,
|
||||||
|
(req, res) => {
|
||||||
|
res.json({
|
||||||
|
creator: {
|
||||||
|
uid: user.id,
|
||||||
|
username: user.username,
|
||||||
|
},
|
||||||
|
id: 'dpl_archive_test',
|
||||||
|
readyState: 'READY',
|
||||||
|
aliasAssigned: true,
|
||||||
|
alias: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// When stderr is not a TTY we expect 5 progress lines to be printed
|
||||||
|
client.stderr.isTTY = false;
|
||||||
|
|
||||||
|
client.setArgv('deploy', '--archive=tgz');
|
||||||
|
const uploadingLines: string[] = [];
|
||||||
|
client.stderr.on('data', data => {
|
||||||
|
if (data.startsWith('Uploading [')) {
|
||||||
|
uploadingLines.push(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
client.stderr.resume();
|
||||||
|
const exitCode = await deploy(client);
|
||||||
|
expect(exitCode).toEqual(0);
|
||||||
|
expect(body?.files?.length).toEqual(1);
|
||||||
|
expect(body?.files?.[0].file).toEqual('.vercel/source.tgz');
|
||||||
|
expect(uploadingLines.length).toEqual(5);
|
||||||
|
expect(
|
||||||
|
uploadingLines[0].startsWith('Uploading [--------------------]')
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
uploadingLines[1].startsWith('Uploading [=====---------------]')
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
uploadingLines[2].startsWith('Uploading [==========----------]')
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
uploadingLines[3].startsWith('Uploading [===============-----]')
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
uploadingLines[4].startsWith('Uploading [====================]')
|
||||||
|
).toEqual(true);
|
||||||
|
} finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ describe('list', () => {
|
|||||||
|
|
||||||
await list(client);
|
await list(client);
|
||||||
|
|
||||||
const output = await readOutputStream(client, 4);
|
const output = await readOutputStream(client, 6);
|
||||||
|
|
||||||
const { org } = pluckIdentifiersFromDeploymentList(output.split('\n')[0]);
|
const { org } = pluckIdentifiersFromDeploymentList(output.split('\n')[2]);
|
||||||
const header: string[] = parseSpacedTableRow(output.split('\n')[3]);
|
const header: string[] = parseSpacedTableRow(output.split('\n')[5]);
|
||||||
const data: string[] = parseSpacedTableRow(output.split('\n')[4]);
|
const data: string[] = parseSpacedTableRow(output.split('\n')[6]);
|
||||||
data.shift();
|
data.shift();
|
||||||
|
|
||||||
expect(org).toEqual(team[0].slug);
|
expect(org).toEqual(team[0].slug);
|
||||||
@@ -81,11 +81,11 @@ describe('list', () => {
|
|||||||
client.setArgv('-S', user.username);
|
client.setArgv('-S', user.username);
|
||||||
await list(client);
|
await list(client);
|
||||||
|
|
||||||
const output = await readOutputStream(client, 4);
|
const output = await readOutputStream(client, 6);
|
||||||
|
|
||||||
const { org } = pluckIdentifiersFromDeploymentList(output.split('\n')[0]);
|
const { org } = pluckIdentifiersFromDeploymentList(output.split('\n')[2]);
|
||||||
const header: string[] = parseSpacedTableRow(output.split('\n')[3]);
|
const header: string[] = parseSpacedTableRow(output.split('\n')[5]);
|
||||||
const data: string[] = parseSpacedTableRow(output.split('\n')[4]);
|
const data: string[] = parseSpacedTableRow(output.split('\n')[6]);
|
||||||
data.shift();
|
data.shift();
|
||||||
|
|
||||||
expect(org).toEqual(user.username);
|
expect(org).toEqual(user.username);
|
||||||
@@ -116,11 +116,11 @@ describe('list', () => {
|
|||||||
client.setArgv(deployment.name);
|
client.setArgv(deployment.name);
|
||||||
await list(client);
|
await list(client);
|
||||||
|
|
||||||
const output = await readOutputStream(client, 4);
|
const output = await readOutputStream(client, 6);
|
||||||
|
|
||||||
const { org } = pluckIdentifiersFromDeploymentList(output.split('\n')[0]);
|
const { org } = pluckIdentifiersFromDeploymentList(output.split('\n')[2]);
|
||||||
const header: string[] = parseSpacedTableRow(output.split('\n')[3]);
|
const header: string[] = parseSpacedTableRow(output.split('\n')[5]);
|
||||||
const data: string[] = parseSpacedTableRow(output.split('\n')[4]);
|
const data: string[] = parseSpacedTableRow(output.split('\n')[6]);
|
||||||
data.shift();
|
data.shift();
|
||||||
|
|
||||||
expect(org).toEqual(teamSlug || team[0].slug);
|
expect(org).toEqual(teamSlug || team[0].slug);
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ describe('project', () => {
|
|||||||
client.setArgv('project', 'ls');
|
client.setArgv('project', 'ls');
|
||||||
await projects(client);
|
await projects(client);
|
||||||
|
|
||||||
const output = await readOutputStream(client, 2);
|
const output = await readOutputStream(client, 3);
|
||||||
const { org } = pluckIdentifiersFromDeploymentList(output.split('\n')[0]);
|
const { org } = pluckIdentifiersFromDeploymentList(output.split('\n')[1]);
|
||||||
const header: string[] = parseSpacedTableRow(output.split('\n')[2]);
|
const header: string[] = parseSpacedTableRow(output.split('\n')[3]);
|
||||||
const data: string[] = parseSpacedTableRow(output.split('\n')[3]);
|
const data: string[] = parseSpacedTableRow(output.split('\n')[4]);
|
||||||
data.pop();
|
data.pop();
|
||||||
|
|
||||||
expect(org).toEqual(user.username);
|
expect(org).toEqual(user.username);
|
||||||
@@ -47,10 +47,10 @@ describe('project', () => {
|
|||||||
client.setArgv('project', 'ls');
|
client.setArgv('project', 'ls');
|
||||||
await projects(client);
|
await projects(client);
|
||||||
|
|
||||||
const output = await readOutputStream(client, 2);
|
const output = await readOutputStream(client, 3);
|
||||||
const { org } = pluckIdentifiersFromDeploymentList(output.split('\n')[0]);
|
const { org } = pluckIdentifiersFromDeploymentList(output.split('\n')[1]);
|
||||||
const header: string[] = parseSpacedTableRow(output.split('\n')[2]);
|
const header: string[] = parseSpacedTableRow(output.split('\n')[3]);
|
||||||
const data: string[] = parseSpacedTableRow(output.split('\n')[3]);
|
const data: string[] = parseSpacedTableRow(output.split('\n')[4]);
|
||||||
data.pop();
|
data.pop();
|
||||||
|
|
||||||
expect(org).toEqual(user.username);
|
expect(org).toEqual(user.username);
|
||||||
|
|||||||
77
packages/cli/test/unit/util/dev/headers.test.ts
Normal file
77
packages/cli/test/unit/util/dev/headers.test.ts
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { Headers } from 'node-fetch';
|
||||||
|
import { applyOverriddenHeaders } from '../../../../src/util/dev/headers';
|
||||||
|
|
||||||
|
describe('applyOverriddenHeaders', () => {
|
||||||
|
it('do nothing if x-middleware-override-headers is not set', async () => {
|
||||||
|
const reqHeaders = { a: '1' };
|
||||||
|
const respHeaders = new Headers();
|
||||||
|
|
||||||
|
applyOverriddenHeaders(reqHeaders, respHeaders);
|
||||||
|
expect(reqHeaders).toStrictEqual({ a: '1' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds a new header', async () => {
|
||||||
|
const reqHeaders = { a: '1' };
|
||||||
|
const respHeaders = new Headers({
|
||||||
|
// Define a new header 'b' and keep the existing header 'a'
|
||||||
|
'x-middleware-override-headers': 'a,b',
|
||||||
|
'x-middleware-request-a': '1',
|
||||||
|
'x-middleware-request-b': '2',
|
||||||
|
});
|
||||||
|
|
||||||
|
applyOverriddenHeaders(reqHeaders, respHeaders);
|
||||||
|
expect(reqHeaders).toStrictEqual({ a: '1', b: '2' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('delete the header if x-middleware-request-* is undefined', async () => {
|
||||||
|
const reqHeaders = { a: '1', b: '2' };
|
||||||
|
const respHeaders = new Headers({
|
||||||
|
// Deletes a new header 'c' and keep the existing headers `a` and `b`
|
||||||
|
'x-middleware-override-headers': 'a,b,c',
|
||||||
|
'x-middleware-request-a': '1',
|
||||||
|
'x-middleware-request-b': '2',
|
||||||
|
});
|
||||||
|
|
||||||
|
applyOverriddenHeaders(reqHeaders, respHeaders);
|
||||||
|
expect(reqHeaders).toStrictEqual({ a: '1', b: '2' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates an existing header', async () => {
|
||||||
|
const reqHeaders = { a: '1', b: '2' };
|
||||||
|
const respHeaders = new Headers({
|
||||||
|
// Modifies the header 'b' and keep the existing header 'a'
|
||||||
|
'x-middleware-override-headers': 'a,b',
|
||||||
|
'x-middleware-request-a': '1',
|
||||||
|
'x-middleware-request-b': 'modified',
|
||||||
|
});
|
||||||
|
|
||||||
|
applyOverriddenHeaders(reqHeaders, respHeaders);
|
||||||
|
expect(reqHeaders).toStrictEqual({ a: '1', b: 'modified' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ignores headers listed in NONOVERRIDABLE_HEADERS', async () => {
|
||||||
|
const reqHeaders = { a: '1', host: 'example.com' };
|
||||||
|
const respHeaders = new Headers({
|
||||||
|
// Define a new header 'b' and 'content-length'
|
||||||
|
'x-middleware-override-headers': 'a,b,content-length',
|
||||||
|
'x-middleware-request-a': '1',
|
||||||
|
'x-middleware-request-b': '2',
|
||||||
|
'x-middleware-request-content-length': '128',
|
||||||
|
});
|
||||||
|
|
||||||
|
applyOverriddenHeaders(reqHeaders, respHeaders);
|
||||||
|
expect(reqHeaders).toStrictEqual({ a: '1', b: '2', host: 'example.com' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('deletes an existing header', async () => {
|
||||||
|
const reqHeaders = { a: '1', b: '2' };
|
||||||
|
const respHeaders = new Headers({
|
||||||
|
// Deletes the header 'a' and keep the existing header 'b'
|
||||||
|
'x-middleware-override-headers': 'b',
|
||||||
|
'x-middleware-request-b': '2',
|
||||||
|
});
|
||||||
|
|
||||||
|
applyOverriddenHeaders(reqHeaders, respHeaders);
|
||||||
|
expect(reqHeaders).toStrictEqual({ b: '2' });
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/client",
|
"name": "@vercel/client",
|
||||||
"version": "12.2.10",
|
"version": "12.2.15",
|
||||||
"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",
|
||||||
@@ -43,8 +43,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "5.5.3",
|
"@vercel/build-utils": "5.5.7",
|
||||||
"@vercel/routing-utils": "2.0.2",
|
"@vercel/routing-utils": "2.1.1",
|
||||||
"@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",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Agent } from 'https';
|
import http from 'http';
|
||||||
|
import https from 'https';
|
||||||
import { Readable } from 'stream';
|
import { Readable } from 'stream';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import retry from 'async-retry';
|
import retry from 'async-retry';
|
||||||
@@ -78,7 +79,9 @@ export async function* upload(
|
|||||||
debug('Building an upload list...');
|
debug('Building an upload list...');
|
||||||
|
|
||||||
const semaphore = new Sema(50, { capacity: 50 });
|
const semaphore = new Sema(50, { capacity: 50 });
|
||||||
const agent = new Agent({ keepAlive: true });
|
const agent = apiUrl?.startsWith('https://')
|
||||||
|
? new https.Agent({ keepAlive: true })
|
||||||
|
: new http.Agent({ keepAlive: true });
|
||||||
|
|
||||||
shas.forEach((sha, index) => {
|
shas.forEach((sha, index) => {
|
||||||
const uploadProgress = uploads[index];
|
const uploadProgress = uploads[index];
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
- [ExtraResponseInit](interfaces/ExtraResponseInit.md)
|
- [ExtraResponseInit](interfaces/ExtraResponseInit.md)
|
||||||
- [Geo](interfaces/Geo.md)
|
- [Geo](interfaces/Geo.md)
|
||||||
|
- [ModifiedRequest](interfaces/ModifiedRequest.md)
|
||||||
|
|
||||||
### Variables
|
### Variables
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
- [LATITUDE_HEADER_NAME](README.md#latitude_header_name)
|
- [LATITUDE_HEADER_NAME](README.md#latitude_header_name)
|
||||||
- [LONGITUDE_HEADER_NAME](README.md#longitude_header_name)
|
- [LONGITUDE_HEADER_NAME](README.md#longitude_header_name)
|
||||||
- [REGION_HEADER_NAME](README.md#region_header_name)
|
- [REGION_HEADER_NAME](README.md#region_header_name)
|
||||||
|
- [REQUEST_ID_HEADER_NAME](README.md#request_id_header_name)
|
||||||
|
|
||||||
### Functions
|
### Functions
|
||||||
|
|
||||||
@@ -89,11 +91,25 @@ Longitude of the original client IP as calculated by Vercel Proxy.
|
|||||||
|
|
||||||
• `Const` **REGION_HEADER_NAME**: `"x-vercel-ip-country-region"`
|
• `Const` **REGION_HEADER_NAME**: `"x-vercel-ip-country-region"`
|
||||||
|
|
||||||
Region of the original client IP as calculated by Vercel Proxy.
|
Country region of the original client IP calculated by Vercel Proxy.
|
||||||
|
|
||||||
|
See [docs](https://vercel.com/docs/concepts/edge-network/headers#x-vercel-ip-country-region).
|
||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/edge-headers.ts:24](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L24)
|
[src/edge-headers.ts:26](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L26)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### REQUEST_ID_HEADER_NAME
|
||||||
|
|
||||||
|
• `Const` **REQUEST_ID_HEADER_NAME**: `"x-vercel-id"`
|
||||||
|
|
||||||
|
The request ID for each request generated by Vercel Proxy.
|
||||||
|
|
||||||
|
#### Defined in
|
||||||
|
|
||||||
|
[src/edge-headers.ts:30](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L30)
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
|
|
||||||
@@ -123,7 +139,7 @@ Returns the location information for the incoming request.
|
|||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/edge-headers.ts:80](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L80)
|
[src/edge-headers.ts:106](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L106)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -149,7 +165,7 @@ Returns the IP address of the request from the headers.
|
|||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/edge-headers.ts:66](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L66)
|
[src/edge-headers.ts:77](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L77)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -197,7 +213,7 @@ export default function middleware(_req: Request) {
|
|||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/middleware-helpers.ts:94](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L94)
|
[src/middleware-helpers.ts:145](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L145)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -259,4 +275,4 @@ export const config = { matcher: '/api/users/:path*' };
|
|||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/middleware-helpers.ts:53](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L53)
|
[src/middleware-helpers.ts:101](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L101)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
### Properties
|
### Properties
|
||||||
|
|
||||||
- [headers](ExtraResponseInit.md#headers)
|
- [headers](ExtraResponseInit.md#headers)
|
||||||
|
- [request](ExtraResponseInit.md#request)
|
||||||
- [status](ExtraResponseInit.md#status)
|
- [status](ExtraResponseInit.md#status)
|
||||||
- [statusText](ExtraResponseInit.md#statustext)
|
- [statusText](ExtraResponseInit.md#statustext)
|
||||||
|
|
||||||
@@ -25,7 +26,19 @@ along with the response headers from the origin.
|
|||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/middleware-helpers.ts:6](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L6)
|
[src/middleware-helpers.ts:31](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L31)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### request
|
||||||
|
|
||||||
|
• `Optional` **request**: [`ModifiedRequest`](ModifiedRequest.md)
|
||||||
|
|
||||||
|
Fields to rewrite for the upstream request.
|
||||||
|
|
||||||
|
#### Defined in
|
||||||
|
|
||||||
|
[src/middleware-helpers.ts:35](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L35)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ The location information of a given request.
|
|||||||
|
|
||||||
- [city](Geo.md#city)
|
- [city](Geo.md#city)
|
||||||
- [country](Geo.md#country)
|
- [country](Geo.md#country)
|
||||||
|
- [countryRegion](Geo.md#countryregion)
|
||||||
- [latitude](Geo.md#latitude)
|
- [latitude](Geo.md#latitude)
|
||||||
- [longitude](Geo.md#longitude)
|
- [longitude](Geo.md#longitude)
|
||||||
- [region](Geo.md#region)
|
- [region](Geo.md#region)
|
||||||
@@ -22,7 +23,7 @@ The city that the request originated from.
|
|||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/edge-headers.ts:41](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L41)
|
[src/edge-headers.ts:47](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L47)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -34,7 +35,20 @@ The country that the request originated from.
|
|||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/edge-headers.ts:44](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L44)
|
[src/edge-headers.ts:50](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L50)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### countryRegion
|
||||||
|
|
||||||
|
• `Optional` **countryRegion**: `string`
|
||||||
|
|
||||||
|
The region part of the ISO 3166-2 code of the client IP.
|
||||||
|
See [docs](https://vercel.com/docs/concepts/edge-network/headers#x-vercel-ip-country-region).
|
||||||
|
|
||||||
|
#### Defined in
|
||||||
|
|
||||||
|
[src/edge-headers.ts:58](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L58)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -46,7 +60,7 @@ The latitude of the client.
|
|||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/edge-headers.ts:50](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L50)
|
[src/edge-headers.ts:61](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L61)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -58,7 +72,7 @@ The longitude of the client.
|
|||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/edge-headers.ts:53](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L53)
|
[src/edge-headers.ts:64](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L64)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -70,4 +84,4 @@ The [Vercel Edge Network region](https://vercel.com/docs/concepts/edge-network/r
|
|||||||
|
|
||||||
#### Defined in
|
#### Defined in
|
||||||
|
|
||||||
[src/edge-headers.ts:47](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L47)
|
[src/edge-headers.ts:53](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L53)
|
||||||
|
|||||||
38
packages/edge/docs/interfaces/ModifiedRequest.md
Normal file
38
packages/edge/docs/interfaces/ModifiedRequest.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Interface: ModifiedRequest
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
- [headers](ModifiedRequest.md#headers)
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### headers
|
||||||
|
|
||||||
|
• `Optional` **headers**: `Headers`
|
||||||
|
|
||||||
|
If set, overwrites the incoming headers to the origin request.
|
||||||
|
|
||||||
|
This is useful when you want to pass data between a Middleware and a
|
||||||
|
Serverless or Edge Function.
|
||||||
|
|
||||||
|
**`Example`**
|
||||||
|
|
||||||
|
<caption>Add a `x-user-id` header and remove the `Authorization` header</caption>
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { rewrite } from '@vercel/edge';
|
||||||
|
export default async function middleware(request: Request): Promise<Response> {
|
||||||
|
const newHeaders = new Headers(request.headers);
|
||||||
|
newHeaders.set('x-user-id', 'user_123');
|
||||||
|
newHeaders.delete('authorization');
|
||||||
|
return rewrite(request.url, {
|
||||||
|
request: { headers: newHeaders },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Defined in
|
||||||
|
|
||||||
|
[src/middleware-helpers.ts:23](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L23)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/edge",
|
"name": "@vercel/edge",
|
||||||
"version": "0.0.4",
|
"version": "0.1.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist/index.mjs",
|
"module": "dist/index.mjs",
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"build:docs": "typedoc && prettier --write docs/**/*.md docs/*.md"
|
"build:docs": "typedoc && prettier --write docs/**/*.md docs/*.md"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@edge-runtime/jest-environment": "1.1.0-beta.7",
|
"@edge-runtime/jest-environment": "2.0.0",
|
||||||
"@types/jest": "27.4.1",
|
"@types/jest": "27.4.1",
|
||||||
"ts-node": "8.9.1",
|
"ts-node": "8.9.1",
|
||||||
"tsup": "6.1.2",
|
"tsup": "6.1.2",
|
||||||
|
|||||||
@@ -19,9 +19,15 @@ export const LATITUDE_HEADER_NAME = 'x-vercel-ip-latitude';
|
|||||||
*/
|
*/
|
||||||
export const LONGITUDE_HEADER_NAME = 'x-vercel-ip-longitude';
|
export const LONGITUDE_HEADER_NAME = 'x-vercel-ip-longitude';
|
||||||
/**
|
/**
|
||||||
* Region of the original client IP as calculated by Vercel Proxy.
|
* Country region of the original client IP calculated by Vercel Proxy.
|
||||||
|
*
|
||||||
|
* See [docs](https://vercel.com/docs/concepts/edge-network/headers#x-vercel-ip-country-region).
|
||||||
*/
|
*/
|
||||||
export const REGION_HEADER_NAME = 'x-vercel-ip-country-region';
|
export const REGION_HEADER_NAME = 'x-vercel-ip-country-region';
|
||||||
|
/**
|
||||||
|
* The request ID for each request generated by Vercel Proxy.
|
||||||
|
*/
|
||||||
|
export const REQUEST_ID_HEADER_NAME = 'x-vercel-id';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We define a new type so this function can be reused with
|
* We define a new type so this function can be reused with
|
||||||
@@ -46,6 +52,11 @@ export interface Geo {
|
|||||||
/** The [Vercel Edge Network region](https://vercel.com/docs/concepts/edge-network/regions) that received the request. */
|
/** The [Vercel Edge Network region](https://vercel.com/docs/concepts/edge-network/regions) that received the request. */
|
||||||
region?: string;
|
region?: string;
|
||||||
|
|
||||||
|
/** The region part of the ISO 3166-2 code of the client IP.
|
||||||
|
* See [docs](https://vercel.com/docs/concepts/edge-network/headers#x-vercel-ip-country-region).
|
||||||
|
*/
|
||||||
|
countryRegion?: string;
|
||||||
|
|
||||||
/** The latitude of the client. */
|
/** The latitude of the client. */
|
||||||
latitude?: string;
|
latitude?: string;
|
||||||
|
|
||||||
@@ -67,6 +78,21 @@ export function ipAddress(request: Request): string | undefined {
|
|||||||
return getHeader(request, IP_HEADER_NAME);
|
return getHeader(request, IP_HEADER_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the Vercel Edge Network region name from the request ID.
|
||||||
|
*
|
||||||
|
* @param requestId The request ID (`x-vercel-id`).
|
||||||
|
* @returns The first region received the client request.
|
||||||
|
*/
|
||||||
|
function getRegionFromRequestId(requestId?: string): string | undefined {
|
||||||
|
if (!requestId) {
|
||||||
|
return 'dev1';
|
||||||
|
}
|
||||||
|
|
||||||
|
// The request ID is in the format of `region::id` or `region1:region2:...::id`.
|
||||||
|
return requestId.split(':')[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the location information for the incoming request.
|
* Returns the location information for the incoming request.
|
||||||
*
|
*
|
||||||
@@ -81,7 +107,8 @@ export function geolocation(request: Request): Geo {
|
|||||||
return {
|
return {
|
||||||
city: getHeader(request, CITY_HEADER_NAME),
|
city: getHeader(request, CITY_HEADER_NAME),
|
||||||
country: getHeader(request, COUNTRY_HEADER_NAME),
|
country: getHeader(request, COUNTRY_HEADER_NAME),
|
||||||
region: getHeader(request, REGION_HEADER_NAME),
|
countryRegion: getHeader(request, REGION_HEADER_NAME),
|
||||||
|
region: getRegionFromRequestId(getHeader(request, REQUEST_ID_HEADER_NAME)),
|
||||||
latitude: getHeader(request, LATITUDE_HEADER_NAME),
|
latitude: getHeader(request, LATITUDE_HEADER_NAME),
|
||||||
longitude: getHeader(request, LONGITUDE_HEADER_NAME),
|
longitude: getHeader(request, LONGITUDE_HEADER_NAME),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,57 @@
|
|||||||
|
export interface ModifiedRequest {
|
||||||
|
/**
|
||||||
|
* If set, overwrites the incoming headers to the origin request.
|
||||||
|
*
|
||||||
|
* This is useful when you want to pass data between a Middleware and a
|
||||||
|
* Serverless or Edge Function.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* <caption>Add a `x-user-id` header and remove the `Authorization` header</caption>
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* import { rewrite } from '@vercel/edge';
|
||||||
|
* export default async function middleware(request: Request): Promise<Response> {
|
||||||
|
* const newHeaders = new Headers(request.headers);
|
||||||
|
* newHeaders.set('x-user-id', 'user_123');
|
||||||
|
* newHeaders.delete('authorization');
|
||||||
|
* return rewrite(request.url, {
|
||||||
|
* request: { headers: newHeaders }
|
||||||
|
* })
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
headers?: Headers;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ExtraResponseInit extends Omit<ResponseInit, 'headers'> {
|
export interface ExtraResponseInit extends Omit<ResponseInit, 'headers'> {
|
||||||
/**
|
/**
|
||||||
* These headers will be sent to the user response
|
* These headers will be sent to the user response
|
||||||
* along with the response headers from the origin.
|
* along with the response headers from the origin.
|
||||||
*/
|
*/
|
||||||
headers?: HeadersInit;
|
headers?: HeadersInit;
|
||||||
|
/**
|
||||||
|
* Fields to rewrite for the upstream request.
|
||||||
|
*/
|
||||||
|
request?: ModifiedRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMiddlewareField(
|
||||||
|
init: ExtraResponseInit | undefined,
|
||||||
|
headers: Headers
|
||||||
|
) {
|
||||||
|
if (init?.request?.headers) {
|
||||||
|
if (!(init.request.headers instanceof Headers)) {
|
||||||
|
throw new Error('request.headers must be an instance of Headers');
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = [];
|
||||||
|
for (const [key, value] of init.request.headers) {
|
||||||
|
headers.set('x-middleware-request-' + key, value);
|
||||||
|
keys.push(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
headers.set('x-middleware-override-headers', keys.join(','));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,6 +104,9 @@ export function rewrite(
|
|||||||
): Response {
|
): Response {
|
||||||
const headers = new Headers(init?.headers ?? {});
|
const headers = new Headers(init?.headers ?? {});
|
||||||
headers.set('x-middleware-rewrite', String(destination));
|
headers.set('x-middleware-rewrite', String(destination));
|
||||||
|
|
||||||
|
handleMiddlewareField(init, headers);
|
||||||
|
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
...init,
|
...init,
|
||||||
headers,
|
headers,
|
||||||
@@ -94,6 +145,9 @@ export function rewrite(
|
|||||||
export function next(init?: ExtraResponseInit): Response {
|
export function next(init?: ExtraResponseInit): Response {
|
||||||
const headers = new Headers(init?.headers ?? {});
|
const headers = new Headers(init?.headers ?? {});
|
||||||
headers.set('x-middleware-next', '1');
|
headers.set('x-middleware-next', '1');
|
||||||
|
|
||||||
|
handleMiddlewareField(init, headers);
|
||||||
|
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
...init,
|
...init,
|
||||||
headers,
|
headers,
|
||||||
|
|||||||
57
packages/edge/test/edge-headers.test.ts
vendored
57
packages/edge/test/edge-headers.test.ts
vendored
@@ -12,6 +12,7 @@ import {
|
|||||||
LATITUDE_HEADER_NAME,
|
LATITUDE_HEADER_NAME,
|
||||||
LONGITUDE_HEADER_NAME,
|
LONGITUDE_HEADER_NAME,
|
||||||
REGION_HEADER_NAME,
|
REGION_HEADER_NAME,
|
||||||
|
REQUEST_ID_HEADER_NAME,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
|
|
||||||
test('`ipAddress` returns the value from the header', () => {
|
test('`ipAddress` returns the value from the header', () => {
|
||||||
@@ -24,9 +25,16 @@ test('`ipAddress` returns the value from the header', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('`geolocation`', () => {
|
describe('`geolocation`', () => {
|
||||||
test('returns an empty object if headers are not found', () => {
|
test('returns an object with lots of undefined if headers are not found', () => {
|
||||||
const req = new Request('https://example.vercel.sh');
|
const req = new Request('https://example.vercel.sh');
|
||||||
expect(geolocation(req)).toEqual({});
|
expect(geolocation(req)).toEqual({
|
||||||
|
city: undefined,
|
||||||
|
country: undefined,
|
||||||
|
countryRegion: undefined,
|
||||||
|
latitude: undefined,
|
||||||
|
longitude: undefined,
|
||||||
|
region: 'dev1',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('reads values from headers', () => {
|
test('reads values from headers', () => {
|
||||||
@@ -36,7 +44,8 @@ describe('`geolocation`', () => {
|
|||||||
[COUNTRY_HEADER_NAME]: 'Israel',
|
[COUNTRY_HEADER_NAME]: 'Israel',
|
||||||
[LATITUDE_HEADER_NAME]: '32.109333',
|
[LATITUDE_HEADER_NAME]: '32.109333',
|
||||||
[LONGITUDE_HEADER_NAME]: '34.855499',
|
[LONGITUDE_HEADER_NAME]: '34.855499',
|
||||||
[REGION_HEADER_NAME]: 'fra1',
|
[REGION_HEADER_NAME]: 'TA', // https://en.wikipedia.org/wiki/ISO_3166-2:IL
|
||||||
|
[REQUEST_ID_HEADER_NAME]: 'fra1::kpwjx-123455678-c0ffee',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(geolocation(req)).toEqual<Geo>({
|
expect(geolocation(req)).toEqual<Geo>({
|
||||||
@@ -45,6 +54,48 @@ describe('`geolocation`', () => {
|
|||||||
latitude: '32.109333',
|
latitude: '32.109333',
|
||||||
longitude: '34.855499',
|
longitude: '34.855499',
|
||||||
region: 'fra1',
|
region: 'fra1',
|
||||||
|
countryRegion: 'TA',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('reads values from headers (with a request ID containing two edge regions)', () => {
|
||||||
|
const req = new Request('https://example.vercel.sh', {
|
||||||
|
headers: {
|
||||||
|
[CITY_HEADER_NAME]: 'Tokyo',
|
||||||
|
[COUNTRY_HEADER_NAME]: 'Japan',
|
||||||
|
[LATITUDE_HEADER_NAME]: '37.1233',
|
||||||
|
[LONGITUDE_HEADER_NAME]: '30.733399',
|
||||||
|
[REGION_HEADER_NAME]: '13',
|
||||||
|
[REQUEST_ID_HEADER_NAME]: 'hnd1:iad1::kpwjx-123455678-c0ffee',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(geolocation(req)).toEqual<Geo>({
|
||||||
|
city: 'Tokyo',
|
||||||
|
country: 'Japan',
|
||||||
|
latitude: '37.1233',
|
||||||
|
longitude: '30.733399',
|
||||||
|
region: 'hnd1',
|
||||||
|
countryRegion: '13',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('reads values from headers (without a request ID)', () => {
|
||||||
|
const req = new Request('https://example.vercel.sh', {
|
||||||
|
headers: {
|
||||||
|
[CITY_HEADER_NAME]: 'Tokyo',
|
||||||
|
[COUNTRY_HEADER_NAME]: 'Japan',
|
||||||
|
[LATITUDE_HEADER_NAME]: '37.1233',
|
||||||
|
[LONGITUDE_HEADER_NAME]: '30.733399',
|
||||||
|
[REGION_HEADER_NAME]: '13',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(geolocation(req)).toEqual<Geo>({
|
||||||
|
city: 'Tokyo',
|
||||||
|
country: 'Japan',
|
||||||
|
latitude: '37.1233',
|
||||||
|
longitude: '30.733399',
|
||||||
|
region: 'dev1',
|
||||||
|
countryRegion: '13',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
52
packages/edge/test/middleware-helpers.test.ts
vendored
52
packages/edge/test/middleware-helpers.test.ts
vendored
@@ -22,6 +22,32 @@ describe('rewrite', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('receives new request headers', () => {
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.set('x-from-middleware1', 'hello1');
|
||||||
|
headers.set('x-from-middleware2', 'hello2');
|
||||||
|
const resp = rewrite(new URL('https://example.vercel.sh/'), {
|
||||||
|
headers: {
|
||||||
|
'x-custom-header': 'custom-value',
|
||||||
|
},
|
||||||
|
request: { headers },
|
||||||
|
});
|
||||||
|
expect({
|
||||||
|
status: resp.status,
|
||||||
|
headers: Object.fromEntries(resp.headers),
|
||||||
|
}).toMatchObject({
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
'x-middleware-rewrite': 'https://example.vercel.sh/',
|
||||||
|
'x-custom-header': 'custom-value',
|
||||||
|
'x-middleware-override-headers':
|
||||||
|
'x-from-middleware1,x-from-middleware2',
|
||||||
|
'x-middleware-request-x-from-middleware2': 'hello2',
|
||||||
|
'x-middleware-request-x-from-middleware1': 'hello1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('next', () => {
|
describe('next', () => {
|
||||||
@@ -42,4 +68,30 @@ describe('next', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('receives new request headers', () => {
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.set('x-from-middleware1', 'hello1');
|
||||||
|
headers.set('x-from-middleware2', 'hello2');
|
||||||
|
const resp = next({
|
||||||
|
headers: {
|
||||||
|
'x-custom-header': 'custom-value',
|
||||||
|
},
|
||||||
|
request: { headers },
|
||||||
|
});
|
||||||
|
expect({
|
||||||
|
status: resp.status,
|
||||||
|
headers: Object.fromEntries(resp.headers),
|
||||||
|
}).toMatchObject({
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
'x-middleware-next': '1',
|
||||||
|
'x-custom-header': 'custom-value',
|
||||||
|
'x-middleware-override-headers':
|
||||||
|
'x-from-middleware1,x-from-middleware2',
|
||||||
|
'x-middleware-request-x-from-middleware2': 'hello2',
|
||||||
|
'x-middleware-request-x-from-middleware1': 'hello1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
13
packages/error-utils/jest.config.js
Normal file
13
packages/error-utils/jest.config.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/** @type {import('@ts-jest/dist/types').InitialOptionsTsJest} */
|
||||||
|
module.exports = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node',
|
||||||
|
coverageThreshold: {
|
||||||
|
global: {
|
||||||
|
branches: 100,
|
||||||
|
functions: 100,
|
||||||
|
lines: 100,
|
||||||
|
statements: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
25
packages/error-utils/package.json
Normal file
25
packages/error-utils/package.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "@vercel/error-utils",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"description": "A collection of error utilities for vercel/vercel",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/vercel/vercel.git",
|
||||||
|
"directory": "packages/error-utils"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "jest --coverage --env node --verbose",
|
||||||
|
"test-unit": "yarn test"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "29.2.1",
|
||||||
|
"@types/node": "16.11.7",
|
||||||
|
"jest": "29.2.2",
|
||||||
|
"ts-jest": "29.0.3",
|
||||||
|
"typescript": "^4.8.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ export const isError = (error: unknown): error is Error => {
|
|||||||
// Walk the prototype tree until we find a matching object.
|
// Walk the prototype tree until we find a matching object.
|
||||||
while (error) {
|
while (error) {
|
||||||
if (Object.prototype.toString.call(error) === '[object Error]') return true;
|
if (Object.prototype.toString.call(error) === '[object Error]') return true;
|
||||||
// eslint-disable-next-line no-param-reassign -- TODO: Fix eslint error following @vercel/style-guide migration
|
|
||||||
error = Object.getPrototypeOf(error);
|
error = Object.getPrototypeOf(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user