{"version":3,"file":"index.cjs","names":[],"sources":["../../src/telemetry/console-logger.ts","../../src/telemetry/metrics-aggregator.ts","../../src/telemetry/noop.ts","../../src/telemetry/structured-logger.ts"],"sourcesContent":["declare const process: { stderr: WriteStream }\ndeclare const console: { error: (message: string, extra?: string) => void }\n\nimport type { RequestEndEvent, RequestStartEvent, RetryEvent, TelemetryOptions } from \"@/types\"\n\ntype WriteStream = {\n  write: (data: string) => boolean\n}\n\n// Simple ANSI color mapping for Node.js terminals\nconst ansiColors: Record<string, string> = {\n  cyan: \"\\x1b[36m\",\n  gray: \"\\x1b[90m\",\n  green: \"\\x1b[32m\",\n  red: \"\\x1b[31m\",\n  yellow: \"\\x1b[33m\",\n  reset: \"\\x1b[0m\",\n}\n\nconst styleText = (text: string, color: string): string => {\n  const code = ansiColors[color]\n  if (!code) return text\n  return `${code}${text}${ansiColors.reset}`\n}\n\nexport type ConsoleLoggerOptions = {\n  /**\n   * Enable colored output using ANSI escape codes.\n   * @default true\n   */\n  colors?: boolean\n\n  /**\n   * Include timestamps in output.\n   * @default true\n   */\n  timestamps?: boolean\n\n  /**\n   * Stream to write output to.\n   * @default process.stderr\n   */\n  errorStream?: WriteStream\n}\n\n/**\n * Create a console logger that formats telemetry events as human-readable output.\n *\n * @example\n * ```typescript\n * const client = new EdgarClient({\n *   userAgent: \"Bot/1.0\",\n *   telemetry: createConsoleLogger()\n * })\n * ```\n */\nexport function createConsoleLogger(options: ConsoleLoggerOptions = {}): TelemetryOptions {\n  const { colors = true, timestamps = true, errorStream = process.stderr } = options\n\n  const colorize = (text: string, color: string) => {\n    if (!colors) return text\n    return styleText(text, color)\n  }\n\n  const write = (message: string) => {\n    errorStream.write(`${message}\\n`)\n  }\n\n  const formatTimestamp = () => {\n    if (!timestamps) return \"\"\n    return `[${new Date().toISOString()}] `\n  }\n\n  const onRequestStart = (event: RequestStartEvent) => {\n    try {\n      const msg = `${formatTimestamp()}${colorize(\"→\", \"cyan\")} ${event.method} ${event.url} ${colorize(`[${event.operation}]`, \"gray\")} {${event.requestId.slice(0, 8)}}`\n      write(msg)\n    } catch (err) {\n      console.error(\n        \"[edgar-ts/telemetry:console-logger] Error in onRequestStart:\",\n        (err as Error).message,\n      )\n      write(JSON.stringify(event))\n    }\n  }\n\n  const onRequestEnd = (event: RequestEndEvent) => {\n    try {\n      const statusColor = event.statusCode >= 200 && event.statusCode < 300 ? \"green\" : \"red\"\n      const msg = `${formatTimestamp()}${colorize(\"←\", \"cyan\")} ${colorize(String(event.statusCode), statusColor)} ${event.method} ${event.url} ${colorize(`${event.durationMs}ms`, \"gray\")} ${colorize(`[${event.operation}]`, \"gray\")}`\n      write(msg)\n    } catch (err) {\n      console.error(\n        \"[edgar-ts/telemetry:console-logger] Error in onRequestEnd:\",\n        (err as Error).message,\n      )\n      write(JSON.stringify(event))\n    }\n  }\n\n  const onRetry = (event: RetryEvent) => {\n    try {\n      const msg = `${formatTimestamp()}${colorize(\"⟳\", \"yellow\")} Retry ${event.attempt}/${event.maxAttempts} after ${event.delayMs}ms: ${event.url} (${colorize(event.error, \"red\")})`\n      write(msg)\n    } catch (err) {\n      console.error(\"[edgar-ts/telemetry:console-logger] Error in onRetry:\", (err as Error).message)\n      write(JSON.stringify(event))\n    }\n  }\n\n  return {\n    onRequestStart,\n    onRequestEnd,\n    onRetry,\n  }\n}\n","declare const console: { error: (message: string, extra?: string) => void }\n\nimport type { RequestEndEvent, RequestStartEvent, RetryEvent, TelemetryOptions } from \"@/types\"\n\ntype LatencyStats = {\n  count: number\n  min: number\n  max: number\n  avg: number\n  total: number\n}\n\nexport type MetricsSnapshot = {\n  requestsTotal: number\n  requestsSuccessful: number\n  requestsFailed: number\n  requestsFailedByError: Record<string, number>\n  retriesTotal: number\n  latencyByOperation: Record<string, LatencyStats>\n  rateLimitedRequests: number\n  runtime: \"node\" | \"bun\"\n}\n\n/**\n * Create a metrics aggregator that tracks request lifecycle and rate limiting metrics.\n *\n * @example\n * ```typescript\n * const metrics = createMetricsAggregator()\n * const client = new EdgarClient({\n *   userAgent: \"Bot/1.0\",\n *   telemetry: metrics\n * })\n *\n * // Later...\n * const snapshot = metrics.getSnapshot()\n * console.log(snapshot.requestsTotal)\n * console.log(snapshot.latencyByOperation)\n * ```\n */\nexport function createMetricsAggregator(): TelemetryOptions & {\n  getSnapshot(): MetricsSnapshot\n  reset(): void\n} {\n  let requestsTotal = 0\n  let requestsSuccessful = 0\n  let requestsFailed = 0\n  let retriesTotal = 0\n  let rateLimitedRequests = 0\n  let detectedRuntime: \"node\" | \"bun\" = \"node\"\n\n  const requestsFailedByError: Record<string, number> = {}\n  const latencyByOperation: Record<string, LatencyStats> = {}\n\n  const onRequestStart = (event: RequestStartEvent) => {\n    try {\n      requestsTotal++\n      detectedRuntime = event.runtime\n    } catch (err) {\n      console.error(\n        \"[edgar-ts/telemetry:metrics-aggregator] Error in onRequestStart:\",\n        (err as Error).message,\n      )\n    }\n  }\n\n  const onRequestEnd = (event: RequestEndEvent) => {\n    try {\n      const isSuccess = event.statusCode >= 200 && event.statusCode < 300\n\n      if (isSuccess) {\n        requestsSuccessful++\n      } else {\n        requestsFailed++\n        const errorKey = String(event.statusCode)\n        requestsFailedByError[errorKey] = (requestsFailedByError[errorKey] || 0) + 1\n      }\n\n      // Track latency\n      const operation = event.operation || \"unknown\"\n      const durationMs = event.durationMs\n\n      if (Number.isNaN(durationMs) || !Number.isFinite(durationMs)) {\n        console.error(\n          \"[edgar-ts/telemetry:metrics-aggregator] Invalid durationMs:\",\n          String(durationMs),\n        )\n        return\n      }\n\n      if (!latencyByOperation[operation]) {\n        latencyByOperation[operation] = {\n          count: 0,\n          min: Infinity,\n          max: -Infinity,\n          avg: 0,\n          total: 0,\n        }\n      }\n\n      const stats = latencyByOperation[operation]\n      stats.count++\n      stats.min = Math.min(stats.min, durationMs)\n      stats.max = Math.max(stats.max, durationMs)\n      stats.total += durationMs\n      stats.avg = stats.total / stats.count\n    } catch (err) {\n      console.error(\n        \"[edgar-ts/telemetry:metrics-aggregator] Error in onRequestEnd:\",\n        (err as Error).message,\n      )\n    }\n  }\n\n  const onRetry = (event: RetryEvent) => {\n    try {\n      retriesTotal++\n\n      if (event.error.includes(\"RATE_LIMITED\")) {\n        rateLimitedRequests++\n      }\n    } catch (err) {\n      console.error(\n        \"[edgar-ts/telemetry:metrics-aggregator] Error in onRetry:\",\n        (err as Error).message,\n      )\n    }\n  }\n\n  const getSnapshot = (): MetricsSnapshot => {\n    return {\n      requestsTotal,\n      requestsSuccessful,\n      requestsFailed,\n      requestsFailedByError: { ...requestsFailedByError },\n      retriesTotal,\n      latencyByOperation: { ...latencyByOperation },\n      rateLimitedRequests,\n      runtime: detectedRuntime,\n    }\n  }\n\n  const reset = () => {\n    requestsTotal = 0\n    requestsSuccessful = 0\n    requestsFailed = 0\n    retriesTotal = 0\n    rateLimitedRequests = 0\n    Object.keys(requestsFailedByError).forEach((key) => {\n      delete requestsFailedByError[key]\n    })\n    Object.keys(latencyByOperation).forEach((key) => {\n      delete latencyByOperation[key]\n    })\n  }\n\n  return {\n    onRequestStart,\n    onRequestEnd,\n    onRetry,\n    getSnapshot,\n    reset,\n  }\n}\n","import type { TelemetryOptions } from \"@/types\"\n\n/**\n * Create a no-op telemetry implementation (all hooks are empty functions).\n * Useful for testing or explicitly disabling telemetry without removing code.\n *\n * @example\n * ```typescript\n * const client = new EdgarClient({\n *   userAgent: \"Bot/1.0\",\n *   telemetry: createNoopTelemetry()\n * })\n * ```\n */\nexport function createNoopTelemetry(): TelemetryOptions {\n  return {\n    onRequestStart: () => {},\n    onRequestEnd: () => {},\n    onRetry: () => {},\n  }\n}\n","declare const process: { stdout: WritableStream }\ndeclare const console: { error: (message: string, extra?: string) => void }\n\nimport type { RequestEndEvent, RequestStartEvent, RetryEvent, TelemetryOptions } from \"@/types\"\n\ntype TelemetryEvent = RequestStartEvent | RequestEndEvent | RetryEvent\n\ntype WritableStream = {\n  write: (data: string) => boolean\n  writable: boolean\n}\n\nexport type StructuredLoggerOptions = {\n  /**\n   * Writable stream to output logs to.\n   * @default process.stdout\n   */\n  stream?: WritableStream\n\n  /**\n   * Custom formatter for events.\n   * @default JSON.stringify\n   */\n  formatter?: (event: TelemetryEvent & { event: string }) => string\n}\n\n/**\n * Create a structured logger that outputs JSON Lines format (one JSON object per line).\n *\n * @example\n * ```typescript\n * const client = new EdgarClient({\n *   userAgent: \"Bot/1.0\",\n *   telemetry: createStructuredLogger()\n * })\n * ```\n */\nexport function createStructuredLogger(options: StructuredLoggerOptions = {}): TelemetryOptions {\n  const { stream = process.stdout, formatter = (event) => JSON.stringify(event) } = options\n\n  // Validate stream at creation time\n  if (!stream.writable) {\n    throw new Error(\"stream must be writable\")\n  }\n\n  const write = (eventType: string, event: TelemetryEvent) => {\n    try {\n      const payload = { event: eventType, ...event }\n      const output = formatter(payload)\n      stream.write(`${output}\\n`)\n    } catch (err) {\n      console.error(\n        \"[edgar-ts/telemetry:structured-logger] Error serializing event:\",\n        (err as Error).message,\n      )\n    }\n  }\n\n  const onRequestStart = (event: RequestStartEvent) => {\n    write(\"request.start\", event)\n  }\n\n  const onRequestEnd = (event: RequestEndEvent) => {\n    write(\"request.end\", event)\n  }\n\n  const onRetry = (event: RetryEvent) => {\n    write(\"request.retry\", event)\n  }\n\n  return {\n    onRequestStart,\n    onRequestEnd,\n    onRetry,\n  }\n}\n"],"mappings":"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"}