From 7a03341301d9d56ae93b4e4e3bd1ca469444f886 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 3 Feb 2025 01:49:52 +0000 Subject: [PATCH] fix: watch mode tweaks --- .changeset/gentle-deers-sit.md | 5 + .changeset/happy-eels-kick.md | 5 + docs/openapi-ts/configuration.md | 2 +- packages/openapi-ts/package.json | 2 +- packages/openapi-ts/src/createClient.ts | 101 +++ .../src/generate/__tests__/class.test.ts | 3 +- .../src/generate/__tests__/core.test.ts | 9 +- .../src/generate/__tests__/index.test.ts | 3 +- .../src/generate/__tests__/output.test.ts | 3 +- packages/openapi-ts/src/getLogs.ts | 17 + packages/openapi-ts/src/getSpec.ts | 150 ++++ packages/openapi-ts/src/index.ts | 653 +----------------- packages/openapi-ts/src/initConfigs.ts | 325 +++++++++ .../schemas/__tests__/schemas.test.ts | 6 +- .../@hey-api/sdk/__tests__/plugin.test.ts | 12 +- .../typescript/__tests__/plugin.test.ts | 3 +- packages/openapi-ts/src/processOutput.ts | 66 ++ .../src/types/{client.ts => client.d.ts} | 0 .../src/types/{config.ts => config.d.ts} | 13 +- packages/openapi-ts/src/types/types.d.ts | 18 + .../src/types/{utils.ts => utils.d.ts} | 0 .../src/utils/__tests__/handlebars.test.ts | 6 +- .../src/utils/__tests__/parse.test.ts | 3 +- packages/openapi-ts/test/openapi-ts.config.ts | 12 +- pnpm-lock.yaml | 388 +++++++++-- 25 files changed, 1099 insertions(+), 706 deletions(-) create mode 100644 .changeset/gentle-deers-sit.md create mode 100644 .changeset/happy-eels-kick.md create mode 100644 packages/openapi-ts/src/createClient.ts create mode 100644 packages/openapi-ts/src/getLogs.ts create mode 100644 packages/openapi-ts/src/getSpec.ts create mode 100644 packages/openapi-ts/src/initConfigs.ts create mode 100644 packages/openapi-ts/src/processOutput.ts rename packages/openapi-ts/src/types/{client.ts => client.d.ts} (100%) rename packages/openapi-ts/src/types/{config.ts => config.d.ts} (95%) rename packages/openapi-ts/src/types/{utils.ts => utils.d.ts} (100%) diff --git a/.changeset/gentle-deers-sit.md b/.changeset/gentle-deers-sit.md new file mode 100644 index 000000000..4c24dbc61 --- /dev/null +++ b/.changeset/gentle-deers-sit.md @@ -0,0 +1,5 @@ +--- +'@hey-api/openapi-ts': patch +--- + +fix: watch mode handles servers not exposing HEAD method for spec diff --git a/.changeset/happy-eels-kick.md b/.changeset/happy-eels-kick.md new file mode 100644 index 000000000..017490ec1 --- /dev/null +++ b/.changeset/happy-eels-kick.md @@ -0,0 +1,5 @@ +--- +'@hey-api/openapi-ts': patch +--- + +fix: add watch.timeout option diff --git a/docs/openapi-ts/configuration.md b/docs/openapi-ts/configuration.md index 5bdc1dd87..6582ec8df 100644 --- a/docs/openapi-ts/configuration.md +++ b/docs/openapi-ts/configuration.md @@ -273,7 +273,7 @@ Setting `output.clean` to `false` may result in broken output. Ensure you typech ## Config API -You can view the complete list of options in the [UserConfig](https://github.com/hey-api/openapi-ts/blob/main/packages/openapi-ts/src/types/config.ts) interface. +You can view the complete list of options in the [UserConfig](https://github.com/hey-api/openapi-ts/blob/main/packages/openapi-ts/src/types/config.d.ts) interface. diff --git a/packages/openapi-ts/package.json b/packages/openapi-ts/package.json index a0cb5fc92..f0073835e 100644 --- a/packages/openapi-ts/package.json +++ b/packages/openapi-ts/package.json @@ -79,7 +79,7 @@ "node": "^18.18.0 || ^20.9.0 || >=22.11.0" }, "dependencies": { - "@hey-api/json-schema-ref-parser": "1.0.1", + "@hey-api/json-schema-ref-parser": "1.0.2", "c12": "2.0.1", "commander": "13.0.0", "handlebars": "4.7.8" diff --git a/packages/openapi-ts/src/createClient.ts b/packages/openapi-ts/src/createClient.ts new file mode 100644 index 000000000..a41f7b41e --- /dev/null +++ b/packages/openapi-ts/src/createClient.ts @@ -0,0 +1,101 @@ +import path from 'node:path'; + +import { generateLegacyOutput, generateOutput } from './generate/output'; +import { getSpec } from './getSpec'; +import type { IR } from './ir/types'; +import { parseLegacy, parseOpenApiSpec } from './openApi'; +import { processOutput } from './processOutput'; +import type { Client } from './types/client'; +import type { Config } from './types/config'; +import type { WatchValues } from './types/types'; +import { isLegacyClient, legacyNameFromConfig } from './utils/config'; +import type { Templates } from './utils/handlebars'; +import { Performance } from './utils/performance'; +import { postProcessClient } from './utils/postprocess'; + +export const createClient = async ({ + config, + templates, + watch: _watch, +}: { + config: Config; + templates: Templates; + watch?: WatchValues; +}) => { + const inputPath = config.input.path; + const timeout = config.watch.timeout; + + const watch: WatchValues = _watch || { headers: new Headers() }; + + Performance.start('spec'); + const { data, error, response } = await getSpec({ + inputPath, + timeout, + watch, + }); + Performance.end('spec'); + + // throw on first run if there's an error to preserve user experience + // if in watch mode, subsequent errors won't throw to gracefully handle + // cases where server might be reloading + if (error && !_watch) { + throw new Error( + `Request failed with status ${response.status}: ${response.statusText}`, + ); + } + + let client: Client | undefined; + let context: IR.Context | undefined; + + if (data) { + if (_watch) { + console.clear(); + console.log(`⏳ Input changed, generating from ${inputPath}`); + } else { + console.log(`⏳ Generating from ${inputPath}`); + } + + Performance.start('parser'); + if ( + config.experimentalParser && + !isLegacyClient(config) && + !legacyNameFromConfig(config) + ) { + context = parseOpenApiSpec({ config, spec: data }); + } + + // fallback to legacy parser + if (!context) { + const parsed = parseLegacy({ openApi: data }); + client = postProcessClient(parsed, config); + } + Performance.end('parser'); + + Performance.start('generator'); + if (context) { + await generateOutput({ context }); + } else if (client) { + await generateLegacyOutput({ client, openApi: data, templates }); + } + Performance.end('generator'); + + Performance.start('postprocess'); + if (!config.dryRun) { + processOutput({ config }); + + const outputPath = process.env.INIT_CWD + ? `./${path.relative(process.env.INIT_CWD, config.output.path)}` + : config.output.path; + console.log(`🚀 Done! Your output is in ${outputPath}`); + } + Performance.end('postprocess'); + } + + if (config.watch.enabled && typeof inputPath === 'string') { + setTimeout(() => { + createClient({ config, templates, watch }); + }, config.watch.interval); + } + + return context || client; +}; diff --git a/packages/openapi-ts/src/generate/__tests__/class.test.ts b/packages/openapi-ts/src/generate/__tests__/class.test.ts index e58342462..53e51af27 100644 --- a/packages/openapi-ts/src/generate/__tests__/class.test.ts +++ b/packages/openapi-ts/src/generate/__tests__/class.test.ts @@ -60,7 +60,8 @@ describe('generateLegacyClientClass', () => { useOptions: true, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); diff --git a/packages/openapi-ts/src/generate/__tests__/core.test.ts b/packages/openapi-ts/src/generate/__tests__/core.test.ts index eaf494147..6f7a09f60 100644 --- a/packages/openapi-ts/src/generate/__tests__/core.test.ts +++ b/packages/openapi-ts/src/generate/__tests__/core.test.ts @@ -75,7 +75,8 @@ describe('generateLegacyCore', () => { useOptions: true, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); @@ -166,7 +167,8 @@ describe('generateLegacyCore', () => { useOptions: true, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); @@ -240,7 +242,8 @@ describe('generateLegacyCore', () => { useOptions: true, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); diff --git a/packages/openapi-ts/src/generate/__tests__/index.test.ts b/packages/openapi-ts/src/generate/__tests__/index.test.ts index 0509180f2..d2ec50db3 100644 --- a/packages/openapi-ts/src/generate/__tests__/index.test.ts +++ b/packages/openapi-ts/src/generate/__tests__/index.test.ts @@ -59,7 +59,8 @@ describe('generateIndexFile', () => { useOptions: true, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); diff --git a/packages/openapi-ts/src/generate/__tests__/output.test.ts b/packages/openapi-ts/src/generate/__tests__/output.test.ts index f2809ed5f..151d42a56 100644 --- a/packages/openapi-ts/src/generate/__tests__/output.test.ts +++ b/packages/openapi-ts/src/generate/__tests__/output.test.ts @@ -61,7 +61,8 @@ describe('generateLegacyOutput', () => { useOptions: false, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); diff --git a/packages/openapi-ts/src/getLogs.ts b/packages/openapi-ts/src/getLogs.ts new file mode 100644 index 000000000..9465b5065 --- /dev/null +++ b/packages/openapi-ts/src/getLogs.ts @@ -0,0 +1,17 @@ +import type { Config, UserConfig } from './types/config'; + +export const getLogs = (userConfig: UserConfig): Config['logs'] => { + let logs: Config['logs'] = { + level: 'info', + path: process.cwd(), + }; + if (typeof userConfig.logs === 'string') { + logs.path = userConfig.logs; + } else { + logs = { + ...logs, + ...userConfig.logs, + }; + } + return logs; +}; diff --git a/packages/openapi-ts/src/getSpec.ts b/packages/openapi-ts/src/getSpec.ts new file mode 100644 index 000000000..f7fbe6593 --- /dev/null +++ b/packages/openapi-ts/src/getSpec.ts @@ -0,0 +1,150 @@ +import { + $RefParser, + getResolvedInput, + type JSONSchema, + sendRequest, +} from '@hey-api/json-schema-ref-parser'; + +import type { Config } from './types/config'; +import type { WatchValues } from './types/types'; + +interface SpecResponse { + data: JSONSchema; + error?: undefined; + response?: undefined; +} + +interface SpecError { + data?: undefined; + error: 'not-modified' | 'not-ok'; + response: Response; +} + +export const getSpec = async ({ + inputPath, + timeout, + watch, +}: { + inputPath: Config['input']['path']; + timeout: number; + watch: WatchValues; +}): Promise => { + const refParser = new $RefParser(); + const resolvedInput = getResolvedInput({ pathOrUrlOrSchema: inputPath }); + + let arrayBuffer: ArrayBuffer | undefined; + // boolean signals whether the file has **definitely** changed + let hasChanged: boolean | undefined; + let response: Response | undefined; + + // no support for watching files and objects for now + if (resolvedInput.type === 'url') { + // do NOT send HEAD request on first run or if unsupported + if (watch.lastValue && watch.isHeadMethodSupported !== false) { + const request = await sendRequest({ + init: { + headers: watch.headers, + method: 'HEAD', + }, + timeout, + url: resolvedInput.path, + }); + response = request.response; + + if (!response.ok && watch.isHeadMethodSupported) { + // assume the server is no longer running + // do nothing, it might be restarted later + return { + error: 'not-ok', + response, + }; + } + + if (watch.isHeadMethodSupported === undefined) { + watch.isHeadMethodSupported = response.ok; + } + + if (response.status === 304) { + return { + error: 'not-modified', + response, + }; + } + + if (hasChanged === undefined) { + const eTag = response.headers.get('ETag'); + if (eTag) { + hasChanged = eTag !== watch.headers.get('If-None-Match'); + + if (hasChanged) { + watch.headers.set('If-None-Match', eTag); + } + } + } + + if (hasChanged === undefined) { + const lastModified = response.headers.get('Last-Modified'); + if (lastModified) { + hasChanged = lastModified !== watch.headers.get('If-Modified-Since'); + + if (hasChanged) { + watch.headers.set('If-Modified-Since', lastModified); + } + } + } + + // we definitely know the input has not changed + if (hasChanged === false) { + return { + error: 'not-modified', + response, + }; + } + } + + const fileRequest = await sendRequest({ + init: { + method: 'GET', + }, + timeout, + url: resolvedInput.path, + }); + response = fileRequest.response; + + if (!response.ok) { + // assume the server is no longer running + // do nothing, it might be restarted later + return { + error: 'not-ok', + response, + }; + } + + arrayBuffer = response.body + ? await response.arrayBuffer() + : new ArrayBuffer(0); + + if (hasChanged === undefined) { + const content = new TextDecoder().decode(arrayBuffer); + hasChanged = content !== watch.lastValue; + watch.lastValue = content; + } + } + + if (hasChanged === false) { + return { + error: 'not-modified', + response: response!, + }; + } + + const data = await refParser.bundle({ + arrayBuffer, + pathOrUrlOrSchema: undefined, + resolvedInput, + }); + + return { + data, + }; +}; diff --git a/packages/openapi-ts/src/index.ts b/packages/openapi-ts/src/index.ts index 036abab44..21bd98fc3 100644 --- a/packages/openapi-ts/src/index.ts +++ b/packages/openapi-ts/src/index.ts @@ -1,564 +1,24 @@ import fs from 'node:fs'; import path from 'node:path'; -import { - $RefParser, - getResolvedInput, - type JSONSchema, - sendRequest, -} from '@hey-api/json-schema-ref-parser'; -import { loadConfig } from 'c12'; -import { sync } from 'cross-spawn'; - -import { generateLegacyOutput, generateOutput } from './generate/output'; +import { createClient as pCreateClient } from './createClient'; import { ensureDirSync } from './generate/utils'; +import { getLogs } from './getLogs'; +import { initConfigs } from './initConfigs'; import type { IR } from './ir/types'; -import { parseLegacy, parseOpenApiSpec } from './openApi'; -import type { ClientPlugins, UserPlugins } from './plugins'; -import { defaultPluginConfigs } from './plugins'; -import type { - AnyPluginName, - DefaultPluginConfigs, - PluginContext, - PluginNames, -} from './plugins/types'; import type { Client } from './types/client'; -import type { Config, Formatters, Linters, UserConfig } from './types/config'; -import { - isLegacyClient, - legacyNameFromConfig, - setConfig, -} from './utils/config'; +import type { Config, UserConfig } from './types/config'; import { registerHandlebarTemplates } from './utils/handlebars'; import { Performance, PerformanceReport } from './utils/performance'; -import { postProcessClient } from './utils/postprocess'; - -type OutputProcessor = { - args: (path: string) => ReadonlyArray; - command: string; - name: string; -}; /** - * Map of supported formatters + * Generate a client from the provided configuration. + * + * @param userConfig User provided {@link UserConfig} configuration. */ -const formatters: Record = { - biome: { - args: (path) => ['format', '--write', path], - command: 'biome', - name: 'Biome (Format)', - }, - prettier: { - args: (path) => [ - '--ignore-unknown', - path, - '--write', - '--ignore-path', - './.prettierignore', - ], - command: 'prettier', - name: 'Prettier', - }, -}; - -/** - * Map of supported linters - */ -const linters: Record = { - biome: { - args: (path) => ['lint', '--apply', path], - command: 'biome', - name: 'Biome (Lint)', - }, - eslint: { - args: (path) => [path, '--fix'], - command: 'eslint', - name: 'ESLint', - }, - oxlint: { - args: (path) => ['--fix', path], - command: 'oxlint', - name: 'oxlint', - }, -}; - -const processOutput = ({ config }: { config: Config }) => { - if (config.output.format) { - const module = formatters[config.output.format]; - console.log(`✨ Running ${module.name}`); - sync(module.command, module.args(config.output.path)); - } - - if (config.output.lint) { - const module = linters[config.output.lint]; - console.log(`✨ Running ${module.name}`); - sync(module.command, module.args(config.output.path)); - } -}; - -const getInput = (userConfig: UserConfig): Config['input'] => { - let input: Config['input'] = { - path: '', - }; - if (typeof userConfig.input === 'string') { - input.path = userConfig.input; - } else if (userConfig.input && userConfig.input.path) { - input = { - ...input, - ...userConfig.input, - }; - } else { - input = { - ...input, - path: userConfig.input, - }; - } - return input; -}; - -const getLogs = (userConfig: UserConfig): Config['logs'] => { - let logs: Config['logs'] = { - level: 'info', - path: process.cwd(), - }; - if (typeof userConfig.logs === 'string') { - logs.path = userConfig.logs; - } else { - logs = { - ...logs, - ...userConfig.logs, - }; - } - return logs; -}; - -const getOutput = (userConfig: UserConfig): Config['output'] => { - let output: Config['output'] = { - clean: true, - format: false, - indexFile: true, - lint: false, - path: '', - }; - if (typeof userConfig.output === 'string') { - output.path = userConfig.output; - } else { - output = { - ...output, - ...userConfig.output, - }; - } - return output; -}; - -const getPluginsConfig = ({ - pluginConfigs, - userPlugins, - userPluginsConfig, -}: { - pluginConfigs: DefaultPluginConfigs; - userPlugins: ReadonlyArray; - userPluginsConfig: Config['plugins']; -}): Pick => { - const circularReferenceTracker = new Set(); - const pluginOrder = new Set(); - const plugins: Config['plugins'] = {}; - - const dfs = (name: AnyPluginName) => { - if (circularReferenceTracker.has(name)) { - throw new Error(`Circular reference detected at '${name}'`); - } - - if (!pluginOrder.has(name)) { - circularReferenceTracker.add(name); - - const pluginConfig = pluginConfigs[name as PluginNames]; - if (!pluginConfig) { - throw new Error( - `🚫 unknown plugin dependency "${name}" - do you need to register a custom plugin with this name?`, - ); - } - - const defaultOptions = defaultPluginConfigs[name as PluginNames]; - const userOptions = userPluginsConfig[name as PluginNames]; - if (userOptions && defaultOptions) { - const nativePluginOption = Object.keys(userOptions).find((key) => - key.startsWith('_'), - ); - if (nativePluginOption) { - throw new Error( - `🚫 cannot register plugin "${name}" - attempting to override a native plugin option "${nativePluginOption}"`, - ); - } - } - - const config = { - _dependencies: [], - ...defaultOptions, - ...userOptions, - }; - - if (config._infer) { - const context: PluginContext = { - ensureDependency: (dependency) => { - if ( - typeof dependency === 'string' && - !config._dependencies.includes(dependency) - ) { - config._dependencies = [...config._dependencies, dependency]; - } - }, - pluginByTag: (tag, errorMessage) => { - for (const userPlugin of userPlugins) { - const defaultConfig = - defaultPluginConfigs[userPlugin as PluginNames]; - if ( - defaultConfig && - defaultConfig._tags?.includes(tag) && - userPlugin !== name - ) { - return userPlugin; - } - } - - throw new Error( - errorMessage || - `🚫 missing plugin - no plugin with tag "${tag}" found`, - ); - }, - }; - config._infer(config, context); - } - - for (const dependency of config._dependencies) { - dfs(dependency); - } - - circularReferenceTracker.delete(name); - pluginOrder.add(name); - - // @ts-expect-error - plugins[name] = config; - } - }; - - for (const name of userPlugins) { - dfs(name); - } - - return { - pluginOrder: Array.from(pluginOrder) as ReadonlyArray, - plugins, - }; -}; - -const getPlugins = ( +export const createClient = async ( userConfig: UserConfig, -): Pick => { - const userPluginsConfig: Config['plugins'] = {}; - - let definedPlugins: UserConfig['plugins'] = defaultPlugins; - if (userConfig.plugins) { - if ( - userConfig.plugins.length === 1 && - ((typeof userConfig.plugins[0] === 'string' && - (userConfig.plugins[0].startsWith('@hey-api/client') || - userConfig.plugins[0].startsWith('legacy/'))) || - (typeof userConfig.plugins[0] !== 'string' && - (userConfig.plugins[0]?.name.startsWith('@hey-api/client') || - userConfig.plugins[0]?.name.startsWith('legacy/')))) - ) { - definedPlugins = [...defaultPlugins, ...userConfig.plugins]; - } else { - definedPlugins = userConfig.plugins; - } - } - - const userPlugins = definedPlugins - .map((plugin) => { - if (typeof plugin === 'string') { - return plugin; - } - - if (plugin.name) { - // @ts-expect-error - userPluginsConfig[plugin.name] = plugin; - } - - return plugin.name; - }) - .filter(Boolean); - - return getPluginsConfig({ - pluginConfigs: { - ...userPluginsConfig, - ...defaultPluginConfigs, - }, - userPlugins, - userPluginsConfig, - }); -}; - -interface WatchValues { - headers: Headers; - lastValue: string | undefined; -} - -const getSpec = async ({ - inputPath, - watch, -}: { - inputPath: Config['input']['path']; - watch: WatchValues; -}): Promise< - | { - data: JSONSchema; - error?: undefined; - response?: undefined; - } - | { - data?: undefined; - error: 'not-modified' | 'not-ok'; - response: Response; - } -> => { - const refParser = new $RefParser(); - const resolvedInput = getResolvedInput({ pathOrUrlOrSchema: inputPath }); - - let arrayBuffer: ArrayBuffer | undefined; - // boolean signals whether the file has **definitely** changed - let hasChanged: boolean | undefined; - let response: Response | undefined; - - // no support for watching files and objects for now - if (resolvedInput.type === 'url') { - // do not send HEAD request on first run - if (watch.lastValue) { - const request = await sendRequest({ - init: { - headers: watch.headers, - method: 'HEAD', - }, - url: resolvedInput.path, - }); - response = request.response; - - if (!response.ok) { - // assume the server is no longer running - // do nothing, it might be restarted later - return { - error: 'not-ok', - response, - }; - } - - if (response.status === 304) { - return { - error: 'not-modified', - response, - }; - } - - if (hasChanged === undefined) { - const eTag = response.headers.get('ETag'); - if (eTag) { - hasChanged = eTag !== watch.headers.get('If-None-Match'); - - if (hasChanged) { - watch.headers.set('If-None-Match', eTag); - } - } - } - - if (hasChanged === undefined) { - const lastModified = response.headers.get('Last-Modified'); - if (lastModified) { - hasChanged = lastModified !== watch.headers.get('If-Modified-Since'); - - if (hasChanged) { - watch.headers.set('If-Modified-Since', lastModified); - } - } - } - - // we definitely know the input has not changed - if (hasChanged === false) { - return { - error: 'not-modified', - response, - }; - } - } - - const fileRequest = await sendRequest({ - init: { - method: 'GET', - }, - url: resolvedInput.path, - }); - response = fileRequest.response; - - if (!response.ok) { - // assume the server is no longer running - // do nothing, it might be restarted later - return { - error: 'not-ok', - response, - }; - } - - arrayBuffer = response.body - ? await response.arrayBuffer() - : new ArrayBuffer(0); - - if (hasChanged === undefined) { - const content = new TextDecoder().decode(arrayBuffer); - hasChanged = content !== watch.lastValue; - watch.lastValue = content; - } - } - - if (hasChanged === false) { - return { - error: 'not-modified', - response: response!, - }; - } - - const data = await refParser.bundle({ - arrayBuffer, - pathOrUrlOrSchema: undefined, - resolvedInput, - }); - - return { - data, - }; -}; - -const getWatch = ( - userConfig: Pick & Pick, -): Config['watch'] => { - let watch: Config['watch'] = { - enabled: false, - interval: 1000, - }; - // we cannot watch spec passed as an object - if (typeof userConfig.input.path !== 'string') { - return watch; - } - if (typeof userConfig.watch === 'boolean') { - watch.enabled = userConfig.watch; - } else if (typeof userConfig.watch === 'number') { - watch = { - enabled: true, - interval: userConfig.watch, - }; - } else if (userConfig.watch) { - watch = { - ...watch, - ...userConfig.watch, - }; - } - return watch; -}; - -const initConfigs = async (userConfig: UserConfig): Promise => { - let configurationFile: string | undefined = undefined; - if (userConfig.configFile) { - const parts = userConfig.configFile.split('.'); - configurationFile = parts.slice(0, parts.length - 1).join('.'); - } - - const { config: configFromFile } = await loadConfig({ - configFile: configurationFile, - name: 'openapi-ts', - }); - - const userConfigs: UserConfig[] = Array.isArray(userConfig) - ? userConfig - : Array.isArray(configFromFile) - ? configFromFile.map((config) => ({ - ...config, - ...userConfig, - })) - : [{ ...(configFromFile ?? {}), ...userConfig }]; - - return userConfigs.map((userConfig) => { - const { - base, - configFile = '', - dryRun = false, - experimentalParser = true, - exportCore = true, - name, - request, - useOptions = true, - } = userConfig; - - const logs = getLogs(userConfig); - - if (logs.level === 'debug') { - console.warn('userConfig:', userConfig); - } - - const input = getInput(userConfig); - const output = getOutput(userConfig); - - if (!input.path) { - throw new Error( - '🚫 missing input - which OpenAPI specification should we use to generate your output?', - ); - } - - if (!output.path) { - throw new Error( - '🚫 missing output - where should we generate your output?', - ); - } - - if (!useOptions) { - console.warn( - '❗️ Deprecation warning: useOptions set to false. This setting will be removed in future versions. Please migrate useOptions to true https://heyapi.dev/openapi-ts/migrating.html#v0-27-38', - ); - } - - output.path = path.resolve(process.cwd(), output.path); - - const config = setConfig({ - ...getPlugins(userConfig), - base, - configFile, - dryRun, - experimentalParser, - exportCore: false, - input, - logs, - name, - output, - request, - useOptions, - watch: getWatch({ ...userConfig, input }), - }); - config.exportCore = isLegacyClient(config) ? exportCore : false; - - if (logs.level === 'debug') { - console.warn('config:', config); - } - - return config; - }); -}; - -/** - * Generate the OpenAPI client. This method will read the OpenAPI specification and based on the - * given language it will generate the client, including the typed models, validation schemas, - * service layer, etc. - * @param userConfig {@link UserConfig} passed to the `createClient()` method - */ -export async function createClient( - userConfig: UserConfig, -): Promise> { +): Promise> => { let configs: Config[] = []; try { @@ -572,90 +32,8 @@ export async function createClient( const templates = registerHandlebarTemplates(); Performance.end('handlebars'); - const pCreateClient = async ({ - config, - watch: _watch, - }: { - config: Config; - watch?: WatchValues; - }) => { - const inputPath = config.input.path; - - const watch = _watch || { - headers: new Headers(), - lastValue: undefined, - }; - - Performance.start('spec'); - const { data, error, response } = await getSpec({ inputPath, watch }); - Performance.end('spec'); - - // throw on first run if there's an error to preserve user experience - // if in watch mode, subsequent errors won't throw to gracefully handle - // cases where server might be reloading - if (error && !_watch) { - throw new Error( - `Request failed with status ${response.status}: ${response.statusText}`, - ); - } - - let client: Client | undefined; - let context: IR.Context | undefined; - - if (data) { - if (_watch) { - console.log(`⏳ Input changed, generating from ${inputPath}`); - } else { - console.log(`⏳ Generating from ${inputPath}`); - } - - Performance.start('parser'); - if ( - config.experimentalParser && - !isLegacyClient(config) && - !legacyNameFromConfig(config) - ) { - context = parseOpenApiSpec({ config, spec: data }); - } - - // fallback to legacy parser - if (!context) { - const parsed = parseLegacy({ openApi: data }); - client = postProcessClient(parsed, config); - } - Performance.end('parser'); - - Performance.start('generator'); - if (context) { - await generateOutput({ context }); - } else if (client) { - await generateLegacyOutput({ client, openApi: data, templates }); - } - Performance.end('generator'); - - Performance.start('postprocess'); - if (!config.dryRun) { - processOutput({ config }); - - const outputPath = process.env.INIT_CWD - ? `./${path.relative(process.env.INIT_CWD, config.output.path)}` - : config.output.path; - console.log(`🚀 Done! Your output is in ${outputPath}`); - } - Performance.end('postprocess'); - } - - if (config.watch.enabled && typeof inputPath === 'string') { - setTimeout(() => { - pCreateClient({ config, watch }); - }, config.watch.interval); - } - - return context || client; - }; - const clients = await Promise.all( - configs.map((config) => pCreateClient({ config })), + configs.map((config) => pCreateClient({ config, templates })), ); const result = clients.filter((client) => Boolean(client)) as ReadonlyArray< Client | IR.Context @@ -699,21 +77,14 @@ export async function createClient( console.error(`🔥 Unexpected error occurred. ${error.message}`); throw error; } -} - -/** - * Default plugins used to generate artifacts if plugins aren't specified. - */ -export const defaultPlugins = [ - '@hey-api/typescript', - '@hey-api/sdk', -] as const satisfies ReadonlyArray; +}; /** * Type helper for openapi-ts.config.ts, returns {@link UserConfig} object */ export const defineConfig = (config: UserConfig): UserConfig => config; +export { defaultPlugins } from './initConfigs'; export type { IR } from './ir/types'; export type { OpenApi } from './openApi/types'; export type { Plugin } from './plugins/types'; diff --git a/packages/openapi-ts/src/initConfigs.ts b/packages/openapi-ts/src/initConfigs.ts new file mode 100644 index 000000000..d0e7d4a76 --- /dev/null +++ b/packages/openapi-ts/src/initConfigs.ts @@ -0,0 +1,325 @@ +import path from 'node:path'; + +import { loadConfig } from 'c12'; + +import { getLogs } from './getLogs'; +import type { ClientPlugins, UserPlugins } from './plugins'; +import { defaultPluginConfigs } from './plugins'; +import type { + AnyPluginName, + DefaultPluginConfigs, + PluginContext, + PluginNames, +} from './plugins/types'; +import type { Config, UserConfig } from './types/config'; +import { isLegacyClient, setConfig } from './utils/config'; + +/** + * Default plugins used to generate artifacts if plugins aren't specified. + */ +export const defaultPlugins = [ + '@hey-api/typescript', + '@hey-api/sdk', +] as const satisfies ReadonlyArray; + +const getInput = (userConfig: UserConfig): Config['input'] => { + let input: Config['input'] = { + path: '', + }; + if (typeof userConfig.input === 'string') { + input.path = userConfig.input; + } else if (userConfig.input && userConfig.input.path) { + input = { + ...input, + ...userConfig.input, + }; + } else { + input = { + ...input, + path: userConfig.input, + }; + } + return input; +}; + +const getPluginsConfig = ({ + pluginConfigs, + userPlugins, + userPluginsConfig, +}: { + pluginConfigs: DefaultPluginConfigs; + userPlugins: ReadonlyArray; + userPluginsConfig: Config['plugins']; +}): Pick => { + const circularReferenceTracker = new Set(); + const pluginOrder = new Set(); + const plugins: Config['plugins'] = {}; + + const dfs = (name: AnyPluginName) => { + if (circularReferenceTracker.has(name)) { + throw new Error(`Circular reference detected at '${name}'`); + } + + if (!pluginOrder.has(name)) { + circularReferenceTracker.add(name); + + const pluginConfig = pluginConfigs[name as PluginNames]; + if (!pluginConfig) { + throw new Error( + `🚫 unknown plugin dependency "${name}" - do you need to register a custom plugin with this name?`, + ); + } + + const defaultOptions = defaultPluginConfigs[name as PluginNames]; + const userOptions = userPluginsConfig[name as PluginNames]; + if (userOptions && defaultOptions) { + const nativePluginOption = Object.keys(userOptions).find((key) => + key.startsWith('_'), + ); + if (nativePluginOption) { + throw new Error( + `🚫 cannot register plugin "${name}" - attempting to override a native plugin option "${nativePluginOption}"`, + ); + } + } + + const config = { + _dependencies: [], + ...defaultOptions, + ...userOptions, + }; + + if (config._infer) { + const context: PluginContext = { + ensureDependency: (dependency) => { + if ( + typeof dependency === 'string' && + !config._dependencies.includes(dependency) + ) { + config._dependencies = [...config._dependencies, dependency]; + } + }, + pluginByTag: (tag, errorMessage) => { + for (const userPlugin of userPlugins) { + const defaultConfig = + defaultPluginConfigs[userPlugin as PluginNames]; + if ( + defaultConfig && + defaultConfig._tags?.includes(tag) && + userPlugin !== name + ) { + return userPlugin; + } + } + + throw new Error( + errorMessage || + `🚫 missing plugin - no plugin with tag "${tag}" found`, + ); + }, + }; + config._infer(config, context); + } + + for (const dependency of config._dependencies) { + dfs(dependency); + } + + circularReferenceTracker.delete(name); + pluginOrder.add(name); + + // @ts-expect-error + plugins[name] = config; + } + }; + + for (const name of userPlugins) { + dfs(name); + } + + return { + pluginOrder: Array.from(pluginOrder) as ReadonlyArray, + plugins, + }; +}; + +const getOutput = (userConfig: UserConfig): Config['output'] => { + let output: Config['output'] = { + clean: true, + format: false, + indexFile: true, + lint: false, + path: '', + }; + if (typeof userConfig.output === 'string') { + output.path = userConfig.output; + } else { + output = { + ...output, + ...userConfig.output, + }; + } + return output; +}; + +const getPlugins = ( + userConfig: UserConfig, +): Pick => { + const userPluginsConfig: Config['plugins'] = {}; + + let definedPlugins: UserConfig['plugins'] = defaultPlugins; + if (userConfig.plugins) { + if ( + userConfig.plugins.length === 1 && + ((typeof userConfig.plugins[0] === 'string' && + (userConfig.plugins[0].startsWith('@hey-api/client') || + userConfig.plugins[0].startsWith('legacy/'))) || + (typeof userConfig.plugins[0] !== 'string' && + (userConfig.plugins[0]?.name.startsWith('@hey-api/client') || + userConfig.plugins[0]?.name.startsWith('legacy/')))) + ) { + definedPlugins = [...defaultPlugins, ...userConfig.plugins]; + } else { + definedPlugins = userConfig.plugins; + } + } + + const userPlugins = definedPlugins + .map((plugin) => { + if (typeof plugin === 'string') { + return plugin; + } + + if (plugin.name) { + // @ts-expect-error + userPluginsConfig[plugin.name] = plugin; + } + + return plugin.name; + }) + .filter(Boolean); + + return getPluginsConfig({ + pluginConfigs: { + ...userPluginsConfig, + ...defaultPluginConfigs, + }, + userPlugins, + userPluginsConfig, + }); +}; + +const getWatch = ( + userConfig: Pick & Pick, +): Config['watch'] => { + let watch: Config['watch'] = { + enabled: false, + interval: 1_000, + timeout: 60_000, + }; + // we cannot watch spec passed as an object + if (typeof userConfig.input.path !== 'string') { + return watch; + } + if (typeof userConfig.watch === 'boolean') { + watch.enabled = userConfig.watch; + } else if (typeof userConfig.watch === 'number') { + watch.enabled = true; + watch.interval = userConfig.watch; + } else if (userConfig.watch) { + watch = { + ...watch, + ...userConfig.watch, + }; + } + return watch; +}; + +export const initConfigs = async ( + userConfig: UserConfig, +): Promise => { + let configurationFile: string | undefined = undefined; + if (userConfig.configFile) { + const parts = userConfig.configFile.split('.'); + configurationFile = parts.slice(0, parts.length - 1).join('.'); + } + + const { config: configFromFile } = await loadConfig({ + configFile: configurationFile, + name: 'openapi-ts', + }); + + const userConfigs: UserConfig[] = Array.isArray(userConfig) + ? userConfig + : Array.isArray(configFromFile) + ? configFromFile.map((config) => ({ + ...config, + ...userConfig, + })) + : [{ ...(configFromFile ?? {}), ...userConfig }]; + + return userConfigs.map((userConfig) => { + const { + base, + configFile = '', + dryRun = false, + experimentalParser = true, + exportCore = true, + name, + request, + useOptions = true, + } = userConfig; + + const logs = getLogs(userConfig); + + if (logs.level === 'debug') { + console.warn('userConfig:', userConfig); + } + + const input = getInput(userConfig); + const output = getOutput(userConfig); + + if (!input.path) { + throw new Error( + '🚫 missing input - which OpenAPI specification should we use to generate your output?', + ); + } + + if (!output.path) { + throw new Error( + '🚫 missing output - where should we generate your output?', + ); + } + + if (!useOptions) { + console.warn( + '❗️ Deprecation warning: useOptions set to false. This setting will be removed in future versions. Please migrate useOptions to true https://heyapi.dev/openapi-ts/migrating.html#v0-27-38', + ); + } + + output.path = path.resolve(process.cwd(), output.path); + + const config = setConfig({ + ...getPlugins(userConfig), + base, + configFile, + dryRun, + experimentalParser, + exportCore: false, + input, + logs, + name, + output, + request, + useOptions, + watch: getWatch({ ...userConfig, input }), + }); + config.exportCore = isLegacyClient(config) ? exportCore : false; + + if (logs.level === 'debug') { + console.warn('config:', config); + } + + return config; + }); +}; diff --git a/packages/openapi-ts/src/plugins/@hey-api/schemas/__tests__/schemas.test.ts b/packages/openapi-ts/src/plugins/@hey-api/schemas/__tests__/schemas.test.ts index 523d16eff..1c3f4dbb2 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/schemas/__tests__/schemas.test.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/schemas/__tests__/schemas.test.ts @@ -61,7 +61,8 @@ describe('generateLegacySchemas', () => { useOptions: true, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); @@ -149,7 +150,8 @@ describe('generateLegacySchemas', () => { useOptions: true, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); diff --git a/packages/openapi-ts/src/plugins/@hey-api/sdk/__tests__/plugin.test.ts b/packages/openapi-ts/src/plugins/@hey-api/sdk/__tests__/plugin.test.ts index e3c1a7f4a..6deb0ef2e 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/sdk/__tests__/plugin.test.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/sdk/__tests__/plugin.test.ts @@ -63,7 +63,8 @@ describe('handlerLegacy', () => { useOptions: false, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); @@ -222,7 +223,8 @@ describe('methodNameBuilder', () => { useOptions: false, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); @@ -304,7 +306,8 @@ describe('methodNameBuilder', () => { useOptions: false, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); @@ -388,7 +391,8 @@ describe('methodNameBuilder', () => { useOptions: false, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); diff --git a/packages/openapi-ts/src/plugins/@hey-api/typescript/__tests__/plugin.test.ts b/packages/openapi-ts/src/plugins/@hey-api/typescript/__tests__/plugin.test.ts index 6735dfd4b..6f6137de3 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/typescript/__tests__/plugin.test.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/typescript/__tests__/plugin.test.ts @@ -61,7 +61,8 @@ describe('generateLegacyTypes', () => { useOptions: true, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); diff --git a/packages/openapi-ts/src/processOutput.ts b/packages/openapi-ts/src/processOutput.ts new file mode 100644 index 000000000..4029c8574 --- /dev/null +++ b/packages/openapi-ts/src/processOutput.ts @@ -0,0 +1,66 @@ +import { sync } from 'cross-spawn'; + +import type { Config, Formatters, Linters } from './types/config'; + +type OutputProcessor = { + args: (path: string) => ReadonlyArray; + command: string; + name: string; +}; + +/** + * Map of supported formatters + */ +const formatters: Record = { + biome: { + args: (path) => ['format', '--write', path], + command: 'biome', + name: 'Biome (Format)', + }, + prettier: { + args: (path) => [ + '--ignore-unknown', + path, + '--write', + '--ignore-path', + './.prettierignore', + ], + command: 'prettier', + name: 'Prettier', + }, +}; + +/** + * Map of supported linters + */ +const linters: Record = { + biome: { + args: (path) => ['lint', '--apply', path], + command: 'biome', + name: 'Biome (Lint)', + }, + eslint: { + args: (path) => [path, '--fix'], + command: 'eslint', + name: 'ESLint', + }, + oxlint: { + args: (path) => ['--fix', path], + command: 'oxlint', + name: 'oxlint', + }, +}; + +export const processOutput = ({ config }: { config: Config }) => { + if (config.output.format) { + const module = formatters[config.output.format]; + console.log(`✨ Running ${module.name}`); + sync(module.command, module.args(config.output.path)); + } + + if (config.output.lint) { + const module = linters[config.output.lint]; + console.log(`✨ Running ${module.name}`); + sync(module.command, module.args(config.output.path)); + } +}; diff --git a/packages/openapi-ts/src/types/client.ts b/packages/openapi-ts/src/types/client.d.ts similarity index 100% rename from packages/openapi-ts/src/types/client.ts rename to packages/openapi-ts/src/types/client.d.ts diff --git a/packages/openapi-ts/src/types/config.ts b/packages/openapi-ts/src/types/config.d.ts similarity index 95% rename from packages/openapi-ts/src/types/config.ts rename to packages/openapi-ts/src/types/config.d.ts index 00eb513d2..7ae80edea 100644 --- a/packages/openapi-ts/src/types/config.ts +++ b/packages/openapi-ts/src/types/config.d.ts @@ -163,7 +163,8 @@ export interface UserConfig { */ plugins?: ReadonlyArray; /** - * Regenerate the client when the input file changes? + * Regenerate the client when the input file changes? You can alternatively + * pass a numeric value for the interval in ms. * * @default false */ @@ -178,11 +179,17 @@ export interface UserConfig { */ enabled?: boolean; /** - * How often should we attempt to detect the input file change? + * How often should we attempt to detect the input file change? (in ms) * * @default 1000 */ interval?: number; + /** + * How long will we wait before the request times out? + * + * @default 60_000 + */ + timeout?: number; }; /** * @deprecated @@ -258,5 +265,5 @@ export type Config = Omit< ExtractArrayOfObjects, { name: string }>, 'name' >; - watch: Extract; + watch: Extract, object>; }; diff --git a/packages/openapi-ts/src/types/types.d.ts b/packages/openapi-ts/src/types/types.d.ts index 028093740..dfa6fc258 100644 --- a/packages/openapi-ts/src/types/types.d.ts +++ b/packages/openapi-ts/src/types/types.d.ts @@ -3,3 +3,21 @@ import type { Operation } from './client'; export namespace LegacyIR { export type LegacyOperation = Operation; } + +export interface WatchValues { + /** + * Headers to be sent with each HEAD and/or GET request. This effectively + * serves as a mechanism resolver because setting certain headers will opt + * into comparing the specifications using that method. + */ + headers: Headers; + /** + * Can we send a HEAD request instead of fetching the whole specification? + * This value will be set after the first successful fetch. + */ + isHeadMethodSupported?: boolean; + /** + * String content of the last successfully fetched specification. + */ + lastValue?: string; +} diff --git a/packages/openapi-ts/src/types/utils.ts b/packages/openapi-ts/src/types/utils.d.ts similarity index 100% rename from packages/openapi-ts/src/types/utils.ts rename to packages/openapi-ts/src/types/utils.d.ts diff --git a/packages/openapi-ts/src/utils/__tests__/handlebars.test.ts b/packages/openapi-ts/src/utils/__tests__/handlebars.test.ts index fa0aeef58..30194aeda 100644 --- a/packages/openapi-ts/src/utils/__tests__/handlebars.test.ts +++ b/packages/openapi-ts/src/utils/__tests__/handlebars.test.ts @@ -58,7 +58,8 @@ describe('registerHandlebarHelpers', () => { useOptions: false, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); registerHandlebarHelpers(); @@ -123,7 +124,8 @@ describe('registerHandlebarTemplates', () => { useOptions: false, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }); const templates = registerHandlebarTemplates(); diff --git a/packages/openapi-ts/src/utils/__tests__/parse.test.ts b/packages/openapi-ts/src/utils/__tests__/parse.test.ts index 86a0ebf35..9ea94f73a 100644 --- a/packages/openapi-ts/src/utils/__tests__/parse.test.ts +++ b/packages/openapi-ts/src/utils/__tests__/parse.test.ts @@ -38,7 +38,8 @@ describe('operationNameFn', () => { useOptions: false, watch: { enabled: false, - interval: 1000, + interval: 1_000, + timeout: 60_000, }, }; diff --git a/packages/openapi-ts/test/openapi-ts.config.ts b/packages/openapi-ts/test/openapi-ts.config.ts index 08ffea8e7..8c8523e60 100644 --- a/packages/openapi-ts/test/openapi-ts.config.ts +++ b/packages/openapi-ts/test/openapi-ts.config.ts @@ -6,7 +6,8 @@ export default defineConfig({ // exclude: '^#/components/schemas/ModelWithCircularReference$', // include: // '^(#/components/schemas/import|#/paths/api/v{api-version}/simple/options)$', - path: './packages/openapi-ts/test/spec/3.1.x/full.json', + // path: './packages/openapi-ts/test/spec/3.1.x/full.json', + path: 'http://localhost:8000/openapi.json', // path: './test/spec/v3-transforms.json', // path: 'https://mongodb-mms-prod-build-server.s3.amazonaws.com/openapi/2caffd88277a4e27c95dcefc7e3b6a63a3b03297-v2-2023-11-15.json', // path: 'https://raw.githubusercontent.com/swagger-api/swagger-petstore/master/src/main/resources/openapi.yaml', @@ -81,8 +82,9 @@ export default defineConfig({ }, ], // useOptions: false, - // watch: { - // enabled: true, - // interval: 1_000, - // }, + watch: { + enabled: true, + interval: 1_000, + timeout: 60_000, + }, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 162316502..d487059ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -309,13 +309,13 @@ importers: version: link:../../packages/client-nuxt nuxt: specifier: 3.14.1592 - version: 3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.2.3)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.31.0)(sass@1.80.7)(terser@5.37.0)(typescript@5.6.1-rc)(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) + version: 3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.2.3)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.31.0)(sass@1.80.7)(terser@5.37.0)(typescript@5.5.3)(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) vue: specifier: 3.5.13 - version: 3.5.13(typescript@5.6.1-rc) + version: 3.5.13(typescript@5.5.3) vue-router: specifier: 4.5.0 - version: 4.5.0(vue@3.5.13(typescript@5.6.1-rc)) + version: 4.5.0(vue@3.5.13(typescript@5.5.3)) zod: specifier: 3.23.8 version: 3.23.8 @@ -444,7 +444,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: ^19.0.6 - version: 19.0.6(@angular/compiler-cli@19.0.5(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.5.3))(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(@types/node@22.10.5)(chokidar@4.0.3)(karma@6.4.4)(tailwindcss@3.4.9(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.5.3)))(typescript@5.5.3)(vite@5.4.11(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)) + version: 19.0.6(@angular/compiler-cli@19.0.5(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.5.3))(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(@types/node@22.10.5)(chokidar@4.0.3)(karma@6.4.4)(tailwindcss@3.4.9(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.5.3)))(typescript@5.5.3)(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) '@angular/cli': specifier: ^19.0.6 version: 19.0.6(@types/node@22.10.5)(chokidar@4.0.3) @@ -758,8 +758,8 @@ importers: packages/openapi-ts: dependencies: '@hey-api/json-schema-ref-parser': - specifier: 1.0.1 - version: 1.0.1 + specifier: 1.0.2 + version: 1.0.2 c12: specifier: 2.0.1 version: 2.0.1(magicast@0.3.5) @@ -772,7 +772,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 19.0.6 - version: 19.0.6(@angular/compiler-cli@19.0.5(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.5.3))(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(@types/node@22.10.5)(chokidar@4.0.3)(karma@6.4.4)(tailwindcss@3.4.9(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.5.3)))(typescript@5.5.3)(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) + version: 19.0.6(@angular/compiler-cli@19.0.5(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.5.3))(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(@types/node@22.10.5)(chokidar@4.0.3)(karma@6.4.4)(tailwindcss@3.4.9(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.5.3)))(typescript@5.5.3)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)) '@angular/animations': specifier: 19.0.5 version: 19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)) @@ -859,7 +859,7 @@ importers: version: 3.3.2 nuxt: specifier: 3.14.1592 - version: 3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.2.3)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.31.0)(sass@1.80.7)(terser@5.37.0)(typescript@5.5.3)(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) + version: 3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.2.3)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.31.0)(sass@1.80.7)(terser@5.36.0)(typescript@5.5.3)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)) prettier: specifier: 3.4.2 version: 3.4.2 @@ -2342,8 +2342,8 @@ packages: '@fontsource/fira-mono@5.0.0': resolution: {integrity: sha512-IsinH/oLYJyv/sQv7SbKmjoAXZsSjm6Q1Tz5GBBXCXi3Jg9MzXmKvWm9bSLC8lFI6CDsi8GkH/DAgZ98t8bhTQ==} - '@hey-api/json-schema-ref-parser@1.0.1': - resolution: {integrity: sha512-dBt0A7op9kf4BcK++x6HBYDmvCvnJUZEGe5QytghPFHnMXPyKwDKomwL/v5e9ERk6E0e1GzL/e/y6pWUso9zrQ==} + '@hey-api/json-schema-ref-parser@1.0.2': + resolution: {integrity: sha512-F6LSkttZcT/XiX3ydeDqTY3uRN3BLJMwyMTk4kg/ichZlKUp3+3Odv0WokSmXGSoZGTW/N66FROMYAm5NPdJlA==} engines: {node: '>= 16'} '@humanfs/core@0.19.1': @@ -11234,7 +11234,7 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@19.0.6(@angular/compiler-cli@19.0.5(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.5.3))(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(@types/node@22.10.5)(chokidar@4.0.3)(karma@6.4.4)(tailwindcss@3.4.9(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.5.3)))(typescript@5.5.3)(vite@5.4.11(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))': + '@angular-devkit/build-angular@19.0.6(@angular/compiler-cli@19.0.5(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.5.3))(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(@types/node@22.10.5)(chokidar@4.0.3)(karma@6.4.4)(tailwindcss@3.4.9(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.5.3)))(typescript@5.5.3)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.1900.6(chokidar@4.0.3) @@ -11253,7 +11253,7 @@ snapshots: '@babel/runtime': 7.26.0 '@discoveryjs/json-ext': 0.6.3 '@ngtools/webpack': 19.0.6(@angular/compiler-cli@19.0.5(@angular/compiler@19.0.5(@angular/core@19.0.5(rxjs@7.8.1)(zone.js@0.15.0)))(typescript@5.5.3))(typescript@5.5.3)(webpack@5.96.1(esbuild@0.24.0)) - '@vitejs/plugin-basic-ssl': 1.1.0(vite@5.4.11(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)) + '@vitejs/plugin-basic-ssl': 1.1.0(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)) ansi-colors: 4.1.3 autoprefixer: 10.4.20(postcss@8.4.49) babel-loader: 9.2.1(@babel/core@7.26.0)(webpack@5.96.1(esbuild@0.24.0)) @@ -12886,7 +12886,7 @@ snapshots: '@fontsource/fira-mono@5.0.0': {} - '@hey-api/json-schema-ref-parser@1.0.1': + '@hey-api/json-schema-ref-parser@1.0.2': dependencies: '@jsdevtools/ono': 7.1.3 '@types/json-schema': 7.0.15 @@ -13439,12 +13439,12 @@ snapshots: '@nuxt/devalue@2.0.2': {} - '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(rollup@4.31.0)(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0))': + '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(rollup@4.31.0)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))': dependencies: '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.31.0) '@nuxt/schema': 3.15.4 execa: 7.2.0 - vite: 6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0) + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) transitivePeerDependencies: - magicast - rollup @@ -13474,13 +13474,13 @@ snapshots: rc9: 2.1.2 semver: 7.7.0 - '@nuxt/devtools@1.7.0(rollup@4.31.0)(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.5.3))': + '@nuxt/devtools@1.7.0(rollup@4.31.0)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))(vue@3.5.13(typescript@5.5.3))': dependencies: '@antfu/utils': 0.7.10 - '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(rollup@4.31.0)(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) + '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(rollup@4.31.0)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)) '@nuxt/devtools-wizard': 1.7.0 '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.31.0) - '@vue/devtools-core': 7.6.8(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.5.3)) + '@vue/devtools-core': 7.6.8(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))(vue@3.5.13(typescript@5.5.3)) '@vue/devtools-kit': 7.6.8 birpc: 0.2.19 consola: 3.4.0 @@ -13509,9 +13509,56 @@ snapshots: sirv: 3.0.0 tinyglobby: 0.2.10 unimport: 3.14.6(rollup@4.31.0) - vite: 6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0) - vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5)(rollup@4.31.0))(rollup@4.31.0)(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) - vite-plugin-vue-inspector: 5.3.1(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) + vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5)(rollup@4.31.0))(rollup@4.31.0)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)) + vite-plugin-vue-inspector: 5.3.1(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)) + which: 3.0.1 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - rollup + - supports-color + - utf-8-validate + - vue + + '@nuxt/devtools@1.7.0(rollup@4.31.0)(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.5.3))': + dependencies: + '@antfu/utils': 0.7.10 + '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(rollup@4.31.0)(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) + '@nuxt/devtools-wizard': 1.7.0 + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.31.0) + '@vue/devtools-core': 7.6.8(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.5.3)) + '@vue/devtools-kit': 7.6.8 + birpc: 0.2.19 + consola: 3.4.0 + cronstrue: 2.53.0 + destr: 2.0.3 + error-stack-parser-es: 0.1.5 + execa: 7.2.0 + fast-npm-meta: 0.2.2 + flatted: 3.3.2 + get-port-please: 3.1.2 + hookable: 5.5.3 + image-meta: 0.2.1 + is-installed-globally: 1.0.0 + launch-editor: 2.9.1 + local-pkg: 0.5.1 + magicast: 0.3.5 + nypm: 0.4.1 + ohash: 1.1.4 + pathe: 1.1.2 + perfect-debounce: 1.0.0 + pkg-types: 1.3.1 + rc9: 2.1.2 + scule: 1.3.0 + semver: 7.7.0 + simple-git: 3.27.0 + sirv: 3.0.0 + tinyglobby: 0.2.10 + unimport: 3.14.6(rollup@4.31.0) + vite: 6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0) + vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5)(rollup@4.31.0))(rollup@4.31.0)(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) + vite-plugin-vue-inspector: 5.3.1(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) which: 3.0.1 ws: 8.18.0 transitivePeerDependencies: @@ -13708,6 +13755,66 @@ snapshots: - rollup - supports-color + '@nuxt/vite-builder@3.14.1592(@types/node@22.10.5)(eslint@9.17.0(jiti@2.4.2))(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.31.0)(sass@1.80.7)(terser@5.36.0)(typescript@5.5.3)(vue@3.5.13(typescript@5.5.3))': + dependencies: + '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@4.31.0) + '@rollup/plugin-replace': 6.0.2(rollup@4.31.0) + '@vitejs/plugin-vue': 5.2.1(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))(vue@3.5.13(typescript@5.5.3)) + '@vitejs/plugin-vue-jsx': 4.1.1(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))(vue@3.5.13(typescript@5.5.3)) + autoprefixer: 10.4.20(postcss@8.5.1) + clear: 0.1.0 + consola: 3.4.0 + cssnano: 7.0.6(postcss@8.5.1) + defu: 6.1.4 + esbuild: 0.24.2 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + externality: 1.0.2 + get-port-please: 3.1.2 + h3: 1.14.0 + jiti: 2.4.2 + knitwork: 1.2.0 + magic-string: 0.30.17 + mlly: 1.7.4 + ohash: 1.1.4 + pathe: 1.1.2 + perfect-debounce: 1.0.0 + pkg-types: 1.3.1 + postcss: 8.5.1 + rollup-plugin-visualizer: 5.14.0(rollup@4.31.0) + std-env: 3.8.0 + strip-literal: 2.1.1 + ufo: 1.5.4 + unenv: 1.10.0 + unplugin: 1.16.1 + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) + vite-node: 2.1.8(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) + vite-plugin-checker: 0.8.0(eslint@9.17.0(jiti@2.4.2))(optionator@0.9.4)(typescript@5.5.3)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)) + vue: 3.5.13(typescript@5.5.3) + vue-bundle-renderer: 2.1.1 + transitivePeerDependencies: + - '@biomejs/biome' + - '@types/node' + - eslint + - less + - lightningcss + - magicast + - meow + - optionator + - rolldown + - rollup + - sass + - sass-embedded + - stylelint + - stylus + - sugarss + - supports-color + - terser + - typescript + - vls + - vti + - vue-tsc + '@nuxt/vite-builder@3.14.1592(@types/node@22.10.5)(eslint@9.17.0(jiti@2.4.2))(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.31.0)(sass@1.80.7)(terser@5.37.0)(typescript@5.5.3)(vue@3.5.13(typescript@5.5.3))': dependencies: '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@4.31.0) @@ -15494,6 +15601,10 @@ snapshots: dependencies: vite: 5.4.11(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))': + dependencies: + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) + '@vitejs/plugin-basic-ssl@1.1.0(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0))': dependencies: vite: 6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0) @@ -15509,6 +15620,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitejs/plugin-vue-jsx@4.1.1(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))(vue@3.5.13(typescript@5.5.3))': + dependencies: + '@babel/core': 7.26.7 + '@babel/plugin-transform-typescript': 7.26.7(@babel/core@7.26.7) + '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.7) + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) + vue: 3.5.13(typescript@5.5.3) + transitivePeerDependencies: + - supports-color + '@vitejs/plugin-vue-jsx@4.1.1(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.37.0))(vue@3.5.13(typescript@5.5.3))': dependencies: '@babel/core': 7.26.7 @@ -15539,6 +15660,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitejs/plugin-vue@5.2.1(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))(vue@3.5.13(typescript@5.5.3))': + dependencies: + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) + vue: 3.5.13(typescript@5.5.3) + '@vitejs/plugin-vue@5.2.1(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.37.0))(vue@3.5.13(typescript@5.5.3))': dependencies: vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.37.0) @@ -15707,14 +15833,26 @@ snapshots: dependencies: '@vue/devtools-kit': 7.7.1 - '@vue/devtools-core@7.6.8(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.5.3))': + '@vue/devtools-core@7.6.8(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))(vue@3.5.13(typescript@5.5.3))': dependencies: '@vue/devtools-kit': 7.7.1 '@vue/devtools-shared': 7.7.1 mitt: 3.0.1 nanoid: 5.0.9 pathe: 1.1.2 - vite-hot-client: 0.2.4(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) + vite-hot-client: 0.2.4(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)) + vue: 3.5.13(typescript@5.5.3) + transitivePeerDependencies: + - vite + + '@vue/devtools-core@7.6.8(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.5.3))': + dependencies: + '@vue/devtools-kit': 7.7.1 + '@vue/devtools-shared': 7.7.1 + mitt: 3.0.1 + nanoid: 5.0.9 + pathe: 1.1.2 + vite-hot-client: 0.2.4(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)) vue: 3.5.13(typescript@5.5.3) transitivePeerDependencies: - vite @@ -17465,8 +17603,8 @@ snapshots: '@typescript-eslint/parser': 7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3) eslint: 9.17.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@2.4.2)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.17.0(jiti@2.4.2)) eslint-plugin-react: 7.37.4(eslint@9.17.0(jiti@2.4.2)) eslint-plugin-react-hooks: 5.1.0(eslint@9.17.0(jiti@2.4.2)) @@ -17489,7 +17627,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)): + eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@2.4.2)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0(supports-color@9.4.0) @@ -17501,22 +17639,22 @@ snapshots: is-glob: 4.0.3 stable-hash: 0.0.4 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@2.4.2)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@2.4.2)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3) eslint: 9.17.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@2.4.2)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@2.4.2)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -17527,7 +17665,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.17.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.15.0(eslint@9.17.0(jiti@2.4.2))(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@2.4.2)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -19958,10 +20096,130 @@ snapshots: nuxi@3.21.1: {} - nuxt@3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.2.3)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.31.0)(sass@1.80.7)(terser@5.37.0)(typescript@5.5.3)(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)): + nuxt@3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.2.3)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.31.0)(sass@1.80.7)(terser@5.36.0)(typescript@5.5.3)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)): dependencies: '@nuxt/devalue': 2.0.2 - '@nuxt/devtools': 1.7.0(rollup@4.31.0)(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.5.3)) + '@nuxt/devtools': 1.7.0(rollup@4.31.0)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))(vue@3.5.13(typescript@5.5.3)) + '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@4.31.0) + '@nuxt/schema': 3.14.1592(magicast@0.3.5)(rollup@4.31.0) + '@nuxt/telemetry': 2.6.4(magicast@0.3.5)(rollup@4.31.0) + '@nuxt/vite-builder': 3.14.1592(@types/node@22.10.5)(eslint@9.17.0(jiti@2.4.2))(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.31.0)(sass@1.80.7)(terser@5.36.0)(typescript@5.5.3)(vue@3.5.13(typescript@5.5.3)) + '@unhead/dom': 1.11.18 + '@unhead/shared': 1.11.18 + '@unhead/ssr': 1.11.18 + '@unhead/vue': 1.11.18(vue@3.5.13(typescript@5.5.3)) + '@vue/shared': 3.5.13 + acorn: 8.14.0 + c12: 2.0.1(magicast@0.3.5) + chokidar: 4.0.3 + compatx: 0.1.8 + consola: 3.4.0 + cookie-es: 1.2.2 + defu: 6.1.4 + destr: 2.0.3 + devalue: 5.1.1 + errx: 0.1.0 + esbuild: 0.24.2 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + globby: 14.0.2 + h3: 1.14.0 + hookable: 5.5.3 + ignore: 6.0.2 + impound: 0.2.0(rollup@4.31.0) + jiti: 2.4.2 + klona: 2.0.6 + knitwork: 1.2.0 + magic-string: 0.30.17 + mlly: 1.7.4 + nanotar: 0.1.1 + nitropack: 2.10.4(encoding@0.1.13)(typescript@5.5.3) + nuxi: 3.21.1 + nypm: 0.3.12 + ofetch: 1.4.1 + ohash: 1.1.4 + pathe: 1.1.2 + perfect-debounce: 1.0.0 + pkg-types: 1.3.1 + radix3: 1.1.2 + scule: 1.3.0 + semver: 7.7.0 + std-env: 3.8.0 + strip-literal: 2.1.1 + tinyglobby: 0.2.10 + ufo: 1.5.4 + ultrahtml: 1.5.3 + uncrypto: 0.1.3 + unctx: 2.4.1 + unenv: 1.10.0 + unhead: 1.11.18 + unimport: 3.14.6(rollup@4.31.0) + unplugin: 1.16.1 + unplugin-vue-router: 0.10.9(rollup@4.31.0)(vue-router@4.5.0(vue@3.5.13(typescript@5.5.3)))(vue@3.5.13(typescript@5.5.3)) + unstorage: 1.14.4(db0@0.2.3)(ioredis@5.4.2) + untyped: 1.5.2 + vue: 3.5.13(typescript@5.5.3) + vue-bundle-renderer: 2.1.1 + vue-devtools-stub: 0.1.0 + vue-router: 4.5.0(vue@3.5.13(typescript@5.5.3)) + optionalDependencies: + '@parcel/watcher': 2.5.1 + '@types/node': 22.10.5 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@biomejs/biome' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/kv' + - aws4fetch + - better-sqlite3 + - bufferutil + - db0 + - drizzle-orm + - encoding + - eslint + - idb-keyval + - ioredis + - less + - lightningcss + - magicast + - meow + - mysql2 + - optionator + - rolldown + - rollup + - sass + - sass-embedded + - sqlite3 + - stylelint + - stylus + - sugarss + - supports-color + - terser + - typescript + - uploadthing + - utf-8-validate + - vite + - vls + - vti + - vue-tsc + - xml2js + + nuxt@3.14.1592(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.2.3)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.31.0)(sass@1.80.7)(terser@5.37.0)(typescript@5.5.3)(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)): + dependencies: + '@nuxt/devalue': 2.0.2 + '@nuxt/devtools': 1.7.0(rollup@4.31.0)(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.5.3)) '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@4.31.0) '@nuxt/schema': 3.14.1592(magicast@0.3.5)(rollup@4.31.0) '@nuxt/telemetry': 2.6.4(magicast@0.3.5)(rollup@4.31.0) @@ -22762,9 +23020,9 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-hot-client@0.2.4(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)): + vite-hot-client@0.2.4(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)): dependencies: - vite: 6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0) + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) vite-hot-client@0.2.4(vite@6.0.9(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)): dependencies: @@ -22788,6 +23046,24 @@ snapshots: - supports-color - terser + vite-node@2.1.8(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0): + dependencies: + cac: 6.7.14 + debug: 4.4.0(supports-color@9.4.0) + es-module-lexer: 1.6.0 + pathe: 1.1.2 + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vite-node@2.1.8(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.37.0): dependencies: cac: 6.7.14 @@ -22806,6 +23082,28 @@ snapshots: - supports-color - terser + vite-plugin-checker@0.8.0(eslint@9.17.0(jiti@2.4.2))(optionator@0.9.4)(typescript@5.5.3)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)): + dependencies: + '@babel/code-frame': 7.26.2 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + chokidar: 3.6.0 + commander: 8.3.0 + fast-glob: 3.3.3 + fs-extra: 11.3.0 + npm-run-path: 4.0.1 + strip-ansi: 6.0.1 + tiny-invariant: 1.3.3 + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) + vscode-languageclient: 7.0.0 + vscode-languageserver: 7.0.0 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + optionalDependencies: + eslint: 9.17.0(jiti@2.4.2) + optionator: 0.9.4 + typescript: 5.5.3 + vite-plugin-checker@0.8.0(eslint@9.17.0(jiti@2.4.2))(optionator@0.9.4)(typescript@5.5.3)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)): dependencies: '@babel/code-frame': 7.26.2 @@ -22850,7 +23148,7 @@ snapshots: optionator: 0.9.4 typescript: 5.6.1-rc - vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5)(rollup@4.31.0))(rollup@4.31.0)(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)): + vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5)(rollup@4.31.0))(rollup@4.31.0)(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)): dependencies: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.1.4(rollup@4.31.0) @@ -22861,7 +23159,7 @@ snapshots: perfect-debounce: 1.0.0 picocolors: 1.1.1 sirv: 3.0.0 - vite: 6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0) + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) optionalDependencies: '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.31.0) transitivePeerDependencies: @@ -22902,7 +23200,7 @@ snapshots: - supports-color - vue - vite-plugin-vue-inspector@5.3.1(vite@6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0)): + vite-plugin-vue-inspector@5.3.1(vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)): dependencies: '@babel/core': 7.26.7 '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.7) @@ -22913,7 +23211,7 @@ snapshots: '@vue/compiler-dom': 3.5.13 kolorist: 1.8.0 magic-string: 0.30.17 - vite: 6.0.11(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.37.0)(yaml@2.7.0) + vite: 5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0) transitivePeerDependencies: - supports-color @@ -22944,6 +23242,18 @@ snapshots: sass: 1.80.7 terser: 5.36.0 + vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.36.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.1 + rollup: 4.31.0 + optionalDependencies: + '@types/node': 22.10.5 + fsevents: 2.3.3 + less: 4.2.0 + sass: 1.80.7 + terser: 5.36.0 + vite@5.4.14(@types/node@22.10.5)(less@4.2.0)(sass@1.80.7)(terser@5.37.0): dependencies: esbuild: 0.21.5