@kubb/cli 5.8.3 → 5.9.0

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 (63) hide show
  1. package/README.md +9 -3
  2. package/dist/{Telemetry-BOCR2q1g.js → Telemetry-BivZAaw9.js} +2 -2
  3. package/dist/{Telemetry-BOCR2q1g.js.map → Telemetry-BivZAaw9.js.map} +1 -1
  4. package/dist/{Telemetry-D1M0d8PT.cjs → Telemetry-D1jiXfo2.cjs} +2 -2
  5. package/dist/{Telemetry-D1M0d8PT.cjs.map → Telemetry-D1jiXfo2.cjs.map} +1 -1
  6. package/dist/{background-1fPYMKIh.cjs → background-Cd2TGkLg.cjs} +2 -2
  7. package/dist/{background-1fPYMKIh.cjs.map → background-Cd2TGkLg.cjs.map} +1 -1
  8. package/dist/background-D0UaV1ZP.js +1 -0
  9. package/dist/{background-lBbQYvN7.js → background-uIIElWXl.js} +2 -2
  10. package/dist/{background-lBbQYvN7.js.map → background-uIIElWXl.js.map} +1 -1
  11. package/dist/{commands-DCwzlFGA.js → commands-BlNFxWKB.js} +3 -3
  12. package/dist/{commands-DCwzlFGA.js.map → commands-BlNFxWKB.js.map} +1 -1
  13. package/dist/{commands-VS9f9all.cjs → commands-ID-cYLXW.cjs} +3 -3
  14. package/dist/{commands-VS9f9all.cjs.map → commands-ID-cYLXW.cjs.map} +1 -1
  15. package/dist/index.cjs +16 -15
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.js +16 -15
  18. package/dist/index.js.map +1 -1
  19. package/dist/{registry-DjGepXb0.js → registry-B7BvdrGE.js} +6 -2
  20. package/dist/registry-B7BvdrGE.js.map +1 -0
  21. package/dist/{registry-CCKUL3ps.cjs → registry-DER9aRyg.cjs} +11 -1
  22. package/dist/registry-DER9aRyg.cjs.map +1 -0
  23. package/dist/{run-mIZ7hJVc.js → run-BF2Wq1Io.js} +3 -3
  24. package/dist/{run-mIZ7hJVc.js.map → run-BF2Wq1Io.js.map} +1 -1
  25. package/dist/{run-C4IHvWT_.cjs → run-C5P5_H0R.cjs} +3 -3
  26. package/dist/run-C5P5_H0R.cjs.map +1 -0
  27. package/dist/{run-BKkuOyne.cjs → run-CNXBX4kr.cjs} +2 -2
  28. package/dist/{run-BKkuOyne.cjs.map → run-CNXBX4kr.cjs.map} +1 -1
  29. package/dist/{run-BaFyksnF.cjs → run-CnBJroZW.cjs} +2 -2
  30. package/dist/{run-BaFyksnF.cjs.map → run-CnBJroZW.cjs.map} +1 -1
  31. package/dist/{run-C31KZ8zp.cjs → run-D4cZ-1zg.cjs} +2 -2
  32. package/dist/{run-C31KZ8zp.cjs.map → run-D4cZ-1zg.cjs.map} +1 -1
  33. package/dist/{run-B9wWJSSx.js → run-DRR30f0e.js} +3 -3
  34. package/dist/run-DRR30f0e.js.map +1 -0
  35. package/dist/{run-DrUd6OfI.cjs → run-DSeEZTnT.cjs} +3 -3
  36. package/dist/{run-DrUd6OfI.cjs.map → run-DSeEZTnT.cjs.map} +1 -1
  37. package/dist/{run-BF_nhSiJ.cjs → run-DfkvTomI.cjs} +2 -2
  38. package/dist/{run-BF_nhSiJ.cjs.map → run-DfkvTomI.cjs.map} +1 -1
  39. package/dist/{run-DjINtbfD.js → run-DnXUzX34.js} +2 -2
  40. package/dist/{run-DjINtbfD.js.map → run-DnXUzX34.js.map} +1 -1
  41. package/dist/{run-CDS3EWEN.js → run-Ey756UCd.js} +2 -2
  42. package/dist/{run-CDS3EWEN.js.map → run-Ey756UCd.js.map} +1 -1
  43. package/dist/{run-DVIqUt1x.cjs → run-VAkf24Cw.cjs} +3 -3
  44. package/dist/run-VAkf24Cw.cjs.map +1 -0
  45. package/dist/{run-CNiUPnC7.js → run-ajUuT3vK.js} +2 -2
  46. package/dist/{run-CNiUPnC7.js.map → run-ajUuT3vK.js.map} +1 -1
  47. package/dist/{run-CkIxVyjD.js → run-mx0KM8y5.js} +2 -2
  48. package/dist/{run-CkIxVyjD.js.map → run-mx0KM8y5.js.map} +1 -1
  49. package/dist/{run-BURZ4hDs.js → run-yb2R1vt0.js} +3 -3
  50. package/dist/run-yb2R1vt0.js.map +1 -0
  51. package/dist/{snapshot-DgsBHsOb.js → snapshot-CHKxNlYg.js} +3 -3
  52. package/dist/{snapshot-DgsBHsOb.js.map → snapshot-CHKxNlYg.js.map} +1 -1
  53. package/dist/{snapshot-CQcQ5L6B.cjs → snapshot-D5OaRDf9.cjs} +3 -3
  54. package/dist/{snapshot-CQcQ5L6B.cjs.map → snapshot-D5OaRDf9.cjs.map} +1 -1
  55. package/dist/studioWorker.js +2 -2
  56. package/package.json +7 -7
  57. package/dist/background-BreCsKLJ.js +0 -1
  58. package/dist/registry-CCKUL3ps.cjs.map +0 -1
  59. package/dist/registry-DjGepXb0.js.map +0 -1
  60. package/dist/run-B9wWJSSx.js.map +0 -1
  61. package/dist/run-BURZ4hDs.js.map +0 -1
  62. package/dist/run-C4IHvWT_.cjs.map +0 -1
  63. package/dist/run-DVIqUt1x.cjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  const require_agent = require("./agent-DElUuYuy.cjs");
2
2
  const require_errors = require("./errors-BdA8M78q.cjs");
3
- const require_Telemetry = require("./Telemetry-D1M0d8PT.cjs");
3
+ const require_Telemetry = require("./Telemetry-D1jiXfo2.cjs");
4
4
  let node_util = require("node:util");
5
5
  let node_process = require("node:process");
6
6
  node_process = require_agent.__toESM(node_process, 1);
@@ -40,4 +40,4 @@ async function run({ input }) {
40
40
  //#endregion
41
41
  exports.run = run;
42
42
 
43
- //# sourceMappingURL=run-BF_nhSiJ.cjs.map
43
+ //# sourceMappingURL=run-DfkvTomI.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-BF_nhSiJ.cjs","names":["trackRun","process","styleText","toError"],"sources":["../src/runners/validate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport { trackRun } from '../../Telemetry.ts'\n\ntype ValidateOptions = {\n /**\n * Path or URL to the OpenAPI/Swagger file to validate.\n */\n input: string\n}\n\n/**\n * Validates an OpenAPI/Swagger file at `input` using `@kubb/adapter-oas`.\n * Exits the process with code 1 on validation failure or missing dependency.\n */\nexport async function run({ input }: ValidateOptions): Promise<void> {\n const report = trackRun({ command: 'validate', hrStart: process.hrtime() })\n\n try {\n const { adapterOas } = await import('@kubb/adapter-oas')\n\n const adapter = adapterOas()\n if (!adapter.validate) {\n throw new Error('The loaded adapter does not support validation.')\n }\n\n await adapter.validate(input, { throwOnError: true })\n await report({ status: 'success' })\n\n console.log('✅ Validation success')\n } catch (error) {\n await report({ status: 'failed' })\n if (error instanceof Error && /@kubb\\/adapter-oas/.test(error.message)) {\n console.error(styleText('red', 'The @kubb/adapter-oas package is not installed.'))\n console.error('')\n console.error('Install it with:')\n console.error(styleText('cyan', ' npm install @kubb/adapter-oas'))\n console.error(styleText('cyan', ' # or'))\n console.error(styleText('cyan', ' pnpm install @kubb/adapter-oas'))\n console.error('')\n }\n console.error('❌ Validation failed')\n console.error(toError(error).message)\n\n process.exit(1)\n }\n}\n"],"mappings":";;;;;;;;;;;AAgBA,eAAsB,IAAI,EAAE,SAAyC;CACnE,MAAM,SAASA,kBAAAA,SAAS;EAAE,SAAS;EAAY,SAASC,aAAAA,QAAQ,OAAO;CAAE,CAAC;CAE1E,IAAI;EACF,MAAM,EAAE,eAAe,MAAM,OAAO;EAEpC,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,QAAQ,UACX,MAAM,IAAI,MAAM,iDAAiD;EAGnE,MAAM,QAAQ,SAAS,OAAO,EAAE,cAAc,KAAK,CAAC;EACpD,MAAM,OAAO,EAAE,QAAQ,UAAU,CAAC;EAElC,QAAQ,IAAI,sBAAsB;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,EAAE,QAAQ,SAAS,CAAC;EACjC,IAAI,iBAAiB,SAAS,qBAAqB,KAAK,MAAM,OAAO,GAAG;GACtE,QAAQ,OAAA,GAAMC,UAAAA,UAAAA,CAAU,OAAO,iDAAiD,CAAC;GACjF,QAAQ,MAAM,EAAE;GAChB,QAAQ,MAAM,kBAAkB;GAChC,QAAQ,OAAA,GAAMA,UAAAA,UAAAA,CAAU,QAAQ,iCAAiC,CAAC;GAClE,QAAQ,OAAA,GAAMA,UAAAA,UAAAA,CAAU,QAAQ,QAAQ,CAAC;GACzC,QAAQ,OAAA,GAAMA,UAAAA,UAAAA,CAAU,QAAQ,kCAAkC,CAAC;GACnE,QAAQ,MAAM,EAAE;EAClB;EACA,QAAQ,MAAM,qBAAqB;EACnC,QAAQ,MAAMC,eAAAA,QAAQ,KAAK,CAAC,CAAC,OAAO;EAEpC,aAAA,QAAQ,KAAK,CAAC;CAChB;AACF"}
1
+ {"version":3,"file":"run-DfkvTomI.cjs","names":["trackRun","process","styleText","toError"],"sources":["../src/runners/validate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport { trackRun } from '../../Telemetry.ts'\n\ntype ValidateOptions = {\n /**\n * Path or URL to the OpenAPI/Swagger file to validate.\n */\n input: string\n}\n\n/**\n * Validates an OpenAPI/Swagger file at `input` using `@kubb/adapter-oas`.\n * Exits the process with code 1 on validation failure or missing dependency.\n */\nexport async function run({ input }: ValidateOptions): Promise<void> {\n const report = trackRun({ command: 'validate', hrStart: process.hrtime() })\n\n try {\n const { adapterOas } = await import('@kubb/adapter-oas')\n\n const adapter = adapterOas()\n if (!adapter.validate) {\n throw new Error('The loaded adapter does not support validation.')\n }\n\n await adapter.validate(input, { throwOnError: true })\n await report({ status: 'success' })\n\n console.log('✅ Validation success')\n } catch (error) {\n await report({ status: 'failed' })\n if (error instanceof Error && /@kubb\\/adapter-oas/.test(error.message)) {\n console.error(styleText('red', 'The @kubb/adapter-oas package is not installed.'))\n console.error('')\n console.error('Install it with:')\n console.error(styleText('cyan', ' npm install @kubb/adapter-oas'))\n console.error(styleText('cyan', ' # or'))\n console.error(styleText('cyan', ' pnpm install @kubb/adapter-oas'))\n console.error('')\n }\n console.error('❌ Validation failed')\n console.error(toError(error).message)\n\n process.exit(1)\n }\n}\n"],"mappings":";;;;;;;;;;;AAgBA,eAAsB,IAAI,EAAE,SAAyC;CACnE,MAAM,SAASA,kBAAAA,SAAS;EAAE,SAAS;EAAY,SAASC,aAAAA,QAAQ,OAAO;CAAE,CAAC;CAE1E,IAAI;EACF,MAAM,EAAE,eAAe,MAAM,OAAO;EAEpC,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,QAAQ,UACX,MAAM,IAAI,MAAM,iDAAiD;EAGnE,MAAM,QAAQ,SAAS,OAAO,EAAE,cAAc,KAAK,CAAC;EACpD,MAAM,OAAO,EAAE,QAAQ,UAAU,CAAC;EAElC,QAAQ,IAAI,sBAAsB;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,EAAE,QAAQ,SAAS,CAAC;EACjC,IAAI,iBAAiB,SAAS,qBAAqB,KAAK,MAAM,OAAO,GAAG;GACtE,QAAQ,OAAA,GAAMC,UAAAA,UAAAA,CAAU,OAAO,iDAAiD,CAAC;GACjF,QAAQ,MAAM,EAAE;GAChB,QAAQ,MAAM,kBAAkB;GAChC,QAAQ,OAAA,GAAMA,UAAAA,UAAAA,CAAU,QAAQ,iCAAiC,CAAC;GAClE,QAAQ,OAAA,GAAMA,UAAAA,UAAAA,CAAU,QAAQ,QAAQ,CAAC;GACzC,QAAQ,OAAA,GAAMA,UAAAA,UAAAA,CAAU,QAAQ,kCAAkC,CAAC;GACnE,QAAQ,MAAM,EAAE;EAClB;EACA,QAAQ,MAAM,qBAAqB;EACnC,QAAQ,MAAMC,eAAAA,QAAQ,KAAK,CAAC,CAAC,OAAO;EAEpC,aAAA,QAAQ,KAAK,CAAC;CAChB;AACF"}
@@ -1,6 +1,6 @@
1
1
  import "./rolldown-runtime-CRm0XQPb.js";
2
2
  import { n as toError } from "./errors-DmC83ALX.js";
3
- import { n as trackRun } from "./Telemetry-BOCR2q1g.js";
3
+ import { n as trackRun } from "./Telemetry-BivZAaw9.js";
4
4
  import { styleText } from "node:util";
5
5
  import process from "node:process";
6
6
  //#region src/runners/validate/run.ts
@@ -39,4 +39,4 @@ async function run({ input }) {
39
39
  //#endregion
40
40
  export { run };
41
41
 
42
- //# sourceMappingURL=run-DjINtbfD.js.map
42
+ //# sourceMappingURL=run-DnXUzX34.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-DjINtbfD.js","names":[],"sources":["../src/runners/validate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport { trackRun } from '../../Telemetry.ts'\n\ntype ValidateOptions = {\n /**\n * Path or URL to the OpenAPI/Swagger file to validate.\n */\n input: string\n}\n\n/**\n * Validates an OpenAPI/Swagger file at `input` using `@kubb/adapter-oas`.\n * Exits the process with code 1 on validation failure or missing dependency.\n */\nexport async function run({ input }: ValidateOptions): Promise<void> {\n const report = trackRun({ command: 'validate', hrStart: process.hrtime() })\n\n try {\n const { adapterOas } = await import('@kubb/adapter-oas')\n\n const adapter = adapterOas()\n if (!adapter.validate) {\n throw new Error('The loaded adapter does not support validation.')\n }\n\n await adapter.validate(input, { throwOnError: true })\n await report({ status: 'success' })\n\n console.log('✅ Validation success')\n } catch (error) {\n await report({ status: 'failed' })\n if (error instanceof Error && /@kubb\\/adapter-oas/.test(error.message)) {\n console.error(styleText('red', 'The @kubb/adapter-oas package is not installed.'))\n console.error('')\n console.error('Install it with:')\n console.error(styleText('cyan', ' npm install @kubb/adapter-oas'))\n console.error(styleText('cyan', ' # or'))\n console.error(styleText('cyan', ' pnpm install @kubb/adapter-oas'))\n console.error('')\n }\n console.error('❌ Validation failed')\n console.error(toError(error).message)\n\n process.exit(1)\n }\n}\n"],"mappings":";;;;;;;;;;AAgBA,eAAsB,IAAI,EAAE,SAAyC;CACnE,MAAM,SAAS,SAAS;EAAE,SAAS;EAAY,SAAS,QAAQ,OAAO;CAAE,CAAC;CAE1E,IAAI;EACF,MAAM,EAAE,eAAe,MAAM,OAAO;EAEpC,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,QAAQ,UACX,MAAM,IAAI,MAAM,iDAAiD;EAGnE,MAAM,QAAQ,SAAS,OAAO,EAAE,cAAc,KAAK,CAAC;EACpD,MAAM,OAAO,EAAE,QAAQ,UAAU,CAAC;EAElC,QAAQ,IAAI,sBAAsB;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,EAAE,QAAQ,SAAS,CAAC;EACjC,IAAI,iBAAiB,SAAS,qBAAqB,KAAK,MAAM,OAAO,GAAG;GACtE,QAAQ,MAAM,UAAU,OAAO,iDAAiD,CAAC;GACjF,QAAQ,MAAM,EAAE;GAChB,QAAQ,MAAM,kBAAkB;GAChC,QAAQ,MAAM,UAAU,QAAQ,iCAAiC,CAAC;GAClE,QAAQ,MAAM,UAAU,QAAQ,QAAQ,CAAC;GACzC,QAAQ,MAAM,UAAU,QAAQ,kCAAkC,CAAC;GACnE,QAAQ,MAAM,EAAE;EAClB;EACA,QAAQ,MAAM,qBAAqB;EACnC,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC,OAAO;EAEpC,QAAQ,KAAK,CAAC;CAChB;AACF"}
1
+ {"version":3,"file":"run-DnXUzX34.js","names":[],"sources":["../src/runners/validate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport { trackRun } from '../../Telemetry.ts'\n\ntype ValidateOptions = {\n /**\n * Path or URL to the OpenAPI/Swagger file to validate.\n */\n input: string\n}\n\n/**\n * Validates an OpenAPI/Swagger file at `input` using `@kubb/adapter-oas`.\n * Exits the process with code 1 on validation failure or missing dependency.\n */\nexport async function run({ input }: ValidateOptions): Promise<void> {\n const report = trackRun({ command: 'validate', hrStart: process.hrtime() })\n\n try {\n const { adapterOas } = await import('@kubb/adapter-oas')\n\n const adapter = adapterOas()\n if (!adapter.validate) {\n throw new Error('The loaded adapter does not support validation.')\n }\n\n await adapter.validate(input, { throwOnError: true })\n await report({ status: 'success' })\n\n console.log('✅ Validation success')\n } catch (error) {\n await report({ status: 'failed' })\n if (error instanceof Error && /@kubb\\/adapter-oas/.test(error.message)) {\n console.error(styleText('red', 'The @kubb/adapter-oas package is not installed.'))\n console.error('')\n console.error('Install it with:')\n console.error(styleText('cyan', ' npm install @kubb/adapter-oas'))\n console.error(styleText('cyan', ' # or'))\n console.error(styleText('cyan', ' pnpm install @kubb/adapter-oas'))\n console.error('')\n }\n console.error('❌ Validation failed')\n console.error(toError(error).message)\n\n process.exit(1)\n }\n}\n"],"mappings":";;;;;;;;;;AAgBA,eAAsB,IAAI,EAAE,SAAyC;CACnE,MAAM,SAAS,SAAS;EAAE,SAAS;EAAY,SAAS,QAAQ,OAAO;CAAE,CAAC;CAE1E,IAAI;EACF,MAAM,EAAE,eAAe,MAAM,OAAO;EAEpC,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,QAAQ,UACX,MAAM,IAAI,MAAM,iDAAiD;EAGnE,MAAM,QAAQ,SAAS,OAAO,EAAE,cAAc,KAAK,CAAC;EACpD,MAAM,OAAO,EAAE,QAAQ,UAAU,CAAC;EAElC,QAAQ,IAAI,sBAAsB;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,EAAE,QAAQ,SAAS,CAAC;EACjC,IAAI,iBAAiB,SAAS,qBAAqB,KAAK,MAAM,OAAO,GAAG;GACtE,QAAQ,MAAM,UAAU,OAAO,iDAAiD,CAAC;GACjF,QAAQ,MAAM,EAAE;GAChB,QAAQ,MAAM,kBAAkB;GAChC,QAAQ,MAAM,UAAU,QAAQ,iCAAiC,CAAC;GAClE,QAAQ,MAAM,UAAU,QAAQ,QAAQ,CAAC;GACzC,QAAQ,MAAM,UAAU,QAAQ,kCAAkC,CAAC;GACnE,QAAQ,MAAM,EAAE;EAClB;EACA,QAAQ,MAAM,qBAAqB;EACnC,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC,OAAO;EAEpC,QAAQ,KAAK,CAAC;CAChB;AACF"}
@@ -1,7 +1,7 @@
1
1
  import "./rolldown-runtime-CRm0XQPb.js";
2
2
  import { t as getErrorMessage } from "./errors-DmC83ALX.js";
3
3
  import { d as logWarn, i as logError, r as logBlock, s as logOutro } from "./output-B9Yw7vL0.js";
4
- import { a as registryUrl, i as isOutdated, n as fetchRegistryIndex } from "./registry-DjGepXb0.js";
4
+ import { a as isOutdated, n as fetchRegistryIndex, o as registryUrl } from "./registry-B7BvdrGE.js";
5
5
  import { styleText } from "node:util";
6
6
  import process from "node:process";
7
7
  import { readInstalledPackages } from "@kubb/core";
@@ -68,4 +68,4 @@ async function run() {
68
68
  //#endregion
69
69
  export { run };
70
70
 
71
- //# sourceMappingURL=run-CDS3EWEN.js.map
71
+ //# sourceMappingURL=run-Ey756UCd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-CDS3EWEN.js","names":[],"sources":["../src/runners/list/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { getErrorMessage } from '@internals/utils'\nimport { readInstalledPackages, type RegistryEntry } from '@kubb/core'\nimport { logBlock, logError, logOutro, logWarn } from '../../loggers/output.ts'\nimport { fetchRegistryIndex, isOutdated, registryUrl } from '../../utils/registry.ts'\n\nexport type ListRow = {\n id?: string\n package: string\n installed?: string\n registry?: string\n update: boolean\n}\n\n/**\n * The installed packages that ship a `kubb-extension.json` or have a registry entry, with the\n * version the registry pins.\n */\nexport async function listExtensions({ cwd, registry }: { cwd: string; registry: string }): Promise<Array<ListRow>> {\n const [installed, entries] = await Promise.all([\n readInstalledPackages({ root: cwd }),\n fetchRegistryIndex({ registry }).catch((error: unknown): Array<RegistryEntry> => {\n logWarn(`Showing installed extensions only: ${getErrorMessage(error)}`)\n return []\n }),\n ])\n const byPackage = new Map(entries.map((entry) => [entry.artifact.package, entry]))\n\n return installed.flatMap(({ package: name, version, manifest }): Array<ListRow> => {\n const entry = byPackage.get(name)\n if (!entry && !manifest) return []\n const latest = entry?.artifact.version\n return [{ id: entry?.id, package: name, installed: version, registry: latest, update: !!latest && isOutdated({ installed: version, latest }) }]\n })\n}\n\n/** Prints the installed extensions as a table. */\nexport async function run(): Promise<void> {\n try {\n const rows = await listExtensions({ cwd: process.cwd(), registry: registryUrl() })\n if (!rows.length) {\n logOutro('No installed extensions found.')\n return\n }\n\n const header = ['ID', 'PACKAGE', 'INSTALLED', 'REGISTRY', 'UPDATE']\n const cells = rows.map((row) => [row.id ?? '-', row.package, row.installed ?? '-', row.registry ?? '-', row.update ? 'yes' : 'no'])\n const widths = header.map((title, index) => Math.max(title.length, ...cells.map((cell) => cell[index]!.length)))\n const line = (cell: Array<string>) =>\n cell\n .map((value, index) => value.padEnd(widths[index]!))\n .join(' ')\n .trimEnd()\n\n logBlock([styleText('dim', line(header)), ...cells.map(line)])\n } catch (error) {\n logError(getErrorMessage(error))\n process.exitCode = 1\n }\n}\n"],"mappings":";;;;;;;;;;;;AAmBA,eAAsB,eAAe,EAAE,KAAK,YAAwE;CAClH,MAAM,CAAC,WAAW,WAAW,MAAM,QAAQ,IAAI,CAC7C,sBAAsB,EAAE,MAAM,IAAI,CAAC,GACnC,mBAAmB,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,UAAyC;EAC/E,QAAQ,sCAAsC,gBAAgB,KAAK,GAAG;EACtE,OAAO,CAAC;CACV,CAAC,CACH,CAAC;CACD,MAAM,YAAY,IAAI,IAAI,QAAQ,KAAK,UAAU,CAAC,MAAM,SAAS,SAAS,KAAK,CAAC,CAAC;CAEjF,OAAO,UAAU,SAAS,EAAE,SAAS,MAAM,SAAS,eAA+B;EACjF,MAAM,QAAQ,UAAU,IAAI,IAAI;EAChC,IAAI,CAAC,SAAS,CAAC,UAAU,OAAO,CAAC;EACjC,MAAM,SAAS,OAAO,SAAS;EAC/B,OAAO,CAAC;GAAE,IAAI,OAAO;GAAI,SAAS;GAAM,WAAW;GAAS,UAAU;GAAQ,QAAQ,CAAC,CAAC,UAAU,WAAW;IAAE,WAAW;IAAS;GAAO,CAAC;EAAE,CAAC;CAChJ,CAAC;AACH;;AAGA,eAAsB,MAAqB;CACzC,IAAI;EACF,MAAM,OAAO,MAAM,eAAe;GAAE,KAAK,QAAQ,IAAI;GAAG,UAAU,YAAY;EAAE,CAAC;EACjF,IAAI,CAAC,KAAK,QAAQ;GAChB,SAAS,gCAAgC;GACzC;EACF;EAEA,MAAM,SAAS;GAAC;GAAM;GAAW;GAAa;GAAY;EAAQ;EAClE,MAAM,QAAQ,KAAK,KAAK,QAAQ;GAAC,IAAI,MAAM;GAAK,IAAI;GAAS,IAAI,aAAa;GAAK,IAAI,YAAY;GAAK,IAAI,SAAS,QAAQ;EAAI,CAAC;EAClI,MAAM,SAAS,OAAO,KAAK,OAAO,UAAU,KAAK,IAAI,MAAM,QAAQ,GAAG,MAAM,KAAK,SAAS,KAAK,MAAM,CAAE,MAAM,CAAC,CAAC;EAC/G,MAAM,QAAQ,SACZ,KACG,KAAK,OAAO,UAAU,MAAM,OAAO,OAAO,MAAO,CAAC,CAAC,CACnD,KAAK,IAAI,CAAC,CACV,QAAQ;EAEb,SAAS,CAAC,UAAU,OAAO,KAAK,MAAM,CAAC,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC;CAC/D,SAAS,OAAO;EACd,SAAS,gBAAgB,KAAK,CAAC;EAC/B,QAAQ,WAAW;CACrB;AACF"}
1
+ {"version":3,"file":"run-Ey756UCd.js","names":[],"sources":["../src/runners/list/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { getErrorMessage } from '@internals/utils'\nimport { readInstalledPackages, type RegistryEntry } from '@kubb/core'\nimport { logBlock, logError, logOutro, logWarn } from '../../loggers/output.ts'\nimport { fetchRegistryIndex, isOutdated, registryUrl } from '../../utils/registry.ts'\n\nexport type ListRow = {\n id?: string\n package: string\n installed?: string\n registry?: string\n update: boolean\n}\n\n/**\n * The installed packages that ship a `kubb-extension.json` or have a registry entry, with the\n * version the registry pins.\n */\nexport async function listExtensions({ cwd, registry }: { cwd: string; registry: string }): Promise<Array<ListRow>> {\n const [installed, entries] = await Promise.all([\n readInstalledPackages({ root: cwd }),\n fetchRegistryIndex({ registry }).catch((error: unknown): Array<RegistryEntry> => {\n logWarn(`Showing installed extensions only: ${getErrorMessage(error)}`)\n return []\n }),\n ])\n const byPackage = new Map(entries.map((entry) => [entry.artifact.package, entry]))\n\n return installed.flatMap(({ package: name, version, manifest }): Array<ListRow> => {\n const entry = byPackage.get(name)\n if (!entry && !manifest) return []\n const latest = entry?.artifact.version\n return [{ id: entry?.id, package: name, installed: version, registry: latest, update: !!latest && isOutdated({ installed: version, latest }) }]\n })\n}\n\n/** Prints the installed extensions as a table. */\nexport async function run(): Promise<void> {\n try {\n const rows = await listExtensions({ cwd: process.cwd(), registry: registryUrl() })\n if (!rows.length) {\n logOutro('No installed extensions found.')\n return\n }\n\n const header = ['ID', 'PACKAGE', 'INSTALLED', 'REGISTRY', 'UPDATE']\n const cells = rows.map((row) => [row.id ?? '-', row.package, row.installed ?? '-', row.registry ?? '-', row.update ? 'yes' : 'no'])\n const widths = header.map((title, index) => Math.max(title.length, ...cells.map((cell) => cell[index]!.length)))\n const line = (cell: Array<string>) =>\n cell\n .map((value, index) => value.padEnd(widths[index]!))\n .join(' ')\n .trimEnd()\n\n logBlock([styleText('dim', line(header)), ...cells.map(line)])\n } catch (error) {\n logError(getErrorMessage(error))\n process.exitCode = 1\n }\n}\n"],"mappings":";;;;;;;;;;;;AAmBA,eAAsB,eAAe,EAAE,KAAK,YAAwE;CAClH,MAAM,CAAC,WAAW,WAAW,MAAM,QAAQ,IAAI,CAC7C,sBAAsB,EAAE,MAAM,IAAI,CAAC,GACnC,mBAAmB,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,UAAyC;EAC/E,QAAQ,sCAAsC,gBAAgB,KAAK,GAAG;EACtE,OAAO,CAAC;CACV,CAAC,CACH,CAAC;CACD,MAAM,YAAY,IAAI,IAAI,QAAQ,KAAK,UAAU,CAAC,MAAM,SAAS,SAAS,KAAK,CAAC,CAAC;CAEjF,OAAO,UAAU,SAAS,EAAE,SAAS,MAAM,SAAS,eAA+B;EACjF,MAAM,QAAQ,UAAU,IAAI,IAAI;EAChC,IAAI,CAAC,SAAS,CAAC,UAAU,OAAO,CAAC;EACjC,MAAM,SAAS,OAAO,SAAS;EAC/B,OAAO,CAAC;GAAE,IAAI,OAAO;GAAI,SAAS;GAAM,WAAW;GAAS,UAAU;GAAQ,QAAQ,CAAC,CAAC,UAAU,WAAW;IAAE,WAAW;IAAS;GAAO,CAAC;EAAE,CAAC;CAChJ,CAAC;AACH;;AAGA,eAAsB,MAAqB;CACzC,IAAI;EACF,MAAM,OAAO,MAAM,eAAe;GAAE,KAAK,QAAQ,IAAI;GAAG,UAAU,YAAY;EAAE,CAAC;EACjF,IAAI,CAAC,KAAK,QAAQ;GAChB,SAAS,gCAAgC;GACzC;EACF;EAEA,MAAM,SAAS;GAAC;GAAM;GAAW;GAAa;GAAY;EAAQ;EAClE,MAAM,QAAQ,KAAK,KAAK,QAAQ;GAAC,IAAI,MAAM;GAAK,IAAI;GAAS,IAAI,aAAa;GAAK,IAAI,YAAY;GAAK,IAAI,SAAS,QAAQ;EAAI,CAAC;EAClI,MAAM,SAAS,OAAO,KAAK,OAAO,UAAU,KAAK,IAAI,MAAM,QAAQ,GAAG,MAAM,KAAK,SAAS,KAAK,MAAM,CAAE,MAAM,CAAC,CAAC;EAC/G,MAAM,QAAQ,SACZ,KACG,KAAK,OAAO,UAAU,MAAM,OAAO,OAAO,MAAO,CAAC,CAAC,CACnD,KAAK,IAAI,CAAC,CACV,QAAQ;EAEb,SAAS,CAAC,UAAU,OAAO,KAAK,MAAM,CAAC,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC;CAC/D,SAAS,OAAO;EACd,SAAS,gBAAgB,KAAK,CAAC;EAC/B,QAAQ,WAAW;CACrB;AACF"}
@@ -1,7 +1,7 @@
1
1
  const require_agent = require("./agent-DElUuYuy.cjs");
2
2
  const require_errors = require("./errors-BdA8M78q.cjs");
3
3
  const require_output = require("./output-CWupdozw.cjs");
4
- const require_registry = require("./registry-CCKUL3ps.cjs");
4
+ const require_registry = require("./registry-DER9aRyg.cjs");
5
5
  const require_utils = require("./utils-ZcCFqERz.cjs");
6
6
  let node_util = require("node:util");
7
7
  let node_process = require("node:process");
@@ -51,7 +51,7 @@ async function run({ ids, check, yes }) {
51
51
  return;
52
52
  }
53
53
  const packageManager = require_utils.detectPackageManager(cwd);
54
- const specs = proposals.map(({ artifact }) => `${artifact.package}@${artifact.version}`);
54
+ const specs = proposals.map(({ artifact }) => require_registry.installSpec(artifact));
55
55
  require_output.logStep(`Installing ${specs.join(", ")} with ${packageManager.name}`);
56
56
  await require_utils.installPackages(specs, packageManager, cwd);
57
57
  require_output.logInfo(`Updated ${specs.length} extension${plural}`);
@@ -64,4 +64,4 @@ async function run({ ids, check, yes }) {
64
64
  //#endregion
65
65
  exports.run = run;
66
66
 
67
- //# sourceMappingURL=run-DVIqUt1x.cjs.map
67
+ //# sourceMappingURL=run-VAkf24Cw.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-VAkf24Cw.cjs","names":["process","styleText","toRegistryId","fetchRegistryIndex","registryUrl","readInstalledPackages","isOutdated","incompatibility","clack","detectPackageManager","installSpec","installPackages","getErrorMessage"],"sources":["../src/runners/update/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport * as clack from '@clack/prompts'\nimport { getErrorMessage } from '@internals/utils'\nimport { readInstalledPackages } from '@kubb/core'\nimport { logBlock, logError, logInfo, logIntro, logOutro, logStep, logWarn } from '../../loggers/output.ts'\nimport { fetchRegistryIndex, incompatibility, installSpec, isOutdated, registryUrl, toRegistryId } from '../../utils/registry.ts'\nimport { detectPackageManager, installPackages } from '../init/utils.ts'\n\nexport type UpdateOptions = {\n /**\n * Registry ids to update. Empty updates every installed extension the registry lists.\n */\n ids: Array<string>\n check: boolean\n yes: boolean\n}\n\n/**\n * Moves installed extensions to the version the registry pins. Lists the proposals, asks, then\n * installs them. With `check`, only lists them.\n */\nexport async function run({ ids, check, yes }: UpdateOptions): Promise<void> {\n const cwd = process.cwd()\n logIntro({ title: styleText('bgCyan', styleText('black', ' Kubb Update ')) })\n\n try {\n const wanted = new Set(ids.map(toRegistryId))\n const [entries, installed] = await Promise.all([fetchRegistryIndex({ registry: registryUrl() }), readInstalledPackages({ root: cwd })])\n const versions = new Map(installed.map((item) => [item.package, item.version]))\n\n const tracked = entries.filter((entry) => versions.has(entry.artifact.package) && (!wanted.size || wanted.has(entry.id)))\n for (const id of wanted) {\n if (!tracked.some((entry) => entry.id === id)) logWarn(`${id} is not installed, or not in the registry.`)\n }\n\n const proposals = tracked.filter((entry) => {\n if (!isOutdated({ installed: versions.get(entry.artifact.package), latest: entry.artifact.version })) return false\n const problem = incompatibility(entry.manifest)\n if (problem) logWarn(`Skipped ${entry.id}: ${problem}`)\n return !problem\n })\n\n if (!proposals.length) {\n logOutro(ids.length ? `No updates for ${ids.join(', ')}.` : 'Every installed extension is up to date.')\n return\n }\n\n const plural = proposals.length === 1 ? '' : 's'\n logBlock(\n proposals.map(({ artifact }) => `${artifact.package} ${versions.get(artifact.package) ?? 'not installed'} -> ${styleText('green', artifact.version)}`),\n )\n\n if (check) {\n logOutro(`${proposals.length} update${plural} available. Run \\`kubb update\\` to install.`)\n return\n }\n\n const confirmed = yes || (await clack.confirm({ message: `Install ${proposals.length} update${plural}?`, initialValue: true }))\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel('Operation canceled.')\n return\n }\n\n const packageManager = detectPackageManager(cwd)\n const specs = proposals.map(({ artifact }) => installSpec(artifact))\n logStep(`Installing ${specs.join(', ')} with ${packageManager.name}`)\n await installPackages(specs, packageManager, cwd)\n\n logInfo(`Updated ${specs.length} extension${plural}`)\n logOutro(styleText('green', 'Done'))\n } catch (error) {\n logError(getErrorMessage(error))\n process.exitCode = 1\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,eAAsB,IAAI,EAAE,KAAK,OAAO,OAAqC;CAC3E,MAAM,MAAMA,aAAAA,QAAQ,IAAI;CACxB,eAAA,SAAS,EAAE,QAAA,GAAOC,UAAAA,UAAAA,CAAU,WAAA,GAAUA,UAAAA,UAAAA,CAAU,SAAS,eAAe,CAAC,EAAE,CAAC;CAE5E,IAAI;EACF,MAAM,SAAS,IAAI,IAAI,IAAI,IAAIC,iBAAAA,YAAY,CAAC;EAC5C,MAAM,CAAC,SAAS,aAAa,MAAM,QAAQ,IAAI,CAACC,iBAAAA,mBAAmB,EAAE,UAAUC,iBAAAA,YAAY,EAAE,CAAC,IAAA,GAAGC,WAAAA,sBAAAA,CAAsB,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC;EACtI,MAAM,WAAW,IAAI,IAAI,UAAU,KAAK,SAAS,CAAC,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC;EAE9E,MAAM,UAAU,QAAQ,QAAQ,UAAU,SAAS,IAAI,MAAM,SAAS,OAAO,MAAM,CAAC,OAAO,QAAQ,OAAO,IAAI,MAAM,EAAE,EAAE;EACxH,KAAK,MAAM,MAAM,QACf,IAAI,CAAC,QAAQ,MAAM,UAAU,MAAM,OAAO,EAAE,GAAG,eAAA,QAAQ,GAAG,GAAG,2CAA2C;EAG1G,MAAM,YAAY,QAAQ,QAAQ,UAAU;GAC1C,IAAI,CAACC,iBAAAA,WAAW;IAAE,WAAW,SAAS,IAAI,MAAM,SAAS,OAAO;IAAG,QAAQ,MAAM,SAAS;GAAQ,CAAC,GAAG,OAAO;GAC7G,MAAM,UAAUC,iBAAAA,gBAAgB,MAAM,QAAQ;GAC9C,IAAI,SAAS,eAAA,QAAQ,WAAW,MAAM,GAAG,IAAI,SAAS;GACtD,OAAO,CAAC;EACV,CAAC;EAED,IAAI,CAAC,UAAU,QAAQ;GACrB,eAAA,SAAS,IAAI,SAAS,kBAAkB,IAAI,KAAK,IAAI,EAAE,KAAK,0CAA0C;GACtG;EACF;EAEA,MAAM,SAAS,UAAU,WAAW,IAAI,KAAK;EAC7C,eAAA,SACE,UAAU,KAAK,EAAE,eAAe,GAAG,SAAS,QAAQ,IAAI,SAAS,IAAI,SAAS,OAAO,KAAK,gBAAgB,OAAA,GAAMN,UAAAA,UAAAA,CAAU,SAAS,SAAS,OAAO,GAAG,CACxJ;EAEA,IAAI,OAAO;GACT,eAAA,SAAS,GAAG,UAAU,OAAO,SAAS,OAAO,4CAA4C;GACzF;EACF;EAEA,MAAM,YAAY,OAAQ,MAAMO,eAAM,QAAQ;GAAE,SAAS,WAAW,UAAU,OAAO,SAAS,OAAO;GAAI,cAAc;EAAK,CAAC;EAC7H,IAAIA,eAAM,SAAS,SAAS,KAAK,CAAC,WAAW;GAC3C,eAAM,OAAO,qBAAqB;GAClC;EACF;EAEA,MAAM,iBAAiBC,cAAAA,qBAAqB,GAAG;EAC/C,MAAM,QAAQ,UAAU,KAAK,EAAE,eAAeC,iBAAAA,YAAY,QAAQ,CAAC;EACnE,eAAA,QAAQ,cAAc,MAAM,KAAK,IAAI,EAAE,QAAQ,eAAe,MAAM;EACpE,MAAMC,cAAAA,gBAAgB,OAAO,gBAAgB,GAAG;EAEhD,eAAA,QAAQ,WAAW,MAAM,OAAO,YAAY,QAAQ;EACpD,eAAA,UAAA,GAASV,UAAAA,UAAAA,CAAU,SAAS,MAAM,CAAC;CACrC,SAAS,OAAO;EACd,eAAA,SAASW,eAAAA,gBAAgB,KAAK,CAAC;EAC/B,aAAA,QAAA,WAAmB;CACrB;AACF"}
@@ -1,6 +1,6 @@
1
1
  import "./rolldown-runtime-CRm0XQPb.js";
2
2
  import { n as toError } from "./errors-DmC83ALX.js";
3
- import { n as trackRun } from "./Telemetry-BOCR2q1g.js";
3
+ import { n as trackRun } from "./Telemetry-BivZAaw9.js";
4
4
  import { styleText } from "node:util";
5
5
  import process from "node:process";
6
6
  //#region src/runners/mcp/run.ts
@@ -27,4 +27,4 @@ async function run() {
27
27
  //#endregion
28
28
  export { run };
29
29
 
30
- //# sourceMappingURL=run-CNiUPnC7.js.map
30
+ //# sourceMappingURL=run-ajUuT3vK.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-CNiUPnC7.js","names":[],"sources":["../src/runners/mcp/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport type * as McpModule from '@kubb/mcp'\nimport { trackRun } from '../../Telemetry.ts'\n\n/**\n * Starts the `@kubb/mcp` server over stdio and reports the outcome to telemetry.\n */\nexport async function run(): Promise<void> {\n const { run: startMcpServer } = (await import('@kubb/mcp')) as typeof McpModule\n\n const report = trackRun({ command: 'mcp', hrStart: process.hrtime() })\n\n try {\n // The MCP stdio transport owns stdout: anything else written there corrupts the JSON-RPC stream.\n console.error(styleText('cyan', '⏳ Starting MCP server...'))\n console.warn(styleText('yellow', 'This feature is still under development, use with caution'))\n await startMcpServer()\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":";;;;;;;;;AASA,eAAsB,MAAqB;CACzC,MAAM,EAAE,KAAK,mBAAoB,MAAM,OAAO;CAE9C,MAAM,SAAS,SAAS;EAAE,SAAS;EAAO,SAAS,QAAQ,OAAO;CAAE,CAAC;CAErE,IAAI;EAEF,QAAQ,MAAM,UAAU,QAAQ,0BAA0B,CAAC;EAC3D,QAAQ,KAAK,UAAU,UAAU,2DAA2D,CAAC;EAC7F,MAAM,eAAe;EACrB,MAAM,OAAO,EAAE,QAAQ,UAAU,CAAC;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,EAAE,QAAQ,SAAS,CAAC;EACjC,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC,OAAO;EACpC,QAAQ,WAAW;CACrB;AACF"}
1
+ {"version":3,"file":"run-ajUuT3vK.js","names":[],"sources":["../src/runners/mcp/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { toError } from '@internals/utils'\nimport type * as McpModule from '@kubb/mcp'\nimport { trackRun } from '../../Telemetry.ts'\n\n/**\n * Starts the `@kubb/mcp` server over stdio and reports the outcome to telemetry.\n */\nexport async function run(): Promise<void> {\n const { run: startMcpServer } = (await import('@kubb/mcp')) as typeof McpModule\n\n const report = trackRun({ command: 'mcp', hrStart: process.hrtime() })\n\n try {\n // The MCP stdio transport owns stdout: anything else written there corrupts the JSON-RPC stream.\n console.error(styleText('cyan', '⏳ Starting MCP server...'))\n console.warn(styleText('yellow', 'This feature is still under development, use with caution'))\n await startMcpServer()\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":";;;;;;;;;AASA,eAAsB,MAAqB;CACzC,MAAM,EAAE,KAAK,mBAAoB,MAAM,OAAO;CAE9C,MAAM,SAAS,SAAS;EAAE,SAAS;EAAO,SAAS,QAAQ,OAAO;CAAE,CAAC;CAErE,IAAI;EAEF,QAAQ,MAAM,UAAU,QAAQ,0BAA0B,CAAC;EAC3D,QAAQ,KAAK,UAAU,UAAU,2DAA2D,CAAC;EAC7F,MAAM,eAAe;EACrB,MAAM,OAAO,EAAE,QAAQ,UAAU,CAAC;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,EAAE,QAAQ,SAAS,CAAC;EACjC,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC,OAAO;EACpC,QAAQ,WAAW;CACrB;AACF"}
@@ -1,6 +1,6 @@
1
1
  import "./rolldown-runtime-CRm0XQPb.js";
2
2
  import { n as toError } from "./errors-DmC83ALX.js";
3
- import { n as trackRun, r as version } from "./Telemetry-BOCR2q1g.js";
3
+ import { n as trackRun, r as version } from "./Telemetry-BivZAaw9.js";
4
4
  import { n as getConfigs } from "./config-DAdYwK_D.js";
5
5
  import { _ as pluralize, a as logInfo, c as logSpacer, i as logError, l as logStep, n as logBanner, o as logIntro, s as logOutro, t as createSpinner, u as logTip } from "./output-B9Yw7vL0.js";
6
6
  import { n as setupReporters, t as selectReporters } from "./reporters-CNZQUlXY.js";
@@ -348,4 +348,4 @@ async function run({ input, configPath, logLevel: logLevelKey, watch, reporters:
348
348
  //#endregion
349
349
  export { run };
350
350
 
351
- //# sourceMappingURL=run-CkIxVyjD.js.map
351
+ //# sourceMappingURL=run-mx0KM8y5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-CkIxVyjD.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'\nimport { isGreaterThan, isValid, truncate } from 'verkit'\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\n/**\n * Returns `true` when `latest` is a newer semver version than `current`. Compares each numeric\n * part, so `5.10.0` beats `5.9.0` where a plain string comparison would not. Prerelease\n * suffixes are ignored, and a malformed version never reports an update.\n *\n * @example Double-digit minor\n * `isNewerVersion('5.9.0', '5.10.0') // true`\n *\n * @example String comparison would get this wrong the other way\n * `isNewerVersion('5.10.0', '5.9.0') // false`\n */\nexport function isNewerVersion(current: string, latest: string): boolean {\n if (!isValid(current) || !isValid(latest)) return false\n\n return isGreaterThan(truncate(latest, 'patch') as string, truncate(current, 'patch') as string)\n}\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 { fetchUrlBody, isNewerVersion, 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 && isNewerVersion(version, 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
+ {"version":3,"file":"run-mx0KM8y5.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'\nimport { isGreaterThan, isValid, truncate } from 'verkit'\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\n/**\n * Returns `true` when `latest` is a newer semver version than `current`. Compares each numeric\n * part, so `5.10.0` beats `5.9.0` where a plain string comparison would not. Prerelease\n * suffixes are ignored, and a malformed version never reports an update.\n *\n * @example Double-digit minor\n * `isNewerVersion('5.9.0', '5.10.0') // true`\n *\n * @example String comparison would get this wrong the other way\n * `isNewerVersion('5.10.0', '5.9.0') // false`\n */\nexport function isNewerVersion(current: string, latest: string): boolean {\n if (!isValid(current) || !isValid(latest)) return false\n\n return isGreaterThan(truncate(latest, 'patch') as string, truncate(current, 'patch') as string)\n}\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 { fetchUrlBody, isNewerVersion, 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 && isNewerVersion(version, 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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"}
@@ -2,7 +2,7 @@ import "./rolldown-runtime-CRm0XQPb.js";
2
2
  import { t as getErrorMessage } from "./errors-DmC83ALX.js";
3
3
  import { t as findConfigFile } from "./config-DAdYwK_D.js";
4
4
  import { a as logInfo, d as logWarn, i as logError, l as logStep, o as logIntro, r as logBlock, s as logOutro } from "./output-B9Yw7vL0.js";
5
- import { a as registryUrl, o as toRegistryId, r as incompatibility, t as fetchRegistryDetail } from "./registry-DjGepXb0.js";
5
+ import { i as installSpec, o as registryUrl, r as incompatibility, s as toRegistryId, t as fetchRegistryDetail } from "./registry-B7BvdrGE.js";
6
6
  import { i as installPackages, t as detectPackageManager } from "./utils-Dhx5PMpD.js";
7
7
  import { styleText } from "node:util";
8
8
  import process from "node:process";
@@ -62,7 +62,7 @@ async function run({ id: input, configPath, yes, install }) {
62
62
  const { artifact, manifest } = detail;
63
63
  const problem = incompatibility(manifest);
64
64
  if (problem) throw new Error(problem);
65
- const spec = `${artifact.package}@${artifact.version}`;
65
+ const spec = installSpec(artifact);
66
66
  const configFile = manifest.kind === "plugin" ? configPath ? path.resolve(configPath) : findConfigFile(cwd) : void 0;
67
67
  if (manifest.kind === "plugin" && !configFile) throw new Error("No kubb.config.ts found. Run `kubb init` first, or pass --config.");
68
68
  logInfo(`${styleText("cyan", manifest.displayName)} (${manifest.kind}): ${manifest.description}`);
@@ -103,4 +103,4 @@ async function run({ id: input, configPath, yes, install }) {
103
103
  //#endregion
104
104
  export { run };
105
105
 
106
- //# sourceMappingURL=run-BURZ4hDs.js.map
106
+ //# sourceMappingURL=run-yb2R1vt0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-yb2R1vt0.js","names":[],"sources":["../src/runners/add/run.ts"],"sourcesContent":["import path from 'node:path'\nimport process from 'node:process'\nimport { styleText } from 'node:util'\nimport * as clack from '@clack/prompts'\nimport { getErrorMessage } from '@internals/utils'\nimport type { ExtensionManifest, RegistryDetail } from '@kubb/core'\nimport { findConfigFile } from '../../config.ts'\nimport { logBlock, logError, logInfo, logIntro, logOutro, logStep, logWarn } from '../../loggers/output.ts'\nimport { fetchRegistryDetail, incompatibility, installSpec, registryUrl, toRegistryId } from '../../utils/registry.ts'\nimport { detectPackageManager, installPackages } from '../init/utils.ts'\n\nexport type AddOptions = {\n /**\n * `owner/slug`, or a bare `slug` for an official extension.\n */\n id: string\n configPath?: string\n yes: boolean\n install: boolean\n}\n\n/** The import and the `defineConfig` property to merge into `kubb.config.ts` by hand. */\nexport function toSnippet({ artifact, manifest }: Pick<RegistryDetail, 'artifact' | 'manifest'>): string {\n const call = `${manifest.export}()`\n const property: Record<ExtensionManifest['kind'], string> = {\n plugin: `plugins: [..., ${call}],`,\n adapter: `adapter: ${call},`,\n parser: `parsers: [..., ${call}],`,\n }\n return [`import { ${manifest.export} } from '${artifact.package}'`, '', property[manifest.kind]].join('\\n')\n}\n\n/** Adds the plugin call and its import to the config file. Returns why it could not, or `undefined`. */\nasync function addToConfig({ detail, configFile }: { detail: RegistryDetail; configFile: string }): Promise<string | undefined> {\n const { artifact, manifest } = detail\n try {\n const { writeConfigEdits } = await import('@kubb/studio')\n const { outcomes } = await writeConfigEdits({\n filePath: configFile,\n edits: [{ operation: 'add-plugin', plugin: artifact.package, importName: manifest.export }],\n extensions: new Map([[artifact.package, { package: artifact.package, version: artifact.version, manifest }]]),\n })\n return outcomes[0]?.applied ? undefined : (outcomes[0]?.reason ?? 'the config file was not changed')\n } catch (error) {\n return getErrorMessage(error)\n }\n}\n\n/**\n * Installs an extension from the Kubb registry at its reviewed version and, for a plugin, adds it to\n * `kubb.config.ts`. Refuses when the running Kubb or Node.js version is outside its compatibility.\n */\nexport async function run({ id: input, configPath, yes, install }: AddOptions): Promise<void> {\n const cwd = process.cwd()\n logIntro({ title: styleText('bgCyan', styleText('black', ' Kubb Add ')) })\n\n try {\n const registry = registryUrl()\n const detail = await fetchRegistryDetail({ id: toRegistryId(input), registry })\n const { artifact, manifest } = detail\n\n const problem = incompatibility(manifest)\n if (problem) throw new Error(problem)\n\n const spec = installSpec(artifact)\n const configFile = manifest.kind === 'plugin' ? (configPath ? path.resolve(configPath) : findConfigFile(cwd)) : undefined\n if (manifest.kind === 'plugin' && !configFile) throw new Error('No kubb.config.ts found. Run `kubb init` first, or pass --config.')\n\n logInfo(`${styleText('cyan', manifest.displayName)} (${manifest.kind}): ${manifest.description}`)\n logBlock([\n install ? `Install ${styleText('cyan', spec)} as a dev dependency` : `Skip installing ${spec}`,\n configFile\n ? `Add ${styleText('cyan', `${manifest.export}()`)} to ${path.relative(cwd, configFile) || configFile}`\n : `Print the ${manifest.kind} snippet to add`,\n ])\n\n const confirmed = yes || (await clack.confirm({ message: 'Continue?', initialValue: true }))\n if (clack.isCancel(confirmed) || !confirmed) {\n clack.cancel('Operation canceled.')\n return\n }\n\n if (install) {\n const packageManager = detectPackageManager(cwd)\n logStep(`Installing ${spec} with ${packageManager.name}`)\n await installPackages([spec], packageManager, cwd)\n }\n\n const reason = configFile ? await addToConfig({ detail, configFile }) : `add the ${manifest.kind} to your config`\n if (!reason) {\n logOutro(styleText('green', install ? `Added ${spec}` : `Added ${manifest.export}() to the config. Install ${spec} to use it.`))\n return\n }\n\n if (configFile) logWarn(`Could not edit ${configFile}: ${reason}`)\n logBlock(['Add the import to your Kubb config and merge the property into its defineConfig call:', '', toSnippet(detail)])\n logOutro(styleText('green', install ? `Installed ${spec}. Add it with the snippet above.` : `Install ${spec} and add the snippet above.`))\n } catch (error) {\n logError(getErrorMessage(error))\n process.exitCode = 1\n }\n}\n"],"mappings":";;;;;;;;;;;;AAsBA,SAAgB,UAAU,EAAE,UAAU,YAAmE;CACvG,MAAM,OAAO,GAAG,SAAS,OAAO;CAChC,MAAM,WAAsD;EAC1D,QAAQ,kBAAkB,KAAK;EAC/B,SAAS,YAAY,KAAK;EAC1B,QAAQ,kBAAkB,KAAK;CACjC;CACA,OAAO;EAAC,YAAY,SAAS,OAAO,WAAW,SAAS,QAAQ;EAAI;EAAI,SAAS,SAAS;CAAK,CAAC,CAAC,KAAK,IAAI;AAC5G;;AAGA,eAAe,YAAY,EAAE,QAAQ,cAA2F;CAC9H,MAAM,EAAE,UAAU,aAAa;CAC/B,IAAI;EACF,MAAM,EAAE,qBAAqB,MAAM,OAAO;EAC1C,MAAM,EAAE,aAAa,MAAM,iBAAiB;GAC1C,UAAU;GACV,OAAO,CAAC;IAAE,WAAW;IAAc,QAAQ,SAAS;IAAS,YAAY,SAAS;GAAO,CAAC;GAC1F,4BAAY,IAAI,IAAI,CAAC,CAAC,SAAS,SAAS;IAAE,SAAS,SAAS;IAAS,SAAS,SAAS;IAAS;GAAS,CAAC,CAAC,CAAC;EAC9G,CAAC;EACD,OAAO,SAAS,EAAE,EAAE,UAAU,KAAA,IAAa,SAAS,EAAE,EAAE,UAAU;CACpE,SAAS,OAAO;EACd,OAAO,gBAAgB,KAAK;CAC9B;AACF;;;;;AAMA,eAAsB,IAAI,EAAE,IAAI,OAAO,YAAY,KAAK,WAAsC;CAC5F,MAAM,MAAM,QAAQ,IAAI;CACxB,SAAS,EAAE,OAAO,UAAU,UAAU,UAAU,SAAS,YAAY,CAAC,EAAE,CAAC;CAEzE,IAAI;EACF,MAAM,WAAW,YAAY;EAC7B,MAAM,SAAS,MAAM,oBAAoB;GAAE,IAAI,aAAa,KAAK;GAAG;EAAS,CAAC;EAC9E,MAAM,EAAE,UAAU,aAAa;EAE/B,MAAM,UAAU,gBAAgB,QAAQ;EACxC,IAAI,SAAS,MAAM,IAAI,MAAM,OAAO;EAEpC,MAAM,OAAO,YAAY,QAAQ;EACjC,MAAM,aAAa,SAAS,SAAS,WAAY,aAAa,KAAK,QAAQ,UAAU,IAAI,eAAe,GAAG,IAAK,KAAA;EAChH,IAAI,SAAS,SAAS,YAAY,CAAC,YAAY,MAAM,IAAI,MAAM,mEAAmE;EAElI,QAAQ,GAAG,UAAU,QAAQ,SAAS,WAAW,EAAE,IAAI,SAAS,KAAK,KAAK,SAAS,aAAa;EAChG,SAAS,CACP,UAAU,WAAW,UAAU,QAAQ,IAAI,EAAE,wBAAwB,mBAAmB,QACxF,aACI,OAAO,UAAU,QAAQ,GAAG,SAAS,OAAO,GAAG,EAAE,MAAM,KAAK,SAAS,KAAK,UAAU,KAAK,eACzF,aAAa,SAAS,KAAK,gBACjC,CAAC;EAED,MAAM,YAAY,OAAQ,MAAM,MAAM,QAAQ;GAAE,SAAS;GAAa,cAAc;EAAK,CAAC;EAC1F,IAAI,MAAM,SAAS,SAAS,KAAK,CAAC,WAAW;GAC3C,MAAM,OAAO,qBAAqB;GAClC;EACF;EAEA,IAAI,SAAS;GACX,MAAM,iBAAiB,qBAAqB,GAAG;GAC/C,QAAQ,cAAc,KAAK,QAAQ,eAAe,MAAM;GACxD,MAAM,gBAAgB,CAAC,IAAI,GAAG,gBAAgB,GAAG;EACnD;EAEA,MAAM,SAAS,aAAa,MAAM,YAAY;GAAE;GAAQ;EAAW,CAAC,IAAI,WAAW,SAAS,KAAK;EACjG,IAAI,CAAC,QAAQ;GACX,SAAS,UAAU,SAAS,UAAU,SAAS,SAAS,SAAS,SAAS,OAAO,4BAA4B,KAAK,YAAY,CAAC;GAC/H;EACF;EAEA,IAAI,YAAY,QAAQ,kBAAkB,WAAW,IAAI,QAAQ;EACjE,SAAS;GAAC;GAAyF;GAAI,UAAU,MAAM;EAAC,CAAC;EACzH,SAAS,UAAU,SAAS,UAAU,aAAa,KAAK,oCAAoC,WAAW,KAAK,4BAA4B,CAAC;CAC3I,SAAS,OAAO;EACd,SAAS,gBAAgB,KAAK,CAAC;EAC/B,QAAQ,WAAW;CACrB;AACF"}
@@ -1,6 +1,6 @@
1
1
  import "./rolldown-runtime-CRm0XQPb.js";
2
- import { i as loadConfigs, s as run } from "./run-mIZ7hJVc.js";
3
- import { i as runtime } from "./Telemetry-BOCR2q1g.js";
2
+ import { i as loadConfigs, s as run } from "./run-BF2Wq1Io.js";
3
+ import { i as runtime } from "./Telemetry-BivZAaw9.js";
4
4
  import { h as createPlainLogger, r as logBlock } from "./output-B9Yw7vL0.js";
5
5
  import { n as setupReporters } from "./reporters-CNZQUlXY.js";
6
6
  import { styleText } from "node:util";
@@ -256,4 +256,4 @@ const runner = async ({ values }) => {
256
256
  //#endregion
257
257
  export { runner };
258
258
 
259
- //# sourceMappingURL=snapshot-DgsBHsOb.js.map
259
+ //# sourceMappingURL=snapshot-CHKxNlYg.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot-DgsBHsOb.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, rm, 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 * Recursively removes `path`. Silently succeeds when `path` does not exist.\n *\n * @example\n * ```ts\n * await clean('./dist')\n * ```\n */\nexport async function clean(path: string): Promise<void> {\n return rm(path, { recursive: true, force: true })\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, defaultStudioUrl } 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, run, 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: {} }> = async ({ values }) => {\n const options: SnapshotOptions = {\n configPath: values.config,\n studioUrl: values.url ?? defaultStudioUrl,\n logLevel: values.logLevel,\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 await run({ options, action: () => snapshot(options), json: options.json })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"snapshot-CHKxNlYg.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, rm, 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 * Recursively removes `path`. Silently succeeds when `path` does not exist.\n *\n * @example\n * ```ts\n * await clean('./dist')\n * ```\n */\nexport async function clean(path: string): Promise<void> {\n return rm(path, { recursive: true, force: true })\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, defaultStudioUrl } 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, run, 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: {} }> = async ({ values }) => {\n const options: SnapshotOptions = {\n configPath: values.config,\n studioUrl: values.url ?? defaultStudioUrl,\n logLevel: values.logLevel,\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 await run({ options, action: () => snapshot(options), json: options.json })\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  const require_agent = require("./agent-DElUuYuy.cjs");
2
- const require_run = require("./run-DrUd6OfI.cjs");
3
- const require_Telemetry = require("./Telemetry-D1M0d8PT.cjs");
2
+ const require_run = require("./run-DSeEZTnT.cjs");
3
+ const require_Telemetry = require("./Telemetry-D1jiXfo2.cjs");
4
4
  const require_output = require("./output-CWupdozw.cjs");
5
5
  const require_reporters = require("./reporters-C5HAypFq.cjs");
6
6
  let node_util = require("node:util");
@@ -257,4 +257,4 @@ const runner = async ({ values }) => {
257
257
  //#endregion
258
258
  exports.runner = runner;
259
259
 
260
- //# sourceMappingURL=snapshot-CQcQ5L6B.cjs.map
260
+ //# sourceMappingURL=snapshot-D5OaRDf9.cjs.map