{"version":3,"file":"init-BXiuPK6j.cjs","names":["safeRequire","propagation","otelContext","requireModule","REDACTOR_PRESETS","AlwaysOnSampler","AlwaysOffSampler","TraceIdRatioBasedSampler","ParentBasedSampler","SamplingDecision","requireModule","OTLPTraceExporterHTTP","OTLPMetricExporterHTTP","OTLPLogExporterHTTP","safeRequire","loadYamlConfig","normalizeAttributeRedactorConfig","ATTR_SERVICE_NAME","ATTR_SERVICE_VERSION","TailSamplingSpanProcessor","BatchSpanProcessor","SimpleSpanProcessor","PrettyConsoleExporter","ConsoleSpanExporter","CanonicalLogLineProcessor","AttributeRedactingProcessor","SpanNameNormalizingProcessor","FilteringSpanProcessor","PeriodicExportingMetricReader","BatchLogRecordProcessor","resolveSamplingPreset","samplingPresets","NodeSDK"],"sources":["../src/posthog-logs.ts","../src/baggage-span-processor.ts","../src/redact-values.ts","../src/env-config.ts","../src/devtools.ts","../src/init.ts"],"sourcesContent":["import type { LogRecordProcessor } from '@opentelemetry/sdk-logs';\nimport { safeRequire } from './node-require';\nimport type { StringRedactor } from './redact-values';\n\nexport class RedactingLogRecordProcessor implements LogRecordProcessor {\n  constructor(\n    private wrapped: LogRecordProcessor,\n    private redact: StringRedactor,\n  ) {}\n\n  onEmit(logRecord: any, context?: any): void {\n    if (logRecord.body && typeof logRecord.body === 'string') {\n      logRecord.body = this.redact(logRecord.body);\n    }\n    if (logRecord.attributes) {\n      for (const [key, value] of Object.entries(logRecord.attributes)) {\n        if (typeof value === 'string') {\n          logRecord.attributes[key] = this.redact(value);\n        } else if (Array.isArray(value)) {\n          logRecord.attributes[key] = value.map((item: unknown) =>\n            typeof item === 'string' ? this.redact(item) : item,\n          );\n        }\n      }\n    }\n    this.wrapped.onEmit(logRecord, context);\n  }\n\n  shutdown(): Promise<void> {\n    return this.wrapped.shutdown();\n  }\n\n  forceFlush(): Promise<void> {\n    return this.wrapped.forceFlush();\n  }\n}\n\nexport interface PostHogConfig {\n  /** OTLP logs endpoint URL (e.g., https://us.i.posthog.com/i/v1/logs?token=phc_xxx) */\n  url: string;\n}\n\n/**\n * Build log record processors for PostHog OTLP logs integration.\n *\n * Resolution order:\n * 1. config.url if provided\n * 2. POSTHOG_LOGS_URL env var\n * 3. Empty array (disabled)\n */\nexport function buildPostHogLogProcessors(\n  config: PostHogConfig | undefined,\n  stringRedactor?: StringRedactor | null,\n): LogRecordProcessor[] {\n  const url = config?.url || process.env.POSTHOG_LOGS_URL;\n  if (!url) return [];\n\n  const sdkLogs = safeRequire<{\n    BatchLogRecordProcessor: new (exporter: unknown) => LogRecordProcessor;\n  }>('@opentelemetry/sdk-logs');\n\n  const exporterModule = safeRequire<{\n    OTLPLogExporter: new (config: { url: string }) => unknown;\n  }>('@opentelemetry/exporter-logs-otlp-http');\n\n  if (!sdkLogs || !exporterModule) return [];\n\n  const exporter = new exporterModule.OTLPLogExporter({ url });\n  let processor: LogRecordProcessor = new sdkLogs.BatchLogRecordProcessor(\n    exporter,\n  );\n  if (stringRedactor) {\n    processor = new RedactingLogRecordProcessor(processor, stringRedactor);\n  }\n\n  return [processor];\n}\n","/**\n * Span processor that copies baggage entries to span attributes\n *\n * This makes baggage visible in trace UIs without manual attribute setting.\n * Enabled via init({ baggage: true }) or init({ baggage: 'custom-prefix' })\n */\n\nimport type { Span, Context } from '@opentelemetry/api';\nimport { propagation, context as otelContext } from '@opentelemetry/api';\nimport type { SpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport type { ReadableSpan } from '@opentelemetry/sdk-trace-base';\nimport { requireModule } from './node-require';\n\nexport interface BaggageSpanProcessorOptions {\n  /**\n   * Prefix for baggage attributes\n   * @default 'baggage.'\n   */\n  prefix?: string;\n}\n\n/**\n * Span processor that automatically copies baggage entries to span attributes\n *\n * This makes baggage visible in trace UIs (Jaeger, Grafana, DataDog, etc.)\n * without manually calling ctx.setAttribute() for each baggage entry.\n *\n * @example Enable in init()\n * ```typescript\n * init({\n *   service: 'my-app',\n *   baggage: true // Uses default 'baggage.' prefix\n * });\n *\n * // Now baggage automatically appears as span attributes\n * await withBaggage({\n *   baggage: { 'tenant.id': 't1', 'user.id': 'u1' },\n *   fn: async () => {\n *     // Span has baggage.tenant.id and baggage.user.id attributes!\n *   }\n * });\n * ```\n *\n * @example Custom prefix\n * ```typescript\n * init({\n *   service: 'my-app',\n *   baggage: 'ctx' // Uses 'ctx.' prefix\n * });\n * // Creates attributes: ctx.tenant.id, ctx.user.id\n * ```\n */\nexport class BaggageSpanProcessor implements SpanProcessor {\n  private readonly prefix: string;\n\n  constructor(options: BaggageSpanProcessorOptions = {}) {\n    this.prefix = options.prefix ?? 'baggage.';\n  }\n\n  onStart(span: Span, parentContext: Context): void {\n    // Read baggage from parentContext first (spans created with explicit context)\n    // Then fall back to active context (spans created without explicit context)\n    // Also check getActiveContextWithBaggage() to see baggage set via ctx.setBaggage()\n    let baggage = propagation.getBaggage(parentContext);\n    if (!baggage) {\n      baggage = propagation.getBaggage(otelContext.active());\n    }\n    // Check stored context from ctx.setBaggage() if still no baggage\n    if (!baggage) {\n      try {\n        const { getActiveContextWithBaggage } = requireModule<{\n          getActiveContextWithBaggage: () => Context;\n        }>('./trace-context');\n        const storedContext = getActiveContextWithBaggage();\n        baggage = propagation.getBaggage(storedContext);\n      } catch {\n        // Fallback if trace-context isn't available\n      }\n    }\n    if (!baggage) return;\n\n    // Copy all baggage entries to span attributes\n    for (const [key, entry] of baggage.getAllEntries()) {\n      span.setAttribute(`${this.prefix}${key}`, entry.value);\n    }\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  onEnd(_span: ReadableSpan): void {\n    // No-op - required by SpanProcessor interface\n  }\n\n  async shutdown(): Promise<void> {\n    // No-op\n  }\n\n  async forceFlush(): Promise<void> {\n    // No-op\n  }\n}\n","/** Standalone string redaction for use outside the span processor pipeline. */\n\nimport {\n  REDACTOR_PRESETS,\n  type AttributeRedactorConfig,\n  type AttributeRedactorPreset,\n  type ValuePatternConfig,\n} from './attribute-redacting-processor';\n\nexport type StringRedactor = (value: string) => string;\nexport function createStringRedactor(\n  config: AttributeRedactorConfig | AttributeRedactorPreset,\n): StringRedactor {\n  const resolved =\n    typeof config === 'string' ? REDACTOR_PRESETS[config] : config;\n  const valuePatterns: ValuePatternConfig[] = resolved.valuePatterns ?? [];\n  const defaultReplacement = resolved.replacement ?? '[REDACTED]';\n\n  return (value: string): string => {\n    let result = value;\n    for (const { pattern, replacement, mask } of valuePatterns) {\n      pattern.lastIndex = 0;\n      // Smart masks (e.g. email → a***@***.com) take precedence over the\n      // static replacement so callers see the same output as the\n      // span-attribute redactor does.\n      if (mask) {\n        result = result.replaceAll(pattern, (match) => mask(match));\n      } else {\n        result = result.replaceAll(pattern, replacement ?? defaultReplacement);\n      }\n    }\n    return result;\n  };\n}\n","/**\n * Standard OpenTelemetry environment variables\n */\nimport type { Sampler as OtelSampler } from '@opentelemetry/sdk-trace-base';\nimport {\n  AlwaysOffSampler,\n  AlwaysOnSampler,\n  ParentBasedSampler,\n  TraceIdRatioBasedSampler,\n} from '@opentelemetry/sdk-trace-base';\n\nexport interface OtelEnvVars {\n  OTEL_SERVICE_NAME?: string;\n  OTEL_EXPORTER_OTLP_ENDPOINT?: string;\n  OTEL_EXPORTER_OTLP_HEADERS?: string;\n  OTEL_RESOURCE_ATTRIBUTES?: string;\n  OTEL_EXPORTER_OTLP_PROTOCOL?: 'http' | 'grpc';\n  OTEL_TRACES_SAMPLER?: string;\n  OTEL_TRACES_SAMPLER_ARG?: string;\n}\n\n/**\n * Parsed resource attributes as key-value pairs\n */\nexport interface ResourceAttributes {\n  [key: string]: string;\n}\n\n/**\n * Parsed OTLP headers as key-value pairs\n */\nexport interface OtlpHeaders {\n  [key: string]: string;\n}\n\n/**\n * Environment-resolved configuration (subset of AutotelConfig)\n * Defined locally to avoid circular dependency with init.ts\n */\nexport interface EnvConfig {\n  service?: string;\n  endpoint?: string;\n  protocol?: 'http' | 'grpc';\n  headers?: Record<string, string>;\n  resourceAttributes?: Record<string, string>;\n  otelSampler?: OtelSampler;\n}\n\n/**\n * Validate URL format\n */\nfunction isValidUrl(urlString: string): boolean {\n  try {\n    const url = new URL(urlString);\n    return url.protocol === 'http:' || url.protocol === 'https:';\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Resolve OpenTelemetry environment variables from process.env\n */\nexport function resolveOtelEnv(): OtelEnvVars {\n  const env: OtelEnvVars = {};\n\n  // OTEL_SERVICE_NAME - optional string\n  if (process.env.OTEL_SERVICE_NAME) {\n    const value = process.env.OTEL_SERVICE_NAME.trim();\n    if (value) {\n      env.OTEL_SERVICE_NAME = value;\n    }\n  }\n\n  // OTEL_EXPORTER_OTLP_ENDPOINT - optional URL\n  if (process.env.OTEL_EXPORTER_OTLP_ENDPOINT) {\n    const value = process.env.OTEL_EXPORTER_OTLP_ENDPOINT.trim();\n    if (value && isValidUrl(value)) {\n      env.OTEL_EXPORTER_OTLP_ENDPOINT = value;\n    }\n  }\n\n  // OTEL_EXPORTER_OTLP_HEADERS - optional string\n  if (process.env.OTEL_EXPORTER_OTLP_HEADERS) {\n    const value = process.env.OTEL_EXPORTER_OTLP_HEADERS.trim();\n    if (value) {\n      env.OTEL_EXPORTER_OTLP_HEADERS = value;\n    }\n  }\n\n  // OTEL_RESOURCE_ATTRIBUTES - optional string\n  if (process.env.OTEL_RESOURCE_ATTRIBUTES) {\n    const value = process.env.OTEL_RESOURCE_ATTRIBUTES.trim();\n    if (value) {\n      env.OTEL_RESOURCE_ATTRIBUTES = value;\n    }\n  }\n\n  // OTEL_EXPORTER_OTLP_PROTOCOL - optional enum ('http' | 'grpc')\n  if (process.env.OTEL_EXPORTER_OTLP_PROTOCOL) {\n    const value = process.env.OTEL_EXPORTER_OTLP_PROTOCOL.trim().toLowerCase();\n    if (value === 'http' || value === 'grpc') {\n      env.OTEL_EXPORTER_OTLP_PROTOCOL = value;\n    }\n  }\n\n  if (process.env.OTEL_TRACES_SAMPLER) {\n    const value = process.env.OTEL_TRACES_SAMPLER.trim();\n    if (value) {\n      env.OTEL_TRACES_SAMPLER = value;\n    }\n  }\n\n  if (process.env.OTEL_TRACES_SAMPLER_ARG) {\n    const value = process.env.OTEL_TRACES_SAMPLER_ARG.trim();\n    if (value) {\n      env.OTEL_TRACES_SAMPLER_ARG = value;\n    }\n  }\n\n  return env;\n}\n\nfunction parseRatioSamplerArg(\n  samplerName: string,\n  samplerArg: string | undefined,\n): number {\n  if (samplerArg === undefined) {\n    return 1.0;\n  }\n\n  const ratio = Number(samplerArg);\n  if (!Number.isFinite(ratio) || ratio < 0 || ratio > 1) {\n    console.error(\n      `[autotel] Invalid OTEL_TRACES_SAMPLER_ARG=\"${samplerArg}\" for ${samplerName}. Expected a number in [0..1]. Falling back to 1.0.`,\n    );\n    return 1.0;\n  }\n\n  return ratio;\n}\n\nfunction warnOnUnusedSamplerArg(\n  samplerName: string,\n  samplerArg: string | undefined,\n): void {\n  if (samplerArg !== undefined) {\n    console.error(\n      `[autotel] OTEL_TRACES_SAMPLER_ARG is not used by OTEL_TRACES_SAMPLER=\"${samplerName}\". Ignoring value \"${samplerArg}\".`,\n    );\n  }\n}\n\nexport function createSamplerFromEnv(\n  env: Pick<OtelEnvVars, 'OTEL_TRACES_SAMPLER' | 'OTEL_TRACES_SAMPLER_ARG'>,\n): OtelSampler | undefined {\n  const samplerName = env.OTEL_TRACES_SAMPLER;\n  if (!samplerName) {\n    return undefined;\n  }\n\n  switch (samplerName) {\n    case 'always_on':\n      warnOnUnusedSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG);\n      return new AlwaysOnSampler();\n    case 'always_off':\n      warnOnUnusedSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG);\n      return new AlwaysOffSampler();\n    case 'traceidratio':\n      return new TraceIdRatioBasedSampler(\n        parseRatioSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG),\n      );\n    case 'parentbased_always_on':\n      warnOnUnusedSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG);\n      return new ParentBasedSampler({ root: new AlwaysOnSampler() });\n    case 'parentbased_always_off':\n      warnOnUnusedSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG);\n      return new ParentBasedSampler({ root: new AlwaysOffSampler() });\n    case 'parentbased_traceidratio':\n      return new ParentBasedSampler({\n        root: new TraceIdRatioBasedSampler(\n          parseRatioSamplerArg(samplerName, env.OTEL_TRACES_SAMPLER_ARG),\n        ),\n      });\n    case 'jaeger_remote':\n    case 'parentbased_jaeger_remote':\n    case 'xray':\n      console.error(\n        `[autotel] OTEL_TRACES_SAMPLER=\"${samplerName}\" is not supported yet by autotel. Falling back to the next sampler source.`,\n      );\n      return undefined;\n    default:\n      console.error(\n        `[autotel] Unknown OTEL_TRACES_SAMPLER=\"${samplerName}\". Falling back to the next sampler source.`,\n      );\n      return undefined;\n  }\n}\n\n/**\n * Parse OTEL_RESOURCE_ATTRIBUTES from comma-separated key=value pairs\n * Example: \"service.version=1.0.0,deployment.environment=production\"\n */\nexport function parseResourceAttributes(\n  input: string | undefined,\n): ResourceAttributes {\n  if (!input || input.trim() === '') {\n    return {};\n  }\n\n  const attributes: ResourceAttributes = {};\n  const pairs = input.split(',');\n\n  for (const pair of pairs) {\n    const trimmedPair = pair.trim();\n    if (!trimmedPair) continue;\n\n    const equalIndex = trimmedPair.indexOf('=');\n    if (equalIndex === -1) {\n      // Invalid format, skip this pair\n      continue;\n    }\n\n    const key = trimmedPair.slice(0, equalIndex).trim();\n    const value = trimmedPair.slice(equalIndex + 1).trim();\n\n    if (key && value) {\n      attributes[key] = value;\n    }\n  }\n\n  return attributes;\n}\n\n/**\n * Parse OTEL_EXPORTER_OTLP_HEADERS from comma-separated key=value pairs\n * Example: \"api-key=secret123,x-custom-header=value\"\n */\nexport function parseOtlpHeaders(input: string | undefined): OtlpHeaders {\n  if (!input || input.trim() === '') {\n    return {};\n  }\n\n  const headers: OtlpHeaders = {};\n  const pairs = input.split(',');\n\n  for (const pair of pairs) {\n    const trimmedPair = pair.trim();\n    if (!trimmedPair) continue;\n\n    const equalIndex = trimmedPair.indexOf('=');\n    if (equalIndex === -1) {\n      // Invalid format, skip this pair\n      continue;\n    }\n\n    const key = trimmedPair.slice(0, equalIndex).trim();\n    const value = trimmedPair.slice(equalIndex + 1).trim();\n\n    if (key && value) {\n      headers[key] = value;\n    }\n  }\n\n  return headers;\n}\n\n/**\n * Convert resolved environment variables to config\n */\nexport function envToConfig(env: OtelEnvVars): EnvConfig {\n  const config: EnvConfig = {};\n\n  if (env.OTEL_SERVICE_NAME) {\n    config.service = env.OTEL_SERVICE_NAME;\n  }\n\n  if (env.OTEL_EXPORTER_OTLP_ENDPOINT) {\n    config.endpoint = env.OTEL_EXPORTER_OTLP_ENDPOINT;\n  }\n\n  if (env.OTEL_EXPORTER_OTLP_PROTOCOL) {\n    config.protocol = env.OTEL_EXPORTER_OTLP_PROTOCOL;\n  }\n\n  if (env.OTEL_EXPORTER_OTLP_HEADERS) {\n    config.headers = parseOtlpHeaders(env.OTEL_EXPORTER_OTLP_HEADERS);\n  }\n\n  const resourceAttrs = parseResourceAttributes(env.OTEL_RESOURCE_ATTRIBUTES);\n  if (Object.keys(resourceAttrs).length > 0) {\n    config.resourceAttributes = resourceAttrs;\n  }\n\n  const sampler = createSamplerFromEnv(env);\n  if (sampler) {\n    config.otelSampler = sampler;\n  }\n\n  return config;\n}\n\n/**\n * Main function to resolve config from environment variables\n */\nexport function resolveConfigFromEnv(): EnvConfig {\n  const env = resolveOtelEnv();\n  return envToConfig(env);\n}\n","export interface AutotelDevtoolsConfig {\n  enabled?: boolean;\n  endpoint?: string;\n  embedded?: boolean;\n  host?: string;\n  port?: number;\n  verbose?: boolean;\n}\n\nexport interface ResolvedAutotelDevtoolsConfig {\n  enabled: boolean;\n  endpoint?: string;\n  embedded: boolean;\n  host: string;\n  port: number;\n  verbose: boolean;\n}\n\nconst defaultHost = '127.0.0.1';\nconst defaultPort = 4318;\n\nexport function resolveDevtoolsConfig(\n  config: boolean | AutotelDevtoolsConfig | undefined,\n): ResolvedAutotelDevtoolsConfig {\n  if (!config) {\n    return {\n      enabled: false,\n      endpoint: undefined,\n      embedded: false,\n      host: defaultHost,\n      port: defaultPort,\n      verbose: false,\n    };\n  }\n\n  if (config === true) {\n    return {\n      enabled: true,\n      endpoint: `http://${defaultHost}:${defaultPort}`,\n      embedded: false,\n      host: defaultHost,\n      port: defaultPort,\n      verbose: false,\n    };\n  }\n\n  const enabled = config.enabled ?? true;\n  const host = config.host ?? defaultHost;\n  const port = config.port ?? defaultPort;\n  const endpoint = config.endpoint ?? `http://${host}:${port}`;\n\n  return {\n    enabled,\n    endpoint: enabled ? endpoint : undefined,\n    embedded: enabled && (config.embedded ?? false),\n    host,\n    port,\n    verbose: config.verbose ?? false,\n  };\n}\n","/**\n * Simplified initialization for autotel\n *\n * Single init() function with sensible defaults.\n * Replaces initInstrumentation() and separate events config.\n */\n\nimport { NodeSDK } from '@opentelemetry/sdk-node';\nimport type { NodeSDKConfiguration } from '@opentelemetry/sdk-node';\nimport {\n  BatchSpanProcessor,\n  type SpanProcessor,\n  SimpleSpanProcessor,\n  ConsoleSpanExporter,\n  SamplingDecision,\n  type SpanExporter,\n  type Sampler as OtelSampler,\n  type SamplingResult,\n} from '@opentelemetry/sdk-trace-base';\nimport {\n  resourceFromAttributes,\n  type Resource,\n} from '@opentelemetry/resources';\nimport {\n  ATTR_SERVICE_NAME,\n  ATTR_SERVICE_VERSION,\n} from '@opentelemetry/semantic-conventions';\nimport type { Sampler, SamplingPreset } from './sampling';\nimport { samplingPresets, resolveSamplingPreset } from './sampling';\nimport type { EventSubscriber } from './event-subscriber';\nimport type { Logger } from './logger';\nimport type { Attributes, Context, SpanKind, Link } from '@opentelemetry/api';\nimport type { ValidationConfig } from './validation';\nimport {\n  PeriodicExportingMetricReader,\n  type MetricReader,\n} from '@opentelemetry/sdk-metrics';\nimport { OTLPMetricExporter as OTLPMetricExporterHTTP } from '@opentelemetry/exporter-metrics-otlp-http';\nimport { OTLPTraceExporter as OTLPTraceExporterHTTP } from '@opentelemetry/exporter-trace-otlp-http';\nimport { OTLPLogExporter as OTLPLogExporterHTTP } from '@opentelemetry/exporter-logs-otlp-http';\nimport type { PushMetricExporter } from '@opentelemetry/sdk-metrics';\nimport {\n  BatchLogRecordProcessor,\n  type LogRecordExporter,\n  type LogRecordProcessor,\n} from '@opentelemetry/sdk-logs';\nimport {\n  buildPostHogLogProcessors,\n  RedactingLogRecordProcessor,\n} from './posthog-logs';\nimport { TailSamplingSpanProcessor } from './tail-sampling-processor';\nimport { BaggageSpanProcessor } from './baggage-span-processor';\nimport {\n  FilteringSpanProcessor,\n  type SpanFilterPredicate,\n} from './filtering-span-processor';\nimport {\n  SpanNameNormalizingProcessor,\n  type SpanNameNormalizerConfig,\n} from './span-name-normalizer';\nimport {\n  AttributeRedactingProcessor,\n  normalizeAttributeRedactorConfig,\n  type AttributeRedactorConfig,\n  type AttributeRedactorPreset,\n} from './attribute-redacting-processor';\nimport { createStringRedactor, type StringRedactor } from './redact-values';\nimport { PrettyConsoleExporter } from './pretty-console-exporter';\nimport { resolveConfigFromEnv } from './env-config';\nimport { loadYamlConfig } from './yaml-config';\nimport { requireModule, safeRequire } from './node-require';\nimport {\n  CanonicalLogLineProcessor,\n  type CanonicalLogLineOptions,\n} from './processors/canonical-log-line-processor';\nimport type { EventsConfig } from './events-config';\nimport { resolveDevtoolsConfig, type AutotelDevtoolsConfig } from './devtools';\n\n/**\n * Silent logger (no-op) - used as default when user doesn't provide one.\n * Internal autotel logs are silent by default to avoid spam.\n * Users can import { autotelLogger } from 'autotel/logger' to create their own.\n */\nconst silentLogger: Logger = {\n  info: () => {},\n  warn: () => {},\n  error: () => {},\n  debug: () => {},\n};\n\n/**\n * Adapts an Autotel Sampler to the OTel SDK Sampler interface.\n */\nfunction toOtelSampler(sampler: Sampler): OtelSampler {\n  return {\n    shouldSample(\n      _context: Context,\n      _traceId: string,\n      spanName: string,\n      _spanKind: SpanKind,\n      _attributes: Attributes,\n      links: Link[],\n    ): SamplingResult {\n      const shouldTrace = sampler.shouldSample({\n        operationName: spanName,\n        args: [],\n        links,\n      });\n      return {\n        decision: shouldTrace\n          ? SamplingDecision.RECORD_AND_SAMPLED\n          : SamplingDecision.NOT_RECORD,\n      };\n    },\n    toString(): string {\n      return `AutotelSamplerAdapter`;\n    },\n  };\n}\n\n// Type imports for exporters\ntype OTLPExporterConfig = {\n  url?: string;\n  headers?: Record<string, string>;\n  timeoutMillis?: number;\n  concurrencyLimit?: number;\n};\n\nexport type OtlpSignal = 'traces' | 'metrics' | 'logs';\n\nexport interface OtlpDestinationConfig {\n  /**\n   * Base OTLP endpoint for this destination.\n   * HTTP destinations may omit `/v1/{signal}`; autotel appends it automatically.\n   * gRPC destinations should point at the collector host:port.\n   */\n  endpoint: string;\n\n  /**\n   * Headers for this destination. Falls back to top-level `headers`.\n   */\n  headers?: Record<string, string> | string;\n\n  /**\n   * Protocol for this destination. Falls back to top-level `protocol`.\n   */\n  protocol?: 'http' | 'grpc';\n\n  /**\n   * Signals to send to this destination.\n   * Defaults to all signals supported by the current init() config.\n   */\n  signals?: OtlpSignal[];\n}\n\n// Lazy-load gRPC exporters (optional peer dependencies)\nlet OTLPTraceExporterGRPC:\n  | (new (config: OTLPExporterConfig) => SpanExporter)\n  | undefined;\nlet OTLPMetricExporterGRPC:\n  | (new (config: OTLPExporterConfig) => PushMetricExporter)\n  | undefined;\nlet OTLPLogExporterGRPC:\n  | (new (config: OTLPExporterConfig) => LogRecordExporter)\n  | undefined;\n\n/**\n * Helper: Lazy-load gRPC trace exporter\n */\nfunction loadGRPCTraceExporter(): new (\n  config: OTLPExporterConfig,\n) => SpanExporter {\n  if (OTLPTraceExporterGRPC) return OTLPTraceExporterGRPC;\n\n  try {\n    // Dynamic import for optional peer dependency\n    const grpcModule = requireModule<{\n      OTLPTraceExporter: new (config: OTLPExporterConfig) => SpanExporter;\n    }>('@opentelemetry/exporter-trace-otlp-grpc');\n    OTLPTraceExporterGRPC = grpcModule.OTLPTraceExporter;\n    return OTLPTraceExporterGRPC;\n  } catch {\n    throw new Error(\n      'gRPC trace exporter not found. Install @opentelemetry/exporter-trace-otlp-grpc',\n    );\n  }\n}\n\n/**\n * Helper: Lazy-load gRPC metric exporter\n */\nfunction loadGRPCMetricExporter(): new (\n  config: OTLPExporterConfig,\n) => PushMetricExporter {\n  if (OTLPMetricExporterGRPC) return OTLPMetricExporterGRPC;\n\n  try {\n    // Dynamic import for optional peer dependency\n    const grpcModule = requireModule<{\n      OTLPMetricExporter: new (\n        config: OTLPExporterConfig,\n      ) => PushMetricExporter;\n    }>('@opentelemetry/exporter-metrics-otlp-grpc');\n    OTLPMetricExporterGRPC = grpcModule.OTLPMetricExporter;\n    return OTLPMetricExporterGRPC;\n  } catch {\n    throw new Error(\n      'gRPC metric exporter not found. Install @opentelemetry/exporter-metrics-otlp-grpc',\n    );\n  }\n}\n\n/**\n * Helper: Create trace exporter based on protocol\n */\nfunction createTraceExporter(\n  protocol: 'http' | 'grpc',\n  config: OTLPExporterConfig,\n): SpanExporter {\n  if (protocol === 'grpc') {\n    const Exporter = loadGRPCTraceExporter();\n    return new Exporter(config);\n  }\n\n  // Default: HTTP\n  return new OTLPTraceExporterHTTP(config);\n}\n\n/**\n * Helper: Create metric exporter based on protocol\n */\nfunction createMetricExporter(\n  protocol: 'http' | 'grpc',\n  config: OTLPExporterConfig,\n): PushMetricExporter {\n  if (protocol === 'grpc') {\n    const Exporter = loadGRPCMetricExporter();\n    return new Exporter(config);\n  }\n\n  // Default: HTTP\n  return new OTLPMetricExporterHTTP(config);\n}\n\n/**\n * Helper: Lazy-load gRPC log exporter\n */\nfunction loadGRPCLogExporter(): new (\n  config: OTLPExporterConfig,\n) => LogRecordExporter {\n  if (OTLPLogExporterGRPC) return OTLPLogExporterGRPC;\n\n  try {\n    const grpcModule = requireModule<{\n      OTLPLogExporter: new (config: OTLPExporterConfig) => LogRecordExporter;\n    }>('@opentelemetry/exporter-logs-otlp-grpc');\n    OTLPLogExporterGRPC = grpcModule.OTLPLogExporter;\n    return OTLPLogExporterGRPC;\n  } catch {\n    throw new Error(\n      'gRPC log exporter not found. Install @opentelemetry/exporter-logs-otlp-grpc',\n    );\n  }\n}\n\n/**\n * Helper: Create log exporter based on protocol\n */\nfunction createLogExporter(\n  protocol: 'http' | 'grpc',\n  config: OTLPExporterConfig,\n): LogRecordExporter {\n  if (protocol === 'grpc') {\n    const Exporter = loadGRPCLogExporter();\n    return new Exporter(config);\n  }\n\n  // Default: HTTP\n  return new OTLPLogExporterHTTP(config);\n}\n\n/**\n * Helper: Resolve protocol from config and environment\n */\nfunction resolveProtocol(configProtocol?: 'http' | 'grpc'): 'http' | 'grpc' {\n  // 1. Check config parameter (highest priority)\n  if (configProtocol === 'grpc' || configProtocol === 'http') {\n    return configProtocol;\n  }\n\n  // 2. Check OTEL_EXPORTER_OTLP_PROTOCOL env var\n  const envProtocol = process.env.OTEL_EXPORTER_OTLP_PROTOCOL;\n  if (envProtocol === 'grpc') return 'grpc';\n  if (envProtocol === 'http/protobuf' || envProtocol === 'http') return 'http';\n\n  // 3. Default to HTTP\n  return 'http';\n}\n\n/**\n * Helper: Adjust endpoint URL for protocol\n * gRPC exporters don't need the /v1/traces or /v1/metrics path\n * HTTP exporters need the full path\n */\nfunction formatEndpointUrl(\n  endpoint: string,\n  signal: 'traces' | 'metrics' | 'logs',\n  protocol: 'http' | 'grpc',\n): string {\n  if (protocol === 'grpc') {\n    // gRPC: strip any paths, return base endpoint\n    return endpoint.replace(/\\/(v1\\/)?(traces|metrics|logs)$/, '');\n  }\n\n  // HTTP: append signal path if not present\n  if (!endpoint.endsWith(`/v1/${signal}`)) {\n    return `${endpoint}/v1/${signal}`;\n  }\n\n  return endpoint;\n}\n\n// Built-in logger is created dynamically in init() with service name\n\nexport interface AutotelConfig {\n  /** Service name (required) */\n  service: string;\n\n  /**\n   * Local developer UX for autotel-devtools.\n   *\n   * - `true`: send traces, metrics, and logs to `http://127.0.0.1:4318`\n   * - `{ embedded: true }`: attempt to start `autotel-devtools` automatically\n   *\n   * When enabled:\n   * - `endpoint` defaults to the local devtools URL\n   * - `logs` default to `true` unless explicitly set\n   *\n   * This keeps production config unchanged while making local debugging\n   * effectively zero-config.\n   */\n  devtools?: boolean | AutotelDevtoolsConfig;\n\n  /** Event subscribers - bring your own (PostHog, Mixpanel, etc.) */\n  subscribers?: EventSubscriber[];\n\n  /**\n   * Additional OpenTelemetry instrumentations to register (raw OTel classes).\n   * Useful when you need custom instrumentation configs or instrumentations\n   * not covered by autoInstrumentations.\n   *\n   * **Important:** If you need custom instrumentation configs (like `requireParentSpan: false`),\n   * use EITHER manual instrumentations OR autoInstrumentations, not both for the same library.\n   * Manual instrumentations always take precedence over auto-instrumentations.\n   *\n   * @example Manual instrumentations with custom config\n   * ```typescript\n   * import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb'\n   *\n   * init({\n   *   service: 'my-app',\n   *   autoInstrumentations: false,  // Disable auto-instrumentations\n   *   instrumentations: [\n   *     new MongoDBInstrumentation({\n   *       requireParentSpan: false  // Custom config\n   *     })\n   *   ]\n   * })\n   * ```\n   *\n   * @example Mix auto + manual (auto for most, manual for specific configs)\n   * ```typescript\n   * import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb'\n   *\n   * init({\n   *   service: 'my-app',\n   *   autoInstrumentations: ['http', 'express'],  // Auto for these\n   *   instrumentations: [\n   *     new MongoDBInstrumentation({\n   *       requireParentSpan: false  // Manual config for MongoDB\n   *     })\n   *   ]\n   * })\n   * ```\n   */\n  instrumentations?: NodeSDKConfiguration['instrumentations'];\n\n  /**\n   * Simple names for auto-instrumentation.\n   * Uses @opentelemetry/auto-instrumentations-node (peer dependency).\n   *\n   * **Important:** If you provide manual instrumentations for the same library,\n   * the manual config takes precedence and auto-instrumentation for that library is disabled.\n   *\n   * @example Enable all auto-instrumentations (simple approach)\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   autoInstrumentations: true  // Enable all with defaults\n   * })\n   * ```\n   *\n   * @example Enable specific auto-instrumentations\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   autoInstrumentations: ['express', 'pino', 'http']\n   * })\n   * ```\n   *\n   * @example Configure specific auto-instrumentations\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   autoInstrumentations: {\n   *     express: { enabled: true },\n   *     pino: { enabled: true },\n   *     http: { enabled: false }\n   *   }\n   * })\n   * ```\n   *\n   * @example Manual config when you need custom settings\n   * ```typescript\n   * import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb'\n   *\n   * init({\n   *   service: 'my-app',\n   *   autoInstrumentations: false,  // Use manual control\n   *   instrumentations: [\n   *     new MongoDBInstrumentation({\n   *       requireParentSpan: false  // Custom config not available with auto\n   *     })\n   *   ]\n   * })\n   * ```\n   */\n  autoInstrumentations?:\n    | string[]\n    | boolean\n    | Record<string, { enabled?: boolean }>;\n\n  /**\n   * OTLP endpoint for traces/metrics/logs\n   * Single-destination shorthand. For multi-backend OTLP fan-out, use\n   * `destinations` instead.\n   * Only used if you don't provide custom exporters/processors\n   * @default process.env.OTLP_ENDPOINT || 'http://localhost:4318'\n   */\n  endpoint?: string;\n\n  /**\n   * Declarative OTLP multi-destination config.\n   * Each destination can override endpoint, headers, protocol, and signals.\n   *\n   * This is the high-level alternative to wiring `spanExporters`,\n   * `spanProcessors`, `metricReaders`, and `logRecordProcessors` manually when\n   * you want to fan telemetry out to multiple OTLP backends.\n   *\n   * When provided, `destinations` takes precedence over the single `endpoint`\n   * shorthand for built-in OTLP exporters/readers/processors.\n   *\n   * @example Grafana + Honeycomb for traces, Grafana only for metrics/logs\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   logs: true,\n   *   destinations: [\n   *     {\n   *       endpoint: 'https://otlp-gateway-prod-eu-west-2.grafana.net/otlp',\n   *       headers: { Authorization: 'Basic ...' },\n   *     },\n   *     {\n   *       endpoint: 'https://api.honeycomb.io',\n   *       headers: { 'x-honeycomb-team': '...' },\n   *       signals: ['traces'],\n   *     },\n   *   ],\n   * })\n   * ```\n   */\n  destinations?: OtlpDestinationConfig[];\n\n  /**\n   * Custom span processors for traces (supports multiple processors)\n   * Allows you to use any backend: Jaeger, Zipkin, Datadog, New Relic, etc.\n   * If not provided, defaults to OTLP with tail sampling\n   *\n   * @example Multiple processors\n   * ```typescript\n   * import { JaegerExporter } from '@opentelemetry/exporter-jaeger'\n   * import { BatchSpanProcessor, SimpleSpanProcessor, ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base'\n   *\n   * init({\n   *   service: 'my-app',\n   *   spanProcessors: [\n   *     new BatchSpanProcessor(new JaegerExporter()),\n   *     new SimpleSpanProcessor(new ConsoleSpanExporter())  // Debug alongside production\n   *   ]\n   * })\n   * ```\n   *\n   * @example Single processor\n   * ```typescript\n   * import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'\n   *\n   * init({\n   *   service: 'my-app',\n   *   spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())]\n   * })\n   * ```\n   */\n  spanProcessors?: SpanProcessor[];\n\n  /**\n   * Custom span processor for traces (single-item alias of spanProcessors)\n   * @deprecated Use spanProcessors for consistency with other multi-value config fields\n   */\n  spanProcessor?: SpanProcessor;\n\n  /**\n   * Custom span exporters for traces (alternative to spanProcessors, supports multiple exporters)\n   * Provide either spanProcessors OR spanExporters, not both\n   * Each exporter will be wrapped in TailSamplingSpanProcessor + BatchSpanProcessor\n   *\n   * @example Multiple exporters\n   * ```typescript\n   * import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'\n   * import { JaegerExporter } from '@opentelemetry/exporter-jaeger'\n   *\n   * init({\n   *   service: 'my-app',\n   *   spanExporters: [\n   *     new ZipkinExporter({ url: 'http://localhost:9411/api/v2/spans' }),\n   *     new JaegerExporter()  // Send to multiple backends simultaneously\n   *   ]\n   * })\n   * ```\n   *\n   * @example Single exporter\n   * ```typescript\n   * import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'\n   *\n   * init({\n   *   service: 'my-app',\n   *   spanExporters: [new ZipkinExporter({ url: 'http://localhost:9411/api/v2/spans' })]\n   * })\n   * ```\n   */\n  spanExporters?: SpanExporter[];\n\n  /**\n   * Custom span exporter for traces (single-item alias of spanExporters)\n   * @deprecated Use spanExporters for consistency with other multi-value config fields\n   */\n  spanExporter?: SpanExporter;\n\n  /**\n   * Custom metric readers (supports multiple readers)\n   * Allows sending metrics to multiple backends: OTLP, Prometheus, custom readers\n   * Defaults to OTLP metrics exporter when metrics are enabled.\n   *\n   * @example Multiple metric readers\n   * ```typescript\n   * import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'\n   * import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'\n   * import { PrometheusExporter } from '@opentelemetry/exporter-prometheus'\n   *\n   * init({\n   *   service: 'my-app',\n   *   metricReaders: [\n   *     new PeriodicExportingMetricReader({ exporter: new OTLPMetricExporter() }),\n   *     new PrometheusExporter()  // Export to multiple backends\n   *   ]\n   * })\n   * ```\n   */\n  metricReaders?: MetricReader[];\n\n  /**\n   * Custom metric reader (single-item alias of metricReaders)\n   * @deprecated Use metricReaders for consistency with other multi-value config fields\n   */\n  metricReader?: MetricReader;\n\n  /**\n   * Custom log record processors. When omitted, logs are not configured.\n   */\n  logRecordProcessors?: LogRecordProcessor[];\n\n  /**\n   * Custom log record processor (single-item alias of logRecordProcessors)\n   * @deprecated Use logRecordProcessors for consistency with other multi-value config fields\n   */\n  logRecordProcessor?: LogRecordProcessor;\n\n  /**\n   * PostHog integration - auto-configures OTLP log exporter.\n   *\n   * @example\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   posthog: { url: 'https://us.i.posthog.com/i/v1/logs?token=phc_xxx' }\n   * });\n   * ```\n   *\n   * Also reads from POSTHOG_LOGS_URL environment variable as fallback.\n   */\n  posthog?: { url: string };\n\n  /** Additional resource attributes to merge with defaults. */\n  resourceAttributes?: Attributes;\n\n  /** Provide a fully custom Resource to merge (advanced use case). */\n  resource?: Resource;\n\n  /**\n   * Headers for OTLP exporters. Accepts either an object map or\n   * a \"key=value\" comma separated string.\n   *\n   * @example\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   endpoint: 'https://api.honeycomb.io',\n   *   headers: { 'x-honeycomb-team': 'YOUR_API_KEY' }\n   * })\n   * ```\n   */\n  headers?: Record<string, string> | string;\n\n  /**\n   * OTLP protocol to use for traces, metrics, and logs\n   * - 'http': HTTP/protobuf (default, uses port 4318)\n   * - 'grpc': gRPC (uses port 4317)\n   *\n   * Can be overridden with OTEL_EXPORTER_OTLP_PROTOCOL env var.\n   *\n   * Note: gRPC exporters are optional peer dependencies. Install them with:\n   * ```bash\n   * pnpm add @opentelemetry/exporter-trace-otlp-grpc @opentelemetry/exporter-metrics-otlp-grpc\n   * ```\n   *\n   * @example HTTP (default)\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   protocol: 'http',  // or omit (defaults to http)\n   *   endpoint: 'http://localhost:4318'\n   * })\n   * ```\n   *\n   * @example gRPC\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   protocol: 'grpc',\n   *   endpoint: 'grpc://localhost:4317'\n   * })\n   * ```\n   *\n   * @default 'http'\n   */\n  protocol?: 'http' | 'grpc';\n\n  /**\n   * Optional factory to build a customised NodeSDK instance from our defaults.\n   */\n  sdkFactory?: (defaults: Partial<NodeSDKConfiguration>) => NodeSDK;\n\n  /**\n   * Infrastructure metrics configuration\n   * - true: always enabled (default)\n   * - false: always disabled\n   * - 'auto': always enabled (same as true)\n   *\n   * Can be overridden with AUTOTEL_METRICS=on|off env var\n   */\n  metrics?: boolean | 'auto';\n\n  /**\n   * OTLP logs configuration\n   * - true: auto-configure OTLP log exporter from endpoint\n   * - false: disabled (default)\n   * - 'auto': same as false (opt-in only)\n   *\n   * When enabled and an endpoint is configured, autotel will automatically\n   * create a BatchLogRecordProcessor with an OTLPLogExporter - no manual\n   * imports needed. Works alongside logRecordProcessors (additive).\n   *\n   * Requires @opentelemetry/sdk-logs and @opentelemetry/exporter-logs-otlp-http\n   * (or -grpc) as peer dependencies.\n   *\n   * Can be overridden with AUTOTEL_LOGS=on|off env var.\n   *\n   * @example\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   endpoint: 'http://localhost:4318',\n   *   logs: true,\n   * });\n   * ```\n   */\n  logs?: boolean | 'auto';\n\n  /** Sampling strategy - takes precedence over `sampling` preset */\n  sampler?: Sampler;\n\n  /**\n   * Sampling preset shorthand — resolves to a pre-configured sampler.\n   * If both `sampler` and `sampling` are provided, `sampler` takes precedence.\n   *\n   * @default 'production' (10% baseline + always-on for errors/slow)\n   *\n   * **Footgun for one-shot scripts:** the default samples ~90% of spans away,\n   * which means a fixture-capture script that emits a single normal span\n   * almost always sees zero output. For local debugging and capture use:\n   *\n   * ```typescript\n   * init({\n   *   service: 'fixture-capture',\n   *   spanProcessors: [new SimpleSpanProcessor(new InMemorySpanExporter())],\n   *   sampling: 'development', // capture EVERY span\n   * });\n   * ```\n   *\n   * Read `exporter.getFinishedSpans()` **before** calling `shutdown()` —\n   * `InMemorySpanExporter.shutdown()` resets state.\n   */\n  sampling?: SamplingPreset;\n\n  /** Service version (default: auto-detect from package.json or '1.0.0') */\n  version?: string;\n\n  /** Environment (default: process.env.NODE_ENV || 'development') */\n  environment?: string;\n\n  /**\n   * Logger instance for internal autotel diagnostic messages\n   *\n   * This logger is used by autotel internally to log initialization, warnings,\n   * and debug information. Any logger with info/warn/error/debug methods works.\n   *\n   * **For OTel instrumentation of your application logs**, use the `autoInstrumentations` option:\n   * - `autoInstrumentations: ['pino']` - Injects traceId/spanId into Pino logs\n   * - `autoInstrumentations: ['winston']` - Injects traceId/spanId into Winston logs\n   *\n   * Default: silent logger (no-op)\n   *\n   * @example Pino with OTel instrumentation\n   * ```typescript\n   * import pino from 'pino'\n   * import { init } from 'autotel'\n   *\n   * const logger = pino({ level: 'info' })\n   * init({\n   *   service: 'my-app',\n   *   logger,                       // For autotel's internal logs\n   *   autoInstrumentations: ['pino'] // For OTel trace context in YOUR logs\n   * })\n   * ```\n   *\n   * @example Custom logger for autotel diagnostics\n   * ```typescript\n   * const logger = {\n   *   info: (msg, extra) => console.log(msg, extra),\n   *   warn: (msg, extra) => console.warn(msg, extra),\n   *   error: (msg, err, extra) => console.error(msg, err, extra),\n   *   debug: (msg, extra) => console.debug(msg, extra),\n   * }\n   * init({ service: 'my-app', logger })\n   * ```\n   */\n  logger?: Logger;\n\n  /**\n   * Flush events queue when root spans end\n   * - true: Flush on root span completion (default)\n   * - false: Use batching (events flush every 10 seconds automatically)\n   *\n   * Only flushes on root spans to avoid excessive network calls.\n   * Default is true for serverless/short-lived processes. Set to false\n   * for long-running services where batching is more efficient.\n   */\n  flushOnRootSpanEnd?: boolean;\n\n  /**\n   * Force-flush OpenTelemetry spans on shutdown (default: false)\n   *\n   * When enabled, spans are force-flushed along with events on root\n   * span completion. This is useful for serverless/short-lived processes where\n   * spans may not export before the process ends.\n   *\n   * - true: Force-flush spans on root span completion (~50-200ms latency)\n   * - false: Spans export via normal batch processor (default behavior)\n   *\n   * Only applies when flushOnRootSpanEnd is also enabled.\n   *\n   * Note: For edge runtimes (Cloudflare Workers, Vercel Edge), use the\n   * 'autotel-edge' package instead, which handles this automatically.\n   *\n   * @example Serverless with force-flush\n   * ```typescript\n   * init({\n   *   service: 'my-lambda',\n   *   flushOnRootSpanEnd: true,\n   *   forceFlushOnShutdown: true, // Force-flush spans\n   * });\n   * ```\n   */\n  forceFlushOnShutdown?: boolean;\n\n  /**\n   * Automatically copy baggage entries to span attributes\n   *\n   * When enabled, all baggage entries are automatically added as span attributes,\n   * making them visible in trace UIs (Jaeger, Grafana, DataDog, etc.) without\n   * manually calling ctx.setAttribute() for each entry.\n   *\n   * - `true`: adds baggage with 'baggage.' prefix (e.g. baggage.tenant.id)\n   * - `string`: uses custom prefix (e.g. 'ctx' → ctx.tenant.id, '' → tenant.id)\n   * - `false` or omit: disabled (default)\n   *\n   * @default false\n   *\n   * @example Enable with default prefix\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   baggage: true\n   * });\n   *\n   * // Now baggage automatically appears as span attributes\n   * await withBaggage({\n   *   baggage: { 'tenant.id': 't1', 'user.id': 'u1' },\n   *   fn: async () => {\n   *     // Span has baggage.tenant.id and baggage.user.id attributes!\n   *   }\n   * });\n   * ```\n   *\n   * @example Custom prefix\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   baggage: 'ctx' // Uses 'ctx.' prefix\n   * });\n   * // Creates attributes: ctx.tenant.id, ctx.user.id\n   * ```\n   *\n   * @example No prefix\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   baggage: '' // No prefix\n   * });\n   * // Creates attributes: tenant.id, user.id\n   * ```\n   */\n  baggage?: boolean | string;\n\n  /**\n   * Validation configuration for events events\n   * - Override default sensitive field patterns for redaction\n   * - Customize max lengths, nesting depth, etc.\n   *\n   * @example Disable redaction for development\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   validation: {\n   *     sensitivePatterns: [] // Disable all redaction\n   *   }\n   * })\n   * ```\n   *\n   * @example Add custom patterns\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   validation: {\n   *     sensitivePatterns: [\n   *       /password/i,\n   *       /apiKey/i,\n   *       /customSecret/i  // Your custom pattern\n   *     ]\n   *   }\n   * })\n   * ```\n   */\n  validation?: Partial<ValidationConfig>;\n\n  /**\n   * Events configuration for trace context, correlation IDs, and enrichment\n   *\n   * Controls how product events integrate with distributed tracing:\n   * - `includeTraceContext`: Automatically include trace context in events\n   * - `includeLinkedTraceIds`: Include full array of linked trace IDs (for batch/fan-in)\n   * - `traceUrl`: Generate clickable trace URLs in events\n   * - `enrichFromBaggage`: Auto-enrich events from baggage with guardrails\n   *\n   * @example Basic trace context\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   events: {\n   *     includeTraceContext: true\n   *   }\n   * });\n   * // Events now include autotel.trace_id, autotel.span_id, autotel.correlation_id\n   * ```\n   *\n   * @example With clickable trace URLs\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   events: {\n   *     includeTraceContext: true,\n   *     traceUrl: (ctx) => `https://grafana.internal/explore?traceId=${ctx.traceId}`\n   *   }\n   * });\n   * ```\n   *\n   * @example With baggage enrichment\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   events: {\n   *     includeTraceContext: true,\n   *     enrichFromBaggage: {\n   *       allow: ['tenant.id', 'user.id'],\n   *       prefix: 'ctx.',\n   *       maxKeys: 10,\n   *       maxBytes: 1024\n   *     }\n   *   }\n   * });\n   * ```\n   */\n  events?: EventsConfig;\n\n  /**\n   * Debug mode for local span inspection.\n   * Enables console output to help you see spans as they're created.\n   *\n   * - `true`: Raw JSON output (ConsoleSpanExporter)\n   * - `'pretty'`: Colorized, hierarchical output (PrettyConsoleExporter)\n   * - `false`/undefined: No console output (default)\n   *\n   * When enabled: Outputs spans to console AND sends to backend (if endpoint/exporter configured)\n   *\n   * Perfect for progressive development:\n   * - Start with debug: 'pretty' (no endpoint) → see traces immediately with nice formatting\n   * - Add endpoint later → console + backend, verify before choosing provider\n   * - Remove debug in production → backend only, clean production config\n   *\n   * Can be overridden with AUTOTEL_DEBUG environment variable.\n   *\n   * @example Pretty debug output (recommended for development)\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   debug: 'pretty'  // Colorized, hierarchical output\n   * })\n   * ```\n   *\n   * @example Raw JSON output (verbose)\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   debug: true  // Raw ConsoleSpanExporter output\n   * })\n   * ```\n   *\n   * @example Environment variable\n   * ```bash\n   * AUTOTEL_DEBUG=pretty node server.js\n   * AUTOTEL_DEBUG=true node server.js\n   * ```\n   */\n  debug?: boolean | 'pretty';\n\n  /**\n   * Filter predicate to drop unwanted spans before processing.\n   *\n   * Useful for filtering out noisy spans from specific instrumentations\n   * (e.g., Next.js internal spans, health check endpoints).\n   *\n   * The filter runs on completed spans (onEnd), so you have access to:\n   * - `span.name` - Span name\n   * - `span.attributes` - All span attributes\n   * - `span.instrumentationScope` - `{ name, version }` of the instrumentation\n   * - `span.status` - Span status code and message\n   * - `span.duration` - Span duration as `[seconds, nanoseconds]`\n   *\n   * Return `true` to keep the span, `false` to drop it.\n   *\n   * @example Filter out Next.js instrumentation spans\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   spanFilter: (span) => span.instrumentationScope.name !== 'next.js'\n   * })\n   * ```\n   *\n   * @example Filter out health check spans\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   spanFilter: (span) => !span.name.includes('/health')\n   * })\n   * ```\n   *\n   * @example Complex filtering (multiple conditions)\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   spanFilter: (span) => {\n   *     // Drop Next.js internal spans\n   *     if (span.instrumentationScope.name === 'next.js') return false;\n   *     // Drop health checks\n   *     if (span.name.includes('/health')) return false;\n   *     // Drop very short spans (less than 1ms)\n   *     const [secs, nanos] = span.duration;\n   *     if (secs === 0 && nanos < 1_000_000) return false;\n   *     return true;\n   *   }\n   * })\n   * ```\n   */\n  spanFilter?: SpanFilterPredicate;\n\n  /**\n   * Normalize span names to reduce cardinality from dynamic path segments.\n   *\n   * High-cardinality span names (e.g., `/users/123/posts/456`) cause issues:\n   * - Cost explosions in observability backends\n   * - Cardinality limits exceeded\n   * - Poor UX when searching/filtering traces\n   *\n   * The normalizer transforms dynamic segments into placeholders:\n   * - `/users/123` → `/users/:id`\n   * - `/items/550e8400-e29b-...` → `/items/:uuid`\n   *\n   * Provide either a custom function or use a built-in preset:\n   * - `'rest-api'` - Numeric IDs, UUIDs, ObjectIds, dates, timestamps, emails\n   * - `'graphql'` - GraphQL operation name normalization\n   * - `'minimal'` - Only numeric IDs and UUIDs\n   *\n   * @example Custom normalizer function\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   spanNameNormalizer: (name) => {\n   *     return name\n   *       .replace(/\\/[0-9]+/g, '/:id')\n   *       .replace(/\\/[a-f0-9-]{36}/gi, '/:uuid');\n   *   }\n   * })\n   * ```\n   *\n   * @example Using built-in preset\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   spanNameNormalizer: 'rest-api'\n   * })\n   * ```\n   *\n   * @example Combining with spanFilter\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   spanNameNormalizer: 'rest-api',\n   *   spanFilter: (span) => span.instrumentationScope.name !== 'next.js'\n   * })\n   * ```\n   */\n  spanNameNormalizer?: SpanNameNormalizerConfig;\n\n  /**\n   * Automatically redact PII and sensitive data from span attributes before export.\n   * Critical for compliance (GDPR, PCI-DSS, HIPAA) and data security.\n   *\n   * Auto-enabled in production: when this is left unset and the resolved\n   * environment is `production`, the `'default'` preset is applied. Override\n   * with the `AUTOTEL_REDACT_PII` env var (`off` / `strict` / `pci-dss` / ...)\n   * or pass `false` to disable redaction entirely.\n   *\n   * Can be a preset name, custom configuration, or `false` to disable:\n   * - `'default'`: Emails, phones, SSNs, credit cards, sensitive keys (password, secret, token)\n   * - `'strict'`: Default + Bearer tokens, JWTs, API keys in values\n   * - `'pci-dss'`: Payment card industry focus (credit cards, CVV, card-related keys)\n   *\n   * @example Use default preset\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   attributeRedactor: 'default'\n   * })\n   * ```\n   *\n   * @example Custom patterns\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   attributeRedactor: {\n   *     keyPatterns: [/password/i, /secret/i],\n   *     valuePatterns: [\n   *       { name: 'customerId', pattern: /CUST-\\d{8}/g, replacement: 'CUST-***' }\n   *     ]\n   *   }\n   * })\n   * ```\n   *\n   * @example Custom redactor function\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   attributeRedactor: {\n   *     redactor: (key, value) => {\n   *       if (key === 'user.email' && typeof value === 'string') {\n   *         return value.replace(/@.+/, '@[REDACTED]');\n   *       }\n   *       return value;\n   *     }\n   *   }\n   * })\n   * ```\n   */\n  attributeRedactor?: AttributeRedactorConfig | AttributeRedactorPreset | false;\n\n  /**\n   * OpenLLMetry integration for LLM observability.\n   * Requires @traceloop/node-server-sdk as an optional peer dependency.\n   *\n   * @example Enable OpenLLMetry with default settings\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   openllmetry: { enabled: true }\n   * })\n   * ```\n   *\n   * @example Enable with custom options\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   openllmetry: {\n   *     enabled: true,\n   *     options: {\n   *       disableBatch: process.env.NODE_ENV !== 'production',\n   *       apiKey: process.env.TRACELOOP_API_KEY\n   *     }\n   *   }\n   * })\n   * ```\n   */\n  openllmetry?: {\n    enabled: boolean;\n    options?: Record<string, unknown>;\n  };\n\n  /**\n   * Canonical log lines - automatically emit spans as wide events (canonical log lines)\n   *\n   * When enabled, each span (or root span only) is automatically emitted as a\n   * comprehensive log record with ALL span attributes. This implements the\n   * \"canonical log line\" pattern: one comprehensive event per request with all context.\n   *\n   * **Benefits:**\n   * - One log line per request with all context (wide event)\n   * - High-cardinality, high-dimensionality data for powerful queries\n   * - Automatic - no manual logging needed\n   * - Queryable as structured data instead of string search\n   *\n   * @example Basic usage (one canonical log line per request)\n   * ```typescript\n   * init({\n   *   service: 'checkout-api',\n   *   canonicalLogLines: {\n   *     enabled: true,\n   *     rootSpansOnly: true, // One canonical log line per request\n   *   },\n   * });\n   * ```\n   *\n   * @example With custom logger\n   * ```typescript\n   * import pino from 'pino';\n   * const logger = pino();\n   * init({\n   *   service: 'my-app',\n   *   logger,\n   *   canonicalLogLines: {\n   *     enabled: true,\n   *     logger, // Use Pino for canonical log lines\n   *     rootSpansOnly: true,\n   *   },\n   * });\n   * ```\n   *\n   * @example Custom message format\n   * ```typescript\n   * init({\n   *   service: 'my-app',\n   *   canonicalLogLines: {\n   *     enabled: true,\n   *     messageFormat: (span) => {\n   *       const status = span.status.code === 2 ? 'ERROR' : 'SUCCESS';\n   *       return `${span.name} [${status}]`;\n   *     },\n   *   },\n   * });\n   * ```\n   */\n  canonicalLogLines?: {\n    enabled: boolean;\n    /** Logger to use for emitting canonical log lines (defaults to OTel Logs API) */\n    logger?: Logger;\n    /** Only emit canonical log lines for root spans (default: false) */\n    rootSpansOnly?: boolean;\n    /** Minimum log level for canonical log lines (default: 'info') */\n    minLevel?: 'debug' | 'info' | 'warn' | 'error';\n    /** Custom message format (default: uses span name) */\n    messageFormat?: (\n      span: import('@opentelemetry/sdk-trace-base').ReadableSpan,\n    ) => string;\n    /** Whether to include resource attributes (default: true) */\n    includeResourceAttributes?: boolean;\n    /** Predicate to decide whether to emit (runs after event is built). */\n    shouldEmit?: CanonicalLogLineOptions['shouldEmit'];\n    /**\n     * Declarative tail sampling conditions (OR logic).\n     * Ignored when `shouldEmit` is provided.\n     * @example keep: [{ status: 500 }, { durationMs: 1000 }]\n     */\n    keep?: CanonicalLogLineOptions['keep'];\n    /** Callback invoked after emit for custom fan-out. */\n    drain?: CanonicalLogLineOptions['drain'];\n    /** Handler for drain failures. */\n    onDrainError?: CanonicalLogLineOptions['onDrainError'];\n    /**\n     * Pretty-print canonical log lines to console.\n     * Defaults to true when NODE_ENV is 'development'.\n     */\n    pretty?: boolean;\n  };\n\n  /**\n   * Suppress console output while keeping OTel exporters running.\n   * Useful for platforms like GCP Cloud Run / AWS Lambda where stdout\n   * is managed externally by the platform's log collector.\n   *\n   * @default false\n   */\n  silent?: boolean;\n\n  /**\n   * Minimum log level for internal autotel diagnostic messages.\n   * Messages below this level are dropped before processing.\n   *\n   * @default 'info'\n   */\n  minLevel?: 'debug' | 'info' | 'warn' | 'error';\n}\n\n// Internal state\nlet initialized = false;\nlet locked = false;\nlet config: AutotelConfig | null = null;\nlet sdk: NodeSDK | null = null;\nlet warnedOnce = false;\nlet logger: Logger = silentLogger; // Silent by default - no spam\nlet validationConfig: Partial<ValidationConfig> | null = null;\nlet eventsConfig: EventsConfig | null = null;\nlet _stringRedactor: StringRedactor | null = null;\nlet _optionalRequire: typeof safeRequire = safeRequire;\nlet _devtoolsClose: (() => Promise<void> | void) | null = null;\n\nconst LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 } as const;\ntype LogLevelKey = keyof typeof LOG_LEVELS;\n\n/**\n * Lock the logger to prevent further `init()` calls.\n * Use this when framework plugins set up instrumentation and you want\n * to prevent accidental re-initialization from user code.\n */\nexport function lockLogger(): void {\n  locked = true;\n}\n\n/**\n * Check if the logger has been locked.\n */\nexport function isLoggerLocked(): boolean {\n  return locked;\n}\n\nfunction createSilentLogger(): Logger {\n  return {\n    info: () => {},\n    warn: () => {},\n    error: () => {},\n    debug: () => {},\n  };\n}\n\nfunction wrapLogger(\n  base: Logger,\n  silent: boolean,\n  minLevel: LogLevelKey,\n): Logger {\n  if (silent) return createSilentLogger();\n  const threshold = LOG_LEVELS[minLevel];\n  const wrap = (fn: Logger['info'], level: LogLevelKey): Logger['info'] => {\n    if (LOG_LEVELS[level] < threshold) {\n      return (() => {}) as Logger['info'];\n    }\n    return ((...args: Parameters<Logger['info']>) =>\n      fn(...args)) as Logger['info'];\n  };\n  return {\n    debug: wrap(base.debug, 'debug'),\n    info: wrap(base.info, 'info'),\n    warn: wrap(base.warn, 'warn'),\n    error: wrap(base.error, 'error'),\n  };\n}\n\n/**\n * Resolve the effective attribute redactor. Explicit config wins (`false`\n * disables). Otherwise the `AUTOTEL_REDACT_PII` env var controls it, and as a\n * final default PII redaction is auto-enabled in production.\n */\nexport function resolveAttributeRedactor(\n  explicit:\n    | AttributeRedactorConfig\n    | AttributeRedactorPreset\n    | false\n    | undefined,\n  environment: string,\n): AttributeRedactorConfig | AttributeRedactorPreset | undefined {\n  if (explicit === false) return undefined;\n  if (explicit !== undefined) return explicit;\n\n  const flag = process.env.AUTOTEL_REDACT_PII?.trim().toLowerCase();\n  if (flag) {\n    if (['off', 'false', '0', 'none', 'disabled'].includes(flag)) {\n      return undefined;\n    }\n    if (flag === 'default' || flag === 'strict' || flag === 'pci-dss') {\n      return flag;\n    }\n    if (['on', 'true', '1', 'enabled'].includes(flag)) {\n      return 'default';\n    }\n  }\n\n  return environment === 'production' ? 'default' : undefined;\n}\n\nfunction detectEnvironmentAttributes(): Record<string, string> {\n  const attrs: Record<string, string> = {};\n\n  const commitSha =\n    process.env.COMMIT_SHA ||\n    process.env.GITHUB_SHA ||\n    process.env.VERCEL_GIT_COMMIT_SHA ||\n    process.env.CF_PAGES_COMMIT_SHA ||\n    process.env.AWS_CODEPIPELINE_EXECUTION_ID;\n  if (commitSha) attrs['service.commit.sha'] = commitSha;\n\n  const region =\n    process.env.VERCEL_REGION ||\n    process.env.AWS_REGION ||\n    process.env.AWS_DEFAULT_REGION ||\n    process.env.FLY_REGION ||\n    process.env.CF_REGION ||\n    process.env.GOOGLE_CLOUD_REGION;\n  if (region) attrs['service.region'] = region;\n\n  const version =\n    process.env.APP_VERSION ||\n    process.env.HEROKU_RELEASE_VERSION ||\n    process.env.VERCEL_GIT_COMMIT_REF;\n  if (version) attrs['service.deploy.version'] = version;\n\n  return attrs;\n}\n\n/**\n * Resolve metrics flag with env var override support\n */\nexport function resolveMetricsFlag(\n  configFlag: boolean | 'auto' = 'auto',\n): boolean {\n  // 1. Check env var override (highest priority)\n  const envFlag = process.env.AUTOTEL_METRICS;\n  if (envFlag === 'on' || envFlag === 'true') return true;\n  if (envFlag === 'off' || envFlag === 'false') return false;\n\n  // 2. Check config flag\n  if (configFlag === true) return true;\n  if (configFlag === false) return false;\n\n  // 3. Default: enabled in all environments (simpler)\n  return true;\n}\n\n/**\n * Resolve logs flag with env var override support.\n * Defaults to disabled (opt-in only) to avoid unexpected log export\n * and to preserve the upstream SDK's OTEL_LOGS_EXPORTER handling.\n */\nexport function resolveLogsFlag(\n  configFlag: boolean | 'auto' = 'auto',\n): boolean {\n  // 1. Check env var override (highest priority)\n  const envFlag = process.env.AUTOTEL_LOGS;\n  if (envFlag === 'on' || envFlag === 'true') return true;\n  if (envFlag === 'off' || envFlag === 'false') return false;\n\n  // 2. Check config flag\n  if (configFlag === true) return true;\n  if (configFlag === false) return false;\n\n  // 3. Default: disabled (opt-in only)\n  return false;\n}\n\n/**\n * Resolve debug flag with env var override support\n *\n * Supports:\n * - `'pretty'`: Colorized, hierarchical output (PrettyConsoleExporter)\n * - `true` / `'true'` / `'1'`: Raw JSON output (ConsoleSpanExporter)\n * - `false` / `'false'` / `'0'`: Disabled\n */\nexport function resolveDebugFlag(\n  configFlag?: boolean | 'pretty',\n): boolean | 'pretty' {\n  // 1. Check env var override (highest priority)\n  const envFlag = process.env.AUTOTEL_DEBUG;\n  if (envFlag === 'pretty') return 'pretty';\n  if (envFlag === 'true' || envFlag === '1') return true;\n  if (envFlag === 'false' || envFlag === '0') return false;\n\n  // 2. Return config flag (defaults to false)\n  return configFlag ?? false;\n}\n\nfunction normalizeOtlpHeaders(\n  headers?: Record<string, string> | string,\n): Record<string, string> | undefined {\n  if (!headers) return undefined;\n  if (typeof headers !== 'string') return headers;\n\n  const parsed: Record<string, string> = {};\n  for (const pair of headers.split(',')) {\n    const [key, ...valueParts] = pair.split('=');\n    if (!key || valueParts.length === 0) continue;\n    parsed[key.trim()] = valueParts.join('=').trim();\n  }\n  return parsed;\n}\n\ntype ResolvedOtlpDestination = {\n  endpoint: string;\n  protocol: 'http' | 'grpc';\n  headers?: Record<string, string>;\n  signals?: Set<OtlpSignal>;\n};\n\nfunction resolveOtlpDestinations(\n  config: AutotelConfig,\n  fallbackEndpoint?: string,\n): ResolvedOtlpDestination[] {\n  const rawDestinations =\n    config.destinations !== undefined\n      ? config.destinations\n      : fallbackEndpoint\n        ? [\n            {\n              endpoint: fallbackEndpoint,\n              headers: config.headers,\n              protocol: config.protocol,\n            },\n          ]\n        : [];\n\n  return rawDestinations.map((destination) => ({\n    endpoint: destination.endpoint,\n    protocol: resolveProtocol(destination.protocol ?? config.protocol),\n    headers: normalizeOtlpHeaders(destination.headers ?? config.headers),\n    signals: destination.signals ? new Set(destination.signals) : undefined,\n  }));\n}\n\nfunction destinationSupportsSignal(\n  destination: ResolvedOtlpDestination,\n  signal: OtlpSignal,\n): boolean {\n  return destination.signals ? destination.signals.has(signal) : true;\n}\n\n/**\n * Initialize autotel - Write Once, Observe Everywhere\n *\n * Follows OpenTelemetry standards: opinionated defaults with full flexibility\n * Idempotent: multiple calls are safe, last one wins\n *\n * @example Minimal setup (OTLP default)\n * ```typescript\n * init({ service: 'my-app' })\n * ```\n *\n * @example With events (observe in PostHog, Mixpanel, etc.)\n * ```typescript\n * import { PostHogSubscriber } from 'autotel-subscribers/posthog';\n *\n * init({\n *   service: 'my-app',\n *   subscribers: [new PostHogSubscriber({ apiKey: '...' })]\n * })\n * ```\n *\n * @example Observe in Jaeger\n * ```typescript\n * import { JaegerExporter } from '@opentelemetry/exporter-jaeger'\n *\n * init({\n *   service: 'my-app',\n *   spanExporter: new JaegerExporter({ endpoint: 'http://localhost:14268/api/traces' })\n * })\n * ```\n *\n * @example Observe in Zipkin\n * ```typescript\n * import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'\n *\n * init({\n *   service: 'my-app',\n *   spanExporter: new ZipkinExporter({ url: 'http://localhost:9411/api/v2/spans' })\n * })\n * ```\n *\n * @example Observe in Datadog\n * ```typescript\n * import { DatadogSpanProcessor } from '@opentelemetry/exporter-datadog'\n *\n * init({\n *   service: 'my-app',\n *   spanProcessor: new DatadogSpanProcessor({ ... })\n * })\n * ```\n *\n * @example Console output (dev)\n * ```typescript\n * import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'\n *\n * init({\n *   service: 'my-app',\n *   spanProcessor: new SimpleSpanProcessor(new ConsoleSpanExporter())\n * })\n * ```\n */\n\nexport function init(cfg: AutotelConfig): void {\n  if (locked) {\n    return;\n  }\n\n  // Resolve configs in priority order: explicit > yaml > env > defaults\n  const envConfig = resolveConfigFromEnv();\n  const yamlConfig = loadYamlConfig() ?? {};\n\n  // Merge configs: explicit config > yaml file > env vars > defaults\n  const mergedConfig: AutotelConfig = {\n    ...envConfig, // Environment variables (lowest priority)\n    ...yamlConfig, // YAML file (middle priority)\n    ...cfg, // Explicit config (highest priority)\n    // Deep merge for resourceAttributes\n    resourceAttributes: {\n      ...envConfig.resourceAttributes,\n      ...yamlConfig.resourceAttributes,\n      ...detectEnvironmentAttributes(),\n      ...cfg.resourceAttributes,\n    },\n    // Handle headers merge (can be string or object)\n    headers: cfg.headers ?? yamlConfig.headers ?? envConfig.headers,\n  } as AutotelConfig;\n\n  const resolvedRedactor = resolveAttributeRedactor(\n    mergedConfig.attributeRedactor,\n    mergedConfig.environment || process.env.NODE_ENV || 'development',\n  );\n  if (resolvedRedactor === undefined) {\n    mergedConfig.attributeRedactor = undefined;\n  } else {\n    const normalizedRedactor =\n      normalizeAttributeRedactorConfig(resolvedRedactor);\n    if (!normalizedRedactor) {\n      throw new Error('Invalid attributeRedactor config');\n    }\n    mergedConfig.attributeRedactor = normalizedRedactor;\n  }\n\n  const devtoolsConfig = resolveDevtoolsConfig(mergedConfig.devtools);\n  if (devtoolsConfig.enabled && mergedConfig.logs === undefined) {\n    mergedConfig.logs = true;\n  }\n\n  const silent = mergedConfig.silent ?? false;\n  const minLevel = mergedConfig.minLevel ?? 'info';\n  const baseLogger = mergedConfig.logger || silentLogger;\n  logger = wrapLogger(baseLogger, silent, minLevel);\n\n  // Warn if re-initializing (same behavior in all environments)\n  if (initialized) {\n    logger.warn(\n      {},\n      '[autotel] init() called again - last config wins. This may cause unexpected behavior.',\n    );\n  }\n\n  config = mergedConfig;\n  validationConfig = mergedConfig.validation || null;\n  eventsConfig = mergedConfig.events || null;\n\n  // Initialize OpenTelemetry\n  // Only use endpoint if explicitly configured (no default fallback)\n  let endpoint = mergedConfig.endpoint ?? devtoolsConfig.endpoint;\n  const version = mergedConfig.version || detectVersion();\n  const environment =\n    mergedConfig.environment || process.env.NODE_ENV || 'development';\n  const metricsEnabled = resolveMetricsFlag(mergedConfig.metrics);\n  const logsEnabled = resolveLogsFlag(mergedConfig.logs);\n\n  if (devtoolsConfig.enabled && devtoolsConfig.embedded) {\n    const devtoolsModule = _optionalRequire<{\n      createDevtools?: (options?: {\n        port?: number;\n        host?: string;\n        verbose?: boolean;\n      }) => { port: number; close: () => Promise<void> | void };\n    }>('autotel-devtools');\n\n    if (devtoolsModule?.createDevtools) {\n      const devtoolsInstance = devtoolsModule.createDevtools({\n        port: devtoolsConfig.port,\n        host: devtoolsConfig.host,\n        verbose: devtoolsConfig.verbose,\n      });\n      _devtoolsClose = devtoolsInstance.close;\n      endpoint = `http://${devtoolsConfig.host}:${devtoolsInstance.port}`;\n      logger.info(\n        {},\n        `[autotel] autotel-devtools embedded server started at ${endpoint}`,\n      );\n    } else {\n      logger.warn(\n        {},\n        '[autotel] devtools.embedded requested but autotel-devtools is not installed. Falling back to endpoint-only mode.',\n      );\n    }\n  }\n\n  // Detect hostname for proper Datadog correlation and Service Catalog discovery\n  const hostname = detectHostname();\n\n  let resource = resourceFromAttributes({\n    [ATTR_SERVICE_NAME]: mergedConfig.service,\n    [ATTR_SERVICE_VERSION]: version,\n    // Support both old and new OpenTelemetry semantic conventions for environment\n    'deployment.environment': environment, // Deprecated but widely supported\n    'deployment.environment.name': environment, // OTel v1.27.0+ standard\n  });\n\n  // Add hostname attributes for Datadog Service Catalog and infrastructure correlation\n  if (hostname) {\n    resource = resource.merge(\n      resourceFromAttributes({\n        'host.name': hostname, // OpenTelemetry standard\n        'datadog.host.name': hostname, // Datadog-specific, highest priority for Datadog\n      }),\n    );\n  }\n\n  if (mergedConfig.resource) {\n    resource = resource.merge(mergedConfig.resource);\n  }\n\n  if (mergedConfig.resourceAttributes) {\n    resource = resource.merge(\n      resourceFromAttributes(mergedConfig.resourceAttributes),\n    );\n  }\n\n  const otlpDestinations = resolveOtlpDestinations(mergedConfig, endpoint);\n\n  // Backward-compatible singular aliases. Plural forms take precedence when both are provided.\n  const configuredSpanProcessors =\n    mergedConfig.spanProcessors && mergedConfig.spanProcessors.length > 0\n      ? mergedConfig.spanProcessors\n      : mergedConfig.spanProcessor\n        ? [mergedConfig.spanProcessor]\n        : undefined;\n  const configuredSpanExporters =\n    mergedConfig.spanExporters && mergedConfig.spanExporters.length > 0\n      ? mergedConfig.spanExporters\n      : mergedConfig.spanExporter\n        ? [mergedConfig.spanExporter]\n        : undefined;\n  const configuredMetricReaders =\n    mergedConfig.metricReaders && mergedConfig.metricReaders.length > 0\n      ? mergedConfig.metricReaders\n      : mergedConfig.metricReader\n        ? [mergedConfig.metricReader]\n        : undefined;\n  const configuredLogRecordProcessors =\n    mergedConfig.logRecordProcessors &&\n    mergedConfig.logRecordProcessors.length > 0\n      ? mergedConfig.logRecordProcessors\n      : mergedConfig.logRecordProcessor\n        ? [mergedConfig.logRecordProcessor]\n        : undefined;\n\n  // Build array of span processors (supports multiple)\n  let spanProcessors: SpanProcessor[] = [];\n\n  if (configuredSpanProcessors && configuredSpanProcessors.length > 0) {\n    // User provided custom processors (full control)\n    spanProcessors.push(...configuredSpanProcessors);\n  } else if (configuredSpanExporters && configuredSpanExporters.length > 0) {\n    // User provided custom exporters (wrap each with tail sampling)\n    for (const exporter of configuredSpanExporters) {\n      spanProcessors.push(\n        new TailSamplingSpanProcessor(new BatchSpanProcessor(exporter)),\n      );\n    }\n  } else {\n    for (const destination of otlpDestinations) {\n      if (!destinationSupportsSignal(destination, 'traces')) continue;\n\n      const traceExporter = createTraceExporter(destination.protocol, {\n        url: formatEndpointUrl(\n          destination.endpoint,\n          'traces',\n          destination.protocol,\n        ),\n        headers: destination.headers,\n      });\n\n      spanProcessors.push(\n        new TailSamplingSpanProcessor(new BatchSpanProcessor(traceExporter)),\n      );\n    }\n  }\n  // If no endpoint and no custom processors/exporters, array remains empty\n  // SDK will still work but won't export traces\n\n  // Add baggage span processor if enabled\n  if (mergedConfig.baggage) {\n    const prefix =\n      typeof mergedConfig.baggage === 'string'\n        ? mergedConfig.baggage\n          ? `${mergedConfig.baggage}.`\n          : ''\n        : 'baggage.';\n    spanProcessors.push(new BaggageSpanProcessor({ prefix }));\n  }\n\n  // Apply debug mode configuration\n  const debugMode = resolveDebugFlag(mergedConfig.debug);\n\n  if (debugMode === 'pretty') {\n    // Pretty debug: colorized, hierarchical output\n    spanProcessors.push(new SimpleSpanProcessor(new PrettyConsoleExporter()));\n  } else if (debugMode === true) {\n    // Raw debug: JSON output\n    spanProcessors.push(new SimpleSpanProcessor(new ConsoleSpanExporter()));\n  }\n\n  // Add canonical log line processor BEFORE wrapping processors\n  // This ensures it gets wrapped with the same filter/normalizer/redactor as other processors,\n  // so canonical logs respect spanFilter (filtered spans aren't logged), spanNameNormalizer\n  // (normalized names are used), and attributeRedactor (sensitive data is redacted).\n  if (mergedConfig.canonicalLogLines?.enabled) {\n    const canonicalOptions: CanonicalLogLineOptions = {\n      logger: mergedConfig.canonicalLogLines.logger || mergedConfig.logger,\n      rootSpansOnly: mergedConfig.canonicalLogLines.rootSpansOnly,\n      minLevel: mergedConfig.canonicalLogLines.minLevel,\n      messageFormat: mergedConfig.canonicalLogLines.messageFormat,\n      includeResourceAttributes:\n        mergedConfig.canonicalLogLines.includeResourceAttributes,\n      shouldEmit: mergedConfig.canonicalLogLines.shouldEmit,\n      keep: mergedConfig.canonicalLogLines.keep,\n      drain: mergedConfig.canonicalLogLines.drain,\n      onDrainError: mergedConfig.canonicalLogLines.onDrainError,\n      pretty: mergedConfig.canonicalLogLines.pretty,\n    };\n    spanProcessors.push(new CanonicalLogLineProcessor(canonicalOptions));\n  }\n\n  // Wrap processors in order: redactor (innermost) → normalizer → filter (outermost)\n  // This ensures onEnd() execution order is: filter → normalizer → redactor\n  // So filtering sees original attributes, and redaction happens last before export.\n\n  // Step 1: Wrap with AttributeRedactingProcessor (innermost - executes last in onEnd)\n  if (mergedConfig.attributeRedactor && spanProcessors.length > 0) {\n    const redactor = mergedConfig.attributeRedactor;\n    spanProcessors = spanProcessors.map(\n      (processor) =>\n        new AttributeRedactingProcessor(processor, {\n          redactor,\n        }),\n    );\n  }\n\n  // Store string redactor for use by PostHog log/subscriber paths\n  if (mergedConfig.attributeRedactor) {\n    _stringRedactor = createStringRedactor(mergedConfig.attributeRedactor);\n  }\n\n  // Wire string redactor to subscribers that support it (e.g., PostHogSubscriber)\n  if (_stringRedactor && mergedConfig.subscribers) {\n    for (const subscriber of mergedConfig.subscribers) {\n      if (\n        'setStringRedactor' in subscriber &&\n        typeof (subscriber as any).setStringRedactor === 'function'\n      ) {\n        (subscriber as any).setStringRedactor(_stringRedactor);\n      }\n    }\n  }\n\n  // Step 2: Wrap with SpanNameNormalizingProcessor (middle)\n  // Normalizer runs in onStart(), so span names are normalized before any onEnd processing\n  if (mergedConfig.spanNameNormalizer && spanProcessors.length > 0) {\n    spanProcessors = spanProcessors.map(\n      (processor) =>\n        new SpanNameNormalizingProcessor(processor, {\n          normalizer: mergedConfig.spanNameNormalizer!,\n        }),\n    );\n  }\n\n  // Step 3: Wrap with FilteringSpanProcessor (outermost - executes first in onEnd)\n  // Filter sees original (unredacted) attributes, so it can match on sensitive values\n  if (mergedConfig.spanFilter && spanProcessors.length > 0) {\n    spanProcessors = spanProcessors.map(\n      (processor) =>\n        new FilteringSpanProcessor(processor, {\n          filter: mergedConfig.spanFilter!,\n        }),\n    );\n  }\n\n  // Build array of metric readers (supports multiple)\n  const metricReaders: MetricReader[] = [];\n\n  if (configuredMetricReaders && configuredMetricReaders.length > 0) {\n    // User provided custom metric readers\n    metricReaders.push(...configuredMetricReaders);\n  } else if (metricsEnabled) {\n    for (const destination of otlpDestinations) {\n      if (!destinationSupportsSignal(destination, 'metrics')) continue;\n\n      const metricExporter = createMetricExporter(destination.protocol, {\n        url: formatEndpointUrl(\n          destination.endpoint,\n          'metrics',\n          destination.protocol,\n        ),\n        headers: destination.headers,\n      });\n\n      metricReaders.push(\n        new PeriodicExportingMetricReader({\n          exporter: metricExporter,\n        }),\n      );\n    }\n  }\n\n  let logRecordProcessors: LogRecordProcessor[] | undefined;\n  if (\n    configuredLogRecordProcessors &&\n    configuredLogRecordProcessors.length > 0\n  ) {\n    logRecordProcessors = [...configuredLogRecordProcessors];\n  }\n\n  // Auto-configure OTLP log exporters when logs are enabled.\n  if (logsEnabled) {\n    for (const destination of otlpDestinations) {\n      if (!destinationSupportsSignal(destination, 'logs')) continue;\n\n      const logExporter = createLogExporter(destination.protocol, {\n        url: formatEndpointUrl(\n          destination.endpoint,\n          'logs',\n          destination.protocol,\n        ),\n        headers: destination.headers,\n      });\n\n      let processor: LogRecordProcessor = new BatchLogRecordProcessor(\n        logExporter,\n      );\n      if (_stringRedactor) {\n        processor = new RedactingLogRecordProcessor(processor, _stringRedactor);\n      }\n      if (!logRecordProcessors) {\n        logRecordProcessors = [];\n      }\n      logRecordProcessors.push(processor);\n    }\n\n    if (\n      otlpDestinations.some((destination) =>\n        destinationSupportsSignal(destination, 'logs'),\n      )\n    ) {\n      logger.info({}, '[autotel] OTLP log exporter configured');\n    }\n  }\n\n  // PostHog OTLP logs integration\n  const posthogProcessors = buildPostHogLogProcessors(\n    mergedConfig.posthog,\n    _stringRedactor,\n  );\n  if (posthogProcessors.length > 0) {\n    if (!logRecordProcessors) {\n      logRecordProcessors = [];\n    }\n    logRecordProcessors.push(...posthogProcessors);\n    logger.info({}, '[autotel] PostHog OTLP logs configured');\n  }\n\n  // Handle instrumentations: merge manual instrumentations with auto-instrumentations\n  let finalInstrumentations: NodeSDKConfiguration['instrumentations'] =\n    mergedConfig.instrumentations ? [...mergedConfig.instrumentations] : [];\n\n  if (\n    mergedConfig.autoInstrumentations !== undefined &&\n    mergedConfig.autoInstrumentations !== false\n  ) {\n    // Check for ESM mode and provide guidance\n    const isESM = isESMMode();\n    if (isESM) {\n      logger.info(\n        {},\n        '[autotel] ESM mode detected. For auto-instrumentation to work:\\n' +\n          '  1. Install @opentelemetry/auto-instrumentations-node as a direct dependency\\n' +\n          '  2. Import autotel/register FIRST in your instrumentation file\\n' +\n          '  3. Use getNodeAutoInstrumentations() directly instead of autoInstrumentations\\n' +\n          '  See: https://github.com/jagreehal/autotel#esm-setup',\n      );\n    }\n\n    try {\n      // Detect manual instrumentations to avoid conflicts\n      const manualInstrumentationNames = getInstrumentationNames(\n        mergedConfig.instrumentations ?? [],\n      );\n\n      // Warn if both autoInstrumentations and manual instrumentations are provided\n      if (manualInstrumentationNames.size > 0) {\n        const manualNames = [...manualInstrumentationNames].join(', ');\n        logger.info(\n          {},\n          `[autotel] Detected manual instrumentations (${manualNames}). ` +\n            'These will take precedence over auto-instrumentations. ' +\n            'Tip: Set autoInstrumentations:false if you want full manual control, or remove manual configs to use auto-instrumentations.',\n        );\n      }\n\n      const autoInstrumentations = getAutoInstrumentations(\n        mergedConfig.autoInstrumentations,\n        manualInstrumentationNames,\n      );\n      if (autoInstrumentations && autoInstrumentations.length > 0) {\n        // Cast to proper type - getNodeAutoInstrumentations returns the correct type\n        finalInstrumentations = [\n          ...finalInstrumentations,\n          ...(autoInstrumentations as NodeSDKConfiguration['instrumentations']),\n        ];\n      }\n    } catch (error) {\n      logger.warn(\n        {},\n        `[autotel] Failed to configure auto-instrumentations: ${error instanceof Error ? error.message : String(error)}`,\n      );\n    }\n  }\n\n  const autotelSampler =\n    mergedConfig.sampler ??\n    (mergedConfig.sampling\n      ? resolveSamplingPreset(mergedConfig.sampling)\n      : undefined);\n  if (autotelSampler) {\n    mergedConfig.sampler = autotelSampler;\n  }\n  const sampler: OtelSampler = autotelSampler\n    ? toOtelSampler(autotelSampler)\n    : (envConfig.otelSampler ?? toOtelSampler(samplingPresets.production()));\n\n  const sdkOptions: Partial<NodeSDKConfiguration> = {\n    resource,\n    sampler,\n    instrumentations: finalInstrumentations,\n  };\n\n  if (spanProcessors.length > 0) {\n    sdkOptions.spanProcessors = spanProcessors;\n  }\n\n  if (metricReaders.length > 0) {\n    sdkOptions.metricReaders = metricReaders;\n  }\n\n  if (logRecordProcessors && logRecordProcessors.length > 0) {\n    sdkOptions.logRecordProcessors = logRecordProcessors;\n  }\n\n  sdk = mergedConfig.sdkFactory\n    ? mergedConfig.sdkFactory(sdkOptions)\n    : new NodeSDK(sdkOptions);\n\n  if (!sdk) {\n    throw new Error('[autotel] sdkFactory must return a NodeSDK instance');\n  }\n\n  sdk.start();\n\n  // Initialize OpenLLMetry if enabled (after SDK starts to reuse tracer provider)\n  if (mergedConfig.openllmetry?.enabled) {\n    const traceloop = _optionalRequire<{\n      initialize?: (options?: Record<string, unknown>) => void;\n    }>('@traceloop/node-server-sdk');\n\n    if (traceloop) {\n      const initOptions: Record<string, unknown> = {\n        ...mergedConfig.openllmetry.options,\n      };\n\n      // Reuse autotel's tracer provider\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 tracerProvider = (sdk as any).getTracerProvider();\n        initOptions.tracerProvider = tracerProvider;\n      } catch {\n        // Ignore if tracer provider not available\n      }\n\n      // Pass span exporter to OpenLLMetry if provided\n      if (configuredSpanExporters?.[0]) {\n        initOptions.exporter = configuredSpanExporters[0];\n      }\n\n      if (typeof traceloop.initialize === 'function') {\n        traceloop.initialize(initOptions);\n        logger.info({}, '[autotel] OpenLLMetry initialized successfully');\n      } else {\n        logger.warn(\n          {},\n          '[autotel] OpenLLMetry initialize function not found. Check @traceloop/node-server-sdk version.',\n        );\n      }\n    } else {\n      logger.warn(\n        {},\n        '[autotel] OpenLLMetry enabled but @traceloop/node-server-sdk is not installed. ' +\n          'Install it as a peer dependency to use OpenLLMetry integration.',\n      );\n    }\n  }\n\n  initialized = true;\n}\n\n/**\n * Extract instrumentation class names from instrumentation instances\n * Used to detect duplicates between manual and auto instrumentations\n */\nfunction getInstrumentationNames(\n  instrumentations: NodeSDKConfiguration['instrumentations'],\n): Set<string> {\n  const names = new Set<string>();\n\n  if (!instrumentations) return names;\n\n  for (const instrumentation of instrumentations) {\n    if (instrumentation && typeof instrumentation === 'object') {\n      names.add(instrumentation.constructor.name);\n    }\n  }\n\n  return names;\n}\n\n/**\n * Map common instrumentation class names to their package names\n * Used to disable auto-instrumentations when user provides manual configs\n */\nconst INSTRUMENTATION_CLASS_TO_PACKAGE: Record<string, string> = {\n  HttpInstrumentation: '@opentelemetry/instrumentation-http',\n  HttpsInstrumentation: '@opentelemetry/instrumentation-http',\n  ExpressInstrumentation: '@opentelemetry/instrumentation-express',\n  FastifyInstrumentation: '@opentelemetry/instrumentation-fastify',\n  MongoDBInstrumentation: '@opentelemetry/instrumentation-mongodb',\n  MongooseInstrumentation: '@opentelemetry/instrumentation-mongoose',\n  PrismaInstrumentation: '@opentelemetry/instrumentation-prisma',\n  PinoInstrumentation: '@opentelemetry/instrumentation-pino',\n  WinstonInstrumentation: '@opentelemetry/instrumentation-winston',\n  RedisInstrumentation: '@opentelemetry/instrumentation-redis',\n  GraphQLInstrumentation: '@opentelemetry/instrumentation-graphql',\n  GrpcInstrumentation: '@opentelemetry/instrumentation-grpc',\n  IORedisInstrumentation: '@opentelemetry/instrumentation-ioredis',\n  KnexInstrumentation: '@opentelemetry/instrumentation-knex',\n  NestJsInstrumentation: '@opentelemetry/instrumentation-nestjs-core',\n  PgInstrumentation: '@opentelemetry/instrumentation-pg',\n  MySQLInstrumentation: '@opentelemetry/instrumentation-mysql',\n  MySQL2Instrumentation: '@opentelemetry/instrumentation-mysql2',\n};\n\n/**\n * Type for the auto-instrumentations loader function\n * @internal Used for testing injection\n */\nexport type AutoInstrumentationsLoader = (\n  config?: Record<string, { enabled?: boolean }>,\n) => unknown[];\n\n/**\n * Detect if we're running in ESM mode\n */\nfunction isESMMode(): boolean {\n  // Check if we're in an ESM context by looking for common ESM indicators\n  try {\n    // In ESM, module.exports doesn't exist in the global scope the same way\n    // Also check if the package.json type is \"module\"\n    const fs = requireModule<typeof import('node:fs')>('node:fs');\n    try {\n      const pkg = JSON.parse(\n        fs.readFileSync(`${process.cwd()}/package.json`, 'utf8'),\n      );\n      return pkg.type === 'module';\n    } catch {\n      return false;\n    }\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Lazy-load auto-instrumentations (optional peer dependency)\n * Only loads when integrations config is truthy, avoiding ~40+ package imports at startup.\n */\nfunction loadNodeAutoInstrumentations(): AutoInstrumentationsLoader {\n  try {\n    const mod = requireModule<{\n      getNodeAutoInstrumentations: AutoInstrumentationsLoader;\n    }>('@opentelemetry/auto-instrumentations-node');\n    return mod.getNodeAutoInstrumentations;\n  } catch {\n    const isESM = isESMMode();\n    const baseMessage = '@opentelemetry/auto-instrumentations-node not found.';\n\n    if (isESM) {\n      throw new Error(\n        `${baseMessage}\\n\\n` +\n          'ESM Setup Required:\\n' +\n          '1. Install as a direct dependency: pnpm add @opentelemetry/auto-instrumentations-node\\n' +\n          '2. Create instrumentation.mjs with:\\n' +\n          \"   import 'autotel/register';  // MUST be first!\\n\" +\n          \"   import { init } from 'autotel';\\n\" +\n          \"   import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';\\n\" +\n          '   init({ service: \"my-app\", instrumentations: getNodeAutoInstrumentations() });\\n' +\n          '3. Run with: tsx --import ./instrumentation.mjs src/index.ts\\n\\n' +\n          'See: https://github.com/jagreehal/autotel#esm-setup',\n      );\n    }\n\n    throw new Error(\n      `${baseMessage} Install it: pnpm add @opentelemetry/auto-instrumentations-node`,\n    );\n  }\n}\n\n/**\n * Injectable loader for testing. Set to override the default loader.\n * @internal\n */\nlet _autoInstrumentationsLoader: (() => AutoInstrumentationsLoader) | null =\n  null;\n\n/**\n * @internal Set custom loader (for testing)\n */\nexport function _setAutoInstrumentationsLoader(\n  loader: (() => AutoInstrumentationsLoader) | null,\n): void {\n  _autoInstrumentationsLoader = loader;\n}\n\n/**\n * @internal Reset loader to default (for testing cleanup)\n */\nexport function _resetAutoInstrumentationsLoader(): void {\n  _autoInstrumentationsLoader = null;\n}\n\n/**\n * Get auto-instrumentations based on simple integration names\n * Excludes instrumentations that are manually provided to avoid conflicts\n */\nfunction getAutoInstrumentations(\n  integrations: string[] | boolean | Record<string, { enabled?: boolean }>,\n  manualInstrumentationNames: Set<string> = new Set(),\n): unknown[] {\n  if (integrations === false) {\n    return [];\n  }\n\n  // Use injected loader if set (for testing), otherwise lazy-load\n  const getNodeAutoInstrumentations = _autoInstrumentationsLoader\n    ? _autoInstrumentationsLoader()\n    : loadNodeAutoInstrumentations();\n\n  // Build exclusion config for manual instrumentations\n  const exclusionConfig: Record<string, { enabled: boolean }> = {};\n  for (const className of manualInstrumentationNames) {\n    const packageName = INSTRUMENTATION_CLASS_TO_PACKAGE[className];\n    if (packageName) {\n      exclusionConfig[packageName] = { enabled: false };\n    }\n  }\n\n  if (integrations === true) {\n    // If exclusions exist, pass them to getNodeAutoInstrumentations\n    if (Object.keys(exclusionConfig).length > 0) {\n      return getNodeAutoInstrumentations(exclusionConfig);\n    }\n    return getNodeAutoInstrumentations();\n  }\n\n  if (Array.isArray(integrations)) {\n    const config: Record<string, { enabled: boolean }> = { ...exclusionConfig };\n    for (const name of integrations) {\n      const packageName = `@opentelemetry/instrumentation-${name}`;\n      // Don't override exclusions\n      if (!exclusionConfig[packageName]) {\n        config[packageName] = { enabled: true };\n      }\n    }\n    return getNodeAutoInstrumentations(config);\n  }\n\n  const config: Record<string, { enabled?: boolean }> = {\n    ...exclusionConfig,\n    ...integrations,\n  };\n\n  // Override any integrations that conflict with manual instrumentations\n  for (const packageName of Object.keys(exclusionConfig)) {\n    const integrationsKey = Object.keys(integrations).find((key) =>\n      packageName.includes(key),\n    );\n    if (integrationsKey) {\n      // Manual instrumentation takes precedence\n      config[packageName] = { enabled: false };\n    }\n  }\n\n  return getNodeAutoInstrumentations(config);\n}\n\n/**\n * Check if autotel has been initialized\n */\nexport function isInitialized(): boolean {\n  return initialized;\n}\n\n/**\n * Get current config (internal use)\n */\nexport function getConfig(): AutotelConfig | null {\n  return config;\n}\n\n/**\n * Get current logger (internal use)\n */\nexport function getLogger(): Logger {\n  return logger;\n}\n\n/**\n * Get validation config (internal use)\n */\nexport function getValidationConfig(): Partial<ValidationConfig> | null {\n  return validationConfig;\n}\n\n/**\n * Get events config (internal use)\n */\nexport function getEventsConfig(): EventsConfig | null {\n  return eventsConfig;\n}\n\n/**\n * Warn once if not initialized (same behavior in all environments)\n */\nexport function warnIfNotInitialized(context: string): void {\n  if (!initialized && !warnedOnce) {\n    logger.warn(\n      {},\n      `[autotel] ${context} used before init() called. ` +\n        'Call init({ service: \"...\" }) first. See: https://docs.autotel.dev/quickstart',\n    );\n    warnedOnce = true;\n  }\n}\n\n/**\n * Get default sampler\n */\nexport function getDefaultSampler(): Sampler {\n  return config?.sampler || samplingPresets.production();\n}\n\n/**\n * Auto-detect version from package.json\n */\nfunction detectVersion(): string {\n  try {\n    // Try to read package.json from cwd using fs\n    const fs = requireModule<typeof import('node:fs')>('node:fs');\n    const pkg = JSON.parse(\n      fs.readFileSync(`${process.cwd()}/package.json`, 'utf8'),\n    );\n    return pkg.version || '1.0.0';\n  } catch {\n    return '1.0.0';\n  }\n}\n\n/**\n * Detect hostname for resource attributes.\n * Supports Datadog conventions (DD_HOSTNAME) and falls back to system hostname.\n *\n * Priority order:\n * 1. DD_HOSTNAME environment variable (Datadog convention)\n * 2. HOSTNAME environment variable (common Unix convention)\n * 3. os.hostname() (system hostname)\n *\n * @returns hostname string or undefined if detection fails\n */\nfunction detectHostname(): string | undefined {\n  // Priority 1: DD_HOSTNAME (Datadog convention)\n  if (process.env.DD_HOSTNAME) {\n    return process.env.DD_HOSTNAME;\n  }\n\n  // Priority 2: HOSTNAME (common in containers and Unix systems)\n  if (process.env.HOSTNAME) {\n    return process.env.HOSTNAME;\n  }\n\n  // Priority 3: System hostname\n  try {\n    const os = requireModule<typeof import('node:os')>('node:os');\n    return os.hostname();\n  } catch {\n    // os module not available (edge runtime, browser, etc.)\n    return undefined;\n  }\n}\n\n/**\n * Get the string redactor configured via init({ attributeRedactor }).\n * Returns null if no redactor was configured.\n */\nexport function getStringRedactor(): StringRedactor | null {\n  return _stringRedactor;\n}\n\n/**\n * @internal Override optional require for deterministic tests.\n */\nexport function _setOptionalRequireForTesting(\n  loader: typeof safeRequire,\n): void {\n  _optionalRequire = loader;\n}\n\n/**\n * @internal Reset optional require override.\n */\nexport function _resetOptionalRequireForTesting(): void {\n  _optionalRequire = safeRequire;\n}\n\n/**\n * @internal Close embedded devtools if running.\n */\nexport async function _closeEmbeddedDevtools(): Promise<void> {\n  if (_devtoolsClose) {\n    await _devtoolsClose();\n    _devtoolsClose = null;\n  }\n}\n\n/**\n * @internal Get embedded devtools close handle.\n */\nexport function _getEmbeddedDevtoolsCloseForTesting():\n  | (() => Promise<void> | void)\n  | null {\n  return _devtoolsClose;\n}\n\n/**\n * Get SDK instance (for shutdown)\n */\nexport function getSdk(): NodeSDK | null {\n  return sdk;\n}\n"],"mappings":"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"}