diff --git a/.changeset/curly-seas-serve.md b/.changeset/curly-seas-serve.md new file mode 100644 index 0000000000..d4a96dcea2 --- /dev/null +++ b/.changeset/curly-seas-serve.md @@ -0,0 +1,5 @@ +--- +"blitz": patch +--- + +Check for new versions when running CLI diff --git a/.npmrc b/.npmrc index da6e0e169d..45a537533e 100644 --- a/.npmrc +++ b/.npmrc @@ -6,4 +6,4 @@ public-hoist-pattern[]=*types* public-hoist-pattern[]=*eslint* public-hoist-pattern[]=@prettier/plugin-* public-hoist-pattern[]=*prettier-plugin-* -strict-peer-dependencies=false + diff --git a/packages/blitz/package.json b/packages/blitz/package.json index 8d8845c8f1..2d66de2a3c 100644 --- a/packages/blitz/package.json +++ b/packages/blitz/package.json @@ -25,6 +25,7 @@ "dependencies": { "@blitzjs/generator": "2.0.0-alpha.54", "arg": "5.0.1", + "boxen": "7.0.0", "chalk": "^4.1.0", "console-table-printer": "2.10.0", "cross-spawn": "7.0.3", @@ -37,6 +38,7 @@ "find-up": "4.1.0", "fs-extra": "10.0.1", "hasbin": "1.2.3", + "node-fetch": "3.2.3", "npm-which": "3.0.1", "ora": "5.3.0", "os-name": "5.0.1", @@ -69,7 +71,6 @@ "@types/test-listen": "1.1.0", "@types/watchpack": "1.1.1", "express": "4.17.3", - "node-fetch": "3.2.3", "react": "18.0.0", "test-listen": "1.1.0", "typescript": "^4.5.3", diff --git a/packages/blitz/src/cli/commands/new.ts b/packages/blitz/src/cli/commands/new.ts index baf3475308..d4bf119ccf 100644 --- a/packages/blitz/src/cli/commands/new.ts +++ b/packages/blitz/src/cli/commands/new.ts @@ -7,6 +7,7 @@ import {CliCommand} from "../index" import arg from "arg" import {AppGenerator, AppGeneratorOptions, getLatestVersion} from "@blitzjs/generator" import {runPrisma} from "../../prisma-utils" +import {checkLatestVersion} from "../utils/check-latest-version" const forms = { "react-final-form": "React Final Form" as const, @@ -220,7 +221,7 @@ const determinePkgManagerToInstallDeps = async () => { const newApp: CliCommand = async (argv) => { const shouldUpgrade = !args["--skip-upgrade"] if (shouldUpgrade) { - //TODO: Handle checking for updates + await checkLatestVersion() } await determineProjectName() diff --git a/packages/blitz/src/cli/index.ts b/packages/blitz/src/cli/index.ts index d73226ca54..7f69226ea5 100644 --- a/packages/blitz/src/cli/index.ts +++ b/packages/blitz/src/cli/index.ts @@ -1,12 +1,12 @@ -import {NON_STANDARD_NODE_ENV} from "./utils/constants" import arg from "arg" +import spawn from "cross-spawn" + import {loadEnvConfig} from "../env-utils" +import {NON_STANDARD_NODE_ENV} from "./utils/constants" import {getCommandBin} from "./utils/config" -import spawn from "cross-spawn" -import {readdirSync} from "fs-extra" -import resolveFrom from "resolve-from" -import pkgDir from "pkg-dir" -import {join} from "path" +import {readVersions} from "./utils/read-versions" + +import {getPkgManager} from "./utils/helpers" const commonArgs = { // Flags @@ -57,9 +57,6 @@ if (aliases[args._[0] as Alias]) { const forwardedArgs = blitzCommand ? args._.slice(1) : args._ -const globalBlitzPath = resolveFrom(__dirname, "blitz") -const localBlitzPath = resolveFrom.silent(process.cwd(), "blitz") - async function runCommandFromBin() { if (!args._[0]) { console.log("No command specified") @@ -83,12 +80,8 @@ async function runCommandFromBin() { async function printEnvInfo() { const osName = await import("os-name") const envinfo = await import("envinfo") - const pkgManager = readdirSync(process.cwd()).includes("pnpm-lock.yaml") - ? "pnpm" - : readdirSync(process.cwd()).includes("yarn-lock.yaml") - ? "yarn" - : "npm" + const pkgManager = getPkgManager() const env = await envinfo.default.run( { System: ["OS", "CPU", "Memory", "Shell"], @@ -106,18 +99,13 @@ async function printEnvInfo() { {showNotFound: true}, ) - const globalBlitzPkgJsonPath = pkgDir.sync(globalBlitzPath) - const localBlitzPkgJsonPath = pkgDir.sync(localBlitzPath) - - if (globalBlitzPkgJsonPath && globalBlitzPkgJsonPath !== localBlitzPkgJsonPath) { - // This branch won't run if user does `npx blitz` or `yarn blitz` - const globalVersion = require(join(globalBlitzPkgJsonPath, "package.json")).version + const {globalVersion, localVersions} = readVersions() + if (globalVersion) { console.log(`Blitz version: ${globalVersion} (global)`) } - if (localBlitzPkgJsonPath) { - const localVersion = require(join(localBlitzPkgJsonPath, "package.json")).version - console.log(`Blitz version: ${localVersion} (local)`) + if (localVersions.blitz) { + console.log(`Blitz version: ${localVersions.blitz} (local)`) } console.log( diff --git a/packages/blitz/src/cli/utils/check-latest-version.ts b/packages/blitz/src/cli/utils/check-latest-version.ts new file mode 100644 index 0000000000..8a46aba14f --- /dev/null +++ b/packages/blitz/src/cli/utils/check-latest-version.ts @@ -0,0 +1,185 @@ +import findUp from "find-up" +import resolveFrom from "resolve-from" +import {join, dirname} from "path" +import fs from "fs" +import {readVersions, resolveVersionType} from "./read-versions" +import {getPkgManager} from "./helpers" +import superjson from "superjson" + +const returnNpmEndpoint = (packageName: string) => { + return `https://registry.npmjs.org/-/package/${packageName}/dist-tags` +} + +function getUpdateString(packageName: string, tag: string, isGlobal?: boolean) { + const pkgManager = getPkgManager() + switch (pkgManager) { + case "npm": + return `npm install${isGlobal ? " -g" : ""} ${packageName}@${tag}` + case "yarn": + return `yarn${isGlobal ? " global" : ""} add ${packageName}@${tag}` + case "pnpm": + return `pnpm install${isGlobal ? " -g" : ""} ${packageName}@${tag}` + } +} +const isInternalBlitzMonorepoDevelopment = fs.existsSync( + join(process.cwd(), "..", "..", "packages", "blitz", "dist", "chunks"), +) + +async function findNodeModulesRoot(src: string) { + const blitzPkgLocation = dirname( + (await findUp("package.json", { + cwd: resolveFrom(src, "blitz"), + })) ?? "", + ) + + if (!blitzPkgLocation) { + throw new Error("Internal Blitz Error: unable to find 'blitz' package location") + } + + return blitzPkgLocation.includes(".pnpm") + ? join(blitzPkgLocation, "../../../../") + : join(blitzPkgLocation, "../") +} + +export async function checkLatestVersion() { + if (!isInternalBlitzMonorepoDevelopment) { + const fetch = await import("node-fetch") + const boxen = await import("boxen") + const versions = readVersions() + const nodeModulesRoot = await findNodeModulesRoot(process.cwd()) + const dotBlitzCacheExists = fs.existsSync( + join(nodeModulesRoot, ".blitz", "checkUpdateCache.json"), + ) + let dotBlitzCache + let shouldRun = true + + if (dotBlitzCacheExists) { + dotBlitzCache = fs.readFileSync(join(nodeModulesRoot, ".blitz", "checkUpdateCache.json")) + const now = new Date() + const msBetweenTimes = Math.abs( + superjson.parse<{lastUpdated: Date}>(dotBlitzCache.toString()).lastUpdated.getTime() - + now.getTime(), + ) + const hoursBetweenTimes = msBetweenTimes / (60 * 60 * 1000) + shouldRun = hoursBetweenTimes > 24 + } + + if (shouldRun) { + let errors: {message: string; instructions: string}[] = [] + try { + const blitzResponse = await fetch.default(returnNpmEndpoint("blitz")) + const remoteBlitzVersions = (await blitzResponse.json()) as Record + + const blitzNextResponse = await fetch.default(returnNpmEndpoint("@blitzjs/next")) + const remoteBlitzNextVersions = (await blitzNextResponse.json()) as Record + + const blitzAuthResponse = await fetch.default(returnNpmEndpoint("@blitzjs/auth")) + const remoteBlitzAuthVersions = (await blitzAuthResponse.json()) as Record + + const blitzRpcResponse = await fetch.default(returnNpmEndpoint("@blitzjs/rpc")) + const remoteBlitzRpcVersions = (await blitzRpcResponse.json()) as Record + + for (const version of Object.entries(versions)) { + if (version[0] === "globalVersion") { + const versionType = resolveVersionType(version[1] as string) + + if (remoteBlitzVersions.hasOwnProperty("beta") && versionType !== "beta") { + errors.push({ + message: `blitz(global) (current) ${version[1]} -> (latest) ${remoteBlitzVersions["beta"]}`, + instructions: `${getUpdateString("blitz", "beta", true)}`, + }) + } else if (remoteBlitzVersions[versionType] !== version[1]) { + errors.push({ + message: `blitz(global) (current) ${version[1]} -> (latest) ${remoteBlitzVersions[versionType]}`, + instructions: `${getUpdateString("blitz", versionType, true)}`, + }) + } + } else if (version[0] === "localVersions") { + for (const localVersion of Object.entries(version[1])) { + const versionType = resolveVersionType(localVersion[1] as string) + + switch (localVersion[0]) { + case "blitz": + if (remoteBlitzVersions.hasOwnProperty("beta") && versionType !== "beta") { + errors.push({ + message: `blitz (current) ${localVersion[1]} -> (latest) ${remoteBlitzVersions["beta"]}`, + instructions: `${getUpdateString("blitz", "beta", false)}`, + }) + } else if (remoteBlitzVersions[versionType] !== localVersion[1]) { + errors.push({ + message: `blitz (current) ${localVersion[1]} -> (latest) ${remoteBlitzVersions[versionType]}`, + instructions: `${getUpdateString("blitz", versionType, false)}`, + }) + } + break + case "blitzAuth": + if (remoteBlitzAuthVersions.hasOwnProperty("beta") && versionType !== "beta") { + errors.push({ + message: `@blitzjs/auth (current) ${localVersion[1]} -> (latest) ${remoteBlitzAuthVersions["beta"]}`, + instructions: `${getUpdateString("@blitzjs/auth", "beta", false)}`, + }) + } else if (remoteBlitzAuthVersions[versionType] !== localVersion[1]) { + errors.push({ + message: `@blitzjs/auth (current) ${localVersion[1]} -> (latest) ${remoteBlitzAuthVersions[versionType]}`, + instructions: `${getUpdateString("@blitzjs/auth", versionType, false)}`, + }) + } + break + case "blitzNext": + if (remoteBlitzNextVersions.hasOwnProperty("beta") && versionType !== "beta") { + errors.push({ + message: `@blitzjs/next (current) ${localVersion[1]} -> (latest) ${remoteBlitzNextVersions["beta"]}`, + instructions: `${getUpdateString("@blitzjs/next", "beta", false)}`, + }) + } else if (remoteBlitzNextVersions[versionType] !== localVersion[1]) { + errors.push({ + message: `@blitzjs/next (current) ${localVersion[1]} -> (latest) ${remoteBlitzNextVersions[versionType]}`, + instructions: `${getUpdateString("@blitzjs/next", versionType, false)}`, + }) + } + break + case "blitzRpc": + if (remoteBlitzRpcVersions.hasOwnProperty("beta") && versionType !== "beta") { + errors.push({ + message: `@blitzjs/rpc (current) ${localVersion[1]} -> (latest) ${remoteBlitzRpcVersions["beta"]}`, + instructions: `${getUpdateString("@blitzjs/rpc", "beta", false)}`, + }) + } else if (remoteBlitzRpcVersions[versionType] !== localVersion[1]) { + errors.push({ + message: `@blitzjs/rpc (current) ${localVersion[1]} -> (latest) ${remoteBlitzRpcVersions[versionType]}`, + instructions: `${getUpdateString("@blitzjs/rpc", versionType, false)}`, + }) + } + break + } + } + } + } + + console.log( + boxen.default( + `You are running outdated blitz packages\n\n ${errors + .map((e) => e.message) + .join("\n")} \n\n Run the following to update:\n ${errors + .map((e) => e.instructions) + .join("\n")}`, + {padding: 1}, + ), + ) + + const dotBlitz = join(nodeModulesRoot, ".blitz") + fs.writeFileSync( + join(dotBlitz, "checkUpdateCache.json"), + superjson.stringify({lastUpdated: new Date()}), + ) + } catch (err) { + if (err instanceof fetch.FetchError) { + // TODO: Check if network error and throw otherwise + // pass fetch error + } else { + console.log(err) + } + } + } + } +} diff --git a/packages/blitz/src/cli/utils/helpers.ts b/packages/blitz/src/cli/utils/helpers.ts new file mode 100644 index 0000000000..8876a9b1fc --- /dev/null +++ b/packages/blitz/src/cli/utils/helpers.ts @@ -0,0 +1,9 @@ +import {readdirSync} from "fs-extra" + +export function getPkgManager() { + return readdirSync(process.cwd()).includes("pnpm-lock.yaml") + ? "pnpm" + : readdirSync(process.cwd()).includes("yarn-lock.yaml") + ? "yarn" + : "npm" +} diff --git a/packages/blitz/src/cli/utils/next-commands.ts b/packages/blitz/src/cli/utils/next-commands.ts index 6ad912a4f6..510dee95f0 100644 --- a/packages/blitz/src/cli/utils/next-commands.ts +++ b/packages/blitz/src/cli/utils/next-commands.ts @@ -7,6 +7,7 @@ import { startCustomServer, buildCustomServer, } from "./next-utils" +import {checkLatestVersion} from "./check-latest-version" import {readBlitzConfig} from "../../server-utils" export async function build(config: ServerConfig) { @@ -18,7 +19,7 @@ export async function build(config: ServerConfig) { export async function dev(config: ServerConfig) { const {rootFolder, nextBin} = await normalize({...config, env: "dev"}) - + void checkLatestVersion() if (customServerExists()) { console.log("Using your custom server") diff --git a/packages/blitz/src/cli/utils/read-versions.ts b/packages/blitz/src/cli/utils/read-versions.ts new file mode 100644 index 0000000000..240621b937 --- /dev/null +++ b/packages/blitz/src/cli/utils/read-versions.ts @@ -0,0 +1,79 @@ +import {join} from "path" +import pkgDir from "pkg-dir" +import resolveFrom from "resolve-from" + +const globalBlitzPath = resolveFrom(__dirname, "blitz") +const localBlitzPath = resolveFrom.silent(process.cwd(), "blitz") +const localBlitzAuthPath = resolveFrom.silent(process.cwd(), "@blitzjs/auth") +const localBlitzRpcPath = resolveFrom.silent(process.cwd(), "@blitzjs/rpc") +const localBlitzNextPath = resolveFrom.silent(process.cwd(), "@blitzjs/next") + +export function readVersions() { + const globalBlitzPkgJsonPath = pkgDir.sync(globalBlitzPath) + const localBlitzPkgJsonPath = pkgDir.sync(localBlitzPath) + const localBlitzAuthPkgJsonPath = pkgDir.sync(localBlitzAuthPath) + const localBlitzNextPkgJsonPath = pkgDir.sync(localBlitzNextPath) + const localBlitzRpcPkgJsonPath = pkgDir.sync(localBlitzRpcPath) + + const versions: { + globalVersion?: string + localVersions: { + blitz?: string + blitzAuth?: string + blitzRpc?: string + blitzNext?: string + } + } = {globalVersion: "", localVersions: {}} + + // This branch won't run if user does `npx blitz` or `yarn blitz` + if (globalBlitzPkgJsonPath && globalBlitzPkgJsonPath !== localBlitzPkgJsonPath) { + versions.globalVersion = require(join(globalBlitzPkgJsonPath, "package.json")).version + } + + if (localBlitzPkgJsonPath) { + versions.localVersions.blitz = require(join(localBlitzPkgJsonPath, "package.json")).version + } + + if (localBlitzAuthPkgJsonPath) { + versions.localVersions.blitzAuth = require(join( + localBlitzAuthPkgJsonPath, + "package.json", + )).version + } + + if (localBlitzNextPkgJsonPath) { + versions.localVersions.blitzNext = require(join( + localBlitzNextPkgJsonPath, + "package.json", + )).version + } + + if (localBlitzRpcPkgJsonPath) { + versions.localVersions.blitzRpc = require(join( + localBlitzRpcPkgJsonPath, + "package.json", + )).version + } + + return versions +} + +export function resolveVersionType(version: string) { + if (version.includes("alpha")) { + return "alpha" as const + } + + if (version.includes("beta")) { + return "beta" as const + } + + if (version.includes("danger")) { + return "danger" as const + } + + if (version.includes("canary")) { + return "canary" as const + } + + return "latest" as const +} diff --git a/patches/next@12.2.0.patch b/patches/next@12.2.0.patch deleted file mode 100644 index 4884066145..0000000000 --- a/patches/next@12.2.0.patch +++ /dev/null @@ -1,29 +0,0 @@ -diff --git a/dist/build/webpack-config.js b/dist/build/webpack-config.js -index f9cab03b74411376898fbf5bd14c187236d9ad1b..f91706ec39cc53d642e477ecc10978b17d2b8bb4 100755 ---- a/dist/build/webpack-config.js -+++ b/dist/build/webpack-config.js -@@ -910,6 +910,7 @@ async function getBaseWebpackConfig(dir, { buildId , config , compilerType , dev - "process.env.__NEXT_I18N_SUPPORT": JSON.stringify(!!config.i18n), - "process.env.__NEXT_I18N_DOMAINS": JSON.stringify((ref9 = config.i18n) == null ? void 0 : ref9.domains), - "process.env.__NEXT_ANALYTICS_ID": JSON.stringify(config.analyticsId), -+ 'process.env.__NEXT_REACT_ONRECOVERABLE_ERROR': config.reactOnRecoverableError, - ...isNodeServer || isEdgeServer ? { - // Fix bad-actors in the npm ecosystem (e.g. `node-formidable`) - // This is typically found in unmaintained modules from the -diff --git a/dist/client/index.js b/dist/client/index.js -index 74242a1991af91cc44c2d4af3516f9225043f987..ed2f298d65a636fa79b3d580ad6e3aa0792efcfd 100755 ---- a/dist/client/index.js -+++ b/dist/client/index.js -@@ -475,7 +475,11 @@ function renderReactElement(domEl, fn) { - if (process.env.__NEXT_REACT_ROOT) { - if (!reactRoot) { - // Unlike with createRoot, you don't need a separate root.render() call here -- reactRoot = ReactDOM.hydrateRoot(domEl, reactEl); -+ reactRoot = ReactDOM.hydrateRoot(domEl, reactEl, Boolean(process.env.__NEXT_REACT_ONRECOVERABLE_ERROR) -+ ? { -+ onRecoverableError: process.env.__NEXT_REACT_ONRECOVERABLE_ERROR, -+ } -+ : undefined); - // TODO: Remove shouldHydrate variable when React 18 is stable as it can depend on `reactRoot` existing - shouldHydrate = false; - } else { \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5a1cece2d..845690e5fc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -493,6 +493,7 @@ importers: "@types/test-listen": 1.1.0 "@types/watchpack": 1.1.1 arg: 5.0.1 + boxen: 7.0.0 chalk: ^4.1.0 console-table-printer: 2.10.0 cross-spawn: 7.0.3 @@ -529,6 +530,7 @@ importers: dependencies: "@blitzjs/generator": link:../generator arg: 5.0.1 + boxen: 7.0.0 chalk: 4.1.2 console-table-printer: 2.10.0 cross-spawn: 7.0.3 @@ -541,6 +543,7 @@ importers: find-up: 4.1.0 fs-extra: 10.0.1 hasbin: 1.2.3 + node-fetch: 3.2.3 npm-which: 3.0.1 ora: 5.3.0 os-name: 5.0.1 @@ -572,7 +575,6 @@ importers: "@types/test-listen": 1.1.0 "@types/watchpack": 1.1.1 express: 4.17.3 - node-fetch: 3.2.3 react: 18.0.0 test-listen: 1.1.0 typescript: 4.6.3 @@ -5897,6 +5899,23 @@ packages: widest-line: 3.1.0 dev: false + /boxen/7.0.0: + resolution: + { + integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==, + } + engines: {node: ">=14.16"} + dependencies: + ansi-align: 3.0.1 + camelcase: 7.0.0 + chalk: 5.0.1 + cli-boxes: 3.0.0 + string-width: 5.1.2 + type-fest: 2.16.0 + widest-line: 4.0.1 + wrap-ansi: 8.0.1 + dev: false + /brace-expansion/1.1.11: resolution: { @@ -6164,6 +6183,14 @@ packages: } engines: {node: ">=10"} + /camelcase/7.0.0: + resolution: + { + integrity: sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==, + } + engines: {node: ">=14.16"} + dev: false + /caniuse-lite/1.0.30001339: resolution: { @@ -6223,7 +6250,6 @@ packages: integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==, } engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: true /char-regex/1.0.2: resolution: @@ -6345,6 +6371,14 @@ packages: engines: {node: ">=6"} dev: false + /cli-boxes/3.0.0: + resolution: + { + integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==, + } + engines: {node: ">=10"} + dev: false + /cli-cursor/3.1.0: resolution: { @@ -6858,7 +6892,6 @@ packages: integrity: sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==, } engines: {node: ">= 12"} - dev: true /data-urls/2.0.0: resolution: @@ -9234,7 +9267,6 @@ packages: dependencies: node-domexception: 1.0.0 web-streams-polyfill: 3.2.1 - dev: true /file-entry-cache/6.0.1: resolution: @@ -9446,7 +9478,6 @@ packages: engines: {node: ">=12.20.0"} dependencies: fetch-blob: 3.1.5 - dev: true /forwarded/0.2.0: resolution: @@ -12890,7 +12921,6 @@ packages: integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==, } engines: {node: ">=10.5.0"} - dev: true /node-fetch/3.2.3: resolution: @@ -12902,7 +12932,6 @@ packages: data-uri-to-buffer: 4.0.0 fetch-blob: 3.1.5 formdata-polyfill: 4.0.10 - dev: true /node-gyp-build/4.4.0: resolution: @@ -16443,6 +16472,14 @@ packages: engines: {node: ">=8"} dev: false + /type-fest/2.16.0: + resolution: + { + integrity: sha512-qpaThT2HQkFb83gMOrdKVsfCN7LKxP26Yq+smPzY1FqoHRjqmjqHXA7n5Gkxi8efirtbeEUxzfEdePthQWCuHw==, + } + engines: {node: ">=12.20"} + dev: false + /type-is/1.6.18: resolution: { @@ -16956,7 +16993,6 @@ packages: integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==, } engines: {node: ">= 8"} - dev: true /webidl-conversions/5.0.0: resolution: @@ -17130,6 +17166,16 @@ packages: string-width: 4.2.3 dev: false + /widest-line/4.0.1: + resolution: + { + integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==, + } + engines: {node: ">=12"} + dependencies: + string-width: 5.1.2 + dev: false + /windows-release/5.0.1: resolution: { @@ -17182,6 +17228,18 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 + /wrap-ansi/8.0.1: + resolution: + { + integrity: sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==, + } + engines: {node: ">=12"} + dependencies: + ansi-styles: 6.1.0 + string-width: 5.1.2 + strip-ansi: 7.0.1 + dev: false + /wrappy/1.0.2: resolution: {