Compare commits

..

3 Commits

Author SHA1 Message Date
Malte Ubl
6b833ee56d Add error handling 2023-01-11 11:20:02 -08:00
Malte Ubl
ed5f2773e7 Update packages/edge/src/response.ts
Co-authored-by: Gal Schlezinger <gal@spitfire.co.il>
2023-01-11 11:13:51 -08:00
Malte Ubl
c2fdc09b18 Implement potentiallyLongRunningResponse helper in @vercel/edge
This helper produces an immediate response, which writes the data once the given promise is resolved.
2023-01-10 15:54:48 -08:00
130 changed files with 17573 additions and 27347 deletions

View File

@@ -6,7 +6,7 @@ Please read our [Code of Conduct](CODE_OF_CONDUCT.md) and follow it in all your
## Local development
This project is configured in a monorepo, where one repository contains multiple npm packages. Dependencies are installed and managed with `pnpm`, not `npm` CLI.
This project is configured in a monorepo, where one repository contains multiple npm packages. Dependencies are installed and managed with `yarn`, not `npm` CLI.
To get started, execute the following:
@@ -14,22 +14,22 @@ To get started, execute the following:
git clone https://github.com/vercel/vercel
cd vercel
corepack enable
pnpm install
pnpm bootstrap
pnpm build
pnpm lint
pnpm test-unit
yarn install
yarn bootstrap
yarn build
yarn lint
yarn test-unit
```
Make sure all the tests pass before making changes.
### Running Vercel CLI Changes
You can use `pnpm dev` from the `cli` package to invoke Vercel CLI with local changes:
You can use `yarn dev` from the `cli` package to invoke Vercel CLI with local changes:
```
cd ./packages/cli
pnpm dev <cli-commands...>
yarn dev <cli-commands...>
```
See [CLI Local Development](../packages/cli#local-development) for more details.
@@ -39,7 +39,7 @@ See [CLI Local Development](../packages/cli#local-development) for more details.
Once you are done with your changes (we even suggest doing it along the way), make sure all the tests still pass by running:
```
pnpm test-unit
yarn test-unit
```
from the root of the project.
@@ -102,7 +102,7 @@ When you run this script, you'll see all the imported files. If anything file is
Sometimes you want to test changes to a Builder against an existing project, maybe with `vercel dev` or actual deployment. You can avoid publishing every Builder change to npm by uploading the Builder as a tarball.
1. Change directory to the desired Builder `cd ./packages/node`
2. Run `pnpm build` to compile typescript and other build steps
2. Run `yarn build` to compile typescript and other build steps
3. Run `npm pack` to create a tarball file
4. Run `vercel *.tgz` to upload the tarball file and get a URL
5. Edit any existing `vercel.json` project and replace `use` with the URL

View File

@@ -47,22 +47,20 @@ jobs:
uses: actions/cache@v3
with:
path: '**/node_modules'
key: pnpm-${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: pnpm-${{ matrix.os }}-${{ matrix.node }}
- name: install pnpm@7.24.2
run: npm i -g pnpm@7.24.2
key: yarn-${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('yarn.lock') }}
restore-keys: yarn-${{ matrix.os }}-${{ matrix.node }}
- name: Install
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
run: pnpm install
run: yarn install --check-files --frozen-lockfile --network-timeout 1000000
- name: Build
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
run: pnpm build
run: yarn build
env:
GA_TRACKING_ID: ${{ secrets.GA_TRACKING_ID }}
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
- name: Publish
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
run: pnpm publish-from-github
run: yarn publish-from-github
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }}
GA_TRACKING_ID: ${{ secrets.GA_TRACKING_ID }}

View File

@@ -41,13 +41,11 @@ jobs:
- uses: actions/cache@v3
with:
path: '**/node_modules'
key: pnpm-${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: pnpm-${{ matrix.os }}-${{ matrix.node }}
- name: install pnpm@7.24.2
run: npm i -g pnpm@7.24.2
- run: pnpm install
- run: pnpm run build
- run: pnpm test-integration-cli
key: yarn-${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('yarn.lock') }}
restore-keys: yarn-${{ matrix.os }}-${{ matrix.node }}
- run: yarn install --network-timeout 1000000 --frozen-lockfile
- run: yarn run build
- run: yarn test-integration-cli
env:
VERCEL_TEST_TOKEN: ${{ secrets.VERCEL_TEST_TOKEN }}
VERCEL_TEST_REGISTRATION_URL: ${{ secrets.VERCEL_TEST_REGISTRATION_URL }}

View File

@@ -41,16 +41,14 @@ jobs:
- uses: actions/cache@v3
with:
path: '**/node_modules'
key: pnpm-${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: pnpm-${{ matrix.os }}-${{ matrix.node }}
- name: install pnpm@7.24.2
run: npm i -g pnpm@7.24.2
- run: pnpm install
- run: pnpm run build
- run: pnpm run lint
key: yarn-${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('yarn.lock') }}
restore-keys: yarn-${{ matrix.os }}-${{ matrix.node }}
- run: yarn install --network-timeout 1000000 --frozen-lockfile
- run: yarn run build
- run: yarn run lint
if: matrix.os == 'ubuntu-latest' && matrix.node == 14 # only run lint once
- run: pnpm run test-unit
- run: pnpm -C packages/cli run coverage
- run: yarn run test-unit
- run: yarn workspace vercel run coverage
if: matrix.os == 'ubuntu-latest' && matrix.node == 14 # only run coverage once
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -39,11 +39,9 @@ jobs:
- uses: actions/cache@v3
with:
path: '**/node_modules'
key: pnpm-${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: pnpm-${{ matrix.os }}-${{ matrix.node }}
- name: install pnpm@7.24.2
run: npm i -g pnpm@7.24.2
- run: pnpm install
key: yarn-${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('yarn.lock') }}
restore-keys: yarn-${{ matrix.os }}-${{ matrix.node }}
- run: yarn install --network-timeout 1000000 --frozen-lockfile
- id: set-tests
run: |
TESTS_ARRAY=$(node utils/chunk-tests.js $SCRIPT_NAME)
@@ -82,17 +80,14 @@ jobs:
- uses: actions/cache@v3
with:
path: '**/node_modules'
key: pnpm-${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: pnpm-${{ matrix.os }}-${{ matrix.node }}
key: yarn-${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('yarn.lock') }}
restore-keys: yarn-${{ matrix.os }}-${{ matrix.node }}
- name: Install Hugo
if: matrix.runner == 'macos-latest'
run: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/cli/test/dev/fixtures/08-hugo/
- name: install pnpm@7.24.2
run: npm i -g pnpm@7.24.2
- run: pnpm install
- run: yarn install --network-timeout 1000000
- name: Build ${{matrix.packageName}} and all its dependencies
run: node utils/gen.js && node_modules/.bin/turbo run build --cache-dir=".turbo" --scope=${{matrix.packageName}} --include-dependencies --no-deps

View File

@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
pnpm pre-commit
yarn pre-commit

5
.npmrc
View File

@@ -1,5 +0,0 @@
save-exact=true
hoist-pattern[]=!"**/@types/**"
hoist-pattern[]=!"**/typedoc"
hoist-pattern[]=!"**/typedoc-plugin-markdown"
hoist-pattern[]=!"**/typedoc-plugin-mdn-links"

1
.yarnrc Normal file
View File

@@ -0,0 +1 @@
save-prefix ""

View File

@@ -33,9 +33,9 @@ For details on how to use Vercel, check out our [documentation](https://vercel.c
## Contributing
This project uses [pnpm](https://pnpm.io/) to install dependencies and run scripts.
This project uses [yarn](https://yarnpkg.com/) to install dependencies and run scripts.
You can use the `dev` script to run local changes as if you were invoking Vercel CLI. For example, `vercel deploy --cwd=/path/to/project` could be run with local changes with `pnpm dev deploy --cwd=/path/to/project`.
You can use the `dev` script to run local changes as if you were invoking Vercel CLI. For example, `vercel deploy --cwd=/path/to/project` could be run with local changes with `yarn dev deploy --cwd=/path/to/project`.
See the [Contributing Guidelines](./.github/CONTRIBUTING.md) for more details.

View File

@@ -13,8 +13,6 @@ function initSentry() {
sentryInitDone = true;
init({
// Cannot figure out whats going wrong here. VSCode resolves this fine. But when we build it blows up.
// @ts-ignore
dsn: assertEnv('SENTRY_DSN'),
environment: process.env.NODE_ENV || 'production',
release: `${serviceName}`,

View File

@@ -4,7 +4,9 @@
"version": "0.0.0",
"description": "API for the vercel/vercel repo",
"main": "index.js",
"scripts": {},
"scripts": {
"//TODO": "We should add this pkg to yarn workspaces"
},
"dependencies": {
"@sentry/node": "5.11.1",
"got": "10.2.1",
@@ -14,9 +16,9 @@
"unzip-stream": "0.3.0"
},
"devDependencies": {
"@types/node": "16.18.11",
"@types/node": "14.18.33",
"@types/node-fetch": "2.5.4",
"@vercel/node": "workspace:*",
"typescript": "4.3.4"
"@vercel/node": "1.9.0",
"typescript": "3.9.6"
}
}

View File

@@ -12,5 +12,5 @@
"resolveJsonModule": true,
"isolatedModules": true
},
"include": ["examples", "frameworks.ts", "_lib"]
"include": ["examples", "frameworks.ts"]
}

524
api/yarn.lock Normal file
View File

@@ -0,0 +1,524 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@sentry/apm@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/apm/-/apm-5.11.1.tgz#cc89fa4150056fbf009f92eca94fccc3980db34e"
integrity sha512-4iZH11p/7w9IMLT9hqNY1+EqLESltiIoF6/YsbpK93sXWGEs8VQ83IuvGuKWxajvHgDmj4ND0TxIliTsYqTqFw==
dependencies:
"@sentry/browser" "5.11.1"
"@sentry/hub" "5.11.1"
"@sentry/minimal" "5.11.1"
"@sentry/types" "5.11.0"
"@sentry/utils" "5.11.1"
tslib "^1.9.3"
"@sentry/browser@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.11.1.tgz#337ffcb52711b23064c847a07629e966f54a5ebb"
integrity sha512-oqOX/otmuP92DEGRyZeBuQokXdeT9HQRxH73oqIURXXNLMP3PWJALSb4HtT4AftEt/2ROGobZLuA4TaID6My/Q==
dependencies:
"@sentry/core" "5.11.1"
"@sentry/types" "5.11.0"
"@sentry/utils" "5.11.1"
tslib "^1.9.3"
"@sentry/core@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.11.1.tgz#9e2da485e196ae32971545c1c49ee6fe719930e2"
integrity sha512-BpvPosVNT20Xso4gAV54Lu3KqDmD20vO63HYwbNdST5LUi8oYV4JhvOkoBraPEM2cbBwQvwVcFdeEYKk4tin9A==
dependencies:
"@sentry/hub" "5.11.1"
"@sentry/minimal" "5.11.1"
"@sentry/types" "5.11.0"
"@sentry/utils" "5.11.1"
tslib "^1.9.3"
"@sentry/hub@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.11.1.tgz#ddcb865563fae53852d405885c46b4c6de68a91b"
integrity sha512-ucKprYCbGGLLjVz4hWUqHN9KH0WKUkGf5ZYfD8LUhksuobRkYVyig0ZGbshECZxW5jcDTzip4Q9Qimq/PkkXBg==
dependencies:
"@sentry/types" "5.11.0"
"@sentry/utils" "5.11.1"
tslib "^1.9.3"
"@sentry/minimal@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.11.1.tgz#0e705d01a567282d8fbbda2aed848b4974cc3cec"
integrity sha512-HK8zs7Pgdq7DsbZQTThrhQPrJsVWzz7MaluAbQA0rTIAJ3TvHKQpsVRu17xDpjZXypqWcKCRsthDrC4LxDM1Bg==
dependencies:
"@sentry/hub" "5.11.1"
"@sentry/types" "5.11.0"
tslib "^1.9.3"
"@sentry/node@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.11.1.tgz#2a9c18cd1209cfdf7a69b9d91303413149d2c910"
integrity sha512-FbJs0blJ36gEzE0rc2yBfA/KE+kXOLl8MUfFTcyJCBdCGF8XMETDCmgINnJ4TyBUJviwKoPw2TCk9TL2pa/A1w==
dependencies:
"@sentry/apm" "5.11.1"
"@sentry/core" "5.11.1"
"@sentry/hub" "5.11.1"
"@sentry/types" "5.11.0"
"@sentry/utils" "5.11.1"
cookie "^0.3.1"
https-proxy-agent "^4.0.0"
lru_map "^0.3.3"
tslib "^1.9.3"
"@sentry/types@5.11.0":
version "5.11.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.11.0.tgz#40f0f3174362928e033ddd9725d55e7c5cb7c5b6"
integrity sha512-1Uhycpmeo1ZK2GLvrtwZhTwIodJHcyIS6bn+t4IMkN9MFoo6ktbAfhvexBDW/IDtdLlCGJbfm8nIZerxy0QUpg==
"@sentry/utils@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.11.1.tgz#aa19fcc234cf632257b2281261651d2fac967607"
integrity sha512-O0Zl4R2JJh8cTkQ8ZL2cDqGCmQdpA5VeXpuBbEl1v78LQPkBDISi35wH4mKmLwMsLBtTVpx2UeUHBj0KO5aLlA==
dependencies:
"@sentry/types" "5.11.0"
tslib "^1.9.3"
"@sindresorhus/is@^1.0.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-1.2.0.tgz#63ce3638cb85231f3704164c90a18ef816da3fb7"
integrity sha512-mwhXGkRV5dlvQc4EgPDxDxO6WuMBVymGFd1CA+2Y+z5dG9MNspoQ+AWjl/Ld1MnpCL8AKbosZlDVohqcIwuWsw==
"@szmarczak/http-timer@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.0.tgz#309789ccb7842ff1e41848cf43da587f78068836"
integrity sha512-3yoXv8OtGr/r3R5gaWWNQ3VUoQ5G3Gmo8DXX95V14ZVvE2b7Pj6Ide9uIDON8ym4D/ItyfL9ejohYUPqOyvRXw==
dependencies:
defer-to-connect "^1.1.1"
"@types/cacheable-request@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976"
integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==
dependencies:
"@types/http-cache-semantics" "*"
"@types/keyv" "*"
"@types/node" "*"
"@types/responselike" "*"
"@types/http-cache-semantics@*":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a"
integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==
"@types/keyv@*":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7"
integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==
dependencies:
"@types/node" "*"
"@types/node-fetch@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.4.tgz#5245b6d8841fc3a6208b82291119bc11c4e0ce44"
integrity sha512-Oz6id++2qAOFuOlE1j0ouk1dzl3mmI1+qINPNBhi9nt/gVOz0G+13Ao6qjhdF0Ys+eOkhu6JnFmt38bR3H0POQ==
dependencies:
"@types/node" "*"
"@types/node@*", "@types/node@13.1.4":
version "13.1.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.4.tgz#4cfd90175a200ee9b02bd6b1cd19bc349741607e"
integrity sha512-Lue/mlp2egZJoHXZr4LndxDAd7i/7SQYhV0EjWfb/a4/OZ6tuVwMCVPiwkU5nsEipxEf7hmkSU7Em5VQ8P5NGA==
"@types/responselike@*":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
dependencies:
"@types/node" "*"
"@vercel/node@1.9.0":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@vercel/node/-/node-1.9.0.tgz#6b64f3b9a962ddb1089276fad00f441a1f4b9cf0"
integrity sha512-Vk/ZpuY4Cdc8oUwBi/kf8qETRaJb/KYdFddVkLuS10QwA0yJx+RQ11trhZ1KFUdc27aBr5S2k8/dDxK8sLr+IA==
dependencies:
"@types/node" "*"
ts-node "8.9.1"
typescript "3.9.3"
agent-base@5:
version "5.1.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
binary@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79"
integrity sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=
dependencies:
buffers "~0.1.1"
chainsaw "~0.1.0"
bl@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==
dependencies:
readable-stream "^3.0.1"
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
buffers@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb"
integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s=
cacheable-lookup@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-0.2.1.tgz#f474ae2c686667d7ea08c43409ad31b2b31b26c2"
integrity sha512-BQ8MRjxJASEq2q+w0SusPU3B054gS278K8sj58QCLMZIso5qG05+MdCdmXxuyVlfvI8h4bPsNOavVUauVCGxrg==
dependencies:
keyv "^3.1.0"
cacheable-request@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.0.tgz#12421aa084e943ec81eac8c93e56af90c624788a"
integrity sha512-UVG4gMn3WjnAeFBBx7RFoprgOANIAkMwN5Dta6ONmfSwrCxfm0Ip7g0mIBxIRJZX9aDsoID0Ry3dU5Pr0csKKA==
dependencies:
clone-response "^1.0.2"
get-stream "^5.1.0"
http-cache-semantics "^4.0.0"
keyv "^3.0.0"
lowercase-keys "^2.0.0"
normalize-url "^4.1.0"
responselike "^2.0.0"
chainsaw@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98"
integrity sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=
dependencies:
traverse ">=0.3.0 <0.4"
chownr@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142"
integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==
clone-response@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
dependencies:
mimic-response "^1.0.0"
cookie@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
debug@4:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
dependencies:
ms "^2.1.1"
decompress-response@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-5.0.0.tgz#7849396e80e3d1eba8cb2f75ef4930f76461cb0f"
integrity sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==
dependencies:
mimic-response "^2.0.0"
defer-to-connect@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.1.tgz#88ae694b93f67b81815a2c8c769aef6574ac8f2f"
integrity sha512-J7thop4u3mRTkYRQ+Vpfwy2G5Ehoy82I14+14W4YMDLKdWloI9gSzRbV30s/NckQGVJtPkWNcW4oMAUigTdqiQ==
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
duplexer3@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
fs-constants@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
get-stream@^5.0.0, get-stream@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
dependencies:
pump "^3.0.0"
got@10.2.1:
version "10.2.1"
resolved "https://registry.yarnpkg.com/got/-/got-10.2.1.tgz#7087485482fb31aa6e6399fd493dd04639da117b"
integrity sha512-IQX//hGm5oLjUj743GJG30U2RzjS58ZlhQQjwQXjsyR50TTD+etVMHlMEbNxYJGWVFa0ASgDVhRkAvQPe6M9iQ==
dependencies:
"@sindresorhus/is" "^1.0.0"
"@szmarczak/http-timer" "^4.0.0"
"@types/cacheable-request" "^6.0.1"
cacheable-lookup "^0.2.1"
cacheable-request "^7.0.0"
decompress-response "^5.0.0"
duplexer3 "^0.1.4"
get-stream "^5.0.0"
lowercase-keys "^2.0.0"
mimic-response "^2.0.0"
p-cancelable "^2.0.0"
responselike "^2.0.0"
to-readable-stream "^2.0.0"
type-fest "^0.8.0"
http-cache-semantics@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5"
integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==
https-proxy-agent@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b"
integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==
dependencies:
agent-base "5"
debug "4"
inherits@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
json-buffer@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
keyv@^3.0.0, keyv@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
dependencies:
json-buffer "3.0.0"
lowercase-keys@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
lru_map@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd"
integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=
make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
mimic-response@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.0.0.tgz#996a51c60adf12cb8a87d7fb8ef24c2f3d5ebb46"
integrity sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ==
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
mkdirp@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
dependencies:
minimist "0.0.8"
ms@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
node-fetch@2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
normalize-url@^4.1.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
p-cancelable@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e"
integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==
parse-github-url@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/parse-github-url/-/parse-github-url-1.0.2.tgz#242d3b65cbcdda14bb50439e3242acf6971db395"
integrity sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
readable-stream@^3.0.1, readable-stream@^3.1.1:
version "3.4.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc"
integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
responselike@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
dependencies:
lowercase-keys "^2.0.0"
safe-buffer@~5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
source-map-support@^0.5.17:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
tar-fs@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad"
integrity sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==
dependencies:
chownr "^1.1.1"
mkdirp "^0.5.1"
pump "^3.0.0"
tar-stream "^2.0.0"
tar-stream@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3"
integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==
dependencies:
bl "^3.0.0"
end-of-stream "^1.4.1"
fs-constants "^1.0.0"
inherits "^2.0.3"
readable-stream "^3.1.1"
to-readable-stream@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-2.1.0.tgz#82880316121bea662cdc226adb30addb50cb06e8"
integrity sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==
"traverse@>=0.3.0 <0.4":
version "0.3.9"
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9"
integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=
ts-node@8.9.1:
version "8.9.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.9.1.tgz#2f857f46c47e91dcd28a14e052482eb14cfd65a5"
integrity sha512-yrq6ODsxEFTLz0R3BX2myf0WBCSQh9A+py8PBo1dCzWIOcvisbyH6akNKqDHMgXePF2kir5mm5JXJTH3OUJYOQ==
dependencies:
arg "^4.1.0"
diff "^4.0.1"
make-error "^1.1.1"
source-map-support "^0.5.17"
yn "3.1.1"
tslib@^1.9.3:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
type-fest@^0.8.0:
version "0.8.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
typescript@3.9.3:
version "3.9.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a"
integrity sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==
typescript@3.9.6:
version "3.9.6"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a"
integrity sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==
unzip-stream@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/unzip-stream/-/unzip-stream-0.3.0.tgz#c30c054cd6b0d64b13a23cd3ece911eb0b2b52d8"
integrity sha512-NG1h/MdGIX3HzyqMjyj1laBCmlPYhcO4xEy7gEqqzGiSLw7XqDQCnY4nYSn5XSaH8mQ6TFkaujrO8d/PIZN85A==
dependencies:
binary "^0.3.0"
mkdirp "^0.5.1"
util-deprecate@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==

View File

@@ -8,8 +8,6 @@ First, run the development server:
npm run dev
# or
yarn dev
# or
pnpm dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

View File

@@ -1,8 +0,0 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -9,10 +9,10 @@
"lint": "next lint"
},
"dependencies": {
"@next/font": "13.1.2",
"eslint": "8.31.0",
"eslint-config-next": "13.1.2",
"next": "13.1.2",
"@next/font": "13.1.1",
"eslint": "8.30.0",
"eslint-config-next": "13.1.1",
"next": "13.1.1",
"react": "18.2.0",
"react-dom": "18.2.0"
}

View File

@@ -1,4 +1,4 @@
import '@/styles/globals.css'
import '../styles/globals.css'
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />

View File

@@ -1,7 +1,7 @@
import Head from 'next/head'
import Image from 'next/image'
import { Inter } from '@next/font/google'
import styles from '@/styles/Home.module.css'
import styles from '../styles/Home.module.css'
const inter = Inter({ subsets: ['latin'] })

View File

@@ -10,7 +10,7 @@
"@remix-run/react": "^1.7.6",
"@remix-run/vercel": "^1.7.6",
"@vercel/analytics": "^0.1.5",
"@vercel/node": "^2.7.0",
"@vercel/node": "^2.6.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
@@ -20,7 +20,7 @@
"@remix-run/serve": "^1.7.6",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9",
"eslint": "^8.28.0",
"eslint": "^8.27.0",
"typescript": "^4.9.3"
},
"engines": {

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@
},
"devDependencies": {
"@sveltejs/adapter-auto": "next",
"@sveltejs/kit": "1.0.0-next.589",
"@sveltejs/kit": "next",
"@types/cookie": "^0.5.1",
"prettier": "^2.6.2",
"prettier-plugin-svelte": "^2.7.0",

View File

@@ -1,5 +1,5 @@
{
"npmClient": "pnpm",
"npmClient": "yarn",
"useWorkspaces": true,
"packages": ["packages/*"],
"command": {

View File

@@ -3,26 +3,30 @@
"version": "0.0.0",
"private": true,
"license": "Apache-2.0",
"packageManager": "pnpm@7.24.2",
"packageManager": "yarn@1.22.19",
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/@types/**",
"**/typedoc",
"**/typedoc-plugin-markdown",
"**/typedoc-plugin-mdn-links"
]
},
"dependencies": {
"lerna": "5.6.2"
"lerna": "3.16.4"
},
"devDependencies": {
"@types/node": "14.18.33",
"@typescript-eslint/eslint-plugin": "5.21.0",
"@typescript-eslint/parser": "5.21.0",
"@vercel/build-utils": "workspace:*",
"@vercel/ncc": "0.24.0",
"@vercel/next": "workspace:*",
"async-retry": "1.2.3",
"buffer-replace": "1.0.0",
"create-svelte": "2.0.1",
"dot": "1.1.3",
"eslint": "8.14.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-jest": "26.1.5",
"execa": "3.2.0",
"fs-extra": "11.1.0",
"husky": "7.0.4",
"jest": "28.0.2",
"json5": "2.1.1",
@@ -30,7 +34,6 @@
"node-fetch": "2.6.7",
"npm-package-arg": "6.1.0",
"prettier": "2.6.2",
"source-map-support": "0.5.12",
"ts-eager": "2.0.2",
"ts-jest": "28.0.5",
"turbo": "1.7.0-canary.9"
@@ -38,15 +41,15 @@
"scripts": {
"lerna": "lerna",
"bootstrap": "lerna bootstrap",
"publish-stable": "echo 'Run `pnpm changelog` for instructions'",
"publish-stable": "echo 'Run `yarn changelog` for instructions'",
"publish-canary": "git checkout main && git pull && lerna version prerelease --preid canary --message \"Publish Canary\" --exact",
"publish-from-github": "./utils/publish.sh",
"changelog": "node utils/changelog.js",
"build": "node utils/gen.js && turbo run build",
"vercel-build": "pnpm build && pnpm 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",
"test": "jest --rootDir=\"test\" --testPathPattern=\"\\.test.js\"",
"test-unit": "pnpm test && node utils/gen.js && turbo run test-unit",
"test-unit": "yarn test && node utils/gen.js && turbo run test-unit",
"test-integration-cli": "node utils/gen.js && turbo run test-integration-cli",
"test-integration-once": "node utils/gen.js && turbo run test-integration-once",
"test-integration-dev": "node utils/gen.js && turbo run test-integration-dev",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "5.8.0",
"version": "5.7.4",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
@@ -13,8 +13,8 @@
"scripts": {
"build": "node build",
"test": "jest --env node --verbose --runInBand --bail",
"test-unit": "pnpm test test/unit.*test.*",
"test-integration-once": "pnpm test test/integration.test.ts"
"test-unit": "yarn test test/unit.*test.*",
"test-integration-once": "yarn test test/integration.test.ts"
},
"devDependencies": {
"@iarna/toml": "2.2.3",
@@ -25,10 +25,8 @@
"@types/glob": "7.2.0",
"@types/jest": "27.4.1",
"@types/js-yaml": "3.12.1",
"@types/minimatch": "^5.1.2",
"@types/ms": "0.7.31",
"@types/multistream": "2.1.1",
"@types/node": "14.18.33",
"@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0",
"@types/yazl": "2.4.2",
@@ -38,10 +36,8 @@
"async-sema": "2.1.4",
"cross-spawn": "6.0.5",
"end-of-stream": "1.4.1",
"execa": "3.2.0",
"fs-extra": "10.0.0",
"glob": "8.0.3",
"ignore": "4.0.6",
"into-stream": "5.0.0",
"js-yaml": "3.13.1",
"minimatch": "3.0.4",

View File

@@ -2,20 +2,15 @@ import path from 'path';
import debug from '../debug';
import FileFsRef from '../file-fs-ref';
import { File, Files, Meta } from '../types';
import { remove, mkdirp, readlink, symlink, chmod } from 'fs-extra';
import { remove, mkdirp, readlink, symlink } from 'fs-extra';
import streamToBuffer from './stream-to-buffer';
export interface DownloadedFiles {
[filePath: string]: FileFsRef;
}
const S_IFDIR = 16384; /* 0040000 directory */
const S_IFLNK = 40960; /* 0120000 symbolic link */
const S_IFMT = 61440; /* 0170000 type of file */
export function isDirectory(mode: number): boolean {
return (mode & S_IFMT) === S_IFDIR;
}
const S_IFLNK = 40960; /* 0120000 symbolic link */
export function isSymbolicLink(mode: number): boolean {
return (mode & S_IFMT) === S_IFLNK;
@@ -51,12 +46,6 @@ export async function downloadFile(
): Promise<FileFsRef> {
const { mode } = file;
if (isDirectory(mode)) {
await mkdirp(fsPath);
await chmod(fsPath, mode);
return FileFsRef.fromFsPath({ mode, fsPath });
}
// If the source is a symlink, try to create it instead of copying the file.
// Note: creating symlinks on Windows requires admin priviliges or symlinks
// enabled in the group policy. We may want to improve the error message.

View File

@@ -15,7 +15,12 @@ export default async function glob(
opts: GlobOptions | string,
mountpoint?: string
): Promise<Record<string, FileFsRef>> {
const options = typeof opts === 'string' ? { cwd: opts } : opts;
let options: GlobOptions;
if (typeof opts === 'string') {
options = { cwd: opts };
} else {
options = opts;
}
if (!options.cwd) {
throw new Error(
@@ -29,18 +34,13 @@ export default async function glob(
const results: Record<string, FileFsRef> = {};
const statCache: Record<string, Stats> = {};
const symlinks: Record<string, boolean | undefined> = {};
const files = await vanillaGlob(pattern, {
...options,
symlinks,
statCache,
stat: true,
dot: true,
});
options.symlinks = {};
options.statCache = statCache;
options.stat = true;
options.dot = true;
const dirs = new Set<string>();
const dirsWithEntries = new Set<string>();
const files = await vanillaGlob(pattern, options);
for (const relativePath of files) {
const fsPath = normalizePath(path.join(options.cwd, relativePath));
@@ -49,20 +49,12 @@ export default async function glob(
stat,
`statCache does not contain value for ${relativePath} (resolved to ${fsPath})`
);
const isSymlink = symlinks[fsPath];
if (isSymlink || stat.isFile() || stat.isDirectory()) {
const isSymlink = options.symlinks![fsPath];
if (isSymlink || stat.isFile()) {
if (isSymlink) {
stat = await lstat(fsPath);
}
// Some bookkeeping to track which directories already have entries within
const dirname = path.dirname(relativePath);
dirsWithEntries.add(dirname);
if (stat.isDirectory()) {
dirs.add(relativePath);
continue;
}
let finalPath = relativePath;
if (mountpoint) {
finalPath = path.join(mountpoint, finalPath);
@@ -72,20 +64,5 @@ export default async function glob(
}
}
// Add empty directory entries
for (const relativePath of dirs) {
if (dirsWithEntries.has(relativePath)) continue;
let finalPath = relativePath;
if (mountpoint) {
finalPath = path.join(mountpoint, finalPath);
}
const fsPath = normalizePath(path.join(options.cwd, relativePath));
const stat = statCache[fsPath];
results[finalPath] = new FileFsRef({ mode: stat.mode, fsPath });
}
return results;
}

View File

@@ -137,9 +137,6 @@ export function execAsync(
child.on('close', (code, signal) => {
if (code === 0 || opts.ignoreNon0Exit) {
return resolve({
// ignoring the next line due to do some Node.js type issue when we removed hoisting of dependencies in https://github.com/vercel/vercel/pull/9198
// should eventually be fixed when this method is remove by https://github.com/vercel/vercel/pull/9200 or we update to Node 16
// @ts-ignore
code,
stdout: Buffer.concat(stdoutList).toString(),
stderr: Buffer.concat(stderrList).toString(),

View File

@@ -8,7 +8,6 @@ import download, {
downloadFile,
DownloadedFiles,
isSymbolicLink,
isDirectory,
} from './fs/download';
import getWriteableDirectory from './fs/get-writable-directory';
import glob, { GlobOptions } from './fs/glob';
@@ -83,7 +82,6 @@ export {
streamToBuffer,
debug,
isSymbolicLink,
isDirectory,
getLambdaOptionsFromFunction,
scanParentDirs,
getIgnoreFilter,

View File

@@ -3,7 +3,7 @@ import Sema from 'async-sema';
import { ZipFile } from 'yazl';
import minimatch from 'minimatch';
import { readlink } from 'fs-extra';
import { isSymbolicLink, isDirectory } from './fs/download';
import { isSymbolicLink } from './fs/download';
import streamToBuffer from './fs/stream-to-buffer';
import type { Files, Config } from './types';
@@ -200,8 +200,6 @@ export async function createZip(files: Files): Promise<Buffer> {
const symlinkTarget = symlinkTargets.get(name);
if (typeof symlinkTarget === 'string') {
zipFile.addBuffer(Buffer.from(symlinkTarget, 'utf8'), name, opts);
} else if (file.mode && isDirectory(file.mode)) {
zipFile.addEmptyDirectory(name, opts);
} else {
const stream = file.toStream();
stream.on('error', reject);

View File

@@ -7,9 +7,6 @@
"dependencies": {
"react": "16.8.0",
"swr": "1.3.0"
},
"engines": {
"node": "16.x"
}
},
"node_modules/js-tokens": {

View File

@@ -1,195 +0,0 @@
import path from 'path';
import fs, { readlink } from 'fs-extra';
import { strict as assert, strictEqual } from 'assert';
import { download, glob, FileBlob } from '../src';
describe('download()', () => {
let warningMessages: string[];
const originalConsoleWarn = console.warn;
beforeEach(() => {
warningMessages = [];
console.warn = m => {
warningMessages.push(m);
};
});
afterEach(() => {
console.warn = originalConsoleWarn;
});
it('should re-create FileFsRef symlinks properly', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = await glob('**', path.join(__dirname, 'symlinks'));
assert.equal(Object.keys(files).length, 4);
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
const files2 = await download(files, outDir);
assert.equal(Object.keys(files2).length, 4);
const [linkStat, linkDirStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'link-dir')),
fs.lstat(path.join(outDir, 'a.txt')),
]);
assert(linkStat.isSymbolicLink());
assert(linkDirStat.isSymbolicLink());
assert(aStat.isFile());
const [linkDirContents, linkTextContents] = await Promise.all([
readlink(path.join(outDir, 'link-dir')),
readlink(path.join(outDir, 'link.txt')),
]);
strictEqual(linkDirContents, 'dir');
strictEqual(linkTextContents, './a.txt');
});
it('should re-create FileBlob symlinks properly', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = {
'a.txt': new FileBlob({
mode: 33188,
contentType: undefined,
data: 'a text',
}),
'dir/b.txt': new FileBlob({
mode: 33188,
contentType: undefined,
data: 'b text',
}),
'link-dir': new FileBlob({
mode: 41453,
contentType: undefined,
data: 'dir',
}),
'link.txt': new FileBlob({
mode: 41453,
contentType: undefined,
data: 'a.txt',
}),
};
strictEqual(Object.keys(files).length, 4);
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
const files2 = await download(files, outDir);
strictEqual(Object.keys(files2).length, 4);
const [linkStat, linkDirStat, aStat, dirStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'link-dir')),
fs.lstat(path.join(outDir, 'a.txt')),
fs.lstat(path.join(outDir, 'dir')),
]);
assert(linkStat.isSymbolicLink());
assert(linkDirStat.isSymbolicLink());
assert(aStat.isFile());
assert(dirStat.isDirectory());
const [linkDirContents, linkTextContents] = await Promise.all([
readlink(path.join(outDir, 'link-dir')),
readlink(path.join(outDir, 'link.txt')),
]);
strictEqual(linkDirContents, 'dir');
strictEqual(linkTextContents, 'a.txt');
});
it('should download symlinks even with incorrect file', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = {
'dir/file.txt': new FileBlob({
mode: 33188,
contentType: undefined,
data: 'file text',
}),
linkdir: new FileBlob({
mode: 41453,
contentType: undefined,
data: 'dir',
}),
'linkdir/file.txt': new FileBlob({
mode: 33188,
contentType: undefined,
data: 'this file should be discarded',
}),
};
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
await fs.mkdirp(outDir);
await download(files, outDir);
const [dir, file, linkdir] = await Promise.all([
fs.lstat(path.join(outDir, 'dir')),
fs.lstat(path.join(outDir, 'dir/file.txt')),
fs.lstat(path.join(outDir, 'linkdir')),
]);
expect(dir.isFile()).toBe(false);
expect(dir.isSymbolicLink()).toBe(false);
expect(file.isFile()).toBe(true);
expect(file.isSymbolicLink()).toBe(false);
expect(linkdir.isSymbolicLink()).toBe(true);
expect(warningMessages).toEqual([
'Warning: file "linkdir/file.txt" is within a symlinked directory "linkdir" and will be ignored',
]);
});
it('should create empty directory entries', async () => {
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
const files = {
'empty-dir': new FileBlob({
mode: 16877, // drwxr-xr-x
contentType: undefined,
data: '',
}),
dir: new FileBlob({
mode: 16877,
contentType: undefined,
data: '',
}),
'dir/subdir': new FileBlob({
mode: 16877,
contentType: undefined,
data: '',
}),
'another/subdir': new FileBlob({
mode: 16895, // drwxrwxrwx
contentType: undefined,
data: '',
}),
};
await download(files, outDir);
for (const [p, f] of Object.entries(files)) {
const stat = await fs.lstat(path.join(outDir, p));
expect(stat.isDirectory()).toEqual(true);
if (process.platform !== 'win32') {
// Don't test Windows since it doesn't support the same permissions
expect(stat.mode).toEqual(f.mode);
}
}
});
});

View File

@@ -1,38 +0,0 @@
import fs from 'fs-extra';
import { join } from 'path';
import { tmpdir } from 'os';
import { glob, isDirectory } from '../src';
describe('glob()', () => {
it('should return entries for empty directories', async () => {
const dir = await fs.mkdtemp(join(tmpdir(), 'build-utils-test'));
try {
await Promise.all([
fs.writeFile(join(dir, 'root.txt'), 'file at the root'),
fs.mkdirp(join(dir, 'empty-dir')),
fs
.mkdirp(join(dir, 'dir-with-file'))
.then(() =>
fs.writeFile(join(dir, 'dir-with-file/data.json'), '{"a":"b"}')
),
fs.mkdirp(join(dir, 'another/subdir')),
]);
const files = await glob('**', dir);
const fileNames = Object.keys(files).sort();
expect(fileNames).toHaveLength(4);
expect(fileNames).toEqual([
'another/subdir',
'dir-with-file/data.json',
'empty-dir',
'root.txt',
]);
expect(isDirectory(files['another/subdir'].mode)).toEqual(true);
expect(isDirectory(files['empty-dir'].mode)).toEqual(true);
expect(isDirectory(files['dir-with-file/data.json'].mode)).toEqual(false);
expect(isDirectory(files['root.txt'].mode)).toEqual(false);
expect(files['dir-with-file']).toBeUndefined();
} finally {
await fs.remove(dir);
}
});
});

View File

@@ -1,97 +0,0 @@
import path from 'path';
import { tmpdir } from 'os';
import fs from 'fs-extra';
import { createZip } from '../src/lambda';
import { FileBlob, glob, spawnAsync } from '../src';
const MODE_DIRECTORY = 16877; /* drwxr-xr-x */
const MODE_FILE = 33188; /* -rw-r--r-- */
describe('Lambda', () => {
it('should create zip file with symlinks', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = await glob('**', path.join(__dirname, 'symlinks'));
expect(Object.keys(files)).toHaveLength(4);
const outFile = path.join(__dirname, 'symlinks.zip');
await fs.remove(outFile);
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
await fs.mkdirp(outDir);
await fs.writeFile(outFile, await createZip(files));
await spawnAsync('unzip', [outFile], { cwd: outDir });
const [linkStat, linkDirStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'link-dir')),
fs.lstat(path.join(outDir, 'a.txt')),
]);
expect(linkStat.isSymbolicLink()).toEqual(true);
expect(linkDirStat.isSymbolicLink()).toEqual(true);
expect(aStat.isFile()).toEqual(true);
});
it('should create zip file with empty directory', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const dir = await fs.mkdtemp(path.join(tmpdir(), 'create-zip-empty-dir'));
try {
const files = {
a: new FileBlob({
data: 'contents',
mode: MODE_FILE,
}),
empty: new FileBlob({
data: '',
mode: MODE_DIRECTORY,
}),
'b/a': new FileBlob({
data: 'inside dir b',
mode: MODE_FILE,
}),
c: new FileBlob({
data: '',
mode: MODE_DIRECTORY,
}),
'c/a': new FileBlob({
data: 'inside dir c',
mode: MODE_FILE,
}),
};
const outFile = path.join(dir, 'lambda.zip');
const outDir = path.join(dir, 'out');
await fs.mkdirp(outDir);
await fs.writeFile(outFile, await createZip(files));
await spawnAsync('unzip', [outFile], { cwd: outDir });
expect(fs.statSync(path.join(outDir, 'empty')).isDirectory()).toEqual(
true
);
expect(fs.statSync(path.join(outDir, 'b')).isDirectory()).toEqual(true);
expect(fs.statSync(path.join(outDir, 'c')).isDirectory()).toEqual(true);
expect(fs.readFileSync(path.join(outDir, 'a'), 'utf8')).toEqual(
'contents'
);
expect(fs.readFileSync(path.join(outDir, 'b/a'), 'utf8')).toEqual(
'inside dir b'
);
expect(fs.readFileSync(path.join(outDir, 'c/a'), 'utf8')).toEqual(
'inside dir c'
);
expect(fs.readdirSync(path.join(outDir, 'empty'))).toHaveLength(0);
} finally {
await fs.remove(dir);
}
});
});

View File

@@ -1,15 +1,20 @@
import ms from 'ms';
import path from 'path';
import fs from 'fs-extra';
import { strict as assert } from 'assert';
import fs, { readlink } from 'fs-extra';
import { strict as assert, strictEqual } from 'assert';
import { createZip } from '../src/lambda';
import { getSupportedNodeVersion } from '../src/fs/node-version';
import download from '../src/fs/download';
import {
glob,
spawnAsync,
getNodeVersion,
getLatestNodeVersion,
getDiscontinuedNodeVersions,
runNpmInstall,
runPackageJsonScript,
scanParentDirs,
FileBlob,
Prerender,
} from '../src';
@@ -46,6 +51,171 @@ afterEach(() => {
console.warn = originalConsoleWarn;
});
it('should re-create FileFsRef symlinks properly', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = await glob('**', path.join(__dirname, 'symlinks'));
assert.equal(Object.keys(files).length, 4);
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
const files2 = await download(files, outDir);
assert.equal(Object.keys(files2).length, 4);
const [linkStat, linkDirStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'link-dir')),
fs.lstat(path.join(outDir, 'a.txt')),
]);
assert(linkStat.isSymbolicLink());
assert(linkDirStat.isSymbolicLink());
assert(aStat.isFile());
const [linkDirContents, linkTextContents] = await Promise.all([
readlink(path.join(outDir, 'link-dir')),
readlink(path.join(outDir, 'link.txt')),
]);
strictEqual(linkDirContents, 'dir');
strictEqual(linkTextContents, './a.txt');
});
it('should re-create FileBlob symlinks properly', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = {
'a.txt': new FileBlob({
mode: 33188,
contentType: undefined,
data: 'a text',
}),
'dir/b.txt': new FileBlob({
mode: 33188,
contentType: undefined,
data: 'b text',
}),
'link-dir': new FileBlob({
mode: 41453,
contentType: undefined,
data: 'dir',
}),
'link.txt': new FileBlob({
mode: 41453,
contentType: undefined,
data: 'a.txt',
}),
};
strictEqual(Object.keys(files).length, 4);
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
const files2 = await download(files, outDir);
strictEqual(Object.keys(files2).length, 4);
const [linkStat, linkDirStat, aStat, dirStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'link-dir')),
fs.lstat(path.join(outDir, 'a.txt')),
fs.lstat(path.join(outDir, 'dir')),
]);
assert(linkStat.isSymbolicLink());
assert(linkDirStat.isSymbolicLink());
assert(aStat.isFile());
assert(dirStat.isDirectory());
const [linkDirContents, linkTextContents] = await Promise.all([
readlink(path.join(outDir, 'link-dir')),
readlink(path.join(outDir, 'link.txt')),
]);
strictEqual(linkDirContents, 'dir');
strictEqual(linkTextContents, 'a.txt');
});
it('should create zip files with symlinks properly', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = await glob('**', path.join(__dirname, 'symlinks'));
assert.equal(Object.keys(files).length, 4);
const outFile = path.join(__dirname, 'symlinks.zip');
await fs.remove(outFile);
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
await fs.mkdirp(outDir);
await fs.writeFile(outFile, await createZip(files));
await spawnAsync('unzip', [outFile], { cwd: outDir });
const [linkStat, linkDirStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'link-dir')),
fs.lstat(path.join(outDir, 'a.txt')),
]);
assert(linkStat.isSymbolicLink());
assert(linkDirStat.isSymbolicLink());
assert(aStat.isFile());
});
it('should download symlinks even with incorrect file', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = {
'dir/file.txt': new FileBlob({
mode: 33188,
contentType: undefined,
data: 'file text',
}),
linkdir: new FileBlob({
mode: 41453,
contentType: undefined,
data: 'dir',
}),
'linkdir/file.txt': new FileBlob({
mode: 33188,
contentType: undefined,
data: 'this file should be discarded',
}),
};
const outDir = path.join(__dirname, 'symlinks-out');
await fs.remove(outDir);
await fs.mkdirp(outDir);
await download(files, outDir);
const [dir, file, linkdir] = await Promise.all([
fs.lstat(path.join(outDir, 'dir')),
fs.lstat(path.join(outDir, 'dir/file.txt')),
fs.lstat(path.join(outDir, 'linkdir')),
]);
expect(dir.isFile()).toBe(false);
expect(dir.isSymbolicLink()).toBe(false);
expect(file.isFile()).toBe(true);
expect(file.isSymbolicLink()).toBe(false);
expect(linkdir.isSymbolicLink()).toBe(true);
expect(warningMessages).toEqual([
'Warning: file "linkdir/file.txt" is within a symlinked directory "linkdir" and will be ignored',
]);
});
it('should only match supported node versions, otherwise throw an error', async () => {
expect(await getSupportedNodeVersion('14.x', false)).toHaveProperty(
'major',
@@ -304,21 +474,21 @@ it('should support initialHeaders and initialStatus correctly', async () => {
});
it('should support require by path for legacy builders', () => {
const index = require('../');
const index = require('@vercel/build-utils');
const download2 = require('../fs/download.js');
const getWriteableDirectory2 = require('../fs/get-writable-directory.js');
const glob2 = require('../fs/glob.js');
const rename2 = require('../fs/rename.js');
const download2 = require('@vercel/build-utils/fs/download.js');
const getWriteableDirectory2 = require('@vercel/build-utils/fs/get-writable-directory.js');
const glob2 = require('@vercel/build-utils/fs/glob.js');
const rename2 = require('@vercel/build-utils/fs/rename.js');
const {
runNpmInstall: runNpmInstall2,
} = require('../fs/run-user-scripts.js');
const streamToBuffer2 = require('../fs/stream-to-buffer.js');
} = require('@vercel/build-utils/fs/run-user-scripts.js');
const streamToBuffer2 = require('@vercel/build-utils/fs/stream-to-buffer.js');
const FileBlob2 = require('../file-blob.js');
const FileFsRef2 = require('../file-fs-ref.js');
const FileRef2 = require('../file-ref.js');
const { Lambda: Lambda2 } = require('../lambda.js');
const FileBlob2 = require('@vercel/build-utils/file-blob.js');
const FileFsRef2 = require('@vercel/build-utils/file-fs-ref.js');
const FileRef2 = require('@vercel/build-utils/file-ref.js');
const { Lambda: Lambda2 } = require('@vercel/build-utils/lambda.js');
expect(download2).toBe(index.download);
expect(getWriteableDirectory2).toBe(index.getWriteableDirectory);
@@ -420,9 +590,9 @@ it('should detect package.json in nested backend', async () => {
'../../node/test/fixtures/18.1-nested-packagejson/backend'
);
const result = await scanParentDirs(fixture);
expect(result.cliType).toEqual('pnpm');
// There is no lockfile but this test will pick up vercel/vercel/pnpm-lock.yaml
expect(result.lockfileVersion).toEqual(5.4);
expect(result.cliType).toEqual('yarn');
expect(result.lockfileVersion).toEqual(undefined);
// There is no lockfile but this test will pick up vercel/vercel/yarn.lock
expect(result.packageJsonPath).toEqual(path.join(fixture, 'package.json'));
});
@@ -432,9 +602,9 @@ it('should detect package.json in nested frontend', async () => {
'../../node/test/fixtures/18.1-nested-packagejson/frontend'
);
const result = await scanParentDirs(fixture);
expect(result.cliType).toEqual('pnpm');
// There is no lockfile but this test will pick up vercel/vercel/pnpm-lock.yaml
expect(result.lockfileVersion).toEqual(5.4);
expect(result.cliType).toEqual('yarn');
expect(result.lockfileVersion).toEqual(undefined);
// There is no lockfile but this test will pick up vercel/vercel/yarn.lock
expect(result.packageJsonPath).toEqual(path.join(fixture, 'package.json'));
});

View File

@@ -2,7 +2,7 @@ import { walkParentDirs } from '../src';
import { strict } from 'assert';
import { join } from 'path';
import { promises } from 'fs';
const { notDeepEqual, fail } = strict;
const { deepEqual, notDeepEqual, fail } = strict;
const { readFile } = promises;
const fixture = (name: string) => join(__dirname, 'walk', name);
const filename = 'file.txt';
@@ -10,7 +10,7 @@ const filename = 'file.txt';
async function assertContent(target: string | null, contents: string) {
notDeepEqual(target, null);
const actual = await readFile(target!, 'utf8');
strict.deepEqual(actual.trim(), contents.trim());
deepEqual(actual.trim(), contents.trim());
}
describe('Test `walkParentDirs`', () => {
@@ -21,7 +21,7 @@ describe('Test `walkParentDirs`', () => {
await walkParentDirs({ base, start, filename });
fail('Expected error');
} catch (error) {
strict.deepEqual(
deepEqual(
(error as Error).message,
'Expected "base" to be absolute path'
);
@@ -35,7 +35,7 @@ describe('Test `walkParentDirs`', () => {
await walkParentDirs({ base, start, filename });
fail('Expected error');
} catch (error) {
strict.deepEqual(
deepEqual(
(error as Error).message,
'Expected "start" to be absolute path'
);
@@ -67,21 +67,21 @@ describe('Test `walkParentDirs`', () => {
const base = fixture('not-found');
const start = base;
const target = await walkParentDirs({ base, start, filename });
strict.deepEqual(target, null);
deepEqual(target, null);
});
it('should not find nested two', async () => {
const base = fixture('not-found');
const start = join(base, 'two');
const target = await walkParentDirs({ base, start, filename });
strict.deepEqual(target, null);
deepEqual(target, null);
});
it('should not find nested three', async () => {
const base = fixture('not-found');
const start = join(base, 'two', 'three');
const target = await walkParentDirs({ base, start, filename });
strict.deepEqual(target, null);
deepEqual(target, null);
});
it('should find only one', async () => {

View File

@@ -41,8 +41,8 @@ To develop Vercel CLI, first check out the source code, install dependencies, an
```bash
git clone https://github.com/vercel/vercel.git
cd vercel
pnpm install
pnpm build
yarn
yarn build
```
At this point you can make modifications to the CLI source code and test them out locally. The CLI source code is located in the `packages/cli` directory.
@@ -51,15 +51,15 @@ At this point you can make modifications to the CLI source code and test them ou
cd packages/cli
```
### `pnpm dev <cli-commands...>`
### `yarn dev <cli-commands...>`
From within the `packages/cli` directory, you can use the "dev" script to quickly execute Vercel CLI from its TypeScript source code directly (without having to manually compile first). For example:
```bash
pnpm dev deploy
pnpm dev whoami
pnpm dev login
pnpm dev switch --debug
yarn dev deploy
yarn dev whoami
yarn dev login
yarn dev switch --debug
```
When you are satisfied with your changes, make a commit and create a pull request!

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "28.12.1",
"version": "28.11.0",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -13,9 +13,9 @@
"scripts": {
"preinstall": "node ./scripts/preinstall.js",
"test": "jest --env node --verbose --bail",
"test-unit": "pnpm test test/unit/",
"test-unit": "yarn test test/unit/",
"test-integration-cli": "rimraf test/fixtures/integration && ava test/integration.js --serial --fail-fast --verbose",
"test-integration-dev": "pnpm test test/dev/",
"test-integration-dev": "yarn test test/dev/",
"coverage": "codecov",
"build": "ts-node ./scripts/build.ts",
"dev": "ts-node ./src/index.ts"
@@ -41,16 +41,17 @@
"node": ">= 14"
},
"dependencies": {
"@vercel/build-utils": "workspace:5.8.0",
"@vercel/go": "workspace:2.2.26",
"@vercel/hydrogen": "workspace:0.0.40",
"@vercel/next": "workspace:3.3.11",
"@vercel/node": "workspace:2.8.8",
"@vercel/python": "workspace:3.1.36",
"@vercel/redwood": "workspace:1.0.47",
"@vercel/remix": "workspace:1.2.1",
"@vercel/ruby": "workspace:1.3.52",
"@vercel/static-build": "workspace:1.1.3"
"@vercel/build-utils": "5.7.4",
"@vercel/go": "2.2.23",
"@vercel/hydrogen": "0.0.37",
"@vercel/next": "3.3.8",
"@vercel/node": "2.8.5",
"@vercel/python": "3.1.33",
"@vercel/redwood": "1.0.44",
"@vercel/remix": "1.1.6",
"@vercel/ruby": "1.3.49",
"@vercel/static-build": "1.1.0",
"update-notifier": "5.1.0"
},
"devDependencies": {
"@alex_neo/jest-expect-message": "1.0.5",
@@ -83,7 +84,6 @@
"@types/npm-package-arg": "6.1.0",
"@types/pluralize": "0.0.29",
"@types/psl": "1.1.0",
"@types/qs": "6.9.7",
"@types/semver": "6.0.1",
"@types/tar-fs": "1.16.1",
"@types/text-table": "0.2.0",
@@ -93,13 +93,13 @@
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@types/yauzl-promise": "2.1.0",
"@vercel/client": "workspace:12.2.28",
"@vercel/error-utils": "workspace:1.0.5",
"@vercel/frameworks": "workspace:1.2.1",
"@vercel/fs-detectors": "workspace:3.7.1",
"@vercel/client": "12.2.25",
"@vercel/error-utils": "1.0.3",
"@vercel/frameworks": "1.1.18",
"@vercel/fs-detectors": "3.6.1",
"@vercel/fun": "1.0.4",
"@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "workspace:2.1.5",
"@vercel/routing-utils": "2.1.3",
"@zeit/source-map-support": "0.6.2",
"ajv": "6.12.2",
"alpha-sort": "2.0.1",
@@ -139,7 +139,6 @@
"is-port-reachable": "3.1.0",
"is-url": "1.2.2",
"jaro-winkler": "0.2.8",
"jest-matcher-utils": "29.3.1",
"json5": "2.2.1",
"jsonlines": "0.1.1",
"line-async-iterator": "3.0.0",

View File

@@ -1,7 +1,7 @@
import cpy from 'cpy';
import execa from 'execa';
import { join } from 'path';
import { remove, readJSON, writeFile } from 'fs-extra';
import { remove, writeFile } from 'fs-extra';
const dirRoot = join(__dirname, '..');
const distRoot = join(dirRoot, 'dist');
@@ -43,16 +43,16 @@ async function main() {
stdio: 'inherit',
});
const pkg = await readJSON(join(dirRoot, 'package.json'));
const dependencies = Object.keys(pkg?.dependencies ?? {});
// Do the initial `ncc` build
console.log('Dependencies:', dependencies);
const externs: Array<string> = [];
for (const dep of dependencies) {
externs.push('--external', dep);
}
const args = ['ncc', 'build', 'src/index.ts', ...externs];
await execa('pnpm', args, { stdio: 'inherit', cwd: dirRoot });
console.log();
const args = [
'ncc',
'build',
'--external',
'update-notifier',
'src/index.ts',
];
await execa('yarn', args, { stdio: 'inherit', cwd: dirRoot });
// `ncc` has some issues with `@vercel/fun`'s runtime files:
// - Executable bits on the `bootstrap` files appear to be lost:
@@ -66,7 +66,10 @@ async function main() {
// get compiled into the final ncc bundle file, however, we want them to be
// present in the npm package because the contents of those files are involved
// with `fun`'s cache invalidation mechanism and they need to be shasum'd.
const runtimes = join(dirRoot, 'node_modules/@vercel/fun/dist/src/runtimes');
const runtimes = join(
dirRoot,
'../../node_modules/@vercel/fun/dist/src/runtimes'
);
await cpy('**/*', join(distRoot, 'runtimes'), {
parents: true,
cwd: runtimes,
@@ -75,10 +78,6 @@ async function main() {
// Band-aid to bundle stuff that `ncc` neglects to bundle
await cpy(join(dirRoot, 'src/util/projects/VERCEL_DIR_README.txt'), distRoot);
await cpy(join(dirRoot, 'src/util/dev/builder-worker.js'), distRoot);
await cpy(
join(dirRoot, 'src/util/get-latest-version/get-latest-worker.js'),
distRoot
);
console.log('Finished building Vercel CLI');
}

View File

@@ -17,11 +17,7 @@ import {
BuildResultV3,
NowBuildError,
} from '@vercel/build-utils';
import {
detectBuilders,
detectFrameworkRecord,
LocalFileSystemDetector,
} from '@vercel/fs-detectors';
import { detectBuilders } from '@vercel/fs-detectors';
import minimatch from 'minimatch';
import {
appendRoutesToPhase,
@@ -63,9 +59,6 @@ import { toEnumerableError } from '../util/error';
import { validateConfig } from '../util/validate-config';
import { setMonorepoDefaultSettings } from '../util/build/monorepo';
import frameworks from '@vercel/frameworks';
import { detectFrameworkVersion } from '@vercel/fs-detectors';
import semver from 'semver';
type BuildResult = BuildResultV2 | BuildResultV3;
@@ -76,20 +69,6 @@ interface SerializedBuilder extends Builder {
apiVersion: number;
}
/**
* Build Output API `config.json` file interface.
*/
interface BuildOutputConfig {
version?: 3;
wildcard?: BuildResultV2Typical['wildcard'];
images?: BuildResultV2Typical['images'];
routes?: BuildResultV2Typical['routes'];
overrides?: Record<string, PathOverride>;
framework?: {
version: string;
};
}
/**
* Contents of the `builds.json` file.
*/
@@ -455,7 +434,7 @@ async function doBuild(
// Execute Builders for detected entrypoints
// TODO: parallelize builds (except for frontend)
const sortedBuilders = sortBuilders(builds);
const buildResults: Map<Builder, BuildResult | BuildOutputConfig> = new Map();
const buildResults: Map<Builder, BuildResult> = new Map();
const overrides: PathOverride[] = [];
const repoRootPath = cwd;
const corepackShimDir = await initCorepack({ repoRootPath });
@@ -559,7 +538,8 @@ async function doBuild(
// Merge existing `config.json` file into the one that will be produced
const configPath = join(outputDir, 'config.json');
const existingConfig = await readJSONFile<BuildOutputConfig>(configPath);
// TODO: properly type
const existingConfig = await readJSONFile<any>(configPath);
if (existingConfig instanceof CantParseJSONFile) {
throw existingConfig;
}
@@ -605,17 +585,15 @@ async function doBuild(
const mergedOverrides: Record<string, PathOverride> =
overrides.length > 0 ? Object.assign({}, ...overrides) : undefined;
const framework = await getFramework(cwd, buildResults);
// Write out the final `config.json` file based on the
// user configuration and Builder build results
const config: BuildOutputConfig = {
// TODO: properly type
const config = {
version: 3,
routes: mergedRoutes,
images: mergedImages,
wildcard: mergedWildcard,
overrides: mergedOverrides,
framework,
};
await fs.writeJSON(join(outputDir, 'config.json'), config, { spaces: 2 });
@@ -630,50 +608,6 @@ async function doBuild(
);
}
async function getFramework(
cwd: string,
buildResults: Map<Builder, BuildResult | BuildOutputConfig>
): Promise<{ version: string } | undefined> {
const detectedFramework = await detectFrameworkRecord({
fs: new LocalFileSystemDetector(cwd),
frameworkList: frameworks,
});
if (!detectedFramework) {
return;
}
// determine framework version from build result
if (detectedFramework.useRuntime) {
for (const [build, buildResult] of buildResults.entries()) {
if (
'framework' in buildResult &&
build.use === detectedFramework.useRuntime.use
) {
return buildResult.framework;
}
}
}
// determine framework version from listed package.json version
if (detectedFramework.detectedVersion) {
// check for a valid, explicit version, not a range
if (semver.valid(detectedFramework.detectedVersion)) {
return {
version: detectedFramework.detectedVersion,
};
}
}
// determine framework version with runtime lookup
const frameworkVersion = detectFrameworkVersion(detectedFramework);
if (frameworkVersion) {
return {
version: frameworkVersion,
};
}
}
function expandBuild(files: string[], build: Builder): Builder[] {
if (!build.use) {
throw new NowBuildError({
@@ -714,7 +648,7 @@ function expandBuild(files: string[], build: Builder): Builder[] {
function mergeImages(
images: BuildResultV2Typical['images'],
buildResults: Iterable<BuildResult | BuildOutputConfig>
buildResults: Iterable<BuildResult>
): BuildResultV2Typical['images'] {
for (const result of buildResults) {
if ('images' in result && result.images) {
@@ -725,7 +659,7 @@ function mergeImages(
}
function mergeWildcard(
buildResults: Iterable<BuildResult | BuildOutputConfig>
buildResults: Iterable<BuildResult>
): BuildResultV2Typical['wildcard'] {
let wildcard: BuildResultV2Typical['wildcard'] = undefined;
for (const result of buildResults) {

View File

@@ -34,7 +34,7 @@ const help = () => {
)} Connect your Vercel Project to your Git repository defined in your local .git config
${chalk.cyan(`$ ${getPkgName()} git connect`)}
${chalk.gray(
''
)} Connect your Vercel Project to a Git repository using the remote URL
@@ -96,7 +96,6 @@ export default async function main(client: Client) {
}
const { org, project } = linkedProject;
client.config.currentTeam = org.type === 'team' ? org.id : undefined;
switch (subcommand) {
case 'connect':

View File

@@ -18,7 +18,7 @@ import sourceMap from '@zeit/source-map-support';
import { mkdirp } from 'fs-extra';
import chalk from 'chalk';
import epipebomb from 'epipebomb';
import getLatestVersion from './util/get-latest-version';
import updateNotifier from 'update-notifier';
import { URL } from 'url';
import * as Sentry from '@sentry/node';
import hp from './util/humanize-path';
@@ -55,6 +55,13 @@ import { VercelConfig } from '@vercel/client';
const isCanary = pkg.version.includes('canary');
// Checks for available update and returns an instance
const notifier = updateNotifier({
pkg,
distTag: isCanary ? 'canary' : 'latest',
updateCheckInterval: 1000 * 60 * 60 * 24 * 7, // 1 week
});
const VERCEL_DIR = getGlobalPathConfig();
const VERCEL_CONFIG_PATH = configFiles.getConfigFilePath();
const VERCEL_AUTH_CONFIG_PATH = configFiles.getAuthConfigFilePath();
@@ -142,26 +149,22 @@ const main = async () => {
}
// Print update information, if available
if (isTTY && !process.env.NO_UPDATE_NOTIFIER) {
// Check if an update is available. If so, `latest` will contain a string
// of the latest version, otherwise `undefined`.
const latest = getLatestVersion({
distTag: isCanary ? 'canary' : 'latest',
output,
pkg,
});
if (latest) {
output.log(
if (notifier.update && notifier.update.latest !== pkg.version && isTTY) {
const { latest } = notifier.update;
console.log(
info(
`${chalk.black.bgCyan('UPDATE AVAILABLE')} ` +
`Run ${cmd(
await getUpdateCommand()
)} to install ${getTitleName()} CLI ${latest}`
);
)
);
output.log(
`Changelog: https://github.com/vercel/vercel/releases/tag/vercel@${latest}\n`
);
}
console.log(
info(
`Changelog: https://github.com/vercel/vercel/releases/tag/vercel@${latest}`
)
);
}
// The second argument to the command can be:

View File

@@ -1,225 +0,0 @@
/**
* This file is spawned in the background and checks npm for the latest version
* of the CLI, then writes the version to the cache file.
*
* NOTE: Since this file runs asynchronously in the background, it's possible
* for multiple instances of this file to be running at the same time leading
* to a race condition where the most recent instance will overwrite the
* previous cache file resetting the `notified` flag and cause the update
* notification to appear for multiple consequetive commands. Not the end of
* the world, but something to be aware of.
*
* IMPORTANT! This file must NOT depend on any 3rd party dependencies. This
* file is NOT bundled by `ncc` and thus any 3rd party dependencies will never
* be available.
*/
const https = require('https');
const { mkdirSync, writeFileSync } = require('fs');
const { access, mkdir, readFile, unlink, writeFile } = require('fs/promises');
const path = require('path');
const { format, inspect } = require('util');
/**
* An simple output helper which accumulates error and debug log messages in
* memory for potential persistance to disk while immediately outputting errors
* and debug messages, when the `--debug` flag is set, to `stderr`.
*/
class WorkerOutput {
debugLog = [];
logFile = null;
constructor({ debug = true }) {
this.debugOutputEnabled = debug;
}
debug(...args) {
this.print('debug', args);
}
error(...args) {
this.print('error', args);
}
print(type, args) {
// note: `args` may contain an `Error` that will be toString()'d and thus
// no stack trace
const str = format(
...args.map(s => (typeof s === 'string' ? s : inspect(s)))
);
this.debugLog.push(`[${new Date().toISOString()}] [${type}] ${str}`);
if (type === 'debug' && this.debugOutputEnabled) {
console.error(`> '[debug] [${new Date().toISOString()}] ${str}`);
} else if (type === 'error') {
console.error(`Error: ${str}`);
}
}
setLogFile(file) {
// wire up the exit handler the first time the log file is set
if (this.logFile === null) {
process.on('exit', () => {
if (this.debugLog.length) {
mkdirSync(path.dirname(this.logFile), { recursive: true });
writeFileSync(this.logFile, this.debugLog.join('\n'));
}
});
}
this.logFile = file;
}
}
const output = new WorkerOutput({
// enable the debug logging if the `--debug` is set or if this worker script
// was directly executed
debug: process.argv.includes('--debug') || !process.connected,
});
process.on('unhandledRejection', err => {
output.error('Exiting worker due to unhandled rejection:', err);
process.exit(1);
});
// this timer will prevent this worker process from running longer than 10s
const timer = setTimeout(() => {
output.error('Worker timed out after 10 seconds');
process.exit(1);
}, 10000);
// wait for the parent to give us the work payload
process.once('message', async msg => {
output.debug('Received message from parent:', msg);
output.debug('Disconnecting from parent');
process.disconnect();
const { cacheFile, distTag, name, updateCheckInterval } = msg;
const cacheFileParsed = path.parse(cacheFile);
await mkdir(cacheFileParsed.dir, { recursive: true });
output.setLogFile(
path.join(cacheFileParsed.dir, `${cacheFileParsed.name}.log`)
);
const lockFile = path.join(
cacheFileParsed.dir,
`${cacheFileParsed.name}.lock`
);
try {
// check for a lock file and either bail if running or write our pid and continue
output.debug(`Checking lock file: ${lockFile}`);
if (await isRunning(lockFile)) {
output.debug('Worker already running, exiting');
process.exit(1);
}
output.debug(`Initializing lock file with pid ${process.pid}`);
await writeFile(lockFile, String(process.pid), 'utf-8');
// fetch the latest version from npm
const agent = new https.Agent({
keepAlive: true,
maxSockets: 15, // See: `npm config get maxsockets`
});
const headers = {
accept:
'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*',
};
const url = `https://registry.npmjs.org/-/package/${name}/dist-tags`;
output.debug(`Fetching ${url}`);
const tags = await new Promise((resolve, reject) => {
const req = https.get(
url,
{
agent,
headers,
},
res => {
let buf = '';
res.on('data', chunk => {
buf += chunk;
});
res.on('end', () => {
try {
resolve(JSON.parse(buf));
} catch (err) {
reject(err);
}
});
}
);
req.on('error', reject);
req.end();
});
const version = tags[distTag];
if (version) {
output.debug(`Found dist tag "${distTag}" with version "${version}"`);
} else {
output.error(`Dist tag "${distTag}" not found`);
output.debug('Available dist tags:', Object.keys(tags));
}
output.debug(`Writing cache file: ${cacheFile}`);
await writeFile(
cacheFile,
JSON.stringify({
expireAt: Date.now() + updateCheckInterval,
notified: false,
version,
})
);
} catch (err) {
output.error(`Failed to get package info:`, err);
} finally {
clearTimeout(timer);
if (await fileExists(lockFile)) {
output.debug(`Releasing lock file: ${lockFile}`);
await unlink(lockFile);
}
output.debug(`Worker finished successfully!`);
// force the worker to exit
process.exit(0);
}
});
// signal the parent process we're ready
if (process.connected) {
output.debug("Notifying parent we're ready");
process.send({ type: 'ready' });
} else {
console.error('No IPC bridge detected, exiting');
process.exit(1);
}
async function fileExists(file) {
return access(file)
.then(() => true)
.catch(() => false);
}
async function isRunning(lockFile) {
try {
const pid = parseInt(await readFile(lockFile, 'utf-8'));
output.debug(`Found lock file with pid: ${pid}`);
// checks for existence of a process; throws if not found
process.kill(pid, 0);
// process is still running
return true;
} catch (err) {
if (await fileExists(lockFile)) {
// lock file does not exist or process is not running and pid is stale
output.debug(`Resetting lock file: ${err.toString()}`);
await unlink(lockFile);
}
return false;
}
}

View File

@@ -1,151 +0,0 @@
import semver from 'semver';
import XDGAppPaths from 'xdg-app-paths';
import { dirname, parse as parsePath, resolve as resolvePath } from 'path';
import type { Output } from '../output';
import { existsSync, outputJSONSync, readJSONSync } from 'fs-extra';
import type { PackageJson } from '@vercel/build-utils';
import { spawn } from 'child_process';
interface GetLatestVersionOptions {
cacheDir?: string;
distTag?: string;
output?: Output;
pkg: PackageJson;
updateCheckInterval?: number;
}
interface PackageInfoCache {
version: string;
expireAt: number;
notified: boolean;
}
interface GetLatestWorkerPayload {
cacheFile?: string;
distTag?: string;
updateCheckInterval?: number;
name?: string;
}
/**
* Determines if it needs to check for a newer CLI version and returns the last
* detected version. The version could be stale, but still newer than the
* current version.
*
* @returns {String|undefined} If a newer version is found, then the lastest
* version, otherwise `undefined`.
*/
export default function getLatestVersion({
cacheDir = XDGAppPaths('com.vercel.cli').cache(),
distTag = 'latest',
output,
pkg,
updateCheckInterval = 1000 * 60 * 60 * 24 * 7, // 1 week
}: GetLatestVersionOptions): string | undefined {
if (
!pkg ||
typeof pkg !== 'object' ||
!pkg.name ||
typeof pkg.name !== 'string'
) {
throw new TypeError('Expected package to be an object with a package name');
}
const cacheFile = resolvePath(
cacheDir,
'package-updates',
`${pkg.name}-${distTag}.json`
);
let cache: PackageInfoCache | undefined;
try {
cache = readJSONSync(cacheFile);
} catch (err: any) {
// cache does not exist or malformed
if (err.code !== 'ENOENT') {
output?.debug(`Error reading latest package cache file: ${err}`);
}
}
if (!cache || cache.expireAt < Date.now()) {
spawnWorker(
{
cacheFile,
distTag,
updateCheckInterval,
name: pkg.name,
},
output
);
}
if (
cache &&
!cache.notified &&
pkg.version &&
semver.lt(pkg.version, cache.version)
) {
cache.notified = true;
outputJSONSync(cacheFile, cache);
return cache.version;
}
}
/**
* Spawn the worker, wait for the worker to report it's ready, then signal the
* worker to fetch the latest version.
*/
function spawnWorker(
payload: GetLatestWorkerPayload,
output: Output | undefined
) {
// we need to find the update worker script since the location is
// different based on production vs tests
let dir = dirname(__filename);
let script = resolvePath(dir, 'dist', 'get-latest-worker.js');
const { root } = parsePath(dir);
while (!existsSync(script)) {
dir = dirname(dir);
if (dir === root) {
// didn't find it, bail
output?.debug('Failed to find the get latest worker script!');
return;
}
script = resolvePath(dir, 'dist', 'get-latest-worker.js');
}
// spawn the worker with an IPC channel
output?.debug(`Spawning ${script}`);
const args = [script];
if (output?.debugEnabled) {
args.push('--debug');
}
const worker = spawn(process.execPath, args, {
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
windowsHide: true,
});
// we allow the child 2 seconds to let us know it's ready before we give up
const workerReadyTimer = setTimeout(() => worker.kill(), 2000);
// listen for an early on close error, but then we remove it when unref
const onClose = (code: number) => {
output?.debug(`Get latest worker exited (code ${code})`);
};
worker.on('close', onClose);
// generally, the parent won't be around long enough to handle a non-zero
// worker process exit code
worker.on('error', err => {
output?.log(`Failed to spawn get latest worker: ${err.stack}`);
});
// wait for the worker to start and notify us it is ready
worker.once('message', () => {
clearTimeout(workerReadyTimer);
worker.removeListener('close', onClose);
worker.send(payload);
worker.unref();
});
}

View File

@@ -1,4 +1,5 @@
import Client from '../client';
import { stringify } from 'qs';
import { Org } from '../../types';
import chalk from 'chalk';
import link from '../output/link';
@@ -18,7 +19,9 @@ export async function disconnectGitProvider(
org: Org,
projectId: string
) {
const fetchUrl = `/v9/projects/${projectId}/link`;
const fetchUrl = `/v9/projects/${projectId}/link?${stringify({
teamId: org.type === 'team' ? org.id : undefined,
})}`;
return client.fetch(fetchUrl, {
method: 'DELETE',
headers: {
@@ -34,7 +37,9 @@ export async function connectGitProvider(
type: string,
repo: string
) {
const fetchUrl = `/v9/projects/${projectId}/link`;
const fetchUrl = `/v9/projects/${projectId}/link?${stringify({
teamId: org.type === 'team' ? org.id : undefined,
})}`;
try {
return await client.fetch(fetchUrl, {
method: 'POST',

View File

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

View File

@@ -1,4 +0,0 @@
{
"name": "next",
"version": "13.0.4"
}

View File

@@ -1,5 +0,0 @@
{
"dependencies": {
"next": "13.0.4"
}
}

View File

@@ -2,12 +2,12 @@ import ms from 'ms';
import fs from 'fs-extra';
import { join } from 'path';
import { getWriteableDirectory } from '@vercel/build-utils';
import build from '../../../../src/commands/build';
import { client } from '../../../mocks/client';
import { defaultProject, useProject } from '../../../mocks/project';
import { useTeams } from '../../../mocks/team';
import { useUser } from '../../../mocks/user';
import { setupFixture } from '../../../helpers/setup-fixture';
import build from '../../../src/commands/build';
import { client } from '../../mocks/client';
import { defaultProject, useProject } from '../../mocks/project';
import { useTeams } from '../../mocks/team';
import { useUser } from '../../mocks/user';
import { setupFixture } from '../../helpers/setup-fixture';
import JSON5 from 'json5';
// TODO (@Ethan-Arrowood) - After shipping support for turbo and nx, revisit rush support
// import execa from 'execa';
@@ -15,7 +15,7 @@ import JSON5 from 'json5';
jest.setTimeout(ms('1 minute'));
const fixture = (name: string) =>
join(__dirname, '../../../fixtures/unit/commands/build', name);
join(__dirname, '../../fixtures/unit/commands/build', name);
describe('build', () => {
const originalCwd = process.cwd();

View File

@@ -1,143 +0,0 @@
import fs from 'fs-extra';
import sleep from '../../../src/util/sleep';
import tmp from 'tmp-promise';
import getLatestVersion from '../../../src/util/get-latest-version';
import { join } from 'path';
tmp.setGracefulCleanup();
jest.setTimeout(25000);
const cacheDir = tmp.tmpNameSync({
prefix: 'test-vercel-cli-get-latest-version-',
});
const cacheFile = join(cacheDir, 'package-updates', 'vercel-latest.json');
const pkg = {
name: 'vercel',
version: '27.3.0',
};
const versionRE = /^\d+\.\d+\.\d+$/;
describe('get latest version', () => {
afterEach(() => fs.remove(cacheDir));
it('should find newer version async', async () => {
// 1. first call, no cache file
let latest = getLatestVersion({
cacheDir,
pkg,
});
expect(latest).toEqual(undefined);
await waitForCacheFile();
let cache = await fs.readJSON(cacheFile);
expect(typeof cache).toEqual('object');
expect(typeof cache.expireAt).toEqual('number');
expect(cache.expireAt).toBeGreaterThan(Date.now());
expect(typeof cache.version).toEqual('string');
expect(cache.version).toEqual(expect.stringMatching(versionRE));
expect(cache.notified).toEqual(false);
// 2. call again and this time it'll return the version from the cache
latest = getLatestVersion({
cacheDir,
pkg,
});
expect(typeof latest).toBe('string');
expect(latest).toEqual(expect.stringMatching(versionRE));
cache = await fs.readJSON(cacheFile);
expect(cache.version).toEqual(expect.stringMatching(versionRE));
expect(cache.notified).toEqual(true);
// 3. notification already done, should skip
latest = getLatestVersion({
cacheDir,
pkg,
});
expect(latest).toEqual(undefined);
});
it('should not find a newer version', async () => {
// 1. first call, no cache file
let latest = getLatestVersion({
cacheDir,
updateCheckInterval: 1,
pkg: {
...pkg,
version: '999.0.0',
},
});
expect(latest).toEqual(undefined);
await waitForCacheFile();
// 2. call again and should recheck and still not find a new version
latest = getLatestVersion({
cacheDir,
updateCheckInterval: 1,
pkg: {
...pkg,
version: '999.0.0',
},
});
expect(latest).toEqual(undefined);
});
it('should not check twice', async () => {
// 1. first call, no cache file
let latest = getLatestVersion({
cacheDir,
updateCheckInterval: 1,
pkg,
});
expect(latest).toEqual(undefined);
// 2. immediately call again, but should hopefully still be undefined
latest = getLatestVersion({
cacheDir,
updateCheckInterval: 1,
pkg,
});
expect(latest).toEqual(undefined);
await waitForCacheFile();
// 3. call again and should recheck and find a new version
latest = getLatestVersion({
cacheDir,
updateCheckInterval: 1,
pkg,
});
expect(typeof latest).toBe('string');
expect(latest).toEqual(expect.stringMatching(versionRE));
});
it('should error if no arguments are passed in', () => {
expect(() => getLatestVersion(undefined as any)).toThrow(TypeError);
});
it('should error package is invalid', () => {
expect(() => getLatestVersion({} as any)).toThrow(TypeError);
expect(() => getLatestVersion({ pkg: null as any })).toThrow(TypeError);
expect(() => getLatestVersion({ pkg: {} })).toThrow(TypeError);
expect(() => getLatestVersion({ pkg: { name: null as any } })).toThrow(
TypeError
);
expect(() => getLatestVersion({ pkg: { name: '' } })).toThrow(TypeError);
});
});
async function waitForCacheFile() {
const seconds = 20;
for (let i = 0; i < seconds * 4; i++) {
await sleep(250);
if (await fs.pathExists(cacheFile)) {
return;
}
}
}

View File

@@ -10,6 +10,8 @@ Firstly, install the package:
```bash
npm install @vercel/client
# or
yarn add @vercel/client
```
Next, load it:

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "12.2.28",
"version": "12.2.25",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://vercel.com",
@@ -15,9 +15,9 @@
},
"scripts": {
"build": "tsc",
"test-integration-once": "pnpm test tests/create-deployment.test.ts tests/create-legacy-deployment.test.ts tests/paths.test.ts",
"test-integration-once": "yarn test tests/create-deployment.test.ts tests/create-legacy-deployment.test.ts tests/paths.test.ts",
"test": "jest --env node --verbose --runInBand --bail",
"test-unit": "pnpm test tests/unit.*test.*"
"test-unit": "yarn test tests/unit.*test.*"
},
"engines": {
"node": ">= 14"
@@ -43,8 +43,8 @@
]
},
"dependencies": {
"@vercel/build-utils": "workspace:5.8.0",
"@vercel/routing-utils": "workspace:2.1.5",
"@vercel/build-utils": "5.7.4",
"@vercel/routing-utils": "2.1.3",
"@zeit/fetch": "5.2.0",
"async-retry": "1.2.3",
"async-sema": "3.0.0",

View File

@@ -24,6 +24,7 @@
- [ipAddress](README.md#ipaddress)
- [json](README.md#json)
- [next](README.md#next)
- [potentiallyLongRunningResponse](README.md#potentiallylongrunningresponse)
- [rewrite](README.md#rewrite)
## Variables
@@ -36,7 +37,7 @@ City of the original client IP as calculated by Vercel Proxy.
#### Defined in
[packages/edge/src/edge-headers.ts:4](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L4)
[src/edge-headers.ts:4](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L4)
---
@@ -48,7 +49,7 @@ Country of the original client IP as calculated by Vercel Proxy.
#### Defined in
[packages/edge/src/edge-headers.ts:8](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L8)
[src/edge-headers.ts:8](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L8)
---
@@ -60,7 +61,7 @@ Client IP as calcualted by Vercel Proxy.
#### Defined in
[packages/edge/src/edge-headers.ts:12](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L12)
[src/edge-headers.ts:12](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L12)
---
@@ -72,7 +73,7 @@ Latitude of the original client IP as calculated by Vercel Proxy.
#### Defined in
[packages/edge/src/edge-headers.ts:16](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L16)
[src/edge-headers.ts:16](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L16)
---
@@ -84,7 +85,7 @@ Longitude of the original client IP as calculated by Vercel Proxy.
#### Defined in
[packages/edge/src/edge-headers.ts:20](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L20)
[src/edge-headers.ts:20](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L20)
---
@@ -98,7 +99,7 @@ See [docs](https://vercel.com/docs/concepts/edge-network/headers#x-vercel-ip-cou
#### Defined in
[packages/edge/src/edge-headers.ts:26](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L26)
[src/edge-headers.ts:26](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L26)
---
@@ -110,7 +111,7 @@ The request ID for each request generated by Vercel Proxy.
#### Defined in
[packages/edge/src/edge-headers.ts:30](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L30)
[src/edge-headers.ts:30](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L30)
## Functions
@@ -140,7 +141,7 @@ Returns the location information for the incoming request.
#### Defined in
[packages/edge/src/edge-headers.ts:106](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L106)
[src/edge-headers.ts:106](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L106)
---
@@ -166,7 +167,7 @@ Returns the IP address of the request from the headers.
#### Defined in
[packages/edge/src/edge-headers.ts:77](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L77)
[src/edge-headers.ts:77](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L77)
---
@@ -209,7 +210,7 @@ const response = json(
#### Defined in
[packages/edge/src/response.ts:19](https://github.com/vercel/vercel/blob/main/packages/edge/src/response.ts#L19)
[src/response.ts:19](https://github.com/vercel/vercel/blob/main/packages/edge/src/response.ts#L19)
---
@@ -257,7 +258,44 @@ export default function middleware(_req: Request) {
#### Defined in
[packages/edge/src/middleware-helpers.ts:145](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L145)
[src/middleware-helpers.ts:145](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L145)
---
### potentiallyLongRunningResponse
**potentiallyLongRunningResponse**(`dataPromise`, `init?`): `Response`
Builds a response for returning data based on promise that take many seconds to resolve.
The response is returned immediately, but data is only written to it when the promise resolves.
**`Example`**
```ts
import { potentiallyLongRunningResponse } from '@vercel/edge';
export default () => {
const slowPromise = new Promise(resolve =>
setTimeout(() => resolve('Done'), 20000)
);
return potentiallyLongRunningResponse(slowPromise);
};
```
#### Parameters
| Name | Type | Description |
| :------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dataPromise` | [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`string` \| [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)\> | Promise for data to be sent as the response body. Note, that if this promise is rejected, then a plain text "ERROR" is returned to the cliet. Catch errors on the promise yourself to add custom error handling. |
| `init?` | `ResponseInit` | optional custom response status, statusText and headers |
#### Returns
`Response`
#### Defined in
[src/response.ts:43](https://github.com/vercel/vercel/blob/main/packages/edge/src/response.ts#L43)
---
@@ -319,4 +357,4 @@ export const config = { matcher: '/api/users/:path*' };
#### Defined in
[packages/edge/src/middleware-helpers.ts:101](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L101)
[src/middleware-helpers.ts:101](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L101)

View File

@@ -26,7 +26,7 @@ along with the response headers from the origin.
#### Defined in
[packages/edge/src/middleware-helpers.ts:31](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L31)
[src/middleware-helpers.ts:31](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L31)
---
@@ -38,7 +38,7 @@ Fields to rewrite for the upstream request.
#### Defined in
[packages/edge/src/middleware-helpers.ts:35](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L35)
[src/middleware-helpers.ts:35](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L35)
---

View File

@@ -23,7 +23,7 @@ The city that the request originated from.
#### Defined in
[packages/edge/src/edge-headers.ts:47](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L47)
[src/edge-headers.ts:47](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L47)
---
@@ -35,7 +35,7 @@ The country that the request originated from.
#### Defined in
[packages/edge/src/edge-headers.ts:50](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L50)
[src/edge-headers.ts:50](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L50)
---
@@ -48,7 +48,7 @@ See [docs](https://vercel.com/docs/concepts/edge-network/headers#x-vercel-ip-cou
#### Defined in
[packages/edge/src/edge-headers.ts:58](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L58)
[src/edge-headers.ts:58](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L58)
---
@@ -60,7 +60,7 @@ The latitude of the client.
#### Defined in
[packages/edge/src/edge-headers.ts:61](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L61)
[src/edge-headers.ts:61](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L61)
---
@@ -72,7 +72,7 @@ The longitude of the client.
#### Defined in
[packages/edge/src/edge-headers.ts:64](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L64)
[src/edge-headers.ts:64](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L64)
---
@@ -84,4 +84,4 @@ The [Vercel Edge Network region](https://vercel.com/docs/concepts/edge-network/r
#### Defined in
[packages/edge/src/edge-headers.ts:53](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L53)
[src/edge-headers.ts:53](https://github.com/vercel/vercel/blob/main/packages/edge/src/edge-headers.ts#L53)

View File

@@ -35,4 +35,4 @@ export default async function middleware(request: Request): Promise<Response> {
#### Defined in
[packages/edge/src/middleware-helpers.ts:23](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L23)
[src/middleware-helpers.ts:23](https://github.com/vercel/vercel/blob/main/packages/edge/src/middleware-helpers.ts#L23)

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/edge",
"version": "0.2.3",
"version": "0.2.1",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.mjs",
@@ -8,8 +8,8 @@
"scripts": {
"build": "tsup src/index.ts --dts --format esm,cjs",
"test": "jest --env node --verbose --runInBand --bail",
"test-unit": "pnpm test",
"build:docs": "typedoc && node scripts/fix-links.js && prettier --write docs/**/*.md docs/*.md"
"test-unit": "yarn test",
"build:docs": "typedoc && prettier --write docs/**/*.md docs/*.md"
},
"devDependencies": {
"@edge-runtime/jest-environment": "2.0.0",

View File

@@ -1,24 +0,0 @@
// this step is necessary until https://github.com/TypeStrong/typedoc/issues/2140 is fixed
const fs = require('fs');
const path = require('path');
const docs = path.join(__dirname, '..', 'docs');
const interfaces = path.join(docs, 'interfaces');
for (const dir of [docs, interfaces]) {
for (const entity of fs.readdirSync(dir)) {
try {
const entityPath = path.join(dir, entity);
const stat = fs.statSync(entityPath);
if (stat.isFile()) {
const contents = fs.readFileSync(entityPath, 'utf-8');
const pattern = /node_modules\/\.pnpm\/typescript@\d*\.\d*\.\d*\//gi;
fs.writeFileSync(entityPath, contents.replace(pattern, ''));
}
} catch (e) {
console.error('Error fixing links in docs', e);
}
}
}

View File

@@ -20,3 +20,51 @@ export function json(data: any, init?: ResponseInit): Response {
// @ts-expect-error This is not in lib/dom right now, and we can't augment it.
return Response.json(data, init);
}
/**
* Builds a response for returning data based on promise that take many seconds to resolve.
* The response is returned immediately, but data is only written to it when the promise resolves.
*
* @param dataPromise Promise for data to be sent as the response body. Note, that if this promise is
* rejected, then a plain text "ERROR" is returned to the cliet. Catch errors on the promise yourself
* to add custom error handling.
* @param init optional custom response status, statusText and headers
*
* @example
* ```ts
* import { potentiallyLongRunningResponse } from '@vercel/edge';
*
* export default () => {
* const slowPromise = new Promise((resolve) => setTimeout(() => resolve("Done"), 20000));
* return potentiallyLongRunningResponse(slowPromise);
* };
* ```
*/
export function potentiallyLongRunningResponse(
dataPromise: Promise<string | Uint8Array>,
init?: ResponseInit
): Response {
return new Response(
new ReadableStream({
start(controller) {
dataPromise
.then((data: string | Uint8Array) => {
if (typeof data === 'string') {
controller.enqueue(new TextEncoder().encode(data));
} else {
controller.enqueue(data);
}
controller.close();
})
.catch(error => {
console.log(
`Error in 'potentiallyLongRunningResponse' dataPromise: ${error}`
);
controller.enqueue(new TextEncoder().encode('ERROR'));
controller.close();
});
},
}),
init
);
}

View File

@@ -9,7 +9,7 @@ const test = process.platform === 'win32' ? it.skip : it;
test('docs are up to date', async () => {
const cwd = path.resolve(__dirname, '../');
await execAsync(`pnpm build:docs`, { cwd });
await execAsync(`yarn build:docs`, { cwd });
const result = await execAsync(`git status --short docs`, {
cwd,
encoding: 'utf-8',
@@ -27,7 +27,10 @@ test('docs are up to date', async () => {
if (lines !== '') {
const diff = await execAsync(`git diff docs`, { cwd, encoding: 'utf8' });
throw new Error(
`Docs are not up to date. Please re-run \`pnpm build:docs\` to re-generate them.\nChanges:\n${lines}\n\n${diff.stdout}`
'Docs are not up to date. Please re-run `yarn build:docs` to re-generate them.\nChanges:\n' +
lines +
'\n\n' +
diff.stdout
);
}

View File

@@ -2,7 +2,7 @@
* @jest-environment @edge-runtime/jest-environment
*/
import { json } from '../src/response';
import { json, potentiallyLongRunningResponse } from '../src/response';
describe('json', () => {
it('returns a response with JSON content', async () => {
@@ -32,3 +32,50 @@ describe('json', () => {
expect(await response.json()).toEqual(content);
});
});
describe('potentiallyLongRunningResponse', () => {
it('returns a response with immediate data', async () => {
const response = potentiallyLongRunningResponse(
new Promise(resolve => resolve('test'))
);
expect(await response.text()).toBe('test');
});
it('returns a response after a timeout', async () => {
const slowPromise: Promise<string> = new Promise(resolve =>
setTimeout(() => resolve('after timeout'), 1000)
);
const response = potentiallyLongRunningResponse(slowPromise);
expect(await response.text()).toBe('after timeout');
});
it('returns a response with custom init', async () => {
const response = potentiallyLongRunningResponse(
new Promise(resolve => resolve('test')),
{
status: 400,
headers: {
'content-type': 'text/custom',
},
}
);
expect(await response.text()).toBe('test');
expect(response.status).toBe(400);
expect(response.headers.get('content-type')).toBe('text/custom');
});
it('returns a response with Uint8Array data', async () => {
const data = new TextEncoder().encode('data');
const response = potentiallyLongRunningResponse(
new Promise(resolve => resolve(data))
);
expect(await response.text()).toBe('data');
});
it('returns ERROR on rejected promise', async () => {
const response = potentiallyLongRunningResponse(
new Promise((_, reject) => reject(new Error('test')))
);
expect(await response.text()).toBe('ERROR');
});
});

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/error-utils",
"version": "1.0.5",
"version": "1.0.3",
"description": "A collection of error utilities for vercel/vercel",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -12,7 +12,7 @@
"scripts": {
"build": "tsc",
"test": "jest --coverage --env node --verbose",
"test-unit": "pnpm test"
"test-unit": "yarn test"
},
"license": "MIT",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/frameworks",
"version": "1.2.1",
"version": "1.1.18",
"main": "./dist/frameworks.js",
"types": "./dist/frameworks.d.ts",
"files": [
@@ -10,7 +10,7 @@
"scripts": {
"build": "tsc",
"test": "jest --env node --verbose --runInBand --bail",
"test-unit": "pnpm test"
"test-unit": "yarn test"
},
"dependencies": {
"@iarna/toml": "2.2.3",
@@ -21,7 +21,7 @@
"@types/js-yaml": "3.12.1",
"@types/node": "14.18.33",
"@types/node-fetch": "2.5.8",
"@vercel/routing-utils": "workspace:2.1.5",
"@vercel/routing-utils": "2.1.3",
"ajv": "6.12.2",
"typescript": "4.3.4"
}

View File

@@ -30,8 +30,6 @@ export const frameworks = [
useRuntime: { src: 'package.json', use: '@vercel/next' },
detectors: {
some: [
// Intentionally does not detect a package name
// https://github.com/vercel/vercel/pull/8432
{
path: 'blitz.config.js',
},
@@ -76,7 +74,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'next',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"next":\\s*".+?"[^}]*}',
},
],
},
@@ -119,7 +119,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'gatsby',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"gatsby":\\s*".+?"[^}]*}',
},
],
},
@@ -203,8 +205,6 @@ export const frameworks = [
ignoreRuntimes: ['@vercel/node'],
detectors: {
every: [
// Intentionally does not detect a package name
// https://github.com/vercel/vercel/pull/7761
{
path: 'remix.config.js',
},
@@ -244,7 +244,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'astro',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"astro":\\s*".+?"[^}]*}',
},
],
},
@@ -286,7 +288,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'hexo',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"hexo":\\s*".+?"[^}]*}',
},
],
},
@@ -321,7 +325,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: '@11ty/eleventy',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@11ty\\/eleventy":\\s*".+?"[^}]*}',
},
],
},
@@ -358,7 +364,9 @@ export const frameworks = [
detectors: {
some: [
{
matchPackage: '@docusaurus/core',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@docusaurus\\/core":\\s*".+?"[^}]*}',
},
],
},
@@ -444,7 +452,9 @@ export const frameworks = [
detectors: {
some: [
{
matchPackage: 'docusaurus',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"docusaurus":\\s*".+?"[^}]*}',
},
],
},
@@ -492,10 +502,10 @@ export const frameworks = [
website: 'https://preactjs.com',
detectors: {
every: [
// Intentionally does not detect "preact" package because that can be
// used to power other frameworks.
{
matchPackage: 'preact-cli',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"preact-cli":\\s*".+?"[^}]*}',
},
],
},
@@ -539,10 +549,14 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'solid-js',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"solid-js":\\s*".+?"[^}]*}',
},
{
matchPackage: 'solid-start',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"solid-start":\\s*".+?"[^}]*}',
},
],
},
@@ -575,7 +589,9 @@ export const frameworks = [
detectors: {
some: [
{
matchPackage: '@dojo/framework',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@dojo\\/framework":\\s*".+?"[^}]*}',
},
{
path: '.dojorc',
@@ -633,12 +649,11 @@ export const frameworks = [
description: 'An Ember app, created with the Ember CLI.',
website: 'https://emberjs.com/',
detectors: {
some: [
every: [
{
matchPackage: 'ember-source',
},
{
matchPackage: 'ember-cli',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"ember-cli":\\s*".+?"[^}]*}',
},
],
},
@@ -683,7 +698,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: '@vue/cli-service',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@vue\\/cli-service":\\s*".+?"[^}]*}',
},
],
},
@@ -736,7 +753,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: '@scullyio/init',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@scullyio\\/init":\\s*".+?"[^}]*}',
},
],
},
@@ -771,7 +790,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: '@ionic/angular',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@ionic\\/angular":\\s*".+?"[^}]*}',
},
],
},
@@ -814,7 +835,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: '@angular/cli',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@angular\\/cli":\\s*".+?"[^}]*}',
},
],
},
@@ -872,7 +895,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'polymer-cli',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"polymer-cli":\\s*".+?"[^}]*}',
},
],
},
@@ -928,10 +953,14 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'svelte',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"svelte":\\s*".+?"[^}]*}',
},
{
matchPackage: 'sirv-cli',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"sirv-cli":\\s*".+?"[^}]*}',
},
],
},
@@ -963,7 +992,6 @@ export const frameworks = [
],
},
{
// TODO: fix detected as "sveltekit-1"
name: 'SvelteKit (Legacy Beta)',
slug: 'sveltekit',
demo: 'https://sveltekit-template.vercel.app',
@@ -1053,7 +1081,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: '@ionic/react',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@ionic\\/react":\\s*".+?"[^}]*}',
},
],
},
@@ -1113,10 +1143,14 @@ export const frameworks = [
detectors: {
some: [
{
matchPackage: 'react-scripts',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"react-scripts":\\s*".+?"[^}]*}',
},
{
matchPackage: 'react-dev-utils',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"react-dev-utils":\\s*".+?"[^}]*}',
},
],
},
@@ -1175,7 +1209,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'gridsome',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"gridsome":\\s*".+?"[^}]*}',
},
],
},
@@ -1210,7 +1246,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'umi',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"umi":\\s*".+?"[^}]*}',
},
],
},
@@ -1254,7 +1292,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'sapper',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"sapper":\\s*".+?"[^}]*}',
},
],
},
@@ -1289,7 +1329,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'saber',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"saber":\\s*".+?"[^}]*}',
},
],
},
@@ -1338,7 +1380,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: '@stencil/core',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@stencil\\/core":\\s*".+?"[^}]*}',
},
],
},
@@ -1399,15 +1443,11 @@ export const frameworks = [
sort: 2,
envPrefix: 'NUXT_ENV_',
detectors: {
some: [
every: [
{
matchPackage: 'nuxt',
},
{
matchPackage: 'nuxt3',
},
{
matchPackage: 'nuxt-edge',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"nuxt3?(-edge)?":\\s*".+?"[^}]*}',
},
],
},
@@ -1463,7 +1503,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: '@redwoodjs/core',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@redwoodjs\\/core":\\s*".+?"[^}]*}',
},
],
},
@@ -1588,10 +1630,7 @@ export const frameworks = [
description: 'A Brunch app, created with the Brunch CLI.',
website: 'https://brunch.io/',
detectors: {
some: [
{
matchPackage: 'brunch',
},
every: [
{
path: 'brunch-config.js',
},
@@ -1684,47 +1723,6 @@ export const frameworks = [
getOutputDirName: async () => 'public',
defaultVersion: '0.13.0', // Must match the build image
},
{
name: 'Hydrogen',
slug: 'hydrogen',
demo: 'https://hydrogen-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/hydrogen.svg',
tagline: 'React framework for headless commerce',
description: 'React framework for headless commerce',
website: 'https://hydrogen.shopify.dev',
useRuntime: { src: 'package.json', use: '@vercel/hydrogen' },
detectors: {
some: [
{
matchPackage: '@shopify/hydrogen',
},
{
path: 'hydrogen.config.js',
},
{
path: 'hydrogen.config.ts',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
value: 'shopify hydrogen build',
placeholder: '`npm run build` or `shopify hydrogen build`',
},
devCommand: {
value: 'shopify hydrogen dev',
placeholder: 'shopify hydrogen dev',
},
outputDirectory: {
value: 'dist',
},
},
dependency: '@shopify/hydrogen',
getOutputDirName: async () => 'dist',
},
{
name: 'Vite',
slug: 'vite',
@@ -1738,7 +1736,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'vite',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"vite":\\s*".+?"[^}]*}',
},
],
},
@@ -1772,7 +1772,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'vitepress',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"vitepress":\\s*".+?"[^}]*}',
},
],
},
@@ -1804,7 +1806,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'vuepress',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*vuepress:\\s*".+?"[^}]*}',
},
],
},
@@ -1837,7 +1841,9 @@ export const frameworks = [
detectors: {
every: [
{
matchPackage: 'parcel',
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"parcel":\\s*".+?"[^}]*}',
},
],
},
@@ -1925,6 +1931,44 @@ export const frameworks = [
},
],
},
{
name: 'Hydrogen',
slug: 'hydrogen',
demo: 'https://hydrogen-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/hydrogen.svg',
tagline: 'React framework for headless commerce',
description: 'React framework for headless commerce',
website: 'https://hydrogen.shopify.dev',
useRuntime: { src: 'package.json', use: '@vercel/hydrogen' },
detectors: {
some: [
{
path: 'hydrogen.config.js',
},
{
path: 'hydrogen.config.ts',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
value: 'shopify hydrogen build',
placeholder: '`npm run build` or `shopify hydrogen build`',
},
devCommand: {
value: 'shopify hydrogen dev',
placeholder: 'shopify hydrogen dev',
},
outputDirectory: {
value: 'dist',
},
},
dependency: '@shopify/hydrogen',
getOutputDirName: async () => 'dist',
},
{
name: 'Other',
slug: null,

View File

@@ -2,24 +2,15 @@ import { Rewrite, Route } from '@vercel/routing-utils';
export interface FrameworkDetectionItem {
/**
* A file path to detect.
* If specified, "matchPackage" cannot be specified.
* @example "some-framework.config.json"
* A file path
* @example "package.json"
*/
path?: string;
path: string;
/**
* A matcher for the entire file.
* If specified, "matchPackage" cannot be specified.
* A matcher
* @example "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"next\":\\s*\".+?\"[^}]*}"
*/
matchContent?: string;
/**
* A matcher for a package specifically found in a "package.json" file.
* If specified, "path" and "matchContext" cannot be specified.
* If specified in multiple detectors, the first one will be used to resolve the framework version.
* @example "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"next\":\\s*\".+?\"[^}]*}"
*/
matchPackage?: string;
}
export interface SettingPlaceholder {

View File

@@ -17,7 +17,7 @@ const SchemaFrameworkDetectionItem = {
items: [
{
type: 'object',
required: [],
required: ['path'],
additionalProperties: false,
properties: {
path: {
@@ -26,9 +26,6 @@ const SchemaFrameworkDetectionItem = {
matchContent: {
type: 'string',
},
matchPackage: {
type: 'string',
},
},
},
],

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/fs-detectors",
"version": "3.7.1",
"version": "3.6.1",
"description": "Vercel filesystem detectors",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -16,12 +16,12 @@
"scripts": {
"build": "tsc",
"test": "jest --env node --verbose --runInBand --bail test/unit.*test.*",
"test-unit": "pnpm test"
"test-unit": "yarn test"
},
"dependencies": {
"@vercel/error-utils": "workspace:1.0.5",
"@vercel/frameworks": "workspace:1.2.1",
"@vercel/routing-utils": "workspace:2.1.5",
"@vercel/error-utils": "1.0.3",
"@vercel/frameworks": "1.1.18",
"@vercel/routing-utils": "2.1.3",
"glob": "8.0.3",
"js-yaml": "4.1.0",
"json5": "2.2.2",
@@ -35,7 +35,7 @@
"@types/minimatch": "3.0.5",
"@types/node": "14.18.33",
"@types/semver": "7.3.10",
"@vercel/build-utils": "workspace:5.8.0",
"@vercel/build-utils": "5.7.4",
"typescript": "4.3.4"
}
}

View File

@@ -453,7 +453,9 @@ function getApiMatches() {
return [
{ src: 'middleware.[jt]s', use: `@vercel/node`, config },
{ src: 'api/**/*.+(js|mjs|ts|tsx)', use: `@vercel/node`, config },
{ src: 'api/**/*.js', use: `@vercel/node`, config },
{ src: 'api/**/*.mjs', use: `@vercel/node`, config },
{ src: 'api/**/*.ts', use: `@vercel/node`, config },
{ src: 'api/**/!(*_test).go', use: `@vercel/go`, config },
{ src: 'api/**/*.py', use: `@vercel/python`, config },
{ src: 'api/**/*.rb', use: `@vercel/ruby`, config },

View File

@@ -1,5 +1,4 @@
import type { Framework, FrameworkDetectionItem } from '@vercel/frameworks';
import { spawnSync } from 'child_process';
import { DetectorFilesystem } from './detectors/filesystem';
interface BaseFramework {
@@ -12,96 +11,49 @@ export interface DetectFrameworkOptions {
frameworkList: readonly BaseFramework[];
}
export interface DetectFrameworkRecordOptions {
fs: DetectorFilesystem;
frameworkList: readonly Framework[];
}
type MatchResult = {
framework: BaseFramework;
detectedVersion?: string;
};
async function matches(
fs: DetectorFilesystem,
framework: BaseFramework
): Promise<MatchResult | undefined> {
async function matches(fs: DetectorFilesystem, framework: BaseFramework) {
const { detectors } = framework;
if (!detectors) {
return;
return false;
}
const { every, some } = detectors;
if (every !== undefined && !Array.isArray(every)) {
return;
return false;
}
if (some !== undefined && !Array.isArray(some)) {
return;
return false;
}
const check = async ({
path,
matchContent,
matchPackage,
}: FrameworkDetectionItem): Promise<MatchResult | undefined> => {
if (matchPackage && matchContent) {
throw new Error(
`Cannot specify "matchPackage" and "matchContent" in the same detector for "${framework.slug}"`
);
}
if (matchPackage && path) {
throw new Error(
`Cannot specify "matchPackage" and "path" in the same detector for "${framework.slug}" because "path" is assumed to be "package.json".`
);
}
if (!path && !matchPackage) {
throw new Error(
`Must specify either "path" or "matchPackage" in detector for "${framework.slug}".`
);
}
const check = async ({ path, matchContent }: FrameworkDetectionItem) => {
if (!path) {
path = 'package.json';
}
if (matchPackage) {
matchContent = `"(dev)?(d|D)ependencies":\\s*{[^}]*"${matchPackage}":\\s*"(.+?)"[^}]*}`;
return false;
}
if ((await fs.hasPath(path)) === false) {
return;
return false;
}
if (matchContent) {
if ((await fs.isFile(path)) === false) {
return;
return false;
}
const regex = new RegExp(matchContent, 'm');
const regex = new RegExp(matchContent, 'gm');
const content = await fs.readFile(path);
const match = content.toString().match(regex);
if (!match) {
return;
}
if (matchPackage && match[3]) {
return {
framework,
detectedVersion: match[3],
};
if (!regex.test(content.toString())) {
return false;
}
}
return {
framework,
};
return true;
};
const result: (MatchResult | undefined)[] = [];
const result: boolean[] = [];
if (every) {
const everyResult = await Promise.all(every.map(item => check(item)));
@@ -109,12 +61,11 @@ async function matches(
}
if (some) {
let someResult: MatchResult | undefined;
let someResult = false;
for (const item of some) {
const itemResult = await check(item);
if (itemResult) {
someResult = itemResult;
if (await check(item)) {
someResult = true;
break;
}
}
@@ -122,20 +73,9 @@ async function matches(
result.push(someResult);
}
if (!result.every(res => !!res)) {
return;
}
const detectedVersion = result.find(
r => typeof r === 'object' && r.detectedVersion
)?.detectedVersion;
return {
framework,
detectedVersion,
};
return result.every(res => res === true);
}
// TODO: Deprecate and replace with `detectFrameworkRecord`
export async function detectFramework({
fs,
frameworkList,
@@ -150,70 +90,3 @@ export async function detectFramework({
);
return result.find(res => res !== null) ?? null;
}
/**
* Framework with a `detectedVersion` specifying the version
* or version range of the relevant package
*/
type VersionedFramework = Framework & {
detectedVersion?: string;
};
// Note: Does not currently support a `frameworkList` of monorepo managers
export async function detectFrameworkRecord({
fs,
frameworkList,
}: DetectFrameworkRecordOptions): Promise<VersionedFramework | null> {
const result = await Promise.all(
frameworkList.map(async frameworkMatch => {
const matchResult = await matches(fs, frameworkMatch);
if (matchResult) {
return {
...frameworkMatch,
detectedVersion: matchResult?.detectedVersion,
};
}
return null;
})
);
const frameworkRecord = result.find(res => res !== null) ?? null;
return frameworkRecord;
}
export function detectFrameworkVersion(
frameworkRecord: Framework
): string | undefined {
const allDetectors = [
...(frameworkRecord.detectors?.every || []),
...(frameworkRecord.detectors?.some || []),
];
const firstMatchPackage = allDetectors.find(d => d.matchPackage);
if (!firstMatchPackage?.matchPackage) {
return;
}
return lookupInstalledVersion(
process.execPath,
firstMatchPackage.matchPackage
);
}
function lookupInstalledVersion(
cwd: string,
packageName: string
): string | undefined {
try {
const script = `require('${packageName}/package.json').version`;
return spawnSync(cwd, ['-p', script], {
encoding: 'utf-8',
}).stdout.trim();
} catch (error) {
console.debug(
`Error looking up version of installed package "${packageName}": ${error}`
);
}
return;
}

View File

@@ -5,11 +5,7 @@ export {
detectApiExtensions,
} from './detect-builders';
export { detectFileSystemAPI } from './detect-file-system-api';
export {
detectFramework,
detectFrameworkRecord,
detectFrameworkVersion,
} from './detect-framework';
export { detectFramework } from './detect-framework';
export { getProjectPaths } from './get-project-paths';
export { DetectorFilesystem } from './detectors/filesystem';
export { LocalFileSystemDetector } from './detectors/local-file-system-detector';

View File

@@ -66,7 +66,7 @@ export async function getMonorepoDefaultSettings(
return {
monorepoManager: 'turbo',
buildCommand: `cd ${relativeToRoot} && npx turbo run build --filter={${projectPath}}...`,
buildCommand: `cd ${relativeToRoot} && npx turbo run build --filter=${projectName}...`,
installCommand: `cd ${relativeToRoot} && ${packageManager} install`,
commandForIgnoringBuildStep: `cd ${relativeToRoot} && npx turbo-ignore`,
};

View File

@@ -1369,25 +1369,6 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
expect((errorRoutes![0] as Source).status).toBe(404);
});
it('api detect node tsx files', async () => {
const files = [
'api/index.tsx',
'api/users.tsx',
'api/config/staging.tsx',
'api/config/production.tsx',
'api/src/controllers/health.tsx',
'api/src/controllers/user.module.tsx',
];
const { builders, errorRoutes } = await detectBuilders(files, undefined, {
featHandleMiss,
});
expect(builders?.length).toBe(6);
expect(builders!.every(b => b.src!.endsWith('.tsx'))).toBe(true);
expect(errorRoutes?.length).toBe(1);
expect((errorRoutes![0] as Source).status).toBe(404);
});
it('just public', async () => {
const files = ['public/index.html', 'public/favicon.ico', 'README.md'];

View File

@@ -1,35 +0,0 @@
import frameworkList from '@vercel/frameworks';
import { detectFramework } from '../src';
import { FixtureFilesystem } from './utils/fixture-filesystem';
import { readdirSync, lstatSync } from 'fs';
import { join } from 'path';
function getExamples() {
const root = join(__dirname, '..', '..', '..');
const examplesPath = join(root, 'examples');
const examples = readdirSync(examplesPath);
const exampleDirs = examples.filter(example => {
const examplePath = join(examplesPath, example);
const stat = lstatSync(examplePath);
return stat.isDirectory();
});
return exampleDirs.map(exampleDirName => {
return [exampleDirName, join(examplesPath, exampleDirName)];
});
}
describe('examples should be detected', () => {
const examples = getExamples();
it.each(examples)('%s', async (example, examplePath) => {
const fs = new FixtureFilesystem(examplePath);
const framework = await detectFramework({ fs, frameworkList });
if (!framework) {
throw new Error(`Framework not detected for example "${example}".`);
}
expect(framework).toBe(example);
});
});

View File

@@ -1,194 +0,0 @@
import frameworkList from '@vercel/frameworks';
import { detectFrameworkRecord } from '../src';
import VirtualFilesystem from './virtual-file-system';
describe('detectFrameworkRecord', () => {
it('Do not detect anything', async () => {
const fs = new VirtualFilesystem({
'README.md': '# hi',
'api/cheese.js': 'export default (req, res) => res.end("cheese");',
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe(undefined);
});
it('Detects a framework record with a matchPackage detector', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
next: '9.0.0',
},
}),
});
const frameworkRecord = await detectFrameworkRecord({ fs, frameworkList });
if (!frameworkRecord) {
throw new Error(
'`frameworkRecord` was not detected, expected "nextjs" frameworks object'
);
}
expect(frameworkRecord.slug).toBe('nextjs');
expect(frameworkRecord.name).toBe('Next.js');
expect(frameworkRecord.detectedVersion).toBe('9.0.0');
});
it('Detects a framework record with a matchPackage detector with slashes', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
'@ionic/angular': '5.0.0',
},
}),
});
const frameworkRecord = await detectFrameworkRecord({ fs, frameworkList });
if (!frameworkRecord) {
throw new Error(
'`frameworkRecord` was not detected, expected "ionic-angular" frameworks object'
);
}
expect(frameworkRecord.slug).toBe('ionic-angular');
expect(frameworkRecord.detectedVersion).toBe('5.0.0');
});
it('Detect first framework version found', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
'nuxt-edge': '3.0.0',
nuxt3: '2.0.0',
nuxt: '1.0.0',
},
}),
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('nuxtjs');
expect(framework?.detectedVersion).toBe('1.0.0');
});
it('Detect frameworks based on ascending order in framework list', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
next: '9.0.0',
gatsby: '4.18.0',
},
}),
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('nextjs');
});
it('Detect Nuxt.js', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
nuxt: '1.0.0',
},
}),
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('nuxtjs');
});
it('Detect Nuxt.js edge', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
'nuxt-edge': '1.0.0',
},
}),
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('nuxtjs');
});
it('Detect Gatsby', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
gatsby: '1.0.0',
},
}),
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('gatsby');
});
it('Detect Hugo #1', async () => {
const fs = new VirtualFilesystem({
'config.yaml': 'baseURL: http://example.org/',
'content/post.md': '# hello world',
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('hugo');
});
it('Detect Hugo #2', async () => {
const fs = new VirtualFilesystem({
'config.json': '{ "baseURL": "http://example.org/" }',
'content/post.md': '# hello world',
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('hugo');
});
it('Detect Hugo #3', async () => {
const fs = new VirtualFilesystem({
'config.toml': 'baseURL = "http://example.org/"',
'content/post.md': '# hello world',
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('hugo');
});
it('Detect Jekyll', async () => {
const fs = new VirtualFilesystem({
'_config.yml': 'config',
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('jekyll');
});
it('Detect Middleman', async () => {
const fs = new VirtualFilesystem({
'config.rb': 'config',
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('middleman');
});
it('Detect Scully', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
'@angular/cli': 'latest',
'@scullyio/init': 'latest',
},
}),
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('scully');
});
it('Detect Zola', async () => {
const fs = new VirtualFilesystem({
'config.toml': 'base_url = "/"',
});
const framework = await detectFrameworkRecord({ fs, frameworkList });
expect(framework?.slug).toBe('zola');
});
});

View File

@@ -1,7 +1,131 @@
import path from 'path';
import frameworkList from '@vercel/frameworks';
import workspaceManagers from '../src/workspaces/workspace-managers';
import { detectFramework } from '../src';
import VirtualFilesystem from './virtual-file-system';
import { detectFramework, DetectorFilesystem } from '../src';
import { DetectorFilesystemStat } from '../src/detectors/filesystem';
const posixPath = path.posix;
class VirtualFilesystem extends DetectorFilesystem {
private files: Map<string, Buffer>;
private cwd: string;
constructor(files: { [key: string]: string | Buffer }, cwd = '') {
super();
this.files = new Map();
this.cwd = cwd;
Object.entries(files).map(([key, value]) => {
const buffer = typeof value === 'string' ? Buffer.from(value) : value;
this.files.set(key, buffer);
});
}
private _normalizePath(rawPath: string): string {
return posixPath.normalize(rawPath);
}
async _hasPath(name: string): Promise<boolean> {
const basePath = this._normalizePath(posixPath.join(this.cwd, name));
for (const file of this.files.keys()) {
if (file.startsWith(basePath)) {
return true;
}
}
return false;
}
async _isFile(name: string): Promise<boolean> {
const basePath = this._normalizePath(posixPath.join(this.cwd, name));
return this.files.has(basePath);
}
async _readFile(name: string): Promise<Buffer> {
const basePath = this._normalizePath(posixPath.join(this.cwd, name));
const file = this.files.get(basePath);
if (file === undefined) {
throw new Error('File does not exist');
}
if (typeof file === 'string') {
return Buffer.from(file);
}
return file;
}
/**
* An example of how to implement readdir for a virtual filesystem.
*/
async _readdir(name = '/'): Promise<DetectorFilesystemStat[]> {
return (
[...this.files.keys()]
.map(filepath => {
const basePath = this._normalizePath(
posixPath.join(this.cwd, name === '/' ? '' : name)
);
const fileDirectoryName = posixPath.dirname(filepath);
if (fileDirectoryName === basePath) {
return {
name: posixPath.basename(filepath),
path: filepath.replace(
this.cwd === '' ? this.cwd : `${this.cwd}/`,
''
),
type: 'file',
};
}
if (
(basePath === '.' && fileDirectoryName !== '.') ||
fileDirectoryName.startsWith(basePath)
) {
let subDirectoryName = fileDirectoryName.replace(
basePath === '.' ? '' : `${basePath}/`,
''
);
if (subDirectoryName.includes('/')) {
subDirectoryName = subDirectoryName.split('/')[0];
}
return {
name: subDirectoryName,
path:
name === '/'
? subDirectoryName
: this._normalizePath(posixPath.join(name, subDirectoryName)),
type: 'dir',
};
}
return null;
})
// remove nulls
.filter((stat): stat is DetectorFilesystemStat => stat !== null)
// remove duplicates
.filter(
(stat, index, self) =>
index ===
self.findIndex(s => s.name === stat.name && s.path === stat.path)
)
);
}
/**
* An example of how to implement chdir for a virtual filesystem.
*/
_chdir(name: string): DetectorFilesystem {
const basePath = this._normalizePath(posixPath.join(this.cwd, name));
const files = Object.fromEntries(
[...this.files.keys()].map(key => [key, this.files.get(key) ?? ''])
);
return new VirtualFilesystem(files, basePath);
}
}
describe('DetectorFilesystem', () => {
it('should return the directory contents relative to the cwd', async () => {
@@ -221,30 +345,6 @@ describe('DetectorFilesystem', () => {
expect(await detectFramework({ fs, frameworkList })).toBe('nuxtjs');
});
it('Detect Nuxt.js Edge', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
'nuxt-edge': '1.0.0',
},
}),
});
expect(await detectFramework({ fs, frameworkList })).toBe('nuxtjs');
});
it('Detect Nuxt.js 3', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
nuxt3: '1.0.0',
},
}),
});
expect(await detectFramework({ fs, frameworkList })).toBe('nuxtjs');
});
it('Detect Gatsby', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
@@ -328,69 +428,5 @@ describe('DetectorFilesystem', () => {
expect(await detectFramework({ fs, frameworkList })).toBe('blitzjs');
});
it('Detect Ember via `ember-source`', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
'ember-source': 'latest',
},
}),
});
expect(await detectFramework({ fs, frameworkList })).toBe('ember');
});
it('Detect Ember via `ember-cli`', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
'ember-cli': 'latest',
},
}),
});
expect(await detectFramework({ fs, frameworkList })).toBe('ember');
});
it('Detect Brunch via `brunch`', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
brunch: 'latest',
},
}),
});
expect(await detectFramework({ fs, frameworkList })).toBe('brunch');
});
it('Detect Brunch via `brunch-config.js`', async () => {
const fs = new VirtualFilesystem({
'brunch-config.js': '// some config',
});
expect(await detectFramework({ fs, frameworkList })).toBe('brunch');
});
it('Detect Hydrogen via `hydrogen.config.js`', async () => {
const fs = new VirtualFilesystem({
'hydrogen.config.js': '// some config',
});
expect(await detectFramework({ fs, frameworkList })).toBe('hydrogen');
});
it('Detect Hydrogen via `@shopify/hydrogen`', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
'@shopify/hydrogen': 'latest',
},
}),
});
expect(await detectFramework({ fs, frameworkList })).toBe('hydrogen');
});
});
});

View File

@@ -37,8 +37,7 @@ describe('getMonorepoDefaultSettings', () => {
const expectedResultMap: Record<string, Record<string, string>> = {
turbo: {
monorepoManager: 'turbo',
buildCommand:
'cd ../.. && npx turbo run build --filter={packages/app-1}...',
buildCommand: 'cd ../.. && npx turbo run build --filter=app-1...',
installCommand: 'cd ../.. && yarn install',
commandForIgnoringBuildStep: 'cd ../.. && npx turbo-ignore',
},

View File

@@ -1,126 +0,0 @@
import path from 'path';
import { DetectorFilesystem } from '../src';
import { DetectorFilesystemStat } from '../src/detectors/filesystem';
const posixPath = path.posix;
export default class VirtualFilesystem extends DetectorFilesystem {
private files: Map<string, Buffer>;
private cwd: string;
constructor(files: { [key: string]: string | Buffer }, cwd = '') {
super();
this.files = new Map();
this.cwd = cwd;
Object.entries(files).map(([key, value]) => {
const buffer = typeof value === 'string' ? Buffer.from(value) : value;
this.files.set(key, buffer);
});
}
private _normalizePath(rawPath: string): string {
return posixPath.normalize(rawPath);
}
async _hasPath(name: string): Promise<boolean> {
const basePath = this._normalizePath(posixPath.join(this.cwd, name));
for (const file of this.files.keys()) {
if (file.startsWith(basePath)) {
return true;
}
}
return false;
}
async _isFile(name: string): Promise<boolean> {
const basePath = this._normalizePath(posixPath.join(this.cwd, name));
return this.files.has(basePath);
}
async _readFile(name: string): Promise<Buffer> {
const basePath = this._normalizePath(posixPath.join(this.cwd, name));
const file = this.files.get(basePath);
if (file === undefined) {
throw new Error('File does not exist');
}
if (typeof file === 'string') {
return Buffer.from(file);
}
return file;
}
/**
* An example of how to implement readdir for a virtual filesystem.
*/
async _readdir(name = '/'): Promise<DetectorFilesystemStat[]> {
return (
[...this.files.keys()]
.map(filepath => {
const basePath = this._normalizePath(
posixPath.join(this.cwd, name === '/' ? '' : name)
);
const fileDirectoryName = posixPath.dirname(filepath);
if (fileDirectoryName === basePath) {
return {
name: posixPath.basename(filepath),
path: filepath.replace(
this.cwd === '' ? this.cwd : `${this.cwd}/`,
''
),
type: 'file',
};
}
if (
(basePath === '.' && fileDirectoryName !== '.') ||
fileDirectoryName.startsWith(basePath)
) {
let subDirectoryName = fileDirectoryName.replace(
basePath === '.' ? '' : `${basePath}/`,
''
);
if (subDirectoryName.includes('/')) {
subDirectoryName = subDirectoryName.split('/')[0];
}
return {
name: subDirectoryName,
path:
name === '/'
? subDirectoryName
: this._normalizePath(posixPath.join(name, subDirectoryName)),
type: 'dir',
};
}
return null;
})
// remove nulls
.filter((stat): stat is DetectorFilesystemStat => stat !== null)
// remove duplicates
.filter(
(stat, index, self) =>
index ===
self.findIndex(s => s.name === stat.name && s.path === stat.path)
)
);
}
/**
* An example of how to implement chdir for a virtual filesystem.
*/
_chdir(name: string): DetectorFilesystem {
const basePath = this._normalizePath(posixPath.join(this.cwd, name));
const files = Object.fromEntries(
[...this.files.keys()].map(key => [key, this.files.get(key) ?? ''])
);
return new VirtualFilesystem(files, basePath);
}
}

View File

@@ -18,6 +18,12 @@ This plugin sends [Core Web Vitals](https://web.dev/vitals/) to Vercel Analytics
npm i @vercel/gatsby-plugin-vercel-analytics
```
or
```bash
yarn add @vercel/gatsby-plugin-vercel-analytics
```
## Usage
```js

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/gatsby-plugin-vercel-analytics",
"version": "1.0.3",
"version": "1.0.0",
"description": "Track Core Web Vitals in Gatsby projects with Vercel Analytics.",
"main": "index.js",
"files": [

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/go",
"version": "2.2.26",
"version": "2.2.23",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
@@ -12,7 +12,7 @@
"scripts": {
"build": "node build",
"test": "jest --env node --verbose --runInBand --bail",
"test-integration-once": "pnpm test"
"test-integration-once": "yarn test"
},
"files": [
"dist"
@@ -33,10 +33,9 @@
"@types/execa": "^0.9.0",
"@types/fs-extra": "^5.0.5",
"@types/jest": "28.1.6",
"@types/node": "14.18.33",
"@types/node-fetch": "^2.3.0",
"@types/tar": "^4.0.0",
"@vercel/build-utils": "workspace:5.8.0",
"@vercel/build-utils": "5.7.4",
"@vercel/ncc": "0.24.0",
"async-retry": "1.3.1",
"execa": "^1.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/hydrogen",
"version": "0.0.40",
"version": "0.0.37",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://vercel.com/docs",
@@ -11,7 +11,7 @@
},
"scripts": {
"build": "node build.js",
"test-integration-once": "pnpm test test/test.js",
"test-integration-once": "yarn test test/test.js",
"test": "jest --env node --verbose --bail --runInBand"
},
"files": [
@@ -21,11 +21,8 @@
"devDependencies": {
"@types/jest": "27.5.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "workspace:5.8.0",
"@vercel/static-config": "workspace:2.0.8",
"execa": "3.2.0",
"fs-extra": "11.1.0",
"ts-morph": "12.0.0",
"@vercel/build-utils": "5.7.4",
"@vercel/static-config": "2.0.6",
"typescript": "4.6.4"
}
}

View File

@@ -1,17 +1,17 @@
{
"name": "@vercel/next",
"version": "3.3.11",
"version": "3.3.8",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
"scripts": {
"build": "node build.js",
"build-dev": "node build.js --dev",
"test": "jest --env node --verbose --bail --runInBand --testTimeout=360000",
"test-unit": "pnpm test test/unit/",
"test-next-local": "pnpm test test/integration/*.test.js test/integration/*.test.ts",
"test-next-local:middleware": "pnpm test test/integration/middleware.test.ts",
"test-integration-once": "rm -f test/builder-info.json; pnpm test test/fixtures/**/*.test.js"
"test": "jest --env node --verbose --bail --runInBand",
"test-unit": "yarn test test/unit/",
"test-next-local": "jest --env node --verbose --bail --testTimeout=360000 test/integration/*.test.js test/integration/*.test.ts",
"test-next-local:middleware": "jest --env node --verbose --bail --useStderr --testTimeout=360000 test/integration/middleware.test.ts",
"test-integration-once": "rm test/builder-info.json; jest --env node --verbose --runInBand --bail test/fixtures/**/*.test.js"
},
"repository": {
"type": "git",
@@ -45,9 +45,9 @@
"@types/semver": "6.0.0",
"@types/text-table": "0.2.1",
"@types/webpack-sources": "3.2.0",
"@vercel/build-utils": "workspace:5.8.0",
"@vercel/build-utils": "5.7.4",
"@vercel/nft": "0.22.5",
"@vercel/routing-utils": "workspace:2.1.5",
"@vercel/routing-utils": "2.1.3",
"async-sema": "3.0.1",
"buffer-crc32": "0.2.13",
"bytes": "3.1.2",
@@ -61,7 +61,6 @@
"get-port": "5.0.0",
"nanoid": "3.3.4",
"ndjson": "2.0.0",
"pretty-bytes": "5.3.0",
"resolve-from": "5.0.0",
"semver": "6.1.1",
"set-cookie-parser": "2.4.6",

View File

@@ -932,7 +932,6 @@ export const build: BuildV2 = async ({
]
: []),
],
framework: { version: nextVersion },
};
}
@@ -2582,7 +2581,6 @@ export const build: BuildV2 = async ({
]),
]),
],
framework: { version: nextVersion },
};
};
@@ -2664,7 +2662,7 @@ async function getServerlessPages(params: {
for (const edgeFunctionFile of Object.keys(
middlewareManifest?.functions ?? {}
)) {
const edgePath = (edgeFunctionFile.slice(1) || 'index') + '.js';
const edgePath = edgeFunctionFile.slice(1) + '.js';
delete normalizedAppPaths[edgePath];
delete pages[edgePath];
}

View File

@@ -1143,15 +1143,15 @@ export async function serverBuild({
if (appDir) {
for (const route of dynamicRoutes) {
completeDynamicRoutes.push(route);
completeDynamicRoutes.push({
...route,
src: route.src.replace(
new RegExp(escapeStringRegexp('(?:/)?$')),
'(?:\\.rsc)(?:/)?$'
'(?:\\.rsc)?(?:/)?$'
),
dest: route.dest?.replace(/($|\?)/, '.rsc$1'),
});
completeDynamicRoutes.push(route);
}
} else {
completeDynamicRoutes.push(...dynamicRoutes);
@@ -1755,6 +1755,5 @@ export async function serverBuild({
},
]),
],
framework: { version: nextVersion },
};
}

View File

@@ -6,15 +6,6 @@
}
],
"probes": [
{
"path": "/dynamic/category-1/id-1",
"status": 200,
"headers": {
"RSC": "1"
},
"mustContain": ":{",
"mustNotContain": "<html"
},
{
"path": "/ssg",
"status": 200,

View File

@@ -8,18 +8,6 @@ jest.setTimeout(ms('6m'));
describe(`${__dirname.split(path.sep).pop()}`, () => {
it('should normalize routes in build results output', async () => {
// TODO: remove after bug with edge functions on Windows
// is resolved upstream in Next.js
if (process.platform === 'win32') {
const indexPage = path.join(__dirname, 'pages/index.tsx');
await fs.writeFile(
indexPage,
(
await fs.readFile(indexPage, 'utf8')
).replace('runtime: ', '// runtime: ')
);
}
const files = [
'index.test.js',
'next.config.js',
@@ -47,9 +35,5 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
expect(output).toHaveProperty('test/api/hello');
expect(output['test/api/hello'].type).toEqual('EdgeFunction');
for (const name in output) {
expect(output[name].type).not.toBe('Lambda');
}
});
});

View File

@@ -9,8 +9,3 @@ const Home: NextPage = () => {
}
export default Home
export const config = {
runtime: 'experimental-edge',
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node-bridge",
"version": "3.1.5",
"version": "3.1.3",
"license": "MIT",
"main": "./index.js",
"repository": {
@@ -18,13 +18,11 @@
"scripts": {
"build": "node build.js",
"test": "jest --env node --verbose --runInBand --bail",
"test-unit": "pnpm test"
"test-unit": "yarn test"
},
"devDependencies": {
"@types/aws-lambda": "8.10.19",
"@types/node": "14.18.33",
"execa": "3.2.0",
"fs-extra": "10.0.0",
"jsonlines": "0.1.1",
"test-listen": "1.1.0",
"typescript": "4.3.4"

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node",
"version": "2.8.8",
"version": "2.8.5",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -12,8 +12,8 @@
"scripts": {
"build": "node build",
"test": "jest --env node --verbose --bail --runInBand",
"test-unit": "pnpm test test/prepare-cache.test.ts test/utils.test.ts",
"test-integration-once": "pnpm test test/integration-*.test.js"
"test-unit": "yarn test test/prepare-cache.test.ts test/utils.test.ts",
"test-integration-once": "yarn test test/integration-*.test.js"
},
"files": [
"dist"
@@ -31,9 +31,9 @@
"dependencies": {
"@edge-runtime/vm": "2.0.0",
"@types/node": "14.18.33",
"@vercel/build-utils": "workspace:5.8.0",
"@vercel/node-bridge": "workspace:3.1.5",
"@vercel/static-config": "workspace:2.0.8",
"@vercel/build-utils": "5.7.4",
"@vercel/node-bridge": "3.1.3",
"@vercel/static-config": "2.0.6",
"edge-runtime": "2.0.0",
"esbuild": "0.14.47",
"exit-hook": "2.2.1",
@@ -57,11 +57,8 @@
"content-type": "1.0.4",
"cookie": "0.4.0",
"etag": "1.8.1",
"execa": "3.2.0",
"fs-extra": "11.1.0",
"path-to-regexp": "6.2.1",
"source-map-support": "0.5.12",
"test-listen": "1.1.0",
"ts-morph": "12.0.0"
"test-listen": "1.1.0"
}
}

View File

@@ -1,5 +1,5 @@
// provided by the edge runtime:
/* global addEventListener Request Response */
/* global addEventListener Request Response atob */
// provided by our edge handler logic:
/* global IS_MIDDLEWARE ENTRYPOINT_LABEL */

View File

@@ -1,32 +0,0 @@
/** @jsx h */
import { h } from '../jsx-runtime.js';
import { ImageResponse } from '@vercel/og';
export const config = { runtime: 'edge' };
export default function () {
return new ImageResponse(
(
<div
style={{
fontSize: 128,
color: 'black',
background: 'green',
width: '100%',
height: '100%',
display: 'flex',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
}}
>
Hello world!
</div>
),
{
width: 1200,
height: 600,
},
);
}

View File

@@ -1,3 +0,0 @@
export function h(type: any, props: any[]) {
return { type, props };
}

View File

@@ -1,15 +0,0 @@
{
"private": true,
"type": "module",
"packageManager": "yarn@1.22.19",
"scripts": {
"test": "rm -rf dist && tsc && cat dist/api/index.js"
},
"dependencies": {
"@vercel/og": "0.0.22"
},
"devDependencies": {
"@types/node": "18.11.18",
"typescript": "4.9.4"
}
}

View File

@@ -1,40 +0,0 @@
const assert = require('assert').strict;
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
async function tryTest({
pathname,
deploymentUrl,
fetch,
randomness,
retries = 4,
}) {
try {
const res = await fetch(`https://${deploymentUrl}${pathname}`);
assert.equal(res.status, 200);
assert.equal(res.headers.get('content-type'), 'image/png');
console.log(`Finished testing "${pathname}" probe.`);
} catch (e) {
if (retries === 0) {
console.error(e);
throw e;
}
console.log(`Failed "${pathname}" probe. Retries remaining: ${retries}`);
await sleep(100);
await tryTest({
pathname,
deploymentUrl,
fetch,
randomness,
retries: retries - 1,
});
}
}
module.exports = async ({ deploymentUrl, fetch, randomness }) => {
await tryTest({
pathname: '/api/og',
deploymentUrl,
fetch,
randomness,
});
};

View File

@@ -1,11 +0,0 @@
{
"compilerOptions": {
"strict": false,
"skipLibCheck": true,
"moduleResolution": "node",
"module": "esnext",
"target": "esnext",
"jsx": "react",
"outDir": "dist"
}
}

View File

@@ -1,114 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@resvg/resvg-wasm@2.0.0-alpha.4":
version "2.0.0-alpha.4"
resolved "https://registry.yarnpkg.com/@resvg/resvg-wasm/-/resvg-wasm-2.0.0-alpha.4.tgz#fc2f86186a9641df030d8f9f3f9d995899cd1ecb"
integrity sha512-pWIG9a/x1ky8gXKRhPH1OPKpHFoMN1ISLbJ+O+gPXQHIAKhNd5I28RlWf7q576hAOQA9JZTlo3p/M2uyLzJmmw==
"@shuding/opentype.js@1.4.0-beta.0":
version "1.4.0-beta.0"
resolved "https://registry.yarnpkg.com/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz#5d1e7e9e056f546aad41df1c5043f8f85d39e24b"
integrity sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==
dependencies:
fflate "^0.7.3"
string.prototype.codepointat "^0.2.1"
"@types/node@18.11.18":
version "18.11.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f"
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
"@types/yoga-layout@1.9.2":
version "1.9.2"
resolved "https://registry.yarnpkg.com/@types/yoga-layout/-/yoga-layout-1.9.2.tgz#efaf9e991a7390dc081a0b679185979a83a9639a"
integrity sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==
"@vercel/og@0.0.22":
version "0.0.22"
resolved "https://registry.yarnpkg.com/@vercel/og/-/og-0.0.22.tgz#f17a6b0dceca4c58ea92499e6957598df5ce392e"
integrity sha512-HJjYfjpuNVnxwH7GnEv5QxzdIV4xytjY2RkVmhaOAKlms4X071WSPR9Jp6vjZ3Zmjz0tKSiRnrT5uN/PkW/q9Q==
dependencies:
"@resvg/resvg-wasm" "2.0.0-alpha.4"
satori "0.0.45"
yoga-wasm-web "0.1.2"
camelize@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
css-background-parser@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/css-background-parser/-/css-background-parser-0.1.0.tgz#48a17f7fe6d4d4f1bca3177ddf16c5617950741b"
integrity sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==
css-box-shadow@1.0.0-3:
version "1.0.0-3"
resolved "https://registry.yarnpkg.com/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz#9eaeb7140947bf5d649fc49a19e4bbaa5f602713"
integrity sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==
css-color-keywords@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==
css-to-react-native@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.1.0.tgz#e783474149997608986afcff614405714a8fe1ac"
integrity sha512-AryfkFA29b4I3vG7N4kxFboq15DxwSXzhXM37XNEjwJMgjYIc8BcqfiprpAqX0zadI5PMByEIwAMzXxk5Vcc4g==
dependencies:
camelize "^1.0.0"
css-color-keywords "^1.0.0"
postcss-value-parser "^4.0.2"
emoji-regex@^10.2.1:
version "10.2.1"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.2.1.tgz#a41c330d957191efd3d9dfe6e1e8e1e9ab048b3f"
integrity sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==
fflate@^0.7.3:
version "0.7.4"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.7.4.tgz#61587e5d958fdabb5a9368a302c25363f4f69f50"
integrity sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==
postcss-value-parser@^4.0.2, postcss-value-parser@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
satori@0.0.45:
version "0.0.45"
resolved "https://registry.yarnpkg.com/satori/-/satori-0.0.45.tgz#b91c7354c2baf5765b43eba6391f72067f5c3fd1"
integrity sha512-jF7AAK5ddZQVE6r6gTG07YxOvhldev0wBrFqBXRNbPH/mEy15gfIqA4xjGfVHczcGYZvY/VWmKri6DzRJF8cgQ==
dependencies:
"@shuding/opentype.js" "1.4.0-beta.0"
css-background-parser "^0.1.0"
css-box-shadow "1.0.0-3"
css-to-react-native "^3.0.0"
emoji-regex "^10.2.1"
postcss-value-parser "^4.2.0"
yoga-layout-prebuilt "^1.10.0"
string.prototype.codepointat@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc"
integrity sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==
typescript@4.9.4:
version "4.9.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
yoga-layout-prebuilt@^1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/yoga-layout-prebuilt/-/yoga-layout-prebuilt-1.10.0.tgz#2936fbaf4b3628ee0b3e3b1df44936d6c146faa6"
integrity sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g==
dependencies:
"@types/yoga-layout" "1.9.2"
yoga-wasm-web@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/yoga-wasm-web/-/yoga-wasm-web-0.1.2.tgz#05d3fc9cbdfd57ac9682debb5001aca075489a39"
integrity sha512-8SkgawHcA0RUbMrnhxbaQkZDBi8rMed8pQHixkFF9w32zGhAwZ9/cOHWlpYfr6RCx42Yp3siV45/jPEkJxsk6w==

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/python",
"version": "3.1.36",
"version": "3.1.33",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
@@ -16,14 +16,13 @@
"scripts": {
"build": "node build",
"test": "jest --env node --verbose --runInBand --bail",
"test-unit": "pnpm test test/unit.test.ts",
"test-integration-once": "pnpm test test/integration.test.ts"
"test-unit": "yarn test test/unit.test.ts",
"test-integration-once": "yarn test test/integration.test.ts"
},
"devDependencies": {
"@types/execa": "^0.9.0",
"@types/jest": "27.4.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "workspace:5.8.0",
"@vercel/build-utils": "5.7.4",
"@vercel/ncc": "0.24.0",
"execa": "^1.0.0",
"typescript": "4.3.4"

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/redwood",
"version": "1.0.47",
"version": "1.0.44",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs",
@@ -14,22 +14,19 @@
},
"scripts": {
"build": "node build.js",
"test-integration-once": "pnpm test test/test.js",
"test-integration-once": "yarn test test/test.js",
"test": "jest --env node --verbose --bail --runInBand",
"test-unit": "pnpm test test/prepare-cache.test.js"
"test-unit": "yarn test test/prepare-cache.test.js"
},
"dependencies": {
"@vercel/nft": "0.22.5",
"@vercel/routing-utils": "workspace:2.1.5",
"@vercel/routing-utils": "2.1.3",
"semver": "6.1.1"
},
"devDependencies": {
"@types/aws-lambda": "8.10.19",
"@types/node": "14.18.33",
"@types/semver": "6.0.0",
"@vercel/build-utils": "workspace:5.8.0",
"execa": "3.2.0",
"fs-extra": "11.1.0",
"typescript": "4.3.4"
"@vercel/build-utils": "5.7.4"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/remix",
"version": "1.2.1",
"version": "1.1.6",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://vercel.com/docs",
@@ -11,9 +11,9 @@
},
"scripts": {
"build": "node build.js",
"test-integration-once": "pnpm test test/test.js",
"test-integration-once": "yarn test test/test.js",
"test": "jest --env node --verbose --bail --runInBand",
"test-unit": "pnpm test test/build.test.ts"
"test-unit": "yarn test test/build.test.ts"
},
"files": [
"dist",
@@ -25,7 +25,7 @@
"devDependencies": {
"@types/jest": "27.5.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "workspace:5.8.0",
"@vercel/build-utils": "5.7.4",
"typescript": "4.6.4"
}
}

View File

@@ -24,8 +24,6 @@ import type {
} from '@vercel/build-utils';
import { nodeFileTrace } from '@vercel/nft';
import type { AppConfig } from './types';
import { pathToFileURL } from 'url';
import { findConfig } from './utils';
// Name of the Remix runtime adapter npm package for Vercel
const REMIX_RUNTIME_ADAPTER_NAME = '@remix-run/vercel';
@@ -164,44 +162,39 @@ export const build: BuildV2 = async ({
let serverBuildPath = 'build/index.js';
let needsHandler = true;
const remixConfigFile = findConfig(entrypointFsDirname, 'remix.config');
try {
if (remixConfigFile) {
const remixConfigModule = await import(
pathToFileURL(remixConfigFile).href
);
const remixConfig: AppConfig = remixConfigModule?.default || {};
const remixConfig: AppConfig = require(join(
entrypointFsDirname,
'remix.config'
));
// If `serverBuildTarget === 'vercel'` then Remix will output a handler
// that is already in Vercel (req, res) format, so don't inject the handler
if (remixConfig.serverBuildTarget) {
if (remixConfig.serverBuildTarget !== 'vercel') {
throw new Error(
`\`serverBuildTarget\` in Remix config must be "vercel" (got "${remixConfig.serverBuildTarget}")`
);
}
serverBuildPath = 'api/index.js';
needsHandler = false;
// If `serverBuildTarget === 'vercel'` then Remix will output a handler
// that is already in Vercel (req, res) format, so don't inject the handler
if (remixConfig.serverBuildTarget) {
if (remixConfig.serverBuildTarget !== 'vercel') {
throw new Error(
`\`serverBuildTarget\` in Remix config must be "vercel" (got "${remixConfig.serverBuildTarget}")`
);
}
serverBuildPath = 'api/index.js';
needsHandler = false;
}
if (remixConfig.serverBuildPath) {
// Explicit file path where the server output file will be
serverBuildPath = remixConfig.serverBuildPath;
} else if (remixConfig.serverBuildDirectory) {
// Explicit directory path the server output will be
serverBuildPath = join(remixConfig.serverBuildDirectory, 'index.js');
}
if (remixConfig.serverBuildPath) {
// Explicit file path where the server output file will be
serverBuildPath = remixConfig.serverBuildPath;
} else if (remixConfig.serverBuildDirectory) {
// Explicit directory path the server output will be
serverBuildPath = join(remixConfig.serverBuildDirectory, 'index.js');
}
// Also check for whether were in a monorepo.
// If we are, prepend the app root directory from config onto the build path.
// e.g. `/apps/my-remix-app/api/index.js`
const isMonorepo = repoRootPath && repoRootPath !== workPath;
if (isMonorepo) {
const rootDirectory = relative(repoRootPath, workPath);
serverBuildPath = join(rootDirectory, serverBuildPath);
}
// Also check for whether were in a monorepo.
// If we are, prepend the app root directory from config onto the build path.
// e.g. `/apps/my-remix-app/api/index.js`
const isMonorepo = repoRootPath && repoRootPath !== workPath;
if (isMonorepo) {
const rootDirectory = relative(repoRootPath, workPath);
serverBuildPath = join(rootDirectory, serverBuildPath);
}
} catch (err: any) {
// Ignore error if `remix.config.js` does not exist

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