@kubb/mcp 5.0.0-beta.53 → 5.0.0-beta.55

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.js CHANGED
@@ -12,10 +12,11 @@ import { tool } from "tmcp/utils";
12
12
  import * as v from "valibot";
13
13
  import fs, { existsSync } from "node:fs";
14
14
  import path from "node:path";
15
+ import { pathToFileURL } from "node:url";
15
16
  import { createJiti } from "jiti";
16
17
  import process$1 from "node:process";
17
18
  //#region package.json
18
- var version = "5.0.0-beta.53";
19
+ var version = "5.0.0-beta.55";
19
20
  //#endregion
20
21
  //#region ../../internals/utils/src/errors.ts
21
22
  /**
@@ -174,38 +175,85 @@ function isPromise(result) {
174
175
  return result !== null && result !== void 0 && typeof result["then"] === "function";
175
176
  }
176
177
  //#endregion
177
- //#region src/schemas/generateSchema.ts
178
- const generateSchema = v.object({
179
- config: v.optional(v.pipe(v.string(), v.minLength(1), v.description("Path to kubb.config file (supports .ts, .js, .cjs). If not provided, will look for kubb.config.{ts,js,cjs} in current directory"))),
180
- input: v.optional(v.pipe(v.string(), v.minLength(1), v.description("Path to OpenAPI/Swagger spec file (overrides config)"))),
181
- output: v.optional(v.pipe(v.string(), v.minLength(1), v.description("Output directory path (overrides config)"))),
182
- logLevel: v.optional(v.pipe(v.picklist([
183
- "silent",
184
- "info",
185
- "verbose"
186
- ]), v.description("Log level for build output")), "info")
187
- });
188
- //#endregion
189
- //#region src/utils/formatDiagnostics.ts
178
+ //#region ../../internals/utils/src/runtime.ts
190
179
  /**
191
- * Renders serialized diagnostics as a plain-text block for an AI assistant. Each entry
192
- * keeps the stable `code`, the source pointer, the suggested fix, and the docs link, so
193
- * the agent can act on the problem rather than parsing a bare message. No ANSI styling,
194
- * unlike the CLI renderer.
180
+ * Detects the JavaScript runtime executing the current process and exposes its name and version.
181
+ *
182
+ * Prefer the shared {@link runtime} instance over constructing your own.
195
183
  */
196
- function formatDiagnostics(diagnostics) {
197
- return diagnostics.map((diagnostic) => formatDiagnostic(diagnostic)).join("\n\n");
198
- }
199
- function formatDiagnostic(diagnostic) {
200
- const { code, severity, message, location, help, plugin, docsUrl } = diagnostic;
201
- const lines = [`${severity} ${plugin ? `${plugin}(${code})` : code}: ${message}`];
202
- if (location && "pointer" in location) lines.push(` at ${location.pointer}`);
203
- if (help) lines.push(` help: ${help}`);
204
- if (docsUrl) lines.push(` docs: ${docsUrl}`);
205
- return lines.join("\n");
206
- }
184
+ var Runtime = class {
185
+ /**
186
+ * `true` when the current process is running under Bun.
187
+ *
188
+ * Detection keys off the global `Bun` object rather than `process.versions`,
189
+ * because Bun polyfills `process.versions.node` for Node compatibility and would
190
+ * otherwise look like Node.
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * if (runtime.isBun) {
195
+ * await Bun.write(path, data)
196
+ * }
197
+ * ```
198
+ */
199
+ get isBun() {
200
+ return typeof Bun !== "undefined";
201
+ }
202
+ /**
203
+ * `true` when the current process is running under Deno.
204
+ */
205
+ get isDeno() {
206
+ return typeof globalThis.Deno !== "undefined";
207
+ }
208
+ /**
209
+ * `true` when the current process is running under Node.
210
+ *
211
+ * Bun and Deno are excluded first so a polyfilled `process` does not register as Node.
212
+ */
213
+ get isNode() {
214
+ return !this.isBun && !this.isDeno && typeof process !== "undefined" && process.versions?.node != null;
215
+ }
216
+ /**
217
+ * Name of the runtime executing the current process.
218
+ *
219
+ * @example
220
+ * ```ts
221
+ * runtime.name // 'bun' when run with `bun kubb`, 'node' otherwise
222
+ * ```
223
+ */
224
+ get name() {
225
+ if (this.isBun) return "bun";
226
+ if (this.isDeno) return "deno";
227
+ return "node";
228
+ }
229
+ /**
230
+ * Version of the active runtime, or an empty string when it cannot be read.
231
+ *
232
+ * @example
233
+ * ```ts
234
+ * runtime.version // '1.3.11' under Bun, '22.22.2' under Node
235
+ * ```
236
+ */
237
+ get version() {
238
+ if (this.isBun) return process.versions.bun ?? "";
239
+ if (this.isDeno) return globalThis.Deno?.version?.deno ?? "";
240
+ return process.versions?.node ?? "";
241
+ }
242
+ };
243
+ /**
244
+ * Shared {@link Runtime} instance describing the JavaScript runtime executing the current process.
245
+ */
246
+ const runtime = new Runtime();
207
247
  //#endregion
208
- //#region src/types.ts
248
+ //#region src/constants.ts
249
+ const ALLOWED_CONFIG_EXTENSIONS = new Set([
250
+ ".ts",
251
+ ".mts",
252
+ ".cts",
253
+ ".js",
254
+ ".mjs",
255
+ ".cjs"
256
+ ]);
209
257
  const NotifyTypes = {
210
258
  INFO: "INFO",
211
259
  SUCCESS: "SUCCESS",
@@ -227,34 +275,201 @@ const NotifyTypes = {
227
275
  BUILD_START: "BUILD_START",
228
276
  BUILD_END: "BUILD_END",
229
277
  BUILD_FAILED: "BUILD_FAILED",
230
- BUILD_SUCCESS: "BUILD_SUCCESS",
231
- FATAL_ERROR: "FATAL_ERROR"
278
+ BUILD_SUCCESS: "BUILD_SUCCESS"
232
279
  };
233
280
  //#endregion
234
- //#region src/constants.ts
235
- const ALLOWED_CONFIG_EXTENSIONS = new Set([
236
- ".ts",
237
- ".mts",
238
- ".cts",
239
- ".js",
240
- ".mjs",
241
- ".cjs"
242
- ]);
281
+ //#region src/schemas/generateSchema.ts
282
+ const generateSchema = v.object({
283
+ config: v.optional(v.pipe(v.string(), v.minLength(1), v.description("Path to kubb.config file (supports .ts, .js, .cjs). If not provided, will look for kubb.config.{ts,js,cjs} in current directory"))),
284
+ input: v.optional(v.pipe(v.string(), v.minLength(1), v.description("Path to OpenAPI/Swagger spec file (overrides config)"))),
285
+ output: v.optional(v.pipe(v.string(), v.minLength(1), v.description("Output directory path (overrides config)"))),
286
+ logLevel: v.optional(v.pipe(v.picklist([
287
+ "silent",
288
+ "info",
289
+ "verbose"
290
+ ]), v.description("Log level for build output")), "info")
291
+ });
292
+ //#endregion
293
+ //#region ../../internals/shared/src/constants.ts
294
+ const KUBB_CONFIG_FILENAME = "kubb.config.ts";
295
+ const availablePlugins = [
296
+ {
297
+ value: "plugin-ts",
298
+ label: "TypeScript",
299
+ hint: "Recommended",
300
+ packageName: "@kubb/plugin-ts",
301
+ importName: "pluginTs",
302
+ category: "types"
303
+ },
304
+ {
305
+ value: "plugin-client",
306
+ label: "Client (Fetch/Axios)",
307
+ packageName: "@kubb/plugin-client",
308
+ importName: "pluginClient",
309
+ category: "client"
310
+ },
311
+ {
312
+ value: "plugin-react-query",
313
+ label: "React Query / TanStack Query",
314
+ packageName: "@kubb/plugin-react-query",
315
+ importName: "pluginReactQuery",
316
+ category: "framework"
317
+ },
318
+ {
319
+ value: "plugin-vue-query",
320
+ label: "Vue Query",
321
+ packageName: "@kubb/plugin-vue-query",
322
+ importName: "pluginVueQuery",
323
+ category: "framework"
324
+ },
325
+ {
326
+ value: "plugin-zod",
327
+ label: "Zod Schemas",
328
+ packageName: "@kubb/plugin-zod",
329
+ importName: "pluginZod",
330
+ category: "validation"
331
+ },
332
+ {
333
+ value: "plugin-faker",
334
+ label: "Faker.js Mocks",
335
+ packageName: "@kubb/plugin-faker",
336
+ importName: "pluginFaker",
337
+ category: "mocks"
338
+ },
339
+ {
340
+ value: "plugin-msw",
341
+ label: "MSW Handlers",
342
+ packageName: "@kubb/plugin-msw",
343
+ importName: "pluginMsw",
344
+ category: "mocks"
345
+ },
346
+ {
347
+ value: "plugin-cypress",
348
+ label: "Cypress Tests",
349
+ packageName: "@kubb/plugin-cypress",
350
+ importName: "pluginCypress",
351
+ category: "testing"
352
+ },
353
+ {
354
+ value: "plugin-mcp",
355
+ label: "MCP Server (AI / Model Context Protocol)",
356
+ packageName: "@kubb/plugin-mcp",
357
+ importName: "pluginMcp",
358
+ category: "ai"
359
+ },
360
+ {
361
+ value: "plugin-redoc",
362
+ label: "ReDoc Documentation",
363
+ packageName: "@kubb/plugin-redoc",
364
+ importName: "pluginRedoc",
365
+ category: "documentation"
366
+ }
367
+ ];
368
+ const pluginDefaultConfigs = {
369
+ "plugin-ts": `pluginTs()`,
370
+ "plugin-client": `pluginClient()`,
371
+ "plugin-react-query": `pluginReactQuery()`,
372
+ "plugin-vue-query": `pluginVueQuery()`,
373
+ "plugin-zod": `pluginZod()`,
374
+ "plugin-faker": `pluginFaker()`,
375
+ "plugin-msw": `pluginMsw()`,
376
+ "plugin-cypress": `pluginCypress()`,
377
+ "plugin-mcp": `pluginMcp()`,
378
+ "plugin-redoc": `pluginRedoc()`
379
+ };
243
380
  //#endregion
244
- //#region src/utils/loadUserConfig.ts
245
- const jiti = createJiti(import.meta.url, {
381
+ //#region ../../internals/shared/src/init.ts
382
+ function generateConfigFile({ selectedPlugins, inputPath, outputPath }) {
383
+ return `import { defineConfig } from 'kubb'
384
+ ${selectedPlugins.map((plugin) => `import { ${plugin.importName} } from '${plugin.packageName}'`).join("\n")}
385
+
386
+ export default defineConfig({
387
+ root: '.',
388
+ input: {
389
+ path: '${inputPath}',
390
+ },
391
+ output: {
392
+ path: '${outputPath}',
393
+ clean: true,
394
+ },
395
+ plugins: [
396
+ ${selectedPlugins.map((plugin) => {
397
+ return ` ${pluginDefaultConfigs[plugin.value] ?? `${plugin.importName}()`},`;
398
+ }).join("\n")}
399
+ ],
400
+ })
401
+ `;
402
+ }
403
+ //#endregion
404
+ //#region ../../internals/shared/src/loader.ts
405
+ /**
406
+ * jiti options for loading Kubb config modules: the automatic JSX runtime pointed at
407
+ * `@kubb/renderer-jsx`, and `moduleCache` off so a re-load re-evaluates the file.
408
+ */
409
+ const JITI_OPTIONS = {
246
410
  jsx: {
247
411
  runtime: "automatic",
248
412
  importSource: "@kubb/renderer-jsx"
249
413
  },
250
414
  moduleCache: false
251
- });
415
+ };
416
+ /**
417
+ * Creates a runtime-aware loader for Kubb's TypeScript and JavaScript config modules.
418
+ *
419
+ * On Bun and Deno it imports the file natively, skipping jiti's transform step, and falls back to
420
+ * jiti only when the native import throws. On Node it always uses jiti, which transpiles TypeScript
421
+ * and the `@kubb/renderer-jsx` JSX runtime on the fly. The jiti instance is created lazily, so the
422
+ * Bun/Deno happy path never pays for it.
423
+ *
424
+ * @example
425
+ * ```ts
426
+ * const config = await createModuleLoader().load('/abs/kubb.config.ts', { default: true })
427
+ * ```
428
+ */
429
+ function createModuleLoader() {
430
+ let jiti;
431
+ const getJiti = () => jiti ??= createJiti(import.meta.url, JITI_OPTIONS);
432
+ const viaJiti = (filePath, options) => options?.default ? getJiti().import(filePath, { default: true }) : getJiti().import(filePath);
433
+ const viaNative = async (filePath, options) => {
434
+ const href = pathToFileURL(filePath).href;
435
+ const mod = await (options?.bust != null ? import(`${href}?t=${options.bust}`) : import(href));
436
+ return options?.default ? mod.default ?? mod : mod;
437
+ };
438
+ return { async load(filePath, options) {
439
+ if (runtime.isBun || runtime.isDeno) try {
440
+ return await viaNative(filePath, options);
441
+ } catch {
442
+ return viaJiti(filePath, options);
443
+ }
444
+ return viaJiti(filePath, options);
445
+ } };
446
+ }
447
+ //#endregion
448
+ //#region src/utils.ts
449
+ /**
450
+ * Renders serialized diagnostics as a plain-text block for an AI assistant. Each entry
451
+ * keeps the stable `code`, the source pointer, the suggested fix, and the docs link, so
452
+ * the agent can act on the problem rather than parsing a bare message. No ANSI styling,
453
+ * unlike the CLI renderer.
454
+ */
455
+ function formatDiagnostics(diagnostics) {
456
+ return diagnostics.map((diagnostic) => formatDiagnostic(diagnostic)).join("\n\n");
457
+ }
458
+ function formatDiagnostic(diagnostic) {
459
+ const { code, severity, message, location, help, plugin, docsUrl } = diagnostic;
460
+ const lines = [`${severity} ${plugin ? `${plugin}(${code})` : code}: ${message}`];
461
+ if (location && "pointer" in location) lines.push(` at ${location.pointer}`);
462
+ if (help) lines.push(` help: ${help}`);
463
+ if (docsUrl) lines.push(` docs: ${docsUrl}`);
464
+ return lines.join("\n");
465
+ }
466
+ const loader = createModuleLoader();
252
467
  const loadedModules = /* @__PURE__ */ new Map();
253
468
  async function loadModule(filePath) {
254
469
  const ext = path.extname(filePath);
255
470
  if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) throw new Error(`Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(", ")}`);
256
471
  if (loadedModules.has(filePath)) return loadedModules.get(filePath);
257
- const mod = await jiti.import(filePath, { default: true });
472
+ const mod = await loader.load(filePath, { default: true });
258
473
  loadedModules.set(filePath, mod);
259
474
  return mod;
260
475
  }
@@ -313,8 +528,6 @@ async function loadUserConfig(configPath, { notify }) {
313
528
  await notify(NotifyTypes.CONFIG_ERROR, "No config file found");
314
529
  throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(", ")}`);
315
530
  }
316
- //#endregion
317
- //#region src/utils/resolveCwd.ts
318
531
  /**
319
532
  * Determine the root directory based on userConfig.root and resolvedConfigDir
320
533
  * 1. If userConfig.root exists and is absolute, use it as-is
@@ -328,8 +541,6 @@ function resolveCwd(userConfig, cwd) {
328
541
  }
329
542
  return cwd;
330
543
  }
331
- //#endregion
332
- //#region src/utils/resolveUserConfig.ts
333
544
  async function resolveUserConfig(config, options) {
334
545
  const result = typeof config === "function" ? config({
335
546
  logLevel: options.logLevel,
@@ -440,137 +651,6 @@ const generateTool = defineTool({
440
651
  }
441
652
  });
442
653
  //#endregion
443
- //#region ../../internals/shared/src/constants.ts
444
- const KUBB_CONFIG_FILENAME = "kubb.config.ts";
445
- const availablePlugins = [
446
- {
447
- value: "plugin-ts",
448
- label: "TypeScript",
449
- hint: "Recommended",
450
- packageName: "@kubb/plugin-ts",
451
- importName: "pluginTs",
452
- category: "types"
453
- },
454
- {
455
- value: "plugin-client",
456
- label: "Client (Fetch/Axios)",
457
- packageName: "@kubb/plugin-client",
458
- importName: "pluginClient",
459
- category: "client"
460
- },
461
- {
462
- value: "plugin-react-query",
463
- label: "React Query / TanStack Query",
464
- packageName: "@kubb/plugin-react-query",
465
- importName: "pluginReactQuery",
466
- category: "framework"
467
- },
468
- {
469
- value: "plugin-vue-query",
470
- label: "Vue Query",
471
- packageName: "@kubb/plugin-vue-query",
472
- importName: "pluginVueQuery",
473
- category: "framework"
474
- },
475
- {
476
- value: "plugin-zod",
477
- label: "Zod Schemas",
478
- packageName: "@kubb/plugin-zod",
479
- importName: "pluginZod",
480
- category: "validation"
481
- },
482
- {
483
- value: "plugin-faker",
484
- label: "Faker.js Mocks",
485
- packageName: "@kubb/plugin-faker",
486
- importName: "pluginFaker",
487
- category: "mocks"
488
- },
489
- {
490
- value: "plugin-msw",
491
- label: "MSW Handlers",
492
- packageName: "@kubb/plugin-msw",
493
- importName: "pluginMsw",
494
- category: "mocks"
495
- },
496
- {
497
- value: "plugin-cypress",
498
- label: "Cypress Tests",
499
- packageName: "@kubb/plugin-cypress",
500
- importName: "pluginCypress",
501
- category: "testing"
502
- },
503
- {
504
- value: "plugin-mcp",
505
- label: "MCP Server (AI / Model Context Protocol)",
506
- packageName: "@kubb/plugin-mcp",
507
- importName: "pluginMcp",
508
- category: "ai"
509
- },
510
- {
511
- value: "plugin-redoc",
512
- label: "ReDoc Documentation",
513
- packageName: "@kubb/plugin-redoc",
514
- importName: "pluginRedoc",
515
- category: "documentation"
516
- }
517
- ];
518
- const pluginDefaultConfigs = {
519
- "plugin-ts": `pluginTs({
520
- output: { path: 'models' },
521
- })`,
522
- "plugin-client": `pluginClient({
523
- output: { path: 'clients' },
524
- })`,
525
- "plugin-react-query": `pluginReactQuery({
526
- output: { path: 'hooks' },
527
- })`,
528
- "plugin-vue-query": `pluginVueQuery({
529
- output: { path: 'hooks' },
530
- })`,
531
- "plugin-zod": `pluginZod({
532
- output: { path: 'zod' },
533
- })`,
534
- "plugin-faker": `pluginFaker({
535
- output: { path: 'mocks' },
536
- })`,
537
- "plugin-msw": `pluginMsw({
538
- output: { path: 'msw' },
539
- })`,
540
- "plugin-cypress": `pluginCypress({
541
- output: { path: 'cypress' },
542
- })`,
543
- "plugin-mcp": `pluginMcp({
544
- output: { path: 'mcp' },
545
- })`,
546
- "plugin-redoc": `pluginRedoc({
547
- output: { path: 'redoc' },
548
- })`
549
- };
550
- //#endregion
551
- //#region ../../internals/shared/src/init.ts
552
- function generateConfigFile({ selectedPlugins, inputPath, outputPath }) {
553
- return `import { defineConfig } from 'kubb'
554
- ${selectedPlugins.map((plugin) => `import { ${plugin.importName} } from '${plugin.packageName}'`).join("\n")}
555
-
556
- export default defineConfig({
557
- root: '.',
558
- input: {
559
- path: '${inputPath}',
560
- },
561
- output: {
562
- path: '${outputPath}',
563
- clean: true,
564
- },
565
- plugins: [
566
- ${selectedPlugins.map((plugin) => {
567
- return ` ${pluginDefaultConfigs[plugin.value] ?? `${plugin.importName}()`},`;
568
- }).join("\n")}
569
- ],
570
- })
571
- `;
572
- }
573
- //#endregion
574
654
  //#region src/schemas/initSchema.ts
575
655
  const initSchema = v.object({
576
656
  input: v.optional(v.pipe(v.string(), v.minLength(1), v.description("Path to OpenAPI spec (default: ./openapi.yaml)"))),