@kubb/cli 5.10.1 → 5.10.3

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.
Files changed (90) hide show
  1. package/dist/{Telemetry-BfdvvZus.cjs → Telemetry-BV4GonCV.cjs} +2 -2
  2. package/dist/Telemetry-BV4GonCV.cjs.map +1 -0
  3. package/dist/Telemetry-CH2kkxWK.cjs +322 -0
  4. package/dist/Telemetry-CH2kkxWK.cjs.map +1 -0
  5. package/dist/{Telemetry-Bf6lUdai.js → Telemetry-Cz9QCzRo.js} +2 -2
  6. package/dist/Telemetry-Cz9QCzRo.js.map +1 -0
  7. package/dist/{background-D5K6ecEo.js → background-DFME5huR.js} +30 -7
  8. package/dist/background-DFME5huR.js.map +1 -0
  9. package/dist/{background-obsD4Gj2.cjs → background-DVZB1n4j.cjs} +25 -6
  10. package/dist/background-DVZB1n4j.cjs.map +1 -0
  11. package/dist/background-WaKtfQWr.cjs +192 -0
  12. package/dist/background-WaKtfQWr.cjs.map +1 -0
  13. package/dist/{background-C8doa9-4.js → background-_A5NwvYH.js} +1 -1
  14. package/dist/{config-CcqzzfB7.cjs → config-DKAqX5sW.cjs} +18 -4
  15. package/dist/config-DKAqX5sW.cjs.map +1 -0
  16. package/dist/{config-IMZ26zcb.js → config-DV_7s1m-.js} +19 -5
  17. package/dist/config-DV_7s1m-.js.map +1 -0
  18. package/dist/config-OL_izsmp.cjs +113 -0
  19. package/dist/config-OL_izsmp.cjs.map +1 -0
  20. package/dist/credentials-xOkTTDWj.cjs +113 -0
  21. package/dist/credentials-xOkTTDWj.cjs.map +1 -0
  22. package/dist/index.cjs +65 -24
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +8 -0
  25. package/dist/index.d.ts +0 -1
  26. package/dist/index.js +65 -24
  27. package/dist/index.js.map +1 -1
  28. package/dist/output-C5g7AtWH.cjs +1008 -0
  29. package/dist/output-C5g7AtWH.cjs.map +1 -0
  30. package/dist/{output-mwVt_Vj9.js → output-D_gc1nrM.js} +99 -44
  31. package/dist/output-D_gc1nrM.js.map +1 -0
  32. package/dist/{output-DLrxGtuN.cjs → output-nieBFDgM.cjs} +104 -43
  33. package/dist/output-nieBFDgM.cjs.map +1 -0
  34. package/dist/{registry-x-_nbYR6.cjs → registry-C8E_G7Xc.cjs} +49 -15
  35. package/dist/registry-C8E_G7Xc.cjs.map +1 -0
  36. package/dist/registry-CIpW2zQc.cjs +157 -0
  37. package/dist/registry-CIpW2zQc.cjs.map +1 -0
  38. package/dist/{registry-ChqX2AFQ.js → registry-De1vVn1d.js} +50 -16
  39. package/dist/registry-De1vVn1d.js.map +1 -0
  40. package/dist/rolldown-runtime-C0BPl7ul.cjs +43 -0
  41. package/dist/run-BbhrOuK6.cjs +40 -0
  42. package/dist/{run-1MJA0P5x.cjs.map → run-BbhrOuK6.cjs.map} +1 -1
  43. package/dist/{run-DHiVlG37.cjs → run-BnLba1gt.cjs} +27 -14
  44. package/dist/run-BnLba1gt.cjs.map +1 -0
  45. package/dist/{run-D4vOhfbJ.js → run-Bp47k1W1.js} +2 -2
  46. package/dist/{run-D4vOhfbJ.js.map → run-Bp47k1W1.js.map} +1 -1
  47. package/dist/run-BpdJ6X75.cjs +32 -0
  48. package/dist/{run-B13e9GQz.cjs.map → run-BpdJ6X75.cjs.map} +1 -1
  49. package/dist/{run-Cm0sJO0h.js → run-CCMlmk-z.js} +1 -1
  50. package/dist/{run-DTz7gAk1.js → run-CPYD1Lp0.js} +27 -14
  51. package/dist/run-CPYD1Lp0.js.map +1 -0
  52. package/dist/run-CSOEGpWZ.cjs +326 -0
  53. package/dist/run-CSOEGpWZ.cjs.map +1 -0
  54. package/dist/{run-B13e9GQz.cjs → run-CvE8ZdKG.cjs} +2 -2
  55. package/dist/run-CvE8ZdKG.cjs.map +1 -0
  56. package/dist/{run-Cu3pmezx.js → run-DaFK-Uy2.js} +2 -2
  57. package/dist/{run-Cu3pmezx.js.map → run-DaFK-Uy2.js.map} +1 -1
  58. package/dist/{run-BAlcXyYw.js → run-Ij84bqza.js} +22 -16
  59. package/dist/run-Ij84bqza.js.map +1 -0
  60. package/dist/{run-1MJA0P5x.cjs → run-MFjzBB_M.cjs} +2 -2
  61. package/dist/run-MFjzBB_M.cjs.map +1 -0
  62. package/dist/run-hgSZImuK.cjs +345 -0
  63. package/dist/run-hgSZImuK.cjs.map +1 -0
  64. package/dist/{run-CUyhuGlK.cjs → run-hyi91b22.cjs} +22 -16
  65. package/dist/run-hyi91b22.cjs.map +1 -0
  66. package/dist/{snapshot-DCG-Jf1A.js → snapshot-B6w3BLum.js} +22 -9
  67. package/dist/snapshot-B6w3BLum.js.map +1 -0
  68. package/dist/snapshot-DP9Pcnsg.cjs +264 -0
  69. package/dist/snapshot-DP9Pcnsg.cjs.map +1 -0
  70. package/dist/{snapshot-C5cthCuU.cjs → snapshot-D_F4XkYQ.cjs} +22 -9
  71. package/dist/snapshot-D_F4XkYQ.cjs.map +1 -0
  72. package/dist/studioWorker.js +2 -2
  73. package/package.json +15 -10
  74. package/dist/Telemetry-Bf6lUdai.js.map +0 -1
  75. package/dist/Telemetry-BfdvvZus.cjs.map +0 -1
  76. package/dist/background-D5K6ecEo.js.map +0 -1
  77. package/dist/background-obsD4Gj2.cjs.map +0 -1
  78. package/dist/config-CcqzzfB7.cjs.map +0 -1
  79. package/dist/config-IMZ26zcb.js.map +0 -1
  80. package/dist/output-DLrxGtuN.cjs.map +0 -1
  81. package/dist/output-mwVt_Vj9.js.map +0 -1
  82. package/dist/registry-ChqX2AFQ.js.map +0 -1
  83. package/dist/registry-x-_nbYR6.cjs.map +0 -1
  84. package/dist/run-BAlcXyYw.js.map +0 -1
  85. package/dist/run-CUyhuGlK.cjs.map +0 -1
  86. package/dist/run-DHiVlG37.cjs.map +0 -1
  87. package/dist/run-DTz7gAk1.js.map +0 -1
  88. package/dist/snapshot-C5cthCuU.cjs.map +0 -1
  89. package/dist/snapshot-DCG-Jf1A.js.map +0 -1
  90. package/dist/studioWorker.d.ts +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"output-mwVt_Vj9.js","names":["process","logLevel","logLevelMap","process"],"sources":["../../../internals/shared/src/constants.ts","../../../internals/shared/src/loader.ts","../../../internals/shared/src/config.ts","../src/utils/env.ts","../src/loggers/banner.ts","../src/loggers/createLogger.ts","../src/loggers/clackLogger.ts","../src/loggers/plainLogger.ts","../src/loggers/output.ts"],"sourcesContent":["export const KUBB_CONFIG_FILENAME = 'kubb.config.ts' as const\n\n/** File extensions a Kubb config file may use. */\nexport const CONFIG_EXTENSIONS = ['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'] as const\n\nexport const KUBB_PACKAGE_NAME = 'kubb' as const\n\nexport const initDefaults = {\n inputPath: './openapi.yaml',\n outputPath: './src/gen',\n plugins: ['plugin-ts'],\n} as const\n","import { readFile } from 'node:fs/promises'\nimport { createJiti } from 'jiti'\n\n/**\n * jiti options for loading Kubb config modules: the automatic JSX runtime pointed at\n * `@kubb/renderer-jsx`, and `moduleCache` off so a re-load re-evaluates the file.\n */\nconst JITI_OPTIONS = {\n jsx: { runtime: 'automatic', importSource: '@kubb/renderer-jsx' },\n moduleCache: false,\n} satisfies Parameters<typeof createJiti>[1]\n\n/**\n * Plain JavaScript files. jiti hands these to Node's native `import()`, whose module cache never\n * lets go of a file, so `moduleCache: false` alone would keep returning the first version of it.\n */\nconst JAVASCRIPT_EXTENSION = /\\.[cm]?jsx?$/\n\n/**\n * Per-call options for {@link loadModule}.\n */\ntype LoadModuleOptions = {\n /**\n * Return the module's default export instead of the full namespace.\n */\n default?: boolean\n}\n\nconst jiti = createJiti(import.meta.url, JITI_OPTIONS)\n\n/**\n * Loads a Kubb TypeScript or JavaScript config module via jiti.\n *\n * jiti transpiles TypeScript and the `@kubb/renderer-jsx` JSX runtime on the fly. Every load\n * re-evaluates the file, so a config edited on disk is picked up by the next load.\n *\n * @example\n * ```ts\n * const config = await loadModule('/abs/kubb.config.ts', { default: true })\n * ```\n */\nexport async function loadModule<T = unknown>(filePath: string, options?: LoadModuleOptions): Promise<T> {\n if (!JAVASCRIPT_EXTENSION.test(filePath)) {\n return (options?.default ? jiti.import(filePath, { default: true }) : jiti.import(filePath)) as Promise<T>\n }\n\n // Transpiled through jiti instead, so every load re-evaluates the file as it is on disk now.\n // A TypeScript file it imports reloads too. A plain JavaScript file it imports still goes\n // through Node's `import()` and stays cached until the process restarts.\n const mod = (await jiti.evalModule(await readFile(filePath, 'utf8'), { filename: filePath, async: true, forceTranspile: true })) as\n | { default?: unknown }\n | undefined\n return (options?.default ? (mod?.default ?? mod) : mod) as T\n}\n","import { existsSync } from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport process from 'node:process'\nimport { CONFIG_EXTENSIONS } from './constants.ts'\nimport { loadModule } from './loader.ts'\n\nconst SEARCH_FILES = ['', '.config/', 'configs/'].flatMap((prefix) => [`${prefix}.kubbrc`, `${prefix}kubb.config`])\n\n/**\n * The first Kubb config file in `cwd` or the nearest parent folder that has one: `.kubbrc` before\n * `kubb.config`, the folder itself before its `.config/` and `configs/`, and {@link CONFIG_EXTENSIONS} in order.\n */\nexport function findConfigFile(cwd: string = process.cwd()): string | undefined {\n for (let dir = resolve(cwd); ; dir = dirname(dir)) {\n const found = SEARCH_FILES.flatMap((file) => CONFIG_EXTENSIONS.map((extension) => join(dir, `${file}${extension}`))).find((file) => existsSync(file))\n if (found || dirname(dir) === dir) return found\n }\n}\n\n/**\n * Loads a Kubb config module, calls it with `cli` when it exports a function, and returns its\n * configs as a list, so a single config and a `defineConfig([...])` array read the same.\n */\nexport async function loadConfigFile<T>(file: string, cli: unknown): Promise<Array<T>> {\n const loaded = await loadModule<unknown>(file, { default: true })\n const resolved = (await (typeof loaded === 'function' ? loaded(cli) : loaded)) as T | Array<T>\n return Array.isArray(resolved) ? resolved : [resolved]\n}\n","import { isCIEnvironment } from '@internals/utils'\nimport { getAgentProfile } from 'gunshi/agent'\n\n/**\n * Returns `true` when the process has an interactive TTY with a valid terminal\n * width and is not running in CI.\n *\n * Some IDE-embedded terminals report `isTTY = true` but set `columns` to `0`,\n * which breaks clack's box-drawing helpers (they call `String.prototype.repeat`\n * with a negative count and throw a `RangeError`). A positive column count is\n * required before the TTY counts as usable.\n *\n * @example\n * ```ts\n * if (canUseTTY()) {\n * renderProgressBar()\n * }\n * ```\n */\nexport function canUseTTY(): boolean {\n return process.stdout.isTTY && (process.stdout.columns ?? 0) > 0 && !isCIEnvironment()\n}\n\n/**\n * Returns `true` when output can carry spinners and clack's gutter: an interactive TTY that no AI\n * coding agent is reading. Cursor-movement escapes are hard for an agent to parse even over a\n * pseudo-TTY, so it gets the plain writer.\n */\nexport function isRichOutput(): boolean {\n return canUseTTY() && !getAgentProfile().isAgent\n}\n","import { styleText } from 'node:util'\nimport { formatMs } from '@internals/utils'\n\n/**\n * Colors for each part of the Kubb mascot illustration.\n */\nconst palette = {\n /**\n * Top cap of the skittle.\n */\n lid: (text: string) => styleText('red', text),\n /**\n * Wood body.\n */\n wood: (text: string) => styleText('yellow', text),\n /**\n * Base wood body.\n */\n woodBase: (text: string) => styleText(['dim', 'yellow'], text),\n /**\n * Eye whites.\n */\n eye: (text: string) => styleText('white', text),\n /**\n * Highlight accent.\n */\n highlight: (text: string) => styleText('gray', text),\n /**\n * Cheek blush.\n */\n blush: (text: string) => styleText('magenta', text),\n}\n\n/**\n * Generates the Kubb mascot welcome banner as an ANSI-colored string.\n *\n * @example\n * ```ts\n * console.log(getIntro({ title: 'kubb.config.ts', description: 'generating…', version: '5.0.0', areEyesOpen: true }))\n * ```\n */\nexport function getIntro({\n title,\n description,\n version,\n areEyesOpen,\n}: {\n /**\n * Name of the active configuration or tool being started.\n */\n title: string\n /**\n * Short subtitle shown next to the arrow prompt.\n */\n description: string\n /**\n * Kubb version string rendered in the header.\n */\n version: string\n /**\n * When `false` the eyes are shown as closed dashes instead of open blocks.\n */\n areEyesOpen: boolean\n}): string {\n const kubbVersion = styleText(['bold', 'yellow'], `KUBB v${version}`)\n\n const eyeTop = areEyesOpen ? palette.eye('█▀█') : palette.eye('───')\n const eyeBottom = areEyesOpen ? palette.eye('▀▀▀') : palette.eye('───')\n\n return [\n ` ${palette.lid('▄▄▄▄▄▄▄▄▄▄▄▄▄')}`,\n ` ${palette.wood('█ ')}${palette.highlight('▄▄')}${palette.wood(' ')}${palette.highlight('▄▄')}${palette.wood(' █')} ${kubbVersion}`,\n ` ${palette.wood('█ ')}${eyeTop}${palette.wood(' ')}${eyeTop}${palette.wood(' █')} ${styleText('gray', title)}`,\n ` ${palette.wood('█ ')}${eyeBottom}${palette.wood(' ')}${palette.blush('◡')}${palette.wood(' ')}${eyeBottom}${palette.wood(' █')} ${styleText('yellow', '➜')} ${styleText('white', description)}`,\n ` ${palette.woodBase('▀▀▀▀▀▀▀▀▀▀▀▀▀')}`,\n ].join('\\n')\n}\n\n/**\n * Formats a millisecond duration with a threshold-based ANSI color.\n * `≤ 500 ms` → green · `≤ 1 000 ms` → yellow · `> 1 000 ms` → red.\n *\n * @example\n * ```ts\n * formatMsWithColor(200) // '\\x1b[32m200ms\\x1b[39m'\n * formatMsWithColor(800) // '\\x1b[33m800ms\\x1b[39m'\n * formatMsWithColor(1500) // '\\x1b[31m1.50s\\x1b[39m'\n * ```\n */\nexport function formatMsWithColor(ms: number): string {\n const formatted = formatMs(ms)\n if (ms <= 500) return styleText('green', formatted)\n if (ms <= 1000) return styleText('yellow', formatted)\n\n return styleText('red', formatted)\n}\n","import { relative } from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport { formatMs, getElapsedMs } from '@internals/utils'\nimport type { Config } from '@kubb/core'\nimport { Diagnostics, logLevel as logLevelMap } from '@kubb/core'\nimport type { StudioConnectedContext } from '@kubb/studio'\nimport { formatMsWithColor } from './banner.ts'\nimport type { Logger, LoggerWriter, LogStatus, WriterProgress, WriterSpinner } from './defineLogger.ts'\n\n/** Display path for a config's input: the string form, or its `path` field when the input is an object. */\nfunction getInputPath(config: Config): string | undefined {\n const { input } = config\n if (typeof input === 'string') return input\n return typeof input?.path === 'string' ? input.path : undefined\n}\n\n/** Counts a noun, so a message never reads `1 files`. */\nexport function pluralize(count: number, noun: string): string {\n return `${count} ${count === 1 ? noun : `${noun}s`}`\n}\n\n/** Prefixes a `[HH:MM:SS]` timestamp at verbose and above. */\nfunction formatMessage(message: string, logLevel: number): string {\n if (logLevel >= logLevelMap.verbose) {\n const timestamp = new Date().toLocaleTimeString('en-US', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n })\n return `${styleText('dim', `[${timestamp}]`)} ${message}`\n }\n return message\n}\n\n/**\n * Renders a `studio:connected` event's versions: the runtime only when it differs from the host.\n */\nfunction formatVersions({ studio, kubb, agent }: StudioConnectedContext['versions']): string {\n return [`v${agent}`, kubb !== agent ? `runtime v${kubb}` : undefined, `Studio v${studio}`].filter(Boolean).join(', ')\n}\n\n/** The first three frames of a stack, without the message line. */\nfunction topFrames(stack: string): Array<string> {\n return stack\n .split('\\n')\n .slice(1, 4)\n .map((frame) => frame.trim())\n}\n\n/** First stack frames for verbose error output, including an optional `cause` chain. */\nfunction formatErrorFrames(error: Error): { frames: Array<string>; cause?: { header: string; frames: Array<string> } } | null {\n if (!error.stack) {\n return null\n }\n\n const frames = topFrames(error.stack)\n const caused = error.cause instanceof Error ? error.cause : undefined\n\n if (!caused?.stack) {\n return { frames }\n }\n\n return {\n frames,\n cause: {\n header: `└─ caused by ${caused.message}`,\n frames: topFrames(caused.stack),\n },\n }\n}\n\ntype ProgressState = {\n totalPlugins: number\n completedPlugins: number\n failedPlugins: number\n totalFiles: number\n processedFiles: number\n /** `process.hrtime()` snapshot taken at the start of generation, for the elapsed time. */\n hrStart: [number, number]\n}\n\n/** The progress summary line the clack logger shows, `null` when there is nothing to display. */\nfunction buildProgressLine(state: ProgressState): string | null {\n const parts: Array<string> = []\n const duration = formatMs(getElapsedMs(state.hrStart))\n\n if (state.totalPlugins > 0) {\n const pluginStr =\n state.failedPlugins > 0\n ? `Plugins ${styleText('green', state.completedPlugins.toString())}/${state.totalPlugins} ${styleText('red', `(${state.failedPlugins} failed)`)}`\n : `Plugins ${styleText('green', state.completedPlugins.toString())}/${state.totalPlugins}`\n parts.push(pluginStr)\n }\n\n if (state.totalFiles > 0) {\n parts.push(`Files ${styleText('green', state.processedFiles.toString())}/${state.totalFiles}`)\n }\n\n if (parts.length === 0) {\n return null\n }\n\n parts.push(`${styleText('green', duration)} elapsed`)\n return parts.join(styleText('dim', ' | '))\n}\n\nfunction createProgressCounters(): ProgressState {\n return {\n totalPlugins: 0,\n completedPlugins: 0,\n failedPlugins: 0,\n totalFiles: 0,\n processedFiles: 0,\n hrStart: process.hrtime(),\n }\n}\n\n/**\n * One output phase while its step owns the line. A phase buffers what it is told, because a spinner\n * redraws over anything written under it, and prints the lot once it knows its own result.\n */\ntype Phase = {\n successLabel: string\n failureLabel: string\n /**\n * Whether each hook's own result is worth a line. Format and lint run one command, so the phase\n * result already says everything; the post-generate phase runs several.\n */\n showHookResults: boolean\n failed: boolean\n hrStart: [number, number]\n lines: Array<string>\n /**\n * Raw lines a hook printed, drawn outside the group.\n */\n output: Array<string>\n}\n\ntype StartPhaseOptions = {\n /**\n * Shown while the phase runs.\n */\n running: string\n success: string\n failure: string\n showHookResults?: boolean\n}\n\n/**\n * The three output phases, in the order the generate runner runs them.\n */\nconst PHASES = {\n format: { running: 'Formatting', success: 'Formatted', failure: 'Formatting failed' },\n lint: { running: 'Linting', success: 'Linted', failure: 'Linting failed' },\n hooks: {\n running: 'Running post-generate hooks',\n success: 'Post-generate hooks completed',\n failure: 'Post-generate hooks failed',\n showHookResults: true,\n },\n} as const satisfies Record<string, StartPhaseOptions>\n\n/**\n * Drops the blank lines a subprocess leaves at either end of its output, so its block does not open\n * or close on an empty row.\n */\nfunction trimBlankEdges(lines: ReadonlyArray<string>): Array<string> {\n const start = lines.findIndex((line) => line.trim())\n if (start === -1) {\n return []\n }\n\n return lines.slice(start, lines.findLastIndex((line) => line.trim()) + 1)\n}\n\n/**\n * Wires a {@link LoggerWriter} onto the run's hooks. This owns what a run says and in what order:\n * one group per config, a step over the plugin work, a progress bar for the writes, one step per\n * output phase, then the summary and the group's closing result. The writer only decides how each\n * line looks, so every logger reports the same run the same way.\n *\n * @example\n * ```ts\n * export const plainLogger = createLogger(writer)\n * ```\n */\nexport function createLogger(writer: LoggerWriter): Logger {\n return function install(context, { logLevel }) {\n const silent = logLevel <= logLevelMap.silent\n const state = {\n ...createProgressCounters(),\n spinner: null as WriterSpinner | null,\n progress: null as WriterProgress | null,\n hooks: new Map<string, { hrStart: [number, number]; lines: Array<string> }>(),\n /**\n * Plugin results held back while the generation step owns the line.\n */\n pluginLines: [] as Array<string>,\n phase: null as Phase | null,\n groupOpen: false,\n /**\n * Whether this run keeps its files in memory, as a `kubb studio` run without `--allow-write` does.\n */\n inMemory: false,\n }\n\n function text(message: string): string {\n return formatMessage(message, logLevel)\n }\n\n function startSpinner(message: string) {\n if (silent) {\n return\n }\n\n state.spinner = writer.spinner()\n state.spinner.start(text(message))\n }\n\n function stopSpinner(message?: string, status: LogStatus = 'success') {\n const spinner = state.spinner\n if (!spinner) {\n return\n }\n state.spinner = null\n\n if (message === undefined) {\n spinner.clear()\n return\n }\n if (status === 'failed') {\n spinner.error(text(message))\n return\n }\n spinner.stop(text(message))\n }\n\n function stopProgress(message?: string) {\n const progress = state.progress\n if (!progress) {\n return\n }\n state.progress = null\n progress.stop(message === undefined ? '' : text(message))\n }\n\n function startPhase({ running, success, failure, showHookResults = false }: StartPhaseOptions) {\n state.phase = { successLabel: success, failureLabel: failure, showHookResults, failed: false, hrStart: process.hrtime(), lines: [], output: [] }\n startSpinner(running)\n }\n\n function endPhase() {\n const phase = state.phase\n state.phase = null\n\n if (!phase || silent) {\n return\n }\n\n const duration = formatMsWithColor(getElapsedMs(phase.hrStart))\n\n stopSpinner(phase.failed ? `${phase.failureLabel} after ${duration}` : `${phase.successLabel} in ${duration}`, phase.failed ? 'failed' : 'success')\n\n if (phase.lines.length) {\n writer.block(phase.lines)\n }\n writeOutput(phase.output)\n }\n\n function writeOutput(lines: ReadonlyArray<string>) {\n const output = trimBlankEdges(lines)\n if (output.length) {\n writer.raw(output)\n }\n }\n\n // A run that throws before `kubb:generation:end` never reaches the summary, so the lifecycle\n // end calls this too rather than leave a group without its closing line.\n function closeGroup(status: LogStatus) {\n if (!state.groupOpen) {\n return\n }\n state.groupOpen = false\n\n stopSpinner()\n stopProgress()\n writer.groupEnd(status === 'failed' ? styleText('red', '✗ Generation failed') : styleText('green', '✓ Generation succeeded'))\n }\n\n function reset() {\n stopSpinner()\n stopProgress()\n Object.assign(state, createProgressCounters())\n state.hooks.clear()\n state.pluginLines = []\n state.phase = null\n state.groupOpen = false\n }\n\n function writeErrorFrames(error: Error) {\n const frames = logLevel >= logLevelMap.verbose ? formatErrorFrames(error) : null\n if (!frames) {\n return\n }\n\n writer.block(frames.frames.map((frame) => text(styleText('dim', frame))))\n if (frames.cause) {\n writer.block([styleText('dim', frames.cause.header), ...frames.cause.frames.map((frame) => text(` ${styleText('dim', frame)}`))])\n }\n }\n\n function formatLine(symbol: string, message: string, info?: string): string {\n return text([symbol, message, info && styleText('dim', info)].filter(Boolean).join(' '))\n }\n\n context.hook('kubb:warn', ({ message, info }) => {\n if (logLevel < logLevelMap.warn) {\n return\n }\n\n writer.warn(formatLine(styleText('yellow', '⚠'), message, logLevel >= logLevelMap.info ? info : undefined))\n })\n\n // Unguarded: a failure stays visible even at silent.\n context.hook('kubb:error', ({ error }) => {\n if (state.phase) {\n state.phase.failed = true\n }\n\n // The writer draws the error symbol, so the message goes in bare.\n if (state.spinner) {\n stopSpinner(error.message, 'failed')\n } else {\n writer.error(text(error.message))\n }\n\n writeErrorFrames(error)\n })\n\n context.hook('kubb:diagnostic', ({ diagnostic }) => {\n // Silent still surfaces errors so failures stay visible. It drops warnings and info.\n if (silent && diagnostic.severity !== 'error') {\n return\n }\n\n stopSpinner()\n stopProgress()\n\n if (Diagnostics.isUpdate(diagnostic)) {\n writer.update(\n [`\\`v${diagnostic.currentVersion}\\` → \\`v${diagnostic.latestVersion}\\``, 'Run `npm install -g @kubb/cli` to update'],\n 'Update available for `Kubb`',\n )\n return\n }\n\n const { headline, details } = Diagnostics.format(diagnostic)\n writer.diagnostic([headline, ...details])\n // The stack of a crash is what its maintainers need in a bug report.\n if (Diagnostics.isProblem(diagnostic) && diagnostic.cause) {\n writeErrorFrames(diagnostic.cause)\n }\n })\n\n // A `kubb studio` session emits these on the same emitter as its generations, so one logger\n // renders the whole command.\n context.hook('studio:disconnected', ({ code, reason }) => {\n if (logLevel < logLevelMap.warn) {\n return\n }\n\n stopSpinner()\n // 4002 is `AgentCloseCode.SUPERSEDED`, spelled out because `@kubb/studio` is an optional peer.\n if (code === 4002) {\n writer.warn(text('⚠ Another process connected to Kubb Studio as this agent, so this one stopped'))\n return\n }\n writer.warn(text(`⚠ Kubb Studio ended the session (${reason || `code ${code}`})`))\n })\n\n context.hook('studio:warn', ({ message, permission }) => {\n if (logLevel < logLevelMap.warn) {\n return\n }\n const remedy = permission ? `; pass --${permission.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`)} to allow it` : ''\n writer.warn(text(`⚠ ${message}${remedy}`))\n })\n\n // Unguarded, like `kubb:error`: a failure stays visible even at silent.\n context.hook('studio:error', ({ error }) => {\n if (state.spinner) {\n stopSpinner(error.message, 'failed')\n return\n }\n writer.error(text(error.message))\n })\n\n context.hook('kubb:lifecycle:start', () => {\n reset()\n })\n\n context.hook('kubb:generation:start', ({ config }) => {\n closeGroup('failed')\n reset()\n\n state.totalPlugins = config.plugins?.length ?? 0\n state.inMemory = config.storage?.name === 'memory'\n\n if (silent) {\n return\n }\n\n const inputPath = getInputPath(config)\n\n writer.group(text([styleText('bold', config.name ?? 'kubb'), inputPath ? styleText('dim', inputPath) : undefined].filter(Boolean).join(' ')))\n state.groupOpen = true\n\n startSpinner('Generating')\n })\n\n context.hook('kubb:format:start', () => startPhase(PHASES.format))\n context.hook('kubb:format:end', endPhase)\n context.hook('kubb:lint:start', () => startPhase(PHASES.lint))\n context.hook('kubb:lint:end', endPhase)\n context.hook('kubb:hooks:start', () => startPhase(PHASES.hooks))\n context.hook('kubb:hooks:end', endPhase)\n\n context.hook('kubb:hook:end', (ctx) => {\n const { id, command, name, args, success, error } = ctx\n if (!id) {\n return\n }\n\n if (!success && state.phase) {\n state.phase.failed = true\n }\n\n if (silent) {\n // Even when silent, surface a failed hook's captured output.\n if (!ctx.success) {\n if (ctx.stdout) console.log(ctx.stdout)\n if (ctx.stderr) console.error(ctx.stderr)\n }\n return\n }\n\n const active = state.hooks.get(id)\n if (!active) {\n return\n }\n state.hooks.delete(id)\n\n const label = styleText('dim', name ?? (args?.length ? `${command} ${args.join(' ')}` : command))\n const reason = error?.message ? ` (${error.message})` : ''\n const result = success\n ? `${styleText('green', '✓')} ${label} in ${formatMsWithColor(getElapsedMs(active.hrStart))}`\n : `${styleText('red', '✗')} ${label} failed${reason}`\n\n const phase = state.phase\n if (phase) {\n if (phase.showHookResults || !success) {\n phase.lines.push(result)\n }\n phase.output.push(...active.lines)\n return\n }\n\n stopSpinner()\n writer.step(text(result))\n writeOutput(active.lines)\n })\n\n context.hook('kubb:generation:end', () => {\n stopSpinner()\n stopProgress()\n })\n\n context.hook('kubb:lifecycle:end', () => {\n closeGroup('failed')\n reset()\n })\n\n // Not registered at silent: the missing `kubb:hook:line` listener is also what tells the runner not to stream.\n if (!silent) {\n context.hook('kubb:info', ({ message, info }) => {\n const line = formatLine(styleText('blue', 'ℹ'), message, info)\n\n // Info carries something new (the auto-detected tool), so inside a phase it waits for the phase to print.\n if (state.phase) {\n state.phase.lines.push(line)\n return\n }\n if (state.spinner) {\n state.spinner.message(line)\n return\n }\n writer.info(line)\n })\n\n context.hook('kubb:success', ({ message, info }) => {\n const line = formatLine(styleText('green', '✓'), message, logLevel >= logLevelMap.info ? info : undefined)\n\n // The phase step's own result already reports these successes, so let the step carry them.\n if (state.spinner) {\n state.spinner.message(line)\n return\n }\n writer.success(line)\n })\n\n context.hook('studio:connected', ({ url, versions }) => {\n stopSpinner()\n writer.success(text(`✓ Connected to ${styleText('cyan', url)} ${styleText('dim', `(${formatVersions(versions)})`)}`))\n startSpinner('✓ Ready to receive jobs')\n })\n\n context.hook('studio:command', ({ command, info }) => {\n stopSpinner()\n writer.success(text(`✓ Finished ${command} ${styleText('dim', `(${info})`)}`))\n startSpinner('✓ Ready to receive jobs')\n })\n\n context.hook('studio:reconnecting', ({ delayMs }) => {\n stopSpinner()\n writer.info(text(styleText('dim', `Retrying connection to Kubb Studio in ${formatMs(delayMs)}`)))\n })\n\n context.hook('kubb:plugin:start', ({ plugin }) => {\n state.spinner?.message(text(`Generating ${styleText('dim', plugin.name)}`))\n })\n\n // Buffered, not printed: a step redraws over anything written while it runs.\n context.hook('kubb:plugin:end', ({ plugin, duration, success }) => {\n if (success) {\n state.completedPlugins++\n }\n if (!success) {\n state.failedPlugins++\n }\n state.pluginLines.push(text(`${plugin.name} ${success ? 'completed' : 'failed'} in ${formatMsWithColor(duration)}`))\n })\n\n context.hook('kubb:plugins:end', () => {\n const failed = state.failedPlugins > 0\n stopSpinner(buildProgressLine(state) ?? 'No plugins ran', failed ? 'failed' : 'success')\n\n if (state.pluginLines.length) {\n writer.block(state.pluginLines)\n state.pluginLines = []\n }\n })\n\n context.hook('kubb:files:processing:start', ({ files }) => {\n stopSpinner()\n state.totalFiles = files.length\n state.processedFiles = 0\n\n state.progress = writer.progress(files.length)\n state.progress.start(text(`${state.inMemory ? 'Generating' : 'Writing'} ${pluralize(files.length, 'file')}`))\n })\n\n context.hook('kubb:files:processing:update', ({ files }) => {\n for (const { file, config } of files) {\n state.processedFiles++\n state.progress?.advance(`${state.inMemory ? 'Generating' : 'Writing'} ${relative(config.root, file.path)}`)\n }\n })\n\n context.hook('kubb:files:processing:end', () => {\n stopProgress(state.inMemory ? `Generated ${pluralize(state.processedFiles, 'file')} in memory` : `Wrote ${pluralize(state.processedFiles, 'file')}`)\n })\n\n context.hook('kubb:hook:start', ({ id }) => {\n if (!id) {\n return\n }\n state.hooks.set(id, { hrStart: process.hrtime(), lines: [] })\n })\n\n context.hook('kubb:hook:line', ({ id, line }) => {\n const active = state.hooks.get(id)\n if (!active) {\n return\n }\n\n // A phase step redraws its own line, so its output waits until the phase ends.\n if (state.phase) {\n active.lines.push(line)\n return\n }\n writer.raw([line])\n })\n }\n\n return {\n renderSummary(lines, { status }) {\n if (silent || !state.groupOpen) {\n return\n }\n\n closeGroup(status)\n writer.diagnostic([...lines])\n },\n }\n }\n}\n","import { styleText } from 'node:util'\nimport * as clack from '@clack/prompts'\nimport { createLogger } from './createLogger.ts'\nimport type { Logger, LoggerWriter } from './defineLogger.ts'\n\n/**\n * Draws with clack: a gutter bar per group, animated steps, and a progress bar for the writes.\n */\nexport const clackWriter: LoggerWriter = {\n group: (title) => clack.intro(title),\n groupEnd: (text) => clack.outro(text),\n step: (text) => clack.log.step(text, { spacing: 0 }),\n info: (text) => clack.log.info(text),\n success: (text) => clack.log.success(text),\n warn: (text) => clack.log.warn(text),\n error: (text) => clack.log.error(text),\n block: (lines) => clack.log.message(lines, { spacing: 0 }),\n // A subprocess's output is not Kubb's tree, so it goes out past clack and its gutter bar. The\n // step above it is already stopped by the time this runs.\n raw: (lines) => console.log(styleText('dim', lines.join('\\n'))),\n // The diagnostic carries its own code and indented rows, so clear clack's gutter and bar and let\n // the block stand on its own.\n diagnostic: (lines) => clack.log.message(lines, { symbol: '', secondarySymbol: '' }),\n update: (lines, title) =>\n clack.box(lines.join('\\n'), title, {\n width: 'auto',\n formatBorder: (border: string) => styleText('yellow', border),\n rounded: true,\n withGuide: false,\n contentAlign: 'center',\n titleAlign: 'center',\n }),\n spinner: () => clack.spinner(),\n progress(max) {\n const bar = clack.progress({ style: 'block', max, size: 30 })\n\n return {\n start: (text) => bar.start(text),\n advance: (text) => bar.advance(1, text),\n stop: (text) => bar.stop(text),\n }\n },\n}\n\n/**\n * TTY logger for local development, with animated steps and progress bars.\n */\nexport const clackLogger: Logger = createLogger(clackWriter)\n","import { createLogger } from './createLogger.ts'\nimport type { Logger, LoggerWriter } from './defineLogger.ts'\n\n/**\n * Prefixes that stand in for the symbols clack draws, so plain output reads the same way.\n */\nexport const SYMBOLS = { info: 'ℹ', warn: '⚠', error: '✗', step: '◇' } as const\n\n/** Draws with one `write` call per line. Nothing animates, so a step prints at start and end. */\nfunction createWriter(write: (line: string) => void): LoggerWriter {\n return {\n group: write,\n groupEnd: write,\n step: (text) => write(`${SYMBOLS.step} ${text}`),\n info: write,\n success: write,\n warn: write,\n error: (text) => write(`${SYMBOLS.error} ${text}`),\n block: (lines) => write(lines.join('\\n')),\n raw: (lines) => write(lines.join('\\n')),\n diagnostic: (lines) => write(lines.join('\\n')),\n update: (lines, title) => write([title, ...lines].join('\\n')),\n spinner: () => ({\n start: write,\n message: write,\n clear: () => {},\n stop: (text) => text && write(text),\n error: (text) => write(`${SYMBOLS.error} ${text}`),\n }),\n progress: () => ({\n start: write,\n advance: write,\n stop: (text) => text && write(text),\n }),\n }\n}\n\n/** The plain logger writing through `write`, e.g. `console.error` so stdout carries only JSON. */\nexport function createPlainLogger(write: (line: string) => void): Logger {\n return createLogger(createWriter(write))\n}\n\n/** Draws on the console, for non-TTY environments and for an AI coding agent reading the output. */\nexport const plainWriter = createWriter((line) => console.log(line))\n\n/**\n * Console adapter for non-TTY environments, and for an AI coding agent reading the output. Reports\n * the same run in the same order as `clackLogger`, without the animation.\n */\nexport const plainLogger = createLogger(plainWriter)\n","import { styleText } from 'node:util'\nimport * as prompts from '@clack/prompts'\nimport { isRichOutput } from '../utils/env.ts'\nimport { getIntro } from './banner.ts'\nimport { clackWriter } from './clackLogger.ts'\nimport type { LoggerWriter, WriterSpinner } from './defineLogger.ts'\nimport { plainWriter, SYMBOLS } from './plainLogger.ts'\n\nconst SPONSOR_TIPS = [\n 'Your sponsorship keeps Kubb codegen, plugins, and docs maintained',\n 'Sponsor faster generators and better Kubb Studio workflows',\n 'Help keep Kubb free for TypeScript teams building APIs',\n 'Support React Query, Zod, Faker, and MSW integrations',\n 'Back open-source tools that turn OpenAPI into TypeScript',\n 'Sponsor fixes, releases, and new plugins for your API workflow',\n 'Help Kubb stay independent and focused on developer tools',\n] as const\n\nconst SPONSOR_LINKS = ['https://github.com/sponsors/stijnvanhulle', 'https://opencollective.com/kubb', 'https://kubb.dev/sponsors'] as const\n\n/** The writer the loggers draw with on this terminal, so a command's own lines look like its run. */\nfunction writer(): LoggerWriter {\n return isRichOutput() ? clackWriter : plainWriter\n}\n\nfunction nextTip(): string {\n const tip = SPONSOR_TIPS[Math.floor(Math.random() * SPONSOR_TIPS.length)]!\n const link = SPONSOR_LINKS[Math.floor(Math.random() * SPONSOR_LINKS.length)]!\n return `${tip}: ${link}`\n}\n\nfunction formatTip(tip: string): string {\n return styleText('magenta', ' Tip ') + styleText('yellow', tip)\n}\n\n/**\n * Prints one random tip outside every group. Rich terminals get the styled variant;\n * plain/CI output gets a stable text-only line so the tip is still visible as final output.\n */\nexport function logTip(): void {\n const tip = nextTip()\n if (!isRichOutput()) {\n console.log(`Tip: ${tip}`)\n return\n }\n\n console.log(`${styleText('magenta', '✦')}${formatTip(tip)}`)\n}\n\ntype Level = keyof typeof SYMBOLS\n\n// Not through the writers: in plain output a command's own info and warning carry their symbol, and clack's step keeps its spacing.\nfunction write(level: Level, message: string): void {\n if (isRichOutput()) {\n prompts.log[level](message)\n\n return\n }\n\n console.log(`${SYMBOLS[level]} ${message}`)\n}\n\ntype IntroOptions = {\n title?: string\n /**\n * Printed under the title, for a command that has a caveat to lead with.\n */\n warning?: string\n /**\n * Whether to open a block a later {@link logOutro} closes. Pass `false` for a command that\n * prints and exits, since nothing would ever close the block.\n *\n * @default true\n */\n block?: boolean\n}\n\n/**\n * Opens a command's output with its title.\n */\nexport function logIntro({ title, warning, block = true }: IntroOptions): void {\n if (block && isRichOutput()) {\n if (title) {\n prompts.intro(title)\n }\n\n if (warning) {\n prompts.log.warn(warning)\n }\n\n return\n }\n\n if (title) {\n console.log(title)\n }\n\n if (warning) {\n console.warn(warning)\n }\n\n if (title || warning) {\n console.log()\n }\n}\n\n/**\n * Closes the block {@link logIntro} opened. The closing gutter is not a written line, so plain\n * output prints the text on its own.\n */\nexport function logOutro(text: string): void {\n writer().groupEnd(text)\n}\n\n/**\n * Prints one empty line between two groups, without clack's gutter bar, since the bar belongs to a\n * group and a spacer sits outside every one.\n */\nexport function logSpacer(): void {\n console.log('')\n}\n\n/**\n * Opens the command with the Kubb mascot and version, or a single version line where the terminal\n * cannot draw it.\n */\nexport function logBanner(version: string): void {\n if (isRichOutput()) {\n console.log(`\\n${getIntro({ title: 'Turn your API spec into type-safe code', description: 'Ready to start', version, areEyesOpen: true })}\\n`)\n\n return\n }\n\n console.log(`Kubb CLI v${version}`)\n}\n\n/** Prints lines as one block, without a symbol in front of them. Not the writer's block, which drops clack's spacing around it. */\nexport function logBlock(lines: string | Array<string>): void {\n if (isRichOutput()) {\n prompts.log.message(lines)\n\n return\n }\n\n console.log([lines].flat().join('\\n'))\n}\n\nexport function logInfo(message: string): void {\n write('info', message)\n}\n\nexport function logWarn(message: string): void {\n write('warn', message)\n}\n\nexport function logError(message: string): void {\n write('error', message)\n}\n\n/**\n * Reports a step the command is taking, rather than something it found.\n */\nexport function logStep(message: string): void {\n write('step', message)\n}\n\n/**\n * A progress spinner, or a writer that prints each message it is given when the terminal cannot\n * animate one. Callers drive both the same way, including the failure state.\n */\nexport function createSpinner(): WriterSpinner {\n return writer().spinner()\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry-ChqX2AFQ.js","names":[],"sources":["../src/utils/registry.ts"],"sourcesContent":["import process from 'node:process'\nimport { getErrorMessage } from '@internals/utils'\nimport { checkCompatibility, type ExtensionManifest, isRegistryEntry, type RegistryArtifact, type RegistryDetail, type RegistryEntry } from '@kubb/core'\nimport { isLessThan, isValid } from 'verkit'\n\nexport const DEFAULT_REGISTRY = 'https://kubb.dev/registry'\n\nconst SLUG = '[a-z0-9]+(?:-[a-z0-9]+)*'\nconst ID = new RegExp(`^${SLUG}(\\\\/${SLUG})?$`)\n\n/** The registry base URL: `KUBB_REGISTRY`, or kubb.dev. */\nexport function registryUrl(): string {\n const url = process.env.KUBB_REGISTRY || DEFAULT_REGISTRY\n if (!/^https?:\\/\\//.test(url)) throw new Error(`KUBB_REGISTRY must be an http(s) URL, got \"${url}\".`)\n return url.replace(/\\/+$/, '')\n}\n\n/**\n * Turns `owner/slug`, or a bare `slug` meaning `kubb-labs/<slug>`, into a registry id.\n *\n * @throws when the id has another shape, so it never reaches a URL unchecked.\n */\nexport function toRegistryId(input: string): string {\n if (!ID.test(input)) throw new Error(`\"${input}\" is not a registry id. Use owner/slug, such as kubb-labs/plugin-zod, or a slug, such as plugin-zod.`)\n return input.includes('/') ? input : `kubb-labs/${input}`\n}\n\n/** GETs `url` as JSON. A non-2xx answer returns only its status; a network error throws with the URL. */\nasync function fetchJSON(url: string): Promise<{ status: number; body?: unknown }> {\n try {\n const response = await globalThis.fetch(url, { headers: { accept: 'application/json' } })\n if (!response.ok) return { status: response.status }\n return { status: response.status, body: (await response.json()) as unknown }\n } catch (cause) {\n throw new Error(`Could not read ${url}: ${getErrorMessage(cause)}`, { cause })\n }\n}\n\n/** Fetches one extension's detail document. */\nexport async function fetchRegistryDetail({ id, registry }: { id: string; registry: string }): Promise<RegistryDetail> {\n const { status, body } = await fetchJSON(`${registry}/${id}.json`)\n if (status === 404) throw new Error(`\"${id}\" is not in the registry at ${registry}.`)\n if (status !== 200 || !isRegistryEntry(body) || body.id !== id)\n throw new Error(`The registry at ${registry} sent an invalid entry for \"${id}\" (HTTP ${status}).`)\n\n const { overview } = body as { overview?: unknown }\n return { ...body, overview: typeof overview === 'string' ? overview : null }\n}\n\n/** Fetches the registry index, leaving out entries that fail validation. */\nexport async function fetchRegistryIndex({ registry }: { registry: string }): Promise<Array<RegistryEntry>> {\n const { status, body } = await fetchJSON(`${registry}/index.json`)\n const index = body as { version?: unknown; extensions?: unknown } | null | undefined\n if (status !== 200 || index?.version !== 1 || !Array.isArray(index.extensions)) {\n throw new Error(`The registry at ${registry} sent an invalid index (HTTP ${status}).`)\n }\n return index.extensions.filter(isRegistryEntry)\n}\n\n/** What the package manager installs: `<package>@<version>`, or a GitHub release's commit, so the install cannot move with the tag. */\nexport function installSpec(artifact: RegistryArtifact): string {\n return artifact.kind === 'github' ? `github:${artifact.owner}/${artifact.repo}#${artifact.commit}` : `${artifact.package}@${artifact.version}`\n}\n\n/** Why the running Kubb or Node.js version cannot use this extension, or `undefined` when it can. */\nexport function incompatibility(manifest: ExtensionManifest): string | undefined {\n try {\n checkCompatibility({ name: manifest.name, compatibility: manifest.compatibility })\n return undefined\n } catch (error) {\n return getErrorMessage(error)\n }\n}\n\n/**\n * Whether `latest` is newer than `installed`. An unknown installed version counts as outdated, and an\n * invalid `latest` never does.\n */\nexport function isOutdated({ installed, latest }: { installed: string | undefined; latest: string }): boolean {\n if (!isValid(latest)) return false\n return !installed || !isValid(installed) || isLessThan(installed, latest)\n}\n"],"mappings":";;;;;AAOA,MAAM,OAAO;AACb,MAAM,KAAK,IAAI,OAAO,IAAI,KAAK,MAAM,KAAK,IAAI;;AAG9C,SAAgB,cAAsB;CACpC,MAAM,MAAM,QAAQ,IAAI,iBAAA;CACxB,IAAI,CAAC,eAAe,KAAK,GAAG,GAAG,MAAM,IAAI,MAAM,8CAA8C,IAAI,GAAG;CACpG,OAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;;;;;;AAOA,SAAgB,aAAa,OAAuB;CAClD,IAAI,CAAC,GAAG,KAAK,KAAK,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,qGAAqG;CACpJ,OAAO,MAAM,SAAS,GAAG,IAAI,QAAQ,aAAa;AACpD;;AAGA,eAAe,UAAU,KAA0D;CACjF,IAAI;EACF,MAAM,WAAW,MAAM,WAAW,MAAM,KAAK,EAAE,SAAS,EAAE,QAAQ,mBAAmB,EAAE,CAAC;EACxF,IAAI,CAAC,SAAS,IAAI,OAAO,EAAE,QAAQ,SAAS,OAAO;EACnD,OAAO;GAAE,QAAQ,SAAS;GAAQ,MAAO,MAAM,SAAS,KAAK;EAAc;CAC7E,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,kBAAkB,IAAI,IAAI,gBAAgB,KAAK,KAAK,EAAE,MAAM,CAAC;CAC/E;AACF;;AAGA,eAAsB,oBAAoB,EAAE,IAAI,YAAuE;CACrH,MAAM,EAAE,QAAQ,SAAS,MAAM,UAAU,GAAG,SAAS,GAAG,GAAG,MAAM;CACjE,IAAI,WAAW,KAAK,MAAM,IAAI,MAAM,IAAI,GAAG,8BAA8B,SAAS,EAAE;CACpF,IAAI,WAAW,OAAO,CAAC,gBAAgB,IAAI,KAAK,KAAK,OAAO,IAC1D,MAAM,IAAI,MAAM,mBAAmB,SAAS,8BAA8B,GAAG,UAAU,OAAO,GAAG;CAEnG,MAAM,EAAE,aAAa;CACrB,OAAO;EAAE,GAAG;EAAM,UAAU,OAAO,aAAa,WAAW,WAAW;CAAK;AAC7E;;AAGA,eAAsB,mBAAmB,EAAE,YAAiE;CAC1G,MAAM,EAAE,QAAQ,SAAS,MAAM,UAAU,GAAG,SAAS,YAAY;CACjE,MAAM,QAAQ;CACd,IAAI,WAAW,OAAO,OAAO,YAAY,KAAK,CAAC,MAAM,QAAQ,MAAM,UAAU,GAC3E,MAAM,IAAI,MAAM,mBAAmB,SAAS,+BAA+B,OAAO,GAAG;CAEvF,OAAO,MAAM,WAAW,OAAO,eAAe;AAChD;;AAGA,SAAgB,YAAY,UAAoC;CAC9D,OAAO,SAAS,SAAS,WAAW,UAAU,SAAS,MAAM,GAAG,SAAS,KAAK,GAAG,SAAS,WAAW,GAAG,SAAS,QAAQ,GAAG,SAAS;AACvI;;AAGA,SAAgB,gBAAgB,UAAiD;CAC/E,IAAI;EACF,mBAAmB;GAAE,MAAM,SAAS;GAAM,eAAe,SAAS;EAAc,CAAC;EACjF;CACF,SAAS,OAAO;EACd,OAAO,gBAAgB,KAAK;CAC9B;AACF;;;;;AAMA,SAAgB,WAAW,EAAE,WAAW,UAAsE;CAC5G,IAAI,CAAC,QAAQ,MAAM,GAAG,OAAO;CAC7B,OAAO,CAAC,aAAa,CAAC,QAAQ,SAAS,KAAK,WAAW,WAAW,MAAM;AAC1E"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry-x-_nbYR6.cjs","names":["process","getErrorMessage","isRegistryEntry","isValid","isLessThan"],"sources":["../src/utils/registry.ts"],"sourcesContent":["import process from 'node:process'\nimport { getErrorMessage } from '@internals/utils'\nimport { checkCompatibility, type ExtensionManifest, isRegistryEntry, type RegistryArtifact, type RegistryDetail, type RegistryEntry } from '@kubb/core'\nimport { isLessThan, isValid } from 'verkit'\n\nexport const DEFAULT_REGISTRY = 'https://kubb.dev/registry'\n\nconst SLUG = '[a-z0-9]+(?:-[a-z0-9]+)*'\nconst ID = new RegExp(`^${SLUG}(\\\\/${SLUG})?$`)\n\n/** The registry base URL: `KUBB_REGISTRY`, or kubb.dev. */\nexport function registryUrl(): string {\n const url = process.env.KUBB_REGISTRY || DEFAULT_REGISTRY\n if (!/^https?:\\/\\//.test(url)) throw new Error(`KUBB_REGISTRY must be an http(s) URL, got \"${url}\".`)\n return url.replace(/\\/+$/, '')\n}\n\n/**\n * Turns `owner/slug`, or a bare `slug` meaning `kubb-labs/<slug>`, into a registry id.\n *\n * @throws when the id has another shape, so it never reaches a URL unchecked.\n */\nexport function toRegistryId(input: string): string {\n if (!ID.test(input)) throw new Error(`\"${input}\" is not a registry id. Use owner/slug, such as kubb-labs/plugin-zod, or a slug, such as plugin-zod.`)\n return input.includes('/') ? input : `kubb-labs/${input}`\n}\n\n/** GETs `url` as JSON. A non-2xx answer returns only its status; a network error throws with the URL. */\nasync function fetchJSON(url: string): Promise<{ status: number; body?: unknown }> {\n try {\n const response = await globalThis.fetch(url, { headers: { accept: 'application/json' } })\n if (!response.ok) return { status: response.status }\n return { status: response.status, body: (await response.json()) as unknown }\n } catch (cause) {\n throw new Error(`Could not read ${url}: ${getErrorMessage(cause)}`, { cause })\n }\n}\n\n/** Fetches one extension's detail document. */\nexport async function fetchRegistryDetail({ id, registry }: { id: string; registry: string }): Promise<RegistryDetail> {\n const { status, body } = await fetchJSON(`${registry}/${id}.json`)\n if (status === 404) throw new Error(`\"${id}\" is not in the registry at ${registry}.`)\n if (status !== 200 || !isRegistryEntry(body) || body.id !== id)\n throw new Error(`The registry at ${registry} sent an invalid entry for \"${id}\" (HTTP ${status}).`)\n\n const { overview } = body as { overview?: unknown }\n return { ...body, overview: typeof overview === 'string' ? overview : null }\n}\n\n/** Fetches the registry index, leaving out entries that fail validation. */\nexport async function fetchRegistryIndex({ registry }: { registry: string }): Promise<Array<RegistryEntry>> {\n const { status, body } = await fetchJSON(`${registry}/index.json`)\n const index = body as { version?: unknown; extensions?: unknown } | null | undefined\n if (status !== 200 || index?.version !== 1 || !Array.isArray(index.extensions)) {\n throw new Error(`The registry at ${registry} sent an invalid index (HTTP ${status}).`)\n }\n return index.extensions.filter(isRegistryEntry)\n}\n\n/** What the package manager installs: `<package>@<version>`, or a GitHub release's commit, so the install cannot move with the tag. */\nexport function installSpec(artifact: RegistryArtifact): string {\n return artifact.kind === 'github' ? `github:${artifact.owner}/${artifact.repo}#${artifact.commit}` : `${artifact.package}@${artifact.version}`\n}\n\n/** Why the running Kubb or Node.js version cannot use this extension, or `undefined` when it can. */\nexport function incompatibility(manifest: ExtensionManifest): string | undefined {\n try {\n checkCompatibility({ name: manifest.name, compatibility: manifest.compatibility })\n return undefined\n } catch (error) {\n return getErrorMessage(error)\n }\n}\n\n/**\n * Whether `latest` is newer than `installed`. An unknown installed version counts as outdated, and an\n * invalid `latest` never does.\n */\nexport function isOutdated({ installed, latest }: { installed: string | undefined; latest: string }): boolean {\n if (!isValid(latest)) return false\n return !installed || !isValid(installed) || isLessThan(installed, latest)\n}\n"],"mappings":";;;;;;AAOA,MAAM,OAAO;AACb,MAAM,KAAK,IAAI,OAAO,IAAI,KAAK,MAAM,KAAK,IAAI;;AAG9C,SAAgB,cAAsB;CACpC,MAAM,MAAMA,aAAAA,QAAQ,IAAI,iBAAA;CACxB,IAAI,CAAC,eAAe,KAAK,GAAG,GAAG,MAAM,IAAI,MAAM,8CAA8C,IAAI,GAAG;CACpG,OAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;;;;;;AAOA,SAAgB,aAAa,OAAuB;CAClD,IAAI,CAAC,GAAG,KAAK,KAAK,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,qGAAqG;CACpJ,OAAO,MAAM,SAAS,GAAG,IAAI,QAAQ,aAAa;AACpD;;AAGA,eAAe,UAAU,KAA0D;CACjF,IAAI;EACF,MAAM,WAAW,MAAM,WAAW,MAAM,KAAK,EAAE,SAAS,EAAE,QAAQ,mBAAmB,EAAE,CAAC;EACxF,IAAI,CAAC,SAAS,IAAI,OAAO,EAAE,QAAQ,SAAS,OAAO;EACnD,OAAO;GAAE,QAAQ,SAAS;GAAQ,MAAO,MAAM,SAAS,KAAK;EAAc;CAC7E,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,kBAAkB,IAAI,IAAIC,kBAAAA,gBAAgB,KAAK,KAAK,EAAE,MAAM,CAAC;CAC/E;AACF;;AAGA,eAAsB,oBAAoB,EAAE,IAAI,YAAuE;CACrH,MAAM,EAAE,QAAQ,SAAS,MAAM,UAAU,GAAG,SAAS,GAAG,GAAG,MAAM;CACjE,IAAI,WAAW,KAAK,MAAM,IAAI,MAAM,IAAI,GAAG,8BAA8B,SAAS,EAAE;CACpF,IAAI,WAAW,OAAO,EAAA,GAACC,WAAAA,gBAAAA,CAAgB,IAAI,KAAK,KAAK,OAAO,IAC1D,MAAM,IAAI,MAAM,mBAAmB,SAAS,8BAA8B,GAAG,UAAU,OAAO,GAAG;CAEnG,MAAM,EAAE,aAAa;CACrB,OAAO;EAAE,GAAG;EAAM,UAAU,OAAO,aAAa,WAAW,WAAW;CAAK;AAC7E;;AAGA,eAAsB,mBAAmB,EAAE,YAAiE;CAC1G,MAAM,EAAE,QAAQ,SAAS,MAAM,UAAU,GAAG,SAAS,YAAY;CACjE,MAAM,QAAQ;CACd,IAAI,WAAW,OAAO,OAAO,YAAY,KAAK,CAAC,MAAM,QAAQ,MAAM,UAAU,GAC3E,MAAM,IAAI,MAAM,mBAAmB,SAAS,+BAA+B,OAAO,GAAG;CAEvF,OAAO,MAAM,WAAW,OAAOA,WAAAA,eAAe;AAChD;;AAGA,SAAgB,YAAY,UAAoC;CAC9D,OAAO,SAAS,SAAS,WAAW,UAAU,SAAS,MAAM,GAAG,SAAS,KAAK,GAAG,SAAS,WAAW,GAAG,SAAS,QAAQ,GAAG,SAAS;AACvI;;AAGA,SAAgB,gBAAgB,UAAiD;CAC/E,IAAI;EACF,CAAA,GAAA,WAAA,mBAAA,CAAmB;GAAE,MAAM,SAAS;GAAM,eAAe,SAAS;EAAc,CAAC;EACjF;CACF,SAAS,OAAO;EACd,OAAOD,kBAAAA,gBAAgB,KAAK;CAC9B;AACF;;;;;AAMA,SAAgB,WAAW,EAAE,WAAW,UAAsE;CAC5G,IAAI,EAAA,GAACE,OAAAA,QAAAA,CAAQ,MAAM,GAAG,OAAO;CAC7B,OAAO,CAAC,aAAa,EAAA,GAACA,OAAAA,QAAAA,CAAQ,SAAS,MAAA,GAAKC,OAAAA,WAAAA,CAAW,WAAW,MAAM;AAC1E"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-BAlcXyYw.js","names":["logLevel","logLevelMap"],"sources":["../src/runners/generate/utils.ts","../src/runners/generate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\n\n/** Glob pattern for paths the file watcher ignores. */\nconst WATCHER_IGNORED_PATHS = '**/{.git,node_modules}/**' as const\n\n/**\n * Quiet window in milliseconds that collapses a burst of watcher events (an editor save emits several) into one rebuild.\n * It outlasts chokidar's 100 ms atomic-save window, which holds back the event of a write-then-rename save.\n */\nconst WATCHER_DEBOUNCE_MS = 250\n\n/** Interval in milliseconds between polls of a remote `input` URL in watch mode, which emits no filesystem events. */\nconst URL_WATCHER_INTERVAL_MS = 2_000\n\n/** Upper bound in milliseconds for one URL watcher request, headers and body read, so a hung server never stalls polling. */\nconst URL_WATCHER_TIMEOUT_MS = 10_000\n\ntype SerialRunnerOptions = {\n /**\n * The async work to serialize.\n */\n run(): Promise<void>\n /**\n * Receives errors thrown by `run`, so a failure never rejects the returned trigger.\n */\n onError(error: Error): void\n}\n\n/**\n * Wraps `run` so invocations never overlap: a trigger that lands while a run is in flight\n * marks it dirty and runs once more after it finishes, no matter how many triggers arrived.\n * Useful for event-driven reruns (a file watcher, a queue drain) where bursts should\n * coalesce into a single trailing run.\n *\n * @example\n * ```ts\n * const rebuild = createSerialRunner({\n * run: () => build(),\n * onError: (error) => log.error(error.message),\n * })\n * watcher.on('change', () => void rebuild())\n * ```\n */\nexport function createSerialRunner({ run, onError }: SerialRunnerOptions): () => Promise<void> {\n let running = false\n let dirty = false\n\n return async (): Promise<void> => {\n if (running) {\n dirty = true\n return\n }\n running = true\n do {\n dirty = false\n try {\n await run()\n } catch (error) {\n onError(toError(error))\n }\n } while (dirty)\n running = false\n }\n}\n\ntype WatcherLog = {\n info: (message: string) => void\n error: (message: string) => void\n}\n\n/**\n * Starts a file watcher on the given paths and calls `cb` on any change.\n * Ignores `.git` and `node_modules` directories. Event bursts (an editor save emits several)\n * are debounced into one build, and builds never overlap: changes during a build queue exactly\n * one rebuild. Resolves to a function that stops watching.\n */\nexport async function startWatcher(\n path: Array<string>,\n cb: (path: Array<string>) => Promise<void>,\n log: WatcherLog = { info: console.log, error: console.log },\n): Promise<() => Promise<void>> {\n const { watch } = await import('chokidar')\n // `ignoreInitial` skips the `add` events chokidar fires for existing files at startup, which\n // would otherwise rebuild right after the initial run.\n const watcher = watch(path, { ignorePermissionErrors: true, ignored: WATCHER_IGNORED_PATHS, ignoreInitial: true })\n\n process.once('SIGINT', () => {\n watcher.close()\n })\n process.once('SIGTERM', () => {\n watcher.close()\n })\n\n // Bursts never overlap builds on the shared hooks emitter: a change during a build\n // queues exactly one rerun.\n const runBuild = createSerialRunner({\n run: () => cb(path),\n onError: () => log.error(styleText('red', 'Watcher failed')),\n })\n let debounceTimer: ReturnType<typeof setTimeout> | null = null\n\n watcher.on('all', (type, file) => {\n log.info(styleText('yellow', styleText('bold', `Change detected: ${type} ${file}`)))\n if (debounceTimer) clearTimeout(debounceTimer)\n debounceTimer = setTimeout(() => {\n debounceTimer = null\n void runBuild()\n }, WATCHER_DEBOUNCE_MS)\n })\n\n return async () => {\n if (debounceTimer) clearTimeout(debounceTimer)\n await watcher.close()\n }\n}\n\n/**\n * Fetches the body of a remote spec URL, `undefined` when the server does not answer with a\n * readable 2xx body before `signal` aborts. The caller seeds `startUrlWatcher` with the result, so\n * the watcher compares polls against the content the initial build ran on.\n */\nexport async function fetchUrlBody(url: string, signal: AbortSignal = AbortSignal.timeout(URL_WATCHER_TIMEOUT_MS)): Promise<string | undefined> {\n try {\n const response = await fetch(url, { signal })\n if (!response.ok) return undefined\n return await response.text()\n } catch {\n return undefined\n }\n}\n\ntype UrlWatcherOptions = {\n /**\n * Sink for watcher messages, `console.log` by default.\n */\n log?: WatcherLog\n /**\n * Time in milliseconds between polls.\n */\n intervalMs?: number\n /**\n * Upper bound in milliseconds for one poll request, covering headers and body read.\n */\n timeoutMs?: number\n /**\n * Body the initial build ran against, the baseline for change detection. When omitted (the\n * server was unreachable at startup), the first successful poll rebuilds so the output catches\n * up as soon as the server responds.\n */\n initialBody?: string\n}\n\n/**\n * Polls a remote spec URL and calls `cb` whenever the response body changes. A remote document\n * emits no filesystem events, so this is the URL counterpart of `startWatcher`.\n *\n * `initialBody` seeds the change detection, so an edit landing between the initial build and the\n * first poll still rebuilds. An unreachable server (the API restarting between saves) is reported\n * once per outage and polling continues; after it recovers, a rebuild happens only when the body\n * actually differs from the last one seen, so a plain restart with an unchanged spec stays quiet.\n * Each request is aborted after `timeoutMs`, so a hung response delays at most one poll.\n *\n * Returns a function that stops polling and aborts the in-flight request, so callers (and tests)\n * can shut the watcher down without signaling the process.\n */\nexport function startUrlWatcher(url: string, cb: (path: Array<string>) => Promise<void>, options: UrlWatcherOptions = {}): () => void {\n const { log = { info: console.log, error: console.log }, intervalMs = URL_WATCHER_INTERVAL_MS, timeoutMs = URL_WATCHER_TIMEOUT_MS, initialBody } = options\n\n let lastBody = initialBody\n let offline = false\n let timer: ReturnType<typeof setTimeout> | null = null\n let controller: AbortController | null = null\n let stopped = false\n\n const stop = () => {\n stopped = true\n if (timer) clearTimeout(timer)\n controller?.abort()\n }\n process.once('SIGINT', stop)\n process.once('SIGTERM', stop)\n\n // Builds never overlap on the shared hooks emitter: a change during a build queues exactly\n // one rerun.\n const runBuild = createSerialRunner({\n run: () => cb([url]),\n onError: () => log.error(styleText('red', 'Watcher failed')),\n })\n\n const schedule = () => {\n if (!stopped) {\n timer = setTimeout(() => void poll(), intervalMs)\n }\n }\n\n const poll = async (): Promise<void> => {\n controller = new AbortController()\n // The signal also aborts the body read, so a response that stalls mid-stream still times out.\n const body = await fetchUrlBody(url, AbortSignal.any([controller.signal, AbortSignal.timeout(timeoutMs)]))\n\n if (body === undefined) {\n // `lastBody` survives the outage so recovery rebuilds only on real content changes.\n if (!offline && !stopped) {\n offline = true\n log.error(styleText('red', `Cannot reach ${url}, polling until it responds again`))\n }\n schedule()\n return\n }\n\n if (offline) {\n offline = false\n log.info(styleText('yellow', `${url} is reachable again`))\n }\n const changed = lastBody !== undefined && body !== lastBody\n if (changed) {\n log.info(styleText('yellow', styleText('bold', `Change detected: ${url}`)))\n }\n if (changed || lastBody === undefined) {\n void runBuild()\n }\n lastBody = body\n schedule()\n }\n\n void poll()\n\n return stop\n}\n","import path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport { formatters, linters, toError } from '@internals/utils'\nimport {\n Hookable,\n type CLIOptions,\n cliReporter,\n type Config,\n createKubb,\n Diagnostics,\n fileReporter,\n getInputKind,\n htmlReporter,\n jsonReporter,\n type KubbHooks,\n logLevel as logLevelMap,\n memoryStorage,\n type ReporterName,\n} from '@kubb/core'\nimport { version } from '../../../package.json'\nimport { trackRun } from '../../Telemetry.ts'\nimport { pluralize } from '../../loggers/createLogger.ts'\nimport setupReporters, { selectReporters } from '../../loggers/reporters.ts'\nimport { createSpinner, logBanner, logError, logInfo, logIntro, logOutro, logSpacer, logStep, logTip } from '../../loggers/output.ts'\nimport { getConfigs } from '../../config.ts'\nimport { isOutdated } from '../../utils/registry.ts'\nimport { fetchUrlBody, startUrlWatcher, startWatcher } from './utils.ts'\n\n/** NPM registry endpoint used to check for @kubb/cli updates. */\nconst KUBB_NPM_PACKAGE_URL = 'https://registry.npmjs.org/@kubb/cli/latest' as const\n\n/** Upper bound in milliseconds for the npm update check, so a slow registry never stalls a run. */\nconst UPDATE_CHECK_TIMEOUT_MS = 3_000\n\n/** The formatter names from `Config['output'].format`, without `'auto'` (detection, not a tool) and `false` (skip). */\ntype FormatterName = Exclude<NonNullable<Config['output']['format']>, 'auto' | false>\ntype LinterName = Exclude<NonNullable<Config['output']['lint']>, 'auto' | false>\n\n// Pinned here, not in `@internals/utils` (which must not import `@kubb/core`): a tool added to the union without a descriptor fails to compile.\nformatters satisfies Record<FormatterName, unknown>\nlinters satisfies Record<LinterName, unknown>\n\ntype GenerateProps = {\n input?: string\n config: Config\n hooks: Hookable<KubbHooks>\n /**\n * When `true`, generates in memory instead of writing to disk, and skips formatting, linting,\n * and post-generate commands.\n */\n dryRun?: boolean\n}\n\nasync function generate(options: GenerateProps): Promise<boolean> {\n const { input, hooks, dryRun = false } = options\n\n const report = trackRun({ command: 'generate', hrStart: process.hrtime() })\n\n const config: Config = {\n ...options.config,\n input: input ?? options.config.input,\n // Dry-run never touches disk, regardless of the config's own storage driver.\n storage: dryRun ? memoryStorage() : options.config.storage,\n // Also keeps core's `hasOutputPasses` false, so dry-run skips the output manifest write too.\n output: dryRun ? { ...options.config.output, format: false, lint: false, postGenerate: [] } : options.config.output,\n }\n\n // Core formats, lints and runs `output.postGenerate` after an error-free build, and reports\n // their failures as coded diagnostics that reach the summary, the json report and the exit code.\n const kubb = createKubb(config, { hooks })\n const result = await kubb.generate()\n\n if (dryRun) {\n await hooks.callHook('kubb:info', { message: 'Dry run: no files were written', info: `${result.files.length} file(s) would be generated` })\n }\n\n await report({\n plugins: Array.from(kubb.driver.plugins.values(), (p) => ({ name: p.name, options: p.options as Record<string, unknown> })),\n filesCreated: result.files.length,\n status: result.success ? 'success' : 'failed',\n })\n\n return result.success\n}\n\ntype GenerateCommandOptions = {\n input?: string\n configPath?: string\n logLevel: string\n watch: boolean\n reporters?: Array<ReporterName>\n dryRun?: boolean\n}\n\nasync function checkForUpdate(hooks: Hookable<KubbHooks>): Promise<void> {\n try {\n const res = await fetch(KUBB_NPM_PACKAGE_URL, { signal: AbortSignal.timeout(UPDATE_CHECK_TIMEOUT_MS) })\n const data = (await res.json()) as { version: string }\n if (data.version && isOutdated({ installed: version, latest: data.version })) {\n await Diagnostics.emit(hooks, Diagnostics.update({ currentVersion: version, latestVersion: data.version }))\n }\n } catch {\n // Ignore network errors\n }\n}\n\n/**\n * Runs the full Kubb generation lifecycle for the given CLI options.\n * Loads configs, sets up the reporters (CLI `--reporter` picks which of `config.reporters` to trigger),\n * checks for a newer version, and calls `generate` for each config entry.\n */\nexport async function run({ input, configPath, logLevel: logLevelKey, watch, reporters: cliReporters, dryRun }: GenerateCommandOptions): Promise<void> {\n const logLevel = logLevelMap[logLevelKey as keyof typeof logLevelMap] ?? logLevelMap.info\n const hooks = new Hookable<KubbHooks>()\n\n // CLI `--reporter` selects which reporters to trigger by name, defaulting to `cli`. `defineConfig`\n // registers the built-in reporters on the config; a config exported without it falls back to them below.\n const requestedNames: Array<ReporterName> = cliReporters?.length ? cliReporters : ['cli']\n\n // The `json` reporter owns stdout, so the command writes nothing of its own around it.\n const quiet = logLevel <= logLevelMap.silent || requestedNames.includes('json')\n\n if (!quiet) {\n logBanner(version)\n logIntro({ title: 'Configuration' })\n }\n\n // Load the config first so `config.reporters` can pick the reporters. A failure here has no\n // reporter installed yet, so fall back to the default `cli` reporter to surface it.\n const configSpinner = createSpinner()\n let configs: Array<Config>\n let resolvedConfigPath: string\n try {\n if (!quiet) configSpinner.start('Loading config')\n\n const loaded = await getConfigs({\n configPath,\n input,\n watch,\n logLevel: logLevelKey as CLIOptions['logLevel'],\n })\n configs = loaded.configs\n resolvedConfigPath = loaded.configPath\n\n if (!quiet) configSpinner.stop(`Loaded ${styleText('dim', path.relative(process.cwd(), resolvedConfigPath))}`)\n } catch (error) {\n if (!quiet) configSpinner.error('Config failed loading')\n\n setupReporters(hooks, { logLevel, reporters: [cliReporter] })\n // A diagnostic thrown while the config file runs, such as invalid extension options, sits in the cause chain.\n const diagnostic = Diagnostics.from(error)\n await (diagnostic.code === Diagnostics.code.unknown ? hooks.callHook('kubb:error', { error: toError(error) }) : Diagnostics.emit(hooks, diagnostic))\n\n if (!quiet) logOutro(styleText('red', '✗ Configuration failed'))\n process.exit(1)\n }\n\n // Without a reporter nothing is printed, not even an error, so a config written without\n // `defineConfig` gets the same built-ins it would have registered.\n const available = configs[0]?.reporters?.length ? configs[0].reporters : [cliReporter, jsonReporter, fileReporter, htmlReporter]\n const reporters = selectReporters(available, requestedNames)\n setupReporters(hooks, { logLevel, reporters })\n\n await hooks.callHook('kubb:lifecycle:start', { version })\n\n // Inside the bootstrap group, so an update notice reads as part of the setup rather than as part\n // of the first config's generation.\n await checkForUpdate(hooks)\n\n if (!quiet) logOutro(`${pluralize(configs.length, 'config')} ready`)\n\n try {\n let anyFailed = false\n for (const config of configs) {\n const effectiveInput = input ?? config.input\n const inputKind = typeof effectiveInput === 'string' ? getInputKind(effectiveInput) : undefined\n const watchPath = inputKind === 'file' || inputKind === 'url' ? (effectiveInput as string) : undefined\n if (watchPath && watch) {\n const watchedPaths = [watchPath]\n // Don't removeAll() between builds, that would also drop logger and lifecycle\n // listeners. Plugin listeners are already disposed by safeBuild's dispose()\n // in its finally block, so re-running generate() on the same hooks emitter is safe.\n const build = async (paths: Array<string>) => {\n const succeeded = await generate({ input, config, hooks, dryRun })\n logStep(styleText('yellow', `Watching for changes in ${paths.join(' and ')}`))\n if (succeeded) {\n logSpacer()\n logTip()\n }\n }\n\n // For a URL input, capture the document before the build: it becomes the watcher's\n // change-detection baseline, so an edit landing before the first poll still rebuilds.\n // When the server is down the baseline stays undefined and the watcher rebuilds on its\n // first successful poll, so recovery with an unchanged document still generates output.\n const initialBody = inputKind === 'url' ? await fetchUrlBody(watchPath) : undefined\n\n // The watchers ignore their startup state, so run the first build here; a failing one keeps watching so the user can fix the input.\n try {\n await build(watchedPaths)\n } catch (buildError) {\n await hooks.callHook('kubb:error', { error: toError(buildError) })\n }\n\n if (inputKind === 'url') {\n startUrlWatcher(watchPath, build, { log: { info: logInfo, error: logError }, initialBody })\n } else {\n await startWatcher(watchedPaths, build, { info: logInfo, error: logError })\n }\n } else {\n try {\n const succeeded = await generate({ input, config, hooks, dryRun })\n if (!succeeded) anyFailed = true\n } catch (configError) {\n await hooks.callHook('kubb:error', { error: toError(configError) })\n anyFailed = true\n }\n }\n }\n\n await hooks.callHook('kubb:lifecycle:end')\n\n // Watch mode prints a tip after each successful build. Regular generate commands need to\n // print one explicitly after the lifecycle group has closed so it stays outside the group.\n if (!quiet && !watch && !anyFailed) {\n logTip()\n }\n\n if (anyFailed) {\n process.exit(1)\n }\n } catch (error) {\n await hooks.callHook('kubb:error', { error: toError(error) })\n process.exit(1)\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-CUyhuGlK.cjs","names":["toError","styleText","trackRun","process","memoryStorage","createKubb","isOutdated","version","Diagnostics","logLevelMap","Hookable","createSpinner","getConfigs","styleText","path","cliReporter","toError","jsonReporter","fileReporter","htmlReporter","selectReporters","pluralize","getInputKind","logInfo","logError"],"sources":["../src/runners/generate/utils.ts","../src/runners/generate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\n\n/** Glob pattern for paths the file watcher ignores. */\nconst WATCHER_IGNORED_PATHS = '**/{.git,node_modules}/**' as const\n\n/**\n * Quiet window in milliseconds that collapses a burst of watcher events (an editor save emits several) into one rebuild.\n * It outlasts chokidar's 100 ms atomic-save window, which holds back the event of a write-then-rename save.\n */\nconst WATCHER_DEBOUNCE_MS = 250\n\n/** Interval in milliseconds between polls of a remote `input` URL in watch mode, which emits no filesystem events. */\nconst URL_WATCHER_INTERVAL_MS = 2_000\n\n/** Upper bound in milliseconds for one URL watcher request, headers and body read, so a hung server never stalls polling. */\nconst URL_WATCHER_TIMEOUT_MS = 10_000\n\ntype SerialRunnerOptions = {\n /**\n * The async work to serialize.\n */\n run(): Promise<void>\n /**\n * Receives errors thrown by `run`, so a failure never rejects the returned trigger.\n */\n onError(error: Error): void\n}\n\n/**\n * Wraps `run` so invocations never overlap: a trigger that lands while a run is in flight\n * marks it dirty and runs once more after it finishes, no matter how many triggers arrived.\n * Useful for event-driven reruns (a file watcher, a queue drain) where bursts should\n * coalesce into a single trailing run.\n *\n * @example\n * ```ts\n * const rebuild = createSerialRunner({\n * run: () => build(),\n * onError: (error) => log.error(error.message),\n * })\n * watcher.on('change', () => void rebuild())\n * ```\n */\nexport function createSerialRunner({ run, onError }: SerialRunnerOptions): () => Promise<void> {\n let running = false\n let dirty = false\n\n return async (): Promise<void> => {\n if (running) {\n dirty = true\n return\n }\n running = true\n do {\n dirty = false\n try {\n await run()\n } catch (error) {\n onError(toError(error))\n }\n } while (dirty)\n running = false\n }\n}\n\ntype WatcherLog = {\n info: (message: string) => void\n error: (message: string) => void\n}\n\n/**\n * Starts a file watcher on the given paths and calls `cb` on any change.\n * Ignores `.git` and `node_modules` directories. Event bursts (an editor save emits several)\n * are debounced into one build, and builds never overlap: changes during a build queue exactly\n * one rebuild. Resolves to a function that stops watching.\n */\nexport async function startWatcher(\n path: Array<string>,\n cb: (path: Array<string>) => Promise<void>,\n log: WatcherLog = { info: console.log, error: console.log },\n): Promise<() => Promise<void>> {\n const { watch } = await import('chokidar')\n // `ignoreInitial` skips the `add` events chokidar fires for existing files at startup, which\n // would otherwise rebuild right after the initial run.\n const watcher = watch(path, { ignorePermissionErrors: true, ignored: WATCHER_IGNORED_PATHS, ignoreInitial: true })\n\n process.once('SIGINT', () => {\n watcher.close()\n })\n process.once('SIGTERM', () => {\n watcher.close()\n })\n\n // Bursts never overlap builds on the shared hooks emitter: a change during a build\n // queues exactly one rerun.\n const runBuild = createSerialRunner({\n run: () => cb(path),\n onError: () => log.error(styleText('red', 'Watcher failed')),\n })\n let debounceTimer: ReturnType<typeof setTimeout> | null = null\n\n watcher.on('all', (type, file) => {\n log.info(styleText('yellow', styleText('bold', `Change detected: ${type} ${file}`)))\n if (debounceTimer) clearTimeout(debounceTimer)\n debounceTimer = setTimeout(() => {\n debounceTimer = null\n void runBuild()\n }, WATCHER_DEBOUNCE_MS)\n })\n\n return async () => {\n if (debounceTimer) clearTimeout(debounceTimer)\n await watcher.close()\n }\n}\n\n/**\n * Fetches the body of a remote spec URL, `undefined` when the server does not answer with a\n * readable 2xx body before `signal` aborts. The caller seeds `startUrlWatcher` with the result, so\n * the watcher compares polls against the content the initial build ran on.\n */\nexport async function fetchUrlBody(url: string, signal: AbortSignal = AbortSignal.timeout(URL_WATCHER_TIMEOUT_MS)): Promise<string | undefined> {\n try {\n const response = await fetch(url, { signal })\n if (!response.ok) return undefined\n return await response.text()\n } catch {\n return undefined\n }\n}\n\ntype UrlWatcherOptions = {\n /**\n * Sink for watcher messages, `console.log` by default.\n */\n log?: WatcherLog\n /**\n * Time in milliseconds between polls.\n */\n intervalMs?: number\n /**\n * Upper bound in milliseconds for one poll request, covering headers and body read.\n */\n timeoutMs?: number\n /**\n * Body the initial build ran against, the baseline for change detection. When omitted (the\n * server was unreachable at startup), the first successful poll rebuilds so the output catches\n * up as soon as the server responds.\n */\n initialBody?: string\n}\n\n/**\n * Polls a remote spec URL and calls `cb` whenever the response body changes. A remote document\n * emits no filesystem events, so this is the URL counterpart of `startWatcher`.\n *\n * `initialBody` seeds the change detection, so an edit landing between the initial build and the\n * first poll still rebuilds. An unreachable server (the API restarting between saves) is reported\n * once per outage and polling continues; after it recovers, a rebuild happens only when the body\n * actually differs from the last one seen, so a plain restart with an unchanged spec stays quiet.\n * Each request is aborted after `timeoutMs`, so a hung response delays at most one poll.\n *\n * Returns a function that stops polling and aborts the in-flight request, so callers (and tests)\n * can shut the watcher down without signaling the process.\n */\nexport function startUrlWatcher(url: string, cb: (path: Array<string>) => Promise<void>, options: UrlWatcherOptions = {}): () => void {\n const { log = { info: console.log, error: console.log }, intervalMs = URL_WATCHER_INTERVAL_MS, timeoutMs = URL_WATCHER_TIMEOUT_MS, initialBody } = options\n\n let lastBody = initialBody\n let offline = false\n let timer: ReturnType<typeof setTimeout> | null = null\n let controller: AbortController | null = null\n let stopped = false\n\n const stop = () => {\n stopped = true\n if (timer) clearTimeout(timer)\n controller?.abort()\n }\n process.once('SIGINT', stop)\n process.once('SIGTERM', stop)\n\n // Builds never overlap on the shared hooks emitter: a change during a build queues exactly\n // one rerun.\n const runBuild = createSerialRunner({\n run: () => cb([url]),\n onError: () => log.error(styleText('red', 'Watcher failed')),\n })\n\n const schedule = () => {\n if (!stopped) {\n timer = setTimeout(() => void poll(), intervalMs)\n }\n }\n\n const poll = async (): Promise<void> => {\n controller = new AbortController()\n // The signal also aborts the body read, so a response that stalls mid-stream still times out.\n const body = await fetchUrlBody(url, AbortSignal.any([controller.signal, AbortSignal.timeout(timeoutMs)]))\n\n if (body === undefined) {\n // `lastBody` survives the outage so recovery rebuilds only on real content changes.\n if (!offline && !stopped) {\n offline = true\n log.error(styleText('red', `Cannot reach ${url}, polling until it responds again`))\n }\n schedule()\n return\n }\n\n if (offline) {\n offline = false\n log.info(styleText('yellow', `${url} is reachable again`))\n }\n const changed = lastBody !== undefined && body !== lastBody\n if (changed) {\n log.info(styleText('yellow', styleText('bold', `Change detected: ${url}`)))\n }\n if (changed || lastBody === undefined) {\n void runBuild()\n }\n lastBody = body\n schedule()\n }\n\n void poll()\n\n return stop\n}\n","import path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport { formatters, linters, toError } from '@internals/utils'\nimport {\n Hookable,\n type CLIOptions,\n cliReporter,\n type Config,\n createKubb,\n Diagnostics,\n fileReporter,\n getInputKind,\n htmlReporter,\n jsonReporter,\n type KubbHooks,\n logLevel as logLevelMap,\n memoryStorage,\n type ReporterName,\n} from '@kubb/core'\nimport { version } from '../../../package.json'\nimport { trackRun } from '../../Telemetry.ts'\nimport { pluralize } from '../../loggers/createLogger.ts'\nimport setupReporters, { selectReporters } from '../../loggers/reporters.ts'\nimport { createSpinner, logBanner, logError, logInfo, logIntro, logOutro, logSpacer, logStep, logTip } from '../../loggers/output.ts'\nimport { getConfigs } from '../../config.ts'\nimport { isOutdated } from '../../utils/registry.ts'\nimport { fetchUrlBody, startUrlWatcher, startWatcher } from './utils.ts'\n\n/** NPM registry endpoint used to check for @kubb/cli updates. */\nconst KUBB_NPM_PACKAGE_URL = 'https://registry.npmjs.org/@kubb/cli/latest' as const\n\n/** Upper bound in milliseconds for the npm update check, so a slow registry never stalls a run. */\nconst UPDATE_CHECK_TIMEOUT_MS = 3_000\n\n/** The formatter names from `Config['output'].format`, without `'auto'` (detection, not a tool) and `false` (skip). */\ntype FormatterName = Exclude<NonNullable<Config['output']['format']>, 'auto' | false>\ntype LinterName = Exclude<NonNullable<Config['output']['lint']>, 'auto' | false>\n\n// Pinned here, not in `@internals/utils` (which must not import `@kubb/core`): a tool added to the union without a descriptor fails to compile.\nformatters satisfies Record<FormatterName, unknown>\nlinters satisfies Record<LinterName, unknown>\n\ntype GenerateProps = {\n input?: string\n config: Config\n hooks: Hookable<KubbHooks>\n /**\n * When `true`, generates in memory instead of writing to disk, and skips formatting, linting,\n * and post-generate commands.\n */\n dryRun?: boolean\n}\n\nasync function generate(options: GenerateProps): Promise<boolean> {\n const { input, hooks, dryRun = false } = options\n\n const report = trackRun({ command: 'generate', hrStart: process.hrtime() })\n\n const config: Config = {\n ...options.config,\n input: input ?? options.config.input,\n // Dry-run never touches disk, regardless of the config's own storage driver.\n storage: dryRun ? memoryStorage() : options.config.storage,\n // Also keeps core's `hasOutputPasses` false, so dry-run skips the output manifest write too.\n output: dryRun ? { ...options.config.output, format: false, lint: false, postGenerate: [] } : options.config.output,\n }\n\n // Core formats, lints and runs `output.postGenerate` after an error-free build, and reports\n // their failures as coded diagnostics that reach the summary, the json report and the exit code.\n const kubb = createKubb(config, { hooks })\n const result = await kubb.generate()\n\n if (dryRun) {\n await hooks.callHook('kubb:info', { message: 'Dry run: no files were written', info: `${result.files.length} file(s) would be generated` })\n }\n\n await report({\n plugins: Array.from(kubb.driver.plugins.values(), (p) => ({ name: p.name, options: p.options as Record<string, unknown> })),\n filesCreated: result.files.length,\n status: result.success ? 'success' : 'failed',\n })\n\n return result.success\n}\n\ntype GenerateCommandOptions = {\n input?: string\n configPath?: string\n logLevel: string\n watch: boolean\n reporters?: Array<ReporterName>\n dryRun?: boolean\n}\n\nasync function checkForUpdate(hooks: Hookable<KubbHooks>): Promise<void> {\n try {\n const res = await fetch(KUBB_NPM_PACKAGE_URL, { signal: AbortSignal.timeout(UPDATE_CHECK_TIMEOUT_MS) })\n const data = (await res.json()) as { version: string }\n if (data.version && isOutdated({ installed: version, latest: data.version })) {\n await Diagnostics.emit(hooks, Diagnostics.update({ currentVersion: version, latestVersion: data.version }))\n }\n } catch {\n // Ignore network errors\n }\n}\n\n/**\n * Runs the full Kubb generation lifecycle for the given CLI options.\n * Loads configs, sets up the reporters (CLI `--reporter` picks which of `config.reporters` to trigger),\n * checks for a newer version, and calls `generate` for each config entry.\n */\nexport async function run({ input, configPath, logLevel: logLevelKey, watch, reporters: cliReporters, dryRun }: GenerateCommandOptions): Promise<void> {\n const logLevel = logLevelMap[logLevelKey as keyof typeof logLevelMap] ?? logLevelMap.info\n const hooks = new Hookable<KubbHooks>()\n\n // CLI `--reporter` selects which reporters to trigger by name, defaulting to `cli`. `defineConfig`\n // registers the built-in reporters on the config; a config exported without it falls back to them below.\n const requestedNames: Array<ReporterName> = cliReporters?.length ? cliReporters : ['cli']\n\n // The `json` reporter owns stdout, so the command writes nothing of its own around it.\n const quiet = logLevel <= logLevelMap.silent || requestedNames.includes('json')\n\n if (!quiet) {\n logBanner(version)\n logIntro({ title: 'Configuration' })\n }\n\n // Load the config first so `config.reporters` can pick the reporters. A failure here has no\n // reporter installed yet, so fall back to the default `cli` reporter to surface it.\n const configSpinner = createSpinner()\n let configs: Array<Config>\n let resolvedConfigPath: string\n try {\n if (!quiet) configSpinner.start('Loading config')\n\n const loaded = await getConfigs({\n configPath,\n input,\n watch,\n logLevel: logLevelKey as CLIOptions['logLevel'],\n })\n configs = loaded.configs\n resolvedConfigPath = loaded.configPath\n\n if (!quiet) configSpinner.stop(`Loaded ${styleText('dim', path.relative(process.cwd(), resolvedConfigPath))}`)\n } catch (error) {\n if (!quiet) configSpinner.error('Config failed loading')\n\n setupReporters(hooks, { logLevel, reporters: [cliReporter] })\n // A diagnostic thrown while the config file runs, such as invalid extension options, sits in the cause chain.\n const diagnostic = Diagnostics.from(error)\n await (diagnostic.code === Diagnostics.code.unknown ? hooks.callHook('kubb:error', { error: toError(error) }) : Diagnostics.emit(hooks, diagnostic))\n\n if (!quiet) logOutro(styleText('red', '✗ Configuration failed'))\n process.exit(1)\n }\n\n // Without a reporter nothing is printed, not even an error, so a config written without\n // `defineConfig` gets the same built-ins it would have registered.\n const available = configs[0]?.reporters?.length ? configs[0].reporters : [cliReporter, jsonReporter, fileReporter, htmlReporter]\n const reporters = selectReporters(available, requestedNames)\n setupReporters(hooks, { logLevel, reporters })\n\n await hooks.callHook('kubb:lifecycle:start', { version })\n\n // Inside the bootstrap group, so an update notice reads as part of the setup rather than as part\n // of the first config's generation.\n await checkForUpdate(hooks)\n\n if (!quiet) logOutro(`${pluralize(configs.length, 'config')} ready`)\n\n try {\n let anyFailed = false\n for (const config of configs) {\n const effectiveInput = input ?? config.input\n const inputKind = typeof effectiveInput === 'string' ? getInputKind(effectiveInput) : undefined\n const watchPath = inputKind === 'file' || inputKind === 'url' ? (effectiveInput as string) : undefined\n if (watchPath && watch) {\n const watchedPaths = [watchPath]\n // Don't removeAll() between builds, that would also drop logger and lifecycle\n // listeners. Plugin listeners are already disposed by safeBuild's dispose()\n // in its finally block, so re-running generate() on the same hooks emitter is safe.\n const build = async (paths: Array<string>) => {\n const succeeded = await generate({ input, config, hooks, dryRun })\n logStep(styleText('yellow', `Watching for changes in ${paths.join(' and ')}`))\n if (succeeded) {\n logSpacer()\n logTip()\n }\n }\n\n // For a URL input, capture the document before the build: it becomes the watcher's\n // change-detection baseline, so an edit landing before the first poll still rebuilds.\n // When the server is down the baseline stays undefined and the watcher rebuilds on its\n // first successful poll, so recovery with an unchanged document still generates output.\n const initialBody = inputKind === 'url' ? await fetchUrlBody(watchPath) : undefined\n\n // The watchers ignore their startup state, so run the first build here; a failing one keeps watching so the user can fix the input.\n try {\n await build(watchedPaths)\n } catch (buildError) {\n await hooks.callHook('kubb:error', { error: toError(buildError) })\n }\n\n if (inputKind === 'url') {\n startUrlWatcher(watchPath, build, { log: { info: logInfo, error: logError }, initialBody })\n } else {\n await startWatcher(watchedPaths, build, { info: logInfo, error: logError })\n }\n } else {\n try {\n const succeeded = await generate({ input, config, hooks, dryRun })\n if (!succeeded) anyFailed = true\n } catch (configError) {\n await hooks.callHook('kubb:error', { error: toError(configError) })\n anyFailed = true\n }\n }\n }\n\n await hooks.callHook('kubb:lifecycle:end')\n\n // Watch mode prints a tip after each successful build. Regular generate commands need to\n // print one explicitly after the lifecycle group has closed so it stays outside the group.\n if (!quiet && !watch && !anyFailed) {\n logTip()\n }\n\n if (anyFailed) {\n process.exit(1)\n }\n } catch (error) {\n await hooks.callHook('kubb:error', { error: toError(error) })\n process.exit(1)\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-DHiVlG37.cjs","names":["isCIEnvironment","process","createSpinner","pairAgent","path","process","hostname","getMachineId","styleText","writeCredentials","getCredentialsPath","PairingCanceledError","KUBB_CONFIG_FILENAME","isCIEnvironment","canUseTTY","prompts","getConfigs","readCredentials","Hookable","logLevelMap","cliReporter","plainLogger","connectAgent","InvalidAgentTokenError","clearCredentials","defaultStudioUrl","trackRun","toError"],"sources":["../../../internals/utils/src/openInBrowser.ts","../src/runners/studio/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { x } from 'tinyexec'\nimport { isCIEnvironment } from './isCIEnvironment.ts'\n\nconst ignore = () => {}\n\n/**\n * Opens a URL or local file in the default browser, unless running in CI.\n */\nexport function openInBrowser(target: string): void {\n if (isCIEnvironment()) return\n\n if (process.platform === 'win32') {\n x('cmd', ['/c', 'start', '', target]).then(ignore, ignore)\n return\n }\n x(process.platform === 'darwin' ? 'open' : 'xdg-open', [target]).then(ignore, ignore)\n}\n","import { hostname } from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport * as prompts from '@clack/prompts'\nimport { KUBB_CONFIG_FILENAME } from '@internals/shared'\nimport { isCIEnvironment, openInBrowser, toError } from '@internals/utils'\nimport type { CLIOptions, Config } from '@kubb/core'\nimport { cliReporter, Hookable, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'\nimport { connectAgent, defaultStudioUrl, InvalidAgentTokenError, pairAgent, PairingCanceledError } from '@kubb/studio'\nimport { trackRun } from '../../Telemetry.ts'\nimport { plainLogger } from '../../loggers/plainLogger.ts'\nimport setupReporters from '../../loggers/reporters.ts'\nimport { createSpinner, logBlock, logIntro, logOutro, logTip } from '../../loggers/output.ts'\nimport { canUseTTY } from '../../utils/env.ts'\nimport { getConfigs } from '../../config.ts'\nimport { clearCredentials, type Credentials, getCredentialsPath, getMachineId, readCredentials, writeCredentials } from './credentials.ts'\nimport { version } from '../../../package.json'\n\ntype Permission = 'allowRead' | 'allowReadAst' | 'allowWrite' | 'allowConfigEdit' | 'allowExec'\n\nexport type StudioOptions = {\n /**\n * Current `@kubb/cli` version, reported to Studio and used for the telemetry payload.\n */\n version: string\n configPath?: string\n /**\n * Base URL of the Studio instance, for a self-hosted deployment. Resolved before it reaches here,\n * since stored credentials are bound to it.\n */\n studioUrl: string\n /**\n * What Studio may do in this project. Each flag grants outright; the rest are asked once per\n * project through {@link resolvePermissions}.\n */\n permission: Record<Permission, boolean>\n /**\n * Whether to open the approval page in a browser during pairing.\n */\n autoOpen: boolean\n logLevel?: CLIOptions['logLevel']\n}\n\nexport type SnapshotOptions = Pick<StudioOptions, 'configPath' | 'studioUrl' | 'logLevel'> & {\n /**\n * Organization CI API key. Falls back to `KUBB_TOKEN`.\n */\n token?: string\n /**\n * Stable identity for the CI agent. Falls back to CI auto-detection.\n */\n id?: string\n /** Identity of another CI agent to also compare with. Falls back to CI auto-detection. */\n baseId?: string\n /**\n * Package name for the generated tarball. Falls back to the nearest package.json.\n */\n name?: string\n /**\n * Package version for the generated tarball. Falls back to the nearest package.json.\n */\n packageVersion?: string\n /**\n * Print the result as one JSON object instead of a summary.\n */\n json?: boolean\n}\n\n/** The flags a `kubb studio` subcommand parsed; each one is optional since a subcommand declares only the flags it uses. */\nexport type StudioValues = {\n config?: string\n url?: string\n allowRead?: boolean\n allowReadAst?: boolean\n allowWrite?: boolean\n allowConfigEdit?: boolean\n allowExec?: boolean\n open?: boolean\n logLevel?: CLIOptions['logLevel']\n}\n\ntype LoginOptions = {\n /**\n * Aborting this cancels an in-flight pairing request or poll and rejects with\n * {@link PairingCanceledError}. Wired to `kubb studio`'s shutdown signal, so Ctrl+C during\n * pairing cancels it instead of leaving the poll running.\n */\n signal?: AbortSignal\n /**\n * Credentials from before this login. When the fresh pairing resolves to the same agent on the\n * same Studio, its saved project permissions carry forward instead of being asked again.\n * Left out for an explicitly requested `kubb studio login`, which always starts clean.\n */\n previousCredentials?: Credentials | null\n}\n\n/**\n * Pairs this machine with Studio and stores the resulting token.\n *\n * The CLI holds a code and the browser approves it, rather than the user copying a token out of\n * the UI. The token comes back over the CLI's own HTTPS POST, so it never lands in a URL, a\n * server log, or a `Referer` header.\n */\nexport async function login({ studioUrl, autoOpen }: StudioOptions, { signal, previousCredentials }: LoginOptions = {}): Promise<Credentials> {\n const spinner = createSpinner()\n // The spinner only starts once a code is shown.\n let waiting = false\n\n try {\n const { token, agent } = await pairAgent({\n studioUrl,\n type: 'cli',\n name: path.basename(process.cwd()),\n hostname: hostname(),\n machineId: await getMachineId(),\n signal,\n onCode: (session) => {\n console.log(`\\nOpen ${styleText('cyan', session.verification_uri)} and approve the code ${styleText('bold', session.user_code)}`)\n\n if (autoOpen) {\n openInBrowser(session.verification_uri_complete)\n }\n\n spinner.start('Waiting for approval')\n waiting = true\n },\n onRetry: (error) => spinner.message(`Could not reach Kubb Studio, retrying: ${error.message}`),\n })\n spinner.stop(`Paired as ${agent.name}`)\n\n const keepsIdentity = previousCredentials?.studioUrl === studioUrl && previousCredentials.agentId === agent.id\n const credentials: Credentials = {\n studioUrl,\n token,\n agentId: agent.id,\n agentSlug: agent.slug,\n ...(keepsIdentity && previousCredentials?.projects ? { projects: previousCredentials.projects } : {}),\n }\n await writeCredentials(credentials)\n\n console.log(`Credentials stored in ${getCredentialsPath()}`)\n\n return credentials\n } catch (error) {\n if (waiting) {\n spinner.stop(error instanceof PairingCanceledError ? 'Pairing canceled' : 'Pairing failed')\n }\n throw error\n }\n}\n\n/**\n * What each permission is asked as, in the order the questions appear.\n */\nconst PERMISSIONS: ReadonlyArray<{\n key: Permission\n /**\n * Short label for status output and the connect summary.\n */\n label: string\n question: (project: string, configPath: string) => string\n}> = [\n {\n key: 'allowRead',\n label: 'read generated files',\n question: () => 'Let Kubb Studio read the files a generation produced?',\n },\n { key: 'allowReadAst', label: 'read parsed spec', question: () => 'Let Kubb Studio read the parsed spec (the Kubb AST)?' },\n { key: 'allowWrite', label: 'write generated files', question: (project) => `Let Kubb Studio write generated files into ${project}?` },\n {\n key: 'allowConfigEdit',\n label: 'edit kubb.config.ts',\n question: (_project, configPath) => `Let Kubb Studio change plugin options in ${configPath}?`,\n },\n {\n key: 'allowExec',\n label: 'run formatter, linter, postGenerate',\n question: () => 'Let Kubb Studio run the formatter, the linter, and output.postGenerate?',\n },\n]\n\n/**\n * One row per permission, for the connect banner and `kubb studio status`. A list rather than a\n * joined line: four labels this long read as one run-on sentence side by side.\n */\nexport function formatPermissionRows(granted: Record<Permission, boolean>): Array<string> {\n return PERMISSIONS.map(({ key, label }) => `${granted[key] ? styleText('green', '✔') : styleText('red', '✘')} ${label}`)\n}\n\n/**\n * Resolves Studio permissions for the current project.\n * Flags win, saved answers are reused, and new answers are stored in `~/.kubb/credentials.json`.\n */\nexport async function resolvePermissions(\n options: StudioOptions,\n credentials: Credentials,\n configPath: string = KUBB_CONFIG_FILENAME,\n): Promise<Record<Permission, boolean>> {\n const project = process.cwd()\n const remembered = credentials.projects?.[project]\n const granted: Record<Permission, boolean> = { allowRead: false, allowReadAst: false, allowWrite: false, allowConfigEdit: false, allowExec: false }\n const answers: Partial<Record<Permission, boolean>> = {}\n prompts.updateSettings({ withGuide: true })\n\n for (const { key, question } of PERMISSIONS) {\n if (options.permission[key] || typeof remembered?.[key] === 'boolean') {\n granted[key] = options.permission[key] || remembered?.[key] === true\n continue\n }\n\n if (isCIEnvironment() || !canUseTTY()) {\n granted[key] = false\n continue\n }\n\n granted[key] = (await prompts.confirm({ message: question(project, configPath), initialValue: false })) === true\n answers[key] = granted[key]\n }\n if (Object.keys(answers).length) {\n await writeCredentials({\n ...credentials,\n projects: { ...credentials.projects, [project]: { ...remembered, ...answers } },\n })\n }\n\n return granted\n}\n\n/**\n * Loads the project's Kubb config the same way `kubb generate` does.\n * Returns the first config.\n */\nexport async function loadConfigs(options: Pick<StudioOptions, 'configPath' | 'logLevel'>): Promise<{ configPath: string; config: Config }> {\n const { configPath, configs } = await getConfigs({ configPath: options.configPath, logLevel: options.logLevel })\n const [config] = configs\n\n if (!config) {\n throw new Error('Config not defined, create a kubb.config.ts or pass it with --config')\n }\n\n // `getConfigs` resolves this to an absolute path. Relativized here, once, so the permission\n // prompt and the path Studio receives over the wire both show the project-relative form instead\n // of leaking the local filesystem layout.\n return { configPath: path.relative(process.cwd(), configPath) || configPath, config }\n}\n\n/**\n * Why a rejected token could not be recovered automatically: no browser is available to re-pair\n * with, or the token this run already re-paired for was rejected again.\n */\ntype RejectedTokenReason = 'nonInteractive' | 'reauthExhausted'\n\n/**\n * Explains a rejected token to the operator. Builds the error and nothing else, so each caller\n * decides what happens to the credentials.\n */\nfunction explainRejectedToken(error: InvalidAgentTokenError, reason: RejectedTokenReason): Error {\n if (reason === 'reauthExhausted') {\n return new Error(`${error.message} Studio rejected the newly approved token too. Run \\`kubb studio login\\` and try again.`)\n }\n\n return new Error(`${error.message} Run \\`kubb studio login\\` to pair again.`)\n}\n\nexport type PreparedConnection = {\n configPath: string\n credentials: Credentials\n permissions: StudioOptions['permission']\n}\n\n/** Validates the project and resolves pairing and permissions before starting its worker. */\nexport async function prepareConnection(options: StudioOptions, signal?: AbortSignal): Promise<PreparedConnection> {\n const { configPath } = await loadConfigs(options)\n const stored = await readCredentials()\n const credentials = await (async () => {\n if (stored?.studioUrl === options.studioUrl) return stored\n if (isCIEnvironment()) {\n throw new Error(\n `Not paired with ${options.studioUrl}. In CI, run \\`kubb studio snapshot\\` instead, or run \\`kubb studio login\\` on a machine with a browser.`,\n )\n }\n return login(options, { signal })\n })()\n const permissions = await resolvePermissions(options, credentials, configPath)\n return { configPath, credentials, permissions }\n}\n\nexport type WorkerState = 'starting' | 'connected' | 'reconnecting' | 'authentication required' | 'stopped'\n\n/** Runs the same project connection in the foreground or in a background worker. */\nexport async function connect(\n options: StudioOptions,\n context: {\n prepared?: PreparedConnection\n signal?: AbortSignal\n onState?: (state: WorkerState) => void | Promise<void>\n } = {},\n): Promise<void> {\n const shutdown = new AbortController()\n const signal = context.signal ?? shutdown.signal\n const stop = () => shutdown.abort()\n const events = process as unknown as NodeJS.EventEmitter\n if (!context.signal) {\n events.once('SIGINT', stop)\n events.once('SIGTERM', stop)\n }\n try {\n if (!context.prepared) {\n const { getWorkerStatus } = await import('./background.ts')\n const worker = await getWorkerStatus()\n if (worker.running) throw new Error('This project is running in the background. Run `kubb studio stop` first.')\n }\n const prepared = context.prepared ?? (await prepareConnection(options, signal))\n let { credentials, permissions } = prepared\n const { configPath } = prepared\n let hinted = false\n // Set by a fresh pairing until it connects, so a token rejected right after approval fails the run instead of looping.\n let pairedAgain = false\n\n // The background worker writes to a log file, so it gets the plain logger rather than the\n // animated one. The logger also covers the `studio:*` events and each generation run.\n const hooks = new Hookable<KubbHooks>()\n setupReporters(hooks, {\n logLevel: logLevelMap[options.logLevel ?? 'info'],\n reporters: [cliReporter],\n ...(context.onState ? { logger: plainLogger } : {}),\n })\n hooks.hook('studio:connected', async () => {\n pairedAgain = false\n await context.onState?.('connected')\n if (hinted || context.onState || options.logLevel === 'silent') return\n hinted = true\n logBlock(styleText('dim', 'Press Ctrl+C to disconnect'))\n logTip()\n })\n hooks.hook('studio:reconnecting', () => context.onState?.('reconnecting'))\n\n for (;;) {\n try {\n await connectAgent({\n token: credentials.token,\n studioUrl: options.studioUrl,\n configPath,\n version: options.version,\n root: process.cwd(),\n permissions,\n loadConfig: async () => (await loadConfigs(options)).config,\n hooks,\n signal,\n })\n break\n } catch (error) {\n if (!(error instanceof InvalidAgentTokenError)) throw error\n await context.onState?.('authentication required')\n await clearCredentials()\n if (pairedAgain) throw explainRejectedToken(error, 'reauthExhausted')\n if (context.onState || isCIEnvironment() || !canUseTTY()) throw explainRejectedToken(error, 'nonInteractive')\n\n console.log(styleText('yellow', `${error.message} Pairing again...`))\n credentials = await login(options, { signal, previousCredentials: credentials })\n pairedAgain = true\n permissions = await resolvePermissions(options, credentials, configPath)\n }\n }\n if (!context.onState && signal.aborted && options.logLevel !== 'silent') logOutro('Disconnected')\n } catch (error) {\n if (!(error instanceof PairingCanceledError)) throw error\n } finally {\n events.off('SIGINT', stop)\n events.off('SIGTERM', stop)\n }\n}\n\n/**\n * Runs a Studio command from its parsed flags: builds the {@link StudioOptions}, prints the intro,\n * and reports the run to telemetry. A failure is printed and sets the exit code instead of throwing.\n */\nexport async function runStudio(\n values: StudioValues,\n action: (options: StudioOptions) => Promise<unknown>,\n { block = false, json = false }: { block?: boolean; json?: boolean } = {},\n): Promise<void> {\n const options: StudioOptions = {\n version,\n configPath: values.config,\n studioUrl: values.url ?? defaultStudioUrl,\n permission: {\n allowRead: values.allowRead ?? false,\n allowReadAst: values.allowReadAst ?? false,\n allowWrite: values.allowWrite ?? false,\n allowConfigEdit: values.allowConfigEdit ?? false,\n allowExec: values.allowExec ?? false,\n },\n autoOpen: values.open ?? true,\n logLevel: values.logLevel,\n }\n const report = trackRun({ command: 'studio', hrStart: process.hrtime() })\n\n try {\n if (options.logLevel !== 'silent' && !json) {\n logIntro({\n warning: styleText('yellow', 'This feature is still under development, use with caution'),\n block,\n })\n }\n\n await action(options)\n\n await report({ status: 'success' })\n } catch (error) {\n await report({ status: 'failed' })\n console.error(toError(error).message)\n process.exitCode = 1\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-DTz7gAk1.js","names":["logLevelMap"],"sources":["../../../internals/utils/src/openInBrowser.ts","../src/runners/studio/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { x } from 'tinyexec'\nimport { isCIEnvironment } from './isCIEnvironment.ts'\n\nconst ignore = () => {}\n\n/**\n * Opens a URL or local file in the default browser, unless running in CI.\n */\nexport function openInBrowser(target: string): void {\n if (isCIEnvironment()) return\n\n if (process.platform === 'win32') {\n x('cmd', ['/c', 'start', '', target]).then(ignore, ignore)\n return\n }\n x(process.platform === 'darwin' ? 'open' : 'xdg-open', [target]).then(ignore, ignore)\n}\n","import { hostname } from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport * as prompts from '@clack/prompts'\nimport { KUBB_CONFIG_FILENAME } from '@internals/shared'\nimport { isCIEnvironment, openInBrowser, toError } from '@internals/utils'\nimport type { CLIOptions, Config } from '@kubb/core'\nimport { cliReporter, Hookable, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'\nimport { connectAgent, defaultStudioUrl, InvalidAgentTokenError, pairAgent, PairingCanceledError } from '@kubb/studio'\nimport { trackRun } from '../../Telemetry.ts'\nimport { plainLogger } from '../../loggers/plainLogger.ts'\nimport setupReporters from '../../loggers/reporters.ts'\nimport { createSpinner, logBlock, logIntro, logOutro, logTip } from '../../loggers/output.ts'\nimport { canUseTTY } from '../../utils/env.ts'\nimport { getConfigs } from '../../config.ts'\nimport { clearCredentials, type Credentials, getCredentialsPath, getMachineId, readCredentials, writeCredentials } from './credentials.ts'\nimport { version } from '../../../package.json'\n\ntype Permission = 'allowRead' | 'allowReadAst' | 'allowWrite' | 'allowConfigEdit' | 'allowExec'\n\nexport type StudioOptions = {\n /**\n * Current `@kubb/cli` version, reported to Studio and used for the telemetry payload.\n */\n version: string\n configPath?: string\n /**\n * Base URL of the Studio instance, for a self-hosted deployment. Resolved before it reaches here,\n * since stored credentials are bound to it.\n */\n studioUrl: string\n /**\n * What Studio may do in this project. Each flag grants outright; the rest are asked once per\n * project through {@link resolvePermissions}.\n */\n permission: Record<Permission, boolean>\n /**\n * Whether to open the approval page in a browser during pairing.\n */\n autoOpen: boolean\n logLevel?: CLIOptions['logLevel']\n}\n\nexport type SnapshotOptions = Pick<StudioOptions, 'configPath' | 'studioUrl' | 'logLevel'> & {\n /**\n * Organization CI API key. Falls back to `KUBB_TOKEN`.\n */\n token?: string\n /**\n * Stable identity for the CI agent. Falls back to CI auto-detection.\n */\n id?: string\n /** Identity of another CI agent to also compare with. Falls back to CI auto-detection. */\n baseId?: string\n /**\n * Package name for the generated tarball. Falls back to the nearest package.json.\n */\n name?: string\n /**\n * Package version for the generated tarball. Falls back to the nearest package.json.\n */\n packageVersion?: string\n /**\n * Print the result as one JSON object instead of a summary.\n */\n json?: boolean\n}\n\n/** The flags a `kubb studio` subcommand parsed; each one is optional since a subcommand declares only the flags it uses. */\nexport type StudioValues = {\n config?: string\n url?: string\n allowRead?: boolean\n allowReadAst?: boolean\n allowWrite?: boolean\n allowConfigEdit?: boolean\n allowExec?: boolean\n open?: boolean\n logLevel?: CLIOptions['logLevel']\n}\n\ntype LoginOptions = {\n /**\n * Aborting this cancels an in-flight pairing request or poll and rejects with\n * {@link PairingCanceledError}. Wired to `kubb studio`'s shutdown signal, so Ctrl+C during\n * pairing cancels it instead of leaving the poll running.\n */\n signal?: AbortSignal\n /**\n * Credentials from before this login. When the fresh pairing resolves to the same agent on the\n * same Studio, its saved project permissions carry forward instead of being asked again.\n * Left out for an explicitly requested `kubb studio login`, which always starts clean.\n */\n previousCredentials?: Credentials | null\n}\n\n/**\n * Pairs this machine with Studio and stores the resulting token.\n *\n * The CLI holds a code and the browser approves it, rather than the user copying a token out of\n * the UI. The token comes back over the CLI's own HTTPS POST, so it never lands in a URL, a\n * server log, or a `Referer` header.\n */\nexport async function login({ studioUrl, autoOpen }: StudioOptions, { signal, previousCredentials }: LoginOptions = {}): Promise<Credentials> {\n const spinner = createSpinner()\n // The spinner only starts once a code is shown.\n let waiting = false\n\n try {\n const { token, agent } = await pairAgent({\n studioUrl,\n type: 'cli',\n name: path.basename(process.cwd()),\n hostname: hostname(),\n machineId: await getMachineId(),\n signal,\n onCode: (session) => {\n console.log(`\\nOpen ${styleText('cyan', session.verification_uri)} and approve the code ${styleText('bold', session.user_code)}`)\n\n if (autoOpen) {\n openInBrowser(session.verification_uri_complete)\n }\n\n spinner.start('Waiting for approval')\n waiting = true\n },\n onRetry: (error) => spinner.message(`Could not reach Kubb Studio, retrying: ${error.message}`),\n })\n spinner.stop(`Paired as ${agent.name}`)\n\n const keepsIdentity = previousCredentials?.studioUrl === studioUrl && previousCredentials.agentId === agent.id\n const credentials: Credentials = {\n studioUrl,\n token,\n agentId: agent.id,\n agentSlug: agent.slug,\n ...(keepsIdentity && previousCredentials?.projects ? { projects: previousCredentials.projects } : {}),\n }\n await writeCredentials(credentials)\n\n console.log(`Credentials stored in ${getCredentialsPath()}`)\n\n return credentials\n } catch (error) {\n if (waiting) {\n spinner.stop(error instanceof PairingCanceledError ? 'Pairing canceled' : 'Pairing failed')\n }\n throw error\n }\n}\n\n/**\n * What each permission is asked as, in the order the questions appear.\n */\nconst PERMISSIONS: ReadonlyArray<{\n key: Permission\n /**\n * Short label for status output and the connect summary.\n */\n label: string\n question: (project: string, configPath: string) => string\n}> = [\n {\n key: 'allowRead',\n label: 'read generated files',\n question: () => 'Let Kubb Studio read the files a generation produced?',\n },\n { key: 'allowReadAst', label: 'read parsed spec', question: () => 'Let Kubb Studio read the parsed spec (the Kubb AST)?' },\n { key: 'allowWrite', label: 'write generated files', question: (project) => `Let Kubb Studio write generated files into ${project}?` },\n {\n key: 'allowConfigEdit',\n label: 'edit kubb.config.ts',\n question: (_project, configPath) => `Let Kubb Studio change plugin options in ${configPath}?`,\n },\n {\n key: 'allowExec',\n label: 'run formatter, linter, postGenerate',\n question: () => 'Let Kubb Studio run the formatter, the linter, and output.postGenerate?',\n },\n]\n\n/**\n * One row per permission, for the connect banner and `kubb studio status`. A list rather than a\n * joined line: four labels this long read as one run-on sentence side by side.\n */\nexport function formatPermissionRows(granted: Record<Permission, boolean>): Array<string> {\n return PERMISSIONS.map(({ key, label }) => `${granted[key] ? styleText('green', '✔') : styleText('red', '✘')} ${label}`)\n}\n\n/**\n * Resolves Studio permissions for the current project.\n * Flags win, saved answers are reused, and new answers are stored in `~/.kubb/credentials.json`.\n */\nexport async function resolvePermissions(\n options: StudioOptions,\n credentials: Credentials,\n configPath: string = KUBB_CONFIG_FILENAME,\n): Promise<Record<Permission, boolean>> {\n const project = process.cwd()\n const remembered = credentials.projects?.[project]\n const granted: Record<Permission, boolean> = { allowRead: false, allowReadAst: false, allowWrite: false, allowConfigEdit: false, allowExec: false }\n const answers: Partial<Record<Permission, boolean>> = {}\n prompts.updateSettings({ withGuide: true })\n\n for (const { key, question } of PERMISSIONS) {\n if (options.permission[key] || typeof remembered?.[key] === 'boolean') {\n granted[key] = options.permission[key] || remembered?.[key] === true\n continue\n }\n\n if (isCIEnvironment() || !canUseTTY()) {\n granted[key] = false\n continue\n }\n\n granted[key] = (await prompts.confirm({ message: question(project, configPath), initialValue: false })) === true\n answers[key] = granted[key]\n }\n if (Object.keys(answers).length) {\n await writeCredentials({\n ...credentials,\n projects: { ...credentials.projects, [project]: { ...remembered, ...answers } },\n })\n }\n\n return granted\n}\n\n/**\n * Loads the project's Kubb config the same way `kubb generate` does.\n * Returns the first config.\n */\nexport async function loadConfigs(options: Pick<StudioOptions, 'configPath' | 'logLevel'>): Promise<{ configPath: string; config: Config }> {\n const { configPath, configs } = await getConfigs({ configPath: options.configPath, logLevel: options.logLevel })\n const [config] = configs\n\n if (!config) {\n throw new Error('Config not defined, create a kubb.config.ts or pass it with --config')\n }\n\n // `getConfigs` resolves this to an absolute path. Relativized here, once, so the permission\n // prompt and the path Studio receives over the wire both show the project-relative form instead\n // of leaking the local filesystem layout.\n return { configPath: path.relative(process.cwd(), configPath) || configPath, config }\n}\n\n/**\n * Why a rejected token could not be recovered automatically: no browser is available to re-pair\n * with, or the token this run already re-paired for was rejected again.\n */\ntype RejectedTokenReason = 'nonInteractive' | 'reauthExhausted'\n\n/**\n * Explains a rejected token to the operator. Builds the error and nothing else, so each caller\n * decides what happens to the credentials.\n */\nfunction explainRejectedToken(error: InvalidAgentTokenError, reason: RejectedTokenReason): Error {\n if (reason === 'reauthExhausted') {\n return new Error(`${error.message} Studio rejected the newly approved token too. Run \\`kubb studio login\\` and try again.`)\n }\n\n return new Error(`${error.message} Run \\`kubb studio login\\` to pair again.`)\n}\n\nexport type PreparedConnection = {\n configPath: string\n credentials: Credentials\n permissions: StudioOptions['permission']\n}\n\n/** Validates the project and resolves pairing and permissions before starting its worker. */\nexport async function prepareConnection(options: StudioOptions, signal?: AbortSignal): Promise<PreparedConnection> {\n const { configPath } = await loadConfigs(options)\n const stored = await readCredentials()\n const credentials = await (async () => {\n if (stored?.studioUrl === options.studioUrl) return stored\n if (isCIEnvironment()) {\n throw new Error(\n `Not paired with ${options.studioUrl}. In CI, run \\`kubb studio snapshot\\` instead, or run \\`kubb studio login\\` on a machine with a browser.`,\n )\n }\n return login(options, { signal })\n })()\n const permissions = await resolvePermissions(options, credentials, configPath)\n return { configPath, credentials, permissions }\n}\n\nexport type WorkerState = 'starting' | 'connected' | 'reconnecting' | 'authentication required' | 'stopped'\n\n/** Runs the same project connection in the foreground or in a background worker. */\nexport async function connect(\n options: StudioOptions,\n context: {\n prepared?: PreparedConnection\n signal?: AbortSignal\n onState?: (state: WorkerState) => void | Promise<void>\n } = {},\n): Promise<void> {\n const shutdown = new AbortController()\n const signal = context.signal ?? shutdown.signal\n const stop = () => shutdown.abort()\n const events = process as unknown as NodeJS.EventEmitter\n if (!context.signal) {\n events.once('SIGINT', stop)\n events.once('SIGTERM', stop)\n }\n try {\n if (!context.prepared) {\n const { getWorkerStatus } = await import('./background.ts')\n const worker = await getWorkerStatus()\n if (worker.running) throw new Error('This project is running in the background. Run `kubb studio stop` first.')\n }\n const prepared = context.prepared ?? (await prepareConnection(options, signal))\n let { credentials, permissions } = prepared\n const { configPath } = prepared\n let hinted = false\n // Set by a fresh pairing until it connects, so a token rejected right after approval fails the run instead of looping.\n let pairedAgain = false\n\n // The background worker writes to a log file, so it gets the plain logger rather than the\n // animated one. The logger also covers the `studio:*` events and each generation run.\n const hooks = new Hookable<KubbHooks>()\n setupReporters(hooks, {\n logLevel: logLevelMap[options.logLevel ?? 'info'],\n reporters: [cliReporter],\n ...(context.onState ? { logger: plainLogger } : {}),\n })\n hooks.hook('studio:connected', async () => {\n pairedAgain = false\n await context.onState?.('connected')\n if (hinted || context.onState || options.logLevel === 'silent') return\n hinted = true\n logBlock(styleText('dim', 'Press Ctrl+C to disconnect'))\n logTip()\n })\n hooks.hook('studio:reconnecting', () => context.onState?.('reconnecting'))\n\n for (;;) {\n try {\n await connectAgent({\n token: credentials.token,\n studioUrl: options.studioUrl,\n configPath,\n version: options.version,\n root: process.cwd(),\n permissions,\n loadConfig: async () => (await loadConfigs(options)).config,\n hooks,\n signal,\n })\n break\n } catch (error) {\n if (!(error instanceof InvalidAgentTokenError)) throw error\n await context.onState?.('authentication required')\n await clearCredentials()\n if (pairedAgain) throw explainRejectedToken(error, 'reauthExhausted')\n if (context.onState || isCIEnvironment() || !canUseTTY()) throw explainRejectedToken(error, 'nonInteractive')\n\n console.log(styleText('yellow', `${error.message} Pairing again...`))\n credentials = await login(options, { signal, previousCredentials: credentials })\n pairedAgain = true\n permissions = await resolvePermissions(options, credentials, configPath)\n }\n }\n if (!context.onState && signal.aborted && options.logLevel !== 'silent') logOutro('Disconnected')\n } catch (error) {\n if (!(error instanceof PairingCanceledError)) throw error\n } finally {\n events.off('SIGINT', stop)\n events.off('SIGTERM', stop)\n }\n}\n\n/**\n * Runs a Studio command from its parsed flags: builds the {@link StudioOptions}, prints the intro,\n * and reports the run to telemetry. A failure is printed and sets the exit code instead of throwing.\n */\nexport async function runStudio(\n values: StudioValues,\n action: (options: StudioOptions) => Promise<unknown>,\n { block = false, json = false }: { block?: boolean; json?: boolean } = {},\n): Promise<void> {\n const options: StudioOptions = {\n version,\n configPath: values.config,\n studioUrl: values.url ?? defaultStudioUrl,\n permission: {\n allowRead: values.allowRead ?? false,\n allowReadAst: values.allowReadAst ?? false,\n allowWrite: values.allowWrite ?? false,\n allowConfigEdit: values.allowConfigEdit ?? false,\n allowExec: values.allowExec ?? false,\n },\n autoOpen: values.open ?? true,\n logLevel: values.logLevel,\n }\n const report = trackRun({ command: 'studio', hrStart: process.hrtime() })\n\n try {\n if (options.logLevel !== 'silent' && !json) {\n logIntro({\n warning: styleText('yellow', 'This feature is still under development, use with caution'),\n block,\n })\n }\n\n await action(options)\n\n await report({ status: 'success' })\n } catch (error) {\n await report({ status: 'failed' })\n console.error(toError(error).message)\n process.exitCode = 1\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"snapshot-C5cthCuU.cjs","names":["runtime","readFile","readFileSync","process","join","dirname","process","styleText","loadConfigs","logLevelMap","Hookable","cliReporter","createPlainLogger","createSnapshot","runStudio"],"sources":["../../../internals/utils/src/fs.ts","../src/runners/studio/ci.ts","../src/runners/studio/snapshot.ts"],"sourcesContent":["import { access, mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, isAbsolute, relative, resolve } from 'node:path'\nimport { runtime } from './runtime.ts'\n\n/**\n * Resolves to `true` when the file or directory at `path` exists.\n * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.\n *\n * @example\n * ```ts\n * if (await exists('./kubb.config.ts')) {\n * const content = await read('./kubb.config.ts')\n * }\n * ```\n */\nexport async function exists(path: string): Promise<boolean> {\n if (runtime.isBun) {\n return Bun.file(path).exists()\n }\n return access(path).then(\n () => true,\n () => false,\n )\n}\n\n/**\n * Reads the file at `path` as a UTF-8 string.\n * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.\n *\n * @example\n * ```ts\n * const source = await read('./src/Pet.ts')\n * ```\n */\nexport async function read(path: string): Promise<string> {\n if (runtime.isBun) {\n return Bun.file(path).text()\n }\n return readFile(path, { encoding: 'utf8' })\n}\n\ntype WriteOptions = {\n /**\n * Previously read content, or `null` when the file does not exist.\n * Omitting this value reads the file before writing.\n */\n stored?: string | null\n /**\n * When `true`, re-reads the file immediately after writing and throws if the\n * content does not match — useful for catching write failures on unreliable file systems.\n */\n sanity?: boolean\n}\n\n/**\n * Whether `stored` already holds `source`, comparing on the trimmed text rather than the exact\n * bytes. Surrounding whitespace is what a formatter adds and what editors strip, and neither is a\n * reason to rewrite the file.\n *\n * Both sides are trimmed, so a storage that keeps bytes verbatim settles on the same answer as one\n * that normalizes what it stores. Trimming only `stored` would leave a source with leading\n * whitespace rewritten on every build, since the stored copy keeps the whitespace the comparison\n * has already dropped.\n */\nexport function matchesStored({ stored, source }: { stored: string; source: string }): boolean {\n return stored.trim() === source.trim()\n}\n\n/**\n * Writes `data` to `path`, trimming surrounding whitespace and ending the file with a single newline\n * the way prettier, biome, and oxfmt all do.\n * Skips the write when the trimmed content is empty, or when the file already holds that content.\n * Creates any missing parent directories automatically.\n * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.\n *\n * @example\n * ```ts\n * await write('./src/Pet.ts', source) // writes and returns the trimmed content plus a newline\n * await write('./src/Pet.ts', source) // null — file unchanged\n * await write('./src/Pet.ts', ' ') // null — empty content skipped\n * ```\n */\nexport async function write(path: string, data: string, options: WriteOptions = {}): Promise<string | null> {\n const trimmed = data.trim()\n if (trimmed === '') return null\n\n const content = `${trimmed}\\n`\n const resolved = resolve(path)\n let stored = options.stored\n\n if (stored === undefined) {\n if (runtime.isBun) {\n const file = Bun.file(resolved)\n stored = (await file.exists()) ? await file.text() : null\n } else {\n try {\n stored = await readFile(resolved, { encoding: 'utf-8' })\n } catch {\n /* file doesn't exist yet */\n stored = null\n }\n }\n }\n if (matchesStored({ stored: stored ?? '', source: trimmed })) return null\n\n if (runtime.isBun) {\n await Bun.write(resolved, content)\n return content\n }\n\n // Creating the directory up front costs a syscall per file, and every file after the first in a\n // directory pays it for nothing. Write first and only fall back when the directory is missing,\n // which also stays correct when something removed it mid-run.\n try {\n await writeFile(resolved, content, { encoding: 'utf-8' })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n\n await mkdir(dirname(resolved), { recursive: true })\n await writeFile(resolved, content, { encoding: 'utf-8' })\n }\n\n if (options.sanity) {\n const savedData = await readFile(resolved, { encoding: 'utf-8' })\n if (savedData !== content) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n return savedData\n }\n\n return content\n}\n\n/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n\n/**\n * Resolves to `true` when `path` is `parent` itself or nested inside it. Both sides are resolved\n * to absolute paths first, so relative and `..`-containing inputs compare correctly.\n *\n * Guards a destructive or an out-of-tree operation: before wiping an output directory, check that\n * it does not contain the project root, and before loading a path a caller supplied, check that it\n * did not escape the directory it is allowed to read from.\n *\n * @example\n * isPathInside('./src/gen', '.') // true — nested inside the root\n * isPathInside('.', '.') // true — the same directory counts as inside\n * isPathInside('.', './src/gen') // false — the root is not inside its own output\n * isPathInside('../other', '.') // false — escapes the root\n */\nexport function isPathInside(path: string, parent: string): boolean {\n const resolvedPath = resolve(path)\n const resolvedParent = resolve(parent)\n if (resolvedPath === resolvedParent) {\n return true\n }\n\n const rel = relative(resolvedParent, resolvedPath)\n\n return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel)\n}\n","import { readFileSync } from 'node:fs'\nimport process from 'node:process'\n\n/**\n * Stable identity for the CI agent a snapshot run registers or reuses.\n */\nexport type CiContext = {\n /**\n * Fed into the machine token, so the same merge or pull request reuses one agent.\n */\n id: string\n /**\n * Agent display name shown in Studio.\n */\n name: string\n /** The commit this run builds, so the next snapshot can diff against it. */\n commit?: string\n /** The branch a pull request merges into, and the `id` runs on that branch register under. */\n base?: { branch: string; id: string }\n}\n\ntype GithubPullRequest = { number: number; head?: { sha?: string }; base?: { ref?: string } }\n\nfunction readGithubPullRequest(eventPath: string | undefined): GithubPullRequest | undefined {\n if (!eventPath) {\n return undefined\n }\n\n try {\n const event = JSON.parse(readFileSync(eventPath, 'utf8')) as { pull_request?: GithubPullRequest }\n return event.pull_request?.number ? event.pull_request : undefined\n } catch {\n return undefined\n }\n}\n\n/** Reproduces GitLab's `CI_COMMIT_REF_SLUG` for a branch it gives no slug of, like a merge request's target. */\nexport function gitlabRefSlug(ref: string): string {\n return ref\n .toLowerCase()\n .replace(/[^a-z0-9]/gu, '-')\n .slice(0, 63)\n .replace(/^-+|-+$/g, '')\n}\n\n/**\n * Detects the CI provider from its environment variables and derives a stable identity from it.\n * The GitHub row reproduces `gh:<repositoryId>:<prNumber>`, the identity `kubb-labs/action` has\n * always registered agents under, so an existing repository keeps reusing its agent.\n */\nexport function detectCi(env: Record<string, string | undefined> = process.env): CiContext | null {\n if (env.GITHUB_ACTIONS) {\n const pullRequest = readGithubPullRequest(env.GITHUB_EVENT_PATH)\n const repositoryId = env.GITHUB_REPOSITORY_ID ?? env.GITHUB_REPOSITORY ?? ''\n const branch = env.GITHUB_REF?.startsWith('refs/heads/') ? env.GITHUB_REF.slice('refs/heads/'.length) : undefined\n // A branch run is scoped by its ref, which a pull request number never collides with.\n const scope = pullRequest?.number ?? (branch ? `refs/heads/${branch}` : env.GITHUB_RUN_ID) ?? ''\n const baseBranch = pullRequest?.base?.ref\n\n return {\n id: `gh:${repositoryId}:${scope}`,\n name: `${env.GITHUB_REPOSITORY ?? 'github'}#${pullRequest?.number ?? branch ?? scope}`,\n // The head commit, not the merge commit a pull request run checks out.\n commit: pullRequest?.head?.sha ?? env.GITHUB_SHA,\n base: baseBranch ? { branch: baseBranch, id: `gh:${repositoryId}:refs/heads/${baseBranch}` } : undefined,\n }\n }\n\n if (env.GITLAB_CI) {\n const scope = env.CI_MERGE_REQUEST_IID ?? env.CI_COMMIT_REF_SLUG ?? ''\n const baseBranch = env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME\n\n return {\n id: `gl:${env.CI_PROJECT_ID ?? ''}:${scope}`,\n name: `${env.CI_PROJECT_PATH ?? 'gitlab'}#${scope}`,\n commit: env.CI_MERGE_REQUEST_SOURCE_BRANCH_SHA || env.CI_COMMIT_SHA,\n base: baseBranch ? { branch: baseBranch, id: `gl:${env.CI_PROJECT_ID ?? ''}:${gitlabRefSlug(baseBranch)}` } : undefined,\n }\n }\n\n if (env.BITBUCKET_BUILD_NUMBER) {\n const scope = env.BITBUCKET_PR_ID ?? env.BITBUCKET_BRANCH ?? ''\n\n return { id: `bb:${env.BITBUCKET_REPO_UUID ?? ''}:${scope}`, name: `${env.BITBUCKET_REPO_FULL_NAME ?? 'bitbucket'}#${scope}`, commit: env.BITBUCKET_COMMIT }\n }\n\n if (env.CIRCLECI) {\n // Owner-qualified: two projects with the same name under different CircleCI orgs must not\n // collide on one agent, since registering it purges the other project's live sessions.\n const owner = env.CIRCLE_PROJECT_USERNAME ?? ''\n const project = env.CIRCLE_PROJECT_REPONAME ?? 'circleci'\n const scope = env.CIRCLE_PR_NUMBER ?? env.CIRCLE_BRANCH ?? ''\n\n return { id: `circle:${owner}:${project}:${scope}`, name: `${owner ? `${owner}/` : ''}${project}#${scope}`, commit: env.CIRCLE_SHA1 }\n }\n\n return null\n}\n","import { dirname, join } from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport { read } from '@internals/utils'\nimport { cliReporter, Hookable, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'\nimport { createSnapshot } from '@kubb/studio'\nimport type { BranchSnapshotChanges, PublishedSnapshot, SnapshotChanges } from '@kubb/studio/protocol'\nimport { logBlock } from '../../loggers/output.ts'\nimport { createPlainLogger } from '../../loggers/plainLogger.ts'\nimport setupReporters from '../../loggers/reporters.ts'\nimport { type CiContext, detectCi } from './ci.ts'\nimport { loadConfigs, runStudio, type SnapshotOptions } from './run.ts'\nimport type { command } from '../../commands/studio/snapshot.ts'\nimport type { CommandRunner } from 'gunshi'\n\n/**\n * Walks up from `directory` to the first package.json with a name and a version.\n */\nasync function findPackageJson(directory: string): Promise<{ name: string; version: string }> {\n const packageJson = JSON.parse(await read(join(directory, 'package.json')).catch(() => '{}')) as Partial<{ name: string; version: string }>\n if (packageJson.name && packageJson.version) return { name: packageJson.name, version: packageJson.version }\n\n const parent = dirname(directory)\n if (parent === directory) throw new Error(`No package.json with a name and a version found above ${process.cwd()}`)\n\n return findPackageJson(parent)\n}\n\n/** Reads package.json only for whichever of name/version --name and --version did not supply. */\nasync function resolvePackageMetadata(options: SnapshotOptions): Promise<{ name: string; version: string }> {\n if (options.name && options.packageVersion) return { name: options.name, version: options.packageVersion }\n\n const found = await findPackageJson(process.cwd())\n return { name: options.name ?? found.name, version: options.packageVersion ?? found.version }\n}\n\nfunction resolveToken(options: SnapshotOptions): string {\n const token = options.token ?? process.env.KUBB_TOKEN\n\n if (!token) {\n throw new Error('An organization CI API key is required. Pass --token or set KUBB_TOKEN.')\n }\n\n return token\n}\n\nfunction resolveCiIdentity(options: SnapshotOptions): CiContext {\n const detected = detectCi()\n // A custom --id drops the detected base, since runs on that branch may use a custom id too.\n const ci = options.id ? { id: options.id, name: detected?.name ?? options.id, commit: detected?.commit } : detected\n\n if (!ci) {\n throw new Error('Could not detect a supported CI provider (GitHub Actions, GitLab CI, Bitbucket Pipelines, CircleCI). Pass --id.')\n }\n\n // An explicit --base-id may not name a branch, so it labels the comparison itself.\n const base = options.baseId ? { branch: options.baseId, id: options.baseId } : ci.base\n\n return { ...ci, base: base?.id === ci.id ? undefined : base }\n}\n\nfunction absoluteUrl(studioUrl: string, path: string): string {\n return new URL(path, `${studioUrl}/`).toString()\n}\n\ntype SnapshotResult = {\n id: string\n name: string | null\n version: string | null\n integrity: string | null\n url: string\n snapshotIdUrl: string\n expiresAt: string\n agentUrl: string\n /** What changed since the previous snapshot of this package on this agent. */\n changes?: SnapshotChanges\n /** What differs from the latest snapshot of the base branch, named by `branch`. */\n branchChanges?: BranchSnapshotChanges & { branch: string }\n}\n\nfunction toResult({ studioUrl, snapshot, ci }: { studioUrl: string; snapshot: PublishedSnapshot; ci: CiContext }): SnapshotResult {\n return {\n id: snapshot.id,\n name: snapshot.name,\n version: snapshot.version,\n integrity: snapshot.integrity,\n url: absoluteUrl(studioUrl, snapshot.url),\n snapshotIdUrl: absoluteUrl(studioUrl, snapshot.snapshotIdUrl),\n expiresAt: snapshot.expiresAt,\n agentUrl: absoluteUrl(studioUrl, `/agents/${snapshot.agent.slug ?? snapshot.agent.id}`),\n changes: snapshot.changes,\n branchChanges: snapshot.branchChanges && ci.base ? { ...snapshot.branchChanges, branch: ci.base.branch } : undefined,\n }\n}\n\n/** How many files differ, `against` what. */\nfunction describeChanges(changes: SnapshotChanges, against: string): string {\n const { added, changed, removed } = changes\n\n return added.length + changed.length + removed.length\n ? `${added.length} added, ${changed.length} changed, ${removed.length} removed ${against}`\n : `No changes ${against}`\n}\n\n/** One summary line: how many files changed, and since which run. */\nexport function formatChanges(changes: SnapshotChanges): string {\n if (!changes.base) {\n return 'First snapshot'\n }\n\n return describeChanges(changes, `since ${changes.base.commit?.slice(0, 7) ?? changes.base.createdAt}`)\n}\n\n/** One summary line: how the snapshot differs from the base branch's latest one. */\nexport function formatBranchChanges(changes: BranchSnapshotChanges & { branch: string }): string {\n if (changes.base) return describeChanges(changes, `against ${changes.branch}`)\n\n return changes.baseFound ? `No snapshot of ${changes.branch} for this package yet` : `No snapshot of ${changes.branch} to compare with`\n}\n\nfunction printSummary(result: SnapshotResult): void {\n logBlock([\n `${styleText('dim', 'Package'.padEnd(10))} ${result.name ?? '(unnamed)'}@${result.version ?? '0.0.0'}`,\n `${styleText('dim', 'Tarball'.padEnd(10))} ${styleText('cyan', result.url)}`,\n `${styleText('dim', 'Agent'.padEnd(10))} ${result.agentUrl}`,\n ...(result.branchChanges ? [`${styleText('dim', 'Branch'.padEnd(10))} ${formatBranchChanges(result.branchChanges)}`] : []),\n ...(result.changes ? [`${styleText('dim', 'Changes'.padEnd(10))} ${formatChanges(result.changes)}`] : []),\n `${styleText('dim', 'Expires'.padEnd(10))} ${result.expiresAt}`,\n ])\n}\n\n/**\n * Generates the project, packs it, and publishes it to Kubb Studio in one request, under the CI\n * agent the run's identity names.\n */\nexport async function snapshot(options: SnapshotOptions): Promise<void> {\n const token = resolveToken(options)\n const { config } = await loadConfigs(options)\n const ci = resolveCiIdentity(options)\n const { name, version: packageVersion } = await resolvePackageMetadata(options)\n const logLevel = logLevelMap[options.logLevel ?? 'info']\n\n const write = options.json ? (line: string) => console.error(line) : (line: string) => console.log(line)\n const hooks = new Hookable<KubbHooks>()\n setupReporters(hooks, { logLevel, reporters: [cliReporter], logger: createPlainLogger(write) })\n const step = (message: string) => {\n if (logLevel > logLevelMap.silent) {\n write(message)\n }\n }\n\n step('Generating the snapshot')\n\n try {\n const published = await createSnapshot({\n studioUrl: options.studioUrl,\n apiKey: token,\n config,\n hooks,\n id: ci.id,\n name: ci.name,\n packageName: name,\n version: packageVersion,\n commit: ci.commit,\n baseId: ci.base?.id,\n })\n const result = toResult({ studioUrl: options.studioUrl, snapshot: published, ci })\n\n step('Snapshot published')\n\n if (options.json) {\n console.log(JSON.stringify(result))\n }\n if (!options.json) {\n printSummary(result)\n }\n } catch (error) {\n step('Snapshot failed')\n throw error\n }\n}\n\nexport const runner: CommandRunner<{ args: typeof command.args; extensions: {} }> = ({ values }) =>\n runStudio(\n values,\n (options) =>\n snapshot({\n ...options,\n token: values.token,\n id: values.id,\n baseId: values.baseId,\n name: values.name,\n packageVersion: values.packageVersion,\n json: values.json,\n }),\n { json: values.json },\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAkCA,eAAsB,KAAK,MAA+B;CACxD,IAAIA,kBAAAA,QAAQ,OACV,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,KAAK;CAE7B,QAAA,GAAOC,iBAAAA,SAAAA,CAAS,MAAM,EAAE,UAAU,OAAO,CAAC;AAC5C;;;AChBA,SAAS,sBAAsB,WAA8D;CAC3F,IAAI,CAAC,WACH;CAGF,IAAI;EACF,MAAM,QAAQ,KAAK,OAAA,GAAMC,QAAAA,aAAAA,CAAa,WAAW,MAAM,CAAC;EACxD,OAAO,MAAM,cAAc,SAAS,MAAM,eAAe,KAAA;CAC3D,QAAQ;EACN;CACF;AACF;;AAGA,SAAgB,cAAc,KAAqB;CACjD,OAAO,IACJ,YAAY,CAAC,CACb,QAAQ,eAAe,GAAG,CAAC,CAC3B,MAAM,GAAG,EAAE,CAAC,CACZ,QAAQ,YAAY,EAAE;AAC3B;;;;;;AAOA,SAAgB,SAAS,MAA0CC,aAAAA,QAAQ,KAAuB;CAChG,IAAI,IAAI,gBAAgB;EACtB,MAAM,cAAc,sBAAsB,IAAI,iBAAiB;EAC/D,MAAM,eAAe,IAAI,wBAAwB,IAAI,qBAAqB;EAC1E,MAAM,SAAS,IAAI,YAAY,WAAW,aAAa,IAAI,IAAI,WAAW,MAAM,EAAoB,IAAI,KAAA;EAExG,MAAM,QAAQ,aAAa,WAAW,SAAS,cAAc,WAAW,IAAI,kBAAkB;EAC9F,MAAM,aAAa,aAAa,MAAM;EAEtC,OAAO;GACL,IAAI,MAAM,aAAa,GAAG;GAC1B,MAAM,GAAG,IAAI,qBAAqB,SAAS,GAAG,aAAa,UAAU,UAAU;GAE/E,QAAQ,aAAa,MAAM,OAAO,IAAI;GACtC,MAAM,aAAa;IAAE,QAAQ;IAAY,IAAI,MAAM,aAAa,cAAc;GAAa,IAAI,KAAA;EACjG;CACF;CAEA,IAAI,IAAI,WAAW;EACjB,MAAM,QAAQ,IAAI,wBAAwB,IAAI,sBAAsB;EACpE,MAAM,aAAa,IAAI;EAEvB,OAAO;GACL,IAAI,MAAM,IAAI,iBAAiB,GAAG,GAAG;GACrC,MAAM,GAAG,IAAI,mBAAmB,SAAS,GAAG;GAC5C,QAAQ,IAAI,sCAAsC,IAAI;GACtD,MAAM,aAAa;IAAE,QAAQ;IAAY,IAAI,MAAM,IAAI,iBAAiB,GAAG,GAAG,cAAc,UAAU;GAAI,IAAI,KAAA;EAChH;CACF;CAEA,IAAI,IAAI,wBAAwB;EAC9B,MAAM,QAAQ,IAAI,mBAAmB,IAAI,oBAAoB;EAE7D,OAAO;GAAE,IAAI,MAAM,IAAI,uBAAuB,GAAG,GAAG;GAAS,MAAM,GAAG,IAAI,4BAA4B,YAAY,GAAG;GAAS,QAAQ,IAAI;EAAiB;CAC7J;CAEA,IAAI,IAAI,UAAU;EAGhB,MAAM,QAAQ,IAAI,2BAA2B;EAC7C,MAAM,UAAU,IAAI,2BAA2B;EAC/C,MAAM,QAAQ,IAAI,oBAAoB,IAAI,iBAAiB;EAE3D,OAAO;GAAE,IAAI,UAAU,MAAM,GAAG,QAAQ,GAAG;GAAS,MAAM,GAAG,QAAQ,GAAG,MAAM,KAAK,KAAK,QAAQ,GAAG;GAAS,QAAQ,IAAI;EAAY;CACtI;CAEA,OAAO;AACT;;;;;;AC/EA,eAAe,gBAAgB,WAA+D;CAC5F,MAAM,cAAc,KAAK,MAAM,MAAM,MAAA,GAAKC,UAAAA,KAAAA,CAAK,WAAW,cAAc,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC;CAC5F,IAAI,YAAY,QAAQ,YAAY,SAAS,OAAO;EAAE,MAAM,YAAY;EAAM,SAAS,YAAY;CAAQ;CAE3G,MAAM,UAAA,GAASC,UAAAA,QAAAA,CAAQ,SAAS;CAChC,IAAI,WAAW,WAAW,MAAM,IAAI,MAAM,yDAAyDC,aAAAA,QAAQ,IAAI,GAAG;CAElH,OAAO,gBAAgB,MAAM;AAC/B;;AAGA,eAAe,uBAAuB,SAAsE;CAC1G,IAAI,QAAQ,QAAQ,QAAQ,gBAAgB,OAAO;EAAE,MAAM,QAAQ;EAAM,SAAS,QAAQ;CAAe;CAEzG,MAAM,QAAQ,MAAM,gBAAgBA,aAAAA,QAAQ,IAAI,CAAC;CACjD,OAAO;EAAE,MAAM,QAAQ,QAAQ,MAAM;EAAM,SAAS,QAAQ,kBAAkB,MAAM;CAAQ;AAC9F;AAEA,SAAS,aAAa,SAAkC;CACtD,MAAM,QAAQ,QAAQ,SAASA,aAAAA,QAAQ,IAAI;CAE3C,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,yEAAyE;CAG3F,OAAO;AACT;AAEA,SAAS,kBAAkB,SAAqC;CAC9D,MAAM,WAAW,SAAS;CAE1B,MAAM,KAAK,QAAQ,KAAK;EAAE,IAAI,QAAQ;EAAI,MAAM,UAAU,QAAQ,QAAQ;EAAI,QAAQ,UAAU;CAAO,IAAI;CAE3G,IAAI,CAAC,IACH,MAAM,IAAI,MAAM,iHAAiH;CAInI,MAAM,OAAO,QAAQ,SAAS;EAAE,QAAQ,QAAQ;EAAQ,IAAI,QAAQ;CAAO,IAAI,GAAG;CAElF,OAAO;EAAE,GAAG;EAAI,MAAM,MAAM,OAAO,GAAG,KAAK,KAAA,IAAY;CAAK;AAC9D;AAEA,SAAS,YAAY,WAAmB,MAAsB;CAC5D,OAAO,IAAI,IAAI,MAAM,GAAG,UAAU,EAAE,CAAC,CAAC,SAAS;AACjD;AAiBA,SAAS,SAAS,EAAE,WAAW,UAAU,MAAyF;CAChI,OAAO;EACL,IAAI,SAAS;EACb,MAAM,SAAS;EACf,SAAS,SAAS;EAClB,WAAW,SAAS;EACpB,KAAK,YAAY,WAAW,SAAS,GAAG;EACxC,eAAe,YAAY,WAAW,SAAS,aAAa;EAC5D,WAAW,SAAS;EACpB,UAAU,YAAY,WAAW,WAAW,SAAS,MAAM,QAAQ,SAAS,MAAM,IAAI;EACtF,SAAS,SAAS;EAClB,eAAe,SAAS,iBAAiB,GAAG,OAAO;GAAE,GAAG,SAAS;GAAe,QAAQ,GAAG,KAAK;EAAO,IAAI,KAAA;CAC7G;AACF;;AAGA,SAAS,gBAAgB,SAA0B,SAAyB;CAC1E,MAAM,EAAE,OAAO,SAAS,YAAY;CAEpC,OAAO,MAAM,SAAS,QAAQ,SAAS,QAAQ,SAC3C,GAAG,MAAM,OAAO,UAAU,QAAQ,OAAO,YAAY,QAAQ,OAAO,WAAW,YAC/E,cAAc;AACpB;;AAGA,SAAgB,cAAc,SAAkC;CAC9D,IAAI,CAAC,QAAQ,MACX,OAAO;CAGT,OAAO,gBAAgB,SAAS,SAAS,QAAQ,KAAK,QAAQ,MAAM,GAAG,CAAC,KAAK,QAAQ,KAAK,WAAW;AACvG;;AAGA,SAAgB,oBAAoB,SAA6D;CAC/F,IAAI,QAAQ,MAAM,OAAO,gBAAgB,SAAS,WAAW,QAAQ,QAAQ;CAE7E,OAAO,QAAQ,YAAY,kBAAkB,QAAQ,OAAO,yBAAyB,kBAAkB,QAAQ,OAAO;AACxH;AAEA,SAAS,aAAa,QAA8B;CAClD,eAAA,SAAS;EACP,IAAA,GAAGC,UAAAA,UAAAA,CAAU,OAAO,UAAU,OAAO,EAAE,CAAC,EAAE,IAAI,OAAO,QAAQ,YAAY,GAAG,OAAO,WAAW;EAC9F,IAAA,GAAGA,UAAAA,UAAAA,CAAU,OAAO,UAAU,OAAO,EAAE,CAAC,EAAE,KAAA,GAAIA,UAAAA,UAAAA,CAAU,QAAQ,OAAO,GAAG;EAC1E,IAAA,GAAGA,UAAAA,UAAAA,CAAU,OAAO,QAAQ,OAAO,EAAE,CAAC,EAAE,IAAI,OAAO;EACnD,GAAI,OAAO,gBAAgB,CAAC,IAAA,GAAGA,UAAAA,UAAAA,CAAU,OAAO,SAAS,OAAO,EAAE,CAAC,EAAE,IAAI,oBAAoB,OAAO,aAAa,GAAG,IAAI,CAAC;EACzH,GAAI,OAAO,UAAU,CAAC,IAAA,GAAGA,UAAAA,UAAAA,CAAU,OAAO,UAAU,OAAO,EAAE,CAAC,EAAE,IAAI,cAAc,OAAO,OAAO,GAAG,IAAI,CAAC;EACxG,IAAA,GAAGA,UAAAA,UAAAA,CAAU,OAAO,UAAU,OAAO,EAAE,CAAC,EAAE,IAAI,OAAO;CACvD,CAAC;AACH;;;;;AAMA,eAAsB,SAAS,SAAyC;CACtE,MAAM,QAAQ,aAAa,OAAO;CAClC,MAAM,EAAE,WAAW,MAAMC,YAAAA,YAAY,OAAO;CAC5C,MAAM,KAAK,kBAAkB,OAAO;CACpC,MAAM,EAAE,MAAM,SAAS,mBAAmB,MAAM,uBAAuB,OAAO;CAC9E,MAAM,WAAWC,WAAAA,SAAY,QAAQ,YAAY;CAEjD,MAAM,QAAQ,QAAQ,QAAQ,SAAiB,QAAQ,MAAM,IAAI,KAAK,SAAiB,QAAQ,IAAI,IAAI;CACvG,MAAM,QAAQ,IAAIC,WAAAA,SAAoB;CACtC,eAAA,eAAe,OAAO;EAAE;EAAU,WAAW,CAACC,WAAAA,WAAW;EAAG,QAAQC,eAAAA,kBAAkB,KAAK;CAAE,CAAC;CAC9F,MAAM,QAAQ,YAAoB;EAChC,IAAI,WAAWH,WAAAA,SAAY,QACzB,MAAM,OAAO;CAEjB;CAEA,KAAK,yBAAyB;CAE9B,IAAI;EACF,MAAM,YAAY,OAAA,GAAMI,aAAAA,eAAAA,CAAe;GACrC,WAAW,QAAQ;GACnB,QAAQ;GACR;GACA;GACA,IAAI,GAAG;GACP,MAAM,GAAG;GACT,aAAa;GACb,SAAS;GACT,QAAQ,GAAG;GACX,QAAQ,GAAG,MAAM;EACnB,CAAC;EACD,MAAM,SAAS,SAAS;GAAE,WAAW,QAAQ;GAAW,UAAU;GAAW;EAAG,CAAC;EAEjF,KAAK,oBAAoB;EAEzB,IAAI,QAAQ,MACV,QAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;EAEpC,IAAI,CAAC,QAAQ,MACX,aAAa,MAAM;CAEvB,SAAS,OAAO;EACd,KAAK,iBAAiB;EACtB,MAAM;CACR;AACF;AAEA,MAAa,UAAwE,EAAE,aACrFC,YAAAA,UACE,SACC,YACC,SAAS;CACP,GAAG;CACH,OAAO,OAAO;CACd,IAAI,OAAO;CACX,QAAQ,OAAO;CACf,MAAM,OAAO;CACb,gBAAgB,OAAO;CACvB,MAAM,OAAO;AACf,CAAC,GACH,EAAE,MAAM,OAAO,KAAK,CACtB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"snapshot-DCG-Jf1A.js","names":["logLevel","logLevelMap"],"sources":["../../../internals/utils/src/fs.ts","../src/runners/studio/ci.ts","../src/runners/studio/snapshot.ts"],"sourcesContent":["import { access, mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, isAbsolute, relative, resolve } from 'node:path'\nimport { runtime } from './runtime.ts'\n\n/**\n * Resolves to `true` when the file or directory at `path` exists.\n * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.\n *\n * @example\n * ```ts\n * if (await exists('./kubb.config.ts')) {\n * const content = await read('./kubb.config.ts')\n * }\n * ```\n */\nexport async function exists(path: string): Promise<boolean> {\n if (runtime.isBun) {\n return Bun.file(path).exists()\n }\n return access(path).then(\n () => true,\n () => false,\n )\n}\n\n/**\n * Reads the file at `path` as a UTF-8 string.\n * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.\n *\n * @example\n * ```ts\n * const source = await read('./src/Pet.ts')\n * ```\n */\nexport async function read(path: string): Promise<string> {\n if (runtime.isBun) {\n return Bun.file(path).text()\n }\n return readFile(path, { encoding: 'utf8' })\n}\n\ntype WriteOptions = {\n /**\n * Previously read content, or `null` when the file does not exist.\n * Omitting this value reads the file before writing.\n */\n stored?: string | null\n /**\n * When `true`, re-reads the file immediately after writing and throws if the\n * content does not match — useful for catching write failures on unreliable file systems.\n */\n sanity?: boolean\n}\n\n/**\n * Whether `stored` already holds `source`, comparing on the trimmed text rather than the exact\n * bytes. Surrounding whitespace is what a formatter adds and what editors strip, and neither is a\n * reason to rewrite the file.\n *\n * Both sides are trimmed, so a storage that keeps bytes verbatim settles on the same answer as one\n * that normalizes what it stores. Trimming only `stored` would leave a source with leading\n * whitespace rewritten on every build, since the stored copy keeps the whitespace the comparison\n * has already dropped.\n */\nexport function matchesStored({ stored, source }: { stored: string; source: string }): boolean {\n return stored.trim() === source.trim()\n}\n\n/**\n * Writes `data` to `path`, trimming surrounding whitespace and ending the file with a single newline\n * the way prettier, biome, and oxfmt all do.\n * Skips the write when the trimmed content is empty, or when the file already holds that content.\n * Creates any missing parent directories automatically.\n * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.\n *\n * @example\n * ```ts\n * await write('./src/Pet.ts', source) // writes and returns the trimmed content plus a newline\n * await write('./src/Pet.ts', source) // null — file unchanged\n * await write('./src/Pet.ts', ' ') // null — empty content skipped\n * ```\n */\nexport async function write(path: string, data: string, options: WriteOptions = {}): Promise<string | null> {\n const trimmed = data.trim()\n if (trimmed === '') return null\n\n const content = `${trimmed}\\n`\n const resolved = resolve(path)\n let stored = options.stored\n\n if (stored === undefined) {\n if (runtime.isBun) {\n const file = Bun.file(resolved)\n stored = (await file.exists()) ? await file.text() : null\n } else {\n try {\n stored = await readFile(resolved, { encoding: 'utf-8' })\n } catch {\n /* file doesn't exist yet */\n stored = null\n }\n }\n }\n if (matchesStored({ stored: stored ?? '', source: trimmed })) return null\n\n if (runtime.isBun) {\n await Bun.write(resolved, content)\n return content\n }\n\n // Creating the directory up front costs a syscall per file, and every file after the first in a\n // directory pays it for nothing. Write first and only fall back when the directory is missing,\n // which also stays correct when something removed it mid-run.\n try {\n await writeFile(resolved, content, { encoding: 'utf-8' })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n\n await mkdir(dirname(resolved), { recursive: true })\n await writeFile(resolved, content, { encoding: 'utf-8' })\n }\n\n if (options.sanity) {\n const savedData = await readFile(resolved, { encoding: 'utf-8' })\n if (savedData !== content) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n return savedData\n }\n\n return content\n}\n\n/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n\n/**\n * Resolves to `true` when `path` is `parent` itself or nested inside it. Both sides are resolved\n * to absolute paths first, so relative and `..`-containing inputs compare correctly.\n *\n * Guards a destructive or an out-of-tree operation: before wiping an output directory, check that\n * it does not contain the project root, and before loading a path a caller supplied, check that it\n * did not escape the directory it is allowed to read from.\n *\n * @example\n * isPathInside('./src/gen', '.') // true — nested inside the root\n * isPathInside('.', '.') // true — the same directory counts as inside\n * isPathInside('.', './src/gen') // false — the root is not inside its own output\n * isPathInside('../other', '.') // false — escapes the root\n */\nexport function isPathInside(path: string, parent: string): boolean {\n const resolvedPath = resolve(path)\n const resolvedParent = resolve(parent)\n if (resolvedPath === resolvedParent) {\n return true\n }\n\n const rel = relative(resolvedParent, resolvedPath)\n\n return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel)\n}\n","import { readFileSync } from 'node:fs'\nimport process from 'node:process'\n\n/**\n * Stable identity for the CI agent a snapshot run registers or reuses.\n */\nexport type CiContext = {\n /**\n * Fed into the machine token, so the same merge or pull request reuses one agent.\n */\n id: string\n /**\n * Agent display name shown in Studio.\n */\n name: string\n /** The commit this run builds, so the next snapshot can diff against it. */\n commit?: string\n /** The branch a pull request merges into, and the `id` runs on that branch register under. */\n base?: { branch: string; id: string }\n}\n\ntype GithubPullRequest = { number: number; head?: { sha?: string }; base?: { ref?: string } }\n\nfunction readGithubPullRequest(eventPath: string | undefined): GithubPullRequest | undefined {\n if (!eventPath) {\n return undefined\n }\n\n try {\n const event = JSON.parse(readFileSync(eventPath, 'utf8')) as { pull_request?: GithubPullRequest }\n return event.pull_request?.number ? event.pull_request : undefined\n } catch {\n return undefined\n }\n}\n\n/** Reproduces GitLab's `CI_COMMIT_REF_SLUG` for a branch it gives no slug of, like a merge request's target. */\nexport function gitlabRefSlug(ref: string): string {\n return ref\n .toLowerCase()\n .replace(/[^a-z0-9]/gu, '-')\n .slice(0, 63)\n .replace(/^-+|-+$/g, '')\n}\n\n/**\n * Detects the CI provider from its environment variables and derives a stable identity from it.\n * The GitHub row reproduces `gh:<repositoryId>:<prNumber>`, the identity `kubb-labs/action` has\n * always registered agents under, so an existing repository keeps reusing its agent.\n */\nexport function detectCi(env: Record<string, string | undefined> = process.env): CiContext | null {\n if (env.GITHUB_ACTIONS) {\n const pullRequest = readGithubPullRequest(env.GITHUB_EVENT_PATH)\n const repositoryId = env.GITHUB_REPOSITORY_ID ?? env.GITHUB_REPOSITORY ?? ''\n const branch = env.GITHUB_REF?.startsWith('refs/heads/') ? env.GITHUB_REF.slice('refs/heads/'.length) : undefined\n // A branch run is scoped by its ref, which a pull request number never collides with.\n const scope = pullRequest?.number ?? (branch ? `refs/heads/${branch}` : env.GITHUB_RUN_ID) ?? ''\n const baseBranch = pullRequest?.base?.ref\n\n return {\n id: `gh:${repositoryId}:${scope}`,\n name: `${env.GITHUB_REPOSITORY ?? 'github'}#${pullRequest?.number ?? branch ?? scope}`,\n // The head commit, not the merge commit a pull request run checks out.\n commit: pullRequest?.head?.sha ?? env.GITHUB_SHA,\n base: baseBranch ? { branch: baseBranch, id: `gh:${repositoryId}:refs/heads/${baseBranch}` } : undefined,\n }\n }\n\n if (env.GITLAB_CI) {\n const scope = env.CI_MERGE_REQUEST_IID ?? env.CI_COMMIT_REF_SLUG ?? ''\n const baseBranch = env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME\n\n return {\n id: `gl:${env.CI_PROJECT_ID ?? ''}:${scope}`,\n name: `${env.CI_PROJECT_PATH ?? 'gitlab'}#${scope}`,\n commit: env.CI_MERGE_REQUEST_SOURCE_BRANCH_SHA || env.CI_COMMIT_SHA,\n base: baseBranch ? { branch: baseBranch, id: `gl:${env.CI_PROJECT_ID ?? ''}:${gitlabRefSlug(baseBranch)}` } : undefined,\n }\n }\n\n if (env.BITBUCKET_BUILD_NUMBER) {\n const scope = env.BITBUCKET_PR_ID ?? env.BITBUCKET_BRANCH ?? ''\n\n return { id: `bb:${env.BITBUCKET_REPO_UUID ?? ''}:${scope}`, name: `${env.BITBUCKET_REPO_FULL_NAME ?? 'bitbucket'}#${scope}`, commit: env.BITBUCKET_COMMIT }\n }\n\n if (env.CIRCLECI) {\n // Owner-qualified: two projects with the same name under different CircleCI orgs must not\n // collide on one agent, since registering it purges the other project's live sessions.\n const owner = env.CIRCLE_PROJECT_USERNAME ?? ''\n const project = env.CIRCLE_PROJECT_REPONAME ?? 'circleci'\n const scope = env.CIRCLE_PR_NUMBER ?? env.CIRCLE_BRANCH ?? ''\n\n return { id: `circle:${owner}:${project}:${scope}`, name: `${owner ? `${owner}/` : ''}${project}#${scope}`, commit: env.CIRCLE_SHA1 }\n }\n\n return null\n}\n","import { dirname, join } from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport { read } from '@internals/utils'\nimport { cliReporter, Hookable, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'\nimport { createSnapshot } from '@kubb/studio'\nimport type { BranchSnapshotChanges, PublishedSnapshot, SnapshotChanges } from '@kubb/studio/protocol'\nimport { logBlock } from '../../loggers/output.ts'\nimport { createPlainLogger } from '../../loggers/plainLogger.ts'\nimport setupReporters from '../../loggers/reporters.ts'\nimport { type CiContext, detectCi } from './ci.ts'\nimport { loadConfigs, runStudio, type SnapshotOptions } from './run.ts'\nimport type { command } from '../../commands/studio/snapshot.ts'\nimport type { CommandRunner } from 'gunshi'\n\n/**\n * Walks up from `directory` to the first package.json with a name and a version.\n */\nasync function findPackageJson(directory: string): Promise<{ name: string; version: string }> {\n const packageJson = JSON.parse(await read(join(directory, 'package.json')).catch(() => '{}')) as Partial<{ name: string; version: string }>\n if (packageJson.name && packageJson.version) return { name: packageJson.name, version: packageJson.version }\n\n const parent = dirname(directory)\n if (parent === directory) throw new Error(`No package.json with a name and a version found above ${process.cwd()}`)\n\n return findPackageJson(parent)\n}\n\n/** Reads package.json only for whichever of name/version --name and --version did not supply. */\nasync function resolvePackageMetadata(options: SnapshotOptions): Promise<{ name: string; version: string }> {\n if (options.name && options.packageVersion) return { name: options.name, version: options.packageVersion }\n\n const found = await findPackageJson(process.cwd())\n return { name: options.name ?? found.name, version: options.packageVersion ?? found.version }\n}\n\nfunction resolveToken(options: SnapshotOptions): string {\n const token = options.token ?? process.env.KUBB_TOKEN\n\n if (!token) {\n throw new Error('An organization CI API key is required. Pass --token or set KUBB_TOKEN.')\n }\n\n return token\n}\n\nfunction resolveCiIdentity(options: SnapshotOptions): CiContext {\n const detected = detectCi()\n // A custom --id drops the detected base, since runs on that branch may use a custom id too.\n const ci = options.id ? { id: options.id, name: detected?.name ?? options.id, commit: detected?.commit } : detected\n\n if (!ci) {\n throw new Error('Could not detect a supported CI provider (GitHub Actions, GitLab CI, Bitbucket Pipelines, CircleCI). Pass --id.')\n }\n\n // An explicit --base-id may not name a branch, so it labels the comparison itself.\n const base = options.baseId ? { branch: options.baseId, id: options.baseId } : ci.base\n\n return { ...ci, base: base?.id === ci.id ? undefined : base }\n}\n\nfunction absoluteUrl(studioUrl: string, path: string): string {\n return new URL(path, `${studioUrl}/`).toString()\n}\n\ntype SnapshotResult = {\n id: string\n name: string | null\n version: string | null\n integrity: string | null\n url: string\n snapshotIdUrl: string\n expiresAt: string\n agentUrl: string\n /** What changed since the previous snapshot of this package on this agent. */\n changes?: SnapshotChanges\n /** What differs from the latest snapshot of the base branch, named by `branch`. */\n branchChanges?: BranchSnapshotChanges & { branch: string }\n}\n\nfunction toResult({ studioUrl, snapshot, ci }: { studioUrl: string; snapshot: PublishedSnapshot; ci: CiContext }): SnapshotResult {\n return {\n id: snapshot.id,\n name: snapshot.name,\n version: snapshot.version,\n integrity: snapshot.integrity,\n url: absoluteUrl(studioUrl, snapshot.url),\n snapshotIdUrl: absoluteUrl(studioUrl, snapshot.snapshotIdUrl),\n expiresAt: snapshot.expiresAt,\n agentUrl: absoluteUrl(studioUrl, `/agents/${snapshot.agent.slug ?? snapshot.agent.id}`),\n changes: snapshot.changes,\n branchChanges: snapshot.branchChanges && ci.base ? { ...snapshot.branchChanges, branch: ci.base.branch } : undefined,\n }\n}\n\n/** How many files differ, `against` what. */\nfunction describeChanges(changes: SnapshotChanges, against: string): string {\n const { added, changed, removed } = changes\n\n return added.length + changed.length + removed.length\n ? `${added.length} added, ${changed.length} changed, ${removed.length} removed ${against}`\n : `No changes ${against}`\n}\n\n/** One summary line: how many files changed, and since which run. */\nexport function formatChanges(changes: SnapshotChanges): string {\n if (!changes.base) {\n return 'First snapshot'\n }\n\n return describeChanges(changes, `since ${changes.base.commit?.slice(0, 7) ?? changes.base.createdAt}`)\n}\n\n/** One summary line: how the snapshot differs from the base branch's latest one. */\nexport function formatBranchChanges(changes: BranchSnapshotChanges & { branch: string }): string {\n if (changes.base) return describeChanges(changes, `against ${changes.branch}`)\n\n return changes.baseFound ? `No snapshot of ${changes.branch} for this package yet` : `No snapshot of ${changes.branch} to compare with`\n}\n\nfunction printSummary(result: SnapshotResult): void {\n logBlock([\n `${styleText('dim', 'Package'.padEnd(10))} ${result.name ?? '(unnamed)'}@${result.version ?? '0.0.0'}`,\n `${styleText('dim', 'Tarball'.padEnd(10))} ${styleText('cyan', result.url)}`,\n `${styleText('dim', 'Agent'.padEnd(10))} ${result.agentUrl}`,\n ...(result.branchChanges ? [`${styleText('dim', 'Branch'.padEnd(10))} ${formatBranchChanges(result.branchChanges)}`] : []),\n ...(result.changes ? [`${styleText('dim', 'Changes'.padEnd(10))} ${formatChanges(result.changes)}`] : []),\n `${styleText('dim', 'Expires'.padEnd(10))} ${result.expiresAt}`,\n ])\n}\n\n/**\n * Generates the project, packs it, and publishes it to Kubb Studio in one request, under the CI\n * agent the run's identity names.\n */\nexport async function snapshot(options: SnapshotOptions): Promise<void> {\n const token = resolveToken(options)\n const { config } = await loadConfigs(options)\n const ci = resolveCiIdentity(options)\n const { name, version: packageVersion } = await resolvePackageMetadata(options)\n const logLevel = logLevelMap[options.logLevel ?? 'info']\n\n const write = options.json ? (line: string) => console.error(line) : (line: string) => console.log(line)\n const hooks = new Hookable<KubbHooks>()\n setupReporters(hooks, { logLevel, reporters: [cliReporter], logger: createPlainLogger(write) })\n const step = (message: string) => {\n if (logLevel > logLevelMap.silent) {\n write(message)\n }\n }\n\n step('Generating the snapshot')\n\n try {\n const published = await createSnapshot({\n studioUrl: options.studioUrl,\n apiKey: token,\n config,\n hooks,\n id: ci.id,\n name: ci.name,\n packageName: name,\n version: packageVersion,\n commit: ci.commit,\n baseId: ci.base?.id,\n })\n const result = toResult({ studioUrl: options.studioUrl, snapshot: published, ci })\n\n step('Snapshot published')\n\n if (options.json) {\n console.log(JSON.stringify(result))\n }\n if (!options.json) {\n printSummary(result)\n }\n } catch (error) {\n step('Snapshot failed')\n throw error\n }\n}\n\nexport const runner: CommandRunner<{ args: typeof command.args; extensions: {} }> = ({ values }) =>\n runStudio(\n values,\n (options) =>\n snapshot({\n ...options,\n token: values.token,\n id: values.id,\n baseId: values.baseId,\n name: values.name,\n packageVersion: values.packageVersion,\n json: values.json,\n }),\n { json: values.json },\n )\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {}