Compare commits

..

3 Commits

Author SHA1 Message Date
Nathan Rajlich
6155759e40 Revert "[cli] Fix how we determine the GIT_CONFIG_PATH to support git worktrees and git submodules (#11283)"
This reverts commit 5b8b87739e.
2024-04-08 11:35:37 -07:00
Nathan Rajlich
f0bc911514 . 2024-04-08 11:35:05 -07:00
Nathan Rajlich
dc30c134ef [do not merge] Debugging for Jake 2024-04-05 00:06:19 -07:00
89 changed files with 673 additions and 8701 deletions

View File

@@ -0,0 +1,4 @@
---
---
disable eslint for a few files

View File

@@ -0,0 +1,5 @@
---
"@vercel/go": patch
---
Add support for `1.22` and update Go minor versions `1.19`, `1.20` and `1.21`

View File

@@ -0,0 +1,4 @@
---
---
[framework-fixtures]: Bump the core group in /packages/static-build/test/fixtures/ionic-react-v7 with 2 updates

View File

@@ -0,0 +1,5 @@
---
"vercel": patch
---
avoid printing errors when user does ctrl+c

View File

@@ -0,0 +1,4 @@
---
---
[framework-fixtures]: Bump the core group in /packages/static-build/test/fixtures/stencil-v4 with 1 update

View File

@@ -0,0 +1,4 @@
---
---
[framework-fixtures]: Bump the core group in /packages/static-build/test/fixtures/nuxt-v3 with 3 updates

View File

@@ -0,0 +1,5 @@
---
'vercel': minor
---
improve UX for text input validation

View File

@@ -0,0 +1,5 @@
---
'vercel': minor
---
Replace the implementation of the yes/no prompt in several areas to be consistent with the rest of the CLI.

View File

@@ -0,0 +1,4 @@
---
---
[framework-fixtures]: Bump the core group in /packages/static-build/test/fixtures/nuxt-v3 with 3 updates

View File

@@ -0,0 +1,4 @@
---
---
[framework-fixtures]: Bump the core group in /packages/static-build/test/fixtures/preact-v10 with 2 updates

View File

@@ -0,0 +1,4 @@
---
---
Move CONTRIBUTING into README and improve docs on running integration tests locally

View File

@@ -0,0 +1,2 @@
---
---

View File

@@ -0,0 +1,5 @@
---
'vercel': patch
---
Warn that promoting preview deploys is deprecated

View File

@@ -85,7 +85,7 @@ jobs:
env:
FORCE_COLOR: '1'
- name: Test ${{matrix.packageName}}
run: node utils/gen.js && node_modules/.bin/turbo run ${{matrix.testScript}} --summarize --cache-dir=".turbo" --log-order=stream --scope=${{matrix.packageName}} --no-deps -- ${{ join(matrix.testPaths, ' ') }}
run: node utils/gen.js && node_modules/.bin/turbo run test --summarize --cache-dir=".turbo" --log-order=stream --scope=${{matrix.packageName}} --no-deps -- ${{ join(matrix.testPaths, ' ') }}
shell: bash
env:
JEST_JUNIT_OUTPUT_FILE: ${{github.workspace}}/.junit-reports/${{matrix.scriptName}}-${{matrix.packageName}}-${{matrix.chunkNumber}}-${{ matrix.runner }}.xml

View File

@@ -50,4 +50,4 @@ Ensure any segments used in the `destination` property are also used in the `sou
- [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v6.1.0)
- [named parameters](https://github.com/pillarjs/path-to-regexp/blob/v6.1.0/Readme.md#named-parameters)
- [un-named parameters](https://github.com/pillarjs/path-to-regexp/blob/v6.1.0/Readme.md#unnamed-parameters)
- [un-named paramters](https://github.com/pillarjs/path-to-regexp/blob/v6.1.0/Readme.md#unnamed-parameters)

View File

@@ -33,7 +33,7 @@
"source-map-support": "0.5.12",
"ts-eager": "2.0.2",
"ts-jest": "29.1.0",
"turbo": "1.13.2",
"turbo": "1.13.0",
"typescript": "4.9.5"
},
"scripts": {

View File

@@ -1,47 +1,5 @@
# vercel
## 34.0.0
### Major Changes
- Disables promotion of preview deployments ([#11411](https://github.com/vercel/vercel/pull/11411))
### Patch Changes
- Always set `projectSettings.nodeVersion` in `vc deploy` ([#11351](https://github.com/vercel/vercel/pull/11351))
- [cli] optional override of existing environment variables with --force ([#11348](https://github.com/vercel/vercel/pull/11348))
## 33.7.1
### Patch Changes
- fix flickering during interactive UI rerendering ([#11392](https://github.com/vercel/vercel/pull/11392))
- fix `vc ls` message to be `vc projects ls` ([#11400](https://github.com/vercel/vercel/pull/11400))
- Updated dependencies [[`2461b571a`](https://github.com/vercel/vercel/commit/2461b571af037fbfdf92299a272010a5a8f4898b)]:
- @vercel/next@4.2.0
## 33.7.0
### Minor Changes
- improve UX for text input validation ([#11388](https://github.com/vercel/vercel/pull/11388))
- Replace the implementation of the yes/no prompt in several areas to be consistent with the rest of the CLI. ([#11279](https://github.com/vercel/vercel/pull/11279))
### Patch Changes
- [cli] Fix how we determine the GIT_CONFIG_PATH to support git worktrees and git submodules ([#11283](https://github.com/vercel/vercel/pull/11283))
- avoid printing errors when user does ctrl+c ([#11377](https://github.com/vercel/vercel/pull/11377))
- Warn that promoting preview deploys is deprecated ([#11376](https://github.com/vercel/vercel/pull/11376))
- Updated dependencies [[`a3fb7e6ab`](https://github.com/vercel/vercel/commit/a3fb7e6abe9bb619a653850decd739728b1af225)]:
- @vercel/go@3.1.1
## 33.6.3
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "34.0.0",
"version": "33.6.3",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -12,8 +12,7 @@
},
"scripts": {
"test": "jest --reporters=default --reporters=jest-junit --env node --verbose --bail",
"vitest-unit-run": "pnpm vitest",
"vitest-unit": "pnpm jest test/unit/ --listTests",
"test-unit": "pnpm vitest test/unit/",
"test-e2e": "rimraf test/fixtures/integration && pnpm test test/integration-1.test.ts test/integration-2.test.ts test/integration-3.test.ts",
"test-dev": "pnpm test test/dev/",
"coverage": "codecov",
@@ -34,9 +33,9 @@
"dependencies": {
"@vercel/build-utils": "7.11.0",
"@vercel/fun": "1.1.0",
"@vercel/go": "3.1.1",
"@vercel/go": "3.1.0",
"@vercel/hydrogen": "1.0.2",
"@vercel/next": "4.2.0",
"@vercel/next": "4.1.6",
"@vercel/node": "3.0.26",
"@vercel/python": "4.1.1",
"@vercel/redwood": "2.0.8",
@@ -48,11 +47,11 @@
"devDependencies": {
"@alex_neo/jest-expect-message": "1.0.5",
"@edge-runtime/node-utils": "2.3.0",
"@inquirer/checkbox": "2.2.2",
"@inquirer/confirm": "3.1.2",
"@inquirer/expand": "2.1.2",
"@inquirer/input": "2.1.2",
"@inquirer/select": "2.2.2",
"@inquirer/checkbox": "2.2.0",
"@inquirer/confirm": "3.1.0",
"@inquirer/expand": "2.1.0",
"@inquirer/input": "2.1.1",
"@inquirer/select": "2.2.0",
"@next/env": "11.1.2",
"@sentry/node": "5.5.0",
"@sindresorhus/slugify": "0.11.0",
@@ -84,6 +83,7 @@
"@types/qs": "6.9.7",
"@types/semver": "6.0.1",
"@types/tar-fs": "1.16.1",
"@types/text-table": "0.2.0",
"@types/title": "3.4.1",
"@types/universal-analytics": "0.4.2",
"@types/update-notifier": "5.1.0",
@@ -93,7 +93,7 @@
"@vercel-internals/constants": "1.0.4",
"@vercel-internals/get-package-json": "1.0.0",
"@vercel-internals/types": "1.0.29",
"@vercel/client": "13.2.0",
"@vercel/client": "13.1.9",
"@vercel/error-utils": "2.0.2",
"@vercel/frameworks": "3.0.1",
"@vercel/fs-detectors": "5.2.2",
@@ -162,6 +162,7 @@
"strip-ansi": "6.0.1",
"supports-hyperlinks": "3.0.0",
"tar-fs": "1.16.3",
"text-table": "0.2.0",
"title": "3.4.1",
"tmp-promise": "1.0.3",
"tree-kill": "1.2.2",

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk';
import ms from 'ms';
import table from '../../util/output/table';
import table from 'text-table';
import Client from '../../util/client';
import getAliases from '../../util/alias/get-aliases';
import getScope from '../../util/get-scope';
@@ -9,6 +9,7 @@ import {
getPaginationOpts,
} from '../../util/get-pagination-opts';
import stamp from '../../util/output/stamp';
import strlen from '../../util/strlen';
import getCommandFlags from '../../util/get-command-flags';
import { getCommandName } from '../../util/pkg-name';
import type { Alias } from '@vercel-internals/types';
@@ -77,6 +78,10 @@ function printAliasTable(aliases: Alias[]) {
ms(Date.now() - a.createdAt),
]),
],
{ align: ['l', 'l', 'r'], hsep: 4 }
{
align: ['l', 'l', 'r'],
hsep: ' '.repeat(4),
stringLength: strlen,
}
).replace(/^/gm, ' ')}\n\n`;
}

View File

@@ -1,10 +1,11 @@
import chalk from 'chalk';
import ms from 'ms';
import table from '../../util/output/table';
import table from 'text-table';
import Client from '../../util/client';
import getScope from '../../util/get-scope';
import removeAliasById from '../../util/alias/remove-alias-by-id';
import stamp from '../../util/output/stamp';
import strlen from '../../util/strlen';
import confirm from '../../util/input/confirm';
import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id';
@@ -83,7 +84,11 @@ async function confirmAliasRemove(client: Client, alias: Alias) {
chalk.gray(`${ms(Date.now() - alias.createdAt)} ago`),
],
],
{ hsep: 4 }
{
align: ['l', 'l', 'r'],
hsep: ' '.repeat(4),
stringLength: strlen,
}
);
client.output.log(`The following alias will be removed permanently`);

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk';
import ms from 'ms';
import table from '../../util/output/table';
import table from 'text-table';
import Client from '../../util/client';
import getScope from '../../util/get-scope';
import {
@@ -9,6 +9,7 @@ import {
} from '../../util/get-pagination-opts';
import stamp from '../../util/output/stamp';
import getCerts from '../../util/certs/get-certs';
import strlen from '../../util/strlen';
import type { Cert } from '@vercel-internals/types';
import getCommandFlags from '../../util/get-command-flags';
import { getCommandName } from '../../util/pkg-name';
@@ -69,7 +70,11 @@ async function ls(
function formatCertsTable(certsList: Cert[]) {
return `${table(
[formatCertsTableHead(), ...formatCertsTableBody(certsList)],
{ align: ['l', 'l', 'r', 'c', 'r'], hsep: 2 }
{
align: ['l', 'l', 'r', 'c', 'r'],
hsep: ' '.repeat(2),
stringLength: strlen,
}
).replace(/^(.*)/gm, ' $1')}\n`;
}

View File

@@ -1,7 +1,7 @@
import chalk from 'chalk';
import ms from 'ms';
import plural from 'pluralize';
import table from '../../util/output/table';
import table from 'text-table';
import type { Cert } from '@vercel-internals/types';
import * as ERRORS from '../../util/errors-ts';
import { Output } from '../../util/output';
@@ -98,7 +98,7 @@ function readConfirmation(output: Output, msg: string, certs: Cert[]) {
output.print(
`${table(certs.map(formatCertRow), {
align: ['l', 'r', 'l'],
hsep: 6,
hsep: ' '.repeat(6),
}).replace(/^(.*)/gm, ' $1')}\n`
);
output.print(

View File

@@ -169,6 +169,7 @@ export default async (client: Client): Promise<number> => {
const quiet = !client.stdout.isTTY;
let { path: cwd } = pathValidation;
console.log('deploy', { cwd });
const autoConfirm = argv['--yes'];
// deprecate --name
@@ -208,6 +209,7 @@ export default async (client: Client): Promise<number> => {
// retrieve `project` and `org` from .vercel
const link = await getLinkedProject(client, cwd);
console.log(link);
if (link.status === 'error') {
return link.exitCode;
@@ -520,6 +522,23 @@ export default async (client: Client): Promise<number> => {
);
}
const { packageJson } = await scanParentDirs(
join(cwd, project?.rootDirectory ?? ''),
true,
cwd
);
let nodeVersion: string | undefined;
if (packageJson?.engines?.node) {
try {
const { range } = await getSupportedNodeVersion(packageJson.engines.node);
nodeVersion = range;
} catch (error) {
if (error instanceof Error) {
output.warn(error.message);
}
}
}
try {
// if this flag is not set, use `undefined` to allow the project setting to be used
const autoAssignCustomDomains = argv['--skip-domain'] ? false : undefined;
@@ -556,6 +575,7 @@ export default async (client: Client): Promise<number> => {
createArgs.projectSettings = {
sourceFilesOutsideRootDirectory,
rootDirectory,
nodeVersion,
};
if (status === 'linked') {
@@ -566,30 +586,6 @@ export default async (client: Client): Promise<number> => {
}
}
// Read the `engines.node` field from `package.json` and send as a
// `projectSettings` property as an optimization (so that the API
// does not need to retrieve the file to do this check).
const { packageJson } = await scanParentDirs(
join(cwd, project?.rootDirectory ?? ''),
true,
cwd
);
let nodeVersion: string | undefined;
if (packageJson?.engines?.node) {
try {
const { range } = await getSupportedNodeVersion(
packageJson.engines.node
);
nodeVersion = range;
} catch (error) {
if (error instanceof Error) {
output.warn(error.message);
}
}
}
if (!createArgs.projectSettings) createArgs.projectSettings = {};
createArgs.projectSettings.nodeVersion = nodeVersion;
deployment = await createDeploy(
client,
now,

View File

@@ -1,6 +1,6 @@
import chalk from 'chalk';
import ms from 'ms';
import table from '../../util/output/table';
import table from 'text-table';
import type { DNSRecord } from '@vercel-internals/types';
import { Output } from '../../util/output';
import Client from '../../util/client';
@@ -71,7 +71,7 @@ function readConfirmation(
output.print(
`${table([getDeleteTableRow(domainName, record)], {
align: ['l', 'r', 'l'],
hsep: 6,
hsep: ' '.repeat(6),
}).replace(/^(.*)/gm, ' $1')}\n`
);
output.print(

View File

@@ -20,7 +20,6 @@ import { isAPIError } from '../../util/errors-ts';
type Options = {
'--debug': boolean;
'--sensitive': boolean;
'--force': boolean;
};
export default async function add(
@@ -82,7 +81,7 @@ export default async function add(
);
const choices = envTargetChoices.filter(c => !existing.has(c.value));
if (choices.length === 0 && !opts['--force']) {
if (choices.length === 0) {
output.error(
`The variable ${param(
envName
@@ -126,7 +125,6 @@ export default async function add(
}
const type = opts['--sensitive'] ? 'sensitive' : 'encrypted';
const upsert = opts['--force'] ? 'true' : '';
const addStamp = stamp();
try {
@@ -135,7 +133,6 @@ export default async function add(
output,
client,
project.id,
upsert,
type,
envName,
envValue,
@@ -152,11 +149,9 @@ export default async function add(
output.print(
`${prependEmoji(
`${
opts['--force'] ? 'Overrode' : 'Added'
} Environment Variable ${chalk.bold(envName)} to Project ${chalk.bold(
project.name
)} ${chalk.gray(addStamp())}`,
`Added Environment Variable ${chalk.bold(
envName
)} to Project ${chalk.bold(project.name)} ${chalk.gray(addStamp())}`,
emoji('success')
)}\n`
);

View File

@@ -43,14 +43,6 @@ export const envCommand: Command = {
deprecated: false,
multi: false,
},
{
name: 'force',
description: 'Force overwrites when a command would normally fail',
shorthand: null,
type: 'boolean',
deprecated: false,
multi: false,
},
],
examples: [],
},
@@ -134,10 +126,6 @@ export const envCommand: Command = {
`${packageName} env add DB_PASS production`,
],
},
{
name: 'Override an existing Environment Variable of same target (production, preview, deployment)',
value: `${packageName} env add API_TOKEN --force`,
},
{
name: 'Add a sensitive Environment Variable',
value: `${packageName} env add API_TOKEN --sensitive`,

View File

@@ -35,7 +35,6 @@ export default async function main(client: Client) {
'--environment': String,
'--git-branch': String,
'--sensitive': Boolean,
'--force': Boolean,
});
} catch (error) {
handleError(error);

View File

@@ -1,7 +1,6 @@
import chalk from 'chalk';
import { LOGO, NAME } from '@vercel-internals/constants';
import Table, { CellOptions } from 'cli-table3';
import { noBorderChars } from '../util/output/table';
const INDENT = ' '.repeat(2);
const NEWLINE = '\n';
@@ -40,7 +39,23 @@ type _CellOptions = CellOptions & {
};
const tableOptions = {
chars: noBorderChars,
chars: {
top: '',
'top-mid': '',
'top-left': '',
'top-right': '',
bottom: '',
'bottom-mid': '',
'bottom-left': '',
'bottom-right': '',
left: '',
'left-mid': '',
mid: '',
'mid-mid': '',
right: '',
'right-mid': '',
middle: '',
},
style: {
'padding-left': 0,
'padding-right': 0,

View File

@@ -1,11 +1,12 @@
import chalk from 'chalk';
import ms from 'ms';
import table from '../../util/output/table';
import table from 'text-table';
import title from 'title';
import Now from '../../util';
import getArgs from '../../util/get-args';
import { handleError } from '../../util/error';
import elapsed from '../../util/output/elapsed';
import strlen from '../../util/strlen';
import toHost from '../../util/to-host';
import parseMeta from '../../util/parse-meta';
import { isValidName } from '../../util/is-valid-name';
@@ -274,7 +275,11 @@ export default async function list(client: Client) {
app === null ? filterUniqueApps() : () => true
),
],
{ hsep: 5 }
{
align: ['l', 'l', 'l', 'l', 'l'],
hsep: ' '.repeat(5),
stringLength: strlen,
}
).replace(/^/gm, ' ')}\n\n`
);

View File

@@ -1,10 +1,11 @@
import chalk from 'chalk';
import ms from 'ms';
import table from '../../util/output/table';
import table from 'text-table';
import type { Project } from '@vercel-internals/types';
import Client from '../../util/client';
import getCommandFlags from '../../util/get-command-flags';
import { getCommandName } from '../../util/pkg-name';
import strlen from '../../util/strlen';
import { NODE_VERSIONS } from '@vercel/build-utils';
export default async function list(
@@ -99,7 +100,11 @@ export default async function list(
])
.flat(),
],
{ hsep: 3 }
{
align: ['l', 'l', 'l'],
hsep: ' '.repeat(3),
stringLength: strlen,
}
).replace(/^/gm, ' ');
output.print(`\n${tablePrint}\n\n`);

View File

@@ -32,9 +32,15 @@ export default async function requestPromote({
output: client.output,
});
if (deployment.target !== 'production') {
output.warn(
'Promoting a preview deployment to production is deprecated and will be removed in the next major release. This behavior will be removed entirely on 2024-05-03.'
);
}
if (deployment.target !== 'production' && !yes) {
const question =
'This deployment is not a production deployment and cannot be directly promoted. A new deployment will be built using your production environment. Are you sure you want to continue?';
'This deployment does not target production, therefore promotion will not apply production environment variables. Are you sure you want to continue?';
const answer = await confirm(client, question, false);
if (!answer) {
output.error('Canceled');
@@ -43,7 +49,7 @@ export default async function requestPromote({
}
// request the promotion
await client.fetch(`/v10/projects/${project.id}/promote/${deployment.id}`, {
await client.fetch(`/v9/projects/${project.id}/promote/${deployment.id}`, {
body: {}, // required
json: false,
method: 'POST',

View File

@@ -1,7 +1,7 @@
import chalk from 'chalk';
import ms from 'ms';
import plural from 'pluralize';
import table from '../../util/output/table';
import table from 'text-table';
import Now from '../../util';
import getAliases from '../../util/alias/get-aliases';
import elapsed from '../../util/output/elapsed';
@@ -169,7 +169,7 @@ export default async function remove(client: Client) {
`or projects matching ` +
`${ids
.map(id => chalk.bold(`"${id}"`))
.join(', ')}. Run ${getCommandName('projects ls')} to list.`
.join(', ')}. Run ${getCommandName('ls')} to list.`
);
return 1;
}
@@ -245,7 +245,7 @@ function readConfirmation(
const url = depl.url ? chalk.underline(`https://${depl.url}`) : '';
return [` ${depl.id}`, url, time];
}),
{ align: ['l', 'r', 'l'], hsep: 6 }
{ align: ['l', 'r', 'l'], hsep: ' '.repeat(6) }
);
output.print(`${deploymentTable}\n`);
}

View File

@@ -1,7 +1,8 @@
import isErrnoException from '@vercel/error-utils';
import chalk from 'chalk';
import table from '../../util/output/table';
import table from 'text-table';
import ms from 'ms';
import strlen from '../../util/strlen';
import { handleError, error } from '../../util/error';
import NowSecrets from '../../util/secrets';
import getScope from '../../util/get-scope';
@@ -123,7 +124,11 @@ async function run({ output, contextName, currentTeam, client }) {
chalk.gray(`${ms(cur - new Date(secret.created))} ago`),
])
),
{ hsep: 2 }
{
align: ['l', 'l', 'l'],
hsep: ' '.repeat(2),
stringLength: strlen,
}
);
if (out) {
@@ -280,7 +285,7 @@ async function readConfirmation(client, output, secret, contextName) {
const time = chalk.gray(`${ms(new Date() - new Date(secret.created))} ago`);
const tbl = table([[chalk.bold(secret.name), time]], {
align: ['r', 'l'],
hsep: 6,
hsep: ' '.repeat(6),
});
output.print(

View File

@@ -1,6 +1,5 @@
import chars from '../../util/output/chars';
import table from '../../util/output/table';
import { gray } from 'chalk';
import getUser from '../../util/get-user';
import getTeams from '../../util/teams/get-teams';
import { packageName } from '../../util/pkg-name';
@@ -54,7 +53,7 @@ export default async function list(client: Client): Promise<number> {
id,
name,
value: slug,
prefix: id === currentTeam ? chars.tick : ' ',
current: id === currentTeam ? chars.tick : '',
}));
if (user.version !== 'northstar') {
@@ -62,7 +61,7 @@ export default async function list(client: Client): Promise<number> {
id: user.id,
name: user.email,
value: user.username || user.email,
prefix: accountIsCurrent ? chars.tick : ' ',
current: accountIsCurrent ? chars.tick : '',
});
}
@@ -77,22 +76,14 @@ export default async function list(client: Client): Promise<number> {
output.stopSpinner();
client.stdout.write('\n'); // empty line
const teamTable = table(
[
['id', 'email / name'].map(str => gray(str)),
...teamList.map(team => [team.value, team.name]),
],
{ hsep: 5 }
table(
['', 'id', 'email / name'],
teamList.map(team => [team.current, team.value, team.name]),
[1, 5],
(str: string) => {
client.stdout.write(str);
}
);
client.stderr.write(
currentTeam
? teamTable
.split('\n')
.map((line, i) => `${i > 0 ? teamList[i - 1].prefix : ' '} ${line}`)
.join('\n')
: teamTable
);
client.stderr.write('\n');
if (pagination?.count === 20) {
const flags = getCommandFlags(argv, ['_', '--next', '-N', '-d']);

View File

@@ -10,16 +10,14 @@ export default async function addEnvRecord(
output: Output,
client: Client,
projectId: string,
upsert: string,
type: ProjectEnvType,
key: string,
value: string,
targets: ProjectEnvTarget[],
gitBranch: string
): Promise<void> {
const actionWord = upsert ? 'Overriding' : 'Adding';
output.debug(
`${actionWord} ${type} Environment Variable ${key} to ${targets.length} targets`
`Adding ${type} Environment Variable ${key} to ${targets.length} targets`
);
const body: Omit<ProjectEnvVariable, 'id'> = {
type,
@@ -28,8 +26,7 @@ export default async function addEnvRecord(
target: targets,
gitBranch: gitBranch || undefined,
};
const args = upsert ? `?upsert=${upsert}` : '';
const url = `/v10/projects/${projectId}/env${args}`;
const url = `/v8/projects/${projectId}/env`;
await client.fetch(url, {
method: 'POST',
body,

View File

@@ -48,7 +48,7 @@ export default async function getEnvRecords(
query.set('source', source);
}
const url = `/v10/projects/${projectId}/env?${query}`;
const url = `/v8/projects/${projectId}/env?${query}`;
return client.fetch<{ envs: ProjectEnvVariable[] }>(url);
}

View File

@@ -1,34 +1,12 @@
import { isErrnoException } from '@vercel/error-utils';
const knownErrorsCodes = new Set([
'PAYMENT_REQUIRED',
'BAD_REQUEST',
'ENV_ALREADY_EXISTS',
'ENV_CONFLICT',
'ENV_SHOULD_BE_A_SECRET',
'EXISTING_KEY_AND_TARGET',
'FORBIDDEN',
'ID_NOT_FOUND',
'INVALID_KEY',
'INVALID_VALUE',
'KEY_INVALID_CHARACTERS',
'KEY_INVALID_LENGTH',
'KEY_RESERVED',
'RESERVED_ENV_VARIABLE',
'MAX_ENVS_EXCEEDED',
'MISSING_ID',
'MISSING_KEY',
'MISSING_TARGET',
'MISSING_VALUE',
'NOT_AUTHORIZED',
'NOT_DECRYPTABLE',
'SECRET_MISSING',
'SYSTEM_ENV_WITH_VALUE',
'TEAM_NOT_FOUND',
'TOO_MANY_IDS',
'TOO_MANY_KEYS',
'UNKNOWN_ERROR',
'VALUE_INVALID_LENGTH',
'VALUE_INVALID_TYPE',
'RESERVED_ENV_VARIABLE',
'ENV_ALREADY_EXISTS',
'ENV_SHOULD_BE_A_SECRET',
]);
export function isKnownError(error: unknown) {

View File

@@ -10,9 +10,9 @@ export default async function removeEnvRecord(
): Promise<void> {
output.debug(`Removing Environment Variable ${env.key}`);
const url = `/v10/projects/${projectId}/env/${env.id}`;
const urlProject = `/v8/projects/${projectId}/env/${env.id}`;
await client.fetch<ProjectEnvVariable>(url, {
await client.fetch<ProjectEnvVariable>(urlProject, {
method: 'DELETE',
});
}

View File

@@ -1,8 +1,16 @@
import table from './output/table';
import { gray } from 'chalk';
import chalk from 'chalk';
import table from 'text-table';
import strlen from './strlen';
const HEADER = ['name', 'type', 'value'].map(v => gray(v));
const HEADER = ['name', 'type', 'value'].map(v => chalk.gray(v));
export default function formatDNSTable(rows: string[][]) {
return table([HEADER, ...rows], { hsep: 8 });
export default function formatDNSTable(
rows: string[][],
{ extraSpace = '' } = {}
) {
return table([HEADER, ...rows], {
align: ['l', 'l', 'l'],
hsep: ' '.repeat(8),
stringLength: strlen,
}).replace(/^(.*)/gm, `${extraSpace}$1`);
}

View File

@@ -1,5 +1,6 @@
import chalk from 'chalk';
import table from './output/table';
import table from 'text-table';
import strlen from './strlen';
import chars from './output/chars';
export default function formatNSTable(
@@ -34,6 +35,10 @@ export default function formatNSTable(
],
...rows,
],
{ hsep: 4 }
{
align: ['l', 'l', 'l', 'l'],
hsep: ' '.repeat(4),
stringLength: strlen,
}
).replace(/^(.*)/gm, `${extraSpace}$1`);
}

View File

@@ -1,5 +1,5 @@
import chalk from 'chalk';
import table from './output/table';
import table from 'text-table';
import strlen from './strlen';
// header:
@@ -19,8 +19,9 @@ import strlen from './strlen';
// ]
export default function formatTable(
header: string[],
align: Array<'l' | 'r' | 'c'>,
blocks: { name?: string; rows: string[][] }[]
align: Array<'l' | 'r' | 'c' | '.'>,
blocks: { name?: string; rows: string[][] }[],
hsep = ' '
) {
const nrCols = header.length;
const padding = [];
@@ -56,7 +57,7 @@ export default function formatTable(
rows[i][j] = al === 'l' ? col + pad : pad + col;
}
}
out += table(rows, { align, hsep: 4 });
out += table(rows, { align, hsep, stringLength: strlen });
}
out += '\n\n';
}

View File

@@ -1,86 +0,0 @@
import { execSync } from 'node:child_process';
/** Defines the options for executing Git commands */
export type GitExecOptions = Readonly<{
/** If set to true, the function will throw
* an error if any occurs during the execution of the Git command. By default,
* it is set to false, meaning errors are caught and handled gracefully.*/
unsafe?: boolean;
/** Specifies the current working directory
* from which the Git command should be executed.
*/
cwd: string;
}>;
const DEFAULT_GIT_EXEC_OPTS = {
unsafe: false,
};
/**
* Attempts to retrieve the Git directory for the specified working directory.
*
* This function runs the Git command to find the `.git` directory associated
* with the current or specified working directory. This is useful for
* determining if the current working environment is within a Git repository.
*
* @param {GitExecOptions} opts - The options for executing the Git command.
* @returns {string | null} The path to the Git directory if found; otherwise, null.
* If `opts.unsafe` is set to true and an error occurs, the function will throw
* an error instead of returning null.
*
* @throws {Error} Can throw an error if `opts.unsafe` is set to `true`
*/
export function getGitDirectory(opts: GitExecOptions): string | null {
const { cwd, unsafe } = { ...DEFAULT_GIT_EXEC_OPTS, ...opts };
try {
const gitConfigPath = execSync('git rev-parse --git-dir', {
cwd,
encoding: 'utf8',
});
return gitConfigPath;
} catch (error) {
if (unsafe) {
throw error;
}
return null;
}
}
/**
* Checks if a given directory is a Git worktree or Git submodule.
*
* A Git worktree is a linked working tree, which allows you to have multiple
* working trees attached to the same repository. This function checks if the
* specified directory (or the current working directory if none is specified)
* is a Git worktree by looking for the '.git/worktrees/' path in the Git
* configuration.
*
* A Git submodule is a repository embedded inside another repository. This
* function checks if the current working directory or the specified directory
* is part of a Git submodule by looking for the '.git/modules/' path in the
* Git configuration.
*
* @param {GitExecOptions} [opts={}] The options to use. Options include:
* - `cwd`: The directory to check. Defaults to `process.cwd()`.
* - `unsafe`: If true, throws if an error occurs during execution.
* Defaults to `false`.
* @returns {boolean} Returns `true` if the directory is a Git worktree or Git
* Submodule, otherwise `false`.
*
* @throws {Error} Can throw an error if `opts.unsafe` is set to `true`
*/
export function isGitWorktreeOrSubmodule(opts: GitExecOptions): boolean {
const gitDir = getGitDirectory(opts);
if (gitDir === null) {
return false;
}
const isGitWorktree = gitDir.includes('.git/worktrees/');
const isGitSubmodule = gitDir.includes('.git/modules/');
return isGitWorktree || isGitSubmodule;
}

View File

@@ -22,7 +22,6 @@ import { detectProjects } from '../projects/detect-projects';
import { repoInfoToUrl } from '../git/repo-info-to-url';
import { connectGitProvider, parseRepoUrl } from '../git/connect-git-provider';
import { isAPIError } from '../errors-ts';
import { isGitWorktreeOrSubmodule } from '../git-helpers';
const home = homedir();
@@ -360,13 +359,7 @@ export async function findRepoRoot(
): Promise<string | undefined> {
const { debug } = client.output;
const REPO_JSON_PATH = join(VERCEL_DIR, VERCEL_DIR_REPO);
/**
* If the current repo is a git submodule or git worktree '.git' is a file
* with a pointer to the "parent" git repository instead of a directory.
*/
const GIT_PATH = isGitWorktreeOrSubmodule({ cwd: client.cwd })
? normalize('.git')
: normalize('.git/config');
const GIT_CONFIG_PATH = normalize('.git/config');
for (const current of traverseUpDirectories({ start })) {
if (current === home) {
@@ -390,12 +383,12 @@ export async function findRepoRoot(
// if `.git/config` exists (unlinked),
// then consider this the repo root
const gitConfigPath = join(current, GIT_PATH);
const gitConfigPath = join(current, GIT_CONFIG_PATH);
stat = await lstat(gitConfigPath).catch(err => {
if (err.code !== 'ENOENT') throw err;
});
if (stat) {
debug(`Found "${GIT_PATH}" - detected "${current}" as repo root`);
debug(`Found "${GIT_CONFIG_PATH}" - detected "${current}" as repo root`);
return current;
}
}

View File

@@ -1,52 +1,38 @@
import Table from 'cli-table3';
import chalk from 'chalk';
const defaultStyle = {
'padding-left': 0,
'padding-right': 2,
};
export const noBorderChars = {
top: '',
'top-mid': '',
'top-left': '',
'top-right': '',
bottom: '',
'bottom-mid': '',
'bottom-left': '',
'bottom-right': '',
left: '',
'left-mid': '',
mid: '',
'mid-mid': '',
right: '',
'right-mid': '',
middle: '',
};
const alignMap = {
l: 'left',
c: 'center',
r: 'right',
} as const;
const printLine = (data: string[], sizes: number[]) =>
data.reduce((line, col, i) => line + col.padEnd(sizes[i]), '');
/**
* Print a table.
*/
export default function table(
rows: string[][],
opts?: { hsep?: number; align?: ('l' | 'c' | 'r')[] }
fieldNames: string[] = [],
data: string[][] = [],
margins: number[] = [],
print: (str: string) => void
) {
const table = new Table({
style: {
...defaultStyle,
'padding-right': opts?.hsep ?? defaultStyle['padding-right'],
},
chars: noBorderChars,
});
table.push(
...rows.map(row =>
row.map((cell, i) => ({
content: cell,
hAlign: alignMap[opts?.align?.[i] ?? 'l'],
}))
// Compute size of each column
const sizes = data
.reduce(
(acc, row) =>
row.map((col, i) => {
const currentMaxColSize = acc[i] || 0;
const colSize = (col && col.length) || 0;
return Math.max(currentMaxColSize, colSize);
}),
fieldNames.map(col => col.length)
)
);
return table.toString();
// Add margin to all columns except the last
.map((size, i) => (i < margins.length && size + margins[i]) || size);
// Print header
print(chalk.grey(printLine(fieldNames, sizes)));
print('\n');
// Print content
for (const row of data) {
print(printLine(row, sizes));
print('\n');
}
}

View File

@@ -0,0 +1,3 @@
handler() {
echo "Hello, from Bash!"
}

View File

@@ -1,3 +0,0 @@
export default (req: Request) => {
return new Response('Hello, from Deno!');
}

View File

@@ -0,0 +1,6 @@
{
"private": true,
"engines": {
"node": "16.x"
}
}

View File

@@ -1,7 +1,7 @@
{
"functions": {
"api/user.ts": {
"runtime": "vercel-deno@3.1.0"
"api/user.sh": {
"runtime": "vercel-bash@3.0.8"
}
}
}

View File

@@ -1,4 +1,3 @@
import execa from 'execa';
import { isIP } from 'net';
const { exec, fixture, testFixture, testFixtureStdio } = require('./utils.js');
@@ -126,24 +125,13 @@ test(
})
);
test('[vercel dev] Use custom runtime from the "functions" property', async () => {
const origPATH = process.env.PATH;
try {
// "deno" needs to be installed for this test
await execa('curl -fsSL https://deno.land/install.sh | sh', {
stdio: 'inherit',
shell: true,
});
process.env.PATH = `${process.env.HOME}/.deno/bin:${origPATH}`;
const tester = testFixtureStdio('custom-runtime', async (testPath: any) => {
await testPath(200, `/api/user`, /Hello, from Deno!/m);
await testPath(200, `/api/user.ts`, /Hello, from Deno!/m);
});
await tester();
} finally {
process.env.PATH = origPATH;
}
});
test(
'[vercel dev] Use custom runtime from the "functions" property',
testFixtureStdio('custom-runtime', async (testPath: any) => {
await testPath(200, `/api/user`, /Hello, from Bash!/m);
await testPath(200, `/api/user.sh`, /Hello, from Bash!/m);
})
);
test(
'[vercel dev] Should work with nested `tsconfig.json` files',

View File

@@ -7,6 +7,7 @@ const { satisfies } = require('semver');
const stripAnsi = require('strip-ansi');
const {
fetchCachedToken,
disableSSO,
} = require('../../../../test/lib/deployment/now-deploy');
const { spawnSync, execFileSync } = require('child_process');
@@ -398,6 +399,9 @@ function testFixtureStdio(
// Expect the deploy succeeded with exit of 0;
expect(deployResult.exitCode).toBe(0);
deploymentUrl = new URL(deployResult.stdout).host;
// Disable the Project SSO Protection
await disableSSO(deployResult.stdout, true);
} finally {
if (!hasGitignore) {
await fs.remove(gitignore);

View File

@@ -1,4 +0,0 @@
{
"orgId": "team_dummy",
"projectId": "legacy-builds"
}

View File

@@ -1 +0,0 @@
module.exports = (req, res) => res.end('Vercel');

View File

@@ -1,8 +0,0 @@
{
"name": "node",
"version": "1.0.0",
"private": true,
"engines": {
"node": "18.x"
}
}

View File

@@ -1,5 +0,0 @@
{
"builds": [
{ "src": "index.js", "use": "@vercel/node" }
]
}

View File

@@ -405,9 +405,6 @@ module.exports = async function prepare(session, binaryPath, tmpFixturesDir) {
'project-sensitive-env-vars': {
'package.json': '{}',
},
'project-override-env-vars': {
'package.json': '{}',
},
'dev-proxy-headers-and-env': {
'package.json': JSON.stringify({}),
'server.js': `require('http').createServer((req, res) => {

View File

@@ -5,7 +5,10 @@ import fetch, { RequestInit } from 'node-fetch';
import retry from 'async-retry';
import fs from 'fs-extra';
import sleep from '../src/util/sleep';
import { fetchTokenWithRetry } from '../../../test/lib/deployment/now-deploy';
import {
disableSSO,
fetchTokenWithRetry,
} from '../../../test/lib/deployment/now-deploy';
import waitForPrompt from './helpers/wait-for-prompt';
import { listTmpDirs } from './helpers/get-tmp-dir';
import getGlobalDir from './helpers/get-global-dir';
@@ -402,6 +405,7 @@ test('default command should work with --cwd option', async () => {
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
const url = stdout;
await disableSSO(url, false);
const deploymentResult = await fetch(`${url}/README.md`);
const body = await deploymentResult.text();
@@ -431,6 +435,7 @@ test('should allow deploying a directory that was built with a target environmen
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
const url = stdout;
await disableSSO(url, false);
const deploymentResult = await fetch(`${url}/README.md`);
const body = await deploymentResult.text();
@@ -458,6 +463,7 @@ test('should allow deploying a directory that was prebuilt, but has no builds.js
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
const url = stdout;
await disableSSO(url, false);
const deploymentResult = await fetch(`${url}/README.md`);
const body = await deploymentResult.text();
@@ -521,6 +527,7 @@ test('deploy using only now.json with `redirects` defined', async () => {
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
const url = stdout;
await disableSSO(url, false);
const res = await fetch(`${url}/foo/bar`, { redirect: 'manual' });
const location = res.headers.get('location');
expect(location).toBe('https://example.com/foo/bar');
@@ -542,6 +549,7 @@ test('deploy using --local-config flag v2', async () => {
const { host } = new URL(stdout);
expect(host).toMatch(/secondary/gm);
await disableSSO(host, false);
const testRes = await fetch(`https://${host}/test-${contextName}.html`);
const testText = await testRes.text();
@@ -577,7 +585,7 @@ test('deploy fails using --local-config flag with non-existent path', async () =
expect(stderr).toMatch(/does-not-exist\.json/);
});
test('deploy from a nested directory', async () => {
test('deploy using --local-config flag above target', async () => {
const root = await setupE2EFixture('zero-config-next-js-nested');
const projectName = `project-link-dev-${
Math.random().toString(36).split('.')[1]
@@ -623,6 +631,7 @@ test('deploy using --local-config flag above target', async () => {
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
const { host } = new URL(stdout);
await disableSSO(host, false);
const testRes = await fetch(`https://${host}/index.html`);
const testText = await testRes.text();
@@ -844,6 +853,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async () => {
});
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
const { host } = new URL(stdout);
await disableSSO(host, false);
const apiUrl = `https://${host}/api/get-env`;
const apiRes = await fetch(apiUrl);

View File

@@ -11,7 +11,10 @@ import fs, {
mkdir,
} from 'fs-extra';
import sleep from '../src/util/sleep';
import { fetchTokenWithRetry } from '../../../test/lib/deployment/now-deploy';
import {
disableSSO,
fetchTokenWithRetry,
} from '../../../test/lib/deployment/now-deploy';
import waitForPrompt from './helpers/wait-for-prompt';
import { execCli } from './helpers/exec';
import getGlobalDir from './helpers/get-global-dir';
@@ -327,7 +330,8 @@ test('should show prompts to set up project during first deploy', async () => {
'README.txt'
).toBe(true);
const { href } = new URL(output.stdout);
const { host, href } = new URL(output.stdout);
await disableSSO(host, false);
// Send a test request to the deployment
const response = await fetch(href);
@@ -642,7 +646,8 @@ test('use `rootDirectory` from project when deploying', async () => {
const secondResult = await execCli(binaryPath, [directory, '--public']);
expect(secondResult.exitCode, formatOutput(secondResult)).toBe(0);
const { href } = new URL(secondResult.stdout);
const { host, href } = new URL(secondResult.stdout);
await disableSSO(host, false);
const pageResponse1 = await fetch(href);
expect(pageResponse1.status).toBe(200);
@@ -723,72 +728,6 @@ test('add a sensitive env var', async () => {
);
});
test('override an existing env var', async () => {
const dir = await setupE2EFixture('project-override-env-vars');
const projectName = `project-override-env-vars-${
Math.random().toString(36).split('.')[1]
}`;
// remove previously linked project if it exists
await remove(path.join(dir, '.vercel'));
const vc = execCli(binaryPath, ['link'], {
cwd: dir,
env: {
FORCE_TTY: '1',
},
});
await setupProject(vc, projectName, {
buildCommand: `mkdir -p o && echo '<h1>custom hello</h1>' > o/index.html`,
outputDirectory: 'o',
});
await vc;
const link = require(path.join(dir, '.vercel/project.json'));
const options = {
env: {
VERCEL_ORG_ID: link.orgId,
VERCEL_PROJECT_ID: link.projectId,
},
};
// 1. Initial add
const addEnvCommand = execCli(
binaryPath,
['env', 'add', 'envVarName', 'production'],
options
);
await waitForPrompt(addEnvCommand, /Whats the value of [^?]+\?/);
addEnvCommand.stdin?.write('test\n');
const output = await addEnvCommand;
expect(output.exitCode, formatOutput(output)).toBe(0);
expect(output.stderr).toContain(
'Added Environment Variable envVarName to Project'
);
// 2. Override
const overrideEnvCommand = execCli(
binaryPath,
['env', 'add', 'envVarName', 'production', '--force'],
options
);
await waitForPrompt(overrideEnvCommand, /Whats the value of [^?]+\?/);
overrideEnvCommand.stdin?.write('test\n');
const outputOverride = await overrideEnvCommand;
expect(outputOverride.exitCode, formatOutput(outputOverride)).toBe(0);
expect(outputOverride.stderr).toContain(
'Overrode Environment Variable envVarName to Project'
);
});
test('whoami with `VERCEL_ORG_ID` should favor `--scope` and should error', async () => {
if (!token) {
throw new Error('Shared state "token" not set.');
@@ -839,6 +778,7 @@ test('deploys with only now.json and README.md', async () => {
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
const { host } = new URL(stdout);
await disableSSO(host, false);
const res = await fetch(`https://${host}/README.md`);
const text = await res.text();
expect(text).toMatch(/readme contents/);
@@ -861,6 +801,7 @@ test('deploys with only vercel.json and README.md', async () => {
);
const { host } = new URL(stdout);
await disableSSO(host, false);
const res = await fetch(`https://${host}/README.md`);
const text = await res.text();
expect(text).toMatch(/readme contents/);
@@ -946,6 +887,7 @@ test('deploy pnpm twice using pnp and symlink=false', async () => {
'--public',
'--yes',
]);
await disableSSO(res.stdout, false);
return res;
}
@@ -1402,6 +1344,8 @@ test('vercel.json configuration overrides in a new project prompt user and merge
const deployment = await vc;
expect(deployment.exitCode, formatOutput(deployment)).toBe(0);
// assert the command were executed
await disableSSO(deployment.stdout, false);
let page = await fetch(deployment.stdout);
let text = await page.text();
expect(text).toBe('1\n');
@@ -1432,7 +1376,8 @@ test('vercel.json configuration overrides in an existing project do not prompt u
// auto-confirm this deployment
let deployment = await deploy(true);
const { href } = new URL(deployment.stdout);
const { host, href } = new URL(deployment.stdout);
await disableSSO(host, false);
let page = await fetch(href);
let text = await page.text();
expect(text).toBe('0');

View File

@@ -14,7 +14,10 @@ import { logo } from '../src/util/pkg-name';
import sleep from '../src/util/sleep';
import humanizePath from '../src/util/humanize-path';
import pkg from '../package.json';
import { fetchTokenWithRetry } from '../../../test/lib/deployment/now-deploy';
import {
disableSSO,
fetchTokenWithRetry,
} from '../../../test/lib/deployment/now-deploy';
import waitForPrompt from './helpers/wait-for-prompt';
import { getNewTmpDir, listTmpDirs } from './helpers/get-tmp-dir';
import getGlobalDir from './helpers/get-global-dir';
@@ -309,6 +312,7 @@ test('should add secret with hyphen prefix', async () => {
expect(targetCall.exitCode, formatOutput(targetCall)).toBe(0);
const { host } = new URL(targetCall.stdout);
await disableSSO(host, false);
const response = await fetch(`https://${host}`);
expect(response.status).toBe(200);
expect(await response.text()).toBe(`${value}\n`);
@@ -337,6 +341,7 @@ test('ignore files specified in .nowignore', async () => {
});
const { host } = new URL(targetCall.stdout);
await disableSSO(host, false);
const ignoredFile = await fetch(`https://${host}/ignored.txt`);
expect(ignoredFile.status).toBe(404);
@@ -353,6 +358,7 @@ test('ignore files specified in .nowignore via allowlist', async () => {
});
const { host } = new URL(targetCall.stdout);
await disableSSO(host, false);
const ignoredFile = await fetch(`https://${host}/ignored.txt`);
expect(ignoredFile.status).toBe(404);
@@ -369,7 +375,7 @@ test('list the scopes', async () => {
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
const include = new RegExp(`${contextName}\\s+${email}`);
expect(stderr).toMatch(include);
expect(stdout).toMatch(include);
});
test('domains inspect', async () => {
@@ -549,6 +555,7 @@ test('ensure we render a warning for deployments with no files', async () => {
// Ensure the exit code is right
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
await disableSSO(host, false);
// Send a test request to the deployment
const res = await fetch(href);
@@ -900,6 +907,7 @@ test('try to revert a deployment and assign the automatic aliases', async () =>
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
await disableSSO(deploymentUrl, false);
await waitForDeployment(deploymentUrl);
await sleep(20000);
@@ -914,6 +922,7 @@ test('try to revert a deployment and assign the automatic aliases', async () =>
'--yes',
]);
const deploymentUrl = stdout;
await disableSSO(deploymentUrl, false);
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
@@ -933,6 +942,7 @@ test('try to revert a deployment and assign the automatic aliases', async () =>
'--yes',
]);
const deploymentUrl = stdout;
await disableSSO(deploymentUrl, false);
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
@@ -1204,6 +1214,7 @@ test('deploy a Lambda with 128MB of memory', async () => {
expect(output.exitCode, formatOutput(output)).toBe(0);
const { host: url } = new URL(output.stdout);
await disableSSO(url, false);
const response = await fetch('https://' + url + '/api/memory');
expect(response.status).toBe(200);
@@ -1230,6 +1241,7 @@ test('deploy a Lambda with 3 seconds of maxDuration', async () => {
expect(output.exitCode, formatOutput(output)).toBe(0);
const url = new URL(output.stdout);
await disableSSO(url.host, false);
// Should time out
url.pathname = '/api/wait-for/5';
@@ -1268,6 +1280,7 @@ test('deploy a Lambda with a specific runtime', async () => {
expect(output.exitCode, formatOutput(output)).toBe(0);
const url = new URL(output.stdout);
await disableSSO(url.host, false);
const res = await fetch(`${url}/api/test`);
const text = await res.text();
expect(text).toBe('Hello from PHP');
@@ -1298,6 +1311,7 @@ test('use build-env', async () => {
// Test if the output is really a URL
const deploymentUrl = pickUrl(stdout);
const { href } = new URL(deploymentUrl);
await disableSSO(deploymentUrl, false);
await waitForDeployment(href);

View File

@@ -270,7 +270,7 @@ export function useProject(
});
}
);
client.scenario.get(`/v10/projects/${project.id}/env`, (req, res) => {
client.scenario.get(`/v8/projects/${project.id}/env`, (req, res) => {
const target: ProjectEnvTarget | undefined =
typeof req.query.target === 'string'
? parseEnvironment(req.query.target)
@@ -291,14 +291,14 @@ export function useProject(
res.json({ envs: targetEnvs });
});
client.scenario.post(`/v10/projects/${project.id}/env`, (req, res) => {
client.scenario.post(`/v8/projects/${project.id}/env`, (req, res) => {
const envObj = req.body;
envObj.id = envObj.key;
envs.push(envObj);
res.json({ envs });
});
client.scenario.delete(
`/v10/projects/${project.id}/env/:envId`,
`/v8/projects/${project.id}/env/:envId`,
(req, res) => {
const envId = req.params.envId;
for (const [i, env] of envs.entries()) {

View File

@@ -466,54 +466,6 @@ describe('deploy', () => {
});
});
it('should send `projectSettings.nodeVersion` based on `engines.node` package.json field with `builds` in `vercel.json`', async () => {
const user = useUser();
useTeams('team_dummy');
useProject({
...defaultProject,
name: 'legacy-builds',
id: 'QmbKpqpiUqbcke',
});
let body: any;
client.scenario.post(`/v13/deployments`, (req, res) => {
body = req.body;
res.json({
creator: {
uid: user.id,
username: user.username,
},
id: 'dpl_',
});
});
client.scenario.get(`/v13/deployments/dpl_`, (req, res) => {
res.json({
creator: {
uid: user.id,
username: user.username,
},
id: 'dpl_',
readyState: 'READY',
aliasAssigned: true,
alias: [],
});
});
const repoRoot = setupUnitFixture('commands/deploy/legacy-builds');
client.cwd = repoRoot;
client.setArgv('deploy');
const exitCode = await deploy(client);
expect(exitCode).toEqual(0);
expect(body).toMatchObject({
source: 'cli',
version: 2,
projectSettings: {
nodeVersion: '18.x',
sourceFilesOutsideRootDirectory: true,
},
});
});
it('should send latest supported node version when given a >low-node-version based on `engines.node` package.json field', async () => {
const user = useUser();
useTeams('team_dummy');

View File

@@ -115,9 +115,7 @@ describe('promote', () => {
`Fetching deployment "${previousDeployment.url}" in ${previousDeployment.creator?.username}`
);
await expect(client.stderr).toOutput(
'? This deployment is not a production deployment and cannot be directly \n' +
'promoted. A new deployment will be built using your production environment. Are \n' +
'you sure you want to continue? (y/N)'
'? This deployment does not target production, therefore promotion will not apply\n production environment variables. Are you sure you want to continue?'
);
// say "no" to the prompt
@@ -140,9 +138,7 @@ describe('promote', () => {
`Fetching deployment "${previousDeployment.url}" in ${previousDeployment.creator?.username}`
);
await expect(client.stderr).toOutput(
'? This deployment is not a production deployment and cannot be directly \n' +
'promoted. A new deployment will be built using your production environment. Are \n' +
'you sure you want to continue? (y/N)'
'? This deployment does not target production, therefore promotion will not apply\n production environment variables. Are you sure you want to continue?'
);
// say "yes" to the prompt

View File

@@ -11,7 +11,7 @@ describe('teams', () => {
const user = useUser();
useTeams(undefined, { apiVersion: 2 });
const exitCodePromise = teamsList(client);
await expect(client.stderr).toOutput(user.username);
await expect(client.stdout).toOutput(user.username);
await expect(exitCodePromise).resolves.toEqual(0);
});
});

View File

@@ -123,7 +123,7 @@ describe('importBuilders()', () => {
const cwd = await getWriteableDirectory();
try {
const spec = 'vercel-deno@2.0.1';
const tarballSpec = 'https://files-njlxk3l0r-curated-tests.vercel.app';
const tarballSpec = 'https://test2020-h5hdll5dz-tootallnate.vercel.app';
const specs = new Set([spec, tarballSpec]);
const builders = await importBuilders(specs, cwd, client.output);
expect(builders.size).toEqual(2);
@@ -142,7 +142,7 @@ describe('importBuilders()', () => {
'function'
);
await expect(client.stderr).toOutput(
'> Installing Builders: vercel-deno@2.0.1, https://files-njlxk3l0r-curated-tests.vercel.app'
'> Installing Builders: vercel-deno@2.0.1, https://test2020-h5hdll5dz-tootallnate.vercel.app'
);
} finally {
await remove(cwd);

View File

@@ -1,11 +1,5 @@
# @vercel/client
## 13.2.0
### Minor Changes
- Always use v13 of create deployment API endpoint ([#11351](https://github.com/vercel/vercel/pull/11351))
## 13.1.9
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "13.2.0",
"version": "13.1.9",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://vercel.com",

View File

@@ -31,7 +31,10 @@ export async function* checkDeploymentStatus(
let deploymentState = deployment;
const apiDeployments = getApiDeploymentsUrl();
const apiDeployments = getApiDeploymentsUrl({
builds: deployment.builds,
functions: deployment.functions,
});
// If the deployment is ready, we don't want any of this to run
if (isDone(deploymentState) && isAliasAssigned(deploymentState)) {

View File

@@ -121,9 +121,8 @@ export default function buildCreateDeployment() {
err.code === 'ENOENT' &&
err.path
) {
const errPath = relative(workPath, err.path);
err.message = `File does not exist: "${relative(workPath, errPath)}"`;
if (errPath.split(sep).includes('node_modules')) {
err.message = `File does not exist: "${err.path}"`;
if (err.path.split(sep).includes('node_modules')) {
err.message = `Please ensure project dependencies have been installed:\n${err.message}`;
}
}

View File

@@ -27,11 +27,7 @@ async function* postDeployment(
}> {
const debug = createDebug(clientOptions.debug);
const preparedFiles = prepareFiles(files, clientOptions);
const apiDeployments = getApiDeploymentsUrl();
if (deploymentOptions?.builds && !deploymentOptions.functions) {
clientOptions.skipAutoDetectionConfirmation = true;
}
const apiDeployments = getApiDeploymentsUrl(deploymentOptions);
debug('Sending deployment creation API request');
try {

View File

@@ -6,7 +6,7 @@ import { URL } from 'url';
import ignore from 'ignore';
import { pkgVersion } from '../pkg';
import { NowBuildError } from '@vercel/build-utils';
import { VercelClientOptions, VercelConfig } from '../types';
import { VercelClientOptions, DeploymentOptions, VercelConfig } from '../types';
import { Sema } from 'async-sema';
import { readFile } from 'fs-extra';
import readdir from './readdir-recursive';
@@ -46,7 +46,13 @@ const EVENTS_ARRAY = [
export type DeploymentEventType = typeof EVENTS_ARRAY[number];
export const EVENTS = new Set(EVENTS_ARRAY);
export function getApiDeploymentsUrl() {
export function getApiDeploymentsUrl(
metadata?: Pick<DeploymentOptions, 'builds' | 'functions'>
) {
if (metadata && metadata.builds && !metadata.functions) {
return '/v10/deployments';
}
return '/v13/deployments';
}
@@ -106,6 +112,7 @@ export async function buildFileTree(
fileList = await readdir(path, [ignores]);
if (prebuilt) {
console.log('buildFileTree:', { path, vercelOutputDir });
// Traverse over the `.vc-config.json` files and include
// the files referenced by the "filePathMap" properties
const refs = new Set<string>();

View File

@@ -4,6 +4,8 @@ import { generateNewToken } from './common';
import { fetch, getApiDeploymentsUrl } from '../src/utils';
import { Deployment } from './types';
import { createDeployment } from '../src/index';
// @ts-expect-error non-TS
import { disableSSO } from '../../../test/lib/deployment/now-deploy';
describe('create v2 deployment', () => {
let deployment: Deployment;
@@ -43,6 +45,7 @@ describe('create v2 deployment', () => {
if (event.type === 'ready') {
deployment = event.payload;
await disableSSO(deployment.id);
break;
}
}
@@ -65,6 +68,7 @@ describe('create v2 deployment', () => {
if (event.type === 'ready') {
deployment = event.payload;
await disableSSO(deployment.id);
break;
}
}
@@ -83,6 +87,7 @@ describe('create v2 deployment', () => {
)) {
if (event.type === 'ready') {
deployment = event.payload;
await disableSSO(deployment.id);
expect(deployment.readyState).toEqual('READY');
break;
}
@@ -109,6 +114,7 @@ describe('create v2 deployment', () => {
)) {
if (event.type === 'ready') {
deployment = event.payload;
await disableSSO(deployment.id);
break;
} else if (event.type === 'error') {
error = event.payload;
@@ -148,6 +154,7 @@ describe('create v2 deployment', () => {
)) {
if (event.type === 'ready') {
deployment = event.payload;
await disableSSO(deployment.id);
break;
} else if (event.type === 'error') {
error = event.payload;

View File

@@ -1,11 +1,5 @@
# @vercel/go
## 3.1.1
### Patch Changes
- Add support for `1.22` and update Go minor versions `1.19`, `1.20` and `1.21` ([#11156](https://github.com/vercel/vercel/pull/11156))
## 3.1.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/go",
"version": "3.1.1",
"version": "3.1.0",
"license": "Apache-2.0",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",

View File

@@ -1,11 +1,5 @@
# @vercel/next
## 4.2.0
### Minor Changes
- Add support for edge function environment variables ([#11390](https://github.com/vercel/vercel/pull/11390))
## 4.1.6
### Patch Changes

View File

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

View File

@@ -2753,10 +2753,7 @@ export type FunctionsConfigManifestV1 = {
>;
};
type MiddlewareManifest =
| MiddlewareManifestV1
| MiddlewareManifestV2
| MiddlewareManifestV3;
type MiddlewareManifest = MiddlewareManifestV1 | MiddlewareManifestV2;
interface MiddlewareManifestV1 {
version: 1;
@@ -2772,13 +2769,6 @@ interface MiddlewareManifestV2 {
functions?: { [page: string]: EdgeFunctionInfoV2 };
}
interface MiddlewareManifestV3 {
version: 3;
sortedMiddleware: string[];
middleware: { [page: string]: EdgeFunctionInfoV3 };
functions?: { [page: string]: EdgeFunctionInfoV3 };
}
type Regions = 'home' | 'global' | 'auto' | string[] | 'all' | 'default';
interface BaseEdgeFunctionInfo {
@@ -2798,11 +2788,6 @@ interface EdgeFunctionInfoV2 extends BaseEdgeFunctionInfo {
matchers: EdgeFunctionMatcher[];
}
interface EdgeFunctionInfoV3 extends BaseEdgeFunctionInfo {
matchers: EdgeFunctionMatcher[];
environments: Record<string, string>;
}
interface EdgeFunctionMatcher {
regexp: string;
has?: HasField;
@@ -3035,7 +3020,6 @@ export async function getMiddlewareBundle({
slug: 'nextjs',
version: nextVersion,
},
environment: edgeFunction.environments,
});
})(),
routeMatchers: getRouteMatchers(edgeFunction, routesManifest),
@@ -3176,7 +3160,7 @@ export async function getFunctionsConfigManifest(
export async function getMiddlewareManifest(
entryPath: string,
outputDirectory: string
): Promise<MiddlewareManifestV3 | undefined> {
): Promise<MiddlewareManifestV2 | undefined> {
const middlewareManifestPath = path.join(
entryPath,
outputDirectory,
@@ -3195,27 +3179,19 @@ export async function getMiddlewareManifest(
const manifest = (await fs.readJSON(
middlewareManifestPath
)) as MiddlewareManifest;
if (manifest.version === 1) {
return upgradeMiddlewareManifestV1(manifest);
}
if (manifest.version === 2) {
return upgradeMiddlewareManifestV2(manifest);
}
return manifest;
return manifest.version === 1
? upgradeMiddlewareManifest(manifest)
: manifest;
}
export function upgradeMiddlewareManifestV1(
export function upgradeMiddlewareManifest(
v1: MiddlewareManifestV1
): MiddlewareManifestV3 {
function updateInfo(v1Info: EdgeFunctionInfoV1): EdgeFunctionInfoV3 {
): MiddlewareManifestV2 {
function updateInfo(v1Info: EdgeFunctionInfoV1): EdgeFunctionInfoV2 {
const { regexp, ...rest } = v1Info;
return {
...rest,
matchers: [{ regexp }],
environments: {},
};
}
@@ -3230,35 +3206,7 @@ export function upgradeMiddlewareManifestV1(
return {
...v1,
version: 3,
middleware,
functions,
};
}
export function upgradeMiddlewareManifestV2(
v2: MiddlewareManifestV2
): MiddlewareManifestV3 {
function updateInfo(v2Info: EdgeFunctionInfoV2): EdgeFunctionInfoV3 {
const { ...rest } = v2Info;
return {
...rest,
environments: {},
};
}
const middleware = Object.fromEntries(
Object.entries(v2.middleware).map(([p, info]) => [p, updateInfo(info)])
);
const functions = v2.functions
? Object.fromEntries(
Object.entries(v2.functions).map(([p, info]) => [p, updateInfo(info)])
)
: undefined;
return {
...v2,
version: 3,
version: 2,
middleware,
functions,
};

View File

@@ -1,5 +0,0 @@
node_modules
/build
.env
.vercel

View File

@@ -1,38 +0,0 @@
# Remix
This directory is a brief example of a [Remix](https://remix.run/docs) site that can be deployed to Vercel with zero configuration.
To get started, run the Remix cli with this template
```sh
npx create-remix@latest --template vercel/vercel/examples/remix
```
## Deploy Your Own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/vercel/tree/main/examples/remix&template=remix)
_Live Example: https://remix-run-template.vercel.app_
You can also deploy using the [Vercel CLI](https://vercel.com/docs/cli):
```sh
npm i -g vercel
vercel
```
## Development
To run your Remix app locally, make sure your project's local dependencies are installed:
```sh
npm install
```
Afterwards, start the Remix development server like so:
```sh
npm run dev
```
Open up [http://localhost:5173](http://localhost:5173) and you should be ready to go!

View File

@@ -1,5 +0,0 @@
export default function handleRequest(
request: Request,
) {
return new Response("This is a custom entry.server response");
}

View File

@@ -1,31 +0,0 @@
import {
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
import { Analytics } from "@vercel/analytics/react";
export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
<Analytics />
</body>
</html>
);
}
export default function App() {
return <Outlet />;
}

View File

@@ -1,41 +0,0 @@
import type { MetaFunction } from "@vercel/remix";
export const meta: MetaFunction = () => {
return [
{ title: "New Remix App" },
{ name: "description", content: "Welcome to Remix!" },
];
};
export default function Index() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
<h1>Welcome to Remix</h1>
<ul>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/blog"
rel="noreferrer"
>
15m Quickstart Blog Tutorial
</a>
</li>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/jokes"
rel="noreferrer"
>
Deep Dive Jokes App Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/docs" rel="noreferrer">
Remix Docs
</a>
</li>
</ul>
</div>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +0,0 @@
{
"name": "my-remix-app",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"build": "remix vite:build",
"dev": "remix vite:dev",
"typecheck": "tsc"
},
"dependencies": {
"@remix-run/node": "^2.8.1",
"@remix-run/react": "^2.8.1",
"@remix-run/server-runtime": "^2.8.1",
"@vercel/analytics": "^1.2.2",
"@vercel/remix": "^2.8.1-patch.2",
"isbot": "^4",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@remix-run/dev": "^2.8.1",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"typescript": "^5.1.6",
"vite": "^5.1.0",
"vite-tsconfig-paths": "^4.2.1"
},
"engines": {
"node": ">=18.0.0"
}
}

View File

@@ -1,12 +0,0 @@
{
"probes": [
{
"path": "/",
"mustContain": "This is a custom entry.server response"
},
{
"path": "/does-not-exist",
"mustContain": "This is a custom entry.server response"
}
]
}

View File

@@ -1,25 +0,0 @@
{
"include": ["**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"types": ["@vercel/remix", "node", "vite/client"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"target": "ES2022",
"strict": true,
"allowJs": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
// Vite takes care of building everything, not tsc.
"noEmit": true
}
}

View File

@@ -1,11 +0,0 @@
import { vitePlugin as remix } from "@remix-run/dev";
import { installGlobals } from "@remix-run/node";
import { defineConfig } from "vite";
import { vercelPreset } from '@vercel/remix/vite';
import tsconfigPaths from "vite-tsconfig-paths";
installGlobals();
export default defineConfig({
plugins: [remix({ presets: [vercelPreset()] }), tsconfigPaths()],
});

304
pnpm-lock.yaml generated
View File

@@ -89,8 +89,8 @@ importers:
specifier: 29.1.0
version: 29.1.0(@babel/core@7.5.0)(esbuild@0.19.2)(jest@29.5.0)(typescript@4.9.5)
turbo:
specifier: 1.13.2
version: 1.13.2
specifier: 1.13.0
version: 1.13.0
typescript:
specifier: 4.9.5
version: 4.9.5
@@ -319,13 +319,13 @@ importers:
specifier: 1.1.0
version: 1.1.0
'@vercel/go':
specifier: 3.1.1
specifier: 3.1.0
version: link:../go
'@vercel/hydrogen':
specifier: 1.0.2
version: link:../hydrogen
'@vercel/next':
specifier: 4.2.0
specifier: 4.1.6
version: link:../next
'@vercel/node':
specifier: 3.0.26
@@ -356,20 +356,20 @@ importers:
specifier: 2.3.0
version: 2.3.0
'@inquirer/checkbox':
specifier: 2.2.2
version: 2.2.2
specifier: 2.2.0
version: 2.2.0
'@inquirer/confirm':
specifier: 3.1.2
version: 3.1.2
specifier: 3.1.0
version: 3.1.0
'@inquirer/expand':
specifier: 2.1.2
version: 2.1.2
specifier: 2.1.0
version: 2.1.0
'@inquirer/input':
specifier: 2.1.2
version: 2.1.2
specifier: 2.1.1
version: 2.1.1
'@inquirer/select':
specifier: 2.2.2
version: 2.2.2
specifier: 2.2.0
version: 2.2.0
'@next/env':
specifier: 11.1.2
version: 11.1.2
@@ -463,6 +463,9 @@ importers:
'@types/tar-fs':
specifier: 1.16.1
version: 1.16.1
'@types/text-table':
specifier: 0.2.0
version: 0.2.0
'@types/title':
specifier: 3.4.1
version: 3.4.1
@@ -491,7 +494,7 @@ importers:
specifier: 1.0.29
version: link:../../internals/types
'@vercel/client':
specifier: 13.2.0
specifier: 13.1.9
version: link:../client
'@vercel/error-utils':
specifier: 2.0.2
@@ -697,6 +700,9 @@ importers:
tar-fs:
specifier: 1.16.3
version: 1.16.3
text-table:
specifier: 0.2.0
version: 0.2.0
title:
specifier: 3.4.1
version: 3.4.1
@@ -1603,6 +1609,14 @@ packages:
resolution: {integrity: sha512-1eBykZCd0pPGl5qKtV6Z5ARA6yuhXzHsVN2h5GH5/H6svYa37Jr7vMio5OFpiw1LBHtscrZs7amSkZkcwm0cvQ==}
dev: true
/@ampproject/remapping@2.2.1:
resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
engines: {node: '>=6.0.0'}
dependencies:
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
dev: true
/@ampproject/remapping@2.3.0:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
@@ -1614,8 +1628,16 @@ packages:
/@babel/code-frame@7.18.6:
resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/highlight': 7.22.20
dev: true
/@babel/code-frame@7.22.13:
resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/highlight': 7.24.2
chalk: 2.4.2
dev: true
/@babel/code-frame@7.24.2:
@@ -1635,16 +1657,16 @@ packages:
resolution: {integrity: sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==}
engines: {node: '>=6.9.0'}
dependencies:
'@ampproject/remapping': 2.3.0
'@babel/code-frame': 7.24.2
'@babel/generator': 7.24.1
'@babel/helper-compilation-targets': 7.23.6
'@babel/helper-module-transforms': 7.23.3(@babel/core@7.21.8)
'@babel/helpers': 7.24.1
'@babel/parser': 7.24.1
'@babel/template': 7.24.0
'@babel/traverse': 7.24.1
'@babel/types': 7.24.0
'@ampproject/remapping': 2.2.1
'@babel/code-frame': 7.22.13
'@babel/generator': 7.23.0
'@babel/helper-compilation-targets': 7.21.5(@babel/core@7.21.8)
'@babel/helper-module-transforms': 7.21.5
'@babel/helpers': 7.21.5
'@babel/parser': 7.23.0
'@babel/template': 7.22.15
'@babel/traverse': 7.23.2
'@babel/types': 7.23.0
convert-source-map: 1.8.0
debug: 4.3.4
gensync: 1.0.0-beta.2
@@ -1722,6 +1744,16 @@ packages:
jsesc: 2.5.2
dev: true
/@babel/generator@7.23.0:
resolution: {integrity: sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.24.0
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
jsesc: 2.5.2
dev: true
/@babel/generator@7.24.1:
resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==}
engines: {node: '>=6.9.0'}
@@ -1739,6 +1771,20 @@ packages:
'@babel/types': 7.24.0
dev: true
/@babel/helper-compilation-targets@7.21.5(@babel/core@7.21.8):
resolution: {integrity: sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
dependencies:
'@babel/compat-data': 7.24.1
'@babel/core': 7.21.8
'@babel/helper-validator-option': 7.23.5
browserslist: 4.23.0
lru-cache: 5.1.1
semver: 6.3.1
dev: true
/@babel/helper-compilation-targets@7.23.6:
resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
engines: {node: '>=6.9.0'}
@@ -1827,18 +1873,20 @@ packages:
- supports-color
dev: true
/@babel/helper-module-transforms@7.23.3(@babel/core@7.21.8):
resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==}
/@babel/helper-module-transforms@7.21.5:
resolution: {integrity: sha512-bI2Z9zBGY2q5yMHoBvJ2a9iX3ZOAzJPm7Q8Yz6YeoUjU/Cvhmi2G4QyTNyPBqqXSgTjUxRg3L0xV45HvkNWWBw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
dependencies:
'@babel/core': 7.21.8
'@babel/helper-environment-visitor': 7.22.20
'@babel/helper-module-imports': 7.24.3
'@babel/helper-simple-access': 7.22.5
'@babel/helper-split-export-declaration': 7.22.6
'@babel/helper-validator-identifier': 7.22.20
'@babel/template': 7.24.0
'@babel/traverse': 7.24.1
'@babel/types': 7.24.0
transitivePeerDependencies:
- supports-color
dev: true
/@babel/helper-module-transforms@7.23.3(@babel/core@7.24.3):
@@ -1947,6 +1995,17 @@ packages:
- supports-color
dev: true
/@babel/helpers@7.21.5:
resolution: {integrity: sha512-BSY+JSlHxOmGsPTydUkPf1MdMQ3M81x5xGCOVgWM3G8XH77sJ292Y2oqcp0CbbgxhqBuI46iUz1tT7hqP7EfgA==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/template': 7.24.0
'@babel/traverse': 7.24.1
'@babel/types': 7.24.0
transitivePeerDependencies:
- supports-color
dev: true
/@babel/helpers@7.24.1:
resolution: {integrity: sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==}
engines: {node: '>=6.9.0'}
@@ -1958,6 +2017,15 @@ packages:
- supports-color
dev: true
/@babel/highlight@7.22.20:
resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-validator-identifier': 7.22.20
chalk: 2.4.2
js-tokens: 4.0.0
dev: true
/@babel/highlight@7.24.2:
resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==}
engines: {node: '>=6.9.0'}
@@ -1975,6 +2043,14 @@ packages:
'@babel/types': 7.24.0
dev: true
/@babel/parser@7.23.0:
resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==}
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': 7.24.0
dev: true
/@babel/parser@7.24.1:
resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==}
engines: {node: '>=6.0.0'}
@@ -2195,6 +2271,15 @@ packages:
'@babel/types': 7.24.0
dev: true
/@babel/template@7.22.15:
resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/code-frame': 7.24.2
'@babel/parser': 7.24.1
'@babel/types': 7.24.0
dev: true
/@babel/template@7.24.0:
resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
engines: {node: '>=6.9.0'}
@@ -2222,6 +2307,24 @@ packages:
- supports-color
dev: true
/@babel/traverse@7.23.2:
resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/code-frame': 7.24.2
'@babel/generator': 7.24.1
'@babel/helper-environment-visitor': 7.22.20
'@babel/helper-function-name': 7.23.0
'@babel/helper-hoist-variables': 7.22.5
'@babel/helper-split-export-declaration': 7.22.6
'@babel/parser': 7.24.1
'@babel/types': 7.24.0
debug: 4.3.4
globals: 11.12.0
transitivePeerDependencies:
- supports-color
dev: true
/@babel/traverse@7.24.1:
resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==}
engines: {node: '>=6.9.0'}
@@ -2249,6 +2352,15 @@ packages:
to-fast-properties: 2.0.0
dev: true
/@babel/types@7.23.0:
resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-string-parser': 7.24.1
'@babel/helper-validator-identifier': 7.22.20
to-fast-properties: 2.0.0
dev: true
/@babel/types@7.24.0:
resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==}
engines: {node: '>=6.9.0'}
@@ -3371,32 +3483,52 @@ packages:
/@iarna/toml@2.2.3:
resolution: {integrity: sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg==}
/@inquirer/checkbox@2.2.2:
resolution: {integrity: sha512-EyPKpHIJ4bOw7S+Gbbwdy1V/kR3L5I2lLa/b9L/lOQDhdbk7Q1d0ET2k2kU8DNPu7FgQ8xvdzEUf92tSomrpzQ==}
/@inquirer/checkbox@2.2.0:
resolution: {integrity: sha512-L+owhbEm98dnP15XtT/8D1+nNvQecf8HngVFYTJaDR0jlfIeOHFHRbjhLKoVYxks85yY8mLaYXVZQLU46KTkXg==}
engines: {node: '>=18'}
dependencies:
'@inquirer/core': 7.1.2
'@inquirer/core': 7.1.0
'@inquirer/type': 1.2.1
ansi-escapes: 4.3.2
chalk: 4.1.2
figures: 3.2.0
dev: true
/@inquirer/confirm@3.1.2:
resolution: {integrity: sha512-xQeRxRpVOQdBinIyOHX9+/nTrvt84NnaP8hym5ARdLr6a5T1ckowx70sEaItgULBHlxSIJL970BoRfFxlzO2IA==}
/@inquirer/confirm@3.1.0:
resolution: {integrity: sha512-nH5mxoTEoqk6WpoBz80GMpDSm9jH5V9AF8n+JZAZfMzd9gHeEG9w1o3KawPRR72lfzpP+QxBHLkOKLEApwhDiQ==}
engines: {node: '>=18'}
dependencies:
'@inquirer/core': 7.1.2
'@inquirer/core': 7.1.0
'@inquirer/type': 1.2.1
dev: true
/@inquirer/core@7.1.2:
resolution: {integrity: sha512-ne5VhDqruYYzx8mmjDZ9F58ymrLJGxmSHJUcJGiW3tifzvl3goAm6gNX11w6+zUnGE54vgQ6ALDXL3IOSezMRw==}
/@inquirer/core@7.1.0:
resolution: {integrity: sha512-FRCiDiU54XHt5B/D8hX4twwZuzSP244ANHbu3R7CAsJfiv1dUOz24ePBgCZjygEjDUi6BWIJuk4eWLKJ7LATUw==}
engines: {node: '>=18'}
dependencies:
'@inquirer/type': 1.2.1
'@types/mute-stream': 0.0.4
'@types/node': 20.12.4
'@types/node': 20.11.30
'@types/wrap-ansi': 3.0.0
ansi-escapes: 4.3.2
chalk: 4.1.2
cli-spinners: 2.9.2
cli-width: 4.1.0
figures: 3.2.0
mute-stream: 1.0.0
run-async: 3.0.0
signal-exit: 4.1.0
strip-ansi: 6.0.1
wrap-ansi: 6.2.0
dev: true
/@inquirer/core@7.1.1:
resolution: {integrity: sha512-rD1UI3eARN9qJBcLRXPOaZu++Bg+xsk0Tuz1EUOXEW+UbYif1sGjr0Tw7lKejHzKD9IbXE1CEtZ+xR/DrNlQGQ==}
engines: {node: '>=18'}
dependencies:
'@inquirer/type': 1.2.1
'@types/mute-stream': 0.0.4
'@types/node': 20.11.30
'@types/wrap-ansi': 3.0.0
ansi-escapes: 4.3.2
chalk: 4.1.2
@@ -3409,28 +3541,29 @@ packages:
wrap-ansi: 6.2.0
dev: true
/@inquirer/expand@2.1.2:
resolution: {integrity: sha512-QTcmxuKBXvsitEmHrz7Nrr30OPTYQWZf+hWrPUHoLSs1Qg1CLIUxFUfKDguiHZGubXmMydKB9m6TJZlAmU+WTA==}
/@inquirer/expand@2.1.0:
resolution: {integrity: sha512-jQgF7ImxxsX4MM8BUk33ffOvx3YOlaEqNCLTxBk7eZ5KOqOshmUq9FnOMnacUXpu7MJtkV/DJHubFiC/q4NF6g==}
engines: {node: '>=18'}
dependencies:
'@inquirer/core': 7.1.2
'@inquirer/core': 7.1.0
'@inquirer/type': 1.2.1
chalk: 4.1.2
figures: 3.2.0
dev: true
/@inquirer/input@2.1.2:
resolution: {integrity: sha512-Szr9POj/NxbKSmbOx81ZD76b6xmvXXUY56QLWBXRv8zIGTIKtj03V4zAsw3MTiL6Qoo+IaRLwTLr3bI+qIblzA==}
/@inquirer/input@2.1.1:
resolution: {integrity: sha512-Ag5PDh3/V3B68WGD/5LKXDqbdWKlF7zyfPAlstzu0NoZcZGBbZFjfgXlZIcb6Gs+AfdSi7wNf7soVAaMGH7moQ==}
engines: {node: '>=18'}
dependencies:
'@inquirer/core': 7.1.2
'@inquirer/core': 7.1.1
'@inquirer/type': 1.2.1
dev: true
/@inquirer/select@2.2.2:
resolution: {integrity: sha512-WaoleV3O/7iDAHFC0GArOkl7Yg/7wQ/UptxEkfM+bG67h65v0troAjkNASBbNiz9vvoNZxOGhVrug0LNDftCoQ==}
/@inquirer/select@2.2.0:
resolution: {integrity: sha512-Pml3DhVM1LnfqasUMIzaBtw+s5UjM5k0bzDeWrWOgqAMWe16AOg0DcAhXHf+SYbnj2CFBeP/TvkvedL4aAEWww==}
engines: {node: '>=18'}
dependencies:
'@inquirer/core': 7.1.2
'@inquirer/core': 7.1.0
'@inquirer/type': 1.2.1
ansi-escapes: 4.3.2
chalk: 4.1.2
@@ -5134,8 +5267,8 @@ packages:
/@types/node@16.18.11:
resolution: {integrity: sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==}
/@types/node@20.12.4:
resolution: {integrity: sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==}
/@types/node@20.11.30:
resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==}
dependencies:
undici-types: 5.26.5
dev: true
@@ -5265,6 +5398,10 @@ packages:
minipass: 4.2.8
dev: true
/@types/text-table@0.2.0:
resolution: {integrity: sha512-om4hNWnI01IKUFCjGQG33JqFcnmt0W5C3WX0G1FVBaucr7oRnL29aAz2hnxpbZnE2t9f8/BR5VOtgcOtsonpLA==}
dev: true
/@types/text-table@0.2.1:
resolution: {integrity: sha512-dchbFCWfVgUSWEvhOkXGS7zjm+K7jCUvGrQkAHPk2Fmslfofp4HQTH2pqnQ3Pw5GPYv0zWa2AQjKtsfZThuemQ==}
dev: true
@@ -6221,6 +6358,14 @@ packages:
acorn: 8.11.3
dev: true
/acorn-jsx@5.3.2(acorn@8.8.2):
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
acorn: 8.8.2
dev: true
/acorn-walk@8.2.0:
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
engines: {node: '>=0.4.0'}
@@ -6244,7 +6389,6 @@ packages:
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: false
/agent-base@4.3.0:
resolution: {integrity: sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==}
@@ -8517,6 +8661,11 @@ packages:
'@esbuild/win32-x64': 0.19.2
dev: true
/escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
dev: true
/escalade@3.1.2:
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'}
@@ -8962,8 +9111,8 @@ packages:
resolution: {integrity: sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
acorn: 8.11.3
acorn-jsx: 5.3.2(acorn@8.11.3)
acorn: 8.8.2
acorn-jsx: 5.3.2(acorn@8.8.2)
eslint-visitor-keys: 3.4.1
dev: true
@@ -11138,7 +11287,7 @@ packages:
resolution: {integrity: sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@babel/code-frame': 7.24.2
'@babel/code-frame': 7.22.13
'@jest/types': 29.5.0
'@types/stack-utils': 2.0.1
chalk: 4.1.0
@@ -14183,6 +14332,11 @@ packages:
fsevents: 2.3.3
dev: true
/run-async@3.0.0:
resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==}
engines: {node: '>=0.12.0'}
dev: true
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
@@ -15427,64 +15581,64 @@ packages:
safe-buffer: 5.2.1
dev: true
/turbo-darwin-64@1.13.2:
resolution: {integrity: sha512-CCSuD8CfmtncpohCuIgq7eAzUas0IwSbHfI8/Q3vKObTdXyN8vAo01gwqXjDGpzG9bTEVedD0GmLbD23dR0MLA==}
/turbo-darwin-64@1.13.0:
resolution: {integrity: sha512-ctHeJXtQgBcgxnCXwrJTGiq57HtwF7zWz5NTuSv//5yeU01BtQIt62ArKfjudOhRefWJbX3Z5srn88XTb9hfww==}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/turbo-darwin-arm64@1.13.2:
resolution: {integrity: sha512-0HySm06/D2N91rJJ89FbiI/AodmY8B3WDSFTVEpu2+8spUw7hOJ8okWOT0e5iGlyayUP9gr31eOeL3VFZkpfCw==}
/turbo-darwin-arm64@1.13.0:
resolution: {integrity: sha512-/Q9/pNFkF9w83tNxwMpgapwLYdQ12p8mpty2YQRoUiS9ClWkcqe136jR0mtuMqzlNlpREOFZaoyIthjt6Sdo0g==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/turbo-linux-64@1.13.2:
resolution: {integrity: sha512-7HnibgbqZrjn4lcfIouzlPu8ZHSBtURG4c7Bedu7WJUDeZo+RE1crlrQm8wuwO54S0siYqUqo7GNHxu4IXbioQ==}
/turbo-linux-64@1.13.0:
resolution: {integrity: sha512-hgbT7o020BGV4L7Sd8hhFTd5zVKPKxbsr0dPfel/9NkdTmptz2aGZ0Vb2MAa18SY3XaCQpDxmdYuOzvvRpo5ZA==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/turbo-linux-arm64@1.13.2:
resolution: {integrity: sha512-sUq4dbpk6SNKg/Hkwn256Vj2AEYSQdG96repio894h5/LEfauIK2QYiC/xxAeW3WBMc6BngmvNyURIg7ltrePg==}
/turbo-linux-arm64@1.13.0:
resolution: {integrity: sha512-WK01i2wDZARrV+HEs495A3hNeGMwQR5suYk7G+ceqqW7b+dOTlQdvUjnI3sg7wAnZPgjafFs/hoBaZdJjVa/nw==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/turbo-windows-64@1.13.2:
resolution: {integrity: sha512-DqzhcrciWq3dpzllJR2VVIyOhSlXYCo4mNEWl98DJ3FZ08PEzcI3ceudlH6F0t/nIcfSItK1bDP39cs7YoZHEA==}
/turbo-windows-64@1.13.0:
resolution: {integrity: sha512-hJgSZJZwlWHNwLEthaqJqJWGm4NqF5X/I7vE0sPE4i/jeDl8f0n1hcOkgJkJiNXVxhj+qy/9+4dzbPLKT9imaQ==}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/turbo-windows-arm64@1.13.2:
resolution: {integrity: sha512-WnPMrwfCXxK69CdDfS1/j2DlzcKxSmycgDAqV0XCYpK/812KB0KlvsVAt5PjEbZGXkY88pCJ1BLZHAjF5FcbqA==}
/turbo-windows-arm64@1.13.0:
resolution: {integrity: sha512-L/ErxYoXeq8tmjU/AIGicC9VyBN1zdYw8JlM4yPmMI0pJdY8E4GaYK1IiIazqq7M72lmQhU/WW7fV9FqEktwrw==}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/turbo@1.13.2:
resolution: {integrity: sha512-rX/d9f4MgRT3yK6cERPAkfavIxbpBZowDQpgvkYwGMGDQ0Nvw1nc0NVjruE76GrzXQqoxR1UpnmEP54vBARFHQ==}
/turbo@1.13.0:
resolution: {integrity: sha512-r02GtNmkOPcQvUzVE6lg474QVLyU02r3yh3lUGqrFHf5h5ZEjgDGWILsAUqplVqjri1Y/oOkTssks4CObTAaiw==}
hasBin: true
optionalDependencies:
turbo-darwin-64: 1.13.2
turbo-darwin-arm64: 1.13.2
turbo-linux-64: 1.13.2
turbo-linux-arm64: 1.13.2
turbo-windows-64: 1.13.2
turbo-windows-arm64: 1.13.2
turbo-darwin-64: 1.13.0
turbo-darwin-arm64: 1.13.0
turbo-linux-64: 1.13.0
turbo-linux-arm64: 1.13.0
turbo-windows-64: 1.13.0
turbo-windows-arm64: 1.13.0
dev: true
/tweetnacl@0.14.5:
@@ -16375,7 +16529,7 @@ packages:
engines: {node: '>=12'}
dependencies:
cliui: 8.0.1
escalade: 3.1.2
escalade: 3.1.1
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3

View File

@@ -104,9 +104,85 @@ async function nowDeploy(projectName, bodies, randomness, uploadNowJson, opts) {
await new Promise(r => setTimeout(r, 1000));
}
await disableSSO(deploymentId);
return { deploymentId, deploymentUrl };
}
async function disableSSO(deploymentId, useTeam = true) {
if (deploymentId.startsWith('https://')) {
deploymentId = new URL(deploymentId).hostname;
}
const deployRes = await fetchWithAuth(
`https://vercel.com/api/v13/deployments/${encodeURIComponent(
deploymentId
)}`,
{
method: 'GET',
}
);
const text = await deployRes.text();
if (!deployRes.ok) {
throw new Error(
`Failed to get deployment info (status: ${deployRes.status}, body: ${text})`
);
}
let info;
try {
info = JSON.parse(text);
} catch (err) {
throw new Error('Failed to parse deployment info JSON', { cause: err });
}
const { projectId, url: deploymentUrl } = info;
if (!deploymentUrl || typeof deploymentUrl !== 'string') {
throw new Error(
`Failed to get deployment URL (status: ${deployRes.status}, body: ${text})`
);
}
const settingRes = await fetchWithAuth(
`https://vercel.com/api/v5/projects/${encodeURIComponent(projectId)}`,
{
method: 'PATCH',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
ssoProtection: null,
}),
...(useTeam
? {}
: {
skipTeam: true,
}),
}
);
if (settingRes.ok) {
for (let i = 0; i < 10; i++) {
const res = await fetch(`https://${deploymentUrl}`);
if (res.status !== 401) {
break;
}
await new Promise(resolve => setTimeout(resolve, 5 * 1000));
}
console.log(
`Disabled deployment protection for deploymentId: ${deploymentId} projectId: ${projectId}`
);
} else {
console.error(settingRes.status, await settingRes.text(), text);
throw new Error(
`Failed to disable deployment protection projectId: ${projectId} deploymentId ${deploymentId}`
);
}
}
function digestOfFile(body) {
return createHash('sha1').update(body).digest('hex');
}
@@ -310,4 +386,5 @@ module.exports = {
fetchCachedToken,
fetchTokenWithRetry,
fileModeSymbol,
disableSSO,
};

View File

@@ -12,14 +12,6 @@
"outputMode": "new-only",
"outputs": ["dist/**"]
},
"vitest-unit": {
"dependsOn": ["build"],
"outputMode": "new-only"
},
"vitest-unit-run": {
"dependsOn": ["build"],
"outputMode": "new-only"
},
"test-unit": {
"dependsOn": ["build"],
"outputMode": "new-only"

58
utils/chunk-tests.js vendored
View File

@@ -3,58 +3,24 @@ const child_process = require('child_process');
const path = require('path');
const runnersMap = new Map([
[
'vitest-unit',
{
min: 1,
max: 1,
testScript: 'vitest-unit-run',
runners: ['ubuntu-latest', 'macos-latest', 'windows-latest'],
},
],
[
'test-unit',
{
min: 1,
max: 1,
testScript: 'test',
runners: ['ubuntu-latest', 'macos-latest', 'windows-latest'],
},
],
[
'test-e2e',
{ min: 1, max: 7, testScript: 'test', runners: ['ubuntu-latest'] },
],
['test-e2e', { min: 1, max: 7, runners: ['ubuntu-latest'] }],
[
'test-next-local',
{
min: 1,
max: 5,
runners: ['ubuntu-latest'],
testScript: 'test',
nodeVersion: '18',
},
{ min: 1, max: 5, runners: ['ubuntu-latest'], nodeVersion: '18' },
],
[
'test-next-local-legacy',
{
min: 1,
max: 5,
runners: ['ubuntu-latest'],
testScript: 'test',
nodeVersion: '16',
},
],
[
'test-dev',
{
min: 1,
max: 7,
testScript: 'test',
runners: ['ubuntu-latest', 'macos-latest'],
},
{ min: 1, max: 5, runners: ['ubuntu-latest'], nodeVersion: '16' },
],
['test-dev', { min: 1, max: 7, runners: ['ubuntu-latest', 'macos-latest'] }],
]);
const packageOptionsOverrides = {
@@ -70,12 +36,13 @@ function getRunnerOptions(scriptName, packageName) {
packageOptionsOverrides[packageName]
);
}
if (!runnerOptions) {
throw new Error(
`Unable to find runner options for package "${packageName}" and script ${scriptName}`
);
}
return runnerOptions;
return (
runnerOptions || {
min: 1,
max: 1,
runners: ['ubuntu-latest'],
}
);
}
async function getChunkedTests() {
@@ -131,7 +98,7 @@ async function getChunkedTests() {
const [packagePath, packageName] = packagePathAndName.split(',');
return Object.entries(scriptNames).flatMap(([scriptName, testPaths]) => {
const runnerOptions = getRunnerOptions(scriptName, packageName);
const { runners, min, max, testScript, nodeVersion } = runnerOptions;
const { runners, min, max, nodeVersion } = runnerOptions;
const sortedTestPaths = testPaths.sort((a, b) => a.localeCompare(b));
return intoChunks(min, max, sortedTestPaths).flatMap(
@@ -142,7 +109,6 @@ async function getChunkedTests() {
packagePath,
packageName,
scriptName,
testScript,
nodeVersion,
testPaths: chunk.map(testFile =>
path.relative(