@kubb/cli 5.0.0-beta.50 → 5.0.0-beta.52

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 (64) hide show
  1. package/dist/Telemetry-BZH4YIxq.js +312 -0
  2. package/dist/Telemetry-BZH4YIxq.js.map +1 -0
  3. package/dist/Telemetry-DC5WVMB9.cjs +349 -0
  4. package/dist/Telemetry-DC5WVMB9.cjs.map +1 -0
  5. package/dist/{generate-CKnn3tQa.js → generate-BYoW6Tbf.js} +2 -2
  6. package/dist/{generate-CKnn3tQa.js.map → generate-BYoW6Tbf.js.map} +1 -1
  7. package/dist/{generate-Q6GMu4L8.cjs → generate-BtVVpqYI.cjs} +2 -2
  8. package/dist/{generate-Q6GMu4L8.cjs.map → generate-BtVVpqYI.cjs.map} +1 -1
  9. package/dist/index.cjs +8 -9
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.js +6 -7
  12. package/dist/index.js.map +1 -1
  13. package/dist/{init-C5iCqBwA.cjs → init-C5MBsMV9.cjs} +2 -2
  14. package/dist/{init-C5iCqBwA.cjs.map → init-C5MBsMV9.cjs.map} +1 -1
  15. package/dist/{init-DyOF6CiQ.js → init-Dc5SDV9B.js} +2 -2
  16. package/dist/{init-DyOF6CiQ.js.map → init-Dc5SDV9B.js.map} +1 -1
  17. package/dist/{mcp-BN5HQYdK.cjs → mcp-B6ycoHpi.cjs} +3 -3
  18. package/dist/{mcp-BN5HQYdK.cjs.map → mcp-B6ycoHpi.cjs.map} +1 -1
  19. package/dist/{mcp-09FvxYWS.js → mcp-CuLcYL2g.js} +3 -3
  20. package/dist/{mcp-09FvxYWS.js.map → mcp-CuLcYL2g.js.map} +1 -1
  21. package/dist/{package-DOVOGEEY.cjs → package-CMoiVX61.cjs} +2 -2
  22. package/dist/package-CMoiVX61.cjs.map +1 -0
  23. package/dist/package-ChkqOLMB.js +6 -0
  24. package/dist/package-ChkqOLMB.js.map +1 -0
  25. package/dist/{run-CrvmI4G2.cjs → run-B2etCFG8.cjs} +42 -104
  26. package/dist/run-B2etCFG8.cjs.map +1 -0
  27. package/dist/{run-BO7phoNN.js → run-C7cr0qhi.js} +2 -2
  28. package/dist/run-C7cr0qhi.js.map +1 -0
  29. package/dist/{run-DvZ5i2lT.js → run-D2s4baOU.js} +34 -96
  30. package/dist/run-D2s4baOU.js.map +1 -0
  31. package/dist/{run-Cl4SrSob.cjs → run-DGMgkbD3.cjs} +3 -3
  32. package/dist/run-DGMgkbD3.cjs.map +1 -0
  33. package/dist/{run-BzaKz_nl.js → run-DLVIbuN0.js} +2 -2
  34. package/dist/run-DLVIbuN0.js.map +1 -0
  35. package/dist/{run-CkTpemme.cjs → run-DMWGLJUx.cjs} +3 -3
  36. package/dist/run-DMWGLJUx.cjs.map +1 -0
  37. package/dist/{validate-C6KPFEex.cjs → validate-B-8HQq1B.cjs} +3 -3
  38. package/dist/{validate-C6KPFEex.cjs.map → validate-B-8HQq1B.cjs.map} +1 -1
  39. package/dist/{validate-5atkOC73.js → validate-BWtbWM9F.js} +3 -3
  40. package/dist/{validate-5atkOC73.js.map → validate-BWtbWM9F.js.map} +1 -1
  41. package/package.json +6 -6
  42. package/src/Telemetry.ts +290 -0
  43. package/src/constants.ts +2 -2
  44. package/src/index.ts +1 -1
  45. package/src/loggers/clackLogger.ts +2 -27
  46. package/src/loggers/defineLogger.ts +59 -0
  47. package/src/loggers/plainLogger.ts +2 -4
  48. package/src/loggers/utils.ts +27 -1
  49. package/src/runners/generate/run.ts +3 -6
  50. package/src/runners/mcp/run.ts +1 -1
  51. package/src/runners/validate/run.ts +1 -1
  52. package/dist/constants-BQ8LZB1P.js +0 -23
  53. package/dist/constants-BQ8LZB1P.js.map +0 -1
  54. package/dist/constants-MzEjK668.cjs +0 -40
  55. package/dist/constants-MzEjK668.cjs.map +0 -1
  56. package/dist/package-Bm6VUbtL.js +0 -6
  57. package/dist/package-Bm6VUbtL.js.map +0 -1
  58. package/dist/package-DOVOGEEY.cjs.map +0 -1
  59. package/dist/run-BO7phoNN.js.map +0 -1
  60. package/dist/run-BzaKz_nl.js.map +0 -1
  61. package/dist/run-CkTpemme.cjs.map +0 -1
  62. package/dist/run-Cl4SrSob.cjs.map +0 -1
  63. package/dist/run-CrvmI4G2.cjs.map +0 -1
  64. package/dist/run-DvZ5i2lT.js.map +0 -1
@@ -0,0 +1,290 @@
1
+ import { randomBytes } from 'node:crypto'
2
+ import os from 'node:os'
3
+ import process from 'node:process'
4
+ import { executeIfOnline, getRuntimeName, getRuntimeVersion, isCIEnvironment, type RuntimeName } from '@internals/utils'
5
+ import { OTLP_ENDPOINT } from './constants.ts'
6
+
7
+ // OpenTelemetry OTLP JSON types
8
+ // https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto
9
+ // https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/common/v1/common.proto
10
+
11
+ type OtlpStringValue = { stringValue: string }
12
+ type OtlpBoolValue = { boolValue: boolean }
13
+ type OtlpIntValue = { intValue: number }
14
+ type OtlpDoubleValue = { doubleValue: number }
15
+ type OtlpBytesValue = { bytesValue: string }
16
+ type OtlpArrayValue = { arrayValue: { values: Array<OtlpAnyValue> } }
17
+ type OtlpKvListValue = { kvlistValue: { values: Array<OtlpKeyValue> } }
18
+
19
+ type OtlpAnyValue = OtlpStringValue | OtlpBoolValue | OtlpIntValue | OtlpDoubleValue | OtlpBytesValue | OtlpArrayValue | OtlpKvListValue
20
+
21
+ type OtlpKeyValue = {
22
+ key: string
23
+ value: OtlpAnyValue
24
+ }
25
+
26
+ type OtlpResource = {
27
+ attributes: Array<OtlpKeyValue>
28
+ droppedAttributesCount?: number
29
+ }
30
+
31
+ type OtlpInstrumentationScope = {
32
+ name: string
33
+ version?: string
34
+ attributes?: Array<OtlpKeyValue>
35
+ droppedAttributesCount?: number
36
+ }
37
+
38
+ /** https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto#L103 */
39
+ type OtlpSpanKind = 0 | 1 | 2 | 3 | 4 | 5
40
+
41
+ /** 0 = STATUS_CODE_UNSET, 1 = STATUS_CODE_OK, 2 = STATUS_CODE_ERROR */
42
+ type OtlpStatusCode = 0 | 1 | 2
43
+
44
+ type OtlpStatus = {
45
+ code: OtlpStatusCode
46
+ message?: string
47
+ }
48
+
49
+ type OtlpSpan = {
50
+ traceId: string
51
+ spanId: string
52
+ traceState?: string
53
+ parentSpanId?: string
54
+ name: string
55
+ kind: OtlpSpanKind
56
+ startTimeUnixNano: string
57
+ endTimeUnixNano: string
58
+ attributes?: Array<OtlpKeyValue>
59
+ droppedAttributesCount?: number
60
+ events?: Array<OtlpSpanEvent>
61
+ droppedEventsCount?: number
62
+ links?: Array<OtlpSpanLink>
63
+ droppedLinksCount?: number
64
+ status?: OtlpStatus
65
+ }
66
+
67
+ type OtlpSpanEvent = {
68
+ timeUnixNano: string
69
+ name: string
70
+ attributes?: Array<OtlpKeyValue>
71
+ droppedAttributesCount?: number
72
+ }
73
+
74
+ type OtlpSpanLink = {
75
+ traceId: string
76
+ spanId: string
77
+ traceState?: string
78
+ attributes?: Array<OtlpKeyValue>
79
+ droppedAttributesCount?: number
80
+ }
81
+
82
+ type OtlpScopeSpans = {
83
+ scope: OtlpInstrumentationScope
84
+ spans: Array<OtlpSpan>
85
+ schemaUrl?: string
86
+ }
87
+
88
+ type OtlpResourceSpans = {
89
+ resource: OtlpResource
90
+ scopeSpans: Array<OtlpScopeSpans>
91
+ schemaUrl?: string
92
+ }
93
+
94
+ /** Root payload sent to POST /v1/traces */
95
+ type OtlpExportTraceServiceRequest = {
96
+ resourceSpans: Array<OtlpResourceSpans>
97
+ }
98
+
99
+ /**
100
+ * Anonymous plugin name and options snapshot sent with each telemetry event.
101
+ */
102
+ export type TelemetryPlugin = {
103
+ /**
104
+ * Plugin name as registered in the Kubb config, e.g. `'@kubb/plugin-ts'`.
105
+ */
106
+ name: string
107
+ /**
108
+ * anonymized plugin options snapshot, values are included but cannot be traced back to the user.
109
+ */
110
+ options: Record<string, unknown>
111
+ }
112
+
113
+ export type TelemetryEvent = {
114
+ command: string
115
+ kubbVersion: string
116
+ nodeVersion: string
117
+ /**
118
+ * Name of the JavaScript runtime that executed the run, `'bun'`, `'deno'`, or `'node'`.
119
+ */
120
+ runtime: RuntimeName
121
+ /**
122
+ * Major version of the active runtime, e.g. `'1'` under Bun or `'22'` under Node.
123
+ */
124
+ runtimeVersion: string
125
+ platform: string
126
+ ci: boolean
127
+ plugins: Array<TelemetryPlugin>
128
+ duration: number
129
+ filesCreated: number
130
+ status: 'success' | 'failed'
131
+ }
132
+
133
+ /**
134
+ * Anonymous OTLP usage telemetry for the Kubb run. All methods are static, so call them as
135
+ * `Telemetry.build(...)`, `Telemetry.send(...)`, and `Telemetry.isDisabled()`. No file paths,
136
+ * OpenAPI specs, or secrets are ever included, and sending fails silently to never break a run.
137
+ */
138
+ export class Telemetry {
139
+ /**
140
+ * Returns `true` when telemetry is disabled via `DO_NOT_TRACK` or `KUBB_DISABLE_TELEMETRY`.
141
+ */
142
+ static isDisabled(): boolean {
143
+ return (
144
+ process.env['DO_NOT_TRACK'] === '1' ||
145
+ process.env['DO_NOT_TRACK'] === 'true' ||
146
+ process.env['KUBB_DISABLE_TELEMETRY'] === '1' ||
147
+ process.env['KUBB_DISABLE_TELEMETRY'] === 'true'
148
+ )
149
+ }
150
+
151
+ /**
152
+ * Build an anonymous telemetry payload from a completed generation run.
153
+ */
154
+ static build(options: {
155
+ command: 'generate' | 'mcp' | 'validate' | 'agent'
156
+ kubbVersion: string
157
+ plugins?: Array<TelemetryPlugin>
158
+ hrStart: [number, number]
159
+ filesCreated?: number
160
+ status: 'success' | 'failed'
161
+ }): TelemetryEvent {
162
+ const [seconds, nanoseconds] = process.hrtime(options.hrStart)
163
+ const duration = Math.round(seconds * 1000 + nanoseconds / 1e6)
164
+
165
+ return {
166
+ command: options.command,
167
+ kubbVersion: options.kubbVersion,
168
+ nodeVersion: process.versions.node.split('.')[0] as string,
169
+ runtime: getRuntimeName(),
170
+ runtimeVersion: getRuntimeVersion().split('.')[0] as string,
171
+ platform: os.platform(),
172
+ ci: isCIEnvironment(),
173
+ plugins: options.plugins ?? [],
174
+ duration,
175
+ filesCreated: options.filesCreated ?? 0,
176
+ status: options.status,
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Convert a {@link TelemetryEvent} into an OTLP-compatible JSON trace payload.
182
+ * See https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/
183
+ */
184
+ static buildOtlpPayload(event: TelemetryEvent): OtlpExportTraceServiceRequest {
185
+ const traceId = randomBytes(16).toString('hex')
186
+ const spanId = randomBytes(8).toString('hex')
187
+ const endTimeNs = BigInt(Date.now()) * 1_000_000n
188
+ const startTimeNs = endTimeNs - BigInt(event.duration) * 1_000_000n
189
+
190
+ const attributes: Array<OtlpKeyValue> = [
191
+ { key: 'kubb.command', value: { stringValue: event.command } },
192
+ { key: 'kubb.version', value: { stringValue: event.kubbVersion } },
193
+ { key: 'kubb.node_version', value: { stringValue: event.nodeVersion } },
194
+ { key: 'kubb.runtime', value: { stringValue: event.runtime } },
195
+ { key: 'kubb.runtime_version', value: { stringValue: event.runtimeVersion } },
196
+ { key: 'kubb.platform', value: { stringValue: event.platform } },
197
+ { key: 'kubb.ci', value: { boolValue: event.ci } },
198
+ { key: 'kubb.files_created', value: { intValue: event.filesCreated } },
199
+ { key: 'kubb.status', value: { stringValue: event.status } },
200
+ {
201
+ key: 'kubb.plugins',
202
+ value: {
203
+ arrayValue: {
204
+ values: event.plugins.map(
205
+ (p): OtlpKvListValue => ({
206
+ kvlistValue: {
207
+ values: [
208
+ { key: 'name', value: { stringValue: p.name } },
209
+ {
210
+ key: 'options',
211
+ value: {
212
+ stringValue: JSON.stringify({
213
+ ...p.options,
214
+ usedEnumNames: undefined,
215
+ }),
216
+ },
217
+ },
218
+ ],
219
+ },
220
+ }),
221
+ ),
222
+ },
223
+ },
224
+ },
225
+ ]
226
+
227
+ return {
228
+ resourceSpans: [
229
+ {
230
+ resource: {
231
+ attributes: [
232
+ { key: 'service.name', value: { stringValue: 'kubb-core' } },
233
+ {
234
+ key: 'service.version',
235
+ value: { stringValue: event.kubbVersion },
236
+ },
237
+ { key: 'telemetry.sdk.language', value: { stringValue: 'nodejs' } },
238
+ ],
239
+ },
240
+ scopeSpans: [
241
+ {
242
+ scope: { name: 'kubb-core', version: event.kubbVersion },
243
+ spans: [
244
+ {
245
+ traceId,
246
+ spanId,
247
+ name: event.command,
248
+ kind: 1 satisfies OtlpSpanKind,
249
+ startTimeUnixNano: String(startTimeNs),
250
+ endTimeUnixNano: String(endTimeNs),
251
+ attributes,
252
+ status: {
253
+ code: (event.status === 'success' ? 1 : 2) satisfies OtlpStatusCode,
254
+ },
255
+ },
256
+ ],
257
+ },
258
+ ],
259
+ },
260
+ ],
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Send an anonymous telemetry event to the Kubb OTLP endpoint. Respects `DO_NOT_TRACK` and
266
+ * `KUBB_DISABLE_TELEMETRY`, and fails silently so telemetry never interrupts a run.
267
+ */
268
+ static async send(event: TelemetryEvent): Promise<void> {
269
+ if (Telemetry.isDisabled()) {
270
+ return
271
+ }
272
+
273
+ await executeIfOnline(async () => {
274
+ try {
275
+ await fetch(`${OTLP_ENDPOINT}/v1/traces`, {
276
+ method: 'POST',
277
+ headers: {
278
+ 'Content-Type': 'application/json',
279
+ 'Kubb-Telemetry-Version': '1',
280
+ 'Kubb-Telemetry-Source': 'kubb-core',
281
+ },
282
+ body: JSON.stringify(Telemetry.buildOtlpPayload(event)),
283
+ signal: AbortSignal.timeout(5_000),
284
+ })
285
+ } catch (_e) {
286
+ // Fail silently, telemetry must never break the run
287
+ }
288
+ })
289
+ }
290
+ }
package/src/constants.ts CHANGED
@@ -4,9 +4,9 @@
4
4
  export const KUBB_NPM_PACKAGE_URL = 'https://registry.npmjs.org/@kubb/cli/latest' as const
5
5
 
6
6
  /**
7
- * Horizontal rule rendered above/below the plain-logger generation summary.
7
+ * OpenTelemetry ingestion endpoint for anonymous usage telemetry.
8
8
  */
9
- export const SUMMARY_SEPARATOR = ''.repeat(27)
9
+ export const OTLP_ENDPOINT = 'https://otlp.kubb.dev' as const
10
10
 
11
11
  /**
12
12
  * Glob pattern for paths the file watcher ignores.
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { styleText } from 'node:util'
2
2
  import { createCLI, isFlag } from '@internals/utils'
3
- import { Telemetry } from '@kubb/core'
3
+ import { Telemetry } from './Telemetry.ts'
4
4
  import { version } from '../package.json'
5
5
  import { QUIET_FLAGS } from './constants.ts'
6
6
 
@@ -3,7 +3,8 @@ import process from 'node:process'
3
3
  import { styleText } from 'node:util'
4
4
  import * as clack from '@clack/prompts'
5
5
  import { formatMsWithColor, getElapsedMs, getIntro, toCause } from '@internals/utils'
6
- import { defineLogger, Diagnostics, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'
6
+ import { Diagnostics, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'
7
+ import { defineLogger } from './defineLogger.ts'
7
8
  import { buildProgressLine, createProgressCounters, formatCommandWithArgs, formatMessage, recordPluginResult, resetProgressCounters } from './utils.ts'
8
9
 
9
10
  /**
@@ -74,11 +75,6 @@ export const clackLogger = defineLogger({
74
75
  })
75
76
  }
76
77
 
77
- function startSpinner(text?: string) {
78
- state.spinner.start(text)
79
- state.isSpinning = true
80
- }
81
-
82
78
  function stopSpinner(text?: string) {
83
79
  if (!state.isSpinning) {
84
80
  return
@@ -199,27 +195,6 @@ Run \`npm install -g @kubb/cli\` to update`,
199
195
  reset()
200
196
  })
201
197
 
202
- context.on('kubb:config:start', () => {
203
- if (logLevel <= logLevelMap.silent) {
204
- return
205
- }
206
-
207
- const text = getMessage('Configuration started')
208
-
209
- clack.intro(text)
210
- startSpinner(getMessage('Configuration loading'))
211
- })
212
-
213
- context.on('kubb:config:end', () => {
214
- if (logLevel <= logLevelMap.silent) {
215
- return
216
- }
217
-
218
- const text = getMessage('Configuration completed')
219
-
220
- clack.outro(text)
221
- })
222
-
223
198
  context.on('kubb:generation:start', ({ config }) => {
224
199
  reset()
225
200
 
@@ -0,0 +1,59 @@
1
+ import type { AsyncEventEmitter } from '@internals/utils'
2
+ import type { KubbHooks } from '@kubb/core'
3
+
4
+ /**
5
+ * Options accepted by a logger's `install` callback.
6
+ */
7
+ export type LoggerOptions = {
8
+ /**
9
+ * Output verbosity. Use the `logLevel` constants exported from `@kubb/core`
10
+ * (`silent`, `error`, `warn`, `info`, `verbose`, `debug`).
11
+ */
12
+ logLevel: number
13
+ }
14
+
15
+ /**
16
+ * Event emitter handed to `Logger.install`. Use `.on('kubb:info', ...)` and
17
+ * friends to subscribe to build events.
18
+ */
19
+ export type LoggerContext = AsyncEventEmitter<KubbHooks>
20
+
21
+ /**
22
+ * Logger contract. A logger receives the build's event emitter and subscribes
23
+ * to whichever lifecycle events it wants to forward to its destination
24
+ * (console, file, remote service).
25
+ */
26
+ export type Logger<TOptions extends LoggerOptions = LoggerOptions> = {
27
+ /**
28
+ * Display name used in diagnostics.
29
+ */
30
+ name: string
31
+ /**
32
+ * Called once per build with the shared event emitter. Subscribe to the
33
+ * lifecycle events the logger wants to forward to its destination.
34
+ */
35
+ install: (context: LoggerContext, options?: TOptions) => void | Promise<void>
36
+ }
37
+
38
+ export type UserLogger<TOptions extends LoggerOptions = LoggerOptions> = Logger<TOptions>
39
+
40
+ /**
41
+ * Defines a typed logger. The `install` method subscribes to lifecycle events
42
+ * on the shared emitter and forwards them to the logger's destination.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * import { defineLogger } from '@kubb/cli'
47
+ *
48
+ * export const myLogger = defineLogger({
49
+ * name: 'my-logger',
50
+ * install(context) {
51
+ * context.on('kubb:info', ({ message }) => console.log('ℹ', message))
52
+ * context.on('kubb:error', ({ error }) => console.error('✗', error.message))
53
+ * },
54
+ * })
55
+ * ```
56
+ */
57
+ export function defineLogger<Options extends LoggerOptions = LoggerOptions>(logger: UserLogger<Options>): Logger<Options> {
58
+ return logger
59
+ }
@@ -1,6 +1,7 @@
1
1
  import { relative } from 'node:path'
2
2
  import { formatMs, toCause } from '@internals/utils'
3
- import { defineLogger, Diagnostics, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'
3
+ import { Diagnostics, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'
4
+ import { defineLogger } from './defineLogger.ts'
4
5
  import { createHookTimer, formatCommandWithArgs, formatMessage } from './utils.ts'
5
6
 
6
7
  /**
@@ -93,9 +94,6 @@ export const plainLogger = defineLogger({
93
94
  console.log(`Kubb CLI v${version}`)
94
95
  })
95
96
 
96
- onStep('kubb:config:start', 'Configuration started')
97
- onStep('kubb:config:end', 'Configuration completed')
98
-
99
97
  context.on('kubb:generation:start', () => {
100
98
  const text = getMessage('Generation started')
101
99
 
@@ -1,8 +1,9 @@
1
1
  import process from 'node:process'
2
2
  import { styleText } from 'node:util'
3
3
  import { canUseTTY, formatHrtime, getElapsedMs } from '@internals/utils'
4
- import type { Logger, LoggerContext, LoggerOptions, Reporter, ReporterContext } from '@kubb/core'
4
+ import type { Reporter, ReporterContext } from '@kubb/core'
5
5
  import { logLevel as logLevelMap } from '@kubb/core'
6
+ import type { Logger, LoggerContext, LoggerOptions } from './defineLogger.ts'
6
7
  import { clackLogger } from './clackLogger.ts'
7
8
  import { plainLogger } from './plainLogger.ts'
8
9
  import type { LoggerType } from './types.ts'
@@ -219,3 +220,28 @@ async function setupReporters(context: LoggerContext, { logLevel, reporters }: L
219
220
  }
220
221
 
221
222
  export default setupReporters
223
+
224
+ /**
225
+ * Picks the reporters whose `name` matches one of `names`, in the order the names are given.
226
+ * The config carries every available reporter, and the host selects which to activate by name
227
+ * (the CLI maps `--reporter` to this). Duplicate names and names without a matching reporter are
228
+ * skipped.
229
+ */
230
+ export function selectReporters(reporters: ReadonlyArray<Reporter>, names: ReadonlyArray<string>): Array<Reporter> {
231
+ const seen = new Set<string>()
232
+ const selected: Array<Reporter> = []
233
+
234
+ for (const name of names) {
235
+ if (seen.has(name)) {
236
+ continue
237
+ }
238
+ seen.add(name)
239
+
240
+ const reporter = reporters.find((candidate) => candidate.name === name)
241
+ if (reporter) {
242
+ selected.push(reporter)
243
+ }
244
+ }
245
+
246
+ return selected
247
+ }
@@ -17,12 +17,11 @@ import {
17
17
  logLevel as logLevelMap,
18
18
  type ProblemDiagnostic,
19
19
  type ReporterName,
20
- selectReporters,
21
- Telemetry,
22
20
  } from '@kubb/core'
23
21
  import { version } from '../../../package.json'
24
22
  import { KUBB_NPM_PACKAGE_URL } from '../../constants.ts'
25
- import setupReporters from '../../loggers/utils.ts'
23
+ import { Telemetry } from '../../Telemetry.ts'
24
+ import setupReporters, { selectReporters } from '../../loggers/utils.ts'
26
25
  import { executeHooks, getConfigs, runHook, startWatcher } from './utils.ts'
27
26
 
28
27
  type GenerateProps = {
@@ -363,10 +362,8 @@ export async function run({ input, configPath, logLevel: logLevelKey, watch, rep
363
362
  try {
364
363
  const relativeConfigPath = path.relative(process.cwd(), resolvedConfigPath)
365
364
 
366
- await hooks.emit('kubb:config:start')
367
365
  await hooks.emit('kubb:info', { message: 'Config loaded', info: relativeConfigPath })
368
366
  await hooks.emit('kubb:success', { message: 'Config loaded successfully', info: relativeConfigPath })
369
- await hooks.emit('kubb:config:end', { configs })
370
367
 
371
368
  let anyFailed = false
372
369
  for (const config of configs) {
@@ -375,7 +372,7 @@ export async function run({ input, configPath, logLevel: logLevelKey, watch, rep
375
372
  [input || config.input.path],
376
373
  async (paths) => {
377
374
  // Don't removeAll(), that would also drop logger and lifecycle listeners.
378
- // Plugin and middleware listeners are already disposed by safeBuild's
375
+ // Plugin listeners are already disposed by safeBuild's
379
376
  // setupResult.dispose() in its finally block, so re-running generate()
380
377
  // on the same hooks emitter is safe.
381
378
  await generate({ input, config, logLevel, hooks })
@@ -1,7 +1,7 @@
1
1
  import process from 'node:process'
2
2
  import { styleText } from 'node:util'
3
3
  import { getErrorMessage } from '@internals/utils'
4
- import { Telemetry } from '@kubb/core'
4
+ import { Telemetry } from '../../Telemetry.ts'
5
5
  import type * as McpModule from '@kubb/mcp'
6
6
 
7
7
  type McpOptions = {
@@ -1,7 +1,7 @@
1
1
  import process from 'node:process'
2
2
  import { styleText } from 'node:util'
3
3
  import { getErrorMessage } from '@internals/utils'
4
- import { Telemetry } from '@kubb/core'
4
+ import { Telemetry } from '../../Telemetry.ts'
5
5
 
6
6
  type ValidateOptions = {
7
7
  /**
@@ -1,23 +0,0 @@
1
- //#region src/constants.ts
2
- /**
3
- * NPM registry endpoint used to check for @kubb/cli updates.
4
- */
5
- const KUBB_NPM_PACKAGE_URL = "https://registry.npmjs.org/@kubb/cli/latest";
6
- "─".repeat(27);
7
- /**
8
- * Glob pattern for paths the file watcher ignores.
9
- */
10
- const WATCHER_IGNORED_PATHS = "**/{.git,node_modules}/**";
11
- /**
12
- * Flags that short-circuit execution (help/version), no telemetry notice is shown.
13
- */
14
- const QUIET_FLAGS = new Set([
15
- "--help",
16
- "-h",
17
- "--version",
18
- "-v"
19
- ]);
20
- //#endregion
21
- export { QUIET_FLAGS as n, WATCHER_IGNORED_PATHS as r, KUBB_NPM_PACKAGE_URL as t };
22
-
23
- //# sourceMappingURL=constants-BQ8LZB1P.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants-BQ8LZB1P.js","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * NPM registry endpoint used to check for @kubb/cli updates.\n */\nexport const KUBB_NPM_PACKAGE_URL = 'https://registry.npmjs.org/@kubb/cli/latest' as const\n\n/**\n * Horizontal rule rendered above/below the plain-logger generation summary.\n */\nexport const SUMMARY_SEPARATOR = '─'.repeat(27)\n\n/**\n * Glob pattern for paths the file watcher ignores.\n */\nexport const WATCHER_IGNORED_PATHS = '**/{.git,node_modules}/**' as const\n\n/**\n * Flags that short-circuit execution (help/version), no telemetry notice is shown.\n */\nexport const QUIET_FLAGS = new Set(['--help', '-h', '--version', '-v'] as const)\n"],"mappings":";;;;AAGA,MAAa,uBAAuB;AAKH,IAAI,OAAO,EAAE;;;;AAK9C,MAAa,wBAAwB;;;;AAKrC,MAAa,cAAc,IAAI,IAAI;CAAC;CAAU;CAAM;CAAa;AAAI,CAAU"}
@@ -1,40 +0,0 @@
1
- //#region src/constants.ts
2
- /**
3
- * NPM registry endpoint used to check for @kubb/cli updates.
4
- */
5
- const KUBB_NPM_PACKAGE_URL = "https://registry.npmjs.org/@kubb/cli/latest";
6
- "─".repeat(27);
7
- /**
8
- * Glob pattern for paths the file watcher ignores.
9
- */
10
- const WATCHER_IGNORED_PATHS = "**/{.git,node_modules}/**";
11
- /**
12
- * Flags that short-circuit execution (help/version), no telemetry notice is shown.
13
- */
14
- const QUIET_FLAGS = new Set([
15
- "--help",
16
- "-h",
17
- "--version",
18
- "-v"
19
- ]);
20
- //#endregion
21
- Object.defineProperty(exports, "KUBB_NPM_PACKAGE_URL", {
22
- enumerable: true,
23
- get: function() {
24
- return KUBB_NPM_PACKAGE_URL;
25
- }
26
- });
27
- Object.defineProperty(exports, "QUIET_FLAGS", {
28
- enumerable: true,
29
- get: function() {
30
- return QUIET_FLAGS;
31
- }
32
- });
33
- Object.defineProperty(exports, "WATCHER_IGNORED_PATHS", {
34
- enumerable: true,
35
- get: function() {
36
- return WATCHER_IGNORED_PATHS;
37
- }
38
- });
39
-
40
- //# sourceMappingURL=constants-MzEjK668.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants-MzEjK668.cjs","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * NPM registry endpoint used to check for @kubb/cli updates.\n */\nexport const KUBB_NPM_PACKAGE_URL = 'https://registry.npmjs.org/@kubb/cli/latest' as const\n\n/**\n * Horizontal rule rendered above/below the plain-logger generation summary.\n */\nexport const SUMMARY_SEPARATOR = '─'.repeat(27)\n\n/**\n * Glob pattern for paths the file watcher ignores.\n */\nexport const WATCHER_IGNORED_PATHS = '**/{.git,node_modules}/**' as const\n\n/**\n * Flags that short-circuit execution (help/version), no telemetry notice is shown.\n */\nexport const QUIET_FLAGS = new Set(['--help', '-h', '--version', '-v'] as const)\n"],"mappings":";;;;AAGA,MAAa,uBAAuB;AAKH,IAAI,OAAO,EAAE;;;;AAK9C,MAAa,wBAAwB;;;;AAKrC,MAAa,cAAc,IAAI,IAAI;CAAC;CAAU;CAAM;CAAa;AAAI,CAAU"}
@@ -1,6 +0,0 @@
1
- //#region package.json
2
- var version = "5.0.0-beta.50";
3
- //#endregion
4
- export { version as t };
5
-
6
- //# sourceMappingURL=package-Bm6VUbtL.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"package-Bm6VUbtL.js","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"package-DOVOGEEY.cjs","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-BO7phoNN.js","names":[],"sources":["../src/runners/validate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { getErrorMessage } from '@internals/utils'\nimport { Telemetry } from '@kubb/core'\n\ntype ValidateOptions = {\n /**\n * Path or URL to the OpenAPI/Swagger file to validate.\n */\n input: string\n /**\n * Current `@kubb/cli` version string, used for the telemetry payload.\n */\n version: string\n}\n\ntype ValidateModule = typeof import('@kubb/adapter-oas')\ntype ValidateDependencies = {\n /**\n * Loads `@kubb/adapter-oas`. Injected so tests can substitute a mock.\n */\n loadValidateModule: () => Promise<ValidateModule>\n}\n\n/**\n * Dynamically loads `@kubb/adapter-oas` for OpenAPI validation.\n */\nexport function loadValidateModule(): Promise<ValidateModule> {\n return import('@kubb/adapter-oas') as Promise<ValidateModule>\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, version }: ValidateOptions, dependencies: ValidateDependencies = { loadValidateModule }): Promise<void> {\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => Telemetry.send(Telemetry.build({ command: 'validate', kubbVersion: version, hrStart, status }))\n try {\n const { adapterOas } = await dependencies.loadValidateModule()\n const adapter = adapterOas()\n if (!adapter.validate) {\n throw new Error('The loaded adapter does not support validation.')\n }\n await adapter.validate(input, { throwOnError: true })\n await report('success')\n console.log('✅ Validation success')\n } catch (error) {\n await report('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(getErrorMessage(error))\n process.exit(1)\n }\n}\n"],"mappings":";;;;;;;;;AA2BA,SAAgB,qBAA8C;CAC5D,OAAO,OAAO;AAChB;;;;;AAMA,eAAsB,IAAI,EAAE,OAAO,WAA4B,eAAqC,EAAE,mBAAmB,GAAkB;CACzI,MAAM,UAAU,QAAQ,OAAO;CAC/B,MAAM,UAAU,WAAiC,UAAU,KAAK,UAAU,MAAM;EAAE,SAAS;EAAY,aAAa;EAAS;EAAS;CAAO,CAAC,CAAC;CAC/I,IAAI;EACF,MAAM,EAAE,eAAe,MAAM,aAAa,mBAAmB;EAC7D,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,QAAQ,UACX,MAAM,IAAI,MAAM,iDAAiD;EAEnE,MAAM,QAAQ,SAAS,OAAO,EAAE,cAAc,KAAK,CAAC;EACpD,MAAM,OAAO,SAAS;EACtB,QAAQ,IAAI,sBAAsB;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ;EACrB,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,gBAAgB,KAAK,CAAC;EACpC,QAAQ,KAAK,CAAC;CAChB;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-BzaKz_nl.js","names":[],"sources":["../src/runners/mcp/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { getErrorMessage } from '@internals/utils'\nimport { Telemetry } from '@kubb/core'\nimport type * as McpModule from '@kubb/mcp'\n\ntype McpOptions = {\n /**\n * Current `@kubb/cli` version string, used for the telemetry payload.\n */\n version: string\n /**\n * TCP port for the HTTP MCP server. When `undefined`, the server uses stdio transport.\n */\n port?: string\n /**\n * Hostname to bind to when running in HTTP mode.\n *\n * @default 'localhost'\n */\n host?: string\n}\n\nexport async function run({ version, port, host }: McpOptions): Promise<void> {\n const { run: startMcpServer } = (await import('@kubb/mcp')) as typeof McpModule\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => Telemetry.send(Telemetry.build({ command: 'mcp', kubbVersion: version, hrStart, status }))\n try {\n console.log(styleText('cyan', '⏳ Starting MCP server...'))\n console.warn(styleText('yellow', 'This feature is still under development, use with caution'))\n await startMcpServer(undefined, { port: port !== undefined ? Number(port) : undefined, host })\n await report('success')\n } catch (error) {\n await report('failed')\n console.error(getErrorMessage(error))\n }\n}\n"],"mappings":";;;;;;AAuBA,eAAsB,IAAI,EAAE,SAAS,MAAM,QAAmC;CAC5E,MAAM,EAAE,KAAK,mBAAoB,MAAM,OAAO;CAC9C,MAAM,UAAU,QAAQ,OAAO;CAC/B,MAAM,UAAU,WAAiC,UAAU,KAAK,UAAU,MAAM;EAAE,SAAS;EAAO,aAAa;EAAS;EAAS;CAAO,CAAC,CAAC;CAC1I,IAAI;EACF,QAAQ,IAAI,UAAU,QAAQ,0BAA0B,CAAC;EACzD,QAAQ,KAAK,UAAU,UAAU,2DAA2D,CAAC;EAC7F,MAAM,eAAe,KAAA,GAAW;GAAE,MAAM,SAAS,KAAA,IAAY,OAAO,IAAI,IAAI,KAAA;GAAW;EAAK,CAAC;EAC7F,MAAM,OAAO,SAAS;CACxB,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ;EACrB,QAAQ,MAAM,gBAAgB,KAAK,CAAC;CACtC;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-CkTpemme.cjs","names":["process","Telemetry","getErrorMessage"],"sources":["../src/runners/validate/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { getErrorMessage } from '@internals/utils'\nimport { Telemetry } from '@kubb/core'\n\ntype ValidateOptions = {\n /**\n * Path or URL to the OpenAPI/Swagger file to validate.\n */\n input: string\n /**\n * Current `@kubb/cli` version string, used for the telemetry payload.\n */\n version: string\n}\n\ntype ValidateModule = typeof import('@kubb/adapter-oas')\ntype ValidateDependencies = {\n /**\n * Loads `@kubb/adapter-oas`. Injected so tests can substitute a mock.\n */\n loadValidateModule: () => Promise<ValidateModule>\n}\n\n/**\n * Dynamically loads `@kubb/adapter-oas` for OpenAPI validation.\n */\nexport function loadValidateModule(): Promise<ValidateModule> {\n return import('@kubb/adapter-oas') as Promise<ValidateModule>\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, version }: ValidateOptions, dependencies: ValidateDependencies = { loadValidateModule }): Promise<void> {\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => Telemetry.send(Telemetry.build({ command: 'validate', kubbVersion: version, hrStart, status }))\n try {\n const { adapterOas } = await dependencies.loadValidateModule()\n const adapter = adapterOas()\n if (!adapter.validate) {\n throw new Error('The loaded adapter does not support validation.')\n }\n await adapter.validate(input, { throwOnError: true })\n await report('success')\n console.log('✅ Validation success')\n } catch (error) {\n await report('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(getErrorMessage(error))\n process.exit(1)\n }\n}\n"],"mappings":";;;;;;;;;;AA2BA,SAAgB,qBAA8C;CAC5D,OAAO,OAAO;AAChB;;;;;AAMA,eAAsB,IAAI,EAAE,OAAO,WAA4B,eAAqC,EAAE,mBAAmB,GAAkB;CACzI,MAAM,UAAUA,aAAAA,QAAQ,OAAO;CAC/B,MAAM,UAAU,WAAiCC,WAAAA,UAAU,KAAKA,WAAAA,UAAU,MAAM;EAAE,SAAS;EAAY,aAAa;EAAS;EAAS;CAAO,CAAC,CAAC;CAC/I,IAAI;EACF,MAAM,EAAE,eAAe,MAAM,aAAa,mBAAmB;EAC7D,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,QAAQ,UACX,MAAM,IAAI,MAAM,iDAAiD;EAEnE,MAAM,QAAQ,SAAS,OAAO,EAAE,cAAc,KAAK,CAAC;EACpD,MAAM,OAAO,SAAS;EACtB,QAAQ,IAAI,sBAAsB;CACpC,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ;EACrB,IAAI,iBAAiB,SAAS,qBAAqB,KAAK,MAAM,OAAO,GAAG;GACtE,QAAQ,OAAA,GAAA,UAAA,UAAA,CAAgB,OAAO,iDAAiD,CAAC;GACjF,QAAQ,MAAM,EAAE;GAChB,QAAQ,MAAM,kBAAkB;GAChC,QAAQ,OAAA,GAAA,UAAA,UAAA,CAAgB,QAAQ,iCAAiC,CAAC;GAClE,QAAQ,OAAA,GAAA,UAAA,UAAA,CAAgB,QAAQ,QAAQ,CAAC;GACzC,QAAQ,OAAA,GAAA,UAAA,UAAA,CAAgB,QAAQ,kCAAkC,CAAC;GACnE,QAAQ,MAAM,EAAE;EAClB;EACA,QAAQ,MAAM,qBAAqB;EACnC,QAAQ,MAAMC,eAAAA,gBAAgB,KAAK,CAAC;EACpC,aAAA,QAAQ,KAAK,CAAC;CAChB;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-Cl4SrSob.cjs","names":["process","Telemetry","getErrorMessage"],"sources":["../src/runners/mcp/run.ts"],"sourcesContent":["import process from 'node:process'\nimport { styleText } from 'node:util'\nimport { getErrorMessage } from '@internals/utils'\nimport { Telemetry } from '@kubb/core'\nimport type * as McpModule from '@kubb/mcp'\n\ntype McpOptions = {\n /**\n * Current `@kubb/cli` version string, used for the telemetry payload.\n */\n version: string\n /**\n * TCP port for the HTTP MCP server. When `undefined`, the server uses stdio transport.\n */\n port?: string\n /**\n * Hostname to bind to when running in HTTP mode.\n *\n * @default 'localhost'\n */\n host?: string\n}\n\nexport async function run({ version, port, host }: McpOptions): Promise<void> {\n const { run: startMcpServer } = (await import('@kubb/mcp')) as typeof McpModule\n const hrStart = process.hrtime()\n const report = (status: 'success' | 'failed') => Telemetry.send(Telemetry.build({ command: 'mcp', kubbVersion: version, hrStart, status }))\n try {\n console.log(styleText('cyan', '⏳ Starting MCP server...'))\n console.warn(styleText('yellow', 'This feature is still under development, use with caution'))\n await startMcpServer(undefined, { port: port !== undefined ? Number(port) : undefined, host })\n await report('success')\n } catch (error) {\n await report('failed')\n console.error(getErrorMessage(error))\n }\n}\n"],"mappings":";;;;;;;AAuBA,eAAsB,IAAI,EAAE,SAAS,MAAM,QAAmC;CAC5E,MAAM,EAAE,KAAK,mBAAoB,MAAM,OAAO;CAC9C,MAAM,UAAUA,aAAAA,QAAQ,OAAO;CAC/B,MAAM,UAAU,WAAiCC,WAAAA,UAAU,KAAKA,WAAAA,UAAU,MAAM;EAAE,SAAS;EAAO,aAAa;EAAS;EAAS;CAAO,CAAC,CAAC;CAC1I,IAAI;EACF,QAAQ,KAAA,GAAA,UAAA,UAAA,CAAc,QAAQ,0BAA0B,CAAC;EACzD,QAAQ,MAAA,GAAA,UAAA,UAAA,CAAe,UAAU,2DAA2D,CAAC;EAC7F,MAAM,eAAe,KAAA,GAAW;GAAE,MAAM,SAAS,KAAA,IAAY,OAAO,IAAI,IAAI,KAAA;GAAW;EAAK,CAAC;EAC7F,MAAM,OAAO,SAAS;CACxB,SAAS,OAAO;EACd,MAAM,OAAO,QAAQ;EACrB,QAAQ,MAAMC,eAAAA,gBAAgB,KAAK,CAAC;CACtC;AACF"}