Compare commits

..

18 Commits

Author SHA1 Message Date
Vercel Release Bot
f057f0421b Version Packages (#10081) 2023-06-14 10:47:10 -07:00
Nathan Rajlich
42c0b32a8d [fs-detectors] Use LocalFileSystemDetector instead of FixtureFilesystem (#10100)
The code for these two are almost identical, so consolidate into one codebase.

Also adjusts the `pnpm test` script to allow for specifying a file name to be executed, instead of running all tests.
2023-06-13 23:30:00 +00:00
Chris Barber
d61a1a7988 [cli] Fix team validation bug where you are apart of a team (#10092)
When consolidating the deployment team validation, a bug was introduced where the command would error if the user was currently using a team. The logic was meant to copy the logic in `getDeploymentByIdOrURL()`: https://github.com/vercel/vercel/blob/main/packages/cli/src/util/deploy/get-deployment-by-id-or-url.ts#L80.
2023-06-12 16:32:01 +00:00
Vercel Release Bot
c438bbb362 [examples][tests] Upgrade Next.js to version 13.4.5 (#10097)
This auto-generated PR updates 3 packages to Next.js version 13.4.5
2023-06-12 15:02:47 +00:00
Vercel Release Bot
cb5eef0eb5 [tests] Upgrade Turbo to version 1.10.3 (#10096)
This auto-generated PR updates Turbo to version 1.10.3
2023-06-11 07:44:11 +00:00
Nathan Rajlich
79dee367cf [cli] Remove findProjectFromPath() (#10093)
Superceded by the `findProjectsFromPath()` function which may return multiple matches, and it was only being used in tests.

The relevant tests have been updated to use the multiple matches version instead, and updated to include the case where multiple matches are returned.

__Note:__ No changeset for this one since it's an internal function being removed, and doesn't need to be referenced in the public changelog.
2023-06-09 22:59:17 +00:00
Nathan Rajlich
dea58dea7e [cli] Add support for vc deploy --prebuilt command with repo link (#10083)
When repo linked, `vc deploy --prebuilt` will change working directory to the Project root directory, instead of the repo root, so that the project's local `.vercel/output` directory is what gets uploaded + deployed.
2023-06-09 09:54:17 +00:00
Steven
fecebfa7fa [cli] vc env pull should add .env*.local to .gitignore (#10085)
This is a follow up to PR #9892 which changed the default to `.env.local`.

Now that we know local files should never be committed to git, we can automatically add `.env*.local` to `.gitignore`. Note that this is the same ignore pattern that ships with create-next-app [as seen here](06abd63489/packages/create-next-app/templates/app/js/gitignore (L28)), so most Next.js users won't see anything change.

See the related [Linear ticket](https://linear.app/vercel/issue/VCCLI-461/)
2023-06-08 00:09:22 +00:00
Nathan Rajlich
94d5612dce [cli] Move readme copy logic to a helper function for vc link (#10084)
ncc has an issue with detecting + rewriting this file path for some reason. Moving to a helper function should work around that issue.

Fixing:

```
Error: ENOENT: no such file or directory, open '/node_modules/vercel/projects/VERCEL_DIR_README.txt'
```
2023-06-07 21:33:47 +00:00
Nathan Rajlich
3eaf58bb74 [cli] Add support for vc dev command with repo link (#10082)
When repo linked, `vc dev` already works fine when run from the root of the repo. This change makes it so that `vc dev` also works as expected when executed within a project subdirectory.
2023-06-07 18:48:28 +00:00
Nathan Rajlich
e63cf40153 [cli] Add support for vc build command with repo link (#10075)
When the repo is linked to Vercel with `vc link --repo`, the `vc build` command should be invoked from the project subdirectory (otherwise the project selector is displayed). The output directory is at `<projectRoot>/.vercel/output` instead of at the repo root.
2023-06-07 08:26:13 +00:00
Sean Massa
709c9509f4 Revert "Revert "[cli] Add support for vc pull command with repo link"" (#10078)
Reverts vercel/vercel#10076

Restores the original PR: https://github.com/vercel/vercel/pull/10071

With the fix from: https://github.com/vercel/vercel/pull/10073
2023-06-07 07:49:45 +00:00
Nathan Rajlich
6107c1ed22 Disable "Enforce Changeset" job for release PRs (#10080)
This job leads to a false-positive for the release PR, so disable it.
2023-06-06 23:27:39 -07:00
Vercel Release Bot
7a0f377afe Version Packages (#10074)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-07 01:23:29 -05:00
Sean Massa
a04bf557fc handle undefined content type in vc dev (#10077)
When no content type header is sent to an API request during `vc dev`, the request fails:

```
/Users/smassa/source/vercel/vercel-2/node_modules/.pnpm/content-type@1.0.4/node_modules/content-type/index.js:108
    throw new TypeError('argument string is required')
          ^
TypeError: argument string is required
...
```

This comes from some runtime type validation happening in the `content-type` package, for which we do not have types, which is why typescript didn't catch this.
2023-06-07 06:20:19 +00:00
Sean Massa
b6736e82cf Clear revert out of changelog (#10079) 2023-06-07 00:46:21 -05:00
Sean Massa
7923056bc0 Revert "[cli] Add support for vc pull command with repo link" (#10076) 2023-06-07 00:35:12 -05:00
Nathan Rajlich
71ff193ea3 [cli] Add support for vc pull command with repo link (#10071)
When the repo is linked to Vercel with `vc link --repo`, the `.vercel` directory will be created at the _project root_ instead of the _repo root_, and will still contain the `project.json`.

The difference is that the `orgId` and `projectId` props will not be present in the `project.json` file when repo linked, since that information is available at the root level `repo.json` file.
2023-06-06 22:01:37 +00:00
56 changed files with 874 additions and 409 deletions

View File

@@ -22,7 +22,7 @@ jobs:
enforce-changeset:
name: Enforce Changeset
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
if: github.event_name == 'pull_request' && github.event.pull_request.title != 'Version Packages'
steps:
- uses: actions/checkout@v3
with:

View File

@@ -8,17 +8,17 @@
"name": "nextjs",
"version": "0.1.0",
"dependencies": {
"eslint": "8.41.0",
"eslint-config-next": "13.4.4",
"next": "13.4.4",
"eslint": "8.42.0",
"eslint-config-next": "13.4.5",
"next": "13.4.5",
"react": "18.2.0",
"react-dom": "18.2.0"
}
},
"node_modules/@babel/runtime": {
"version": "7.21.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz",
"integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==",
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz",
"integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==",
"dependencies": {
"regenerator-runtime": "^0.13.11"
},
@@ -71,17 +71,17 @@
}
},
"node_modules/@eslint/js": {
"version": "8.41.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz",
"integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
"version": "8.42.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
"integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.8",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
"integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
"integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
"dependencies": {
"@humanwhocodes/object-schema": "^1.2.1",
"debug": "^4.1.1",
@@ -109,22 +109,22 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
},
"node_modules/@next/env": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.4.tgz",
"integrity": "sha512-q/y7VZj/9YpgzDe64Zi6rY1xPizx80JjlU2BTevlajtaE3w1LqweH1gGgxou2N7hdFosXHjGrI4OUvtFXXhGLg=="
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.5.tgz",
"integrity": "sha512-SG/gKH6eij4vwQy87b/3mbpQ1X3x2vUdnpwq6/qL2IQWjtq58EY/UuNAp9CoEZoC9sI4L9AD1r+73Z9r4d3uug=="
},
"node_modules/@next/eslint-plugin-next": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.4.4.tgz",
"integrity": "sha512-5jnh7q6I15efnjR/rR+/TGTc9hn53g3JTbEjAMjmeQiExKqEUgIXqrHI5zlTNlNyzCPkBB860/ctxXheZaF2Vw==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.4.5.tgz",
"integrity": "sha512-/xD/kyJhXmBZq+0xGKOdjL22c9/4i3mBAXaU9aOGEHTXqqFeOz8scJbScWF13aMqigeoFCsDqngIB2MIatcn4g==",
"dependencies": {
"glob": "7.1.7"
}
},
"node_modules/@next/swc-darwin-arm64": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.4.tgz",
"integrity": "sha512-xfjgXvp4KalNUKZMHmsFxr1Ug+aGmmO6NWP0uoh4G3WFqP/mJ1xxfww0gMOeMeSq/Jyr5k7DvoZ2Pv+XOITTtw==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.5.tgz",
"integrity": "sha512-XvTzi2ASUN5bECFIAAcBiSoDb0xsq+KLj4F0bof4d4rdc+FgOqLvseGQaOXwVi1TIh5bHa7o4b6droSJMO5+2g==",
"cpu": [
"arm64"
],
@@ -137,9 +137,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.4.tgz",
"integrity": "sha512-ZY9Ti1hkIwJsxGus3nlubIkvYyB0gNOYxKrfsOrLEqD0I2iCX8D7w8v6QQZ2H+dDl6UT29oeEUdDUNGk4UEpfg==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.5.tgz",
"integrity": "sha512-NQdqal/VKAqlJTuzhjZmNtdo8QSqwmfO7b2xJSAengTEVxQvsH76oGEzQeIv8Ci4NP6DysAFtFrJq++TmIxcUA==",
"cpu": [
"x64"
],
@@ -152,9 +152,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.4.tgz",
"integrity": "sha512-+KZnDeMShYkpkqAvGCEDeqYTRADJXc6SY1jWXz+Uo6qWQO/Jd9CoyhTJwRSxvQA16MoYzvILkGaDqirkRNctyA==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.5.tgz",
"integrity": "sha512-nB8TjtpJCXtzIFjYOMbnQu68ajkA8QK58TreHjTGojSQjsF0StDqo5zFHglVVVHrd8d3N/+EjC18yFNSWnd/ZA==",
"cpu": [
"arm64"
],
@@ -167,9 +167,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.4.tgz",
"integrity": "sha512-evC1twrny2XDT4uOftoubZvW3EG0zs0ZxMwEtu/dDGVRO5n5pT48S8qqEIBGBUZYu/Xx4zzpOkIxx1vpWdE+9A==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.5.tgz",
"integrity": "sha512-W126XUW599OV3giSH9Co40VpT8VAOT47xONVHXZaYEpeca0qEevjj6WUr5IJu/8u+XGWm5xI1S0DYWjR6W+olw==",
"cpu": [
"arm64"
],
@@ -182,9 +182,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.4.tgz",
"integrity": "sha512-PX706XcCHr2FfkyhP2lpf+pX/tUvq6/ke7JYnnr0ykNdEMo+sb7cC/o91gnURh4sPYSiZJhsF2gbIqg9rciOHQ==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.5.tgz",
"integrity": "sha512-ZbPLO/oztQdtjGmWvGhRmtkZ6j9kQqg65kiO7F7Ijj7ojTtu3hh/vY+XRsHa/4Cse6HgyJ8XGZJMGoLb8ecQfQ==",
"cpu": [
"x64"
],
@@ -197,9 +197,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.4.tgz",
"integrity": "sha512-TKUUx3Ftd95JlHV6XagEnqpT204Y+IsEa3awaYIjayn0MOGjgKZMZibqarK3B1FsMSPaieJf2FEAcu9z0yT5aA==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.5.tgz",
"integrity": "sha512-f+/h8KMNixVUoRB+2vza8I+jsthJ4KcvopGUsDIUHe7Q4t+m8nKwGFBeyNu9qNIenYK5g5QYEsSwYFEqZylrTQ==",
"cpu": [
"x64"
],
@@ -212,9 +212,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.4.tgz",
"integrity": "sha512-FP8AadgSq4+HPtim7WBkCMGbhr5vh9FePXiWx9+YOdjwdQocwoCK5ZVC3OW8oh3TWth6iJ0AXJ/yQ1q1cwSZ3A==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.5.tgz",
"integrity": "sha512-dvtPQZ5+J+zUE1uq7gP853Oj63e+n0T1ydZ/yRdVh7d8zW9ZFuC9fFrg3MqP1cv1NPPur8rrTqDKN2mRBkSSBw==",
"cpu": [
"arm64"
],
@@ -227,9 +227,9 @@
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.4.tgz",
"integrity": "sha512-3WekVmtuA2MCdcAOrgrI+PuFiFURtSyyrN1I3UPtS0ckR2HtLqyqmS334Eulf15g1/bdwMteePdK363X/Y9JMg==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.5.tgz",
"integrity": "sha512-gK9zwGe25x31S4AjPy3Bf2niQvHIAbmwgkzmqWG3OmD4K2Z/Dh2ju4vuyzPzIt0pwQe4B520meP9NizTBmVWSg==",
"cpu": [
"ia32"
],
@@ -242,9 +242,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.4.tgz",
"integrity": "sha512-AHRITu/CrlQ+qzoqQtEMfaTu7GHaQ6bziQln/pVWpOYC1wU+Mq6VQQFlsDtMCnDztPZtppAXdvvbNS7pcfRzlw==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.5.tgz",
"integrity": "sha512-iyNQVc7eGehrik9RJt9xGcnO6b/pi8C7GCfg8RGenx1IlalEKbYRgBJloF7DQzwlrV47E9bQl8swT+JawaNcKA==",
"cpu": [
"x64"
],
@@ -308,9 +308,9 @@
}
},
"node_modules/@rushstack/eslint-patch": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.0.tgz",
"integrity": "sha512-IthPJsJR85GhOkp3Hvp8zFOPK5ynKn6STyHa/WZpioK7E1aYDiBzpqQPrngc14DszIUkIrdd3k9Iu0XSzlP/1w=="
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.1.tgz",
"integrity": "sha512-RkmuBcqiNioeeBKbgzMlOdreUkJfYaSjwgx9XDgGGpjvWgyaxWvDmZVSN9CS6LjEASadhgPv2BcFp+SeouWXXA=="
},
"node_modules/@swc/helpers": {
"version": "0.5.1",
@@ -326,13 +326,13 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
},
"node_modules/@typescript-eslint/parser": {
"version": "5.59.7",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.7.tgz",
"integrity": "sha512-VhpsIEuq/8i5SF+mPg9jSdIwgMBBp0z9XqjiEay+81PYLJuroN+ET1hM5IhkiYMJd9MkTz8iJLt7aaGAgzWUbQ==",
"version": "5.59.9",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.9.tgz",
"integrity": "sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ==",
"dependencies": {
"@typescript-eslint/scope-manager": "5.59.7",
"@typescript-eslint/types": "5.59.7",
"@typescript-eslint/typescript-estree": "5.59.7",
"@typescript-eslint/scope-manager": "5.59.9",
"@typescript-eslint/types": "5.59.9",
"@typescript-eslint/typescript-estree": "5.59.9",
"debug": "^4.3.4"
},
"engines": {
@@ -352,12 +352,12 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.59.7",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.7.tgz",
"integrity": "sha512-FL6hkYWK9zBGdxT2wWEd2W8ocXMu3K94i3gvMrjXpx+koFYdYV7KprKfirpgY34vTGzEPPuKoERpP8kD5h7vZQ==",
"version": "5.59.9",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.9.tgz",
"integrity": "sha512-8RA+E+w78z1+2dzvK/tGZ2cpGigBZ58VMEHDZtpE1v+LLjzrYGc8mMaTONSxKyEkz3IuXFM0IqYiGHlCsmlZxQ==",
"dependencies": {
"@typescript-eslint/types": "5.59.7",
"@typescript-eslint/visitor-keys": "5.59.7"
"@typescript-eslint/types": "5.59.9",
"@typescript-eslint/visitor-keys": "5.59.9"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -368,9 +368,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.59.7",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.7.tgz",
"integrity": "sha512-UnVS2MRRg6p7xOSATscWkKjlf/NDKuqo5TdbWck6rIRZbmKpVNTLALzNvcjIfHBE7736kZOFc/4Z3VcZwuOM/A==",
"version": "5.59.9",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.9.tgz",
"integrity": "sha512-uW8H5NRgTVneSVTfiCVffBb8AbwWSKg7qcA4Ot3JI3MPCJGsB4Db4BhvAODIIYE5mNj7Q+VJkK7JxmRhk2Lyjw==",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@@ -380,12 +380,12 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.59.7",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.7.tgz",
"integrity": "sha512-4A1NtZ1I3wMN2UGDkU9HMBL+TIQfbrh4uS0WDMMpf3xMRursDbqEf1ahh6vAAe3mObt8k3ZATnezwG4pdtWuUQ==",
"version": "5.59.9",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.9.tgz",
"integrity": "sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==",
"dependencies": {
"@typescript-eslint/types": "5.59.7",
"@typescript-eslint/visitor-keys": "5.59.7",
"@typescript-eslint/types": "5.59.9",
"@typescript-eslint/visitor-keys": "5.59.9",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@@ -406,11 +406,11 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.59.7",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.7.tgz",
"integrity": "sha512-tyN+X2jvMslUszIiYbF0ZleP+RqQsFVpGrKI6e0Eet1w8WmhsAtmzaqm8oM8WJQ1ysLwhnsK/4hYHJjOgJVfQQ==",
"version": "5.59.9",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.9.tgz",
"integrity": "sha512-bT7s0td97KMaLwpEBckbzj/YohnvXtqbe2XgqNvTl6RJVakY5mvENOTPvw5u66nljfZxthESpDozs86U+oLY8Q==",
"dependencies": {
"@typescript-eslint/types": "5.59.7",
"@typescript-eslint/types": "5.59.9",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@@ -696,9 +696,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001489",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001489.tgz",
"integrity": "sha512-x1mgZEXK8jHIfAxm+xgdpHpk50IN3z3q3zP261/WS+uvePxW8izXuCu6AHz0lkuYTlATDehiZ/tNyYBdSQsOUQ==",
"version": "1.0.30001498",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001498.tgz",
"integrity": "sha512-LFInN2zAwx3ANrGCDZ5AKKJroHqNKyjXitdV5zRIVIaQlXKj3GmxUKagoKsjqUfckpAObPCEWnk5EeMlyMWcgw==",
"funding": [
{
"type": "opencollective",
@@ -1034,15 +1034,15 @@
}
},
"node_modules/eslint": {
"version": "8.41.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz",
"integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
"version": "8.42.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
"integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.3",
"@eslint/js": "8.41.0",
"@humanwhocodes/config-array": "^0.11.8",
"@eslint/js": "8.42.0",
"@humanwhocodes/config-array": "^0.11.10",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"ajv": "^6.10.0",
@@ -1089,11 +1089,11 @@
}
},
"node_modules/eslint-config-next": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.4.4.tgz",
"integrity": "sha512-z/PMbm6L0iC/fwISULxe8IVy4DtNqZk2wQY711o35klenq70O6ns82A8yuMVCFjHC0DIyB2lyugesRtuk9u8dQ==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.4.5.tgz",
"integrity": "sha512-7qgJmRp9ClRzPgkzEz7ahK+Rasiv4k2aU3eqkkORzseNUGdtImZVYomcXUhUheHwkxzdN2p//nbIA7zJrCxsCg==",
"dependencies": {
"@next/eslint-plugin-next": "13.4.4",
"@next/eslint-plugin-next": "13.4.5",
"@rushstack/eslint-patch": "^1.1.3",
"@typescript-eslint/parser": "^5.42.0",
"eslint-import-resolver-node": "^0.3.6",
@@ -1664,9 +1664,12 @@
}
},
"node_modules/get-tsconfig": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.5.0.tgz",
"integrity": "sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==",
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.6.0.tgz",
"integrity": "sha512-lgbo68hHTQnFddybKbbs/RDRJnJT5YyGy2kQzVwbq+g67X73i+5MVTval34QxGkOe9X5Ujf1UYpCaphLyltjEg==",
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
},
"funding": {
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
@@ -1701,6 +1704,11 @@
"node": ">=10.13.0"
}
},
"node_modules/glob-to-regexp": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
},
"node_modules/globals": {
"version": "13.20.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
@@ -2453,16 +2461,17 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
},
"node_modules/next": {
"version": "13.4.4",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.4.tgz",
"integrity": "sha512-C5S0ysM0Ily9McL4Jb48nOQHT1BukOWI59uC3X/xCMlYIh9rJZCv7nzG92J6e1cOBqQbKovlpgvHWFmz4eKKEA==",
"version": "13.4.5",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.5.tgz",
"integrity": "sha512-pfNsRLVM9e5Y1/z02VakJRfD6hMQkr24FaN2xc9GbcZDBxoOgiNAViSg5cXwlWCoMhtm4U315D7XYhgOr96Q3Q==",
"dependencies": {
"@next/env": "13.4.4",
"@next/env": "13.4.5",
"@swc/helpers": "0.5.1",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001406",
"postcss": "8.4.14",
"styled-jsx": "5.1.1",
"watchpack": "2.4.0",
"zod": "3.21.4"
},
"bin": {
@@ -2472,15 +2481,15 @@
"node": ">=16.8.0"
},
"optionalDependencies": {
"@next/swc-darwin-arm64": "13.4.4",
"@next/swc-darwin-x64": "13.4.4",
"@next/swc-linux-arm64-gnu": "13.4.4",
"@next/swc-linux-arm64-musl": "13.4.4",
"@next/swc-linux-x64-gnu": "13.4.4",
"@next/swc-linux-x64-musl": "13.4.4",
"@next/swc-win32-arm64-msvc": "13.4.4",
"@next/swc-win32-ia32-msvc": "13.4.4",
"@next/swc-win32-x64-msvc": "13.4.4"
"@next/swc-darwin-arm64": "13.4.5",
"@next/swc-darwin-x64": "13.4.5",
"@next/swc-linux-arm64-gnu": "13.4.5",
"@next/swc-linux-arm64-musl": "13.4.5",
"@next/swc-linux-x64-gnu": "13.4.5",
"@next/swc-linux-x64-musl": "13.4.5",
"@next/swc-win32-arm64-msvc": "13.4.5",
"@next/swc-win32-ia32-msvc": "13.4.5",
"@next/swc-win32-x64-msvc": "13.4.5"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
@@ -2927,6 +2936,14 @@
"node": ">=4"
}
},
"node_modules/resolve-pkg-maps": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
"funding": {
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -3382,9 +3399,9 @@
}
},
"node_modules/tslib": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz",
"integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA=="
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
"integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
},
"node_modules/tsutils": {
"version": "3.21.0",
@@ -3441,16 +3458,16 @@
}
},
"node_modules/typescript": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz",
"integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=12.20"
"node": ">=14.17"
}
},
"node_modules/unbox-primitive": {
@@ -3483,6 +3500,18 @@
"punycode": "^2.1.0"
}
},
"node_modules/watchpack": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@@ -9,9 +9,9 @@
"lint": "next lint"
},
"dependencies": {
"eslint": "8.41.0",
"eslint-config-next": "13.4.4",
"next": "13.4.4",
"eslint": "8.42.0",
"eslint-config-next": "13.4.5",
"next": "13.4.5",
"react": "18.2.0",
"react-dom": "18.2.0"
}

View File

@@ -378,6 +378,11 @@ export interface ProjectLink {
* to the root directory of the repository.
*/
repoRoot?: string;
/**
* When linked as a repository, contains the relative path
* to the selected project root directory.
*/
projectRootDirectory?: string;
}
export interface PaginationOptions {
@@ -398,20 +403,35 @@ export interface PaginationOptions {
prev: number | null;
}
export type ProjectLinked = {
status: 'linked';
org: Org;
project: Project;
repoRoot?: string;
};
export type ProjectNotLinked = {
status: 'not_linked';
org: null;
project: null;
};
export type ProjectLinkedError = {
status: 'error';
exitCode: number;
reason?:
| 'HEADLESS'
| 'NOT_AUTHORIZED'
| 'TEAM_DELETED'
| 'PATH_IS_FILE'
| 'INVALID_ROOT_DIRECTORY'
| 'MISSING_PROJECT_SETTINGS';
};
export type ProjectLinkResult =
| { status: 'linked'; org: Org; project: Project; repoRoot?: string }
| { status: 'not_linked'; org: null; project: null }
| {
status: 'error';
exitCode: number;
reason?:
| 'HEADLESS'
| 'NOT_AUTHORIZED'
| 'TEAM_DELETED'
| 'PATH_IS_FILE'
| 'INVALID_ROOT_DIRECTORY'
| 'MISSING_PROJECT_SETTINGS';
};
| ProjectLinked
| ProjectNotLinked
| ProjectLinkedError;
/**
* @deprecated - `RollbackJobStatus` has been replace by `LastAliasRequest['jobStatus']`.

View File

@@ -32,7 +32,7 @@
"source-map-support": "0.5.12",
"ts-eager": "2.0.2",
"ts-jest": "29.1.0",
"turbo": "1.10.1",
"turbo": "1.10.3",
"typescript": "4.9.5"
},
"scripts": {

View File

@@ -1,5 +1,31 @@
# vercel
## 30.2.2
### Patch Changes
- [cli] vc env pull should add `.env*.local` to `.gitignore` ([#10085](https://github.com/vercel/vercel/pull/10085))
- [cli] Fix team validation bug where you are apart of a team ([#10092](https://github.com/vercel/vercel/pull/10092))
- Add support for `vc dev` command with repo link ([#10082](https://github.com/vercel/vercel/pull/10082))
- Add support for `vc deploy --prebuilt` command with repo link ([#10083](https://github.com/vercel/vercel/pull/10083))
- Move readme copy logic to a helper function for `vc link` ([#10084](https://github.com/vercel/vercel/pull/10084))
- Add support for `vc pull` command with repo link ([#10078](https://github.com/vercel/vercel/pull/10078))
- Add support for `vc build` command with repo link ([#10075](https://github.com/vercel/vercel/pull/10075))
## 30.2.1
### Patch Changes
- Updated dependencies [[`a04bf557f`](https://github.com/vercel/vercel/commit/a04bf557fc6e1080a117428977d0993dec78b004)]:
- @vercel/node@2.15.1
- @vercel/static-build@1.3.36
## 30.2.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "30.2.0",
"version": "30.2.2",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -36,12 +36,12 @@
"@vercel/go": "2.5.1",
"@vercel/hydrogen": "0.0.64",
"@vercel/next": "3.8.6",
"@vercel/node": "2.15.0",
"@vercel/node": "2.15.1",
"@vercel/python": "3.1.60",
"@vercel/redwood": "1.1.15",
"@vercel/remix-builder": "1.8.13",
"@vercel/ruby": "1.3.76",
"@vercel/static-build": "1.3.35"
"@vercel/static-build": "1.3.36"
},
"devDependencies": {
"@alex_neo/jest-expect-message": "1.0.5",
@@ -91,7 +91,7 @@
"@vercel/client": "12.6.2",
"@vercel/error-utils": "1.0.10",
"@vercel/frameworks": "1.4.2",
"@vercel/fs-detectors": "3.9.3",
"@vercel/fs-detectors": "4.0.0",
"@vercel/fun": "1.0.4",
"@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "2.2.1",

View File

@@ -1,7 +1,10 @@
import fs from 'fs-extra';
import chalk from 'chalk';
import dotenv from 'dotenv';
import semver from 'semver';
import minimatch from 'minimatch';
import { join, normalize, relative, resolve, sep } from 'path';
import frameworks from '@vercel/frameworks';
import {
getDiscontinuedNodeVersions,
normalizePath,
@@ -22,9 +25,9 @@ import {
import {
detectBuilders,
detectFrameworkRecord,
detectFrameworkVersion,
LocalFileSystemDetector,
} from '@vercel/fs-detectors';
import minimatch from 'minimatch';
import {
appendRoutesToPhase,
getTransformedRoutes,
@@ -49,7 +52,7 @@ import {
ProjectLinkAndSettings,
readProjectSettings,
} from '../util/projects/project-settings';
import { VERCEL_DIR } from '../util/projects/link';
import { getProjectLink, VERCEL_DIR } from '../util/projects/link';
import confirm from '../util/input/confirm';
import { emoji, prependEmoji } from '../util/emoji';
import stamp from '../util/output/stamp';
@@ -63,11 +66,7 @@ import { initCorepack, cleanupCorepack } from '../util/build/corepack';
import { sortBuilders } from '../util/build/sort-builders';
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;
@@ -134,7 +133,8 @@ const help = () => {
};
export default async function main(client: Client): Promise<number> {
const { cwd, output } = client;
let { cwd } = client;
const { output } = client;
// Ensure that `vc build` is not being invoked recursively
if (process.env.__VERCEL_BUILD_RUNNING) {
@@ -177,10 +177,18 @@ export default async function main(client: Client): Promise<number> {
return 1;
}
// If repo linked, update `cwd` to the repo root
const link = await getProjectLink(client, cwd);
const projectRootDirectory = link?.projectRootDirectory ?? '';
if (link?.repoRoot) {
cwd = client.cwd = link.repoRoot;
}
// TODO: read project settings from the API, fall back to local `project.json` if that fails
// Read project settings, and pull them from Vercel if necessary
let project = await readProjectSettings(join(cwd, VERCEL_DIR));
const vercelDir = join(cwd, projectRootDirectory, VERCEL_DIR);
let project = await readProjectSettings(vercelDir);
const isTTY = process.stdin.isTTY;
while (!project?.settings) {
let confirmed = yes;
@@ -207,6 +215,7 @@ export default async function main(client: Client): Promise<number> {
return 0;
}
const { argv: originalArgv } = client;
client.cwd = join(cwd, projectRootDirectory);
client.argv = [
...originalArgv.slice(0, 2),
'pull',
@@ -217,12 +226,13 @@ export default async function main(client: Client): Promise<number> {
if (result !== 0) {
return result;
}
client.cwd = cwd;
client.argv = originalArgv;
project = await readProjectSettings(join(cwd, VERCEL_DIR));
project = await readProjectSettings(vercelDir);
}
// Delete output directory from potential previous build
const defaultOutputDir = join(cwd, OUTPUT_DIR);
const defaultOutputDir = join(cwd, projectRootDirectory, OUTPUT_DIR);
const outputDir = argv['--output']
? resolve(argv['--output'])
: defaultOutputDir;
@@ -241,7 +251,12 @@ export default async function main(client: Client): Promise<number> {
const envToUnset = new Set<string>(['VERCEL', 'NOW_BUILDER']);
try {
const envPath = join(cwd, VERCEL_DIR, `.env.${target}.local`);
const envPath = join(
cwd,
projectRootDirectory,
VERCEL_DIR,
`.env.${target}.local`
);
// TODO (maybe?): load env vars from the API, fall back to the local file if that fails
const dotenvResult = dotenv.config({
path: envPath,

View File

@@ -203,56 +203,6 @@ export default async (client: Client): Promise<number> => {
return target;
}
// build `--prebuilt`
if (argv['--prebuilt']) {
const prebuiltExists = await fs.pathExists(join(cwd, '.vercel/output'));
if (!prebuiltExists) {
error(
`The ${param(
'--prebuilt'
)} option was used, but no prebuilt output found in ".vercel/output". Run ${getCommandName(
'build'
)} to generate a local build.`
);
return 1;
}
const prebuiltBuild = await getPrebuiltJson(cwd);
// Ensure that there was not a build error
const prebuiltError =
prebuiltBuild?.error ||
prebuiltBuild?.builds?.find(build => 'error' in build)?.error;
if (prebuiltError) {
output.log(
`Prebuilt deployment cannot be created because ${getCommandName(
'build'
)} failed with error:\n`
);
prettyError(prebuiltError);
return 1;
}
// Ensure that the deploy target matches the build target
const assumedTarget = target || 'preview';
if (prebuiltBuild?.target && prebuiltBuild.target !== assumedTarget) {
let specifyTarget = '';
if (prebuiltBuild.target === 'production') {
specifyTarget = ` --prod`;
}
prettyError({
message: `The ${param(
'--prebuilt'
)} option was used with the target environment "${assumedTarget}", but the prebuilt output found in ".vercel/output" was built with target environment "${
prebuiltBuild.target
}". Please run ${getCommandName(`--prebuilt${specifyTarget}`)}.`,
link: 'https://vercel.link/prebuilt-environment-mismatch',
});
return 1;
}
}
const archive = argv['--archive'];
if (typeof archive === 'string' && !isValidArchive(archive)) {
output.error(`Format must be one of: ${VALID_ARCHIVE_FORMATS.join(', ')}`);
@@ -355,6 +305,66 @@ export default async (client: Client): Promise<number> => {
throw new Error(`"org" is not defined`);
}
// build `--prebuilt`
if (argv['--prebuilt']) {
// For repo-style linking, update `cwd` to be the Project
// subdirectory when `rootDirectory` setting is defined
if (
link.status === 'linked' &&
link.repoRoot &&
link.project.rootDirectory
) {
cwd = join(cwd, link.project.rootDirectory);
}
const prebuiltExists = await fs.pathExists(join(cwd, '.vercel/output'));
if (!prebuiltExists) {
error(
`The ${param(
'--prebuilt'
)} option was used, but no prebuilt output found in ".vercel/output". Run ${getCommandName(
'build'
)} to generate a local build.`
);
return 1;
}
const prebuiltBuild = await getPrebuiltJson(cwd);
// Ensure that there was not a build error
const prebuiltError =
prebuiltBuild?.error ||
prebuiltBuild?.builds?.find(build => 'error' in build)?.error;
if (prebuiltError) {
output.log(
`Prebuilt deployment cannot be created because ${getCommandName(
'build'
)} failed with error:\n`
);
prettyError(prebuiltError);
return 1;
}
// Ensure that the deploy target matches the build target
const assumedTarget = target || 'preview';
if (prebuiltBuild?.target && prebuiltBuild.target !== assumedTarget) {
let specifyTarget = '';
if (prebuiltBuild.target === 'production') {
specifyTarget = ` --prod`;
}
prettyError({
message: `The ${param(
'--prebuilt'
)} option was used with the target environment "${assumedTarget}", but the prebuilt output found in ".vercel/output" was built with target environment "${
prebuiltBuild.target
}". Please run ${getCommandName(`--prebuilt${specifyTarget}`)}.`,
link: 'https://vercel.link/prebuilt-environment-mismatch',
});
return 1;
}
}
// Set the `contextName` and `currentTeam` as specified by the
// Project Settings, so that API calls happen with the proper scope
const contextName = org.slug;

View File

@@ -58,7 +58,13 @@ export default async function dev(
let projectSettings: ProjectSettings | undefined;
let envValues: Record<string, string> = {};
if (link.status === 'linked') {
const { project, org } = link;
const { project, org, repoRoot } = link;
// If repo linked, update `cwd` to the repo root
if (repoRoot) {
cwd = repoRoot;
}
client.config.currentTeam = org.type === 'team' ? org.id : undefined;
projectSettings = project;

View File

@@ -167,6 +167,7 @@ export default async function main(client: Client) {
case 'pull':
return pull(
client,
link,
project,
target,
argv,

View File

@@ -2,7 +2,11 @@ import chalk from 'chalk';
import { outputFile } from 'fs-extra';
import { closeSync, openSync, readSync } from 'fs';
import { resolve } from 'path';
import type { Project, ProjectEnvTarget } from '@vercel-internals/types';
import type {
Project,
ProjectEnvTarget,
ProjectLinked,
} from '@vercel-internals/types';
import Client from '../../util/client';
import { emoji, prependEmoji } from '../../util/emoji';
import confirm from '../../util/input/confirm';
@@ -19,6 +23,7 @@ import {
createEnvObject,
} from '../../util/env/diff-env-files';
import { isErrnoException } from '@vercel/error-utils';
import { addToGitIgnore } from '../../util/link/add-to-gitignore';
const CONTENTS_PREFIX = '# Created by Vercel CLI\n';
@@ -51,6 +56,7 @@ function tryReadHeadSync(path: string, length: number) {
export default async function pull(
client: Client,
link: ProjectLinked,
project: Project,
environment: ProjectEnvTarget,
opts: Partial<Options>,
@@ -136,11 +142,22 @@ export default async function pull(
output.log('No changes found.');
}
let isGitIgnoreUpdated = false;
if (filename === '.env.local') {
// When the file is `.env.local`, we also add it to `.gitignore`
// to avoid accidentally committing it to git.
// We use '.env*.local' to match the default .gitignore from
// create-next-app template. See:
// https://github.com/vercel/next.js/blob/06abd634899095b6cc28e6e8315b1e8b9c8df939/packages/create-next-app/templates/app/js/gitignore#L28
const rootPath = link.repoRoot ?? cwd;
isGitIgnoreUpdated = await addToGitIgnore(rootPath, '.env*.local');
}
output.print(
`${prependEmoji(
`${exists ? 'Updated' : 'Created'} ${chalk.bold(
filename
)} file ${chalk.gray(pullStamp())}`,
`${exists ? 'Updated' : 'Created'} ${chalk.bold(filename)} file ${
isGitIgnoreUpdated ? 'and added it to .gitignore' : ''
} ${chalk.gray(pullStamp())}`,
emoji('success')
)}\n`
);

View File

@@ -1,7 +1,11 @@
import chalk from 'chalk';
import { join } from 'path';
import Client from '../util/client';
import type { Project, ProjectEnvTarget } from '@vercel-internals/types';
import type {
Project,
ProjectEnvTarget,
ProjectLinked,
} from '@vercel-internals/types';
import { emoji, prependEmoji } from '../util/emoji';
import getArgs from '../util/get-args';
import logo from '../util/output/logo';
@@ -15,6 +19,7 @@ import {
getEnvTargetPlaceholder,
} from '../util/env/env-target';
import { ensureLink } from '../util/link/ensure-link';
import humanizePath from '../util/humanize-path';
const help = () => {
return console.log(`
@@ -81,6 +86,7 @@ function parseArgs(client: Client) {
async function pullAllEnvFiles(
environment: ProjectEnvTarget,
client: Client,
link: ProjectLinked,
project: Project,
argv: ReturnType<typeof processArgs>,
cwd: string
@@ -88,6 +94,7 @@ async function pullAllEnvFiles(
const environmentFile = `.env.${environment}.local`;
return envPull(
client,
link,
project,
environment,
argv,
@@ -115,7 +122,7 @@ export default async function main(client: Client) {
return argv;
}
const cwd = argv._[1] || process.cwd();
let cwd = argv._[1] || client.cwd;
const autoConfirm = Boolean(argv['--yes']);
const environment = parseEnvironment(argv['--environment'] || undefined);
@@ -124,13 +131,18 @@ export default async function main(client: Client) {
return link;
}
const { project, org } = link;
const { project, org, repoRoot } = link;
if (repoRoot) {
cwd = join(repoRoot, project.rootDirectory || '');
}
client.config.currentTeam = org.type === 'team' ? org.id : undefined;
const pullResultCode = await pullAllEnvFiles(
environment,
client,
link,
project,
argv,
cwd
@@ -141,13 +153,14 @@ export default async function main(client: Client) {
client.output.print('\n');
client.output.log('Downloading project settings');
await writeProjectSettings(cwd, project, org);
const isRepoLinked = typeof repoRoot === 'string';
await writeProjectSettings(cwd, project, org, isRepoLinked);
const settingsStamp = stamp();
client.output.print(
`${prependEmoji(
`Downloaded project settings to ${chalk.bold(
join(VERCEL_DIR, VERCEL_DIR_PROJECT)
humanizePath(join(cwd, VERCEL_DIR, VERCEL_DIR_PROJECT))
)} ${chalk.gray(settingsStamp())}`,
emoji('success')
)}\n`

View File

@@ -1,15 +1,10 @@
import { Org, Project } from '@vercel-internals/types';
import Client from '../client';
import setupAndLink from '../link/setup-and-link';
import param from '../output/param';
import { getCommandName } from '../pkg-name';
import { getLinkedProject } from '../projects/link';
import type { SetupAndLinkOptions } from '../link/setup-and-link';
type LinkResult = {
org: Org;
project: Project;
};
import type { ProjectLinked } from '@vercel-internals/types';
/**
* Checks if a project is already linked and if not, links the project and
@@ -23,15 +18,15 @@ type LinkResult = {
* directory
* @param opts.projectName - The project name to use when linking, otherwise
* the current directory
* @returns {Promise<LinkResult|number>} Returns a numeric exit code when aborted or
* @returns {Promise<ProjectLinked|number>} Returns a numeric exit code when aborted or
* error, otherwise an object containing the org an project
*/
export async function ensureLink(
commandName: string,
client: Client,
cwd: string,
opts: SetupAndLinkOptions
): Promise<LinkResult | number> {
opts: SetupAndLinkOptions = {}
): Promise<ProjectLinked | number> {
let { link } = opts;
if (!link) {
link = await getLinkedProject(client, cwd);
@@ -61,5 +56,5 @@ export async function ensureLink(
return link.exitCode;
}
return { org: link.org, project: link.project };
return link;
}

View File

@@ -3,14 +3,10 @@ import pluralize from 'pluralize';
import { homedir } from 'os';
import { join, normalize } from 'path';
import { normalizePath } from '@vercel/build-utils';
import { lstat, readJSON, outputJSON, writeFile, readFile } from 'fs-extra';
import { lstat, readJSON, outputJSON } from 'fs-extra';
import confirm from '../input/confirm';
import toHumanPath from '../humanize-path';
import {
VERCEL_DIR,
VERCEL_DIR_README,
VERCEL_DIR_REPO,
} from '../projects/link';
import { VERCEL_DIR, VERCEL_DIR_REPO, writeReadme } from '../projects/link';
import { getRemoteUrls } from '../create-git-meta';
import link from '../output/link';
import { emoji, prependEmoji } from '../emoji';
@@ -193,10 +189,7 @@ export async function ensureRepoLink(
};
await outputJSON(repoConfigPath, repoConfig, { spaces: 2 });
await writeFile(
join(rootPath, VERCEL_DIR, VERCEL_DIR_README),
await readFile(join(__dirname, 'VERCEL_DIR_README.txt'), 'utf8')
);
await writeReadme(rootPath);
// update .gitignore
const isGitIgnoreUpdated = await addToGitIgnore(rootPath);
@@ -282,7 +275,7 @@ export function findProjectsFromPath(
path: string
): RepoProjectConfig[] {
const normalizedPath = normalizePath(path);
return projects
const matches = projects
.slice()
.sort(sortByDirectory)
.filter(project => {
@@ -295,14 +288,9 @@ export function findProjectsFromPath(
normalizedPath.startsWith(`${project.directory}/`)
);
});
}
/**
* TODO: remove
*/
export function findProjectFromPath(
projects: RepoProjectConfig[],
path: string
): RepoProjectConfig | undefined {
return findProjectsFromPath(projects, path)[0];
// If there are multiple matches, we only want the most relevant
// selections (with the deepest directory depth), so pick the first
// one and filter on those matches.
const firstMatch = matches[0];
return matches.filter(match => match.directory === firstMatch.directory);
}

View File

@@ -74,9 +74,7 @@ export default async function getProjectByDeployment({
err.code = 'ERR_INVALID_TEAM';
throw err;
}
}
if (team) {
} else if (team) {
const err: NodeJS.ErrnoException = new Error(
`Deployment doesn't belong to current team ${chalk.bold(contextName)}`
);

View File

@@ -69,7 +69,7 @@ export function getVercelDirectory(cwd: string): string {
return existingDirs[0] || possibleDirs[0];
}
async function getProjectLink(
export async function getProjectLink(
client: Client,
path: string
): Promise<ProjectLink | null> {
@@ -108,9 +108,10 @@ async function getProjectLinkFromRepoLink(
}
if (project) {
return {
repoRoot: repoLink.rootPath,
orgId: repoLink.repoConfig.orgId,
projectId: project.id,
repoRoot: repoLink.rootPath,
projectRootDirectory: project.directory,
};
}
return null;
@@ -284,6 +285,13 @@ export async function getLinkedProject(
return { status: 'linked', org, project, repoRoot: link.repoRoot };
}
export async function writeReadme(path: string) {
await writeFile(
join(path, VERCEL_DIR, VERCEL_DIR_README),
await readFile(join(__dirname, 'VERCEL_DIR_README.txt'), 'utf8')
);
}
export async function linkFolderToProject(
client: Client,
path: string,
@@ -313,10 +321,7 @@ export async function linkFolderToProject(
JSON.stringify(projectLink)
);
await writeFile(
join(path, VERCEL_DIR, VERCEL_DIR_README),
await readFile(join(__dirname, 'VERCEL_DIR_README.txt'), 'utf8')
);
await writeReadme(path);
// update .gitignore
const isGitIgnoreUpdated = await addToGitIgnore(path);

View File

@@ -1,11 +1,12 @@
import { outputJSON } from 'fs-extra';
import { Org, Project, ProjectLink } from '@vercel-internals/types';
import { getLinkFromDir, VERCEL_DIR, VERCEL_DIR_PROJECT } from './link';
import { join } from 'path';
import { outputJSON, readFile } from 'fs-extra';
import { VercelConfig } from '@vercel/client';
import { VERCEL_DIR, VERCEL_DIR_PROJECT } from './link';
import { PartialProjectSettings } from '../input/edit-project-settings';
import type { Org, Project, ProjectLink } from '@vercel-internals/types';
import { isErrnoException, isError } from '@vercel/error-utils';
export type ProjectLinkAndSettings = ProjectLink & {
export type ProjectLinkAndSettings = Partial<ProjectLink> & {
settings: {
createdAt: Project['createdAt'];
installCommand: Project['installCommand'];
@@ -26,7 +27,8 @@ export type ProjectLinkAndSettings = ProjectLink & {
export async function writeProjectSettings(
cwd: string,
project: Project,
org: Org
org: Org,
isRepoLinked: boolean
) {
let analyticsId: string | undefined;
if (
@@ -39,8 +41,8 @@ export async function writeProjectSettings(
}
const projectLinkAndSettings: ProjectLinkAndSettings = {
projectId: project.id,
orgId: org.id,
projectId: isRepoLinked ? undefined : project.id,
orgId: isRepoLinked ? undefined : org.id,
settings: {
createdAt: project.createdAt,
framework: project.framework,
@@ -60,8 +62,28 @@ export async function writeProjectSettings(
});
}
export async function readProjectSettings(cwd: string) {
return await getLinkFromDir<ProjectLinkAndSettings>(cwd);
export async function readProjectSettings(vercelDir: string) {
try {
return JSON.parse(
await readFile(join(vercelDir, VERCEL_DIR_PROJECT), 'utf8')
);
} catch (err: unknown) {
// `project.json` file does not exists, so project settings have not been pulled
if (
isErrnoException(err) &&
err.code &&
['ENOENT', 'ENOTDIR'].includes(err.code)
) {
return null;
}
// failed to parse JSON, treat the same as if project settings have not been pulled
if (isError(err) && err.name === 'SyntaxError') {
return null;
}
throw err;
}
}
export function pickOverrides(

View File

@@ -0,0 +1,4 @@
{
"orgId": "team_dummy",
"projectId": "build-output-api-failed-before-builds"
}

View File

@@ -0,0 +1,4 @@
{
"orgId": "team_dummy",
"projectId": "build-output-api-failed-within-build"
}

View File

@@ -0,0 +1,4 @@
{
"orgId": "team_dummy",
"projectId": "build-output-api-preview"
}

View File

@@ -0,0 +1,4 @@
{
"orgId": "team_dummy",
"projectId": "build-output-api-production"
}

View File

@@ -1 +1,3 @@
!.vercel
dist
!/.vercel
.vercel/output

View File

@@ -0,0 +1,6 @@
{
"name": "blog",
"scripts": {
"build": "mkdir -p dist && echo blog > dist/index.txt"
}
}

View File

@@ -0,0 +1,6 @@
{
"name": "dashboard",
"scripts": {
"build": "mkdir -p dist && echo dashboard > dist/index.txt"
}
}

View File

@@ -0,0 +1,6 @@
{
"name": "marketing",
"scripts": {
"build": "mkdir -p dist && echo marketing > dist/index.txt"
}
}

View File

@@ -0,0 +1,4 @@
.next
yarn.lock
!.vercel
.env*.local

View File

@@ -0,0 +1,4 @@
{
"orgId": "team_dummy",
"projectId": "vercel-env-pull-with-gitignore"
}

View File

@@ -47,7 +47,7 @@ export function setupTmpDir(fixtureName?: string) {
const cwd = path.join(tempRoot.name, String(tempNumber++), fixtureName ?? '');
fs.mkdirpSync(cwd);
return cwd;
return fs.realpathSync(cwd);
}
export function cleanupFixtures() {

View File

@@ -1174,4 +1174,77 @@ describe('build', () => {
expect(fs.existsSync(join(output, 'static', 'index.html'))).toBe(true);
expect(fs.existsSync(join(output, 'static', '.env'))).toBe(false);
});
it('should build with `repo.json` link', async () => {
const cwd = fixture('../../monorepo-link');
useUser();
useTeams('team_dummy');
// "blog" app
useProject({
...defaultProject,
id: 'QmScb7GPQt6gsS',
name: 'monorepo-blog',
rootDirectory: 'blog',
outputDirectory: 'dist',
framework: null,
});
let output = join(cwd, 'blog/.vercel/output');
client.cwd = join(cwd, 'blog');
client.setArgv('build', '--yes');
let exitCode = await build(client);
expect(exitCode).toEqual(0);
delete process.env.__VERCEL_BUILD_RUNNING;
let files = await fs.readdir(join(output, 'static'));
expect(files.sort()).toEqual(['index.txt']);
expect(
(await fs.readFile(join(output, 'static/index.txt'), 'utf8')).trim()
).toEqual('blog');
// "dashboard" app
useProject({
...defaultProject,
id: 'QmbKpqpiUqbcke',
name: 'monorepo-dashboard',
rootDirectory: 'dashboard',
outputDirectory: 'dist',
framework: null,
});
output = join(cwd, 'dashboard/.vercel/output');
client.cwd = join(cwd, 'dashboard');
client.setArgv('build', '--yes');
exitCode = await build(client);
expect(exitCode).toEqual(0);
delete process.env.__VERCEL_BUILD_RUNNING;
files = await fs.readdir(join(output, 'static'));
expect(files.sort()).toEqual(['index.txt']);
expect(
(await fs.readFile(join(output, 'static/index.txt'), 'utf8')).trim()
).toEqual('dashboard');
// "marketing" app
useProject({
...defaultProject,
id: 'QmX6P93ChNDoZP',
name: 'monorepo-marketing',
rootDirectory: 'marketing',
outputDirectory: 'dist',
framework: null,
});
output = join(cwd, 'marketing/.vercel/output');
client.cwd = join(cwd, 'marketing');
client.setArgv('build', '--yes');
exitCode = await build(client);
expect(exitCode).toEqual(0);
delete process.env.__VERCEL_BUILD_RUNNING;
files = await fs.readdir(join(output, 'static'));
expect(files.sort()).toEqual(['index.txt']);
expect(
(await fs.readFile(join(output, 'static/index.txt'), 'utf8')).trim()
).toEqual('marketing');
});
});

View File

@@ -45,6 +45,14 @@ describe('deploy', () => {
it('should reject deploying when `--prebuilt` is used and `vc build` failed before Builders', async () => {
const cwd = setupUnitFixture('build-output-api-failed-before-builds');
useUser();
useTeams('team_dummy');
useProject({
...defaultProject,
id: 'build-output-api-failed-before-builds',
name: 'build-output-api-failed-before-builds',
});
client.setArgv('deploy', cwd, '--prebuilt');
const exitCodePromise = deploy(client);
await expect(client.stderr).toOutput(
@@ -56,6 +64,14 @@ describe('deploy', () => {
it('should reject deploying when `--prebuilt` is used and `vc build` failed within a Builder', async () => {
const cwd = setupUnitFixture('build-output-api-failed-within-build');
useUser();
useTeams('team_dummy');
useProject({
...defaultProject,
id: 'build-output-api-failed-within-build',
name: 'build-output-api-failed-within-build',
});
client.setArgv('deploy', cwd, '--prebuilt');
const exitCodePromise = deploy(client);
await expect(client.stderr).toOutput(
@@ -65,7 +81,16 @@ describe('deploy', () => {
});
it('should reject deploying a directory that does not contain ".vercel/output" when `--prebuilt` is used', async () => {
client.setArgv('deploy', __dirname, '--prebuilt');
useUser();
useTeams('team_dummy');
useProject({
...defaultProject,
name: 'static',
id: 'static',
});
client.cwd = setupUnitFixture('commands/deploy/static');
client.setArgv('deploy', '--prebuilt');
const exitCodePromise = deploy(client);
await expect(client.stderr).toOutput(
'Error: The "--prebuilt" option was used, but no prebuilt output found in ".vercel/output". Run `vercel build` to generate a local build.\n'
@@ -102,8 +127,8 @@ describe('deploy', () => {
useTeams('team_dummy');
useProject({
...defaultProject,
id: 'build-output-api-preview',
name: 'build-output-api-preview',
id: 'build-output-api-production',
name: 'build-output-api-production',
});
client.setArgv('deploy', cwd, '--prebuilt');

View File

@@ -25,7 +25,9 @@ describe('env', () => {
await expect(client.stderr).toOutput(
'Downloading `development` Environment Variables for Project vercel-env-pull'
);
await expect(client.stderr).toOutput('Created .env.local file');
await expect(client.stderr).toOutput(
'Created .env.local file and added it to .gitignore'
);
await expect(exitCodePromise).resolves.toEqual(0);
const rawDevEnv = await fs.readFile(path.join(cwd, '.env.local'));
@@ -50,7 +52,9 @@ describe('env', () => {
await expect(client.stderr).toOutput(
'Downloading `preview` Environment Variables for Project vercel-env-pull'
);
await expect(client.stderr).toOutput('Created .env.local file');
await expect(client.stderr).toOutput(
'Created .env.local file and added it to .gitignore'
);
await expect(exitCodePromise).resolves.toEqual(0);
// check for Preview env vars
@@ -86,7 +90,9 @@ describe('env', () => {
await expect(client.stderr).toOutput(
'Downloading `preview` Environment Variables for Project vercel-env-pull'
);
await expect(client.stderr).toOutput('Created .env.local file');
await expect(client.stderr).toOutput(
'Created .env.local file and added it to .gitignore'
);
await expect(exitCodePromise).resolves.toEqual(0);
// check for Preview env vars
@@ -122,6 +128,7 @@ describe('env', () => {
'Downloading `development` Environment Variables for Project vercel-env-pull'
);
await expect(client.stderr).toOutput('Created other.env file');
await expect(client.stderr).not.toOutput('and added it to .gitignore');
await expect(exitCodePromise).resolves.toEqual(0);
const rawDevEnv = await fs.readFile(path.join(cwd, 'other.env'));
@@ -146,7 +153,9 @@ describe('env', () => {
await expect(client.stderr).toOutput(
`Downloading \`production\` Environment Variables for Project vercel-env-pull`
);
await expect(client.stderr).toOutput('Created .env.local file');
await expect(client.stderr).toOutput(
'Created .env.local file and added it to .gitignore'
);
await expect(exitCodePromise).resolves.toEqual(0);
const rawProdEnv = await fs.readFile(path.join(cwd, '.env.local'));
@@ -201,6 +210,7 @@ describe('env', () => {
'Downloading `development` Environment Variables for Project vercel-env-pull'
);
await expect(client.stderr).toOutput('Created other.env file');
await expect(client.stderr).not.toOutput('and added it to .gitignore');
await expect(exitCodePromise).resolves.toEqual(0);
const rawDevEnv = await fs.readFile(path.join(cwd, 'other.env'));
@@ -247,7 +257,9 @@ describe('env', () => {
await expect(client.stderr).toOutput(
'+ SPECIAL_FLAG (Updated)\n+ NEW_VAR\n- TEST\n'
);
await expect(client.stderr).toOutput('Updated .env.local file');
await expect(client.stderr).toOutput(
'Updated .env.local file and added it to .gitignore'
);
await expect(pullPromise).resolves.toEqual(0);
} finally {
@@ -268,7 +280,9 @@ describe('env', () => {
client.cwd = cwd;
client.setArgv('env', 'pull', '--yes');
const pullPromise = env(client);
await expect(client.stderr).toOutput('Updated .env.local file');
await expect(client.stderr).toOutput(
'Updated .env.local file and added it to .gitignore'
);
await expect(pullPromise).resolves.toEqual(0);
});
@@ -284,7 +298,9 @@ describe('env', () => {
client.setArgv('env', 'pull', '--yes');
const pullPromise = env(client);
await expect(client.stderr).toOutput('> No changes found.');
await expect(client.stderr).toOutput('Updated .env.local file');
await expect(client.stderr).toOutput(
'Updated .env.local file and added it to .gitignore'
);
await expect(pullPromise).resolves.toEqual(0);
});
@@ -321,7 +337,9 @@ describe('env', () => {
'Downloading `development` Environment Variables for Project env-pull-delta'
);
await expect(client.stderr).toOutput('No changes found.\n');
await expect(client.stderr).toOutput('Updated .env.local file');
await expect(client.stderr).toOutput(
'Updated .env.local file and added it to .gitignore'
);
await expect(pullPromise).resolves.toEqual(0);
} finally {
@@ -371,5 +389,42 @@ describe('env', () => {
await env(client);
}
});
it('should not update .gitignore if it contains a match', async () => {
const prj = 'vercel-env-pull-with-gitignore';
useUser();
useTeams('team_dummy');
useProject({
...defaultProject,
id: prj,
name: prj,
});
const cwd = setupUnitFixture(prj);
const gitignoreBefore = await fs.readFile(
path.join(cwd, '.gitignore'),
'utf8'
);
client.cwd = cwd;
client.setArgv('env', 'pull', '--yes');
const exitCodePromise = env(client);
await expect(client.stderr).toOutput(
'Downloading `development` Environment Variables for Project ' + prj
);
await expect(client.stderr).toOutput('Created .env.local file');
await expect(client.stderr).not.toOutput('and added it to .gitignore');
await expect(exitCodePromise).resolves.toEqual(0);
const rawDevEnv = await fs.readFile(path.join(cwd, '.env.local'));
// check for development env value
const devFileHasDevEnv = rawDevEnv.toString().includes('SPECIAL_FLAG');
expect(devFileHasDevEnv).toBeTruthy();
const gitignoreAfter = await fs.readFile(
path.join(cwd, '.gitignore'),
'utf8'
);
expect(gitignoreAfter).toBe(gitignoreBefore);
});
});
});

View File

@@ -26,7 +26,7 @@ describe('pull', () => {
`Created .vercel${path.sep}.env.development.local file`
);
await expect(client.stderr).toOutput(
`Downloaded project settings to .vercel${path.sep}project.json`
`Downloaded project settings to ${cwd}${path.sep}.vercel${path.sep}project.json`
);
await expect(exitCodePromise).resolves.toEqual(0);
@@ -92,7 +92,7 @@ describe('pull', () => {
`Created .vercel${path.sep}.env.development.local file`
);
await expect(client.stderr).toOutput(
`Downloaded project settings to .vercel${path.sep}project.json`
`Downloaded project settings to ${cwd}${path.sep}.vercel${path.sep}project.json`
);
await expect(exitCodePromise).resolves.toEqual(0);
@@ -130,7 +130,7 @@ describe('pull', () => {
`Created .vercel${path.sep}.env.preview.local file`
);
await expect(client.stderr).toOutput(
`Downloaded project settings to .vercel${path.sep}project.json`
`Downloaded project settings to ${cwd}${path.sep}.vercel${path.sep}project.json`
);
await expect(exitCodePromise).resolves.toEqual(0);
@@ -161,7 +161,7 @@ describe('pull', () => {
`Created .vercel${path.sep}.env.production.local file`
);
await expect(client.stderr).toOutput(
`Downloaded project settings to .vercel${path.sep}project.json`
`Downloaded project settings to ${cwd}${path.sep}.vercel${path.sep}project.json`
);
await expect(exitCodePromise).resolves.toEqual(0);
@@ -177,4 +177,29 @@ describe('pull', () => {
.includes('SQL_CONNECTION_STRING');
expect(previewFileHasPreviewEnv2).toBeTruthy();
});
it('should work with repo link', async () => {
const cwd = setupUnitFixture('monorepo-link');
useUser();
useTeams('team_dummy');
useProject({
...defaultProject,
id: 'QmbKpqpiUqbcke',
name: 'dashboard',
rootDirectory: 'dashboard',
});
client.cwd = path.join(cwd, 'dashboard');
client.setArgv('pull');
const exitCodePromise = pull(client);
await expect(client.stderr).toOutput(
'Downloading `development` Environment Variables for Project dashboard'
);
await expect(client.stderr).toOutput(
`Created .vercel${path.sep}.env.development.local file`
);
await expect(client.stderr).toOutput(
`Downloaded project settings to ${cwd}${path.sep}dashboard${path.sep}.vercel${path.sep}project.json`
);
await expect(exitCodePromise).resolves.toEqual(0);
});
});

View File

@@ -1,7 +1,7 @@
import { tmpdir } from 'node:os';
import { join, sep } from 'node:path';
import {
findProjectFromPath,
findProjectsFromPath,
findRepoRoot,
RepoProjectConfig,
traverseUpDirectories,
@@ -57,35 +57,36 @@ describe('traverseUpDirectories()', () => {
});
});
describe('findProjectFromPath()', () => {
describe('findProjectsFromPath()', () => {
const projects: RepoProjectConfig[] = [
{ id: 'root', name: 'r', directory: '.' },
{ id: 'site', name: 'a', directory: 'apps/site' },
{ id: 'site2', name: 'a', directory: 'apps/site2' },
{ id: 'other', name: 'b', directory: 'apps/other' },
{ id: 'duplicate', name: 'd', directory: 'apps/other' },
{ id: 'nested', name: 'n', directory: 'apps/other/nested' },
];
it.each([
{ id: 'root', path: '.' },
{ id: 'root', path: 'lib' },
{ id: 'root', path: 'lib' },
{ id: 'site', path: `apps${sep}site` },
{ id: 'site', path: `apps${sep}site` },
{ id: 'site', path: `apps${sep}site${sep}components` },
{ id: 'site2', path: `apps${sep}site2` },
{ id: 'site2', path: `apps${sep}site2${sep}inner` },
{ id: 'other', path: `apps${sep}other` },
{ id: 'other', path: `apps${sep}other${sep}lib` },
{ id: 'nested', path: `apps${sep}other${sep}nested` },
{ id: 'nested', path: `apps${sep}other${sep}nested${sep}foo` },
])('should find Project "$id" for path "$path"', ({ path, id }) => {
const actual = findProjectFromPath(projects, path);
expect(actual?.id).toEqual(id);
{ ids: ['root'], path: '.' },
{ ids: ['root'], path: 'lib' },
{ ids: ['root'], path: 'lib' },
{ ids: ['site'], path: `apps${sep}site` },
{ ids: ['site'], path: `apps${sep}site` },
{ ids: ['site'], path: `apps${sep}site${sep}components` },
{ ids: ['site2'], path: `apps${sep}site2` },
{ ids: ['site2'], path: `apps${sep}site2${sep}inner` },
{ ids: ['other', 'duplicate'], path: `apps${sep}other` },
{ ids: ['other', 'duplicate'], path: `apps${sep}other${sep}lib` },
{ ids: ['nested'], path: `apps${sep}other${sep}nested` },
{ ids: ['nested'], path: `apps${sep}other${sep}nested${sep}foo` },
])('should find Project "$id" for path "$path"', ({ path, ids }) => {
const actual = findProjectsFromPath(projects, path);
expect(actual.map(a => a.id)).toEqual(ids);
});
it('should return `undefined` when there are no matching Projects', () => {
const actual = findProjectFromPath([projects[1]], '.');
expect(actual).toBeUndefined();
it('should return empty array when there are no matching Projects', () => {
const actual = findProjectsFromPath([projects[1]], '.');
expect(actual).toHaveLength(0);
});
});

View File

@@ -0,0 +1,104 @@
import { client } from '../../../mocks/client';
import getProjectByDeployment from '../../../../src/util/projects/get-project-by-deployment';
import { useTeams } from '../../../mocks/team';
import { useUser } from '../../../mocks/user';
import { useDeployment } from '../../../mocks/deployment';
import { defaultProject, useProject } from '../../../mocks/project';
describe('getProjectByDeployment', () => {
it('should get project and deployment', async () => {
const user = useUser();
const { project: p } = useProject({
...defaultProject,
id: 'foo',
name: 'foo',
});
const d = useDeployment({
creator: user,
createdAt: Date.now(),
project: p,
});
const { deployment, project } = await getProjectByDeployment({
client,
deployId: d.id,
output: client.output,
});
expect(project.id).toBe(p.id);
expect(deployment.id).toBe(d.id);
});
it('should get project and deployment associated to a team', async () => {
const [team] = useTeams('team_dummy');
const user = useUser();
const { project: p } = useProject({
...defaultProject,
id: 'foo',
name: 'foo',
});
const d = useDeployment({
creator: {
id: team.id,
name: team.name,
email: user.email,
username: team.slug,
},
createdAt: Date.now(),
project: p,
});
client.config.currentTeam = team.id;
d.team = team;
const { deployment, project } = await getProjectByDeployment({
client,
deployId: d.id,
output: client.output,
});
expect(project.id).toBe(p.id);
expect(deployment.id).toBe(d.id);
});
it("should error if deployment team doesn't match current user's team", async () => {
const [team] = useTeams('team_dummy');
const user = useUser();
const { project: p } = useProject({
...defaultProject,
id: 'foo',
name: 'foo',
});
const d = useDeployment({
creator: {
id: team.id,
name: team.name,
email: user.email,
username: team.slug,
},
createdAt: Date.now(),
project: p,
});
client.config.currentTeam = team.id;
await expect(
getProjectByDeployment({
client,
deployId: d.id,
output: client.output,
})
).rejects.toThrowError("Deployment doesn't belong to current team");
client.config.currentTeam = undefined;
d.team = team;
await expect(
getProjectByDeployment({
client,
deployId: d.id,
output: client.output,
})
).rejects.toThrowError('Deployment belongs to a different team');
});
});

View File

@@ -1,5 +1,11 @@
# @vercel/fs-detectors
## 4.0.0
### Major Changes
- `LocalFileSystemDetector#readdir()` now returns paths relative to the root dir, instead of absolute paths. This is to align with the usage of the detectors that are using the `DetectorFilesystem` interface. ([#10100](https://github.com/vercel/vercel/pull/10100))
## 3.9.3
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/fs-detectors",
"version": "3.9.3",
"version": "4.0.0",
"description": "Vercel filesystem detectors",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -15,8 +15,8 @@
"license": "Apache-2.0",
"scripts": {
"build": "tsc",
"test": "jest --env node --verbose --runInBand --bail test/unit.*test.*",
"test-unit": "pnpm test"
"test": "jest --env node --verbose --runInBand --bail",
"test-unit": "pnpm test test/unit.*test.*"
},
"dependencies": {
"@vercel/error-utils": "1.0.10",

View File

@@ -6,10 +6,12 @@ import { isErrnoException } from '@vercel/error-utils';
export class LocalFileSystemDetector extends DetectorFilesystem {
private rootPath: string;
constructor(rootPath: string) {
super();
this.rootPath = rootPath;
}
async _hasPath(name: string): Promise<boolean> {
try {
await fs.stat(this.getFilePath(name));
@@ -21,13 +23,16 @@ export class LocalFileSystemDetector extends DetectorFilesystem {
throw err;
}
}
_readFile(name: string): Promise<Buffer> {
return fs.readFile(this.getFilePath(name));
}
async _isFile(name: string): Promise<boolean> {
const stat = await fs.stat(this.getFilePath(name));
return stat.isFile();
}
async _readdir(name: string): Promise<DetectorFilesystemStat[]> {
const dirPath = this.getFilePath(name);
const dir = await fs.readdir(dirPath, {
@@ -44,14 +49,22 @@ export class LocalFileSystemDetector extends DetectorFilesystem {
};
return dir.map(dirent => ({
name: dirent.name,
path: path.join(dirPath, dirent.name),
path: path.join(this.getRelativeFilePath(name), dirent.name),
type: getType(dirent),
}));
}
_chdir(name: string): DetectorFilesystem {
return new LocalFileSystemDetector(this.getFilePath(name));
}
private getRelativeFilePath(name: string) {
return name.startsWith(this.rootPath)
? path.relative(this.rootPath, name)
: name;
}
private getFilePath(name: string) {
return path.join(this.rootPath, name);
return path.join(this.rootPath, this.getRelativeFilePath(name));
}
}

View File

@@ -1,7 +1,7 @@
import path from 'path';
import { LocalFileSystemDetector } from '../src';
import { detectFramework } from '../src/detect-framework';
import monorepoManagers from '../src/monorepos/monorepo-managers';
import { FixtureFilesystem } from './utils/fixture-filesystem';
describe('monorepo-managers', () => {
describe.each([
@@ -17,7 +17,7 @@ describe('monorepo-managers', () => {
it(testName, async () => {
const fixture = path.join(__dirname, 'fixtures', fixturePath);
const fs = new FixtureFilesystem(fixture);
const fs = new LocalFileSystemDetector(fixture);
const result = await detectFramework({
fs,

View File

@@ -1,6 +1,9 @@
import path from 'path';
import { packageManagers, detectFramework } from '../src';
import { FixtureFilesystem } from './utils/fixture-filesystem';
import {
packageManagers,
detectFramework,
LocalFileSystemDetector,
} from '../src';
describe('package-managers', () => {
describe.each([
@@ -16,7 +19,7 @@ describe('package-managers', () => {
it(testName, async () => {
const fixture = path.join(__dirname, 'fixtures', fixturePath);
const fs = new FixtureFilesystem(fixture);
const fs = new LocalFileSystemDetector(fixture);
const result = await detectFramework({
fs,

View File

@@ -1,7 +1,7 @@
import path from 'path';
import { LocalFileSystemDetector } from '../src';
import { detectFramework } from '../src/detect-framework';
import workspaceManagers from '../src/workspaces/workspace-managers';
import { FixtureFilesystem } from './utils/fixture-filesystem';
describe('workspace-managers', () => {
describe.each([
@@ -19,7 +19,7 @@ describe('workspace-managers', () => {
it(testName, async () => {
const fixture = path.join(__dirname, 'fixtures', fixturePath);
const fs = new FixtureFilesystem(fixture);
const fs = new LocalFileSystemDetector(fixture);
const result = await detectFramework({
fs,

View File

@@ -1,13 +1,12 @@
import frameworkList from '@vercel/frameworks';
import { detectFramework } from '../src';
import { FixtureFilesystem } from './utils/fixture-filesystem';
import { detectFramework, LocalFileSystemDetector } from '../src';
import { getExamples } from '../../../examples/__tests__/test-utils';
describe('examples should be detected', () => {
it.each(getExamples())(
'should detect $exampleName',
async ({ exampleName, examplePath }) => {
const fs = new FixtureFilesystem(examplePath);
const fs = new LocalFileSystemDetector(examplePath);
const framework = await detectFramework({ fs, frameworkList });
if (!framework) {
throw new Error(`Framework not detected for example "${exampleName}".`);

View File

@@ -1,13 +1,12 @@
import os from 'os';
import path from 'path';
import { mkdtempSync } from 'fs';
import {
getMonorepoDefaultSettings,
LocalFileSystemDetector,
MissingBuildPipeline,
MissingBuildTarget,
} from '../src';
import path from 'path';
import fs from 'fs';
import os from 'os';
import { FixtureFilesystem } from './utils/fixture-filesystem';
describe('getMonorepoDefaultSettings', () => {
test('MissingBuildTarget is an error', () => {
@@ -69,7 +68,7 @@ describe('getMonorepoDefaultSettings', () => {
},
};
const ffs = new FixtureFilesystem(
const fs = new LocalFileSystemDetector(
path.join(
__dirname,
'fixtures',
@@ -81,16 +80,16 @@ describe('getMonorepoDefaultSettings', () => {
packageName,
isRoot ? '/' : 'packages/app-1',
isRoot ? '/' : '../..',
ffs
fs
);
expect(result).toStrictEqual(expectedResultMap[expectedResultKey]);
}
);
test('returns null when neither nx nor turbo is detected', async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'monorepo-test-'));
const lfs = new LocalFileSystemDetector(dir);
const result = await getMonorepoDefaultSettings('', '', '', lfs);
const dir = mkdtempSync(path.join(os.tmpdir(), 'monorepo-test-'));
const fs = new LocalFileSystemDetector(dir);
const result = await getMonorepoDefaultSettings('', '', '', fs);
expect(result).toBe(null);
});
});

View File

@@ -1,7 +1,7 @@
import path from 'path';
import { normalizePath } from '@vercel/build-utils';
import { getProjectPaths, ProjectPath } from '../src/get-project-paths';
import { FixtureFilesystem } from './utils/fixture-filesystem';
import { LocalFileSystemDetector } from '../src';
describe.each<{
fixturePath: string;
@@ -52,7 +52,7 @@ describe.each<{
it(testName, async () => {
const fixture = path.join(__dirname, 'fixtures', fixturePath);
const fs = new FixtureFilesystem(fixture);
const fs = new LocalFileSystemDetector(fixture);
const mockReaddir = jest.fn().mockImplementation(fs.readdir);
const mockHasPath = jest.fn().mockImplementation(fs.hasPath);
fs.readdir = mockReaddir;

View File

@@ -1,7 +1,7 @@
import path from 'path';
import { getWorkspaces } from '../src/workspaces/get-workspaces';
import { getWorkspacePackagePaths } from '../src/workspaces/get-workspace-package-paths';
import { FixtureFilesystem } from './utils/fixture-filesystem';
import { LocalFileSystemDetector } from '../src';
describe.each<[string, string[]]>([
['21-npm-workspaces', ['/a', '/b']],
@@ -32,7 +32,7 @@ describe.each<[string, string[]]>([
it(testName, async () => {
const fixture = path.join(__dirname, 'fixtures', fixturePath);
const fs = new FixtureFilesystem(fixture);
const fs = new LocalFileSystemDetector(fixture);
const workspaces = await getWorkspaces({ fs });
const actualPackagePaths = (

View File

@@ -1,6 +1,6 @@
import path from 'path';
import { LocalFileSystemDetector } from '../src';
import { getWorkspaces, Workspace } from '../src/workspaces/get-workspaces';
import { FixtureFilesystem } from './utils/fixture-filesystem';
describe.each<[string, Workspace[]]>([
['21-npm-workspaces', [{ type: 'npm', rootPath: '/' }]],
@@ -34,7 +34,7 @@ describe.each<[string, Workspace[]]>([
it(testName, async () => {
const fixture = path.join(__dirname, 'fixtures', fixturePath);
const fs = new FixtureFilesystem(fixture);
const fs = new LocalFileSystemDetector(fixture);
const actualWorkspaces = await getWorkspaces({ fs });

View File

@@ -5,7 +5,7 @@ import { LocalFileSystemDetector, DetectorFilesystem } from '../src';
const tmpdir = path.join(os.tmpdir(), 'local-file-system-test');
const dirs = ['', 'a', 'a/b']; // root, single-nested, double-nested
const dirs = ['', 'a', `a${path.sep}b`]; // root, single-nested, double-nested
const files = ['foo', 'bar'];
const filePaths = dirs.flatMap(dir => files.map(file => path.join(dir, file)));
@@ -63,12 +63,7 @@ describe('LocalFileSystemDetector', () => {
const readdirResults = await Promise.all(
dirs.map(dir => localFileSystem.readdir(dir))
);
const expectedPaths = [
...dirs.map(dir => path.join(tmpdir, dir)),
...filePaths.map(filePath => path.join(tmpdir, filePath)),
]
.sort()
.slice(1); // drop the first path since its the root
const expectedPaths = [...dirs, ...filePaths].sort().slice(1); // drop the first path since its the root
const actualPaths = readdirResults
.flatMap(result => result.map(stat => stat.path))
.sort();

View File

@@ -1,51 +0,0 @@
import { promises } from 'fs';
import path from 'path';
import { DetectorFilesystem } from '../../src';
import { DetectorFilesystemStat } from '../../src/detectors/filesystem';
const { stat, readFile, readdir } = promises;
export class FixtureFilesystem extends DetectorFilesystem {
private rootPath: string;
constructor(fixturePath: string) {
super();
this.rootPath = fixturePath;
}
async _hasPath(name: string): Promise<boolean> {
try {
const filePath = path.join(this.rootPath, name);
await stat(filePath);
return true;
} catch {
return false;
}
}
async _readFile(name: string): Promise<Buffer> {
const filePath = path.join(this.rootPath, name);
return readFile(filePath);
}
async _isFile(name: string): Promise<boolean> {
const filePath = path.join(this.rootPath, name);
return (await stat(filePath)).isFile();
}
async _readdir(name: string): Promise<DetectorFilesystemStat[]> {
const dirPath = path.join(this.rootPath, name);
const files = await readdir(dirPath, { withFileTypes: true });
return files.map(file => ({
name: file.name,
type: file.isFile() ? 'file' : 'dir',
path: path.join(name, file.name),
}));
}
_chdir(name: string): DetectorFilesystem {
return new FixtureFilesystem(path.join(this.rootPath, name));
}
}

View File

@@ -1,5 +1,12 @@
# @vercel/gatsby-plugin-vercel-builder
## 1.3.9
### Patch Changes
- Updated dependencies [[`a04bf557f`](https://github.com/vercel/vercel/commit/a04bf557fc6e1080a117428977d0993dec78b004)]:
- @vercel/node@2.15.1
## 1.3.8
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/gatsby-plugin-vercel-builder",
"version": "1.3.8",
"version": "1.3.9",
"main": "dist/index.js",
"files": [
"dist",
@@ -21,7 +21,7 @@
"dependencies": {
"@sinclair/typebox": "0.25.24",
"@vercel/build-utils": "6.7.5",
"@vercel/node": "2.15.0",
"@vercel/node": "2.15.1",
"@vercel/routing-utils": "2.2.1",
"esbuild": "0.14.47",
"etag": "1.8.1",

View File

@@ -1,5 +1,11 @@
# @vercel/node
## 2.15.1
### Patch Changes
- handle undefined content type in `vc dev` ([#10077](https://github.com/vercel/vercel/pull/10077))
## 2.15.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node",
"version": "2.15.0",
"version": "2.15.1",
"license": "Apache-2.0",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",

View File

@@ -27,10 +27,19 @@ class ApiError extends Error {
}
}
function normalizeContentType(contentType: string | undefined) {
if (!contentType) {
return 'text/plain';
}
const { parse: parseContentType } = require('content-type');
const { type } = parseContentType(contentType);
return type;
}
function getBodyParser(body: Buffer, contentType: string | undefined) {
return function parseBody(): VercelRequestBody {
const { parse: parseContentType } = require('content-type');
const { type } = parseContentType(contentType);
const type = normalizeContentType(contentType);
if (type === 'application/json') {
try {

View File

@@ -1,5 +1,12 @@
# @vercel/static-build
## 1.3.36
### Patch Changes
- Updated dependencies []:
- @vercel/gatsby-plugin-vercel-builder@1.3.9
## 1.3.35
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/static-build",
"version": "1.3.35",
"version": "1.3.36",
"license": "Apache-2.0",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/build-step",
@@ -20,7 +20,7 @@
},
"dependencies": {
"@vercel/gatsby-plugin-vercel-analytics": "1.0.10",
"@vercel/gatsby-plugin-vercel-builder": "1.3.8"
"@vercel/gatsby-plugin-vercel-builder": "1.3.9"
},
"devDependencies": {
"@types/aws-lambda": "8.10.64",
@@ -35,7 +35,7 @@
"@vercel/build-utils": "6.7.5",
"@vercel/error-utils": "1.0.10",
"@vercel/frameworks": "1.4.2",
"@vercel/fs-detectors": "3.9.3",
"@vercel/fs-detectors": "4.0.0",
"@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "2.2.1",
"@vercel/static-config": "2.0.17",

56
pnpm-lock.yaml generated
View File

@@ -86,8 +86,8 @@ importers:
specifier: 29.1.0
version: 29.1.0(@babel/core@7.5.0)(jest@29.5.0)(typescript@4.9.5)
turbo:
specifier: 1.10.1
version: 1.10.1
specifier: 1.10.3
version: 1.10.3
typescript:
specifier: 4.9.5
version: 4.9.5
@@ -326,7 +326,7 @@ importers:
specifier: 3.8.6
version: link:../next
'@vercel/node':
specifier: 2.15.0
specifier: 2.15.1
version: link:../node
'@vercel/python':
specifier: 3.1.60
@@ -341,7 +341,7 @@ importers:
specifier: 1.3.76
version: link:../ruby
'@vercel/static-build':
specifier: 1.3.35
specifier: 1.3.36
version: link:../static-build
devDependencies:
'@alex_neo/jest-expect-message':
@@ -486,7 +486,7 @@ importers:
specifier: 1.4.2
version: link:../frameworks
'@vercel/fs-detectors':
specifier: 3.9.3
specifier: 4.0.0
version: link:../fs-detectors
'@vercel/fun':
specifier: 1.0.4
@@ -955,7 +955,7 @@ importers:
specifier: 6.7.5
version: link:../build-utils
'@vercel/node':
specifier: 2.15.0
specifier: 2.15.1
version: link:../node
'@vercel/routing-utils':
specifier: 2.2.1
@@ -1438,7 +1438,7 @@ importers:
specifier: 1.0.10
version: link:../gatsby-plugin-vercel-analytics
'@vercel/gatsby-plugin-vercel-builder':
specifier: 1.3.8
specifier: 1.3.9
version: link:../gatsby-plugin-vercel-builder
devDependencies:
'@types/aws-lambda':
@@ -1478,7 +1478,7 @@ importers:
specifier: 1.4.2
version: link:../frameworks
'@vercel/fs-detectors':
specifier: 3.9.3
specifier: 4.0.0
version: link:../fs-detectors
'@vercel/ncc':
specifier: 0.24.0
@@ -16253,65 +16253,65 @@ packages:
safe-buffer: 5.2.1
dev: true
/turbo-darwin-64@1.10.1:
resolution: {integrity: sha512-isLLoPuAOMNsYovOq9BhuQOZWQuU13zYsW988KkkaA4OJqOn7qwa9V/KBYCJL8uVQqtG+/Y42J37lO8RJjyXuA==}
/turbo-darwin-64@1.10.3:
resolution: {integrity: sha512-IIB9IomJGyD3EdpSscm7Ip1xVWtYb7D0x7oH3vad3gjFcjHJzDz9xZ/iw/qItFEW+wGFcLSRPd+1BNnuLM8AsA==}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/turbo-darwin-arm64@1.10.1:
resolution: {integrity: sha512-x1nloPR10fLElNCv17BKr0kCx/O5gse/UXAcVscMZH2tvRUtXrdBmut62uw2YU3J9hli2fszYjUWXkulVpQvFA==}
/turbo-darwin-arm64@1.10.3:
resolution: {integrity: sha512-SBNmOZU9YEB0eyNIxeeQ+Wi0Ufd+nprEVp41rgUSRXEIpXjsDjyBnKnF+sQQj3+FLb4yyi/yZQckB+55qXWEsw==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/turbo-linux-64@1.10.1:
resolution: {integrity: sha512-abV+ODCeOlz0503OZlHhPWdy3VwJZc1jObf1VQj7uQM+JqJ/kXbMyqJIMQVz+m7QJUFdferYPRxGhYT/NbYK7Q==}
/turbo-linux-64@1.10.3:
resolution: {integrity: sha512-kvAisGKE7xHJdyMxZLvg53zvHxjqPK1UVj4757PQqtx9dnjYHSc8epmivE6niPgDHon5YqImzArCjVZJYpIGHQ==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/turbo-linux-arm64@1.10.1:
resolution: {integrity: sha512-zRC3nZbHQ63tofOmbuySzEn1ROISWTkemYYr1L98rpmT5aVa0kERlGiYcfDwZh3cBso/Ylg/wxexRAaPzcCJYQ==}
/turbo-linux-arm64@1.10.3:
resolution: {integrity: sha512-Qgaqln0IYRgyL0SowJOi+PNxejv1I2xhzXOI+D+z4YHbgSx87ox1IsALYBlK8VRVYY8VCXl+PN12r1ioV09j7A==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/turbo-windows-64@1.10.1:
resolution: {integrity: sha512-Irqz8IU+o7Q/5V44qatZBTunk+FQAOII1hZTsEU54ah62f9Y297K6/LSp+yncmVQOZlFVccXb6MDqcETExIQtA==}
/turbo-windows-64@1.10.3:
resolution: {integrity: sha512-rbH9wManURNN8mBnN/ZdkpUuTvyVVEMiUwFUX4GVE5qmV15iHtZfDLUSGGCP2UFBazHcpNHG1OJzgc55GFFrUw==}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/turbo-windows-arm64@1.10.1:
resolution: {integrity: sha512-124IT15d2gyjC+NEn11pHOaVFvZDRHpxfF+LDUzV7YxfNIfV0mGkR3R/IyVXtQHOgqOdtQTbC4y411sm31+SEw==}
/turbo-windows-arm64@1.10.3:
resolution: {integrity: sha512-ThlkqxhcGZX39CaTjsHqJnqVe+WImjX13pmjnpChz6q5HHbeRxaJSFzgrHIOt0sUUVx90W/WrNRyoIt/aafniw==}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/turbo@1.10.1:
resolution: {integrity: sha512-wq0YeSv6P/eEDXOL42jkMUr+T4z34dM8mdHu5u6C6OOAq8JuLJ72F/v4EVR1JmY8icyTkFz10ICLV0haUUYhbQ==}
/turbo@1.10.3:
resolution: {integrity: sha512-U4gKCWcKgLcCjQd4Pl8KJdfEKumpyWbzRu75A6FCj6Ctea1PIm58W6Ltw1QXKqHrl2pF9e1raAskf/h6dlrPCA==}
hasBin: true
requiresBuild: true
optionalDependencies:
turbo-darwin-64: 1.10.1
turbo-darwin-arm64: 1.10.1
turbo-linux-64: 1.10.1
turbo-linux-arm64: 1.10.1
turbo-windows-64: 1.10.1
turbo-windows-arm64: 1.10.1
turbo-darwin-64: 1.10.3
turbo-darwin-arm64: 1.10.3
turbo-linux-64: 1.10.3
turbo-linux-arm64: 1.10.3
turbo-windows-64: 1.10.3
turbo-windows-arm64: 1.10.3
dev: true
/tweetnacl@0.14.5: