mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-12 21:07:46 +00:00
Compare commits
31 Commits
@vercel/py
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
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.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -82,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
|
||||||
|
|||||||
@@ -35,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)
|
||||||
|
|||||||
@@ -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
10
package.json
10
package.json
@@ -44,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.5",
|
"version": "5.5.6",
|
||||||
"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';
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
49
packages/build-utils/test/unit.test.ts
vendored
49
packages/build-utils/test/unit.test.ts
vendored
@@ -285,6 +285,23 @@ it('should match all semver ranges', async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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 () => {
|
||||||
expect(
|
expect(
|
||||||
await getNodeVersion(
|
await getNodeVersion(
|
||||||
@@ -433,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');
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vercel",
|
"name": "vercel",
|
||||||
"version": "28.4.11",
|
"version": "28.4.13",
|
||||||
"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.5",
|
"@vercel/build-utils": "5.5.6",
|
||||||
"@vercel/go": "2.2.13",
|
"@vercel/go": "2.2.14",
|
||||||
"@vercel/hydrogen": "0.0.26",
|
"@vercel/hydrogen": "0.0.27",
|
||||||
"@vercel/next": "3.2.5",
|
"@vercel/next": "3.2.7",
|
||||||
"@vercel/node": "2.5.25",
|
"@vercel/node": "2.6.0",
|
||||||
"@vercel/python": "3.1.22",
|
"@vercel/python": "3.1.23",
|
||||||
"@vercel/redwood": "1.0.31",
|
"@vercel/redwood": "1.0.32",
|
||||||
"@vercel/remix": "1.0.32",
|
"@vercel/remix": "1.0.33",
|
||||||
"@vercel/ruby": "1.3.39",
|
"@vercel/ruby": "1.3.40",
|
||||||
"@vercel/static-build": "1.0.32",
|
"@vercel/static-build": "1.0.33",
|
||||||
"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.13",
|
"@vercel/client": "12.2.14",
|
||||||
"@vercel/frameworks": "1.1.8",
|
"@vercel/error-utils": "1.0.1",
|
||||||
"@vercel/fs-detectors": "3.4.5",
|
"@vercel/frameworks": "1.1.9",
|
||||||
|
"@vercel/fs-detectors": "3.4.6",
|
||||||
"@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",
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,7 @@ 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';
|
const IS_TEST = process.env.NODE_ENV === 'test';
|
||||||
|
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
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.13",
|
"version": "12.2.14",
|
||||||
"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.5",
|
"@vercel/build-utils": "5.5.6",
|
||||||
"@vercel/routing-utils": "2.0.2",
|
"@vercel/routing-utils": "2.1.0",
|
||||||
"@zeit/fetch": "5.2.0",
|
"@zeit/fetch": "5.2.0",
|
||||||
"async-retry": "1.2.3",
|
"async-retry": "1.2.3",
|
||||||
"async-sema": "3.0.0",
|
"async-sema": "3.0.0",
|
||||||
|
|||||||
@@ -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.0",
|
||||||
"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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
26
packages/error-utils/package.json
Normal file
26
packages/error-utils/package.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "@vercel/error-utils",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"private": true,
|
||||||
|
"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);
|
||||||
}
|
}
|
||||||
|
|
||||||
148
packages/error-utils/test/index.test.ts
vendored
Normal file
148
packages/error-utils/test/index.test.ts
vendored
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
import fs from 'node:fs';
|
||||||
|
import {
|
||||||
|
isObject,
|
||||||
|
isError,
|
||||||
|
isErrnoException,
|
||||||
|
isErrorLike,
|
||||||
|
normalizeError,
|
||||||
|
isSpawnError,
|
||||||
|
errorToString,
|
||||||
|
} from '../src';
|
||||||
|
|
||||||
|
const ARRAY: any[] = [];
|
||||||
|
const BIGINT = 1n;
|
||||||
|
const BOOLEAN = true;
|
||||||
|
const FUNCTION = () => {};
|
||||||
|
const NULL = null;
|
||||||
|
const NUMBER = 0;
|
||||||
|
const OBJECT = {};
|
||||||
|
const STRING = '';
|
||||||
|
const SYMBOL = Symbol('');
|
||||||
|
const UNDEFINED = undefined;
|
||||||
|
|
||||||
|
class CLASS {} // `CLASS` is a function and `new CLASS()` is an Object
|
||||||
|
|
||||||
|
test('isObject returns true for objects only', () => {
|
||||||
|
for (const item of [ARRAY, new CLASS(), OBJECT]) {
|
||||||
|
expect(isObject(item)).toBe(true);
|
||||||
|
}
|
||||||
|
for (const item of [
|
||||||
|
BIGINT,
|
||||||
|
BOOLEAN,
|
||||||
|
CLASS,
|
||||||
|
FUNCTION,
|
||||||
|
NULL,
|
||||||
|
NUMBER,
|
||||||
|
STRING,
|
||||||
|
SYMBOL,
|
||||||
|
UNDEFINED,
|
||||||
|
]) {
|
||||||
|
expect(isObject(item)).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isError returns true for Error instances only', () => {
|
||||||
|
for (const error of [
|
||||||
|
new Error(),
|
||||||
|
new EvalError(),
|
||||||
|
new RangeError(),
|
||||||
|
new ReferenceError(),
|
||||||
|
new SyntaxError(),
|
||||||
|
new TypeError(),
|
||||||
|
new URIError(),
|
||||||
|
]) {
|
||||||
|
expect(isError(error)).toBe(true);
|
||||||
|
}
|
||||||
|
for (const item of [
|
||||||
|
ARRAY,
|
||||||
|
BIGINT,
|
||||||
|
BOOLEAN,
|
||||||
|
CLASS,
|
||||||
|
new CLASS(),
|
||||||
|
FUNCTION,
|
||||||
|
NULL,
|
||||||
|
NUMBER,
|
||||||
|
OBJECT,
|
||||||
|
STRING,
|
||||||
|
SYMBOL,
|
||||||
|
UNDEFINED,
|
||||||
|
]) {
|
||||||
|
expect(isError(item)).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isError returns true for objects with a nested Error prototype', () => {
|
||||||
|
class Foo {}
|
||||||
|
const err = new Error();
|
||||||
|
Object.setPrototypeOf(err, Foo.prototype);
|
||||||
|
expect(isError(err)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isErrnoException returns true for NodeJS.ErrnoException only', () => {
|
||||||
|
try {
|
||||||
|
fs.statSync('./i-definitely-do-not-exist');
|
||||||
|
fail();
|
||||||
|
} catch (err) {
|
||||||
|
expect(isErrnoException(err)).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isErrorLike returns true when object is like an error', () => {
|
||||||
|
expect(isErrorLike(new Error())).toBe(true);
|
||||||
|
expect(isErrorLike({ message: '' })).toBe(true);
|
||||||
|
expect(isErrorLike({})).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('errorToString', () => {
|
||||||
|
const message = 'message';
|
||||||
|
test('return `message` when first argument is an error', () => {
|
||||||
|
expect(errorToString(new Error(message))).toStrictEqual(message);
|
||||||
|
});
|
||||||
|
test('returns `message` when first argument is error like', () => {
|
||||||
|
expect(errorToString({ message })).toStrictEqual(message);
|
||||||
|
});
|
||||||
|
test('returns first argument when it is a string', () => {
|
||||||
|
expect(errorToString(message)).toStrictEqual(message);
|
||||||
|
});
|
||||||
|
test('returns second argument when first argument is not an error, error like, nor a string', () => {
|
||||||
|
expect(errorToString(null, message)).toStrictEqual(message);
|
||||||
|
});
|
||||||
|
test('returns default fallback message when first argument is not an error, error like, nor a string, and the second argument is not provided', () => {
|
||||||
|
expect(errorToString(null)).toStrictEqual('An unknown error has ocurred.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('normalizeError', () => {
|
||||||
|
const message = 'message';
|
||||||
|
test('returns first argument if it is an error', () => {
|
||||||
|
expect(normalizeError(new Error(message))).toStrictEqual(
|
||||||
|
new Error(message)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test('returns a new error if argument is not error like', () => {
|
||||||
|
expect(normalizeError(message)).toStrictEqual(new Error(message));
|
||||||
|
});
|
||||||
|
test('returns a new error if argument is not error like', () => {
|
||||||
|
expect(normalizeError({ message })).toStrictEqual(new Error(message));
|
||||||
|
});
|
||||||
|
test('returns a new error with fallback message if argument is not error like nor a string.', () => {
|
||||||
|
expect(normalizeError(null)).toStrictEqual(
|
||||||
|
new Error('An unknown error has ocurred.')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test('returns an Error with the input object assigned to it', () => {
|
||||||
|
expect(normalizeError({ message, prop: 'value' })).toStrictEqual(
|
||||||
|
Object.assign(new Error(message), { prop: 'value' })
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('isSpawnError', () => {
|
||||||
|
const spawnError = new Error('spawn error');
|
||||||
|
Object.assign(spawnError, {
|
||||||
|
code: 'SPAWN_ERROR',
|
||||||
|
spawnargs: ['a', 'b', 'c'],
|
||||||
|
});
|
||||||
|
expect(isSpawnError(spawnError)).toBe(true);
|
||||||
|
expect(isSpawnError(new Error('not spawn error'))).toBe(false);
|
||||||
|
});
|
||||||
7
packages/error-utils/test/tsconfig.json
vendored
Normal file
7
packages/error-utils/test/tsconfig.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": ["node", "jest"]
|
||||||
|
},
|
||||||
|
"include": ["*.test.ts"]
|
||||||
|
}
|
||||||
22
packages/error-utils/tsconfig.json
Normal file
22
packages/error-utils/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"lib": ["ES2020"],
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"noEmitOnError": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"types": ["node", "jest"],
|
||||||
|
"strict": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"target": "ES2020"
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/frameworks",
|
"name": "@vercel/frameworks",
|
||||||
"version": "1.1.8",
|
"version": "1.1.9",
|
||||||
"main": "./dist/frameworks.js",
|
"main": "./dist/frameworks.js",
|
||||||
"types": "./dist/frameworks.d.ts",
|
"types": "./dist/frameworks.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"@types/js-yaml": "3.12.1",
|
"@types/js-yaml": "3.12.1",
|
||||||
"@types/node": "12.0.4",
|
"@types/node": "12.0.4",
|
||||||
"@types/node-fetch": "2.5.8",
|
"@types/node-fetch": "2.5.8",
|
||||||
"@vercel/routing-utils": "2.0.2",
|
"@vercel/routing-utils": "2.1.0",
|
||||||
"ajv": "6.12.2",
|
"ajv": "6.12.2",
|
||||||
"typescript": "4.3.4"
|
"typescript": "4.3.4"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/fs-detectors",
|
"name": "@vercel/fs-detectors",
|
||||||
"version": "3.4.5",
|
"version": "3.4.6",
|
||||||
"description": "Vercel filesystem detectors",
|
"description": "Vercel filesystem detectors",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@@ -19,8 +19,8 @@
|
|||||||
"test-unit": "yarn test"
|
"test-unit": "yarn test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/frameworks": "1.1.8",
|
"@vercel/frameworks": "1.1.9",
|
||||||
"@vercel/routing-utils": "2.0.2",
|
"@vercel/routing-utils": "2.1.0",
|
||||||
"glob": "8.0.3",
|
"glob": "8.0.3",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"json5": "2.2.1",
|
"json5": "2.2.1",
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export const monorepoManagers: Array<
|
|||||||
value: null,
|
value: null,
|
||||||
},
|
},
|
||||||
outputDirectory: {
|
outputDirectory: {
|
||||||
placeholder: 'Nx default',
|
value: null,
|
||||||
},
|
},
|
||||||
installCommand: {
|
installCommand: {
|
||||||
value: null,
|
value: null,
|
||||||
@@ -93,7 +93,7 @@ export const monorepoManagers: Array<
|
|||||||
value: null,
|
value: null,
|
||||||
},
|
},
|
||||||
outputDirectory: {
|
outputDirectory: {
|
||||||
placeholder: 'Rush default',
|
value: null,
|
||||||
},
|
},
|
||||||
installCommand: {
|
installCommand: {
|
||||||
placeholder: 'Rush default',
|
placeholder: 'Rush default',
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/go",
|
"name": "@vercel/go",
|
||||||
"version": "2.2.13",
|
"version": "2.2.14",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"@types/jest": "28.1.6",
|
"@types/jest": "28.1.6",
|
||||||
"@types/node-fetch": "^2.3.0",
|
"@types/node-fetch": "^2.3.0",
|
||||||
"@types/tar": "^4.0.0",
|
"@types/tar": "^4.0.0",
|
||||||
"@vercel/build-utils": "5.5.5",
|
"@vercel/build-utils": "5.5.6",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.24.0",
|
||||||
"async-retry": "1.3.1",
|
"async-retry": "1.3.1",
|
||||||
"execa": "^1.0.0",
|
"execa": "^1.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/hydrogen",
|
"name": "@vercel/hydrogen",
|
||||||
"version": "0.0.26",
|
"version": "0.0.27",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"homepage": "https://vercel.com/docs",
|
"homepage": "https://vercel.com/docs",
|
||||||
@@ -21,7 +21,8 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "27.5.1",
|
"@types/jest": "27.5.1",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@vercel/build-utils": "5.5.5",
|
"@vercel/build-utils": "5.5.6",
|
||||||
|
"@vercel/static-config": "2.0.4",
|
||||||
"typescript": "4.6.4"
|
"typescript": "4.6.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import {
|
|||||||
scanParentDirs,
|
scanParentDirs,
|
||||||
} from '@vercel/build-utils';
|
} from '@vercel/build-utils';
|
||||||
import type { BuildV2, PackageJson } from '@vercel/build-utils';
|
import type { BuildV2, PackageJson } from '@vercel/build-utils';
|
||||||
|
import { getConfig } from '@vercel/static-config';
|
||||||
|
import { Project } from 'ts-morph';
|
||||||
|
|
||||||
export const build: BuildV2 = async ({
|
export const build: BuildV2 = async ({
|
||||||
entrypoint,
|
entrypoint,
|
||||||
@@ -118,6 +120,15 @@ export const build: BuildV2 = async ({
|
|||||||
deploymentTarget: 'v8-worker',
|
deploymentTarget: 'v8-worker',
|
||||||
entrypoint: 'index.js',
|
entrypoint: 'index.js',
|
||||||
files: edgeFunctionFiles,
|
files: edgeFunctionFiles,
|
||||||
|
regions: (() => {
|
||||||
|
try {
|
||||||
|
const project = new Project();
|
||||||
|
const config = getConfig(project, edgeFunctionFiles['index.js'].fsPath);
|
||||||
|
return config?.regions;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
})(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// The `index.html` file is a template, but we want to serve the
|
// The `index.html` file is a template, but we want to serve the
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/next",
|
"name": "@vercel/next",
|
||||||
"version": "3.2.5",
|
"version": "3.2.7",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||||
@@ -44,9 +44,9 @@
|
|||||||
"@types/semver": "6.0.0",
|
"@types/semver": "6.0.0",
|
||||||
"@types/text-table": "0.2.1",
|
"@types/text-table": "0.2.1",
|
||||||
"@types/webpack-sources": "3.2.0",
|
"@types/webpack-sources": "3.2.0",
|
||||||
"@vercel/build-utils": "5.5.5",
|
"@vercel/build-utils": "5.5.6",
|
||||||
"@vercel/nft": "0.22.1",
|
"@vercel/nft": "0.22.1",
|
||||||
"@vercel/routing-utils": "2.0.2",
|
"@vercel/routing-utils": "2.1.0",
|
||||||
"async-sema": "3.0.1",
|
"async-sema": "3.0.1",
|
||||||
"buffer-crc32": "0.2.13",
|
"buffer-crc32": "0.2.13",
|
||||||
"cheerio": "1.0.0-rc.10",
|
"cheerio": "1.0.0-rc.10",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
Files,
|
Files,
|
||||||
BuildResultV2Typical as BuildResult,
|
BuildResultV2Typical as BuildResult,
|
||||||
} from '@vercel/build-utils';
|
} from '@vercel/build-utils';
|
||||||
import { Route, RouteWithHandle, RouteWithSrc } from '@vercel/routing-utils';
|
import { Route, RouteWithHandle } from '@vercel/routing-utils';
|
||||||
import { MAX_AGE_ONE_YEAR } from '.';
|
import { MAX_AGE_ONE_YEAR } from '.';
|
||||||
import {
|
import {
|
||||||
NextRequiredServerFilesManifest,
|
NextRequiredServerFilesManifest,
|
||||||
@@ -218,7 +218,8 @@ export async function serverBuild({
|
|||||||
nonLambdaSsgPages,
|
nonLambdaSsgPages,
|
||||||
route,
|
route,
|
||||||
routesManifest.pages404,
|
routesManifest.pages404,
|
||||||
routesManifest
|
routesManifest,
|
||||||
|
appDir
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result && result.static404Page) {
|
if (result && result.static404Page) {
|
||||||
@@ -337,6 +338,7 @@ export async function serverBuild({
|
|||||||
|
|
||||||
const apiPages: string[] = [];
|
const apiPages: string[] = [];
|
||||||
const nonApiPages: string[] = [];
|
const nonApiPages: string[] = [];
|
||||||
|
const streamingPages: string[] = [];
|
||||||
|
|
||||||
lambdaPageKeys.forEach(page => {
|
lambdaPageKeys.forEach(page => {
|
||||||
if (
|
if (
|
||||||
@@ -358,6 +360,8 @@ export async function serverBuild({
|
|||||||
|
|
||||||
if (pageMatchesApi(page)) {
|
if (pageMatchesApi(page)) {
|
||||||
apiPages.push(page);
|
apiPages.push(page);
|
||||||
|
} else if (appDir && lambdaAppPaths[page]) {
|
||||||
|
streamingPages.push(page);
|
||||||
} else {
|
} else {
|
||||||
nonApiPages.push(page);
|
nonApiPages.push(page);
|
||||||
}
|
}
|
||||||
@@ -545,7 +549,12 @@ export async function serverBuild({
|
|||||||
const compressedPages: {
|
const compressedPages: {
|
||||||
[page: string]: PseudoFile;
|
[page: string]: PseudoFile;
|
||||||
} = {};
|
} = {};
|
||||||
const mergedPageKeys = [...nonApiPages, ...apiPages, ...internalPages];
|
const mergedPageKeys = [
|
||||||
|
...nonApiPages,
|
||||||
|
...streamingPages,
|
||||||
|
...apiPages,
|
||||||
|
...internalPages,
|
||||||
|
];
|
||||||
const traceCache = {};
|
const traceCache = {};
|
||||||
|
|
||||||
const getOriginalPagePath = (page: string) => {
|
const getOriginalPagePath = (page: string) => {
|
||||||
@@ -703,6 +712,27 @@ export async function serverBuild({
|
|||||||
pageExtensions,
|
pageExtensions,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const streamingPageLambdaGroups = await getPageLambdaGroups({
|
||||||
|
entryPath: requiredServerFilesManifest.appDir || entryPath,
|
||||||
|
config,
|
||||||
|
pages: streamingPages,
|
||||||
|
prerenderRoutes,
|
||||||
|
pageTraces,
|
||||||
|
compressedPages,
|
||||||
|
tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
|
||||||
|
initialPseudoLayer,
|
||||||
|
lambdaCompressedByteLimit,
|
||||||
|
initialPseudoLayerUncompressed: uncompressedInitialSize,
|
||||||
|
internalPages,
|
||||||
|
pageExtensions,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const group of streamingPageLambdaGroups) {
|
||||||
|
if (!group.isPrerenders) {
|
||||||
|
group.isStreaming = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const apiLambdaGroups = await getPageLambdaGroups({
|
const apiLambdaGroups = await getPageLambdaGroups({
|
||||||
entryPath: requiredServerFilesManifest.appDir || entryPath,
|
entryPath: requiredServerFilesManifest.appDir || entryPath,
|
||||||
config,
|
config,
|
||||||
@@ -732,13 +762,23 @@ export async function serverBuild({
|
|||||||
pseudoLayerBytes: group.pseudoLayerBytes,
|
pseudoLayerBytes: group.pseudoLayerBytes,
|
||||||
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
||||||
})),
|
})),
|
||||||
|
streamingPageLambdaGroups: streamingPageLambdaGroups.map(group => ({
|
||||||
|
pages: group.pages,
|
||||||
|
isPrerender: group.isPrerenders,
|
||||||
|
pseudoLayerBytes: group.pseudoLayerBytes,
|
||||||
|
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
||||||
|
})),
|
||||||
nextServerLayerSize: initialPseudoLayer.pseudoLayerBytes,
|
nextServerLayerSize: initialPseudoLayer.pseudoLayerBytes,
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
2
|
2
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const combinedGroups = [...pageLambdaGroups, ...apiLambdaGroups];
|
const combinedGroups = [
|
||||||
|
...pageLambdaGroups,
|
||||||
|
...streamingPageLambdaGroups,
|
||||||
|
...apiLambdaGroups,
|
||||||
|
];
|
||||||
|
|
||||||
await detectLambdaLimitExceeding(
|
await detectLambdaLimitExceeding(
|
||||||
combinedGroups,
|
combinedGroups,
|
||||||
@@ -831,6 +871,7 @@ export async function serverBuild({
|
|||||||
memory: group.memory,
|
memory: group.memory,
|
||||||
runtime: nodeVersion.runtime,
|
runtime: nodeVersion.runtime,
|
||||||
maxDuration: group.maxDuration,
|
maxDuration: group.maxDuration,
|
||||||
|
isStreaming: group.isStreaming,
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const page of group.pages) {
|
for (const page of group.pages) {
|
||||||
@@ -963,61 +1004,6 @@ export async function serverBuild({
|
|||||||
const { staticFiles, publicDirectoryFiles, staticDirectoryFiles } =
|
const { staticFiles, publicDirectoryFiles, staticDirectoryFiles } =
|
||||||
await getStaticFiles(entryPath, entryDirectory, outputDirectory);
|
await getStaticFiles(entryPath, entryDirectory, outputDirectory);
|
||||||
|
|
||||||
const notFoundPreviewRoutes: RouteWithSrc[] = [];
|
|
||||||
|
|
||||||
if (prerenderManifest.notFoundRoutes?.length > 0 && canUsePreviewMode) {
|
|
||||||
// we combine routes into one src here to reduce the number of needed
|
|
||||||
// routes since only the status is being modified and we don't want
|
|
||||||
// to exceed the routes limit
|
|
||||||
const starterRouteSrc = `^${
|
|
||||||
entryDirectory !== '.'
|
|
||||||
? `${path.posix.join('/', entryDirectory)}()`
|
|
||||||
: '()'
|
|
||||||
}`;
|
|
||||||
let currentRouteSrc = starterRouteSrc;
|
|
||||||
|
|
||||||
const pushRoute = (src: string) => {
|
|
||||||
notFoundPreviewRoutes.push({
|
|
||||||
src,
|
|
||||||
missing: [
|
|
||||||
{
|
|
||||||
type: 'cookie',
|
|
||||||
key: '__prerender_bypass',
|
|
||||||
value: prerenderManifest.bypassToken || undefined,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'cookie',
|
|
||||||
key: '__next_preview_data',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
status: 404,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
for (let i = 0; i < prerenderManifest.notFoundRoutes.length; i++) {
|
|
||||||
const route = prerenderManifest.notFoundRoutes[i];
|
|
||||||
const isLastRoute = i === prerenderManifest.notFoundRoutes.length - 1;
|
|
||||||
|
|
||||||
if (prerenderManifest.staticRoutes[route]?.initialRevalidate === false) {
|
|
||||||
if (currentRouteSrc.length + route.length + 1 >= 4000) {
|
|
||||||
pushRoute(currentRouteSrc);
|
|
||||||
currentRouteSrc = starterRouteSrc;
|
|
||||||
}
|
|
||||||
// add to existing route src if src length limit isn't reached
|
|
||||||
currentRouteSrc = `${currentRouteSrc.substring(
|
|
||||||
0,
|
|
||||||
currentRouteSrc.length - 1
|
|
||||||
)}${
|
|
||||||
currentRouteSrc[currentRouteSrc.length - 2] === '(' ? '' : '|'
|
|
||||||
}${route}/?)`;
|
|
||||||
|
|
||||||
if (isLastRoute) {
|
|
||||||
pushRoute(currentRouteSrc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalizeNextDataRoute = (isOverride = false) => {
|
const normalizeNextDataRoute = (isOverride = false) => {
|
||||||
return isNextDataServerResolving
|
return isNextDataServerResolving
|
||||||
? [
|
? [
|
||||||
@@ -1329,10 +1315,6 @@ export async function serverBuild({
|
|||||||
|
|
||||||
...beforeFilesRewrites,
|
...beforeFilesRewrites,
|
||||||
|
|
||||||
// ensure prerender's for notFound: true static routes
|
|
||||||
// have 404 status code when not in preview mode
|
|
||||||
...notFoundPreviewRoutes,
|
|
||||||
|
|
||||||
// Make sure to 404 for the /404 path itself
|
// Make sure to 404 for the /404 path itself
|
||||||
...(i18n
|
...(i18n
|
||||||
? [
|
? [
|
||||||
@@ -1647,18 +1629,6 @@ export async function serverBuild({
|
|||||||
continue: true,
|
continue: true,
|
||||||
important: true,
|
important: true,
|
||||||
},
|
},
|
||||||
...(appDir
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
src: path.posix.join('/', entryDirectory, '/(.*).rsc$'),
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/octet-stream',
|
|
||||||
},
|
|
||||||
continue: true,
|
|
||||||
important: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
|
|
||||||
// TODO: remove below workaround when `/` is allowed to be output
|
// TODO: remove below workaround when `/` is allowed to be output
|
||||||
// different than `/index`
|
// different than `/index`
|
||||||
|
|||||||
@@ -748,6 +748,7 @@ export async function createPseudoLayer(files: {
|
|||||||
|
|
||||||
interface CreateLambdaFromPseudoLayersOptions extends LambdaOptionsWithFiles {
|
interface CreateLambdaFromPseudoLayersOptions extends LambdaOptionsWithFiles {
|
||||||
layers: PseudoLayer[];
|
layers: PseudoLayer[];
|
||||||
|
isStreaming?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// measured with 1, 2, 5, 10, and `os.cpus().length || 5`
|
// measured with 1, 2, 5, 10, and `os.cpus().length || 5`
|
||||||
@@ -757,6 +758,7 @@ const createLambdaSema = new Sema(1);
|
|||||||
export async function createLambdaFromPseudoLayers({
|
export async function createLambdaFromPseudoLayers({
|
||||||
files: baseFiles,
|
files: baseFiles,
|
||||||
layers,
|
layers,
|
||||||
|
isStreaming,
|
||||||
...lambdaOptions
|
...lambdaOptions
|
||||||
}: CreateLambdaFromPseudoLayersOptions) {
|
}: CreateLambdaFromPseudoLayersOptions) {
|
||||||
await createLambdaSema.acquire();
|
await createLambdaSema.acquire();
|
||||||
@@ -791,6 +793,11 @@ export async function createLambdaFromPseudoLayers({
|
|||||||
|
|
||||||
return new NodejsLambda({
|
return new NodejsLambda({
|
||||||
...lambdaOptions,
|
...lambdaOptions,
|
||||||
|
...(isStreaming
|
||||||
|
? {
|
||||||
|
experimentalResponseStreaming: true,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
files,
|
files,
|
||||||
shouldAddHelpers: false,
|
shouldAddHelpers: false,
|
||||||
shouldAddSourcemapSupport: false,
|
shouldAddSourcemapSupport: false,
|
||||||
@@ -1273,6 +1280,7 @@ export type LambdaGroup = {
|
|||||||
pages: string[];
|
pages: string[];
|
||||||
memory?: number;
|
memory?: number;
|
||||||
maxDuration?: number;
|
maxDuration?: number;
|
||||||
|
isStreaming?: boolean;
|
||||||
isPrerenders?: boolean;
|
isPrerenders?: boolean;
|
||||||
pseudoLayer: PseudoLayer;
|
pseudoLayer: PseudoLayer;
|
||||||
pseudoLayerBytes: number;
|
pseudoLayerBytes: number;
|
||||||
@@ -1601,16 +1609,19 @@ export const onPrerenderRouteInitial = (
|
|||||||
nonLambdaSsgPages: Set<string>,
|
nonLambdaSsgPages: Set<string>,
|
||||||
routeKey: string,
|
routeKey: string,
|
||||||
hasPages404: boolean,
|
hasPages404: boolean,
|
||||||
routesManifest?: RoutesManifest
|
routesManifest?: RoutesManifest,
|
||||||
|
appDir?: string | null
|
||||||
) => {
|
) => {
|
||||||
let static404Page: string | undefined;
|
let static404Page: string | undefined;
|
||||||
let static500Page: string | undefined;
|
let static500Page: string | undefined;
|
||||||
|
|
||||||
// Get the route file as it'd be mounted in the builder output
|
// Get the route file as it'd be mounted in the builder output
|
||||||
const pr = prerenderManifest.staticRoutes[routeKey];
|
const pr = prerenderManifest.staticRoutes[routeKey];
|
||||||
const { initialRevalidate, srcRoute } = pr;
|
const { initialRevalidate, srcRoute, dataRoute } = pr;
|
||||||
const route = srcRoute || routeKey;
|
const route = srcRoute || routeKey;
|
||||||
|
|
||||||
|
const isAppPathRoute = appDir && dataRoute?.endsWith('.rsc');
|
||||||
|
|
||||||
const routeNoLocale = routesManifest?.i18n
|
const routeNoLocale = routesManifest?.i18n
|
||||||
? normalizeLocalePath(routeKey, routesManifest.i18n.locales).pathname
|
? normalizeLocalePath(routeKey, routesManifest.i18n.locales).pathname
|
||||||
: routeKey;
|
: routeKey;
|
||||||
@@ -1626,6 +1637,9 @@ export const onPrerenderRouteInitial = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
// App paths must be Prerenders to ensure Vary header is
|
||||||
|
// correctly added
|
||||||
|
!isAppPathRoute &&
|
||||||
initialRevalidate === false &&
|
initialRevalidate === false &&
|
||||||
(!canUsePreviewMode || (hasPages404 && routeNoLocale === '/404')) &&
|
(!canUsePreviewMode || (hasPages404 && routeNoLocale === '/404')) &&
|
||||||
!prerenderManifest.fallbackRoutes[route] &&
|
!prerenderManifest.fallbackRoutes[route] &&
|
||||||
@@ -1836,14 +1850,26 @@ export const onPrerenderRoute =
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const outputPathPage = normalizeIndexOutput(
|
if (isAppPathRoute) {
|
||||||
path.posix.join(entryDirectory, routeFileNoExt),
|
// for literal index routes we need to append an additional /index
|
||||||
isServerMode
|
// due to the proxy's normalizing for /index routes
|
||||||
);
|
if (routeKey !== '/index' && routeKey.endsWith('/index')) {
|
||||||
|
routeKey = `${routeKey}/index`;
|
||||||
|
routeFileNoExt = routeKey;
|
||||||
|
origRouteFileNoExt = routeKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let outputPathPage = path.posix.join(entryDirectory, routeFileNoExt);
|
||||||
|
|
||||||
|
if (!isAppPathRoute) {
|
||||||
|
outputPathPage = normalizeIndexOutput(outputPathPage, isServerMode);
|
||||||
|
}
|
||||||
const outputPathPageOrig = path.posix.join(
|
const outputPathPageOrig = path.posix.join(
|
||||||
entryDirectory,
|
entryDirectory,
|
||||||
origRouteFileNoExt
|
origRouteFileNoExt
|
||||||
);
|
);
|
||||||
|
|
||||||
let lambda: undefined | Lambda;
|
let lambda: undefined | Lambda;
|
||||||
let outputPathData = path.posix.join(entryDirectory, dataRoute);
|
let outputPathData = path.posix.join(entryDirectory, dataRoute);
|
||||||
|
|
||||||
@@ -1887,7 +1913,7 @@ export const onPrerenderRoute =
|
|||||||
lambda = lambdas[outputSrcPathPage];
|
lambda = lambdas[outputSrcPathPage];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNotFound && initialRevalidate === false) {
|
if (!isAppPathRoute && !isNotFound && initialRevalidate === false) {
|
||||||
if (htmlFsRef == null || jsonFsRef == null) {
|
if (htmlFsRef == null || jsonFsRef == null) {
|
||||||
throw new NowBuildError({
|
throw new NowBuildError({
|
||||||
code: 'NEXT_HTMLFSREF_JSONFSREF',
|
code: 'NEXT_HTMLFSREF_JSONFSREF',
|
||||||
@@ -1973,6 +1999,19 @@ export const onPrerenderRoute =
|
|||||||
fallback: htmlFsRef,
|
fallback: htmlFsRef,
|
||||||
group: prerenderGroup,
|
group: prerenderGroup,
|
||||||
bypassToken: prerenderManifest.bypassToken,
|
bypassToken: prerenderManifest.bypassToken,
|
||||||
|
...(isNotFound
|
||||||
|
? {
|
||||||
|
initialStatus: 404,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
|
||||||
|
...(isAppPathRoute
|
||||||
|
? {
|
||||||
|
initialHeaders: {
|
||||||
|
vary: '__rsc__, __next_router_state_tree__, __next_router_prefetch__',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
prerenders[outputPathData] = new Prerender({
|
prerenders[outputPathData] = new Prerender({
|
||||||
expiration: initialRevalidate,
|
expiration: initialRevalidate,
|
||||||
@@ -1981,6 +2020,21 @@ export const onPrerenderRoute =
|
|||||||
fallback: jsonFsRef,
|
fallback: jsonFsRef,
|
||||||
group: prerenderGroup,
|
group: prerenderGroup,
|
||||||
bypassToken: prerenderManifest.bypassToken,
|
bypassToken: prerenderManifest.bypassToken,
|
||||||
|
|
||||||
|
...(isNotFound
|
||||||
|
? {
|
||||||
|
initialStatus: 404,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
|
||||||
|
...(isAppPathRoute
|
||||||
|
? {
|
||||||
|
initialHeaders: {
|
||||||
|
'content-type': 'application/octet-stream',
|
||||||
|
vary: '__rsc__, __next_router_state_tree__, __next_router_prefetch__',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
++prerenderGroup;
|
++prerenderGroup;
|
||||||
@@ -2391,6 +2445,12 @@ export async function getMiddlewareBundle({
|
|||||||
shortPath.replace(/^app\//, '').replace(/(^|\/)page$/, '') || 'index';
|
shortPath.replace(/^app\//, '').replace(/(^|\/)page$/, '') || 'index';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (routesManifest?.basePath) {
|
||||||
|
shortPath = path.posix
|
||||||
|
.join(routesManifest.basePath, shortPath)
|
||||||
|
.replace(/^\//, '');
|
||||||
|
}
|
||||||
|
|
||||||
worker.edgeFunction.name = shortPath;
|
worker.edgeFunction.name = shortPath;
|
||||||
source.edgeFunctions[shortPath] = worker.edgeFunction;
|
source.edgeFunctions[shortPath] = worker.edgeFunction;
|
||||||
|
|
||||||
|
|||||||
7
packages/next/test/fixtures/00-app-dir-static/app/(newroot)/dashboard/another/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-static/app/(newroot)/dashboard/another/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function AnotherPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from newroot/dashboard/another</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
10
packages/next/test/fixtures/00-app-dir-static/app/(newroot)/layout.js
vendored
Normal file
10
packages/next/test/fixtures/00-app-dir-static/app/(newroot)/layout.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export default function Root({ children }) {
|
||||||
|
return (
|
||||||
|
<html className="this-is-another-document-html">
|
||||||
|
<head>
|
||||||
|
<title>{`hello world`}</title>
|
||||||
|
</head>
|
||||||
|
<body className="this-is-another-document-body">{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-static/app/(rootonly)/dashboard/changelog/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-static/app/(rootonly)/dashboard/changelog/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function ChangelogPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/dashboard/changelog</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-static/app/(rootonly)/dashboard/hello/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-static/app/(rootonly)/dashboard/hello/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function HelloPage(props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/dashboard/rootonly/hello</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
20
packages/next/test/fixtures/00-app-dir-static/app/client-component-route/page.js
vendored
Normal file
20
packages/next/test/fixtures/00-app-dir-static/app/client-component-route/page.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
import style from './style.module.css';
|
||||||
|
import './style.css';
|
||||||
|
|
||||||
|
export default function ClientComponentRoute() {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
useEffect(() => {
|
||||||
|
setCount(1);
|
||||||
|
}, [count]);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className={style.red}>
|
||||||
|
hello from app/client-component-route. <b>count: {count}</b>
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
3
packages/next/test/fixtures/00-app-dir-static/app/client-component-route/style.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-static/app/client-component-route/style.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
b {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
3
packages/next/test/fixtures/00-app-dir-static/app/client-component-route/style.module.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-static/app/client-component-route/style.module.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.red {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
20
packages/next/test/fixtures/00-app-dir-static/app/client-nested/layout.js
vendored
Normal file
20
packages/next/test/fixtures/00-app-dir-static/app/client-nested/layout.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
import styles from './style.module.css';
|
||||||
|
import './style.css';
|
||||||
|
|
||||||
|
export default function ClientNestedLayout({ children }) {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
useEffect(() => {
|
||||||
|
setCount(1);
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1 className={styles.red}>Client Nested. Count: {count}</h1>
|
||||||
|
<button onClick={() => setCount(count + 1)}>{count}</button>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
packages/next/test/fixtures/00-app-dir-static/app/client-nested/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-static/app/client-nested/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function ClientPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>hello from app/client-nested</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
3
packages/next/test/fixtures/00-app-dir-static/app/client-nested/style.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-static/app/client-nested/style.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
button {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
3
packages/next/test/fixtures/00-app-dir-static/app/client-nested/style.module.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-static/app/client-nested/style.module.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.red {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user