@kubb/mcp 5.0.0-alpha.70 → 5.0.0-alpha.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -27,13 +27,13 @@ let _modelcontextprotocol_sdk_server_mcp_js = require("@modelcontextprotocol/sdk
27
27
  let _modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
28
28
  let zod = require("zod");
29
29
  let node_events = require("node:events");
30
+ let node_fs = require("node:fs");
30
31
  let node_path = require("node:path");
31
32
  node_path = __toESM(node_path, 1);
32
33
  let _kubb_core = require("@kubb/core");
33
- let jiti = require("jiti");
34
- jiti = __toESM(jiti, 1);
34
+ let unrun = require("unrun");
35
35
  //#region package.json
36
- var version = "5.0.0-alpha.70";
36
+ var version = "5.0.0-alpha.71";
37
37
  //#endregion
38
38
  //#region src/schemas/generateSchema.ts
39
39
  const generateSchema = zod.z.object({
@@ -211,19 +211,48 @@ const NotifyTypes = {
211
211
  FATAL_ERROR: "FATAL_ERROR"
212
212
  };
213
213
  //#endregion
214
+ //#region src/constants.ts
215
+ const ALLOWED_CONFIG_EXTENSIONS = new Set([
216
+ ".ts",
217
+ ".mts",
218
+ ".cts",
219
+ ".js",
220
+ ".mjs",
221
+ ".cjs"
222
+ ]);
223
+ //#endregion
214
224
  //#region src/utils/loadUserConfig.ts
215
- const jiti$1 = (0, jiti.default)(require("url").pathToFileURL(__filename).href, { sourceMaps: true });
216
- /**
217
- * Load the user configuration from the specified path or current directory
218
- */
225
+ const loadedModules = /* @__PURE__ */ new Map();
226
+ async function loadModule(filePath) {
227
+ const ext = node_path.default.extname(filePath);
228
+ if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) throw new Error(`Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(", ")}`);
229
+ if (loadedModules.has(filePath)) return loadedModules.get(filePath);
230
+ const { module } = await (0, unrun.unrun)({ path: filePath });
231
+ loadedModules.set(filePath, module);
232
+ return module;
233
+ }
219
234
  async function loadUserConfig(configPath, { notify }) {
220
235
  let userConfig;
221
236
  let cwd;
222
237
  if (configPath) {
223
- cwd = node_path.default.dirname(node_path.default.resolve(configPath));
238
+ const ext = node_path.default.extname(configPath);
239
+ if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {
240
+ const msg = `Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(", ")}`;
241
+ await notify(NotifyTypes.CONFIG_ERROR, msg);
242
+ throw new Error(msg);
243
+ }
244
+ const base = node_path.default.resolve(process.cwd());
245
+ const resolvedConfigPath = node_path.default.resolve(base, configPath);
246
+ const relative = node_path.default.relative(base, resolvedConfigPath);
247
+ if (relative.startsWith("..") || node_path.default.isAbsolute(relative)) {
248
+ const msg = "Invalid config file path: must be within the current working directory";
249
+ await notify(NotifyTypes.CONFIG_ERROR, msg);
250
+ throw new Error(msg);
251
+ }
252
+ cwd = node_path.default.dirname(resolvedConfigPath);
224
253
  try {
225
- userConfig = await jiti$1.import(configPath, { default: true });
226
- await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${configPath}`);
254
+ userConfig = await loadModule(resolvedConfigPath);
255
+ await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${resolvedConfigPath}`);
227
256
  } catch (error) {
228
257
  await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
229
258
  throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
@@ -237,12 +266,15 @@ async function loadUserConfig(configPath, { notify }) {
237
266
  "kubb.config.js",
238
267
  "kubb.config.cjs"
239
268
  ];
240
- for (const configFileName of configFileNames) try {
269
+ for (const configFileName of configFileNames) {
241
270
  const configFilePath = node_path.default.resolve(process.cwd(), configFileName);
242
- userConfig = await jiti$1.import(configFilePath, { default: true });
243
- await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`);
244
- break;
245
- } catch {}
271
+ if (!(0, node_fs.existsSync)(configFilePath)) continue;
272
+ try {
273
+ userConfig = await loadModule(configFilePath);
274
+ await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`);
275
+ break;
276
+ } catch {}
277
+ }
246
278
  if (!userConfig) {
247
279
  await notify(NotifyTypes.CONFIG_ERROR, "No config file found");
248
280
  throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(", ")}`);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["z","#emitter","NodeEventEmitter","jiti","path","path","StdioServerTransport","McpServer"],"sources":["../package.json","../src/schemas/generateSchema.ts","../../../internals/utils/src/errors.ts","../../../internals/utils/src/asyncEventEmitter.ts","../../../internals/utils/src/promise.ts","../src/types.ts","../src/utils/loadUserConfig.ts","../src/utils/resolveCwd.ts","../src/utils/resolveUserConfig.ts","../src/tools/generate.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["","import { z } from 'zod'\n\nexport const generateSchema = z.object({\n config: z\n .string()\n .optional()\n\n .describe('Path to kubb.config file (supports .ts, .js, .cjs). If not provided, will look for kubb.config.{ts,js,cjs} in current directory'),\n input: z.string().optional().describe('Path to OpenAPI/Swagger spec file (overrides config)'),\n output: z.string().optional().describe('Output directory path (overrides config)'),\n logLevel: z.enum(['silent', 'error', 'warn', 'info', 'verbose', 'debug']).optional().default('info').describe('Log level for build output'),\n})\n","/**\n * Thrown when one or more errors occur during a Kubb build.\n * Carries the full list of underlying errors on `errors`.\n *\n * @example\n * ```ts\n * throw new BuildError('Build failed', { errors: [err1, err2] })\n * ```\n */\nexport class BuildError extends Error {\n errors: Array<Error>\n\n constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {\n super(message, { cause: options.cause })\n this.name = 'BuildError'\n this.errors = options.errors\n }\n}\n\n/**\n * Coerces an unknown thrown value to an `Error` instance.\n * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.\n *\n * @example\n * ```ts\n * try { ... } catch(err) {\n * throw new BuildError('Build failed', { cause: toError(err), errors: [] })\n * }\n * ```\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\n/**\n * Extracts a human-readable message from any thrown value.\n *\n * @example\n * ```ts\n * getErrorMessage(new Error('oops')) // 'oops'\n * getErrorMessage('plain string') // 'plain string'\n * ```\n */\nexport function getErrorMessage(value: unknown): string {\n return value instanceof Error ? value.message : String(value)\n}\n\n/**\n * Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.\n *\n * @example\n * ```ts\n * const cause = toCause(buildError) // Error | undefined\n * ```\n */\nexport function toCause(error: Error): Error | undefined {\n return error.cause instanceof Error ? error.cause : undefined\n}\n","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from './errors.ts'\n\n/**\n * A function that can be registered as an event listener, synchronous or async.\n */\ntype AsyncListener<TArgs extends unknown[]> = (...args: TArgs) => void | Promise<void>\n\n/**\n * Typed `EventEmitter` that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript event-map inference.\n *\n * @example\n * ```ts\n * const emitter = new AsyncEventEmitter<{ build: [name: string] }>()\n * emitter.on('build', async (name) => { console.log(name) })\n * await emitter.emit('build', 'petstore') // all listeners awaited\n * ```\n */\nexport class AsyncEventEmitter<TEvents extends { [K in keyof TEvents]: unknown[] }> {\n /**\n * Maximum number of listeners per event before Node emits a memory-leak warning.\n * @default 10\n */\n constructor(maxListener = 10) {\n this.#emitter.setMaxListeners(maxListener)\n }\n\n #emitter = new NodeEventEmitter()\n\n /**\n * Emits `eventName` and awaits all registered listeners sequentially.\n * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.\n *\n * @example\n * ```ts\n * await emitter.emit('build', 'petstore')\n * ```\n */\n async emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArgs: TEvents[TEventName]): Promise<void> {\n const listeners = this.#emitter.listeners(eventName) as Array<AsyncListener<TEvents[TEventName]>>\n\n if (listeners.length === 0) {\n return\n }\n\n for (const listener of listeners) {\n try {\n await listener(...eventArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(eventArgs)\n } catch {\n serializedArgs = String(eventArgs)\n }\n throw new Error(`Error in async listener for \"${eventName}\" with eventArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }\n }\n\n /**\n * Registers a persistent listener for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', async (name) => { console.log(name) })\n * ```\n */\n on<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.on(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Registers a one-shot listener that removes itself after the first invocation.\n *\n * @example\n * ```ts\n * emitter.onOnce('build', async (name) => { console.log(name) })\n * ```\n */\n onOnce<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n const wrapper: AsyncListener<TEvents[TEventName]> = (...args) => {\n this.off(eventName, wrapper)\n return handler(...args)\n }\n this.on(eventName, wrapper)\n }\n\n /**\n * Removes a previously registered listener.\n *\n * @example\n * ```ts\n * emitter.off('build', handler)\n * ```\n */\n off<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.off(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Returns the number of listeners registered for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', handler)\n * emitter.listenerCount('build') // 1\n * ```\n */\n listenerCount<TEventName extends keyof TEvents & string>(eventName: TEventName): number {\n return this.#emitter.listenerCount(eventName)\n }\n\n /**\n * Removes all listeners from every event channel.\n *\n * @example\n * ```ts\n * emitter.removeAll()\n * ```\n */\n removeAll(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","/** A value that may already be resolved or still pending.\n *\n * @example\n * ```ts\n * function load(id: string): PossiblePromise<string> {\n * return cache.get(id) ?? fetchRemote(id)\n * }\n * ```\n */\nexport type PossiblePromise<T> = Promise<T> | T\n\n/** Returns `true` when `result` is a thenable `Promise`.\n *\n * @example\n * ```ts\n * isPromise(Promise.resolve(1)) // true\n * isPromise(42) // false\n * ```\n */\nexport function isPromise<T>(result: PossiblePromise<T>): result is Promise<T> {\n return result !== null && result !== undefined && typeof (result as Record<string, unknown>)['then'] === 'function'\n}\n\n/** Returns `true` when `result` is a fulfilled `Promise.allSettled` result.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseFulfilledResult).map((r) => r.value)\n * ```\n */\nexport function isPromiseFulfilledResult<T = unknown>(result: PromiseSettledResult<unknown>): result is PromiseFulfilledResult<T> {\n return result.status === 'fulfilled'\n}\n\n/** Returns `true` when `result` is a rejected `Promise.allSettled` result with a typed `reason`.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseRejectedResult<Error>).map((r) => r.reason.message)\n * ```\n */\nexport function isPromiseRejectedResult<T>(result: PromiseSettledResult<unknown>): result is Omit<PromiseRejectedResult, 'reason'> & { reason: T } {\n return result.status === 'rejected'\n}\n","export const NotifyTypes = {\n INFO: 'INFO',\n SUCCESS: 'SUCCESS',\n ERROR: 'ERROR',\n WARN: 'WARN',\n PLUGIN_START: 'PLUGIN_START',\n PLUGIN_END: 'PLUGIN_END',\n FILES_START: 'FILES_START',\n FILE_UPDATE: 'FILE_UPDATE',\n FILES_END: 'FILES_END',\n GENERATION_START: 'GENERATION_START',\n GENERATION_END: 'GENERATION_END',\n CONFIG_LOADED: 'CONFIG_LOADED',\n CONFIG_ERROR: 'CONFIG_ERROR',\n CONFIG_READY: 'CONFIG_READY',\n SETUP_START: 'SETUP_START',\n SETUP_END: 'SETUP_END',\n BUILD_START: 'BUILD_START',\n BUILD_END: 'BUILD_END',\n BUILD_FAILED: 'BUILD_FAILED',\n BUILD_SUCCESS: 'BUILD_SUCCESS',\n FATAL_ERROR: 'FATAL_ERROR',\n} as const\n","import path from 'node:path'\nimport type { Config } from '@kubb/core'\nimport createJiti from 'jiti'\nimport { NotifyTypes } from '../types.ts'\n\ntype NotifyFunction = (type: string, message: string, data?: Record<string, unknown>) => Promise<void>\n\nconst jiti = createJiti(import.meta.url, {\n sourceMaps: true,\n})\n\n/**\n * Load the user configuration from the specified path or current directory\n */\nexport async function loadUserConfig(configPath: string | undefined, { notify }: { notify: NotifyFunction }): Promise<{ userConfig: Config; cwd: string }> {\n let userConfig: Config | undefined\n let cwd: string\n\n if (configPath) {\n // Resolve the config path to absolute path and get its directory\n cwd = path.dirname(path.resolve(configPath))\n\n // Try to load from path\n try {\n userConfig = await jiti.import(configPath, { default: true })\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${configPath}`)\n } catch (error) {\n await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n }\n } else {\n // Look for kubb.config in current directory with various extensions\n cwd = process.cwd()\n const configFileNames = ['kubb.config.ts', 'kubb.config.mts', 'kubb.config.cts', 'kubb.config.js', 'kubb.config.cjs']\n\n for (const configFileName of configFileNames) {\n try {\n const configFilePath = path.resolve(process.cwd(), configFileName)\n userConfig = await jiti.import(configFilePath, { default: true })\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)\n break\n } catch {\n // Continue trying next config file\n }\n }\n\n if (!userConfig) {\n await notify(NotifyTypes.CONFIG_ERROR, 'No config file found')\n\n throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(', ')}`)\n }\n }\n\n return { userConfig: userConfig!, cwd }\n}\n","import path from 'node:path'\nimport type { Config } from '@kubb/core'\n\n/**\n * Determine the root directory based on userConfig.root and resolvedConfigDir\n * 1. If userConfig.root exists and is absolute, use it as-is\n * 2. If userConfig.root exists and is relative, resolve it relative to config directory\n * 3. Otherwise, use the config directory as root\n */\nexport function resolveCwd(userConfig: Config, cwd: string): string {\n if (userConfig.root) {\n if (path.isAbsolute(userConfig.root)) {\n return userConfig.root\n }\n\n return path.resolve(cwd, userConfig.root)\n }\n\n return cwd\n}\n","import { isPromise } from '@internals/utils'\nimport type { CLIOptions, Config } from '@kubb/core'\n\nexport type ResolveUserConfigOptions = {\n configPath?: string\n logLevel?: string\n}\n\n/**\n * Resolve the config by handling function configs and returning the final configuration\n */\nexport async function resolveUserConfig(config: Config, options: ResolveUserConfigOptions): Promise<Config> {\n let kubbUserConfig = Promise.resolve(config) as Promise<Config>\n\n if (typeof config === 'function') {\n const possiblePromise = (config as any)({\n logLevel: options.logLevel,\n config: options.configPath,\n } as CLIOptions)\n if (isPromise(possiblePromise)) {\n kubbUserConfig = possiblePromise\n } else {\n kubbUserConfig = Promise.resolve(possiblePromise)\n }\n }\n\n return (await kubbUserConfig) as Config\n}\n","import { AsyncEventEmitter } from '@internals/utils'\nimport { type Config, createKubb, type KubbHooks } from '@kubb/core'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.d.ts'\nimport type { z } from 'zod'\nimport type { generateSchema } from '../schemas/generateSchema.ts'\nimport { NotifyTypes } from '../types.ts'\nimport { loadUserConfig } from '../utils/loadUserConfig.ts'\nimport { resolveCwd } from '../utils/resolveCwd.ts'\nimport { resolveUserConfig } from '../utils/resolveUserConfig.ts'\n\ninterface NotificationHandler {\n sendNotification(method: string, params: unknown): Promise<void>\n}\n\n/**\n * Build tool that generates code from OpenAPI specs using Kubb.\n * Sends real-time notifications of build progress and events.\n */\nexport async function generate(schema: z.infer<typeof generateSchema>, handler: NotificationHandler): Promise<CallToolResult> {\n const { config: configPath, input, output, logLevel } = schema\n\n try {\n const hooks = new AsyncEventEmitter<KubbHooks>()\n const messages: string[] = []\n\n // Helper to send notifications\n const notify = async (type: string, message: string, data?: Record<string, unknown>) => {\n messages.push(`${type}: ${message}`)\n\n await handler.sendNotification('kubb/progress', {\n type,\n message,\n timestamp: new Date().toISOString(),\n ...data,\n })\n }\n\n // Capture events for output and send notifications\n hooks.on('kubb:info', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.INFO, message)\n })\n\n hooks.on('kubb:success', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.SUCCESS, message)\n })\n\n hooks.on('kubb:error', async ({ error }: { error: Error }) => {\n await notify(NotifyTypes.ERROR, error.message, { stack: error.stack })\n })\n\n hooks.on('kubb:warn', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.WARN, message)\n })\n\n // Plugin lifecycle events\n hooks.on('kubb:plugin:start', async ({ plugin }) => {\n await notify(NotifyTypes.PLUGIN_START, `Plugin starting: ${plugin.name}`)\n })\n\n hooks.on('kubb:plugin:end', async ({ plugin, duration }) => {\n await notify(NotifyTypes.PLUGIN_END, `Plugin finished: ${plugin.name}`, {\n duration,\n })\n })\n\n // File processing events\n hooks.on('kubb:files:processing:start', async () => {\n await notify(NotifyTypes.FILES_START, 'Starting file processing')\n })\n\n hooks.on('kubb:file:processing:update', async ({ file }: { file: { name: string } }) => {\n await notify(NotifyTypes.FILE_UPDATE, `Processing file: ${file.name}`)\n })\n\n hooks.on('kubb:files:processing:end', async () => {\n await notify(NotifyTypes.FILES_END, 'File processing complete')\n })\n\n // Generation events\n hooks.on('kubb:generation:start', async () => {\n await notify(NotifyTypes.GENERATION_START, 'Generation started')\n })\n\n hooks.on('kubb:generation:end', async () => {\n await notify(NotifyTypes.GENERATION_END, 'Generation ended')\n })\n\n // Load and process configuration\n let userConfig: Config\n let cwd: string\n\n try {\n const configResult = await loadUserConfig(configPath, { notify })\n userConfig = configResult.userConfig\n cwd = configResult.cwd\n\n if (Array.isArray(userConfig) && userConfig.length) {\n throw new Error('Array type in kubb.config.ts is not supported in this tool. Please provide a single configuration object.')\n }\n\n userConfig = await resolveUserConfig(userConfig, {\n configPath,\n logLevel,\n })\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n await notify(NotifyTypes.CONFIG_ERROR, errorMessage)\n return {\n content: [\n {\n type: 'text',\n text: errorMessage,\n },\n ],\n isError: true,\n }\n }\n\n const inputPath = input ?? ('path' in userConfig.input ? userConfig.input.path : undefined)\n\n // Override config with CLI options\n const config: Config = {\n ...userConfig,\n root: resolveCwd(userConfig, cwd),\n input: inputPath\n ? {\n ...userConfig.input,\n path: inputPath,\n }\n : userConfig.input,\n output: output\n ? {\n ...userConfig.output,\n path: output,\n }\n : userConfig.output,\n }\n\n await notify(NotifyTypes.CONFIG_READY, 'Configuration ready', {\n root: config.root,\n })\n\n // Setup and build\n await notify(NotifyTypes.SETUP_START, 'Setting up Kubb')\n\n const kubb = createKubb(config, { hooks })\n await kubb.setup()\n await notify(NotifyTypes.SETUP_END, 'Kubb setup complete')\n\n await notify(NotifyTypes.BUILD_START, 'Starting build')\n const { files, failedPlugins, error } = await kubb.safeBuild()\n await notify(NotifyTypes.BUILD_END, `Build complete - Generated ${files.length} files`)\n\n if (error || failedPlugins.size > 0) {\n const allErrors: Error[] = [\n error,\n ...Array.from(failedPlugins)\n .filter((it) => it.error)\n .map((it) => it.error),\n ].filter(Boolean)\n\n await notify(NotifyTypes.BUILD_FAILED, `Build failed with ${allErrors.length} error(s)`, {\n errorCount: allErrors.length,\n errors: allErrors.map((err) => err.message),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build failed:\\n${allErrors.map((err) => err.message).join('\\n')}\\n\\n${messages.join('\\n')}`,\n },\n ],\n isError: true,\n }\n }\n\n await notify(NotifyTypes.BUILD_SUCCESS, `Build completed successfully - Generated ${files.length} files`, {\n filesCount: files.length,\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build completed successfully!\\n\\nGenerated ${files.length} files\\n\\n${messages.join('\\n')}`,\n },\n ],\n }\n } catch (caughtError) {\n const error = caughtError as Error\n\n await handler.sendNotification('kubb/progress', {\n type: NotifyTypes.FATAL_ERROR,\n message: error.message,\n stack: error.stack,\n timestamp: new Date().toISOString(),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build error: ${error.message}\\n${error.stack || ''}`,\n },\n ],\n isError: true,\n }\n }\n}\n","import process from 'node:process'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { version } from '../package.json'\nimport { generateSchema } from './schemas/generateSchema.ts'\nimport { generate } from './tools/generate.ts'\n\n/**\n * Kubb MCP Server\n *\n * Provides tools for building OpenAPI specifications using Kubb.\n */\nexport async function startServer() {\n try {\n const transport = new StdioServerTransport()\n const server = new McpServer({\n name: 'Kubb',\n version,\n })\n\n // Build tool - runs Kubb build using @kubb/core\n // Wrapped to pass notification handler for real-time progress updates\n server.tool('generate', 'Generate OpenAPI spec helpers using Kubb configuration', generateSchema.shape, async (args) => {\n // Create notification handler that sends events back to the client\n const notificationHandler = {\n sendNotification: async (method: string, params: any) => {\n try {\n await transport.send({\n jsonrpc: '2.0',\n method,\n params,\n })\n } catch (error) {\n console.error('Failed to send notification:', error)\n }\n },\n }\n\n // Call build tool with notification handler\n return generate(args, notificationHandler)\n })\n\n await server.connect(transport)\n } catch (error) {\n console.error('Failed to start MCP server:', error)\n process.exit(1)\n }\n}\n","import { startServer } from './server.ts'\n\nexport async function run(_argv?: string[]): Promise<void> {\n await startServer()\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["z","#emitter","NodeEventEmitter","path","path","StdioServerTransport","McpServer"],"sources":["../package.json","../src/schemas/generateSchema.ts","../../../internals/utils/src/errors.ts","../../../internals/utils/src/asyncEventEmitter.ts","../../../internals/utils/src/promise.ts","../src/types.ts","../src/constants.ts","../src/utils/loadUserConfig.ts","../src/utils/resolveCwd.ts","../src/utils/resolveUserConfig.ts","../src/tools/generate.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["","import { z } from 'zod'\n\nexport const generateSchema = z.object({\n config: z\n .string()\n .optional()\n\n .describe('Path to kubb.config file (supports .ts, .js, .cjs). If not provided, will look for kubb.config.{ts,js,cjs} in current directory'),\n input: z.string().optional().describe('Path to OpenAPI/Swagger spec file (overrides config)'),\n output: z.string().optional().describe('Output directory path (overrides config)'),\n logLevel: z.enum(['silent', 'error', 'warn', 'info', 'verbose', 'debug']).optional().default('info').describe('Log level for build output'),\n})\n","/**\n * Thrown when one or more errors occur during a Kubb build.\n * Carries the full list of underlying errors on `errors`.\n *\n * @example\n * ```ts\n * throw new BuildError('Build failed', { errors: [err1, err2] })\n * ```\n */\nexport class BuildError extends Error {\n errors: Array<Error>\n\n constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {\n super(message, { cause: options.cause })\n this.name = 'BuildError'\n this.errors = options.errors\n }\n}\n\n/**\n * Coerces an unknown thrown value to an `Error` instance.\n * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.\n *\n * @example\n * ```ts\n * try { ... } catch(err) {\n * throw new BuildError('Build failed', { cause: toError(err), errors: [] })\n * }\n * ```\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\n/**\n * Extracts a human-readable message from any thrown value.\n *\n * @example\n * ```ts\n * getErrorMessage(new Error('oops')) // 'oops'\n * getErrorMessage('plain string') // 'plain string'\n * ```\n */\nexport function getErrorMessage(value: unknown): string {\n return value instanceof Error ? value.message : String(value)\n}\n\n/**\n * Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.\n *\n * @example\n * ```ts\n * const cause = toCause(buildError) // Error | undefined\n * ```\n */\nexport function toCause(error: Error): Error | undefined {\n return error.cause instanceof Error ? error.cause : undefined\n}\n","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from './errors.ts'\n\n/**\n * A function that can be registered as an event listener, synchronous or async.\n */\ntype AsyncListener<TArgs extends unknown[]> = (...args: TArgs) => void | Promise<void>\n\n/**\n * Typed `EventEmitter` that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript event-map inference.\n *\n * @example\n * ```ts\n * const emitter = new AsyncEventEmitter<{ build: [name: string] }>()\n * emitter.on('build', async (name) => { console.log(name) })\n * await emitter.emit('build', 'petstore') // all listeners awaited\n * ```\n */\nexport class AsyncEventEmitter<TEvents extends { [K in keyof TEvents]: unknown[] }> {\n /**\n * Maximum number of listeners per event before Node emits a memory-leak warning.\n * @default 10\n */\n constructor(maxListener = 10) {\n this.#emitter.setMaxListeners(maxListener)\n }\n\n #emitter = new NodeEventEmitter()\n\n /**\n * Emits `eventName` and awaits all registered listeners sequentially.\n * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.\n *\n * @example\n * ```ts\n * await emitter.emit('build', 'petstore')\n * ```\n */\n async emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArgs: TEvents[TEventName]): Promise<void> {\n const listeners = this.#emitter.listeners(eventName) as Array<AsyncListener<TEvents[TEventName]>>\n\n if (listeners.length === 0) {\n return\n }\n\n for (const listener of listeners) {\n try {\n await listener(...eventArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(eventArgs)\n } catch {\n serializedArgs = String(eventArgs)\n }\n throw new Error(`Error in async listener for \"${eventName}\" with eventArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }\n }\n\n /**\n * Registers a persistent listener for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', async (name) => { console.log(name) })\n * ```\n */\n on<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.on(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Registers a one-shot listener that removes itself after the first invocation.\n *\n * @example\n * ```ts\n * emitter.onOnce('build', async (name) => { console.log(name) })\n * ```\n */\n onOnce<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n const wrapper: AsyncListener<TEvents[TEventName]> = (...args) => {\n this.off(eventName, wrapper)\n return handler(...args)\n }\n this.on(eventName, wrapper)\n }\n\n /**\n * Removes a previously registered listener.\n *\n * @example\n * ```ts\n * emitter.off('build', handler)\n * ```\n */\n off<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.off(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Returns the number of listeners registered for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', handler)\n * emitter.listenerCount('build') // 1\n * ```\n */\n listenerCount<TEventName extends keyof TEvents & string>(eventName: TEventName): number {\n return this.#emitter.listenerCount(eventName)\n }\n\n /**\n * Removes all listeners from every event channel.\n *\n * @example\n * ```ts\n * emitter.removeAll()\n * ```\n */\n removeAll(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","/** A value that may already be resolved or still pending.\n *\n * @example\n * ```ts\n * function load(id: string): PossiblePromise<string> {\n * return cache.get(id) ?? fetchRemote(id)\n * }\n * ```\n */\nexport type PossiblePromise<T> = Promise<T> | T\n\n/** Returns `true` when `result` is a thenable `Promise`.\n *\n * @example\n * ```ts\n * isPromise(Promise.resolve(1)) // true\n * isPromise(42) // false\n * ```\n */\nexport function isPromise<T>(result: PossiblePromise<T>): result is Promise<T> {\n return result !== null && result !== undefined && typeof (result as Record<string, unknown>)['then'] === 'function'\n}\n\n/** Returns `true` when `result` is a fulfilled `Promise.allSettled` result.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseFulfilledResult).map((r) => r.value)\n * ```\n */\nexport function isPromiseFulfilledResult<T = unknown>(result: PromiseSettledResult<unknown>): result is PromiseFulfilledResult<T> {\n return result.status === 'fulfilled'\n}\n\n/** Returns `true` when `result` is a rejected `Promise.allSettled` result with a typed `reason`.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseRejectedResult<Error>).map((r) => r.reason.message)\n * ```\n */\nexport function isPromiseRejectedResult<T>(result: PromiseSettledResult<unknown>): result is Omit<PromiseRejectedResult, 'reason'> & { reason: T } {\n return result.status === 'rejected'\n}\n","export const NotifyTypes = {\n INFO: 'INFO',\n SUCCESS: 'SUCCESS',\n ERROR: 'ERROR',\n WARN: 'WARN',\n PLUGIN_START: 'PLUGIN_START',\n PLUGIN_END: 'PLUGIN_END',\n FILES_START: 'FILES_START',\n FILE_UPDATE: 'FILE_UPDATE',\n FILES_END: 'FILES_END',\n GENERATION_START: 'GENERATION_START',\n GENERATION_END: 'GENERATION_END',\n CONFIG_LOADED: 'CONFIG_LOADED',\n CONFIG_ERROR: 'CONFIG_ERROR',\n CONFIG_READY: 'CONFIG_READY',\n SETUP_START: 'SETUP_START',\n SETUP_END: 'SETUP_END',\n BUILD_START: 'BUILD_START',\n BUILD_END: 'BUILD_END',\n BUILD_FAILED: 'BUILD_FAILED',\n BUILD_SUCCESS: 'BUILD_SUCCESS',\n FATAL_ERROR: 'FATAL_ERROR',\n} as const\n","export const ALLOWED_CONFIG_EXTENSIONS = new Set(['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'])\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport type { Config } from '@kubb/core'\nimport { unrun } from 'unrun'\nimport { ALLOWED_CONFIG_EXTENSIONS } from '../constants.ts'\nimport { NotifyTypes } from '../types.ts'\n\ntype NotifyFunction = (type: string, message: string, data?: Record<string, unknown>) => Promise<void>\n\nconst loadedModules = new Map<string, unknown>()\n\nasync function loadModule(filePath: string): Promise<unknown> {\n const ext = path.extname(filePath)\n if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {\n throw new Error(`Invalid config file extension \"${ext}\". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`)\n }\n if (loadedModules.has(filePath)) {\n return loadedModules.get(filePath)\n }\n const { module } = await unrun({ path: filePath })\n loadedModules.set(filePath, module)\n return module\n}\n\nexport async function loadUserConfig(configPath: string | undefined, { notify }: { notify: NotifyFunction }): Promise<{ userConfig: Config; cwd: string }> {\n let userConfig: Config | undefined\n let cwd: string\n\n if (configPath) {\n const ext = path.extname(configPath)\n if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {\n const msg = `Invalid config file extension \"${ext}\". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`\n await notify(NotifyTypes.CONFIG_ERROR, msg)\n throw new Error(msg)\n }\n const base = path.resolve(process.cwd())\n const resolvedConfigPath = path.resolve(base, configPath)\n const relative = path.relative(base, resolvedConfigPath)\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n const msg = 'Invalid config file path: must be within the current working directory'\n await notify(NotifyTypes.CONFIG_ERROR, msg)\n throw new Error(msg)\n }\n cwd = path.dirname(resolvedConfigPath)\n\n try {\n userConfig = (await loadModule(resolvedConfigPath)) as Config\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${resolvedConfigPath}`)\n } catch (error) {\n await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n }\n } else {\n cwd = process.cwd()\n const configFileNames = ['kubb.config.ts', 'kubb.config.mts', 'kubb.config.cts', 'kubb.config.js', 'kubb.config.cjs']\n\n for (const configFileName of configFileNames) {\n const configFilePath = path.resolve(process.cwd(), configFileName)\n if (!existsSync(configFilePath)) continue\n try {\n userConfig = (await loadModule(configFilePath)) as Config\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)\n break\n } catch {\n // Continue trying next config file\n }\n }\n\n if (!userConfig) {\n await notify(NotifyTypes.CONFIG_ERROR, 'No config file found')\n\n throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(', ')}`)\n }\n }\n\n return { userConfig: userConfig!, cwd }\n}\n","import path from 'node:path'\nimport type { Config } from '@kubb/core'\n\n/**\n * Determine the root directory based on userConfig.root and resolvedConfigDir\n * 1. If userConfig.root exists and is absolute, use it as-is\n * 2. If userConfig.root exists and is relative, resolve it relative to config directory\n * 3. Otherwise, use the config directory as root\n */\nexport function resolveCwd(userConfig: Config, cwd: string): string {\n if (userConfig.root) {\n if (path.isAbsolute(userConfig.root)) {\n return userConfig.root\n }\n\n return path.resolve(cwd, userConfig.root)\n }\n\n return cwd\n}\n","import { isPromise } from '@internals/utils'\nimport type { CLIOptions, Config } from '@kubb/core'\n\nexport type ResolveUserConfigOptions = {\n configPath?: string\n logLevel?: string\n}\n\n/**\n * Resolve the config by handling function configs and returning the final configuration\n */\nexport async function resolveUserConfig(config: Config, options: ResolveUserConfigOptions): Promise<Config> {\n let kubbUserConfig = Promise.resolve(config) as Promise<Config>\n\n if (typeof config === 'function') {\n const possiblePromise = (config as any)({\n logLevel: options.logLevel,\n config: options.configPath,\n } as CLIOptions)\n if (isPromise(possiblePromise)) {\n kubbUserConfig = possiblePromise\n } else {\n kubbUserConfig = Promise.resolve(possiblePromise)\n }\n }\n\n return (await kubbUserConfig) as Config\n}\n","import { AsyncEventEmitter } from '@internals/utils'\nimport { type Config, createKubb, type KubbHooks } from '@kubb/core'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.d.ts'\nimport type { z } from 'zod'\nimport type { generateSchema } from '../schemas/generateSchema.ts'\nimport { NotifyTypes } from '../types.ts'\nimport { loadUserConfig } from '../utils/loadUserConfig.ts'\nimport { resolveCwd } from '../utils/resolveCwd.ts'\nimport { resolveUserConfig } from '../utils/resolveUserConfig.ts'\n\ninterface NotificationHandler {\n sendNotification(method: string, params: unknown): Promise<void>\n}\n\n/**\n * Build tool that generates code from OpenAPI specs using Kubb.\n * Sends real-time notifications of build progress and events.\n */\nexport async function generate(schema: z.infer<typeof generateSchema>, handler: NotificationHandler): Promise<CallToolResult> {\n const { config: configPath, input, output, logLevel } = schema\n\n try {\n const hooks = new AsyncEventEmitter<KubbHooks>()\n const messages: string[] = []\n\n // Helper to send notifications\n const notify = async (type: string, message: string, data?: Record<string, unknown>) => {\n messages.push(`${type}: ${message}`)\n\n await handler.sendNotification('kubb/progress', {\n type,\n message,\n timestamp: new Date().toISOString(),\n ...data,\n })\n }\n\n // Capture events for output and send notifications\n hooks.on('kubb:info', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.INFO, message)\n })\n\n hooks.on('kubb:success', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.SUCCESS, message)\n })\n\n hooks.on('kubb:error', async ({ error }: { error: Error }) => {\n await notify(NotifyTypes.ERROR, error.message, { stack: error.stack })\n })\n\n hooks.on('kubb:warn', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.WARN, message)\n })\n\n // Plugin lifecycle events\n hooks.on('kubb:plugin:start', async ({ plugin }) => {\n await notify(NotifyTypes.PLUGIN_START, `Plugin starting: ${plugin.name}`)\n })\n\n hooks.on('kubb:plugin:end', async ({ plugin, duration }) => {\n await notify(NotifyTypes.PLUGIN_END, `Plugin finished: ${plugin.name}`, {\n duration,\n })\n })\n\n // File processing events\n hooks.on('kubb:files:processing:start', async () => {\n await notify(NotifyTypes.FILES_START, 'Starting file processing')\n })\n\n hooks.on('kubb:file:processing:update', async ({ file }: { file: { name: string } }) => {\n await notify(NotifyTypes.FILE_UPDATE, `Processing file: ${file.name}`)\n })\n\n hooks.on('kubb:files:processing:end', async () => {\n await notify(NotifyTypes.FILES_END, 'File processing complete')\n })\n\n // Generation events\n hooks.on('kubb:generation:start', async () => {\n await notify(NotifyTypes.GENERATION_START, 'Generation started')\n })\n\n hooks.on('kubb:generation:end', async () => {\n await notify(NotifyTypes.GENERATION_END, 'Generation ended')\n })\n\n // Load and process configuration\n let userConfig: Config\n let cwd: string\n\n try {\n const configResult = await loadUserConfig(configPath, { notify })\n userConfig = configResult.userConfig\n cwd = configResult.cwd\n\n if (Array.isArray(userConfig) && userConfig.length) {\n throw new Error('Array type in kubb.config.ts is not supported in this tool. Please provide a single configuration object.')\n }\n\n userConfig = await resolveUserConfig(userConfig, {\n configPath,\n logLevel,\n })\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n await notify(NotifyTypes.CONFIG_ERROR, errorMessage)\n return {\n content: [\n {\n type: 'text',\n text: errorMessage,\n },\n ],\n isError: true,\n }\n }\n\n const inputPath = input ?? ('path' in userConfig.input ? userConfig.input.path : undefined)\n\n // Override config with CLI options\n const config: Config = {\n ...userConfig,\n root: resolveCwd(userConfig, cwd),\n input: inputPath\n ? {\n ...userConfig.input,\n path: inputPath,\n }\n : userConfig.input,\n output: output\n ? {\n ...userConfig.output,\n path: output,\n }\n : userConfig.output,\n }\n\n await notify(NotifyTypes.CONFIG_READY, 'Configuration ready', {\n root: config.root,\n })\n\n // Setup and build\n await notify(NotifyTypes.SETUP_START, 'Setting up Kubb')\n\n const kubb = createKubb(config, { hooks })\n await kubb.setup()\n await notify(NotifyTypes.SETUP_END, 'Kubb setup complete')\n\n await notify(NotifyTypes.BUILD_START, 'Starting build')\n const { files, failedPlugins, error } = await kubb.safeBuild()\n await notify(NotifyTypes.BUILD_END, `Build complete - Generated ${files.length} files`)\n\n if (error || failedPlugins.size > 0) {\n const allErrors: Error[] = [\n error,\n ...Array.from(failedPlugins)\n .filter((it) => it.error)\n .map((it) => it.error),\n ].filter(Boolean)\n\n await notify(NotifyTypes.BUILD_FAILED, `Build failed with ${allErrors.length} error(s)`, {\n errorCount: allErrors.length,\n errors: allErrors.map((err) => err.message),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build failed:\\n${allErrors.map((err) => err.message).join('\\n')}\\n\\n${messages.join('\\n')}`,\n },\n ],\n isError: true,\n }\n }\n\n await notify(NotifyTypes.BUILD_SUCCESS, `Build completed successfully - Generated ${files.length} files`, {\n filesCount: files.length,\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build completed successfully!\\n\\nGenerated ${files.length} files\\n\\n${messages.join('\\n')}`,\n },\n ],\n }\n } catch (caughtError) {\n const error = caughtError as Error\n\n await handler.sendNotification('kubb/progress', {\n type: NotifyTypes.FATAL_ERROR,\n message: error.message,\n stack: error.stack,\n timestamp: new Date().toISOString(),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build error: ${error.message}\\n${error.stack || ''}`,\n },\n ],\n isError: true,\n }\n }\n}\n","import process from 'node:process'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { version } from '../package.json'\nimport { generateSchema } from './schemas/generateSchema.ts'\nimport { generate } from './tools/generate.ts'\n\n/**\n * Kubb MCP Server\n *\n * Provides tools for building OpenAPI specifications using Kubb.\n */\nexport async function startServer() {\n try {\n const transport = new StdioServerTransport()\n const server = new McpServer({\n name: 'Kubb',\n version,\n })\n\n // Build tool - runs Kubb build using @kubb/core\n // Wrapped to pass notification handler for real-time progress updates\n server.tool('generate', 'Generate OpenAPI spec helpers using Kubb configuration', generateSchema.shape, async (args) => {\n // Create notification handler that sends events back to the client\n const notificationHandler = {\n sendNotification: async (method: string, params: any) => {\n try {\n await transport.send({\n jsonrpc: '2.0',\n method,\n params,\n })\n } catch (error) {\n console.error('Failed to send notification:', error)\n }\n },\n }\n\n // Call build tool with notification handler\n return generate(args, notificationHandler)\n })\n\n await server.connect(transport)\n } catch (error) {\n console.error('Failed to start MCP server:', error)\n process.exit(1)\n }\n}\n","import { startServer } from './server.ts'\n\nexport async function run(_argv?: string[]): Promise<void> {\n await startServer()\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -4,11 +4,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
5
  import { z } from "zod";
6
6
  import { EventEmitter } from "node:events";
7
+ import { existsSync } from "node:fs";
7
8
  import path from "node:path";
8
9
  import { createKubb } from "@kubb/core";
9
- import createJiti from "jiti";
10
+ import { unrun } from "unrun";
10
11
  //#region package.json
11
- var version = "5.0.0-alpha.70";
12
+ var version = "5.0.0-alpha.71";
12
13
  //#endregion
13
14
  //#region src/schemas/generateSchema.ts
14
15
  const generateSchema = z.object({
@@ -186,19 +187,48 @@ const NotifyTypes = {
186
187
  FATAL_ERROR: "FATAL_ERROR"
187
188
  };
188
189
  //#endregion
190
+ //#region src/constants.ts
191
+ const ALLOWED_CONFIG_EXTENSIONS = new Set([
192
+ ".ts",
193
+ ".mts",
194
+ ".cts",
195
+ ".js",
196
+ ".mjs",
197
+ ".cjs"
198
+ ]);
199
+ //#endregion
189
200
  //#region src/utils/loadUserConfig.ts
190
- const jiti = createJiti(import.meta.url, { sourceMaps: true });
191
- /**
192
- * Load the user configuration from the specified path or current directory
193
- */
201
+ const loadedModules = /* @__PURE__ */ new Map();
202
+ async function loadModule(filePath) {
203
+ const ext = path.extname(filePath);
204
+ if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) throw new Error(`Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(", ")}`);
205
+ if (loadedModules.has(filePath)) return loadedModules.get(filePath);
206
+ const { module } = await unrun({ path: filePath });
207
+ loadedModules.set(filePath, module);
208
+ return module;
209
+ }
194
210
  async function loadUserConfig(configPath, { notify }) {
195
211
  let userConfig;
196
212
  let cwd;
197
213
  if (configPath) {
198
- cwd = path.dirname(path.resolve(configPath));
214
+ const ext = path.extname(configPath);
215
+ if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {
216
+ const msg = `Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(", ")}`;
217
+ await notify(NotifyTypes.CONFIG_ERROR, msg);
218
+ throw new Error(msg);
219
+ }
220
+ const base = path.resolve(process.cwd());
221
+ const resolvedConfigPath = path.resolve(base, configPath);
222
+ const relative = path.relative(base, resolvedConfigPath);
223
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
224
+ const msg = "Invalid config file path: must be within the current working directory";
225
+ await notify(NotifyTypes.CONFIG_ERROR, msg);
226
+ throw new Error(msg);
227
+ }
228
+ cwd = path.dirname(resolvedConfigPath);
199
229
  try {
200
- userConfig = await jiti.import(configPath, { default: true });
201
- await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${configPath}`);
230
+ userConfig = await loadModule(resolvedConfigPath);
231
+ await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${resolvedConfigPath}`);
202
232
  } catch (error) {
203
233
  await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
204
234
  throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
@@ -212,12 +242,15 @@ async function loadUserConfig(configPath, { notify }) {
212
242
  "kubb.config.js",
213
243
  "kubb.config.cjs"
214
244
  ];
215
- for (const configFileName of configFileNames) try {
245
+ for (const configFileName of configFileNames) {
216
246
  const configFilePath = path.resolve(process.cwd(), configFileName);
217
- userConfig = await jiti.import(configFilePath, { default: true });
218
- await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`);
219
- break;
220
- } catch {}
247
+ if (!existsSync(configFilePath)) continue;
248
+ try {
249
+ userConfig = await loadModule(configFilePath);
250
+ await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`);
251
+ break;
252
+ } catch {}
253
+ }
221
254
  if (!userConfig) {
222
255
  await notify(NotifyTypes.CONFIG_ERROR, "No config file found");
223
256
  throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(", ")}`);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["#emitter","NodeEventEmitter"],"sources":["../package.json","../src/schemas/generateSchema.ts","../../../internals/utils/src/errors.ts","../../../internals/utils/src/asyncEventEmitter.ts","../../../internals/utils/src/promise.ts","../src/types.ts","../src/utils/loadUserConfig.ts","../src/utils/resolveCwd.ts","../src/utils/resolveUserConfig.ts","../src/tools/generate.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["","import { z } from 'zod'\n\nexport const generateSchema = z.object({\n config: z\n .string()\n .optional()\n\n .describe('Path to kubb.config file (supports .ts, .js, .cjs). If not provided, will look for kubb.config.{ts,js,cjs} in current directory'),\n input: z.string().optional().describe('Path to OpenAPI/Swagger spec file (overrides config)'),\n output: z.string().optional().describe('Output directory path (overrides config)'),\n logLevel: z.enum(['silent', 'error', 'warn', 'info', 'verbose', 'debug']).optional().default('info').describe('Log level for build output'),\n})\n","/**\n * Thrown when one or more errors occur during a Kubb build.\n * Carries the full list of underlying errors on `errors`.\n *\n * @example\n * ```ts\n * throw new BuildError('Build failed', { errors: [err1, err2] })\n * ```\n */\nexport class BuildError extends Error {\n errors: Array<Error>\n\n constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {\n super(message, { cause: options.cause })\n this.name = 'BuildError'\n this.errors = options.errors\n }\n}\n\n/**\n * Coerces an unknown thrown value to an `Error` instance.\n * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.\n *\n * @example\n * ```ts\n * try { ... } catch(err) {\n * throw new BuildError('Build failed', { cause: toError(err), errors: [] })\n * }\n * ```\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\n/**\n * Extracts a human-readable message from any thrown value.\n *\n * @example\n * ```ts\n * getErrorMessage(new Error('oops')) // 'oops'\n * getErrorMessage('plain string') // 'plain string'\n * ```\n */\nexport function getErrorMessage(value: unknown): string {\n return value instanceof Error ? value.message : String(value)\n}\n\n/**\n * Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.\n *\n * @example\n * ```ts\n * const cause = toCause(buildError) // Error | undefined\n * ```\n */\nexport function toCause(error: Error): Error | undefined {\n return error.cause instanceof Error ? error.cause : undefined\n}\n","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from './errors.ts'\n\n/**\n * A function that can be registered as an event listener, synchronous or async.\n */\ntype AsyncListener<TArgs extends unknown[]> = (...args: TArgs) => void | Promise<void>\n\n/**\n * Typed `EventEmitter` that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript event-map inference.\n *\n * @example\n * ```ts\n * const emitter = new AsyncEventEmitter<{ build: [name: string] }>()\n * emitter.on('build', async (name) => { console.log(name) })\n * await emitter.emit('build', 'petstore') // all listeners awaited\n * ```\n */\nexport class AsyncEventEmitter<TEvents extends { [K in keyof TEvents]: unknown[] }> {\n /**\n * Maximum number of listeners per event before Node emits a memory-leak warning.\n * @default 10\n */\n constructor(maxListener = 10) {\n this.#emitter.setMaxListeners(maxListener)\n }\n\n #emitter = new NodeEventEmitter()\n\n /**\n * Emits `eventName` and awaits all registered listeners sequentially.\n * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.\n *\n * @example\n * ```ts\n * await emitter.emit('build', 'petstore')\n * ```\n */\n async emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArgs: TEvents[TEventName]): Promise<void> {\n const listeners = this.#emitter.listeners(eventName) as Array<AsyncListener<TEvents[TEventName]>>\n\n if (listeners.length === 0) {\n return\n }\n\n for (const listener of listeners) {\n try {\n await listener(...eventArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(eventArgs)\n } catch {\n serializedArgs = String(eventArgs)\n }\n throw new Error(`Error in async listener for \"${eventName}\" with eventArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }\n }\n\n /**\n * Registers a persistent listener for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', async (name) => { console.log(name) })\n * ```\n */\n on<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.on(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Registers a one-shot listener that removes itself after the first invocation.\n *\n * @example\n * ```ts\n * emitter.onOnce('build', async (name) => { console.log(name) })\n * ```\n */\n onOnce<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n const wrapper: AsyncListener<TEvents[TEventName]> = (...args) => {\n this.off(eventName, wrapper)\n return handler(...args)\n }\n this.on(eventName, wrapper)\n }\n\n /**\n * Removes a previously registered listener.\n *\n * @example\n * ```ts\n * emitter.off('build', handler)\n * ```\n */\n off<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.off(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Returns the number of listeners registered for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', handler)\n * emitter.listenerCount('build') // 1\n * ```\n */\n listenerCount<TEventName extends keyof TEvents & string>(eventName: TEventName): number {\n return this.#emitter.listenerCount(eventName)\n }\n\n /**\n * Removes all listeners from every event channel.\n *\n * @example\n * ```ts\n * emitter.removeAll()\n * ```\n */\n removeAll(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","/** A value that may already be resolved or still pending.\n *\n * @example\n * ```ts\n * function load(id: string): PossiblePromise<string> {\n * return cache.get(id) ?? fetchRemote(id)\n * }\n * ```\n */\nexport type PossiblePromise<T> = Promise<T> | T\n\n/** Returns `true` when `result` is a thenable `Promise`.\n *\n * @example\n * ```ts\n * isPromise(Promise.resolve(1)) // true\n * isPromise(42) // false\n * ```\n */\nexport function isPromise<T>(result: PossiblePromise<T>): result is Promise<T> {\n return result !== null && result !== undefined && typeof (result as Record<string, unknown>)['then'] === 'function'\n}\n\n/** Returns `true` when `result` is a fulfilled `Promise.allSettled` result.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseFulfilledResult).map((r) => r.value)\n * ```\n */\nexport function isPromiseFulfilledResult<T = unknown>(result: PromiseSettledResult<unknown>): result is PromiseFulfilledResult<T> {\n return result.status === 'fulfilled'\n}\n\n/** Returns `true` when `result` is a rejected `Promise.allSettled` result with a typed `reason`.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseRejectedResult<Error>).map((r) => r.reason.message)\n * ```\n */\nexport function isPromiseRejectedResult<T>(result: PromiseSettledResult<unknown>): result is Omit<PromiseRejectedResult, 'reason'> & { reason: T } {\n return result.status === 'rejected'\n}\n","export const NotifyTypes = {\n INFO: 'INFO',\n SUCCESS: 'SUCCESS',\n ERROR: 'ERROR',\n WARN: 'WARN',\n PLUGIN_START: 'PLUGIN_START',\n PLUGIN_END: 'PLUGIN_END',\n FILES_START: 'FILES_START',\n FILE_UPDATE: 'FILE_UPDATE',\n FILES_END: 'FILES_END',\n GENERATION_START: 'GENERATION_START',\n GENERATION_END: 'GENERATION_END',\n CONFIG_LOADED: 'CONFIG_LOADED',\n CONFIG_ERROR: 'CONFIG_ERROR',\n CONFIG_READY: 'CONFIG_READY',\n SETUP_START: 'SETUP_START',\n SETUP_END: 'SETUP_END',\n BUILD_START: 'BUILD_START',\n BUILD_END: 'BUILD_END',\n BUILD_FAILED: 'BUILD_FAILED',\n BUILD_SUCCESS: 'BUILD_SUCCESS',\n FATAL_ERROR: 'FATAL_ERROR',\n} as const\n","import path from 'node:path'\nimport type { Config } from '@kubb/core'\nimport createJiti from 'jiti'\nimport { NotifyTypes } from '../types.ts'\n\ntype NotifyFunction = (type: string, message: string, data?: Record<string, unknown>) => Promise<void>\n\nconst jiti = createJiti(import.meta.url, {\n sourceMaps: true,\n})\n\n/**\n * Load the user configuration from the specified path or current directory\n */\nexport async function loadUserConfig(configPath: string | undefined, { notify }: { notify: NotifyFunction }): Promise<{ userConfig: Config; cwd: string }> {\n let userConfig: Config | undefined\n let cwd: string\n\n if (configPath) {\n // Resolve the config path to absolute path and get its directory\n cwd = path.dirname(path.resolve(configPath))\n\n // Try to load from path\n try {\n userConfig = await jiti.import(configPath, { default: true })\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${configPath}`)\n } catch (error) {\n await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n }\n } else {\n // Look for kubb.config in current directory with various extensions\n cwd = process.cwd()\n const configFileNames = ['kubb.config.ts', 'kubb.config.mts', 'kubb.config.cts', 'kubb.config.js', 'kubb.config.cjs']\n\n for (const configFileName of configFileNames) {\n try {\n const configFilePath = path.resolve(process.cwd(), configFileName)\n userConfig = await jiti.import(configFilePath, { default: true })\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)\n break\n } catch {\n // Continue trying next config file\n }\n }\n\n if (!userConfig) {\n await notify(NotifyTypes.CONFIG_ERROR, 'No config file found')\n\n throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(', ')}`)\n }\n }\n\n return { userConfig: userConfig!, cwd }\n}\n","import path from 'node:path'\nimport type { Config } from '@kubb/core'\n\n/**\n * Determine the root directory based on userConfig.root and resolvedConfigDir\n * 1. If userConfig.root exists and is absolute, use it as-is\n * 2. If userConfig.root exists and is relative, resolve it relative to config directory\n * 3. Otherwise, use the config directory as root\n */\nexport function resolveCwd(userConfig: Config, cwd: string): string {\n if (userConfig.root) {\n if (path.isAbsolute(userConfig.root)) {\n return userConfig.root\n }\n\n return path.resolve(cwd, userConfig.root)\n }\n\n return cwd\n}\n","import { isPromise } from '@internals/utils'\nimport type { CLIOptions, Config } from '@kubb/core'\n\nexport type ResolveUserConfigOptions = {\n configPath?: string\n logLevel?: string\n}\n\n/**\n * Resolve the config by handling function configs and returning the final configuration\n */\nexport async function resolveUserConfig(config: Config, options: ResolveUserConfigOptions): Promise<Config> {\n let kubbUserConfig = Promise.resolve(config) as Promise<Config>\n\n if (typeof config === 'function') {\n const possiblePromise = (config as any)({\n logLevel: options.logLevel,\n config: options.configPath,\n } as CLIOptions)\n if (isPromise(possiblePromise)) {\n kubbUserConfig = possiblePromise\n } else {\n kubbUserConfig = Promise.resolve(possiblePromise)\n }\n }\n\n return (await kubbUserConfig) as Config\n}\n","import { AsyncEventEmitter } from '@internals/utils'\nimport { type Config, createKubb, type KubbHooks } from '@kubb/core'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.d.ts'\nimport type { z } from 'zod'\nimport type { generateSchema } from '../schemas/generateSchema.ts'\nimport { NotifyTypes } from '../types.ts'\nimport { loadUserConfig } from '../utils/loadUserConfig.ts'\nimport { resolveCwd } from '../utils/resolveCwd.ts'\nimport { resolveUserConfig } from '../utils/resolveUserConfig.ts'\n\ninterface NotificationHandler {\n sendNotification(method: string, params: unknown): Promise<void>\n}\n\n/**\n * Build tool that generates code from OpenAPI specs using Kubb.\n * Sends real-time notifications of build progress and events.\n */\nexport async function generate(schema: z.infer<typeof generateSchema>, handler: NotificationHandler): Promise<CallToolResult> {\n const { config: configPath, input, output, logLevel } = schema\n\n try {\n const hooks = new AsyncEventEmitter<KubbHooks>()\n const messages: string[] = []\n\n // Helper to send notifications\n const notify = async (type: string, message: string, data?: Record<string, unknown>) => {\n messages.push(`${type}: ${message}`)\n\n await handler.sendNotification('kubb/progress', {\n type,\n message,\n timestamp: new Date().toISOString(),\n ...data,\n })\n }\n\n // Capture events for output and send notifications\n hooks.on('kubb:info', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.INFO, message)\n })\n\n hooks.on('kubb:success', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.SUCCESS, message)\n })\n\n hooks.on('kubb:error', async ({ error }: { error: Error }) => {\n await notify(NotifyTypes.ERROR, error.message, { stack: error.stack })\n })\n\n hooks.on('kubb:warn', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.WARN, message)\n })\n\n // Plugin lifecycle events\n hooks.on('kubb:plugin:start', async ({ plugin }) => {\n await notify(NotifyTypes.PLUGIN_START, `Plugin starting: ${plugin.name}`)\n })\n\n hooks.on('kubb:plugin:end', async ({ plugin, duration }) => {\n await notify(NotifyTypes.PLUGIN_END, `Plugin finished: ${plugin.name}`, {\n duration,\n })\n })\n\n // File processing events\n hooks.on('kubb:files:processing:start', async () => {\n await notify(NotifyTypes.FILES_START, 'Starting file processing')\n })\n\n hooks.on('kubb:file:processing:update', async ({ file }: { file: { name: string } }) => {\n await notify(NotifyTypes.FILE_UPDATE, `Processing file: ${file.name}`)\n })\n\n hooks.on('kubb:files:processing:end', async () => {\n await notify(NotifyTypes.FILES_END, 'File processing complete')\n })\n\n // Generation events\n hooks.on('kubb:generation:start', async () => {\n await notify(NotifyTypes.GENERATION_START, 'Generation started')\n })\n\n hooks.on('kubb:generation:end', async () => {\n await notify(NotifyTypes.GENERATION_END, 'Generation ended')\n })\n\n // Load and process configuration\n let userConfig: Config\n let cwd: string\n\n try {\n const configResult = await loadUserConfig(configPath, { notify })\n userConfig = configResult.userConfig\n cwd = configResult.cwd\n\n if (Array.isArray(userConfig) && userConfig.length) {\n throw new Error('Array type in kubb.config.ts is not supported in this tool. Please provide a single configuration object.')\n }\n\n userConfig = await resolveUserConfig(userConfig, {\n configPath,\n logLevel,\n })\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n await notify(NotifyTypes.CONFIG_ERROR, errorMessage)\n return {\n content: [\n {\n type: 'text',\n text: errorMessage,\n },\n ],\n isError: true,\n }\n }\n\n const inputPath = input ?? ('path' in userConfig.input ? userConfig.input.path : undefined)\n\n // Override config with CLI options\n const config: Config = {\n ...userConfig,\n root: resolveCwd(userConfig, cwd),\n input: inputPath\n ? {\n ...userConfig.input,\n path: inputPath,\n }\n : userConfig.input,\n output: output\n ? {\n ...userConfig.output,\n path: output,\n }\n : userConfig.output,\n }\n\n await notify(NotifyTypes.CONFIG_READY, 'Configuration ready', {\n root: config.root,\n })\n\n // Setup and build\n await notify(NotifyTypes.SETUP_START, 'Setting up Kubb')\n\n const kubb = createKubb(config, { hooks })\n await kubb.setup()\n await notify(NotifyTypes.SETUP_END, 'Kubb setup complete')\n\n await notify(NotifyTypes.BUILD_START, 'Starting build')\n const { files, failedPlugins, error } = await kubb.safeBuild()\n await notify(NotifyTypes.BUILD_END, `Build complete - Generated ${files.length} files`)\n\n if (error || failedPlugins.size > 0) {\n const allErrors: Error[] = [\n error,\n ...Array.from(failedPlugins)\n .filter((it) => it.error)\n .map((it) => it.error),\n ].filter(Boolean)\n\n await notify(NotifyTypes.BUILD_FAILED, `Build failed with ${allErrors.length} error(s)`, {\n errorCount: allErrors.length,\n errors: allErrors.map((err) => err.message),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build failed:\\n${allErrors.map((err) => err.message).join('\\n')}\\n\\n${messages.join('\\n')}`,\n },\n ],\n isError: true,\n }\n }\n\n await notify(NotifyTypes.BUILD_SUCCESS, `Build completed successfully - Generated ${files.length} files`, {\n filesCount: files.length,\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build completed successfully!\\n\\nGenerated ${files.length} files\\n\\n${messages.join('\\n')}`,\n },\n ],\n }\n } catch (caughtError) {\n const error = caughtError as Error\n\n await handler.sendNotification('kubb/progress', {\n type: NotifyTypes.FATAL_ERROR,\n message: error.message,\n stack: error.stack,\n timestamp: new Date().toISOString(),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build error: ${error.message}\\n${error.stack || ''}`,\n },\n ],\n isError: true,\n }\n }\n}\n","import process from 'node:process'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { version } from '../package.json'\nimport { generateSchema } from './schemas/generateSchema.ts'\nimport { generate } from './tools/generate.ts'\n\n/**\n * Kubb MCP Server\n *\n * Provides tools for building OpenAPI specifications using Kubb.\n */\nexport async function startServer() {\n try {\n const transport = new StdioServerTransport()\n const server = new McpServer({\n name: 'Kubb',\n version,\n })\n\n // Build tool - runs Kubb build using @kubb/core\n // Wrapped to pass notification handler for real-time progress updates\n server.tool('generate', 'Generate OpenAPI spec helpers using Kubb configuration', generateSchema.shape, async (args) => {\n // Create notification handler that sends events back to the client\n const notificationHandler = {\n sendNotification: async (method: string, params: any) => {\n try {\n await transport.send({\n jsonrpc: '2.0',\n method,\n params,\n })\n } catch (error) {\n console.error('Failed to send notification:', error)\n }\n },\n }\n\n // Call build tool with notification handler\n return generate(args, notificationHandler)\n })\n\n await server.connect(transport)\n } catch (error) {\n console.error('Failed to start MCP server:', error)\n process.exit(1)\n }\n}\n","import { startServer } from './server.ts'\n\nexport async function run(_argv?: string[]): Promise<void> {\n await startServer()\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["#emitter","NodeEventEmitter"],"sources":["../package.json","../src/schemas/generateSchema.ts","../../../internals/utils/src/errors.ts","../../../internals/utils/src/asyncEventEmitter.ts","../../../internals/utils/src/promise.ts","../src/types.ts","../src/constants.ts","../src/utils/loadUserConfig.ts","../src/utils/resolveCwd.ts","../src/utils/resolveUserConfig.ts","../src/tools/generate.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["","import { z } from 'zod'\n\nexport const generateSchema = z.object({\n config: z\n .string()\n .optional()\n\n .describe('Path to kubb.config file (supports .ts, .js, .cjs). If not provided, will look for kubb.config.{ts,js,cjs} in current directory'),\n input: z.string().optional().describe('Path to OpenAPI/Swagger spec file (overrides config)'),\n output: z.string().optional().describe('Output directory path (overrides config)'),\n logLevel: z.enum(['silent', 'error', 'warn', 'info', 'verbose', 'debug']).optional().default('info').describe('Log level for build output'),\n})\n","/**\n * Thrown when one or more errors occur during a Kubb build.\n * Carries the full list of underlying errors on `errors`.\n *\n * @example\n * ```ts\n * throw new BuildError('Build failed', { errors: [err1, err2] })\n * ```\n */\nexport class BuildError extends Error {\n errors: Array<Error>\n\n constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {\n super(message, { cause: options.cause })\n this.name = 'BuildError'\n this.errors = options.errors\n }\n}\n\n/**\n * Coerces an unknown thrown value to an `Error` instance.\n * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.\n *\n * @example\n * ```ts\n * try { ... } catch(err) {\n * throw new BuildError('Build failed', { cause: toError(err), errors: [] })\n * }\n * ```\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\n/**\n * Extracts a human-readable message from any thrown value.\n *\n * @example\n * ```ts\n * getErrorMessage(new Error('oops')) // 'oops'\n * getErrorMessage('plain string') // 'plain string'\n * ```\n */\nexport function getErrorMessage(value: unknown): string {\n return value instanceof Error ? value.message : String(value)\n}\n\n/**\n * Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.\n *\n * @example\n * ```ts\n * const cause = toCause(buildError) // Error | undefined\n * ```\n */\nexport function toCause(error: Error): Error | undefined {\n return error.cause instanceof Error ? error.cause : undefined\n}\n","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from './errors.ts'\n\n/**\n * A function that can be registered as an event listener, synchronous or async.\n */\ntype AsyncListener<TArgs extends unknown[]> = (...args: TArgs) => void | Promise<void>\n\n/**\n * Typed `EventEmitter` that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript event-map inference.\n *\n * @example\n * ```ts\n * const emitter = new AsyncEventEmitter<{ build: [name: string] }>()\n * emitter.on('build', async (name) => { console.log(name) })\n * await emitter.emit('build', 'petstore') // all listeners awaited\n * ```\n */\nexport class AsyncEventEmitter<TEvents extends { [K in keyof TEvents]: unknown[] }> {\n /**\n * Maximum number of listeners per event before Node emits a memory-leak warning.\n * @default 10\n */\n constructor(maxListener = 10) {\n this.#emitter.setMaxListeners(maxListener)\n }\n\n #emitter = new NodeEventEmitter()\n\n /**\n * Emits `eventName` and awaits all registered listeners sequentially.\n * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.\n *\n * @example\n * ```ts\n * await emitter.emit('build', 'petstore')\n * ```\n */\n async emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArgs: TEvents[TEventName]): Promise<void> {\n const listeners = this.#emitter.listeners(eventName) as Array<AsyncListener<TEvents[TEventName]>>\n\n if (listeners.length === 0) {\n return\n }\n\n for (const listener of listeners) {\n try {\n await listener(...eventArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(eventArgs)\n } catch {\n serializedArgs = String(eventArgs)\n }\n throw new Error(`Error in async listener for \"${eventName}\" with eventArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }\n }\n\n /**\n * Registers a persistent listener for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', async (name) => { console.log(name) })\n * ```\n */\n on<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.on(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Registers a one-shot listener that removes itself after the first invocation.\n *\n * @example\n * ```ts\n * emitter.onOnce('build', async (name) => { console.log(name) })\n * ```\n */\n onOnce<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n const wrapper: AsyncListener<TEvents[TEventName]> = (...args) => {\n this.off(eventName, wrapper)\n return handler(...args)\n }\n this.on(eventName, wrapper)\n }\n\n /**\n * Removes a previously registered listener.\n *\n * @example\n * ```ts\n * emitter.off('build', handler)\n * ```\n */\n off<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.off(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Returns the number of listeners registered for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', handler)\n * emitter.listenerCount('build') // 1\n * ```\n */\n listenerCount<TEventName extends keyof TEvents & string>(eventName: TEventName): number {\n return this.#emitter.listenerCount(eventName)\n }\n\n /**\n * Removes all listeners from every event channel.\n *\n * @example\n * ```ts\n * emitter.removeAll()\n * ```\n */\n removeAll(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","/** A value that may already be resolved or still pending.\n *\n * @example\n * ```ts\n * function load(id: string): PossiblePromise<string> {\n * return cache.get(id) ?? fetchRemote(id)\n * }\n * ```\n */\nexport type PossiblePromise<T> = Promise<T> | T\n\n/** Returns `true` when `result` is a thenable `Promise`.\n *\n * @example\n * ```ts\n * isPromise(Promise.resolve(1)) // true\n * isPromise(42) // false\n * ```\n */\nexport function isPromise<T>(result: PossiblePromise<T>): result is Promise<T> {\n return result !== null && result !== undefined && typeof (result as Record<string, unknown>)['then'] === 'function'\n}\n\n/** Returns `true` when `result` is a fulfilled `Promise.allSettled` result.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseFulfilledResult).map((r) => r.value)\n * ```\n */\nexport function isPromiseFulfilledResult<T = unknown>(result: PromiseSettledResult<unknown>): result is PromiseFulfilledResult<T> {\n return result.status === 'fulfilled'\n}\n\n/** Returns `true` when `result` is a rejected `Promise.allSettled` result with a typed `reason`.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseRejectedResult<Error>).map((r) => r.reason.message)\n * ```\n */\nexport function isPromiseRejectedResult<T>(result: PromiseSettledResult<unknown>): result is Omit<PromiseRejectedResult, 'reason'> & { reason: T } {\n return result.status === 'rejected'\n}\n","export const NotifyTypes = {\n INFO: 'INFO',\n SUCCESS: 'SUCCESS',\n ERROR: 'ERROR',\n WARN: 'WARN',\n PLUGIN_START: 'PLUGIN_START',\n PLUGIN_END: 'PLUGIN_END',\n FILES_START: 'FILES_START',\n FILE_UPDATE: 'FILE_UPDATE',\n FILES_END: 'FILES_END',\n GENERATION_START: 'GENERATION_START',\n GENERATION_END: 'GENERATION_END',\n CONFIG_LOADED: 'CONFIG_LOADED',\n CONFIG_ERROR: 'CONFIG_ERROR',\n CONFIG_READY: 'CONFIG_READY',\n SETUP_START: 'SETUP_START',\n SETUP_END: 'SETUP_END',\n BUILD_START: 'BUILD_START',\n BUILD_END: 'BUILD_END',\n BUILD_FAILED: 'BUILD_FAILED',\n BUILD_SUCCESS: 'BUILD_SUCCESS',\n FATAL_ERROR: 'FATAL_ERROR',\n} as const\n","export const ALLOWED_CONFIG_EXTENSIONS = new Set(['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'])\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport type { Config } from '@kubb/core'\nimport { unrun } from 'unrun'\nimport { ALLOWED_CONFIG_EXTENSIONS } from '../constants.ts'\nimport { NotifyTypes } from '../types.ts'\n\ntype NotifyFunction = (type: string, message: string, data?: Record<string, unknown>) => Promise<void>\n\nconst loadedModules = new Map<string, unknown>()\n\nasync function loadModule(filePath: string): Promise<unknown> {\n const ext = path.extname(filePath)\n if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {\n throw new Error(`Invalid config file extension \"${ext}\". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`)\n }\n if (loadedModules.has(filePath)) {\n return loadedModules.get(filePath)\n }\n const { module } = await unrun({ path: filePath })\n loadedModules.set(filePath, module)\n return module\n}\n\nexport async function loadUserConfig(configPath: string | undefined, { notify }: { notify: NotifyFunction }): Promise<{ userConfig: Config; cwd: string }> {\n let userConfig: Config | undefined\n let cwd: string\n\n if (configPath) {\n const ext = path.extname(configPath)\n if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {\n const msg = `Invalid config file extension \"${ext}\". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`\n await notify(NotifyTypes.CONFIG_ERROR, msg)\n throw new Error(msg)\n }\n const base = path.resolve(process.cwd())\n const resolvedConfigPath = path.resolve(base, configPath)\n const relative = path.relative(base, resolvedConfigPath)\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n const msg = 'Invalid config file path: must be within the current working directory'\n await notify(NotifyTypes.CONFIG_ERROR, msg)\n throw new Error(msg)\n }\n cwd = path.dirname(resolvedConfigPath)\n\n try {\n userConfig = (await loadModule(resolvedConfigPath)) as Config\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${resolvedConfigPath}`)\n } catch (error) {\n await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n }\n } else {\n cwd = process.cwd()\n const configFileNames = ['kubb.config.ts', 'kubb.config.mts', 'kubb.config.cts', 'kubb.config.js', 'kubb.config.cjs']\n\n for (const configFileName of configFileNames) {\n const configFilePath = path.resolve(process.cwd(), configFileName)\n if (!existsSync(configFilePath)) continue\n try {\n userConfig = (await loadModule(configFilePath)) as Config\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)\n break\n } catch {\n // Continue trying next config file\n }\n }\n\n if (!userConfig) {\n await notify(NotifyTypes.CONFIG_ERROR, 'No config file found')\n\n throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(', ')}`)\n }\n }\n\n return { userConfig: userConfig!, cwd }\n}\n","import path from 'node:path'\nimport type { Config } from '@kubb/core'\n\n/**\n * Determine the root directory based on userConfig.root and resolvedConfigDir\n * 1. If userConfig.root exists and is absolute, use it as-is\n * 2. If userConfig.root exists and is relative, resolve it relative to config directory\n * 3. Otherwise, use the config directory as root\n */\nexport function resolveCwd(userConfig: Config, cwd: string): string {\n if (userConfig.root) {\n if (path.isAbsolute(userConfig.root)) {\n return userConfig.root\n }\n\n return path.resolve(cwd, userConfig.root)\n }\n\n return cwd\n}\n","import { isPromise } from '@internals/utils'\nimport type { CLIOptions, Config } from '@kubb/core'\n\nexport type ResolveUserConfigOptions = {\n configPath?: string\n logLevel?: string\n}\n\n/**\n * Resolve the config by handling function configs and returning the final configuration\n */\nexport async function resolveUserConfig(config: Config, options: ResolveUserConfigOptions): Promise<Config> {\n let kubbUserConfig = Promise.resolve(config) as Promise<Config>\n\n if (typeof config === 'function') {\n const possiblePromise = (config as any)({\n logLevel: options.logLevel,\n config: options.configPath,\n } as CLIOptions)\n if (isPromise(possiblePromise)) {\n kubbUserConfig = possiblePromise\n } else {\n kubbUserConfig = Promise.resolve(possiblePromise)\n }\n }\n\n return (await kubbUserConfig) as Config\n}\n","import { AsyncEventEmitter } from '@internals/utils'\nimport { type Config, createKubb, type KubbHooks } from '@kubb/core'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.d.ts'\nimport type { z } from 'zod'\nimport type { generateSchema } from '../schemas/generateSchema.ts'\nimport { NotifyTypes } from '../types.ts'\nimport { loadUserConfig } from '../utils/loadUserConfig.ts'\nimport { resolveCwd } from '../utils/resolveCwd.ts'\nimport { resolveUserConfig } from '../utils/resolveUserConfig.ts'\n\ninterface NotificationHandler {\n sendNotification(method: string, params: unknown): Promise<void>\n}\n\n/**\n * Build tool that generates code from OpenAPI specs using Kubb.\n * Sends real-time notifications of build progress and events.\n */\nexport async function generate(schema: z.infer<typeof generateSchema>, handler: NotificationHandler): Promise<CallToolResult> {\n const { config: configPath, input, output, logLevel } = schema\n\n try {\n const hooks = new AsyncEventEmitter<KubbHooks>()\n const messages: string[] = []\n\n // Helper to send notifications\n const notify = async (type: string, message: string, data?: Record<string, unknown>) => {\n messages.push(`${type}: ${message}`)\n\n await handler.sendNotification('kubb/progress', {\n type,\n message,\n timestamp: new Date().toISOString(),\n ...data,\n })\n }\n\n // Capture events for output and send notifications\n hooks.on('kubb:info', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.INFO, message)\n })\n\n hooks.on('kubb:success', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.SUCCESS, message)\n })\n\n hooks.on('kubb:error', async ({ error }: { error: Error }) => {\n await notify(NotifyTypes.ERROR, error.message, { stack: error.stack })\n })\n\n hooks.on('kubb:warn', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.WARN, message)\n })\n\n // Plugin lifecycle events\n hooks.on('kubb:plugin:start', async ({ plugin }) => {\n await notify(NotifyTypes.PLUGIN_START, `Plugin starting: ${plugin.name}`)\n })\n\n hooks.on('kubb:plugin:end', async ({ plugin, duration }) => {\n await notify(NotifyTypes.PLUGIN_END, `Plugin finished: ${plugin.name}`, {\n duration,\n })\n })\n\n // File processing events\n hooks.on('kubb:files:processing:start', async () => {\n await notify(NotifyTypes.FILES_START, 'Starting file processing')\n })\n\n hooks.on('kubb:file:processing:update', async ({ file }: { file: { name: string } }) => {\n await notify(NotifyTypes.FILE_UPDATE, `Processing file: ${file.name}`)\n })\n\n hooks.on('kubb:files:processing:end', async () => {\n await notify(NotifyTypes.FILES_END, 'File processing complete')\n })\n\n // Generation events\n hooks.on('kubb:generation:start', async () => {\n await notify(NotifyTypes.GENERATION_START, 'Generation started')\n })\n\n hooks.on('kubb:generation:end', async () => {\n await notify(NotifyTypes.GENERATION_END, 'Generation ended')\n })\n\n // Load and process configuration\n let userConfig: Config\n let cwd: string\n\n try {\n const configResult = await loadUserConfig(configPath, { notify })\n userConfig = configResult.userConfig\n cwd = configResult.cwd\n\n if (Array.isArray(userConfig) && userConfig.length) {\n throw new Error('Array type in kubb.config.ts is not supported in this tool. Please provide a single configuration object.')\n }\n\n userConfig = await resolveUserConfig(userConfig, {\n configPath,\n logLevel,\n })\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n await notify(NotifyTypes.CONFIG_ERROR, errorMessage)\n return {\n content: [\n {\n type: 'text',\n text: errorMessage,\n },\n ],\n isError: true,\n }\n }\n\n const inputPath = input ?? ('path' in userConfig.input ? userConfig.input.path : undefined)\n\n // Override config with CLI options\n const config: Config = {\n ...userConfig,\n root: resolveCwd(userConfig, cwd),\n input: inputPath\n ? {\n ...userConfig.input,\n path: inputPath,\n }\n : userConfig.input,\n output: output\n ? {\n ...userConfig.output,\n path: output,\n }\n : userConfig.output,\n }\n\n await notify(NotifyTypes.CONFIG_READY, 'Configuration ready', {\n root: config.root,\n })\n\n // Setup and build\n await notify(NotifyTypes.SETUP_START, 'Setting up Kubb')\n\n const kubb = createKubb(config, { hooks })\n await kubb.setup()\n await notify(NotifyTypes.SETUP_END, 'Kubb setup complete')\n\n await notify(NotifyTypes.BUILD_START, 'Starting build')\n const { files, failedPlugins, error } = await kubb.safeBuild()\n await notify(NotifyTypes.BUILD_END, `Build complete - Generated ${files.length} files`)\n\n if (error || failedPlugins.size > 0) {\n const allErrors: Error[] = [\n error,\n ...Array.from(failedPlugins)\n .filter((it) => it.error)\n .map((it) => it.error),\n ].filter(Boolean)\n\n await notify(NotifyTypes.BUILD_FAILED, `Build failed with ${allErrors.length} error(s)`, {\n errorCount: allErrors.length,\n errors: allErrors.map((err) => err.message),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build failed:\\n${allErrors.map((err) => err.message).join('\\n')}\\n\\n${messages.join('\\n')}`,\n },\n ],\n isError: true,\n }\n }\n\n await notify(NotifyTypes.BUILD_SUCCESS, `Build completed successfully - Generated ${files.length} files`, {\n filesCount: files.length,\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build completed successfully!\\n\\nGenerated ${files.length} files\\n\\n${messages.join('\\n')}`,\n },\n ],\n }\n } catch (caughtError) {\n const error = caughtError as Error\n\n await handler.sendNotification('kubb/progress', {\n type: NotifyTypes.FATAL_ERROR,\n message: error.message,\n stack: error.stack,\n timestamp: new Date().toISOString(),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build error: ${error.message}\\n${error.stack || ''}`,\n },\n ],\n isError: true,\n }\n }\n}\n","import process from 'node:process'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { version } from '../package.json'\nimport { generateSchema } from './schemas/generateSchema.ts'\nimport { generate } from './tools/generate.ts'\n\n/**\n * Kubb MCP Server\n *\n * Provides tools for building OpenAPI specifications using Kubb.\n */\nexport async function startServer() {\n try {\n const transport = new StdioServerTransport()\n const server = new McpServer({\n name: 'Kubb',\n version,\n })\n\n // Build tool - runs Kubb build using @kubb/core\n // Wrapped to pass notification handler for real-time progress updates\n server.tool('generate', 'Generate OpenAPI spec helpers using Kubb configuration', generateSchema.shape, async (args) => {\n // Create notification handler that sends events back to the client\n const notificationHandler = {\n sendNotification: async (method: string, params: any) => {\n try {\n await transport.send({\n jsonrpc: '2.0',\n method,\n params,\n })\n } catch (error) {\n console.error('Failed to send notification:', error)\n }\n },\n }\n\n // Call build tool with notification handler\n return generate(args, notificationHandler)\n })\n\n await server.connect(transport)\n } catch (error) {\n console.error('Failed to start MCP server:', error)\n process.exit(1)\n }\n}\n","import { startServer } from './server.ts'\n\nexport async function run(_argv?: string[]): Promise<void> {\n await startServer()\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/mcp",
3
- "version": "5.0.0-alpha.70",
3
+ "version": "5.0.0-alpha.71",
4
4
  "description": "Model Context Protocol (MCP) server for Kubb, enabling AI assistants to generate code from OpenAPI specifications.",
5
5
  "keywords": [
6
6
  "ai",
@@ -50,16 +50,16 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@modelcontextprotocol/sdk": "^1.29.0",
53
- "jiti": "^2.6.1",
53
+ "unrun": "^0.2.37",
54
54
  "zod": "^4.3.6",
55
- "@kubb/core": "5.0.0-alpha.70"
55
+ "@kubb/core": "5.0.0-alpha.71"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@internals/utils": "0.0.0",
59
- "@kubb/renderer-jsx": "5.0.0-alpha.70"
59
+ "@kubb/renderer-jsx": "5.0.0-alpha.71"
60
60
  },
61
61
  "peerDependencies": {
62
- "@kubb/renderer-jsx": "5.0.0-alpha.70"
62
+ "@kubb/renderer-jsx": "5.0.0-alpha.71"
63
63
  },
64
64
  "size-limit": [
65
65
  {
@@ -0,0 +1 @@
1
+ export const ALLOWED_CONFIG_EXTENSIONS = new Set(['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'])
@@ -1,42 +1,64 @@
1
+ import { existsSync } from 'node:fs'
1
2
  import path from 'node:path'
2
3
  import type { Config } from '@kubb/core'
3
- import createJiti from 'jiti'
4
+ import { unrun } from 'unrun'
5
+ import { ALLOWED_CONFIG_EXTENSIONS } from '../constants.ts'
4
6
  import { NotifyTypes } from '../types.ts'
5
7
 
6
8
  type NotifyFunction = (type: string, message: string, data?: Record<string, unknown>) => Promise<void>
7
9
 
8
- const jiti = createJiti(import.meta.url, {
9
- sourceMaps: true,
10
- })
10
+ const loadedModules = new Map<string, unknown>()
11
+
12
+ async function loadModule(filePath: string): Promise<unknown> {
13
+ const ext = path.extname(filePath)
14
+ if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {
15
+ throw new Error(`Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`)
16
+ }
17
+ if (loadedModules.has(filePath)) {
18
+ return loadedModules.get(filePath)
19
+ }
20
+ const { module } = await unrun({ path: filePath })
21
+ loadedModules.set(filePath, module)
22
+ return module
23
+ }
11
24
 
12
- /**
13
- * Load the user configuration from the specified path or current directory
14
- */
15
25
  export async function loadUserConfig(configPath: string | undefined, { notify }: { notify: NotifyFunction }): Promise<{ userConfig: Config; cwd: string }> {
16
26
  let userConfig: Config | undefined
17
27
  let cwd: string
18
28
 
19
29
  if (configPath) {
20
- // Resolve the config path to absolute path and get its directory
21
- cwd = path.dirname(path.resolve(configPath))
30
+ const ext = path.extname(configPath)
31
+ if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {
32
+ const msg = `Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`
33
+ await notify(NotifyTypes.CONFIG_ERROR, msg)
34
+ throw new Error(msg)
35
+ }
36
+ const base = path.resolve(process.cwd())
37
+ const resolvedConfigPath = path.resolve(base, configPath)
38
+ const relative = path.relative(base, resolvedConfigPath)
39
+ if (relative.startsWith('..') || path.isAbsolute(relative)) {
40
+ const msg = 'Invalid config file path: must be within the current working directory'
41
+ await notify(NotifyTypes.CONFIG_ERROR, msg)
42
+ throw new Error(msg)
43
+ }
44
+ cwd = path.dirname(resolvedConfigPath)
22
45
 
23
- // Try to load from path
24
46
  try {
25
- userConfig = await jiti.import(configPath, { default: true })
26
- await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${configPath}`)
47
+ userConfig = (await loadModule(resolvedConfigPath)) as Config
48
+ await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${resolvedConfigPath}`)
27
49
  } catch (error) {
28
50
  await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`)
29
51
  throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`)
30
52
  }
31
53
  } else {
32
- // Look for kubb.config in current directory with various extensions
33
54
  cwd = process.cwd()
34
55
  const configFileNames = ['kubb.config.ts', 'kubb.config.mts', 'kubb.config.cts', 'kubb.config.js', 'kubb.config.cjs']
35
56
 
36
57
  for (const configFileName of configFileNames) {
58
+ const configFilePath = path.resolve(process.cwd(), configFileName)
59
+ if (!existsSync(configFilePath)) continue
37
60
  try {
38
- const configFilePath = path.resolve(process.cwd(), configFileName)
39
- userConfig = await jiti.import(configFilePath, { default: true })
61
+ userConfig = (await loadModule(configFilePath)) as Config
40
62
  await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)
41
63
  break
42
64
  } catch {