diff --git a/.changeset/hungry-ideas-buy.md b/.changeset/hungry-ideas-buy.md new file mode 100644 index 00000000..9d44bce6 --- /dev/null +++ b/.changeset/hungry-ideas-buy.md @@ -0,0 +1,5 @@ +--- +"@opennextjs/cloudflare": minor +--- + +refactor: use yargs for the cli diff --git a/packages/cloudflare/package.json b/packages/cloudflare/package.json index 3c3888bc..16f62e13 100644 --- a/packages/cloudflare/package.json +++ b/packages/cloudflare/package.json @@ -57,7 +57,8 @@ "cloudflare": "^4.4.1", "enquirer": "^2.4.1", "glob": "catalog:", - "ts-tqdm": "^0.8.6" + "ts-tqdm": "^0.8.6", + "yargs": "catalog:" }, "devDependencies": { "@cloudflare/workers-types": "catalog:", @@ -66,6 +67,7 @@ "@types/mock-fs": "catalog:", "@types/node": "catalog:", "@types/picomatch": "^4.0.0", + "@types/yargs": "catalog:", "diff": "^8.0.2", "esbuild": "catalog:", "eslint": "catalog:", diff --git a/packages/cloudflare/src/cli/args.spec.ts b/packages/cloudflare/src/cli/args.spec.ts deleted file mode 100644 index f4fb0234..00000000 --- a/packages/cloudflare/src/cli/args.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { getPassthroughArgs } from "./args.js"; - -describe("getPassthroughArgs", () => { - it("should return args not used by the cli", () => { - const args = [ - "pnpm", - "/opennextjs/cloudflare/examples/ssg-app/node_modules/@opennextjs/cloudflare/dist/cli/index.js", - "preview", - "--skipBuild", - "--preview", - "-t", - "-v=1", - "-pre", - "152", - "--pre2=1543", - "--", - "--port", - "1234", - "--inspector-port", - "1234", - ]; - - expect(getPassthroughArgs(args, { options: { skipBuild: { type: "boolean" } } })).toEqual([ - "--preview", - "-t", - "-v=1", - "-pre", - "152", - "--pre2=1543", - "--port", - "1234", - "--inspector-port", - "1234", - ]); - }); -}); diff --git a/packages/cloudflare/src/cli/args.ts b/packages/cloudflare/src/cli/args.ts deleted file mode 100644 index 8669dde5..00000000 --- a/packages/cloudflare/src/cli/args.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { mkdirSync, type Stats, statSync } from "node:fs"; -import { resolve } from "node:path"; -import type { ParseArgsConfig } from "node:util"; -import { parseArgs } from "node:util"; - -import type { WranglerTarget } from "./utils/run-wrangler.js"; -import { getWranglerEnvironmentFlag, isWranglerTarget } from "./utils/run-wrangler.js"; - -export type Arguments = ( - | { - command: "build"; - skipNextBuild: boolean; - skipWranglerConfigCheck: boolean; - minify: boolean; - } - | { - command: "preview" | "deploy" | "upload"; - passthroughArgs: string[]; - cacheChunkSize?: number; - } - | { - command: "populateCache"; - target: WranglerTarget; - environment?: string; - cacheChunkSize?: number; - } -) & { outputDir?: string }; - -// Config for parsing CLI arguments -const config = { - allowPositionals: true, - strict: false, - options: { - skipBuild: { type: "boolean", short: "s", default: false }, - output: { type: "string", short: "o" }, - noMinify: { type: "boolean", default: false }, - skipWranglerConfigCheck: { type: "boolean", default: false }, - cacheChunkSize: { type: "string" }, - }, -} as const satisfies ParseArgsConfig; - -export function getArgs(): Arguments { - const { positionals, values } = parseArgs(config); - - const outputDir = typeof values.output === "string" ? resolve(values.output) : undefined; - if (outputDir) assertDirArg(outputDir, "output", true); - - switch (positionals[0]) { - case "build": - return { - command: "build", - outputDir, - skipNextBuild: - !!values.skipBuild || ["1", "true", "yes"].includes(String(process.env.SKIP_NEXT_APP_BUILD)), - skipWranglerConfigCheck: - !!values.skipWranglerConfigCheck || - ["1", "true", "yes"].includes(String(process.env.SKIP_WRANGLER_CONFIG_CHECK)), - minify: !values.noMinify, - }; - case "preview": - case "deploy": - case "upload": - return { - command: positionals[0], - outputDir, - passthroughArgs: getPassthroughArgs(process.argv, config), - ...(values.cacheChunkSize && { cacheChunkSize: Number(values.cacheChunkSize) }), - }; - case "populateCache": - if (!isWranglerTarget(positionals[1])) { - throw new Error(`Error: invalid target for populating the cache, expected 'local' | 'remote'`); - } - return { - command: "populateCache", - outputDir, - target: positionals[1], - environment: getWranglerEnvironmentFlag(process.argv), - ...(values.cacheChunkSize && { cacheChunkSize: Number(values.cacheChunkSize) }), - }; - default: - throw new Error( - "Error: invalid command, expected 'build' | 'preview' | 'deploy' | 'upload' | 'populateCache'" - ); - } -} - -export function getPassthroughArgs(args: string[], { options = {} }: T) { - const passthroughArgs: string[] = []; - - for (let i = 0; i < args.length; i++) { - if (args[i] === "--") { - passthroughArgs.push(...args.slice(i + 1)); - return passthroughArgs; - } - - // look for `--arg(=value)`, `-arg(=value)` - const [, name] = /^--?(\w[\w-]*)(=.+)?$/.exec(args[i]!) ?? []; - if (name && !(name in options)) { - passthroughArgs.push(args[i]!); - - // Array args can have multiple values - // ref https://github.com/yargs/yargs-parser/blob/main/README.md#greedy-arrays - while (i < args.length - 1 && !args[i + 1]?.startsWith("-")) { - passthroughArgs.push(args[++i]!); - } - } - } - - return passthroughArgs; -} - -function assertDirArg(path: string, argName?: string, make?: boolean) { - let dirStats: Stats; - try { - dirStats = statSync(path); - } catch { - if (!make) { - throw new Error(`Error: the provided${argName ? ` "${argName}"` : ""} input is not a valid path`); - } - mkdirSync(path); - return; - } - - if (!dirStats.isDirectory()) { - throw new Error(`Error: the provided${argName ? ` "${argName}"` : ""} input is not a directory`); - } -} diff --git a/packages/cloudflare/src/cli/commands/build.ts b/packages/cloudflare/src/cli/commands/build.ts new file mode 100644 index 00000000..efb035d0 --- /dev/null +++ b/packages/cloudflare/src/cli/commands/build.ts @@ -0,0 +1,71 @@ +import type yargs from "yargs"; + +import { build as buildImpl } from "../build/build.js"; +import type { WithWranglerArgs } from "./utils.js"; +import { + compileConfig, + getNormalizedOptions, + nextAppDir, + printHeaders, + readWranglerConfig, + withWranglerOptions, + withWranglerPassthroughArgs, +} from "./utils.js"; + +/** + * Implementation of the `opennextjs-cloudflare build` command. + * + * @param args + */ +async function buildCommand( + args: WithWranglerArgs<{ + skipNextBuild: boolean; + noMinify: boolean; + skipWranglerConfigCheck: boolean; + }> +): Promise { + printHeaders("build"); + + const { config, buildDir } = await compileConfig(); + const options = getNormalizedOptions(config, buildDir); + + const wranglerConfig = readWranglerConfig(args); + + await buildImpl( + options, + config, + { ...args, minify: !args.noMinify, sourceDir: nextAppDir }, + wranglerConfig + ); +} + +/** + * Add the `build` command to yargs configuration. + * + * Consumes 1 positional parameter. + */ +export function addBuildCommand(y: T) { + return y.command( + "build", + "Build an OpenNext Cloudflare worker", + (c) => + withWranglerOptions(c) + .option("skipNextBuild", { + type: "boolean", + alias: ["skipBuild", "s"], + default: ["1", "true", "yes"].includes(String(process.env.SKIP_NEXT_APP_BUILD)), + desc: "Skip building the Next.js app", + }) + .option("noMinify", { + type: "boolean", + default: false, + desc: "Disable worker minification", + }) + .option("skipWranglerConfigCheck", { + type: "boolean", + default: ["1", "true", "yes"].includes(String(process.env.SKIP_WRANGLER_CONFIG_CHECK)), + desc: "Skip checking for a Wrangler config", + }), + (args) => buildCommand(withWranglerPassthroughArgs(args)) + ); +} diff --git a/packages/cloudflare/src/cli/commands/deploy.ts b/packages/cloudflare/src/cli/commands/deploy.ts index f8edb26f..29625926 100644 --- a/packages/cloudflare/src/cli/commands/deploy.ts +++ b/packages/cloudflare/src/cli/commands/deploy.ts @@ -1,35 +1,51 @@ -import { BuildOptions } from "@opennextjs/aws/build/helper.js"; +import type yargs from "yargs"; -import type { OpenNextConfig } from "../../api/config.js"; import { DEPLOYMENT_MAPPING_ENV_NAME } from "../templates/skew-protection.js"; -import { getWranglerEnvironmentFlag, runWrangler } from "../utils/run-wrangler.js"; +import { runWrangler } from "../utils/run-wrangler.js"; import { getEnvFromPlatformProxy, quoteShellMeta } from "./helpers.js"; -import { populateCache } from "./populate-cache.js"; +import { populateCache, withPopulateCacheOptions } from "./populate-cache.js"; import { getDeploymentMapping } from "./skew-protection.js"; +import type { WithWranglerArgs } from "./utils.js"; +import { + getNormalizedOptions, + printHeaders, + readWranglerConfig, + retrieveCompiledConfig, + withWranglerPassthroughArgs, +} from "./utils.js"; + +/** + * Implementation of the `opennextjs-cloudflare deploy` command. + * + * @param args + */ +export async function deployCommand(args: WithWranglerArgs<{ cacheChunkSize: number }>): Promise { + printHeaders("deploy"); + + const { config } = await retrieveCompiledConfig(); + const options = getNormalizedOptions(config); + + const wranglerConfig = readWranglerConfig(args); -export async function deploy( - options: BuildOptions, - config: OpenNextConfig, - deployOptions: { passthroughArgs: string[]; cacheChunkSize?: number } -) { const envVars = await getEnvFromPlatformProxy({ - // TODO: Pass the configPath, update everywhere applicable - environment: getWranglerEnvironmentFlag(deployOptions.passthroughArgs), + configPath: args.configPath, + environment: args.env, }); const deploymentMapping = await getDeploymentMapping(options, config, envVars); - await populateCache(options, config, { + await populateCache(options, config, wranglerConfig, { target: "remote", - environment: getWranglerEnvironmentFlag(deployOptions.passthroughArgs), - cacheChunkSize: deployOptions.cacheChunkSize, + environment: args.env, + configPath: args.configPath, + cacheChunkSize: args.cacheChunkSize, }); runWrangler( options, [ "deploy", - ...deployOptions.passthroughArgs, + ...args.wranglerArgs, ...(deploymentMapping ? [`--var ${DEPLOYMENT_MAPPING_ENV_NAME}:${quoteShellMeta(JSON.stringify(deploymentMapping))}`] : []), @@ -39,3 +55,17 @@ export async function deploy( } ); } + +/** + * Add the `deploy` command to yargs configuration. + * + * Consumes 1 positional parameter. + */ +export function addDeployCommand(y: T) { + return y.command( + "deploy", + "Deploy a built OpenNext app to Cloudflare Workers", + (c) => withPopulateCacheOptions(c), + (args) => deployCommand(withWranglerPassthroughArgs(args)) + ); +} diff --git a/packages/cloudflare/src/cli/commands/populate-cache.ts b/packages/cloudflare/src/cli/commands/populate-cache.ts index 70dbe5e1..b18e4463 100644 --- a/packages/cloudflare/src/cli/commands/populate-cache.ts +++ b/packages/cloudflare/src/cli/commands/populate-cache.ts @@ -12,7 +12,8 @@ import type { import type { IncrementalCache, TagCache } from "@opennextjs/aws/types/overrides.js"; import { globSync } from "glob"; import { tqdm } from "ts-tqdm"; -import { unstable_readConfig } from "wrangler"; +import type { Unstable_Config as WranglerConfig } from "wrangler"; +import type yargs from "yargs"; import { BINDING_NAME as KV_CACHE_BINDING_NAME, @@ -37,6 +38,15 @@ import { normalizePath } from "../build/utils/normalize-path.js"; import type { WranglerTarget } from "../utils/run-wrangler.js"; import { runWrangler } from "../utils/run-wrangler.js"; import { getEnvFromPlatformProxy, quoteShellMeta } from "./helpers.js"; +import type { WithWranglerArgs } from "./utils.js"; +import { + getNormalizedOptions, + printHeaders, + readWranglerConfig, + retrieveCompiledConfig, + withWranglerOptions, + withWranglerPassthroughArgs, +} from "./utils.js"; async function resolveCacheName( value: @@ -94,14 +104,20 @@ export function getCacheAssets(opts: BuildOptions): CacheAsset[] { return assets; } +type PopulateCacheOptions = { + target: WranglerTarget; + environment?: string; + configPath?: string; + cacheChunkSize?: number; +}; + async function populateR2IncrementalCache( options: BuildOptions, - populateCacheOptions: { target: WranglerTarget; environment?: string } + config: WranglerConfig, + populateCacheOptions: PopulateCacheOptions ) { logger.info("\nPopulating R2 incremental cache..."); - const config = unstable_readConfig({ env: populateCacheOptions.environment }); - const binding = config.r2_buckets.find(({ binding }) => binding === R2_CACHE_BINDING_NAME); if (!binding) { throw new Error(`No R2 binding ${JSON.stringify(R2_CACHE_BINDING_NAME)} found!`); @@ -140,12 +156,11 @@ async function populateR2IncrementalCache( async function populateKVIncrementalCache( options: BuildOptions, - populateCacheOptions: { target: WranglerTarget; environment?: string; cacheChunkSize?: number } + config: WranglerConfig, + populateCacheOptions: PopulateCacheOptions ) { logger.info("\nPopulating KV incremental cache..."); - const config = unstable_readConfig({ env: populateCacheOptions.environment }); - const binding = config.kv_namespaces.find(({ binding }) => binding === KV_CACHE_BINDING_NAME); if (!binding) { throw new Error(`No KV binding ${JSON.stringify(KV_CACHE_BINDING_NAME)} found!`); @@ -190,12 +205,11 @@ async function populateKVIncrementalCache( function populateD1TagCache( options: BuildOptions, - populateCacheOptions: { target: WranglerTarget; environment?: string } + config: WranglerConfig, + populateCacheOptions: PopulateCacheOptions ) { logger.info("\nCreating D1 table if necessary..."); - const config = unstable_readConfig({ env: populateCacheOptions.environment }); - const binding = config.d1_databases.find(({ binding }) => binding === D1_TAG_BINDING_NAME); if (!binding) { throw new Error(`No D1 binding ${JSON.stringify(D1_TAG_BINDING_NAME)} found!`); @@ -229,7 +243,8 @@ function populateStaticAssetsIncrementalCache(options: BuildOptions) { export async function populateCache( options: BuildOptions, config: OpenNextConfig, - populateCacheOptions: { target: WranglerTarget; environment?: string; cacheChunkSize?: number } + wranglerConfig: WranglerConfig, + populateCacheOptions: PopulateCacheOptions ) { const { incrementalCache, tagCache } = config.default.override ?? {}; @@ -242,10 +257,10 @@ export async function populateCache( const name = await resolveCacheName(incrementalCache); switch (name) { case R2_CACHE_NAME: - await populateR2IncrementalCache(options, populateCacheOptions); + await populateR2IncrementalCache(options, wranglerConfig, populateCacheOptions); break; case KV_CACHE_NAME: - await populateKVIncrementalCache(options, populateCacheOptions); + await populateKVIncrementalCache(options, wranglerConfig, populateCacheOptions); break; case STATIC_ASSETS_CACHE_NAME: populateStaticAssetsIncrementalCache(options); @@ -259,10 +274,66 @@ export async function populateCache( const name = await resolveCacheName(tagCache); switch (name) { case D1_TAG_NAME: - populateD1TagCache(options, populateCacheOptions); + populateD1TagCache(options, wranglerConfig, populateCacheOptions); break; default: logger.info("Tag cache does not need populating"); } } } + +/** + * Implementation of the `opennextjs-cloudflare populateCache` command. + * + * @param args + */ +async function populateCacheCommand( + target: "local" | "remote", + args: WithWranglerArgs<{ cacheChunkSize: number }> +) { + printHeaders(`populate cache - ${target}`); + + const { config } = await retrieveCompiledConfig(); + const options = getNormalizedOptions(config); + + const wranglerConfig = readWranglerConfig(args); + + await populateCache(options, config, wranglerConfig, { + target, + environment: args.env, + configPath: args.configPath, + cacheChunkSize: args.cacheChunkSize, + }); +} + +/** + * Add the `populateCache` command to yargs configuration, with nested commands for `local` and `remote`. + * + * Consumes 2 positional parameters. + */ +export function addPopulateCacheCommand(y: T) { + return y.command("populateCache", "Populate the cache for a built Next.js app", (c) => + c + .command( + "local", + "Local dev server cache", + (c) => withPopulateCacheOptions(c), + (args) => populateCacheCommand("local", withWranglerPassthroughArgs(args)) + ) + .command( + "remote", + "Remote Cloudflare Worker cache", + (c) => withPopulateCacheOptions(c), + (args) => populateCacheCommand("remote", withWranglerPassthroughArgs(args)) + ) + .demandCommand(1, 1) + ); +} + +export function withPopulateCacheOptions(args: T) { + return withWranglerOptions(args).options("cacheChunkSize", { + type: "number", + default: 25, + desc: "Number of entries per chunk when populating the cache", + }); +} diff --git a/packages/cloudflare/src/cli/commands/preview.ts b/packages/cloudflare/src/cli/commands/preview.ts index 9640e535..50cd8010 100644 --- a/packages/cloudflare/src/cli/commands/preview.ts +++ b/packages/cloudflare/src/cli/commands/preview.ts @@ -1,19 +1,49 @@ -import { BuildOptions } from "@opennextjs/aws/build/helper.js"; +import type yargs from "yargs"; -import type { OpenNextConfig } from "../../api/config.js"; -import { getWranglerEnvironmentFlag, runWrangler } from "../utils/run-wrangler.js"; -import { populateCache } from "./populate-cache.js"; +import { runWrangler } from "../utils/run-wrangler.js"; +import { populateCache, withPopulateCacheOptions } from "./populate-cache.js"; +import type { WithWranglerArgs } from "./utils.js"; +import { + getNormalizedOptions, + printHeaders, + readWranglerConfig, + retrieveCompiledConfig, + withWranglerPassthroughArgs, +} from "./utils.js"; -export async function preview( - options: BuildOptions, - config: OpenNextConfig, - previewOptions: { passthroughArgs: string[]; cacheChunkSize?: number } -) { - await populateCache(options, config, { +/** + * Implementation of the `opennextjs-cloudflare preview` command. + * + * @param args + */ +export async function previewCommand(args: WithWranglerArgs<{ cacheChunkSize: number }>): Promise { + printHeaders("preview"); + + const { config } = await retrieveCompiledConfig(); + const options = getNormalizedOptions(config); + + const wranglerConfig = readWranglerConfig(args); + + await populateCache(options, config, wranglerConfig, { target: "local", - environment: getWranglerEnvironmentFlag(previewOptions.passthroughArgs), - cacheChunkSize: previewOptions.cacheChunkSize, + environment: args.env, + configPath: args.configPath, + cacheChunkSize: args.cacheChunkSize, }); - runWrangler(options, ["dev", ...previewOptions.passthroughArgs], { logging: "all" }); + runWrangler(options, ["dev", ...args.wranglerArgs], { logging: "all" }); +} + +/** + * Add the `preview` command to yargs configuration. + * + * Consumes 1 positional parameter. + */ +export function addPreviewCommand(y: T) { + return y.command( + "preview", + "Preview a built OpenNext app with a Wrangler dev server", + (c) => withPopulateCacheOptions(c), + (args) => previewCommand(withWranglerPassthroughArgs(args)) + ); } diff --git a/packages/cloudflare/src/cli/commands/upload.ts b/packages/cloudflare/src/cli/commands/upload.ts index 24200abf..51c799ae 100644 --- a/packages/cloudflare/src/cli/commands/upload.ts +++ b/packages/cloudflare/src/cli/commands/upload.ts @@ -1,35 +1,51 @@ -import { BuildOptions } from "@opennextjs/aws/build/helper.js"; +import type yargs from "yargs"; -import type { OpenNextConfig } from "../../api/config.js"; import { DEPLOYMENT_MAPPING_ENV_NAME } from "../templates/skew-protection.js"; -import { getWranglerEnvironmentFlag, runWrangler } from "../utils/run-wrangler.js"; +import { runWrangler } from "../utils/run-wrangler.js"; import { getEnvFromPlatformProxy, quoteShellMeta } from "./helpers.js"; -import { populateCache } from "./populate-cache.js"; +import { populateCache, withPopulateCacheOptions } from "./populate-cache.js"; import { getDeploymentMapping } from "./skew-protection.js"; +import type { WithWranglerArgs } from "./utils.js"; +import { + getNormalizedOptions, + printHeaders, + readWranglerConfig, + retrieveCompiledConfig, + withWranglerPassthroughArgs, +} from "./utils.js"; + +/** + * Implementation of the `opennextjs-cloudflare upload` command. + * + * @param args + */ +export async function uploadCommand(args: WithWranglerArgs<{ cacheChunkSize: number }>): Promise { + printHeaders("upload"); + + const { config } = await retrieveCompiledConfig(); + const options = getNormalizedOptions(config); + + const wranglerConfig = readWranglerConfig(args); -export async function upload( - options: BuildOptions, - config: OpenNextConfig, - uploadOptions: { passthroughArgs: string[]; cacheChunkSize?: number } -) { const envVars = await getEnvFromPlatformProxy({ - // TODO: Pass the configPath, update everywhere applicable - environment: getWranglerEnvironmentFlag(uploadOptions.passthroughArgs), + configPath: args.configPath, + environment: args.env, }); const deploymentMapping = await getDeploymentMapping(options, config, envVars); - await populateCache(options, config, { + await populateCache(options, config, wranglerConfig, { target: "remote", - environment: getWranglerEnvironmentFlag(uploadOptions.passthroughArgs), - cacheChunkSize: uploadOptions.cacheChunkSize, + environment: args.env, + configPath: args.configPath, + cacheChunkSize: args.cacheChunkSize, }); runWrangler( options, [ "versions upload", - ...uploadOptions.passthroughArgs, + ...args.wranglerArgs, ...(deploymentMapping ? [`--var ${DEPLOYMENT_MAPPING_ENV_NAME}:${quoteShellMeta(JSON.stringify(deploymentMapping))}`] : []), @@ -37,3 +53,17 @@ export async function upload( { logging: "all" } ); } + +/** + * Add the `upload` command to yargs configuration. + * + * Consumes 1 positional parameter. + */ +export function addUploadCommand(y: T) { + return y.command( + "upload", + "Upload a built OpenNext app to Cloudflare Workers", + (c) => withPopulateCacheOptions(c), + (args) => uploadCommand(withWranglerPassthroughArgs(args)) + ); +} diff --git a/packages/cloudflare/src/cli/commands/utils.ts b/packages/cloudflare/src/cli/commands/utils.ts new file mode 100644 index 00000000..ae6afb4d --- /dev/null +++ b/packages/cloudflare/src/cli/commands/utils.ts @@ -0,0 +1,142 @@ +import { existsSync } from "node:fs"; +import { createRequire } from "node:module"; +import path from "node:path"; + +import { compileOpenNextConfig } from "@opennextjs/aws/build/compileConfig.js"; +import { normalizeOptions } from "@opennextjs/aws/build/helper.js"; +import { printHeader, showWarningOnWindows } from "@opennextjs/aws/build/utils.js"; +import logger from "@opennextjs/aws/logger.js"; +import { unstable_readConfig } from "wrangler"; +import type yargs from "yargs"; + +import type { OpenNextConfig } from "../../api/config.js"; +import { createOpenNextConfigIfNotExistent, ensureCloudflareConfig } from "../build/utils/index.js"; + +export type WithWranglerArgs = T & { + // Array of arguments that can be given to wrangler commands, including the `--config` and `--env` args. + wranglerArgs: string[]; + configPath: string | undefined; + env: string | undefined; +}; + +export const nextAppDir = process.cwd(); + +/** + * Print headers and warnings for the CLI. + * + * @param command + */ +export function printHeaders(command: string) { + printHeader(`Cloudflare ${command}`); + + showWarningOnWindows(); +} + +/** + * Compile the OpenNext config, and ensure it is for Cloudflare. + * + * @returns OpenNext config. + */ +export async function compileConfig() { + await createOpenNextConfigIfNotExistent(nextAppDir); + + const { config, buildDir } = await compileOpenNextConfig(nextAppDir, undefined, { compileEdge: true }); + ensureCloudflareConfig(config); + + return { config, buildDir }; +} + +/** + * Retrieve a compiled OpenNext config, and ensure it is for Cloudflare. + * + * @returns OpenNext config. + */ +export async function retrieveCompiledConfig() { + const configPath = path.join(nextAppDir, ".open-next/.build/open-next.config.edge.mjs"); + + if (!existsSync(configPath)) { + logger.error("Could not find compiled Open Next config, did you run the build command?"); + process.exit(1); + } + + const config = await import(configPath).then((mod) => mod.default); + ensureCloudflareConfig(config); + + return { config }; +} + +/** + * Normalize the OpenNext options and set the logging level. + * + * @param config + * @param buildDir Directory to use when building the application + * @returns Normalized options. + */ +export function getNormalizedOptions(config: OpenNextConfig, buildDir = nextAppDir) { + const require = createRequire(import.meta.url); + const openNextDistDir = path.dirname(require.resolve("@opennextjs/aws/index.js")); + + const options = normalizeOptions(config, openNextDistDir, buildDir); + logger.setLevel(options.debug ? "debug" : "info"); + + return options; +} + +/** + * Read the Wrangler config. + * + * @param args Wrangler environment and config path. + * @returns Wrangler config. + */ +export function readWranglerConfig(args: WithWranglerArgs) { + return unstable_readConfig({ env: args.env, config: args.configPath }); +} + +/** + * Adds flags for the wrangler config path and environment to the yargs configuration. + */ +export function withWranglerOptions(args: T) { + return args + .options("configPath", { + type: "string", + alias: ["config", "c"], + desc: "Path to Wrangler configuration file", + }) + .options("env", { + type: "string", + alias: "e", + desc: "Wrangler environment to use for operations", + }); +} + +/** + * + * @param args + * @returns An array of arguments that can be given to wrangler commands, including the `--config` and `--env` args. + */ +function getWranglerArgs(args: { + _: (string | number)[]; + configPath: string | undefined; + env: string | undefined; +}): string[] { + return [ + ...(args.configPath ? ["--config", args.configPath] : []), + ...(args.env ? ["--env", args.env] : []), + // Note: the first args in `_` will be the commands. + ...args._.slice(args._[0] === "populateCache" ? 2 : 1).map((a) => `${a}`), + ]; +} + +/** + * + * @param args + * @returns The inputted args, and an array of arguments that can be given to wrangler commands, including the `--config` and `--env` args. + */ +export function withWranglerPassthroughArgs< + T extends yargs.ArgumentsCamelCase<{ + configPath: string | undefined; + env: string | undefined; + }>, +>(args: T) { + return { ...args, wranglerArgs: getWranglerArgs(args) }; +} diff --git a/packages/cloudflare/src/cli/index.ts b/packages/cloudflare/src/cli/index.ts index d3139faf..6f982c67 100644 --- a/packages/cloudflare/src/cli/index.ts +++ b/packages/cloudflare/src/cli/index.ts @@ -1,63 +1,25 @@ #!/usr/bin/env node -import { createRequire } from "node:module"; -import path from "node:path"; -import { compileOpenNextConfig } from "@opennextjs/aws/build/compileConfig.js"; -import { normalizeOptions } from "@opennextjs/aws/build/helper.js"; -import { printHeader, showWarningOnWindows } from "@opennextjs/aws/build/utils.js"; -import logger from "@opennextjs/aws/logger.js"; -import { unstable_readConfig } from "wrangler"; +import yargs from "yargs"; -import { Arguments, getArgs } from "./args.js"; -import { build } from "./build/build.js"; -import { createOpenNextConfigIfNotExistent, ensureCloudflareConfig } from "./build/utils/index.js"; -import { deploy } from "./commands/deploy.js"; -import { populateCache } from "./commands/populate-cache.js"; -import { preview } from "./commands/preview.js"; -import { upload } from "./commands/upload.js"; -import { getWranglerConfigFlag, getWranglerEnvironmentFlag } from "./utils/run-wrangler.js"; +import { addBuildCommand } from "./commands/build.js"; +import { addDeployCommand } from "./commands/deploy.js"; +import { addPopulateCacheCommand } from "./commands/populate-cache.js"; +import { addPreviewCommand } from "./commands/preview.js"; +import { addUploadCommand } from "./commands/upload.js"; -const nextAppDir = process.cwd(); +export function runCommand() { + const y = yargs(process.argv.slice(2).filter((arg) => arg !== "--")) + .scriptName("opennextjs-cloudflare") + .parserConfiguration({ "unknown-options-as-args": true }); -async function runCommand(args: Arguments) { - printHeader(`Cloudflare ${args.command}`); + addBuildCommand(y); + addPreviewCommand(y); + addDeployCommand(y); + addUploadCommand(y); + addPopulateCacheCommand(y); - showWarningOnWindows(); - - const baseDir = nextAppDir; - const require = createRequire(import.meta.url); - const openNextDistDir = path.dirname(require.resolve("@opennextjs/aws/index.js")); - - // TODO: retrieve the compiled version if command != build - await createOpenNextConfigIfNotExistent(baseDir); - const { config, buildDir } = await compileOpenNextConfig(baseDir, undefined, { - compileEdge: true, - }); - - ensureCloudflareConfig(config); - - // Initialize options - const options = normalizeOptions(config, openNextDistDir, buildDir); - logger.setLevel(options.debug ? "debug" : "info"); - - switch (args.command) { - case "build": { - const argv = process.argv.slice(2); - const wranglerEnv = getWranglerEnvironmentFlag(argv); - const wranglerConfigFile = getWranglerConfigFlag(argv); - const wranglerConfig = unstable_readConfig({ env: wranglerEnv, config: wranglerConfigFile }); - - return build(options, config, { ...args, sourceDir: baseDir }, wranglerConfig); - } - case "preview": - return preview(options, config, args); - case "deploy": - return deploy(options, config, args); - case "upload": - return upload(options, config, args); - case "populateCache": - return populateCache(options, config, args); - } + return y.demandCommand(1, 1).parse(); } -await runCommand(getArgs()); +await runCommand(); diff --git a/packages/cloudflare/src/cli/templates/images.ts b/packages/cloudflare/src/cli/templates/images.ts index 76a0ffd4..777dfa49 100644 --- a/packages/cloudflare/src/cli/templates/images.ts +++ b/packages/cloudflare/src/cli/templates/images.ts @@ -218,7 +218,6 @@ export function detectContentType(buffer: Uint8Array) { } } -/* eslint-disable no-var */ declare global { var __IMAGES_REMOTE_PATTERNS__: RemotePattern[]; var __IMAGES_LOCAL_PATTERNS__: LocalPattern[]; @@ -226,4 +225,3 @@ declare global { var __IMAGES_CONTENT_SECURITY_POLICY__: string; var __IMAGES_CONTENT_DISPOSITION__: string; } -/* eslint-enable no-var */ diff --git a/packages/cloudflare/src/cli/templates/init.ts b/packages/cloudflare/src/cli/templates/init.ts index 832e74c2..49ac9fff 100644 --- a/packages/cloudflare/src/cli/templates/init.ts +++ b/packages/cloudflare/src/cli/templates/init.ts @@ -146,7 +146,6 @@ function populateProcessEnv(url: URL, env: CloudflareEnv) { } } -/* eslint-disable no-var */ declare global { // Build timestamp var __BUILD_TIMESTAMP_MS__: number; @@ -157,4 +156,3 @@ declare global { // Deployment ID var __DEPLOYMENT_ID__: string; } -/* eslint-enable no-var */ diff --git a/packages/cloudflare/src/cli/templates/skew-protection.ts b/packages/cloudflare/src/cli/templates/skew-protection.ts index ed231d86..b432d52d 100644 --- a/packages/cloudflare/src/cli/templates/skew-protection.ts +++ b/packages/cloudflare/src/cli/templates/skew-protection.ts @@ -66,9 +66,7 @@ export function maybeGetSkewProtectionResponse(request: Request): Promise { - test("long", () => { - expect(getFlagValue(["--flag", "value"], "--flag", "-f")).toEqual("value"); - expect(getFlagValue(["--flag=value"], "--flag", "-f")).toEqual("value"); - }); - - test("short", () => { - expect(getFlagValue(["-f", "value"], "--flag", "-f")).toEqual("value"); - expect(getFlagValue(["-f=value"], "--flag", "-f")).toEqual("value"); - }); - - test("not found", () => { - expect(getFlagValue(["--some", "value"], "--other", "-o")).toBeUndefined(); - expect(getFlagValue(["--some=value"], "--other", "-o")).toBeUndefined(); - }); -}); - -describe("getWranglerEnvironmentFlag", () => { - test("long", () => { - expect(getWranglerEnvironmentFlag(["--env", "value"])).toEqual("value"); - expect(getWranglerEnvironmentFlag(["--env=value"])).toEqual("value"); - }); - - test("short", () => { - expect(getWranglerEnvironmentFlag(["-e", "value"])).toEqual("value"); - expect(getWranglerEnvironmentFlag(["-e=value"])).toEqual("value"); - }); - - test("not found", () => { - expect(getWranglerEnvironmentFlag(["--some", "value"])).toBeUndefined(); - expect(getWranglerEnvironmentFlag(["--some=value"])).toBeUndefined(); - }); -}); - -describe("getWranglerConfigFlag", () => { - test("long", () => { - expect(getWranglerConfigFlag(["--config", "path/to/wrangler.jsonc"])).toEqual("path/to/wrangler.jsonc"); - expect(getWranglerConfigFlag(["--config=path/to/wrangler.jsonc"])).toEqual("path/to/wrangler.jsonc"); - }); - - test("short", () => { - expect(getWranglerConfigFlag(["-c", "path/to/wrangler.jsonc"])).toEqual("path/to/wrangler.jsonc"); - expect(getWranglerConfigFlag(["-c=path/to/wrangler.jsonc"])).toEqual("path/to/wrangler.jsonc"); - }); - - test("not found", () => { - expect(getWranglerConfigFlag(["--some", "value"])).toBeUndefined(); - expect(getWranglerConfigFlag(["--some=value"])).toBeUndefined(); - }); -}); diff --git a/packages/cloudflare/src/cli/utils/run-wrangler.ts b/packages/cloudflare/src/cli/utils/run-wrangler.ts index 2ecb3cfb..f7dd5eb0 100644 --- a/packages/cloudflare/src/cli/utils/run-wrangler.ts +++ b/packages/cloudflare/src/cli/utils/run-wrangler.ts @@ -93,54 +93,3 @@ export function runWrangler(options: BuildOptions, args: string[], wranglerOpts: export function isWranglerTarget(v: string | undefined): v is WranglerTarget { return !!v && ["local", "remote"].includes(v); } - -/** - * Returns the value of the flag. - * - * The value is retrieved for ` value` or `=value`. - * - * @param args List of args - * @param argName The arg name with leading dashes, i.e. `--env` or `-e` - * @returns The value or undefined when not found - */ -export function getFlagValue(args: string[], ...argNames: string[]): string | undefined { - if (argNames.some((name) => !name.startsWith("-"))) { - // Names should start with "-" or "--" - throw new Error(`Invalid arg names: ${argNames}`); - } - - for (const argName of argNames) { - for (let i = 0; i <= args.length; i++) { - const arg = args[i]; - if (!arg) continue; - - if (arg === argName) { - return args[i + 1]; - } - - if (arg.startsWith(argName)) { - return arg.split("=")[1]; - } - } - } -} - -/** - * Find the value of the environment flag (`--env` / `-e`) used by Wrangler. - * - * @param args - CLI arguments. - * @returns Value of the environment flag or undefined when not found - */ -export function getWranglerEnvironmentFlag(args: string[]): string | undefined { - return getFlagValue(args, "--env", "-e"); -} - -/** - * Find the value of the config flag (`--config` / `-c`) used by Wrangler. - * - * @param args - CLI arguments. - * @returns Value of the config flag or undefined when not found - */ -export function getWranglerConfigFlag(args: string[]): string | undefined { - return getFlagValue(args, "--config", "-c"); -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4718c6c1..2e92abef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,12 +33,15 @@ catalogs: '@types/react-dom': specifier: ^18 version: 18.3.0 + '@types/yargs': + specifier: ^17.0.33 + version: 17.0.33 esbuild: specifier: ^0.25.4 version: 0.25.4 eslint: - specifier: ^9.11.1 - version: 9.11.1 + specifier: ^9.31.0 + version: 9.31.0 eslint-plugin-import: specifier: ^2.31.0 version: 2.31.0 @@ -76,14 +79,17 @@ catalogs: specifier: ^5.7.3 version: 5.7.3 typescript-eslint: - specifier: ^8.7.0 - version: 8.7.0 + specifier: ^8.37.0 + version: 8.37.0 vitest: specifier: ^2.1.1 version: 2.1.1 wrangler: specifier: ^4.24.4 version: 4.24.4 + yargs: + specifier: ^18.0.0 + version: 18.0.0 e2e: '@types/node': specifier: 20.17.6 @@ -645,7 +651,7 @@ importers: version: 18.3.0 eslint: specifier: 'catalog:' - version: 9.11.1(jiti@1.21.6) + version: 9.31.0(jiti@1.21.6) typescript: specifier: 'catalog:' version: 5.7.3 @@ -1052,6 +1058,9 @@ importers: wrangler: specifier: 'catalog:' version: 4.24.4(@cloudflare/workers-types@4.20250224.0) + yargs: + specifier: 'catalog:' + version: 18.0.0 devDependencies: '@cloudflare/workers-types': specifier: 'catalog:' @@ -1071,6 +1080,9 @@ importers: '@types/picomatch': specifier: ^4.0.0 version: 4.0.0 + '@types/yargs': + specifier: 'catalog:' + version: 17.0.33 diff: specifier: ^8.0.2 version: 8.0.2 @@ -1079,16 +1091,16 @@ importers: version: 0.25.4 eslint: specifier: 'catalog:' - version: 9.11.1(jiti@1.21.6) + version: 9.31.0(jiti@1.21.6) eslint-plugin-import: specifier: 'catalog:' - version: 2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.11.1(jiti@1.21.6)) + version: 2.31.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.31.0(jiti@1.21.6)) eslint-plugin-simple-import-sort: specifier: 'catalog:' - version: 12.1.1(eslint@9.11.1(jiti@1.21.6)) + version: 12.1.1(eslint@9.31.0(jiti@1.21.6)) eslint-plugin-unicorn: specifier: 'catalog:' - version: 55.0.0(eslint@9.11.1(jiti@1.21.6)) + version: 55.0.0(eslint@9.31.0(jiti@1.21.6)) globals: specifier: 'catalog:' version: 15.9.0 @@ -1109,7 +1121,7 @@ importers: version: 5.7.3 typescript-eslint: specifier: 'catalog:' - version: 8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3) + version: 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3) vitest: specifier: 'catalog:' version: 2.1.1(@edge-runtime/vm@3.2.0)(@types/node@22.2.0)(terser@5.16.9) @@ -2541,6 +2553,14 @@ packages: resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-array@0.21.0': + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.3.0': + resolution: {integrity: sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@0.10.0': resolution: {integrity: sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2549,6 +2569,10 @@ packages: resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@0.15.1': + resolution: {integrity: sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@0.6.0': resolution: {integrity: sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2581,6 +2605,10 @@ packages: resolution: {integrity: sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@9.31.0': + resolution: {integrity: sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/object-schema@2.1.6': resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2593,6 +2621,10 @@ packages: resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/plugin-kit@0.3.3': + resolution: {integrity: sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} @@ -2882,6 +2914,10 @@ packages: resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} engines: {node: '>=18.18'} + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -4810,6 +4846,20 @@ packages: '@types/ws@8.5.14': resolution: {integrity: sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==} + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + + '@typescript-eslint/eslint-plugin@8.37.0': + resolution: {integrity: sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.37.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/eslint-plugin@8.7.0': resolution: {integrity: sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4821,6 +4871,13 @@ packages: typescript: optional: true + '@typescript-eslint/parser@8.37.0': + resolution: {integrity: sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/parser@8.7.0': resolution: {integrity: sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4831,10 +4888,33 @@ packages: typescript: optional: true + '@typescript-eslint/project-service@8.37.0': + resolution: {integrity: sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/scope-manager@8.37.0': + resolution: {integrity: sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.7.0': resolution: {integrity: sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.37.0': + resolution: {integrity: sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/type-utils@8.37.0': + resolution: {integrity: sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/type-utils@8.7.0': resolution: {integrity: sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4844,10 +4924,20 @@ packages: typescript: optional: true + '@typescript-eslint/types@8.37.0': + resolution: {integrity: sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.7.0': resolution: {integrity: sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.37.0': + resolution: {integrity: sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/typescript-estree@8.7.0': resolution: {integrity: sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4857,12 +4947,23 @@ packages: typescript: optional: true + '@typescript-eslint/utils@8.37.0': + resolution: {integrity: sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + '@typescript-eslint/utils@8.7.0': resolution: {integrity: sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/visitor-keys@8.37.0': + resolution: {integrity: sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.7.0': resolution: {integrity: sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5002,6 +5103,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -5377,6 +5483,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + cloudflare@4.4.1: resolution: {integrity: sha512-wrtQ9WMflnfRcmdQZf/XfVVkeucgwzzYeqFDfgbNdADTaexsPwrtt3etzUvPGvVUeEk9kOPfNkl8MSzObxrIsg==} @@ -6222,6 +6332,10 @@ packages: resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -6230,6 +6344,10 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@8.57.1: resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -6256,6 +6374,16 @@ packages: jiti: optional: true + eslint@9.31.0: + resolution: {integrity: sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + esm@3.2.25: resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} engines: {node: '>=6'} @@ -6268,6 +6396,10 @@ packages: resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -6448,9 +6580,6 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} @@ -6786,6 +6915,10 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -9076,6 +9209,12 @@ packages: peerDependencies: typescript: '>=4.2.0' + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -9166,14 +9305,12 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typescript-eslint@8.7.0: - resolution: {integrity: sha512-nEHbEYJyHwsuf7c3V3RS7Saq+1+la3i0ieR3qP0yjqWSzVmh8Drp47uOl9LjbPANac4S7EFSqvcYIKXUUwIfIQ==} + typescript-eslint@8.37.0: + resolution: {integrity: sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' typescript@4.9.5: resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} @@ -9487,6 +9624,10 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -9537,10 +9678,18 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yauzl-clone@1.0.4: resolution: {integrity: sha512-igM2RRCf3k8TvZoxR2oguuw4z1xasOnA31joCqHIyLkeWrvAc2Jgay5ISQ2ZplinkoGaJ6orCz56Ey456c5ESA==} engines: {node: '>=6'} @@ -11670,6 +11819,11 @@ snapshots: eslint: 9.19.0(jiti@1.21.6) eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.7.0(eslint@9.31.0(jiti@1.21.6))': + dependencies: + eslint: 9.31.0(jiti@1.21.6) + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.11.0': {} '@eslint-community/regexpp@4.12.1': {} @@ -11690,6 +11844,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/config-array@0.21.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.3.0': {} + '@eslint/core@0.10.0': dependencies: '@types/json-schema': 7.0.15 @@ -11698,6 +11862,10 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 + '@eslint/core@0.15.1': + dependencies: + '@types/json-schema': 7.0.15 + '@eslint/core@0.6.0': {} '@eslint/eslintrc@2.1.4': @@ -11746,7 +11914,7 @@ snapshots: dependencies: ajv: 6.12.6 debug: 4.4.0 - espree: 10.3.0 + espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 @@ -11762,6 +11930,8 @@ snapshots: '@eslint/js@9.19.0': {} + '@eslint/js@9.31.0': {} + '@eslint/object-schema@2.1.6': {} '@eslint/plugin-kit@0.2.5': @@ -11774,6 +11944,11 @@ snapshots: '@eslint/core': 0.13.0 levn: 0.4.1 + '@eslint/plugin-kit@0.3.3': + dependencies: + '@eslint/core': 0.15.1 + levn: 0.4.1 + '@fastify/busboy@2.1.1': {} '@fastify/busboy@3.1.1': {} @@ -12190,6 +12365,8 @@ snapshots: '@humanwhocodes/retry@0.4.1': {} + '@humanwhocodes/retry@0.4.3': {} + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.4 @@ -14335,6 +14512,29 @@ snapshots: dependencies: '@types/node': 20.14.10 + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@typescript-eslint/eslint-plugin@8.37.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.37.0 + '@typescript-eslint/type-utils': 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3) + '@typescript-eslint/utils': 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.37.0 + eslint: 9.31.0(jiti@1.21.6) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -14389,6 +14589,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.37.0 + '@typescript-eslint/types': 8.37.0 + '@typescript-eslint/typescript-estree': 8.37.0(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.37.0 + debug: 4.4.0 + eslint: 9.31.0(jiti@1.21.6) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3)': dependencies: '@typescript-eslint/scope-manager': 8.7.0 @@ -14428,11 +14640,41 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.37.0(typescript@5.7.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.37.0(typescript@5.7.3) + '@typescript-eslint/types': 8.37.0 + debug: 4.4.0 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.37.0': + dependencies: + '@typescript-eslint/types': 8.37.0 + '@typescript-eslint/visitor-keys': 8.37.0 + '@typescript-eslint/scope-manager@8.7.0': dependencies: '@typescript-eslint/types': 8.7.0 '@typescript-eslint/visitor-keys': 8.7.0 + '@typescript-eslint/tsconfig-utils@8.37.0(typescript@5.7.3)': + dependencies: + typescript: 5.7.3 + + '@typescript-eslint/type-utils@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3)': + dependencies: + '@typescript-eslint/types': 8.37.0 + '@typescript-eslint/typescript-estree': 8.37.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3) + debug: 4.4.0 + eslint: 9.31.0(jiti@1.21.6) + ts-api-utils: 2.1.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/type-utils@8.7.0(eslint@8.57.1)(typescript@5.7.3)': dependencies: '@typescript-eslint/typescript-estree': 8.7.0(typescript@5.7.3) @@ -14469,8 +14711,26 @@ snapshots: - eslint - supports-color + '@typescript-eslint/types@8.37.0': {} + '@typescript-eslint/types@8.7.0': {} + '@typescript-eslint/typescript-estree@8.37.0(typescript@5.7.3)': + dependencies: + '@typescript-eslint/project-service': 8.37.0(typescript@5.7.3) + '@typescript-eslint/tsconfig-utils': 8.37.0(typescript@5.7.3) + '@typescript-eslint/types': 8.37.0 + '@typescript-eslint/visitor-keys': 8.37.0 + debug: 4.4.0 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.1 + ts-api-utils: 2.1.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/typescript-estree@8.7.0(typescript@5.7.3)': dependencies: '@typescript-eslint/types': 8.7.0 @@ -14486,6 +14746,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3)': + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@1.21.6)) + '@typescript-eslint/scope-manager': 8.37.0 + '@typescript-eslint/types': 8.37.0 + '@typescript-eslint/typescript-estree': 8.37.0(typescript@5.7.3) + eslint: 9.31.0(jiti@1.21.6) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.7.0(eslint@8.57.1)(typescript@5.7.3)': dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) @@ -14519,6 +14790,11 @@ snapshots: - supports-color - typescript + '@typescript-eslint/visitor-keys@8.37.0': + dependencies: + '@typescript-eslint/types': 8.37.0 + eslint-visitor-keys: 4.2.1 + '@typescript-eslint/visitor-keys@8.7.0': dependencies: '@typescript-eslint/types': 8.7.0 @@ -14751,6 +15027,10 @@ snapshots: dependencies: acorn: 8.14.1 + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-walk@8.3.2: {} acorn-walk@8.3.3: @@ -14763,6 +15043,8 @@ snapshots: acorn@8.14.1: {} + acorn@8.15.0: {} + agent-base@6.0.2: dependencies: debug: 4.4.0 @@ -15159,6 +15441,12 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + cloudflare@4.4.1: dependencies: '@types/node': 18.19.112 @@ -16084,6 +16372,16 @@ snapshots: transitivePeerDependencies: - supports-color + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.31.0(jiti@1.21.6)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3) + eslint: 9.31.0(jiti@1.21.6) + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: debug: 3.2.7 @@ -16145,6 +16443,35 @@ snapshots: - eslint-import-resolver-webpack - supports-color + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.31.0(jiti@1.21.6)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.31.0(jiti@1.21.6) + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.31.0(jiti@1.21.6)) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 @@ -16374,18 +16701,18 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-simple-import-sort@12.1.1(eslint@9.11.1(jiti@1.21.6)): + eslint-plugin-simple-import-sort@12.1.1(eslint@9.31.0(jiti@1.21.6)): dependencies: - eslint: 9.11.1(jiti@1.21.6) + eslint: 9.31.0(jiti@1.21.6) - eslint-plugin-unicorn@55.0.0(eslint@9.11.1(jiti@1.21.6)): + eslint-plugin-unicorn@55.0.0(eslint@9.31.0(jiti@1.21.6)): dependencies: '@babel/helper-validator-identifier': 7.27.1 - '@eslint-community/eslint-utils': 4.7.0(eslint@9.11.1(jiti@1.21.6)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@1.21.6)) ci-info: 4.2.0 clean-regexp: 1.0.0 core-js-compat: 3.42.0 - eslint: 9.11.1(jiti@1.21.6) + eslint: 9.31.0(jiti@1.21.6) esquery: 1.6.0 globals: 15.9.0 indent-string: 4.0.0 @@ -16413,10 +16740,17 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + eslint-visitor-keys@3.4.3: {} eslint-visitor-keys@4.2.0: {} + eslint-visitor-keys@4.2.1: {} + eslint@8.57.1: dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) @@ -16545,6 +16879,48 @@ snapshots: transitivePeerDependencies: - supports-color + eslint@9.31.0(jiti@1.21.6): + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@1.21.6)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.3.0 + '@eslint/core': 0.15.1 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.31.0 + '@eslint/plugin-kit': 0.3.3 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.7 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 1.21.6 + transitivePeerDependencies: + - supports-color + esm@3.2.25: optional: true @@ -16560,6 +16936,12 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.14.1) eslint-visitor-keys: 4.2.0 + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + espree@9.6.1: dependencies: acorn: 8.12.1 @@ -16826,7 +17208,7 @@ snapshots: flat-cache@3.2.0: dependencies: - flatted: 3.3.1 + flatted: 3.3.3 keyv: 4.5.4 rimraf: 3.0.2 @@ -16835,8 +17217,6 @@ snapshots: flatted: 3.3.3 keyv: 4.5.4 - flatted@3.3.1: {} - flatted@3.3.3: {} for-each@0.3.5: @@ -17256,6 +17636,8 @@ snapshots: ignore@5.3.2: {} + ignore@7.0.5: {} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -19999,6 +20381,10 @@ snapshots: dependencies: typescript: 5.7.3 + ts-api-utils@2.1.0(typescript@5.7.3): + dependencies: + typescript: 5.7.3 + ts-interface-checker@0.1.13: {} ts-morph@12.0.0: @@ -20181,15 +20567,15 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3): + typescript-eslint@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.7.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3) - '@typescript-eslint/parser': 8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3) - '@typescript-eslint/utils': 8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3) - optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.37.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3) + '@typescript-eslint/parser': 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3) + '@typescript-eslint/typescript-estree': 8.37.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.7.3) + eslint: 9.31.0(jiti@1.21.6) typescript: 5.7.3 transitivePeerDependencies: - - eslint - supports-color typescript@4.9.5: {} @@ -20568,6 +20954,12 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + wrappy@1.0.2: {} ws@8.18.0: {} @@ -20595,6 +20987,8 @@ snapshots: yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -20605,6 +20999,15 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + yauzl-clone@1.0.4: dependencies: events-intercept: 2.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5d29848b..786ed532 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -17,11 +17,12 @@ catalog: "@types/node": ^22.2.0 "@types/react-dom": ^18 "@types/react": ^18 + "@types/yargs": ^17.0.33 esbuild: ^0.25.4 eslint-plugin-import: ^2.31.0 eslint-plugin-simple-import-sort: ^12.1.1 eslint-plugin-unicorn: ^55.0.0 - eslint: ^9.11.1 + eslint: ^9.31.0 glob: ^11.0.0 globals: ^15.9.0 mock-fs: ^5.4.1 @@ -31,10 +32,11 @@ catalog: react: ^18 rimraf: ^6.0.1 tsx: ^4.19.2 - typescript-eslint: ^8.7.0 + typescript-eslint: ^8.37.0 typescript: ^5.7.3 vitest: ^2.1.1 wrangler: ^4.24.4 + yargs: ^18.0.0 # e2e tests catalogs: