{"version":3,"sources":["../src/trace-hybrid.ts","../src/shutdown.ts","../src/request-logger.ts","../src/drain-toolkit.ts","../src/enricher-toolkit.ts","../src/gen-ai-metrics.ts","../src/gen-ai-events.ts"],"names":["otelTraceApi","trace","getEventQueue","getSdk","getLogger","_closeEmbeddedDevtools","resetEvents","resetMetrics","resetEventQueue","AsyncLocalStorage","ctx","span","otelTrace","createTraceContext","attrs","flattenToAttributes","emitCorrelatedEvent","recordStructuredError","request","mergeInto","AggregationType"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Hybrid `trace` export: callable like autotel's `trace(fn)`, AND exposes the\n * full `@opentelemetry/api` `TraceAPI` surface (`trace.getActiveSpan()`,\n * `trace.getTracer()`, …) so existing OTel code \"just works\" when imported\n * from `autotel`.\n *\n * Implementation: `Object.assign` mutates the autotel `trace` function to\n * attach the OTel TraceAPI methods. Because every reference to `trace` across\n * autotel resolves to the same function instance, this is a one-time, global\n * augmentation.\n */\n\nimport { trace as otelTraceApi } from '@opentelemetry/api';\nimport { trace as autotelTraceFn } from './functional';\n\nconst otelMethods = {\n  // Class methods on TraceAPI — bind to the singleton.\n  setGlobalTracerProvider:\n    otelTraceApi.setGlobalTracerProvider.bind(otelTraceApi),\n  getTracerProvider: otelTraceApi.getTracerProvider.bind(otelTraceApi),\n  getTracer: otelTraceApi.getTracer.bind(otelTraceApi),\n  disable: otelTraceApi.disable.bind(otelTraceApi),\n  // Instance fields on TraceAPI — already standalone, copy by reference.\n  wrapSpanContext: otelTraceApi.wrapSpanContext,\n  isSpanContextValid: otelTraceApi.isSpanContextValid,\n  deleteSpan: otelTraceApi.deleteSpan,\n  getSpan: otelTraceApi.getSpan,\n  getActiveSpan: otelTraceApi.getActiveSpan,\n  getSpanContext: otelTraceApi.getSpanContext,\n  setSpan: otelTraceApi.setSpan,\n  setSpanContext: otelTraceApi.setSpanContext,\n};\n\nexport const trace: typeof autotelTraceFn & typeof otelTraceApi = Object.assign(\n  autotelTraceFn,\n  otelMethods,\n) as typeof autotelTraceFn & typeof otelTraceApi;\n","/**\n * Graceful shutdown with flush and cleanup\n */\n\nimport { getSdk, getLogger, _closeEmbeddedDevtools } from './init';\nimport { getEventQueue, resetEventQueue } from './track';\nimport { resetEvents } from './event';\nimport { resetMetrics } from './metric';\n\n/**\n * Flush all pending telemetry\n *\n * Flushes both events events and OpenTelemetry spans to their destinations.\n * Includes timeout protection to prevent hanging in serverless environments.\n *\n * Safe to call multiple times.\n *\n * @param options - Optional configuration\n * @param options.timeout - Timeout in milliseconds (default: 2000ms)\n * @param options.forShutdown - If true, permanently disables the events queue after flush (used internally by shutdown())\n *\n * @example Manual flush in serverless\n * ```typescript\n * import { flush } from 'autotel';\n *\n * export const handler = async (event) => {\n *   // ... process event\n *   await flush(); // Flush before function returns\n *   return result;\n * };\n * ```\n *\n * @example With custom timeout\n * ```typescript\n * await flush({ timeout: 5000 }); // 5 second timeout\n * ```\n */\nexport async function flush(options?: {\n  timeout?: number;\n  forShutdown?: boolean;\n}): Promise<void> {\n  const timeout = options?.timeout ?? 2000;\n  const forShutdown = options?.forShutdown ?? false;\n\n  const doFlush = async () => {\n    // Flush events queue (or shutdown queue when tearing down)\n    const eventsQueue = getEventQueue();\n    if (eventsQueue) {\n      if (forShutdown) {\n        await eventsQueue.shutdown();\n      } else {\n        await eventsQueue.flush();\n      }\n    }\n\n    // Flush OpenTelemetry spans\n    // This ensures spans are exported immediately, critical for serverless\n    const sdk = getSdk();\n    if (sdk) {\n      try {\n        // Type assertion needed as getTracerProvider is not in the public NodeSDK interface\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        const sdkAny = sdk as any;\n        if (typeof sdkAny.getTracerProvider === 'function') {\n          const tracerProvider = sdkAny.getTracerProvider();\n          if (\n            tracerProvider &&\n            typeof tracerProvider.forceFlush === 'function'\n          ) {\n            await tracerProvider.forceFlush();\n          }\n        }\n      } catch {\n        // Ignore errors when accessing tracer provider (may not be available in test mocks)\n      }\n    }\n  };\n\n  // Add timeout protection to prevent hanging\n  let timeoutHandle: NodeJS.Timeout | undefined;\n  try {\n    await Promise.race([\n      doFlush().finally(() => {\n        // Clear timeout as soon as flush completes\n        if (timeoutHandle) {\n          clearTimeout(timeoutHandle);\n        }\n      }),\n      new Promise<void>((_, reject) => {\n        timeoutHandle = setTimeout(\n          () => reject(new Error('Flush timeout')),\n          timeout,\n        );\n        // Use unref() to allow Node to exit if flush completes first\n        // This prevents the 2s delay in serverless when flush succeeds immediately\n        timeoutHandle.unref();\n      }),\n    ]);\n  } catch (error) {\n    // Clear timeout on error too\n    if (timeoutHandle) {\n      clearTimeout(timeoutHandle);\n    }\n    const logger = getLogger();\n    logger.error(\n      {\n        err: error instanceof Error ? error : new Error(String(error)),\n      },\n      '[autotel] Flush error',\n    );\n    throw error;\n  }\n}\n\n/**\n * Shutdown telemetry and cleanup resources\n *\n * - Flushes all pending data\n * - Shuts down OpenTelemetry SDK\n * - Cleans up resources\n *\n * Call this before process exit.\n *\n * Always performs cleanup even if flush fails, preventing resource leaks\n * in serverless handlers or tests.\n *\n * @example Express server\n * ```typescript\n * const server = app.listen(3000)\n *\n * process.on('SIGTERM', async () => {\n *   await server.close()\n *   await shutdown()\n *   process.exit(0)\n * })\n * ```\n */\nexport async function shutdown(): Promise<void> {\n  const logger = getLogger();\n  let shutdownError: Error | null = null;\n\n  // Attempt to flush (with queue shutdown so new events are rejected), but continue with cleanup even if it fails\n  try {\n    await flush({ forShutdown: true });\n  } catch (error) {\n    const err = error instanceof Error ? error : new Error(String(error));\n    shutdownError = err;\n    logger.error(\n      {\n        err,\n      },\n      '[autotel] Flush failed during shutdown, continuing cleanup',\n    );\n  }\n\n  // Always shutdown SDK and clean up resources\n  try {\n    // Shutdown OpenTelemetry SDK\n    const sdk = getSdk();\n    if (sdk) {\n      await sdk.shutdown();\n    }\n  } catch (error) {\n    const err = error instanceof Error ? error : new Error(String(error));\n\n    // Ignore ECONNREFUSED errors - this happens when no OTLP endpoint was configured\n    // The SDK tries to flush exporters that don't exist, which is harmless\n    const isConnectionRefused =\n      typeof error === 'object' &&\n      error !== null &&\n      'code' in error &&\n      error.code === 'ECONNREFUSED';\n\n    if (!isConnectionRefused) {\n      // Only store/log non-connection errors\n      if (!shutdownError) {\n        shutdownError = err;\n      }\n      logger.error({ err }, '[autotel] SDK shutdown failed');\n    }\n  } finally {\n    await _closeEmbeddedDevtools();\n\n    // Clean up singleton Maps and queues to prevent memory leaks\n    // This runs even if SDK shutdown fails\n    const eventsQueue = getEventQueue();\n    if (eventsQueue && typeof eventsQueue.cleanup === 'function') {\n      eventsQueue.cleanup();\n    }\n    resetEvents();\n    resetMetrics();\n    resetEventQueue();\n  }\n\n  // Rethrow first error after cleanup completes\n  // This allows tests and CI to detect failures while still ensuring cleanup\n  if (shutdownError) {\n    throw shutdownError;\n  }\n}\n\n/**\n * Register automatic shutdown hooks for common signals\n *\n * Handles:\n * - SIGTERM (Docker/K8s graceful shutdown)\n * - SIGINT (Ctrl+C)\n *\n * @internal Called automatically on module load\n */\nfunction registerShutdownHooks(): void {\n  if (typeof process === 'undefined') return; // Not in Node.js\n\n  const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];\n  let shuttingDown = false;\n\n  for (const signal of signals) {\n    process.on(signal, async () => {\n      if (shuttingDown) return; // Prevent double shutdown\n      shuttingDown = true;\n\n      if (process.env.NODE_ENV !== 'test') {\n        getLogger().info(\n          {},\n          `[autotel] Received ${signal}, flushing telemetry...`,\n        );\n      }\n\n      try {\n        await shutdown();\n      } catch (error) {\n        getLogger().error(\n          {\n            err: error instanceof Error ? error : undefined,\n          },\n          '[autotel] Error during shutdown',\n        );\n      } finally {\n        process.exit(0);\n      }\n    });\n  }\n}\n\n// Auto-register shutdown hooks\nregisterShutdownHooks();\n","import { AsyncLocalStorage } from 'node:async_hooks';\nimport { trace as otelTrace } from '@opentelemetry/api';\nimport type { TraceContext } from './trace-context';\nimport { createTraceContext } from './trace-context';\nimport { recordStructuredError } from './structured-error';\nimport { flattenToAttributes } from './flatten-attributes';\nimport { emitCorrelatedEvent } from './correlated-events';\n\nconst POST_EMIT_FORK_HINT =\n  \"For intentional background work tied to this request, use log.fork('label', fn) when available.\";\n\nfunction warnPostEmit(method: string, detail: string): void {\n  console.warn(\n    `[autotel] ${method} called after the wide event was emitted — ${detail} This data will not appear in observability. ${POST_EMIT_FORK_HINT}`,\n  );\n}\n\nfunction mergeInto(\n  target: Record<string, unknown>,\n  source: Record<string, unknown>,\n): void {\n  for (const key in source) {\n    const sourceVal = source[key];\n    if (sourceVal === undefined) continue;\n    const targetVal = target[key];\n    if (\n      sourceVal !== null &&\n      typeof sourceVal === 'object' &&\n      !Array.isArray(sourceVal) &&\n      targetVal !== null &&\n      typeof targetVal === 'object' &&\n      !Array.isArray(targetVal)\n    ) {\n      mergeInto(\n        targetVal as Record<string, unknown>,\n        sourceVal as Record<string, unknown>,\n      );\n    } else if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {\n      target[key] = [...targetVal, ...sourceVal];\n    } else {\n      target[key] = sourceVal;\n    }\n  }\n}\n\nconst requestContextStore = new AsyncLocalStorage<TraceContext>();\n\nexport function runWithRequestContext<T>(ctx: TraceContext, fn: () => T): T {\n  return requestContextStore.run(ctx, fn);\n}\n\nexport interface RequestLogger {\n  set(fields: Record<string, unknown>): void;\n  info(message: string, fields?: Record<string, unknown>): void;\n  warn(message: string, fields?: Record<string, unknown>): void;\n  error(error: Error | string, fields?: Record<string, unknown>): void;\n  getContext(): Record<string, unknown>;\n  emitNow(overrides?: Record<string, unknown>): RequestLogSnapshot;\n  fork(\n    label: string,\n    fn: () => void | Promise<void>,\n    options?: ForkOptions,\n  ): void;\n}\n\nexport interface RequestLogSnapshot {\n  timestamp: string;\n  traceId: string;\n  spanId: string;\n  correlationId: string;\n  context: Record<string, unknown>;\n}\n\nexport interface RequestLoggerOptions {\n  /** Callback invoked by emitNow() for manual fan-out. */\n  onEmit?: (snapshot: RequestLogSnapshot) => void | Promise<void>;\n}\n\n/**\n * Optional lifecycle hooks for adapters that need to track child loggers\n * spawned by `log.fork()` (e.g. active logger maps in framework integrations).\n */\nexport interface ForkLifecycle {\n  /** Called after the child logger is created, before `fn` runs. */\n  onChildEnter?: (child: RequestLogger) => void;\n  /** Called after the child has finished (emit + drain), success or failure. */\n  onChildExit?: (child: RequestLogger) => void;\n}\n\nexport interface ForkOptions {\n  lifecycle?: ForkLifecycle;\n}\n\nfunction resolveContext(ctx?: TraceContext): TraceContext {\n  if (ctx) return ctx;\n\n  const stored = requestContextStore.getStore();\n  if (stored) return stored;\n\n  const span = otelTrace.getActiveSpan();\n  if (!span) {\n    throw new Error(\n      '[autotel] getRequestLogger() requires an active span or runWithRequestContext(). Wrap your handler with trace() or use runWithRequestContext().',\n    );\n  }\n  return createTraceContext(span);\n}\n\nexport function getRequestLogger(\n  ctx?: TraceContext,\n  options?: RequestLoggerOptions,\n): RequestLogger {\n  const activeContext = resolveContext(ctx);\n  let contextState: Record<string, unknown> = {};\n  let emitted = false;\n  let lastSnapshot: RequestLogSnapshot | null = null;\n\n  const addLogEvent = (\n    level: 'info' | 'warn' | 'error',\n    message: string,\n    fields?: Record<string, unknown>,\n  ) => {\n    const attrs = fields ? flattenToAttributes(fields) : undefined;\n    emitCorrelatedEvent(activeContext, `log.${level}`, {\n      message,\n      ...(attrs ?? {}),\n    });\n  };\n\n  const sealCheck = (method: string, keys: string[]): void => {\n    if (emitted) {\n      warnPostEmit(\n        method,\n        `Keys dropped: ${keys.length ? keys.join(', ') : '(empty)'}.`,\n      );\n    }\n  };\n\n  return {\n    set(fields: Record<string, unknown>) {\n      sealCheck('log.set()', Object.keys(fields));\n      if (emitted) return;\n      mergeInto(contextState, fields);\n      activeContext.setAttributes(flattenToAttributes(fields));\n    },\n\n    info(message: string, fields?: Record<string, unknown>) {\n      const keys = fields\n        ? ['message', ...Object.keys(fields).filter((k) => k !== 'requestLogs')]\n        : ['message'];\n      sealCheck('log.info()', keys);\n      if (emitted) return;\n      addLogEvent('info', message, fields);\n      if (fields) {\n        mergeInto(contextState, fields);\n        activeContext.setAttributes(flattenToAttributes(fields));\n      }\n    },\n\n    warn(message: string, fields?: Record<string, unknown>) {\n      const keys = fields\n        ? ['message', ...Object.keys(fields).filter((k) => k !== 'requestLogs')]\n        : ['message'];\n      sealCheck('log.warn()', keys);\n      if (emitted) return;\n      addLogEvent('warn', message, fields);\n      activeContext.setAttribute('autotel.log.level', 'warn');\n      if (fields) {\n        mergeInto(contextState, fields);\n        activeContext.setAttributes(flattenToAttributes(fields));\n      }\n    },\n\n    error(error: Error | string, fields?: Record<string, unknown>) {\n      const keys = fields ? [...Object.keys(fields), 'error'] : ['error'];\n      sealCheck('log.error()', keys);\n      if (emitted) return;\n      const err = typeof error === 'string' ? new Error(error) : error;\n      recordStructuredError(activeContext, err);\n      addLogEvent('error', err.message, fields);\n\n      if (fields) {\n        mergeInto(contextState, fields);\n        activeContext.setAttributes(flattenToAttributes(fields));\n      }\n      activeContext.setAttribute('autotel.log.level', 'error');\n    },\n\n    getContext() {\n      return { ...contextState };\n    },\n\n    emitNow(overrides?: Record<string, unknown>): RequestLogSnapshot {\n      if (emitted) {\n        warnPostEmit('log.emitNow()', 'Ignoring duplicate emit.');\n        return lastSnapshot as RequestLogSnapshot;\n      }\n\n      const mergedContext = {\n        ...contextState,\n        ...(overrides ?? {}),\n      };\n      const flattened = flattenToAttributes(mergedContext);\n      activeContext.setAttributes(flattened);\n\n      const snapshot: RequestLogSnapshot = {\n        timestamp: new Date().toISOString(),\n        traceId: activeContext.traceId,\n        spanId: activeContext.spanId,\n        correlationId: activeContext.correlationId,\n        context: mergedContext,\n      };\n\n      emitCorrelatedEvent(activeContext, 'log.emit.manual', {\n        ...flattened,\n      });\n\n      if (options?.onEmit) {\n        Promise.resolve(options.onEmit(snapshot)).catch((error) => {\n          console.warn('[autotel] request logger onEmit failed:', error);\n        });\n      }\n\n      emitted = true;\n      lastSnapshot = snapshot;\n      return snapshot;\n    },\n\n    fork(\n      label: string,\n      fn: () => void | Promise<void>,\n      forkOptions?: ForkOptions,\n    ): void {\n      const parentRequestId = activeContext.correlationId;\n      if (typeof parentRequestId !== 'string' || parentRequestId.length === 0) {\n        throw new Error(\n          '[autotel] log.fork() requires the parent logger to have a correlationId. ' +\n            'Ensure the request was created by autotel middleware.',\n        );\n      }\n\n      const tracer = otelTrace.getTracer('autotel.request-logger');\n      const lifecycle = forkOptions?.lifecycle;\n      void tracer.startActiveSpan(`request.fork:${label}`, (childSpan) => {\n        const childContext: TraceContext = {\n          ...createTraceContext(childSpan),\n          correlationId: crypto.randomUUID(),\n        };\n\n        requestContextStore.run(childContext, () => {\n          const childLog = getRequestLogger(childContext);\n          childLog.set({\n            operation: label,\n            _parentCorrelationId: parentRequestId,\n          });\n\n          lifecycle?.onChildEnter?.(childLog);\n\n          void Promise.resolve()\n            .then(() => fn())\n            .then(() => {\n              childLog.emitNow();\n            })\n            .catch((err: unknown) => {\n              const error = err instanceof Error ? err : new Error(String(err));\n              childLog.error(error);\n              childLog.emitNow();\n            })\n            .finally(() => {\n              try {\n                lifecycle?.onChildExit?.(childLog);\n              } catch (hookError) {\n                console.warn(\n                  '[autotel] fork onChildExit hook threw:',\n                  hookError,\n                );\n              }\n              childSpan.end();\n            });\n        });\n      });\n    },\n  };\n}\n","export interface DrainOptions<TContext, TConfig, TPayload = TContext> {\n  /** Stable identifier used in error logs. */\n  name: string;\n  /** Return null to skip draining (e.g. missing API key in dev). */\n  resolve: () => TConfig | null | Promise<TConfig | null>;\n  /** Transform contexts into payloads. Defaults to identity. */\n  transform?: (contexts: TContext[]) => TPayload[];\n  /** Transport implementation. */\n  send: (payloads: TPayload[], config: TConfig) => Promise<void>;\n}\n\nexport interface HttpDrainRequest {\n  url: string;\n  headers: Record<string, string>;\n  body: string;\n}\n\nexport interface HttpDrainOptions<\n  TContext,\n  TConfig,\n  TPayload = TContext,\n> extends Omit<DrainOptions<TContext, TConfig, TPayload>, 'send'> {\n  encode: (payloads: TPayload[], config: TConfig) => HttpDrainRequest | null;\n  timeoutMs?: number;\n  retries?: number;\n  resolveTimeoutMs?: (config: TConfig) => number | undefined;\n  resolveRetries?: (config: TConfig) => number | undefined;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst DEFAULT_RETRIES = 2;\n\nfunction delay(ms: number): Promise<void> {\n  return new Promise((resolve) => {\n    const t = setTimeout(resolve, ms);\n    t.unref?.();\n  });\n}\n\nasync function postWithRetry(options: {\n  name: string;\n  request: HttpDrainRequest;\n  timeoutMs: number;\n  retries: number;\n}): Promise<void> {\n  const { name, request, timeoutMs, retries } = options;\n  const attempts = Math.max(1, retries);\n  let lastError: unknown;\n\n  for (let attempt = 1; attempt <= attempts; attempt++) {\n    const controller = new AbortController();\n    const timeout = setTimeout(() => controller.abort(), timeoutMs);\n    timeout.unref?.();\n    try {\n      const response = await fetch(request.url, {\n        method: 'POST',\n        headers: request.headers,\n        body: request.body,\n        signal: controller.signal,\n      });\n      if (!response.ok) {\n        throw new Error(\n          `[autotel/${name}] HTTP ${response.status} draining ${request.url}`,\n        );\n      }\n      return;\n    } catch (error) {\n      lastError = error;\n      if (attempt < attempts) {\n        await delay(100 * attempt);\n      }\n    } finally {\n      clearTimeout(timeout);\n    }\n  }\n\n  throw lastError;\n}\n\nexport function defineDrain<TContext, TConfig, TPayload = TContext>(\n  options: DrainOptions<TContext, TConfig, TPayload>,\n): (ctx: TContext | TContext[]) => Promise<void> {\n  return async (ctx: TContext | TContext[]) => {\n    const contexts = Array.isArray(ctx) ? ctx : [ctx];\n    if (contexts.length === 0) return;\n\n    const config = await options.resolve();\n    if (!config) return;\n\n    const payloads = options.transform\n      ? options.transform(contexts)\n      : (contexts as unknown as TPayload[]);\n\n    if (payloads.length === 0) return;\n\n    try {\n      await options.send(payloads, config);\n    } catch (error) {\n      console.error(`[autotel/${options.name}] drain failed:`, error);\n    }\n  };\n}\n\nexport function defineHttpDrain<TContext, TConfig, TPayload = TContext>(\n  options: HttpDrainOptions<TContext, TConfig, TPayload>,\n): (ctx: TContext | TContext[]) => Promise<void> {\n  return defineDrain<TContext, TConfig, TPayload>({\n    name: options.name,\n    resolve: options.resolve,\n    transform: options.transform,\n    send: async (payloads, config) => {\n      const request = options.encode(payloads, config);\n      if (!request) return;\n      const timeoutMs =\n        options.resolveTimeoutMs?.(config) ??\n        options.timeoutMs ??\n        DEFAULT_TIMEOUT_MS;\n      const retries =\n        options.resolveRetries?.(config) ?? options.retries ?? DEFAULT_RETRIES;\n\n      await postWithRetry({\n        name: options.name,\n        request,\n        timeoutMs,\n        retries,\n      });\n    },\n  });\n}\n","export interface EnrichContext<TEvent extends Record<string, unknown>> {\n  event: TEvent;\n  request?: {\n    method?: string;\n    path?: string;\n    requestId?: string;\n  };\n  response?: {\n    status?: number;\n  };\n  headers?: Record<string, string>;\n}\n\nexport interface EnricherDefinition<\n  TEvent extends Record<string, unknown>,\n  TValue extends object,\n> {\n  /** Stable identifier used in error logs. */\n  name: string;\n  /** Top-level field to merge computed values into. */\n  field: keyof TEvent & string;\n  /** Return undefined to skip enrichment. */\n  compute: (ctx: EnrichContext<TEvent>) => TValue | undefined;\n}\n\nexport interface EnricherOptions {\n  /** Replace existing field value instead of merge. Default false. */\n  overwrite?: boolean;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n  return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction mergeInto(\n  target: Record<string, unknown>,\n  source: Record<string, unknown>,\n): void {\n  for (const key in source) {\n    const sourceVal = source[key];\n    if (sourceVal === undefined) continue;\n    const targetVal = target[key];\n    if (isPlainObject(sourceVal) && isPlainObject(targetVal)) {\n      mergeInto(targetVal, sourceVal);\n    } else {\n      target[key] = sourceVal;\n    }\n  }\n}\n\nexport function defineEnricher<\n  TEvent extends Record<string, unknown>,\n  TValue extends object,\n>(\n  def: EnricherDefinition<TEvent, TValue>,\n  options: EnricherOptions = {},\n): (ctx: EnrichContext<TEvent>) => void {\n  return (ctx: EnrichContext<TEvent>) => {\n    let computed: TValue | undefined;\n    try {\n      computed = def.compute(ctx);\n    } catch (error) {\n      console.error(`[autotel/${def.name}] enrich failed:`, error);\n      return;\n    }\n\n    if (!computed) return;\n\n    if (options.overwrite || !isPlainObject(ctx.event[def.field])) {\n      (ctx.event as Record<string, unknown>)[def.field] = computed;\n      return;\n    }\n\n    mergeInto(\n      ctx.event[def.field] as unknown as Record<string, unknown>,\n      computed as unknown as Record<string, unknown>,\n    );\n  };\n}\n","/**\n * LLM-tuned histogram buckets.\n *\n * Default OpenTelemetry histogram buckets target HTTP latency (0ms–10s)\n * and small counter values. LLM workloads have very different shapes:\n *\n *   - **Duration**: single-token prompts can be fast (50ms), long\n *     generations and reasoning models can run for minutes. Default buckets\n *     crush everything above 10s into one bucket.\n *   - **Token usage**: heavily right-skewed. A single request can range\n *     from tens of tokens to the million-token context windows.\n *   - **Cost (USD)**: per-request values are tiny (fractions of a cent),\n *     so linear buckets waste resolution at the low end.\n *\n * This module exposes empirically-chosen bucket arrays and a View helper\n * so users can apply them to their `MeterProvider` without knowing the\n * exact instrument names emitted by OpenAI/Anthropic/Traceloop plugins.\n *\n * @example\n * ```typescript\n * import { NodeSDK } from '@opentelemetry/sdk-node';\n * import { genAiMetricViews } from 'autotel';\n *\n * const sdk = new NodeSDK({\n *   serviceName: 'my-agent',\n *   views: [...genAiMetricViews()],\n * });\n * sdk.start();\n * ```\n */\n\nimport { AggregationType, type ViewOptions } from '@opentelemetry/sdk-metrics';\n\n/**\n * Duration buckets for LLM operations, in **seconds**. Covers fast\n * completions (50ms) through long-running reasoning jobs (5 min).\n *\n * Aligns with the OTel GenAI semantic conventions' published advice for\n * `gen_ai.client.operation.duration`.\n */\nexport const GEN_AI_DURATION_BUCKETS_SECONDS: readonly number[] = Object.freeze(\n  [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 20, 30, 60, 120, 300],\n);\n\n/**\n * Token-count buckets for prompt, completion, and total token histograms.\n * Ranges from tiny prompts to million-token context windows.\n *\n * Aligns with the OTel GenAI semantic conventions' published advice for\n * `gen_ai.client.token.usage`.\n */\nexport const GEN_AI_TOKEN_USAGE_BUCKETS: readonly number[] = Object.freeze([\n  1, 4, 16, 64, 256, 1_024, 4_096, 16_384, 65_536, 262_144, 1_048_576,\n  4_194_304,\n]);\n\n/**\n * USD cost buckets. Sub-cent resolution at the low end (fractions of a\n * cent per small call) up to tens of dollars (batch jobs, Opus/o1 runs).\n */\nexport const GEN_AI_COST_USD_BUCKETS: readonly number[] = Object.freeze([\n  0.000_01, 0.000_1, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10, 50,\n]);\n\n/**\n * Instrument-level advice object for `createHistogram(name, advice)`.\n * Use when you control the instrument creation (e.g. custom business\n * LLM metrics); `genAiMetricViews()` is better when the metric comes\n * from a third-party plugin.\n */\nexport function llmHistogramAdvice(kind: 'duration' | 'tokens' | 'cost'): {\n  advice: { explicitBucketBoundaries: number[] };\n} {\n  const boundaries =\n    kind === 'duration'\n      ? GEN_AI_DURATION_BUCKETS_SECONDS\n      : kind === 'tokens'\n        ? GEN_AI_TOKEN_USAGE_BUCKETS\n        : GEN_AI_COST_USD_BUCKETS;\n  return { advice: { explicitBucketBoundaries: [...boundaries] } };\n}\n\n/**\n * Returns `View`s that re-bucket the standard OTel GenAI histograms. Pass\n * the result to your `MeterProvider`'s `views` option.\n *\n * Matches instrument names emitted by:\n * - OpenTelemetry GenAI autoinstrumentation\n * - OpenInference / OpenLLMetry (traceloop)\n * - Arize Phoenix, LangSmith, etc. that follow the OTel spec\n *\n * Add more instrument patterns via the `extra` argument if you emit\n * custom LLM metrics.\n */\nexport function genAiMetricViews(\n  extra: {\n    instrumentName: string;\n    kind: 'duration' | 'tokens' | 'cost';\n  }[] = [],\n): ViewOptions[] {\n  const defaults: Array<{\n    instrumentName: string;\n    kind: 'duration' | 'tokens' | 'cost';\n  }> = [\n    { instrumentName: 'gen_ai.client.operation.duration', kind: 'duration' },\n    { instrumentName: 'gen_ai.client.token.usage', kind: 'tokens' },\n    // Autotel-emitted cost metric. No-op if you don't emit it.\n    { instrumentName: 'gen_ai.client.cost.usd', kind: 'cost' },\n  ];\n\n  return [...defaults, ...extra].map(\n    ({ instrumentName, kind }) =>\n      ({\n        instrumentName,\n        aggregation: {\n          type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM,\n          options: {\n            boundaries:\n              kind === 'duration'\n                ? [...GEN_AI_DURATION_BUCKETS_SECONDS]\n                : kind === 'tokens'\n                  ? [...GEN_AI_TOKEN_USAGE_BUCKETS]\n                  : [...GEN_AI_COST_USD_BUCKETS],\n          },\n        },\n      }) satisfies ViewOptions,\n  );\n}\n","/**\n * Span event helpers for LLM lifecycle, aligned with the OpenTelemetry\n * GenAI semantic conventions.\n *\n * Span events are timestamped points within a span — they render as dots\n * on the trace timeline in Jaeger / Tempo / Langfuse / Arize. Use them\n * to mark lifecycle moments the span attributes alone can't express:\n *\n *   - When the prompt was sent (vs. when the first token arrived)\n *   - When each retry attempt started, and why\n *   - When a streaming response produced its first token (TTFT)\n *   - When a tool was invoked\n *\n * Every helper pins the event name + attribute keys to the published\n * spec so downstream tooling (autotel-mcp, Langfuse, vendor UIs) can\n * render them consistently.\n *\n * @example\n * ```typescript\n * import { trace, recordPromptSent, recordResponseReceived, recordRetry } from 'autotel';\n *\n * export const chat = trace('chat', ctx => async (prompt: string) => {\n *   recordPromptSent(ctx, { model: 'gpt-4o', messageCount: 1 });\n *\n *   for (let attempt = 1; attempt <= 3; attempt++) {\n *     try {\n *       const res = await openai.chat.completions.create({...});\n *       recordResponseReceived(ctx, {\n *         model: res.model,\n *         promptTokens: res.usage?.prompt_tokens,\n *         completionTokens: res.usage?.completion_tokens,\n *         finishReasons: res.choices.map(c => c.finish_reason),\n *       });\n *       return res;\n *     } catch (err) {\n *       recordRetry(ctx, { attempt, reason: 'rate_limit', delayMs: 500 });\n *       await sleep(500 * attempt);\n *     }\n *   }\n * });\n * ```\n */\n\nimport type { TraceContext } from './trace-context';\nimport { emitCorrelatedEvent } from './correlated-events';\n\ntype EventAttrs = Record<string, string | number | boolean>;\n\n/** Attributes expected on a `gen_ai.prompt.sent` event. */\nexport interface PromptSentEvent {\n  /** Model the caller intends to invoke (may differ from response model). */\n  model?: string;\n  /** Estimated input token count, when known before the call. */\n  promptTokens?: number;\n  /** Number of messages in a chat request (system + user + assistant). */\n  messageCount?: number;\n  /** Free-form operation kind — `chat` / `completion` / `embedding`. */\n  operation?: string;\n}\n\n/** Attributes expected on a `gen_ai.response.received` event. */\nexport interface ResponseReceivedEvent {\n  /** Model the provider actually served (may be more specific than requested). */\n  model?: string;\n  promptTokens?: number;\n  completionTokens?: number;\n  totalTokens?: number;\n  /** `stop`, `length`, `content_filter`, `tool_calls`, etc. */\n  finishReasons?: string[];\n}\n\n/** Attributes expected on a `gen_ai.retry` event. */\nexport interface RetryEvent {\n  attempt: number;\n  /** `rate_limit` | `timeout` | `provider_error` | custom label. */\n  reason?: string;\n  /** How long we'll wait before the next attempt. */\n  delayMs?: number;\n  /** HTTP status that triggered the retry, when applicable. */\n  statusCode?: number;\n}\n\n/** Attributes expected on a `gen_ai.tool.call` event. */\nexport interface ToolCallEvent {\n  toolName: string;\n  /** Call identifier so responses can be correlated back to calls. */\n  toolCallId?: string;\n  /** Pre-serialised tool arguments; omit if sensitive. */\n  arguments?: string;\n}\n\n/** Attributes expected on a `gen_ai.stream.first_token` event. */\nexport interface StreamFirstTokenEvent {\n  /** Tokens streamed so far, if the caller tracks that. */\n  tokensSoFar?: number;\n}\n\n/**\n * Record that a prompt was dispatched to the provider. Typically called\n * before `await provider.chat.completions.create(...)`.\n */\nexport function recordPromptSent(\n  ctx: TraceContext,\n  event: PromptSentEvent = {},\n): void {\n  emitCorrelatedEvent(ctx, 'gen_ai.prompt.sent', buildPromptSentAttrs(event));\n}\n\n/**\n * Record a successful provider response. Call after the response arrives\n * (for non-streaming) or after the stream completes.\n */\nexport function recordResponseReceived(\n  ctx: TraceContext,\n  event: ResponseReceivedEvent = {},\n): void {\n  emitCorrelatedEvent(\n    ctx,\n    'gen_ai.response.received',\n    buildResponseAttrs(event),\n  );\n}\n\n/**\n * Record a retry attempt on an LLM call. Call *before* sleeping for\n * `delayMs` so the event timestamp accurately marks when the retry\n * decision was made.\n */\nexport function recordRetry(ctx: TraceContext, event: RetryEvent): void {\n  emitCorrelatedEvent(ctx, 'gen_ai.retry', buildRetryAttrs(event));\n}\n\n/**\n * Record a tool / function call made in the course of an agent step.\n * Emits an event rather than a child span because many frameworks fire\n * several tool calls within a single provider response.\n */\nexport function recordToolCall(ctx: TraceContext, event: ToolCallEvent): void {\n  emitCorrelatedEvent(ctx, 'gen_ai.tool.call', buildToolCallAttrs(event));\n}\n\n/**\n * Record the time-to-first-token for a streaming response. Pair with\n * `recordResponseReceived` at the end so the span carries both the TTFT\n * marker and the final usage numbers.\n */\nexport function recordStreamFirstToken(\n  ctx: TraceContext,\n  event: StreamFirstTokenEvent = {},\n): void {\n  emitCorrelatedEvent(\n    ctx,\n    'gen_ai.stream.first_token',\n    buildStreamFirstTokenAttrs(event),\n  );\n}\n\n// ---- Attribute builders -------------------------------------------------\n\nfunction buildPromptSentAttrs(event: PromptSentEvent): EventAttrs {\n  const attrs: EventAttrs = {};\n  if (event.model) attrs['gen_ai.request.model'] = event.model;\n  if (event.promptTokens !== undefined)\n    attrs['gen_ai.usage.input_tokens'] = event.promptTokens;\n  if (event.messageCount !== undefined)\n    attrs['gen_ai.request.message_count'] = event.messageCount;\n  if (event.operation) attrs['gen_ai.operation.name'] = event.operation;\n  return attrs;\n}\n\nfunction buildResponseAttrs(event: ResponseReceivedEvent): EventAttrs {\n  const attrs: EventAttrs = {};\n  if (event.model) attrs['gen_ai.response.model'] = event.model;\n  if (event.promptTokens !== undefined)\n    attrs['gen_ai.usage.input_tokens'] = event.promptTokens;\n  if (event.completionTokens !== undefined)\n    attrs['gen_ai.usage.output_tokens'] = event.completionTokens;\n  if (event.totalTokens !== undefined)\n    attrs['gen_ai.usage.total_tokens'] = event.totalTokens;\n  if (event.finishReasons && event.finishReasons.length > 0) {\n    // Arrays aren't primitive AttributeValues on this context, so join.\n    attrs['gen_ai.response.finish_reasons'] = event.finishReasons.join(',');\n  }\n  return attrs;\n}\n\nfunction buildRetryAttrs(event: RetryEvent): EventAttrs {\n  const attrs: EventAttrs = { 'retry.attempt': event.attempt };\n  if (event.reason) attrs['retry.reason'] = event.reason;\n  if (event.delayMs !== undefined) attrs['retry.delay_ms'] = event.delayMs;\n  if (event.statusCode !== undefined)\n    attrs['http.response.status_code'] = event.statusCode;\n  return attrs;\n}\n\nfunction buildToolCallAttrs(event: ToolCallEvent): EventAttrs {\n  const attrs: EventAttrs = { 'gen_ai.tool.name': event.toolName };\n  if (event.toolCallId) attrs['gen_ai.tool.call.id'] = event.toolCallId;\n  if (event.arguments) attrs['gen_ai.tool.arguments'] = event.arguments;\n  return attrs;\n}\n\nfunction buildStreamFirstTokenAttrs(event: StreamFirstTokenEvent): EventAttrs {\n  const attrs: EventAttrs = {};\n  if (event.tokensSoFar !== undefined)\n    attrs['gen_ai.stream.tokens_so_far'] = event.tokensSoFar;\n  return attrs;\n}\n"]}