Compare commits

..

2 Commits

Author SHA1 Message Date
Justin Ridgewell
56c732a7f4 Patch into undici to disable body decompression 2023-07-06 16:59:23 -04:00
Kiko Beats
59905cd787 WIP 2023-07-06 22:06:30 +02:00
54 changed files with 278 additions and 581 deletions

View File

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

View File

@@ -10,5 +10,5 @@
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
"ignore": ["@vercel-internals/*", "api", "examples"]
}

View File

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

View File

@@ -0,0 +1,5 @@
---
"@vercel/build-utils": patch
---
Revert "[build-utils] Allow file-ref sema to be controlled through env flag"

View File

@@ -0,0 +1,5 @@
---
'vercel': patch
---
Allow additional project settings in `createProject()`

View File

@@ -0,0 +1,5 @@
---
'vercel': patch
---
Added trailing new line at end of help output

View File

@@ -0,0 +1,6 @@
---
'@vercel-internals/constants': patch
'vercel': patch
---
Create new help output and arg parsing for deploy command

View File

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

View File

@@ -0,0 +1,5 @@
---
'@vercel/remix-builder': patch
---
Update `@remix-run/dev` fork to v1.18.1

View File

@@ -0,0 +1,5 @@
---
"vercel": patch
---
[cli] Remove `preinstall` script

View File

@@ -1,11 +1,5 @@
# @vercel-internals/constants
## 1.0.4
### Patch Changes
- Create new help output and arg parsing for deploy command ([#10090](https://github.com/vercel/vercel/pull/10090))
## 1.0.3
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "@vercel-internals/constants",
"version": "1.0.4",
"version": "1.0.3",
"types": "dist/index.d.ts",
"main": "dist/index.js",
"scripts": {

View File

@@ -1,13 +1,5 @@
# @vercel-internals/types
## 1.0.4
### Patch Changes
- Updated dependencies [[`7021279b2`](https://github.com/vercel/vercel/commit/7021279b284f314a4d1bdbb4306b4c22291efa08), [`718bbd365`](https://github.com/vercel/vercel/commit/718bbd365a50271a980bdca231ca801a0eead32b)]:
- @vercel/build-utils@6.8.1
- @vercel-internals/constants@1.0.4
## 1.0.3
### Patch Changes

View File

@@ -1,13 +1,13 @@
{
"private": true,
"name": "@vercel-internals/types",
"version": "1.0.4",
"version": "1.0.3",
"types": "index.d.ts",
"main": "index.d.ts",
"dependencies": {
"@types/node": "14.14.31",
"@vercel-internals/constants": "1.0.4",
"@vercel/build-utils": "6.8.1",
"@vercel-internals/constants": "1.0.3",
"@vercel/build-utils": "6.8.0",
"@vercel/routing-utils": "2.2.1"
},
"devDependencies": {

View File

@@ -1,11 +1,5 @@
# @vercel/build-utils
## 6.8.1
### Patch Changes
- Revert "[build-utils] Allow file-ref sema to be controlled through env flag" ([#10167](https://github.com/vercel/vercel/pull/10167))
## 6.8.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "6.8.1",
"version": "6.8.0",
"license": "Apache-2.0",
"main": "./dist/index.js",
"types": "./dist/index.d.js",

View File

@@ -1,28 +1,5 @@
# vercel
## 31.0.2
### Patch Changes
- Allow additional project settings in `createProject()` ([#10172](https://github.com/vercel/vercel/pull/10172))
- Run local Project detection during `vc link --repo`. ([#10094](https://github.com/vercel/vercel/pull/10094))
This allows for creation of new Projects that do not yet exist under the selected scope.
- Redeploy command no longer redeploys preview deployments to production ([#10186](https://github.com/vercel/vercel/pull/10186))
- Added trailing new line at end of help output ([#10170](https://github.com/vercel/vercel/pull/10170))
- Create new help output and arg parsing for deploy command ([#10090](https://github.com/vercel/vercel/pull/10090))
- [cli] Remove `preinstall` script ([#10157](https://github.com/vercel/vercel/pull/10157))
- Updated dependencies [[`7021279b2`](https://github.com/vercel/vercel/commit/7021279b284f314a4d1bdbb4306b4c22291efa08), [`5e5332fbc`](https://github.com/vercel/vercel/commit/5e5332fbc9317a8f3cc4ed0b72ec1a2c76020891), [`027bce00b`](https://github.com/vercel/vercel/commit/027bce00b3821d9b4a8f7ec320cd1c43ab9f4215)]:
- @vercel/build-utils@6.8.1
- @vercel/node@2.15.4
- @vercel/remix-builder@1.8.16
- @vercel/static-build@1.3.39
## 31.0.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "31.0.2",
"version": "31.0.1",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -31,16 +31,16 @@
"node": ">= 14"
},
"dependencies": {
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"@vercel/go": "2.5.1",
"@vercel/hydrogen": "0.0.64",
"@vercel/next": "3.8.8",
"@vercel/node": "2.15.4",
"@vercel/node": "2.15.3",
"@vercel/python": "3.1.60",
"@vercel/redwood": "1.1.15",
"@vercel/remix-builder": "1.8.16",
"@vercel/remix-builder": "1.8.15",
"@vercel/ruby": "1.3.76",
"@vercel/static-build": "1.3.39"
"@vercel/static-build": "1.3.38"
},
"devDependencies": {
"@alex_neo/jest-expect-message": "1.0.5",
@@ -84,10 +84,10 @@
"@types/which": "3.0.0",
"@types/write-json-file": "2.2.1",
"@types/yauzl-promise": "2.1.0",
"@vercel-internals/constants": "1.0.4",
"@vercel-internals/constants": "1.0.3",
"@vercel-internals/get-package-json": "1.0.0",
"@vercel-internals/types": "1.0.4",
"@vercel/client": "12.6.4",
"@vercel-internals/types": "1.0.3",
"@vercel/client": "12.6.3",
"@vercel/error-utils": "1.0.10",
"@vercel/frameworks": "1.4.3",
"@vercel/fs-detectors": "4.0.1",

View File

@@ -97,7 +97,7 @@ export default async function main(client: Client) {
client.output.warn(
`The ${cmd('--repo')} flag is in alpha, please report issues`
);
await ensureRepoLink(client, cwd, { yes, overwrite: true });
await ensureRepoLink(client, cwd, yes);
} else {
const link = await ensureLink('link', client, cwd, {
autoConfirm: yes,

View File

@@ -108,7 +108,7 @@ export default async (client: Client): Promise<number> => {
action: 'redeploy',
},
name: fromDeployment.name,
target: fromDeployment.target,
target: fromDeployment.target || 'production',
},
method: 'POST',
});

View File

@@ -1,5 +0,0 @@
import type { RepoInfo } from './connect-git-provider';
export function repoInfoToUrl(info: RepoInfo): string {
return `https://${info.provider}.com/${info.org}/${info.repo}`;
}

View File

@@ -1,9 +1,7 @@
import chalk from 'chalk';
import inquirer from 'inquirer';
import pluralize from 'pluralize';
import { homedir } from 'os';
import slugify from '@sindresorhus/slugify';
import { basename, join, normalize } from 'path';
import { join, normalize } from 'path';
import { normalizePath, traverseUpDirectories } from '@vercel/build-utils';
import { lstat, readJSON, outputJSON } from 'fs-extra';
import confirm from '../input/confirm';
@@ -16,10 +14,6 @@ import selectOrg from '../input/select-org';
import { addToGitIgnore } from './add-to-gitignore';
import type Client from '../client';
import type { Project } from '@vercel-internals/types';
import createProject from '../projects/create-project';
import { detectProjects } from '../projects/detect-projects';
import { repoInfoToUrl } from '../git/repo-info-to-url';
import { connectGitProvider, parseRepoUrl } from '../git/connect-git-provider';
const home = homedir();
@@ -41,11 +35,6 @@ export interface RepoLink {
repoConfig?: RepoProjectsConfig;
}
export interface EnsureRepoLinkOptions {
yes: boolean;
overwrite: boolean;
}
/**
* Given a directory path `cwd`, finds the root of the Git repository
* and returns the parsed `.vercel/repo.json` file if the repository
@@ -73,7 +62,7 @@ export async function getRepoLink(
export async function ensureRepoLink(
client: Client,
cwd: string,
{ yes, overwrite }: EnsureRepoLinkOptions
yes = false
): Promise<RepoLink | undefined> {
const { output } = client;
@@ -85,14 +74,7 @@ export async function ensureRepoLink(
}
let { rootPath, repoConfig, repoConfigPath } = repoLink;
if (overwrite || !repoConfig) {
// Detect the projects on the filesystem out of band, so that
// they will be ready by the time the projects are listed
const detectedProjectsPromise = detectProjects(rootPath).catch(err => {
output.debug(`Failed to detect local projects: ${err}`);
return new Map<string, string>();
});
if (!repoConfig) {
// Not yet linked, so prompt user to begin linking
let shouldLink =
yes ||
@@ -129,36 +111,41 @@ export async function ensureRepoLink(
remoteName = remoteNames[0];
} else {
// Prompt user to select which remote to use
const originIndex = remoteNames.indexOf('origin');
const answer = await client.prompt({
type: 'list',
name: 'value',
message: 'Which Git remote should be used?',
choices: remoteNames.sort().map(name => {
choices: remoteNames.map(name => {
return { name: name, value: name };
}),
default: remoteNames.includes('origin') ? 'origin' : undefined,
default: originIndex === -1 ? 0 : originIndex,
});
remoteName = answer.value;
}
const repoUrl = remoteUrls[remoteName];
const parsedRepoUrl = parseRepoUrl(repoUrl);
if (!parsedRepoUrl) {
throw new Error(`Failed to parse Git URL: ${repoUrl}`);
}
const repoUrlLink = output.link(repoUrl, repoInfoToUrl(parsedRepoUrl), {
fallback: () => link(repoUrl),
});
output.spinner(
`Fetching Projects for ${repoUrlLink} under ${chalk.bold(org.slug)}`
`Fetching Projects for ${link(repoUrl)} under ${chalk.bold(org.slug)}`
);
let projects: Project[] = [];
const query = new URLSearchParams({ repoUrl });
const projectsIterator = client.fetchPaginated<{
projects: Project[];
}>(`/v9/projects?${query}`);
const detectedProjects = await detectedProjectsPromise;
let printedFound = false;
for await (const chunk of projectsIterator) {
projects = projects.concat(chunk.projects);
if (!printedFound && projects.length > 0) {
output.log(
`${pluralize('Project', chunk.projects.length)} linked to ${link(
repoUrl
)} under ${chalk.bold(org.slug)}:`
);
printedFound = true;
}
for (const project of chunk.projects) {
output.print(` * ${chalk.cyan(`${org.slug}/${project.name}\n`)}`);
}
if (chunk.pagination.next) {
output.spinner(`Found ${chalk.bold(projects.length)} Projects…`, 0);
}
@@ -166,111 +153,36 @@ export async function ensureRepoLink(
if (projects.length === 0) {
output.log(
`No Projects are linked to ${repoUrlLink} under ${chalk.bold(
`No Projects are linked to ${link(repoUrl)} under ${chalk.bold(
org.slug
)}.`
);
} else {
output.log(
`Found ${pluralize(
'Project',
projects.length,
true
)} linked to ${repoUrlLink} under ${chalk.bold(org.slug)}`
);
// TODO: run detection logic to find potential projects.
// then prompt user to select valid projects.
// then create new Projects
}
// For any projects that already exists on Vercel, remove them from the
// locally detected directories. Any remaining ones will be prompted to
// create new Projects for.
for (const project of projects) {
detectedProjects.delete(project.rootDirectory ?? '');
}
if (detectedProjects.size > 0) {
output.log(
`Detected ${pluralize(
'new Project',
detectedProjects.size,
true
)} that may be created.`
);
}
const addSeparators = projects.length > 0 && detectedProjects.size > 0;
const { selected } = await client.prompt({
type: 'checkbox',
name: 'selected',
message: `Which Projects should be ${
projects.length ? 'linked to' : 'created'
}?`,
choices: [
...(addSeparators
? [new inquirer.Separator('----- Existing Projects -----')]
: []),
...projects.map(project => {
return {
name: `${org.slug}/${project.name}`,
value: project,
checked: true,
};
}),
...(addSeparators
? [new inquirer.Separator('----- New Projects to be created -----')]
: []),
...Array.from(detectedProjects.entries()).map(
([rootDirectory, framework]) => {
const name = slugify(
[basename(rootPath), basename(rootDirectory)]
.filter(Boolean)
.join('-')
);
return {
name: `${org.slug}/${name} (${framework})`,
value: {
newProject: true,
rootDirectory,
name,
framework,
},
};
}
),
],
});
if (selected.length === 0) {
output.print(`No Projects were selected. Repository not linked.\n`);
return;
}
for (let i = 0; i < selected.length; i++) {
const selection = selected[i];
if (!selection.newProject) continue;
const orgAndName = `${org.slug}/${selection.name}`;
output.spinner(`Creating new Project: ${orgAndName}`);
delete selection.newProject;
if (!selection.rootDirectory) delete selection.rootDirectory;
selected[i] = await createProject(client, selection);
await connectGitProvider(
shouldLink =
yes ||
(await confirm(
client,
org,
selected[i].id,
parsedRepoUrl.provider,
`${parsedRepoUrl.org}/${parsedRepoUrl.repo}`
);
output.log(
`Created new Project: ${output.link(
orgAndName,
`https://vercel.com/${orgAndName}`
)}`
);
`Link to ${
projects.length === 1
? 'this Project'
: `these ${chalk.bold(projects.length)} Projects`
}?`,
true
));
if (!shouldLink) {
output.print(`Canceled. Repository not linked.\n`);
return;
}
repoConfig = {
orgId: org.id,
remoteName,
projects: selected.map((project: Project) => {
projects: projects.map(project => {
return {
id: project.id,
name: project.name,
@@ -287,7 +199,7 @@ export async function ensureRepoLink(
output.print(
prependEmoji(
`Linked to ${repoUrlLink} under ${chalk.bold(
`Linked to ${link(repoUrl)} under ${chalk.bold(
org.slug
)} (created ${VERCEL_DIR}${
isGitIgnoreUpdated ? ' and added it to .gitignore' : ''

View File

@@ -1,38 +0,0 @@
import { join } from 'path';
import frameworks from '@vercel/frameworks';
import {
detectFramework,
getWorkspacePackagePaths,
getWorkspaces,
LocalFileSystemDetector,
} from '@vercel/fs-detectors';
export async function detectProjects(cwd: string) {
const fs = new LocalFileSystemDetector(cwd);
const workspaces = await getWorkspaces({ fs });
const detectedProjects = new Map<string, string>();
const packagePaths = (
await Promise.all(
workspaces.map(workspace =>
getWorkspacePackagePaths({
fs,
workspace,
})
)
)
).flat();
if (packagePaths.length === 0) {
packagePaths.push('/');
}
await Promise.all(
packagePaths.map(async p => {
const framework = await detectFramework({
fs: fs.chdir(join('.', p)),
frameworkList: frameworks,
});
if (!framework) return;
detectedProjects.set(p.slice(1), framework);
})
);
return detectedProjects;
}

View File

@@ -5,7 +5,6 @@ import { setupUnitFixture } from '../../helpers/setup-unit-fixture';
import { useDeployment } from '../../mocks/deployment';
import { useTeams } from '../../mocks/team';
import { useUser } from '../../mocks/user';
import { Deployment } from '@vercel-internals/types';
describe('redeploy', () => {
it('should error if missing deployment url', async () => {
@@ -78,20 +77,9 @@ describe('redeploy', () => {
await expect(exitCodePromise).resolves.toEqual(0);
});
it('should redeploy to preview', async () => {
const { fromDeployment } = initRedeployTest({ target: null });
client.setArgv('rollback', fromDeployment.id);
const exitCodePromise = redeploy(client);
await expect(client.stderr).toOutput(
`Fetching deployment "${fromDeployment.id}" in ${fromDeployment.creator?.username}`
);
await expect(client.stderr).toOutput('Preview');
await expect(exitCodePromise).resolves.toEqual(0);
});
});
function initRedeployTest({ target }: { target?: Deployment['target'] } = {}) {
function initRedeployTest() {
setupUnitFixture('commands/redeploy/simple-static');
const user = useUser();
useTeams('team_dummy');
@@ -100,8 +88,8 @@ function initRedeployTest({ target }: { target?: Deployment['target'] } = {}) {
id: 'vercel-redeploy',
name: 'vercel-redeploy',
});
const fromDeployment = useDeployment({ creator: user, target });
const toDeployment = useDeployment({ creator: user, target });
const fromDeployment = useDeployment({ creator: user });
const toDeployment = useDeployment({ creator: user });
client.scenario.post(`/v13/deployments`, (req, res) => {
res.json(toDeployment);

View File

@@ -1,34 +0,0 @@
import { repoInfoToUrl } from '../../../../src/util/git/repo-info-to-url';
import type { RepoInfo } from '../../../../src/util/git/connect-git-provider';
describe('repoInfoToUrl()', () => {
it('should support "github" URL', () => {
const info: RepoInfo = {
provider: 'github',
org: 'vercel',
repo: 'foo',
url: 'git@github.com:vercel/foo.git',
};
expect(repoInfoToUrl(info)).toEqual('https://github.com/vercel/foo');
});
it('should support "gitlab" URL', () => {
const info: RepoInfo = {
provider: 'gitlab',
org: 'vercel',
repo: 'foo',
url: 'git@gitlab.com:vercel/foo.git',
};
expect(repoInfoToUrl(info)).toEqual('https://gitlab.com/vercel/foo');
});
it('should support "bitbucket" URL', () => {
const info: RepoInfo = {
provider: 'bitbucket',
org: 'vercel',
repo: 'foo',
url: 'git@bitbucket.com:vercel/foo.git',
};
expect(repoInfoToUrl(info)).toEqual('https://bitbucket.com/vercel/foo');
});
});

View File

@@ -1,30 +0,0 @@
import { join } from 'path';
import { detectProjects } from '../../../../src/util/projects/detect-projects';
const REPO_ROOT = join(__dirname, '../../../../../..');
const EXAMPLES_DIR = join(REPO_ROOT, 'examples');
const FS_DETECTORS_FIXTURES = join(
REPO_ROOT,
'packages/fs-detectors/test/fixtures'
);
describe('detectProjects()', () => {
it('should match "nextjs" example', async () => {
const dir = join(EXAMPLES_DIR, 'nextjs');
const detected = await detectProjects(dir);
expect([...detected.entries()]).toEqual([['', 'nextjs']]);
});
it('should match "30-double-nested-workspaces"', async () => {
const dir = join(FS_DETECTORS_FIXTURES, '30-double-nested-workspaces');
const detected = await detectProjects(dir);
expect(
[...detected.entries()].sort((a, b) => a[0].localeCompare(b[0]))
).toEqual([
['packages/backend/c', 'remix'],
['packages/backend/d', 'nextjs'],
['packages/frontend/a', 'hexo'],
['packages/frontend/b', 'ember'],
]);
});
});

View File

@@ -1,12 +1,5 @@
# @vercel/client
## 12.6.4
### Patch Changes
- Updated dependencies [[`7021279b2`](https://github.com/vercel/vercel/commit/7021279b284f314a4d1bdbb4306b4c22291efa08)]:
- @vercel/build-utils@6.8.1
## 12.6.3
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "12.6.4",
"version": "12.6.3",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://vercel.com",
@@ -35,7 +35,7 @@
"typescript": "4.9.5"
},
"dependencies": {
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"@vercel/routing-utils": "2.2.1",
"@zeit/fetch": "5.2.0",
"async-retry": "1.2.3",

View File

@@ -36,7 +36,7 @@
"@types/minimatch": "3.0.5",
"@types/node": "14.18.33",
"@types/semver": "7.3.10",
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"typescript": "4.9.5"
}
}

View File

@@ -1,5 +1,4 @@
{
"private": true,
"name": "backend-c30",
"license": "MIT",
"version": "0.1.0"

View File

@@ -1,10 +1,8 @@
{
"private": true,
"name": "backend-d30",
"license": "MIT",
"version": "0.1.0",
"devDependencies": {
"next": "*",
"once": "1.4.0"
}
}

View File

@@ -1,5 +1,4 @@
{
"private": true,
"name": "frontend-a30",
"version": "1.0.0",
"description": "",
@@ -11,7 +10,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"debug": "^4.3.2",
"hexo": "*"
"debug": "^4.3.2"
}
}

View File

@@ -1,5 +1,4 @@
{
"private": true,
"name": "frontend-b30",
"version": "1.0.0",
"description": "",
@@ -11,7 +10,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"cowsay": "^1.5.0",
"ember-cli": "*"
"cowsay": "^1.5.0"
}
}

View File

@@ -1,13 +1,5 @@
# @vercel/gatsby-plugin-vercel-builder
## 1.3.12
### Patch Changes
- Updated dependencies [[`7021279b2`](https://github.com/vercel/vercel/commit/7021279b284f314a4d1bdbb4306b4c22291efa08), [`5e5332fbc`](https://github.com/vercel/vercel/commit/5e5332fbc9317a8f3cc4ed0b72ec1a2c76020891)]:
- @vercel/build-utils@6.8.1
- @vercel/node@2.15.4
## 1.3.11
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/gatsby-plugin-vercel-builder",
"version": "1.3.12",
"version": "1.3.11",
"main": "dist/index.js",
"files": [
"dist",
@@ -20,8 +20,8 @@
},
"dependencies": {
"@sinclair/typebox": "0.25.24",
"@vercel/build-utils": "6.8.1",
"@vercel/node": "2.15.4",
"@vercel/build-utils": "6.8.0",
"@vercel/node": "2.15.3",
"@vercel/routing-utils": "2.2.1",
"esbuild": "0.14.47",
"etag": "1.8.1",

View File

@@ -27,7 +27,7 @@
"@types/node-fetch": "^2.3.0",
"@types/tar": "^4.0.0",
"@types/yauzl-promise": "2.1.0",
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"@vercel/ncc": "0.24.0",
"async-retry": "1.3.1",
"execa": "^1.0.0",

View File

@@ -21,7 +21,7 @@
"devDependencies": {
"@types/jest": "27.5.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"@vercel/static-config": "2.0.17",
"execa": "3.2.0",
"fs-extra": "11.1.0",

View File

@@ -35,7 +35,7 @@
"@types/semver": "6.0.0",
"@types/text-table": "0.2.1",
"@types/webpack-sources": "3.2.0",
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"@vercel/nft": "0.22.5",
"@vercel/routing-utils": "2.2.1",
"async-sema": "3.0.1",

View File

@@ -1,14 +1,5 @@
# @vercel/node
## 2.15.4
### Patch Changes
- [node] fix decompress mismatching ([#10184](https://github.com/vercel/vercel/pull/10184))
- Updated dependencies [[`7021279b2`](https://github.com/vercel/vercel/commit/7021279b284f314a4d1bdbb4306b4c22291efa08)]:
- @vercel/build-utils@6.8.1
## 2.15.3
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node",
"version": "2.15.4",
"version": "2.15.3",
"license": "Apache-2.0",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -24,7 +24,7 @@
"@edge-runtime/vm": "3.0.1",
"@types/node": "14.18.33",
"@types/node-fetch": "2.6.3",
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"@vercel/error-utils": "1.0.10",
"@vercel/static-config": "2.0.17",
"async-listen": "3.0.0",
@@ -56,6 +56,7 @@
"execa": "3.2.0",
"fs-extra": "11.1.0",
"source-map-support": "0.5.12",
"test-listen": "1.1.0"
"test-listen": "1.1.0",
"undici": "5.22.1"
}
}

View File

@@ -6,6 +6,7 @@ if (!entrypoint) {
}
import { join } from 'path';
// FIXME: use import type { Headers } from '@edge-runtime/primitives';
import type { Headers } from 'node-fetch';
import type { VercelProxyResponse } from './types.js';
import { Config } from '@vercel/build-utils';

View File

@@ -1,16 +1,18 @@
import { addHelpers } from './helpers.js';
import { createServer } from 'http';
import { serializeBody } from '../utils.js';
import { streamToBuffer } from '@vercel/build-utils';
import EdgePrimitives from '@edge-runtime/primitives';
import exitHook from 'exit-hook';
import fetch from 'node-fetch';
import { listen } from 'async-listen';
import { isAbsolute } from 'path';
import { pathToFileURL } from 'url';
import zlib from 'zlib';
import type { ServerResponse, IncomingMessage } from 'http';
import type { VercelProxyResponse } from '../types.js';
import type { VercelRequest, VercelResponse } from './helpers.js';
import { Agent } from 'undici';
import type { Dispatcher } from 'undici';
const { fetch, Headers } = EdgePrimitives;
type ServerlessServerOptions = {
shouldAddHelpers: boolean;
@@ -35,27 +37,6 @@ const HTTP_METHODS = [
'PATCH',
];
function compress(body: Buffer, encoding: string): Buffer {
switch (encoding) {
case 'br':
return zlib.brotliCompressSync(body, {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 0,
},
});
case 'gzip':
return zlib.gzipSync(body, {
level: zlib.constants.Z_BEST_SPEED,
});
case 'deflate':
return zlib.deflateSync(body, {
level: zlib.constants.Z_BEST_SPEED,
});
default:
throw new Error(`encoding '${encoding}' not supported`);
}
}
async function createServerlessServer(userCode: ServerlessFunctionSignature) {
const server = createServer(userCode);
exitHook(() => server.close());
@@ -94,50 +75,100 @@ async function compileUserCode(
};
}
const kEncoding = Symbol('encoding');
class CompressionAgent extends Agent {
[kEncoding]: string | undefined = undefined;
dispatch(opts: Agent.DispatchOptions, handlers: Dispatcher.DispatchHandlers) {
const { onHeaders } = handlers;
const agent = this;
if (onHeaders) {
handlers = {
...handlers,
onHeaders(statusCode, headers, ...rest) {
let outHeaders = headers;
if (statusCode >= 200 && headers) {
outHeaders = [];
for (let n = 0; n < headers.length; n += 2) {
const key = headers[n + 0].toString('latin1');
if (key.toLowerCase() === 'content-encoding') {
agent[kEncoding] = headers[n + 1].toString('latin1');
} else {
outHeaders.push(headers[n + 0] as any);
outHeaders.push(headers[n + 1] as any);
}
}
}
// `this` is not our `Agent`, it's the `DispatchHandlers`!
return onHeaders.call(this, statusCode, outHeaders, ...rest);
},
};
}
return super.dispatch(opts, handlers);
}
}
export async function createServerlessEventHandler(
entrypointPath: string,
options: ServerlessServerOptions
): Promise<(request: IncomingMessage) => Promise<VercelProxyResponse>> {
const userCode = await compileUserCode(entrypointPath, options);
const server = await createServerlessServer(userCode);
const isStreaming = options.mode === 'streaming';
return async function (request: IncomingMessage) {
const url = new URL(request.url ?? '/', server.url);
// @ts-expect-error
const response = await fetch(url, {
const headers = {
...request.headers,
host: request.headers['x-forwarded-host'],
} as any;
const dispatcher = new CompressionAgent();
const webResponse = await fetch(url, {
body: await serializeBody(request),
compress: isStreaming,
headers: {
...request.headers,
host: request.headers['x-forwarded-host'],
},
headers,
method: request.method,
redirect: 'manual',
// @ts-expect-error dispatcher is part of undici, not the fetch spec.
dispatcher,
});
let body;
if (isStreaming) {
body = response.body;
} else {
body = await streamToBuffer(response.body);
const resHeaders = new Headers(webResponse.headers);
if (dispatcher[kEncoding] !== undefined) {
resHeaders.append('content-encoding', dispatcher[kEncoding]);
}
const contentEncoding = response.headers.get('content-encoding');
if (contentEncoding) {
body = compress(body, contentEncoding);
response.headers.set('content-length', Buffer.byteLength(body));
}
let body;
if (options.mode === 'streaming') {
body = webResponse.body as any;
} else {
// FIXME: at this point body is decompressed
// but we are returning `content-encoding`, causing a mismatching
// we should to compress it again. Better solution is to pass a custom undici agent.
body = Buffer.from(await webResponse.arrayBuffer());
/**
* `transfer-encoding` is related to streaming chunks.
* Since we are buffering the response.body, it should be stripped.
*/
response.headers.delete('transfer-encoding');
resHeaders.delete('transfer-encoding');
/**
* Since the entity-length and the transfer-length is different,
* the content-length should be stripped.
*/
if (resHeaders.has('content-encoding')) {
resHeaders.delete('content-length');
}
}
return {
status: response.status,
headers: response.headers,
status: webResponse.status,
headers: resHeaders,
body,
encoding: 'utf8',
};

View File

@@ -1,5 +1,4 @@
import { ServerResponse, IncomingMessage } from 'http';
import type { Headers } from 'node-fetch';
export type VercelRequestCookies = { [key: string]: string };
export type VercelRequestQuery = { [key: string]: string | string[] };

View File

@@ -1,10 +0,0 @@
const baseUrl = ({ headers }) =>
`${headers.get('x-forwarded-proto')}://${headers.get('x-forwarded-host')}`;
export function GET(request) {
const { searchParams } = new URL(request.url, baseUrl(request));
const url = searchParams.get('url');
const encoding = searchParams.get('encoding');
const serverUrl = `${url}?encoding=${encoding}`;
return fetch(serverUrl);
}

View File

@@ -1,9 +1,6 @@
import { forkDevServer, readMessage } from '../../src/fork-dev-server';
import { resolve, extname } from 'path';
import fetch from 'node-fetch';
import { createServer } from 'http';
import { listen } from 'async-listen';
import zlib from 'zlib';
jest.setTimeout(20 * 1000);
@@ -32,7 +29,7 @@ function testForkDevServer(entrypoint: string) {
(NODE_MAJOR < 18 ? test.skip : test)(
'runs an serverless function that exports GET',
async () => {
const child = testForkDevServer('./serverless-response.js');
const child = testForkDevServer('./serverless-web.js');
try {
const result = await readMessage(child);
if (result.state !== 'message') {
@@ -43,7 +40,7 @@ function testForkDevServer(entrypoint: string) {
{
const response = await fetch(
`http://${address}:${port}/api/serverless-response?name=Vercel`
`http://${address}:${port}/api/serverless-web?name=Vercel`
);
expect({
status: response.status,
@@ -53,7 +50,7 @@ function testForkDevServer(entrypoint: string) {
{
const response = await fetch(
`http://${address}:${port}/api/serverless-response?name=Vercel`,
`http://${address}:${port}/api/serverless-web?name=Vercel`,
{ method: 'HEAD' }
);
expect({ status: response.status }).toEqual({ status: 405 });
@@ -64,90 +61,6 @@ function testForkDevServer(entrypoint: string) {
}
);
(NODE_MAJOR < 18 ? test.skip : test)(
'buffer fetch response correctly',
async () => {
const child = testForkDevServer('./serverless-fetch.js');
const server = createServer((req, res) => {
res.setHeader('Content-Encoding', 'br');
const searchParams = new URLSearchParams(req.url!.substring(1));
const encoding = searchParams.get('encoding') ?? 'identity';
res.writeHead(200, {
'content-type': 'text/plain',
'content-encoding': encoding,
});
let payload = Buffer.from('Greetings, Vercel');
if (encoding === 'br') {
payload = zlib.brotliCompressSync(payload, {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 0,
},
});
} else if (encoding === 'gzip') {
payload = zlib.gzipSync(payload, {
level: zlib.constants.Z_BEST_SPEED,
});
} else if (encoding === 'deflate') {
payload = zlib.deflateSync(payload, {
level: zlib.constants.Z_BEST_SPEED,
});
}
res.end(payload);
});
const serverUrl = (await listen(server)).toString();
try {
const result = await readMessage(child);
if (result.state !== 'message') {
throw new Error('Exited. error: ' + JSON.stringify(result.value));
}
const { address, port } = result.value;
{
const response = await fetch(
`http://${address}:${port}/api/serverless-fetch?url=${serverUrl}&encoding=br`
);
expect(response.headers.get('content-encoding')).toBe('br');
expect(response.headers.get('content-length')).toBe('21');
expect({
status: response.status,
body: await response.text(),
}).toEqual({ status: 200, body: 'Greetings, Vercel' });
}
{
const response = await fetch(
`http://${address}:${port}/api/serverless-fetch?url=${serverUrl}&encoding=gzip`
);
expect(response.headers.get('content-encoding')).toBe('gzip');
expect(response.headers.get('content-length')).toBe('37');
expect({
status: response.status,
body: await response.text(),
}).toEqual({ status: 200, body: 'Greetings, Vercel' });
}
{
const response = await fetch(
`http://${address}:${port}/api/serverless-fetch?url=${serverUrl}&encoding=deflate`
);
expect(response.headers.get('content-encoding')).toBe('deflate');
expect(response.headers.get('content-length')).toBe('25');
expect({
status: response.status,
body: await response.text(),
}).toEqual({ status: 200, body: 'Greetings, Vercel' });
}
} finally {
server.close();
child.kill(9);
}
}
);
test('runs an edge function that uses `WebSocket`', async () => {
const child = testForkDevServer('./edge-websocket.js');
try {

View File

@@ -23,7 +23,7 @@
"@types/execa": "^0.9.0",
"@types/jest": "27.4.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"@vercel/ncc": "0.24.0",
"execa": "^1.0.0"
}

View File

@@ -27,7 +27,7 @@
"@types/aws-lambda": "8.10.19",
"@types/node": "14.18.33",
"@types/semver": "6.0.0",
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"execa": "3.2.0",
"fs-extra": "11.1.0"
}

View File

@@ -1,14 +1,5 @@
# @vercel/remix-builder
## 1.8.16
### Patch Changes
- Update `@remix-run/dev` fork to v1.18.1 ([#10180](https://github.com/vercel/vercel/pull/10180))
- Updated dependencies [[`7021279b2`](https://github.com/vercel/vercel/commit/7021279b284f314a4d1bdbb4306b4c22291efa08)]:
- @vercel/build-utils@6.8.1
## 1.8.15
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/remix-builder",
"version": "1.8.16",
"version": "1.8.15",
"license": "Apache-2.0",
"main": "./dist/index.js",
"homepage": "https://vercel.com/docs",
@@ -21,7 +21,7 @@
],
"dependencies": {
"@remix-run/dev": "npm:@vercel/remix-run-dev@1.18.1",
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"@vercel/nft": "0.22.5",
"@vercel/static-config": "2.0.17",
"path-to-regexp": "6.2.1",

View File

@@ -22,7 +22,7 @@
"devDependencies": {
"@types/fs-extra": "8.0.0",
"@types/semver": "6.0.0",
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"@vercel/ncc": "0.24.0",
"execa": "2.0.4",
"fs-extra": "^7.0.1",

View File

@@ -1,12 +1,5 @@
# @vercel/static-build
## 1.3.39
### Patch Changes
- Updated dependencies []:
- @vercel/gatsby-plugin-vercel-builder@1.3.12
## 1.3.38
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/static-build",
"version": "1.3.39",
"version": "1.3.38",
"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.12"
"@vercel/gatsby-plugin-vercel-builder": "1.3.11"
},
"devDependencies": {
"@types/aws-lambda": "8.10.64",
@@ -32,7 +32,7 @@
"@types/node-fetch": "2.5.4",
"@types/promise-timeout": "1.3.0",
"@types/semver": "7.3.13",
"@vercel/build-utils": "6.8.1",
"@vercel/build-utils": "6.8.0",
"@vercel/error-utils": "1.0.10",
"@vercel/frameworks": "1.4.3",
"@vercel/fs-detectors": "4.0.1",

138
pnpm-lock.yaml generated
View File

@@ -84,7 +84,7 @@ importers:
version: 2.0.2
ts-jest:
specifier: 29.1.0
version: 29.1.0(@babel/core@7.5.0)(jest@29.5.0)(typescript@4.9.5)
version: 29.1.0(@babel/core@7.21.8)(jest@29.5.0)(typescript@4.9.5)
turbo:
specifier: 1.10.7
version: 1.10.7
@@ -180,10 +180,10 @@ importers:
specifier: 14.14.31
version: 14.14.31
'@vercel-internals/constants':
specifier: 1.0.4
specifier: 1.0.3
version: link:../constants
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../../packages/build-utils
'@vercel/routing-utils':
specifier: 2.2.1
@@ -307,7 +307,7 @@ importers:
packages/cli:
dependencies:
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/go':
specifier: 2.5.1
@@ -319,7 +319,7 @@ importers:
specifier: 3.8.8
version: link:../next
'@vercel/node':
specifier: 2.15.4
specifier: 2.15.3
version: link:../node
'@vercel/python':
specifier: 3.1.60
@@ -328,13 +328,13 @@ importers:
specifier: 1.1.15
version: link:../redwood
'@vercel/remix-builder':
specifier: 1.8.16
specifier: 1.8.15
version: link:../remix
'@vercel/ruby':
specifier: 1.3.76
version: link:../ruby
'@vercel/static-build':
specifier: 1.3.39
specifier: 1.3.38
version: link:../static-build
devDependencies:
'@alex_neo/jest-expect-message':
@@ -461,16 +461,16 @@ importers:
specifier: 2.1.0
version: 2.1.0
'@vercel-internals/constants':
specifier: 1.0.4
specifier: 1.0.3
version: link:../../internals/constants
'@vercel-internals/get-package-json':
specifier: 1.0.0
version: link:../../internals/get-package-json
'@vercel-internals/types':
specifier: 1.0.4
specifier: 1.0.3
version: link:../../internals/types
'@vercel/client':
specifier: 12.6.4
specifier: 12.6.3
version: link:../client
'@vercel/error-utils':
specifier: 1.0.10
@@ -728,7 +728,7 @@ importers:
packages/client:
dependencies:
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/routing-utils':
specifier: 2.2.1
@@ -917,7 +917,7 @@ importers:
specifier: 7.3.10
version: 7.3.10
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
typescript:
specifier: 4.9.5
@@ -945,10 +945,10 @@ importers:
specifier: 0.25.24
version: 0.25.24
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/node':
specifier: 2.15.4
specifier: 2.15.3
version: link:../node
'@vercel/routing-utils':
specifier: 2.2.1
@@ -1009,7 +1009,7 @@ importers:
specifier: 2.1.0
version: 2.1.0
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/ncc':
specifier: 0.24.0
@@ -1051,7 +1051,7 @@ importers:
specifier: 14.18.33
version: 14.18.33
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/static-config':
specifier: 2.0.17
@@ -1108,7 +1108,7 @@ importers:
specifier: 3.2.0
version: 3.2.0
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/nft':
specifier: 0.22.5
@@ -1198,7 +1198,7 @@ importers:
specifier: 2.6.3
version: 2.6.3
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/error-utils':
specifier: 1.0.10
@@ -1291,6 +1291,9 @@ importers:
test-listen:
specifier: 1.1.0
version: 1.1.0
undici:
specifier: 5.22.1
version: 5.22.1
packages/python:
devDependencies:
@@ -1304,7 +1307,7 @@ importers:
specifier: 14.18.33
version: 14.18.33
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/ncc':
specifier: 0.24.0
@@ -1335,7 +1338,7 @@ importers:
specifier: 6.0.0
version: 6.0.0
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
execa:
specifier: 3.2.0
@@ -1350,7 +1353,7 @@ importers:
specifier: npm:@vercel/remix-run-dev@1.18.1
version: /@vercel/remix-run-dev@1.18.1(@types/node@14.18.33)
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/nft':
specifier: 0.22.5
@@ -1407,7 +1410,7 @@ importers:
specifier: 6.0.0
version: 6.0.0
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/ncc':
specifier: 0.24.0
@@ -1428,7 +1431,7 @@ importers:
specifier: 1.0.10
version: link:../gatsby-plugin-vercel-analytics
'@vercel/gatsby-plugin-vercel-builder':
specifier: 1.3.12
specifier: 1.3.11
version: link:../gatsby-plugin-vercel-builder
devDependencies:
'@types/aws-lambda':
@@ -1459,7 +1462,7 @@ importers:
specifier: 7.3.13
version: 7.3.13
'@vercel/build-utils':
specifier: 6.8.1
specifier: 6.8.0
version: link:../build-utils
'@vercel/error-utils':
specifier: 1.0.10
@@ -6985,6 +6988,13 @@ packages:
load-tsconfig: 0.2.3
dev: true
/busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
dependencies:
streamsearch: 1.1.0
dev: true
/bytes@3.0.0:
resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
engines: {node: '>= 0.8'}
@@ -15388,6 +15398,11 @@ packages:
mixme: 0.5.9
dev: true
/streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
dev: true
/string-argv@0.3.1:
resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==}
engines: {node: '>=0.6.19'}
@@ -15955,6 +15970,40 @@ packages:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
dev: true
/ts-jest@29.1.0(@babel/core@7.21.8)(jest@29.5.0)(typescript@4.9.5):
resolution: {integrity: sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
hasBin: true
peerDependencies:
'@babel/core': '>=7.0.0-beta.0 <8'
'@jest/types': ^29.0.0
babel-jest: ^29.0.0
esbuild: '*'
jest: ^29.0.0
typescript: '>=4.3 <6'
peerDependenciesMeta:
'@babel/core':
optional: true
'@jest/types':
optional: true
babel-jest:
optional: true
esbuild:
optional: true
dependencies:
'@babel/core': 7.21.8
bs-logger: 0.2.6
fast-json-stable-stringify: 2.1.0
jest: 29.5.0(@types/node@14.18.33)
jest-util: 29.3.1
json5: 2.2.3
lodash.memoize: 4.1.2
make-error: 1.3.6
semver: 7.3.8
typescript: 4.9.5
yargs-parser: 21.1.1
dev: true
/ts-jest@29.1.0(@babel/core@7.5.0)(jest@29.5.0)(typescript@4.9.4):
resolution: {integrity: sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -15989,40 +16038,6 @@ packages:
yargs-parser: 21.1.1
dev: true
/ts-jest@29.1.0(@babel/core@7.5.0)(jest@29.5.0)(typescript@4.9.5):
resolution: {integrity: sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
hasBin: true
peerDependencies:
'@babel/core': '>=7.0.0-beta.0 <8'
'@jest/types': ^29.0.0
babel-jest: ^29.0.0
esbuild: '*'
jest: ^29.0.0
typescript: '>=4.3 <6'
peerDependenciesMeta:
'@babel/core':
optional: true
'@jest/types':
optional: true
babel-jest:
optional: true
esbuild:
optional: true
dependencies:
'@babel/core': 7.5.0
bs-logger: 0.2.6
fast-json-stable-stringify: 2.1.0
jest: 29.5.0(@types/node@14.18.33)
jest-util: 29.3.1
json5: 2.2.3
lodash.memoize: 4.1.2
make-error: 1.3.6
semver: 7.3.8
typescript: 4.9.5
yargs-parser: 21.1.1
dev: true
/ts-morph@12.0.0:
resolution: {integrity: sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==}
dependencies:
@@ -16382,6 +16397,13 @@ packages:
which-boxed-primitive: 1.0.2
dev: true
/undici@5.22.1:
resolution: {integrity: sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==}
engines: {node: '>=14.0'}
dependencies:
busboy: 1.6.0
dev: true
/unicode-canonical-property-names-ecmascript@2.0.0:
resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
engines: {node: '>=4'}