{"version":3,"sources":["../src/db.ts"],"names":["getConfig","SpanStatusCode"],"mappings":"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","file":"db.cjs","sourcesContent":["/**\n * Database Instrumentation Helpers\n *\n * Optional import: Not included in main bundle\n * Import from: 'autotel/db'\n *\n * Provides functional utilities for database query instrumentation.\n * Works with Prisma, Drizzle, TypeORM, raw SQL, and more.\n *\n * @example\n * ```typescript\n * import { instrumentDatabase } from 'autotel/db'\n *\n * const db = drizzle(pool)\n * instrumentDatabase(db, { dbSystem: 'postgresql', dbName: 'myapp' })\n *\n * // Now all queries are automatically trace\n * await db.select().from(users)\n * ```\n */\n\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { getConfig } from './config';\n\n/**\n * Helper: Trace a single database query\n *\n * @example\n * ```typescript\n * import { tracebQuery } from 'autotel/db'\n *\n * const users = await tracebQuery(\n *   'postgresql',\n *   'SELECT',\n *   () => db.query('SELECT * FROM users WHERE active = true')\n * )\n * ```\n */\nexport async function tracebQuery<T>(\n  dbSystem: string,\n  operation: string,\n  fn: () => Promise<T>,\n  attributes?: Record<string, string | number>,\n): Promise<T> {\n  const config = getConfig();\n  const tracer = config.tracer;\n\n  const spanName = `${dbSystem}.${operation}`;\n\n  return tracer.startActiveSpan(spanName, async (span) => {\n    const startTime = performance.now();\n\n    try {\n      span.setAttributes({\n        'db.system': dbSystem,\n        'db.operation': operation,\n        ...attributes,\n      });\n\n      const result = await fn();\n\n      const duration = performance.now() - startTime;\n      span.setStatus({ code: SpanStatusCode.OK });\n      span.setAttribute('db.duration_ms', duration);\n\n      if (Array.isArray(result)) {\n        span.setAttribute('db.result_count', result.length);\n      }\n\n      return result;\n    } catch (error) {\n      const duration = performance.now() - startTime;\n\n      span.setStatus({\n        code: SpanStatusCode.ERROR,\n        message: error instanceof Error ? error.message : 'Unknown error',\n      });\n\n      span.setAttributes({\n        'db.duration_ms': duration,\n        'error.type':\n          error instanceof Error ? error.constructor.name : 'Unknown',\n        'error.message':\n          error instanceof Error ? error.message : 'Unknown error',\n      });\n\n      throw error;\n    } finally {\n      span.end();\n    }\n  });\n}\n\n// Helper functions\n\nfunction inferDbOperation(methodName: string): string {\n  const lower = methodName.toLowerCase();\n  if (lower.includes('find') || lower.includes('get') || lower.includes('list'))\n    return 'SELECT';\n  if (lower.includes('create') || lower.includes('insert')) return 'INSERT';\n  if (lower.includes('update') || lower.includes('modify')) return 'UPDATE';\n  if (lower.includes('delete') || lower.includes('remove')) return 'DELETE';\n  if (lower.includes('count')) return 'COUNT';\n  return 'QUERY';\n}\n\nfunction inferTableName(methodName: string): string | undefined {\n  // Extract table name from method patterns like:\n  // findUser -> user\n  // listUsers -> users\n  // createOrder -> order\n\n  const patterns = [\n    /find([A-Z][a-zA-Z]+)/,\n    /get([A-Z][a-zA-Z]+)/,\n    /list([A-Z][a-zA-Z]+)/,\n    /create([A-Z][a-zA-Z]+)/,\n    /update([A-Z][a-zA-Z]+)/,\n    /delete([A-Z][a-zA-Z]+)/,\n    /remove([A-Z][a-zA-Z]+)/,\n  ];\n\n  for (const pattern of patterns) {\n    const match = methodName.match(pattern);\n    if (match && match[1]) {\n      return match[1].toLowerCase();\n    }\n  }\n\n  return undefined;\n}\n\nfunction sanitizeSqlQuery(query: string): string {\n  // Remove string literals and sensitive values (PII, credentials, etc.)\n  // Preserves query structure for debugging while protecting data\n  return query\n    .replaceAll(/'[^']*'/g, \"'?'\")\n    .replaceAll(/\"[^\"]*\"/g, '\"?\"')\n    .replaceAll(/\\b\\d+\\b/g, '?') // Replace literal numbers\n    .trim();\n}\n\n/**\n * Common database operation metrics\n */\nexport const DB_OPERATIONS = {\n  SELECT: 'SELECT',\n  INSERT: 'INSERT',\n  UPDATE: 'UPDATE',\n  DELETE: 'DELETE',\n  COUNT: 'COUNT',\n  AGGREGATE: 'AGGREGATE',\n} as const;\n\n/**\n * Common database systems\n */\nexport const DB_SYSTEMS = {\n  POSTGRESQL: 'postgresql',\n  MYSQL: 'mysql',\n  MONGODB: 'mongodb',\n  REDIS: 'redis',\n  SQLITE: 'sqlite',\n  MSSQL: 'mssql',\n} as const;\n\n// Symbol for idempotency - prevents double-instrumentation\nconst INSTRUMENTED_SYMBOL = Symbol.for('autotel.db.instrumented');\n\n/**\n * Options for instrumentDatabase\n */\nexport interface InstrumentDatabaseOptions {\n  /** Database system (e.g., 'postgresql', 'mysql') */\n  dbSystem: string;\n  /** Database name (optional) */\n  dbName?: string;\n  /** Method names to instrument (if not provided, instruments common patterns) */\n  methods?: string[];\n  /** Method names to skip */\n  skipMethods?: string[];\n  /** Sanitize queries (remove sensitive data) - default: true */\n  sanitizeQuery?: boolean;\n  /** Slow query threshold in milliseconds - default: 1000ms */\n  slowQueryThresholdMs?: number;\n}\n\n/**\n * Instrument a database client instance with OpenTelemetry tracing\n *\n * This is a function-based alternative to @DbInstrumented decorator.\n * Modifies the client in-place and returns it (idempotent - safe to call multiple times).\n *\n * Inspired by otel-drizzle and other otel instrumentation packages.\n *\n * @example Drizzle ORM\n * ```typescript\n * import { drizzle } from 'drizzle-orm/node-postgres'\n * import { instrumentDatabase } from 'autotel/db'\n *\n * const db = drizzle(pool)\n * instrumentDatabase(db, { dbSystem: 'postgresql', dbName: 'myapp' })\n *\n * // Now all db queries are automatically trace\n * await db.select().from(users)\n * ```\n *\n * @example Prisma\n * ```typescript\n * import { PrismaClient } from '@prisma/client'\n * import { instrumentDatabase } from 'autotel/db'\n *\n * const prisma = new PrismaClient()\n * instrumentDatabase(prisma, {\n *   dbSystem: 'postgresql',\n *   methods: ['findMany', 'findUnique', 'create', 'update', 'delete']\n * })\n *\n * // All specified methods are trace\n * await prisma.user.findMany()\n * ```\n *\n * @example Generic database client\n * ```typescript\n * import { instrumentDatabase } from 'autotel/db'\n *\n * const db = createDatabaseClient()\n * instrumentDatabase(db, {\n *   dbSystem: 'mongodb',\n *   methods: ['find', 'findOne', 'insertOne', 'updateOne', 'deleteOne']\n * })\n * ```\n */\nexport function instrumentDatabase<T extends object>(\n  client: T,\n  options: InstrumentDatabaseOptions,\n): T {\n  // Idempotency check - if already instrumented, return as-is\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  if ((client as any)[INSTRUMENTED_SYMBOL]) {\n    return client;\n  }\n\n  const {\n    dbSystem,\n    dbName,\n    methods,\n    skipMethods = [],\n    sanitizeQuery = true,\n    slowQueryThresholdMs = 1000,\n  } = options;\n\n  const config = getConfig();\n  const tracer = config.tracer;\n\n  // Determine which methods to instrument\n  const methodsToInstrument = methods || extractDatabaseMethods(client);\n  const skipSet = new Set(skipMethods);\n\n  for (const methodName of methodsToInstrument) {\n    if (skipSet.has(methodName)) continue;\n    if (methodName.startsWith('_')) continue; // Skip private methods\n\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const method = (client as any)[methodName];\n    if (typeof method !== 'function') continue;\n\n    // Preserve the original method\n    const originalMethod = method;\n\n    // Wrap the method\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    (client as any)[methodName] = async function (this: T, ...args: any[]) {\n      const operation = inferDbOperation(methodName);\n      const table = inferTableName(methodName);\n\n      const spanName = table\n        ? `${dbSystem}.${operation} ${table}`\n        : `${dbSystem}.${operation}`;\n\n      return tracer.startActiveSpan(spanName, async (span) => {\n        const startTime = performance.now();\n\n        try {\n          span.setAttributes({\n            'db.system': dbSystem,\n            'db.operation': operation,\n          });\n\n          if (dbName) {\n            span.setAttribute('db.name', dbName);\n          }\n\n          if (table) {\n            span.setAttribute('db.sql.table', table);\n          }\n\n          // Try to extract query from arguments (common patterns)\n          const query = extractQueryFromArgs(args);\n          if (query) {\n            span.setAttribute(\n              'db.statement',\n              sanitizeQuery ? sanitizeSqlQuery(query) : query,\n            );\n          }\n\n          // Execute original method\n          const result = await originalMethod.apply(this, args);\n\n          const duration = performance.now() - startTime;\n\n          span.setStatus({ code: SpanStatusCode.OK });\n          span.setAttributes({\n            'db.duration_ms': duration,\n          });\n\n          // Mark slow queries\n          if (duration > slowQueryThresholdMs) {\n            span.setAttribute('db.slow_query', true);\n            span.setAttribute(\n              'db.slow_query_threshold_ms',\n              slowQueryThresholdMs,\n            );\n          }\n\n          // Track result count if it's an array\n          if (Array.isArray(result)) {\n            span.setAttribute('db.result_count', result.length);\n          }\n\n          return result;\n        } catch (error) {\n          const duration = performance.now() - startTime;\n\n          span.setStatus({\n            code: SpanStatusCode.ERROR,\n            message: error instanceof Error ? error.message : 'Unknown error',\n          });\n\n          span.setAttributes({\n            'db.duration_ms': duration,\n            'error.type':\n              error instanceof Error ? error.constructor.name : 'Unknown',\n            'error.message':\n              error instanceof Error ? error.message : 'Unknown error',\n          });\n\n          span.recordException(\n            error instanceof Error ? error : new Error(String(error)),\n          );\n\n          throw error;\n        } finally {\n          span.end();\n        }\n      });\n    };\n\n    // Preserve function name\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    Object.defineProperty((client as any)[methodName], 'name', {\n      value: methodName,\n      configurable: true,\n    });\n  }\n\n  // Mark as instrumented\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  (client as any)[INSTRUMENTED_SYMBOL] = true;\n\n  return client;\n}\n\n/**\n * Extract method names from a database client that should be instrumented\n */\nfunction extractDatabaseMethods(client: object): string[] {\n  const methods: string[] = [];\n  const proto = Object.getPrototypeOf(client);\n\n  // Get own methods\n  for (const key of Object.getOwnPropertyNames(client)) {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    if (typeof (client as any)[key] === 'function' && !key.startsWith('_')) {\n      methods.push(key);\n    }\n  }\n\n  // Get prototype methods\n  if (proto) {\n    for (const key of Object.getOwnPropertyNames(proto)) {\n      if (\n        typeof proto[key] === 'function' &&\n        !key.startsWith('_') &&\n        key !== 'constructor'\n      ) {\n        methods.push(key);\n      }\n    }\n  }\n\n  return [...new Set(methods)]; // Deduplicate\n}\n\n/**\n * Try to extract SQL query from common argument patterns\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction extractQueryFromArgs(args: any[]): string | undefined {\n  if (args.length === 0) return undefined;\n\n  const firstArg = args[0];\n\n  // String query (raw SQL)\n  if (typeof firstArg === 'string') {\n    return firstArg;\n  }\n\n  // Object with sql property\n  if (firstArg && typeof firstArg === 'object') {\n    if ('sql' in firstArg && typeof firstArg.sql === 'string') {\n      return firstArg.sql;\n    }\n    // PostgreSQL-style query object\n    if ('text' in firstArg && typeof firstArg.text === 'string') {\n      return firstArg.text;\n    }\n    // Query builder pattern\n    if ('toQuery' in firstArg && typeof firstArg.toQuery === 'function') {\n      try {\n        const queryResult = firstArg.toQuery();\n        if (typeof queryResult === 'string') return queryResult;\n        if (\n          queryResult &&\n          typeof queryResult === 'object' &&\n          'sql' in queryResult\n        ) {\n          return queryResult.sql as string;\n        }\n      } catch {\n        // Ignore errors from toQuery()\n      }\n    }\n  }\n\n  return undefined;\n}\n"]}