{"version":3,"file":"Telemetry-DuO34wMx.cjs","names":["process","getElapsedMs","randomBytes","getAgentProfile","version","runtime","os","isCIEnvironment"],"sources":["../src/Telemetry.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto'\nimport os from 'node:os'\nimport process from 'node:process'\nimport { getElapsedMs, isCIEnvironment, runtime } from '@internals/utils'\nimport { getAgentProfile } from 'gunshi/agent'\nimport { version } from '../package.json'\n\n/** OpenTelemetry ingestion endpoint for anonymous usage telemetry. */\nconst OTLP_ENDPOINT = 'https://otlp.kubb.dev' as const\n\ntype TelemetryCommand = 'generate' | 'mcp' | 'studio' | 'validate'\n\n/**\n * Anonymous plugin name and options snapshot sent with each telemetry event.\n */\nexport type TelemetryPlugin = {\n  /**\n   * Plugin name as registered in the Kubb config, e.g. `'@kubb/plugin-ts'`.\n   */\n  name: string\n  /**\n   * Anonymized snapshot of the plugin options. Values are included but cannot be traced back to a user.\n   */\n  options: Record<string, unknown>\n}\n\n/** How a command run ended, as the command reports it to the function {@link trackRun} returned. */\ntype RunResult = {\n  status: 'success' | 'failed'\n  plugins?: Array<TelemetryPlugin>\n  filesCreated?: number\n  /**\n   * Name the MCP client sends in its `initialize` request, e.g. `'claude-code'`. Only set for `kubb mcp`.\n   */\n  mcpClient?: string\n}\n\n/**\n * Returns `true` when telemetry is disabled via `DO_NOT_TRACK` or `KUBB_DISABLE_TELEMETRY`.\n */\nexport function isDisabled(): boolean {\n  return ['DO_NOT_TRACK', 'KUBB_DISABLE_TELEMETRY'].some((name) => ['1', 'true'].includes(process.env[name] ?? ''))\n}\n\n/** Tracks one command run for the running CLI version; returns the reporter the command calls once it knows how it ended. */\nexport function trackRun({ command, hrStart }: { command: TelemetryCommand; hrStart: [number, number] }): (result: RunResult) => Promise<void> {\n  return (result) => sendTelemetry(buildOtlpPayload({ command, duration: Math.round(getElapsedMs(hrStart)), ...result }))\n}\n\n/**\n * The OTLP trace payload for one run: a span named after the command whose attributes are the\n * anonymous run facts. The attribute keys are the contract with otlp.kubb.dev.\n *\n * @see https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/\n */\nexport function buildOtlpPayload({\n  command,\n  duration,\n  status,\n  plugins = [],\n  filesCreated = 0,\n  mcpClient,\n}: RunResult & { command: TelemetryCommand; duration: number }) {\n  const traceId = randomBytes(16).toString('hex')\n  const spanId = randomBytes(8).toString('hex')\n  const endTimeNs = BigInt(Date.now()) * 1_000_000n\n  const startTimeNs = endTimeNs - BigInt(duration) * 1_000_000n\n  const pluginNames = [...new Set(plugins.map((plugin) => plugin.name))].sort()\n  const agent = getAgentProfile()\n\n  const attributes = [\n    { key: 'kubb.command', value: { stringValue: command } },\n    { key: 'kubb.version', value: { stringValue: version } },\n    { key: 'kubb.node_version', value: { stringValue: process.versions.node.split('.')[0] as string } },\n    { key: 'kubb.runtime', value: { stringValue: runtime.name } },\n    { key: 'kubb.runtime_version', value: { stringValue: runtime.version.split('.')[0] as string } },\n    { key: 'kubb.platform', value: { stringValue: os.platform() } },\n    { key: 'kubb.ci', value: { boolValue: isCIEnvironment() } },\n    // A terminal on stdin means a person typed the command; agents, scripts, and CI pipe it.\n    { key: 'kubb.tty', value: { boolValue: process.stdin.isTTY === true } },\n    ...(agent.isAgent && agent.name ? [{ key: 'kubb.agent', value: { stringValue: agent.name } }] : []),\n    // The client picks this name, so cap its length before it leaves the machine.\n    ...(mcpClient ? [{ key: 'kubb.mcp_client', value: { stringValue: mcpClient.slice(0, 64) } }] : []),\n    { key: 'kubb.files_created', value: { intValue: filesCreated } },\n    { key: 'kubb.status', value: { stringValue: status } },\n    {\n      key: 'kubb.plugins',\n      value: { arrayValue: { values: pluginNames.map((name) => ({ stringValue: name })) } },\n    },\n    ...pluginNames.map((name) => ({ key: `kubb.plugin.${name}`, value: { boolValue: true } })),\n    {\n      key: 'kubb.plugin_options',\n      value: {\n        arrayValue: {\n          values: plugins.map((p) => ({\n            kvlistValue: {\n              values: [\n                { key: 'name', value: { stringValue: p.name } },\n                {\n                  key: 'options',\n                  value: {\n                    stringValue: JSON.stringify({\n                      ...p.options,\n                      usedEnumNames: undefined,\n                    }),\n                  },\n                },\n              ],\n            },\n          })),\n        },\n      },\n    },\n  ]\n\n  return {\n    resourceSpans: [\n      {\n        resource: {\n          attributes: [\n            { key: 'service.name', value: { stringValue: 'kubb' } },\n            { key: 'service.version', value: { stringValue: version } },\n            { key: 'telemetry.sdk.language', value: { stringValue: 'nodejs' } },\n          ],\n        },\n        scopeSpans: [\n          {\n            scope: { name: 'kubb-core', version },\n            spans: [\n              {\n                traceId,\n                spanId,\n                name: command,\n                kind: 1,\n                startTimeUnixNano: String(startTimeNs),\n                endTimeUnixNano: String(endTimeNs),\n                attributes,\n                status: {\n                  code: status === 'success' ? 1 : 2,\n                },\n              },\n            ],\n          },\n        ],\n      },\n    ],\n  }\n}\n\n/**\n * Send an OTLP payload to the Kubb endpoint. Respects `DO_NOT_TRACK` and\n * `KUBB_DISABLE_TELEMETRY`, and fails silently so telemetry never interrupts a run. No file\n * paths, OpenAPI specs, or secrets are sent.\n */\nexport async function sendTelemetry(payload: ReturnType<typeof buildOtlpPayload>): Promise<void> {\n  if (isDisabled()) {\n    return\n  }\n\n  try {\n    await fetch(`${OTLP_ENDPOINT}/v1/traces`, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'Kubb-Telemetry-Version': '1',\n        'Kubb-Telemetry-Source': 'kubb-cli',\n      },\n      body: JSON.stringify(payload),\n      // Short, since an unfinished request keeps the process alive after the run.\n      signal: AbortSignal.timeout(1_000),\n    })\n  } catch (_e) {\n    // Fail silently, telemetry must never break the run\n  }\n}\n"],"mappings":"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"}