@spfn/core 0.2.0-beta.5 → 0.2.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/db/postgres-errors.ts","../../src/db/manager/connection.ts","../../src/db/manager/config.ts","../../src/db/manager/factory.ts","../../src/db/manager/global-state.ts","../../src/db/manager/health-check.ts","../../src/db/manager/manager.ts","../../src/db/manager/config-generator.ts","../../src/db/schema/entity-helper.ts","../../src/db/schema/schema-helper.ts","../../src/db/transaction/context.ts","../../src/db/transaction/runner.ts","../../src/db/transaction/middleware.ts","../../src/db/query-utils.ts","../../src/db/helpers.ts","../../src/db/repository.ts"],"names":["ConnectionError","dbLogger","logger","getDatabase","closeDatabase","env","dir","packageSchemas","schema","pgUuid","txLogger","TransactionError","DatabaseError","sqlCount"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * PostgreSQL Error Conversion Utilities\n *\n * Converts PostgreSQL-specific error codes to custom error types\n * @see https://www.postgresql.org/docs/current/errcodes-appendix.html\n */\n\nimport {\n DatabaseError,\n ConnectionError,\n DuplicateEntryError,\n DeadlockError,\n ConstraintViolationError,\n QueryError,\n TransactionError,\n} from '@spfn/core/errors';\n\n/**\n * Extract field and value from PostgreSQL unique violation message\n *\n * Handles various formats:\n * - Simple: Key (email)=(test@example.com)\n * - Complex: Key (user_id, tenant_id)=(123, 456)\n * - With quotes: Key (\"field\")=('value')\n */\nfunction parseUniqueViolation(message: string): { field: string; value: string } | null\n{\n // Try multiple patterns for robustness\n const patterns = [\n // Standard format: Key (field)=(value)\n /Key \\(([^)]+)\\)=\\(([^)]+)\\)/i,\n // With quotes: Key (\"field\")=('value')\n /Key \\([\"']?([^)\"']+)[\"']?\\)=\\([\"']?([^)\"']+)[\"']?\\)/i,\n // Alternative format\n /Key `([^`]+)`=`([^`]+)`/i,\n ];\n\n for (const pattern of patterns)\n {\n const match = message.match(pattern);\n if (match)\n {\n // Clean up extracted values\n const field = match[1].trim().replace(/[\"'`]/g, '');\n const value = match[2].trim().replace(/[\"'`]/g, '');\n return { field, value };\n }\n }\n\n return null;\n}\n\n/**\n * Convert PostgreSQL error to custom DatabaseError\n *\n * Maps PostgreSQL error codes to appropriate error classes with correct status codes\n *\n * @param error - PostgreSQL error object (from pg driver or Drizzle)\n * @returns Custom DatabaseError instance\n *\n * @example\n * ```typescript\n * import { fromPostgresError } from '@spfn/core/db';\n *\n * try {\n * await db.insert(users).values(data);\n * } catch (pgError) {\n * throw fromPostgresError(pgError);\n * }\n * ```\n */\nexport function fromPostgresError(error: any): DatabaseError\n{\n const code = error?.code;\n const message = error?.message || 'Database error occurred';\n\n switch (code)\n {\n // Class 08 — Connection Exception\n case '08000': // connection_exception\n case '08001': // sqlclient_unable_to_establish_sqlconnection\n case '08003': // connection_does_not_exist\n case '08004': // sqlserver_rejected_establishment_of_sqlconnection\n case '08006': // connection_failure\n case '08007': // transaction_resolution_unknown\n case '08P01': // protocol_violation\n return new ConnectionError({ message, details: { code } });\n\n // Class 23 — Integrity Constraint Violation\n case '23000': // integrity_constraint_violation\n case '23001': // restrict_violation\n return new ConstraintViolationError({ message, details: { code, constraint: 'integrity' } });\n\n case '23502': // not_null_violation\n return new ConstraintViolationError({ message, details: { code, constraint: 'not_null' } });\n\n case '23503': // foreign_key_violation\n return new ConstraintViolationError({ message, details: { code, constraint: 'foreign_key' } });\n\n case '23505': // unique_violation\n const parsed = parseUniqueViolation(message);\n if (parsed)\n {\n return new DuplicateEntryError({ field: parsed.field, value: parsed.value });\n }\n return new DuplicateEntryError({ field: 'field', value: 'value' });\n\n case '23514': // check_violation\n return new ConstraintViolationError({ message, details: { code, constraint: 'check' } });\n\n // Class 40 — Transaction Rollback\n case '40000': // transaction_rollback\n case '40001': // serialization_failure\n case '40002': // transaction_integrity_constraint_violation\n case '40003': // statement_completion_unknown\n return new TransactionError({ message, statusCode: 500, details: { code } });\n\n case '40P01': // deadlock_detected\n return new DeadlockError({ message, details: { code } });\n\n // Class 42 — Syntax Error or Access Rule Violation\n case '42000': // syntax_error_or_access_rule_violation\n case '42601': // syntax_error\n case '42501': // insufficient_privilege\n case '42602': // invalid_name\n case '42622': // name_too_long\n case '42701': // duplicate_column\n case '42702': // ambiguous_column\n case '42703': // undefined_column\n case '42704': // undefined_object\n case '42P01': // undefined_table\n case '42P02': // undefined_parameter\n return new QueryError({ message, statusCode: 400, details: { code } });\n\n // Class 53 — Insufficient Resources\n case '53000': // insufficient_resources\n case '53100': // disk_full\n case '53200': // out_of_memory\n case '53300': // too_many_connections\n return new ConnectionError({ message, details: { code } });\n\n // Class 57 — Operator Intervention\n case '57000': // operator_intervention\n case '57014': // query_canceled\n case '57P01': // admin_shutdown\n case '57P02': // crash_shutdown\n case '57P03': // cannot_connect_now\n return new ConnectionError({ message, details: { code } });\n\n // Default: Unknown error\n default:\n return new QueryError({ message, statusCode: 500, details: { code } });\n }\n}","import postgres from 'postgres';\nimport type { Sql } from 'postgres';\n\nimport { logger } from '@spfn/core/logger';\nimport { ConnectionError } from '@spfn/core/errors';\nimport { fromPostgresError } from '../postgres-errors';\nimport type { PoolConfig, RetryConfig } from './config';\n\nconst dbLogger = logger.child('@spfn/core:database');\n\n/**\n * Connection timeout in seconds\n *\n * Timeout for PostgreSQL server connection and initial query execution.\n */\nconst DEFAULT_CONNECT_TIMEOUT = 10;\n\n/**\n * Delay execution for specified milliseconds\n *\n * @param ms - Milliseconds to delay\n * @returns Promise that resolves after the delay\n */\nfunction delay(ms: number): Promise<void>\n{\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Mask password in connection string for secure logging\n *\n * Replaces password with *** to prevent credentials from appearing in logs.\n *\n * @param connectionString - Database connection string\n * @returns Masked connection string with password replaced by ***\n *\n * @example\n * ```typescript\n * maskConnectionString('postgresql://user:password@host:5432/db')\n * // Returns: 'postgresql://user:***@host:5432/db'\n *\n * maskConnectionString('postgresql://user:p@ssw0rd@host:5432/db')\n * // Returns: 'postgresql://user:***@host:5432/db'\n * ```\n */\nfunction maskConnectionString(connectionString: string): string\n{\n try\n {\n // Safe password masking using URL parsing\n const url = new URL(connectionString);\n if (url.password)\n {\n // Replace password with ***\n return connectionString.replace(`:${url.password}@`, ':***@');\n }\n return connectionString;\n }\n catch\n {\n // Fallback to regex if URL parsing fails (safe only for passwords without @)\n return connectionString.replace(/(:\\/\\/[^:/@]+:)([^@]+)(@)/, '$1***$3');\n }\n}\n\n/**\n * Check if error is an authentication error\n *\n * Detects password authentication failures, missing passwords, and invalid authorization.\n *\n * @param error - Error object to check\n * @returns true if error is authentication-related, false otherwise\n */\nfunction isAuthenticationError(error: Error): boolean\n{\n const message = error.message.toLowerCase();\n return message.includes('password authentication failed') ||\n message.includes('no password supplied') ||\n message.includes('authentication failed') ||\n message.includes('invalid authorization');\n}\n\n/**\n * Check if error indicates database does not exist\n *\n * @param error - Error object to check\n * @returns true if database not found, false otherwise\n */\nfunction isDatabaseNotFoundError(error: Error): boolean\n{\n const message = error.message.toLowerCase();\n return message.includes('database') && message.includes('does not exist');\n}\n\n/**\n * Check if error is SSL/TLS related\n *\n * Detects SSL, TLS, certificate, and verification errors.\n *\n * @param error - Error object to check\n * @returns true if SSL/TLS error, false otherwise\n */\nfunction isSSLError(error: Error): boolean\n{\n const message = error.message.toLowerCase();\n return message.includes('ssl') ||\n message.includes('tls') ||\n message.includes('certificate') ||\n message.includes('self signed certificate') ||\n message.includes('unable to verify');\n}\n\n/**\n * Check if error should not be retried\n *\n * Non-retryable errors include:\n * - Authentication failures (wrong password, username, etc.)\n * - Database not found errors\n * - SSL/TLS configuration errors\n *\n * These errors indicate configuration issues that won't be resolved by retrying.\n *\n * @param error - Error object to check\n * @returns true if error should not be retried, false if retry is appropriate\n */\nfunction isNonRetryableError(error: Error): boolean\n{\n return isAuthenticationError(error) ||\n isDatabaseNotFoundError(error) ||\n isSSLError(error);\n}\n\n/**\n * Validate retry configuration parameters\n *\n * Ensures all retry config values are within valid ranges.\n *\n * @param retryConfig - Retry configuration to validate\n * @throws ConnectionError if any configuration value is invalid\n */\nfunction validateRetryConfig(retryConfig: RetryConfig): void\n{\n if (retryConfig.maxRetries < 0)\n {\n throw new ConnectionError({ message: `maxRetries must be non-negative, got ${retryConfig.maxRetries}` });\n }\n\n if (retryConfig.initialDelay <= 0)\n {\n throw new ConnectionError({ message: `initialDelay must be positive, got ${retryConfig.initialDelay}` });\n }\n\n if (retryConfig.factor <= 0)\n {\n throw new ConnectionError({ message: `factor must be positive, got ${retryConfig.factor}` });\n }\n\n if (retryConfig.maxDelay <= 0)\n {\n throw new ConnectionError({ message: `maxDelay must be positive, got ${retryConfig.maxDelay}` });\n }\n}\n\n/**\n * Validate pool configuration parameters\n *\n * Ensures pool configuration values are valid.\n *\n * @param poolConfig - Pool configuration to validate\n * @throws ConnectionError if configuration is invalid\n */\nfunction validatePoolConfig(poolConfig: PoolConfig): void\n{\n if (poolConfig.max <= 0)\n {\n throw new ConnectionError({ message: `pool max must be positive, got ${poolConfig.max}` });\n }\n}\n\n/**\n * Create database connection with exponential backoff retry strategy\n *\n * Attempts to establish a database connection with automatic retries using\n * exponential backoff with jitter. Non-retryable errors (authentication,\n * database not found, SSL issues) fail immediately.\n *\n * Retry Strategy:\n * - Exponential backoff: delay = initialDelay * (factor ^ attempt)\n * - Jitter: randomized delay between 50-100% of calculated delay\n * - Max delay cap: prevents excessive wait times\n *\n * @param connectionString - PostgreSQL connection string\n * @param poolConfig - Connection pool configuration\n * @param retryConfig - Retry configuration (max attempts, delays, etc.)\n * @returns PostgreSQL client instance\n * @throws ConnectionError if connection fails after all retries or on non-retryable errors\n *\n * @example\n * ```typescript\n * const client = await createDatabaseConnection(\n * 'postgresql://localhost:5432/mydb',\n * { max: 20, idleTimeout: 30 },\n * { maxRetries: 5, initialDelay: 100, maxDelay: 10000, factor: 2 }\n * );\n * ```\n */\nexport async function createDatabaseConnection(\n connectionString: string,\n poolConfig: PoolConfig,\n retryConfig: RetryConfig\n) {\n // Validate input parameters\n if (!connectionString)\n {\n throw new ConnectionError({ message: 'Connection string must be a non-empty string' });\n }\n\n validateRetryConfig(retryConfig);\n validatePoolConfig(poolConfig);\n\n let lastError: Error | undefined;\n let client: Sql | undefined;\n\n for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++)\n {\n try\n {\n // Create PostgreSQL client\n client = postgres(connectionString, {\n max: poolConfig.max,\n idle_timeout: poolConfig.idleTimeout,\n connect_timeout: DEFAULT_CONNECT_TIMEOUT,\n });\n\n // Test connection with simple query\n // connect_timeout is applied at DB level, so Promise.race is not needed\n await client`SELECT 1 as test`;\n\n // Connection successful\n if (attempt > 0)\n {\n dbLogger.info(\n 'Database connected successfully',\n { retriesNeeded: attempt }\n );\n }\n else\n {\n dbLogger.info('Database connected successfully');\n }\n\n return client;\n }\n catch (error)\n {\n // Cleanup failed client (prevent resource leak)\n if (client)\n {\n try\n {\n await client.end();\n }\n catch\n {\n // Ignore cleanup errors (client may already be closed)\n }\n\n client = undefined;\n }\n\n lastError = fromPostgresError(error);\n\n // Throw immediately on non-retryable errors\n if (isNonRetryableError(lastError))\n {\n dbLogger.error(\n 'Cannot connect to database (non-retryable error)',\n lastError,\n {\n connectionString: maskConnectionString(connectionString),\n poolConfig: {\n max: poolConfig.max,\n idleTimeout: poolConfig.idleTimeout,\n connectTimeout: DEFAULT_CONNECT_TIMEOUT,\n },\n reason: isAuthenticationError(lastError)\n ? 'authentication_failed'\n : isDatabaseNotFoundError(lastError)\n ? 'database_not_found'\n : 'ssl_error',\n }\n );\n\n throw new ConnectionError({\n message: `Cannot connect to database: ${lastError.message}`\n });\n }\n\n // Retry if not last attempt\n if (attempt < retryConfig.maxRetries)\n {\n // Calculate exponential backoff with jitter\n const baseDelay = Math.min(\n retryConfig.initialDelay * Math.pow(retryConfig.factor, attempt),\n retryConfig.maxDelay\n );\n // Jitter: randomize delay between 50-100% (prevents thundering herd)\n const jitter = 0.5 + Math.random() * 0.5;\n const delayMs = Math.floor(baseDelay * jitter);\n\n dbLogger.warn(\n 'Database connection failed, retrying...',\n lastError,\n {\n attempt: attempt + 1,\n totalAttempts: retryConfig.maxRetries + 1,\n nextRetryIn: delayMs,\n connectionString: maskConnectionString(connectionString),\n poolConfig: {\n max: poolConfig.max,\n idleTimeout: poolConfig.idleTimeout,\n connectTimeout: DEFAULT_CONNECT_TIMEOUT,\n },\n }\n );\n\n await delay(delayMs);\n }\n }\n }\n\n // All retries failed\n // lastError is assigned at least once in the loop, so it cannot be undefined\n if (!lastError)\n {\n throw new ConnectionError({\n message: 'Unexpected error: no error recorded after failed connection attempts'\n });\n }\n\n dbLogger.error(\n 'Failed to connect to database after all retries',\n lastError,\n {\n totalAttempts: retryConfig.maxRetries + 1,\n connectionString: maskConnectionString(connectionString),\n poolConfig: {\n max: poolConfig.max,\n idleTimeout: poolConfig.idleTimeout,\n connectTimeout: DEFAULT_CONNECT_TIMEOUT,\n },\n retryConfig: {\n maxRetries: retryConfig.maxRetries,\n initialDelay: retryConfig.initialDelay,\n factor: retryConfig.factor,\n maxDelay: retryConfig.maxDelay,\n },\n }\n );\n\n throw new ConnectionError({\n message: `Failed to connect to database after ${retryConfig.maxRetries + 1} attempts: ${lastError.message}`\n });\n}\n\n/**\n * Check database connection health\n *\n * Uses the client's configured timeout settings (connect_timeout, etc.).\n * Executes a simple SELECT query to verify the connection is alive.\n *\n * @param client - PostgreSQL client to check\n * @returns true if connection is healthy, false otherwise\n *\n * @example\n * ```typescript\n * const isHealthy = await checkConnection(client);\n * if (!isHealthy) {\n * console.error('Database connection is down');\n * }\n * ```\n */\nexport async function checkConnection(client: Sql): Promise<boolean>\n{\n try\n {\n // Health check query\n // Uses client's default timeout settings\n await client`SELECT 1 as health_check`;\n\n return true;\n }\n catch (error)\n {\n const errorObj = fromPostgresError(error);\n\n dbLogger.error(\n 'Database health check failed',\n errorObj,\n { errorType: errorObj.name }\n );\n\n return false;\n }\n}","/**\n * Database Configuration\n *\n * Database connection and connection pool configuration.\n *\n * Features:\n * - Environment-specific connection pool configuration\n * - Retry configuration with exponential backoff\n * - Environment variable-based configuration\n * - Health check and monitoring configuration\n *\n * Related files:\n * - src/server/core/db/connection.ts (connection logic)\n * - src/server/core/db/index.ts (main exports)\n */\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\";\nimport type { Sql } from \"postgres\";\nimport { parseNumber, parseBoolean } from '@spfn/core/env';\n\nexport interface DatabaseClients\n{\n /** Primary database for writes (or both read/write if no replica) */\n write?: PostgresJsDatabase;\n /** Replica database for reads (optional, falls back to write) */\n read?: PostgresJsDatabase;\n /** Raw postgres client for write operations (for cleanup) */\n writeClient?: Sql;\n /** Raw postgres client for read operations (for cleanup) */\n readClient?: Sql;\n}\n\n/**\n * Health check configuration\n */\nexport interface HealthCheckConfig\n{\n enabled: boolean;\n interval: number;\n reconnect: boolean;\n maxRetries: number;\n retryInterval: number;\n}\n\n/**\n * Query performance monitoring configuration\n */\nexport interface MonitoringConfig\n{\n enabled: boolean;\n slowThreshold: number;\n logQueries: boolean;\n}\n\n/**\n * Database initialization options\n */\nexport interface DatabaseOptions\n{\n /**\n * Connection pool configuration\n * Overrides environment variables and defaults\n */\n pool?: Partial<PoolConfig>;\n\n /**\n * Health check configuration\n * Periodic checks to ensure database connection is alive\n */\n healthCheck?: Partial<HealthCheckConfig>;\n\n /**\n * Query performance monitoring configuration\n * Tracks slow queries and logs performance metrics\n */\n monitoring?: Partial<MonitoringConfig>;\n}\n\n/**\n * Connection pool configuration\n *\n * Controls the maximum number of connections and idle timeout behavior.\n */\nexport interface PoolConfig\n{\n /** Maximum number of connections in the pool */\n max: number;\n /** Idle connection timeout in seconds */\n idleTimeout: number;\n}\n\n/**\n * Retry configuration for exponential backoff algorithm\n *\n * Controls retry behavior when connection attempts fail.\n */\nexport interface RetryConfig\n{\n /** Maximum number of retry attempts */\n maxRetries: number;\n /** Initial delay between retries in milliseconds */\n initialDelay: number;\n /** Maximum delay cap in milliseconds */\n maxDelay: number;\n /** Exponential backoff factor (delay multiplier) */\n factor: number;\n}\n\n// ============================================================================\n// Environment Variable Parsing Utilities\n// ============================================================================\n\n/**\n * Parse environment variable as number with production/development defaults\n *\n * Uses @spfn/core/env parseNumber for consistent parsing across the codebase.\n *\n * @param key - Environment variable name\n * @param prodDefault - Default value for production\n * @param devDefault - Default value for development\n * @returns Parsed number or default based on NODE_ENV\n *\n * @example\n * ```typescript\n * const max = parseEnvNumber('DB_POOL_MAX', 20, 10);\n * // Production: 20, Development: 10, or parsed value from env\n * ```\n */\nfunction parseEnvNumber(\n key: string,\n prodDefault: number,\n devDefault: number\n): number\n{\n const isProduction = process.env.NODE_ENV === 'production';\n const defaultValue = isProduction ? prodDefault : devDefault;\n\n const value = process.env[key];\n\n if (value === undefined)\n {\n return defaultValue;\n }\n\n try\n {\n return parseNumber(value, { min: 0, integer: true });\n }\n catch (error)\n {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`${key}: ${message}`);\n }\n}\n\n/**\n * Parse environment variable as boolean with enhanced format support\n *\n * Uses @spfn/core/env parseBoolean for consistent parsing across the codebase.\n * Supports multiple truthy/falsy formats: true/false, 1/0, yes/no.\n *\n * @param key - Environment variable name\n * @param defaultValue - Default value if not set\n * @returns Boolean value\n *\n * @example\n * ```typescript\n * const enabled = parseEnvBoolean('DB_HEALTH_CHECK_ENABLED', true);\n * // Accepts: 'true', '1', 'yes' → true\n * // Accepts: 'false', '0', 'no' → false\n * ```\n */\nfunction parseEnvBoolean(key: string, defaultValue: boolean): boolean\n{\n const value = process.env[key];\n\n if (value === undefined)\n {\n return defaultValue;\n }\n\n try\n {\n return parseBoolean(value);\n }\n catch (error)\n {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`${key}: ${message}`);\n }\n}\n\n// ============================================================================\n// Configuration Builders\n// ============================================================================\n\n/**\n * Get connection pool configuration based on environment\n *\n * Configuration priority (highest to lowest):\n * 1. options parameter (passed from ServerConfig)\n * 2. Environment variables (DB_POOL_MAX, DB_POOL_IDLE_TIMEOUT)\n * 3. Default values (based on NODE_ENV)\n *\n * @param options - Optional pool configuration from ServerConfig\n * @returns Pool configuration\n *\n * @example\n * ```typescript\n * // 1. ServerConfig priority (highest)\n * const config = getPoolConfig({ max: 50, idleTimeout: 60 });\n *\n * // 2. Environment variable priority\n * // DB_POOL_MAX=30 DB_POOL_IDLE_TIMEOUT=45\n * const config = getPoolConfig();\n *\n * // 3. Default (lowest)\n * // Production: max=20, idleTimeout=30\n * // Development: max=10, idleTimeout=20\n * ```\n */\nexport function getPoolConfig(options?: Partial<PoolConfig>): PoolConfig\n{\n return {\n max: options?.max ?? parseEnvNumber('DB_POOL_MAX', 20, 10),\n idleTimeout: options?.idleTimeout ?? parseEnvNumber('DB_POOL_IDLE_TIMEOUT', 30, 20),\n };\n}\n\n/**\n * Get retry configuration based on environment\n *\n * Configuration priority (highest to lowest):\n * 1. Environment variables (DB_RETRY_MAX, DB_RETRY_INITIAL_DELAY, etc.)\n * 2. Default values (based on NODE_ENV)\n *\n * @returns Retry configuration\n *\n * @example\n * ```typescript\n * // Environment variables (highest priority)\n * // DB_RETRY_MAX=10\n * // DB_RETRY_INITIAL_DELAY=200\n * const config = getRetryConfig();\n *\n * // Defaults (lowest priority)\n * // Production: 5 retries, 100ms initial, 10s max, factor 2\n * // Development: 3 retries, 50ms initial, 5s max, factor 2\n * ```\n */\nexport function getRetryConfig(): RetryConfig\n{\n return {\n maxRetries: parseEnvNumber('DB_RETRY_MAX', 5, 3),\n initialDelay: parseEnvNumber('DB_RETRY_INITIAL_DELAY', 100, 50),\n maxDelay: parseEnvNumber('DB_RETRY_MAX_DELAY', 10000, 5000),\n factor: parseEnvNumber('DB_RETRY_FACTOR', 2, 2),\n };\n}\n\n/**\n * Build health check configuration with priority resolution\n *\n * Configuration priority (highest to lowest):\n * 1. options parameter\n * 2. Environment variables\n * 3. Default values\n *\n * @param options - Optional health check configuration\n * @returns Health check configuration\n *\n * @example\n * ```typescript\n * // Custom options (highest priority)\n * const config = buildHealthCheckConfig({ enabled: false });\n *\n * // Environment variables\n * // DB_HEALTH_CHECK_ENABLED=true\n * // DB_HEALTH_CHECK_INTERVAL=30000\n * const config = buildHealthCheckConfig();\n *\n * // Defaults (lowest priority)\n * // enabled: true, interval: 60000ms, reconnect: true\n * ```\n */\nexport function buildHealthCheckConfig(options?: Partial<HealthCheckConfig>): HealthCheckConfig\n{\n return {\n enabled: options?.enabled\n ?? parseEnvBoolean('DB_HEALTH_CHECK_ENABLED', true),\n interval: options?.interval\n ?? parseEnvNumber('DB_HEALTH_CHECK_INTERVAL', 60000, 60000),\n reconnect: options?.reconnect\n ?? parseEnvBoolean('DB_HEALTH_CHECK_RECONNECT', true),\n maxRetries: options?.maxRetries\n ?? parseEnvNumber('DB_HEALTH_CHECK_MAX_RETRIES', 3, 3),\n retryInterval: options?.retryInterval\n ?? parseEnvNumber('DB_HEALTH_CHECK_RETRY_INTERVAL', 5000, 5000),\n };\n}\n\n/**\n * Build monitoring configuration with priority resolution\n *\n * Configuration priority (highest to lowest):\n * 1. options parameter\n * 2. Environment variables\n * 3. Default values\n *\n * @param options - Optional monitoring configuration\n * @returns Monitoring configuration\n *\n * @example\n * ```typescript\n * // Custom options (highest priority)\n * const config = buildMonitoringConfig({ slowThreshold: 2000 });\n *\n * // Environment variables\n * // DB_MONITORING_ENABLED=true\n * // DB_MONITORING_SLOW_THRESHOLD=500\n * const config = buildMonitoringConfig();\n *\n * // Defaults (lowest priority)\n * // Development: enabled=true, slowThreshold=1000ms, logQueries=false\n * // Production: enabled=false, slowThreshold=1000ms, logQueries=false\n * ```\n */\nexport function buildMonitoringConfig(options?: Partial<MonitoringConfig>): MonitoringConfig\n{\n const isDevelopment = process.env.NODE_ENV !== 'production';\n\n return {\n enabled: options?.enabled\n ?? parseEnvBoolean('DB_MONITORING_ENABLED', isDevelopment),\n slowThreshold: options?.slowThreshold\n ?? parseEnvNumber('DB_MONITORING_SLOW_THRESHOLD', 1000, 1000),\n logQueries: options?.logQueries\n ?? parseEnvBoolean('DB_MONITORING_LOG_QUERIES', false),\n };\n}","/**\n * Database factory with automatic environment variable detection\n * Supports: Single primary, Primary + Replica\n */\n\nimport { drizzle } from 'drizzle-orm/postgres-js';\nimport type { Sql } from 'postgres';\n\nimport { env } from '@spfn/core/config';\nimport { logger } from '@spfn/core/logger';\nimport { createDatabaseConnection } from './connection';\nimport { getPoolConfig, getRetryConfig, type DatabaseOptions, type DatabaseClients, type PoolConfig, type RetryConfig } from './config';\n\nconst dbLogger = logger.child('@spfn/core:database');\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Database configuration pattern types\n *\n * Represents different ways to configure database connections via environment variables.\n */\ntype DatabasePattern =\n | { type: 'write-read'; write: string; read: string } // Explicit write/read separation\n | { type: 'single'; url: string } // Single database\n | { type: 'none' }; // No configuration\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Check if any database configuration exists in environment\n */\nfunction hasDatabaseConfig(): boolean\n{\n return env.DATABASE_URL !== undefined ||\n env.DATABASE_WRITE_URL !== undefined ||\n env.DATABASE_READ_URL !== undefined;\n}\n\n/**\n * Detect database configuration pattern from environment variables\n *\n * Priority order (highest to lowest):\n * 1. write-read: DATABASE_WRITE_URL + DATABASE_READ_URL (explicit separation)\n * 2. single: DATABASE_URL (most common)\n * 3. single: DATABASE_WRITE_URL (write-only, no replica)\n * 4. none: No configuration found\n *\n * @returns Detected database configuration pattern\n *\n * @example\n * ```typescript\n * const pattern = detectDatabasePattern();\n *\n * if (pattern.type === 'write-read') {\n * console.log(`Write: ${pattern.write}, Read: ${pattern.read}`);\n * }\n * ```\n */\nfunction detectDatabasePattern(): DatabasePattern\n{\n const DATABASE_WRITE_URL = env.DATABASE_WRITE_URL;\n const DATABASE_READ_URL = env.DATABASE_READ_URL;\n const DATABASE_URL = env.DATABASE_URL;\n\n // Priority 1: Explicit write/read separation (recommended)\n if (DATABASE_WRITE_URL && DATABASE_READ_URL)\n {\n return {\n type: 'write-read',\n write: DATABASE_WRITE_URL,\n read: DATABASE_READ_URL,\n };\n }\n\n // Priority 2: Single primary (most common)\n if (DATABASE_URL)\n {\n return {\n type: 'single',\n url: DATABASE_URL,\n };\n }\n\n // Priority 3: Write-only (no replica)\n if (DATABASE_WRITE_URL)\n {\n return {\n type: 'single',\n url: DATABASE_WRITE_URL,\n };\n }\n\n // No configuration found\n return { type: 'none' };\n}\n\n/**\n * Create write and read database clients\n *\n * Write connection is required and will throw if it fails.\n * Read connection is optional - if it fails, falls back to using write connection with a warning.\n *\n * @param writeUrl - Write database connection string\n * @param readUrl - Read database connection string\n * @param poolConfig - Connection pool configuration\n * @param retryConfig - Retry configuration\n * @returns Database clients\n * @throws Error if write connection fails\n */\nasync function createWriteReadClients(\n writeUrl: string,\n readUrl: string,\n poolConfig: PoolConfig,\n retryConfig: RetryConfig\n): Promise<DatabaseClients>\n{\n let writeClient: Sql | undefined;\n let readClient: Sql | undefined;\n\n try\n {\n // Write connection is required - must succeed\n writeClient = await createDatabaseConnection(writeUrl, poolConfig, retryConfig);\n }\n catch (error)\n {\n const errorObj = error instanceof Error ? error : new Error(String(error));\n dbLogger.error('Failed to connect to write database', errorObj);\n throw new Error(`Write database connection failed: ${errorObj.message}`, { cause: error });\n }\n\n // Read connection is optional - fallback to write if it fails\n try\n {\n readClient = await createDatabaseConnection(readUrl, poolConfig, retryConfig);\n\n return {\n write: drizzle(writeClient),\n read: drizzle(readClient),\n writeClient,\n readClient,\n };\n }\n catch (error)\n {\n const errorObj = error instanceof Error ? error : new Error(String(error));\n\n // Log warning but continue with write connection as fallback\n dbLogger.warn(\n 'Failed to connect to read database (replica). Falling back to write database for read operations.',\n {\n error: errorObj.message,\n readUrl: readUrl.replace(/:[^:@]+@/, ':***@'), // Mask password in logs\n fallbackBehavior: 'Using write connection for both read and write operations',\n }\n );\n\n // Use write connection for both read and write\n return {\n write: drizzle(writeClient),\n read: drizzle(writeClient),\n writeClient,\n readClient: writeClient,\n };\n }\n}\n\n/**\n * Create single database client (used for both read and write)\n *\n * @param url - Database connection string\n * @param poolConfig - Connection pool configuration\n * @param retryConfig - Retry configuration\n * @returns Database clients\n */\nasync function createSingleClient(\n url: string,\n poolConfig: PoolConfig,\n retryConfig: RetryConfig\n): Promise<DatabaseClients>\n{\n const client = await createDatabaseConnection(url, poolConfig, retryConfig);\n const db = drizzle(client);\n\n return {\n write: db,\n read: db,\n writeClient: client,\n readClient: client,\n };\n}\n\n/**\n * Create database client(s) from environment variables\n *\n * Supported patterns (priority order):\n * 1. Primary + Replica: DATABASE_WRITE_URL + DATABASE_READ_URL\n * 2. Single primary: DATABASE_URL\n *\n * @param options - Optional database configuration (pool settings, etc.)\n * @returns Database client(s)\n * @throws {Error} If no database configuration is found or connection fails\n *\n * @example\n * ```bash\n * # Single primary (most common)\n * DATABASE_URL=postgresql://localhost:5432/mydb\n *\n * # Primary + Replica\n * DATABASE_WRITE_URL=postgresql://primary:5432/mydb\n * DATABASE_READ_URL=postgresql://replica:5432/mydb\n * ```\n *\n * @example\n * ```typescript\n * // Custom pool configuration\n * const db = await createDatabaseFromEnv({\n * pool: { max: 50, idleTimeout: 60 }\n * });\n * ```\n */\nexport async function createDatabaseFromEnv(options?: DatabaseOptions): Promise<DatabaseClients>\n{\n // Quick exit if no database config\n if (!hasDatabaseConfig())\n {\n const error = new Error(\n 'No database configuration found. Please set DATABASE_URL, DATABASE_WRITE_URL, or DATABASE_READ_URL environment variable.'\n );\n\n dbLogger.error('No database configuration found', {\n cwd: process.cwd(),\n nodeEnv: env.NODE_ENV,\n checkedVars: ['DATABASE_URL', 'DATABASE_WRITE_URL', 'DATABASE_READ_URL'],\n });\n\n throw error;\n }\n\n try\n {\n const poolConfig = getPoolConfig(options?.pool);\n const retryConfig = getRetryConfig();\n const pattern = detectDatabasePattern();\n\n // Create database clients based on detected pattern\n switch (pattern.type)\n {\n case 'write-read':\n return await createWriteReadClients(\n pattern.write,\n pattern.read,\n poolConfig,\n retryConfig\n );\n\n case 'single':\n return await createSingleClient(pattern.url, poolConfig, retryConfig);\n }\n }\n catch (error)\n {\n const errorObj = error instanceof Error ? error : new Error(String(error));\n dbLogger.error(\n 'Failed to create database connection',\n errorObj,\n {\n stage: 'initialization',\n hasWriteUrl: process.env.DATABASE_WRITE_URL !== undefined,\n hasReadUrl: process.env.DATABASE_READ_URL !== undefined,\n hasUrl: process.env.DATABASE_URL !== undefined,\n }\n );\n\n throw new Error(`Database connection failed: ${errorObj.message}`, { cause: error });\n }\n\n throw new Error('No database pattern detected despite passing config check');\n}","/**\n * Global Database State Management\n *\n * Manages global database instances using globalThis for persistence across module reloads.\n * This is particularly useful in development with hot module replacement (HMR).\n *\n * The singleton pattern ensures database connections persist even when modules are reloaded\n * during development (e.g., with tsx watch mode).\n */\n\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport type { Sql } from 'postgres';\nimport type { MonitoringConfig } from './config';\n\n// ============================================================================\n// Global Type Declarations\n// ============================================================================\n\n/**\n * Extend globalThis with database-specific properties\n *\n * Using globalThis allows database instances to persist across module reloads,\n * which is essential for development environments with hot module replacement.\n */\ndeclare global\n{\n var __SPFN_DB_WRITE__: PostgresJsDatabase<Record<string, unknown>> | undefined;\n var __SPFN_DB_READ__: PostgresJsDatabase<Record<string, unknown>> | undefined;\n var __SPFN_DB_WRITE_CLIENT__: Sql | undefined;\n var __SPFN_DB_READ_CLIENT__: Sql | undefined;\n var __SPFN_DB_HEALTH_CHECK__: NodeJS.Timeout | undefined;\n var __SPFN_DB_MONITORING__: MonitoringConfig | undefined;\n}\n\n// ============================================================================\n// Database Instance Accessors\n// ============================================================================\n\n/**\n * Get write database instance from global state\n *\n * @internal - This is an internal API. Use getDatabase() from @spfn/core/db instead.\n */\nexport const getWriteInstance = (): PostgresJsDatabase<Record<string, unknown>> | undefined =>\n globalThis.__SPFN_DB_WRITE__;\n\n/**\n * Set write database instance in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setWriteInstance = (instance: PostgresJsDatabase<Record<string, unknown>> | undefined): void => {\n globalThis.__SPFN_DB_WRITE__ = instance;\n};\n\n/**\n * Get read database instance from global state\n *\n * @internal - This is an internal API. Use getDatabase() from @spfn/core/db instead.\n */\nexport const getReadInstance = (): PostgresJsDatabase<Record<string, unknown>> | undefined =>\n globalThis.__SPFN_DB_READ__;\n\n/**\n * Set read database instance in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setReadInstance = (instance: PostgresJsDatabase<Record<string, unknown>> | undefined): void => {\n globalThis.__SPFN_DB_READ__ = instance;\n};\n\n// ============================================================================\n// Raw Client Accessors\n// ============================================================================\n\n/**\n * Get write client from global state (for cleanup)\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const getWriteClient = (): Sql | undefined =>\n globalThis.__SPFN_DB_WRITE_CLIENT__;\n\n/**\n * Set write client in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setWriteClient = (client: Sql | undefined): void => {\n globalThis.__SPFN_DB_WRITE_CLIENT__ = client;\n};\n\n/**\n * Get read client from global state (for cleanup)\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const getReadClient = (): Sql | undefined =>\n globalThis.__SPFN_DB_READ_CLIENT__;\n\n/**\n * Set read client in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setReadClient = (client: Sql | undefined): void => {\n globalThis.__SPFN_DB_READ_CLIENT__ = client;\n};\n\n// ============================================================================\n// Health Check Accessors\n// ============================================================================\n\n/**\n * Get health check interval from global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const getHealthCheckInterval = (): NodeJS.Timeout | undefined =>\n globalThis.__SPFN_DB_HEALTH_CHECK__;\n\n/**\n * Set health check interval in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setHealthCheckInterval = (interval: NodeJS.Timeout | undefined): void => {\n globalThis.__SPFN_DB_HEALTH_CHECK__ = interval;\n};\n\n// ============================================================================\n// Monitoring Config Accessors\n// ============================================================================\n\n/**\n * Get monitoring configuration from global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const getMonitoringConfig = (): MonitoringConfig | undefined =>\n globalThis.__SPFN_DB_MONITORING__;\n\n/**\n * Set monitoring configuration in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setMonitoringConfig = (config: MonitoringConfig | undefined): void => {\n globalThis.__SPFN_DB_MONITORING__ = config;\n};","/**\n * Database Health Check\n *\n * Periodic health checks for database connections with automatic reconnection.\n * Monitors both write and read database instances and attempts recovery on failure.\n */\n\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\n\nimport { logger } from '@spfn/core/logger';\nimport { createDatabaseFromEnv } from './factory';\nimport type { DatabaseOptions, HealthCheckConfig } from './config';\nimport { buildMonitoringConfig } from './config';\nimport {\n getHealthCheckInterval,\n setHealthCheckInterval,\n setWriteInstance,\n setReadInstance,\n setWriteClient,\n setReadClient,\n setMonitoringConfig,\n} from './global-state';\nimport type { GetDatabaseFn } from './types';\n\nconst dbLogger = logger.child('@spfn/core:database');\n\n// ============================================================================\n// Helper Functions (Private)\n// ============================================================================\n\n/**\n * Test a single database connection\n *\n * @param db - Database instance to test\n * @throws Error if connection test fails\n * @internal\n */\nasync function testDatabaseConnection(\n db: PostgresJsDatabase<Record<string, unknown>>\n): Promise<void>\n{\n await db.execute('SELECT 1');\n}\n\n/**\n * Perform health check on database connections\n *\n * Tests both write and read connections.\n *\n * @param getDatabase - Function to get database instance\n * @throws Error if health check fails\n * @internal\n */\nasync function performHealthCheck(getDatabase: GetDatabaseFn): Promise<void>\n{\n const write = getDatabase('write');\n const read = getDatabase('read');\n\n await testDatabaseConnection(write);\n\n // Check read connection if different from write\n if (read !== write)\n {\n await testDatabaseConnection(read);\n }\n}\n\n/**\n * Reconnect database and restore instances\n *\n * Closes existing connections, creates new ones, tests them, and restores global state.\n *\n * @param options - Optional database configuration\n * @param closeDatabase - Function to close existing connections\n * @returns true if reconnection successful, false otherwise\n * @internal\n */\nasync function reconnectAndRestore(\n options: DatabaseOptions | undefined,\n closeDatabase: () => Promise<void>\n): Promise<boolean>\n{\n // Close existing connections\n await closeDatabase();\n\n // Create new connections\n const result = await createDatabaseFromEnv(options);\n\n if (!result.write)\n {\n return false;\n }\n\n // Test both connections before restoring\n await testDatabaseConnection(result.write);\n if (result.read && result.read !== result.write)\n {\n await testDatabaseConnection(result.read);\n }\n\n // Store instances\n setWriteInstance(result.write);\n setReadInstance(result.read);\n setWriteClient(result.writeClient);\n setReadClient(result.readClient);\n\n // Restore monitoring configuration\n const monConfig = buildMonitoringConfig(options?.monitoring);\n setMonitoringConfig(monConfig);\n\n return true;\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Start database health check\n *\n * Periodically checks database connection health and attempts reconnection if enabled.\n * Automatically started by initDatabase() when health check is enabled.\n *\n * @param config - Health check configuration\n * @param options - Optional database configuration (pool settings, etc.)\n * @param getDatabase - Function to get database instance (to avoid circular dependency)\n * @param closeDatabase - Function to close database (for reconnection)\n *\n * @example\n * ```typescript\n * import { startHealthCheck } from '@spfn/core/db/manager/health-check';\n *\n * startHealthCheck(\n * {\n * enabled: true,\n * interval: 30000, // 30 seconds\n * reconnect: true,\n * maxRetries: 5,\n * retryInterval: 10000, // 10 seconds\n * },\n * undefined,\n * getDatabase,\n * closeDatabase\n * );\n * ```\n */\nexport function startHealthCheck(\n config: HealthCheckConfig,\n options: DatabaseOptions | undefined,\n getDatabase: GetDatabaseFn,\n closeDatabase: () => Promise<void>\n): void\n{\n const healthCheck = getHealthCheckInterval();\n if (healthCheck)\n {\n dbLogger.debug('Health check already running');\n return;\n }\n\n dbLogger.info('Starting database health check', {\n interval: `${config.interval}ms`,\n reconnect: config.reconnect,\n });\n\n const interval = setInterval(async () =>\n {\n try\n {\n await performHealthCheck(getDatabase);\n // Health check passed - no need to log (only log failures)\n }\n catch (error: unknown)\n {\n const message = error instanceof Error ? error.message : 'Unknown error';\n dbLogger.error('Database health check failed', { error: message });\n\n // Attempt reconnection if enabled\n if (config.reconnect)\n {\n await attemptReconnection(config, options, closeDatabase);\n }\n }\n }, config.interval);\n\n setHealthCheckInterval(interval);\n}\n\n/**\n * Attempt database reconnection with retry logic\n *\n * Closes existing connections and attempts to reinitialize the database.\n * Retries multiple times with configurable delay between attempts.\n *\n * @param config - Health check configuration\n * @param options - Optional database configuration (pool settings, etc.)\n * @param closeDatabase - Function to close existing database connections\n */\nasync function attemptReconnection(\n config: HealthCheckConfig,\n options: DatabaseOptions | undefined,\n closeDatabase: () => Promise<void>\n): Promise<void>\n{\n dbLogger.warn('Attempting database reconnection', {\n maxRetries: config.maxRetries,\n retryInterval: `${config.retryInterval}ms`,\n });\n\n for (let attempt = 1; attempt <= config.maxRetries; attempt++)\n {\n try\n {\n dbLogger.debug(`Reconnection attempt ${attempt}/${config.maxRetries}`);\n\n // Wait before retry (skip for first attempt)\n if (attempt > 1)\n {\n await new Promise(resolve => setTimeout(resolve, config.retryInterval));\n }\n\n // Attempt reconnection\n const success = await reconnectAndRestore(options, closeDatabase);\n\n if (success)\n {\n dbLogger.info('Database reconnection successful', { attempt });\n return;\n }\n else\n {\n dbLogger.error(`Reconnection attempt ${attempt} failed: No write database instance created`);\n }\n }\n catch (error: unknown)\n {\n const message = error instanceof Error ? error.message : 'Unknown error';\n dbLogger.error(`Reconnection attempt ${attempt} failed`, {\n error: message,\n attempt,\n maxRetries: config.maxRetries,\n });\n }\n\n if (attempt === config.maxRetries)\n {\n dbLogger.error('Max reconnection attempts reached, giving up');\n }\n }\n}\n\n/**\n * Stop database health check\n *\n * Automatically called by closeDatabase().\n * Can also be called manually to stop health checks.\n *\n * @example\n * ```typescript\n * import { stopHealthCheck } from '@spfn/core/db/manager/health-check';\n *\n * stopHealthCheck();\n * ```\n */\nexport function stopHealthCheck(): void\n{\n const healthCheck = getHealthCheckInterval();\n if (healthCheck)\n {\n clearInterval(healthCheck);\n setHealthCheckInterval(undefined);\n dbLogger.info('Database health check stopped');\n }\n}","/**\n * Global Database instance manager\n * Provides singleton access to database across all modules\n * Supports Primary + Replica pattern with separate read/write instances\n */\n\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport type { Sql } from 'postgres';\n\nimport { logger } from '@spfn/core/logger';\nimport { createDatabaseFromEnv } from './factory';\nimport type { DatabaseOptions, MonitoringConfig } from \"./config.js\";\nimport { buildHealthCheckConfig, buildMonitoringConfig } from \"./config.js\";\nimport { env } from '@spfn/core/config';\nimport {\n getWriteInstance,\n setWriteInstance,\n getReadInstance,\n setReadInstance,\n getWriteClient,\n setWriteClient,\n getReadClient,\n setReadClient,\n getMonitoringConfig,\n setMonitoringConfig,\n} from './global-state';\nimport { startHealthCheck, stopHealthCheck } from './health-check';\nimport type { DbConnectionType } from './types';\n\nconst dbLogger = logger.child('@spfn/core:database');\n\n/**\n * Connection close timeout in seconds\n */\nconst DB_CONNECTION_CLOSE_TIMEOUT = 5;\n\n/**\n * Number of stack trace lines to skip when detecting caller\n */\nconst STACK_TRACE_SKIP_LINES = 3;\n\n/**\n * Regular expressions for parsing stack trace lines\n */\nconst STACK_TRACE_PATTERNS = {\n withParens: /\\((.+):(\\d+):(\\d+)\\)/,\n withoutParens: /at (.+):(\\d+):(\\d+)/,\n};\n\n/**\n * Initialization promise to prevent concurrent initialization\n */\nlet initPromise: Promise<{\n write?: PostgresJsDatabase<Record<string, unknown>>;\n read?: PostgresJsDatabase<Record<string, unknown>>;\n}> | null = null;\n\n/**\n * Close in progress flag to prevent concurrent closeDatabase calls\n */\nlet isClosing = false;\n\n// ============================================================================\n// Helper Functions (Private)\n// ============================================================================\n\n/**\n * Cleanup database connections\n *\n * Closes write and read client connections with timeout.\n * Ignores cleanup errors to ensure all cleanup attempts complete.\n *\n * @param writeClient - Write client to cleanup\n * @param readClient - Read client to cleanup\n * @internal\n */\nasync function cleanupDatabaseConnections(\n writeClient: Sql | undefined,\n readClient: Sql | undefined\n): Promise<void>\n{\n const cleanupPromises: Promise<void>[] = [];\n\n if (writeClient)\n {\n cleanupPromises.push(\n writeClient.end({ timeout: DB_CONNECTION_CLOSE_TIMEOUT }).catch((err) => {\n dbLogger.debug('Write client cleanup failed', { error: err });\n })\n );\n }\n\n if (readClient && readClient !== writeClient)\n {\n cleanupPromises.push(\n readClient.end({ timeout: DB_CONNECTION_CLOSE_TIMEOUT }).catch((err) => {\n dbLogger.debug('Read client cleanup failed', { error: err });\n })\n );\n }\n\n await Promise.allSettled(cleanupPromises);\n}\n\n/**\n * Close a single database client connection\n *\n * @param client - Database client to close\n * @param type - Connection type ('write' or 'read')\n * @internal\n */\nasync function closeDatabaseClient(client: Sql, type: 'write' | 'read'): Promise<void>\n{\n const typeName = type.charAt(0).toUpperCase() + type.slice(1);\n dbLogger.debug(`Closing ${type} connection...`);\n\n try\n {\n await client.end({ timeout: DB_CONNECTION_CLOSE_TIMEOUT });\n dbLogger.debug(`${typeName} connection closed`);\n }\n catch (err: unknown)\n {\n const error = err instanceof Error ? err : new Error(String(err));\n dbLogger.error(`Error closing ${type} connection`, error);\n }\n}\n\n/**\n * Test database connections\n *\n * Executes a simple SELECT 1 query on both write and read connections.\n *\n * @param write - Write database instance\n * @param read - Read database instance\n * @throws Error if connection test fails\n * @internal\n */\nasync function testDatabaseConnections(\n write: PostgresJsDatabase<Record<string, unknown>> | undefined,\n read: PostgresJsDatabase<Record<string, unknown>> | undefined\n): Promise<void>\n{\n if (write)\n {\n await write.execute('SELECT 1');\n\n // Test read connection if different from write\n if (read && read !== write)\n {\n await read.execute('SELECT 1');\n }\n }\n}\n\n/**\n * Get caller information from stack trace\n */\nfunction getCallerInfo(): string | undefined\n{\n try\n {\n const stack = new Error().stack;\n if (!stack) return undefined;\n\n const lines = stack.split('\\n');\n // Skip first 3 lines: Error, getCallerInfo, getDatabase\n for (let i = STACK_TRACE_SKIP_LINES; i < lines.length; i++)\n {\n const line = lines[i];\n // Find first meaningful caller (not node_modules/@spfn/core/db)\n if (!line.includes('node_modules') && !line.includes('/db/manager/'))\n {\n // Extract file:line from stack line\n const match = line.match(STACK_TRACE_PATTERNS.withParens) || line.match(STACK_TRACE_PATTERNS.withoutParens);\n if (match)\n {\n const fullPath = match[1];\n // Get relative path from project root\n const parts = fullPath.split('/');\n const srcIndex = parts.lastIndexOf('src');\n if (srcIndex !== -1)\n {\n const relativePath = parts.slice(srcIndex).join('/');\n return `${relativePath}:${match[2]}`;\n }\n return `${fullPath}:${match[2]}`;\n }\n break;\n }\n }\n }\n catch (error: unknown)\n {\n // Stack trace parsing failed - log for debugging\n dbLogger.debug('Failed to extract caller info from stack trace', {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n return undefined;\n}\n\n/**\n * Create database not initialized error message\n *\n * @param type - Database connection type ('read' or 'write')\n * @returns Error with descriptive message for uninitialized database\n *\n * @internal\n */\nfunction createNotInitializedError(type: DbConnectionType): Error\n{\n return new Error(\n `Database not initialized (type: ${type}). Call initDatabase() first or set DATABASE_URL environment variable.`\n );\n}\n\n/**\n * Get global database instance\n *\n * @param type - Connection type ('read' or 'write', defaults to 'write')\n * @returns Database instance (never undefined)\n * @throws Error if database is not initialized\n *\n * @example\n * ```typescript\n * import { getDatabase } from '@spfn/core/db';\n *\n * // Always returns a valid instance or throws\n * const db = getDatabase();\n * const users = await db.select().from(usersTable);\n *\n * // For read operations (uses replica if available, falls back to primary)\n * const dbRead = getDatabase('read');\n * const posts = await dbRead.select().from(postsTable);\n * ```\n */\nexport function getDatabase(type?: DbConnectionType): PostgresJsDatabase<Record<string, unknown>>\n{\n const writeInst = getWriteInstance();\n const readInst = getReadInstance();\n\n // Detailed debug logging with caller info (only if DB_DEBUG_TRACE is enabled in non-production)\n if (env.DB_DEBUG_TRACE && env.NODE_ENV !== 'production')\n {\n const caller = getCallerInfo();\n dbLogger.debug('getDatabase() called', {\n type: type ?? 'write',\n hasWrite: !!writeInst,\n hasRead: !!readInst,\n caller,\n });\n }\n\n if (type === 'read')\n {\n const db = readInst ?? writeInst;\n if (!db)\n {\n throw createNotInitializedError('read');\n }\n return db;\n }\n\n // Default: 'write' type\n if (!writeInst)\n {\n throw createNotInitializedError('write');\n }\n\n return writeInst;\n}\n\n/**\n * Set global database instances (for testing or manual configuration)\n *\n * This function directly sets database instances without creating connections\n * or performing validation. It's primarily intended for testing scenarios.\n *\n * @param write - Database write instance (pass undefined to clear)\n * @param read - Database read instance (optional, defaults to write, pass undefined to clear)\n *\n * @remarks\n * **Important:** To properly close database connections with cleanup, use `closeDatabase()` instead.\n * This function only updates the global instances without closing the underlying connections.\n * Setting both to undefined will clear the instances but leave connections open, which may cause resource leaks.\n *\n * @example\n * ```typescript\n * import { setDatabase } from '@spfn/core/db';\n * import { drizzle } from 'drizzle-orm/postgres-js';\n * import postgres from 'postgres';\n *\n * // Set custom database instances (testing)\n * const writeClient = postgres('postgresql://primary:5432/mydb');\n * const readClient = postgres('postgresql://replica:5432/mydb');\n * setDatabase(drizzle(writeClient), drizzle(readClient));\n *\n * // Clear instances (not recommended - use closeDatabase() instead)\n * setDatabase(undefined, undefined);\n * ```\n */\nexport function setDatabase(\n write: PostgresJsDatabase<Record<string, unknown>> | undefined,\n read?: PostgresJsDatabase<Record<string, unknown>> | undefined\n): void\n{\n setWriteInstance(write);\n setReadInstance(read ?? write);\n}\n\n/**\n * Initialize database from environment variables\n * Automatically called by server startup\n *\n * Supported environment variables:\n * - DATABASE_URL (single primary)\n * - DATABASE_WRITE_URL + DATABASE_READ_URL (primary + replica)\n * - DB_POOL_MAX (connection pool max size)\n * - DB_POOL_IDLE_TIMEOUT (connection idle timeout in seconds)\n * - DB_HEALTH_CHECK_ENABLED (enable health checks, default: true)\n * - DB_HEALTH_CHECK_INTERVAL (health check interval in ms, default: 60000)\n * - DB_HEALTH_CHECK_RECONNECT (enable auto-reconnect, default: true)\n * - DB_HEALTH_CHECK_MAX_RETRIES (max reconnection attempts, default: 3)\n * - DB_HEALTH_CHECK_RETRY_INTERVAL (retry interval in ms, default: 5000)\n * - DB_MONITORING_ENABLED (enable query monitoring, default: true in dev, false in prod)\n * - DB_MONITORING_SLOW_THRESHOLD (slow query threshold in ms, default: 1000)\n * - DB_MONITORING_LOG_QUERIES (log actual SQL queries, default: false)\n * - DB_DEBUG_TRACE (enable detailed getDatabase() call tracing with caller info, default: false)\n *\n * Configuration priority:\n * 1. options parameter (ServerConfig)\n * 2. Environment variables\n * 3. Defaults (based on NODE_ENV)\n *\n * @param options - Optional database configuration (pool settings, etc.)\n * @returns Object with write and read instances\n *\n * @example\n * ```typescript\n * import { initDatabase } from '@spfn/core/db';\n *\n * // Manual initialization (not needed if using server startup)\n * const { write, read } = await initDatabase();\n * if (write) {\n * console.log('Database connected');\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Custom pool configuration\n * const { write, read } = await initDatabase({\n * pool: { max: 50, idleTimeout: 60 }\n * });\n * ```\n */\nexport async function initDatabase(options?: DatabaseOptions): Promise<{\n write?: PostgresJsDatabase<Record<string, unknown>>;\n read?: PostgresJsDatabase<Record<string, unknown>>;\n}>\n{\n // Prevent initialization during close operation\n if (isClosing)\n {\n throw new Error('Cannot initialize database while closing');\n }\n\n // Already initialized\n const writeInst = getWriteInstance();\n if (writeInst)\n {\n dbLogger.debug('Database already initialized');\n return { write: writeInst, read: getReadInstance() };\n }\n\n // Initialization in progress - wait for it to complete\n if (initPromise)\n {\n dbLogger.debug('Database initialization in progress, waiting...');\n return await initPromise;\n }\n\n // Start initialization with lock\n initPromise = (async () =>\n {\n try\n {\n // Auto-detect from environment\n const result = await createDatabaseFromEnv(options);\n\n // Test connections\n try\n {\n await testDatabaseConnections(result.write, result.read);\n }\n catch (error: unknown)\n {\n // Connection test failed - cleanup and throw\n await cleanupDatabaseConnections(result.writeClient, result.readClient);\n\n const message = error instanceof Error ? error.message : 'Unknown error';\n throw new Error(`Database connection test failed: ${message}`);\n }\n\n // Check if database was closed during initialization\n if (isClosing)\n {\n dbLogger.warn('Database closed during initialization, cleaning up...');\n await cleanupDatabaseConnections(result.writeClient, result.readClient);\n throw new Error('Database closed during initialization');\n }\n\n // Store instances in globalThis\n setWriteInstance(result.write);\n setReadInstance(result.read);\n setWriteClient(result.writeClient);\n setReadClient(result.readClient);\n\n const hasReplica = result.read && result.read !== result.write;\n dbLogger.info(\n hasReplica\n ? 'Database connected (Primary + Replica)'\n : 'Database connected'\n );\n\n // Start health check (automatic)\n const healthCheckConfig = buildHealthCheckConfig(options?.healthCheck);\n if (healthCheckConfig.enabled)\n {\n startHealthCheck(healthCheckConfig, options, getDatabase, closeDatabase);\n }\n\n // Initialize monitoring configuration\n const monConfig = buildMonitoringConfig(options?.monitoring);\n setMonitoringConfig(monConfig);\n if (monConfig.enabled)\n {\n dbLogger.info('Database query monitoring enabled', {\n slowThreshold: `${monConfig.slowThreshold}ms`,\n logQueries: monConfig.logQueries,\n });\n }\n\n return { write: getWriteInstance(), read: getReadInstance() };\n }\n finally\n {\n // Clear lock after initialization completes (success or failure)\n initPromise = null;\n }\n })();\n\n return await initPromise;\n}\n\n/**\n * Close all database connections and cleanup\n *\n * Properly closes postgres connection pools with timeout.\n * Should be called during graceful shutdown or after tests.\n *\n * @example\n * ```typescript\n * import { closeDatabase } from '@spfn/core/db';\n *\n * // During graceful shutdown\n * process.on('SIGTERM', async () => {\n * await closeDatabase();\n * process.exit(0);\n * });\n *\n * // In tests\n * afterAll(async () => {\n * await closeDatabase();\n * });\n * ```\n */\nexport async function closeDatabase(): Promise<void>\n{\n // Prevent concurrent close operations\n if (isClosing)\n {\n dbLogger.debug('Database close already in progress');\n return;\n }\n\n // Set closing flag early to prevent new operations\n isClosing = true;\n\n // Wait for any in-progress initialization to complete before closing\n if (initPromise)\n {\n dbLogger.debug('Waiting for database initialization to complete before closing...');\n\n try\n {\n await initPromise;\n }\n catch (_error: unknown)\n {\n // Initialization failed, but we still need to cleanup any partial state\n dbLogger.debug('Initialization failed during close, proceeding with cleanup');\n }\n }\n\n const writeInst = getWriteInstance();\n const readInst = getReadInstance();\n if (!writeInst && !readInst)\n {\n dbLogger.debug('No database connections to close');\n isClosing = false;\n return;\n }\n\n try\n {\n // Stop health check\n stopHealthCheck();\n\n const closePromises: Promise<void>[] = [];\n\n // Close write client\n const writeC = getWriteClient();\n if (writeC)\n {\n closePromises.push(closeDatabaseClient(writeC, 'write'));\n }\n\n // Close read client (if different from write)\n const readC = getReadClient();\n if (readC && readC !== writeC)\n {\n closePromises.push(closeDatabaseClient(readC, 'read'));\n }\n\n // Wait for all connections to close (use allSettled to ensure all cleanup attempts complete)\n await Promise.allSettled(closePromises);\n\n dbLogger.info('All database connections closed');\n }\n finally\n {\n // Always clear instances and reset flag\n setWriteInstance(undefined);\n setReadInstance(undefined);\n setWriteClient(undefined);\n setReadClient(undefined);\n setMonitoringConfig(undefined);\n isClosing = false;\n }\n}\n\n/**\n * Get database connection info (for debugging)\n *\n * Returns the current state of database connections without throwing errors.\n * Useful for health checks, monitoring, and debugging initialization issues.\n *\n * @returns Connection status information\n * - `hasWrite`: Whether write database instance is initialized\n * - `hasRead`: Whether read database instance is initialized\n * - `isReplica`: Whether read and write are different instances (Primary + Replica setup)\n *\n * @example\n * ```typescript\n * import { getDatabaseInfo } from '@spfn/core/db';\n *\n * const info = getDatabaseInfo();\n * console.log(`Write: ${info.hasWrite}, Read: ${info.hasRead}, Replica: ${info.isReplica}`);\n *\n * // Check before using database\n * if (!info.hasWrite) {\n * console.warn('Database not initialized');\n * }\n *\n * // Detect Primary + Replica setup\n * if (info.isReplica) {\n * console.log('Using Primary + Replica configuration');\n * }\n * ```\n */\nexport function getDatabaseInfo(): {\n hasWrite: boolean;\n hasRead: boolean;\n isReplica: boolean;\n}\n{\n const writeInst = getWriteInstance();\n const readInst = getReadInstance();\n\n return {\n hasWrite: !!writeInst,\n hasRead: !!readInst,\n isReplica: !!(readInst && readInst !== writeInst),\n };\n}\n\n/**\n * Get current monitoring configuration\n *\n * Returns the monitoring configuration that was set during database initialization.\n * Used by Repository to determine if and how to monitor query performance.\n *\n * @returns Current monitoring configuration or undefined if database not initialized\n *\n * @example\n * ```typescript\n * import { getDatabaseMonitoringConfig } from '@spfn/core/db';\n *\n * const config = getDatabaseMonitoringConfig();\n * if (config?.enabled) {\n * console.log(`Slow query threshold: ${config.slowThreshold}ms`);\n * }\n * ```\n */\nexport function getDatabaseMonitoringConfig(): MonitoringConfig | undefined\n{\n return getMonitoringConfig();\n}","/**\n * Drizzle Kit configuration generator\n * Automatically generates drizzle.config.ts from environment variables\n */\n\nimport { existsSync, readdirSync, readFileSync, statSync } from 'fs';\nimport { join, dirname, basename } from 'path';\nimport { env } from '@spfn/core/config';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Index file patterns to exclude from schema discovery\n */\nconst INDEX_FILE_PATTERNS = [\n '/index',\n '/index.ts',\n '/index.js',\n '/index.mjs',\n '\\\\index',\n '\\\\index.ts',\n '\\\\index.js',\n '\\\\index.mjs',\n];\n\n/**\n * Supported file extensions for schema files\n * Only these extensions will be included in schema discovery\n */\nconst SUPPORTED_EXTENSIONS = ['.ts', '.js', '.mjs'];\n\n// ============================================================================\n// Helper Functions (Private)\n// ============================================================================\n\n/**\n * Check if a file path is an index file\n *\n * @param filePath - File path to check\n * @returns true if file is an index file\n * @internal\n */\nfunction isIndexFile(filePath: string): boolean\n{\n return INDEX_FILE_PATTERNS.some(pattern => filePath.endsWith(pattern));\n}\n\n/**\n * Check if a path is absolute\n *\n * @param path - Path to check\n * @returns true if path is absolute\n * @internal\n */\nfunction isAbsolutePath(path: string): boolean\n{\n // Unix absolute path (starts with /)\n if (path.startsWith('/')) return true;\n\n // Windows absolute path (C:\\ or C:/)\n return !!path.match(/^[A-Za-z]:[\\/\\\\]/);\n}\n\n/**\n * Check if a file has a supported extension\n *\n * @param filePath - File path to check\n * @returns true if file has supported extension\n * @internal\n */\nfunction hasSupportedExtension(filePath: string): boolean\n{\n // Exclude .d.ts files (TypeScript declaration files - not actual schemas)\n if (filePath.endsWith('.d.ts')) return false;\n\n return SUPPORTED_EXTENSIONS.some(ext => filePath.endsWith(ext));\n}\n\n/**\n * Filter out index files from file list\n *\n * @param files - Array of file paths\n * @returns Filtered array without index files\n * @internal\n */\nfunction filterIndexFiles(files: string[]): string[]\n{\n return files.filter(file => !isIndexFile(file));\n}\n\n/**\n * Scan directory recursively for files\n *\n * @param dir - Directory to scan\n * @param extension - Optional file extension filter\n * @returns Array of file paths\n * @internal\n */\nfunction scanDirectoryRecursive(dir: string, extension?: string): string[]\n{\n const files: string[] = [];\n\n if (!existsSync(dir)) return files;\n\n try\n {\n const entries = readdirSync(dir);\n\n for (const entry of entries)\n {\n const fullPath = join(dir, entry);\n\n try\n {\n const stat = statSync(fullPath);\n\n if (stat.isDirectory())\n {\n files.push(...scanDirectoryRecursive(fullPath, extension));\n }\n else if (stat.isFile())\n {\n // Check if file matches extension AND has supported extension\n if ((!extension || fullPath.endsWith(extension)) && hasSupportedExtension(fullPath))\n {\n files.push(fullPath);\n }\n }\n }\n catch (error: unknown)\n {\n // Skip files we can't stat (permission denied, etc.)\n // Silent skip is intentional - we don't want to fail on restricted files\n }\n }\n }\n catch (error: unknown)\n {\n // Skip directories we can't read (permission denied, etc.)\n // Silent skip is intentional - we don't want to fail on restricted directories\n }\n\n return files;\n}\n\n/**\n * Scan directory (single level) for files matching pattern\n *\n * @param dir - Directory to scan\n * @param filePattern - File pattern to match (e.g., \"*.js\")\n * @returns Array of file paths\n * @internal\n */\nfunction scanDirectorySingleLevel(dir: string, filePattern: string): string[]\n{\n const files: string[] = [];\n\n if (!existsSync(dir)) return files;\n\n try\n {\n const entries = readdirSync(dir);\n\n for (const entry of entries)\n {\n const fullPath = join(dir, entry);\n\n try\n {\n const stat = statSync(fullPath);\n\n if (stat.isFile())\n {\n // Simple pattern matching (*.js matches foo.js) AND check supported extensions\n if ((filePattern === '*' ||\n (filePattern.startsWith('*.') && entry.endsWith(filePattern.slice(1)))) &&\n hasSupportedExtension(fullPath))\n {\n files.push(fullPath);\n }\n }\n }\n catch (error: unknown)\n {\n // Skip files we can't stat\n }\n }\n }\n catch (error: unknown)\n {\n // Skip directories we can't read\n }\n\n return files;\n}\n\n// ============================================================================\n// Types & Interfaces\n// ============================================================================\n\nexport interface DrizzleConfigOptions\n{\n /** Database connection URL (defaults to process.env.DATABASE_URL) */\n databaseUrl?: string;\n\n /** Schema files glob pattern or array of patterns (defaults to './src/server/entities/\\*\\*\\/*.ts') */\n schema?: string | string[];\n\n /** Migration output directory (defaults to './src/server/drizzle') */\n out?: string;\n\n /** Database dialect (auto-detected from URL if not provided) */\n dialect?: 'postgresql' | 'mysql' | 'sqlite';\n\n /** Current working directory for discovering package schemas */\n cwd?: string;\n\n /** Disable automatic package schema discovery */\n disablePackageDiscovery?: boolean;\n\n /** Only include schemas from specific package (e.g., '@spfn/cms') */\n packageFilter?: string;\n\n /** Expand glob patterns to actual file paths (useful for Drizzle Studio) */\n expandGlobs?: boolean;\n}\n\n/**\n * Expand glob patterns to actual file paths\n * Handles patterns like:\n * - ./dist/entities/*.js → [./dist/entities/foo.js, ./dist/entities/bar.js]\n * - ./dist/entities/**\\/*.js → recursively finds all .js files\n *\n * @param pattern - Glob pattern or file path\n * @returns Array of expanded file paths\n */\nfunction expandGlobPattern(pattern: string): string[]\n{\n // If pattern doesn't contain wildcards, return as-is\n if (!pattern.includes('*'))\n {\n return existsSync(pattern) ? [pattern] : [];\n }\n\n // Handle /**/* pattern (recursive)\n if (pattern.includes('**'))\n {\n const [baseDir, ...rest] = pattern.split('**');\n const extension = rest.join('').replace(/[\\/\\\\]\\*\\./g, '').trim();\n const dir = baseDir.trim() || '.';\n\n return scanDirectoryRecursive(dir, extension || undefined);\n }\n\n // Handle /* pattern (single level)\n const dir = dirname(pattern);\n const filePattern = basename(pattern);\n\n return scanDirectorySingleLevel(dir, filePattern);\n}\n\n/**\n * Discover schema paths from installed packages\n * Only scans packages that:\n * 1. Are in @spfn scope\n * 2. Are direct dependencies with \"spfn\" keyword or \"spfn\" field in package.json\n */\nfunction discoverPackageSchemas(cwd: string): string[]\n{\n const schemas: string[] = [];\n const nodeModulesPath = join(cwd, 'node_modules');\n\n if (!existsSync(nodeModulesPath))\n {\n return schemas;\n }\n\n // Get direct dependencies from project's package.json\n const projectPkgPath = join(cwd, 'package.json');\n let directDeps: Set<string> = new Set();\n\n if (existsSync(projectPkgPath))\n {\n try\n {\n const projectPkg = JSON.parse(readFileSync(projectPkgPath, 'utf-8'));\n directDeps = new Set([\n ...Object.keys(projectPkg.dependencies || {}),\n ...Object.keys(projectPkg.devDependencies || {})\n ]);\n }\n catch (error: unknown)\n {\n // If we can't read project package.json, just scan @spfn packages\n // Silent skip is intentional - we continue with @spfn package discovery\n }\n }\n\n const checkPackage = (_pkgName: string, pkgPath: string) =>\n {\n const pkgJsonPath = join(pkgPath, 'package.json');\n\n if (!existsSync(pkgJsonPath)) return;\n\n try\n {\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));\n\n // Check if package has schema declarations\n if (pkgJson.spfn?.schemas)\n {\n const packageSchemas = Array.isArray(pkgJson.spfn.schemas)\n ? pkgJson.spfn.schemas\n : [pkgJson.spfn.schemas];\n\n // Convert to absolute paths from package root and expand globs\n for (const schema of packageSchemas)\n {\n const absolutePath = join(pkgPath, schema);\n\n // Expand glob patterns to actual file lists\n // This prevents drizzle-kit from hanging on glob patterns\n const expandedFiles = expandGlobPattern(absolutePath);\n\n // Filter out index files (they are re-exports, not schema definitions)\n const schemaFiles = filterIndexFiles(expandedFiles);\n\n schemas.push(...schemaFiles);\n }\n }\n }\n catch (error: unknown)\n {\n // Skip packages with invalid package.json\n // Silent skip is intentional - we continue checking other packages\n }\n };\n\n // 1. Always scan @spfn/* packages\n const spfnDir = join(nodeModulesPath, '@spfn');\n if (existsSync(spfnDir))\n {\n try\n {\n const spfnPackages = readdirSync(spfnDir);\n for (const pkg of spfnPackages)\n {\n checkPackage(`@spfn/${pkg}`, join(spfnDir, pkg));\n }\n }\n catch (error: unknown)\n {\n // Skip if can't read @spfn directory\n // Silent skip is intentional - we continue with direct dependencies\n }\n }\n\n // 2. Check direct dependencies for SPFN integration\n for (const depName of directDeps)\n {\n // Skip if already checked (@spfn/* packages)\n if (depName.startsWith('@spfn/')) continue;\n\n // Resolve package path (handle scoped packages)\n const pkgPath = depName.startsWith('@')\n ? join(nodeModulesPath, ...depName.split('/'))\n : join(nodeModulesPath, depName);\n\n checkPackage(depName, pkgPath);\n }\n\n return schemas;\n}\n\n/**\n * Detect database dialect from connection URL\n */\nexport function detectDialect(url: string): 'postgresql' | 'mysql' | 'sqlite'\n{\n if (url.startsWith('postgres://') || url.startsWith('postgresql://'))\n {\n return 'postgresql';\n }\n\n if (url.startsWith('mysql://'))\n {\n return 'mysql';\n }\n\n if (url.startsWith('sqlite://') || url.includes('.db') || url.includes('.sqlite'))\n {\n return 'sqlite';\n }\n\n throw new Error(\n `Unsupported database URL format: ${url}. Supported: postgresql://, mysql://, sqlite://`\n );\n}\n\n/**\n * Generate Drizzle Kit configuration\n *\n * @param options - Configuration options\n * @returns Drizzle Kit configuration object\n *\n * @example\n * ```ts\n * // Zero-config (reads from process.env.DATABASE_URL)\n * const config = getDrizzleConfig();\n *\n * // Custom config\n * const config = getDrizzleConfig({\n * databaseUrl: 'postgresql://localhost/mydb',\n * schema: './src/db/schema/*.ts',\n * out: './migrations',\n * });\n * ```\n */\nexport function getDrizzleConfig(options: DrizzleConfigOptions = {})\n{\n const databaseUrl = options.databaseUrl ?? env.DATABASE_URL;\n\n if (!databaseUrl)\n {\n throw new Error(\n 'DATABASE_URL is required. Set it in .env or pass it to getDrizzleConfig()'\n );\n }\n\n const dialect = options.dialect ?? detectDialect(databaseUrl);\n const out = options.out ?? './src/server/drizzle';\n\n // If packageFilter is specified, only include that package's schemas\n if (options.packageFilter)\n {\n const packageSchemas = options.disablePackageDiscovery\n ? []\n : discoverPackageSchemas(options.cwd ?? process.cwd());\n\n // Filter to only the specified package\n const filteredSchemas = packageSchemas.filter(schemaPath =>\n schemaPath.includes(`node_modules/${options.packageFilter}/`)\n );\n\n if (filteredSchemas.length === 0)\n {\n throw new Error(\n `No schemas found for package ${options.packageFilter}. ` +\n `Make sure the package is installed and has \"spfn.schemas\" in package.json.`\n );\n }\n\n const schema = filteredSchemas.length === 1 ? filteredSchemas[0] : filteredSchemas;\n\n return {\n schema,\n out,\n dialect,\n dbCredentials: getDbCredentials(dialect, databaseUrl),\n };\n }\n\n // Default: merge user schemas and all package schemas\n const userSchema = options.schema ?? './src/server/entities/**/*.ts'; // Support nested folders\n const userSchemas = Array.isArray(userSchema) ? userSchema : [userSchema];\n\n // Discover package schemas unless disabled\n const packageSchemas = options.disablePackageDiscovery\n ? []\n : discoverPackageSchemas(options.cwd ?? process.cwd());\n\n // Merge user schemas and package schemas\n let allSchemas = [...userSchemas, ...packageSchemas];\n\n // Expand glob patterns if requested (useful for Drizzle Studio)\n if (options.expandGlobs)\n {\n const expandedSchemas: string[] = [];\n for (const schema of allSchemas)\n {\n const expanded = expandGlobPattern(schema);\n\n // Filter out index files (they are re-exports, not schema definitions)\n const filtered = filterIndexFiles(expanded);\n\n expandedSchemas.push(...filtered);\n }\n allSchemas = expandedSchemas;\n }\n\n const schema = allSchemas.length === 1 ? allSchemas[0] : allSchemas;\n\n return {\n schema,\n out,\n dialect,\n dbCredentials: getDbCredentials(dialect, databaseUrl),\n };\n}\n\n/**\n * Get database credentials based on dialect\n */\nfunction getDbCredentials(dialect: string, url: string)\n{\n switch (dialect)\n {\n case 'postgresql':\n case 'mysql':\n return { url };\n\n case 'sqlite':\n // Extract file path from sqlite:// URL\n const dbPath = url.replace('sqlite://', '').replace('sqlite:', '');\n return { url: dbPath };\n\n default:\n throw new Error(`Unsupported dialect: ${dialect}`);\n }\n}\n\n/**\n * Generate drizzle.config.ts file content\n *\n * @param options - Configuration options\n * @returns File content as string\n */\nexport function generateDrizzleConfigFile(options: DrizzleConfigOptions = {}): string\n{\n const config = getDrizzleConfig(options);\n const cwd = options.cwd ?? process.cwd();\n\n // Convert schema paths to absolute paths for Drizzle Studio compatibility\n const normalizeSchemaPath = (schemaPath: string): string =>\n {\n // If already absolute, return as-is\n if (isAbsolutePath(schemaPath))\n {\n return schemaPath;\n }\n // Convert relative to absolute\n return join(cwd, schemaPath);\n };\n\n // Format schema value (handle both string and array)\n const schemaValue = Array.isArray(config.schema)\n ? `[\\n ${config.schema.map(s => `'${normalizeSchemaPath(s)}'`).join(',\\n ')}\\n ]`\n : `'${normalizeSchemaPath(config.schema as string)}'`;\n\n return `import { defineConfig } from 'drizzle-kit';\n\nexport default defineConfig({\n schema: ${schemaValue},\n out: '${config.out}',\n dialect: '${config.dialect}',\n dbCredentials: ${JSON.stringify(config.dbCredentials, null, 4)},\n});\n`;\n}","/**\n * Schema Helper Functions\n *\n * Common field patterns for Drizzle ORM entities to reduce boilerplate.\n *\n * @example\n * ```typescript\n * import { pgTable, text } from 'drizzle-orm/pg-core';\n * import { id, timestamps } from '@spfn/core';\n *\n * export const users = pgTable('users', {\n * id: id(),\n * email: text('email').unique(),\n * ...timestamps(),\n * });\n * ```\n */\n\nimport type { PgColumn } from 'drizzle-orm/pg-core';\nimport { bigserial, timestamp, text, uuid as pgUuid, jsonb } from 'drizzle-orm/pg-core';\n\n/**\n * Standard auto-incrementing primary key\n *\n * @returns bigserial primary key column\n *\n * @example\n * ```typescript\n * export const users = pgTable('users', {\n * id: id(),\n * // ...\n * });\n * ```\n */\nexport function id()\n{\n return bigserial('id', { mode: 'number' }).primaryKey();\n}\n\n/**\n * Standard timestamp fields (createdAt, updatedAt)\n *\n * Both fields are timezone-aware, auto-set to current time on creation.\n * updatedAt must be manually updated in your application code.\n *\n * @returns Object with createdAt and updatedAt columns\n *\n * @example\n * ```typescript\n * export const users = pgTable('users', {\n * id: id(),\n * email: text('email'),\n * ...timestamps(),\n * });\n *\n * // Manual update\n * await db.update(users)\n * .set({\n * email: 'new@example.com',\n * updatedAt: new Date()\n * })\n * .where(eq(users.id, userId));\n * ```\n */\nexport function timestamps()\n{\n return {\n createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' })\n .defaultNow()\n .notNull(),\n updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' })\n .defaultNow()\n .notNull(),\n };\n}\n\n/**\n * Foreign key reference to another table\n *\n * Creates a bigserial column with cascade delete.\n * Type-safe: ensures the reference points to a valid PostgreSQL column.\n *\n * @param name - Column name (e.g., 'author' creates 'author_id')\n * @param reference - Reference to parent table column\n * @param options - Optional foreign key options\n *\n * @example\n * ```typescript\n * import { users } from './users';\n *\n * export const posts = pgTable('posts', {\n * id: id(),\n * authorId: foreignKey('author', () => users.id),\n * ...timestamps(),\n * });\n * ```\n */\nexport function foreignKey<T extends PgColumn>(\n name: string,\n reference: () => T,\n options?: { onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action' }\n)\n{\n return bigserial(`${name}_id`, { mode: 'number' })\n .notNull()\n .references(reference, { onDelete: options?.onDelete ?? 'cascade' });\n}\n\n/**\n * Optional foreign key reference (nullable)\n *\n * Type-safe: ensures the reference points to a valid PostgreSQL column.\n *\n * @param name - Column name (e.g., 'author' creates 'author_id')\n * @param reference - Reference to parent table column\n * @param options - Optional foreign key options\n *\n * @example\n * ```typescript\n * export const posts = pgTable('posts', {\n * id: id(),\n * authorId: optionalForeignKey('author', () => users.id),\n * });\n * ```\n */\nexport function optionalForeignKey<T extends PgColumn>(\n name: string,\n reference: () => T,\n options?: { onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action' }\n)\n{\n return bigserial(`${name}_id`, { mode: 'number' })\n .references(reference, { onDelete: options?.onDelete ?? 'set null' });\n}\n\n/**\n * UUID primary key\n *\n * Creates a UUID column as primary key with automatic default value generation.\n * Useful for distributed systems or when you need globally unique identifiers.\n *\n * @returns uuid primary key column with gen_random_uuid() default\n *\n * @example\n * ```typescript\n * export const sessions = pgTable('sessions', {\n * id: uuid(),\n * userId: foreignKey('user', () => users.id),\n * ...timestamps(),\n * });\n * ```\n */\nexport function uuid()\n{\n return pgUuid('id').defaultRandom().primaryKey();\n}\n\n/**\n * Audit fields for tracking record creators and updaters\n *\n * Adds createdBy and updatedBy fields for user tracking.\n * Typically stores user IDs, emails, or usernames.\n *\n * @returns Object with createdBy and updatedBy columns\n *\n * @example\n * ```typescript\n * export const posts = pgTable('posts', {\n * id: id(),\n * title: text('title'),\n * ...timestamps(),\n * ...auditFields(),\n * });\n *\n * // Usage in route\n * await db.insert(posts).values({\n * title: 'New Post',\n * createdBy: currentUser.email,\n * });\n * ```\n */\nexport function auditFields()\n{\n return {\n createdBy: text('created_by'),\n updatedBy: text('updated_by'),\n };\n}\n\n/**\n * Publishing fields for content management\n *\n * Tracks when and by whom content was published.\n * Useful for CMS, blog posts, articles, etc.\n *\n * @returns Object with publishedAt and publishedBy columns\n *\n * @example\n * ```typescript\n * export const articles = pgTable('articles', {\n * id: id(),\n * title: text('title'),\n * status: text('status'), // draft/published/archived\n * ...publishingFields(),\n * ...timestamps(),\n * });\n *\n * // Publishing an article\n * await db.update(articles)\n * .set({\n * status: 'published',\n * publishedAt: new Date(),\n * publishedBy: currentUser.email,\n * })\n * .where(eq(articles.id, articleId));\n * ```\n */\nexport function publishingFields()\n{\n return {\n publishedAt: timestamp('published_at', { withTimezone: true, mode: 'date' }),\n publishedBy: text('published_by'),\n };\n}\n\n/**\n * Custom verification timestamp field\n *\n * Creates a nullable timestamp field for tracking verification status.\n * Useful for email verification, phone verification, etc.\n *\n * @param fieldName - Field name in camelCase (e.g., 'emailVerified', 'phoneVerified')\n * @returns Object with verification timestamp column (converts to snake_case + '_at')\n *\n * @example\n * ```typescript\n * export const users = pgTable('users', {\n * id: id(),\n * email: text('email'),\n * phone: text('phone'),\n * ...verificationTimestamp('emailVerified'), // emailVerifiedAt -> email_verified_at\n * ...verificationTimestamp('phoneVerified'), // phoneVerifiedAt -> phone_verified_at\n * ...timestamps(),\n * });\n *\n * // Verify email\n * await db.update(users)\n * .set({ emailVerifiedAt: new Date() })\n * .where(eq(users.email, userEmail));\n * ```\n */\nexport function verificationTimestamp(fieldName: string)\n{\n // Convert camelCase to snake_case and add '_at' suffix\n const columnName = fieldName\n .replace(/([A-Z])/g, '_$1')\n .toLowerCase()\n .replace(/^_/, '') + '_at';\n\n return {\n [fieldName + 'At']: timestamp(columnName, { withTimezone: true, mode: 'date' }),\n };\n}\n\n/**\n * Soft delete fields\n *\n * Adds deletedAt and deletedBy for logical deletion.\n * Records are marked as deleted instead of being physically removed.\n *\n * @returns Object with deletedAt and deletedBy columns\n *\n * @example\n * ```typescript\n * export const posts = pgTable('posts', {\n * id: id(),\n * title: text('title'),\n * ...timestamps(),\n * ...softDelete(),\n * });\n *\n * // Soft delete\n * await db.update(posts)\n * .set({\n * deletedAt: new Date(),\n * deletedBy: currentUser.email,\n * })\n * .where(eq(posts.id, postId));\n *\n * // Query only non-deleted records\n * const activePosts = await db.select()\n * .from(posts)\n * .where(isNull(posts.deletedAt));\n * ```\n */\nexport function softDelete()\n{\n return {\n deletedAt: timestamp('deleted_at', { withTimezone: true, mode: 'date' }),\n deletedBy: text('deleted_by'),\n };\n}\n\n/**\n * UTC timestamp field\n *\n * Creates a timezone-aware timestamp column (TIMESTAMPTZ) that stores values in UTC.\n * PostgreSQL automatically converts between client timezone and UTC.\n * Chain with .notNull(), .defaultNow(), etc. for additional constraints.\n *\n * @param fieldName - Database column name (in snake_case)\n * @param mode - Data type mode: 'date' (Date object) or 'string' (ISO string)\n * @returns Timestamp column with timezone support\n *\n * @example\n * ```typescript\n * export const users = pgTable('users', {\n * id: id(),\n * email: text('email'),\n *\n * // Nullable timestamp\n * emailVerifiedAt: utcTimestamp('email_verified_at'),\n *\n * // Required with default\n * lastLoginAt: utcTimestamp('last_login_at').defaultNow().notNull(),\n *\n * // String mode\n * processedAt: utcTimestamp('processed_at', 'string'),\n *\n * ...timestamps(),\n * });\n * ```\n */\nexport function utcTimestamp(\n fieldName: string,\n mode: 'date' | 'string' = 'date'\n) {\n return timestamp(fieldName, {\n withTimezone: true,\n mode\n });\n}\n\n/**\n * Type-safe enum text field\n *\n * Creates a text column with enum constraint.\n * Chain with .notNull(), .default(), etc. for additional constraints.\n *\n * @param fieldName - Database column name (e.g., 'status', 'role', 'provider')\n * @param values - Const array of allowed values\n * @returns Text column with enum constraint\n *\n * @example\n * ```typescript\n * export const USER_STATUSES = ['active', 'inactive', 'suspended'] as const;\n * export type UserStatus = typeof USER_STATUSES[number];\n *\n * export const SOCIAL_PROVIDERS = ['google', 'github', 'kakao'] as const;\n * export type SocialProvider = typeof SOCIAL_PROVIDERS[number];\n *\n * export const users = pgTable('users', {\n * id: id(),\n * // Nullable\n * role: enumText('role', USER_STATUSES),\n *\n * // Required\n * provider: enumText('provider', SOCIAL_PROVIDERS).notNull(),\n *\n * // Required with default\n * status: enumText('status', USER_STATUSES).default('active').notNull(),\n *\n * ...timestamps(),\n * });\n * ```\n */\nexport function enumText<T extends readonly [string, ...string[]]>(\n fieldName: string,\n values: T\n)\n{\n // readonly를 제거하되 타입 정보는 유지\n return text(fieldName, { enum: values as T & [string, ...string[]] });\n}\n\n/**\n * Type-safe JSONB field\n *\n * Creates a JSONB column with required type parameter to ensure type safety.\n * Prevents the common mistake of using jsonb without type annotation,\n * which would result in `unknown` type and require type assertions.\n *\n * Chain with .notNull(), .default(), etc. for additional constraints.\n *\n * @param fieldName - Database column name (in snake_case)\n * @returns JSONB column with specified type\n *\n * @example\n * ```typescript\n * // Define your types\n * type LabelValue =\n * | { type: 'text'; content: string }\n * | { type: 'image'; url: string; alt?: string };\n *\n * type CachedContent = Record<string, LabelValue>;\n *\n * export const cmsPublishedCache = pgTable('published_cache', {\n * id: id(),\n * section: text('section').notNull(),\n *\n * // Type-safe JSONB field - no more `as any` needed!\n * content: typedJsonb<CachedContent>('content').notNull(),\n *\n * ...timestamps(),\n * });\n *\n * // Usage in route - no type assertion needed\n * const cache = await db.select().from(cmsPublishedCache)...;\n * const labels = cache.content; // Type: CachedContent ✅\n *\n * // For simple objects\n * metadata: typedJsonb<Record<string, any>>('metadata'),\n *\n * // For arrays\n * tags: typedJsonb<string[]>('tags').notNull(),\n * ```\n */\nexport function typedJsonb<T>(fieldName: string)\n{\n return jsonb(fieldName).$type<T>();\n}\n","/**\n * Database Schema Helper\n *\n * Provides utilities for creating isolated PostgreSQL schemas for SPFN functions\n */\n\nimport { pgSchema } from 'drizzle-orm/pg-core';\n\n/**\n * Create a namespaced PostgreSQL schema for a function\n *\n * @param packageName - NPM package name (e.g., '@spfn/cms', 'spfn-auth')\n * @returns PostgreSQL schema object for creating tables\n *\n * @example\n * ```typescript\n * // @spfn/cms → spfn_cms schema\n * import { createSchema } from '@spfn/core/db';\n *\n * const schema = createSchema('@spfn/cms');\n *\n * export const labels = schema.table('labels', {\n * id: id(),\n * name: text('name').notNull(),\n * });\n * // Creates table: spfn_cms.labels\n * ```\n */\nexport function createSchema(packageName: string)\n{\n const schemaName = packageNameToSchema(packageName);\n return pgSchema(schemaName);\n}\n\n/**\n * Convert package name to PostgreSQL schema name\n *\n * @param packageName - NPM package name\n * @returns Schema name in PostgreSQL format\n *\n * @example\n * ```typescript\n * packageNameToSchema('@spfn/cms') // 'spfn_cms'\n * packageNameToSchema('@company/spfn-auth') // 'company_spfn_auth'\n * packageNameToSchema('spfn-storage') // 'spfn_storage'\n * ```\n */\nexport function packageNameToSchema(packageName: string): string\n{\n // Remove @ and replace / and - with _\n return packageName\n .replace(/@/g, '')\n .replace(/\\//g, '_')\n .replace(/-/g, '_');\n}\n\n/**\n * Get recommended schema name for a package\n *\n * @param packageName - NPM package name\n * @returns Object with schema name and whether it's scoped\n *\n * @example\n * ```typescript\n * getSchemaInfo('@spfn/cms')\n * // { schemaName: 'spfn_cms', isScoped: true, scope: 'spfn' }\n *\n * getSchemaInfo('spfn-auth')\n * // { schemaName: 'spfn_auth', isScoped: false, scope: null }\n * ```\n */\nexport function getSchemaInfo(packageName: string)\n{\n const isScoped = packageName.startsWith('@');\n const scope = isScoped ? packageName.split('/')[0].substring(1) : null;\n const schemaName = packageNameToSchema(packageName);\n\n return {\n schemaName,\n isScoped,\n scope,\n };\n}","/**\n * AsyncLocalStorage-based Transaction Context\n *\n * Uses Node.js AsyncLocalStorage to propagate transactions throughout the async call chain.\n *\n * Features:\n * - AsyncLocalStorage-based context management\n * - Type-safe transaction propagation across async chains\n * - Transaction ID tracking for debugging and tracing\n * - Nested transaction detection and logging\n * - Transaction nesting level tracking\n */\nimport { AsyncLocalStorage } from 'async_hooks';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport { logger } from '@spfn/core/logger'; // Assuming logger is accessible\n\n/**\n * Transaction database type\n * Uses Record<string, unknown> to accept any schema shape\n */\nexport type TransactionDB = PostgresJsDatabase<Record<string, unknown>>;\n\nconst txLogger = logger.child('@spfn/core:transaction');\n\n/**\n * Transaction context stored in AsyncLocalStorage\n */\nexport type TransactionContext = {\n /** The actual Drizzle transaction object */\n tx: TransactionDB;\n /** Unique transaction ID for logging and tracing */\n txId: string; // Add txId to the context\n level: number;\n};\n\n/**\n * Global AsyncLocalStorage instance for transaction context\n */\nexport const asyncContext = new AsyncLocalStorage<TransactionContext>();\n\n/**\n * Get current transaction object and metadata from AsyncLocalStorage\n *\n * @returns TransactionContext if available, null otherwise\n */\nexport function getTransactionContext(): TransactionContext | null\n{\n return asyncContext.getStore() ?? null;\n}\n\n/**\n * Get current transaction from AsyncLocalStorage\n *\n * @returns Transaction if available, null otherwise\n */\nexport function getTransaction(): TransactionDB | null\n{\n const context = getTransactionContext();\n return context?.tx ?? null;\n}\n\n/**\n * Get current transaction ID from AsyncLocalStorage\n *\n * @returns Transaction ID if available, null otherwise\n */\nexport function getTransactionId(): string | null\n{\n const context = getTransactionContext();\n return context?.txId ?? null;\n}\n\n/**\n * Run a function within a transaction context\n *\n * The transaction will be available to all async operations within the callback\n * via getTransaction().\n *\n * @param tx - Drizzle transaction object\n * @param txId - Unique ID for the transaction\n * @param callback - Function to run within transaction context\n * @returns Result of the callback\n */\nexport function runWithTransaction<T>(\n tx: TransactionDB,\n txId: string, // Add txId parameter\n callback: () => Promise<T>\n): Promise<T>\n{\n const existingContext = getTransactionContext();\n\n // Determine the current transaction nesting level\n const newLevel = existingContext ? existingContext.level + 1 : 1;\n\n if (existingContext)\n {\n // Nested transaction detected. This means Drizzle will use a SAVEPOINT.\n txLogger.info('Nested transaction started (SAVEPOINT)', {\n outerTxId: existingContext.txId,\n innerTxId: txId,\n level: newLevel,\n });\n }\n else\n {\n // Root transaction\n txLogger.debug('Root transaction context set', { txId, level: newLevel });\n }\n\n // Store transaction, new ID, and the current nesting level\n return asyncContext.run({ tx, txId, level: newLevel }, callback);\n}","/**\n * Transaction Runner\n *\n * Standalone transaction execution utility for scripts, migrations, and CLI commands.\n * Provides the same transaction management capabilities as the Transactional middleware\n * but without Hono dependency.\n *\n * Features:\n * - Automatic transaction management (start/commit/rollback)\n * - Transaction propagation via AsyncLocalStorage\n * - PostgreSQL-level timeout with automatic rollback guarantee\n * - Execution time tracking and slow transaction warnings\n * - UUID-based transaction IDs for debugging\n *\n * Timeout Implementation:\n * Uses PostgreSQL `SET LOCAL statement_timeout` to ensure database-level timeout\n * enforcement. This guarantees that long-running transactions are actually rolled\n * back at the database level, preventing data inconsistency.\n *\n * @example\n * ```typescript\n * import { runInTransaction } from '@spfn/core/db/transaction';\n * import { users } from './schema';\n *\n * // Simple usage\n * const user = await runInTransaction(async (tx) => {\n * const [user] = await tx.insert(users).values({ name: 'John' }).returning();\n * return user;\n * });\n *\n * // With options\n * await runInTransaction(\n * async (tx) => {\n * await tx.insert(users).values({ name: 'Jane' });\n * await tx.insert(profiles).values({ userId: 1 });\n * },\n * {\n * context: 'migration:add-user',\n * timeout: 60000,\n * slowThreshold: 2000,\n * }\n * );\n * ```\n */\nimport { randomUUID } from 'crypto';\nimport { sql } from 'drizzle-orm';\nimport { logger } from '@spfn/core/logger';\nimport { getDatabase } from '../manager';\nimport { runWithTransaction, getTransactionContext, type TransactionDB } from './context';\nimport { TransactionError } from '@spfn/core/errors';\nimport { env } from '@spfn/core/config';\n\n/**\n * PostgreSQL maximum timeout value (max int4)\n */\nconst MAX_TIMEOUT_MS = 2147483647;\nconst txLogger = logger.child('@spfn/core:transaction');\n\n/**\n * Transaction runner options\n */\nexport interface RunInTransactionOptions\n{\n /**\n * Slow transaction warning threshold in milliseconds\n * @default 1000 (1 second)\n */\n slowThreshold?: number;\n\n /**\n * Enable transaction logging\n * @default true\n */\n enableLogging?: boolean;\n\n /**\n * Transaction timeout in milliseconds\n *\n * Sets PostgreSQL `statement_timeout` to enforce database-level timeout.\n * If transaction exceeds this duration, PostgreSQL will automatically cancel\n * the query and rollback the transaction, ensuring data consistency.\n *\n * Behavior:\n * - `timeout: 0` - Disables timeout (unlimited execution time)\n * - `timeout: null` - Uses default (30s or TRANSACTION_TIMEOUT env var)\n * - `timeout: undefined` - Uses default (30s or TRANSACTION_TIMEOUT env var)\n * - `timeout: N` - Sets timeout to N milliseconds (1 to 2147483647)\n *\n * Note: Timeout is only applied to root transactions. Nested transactions\n * (SAVEPOINTs) inherit the timeout from the outer transaction.\n *\n * @default 30000 (30 seconds) or TRANSACTION_TIMEOUT environment variable\n *\n * @example\n * ```typescript\n * // Use default timeout (30s)\n * await runInTransaction(callback);\n *\n * // Disable timeout for long-running operations\n * await runInTransaction(callback, { timeout: 0 });\n *\n * // Set custom timeout (60s)\n * await runInTransaction(callback, { timeout: 60000 });\n * ```\n */\n timeout?: number;\n\n /**\n * Context string for logging (e.g., 'migration:add-user', 'script:cleanup')\n * @default 'transaction'\n */\n context?: string;\n}\n\n/**\n * Run a callback function within a database transaction\n *\n * Automatically manages transaction lifecycle:\n * - Commits on success\n * - Rolls back on error\n * - Tracks execution time\n * - Warns about slow transactions\n * - Enforces timeout if configured\n *\n * Errors are propagated to the caller without modification.\n * Caller is responsible for error handling and conversion.\n *\n * @param callback - Function to execute within transaction\n * @param options - Transaction options\n * @returns Result of callback function\n * @throws TransactionError if database not initialized or timeout exceeded\n * @throws Any error thrown by callback function\n */\nexport async function runInTransaction<T>(\n callback: (tx: TransactionDB) => Promise<T>,\n options: RunInTransactionOptions = {}\n): Promise<T>\n{\n // Get default timeout from environment variable (default: 30 seconds)\n const defaultTimeout = env.TRANSACTION_TIMEOUT;\n\n const {\n slowThreshold = 1000,\n enableLogging = true,\n context = 'transaction',\n } = options;\n\n // Handle timeout: null/undefined → default, 0 → disabled, N → N milliseconds\n const timeout = options.timeout ?? defaultTimeout;\n\n // Generate transaction ID for debugging\n const txId = `tx_${randomUUID()}`;\n\n /**\n * Helper function to validate parameters and throw TransactionError\n */\n const validateAndThrow = (\n condition: boolean,\n message: string,\n logMessage: string,\n metadata: Record<string, unknown>\n ): void =>\n {\n if (condition)\n {\n const error = new TransactionError({ message, statusCode: 400, details: metadata });\n\n if (enableLogging)\n {\n txLogger.error(logMessage, { ...metadata, error: error.message });\n }\n\n throw error;\n }\n };\n\n // Validate all input parameters before DB access (fail-fast pattern)\n\n // Validate callback is a function\n validateAndThrow(\n typeof callback !== 'function',\n 'Callback must be a function',\n 'Invalid callback type',\n { txId, context, callbackType: typeof callback }\n );\n\n // Validate slowThreshold\n validateAndThrow(\n !Number.isInteger(slowThreshold) || slowThreshold < 0,\n `Invalid slowThreshold value: ${slowThreshold}. Must be a non-negative integer.`,\n 'Invalid slowThreshold',\n { txId, context, slowThreshold }\n );\n\n // Validate timeout value for SQL safety\n validateAndThrow(\n !Number.isInteger(timeout),\n `Invalid timeout value: ${timeout}. Must be an integer.`,\n 'Invalid timeout type',\n { txId, context, timeout }\n );\n\n validateAndThrow(\n timeout < 0,\n `Invalid timeout value: ${timeout}. Timeout must be non-negative (0 to disable, or 1-${MAX_TIMEOUT_MS}ms).`,\n 'Invalid timeout range',\n { txId, context, timeout }\n );\n\n validateAndThrow(\n timeout > MAX_TIMEOUT_MS,\n `Invalid timeout value: ${timeout}. Maximum timeout is ${MAX_TIMEOUT_MS}ms.`,\n 'Timeout exceeds maximum',\n { txId, context, timeout, maxTimeout: MAX_TIMEOUT_MS }\n );\n\n // Get write database instance (after all input validations)\n const writeDb = getDatabase('write');\n if (!writeDb)\n {\n const error = new TransactionError({\n message: 'Database not initialized. Cannot start transaction.',\n statusCode: 500,\n details: { txId, context }\n });\n\n if (enableLogging)\n {\n txLogger.error('Database not initialized', {\n txId,\n context,\n error: error.message,\n });\n }\n\n throw error;\n }\n\n // Check if we're in a nested transaction\n const existingContext = getTransactionContext();\n const isNested = existingContext !== null;\n\n // Warn about nested transaction timeout\n if (isNested && timeout > 0 && enableLogging)\n {\n txLogger.warn('Timeout ignored in nested transaction', {\n txId,\n context,\n outerTxId: existingContext.txId,\n requestedTimeout: `${timeout}ms`,\n reason: 'SET LOCAL statement_timeout affects the entire outer transaction',\n });\n }\n\n // Log transaction start AFTER all validations pass\n if (enableLogging)\n {\n txLogger.debug('Transaction started', { txId, context });\n }\n\n // Start timing from actual transaction execution\n const startTime = Date.now();\n\n // Execute transaction within try-catch to capture all errors\n try\n {\n // Execute transaction with PostgreSQL-level timeout\n const result = await writeDb.transaction(async (tx: TransactionDB) =>\n {\n // Set PostgreSQL statement timeout only for root transactions\n // Nested transactions (SAVEPOINTs) would affect the entire outer transaction\n if (timeout > 0 && !isNested)\n {\n // Using sql.raw() because SET commands don't support parameter binding\n await tx.execute(sql.raw(`SET LOCAL statement_timeout = ${timeout}`));\n }\n\n // Store transaction in AsyncLocalStorage\n return await runWithTransaction(tx, txId, async () =>\n {\n // Execute callback\n return await callback(tx);\n });\n });\n\n // Transaction successful (committed)\n const duration = Date.now() - startTime;\n\n if (enableLogging)\n {\n if (duration >= slowThreshold)\n {\n txLogger.warn('Slow transaction committed', {\n txId,\n context,\n duration: `${duration}ms`,\n threshold: `${slowThreshold}ms`,\n });\n }\n else\n {\n txLogger.debug('Transaction committed', {\n txId,\n context,\n duration: `${duration}ms`,\n });\n }\n }\n\n return result;\n }\n catch (error)\n {\n // Transaction failed (rolled back)\n const duration = Date.now() - startTime;\n\n if (enableLogging)\n {\n if (duration >= slowThreshold)\n {\n txLogger.warn('Slow transaction rolled back', {\n txId,\n context,\n duration: `${duration}ms`,\n threshold: `${slowThreshold}ms`,\n error: error instanceof Error ? error.message : String(error),\n errorType: error instanceof Error ? error.name : 'Unknown',\n });\n }\n else\n {\n txLogger.error('Transaction rolled back', {\n txId,\n context,\n duration: `${duration}ms`,\n error: error instanceof Error ? error.message : String(error),\n errorType: error instanceof Error ? error.name : 'Unknown',\n });\n }\n }\n\n // Re-throw error for caller to handle\n throw error;\n }\n}","/**\n * Transactional Middleware\n *\n * Wraps route handlers in a database transaction.\n * Auto-commits on success, auto-rolls back on error.\n *\n * Features:\n * - Automatic transaction management (start/commit/rollback)\n * - Transaction propagation via AsyncLocalStorage\n * - Nested transaction detection and logging\n * - Hono Context error detection\n * - Transaction timeout with configurable threshold\n * - Execution time tracking and slow transaction warnings\n * - UUID-based transaction IDs for debugging\n * - PostgreSQL error conversion to custom errors\n */\nimport { createMiddleware } from 'hono/factory';\nimport { TransactionError, DatabaseError } from '@spfn/core/errors';\nimport { fromPostgresError } from '../postgres-errors';\nimport { runInTransaction } from './runner';\n\n/**\n * Transaction middleware options\n */\nexport interface TransactionalOptions\n{\n /**\n * Slow transaction warning threshold in milliseconds\n * @default 1000 (1 second)\n */\n slowThreshold?: number;\n\n /**\n * Enable transaction logging\n * @default true\n */\n enableLogging?: boolean;\n\n /**\n * Transaction timeout in milliseconds\n *\n * If transaction exceeds this duration, it will be aborted with TransactionError.\n *\n * @default 30000 (30 seconds) or TRANSACTION_TIMEOUT environment variable\n *\n * @example\n * ```typescript\n * // Default timeout (30s or TRANSACTION_TIMEOUT env var)\n * Transactional()\n *\n * // Custom timeout for specific route (60s)\n * Transactional({ timeout: 60000 })\n *\n * // Disable timeout\n * Transactional({ timeout: 0 })\n * ```\n */\n timeout?: number;\n}\n\n/**\n * Transaction middleware for Hono routes\n *\n * Automatically wraps route handlers in a database transaction.\n * Commits on success, rolls back on error.\n *\n * @example\n * ```typescript\n * // In your route file\n * export const middlewares = [Transactional()];\n *\n * export async function POST(c: RouteContext) {\n * // All DB operations run in a transaction\n * const [user] = await db.insert(users).values(body).returning();\n * await db.insert(profiles).values({ userId: user.id });\n * // Auto-commits on success\n * return c.json(user, 201);\n * }\n * ```\n *\n * @example\n * ```typescript\n * // With custom options\n * export const middlewares = [\n * Transactional({\n * slowThreshold: 2000, // Warn if transaction takes > 2s\n * enableLogging: false, // Disable logging\n * timeout: 60000, // 60 second timeout for long operations\n * })\n * ];\n * ```\n *\n * 🔄 Transaction behavior:\n * - Success: Auto-commit\n * - Error: Auto-rollback\n * - Detects context.error to trigger rollback\n *\n * 📊 Transaction logging:\n * - Auto-logs transaction start/commit/rollback\n * - Measures and records execution time\n * - Warns about slow transactions (default: > 1s)\n */\nexport function Transactional(options: TransactionalOptions = {})\n{\n return createMiddleware(async (c, next) =>\n {\n const route = `${c.req.method} ${c.req.path}`;\n\n try\n {\n // Run route handler within transaction\n await runInTransaction(\n async () =>\n {\n // Execute handler\n await next();\n\n // Detect if Hono caught an error and stored it in context.error\n // Context type doesn't officially define error property, so we extend it\n type ContextWithError = typeof c & { error?: Error };\n const contextWithError = c as ContextWithError;\n if (contextWithError.error)\n {\n // Throw to rollback transaction\n throw contextWithError.error;\n }\n },\n {\n context: route,\n ...options,\n }\n );\n }\n catch (error)\n {\n // DatabaseError 계열 (비즈니스 로직 에러)는 그대로 throw\n if (error instanceof DatabaseError)\n {\n throw error;\n }\n\n // TransactionError는 그대로 throw\n if (error instanceof TransactionError)\n {\n throw error;\n }\n\n // PostgreSQL 에러 코드가 있으면 변환\n if (error && typeof error === 'object' && 'code' in error && typeof error.code === 'string')\n {\n throw fromPostgresError(error);\n }\n\n // 그 외 모든 에러는 그대로 throw (InvalidCredentialsError 등 비즈니스 로직 에러)\n throw error;\n }\n });\n}","/**\n * Query Utility Functions\n *\n * Common utilities for building database queries.\n * Used by both helpers.ts and repository.ts to avoid code duplication.\n *\n * @internal\n */\n\nimport type { SQL } from 'drizzle-orm';\nimport { eq, and } from 'drizzle-orm';\nimport type { PgTable } from 'drizzle-orm/pg-core';\n\n/**\n * Check if value is a Drizzle SQL wrapper\n *\n * @param value - Value to check\n * @returns true if value is a SQL wrapper\n *\n * @internal\n */\nexport function isSQLWrapper(value: unknown): value is SQL\n{\n return value !== null &&\n typeof value === 'object' &&\n 'queryChunks' in value;\n}\n\n/**\n * Build SQL WHERE clause from plain object\n *\n * Converts an object like `{ id: 1, name: 'test' }` into\n * SQL condition `id = 1 AND name = 'test'`.\n *\n * @param table - Drizzle table schema\n * @param where - Object with column-value pairs\n * @returns SQL condition or undefined if no valid conditions\n *\n * @internal\n */\nexport function buildWhereFromObject<T extends PgTable>(\n table: T,\n where: Record<string, unknown>\n): SQL | undefined\n{\n const entries = Object.entries(where).filter(([_, value]) => value !== undefined);\n\n if (entries.length === 0)\n {\n return undefined;\n }\n\n const conditions = entries.map(([key, value]) =>\n eq((table as any)[key], value)\n );\n\n return conditions.length === 1 ? conditions[0] : and(...conditions);\n}\n","/**\n * Database Helper Functions\n *\n * Type-safe helper functions for common database operations.\n * Automatically handles:\n * - Transaction context detection\n * - Read/Write database separation\n * - Type inference from table schema\n *\n * @example\n * ```typescript\n * // Simple object-based where\n * const user = await findOne(users, { id: 1 });\n * const labels = await findMany(cmsLabels, { section: 'hero' });\n *\n * // Complex SQL-based where\n * const user = await findOne(users, and(eq(users.id, 1), gt(users.age, 18)));\n * const labels = await findMany(cmsLabels, {\n * where: or(like(cmsLabels.key, 'hero.%'), eq(cmsLabels.section, 'footer')),\n * limit: 10\n * });\n * ```\n */\n\nimport type { SQL } from 'drizzle-orm';\nimport { count as sqlCount } from 'drizzle-orm';\nimport type { PgTable, PgColumn } from 'drizzle-orm/pg-core';\nimport { getDatabase } from './manager';\nimport { isSQLWrapper, buildWhereFromObject } from './query-utils';\n\n/**\n * Infer SELECT model from PgTable\n */\ntype InferSelectModel<T extends PgTable> = T['$inferSelect'];\n\n/**\n * Infer INSERT model from PgTable\n */\ntype InferInsertModel<T extends PgTable> = T['$inferInsert'];\n\n/**\n * Object-based where condition (AND only, equality only)\n */\ntype WhereObject<T> = {\n [K in keyof T]?: T[K];\n};\n\n/**\n * Find a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Single record or null\n *\n * @example\n * ```typescript\n * // Object-based\n * const user = await findOne(users, { id: 1 });\n * const label = await findOne(cmsLabels, { key: 'hero.title', section: 'hero' });\n *\n * // SQL-based\n * const user = await findOne(users, and(eq(users.id, 1), gt(users.age, 18)));\n * ```\n */\nexport async function findOne<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>>\n): Promise<InferSelectModel<T> | null>;\n\nexport async function findOne<T extends PgTable>(\n table: T,\n where: SQL | undefined\n): Promise<InferSelectModel<T> | null>;\n\nexport async function findOne<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>> | SQL | undefined\n): Promise<InferSelectModel<T> | null>\n{\n const db = getDatabase('read');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('findOne requires at least one where condition');\n }\n\n const results = await db.select().from(table as PgTable).where(whereClause).limit(1);\n return (results[0] as InferSelectModel<T>) ?? null;\n}\n\n/**\n * Find multiple records\n *\n * @param table - Drizzle table schema\n * @param options - Query options (where, orderBy, limit, offset)\n * @returns Array of records\n *\n * @example\n * ```typescript\n * // Simple object where\n * const labels = await findMany(cmsLabels, { section: 'hero' });\n *\n * // With options\n * const labels = await findMany(cmsLabels, {\n * where: { section: 'hero' },\n * orderBy: desc(cmsLabels.updatedAt),\n * limit: 10,\n * offset: 0\n * });\n *\n * // Complex SQL where\n * const labels = await findMany(cmsLabels, {\n * where: and(\n * like(cmsLabels.key, 'hero.%'),\n * eq(cmsLabels.section, 'hero')\n * ),\n * limit: 10\n * });\n * ```\n */\nexport async function findMany<T extends PgTable>(\n table: T,\n options?: {\n where?: WhereObject<InferSelectModel<T>> | SQL | undefined;\n orderBy?: SQL | SQL[];\n limit?: number;\n offset?: number;\n }\n): Promise<InferSelectModel<T>[]>\n{\n const db = getDatabase('read');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n let query = db.select().from(table as PgTable);\n\n // Apply where\n if (options?.where)\n {\n const whereClause = isSQLWrapper(options.where)\n ? options.where\n : options.where ? buildWhereFromObject(table, options.where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (whereClause)\n {\n query = query.where(whereClause) as any;\n }\n }\n\n // Apply orderBy\n if (options?.orderBy)\n {\n const orderByArray = Array.isArray(options.orderBy) ? options.orderBy : [options.orderBy];\n query = query.orderBy(...orderByArray) as any;\n }\n\n // Apply limit\n if (options?.limit)\n {\n query = query.limit(options.limit) as any;\n }\n\n // Apply offset\n if (options?.offset)\n {\n query = query.offset(options.offset) as any;\n }\n\n return query as Promise<InferSelectModel<T>[]>;\n}\n\n/**\n * Create a new record\n *\n * @param table - Drizzle table schema\n * @param data - Insert data\n * @returns Created record\n *\n * @example\n * ```typescript\n * const user = await create(users, {\n * email: 'test@example.com',\n * name: 'Test User'\n * });\n * ```\n */\nexport async function create<T extends PgTable>(\n table: T,\n data: InferInsertModel<T>\n): Promise<InferSelectModel<T>>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const [result] = await db.insert(table).values(data).returning();\n return result as InferSelectModel<T>;\n}\n\n/**\n * Create multiple records\n *\n * @param table - Drizzle table schema\n * @param data - Array of insert data\n * @returns Array of created records\n *\n * @example\n * ```typescript\n * const users = await createMany(users, [\n * { email: 'user1@example.com', name: 'User 1' },\n * { email: 'user2@example.com', name: 'User 2' }\n * ]);\n * ```\n */\nexport async function createMany<T extends PgTable>(\n table: T,\n data: InferInsertModel<T>[]\n): Promise<InferSelectModel<T>[]>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const results = await db.insert(table).values(data).returning();\n return results as InferSelectModel<T>[];\n}\n\n/**\n * Upsert a record (INSERT or UPDATE on conflict)\n *\n * @param table - Drizzle table schema\n * @param data - Insert data\n * @param options - Conflict resolution options\n * @returns Upserted record\n *\n * @example\n * ```typescript\n * // Basic upsert\n * const cache = await upsert(cmsPublishedCache, {\n * section: 'home',\n * locale: 'ko',\n * content: {...}\n * }, {\n * target: [cmsPublishedCache.section, cmsPublishedCache.locale],\n * set: {\n * content: data.content,\n * updatedAt: new Date()\n * }\n * });\n *\n * // With SQL expression\n * const cache = await upsert(cmsPublishedCache, data, {\n * target: [cmsPublishedCache.section, cmsPublishedCache.locale],\n * set: {\n * content: data.content,\n * version: sql`${cmsPublishedCache.version} + 1`\n * }\n * });\n * ```\n */\nexport async function upsert<T extends PgTable>(\n table: T,\n data: InferInsertModel<T>,\n options: {\n target: PgColumn[];\n set?: Partial<InferInsertModel<T>> | Record<string, SQL | any>;\n }\n): Promise<InferSelectModel<T>>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const [result] = await db\n .insert(table)\n .values(data)\n .onConflictDoUpdate({\n target: options.target,\n set: options.set || data,\n })\n .returning();\n\n return result as InferSelectModel<T>;\n}\n\n/**\n * Update a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @param data - Update data\n * @returns Updated record or null\n *\n * @example\n * ```typescript\n * // Object-based where\n * const user = await updateOne(users, { id: 1 }, { name: 'Updated Name' });\n *\n * // SQL-based where\n * const user = await updateOne(users, eq(users.id, 1), { name: 'Updated Name' });\n * ```\n */\nexport async function updateOne<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>> | SQL | undefined,\n data: Partial<InferInsertModel<T>>\n): Promise<InferSelectModel<T> | null>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('updateOne requires at least one where condition');\n }\n\n const [result] = await db.update(table).set(data).where(whereClause).returning();\n return (result as InferSelectModel<T>) ?? null;\n}\n\n/**\n * Update multiple records\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @param data - Update data\n * @returns Array of updated records\n *\n * @example\n * ```typescript\n * const users = await updateMany(users,\n * { role: 'user' },\n * { verified: true }\n * );\n * ```\n */\nexport async function updateMany<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>> | SQL | undefined,\n data: Partial<InferInsertModel<T>>\n): Promise<InferSelectModel<T>[]>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('updateMany requires at least one where condition');\n }\n\n const results = await db.update(table).set(data).where(whereClause).returning();\n return results as InferSelectModel<T>[];\n}\n\n/**\n * Delete a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Deleted record or null\n *\n * @example\n * ```typescript\n * // Object-based where\n * const user = await deleteOne(users, { id: 1 });\n *\n * // SQL-based where\n * const user = await deleteOne(users, eq(users.id, 1));\n * ```\n */\nexport async function deleteOne<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>> | SQL | undefined\n): Promise<InferSelectModel<T> | null>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('deleteOne requires at least one where condition');\n }\n\n const [result] = await db.delete(table).where(whereClause).returning();\n return (result as InferSelectModel<T>) ?? null;\n}\n\n/**\n * Delete multiple records\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Array of deleted records\n *\n * @example\n * ```typescript\n * const users = await deleteMany(users, { verified: false });\n * ```\n */\nexport async function deleteMany<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>> | SQL | undefined\n): Promise<InferSelectModel<T>[]>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('deleteMany requires at least one where condition');\n }\n\n const results = await db.delete(table).where(whereClause).returning();\n return results as InferSelectModel<T>[];\n}\n\n/**\n * Count records\n *\n * @param table - Drizzle table schema\n * @param where - Optional object or SQL condition\n * @returns Number of records\n *\n * @example\n * ```typescript\n * const total = await count(users);\n * const activeUsers = await count(users, { active: true });\n * const adults = await count(users, gt(users.age, 18));\n * ```\n */\nexport async function count<T extends PgTable>(\n table: T,\n where?: WhereObject<InferSelectModel<T>> | SQL | undefined\n): Promise<number>\n{\n const db = getDatabase('read');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n let query = db.select({ count: sqlCount() }).from(table as PgTable);\n\n if (where)\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (whereClause)\n {\n query = query.where(whereClause) as any;\n }\n }\n\n const [result] = await query;\n return Number(result?.count ?? 0);\n}\n","/**\n * Base Repository Pattern\n *\n * Provides automatic database instance management with transaction context support.\n * Eliminates the need for manual `getDatabaseOrThrow()` calls in repository classes.\n *\n * Features:\n * - Automatic transaction context detection and usage\n * - Read/Write connection separation (with replica support)\n * - Type-safe schema generics\n * - Consistent database access pattern across all repositories\n * - Enhanced error tracking with repository context\n *\n * @example Basic Repository\n * ```typescript\n * import { BaseRepository } from '@spfn/core/db';\n * import { users } from './schema';\n * import { eq } from 'drizzle-orm';\n *\n * export class UserRepository extends BaseRepository {\n * async findById(id: string) {\n * // Uses read replica when available\n * return await this.readDb\n * .select()\n * .from(users)\n * .where(eq(users.id, id));\n * }\n *\n * async create(data: NewUser) {\n * // Uses write primary\n * return await this.db\n * .insert(users)\n * .values(data)\n * .returning();\n * }\n * }\n * ```\n *\n * @example With Transactions\n * ```typescript\n * import { runWithTransaction } from '@spfn/core/db';\n *\n * const userRepo = new UserRepository();\n *\n * await runWithTransaction(async () => {\n * // Both db and readDb automatically use the transaction context\n * const user = await userRepo.create({ name: 'John' });\n * await userRepo.findById(user.id); // Uses same transaction\n * });\n * ```\n *\n * @example With Custom Schema Type\n * ```typescript\n * import type { AppSchema } from './schema';\n *\n * export class UserRepository extends BaseRepository<AppSchema> {\n * // Now this.db and this.readDb are typed with AppSchema\n * }\n * ```\n *\n * @example With Enhanced Error Tracking\n * ```typescript\n * export class UserRepository extends BaseRepository {\n * async updateStatus(id: string, status: string) {\n * // Errors will include repository context automatically\n * return await this.db\n * .update(users)\n * .set({ status })\n * .where(eq(users.id, id))\n * .returning();\n * }\n * }\n * // On error: logs will show \"UserRepository\" context\n * ```\n */\n\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport type { SQL } from 'drizzle-orm';\nimport { count as sqlCount } from 'drizzle-orm';\nimport type { PgTable, PgColumn } from 'drizzle-orm/pg-core';\nimport { getDatabase } from './manager';\nimport { getTransaction } from './transaction';\nimport { isSQLWrapper, buildWhereFromObject } from './query-utils';\n\n/**\n * Enhanced error class that includes repository context\n */\nexport class RepositoryError extends Error\n{\n constructor(\n message: string,\n public readonly repository: string,\n public readonly method?: string,\n public readonly table?: string,\n public readonly originalError?: Error\n )\n {\n super(message);\n this.name = 'RepositoryError';\n\n // Preserve original stack trace if available\n if (originalError?.stack)\n {\n this.stack = originalError.stack;\n }\n }\n}\n\n/**\n * Base Repository class for database operations\n *\n * Provides automatic database instance management with transaction support.\n * Extend this class to create domain-specific repositories.\n *\n * The repository automatically detects if running within a transaction context\n * and uses the appropriate database instance:\n * - Inside transaction: Uses transaction DB\n * - Outside transaction: Uses global DB instance (with read/write separation)\n *\n * @template TSchema - Database schema type (defaults to Record<string, unknown>)\n */\nexport abstract class BaseRepository<TSchema extends Record<string, unknown> = Record<string, unknown>>\n{\n /**\n * Write database instance\n *\n * Automatically resolves to:\n * - Transaction DB if running within transaction context\n * - Global write (primary) instance otherwise\n *\n * Use this for INSERT, UPDATE, DELETE operations.\n *\n * @example\n * ```typescript\n * async create(data: NewUser) {\n * return await this.db.insert(users).values(data).returning();\n * }\n * ```\n */\n protected get db(): PostgresJsDatabase<TSchema>\n {\n // Transaction context takes precedence\n const txDb = getTransaction();\n if (txDb)\n {\n return txDb as PostgresJsDatabase<TSchema>;\n }\n\n // Fall back to global write instance\n return getDatabase('write') as PostgresJsDatabase<TSchema>;\n }\n\n /**\n * Read database instance\n *\n * Automatically resolves to:\n * - Transaction DB if running within transaction context\n * - Global read (replica) instance otherwise\n *\n * Use this for SELECT operations to leverage read replicas\n * and reduce load on the primary database.\n *\n * @example\n * ```typescript\n * async findById(id: string) {\n * return await this.readDb\n * .select()\n * .from(users)\n * .where(eq(users.id, id));\n * }\n * ```\n */\n protected get readDb(): PostgresJsDatabase<TSchema>\n {\n // Transaction context takes precedence\n const txDb = getTransaction();\n if (txDb)\n {\n return txDb as PostgresJsDatabase<TSchema>;\n }\n\n // Fall back to global read instance (uses replica if configured)\n return getDatabase('read') as PostgresJsDatabase<TSchema>;\n }\n\n /**\n * Wrap query execution with repository context\n *\n * Enhances error messages with repository information to make debugging easier.\n * When an error occurs, it will include:\n * - Repository class name\n * - Method name\n * - Table name (if provided)\n * - Original error details\n *\n * @param queryFn - Query function to execute\n * @param context - Context information (operation name, table name, etc.)\n * @returns Query result\n * @throws RepositoryError with enhanced context\n *\n * @example\n * ```typescript\n * async findById(id: number) {\n * return await this.withContext(\n * () => this.readDb.select().from(users).where(eq(users.id, id)),\n * { method: 'findById', table: 'users' }\n * );\n * }\n * ```\n */\n protected async withContext<T>(\n queryFn: () => Promise<T>,\n context: { method?: string; table?: string } = {}\n ): Promise<T>\n {\n try\n {\n return await queryFn();\n }\n catch (error)\n {\n const err = error instanceof Error ? error : new Error(String(error));\n const repositoryName = this.constructor.name;\n\n // Create enhanced error with repository context\n throw new RepositoryError(\n err.message,\n repositoryName,\n context.method,\n context.table,\n err\n );\n }\n }\n\n // ============================================================================\n // CRUD Methods\n // ============================================================================\n\n /**\n * Find a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Single record or null\n *\n * @example\n * ```typescript\n * // Object-based\n * const user = await this._findOne(users, { id: 1 });\n *\n * // SQL-based\n * const user = await this._findOne(users, eq(users.id, 1));\n * ```\n */\n protected async _findOne<T extends PgTable>(\n table: T,\n where: Record<string, any> | SQL | undefined\n ): Promise<T['$inferSelect'] | null>\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('findOne requires at least one where condition');\n }\n\n const results = await this.readDb.select().from(table as PgTable).where(whereClause).limit(1);\n return (results[0] as T['$inferSelect']) ?? null;\n }\n\n /**\n * Find multiple records\n *\n * @param table - Drizzle table schema\n * @param options - Query options\n * @returns Array of records\n *\n * @example\n * ```typescript\n * const users = await this._findMany(users, {\n * where: { active: true },\n * orderBy: desc(users.createdAt),\n * limit: 10\n * });\n * ```\n */\n protected async _findMany<T extends PgTable>(\n table: T,\n options?: {\n where?: Record<string, any> | SQL | undefined;\n orderBy?: SQL | SQL[];\n limit?: number;\n offset?: number;\n }\n ): Promise<T['$inferSelect'][]>\n {\n let query = this.readDb.select().from(table as PgTable);\n\n // Apply where\n if (options?.where)\n {\n const whereClause = isSQLWrapper(options.where)\n ? options.where\n : options.where ? buildWhereFromObject(table, options.where as Record<string, any>) : undefined;\n\n if (whereClause)\n {\n query = query.where(whereClause) as any;\n }\n }\n\n // Apply orderBy\n if (options?.orderBy)\n {\n const orderByArray = Array.isArray(options.orderBy) ? options.orderBy : [options.orderBy];\n query = query.orderBy(...orderByArray) as any;\n }\n\n // Apply limit\n if (options?.limit)\n {\n query = query.limit(options.limit) as any;\n }\n\n // Apply offset\n if (options?.offset)\n {\n query = query.offset(options.offset) as any;\n }\n\n return query as Promise<T['$inferSelect'][]>;\n }\n\n /**\n * Create a new record\n *\n * @param table - Drizzle table schema\n * @param data - Insert data\n * @returns Created record\n *\n * @example\n * ```typescript\n * const user = await this._create(users, {\n * email: 'test@example.com',\n * name: 'Test User'\n * });\n * ```\n */\n protected async _create<T extends PgTable>(\n table: T,\n data: T['$inferInsert']\n ): Promise<T['$inferSelect']>\n {\n const [result] = await this.db.insert(table).values(data).returning();\n return result as T['$inferSelect'];\n }\n\n /**\n * Create multiple records\n *\n * @param table - Drizzle table schema\n * @param data - Array of insert data\n * @returns Array of created records\n *\n * @example\n * ```typescript\n * const users = await this._createMany(users, [\n * { email: 'user1@example.com', name: 'User 1' },\n * { email: 'user2@example.com', name: 'User 2' }\n * ]);\n * ```\n */\n protected async _createMany<T extends PgTable>(\n table: T,\n data: T['$inferInsert'][]\n ): Promise<T['$inferSelect'][]>\n {\n const results = await this.db.insert(table).values(data).returning();\n return results as T['$inferSelect'][];\n }\n\n /**\n * Upsert a record (INSERT or UPDATE on conflict)\n *\n * @param table - Drizzle table schema\n * @param data - Insert data\n * @param options - Conflict resolution options\n * @returns Upserted record\n *\n * @example\n * ```typescript\n * const cache = await this._upsert(cache, {\n * key: 'config',\n * value: {...}\n * }, {\n * target: [cache.key],\n * set: { value: data.value, updatedAt: new Date() }\n * });\n * ```\n */\n protected async _upsert<T extends PgTable>(\n table: T,\n data: T['$inferInsert'],\n options: {\n target: PgColumn[];\n set?: Partial<T['$inferInsert']> | Record<string, SQL | any>;\n }\n ): Promise<T['$inferSelect']>\n {\n const [result] = await this.db\n .insert(table)\n .values(data)\n .onConflictDoUpdate({\n target: options.target,\n set: options.set || data,\n })\n .returning();\n\n return result as T['$inferSelect'];\n }\n\n /**\n * Update a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @param data - Update data\n * @returns Updated record or null\n *\n * @example\n * ```typescript\n * const user = await this._updateOne(users,\n * { id: 1 },\n * { name: 'Updated Name' }\n * );\n * ```\n */\n protected async _updateOne<T extends PgTable>(\n table: T,\n where: Record<string, any> | SQL | undefined,\n data: Partial<T['$inferInsert']>\n ): Promise<T['$inferSelect'] | null>\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('updateOne requires at least one where condition');\n }\n\n const [result] = await this.db.update(table).set(data).where(whereClause).returning();\n return (result as T['$inferSelect']) ?? null;\n }\n\n /**\n * Update multiple records\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @param data - Update data\n * @returns Array of updated records\n *\n * @example\n * ```typescript\n * const users = await this._updateMany(users,\n * { role: 'user' },\n * { verified: true }\n * );\n * ```\n */\n protected async _updateMany<T extends PgTable>(\n table: T,\n where: Record<string, any> | SQL | undefined,\n data: Partial<T['$inferInsert']>\n ): Promise<T['$inferSelect'][]>\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('updateMany requires at least one where condition');\n }\n\n const results = await this.db.update(table).set(data).where(whereClause).returning();\n return results as T['$inferSelect'][];\n }\n\n /**\n * Delete a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Deleted record or null\n *\n * @example\n * ```typescript\n * const user = await this._deleteOne(users, { id: 1 });\n * ```\n */\n protected async _deleteOne<T extends PgTable>(\n table: T,\n where: Record<string, any> | SQL | undefined\n ): Promise<T['$inferSelect'] | null>\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('deleteOne requires at least one where condition');\n }\n\n const [result] = await this.db.delete(table).where(whereClause).returning();\n return (result as T['$inferSelect']) ?? null;\n }\n\n /**\n * Delete multiple records\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Array of deleted records\n *\n * @example\n * ```typescript\n * const users = await this._deleteMany(users, { verified: false });\n * ```\n */\n protected async _deleteMany<T extends PgTable>(\n table: T,\n where: Record<string, any> | SQL | undefined\n ): Promise<T['$inferSelect'][]>\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('deleteMany requires at least one where condition');\n }\n\n const results = await this.db.delete(table).where(whereClause).returning();\n return results as T['$inferSelect'][];\n }\n\n /**\n * Count records\n *\n * @param table - Drizzle table schema\n * @param where - Optional object or SQL condition\n * @returns Number of records\n *\n * @example\n * ```typescript\n * const total = await this._count(users);\n * const activeUsers = await this._count(users, { active: true });\n * ```\n */\n protected async _count<T extends PgTable>(\n table: T,\n where?: Record<string, any> | SQL | undefined\n ): Promise<number>\n {\n let query = this.readDb.select({ count: sqlCount() }).from(table as PgTable);\n\n if (where)\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (whereClause)\n {\n query = query.where(whereClause) as any;\n }\n }\n\n const [result] = await query;\n return Number(result?.count ?? 0);\n }\n}"]}
1
+ {"version":3,"sources":["../../src/db/postgres-errors.ts","../../src/db/manager/connection.ts","../../src/db/manager/config.ts","../../src/db/manager/factory.ts","../../src/db/manager/global-state.ts","../../src/db/manager/health-check.ts","../../src/db/manager/manager.ts","../../src/db/manager/config-generator.ts","../../src/db/schema/entity-helper.ts","../../src/db/schema/schema-helper.ts","../../src/db/transaction/context.ts","../../src/db/transaction/runner.ts","../../src/db/transaction/middleware.ts","../../src/db/query-utils.ts","../../src/db/helpers.ts","../../src/db/repository.ts"],"names":["ConnectionError","dbLogger","logger","getDatabase","closeDatabase","env","dir","packageSchemas","schema","pgUuid","txLogger","TransactionError","DatabaseError","sqlCount"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * PostgreSQL Error Conversion Utilities\n *\n * Converts PostgreSQL-specific error codes to custom error types\n * @see https://www.postgresql.org/docs/current/errcodes-appendix.html\n */\n\nimport {\n DatabaseError,\n ConnectionError,\n DuplicateEntryError,\n DeadlockError,\n ConstraintViolationError,\n QueryError,\n TransactionError,\n} from '@spfn/core/errors';\n\n/**\n * Extract field and value from PostgreSQL unique violation message\n *\n * Handles various formats:\n * - Simple: Key (email)=(test@example.com)\n * - Complex: Key (user_id, tenant_id)=(123, 456)\n * - With quotes: Key (\"field\")=('value')\n */\nfunction parseUniqueViolation(message: string): { field: string; value: string } | null\n{\n // Try multiple patterns for robustness\n const patterns = [\n // Standard format: Key (field)=(value)\n /Key \\(([^)]+)\\)=\\(([^)]+)\\)/i,\n // With quotes: Key (\"field\")=('value')\n /Key \\([\"']?([^)\"']+)[\"']?\\)=\\([\"']?([^)\"']+)[\"']?\\)/i,\n // Alternative format\n /Key `([^`]+)`=`([^`]+)`/i,\n ];\n\n for (const pattern of patterns)\n {\n const match = message.match(pattern);\n if (match)\n {\n // Clean up extracted values\n const field = match[1].trim().replace(/[\"'`]/g, '');\n const value = match[2].trim().replace(/[\"'`]/g, '');\n return { field, value };\n }\n }\n\n return null;\n}\n\n/**\n * Convert PostgreSQL error to custom DatabaseError\n *\n * Maps PostgreSQL error codes to appropriate error classes with correct status codes\n *\n * @param error - PostgreSQL error object (from pg driver or Drizzle)\n * @returns Custom DatabaseError instance\n *\n * @example\n * ```typescript\n * import { fromPostgresError } from '@spfn/core/db';\n *\n * try {\n * await db.insert(users).values(data);\n * } catch (pgError) {\n * throw fromPostgresError(pgError);\n * }\n * ```\n */\nexport function fromPostgresError(error: any): DatabaseError\n{\n const code = error?.code;\n const message = error?.message || 'Database error occurred';\n\n switch (code)\n {\n // Class 08 — Connection Exception\n case '08000': // connection_exception\n case '08001': // sqlclient_unable_to_establish_sqlconnection\n case '08003': // connection_does_not_exist\n case '08004': // sqlserver_rejected_establishment_of_sqlconnection\n case '08006': // connection_failure\n case '08007': // transaction_resolution_unknown\n case '08P01': // protocol_violation\n return new ConnectionError({ message, details: { code } });\n\n // Class 23 — Integrity Constraint Violation\n case '23000': // integrity_constraint_violation\n case '23001': // restrict_violation\n return new ConstraintViolationError({ message, details: { code, constraint: 'integrity' } });\n\n case '23502': // not_null_violation\n return new ConstraintViolationError({ message, details: { code, constraint: 'not_null' } });\n\n case '23503': // foreign_key_violation\n return new ConstraintViolationError({ message, details: { code, constraint: 'foreign_key' } });\n\n case '23505': // unique_violation\n const parsed = parseUniqueViolation(message);\n if (parsed)\n {\n return new DuplicateEntryError({ field: parsed.field, value: parsed.value });\n }\n return new DuplicateEntryError({ field: 'field', value: 'value' });\n\n case '23514': // check_violation\n return new ConstraintViolationError({ message, details: { code, constraint: 'check' } });\n\n // Class 40 — Transaction Rollback\n case '40000': // transaction_rollback\n case '40001': // serialization_failure\n case '40002': // transaction_integrity_constraint_violation\n case '40003': // statement_completion_unknown\n return new TransactionError({ message, statusCode: 500, details: { code } });\n\n case '40P01': // deadlock_detected\n return new DeadlockError({ message, details: { code } });\n\n // Class 42 — Syntax Error or Access Rule Violation\n case '42000': // syntax_error_or_access_rule_violation\n case '42601': // syntax_error\n case '42501': // insufficient_privilege\n case '42602': // invalid_name\n case '42622': // name_too_long\n case '42701': // duplicate_column\n case '42702': // ambiguous_column\n case '42703': // undefined_column\n case '42704': // undefined_object\n case '42P01': // undefined_table\n case '42P02': // undefined_parameter\n return new QueryError({ message, statusCode: 400, details: { code } });\n\n // Class 53 — Insufficient Resources\n case '53000': // insufficient_resources\n case '53100': // disk_full\n case '53200': // out_of_memory\n case '53300': // too_many_connections\n return new ConnectionError({ message, details: { code } });\n\n // Class 57 — Operator Intervention\n case '57000': // operator_intervention\n case '57014': // query_canceled\n case '57P01': // admin_shutdown\n case '57P02': // crash_shutdown\n case '57P03': // cannot_connect_now\n return new ConnectionError({ message, details: { code } });\n\n // Default: Unknown error\n default:\n return new QueryError({ message, statusCode: 500, details: { code } });\n }\n}","import postgres from 'postgres';\nimport type { Sql } from 'postgres';\n\nimport { logger } from '@spfn/core/logger';\nimport { ConnectionError } from '@spfn/core/errors';\nimport { fromPostgresError } from '../postgres-errors';\nimport type { PoolConfig, RetryConfig } from './config';\n\nconst dbLogger = logger.child('@spfn/core:database');\n\n/**\n * Connection timeout in seconds\n *\n * Timeout for PostgreSQL server connection and initial query execution.\n */\nconst DEFAULT_CONNECT_TIMEOUT = 10;\n\n/**\n * Delay execution for specified milliseconds\n *\n * @param ms - Milliseconds to delay\n * @returns Promise that resolves after the delay\n */\nfunction delay(ms: number): Promise<void>\n{\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Mask password in connection string for secure logging\n *\n * Replaces password with *** to prevent credentials from appearing in logs.\n *\n * @param connectionString - Database connection string\n * @returns Masked connection string with password replaced by ***\n *\n * @example\n * ```typescript\n * maskConnectionString('postgresql://user:password@host:5432/db')\n * // Returns: 'postgresql://user:***@host:5432/db'\n *\n * maskConnectionString('postgresql://user:p@ssw0rd@host:5432/db')\n * // Returns: 'postgresql://user:***@host:5432/db'\n * ```\n */\nfunction maskConnectionString(connectionString: string): string\n{\n try\n {\n // Safe password masking using URL parsing\n const url = new URL(connectionString);\n if (url.password)\n {\n // Replace password with ***\n return connectionString.replace(`:${url.password}@`, ':***@');\n }\n return connectionString;\n }\n catch\n {\n // Fallback to regex if URL parsing fails (safe only for passwords without @)\n return connectionString.replace(/(:\\/\\/[^:/@]+:)([^@]+)(@)/, '$1***$3');\n }\n}\n\n/**\n * Check if error is an authentication error\n *\n * Detects password authentication failures, missing passwords, and invalid authorization.\n *\n * @param error - Error object to check\n * @returns true if error is authentication-related, false otherwise\n */\nfunction isAuthenticationError(error: Error): boolean\n{\n const message = error.message.toLowerCase();\n return message.includes('password authentication failed') ||\n message.includes('no password supplied') ||\n message.includes('authentication failed') ||\n message.includes('invalid authorization');\n}\n\n/**\n * Check if error indicates database does not exist\n *\n * @param error - Error object to check\n * @returns true if database not found, false otherwise\n */\nfunction isDatabaseNotFoundError(error: Error): boolean\n{\n const message = error.message.toLowerCase();\n return message.includes('database') && message.includes('does not exist');\n}\n\n/**\n * Check if error is SSL/TLS related\n *\n * Detects SSL, TLS, certificate, and verification errors.\n *\n * @param error - Error object to check\n * @returns true if SSL/TLS error, false otherwise\n */\nfunction isSSLError(error: Error): boolean\n{\n const message = error.message.toLowerCase();\n return message.includes('ssl') ||\n message.includes('tls') ||\n message.includes('certificate') ||\n message.includes('self signed certificate') ||\n message.includes('unable to verify');\n}\n\n/**\n * Check if error should not be retried\n *\n * Non-retryable errors include:\n * - Authentication failures (wrong password, username, etc.)\n * - Database not found errors\n * - SSL/TLS configuration errors\n *\n * These errors indicate configuration issues that won't be resolved by retrying.\n *\n * @param error - Error object to check\n * @returns true if error should not be retried, false if retry is appropriate\n */\nfunction isNonRetryableError(error: Error): boolean\n{\n return isAuthenticationError(error) ||\n isDatabaseNotFoundError(error) ||\n isSSLError(error);\n}\n\n/**\n * Validate retry configuration parameters\n *\n * Ensures all retry config values are within valid ranges.\n *\n * @param retryConfig - Retry configuration to validate\n * @throws ConnectionError if any configuration value is invalid\n */\nfunction validateRetryConfig(retryConfig: RetryConfig): void\n{\n if (retryConfig.maxRetries < 0)\n {\n throw new ConnectionError({ message: `maxRetries must be non-negative, got ${retryConfig.maxRetries}` });\n }\n\n if (retryConfig.initialDelay <= 0)\n {\n throw new ConnectionError({ message: `initialDelay must be positive, got ${retryConfig.initialDelay}` });\n }\n\n if (retryConfig.factor <= 0)\n {\n throw new ConnectionError({ message: `factor must be positive, got ${retryConfig.factor}` });\n }\n\n if (retryConfig.maxDelay <= 0)\n {\n throw new ConnectionError({ message: `maxDelay must be positive, got ${retryConfig.maxDelay}` });\n }\n}\n\n/**\n * Validate pool configuration parameters\n *\n * Ensures pool configuration values are valid.\n *\n * @param poolConfig - Pool configuration to validate\n * @throws ConnectionError if configuration is invalid\n */\nfunction validatePoolConfig(poolConfig: PoolConfig): void\n{\n if (poolConfig.max <= 0)\n {\n throw new ConnectionError({ message: `pool max must be positive, got ${poolConfig.max}` });\n }\n}\n\n/**\n * Create database connection with exponential backoff retry strategy\n *\n * Attempts to establish a database connection with automatic retries using\n * exponential backoff with jitter. Non-retryable errors (authentication,\n * database not found, SSL issues) fail immediately.\n *\n * Retry Strategy:\n * - Exponential backoff: delay = initialDelay * (factor ^ attempt)\n * - Jitter: randomized delay between 50-100% of calculated delay\n * - Max delay cap: prevents excessive wait times\n *\n * @param connectionString - PostgreSQL connection string\n * @param poolConfig - Connection pool configuration\n * @param retryConfig - Retry configuration (max attempts, delays, etc.)\n * @returns PostgreSQL client instance\n * @throws ConnectionError if connection fails after all retries or on non-retryable errors\n *\n * @example\n * ```typescript\n * const client = await createDatabaseConnection(\n * 'postgresql://localhost:5432/mydb',\n * { max: 20, idleTimeout: 30 },\n * { maxRetries: 5, initialDelay: 100, maxDelay: 10000, factor: 2 }\n * );\n * ```\n */\nexport async function createDatabaseConnection(\n connectionString: string,\n poolConfig: PoolConfig,\n retryConfig: RetryConfig\n) {\n // Validate input parameters\n if (!connectionString)\n {\n throw new ConnectionError({ message: 'Connection string must be a non-empty string' });\n }\n\n validateRetryConfig(retryConfig);\n validatePoolConfig(poolConfig);\n\n let lastError: Error | undefined;\n let client: Sql | undefined;\n\n for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++)\n {\n try\n {\n // Create PostgreSQL client\n client = postgres(connectionString, {\n max: poolConfig.max,\n idle_timeout: poolConfig.idleTimeout,\n connect_timeout: DEFAULT_CONNECT_TIMEOUT,\n });\n\n // Test connection with simple query\n // connect_timeout is applied at DB level, so Promise.race is not needed\n await client`SELECT 1 as test`;\n\n // Connection successful\n if (attempt > 0)\n {\n dbLogger.info(\n 'Database connected successfully',\n { retriesNeeded: attempt }\n );\n }\n else\n {\n dbLogger.info('Database connected successfully');\n }\n\n return client;\n }\n catch (error)\n {\n // Cleanup failed client (prevent resource leak)\n if (client)\n {\n try\n {\n await client.end();\n }\n catch\n {\n // Ignore cleanup errors (client may already be closed)\n }\n\n client = undefined;\n }\n\n lastError = fromPostgresError(error);\n\n // Throw immediately on non-retryable errors\n if (isNonRetryableError(lastError))\n {\n dbLogger.error(\n 'Cannot connect to database (non-retryable error)',\n lastError,\n {\n connectionString: maskConnectionString(connectionString),\n poolConfig: {\n max: poolConfig.max,\n idleTimeout: poolConfig.idleTimeout,\n connectTimeout: DEFAULT_CONNECT_TIMEOUT,\n },\n reason: isAuthenticationError(lastError)\n ? 'authentication_failed'\n : isDatabaseNotFoundError(lastError)\n ? 'database_not_found'\n : 'ssl_error',\n }\n );\n\n throw new ConnectionError({\n message: `Cannot connect to database: ${lastError.message}`\n });\n }\n\n // Retry if not last attempt\n if (attempt < retryConfig.maxRetries)\n {\n // Calculate exponential backoff with jitter\n const baseDelay = Math.min(\n retryConfig.initialDelay * Math.pow(retryConfig.factor, attempt),\n retryConfig.maxDelay\n );\n // Jitter: randomize delay between 50-100% (prevents thundering herd)\n const jitter = 0.5 + Math.random() * 0.5;\n const delayMs = Math.floor(baseDelay * jitter);\n\n dbLogger.warn(\n 'Database connection failed, retrying...',\n lastError,\n {\n attempt: attempt + 1,\n totalAttempts: retryConfig.maxRetries + 1,\n nextRetryIn: delayMs,\n connectionString: maskConnectionString(connectionString),\n poolConfig: {\n max: poolConfig.max,\n idleTimeout: poolConfig.idleTimeout,\n connectTimeout: DEFAULT_CONNECT_TIMEOUT,\n },\n }\n );\n\n await delay(delayMs);\n }\n }\n }\n\n // All retries failed\n // lastError is assigned at least once in the loop, so it cannot be undefined\n if (!lastError)\n {\n throw new ConnectionError({\n message: 'Unexpected error: no error recorded after failed connection attempts'\n });\n }\n\n dbLogger.error(\n 'Failed to connect to database after all retries',\n lastError,\n {\n totalAttempts: retryConfig.maxRetries + 1,\n connectionString: maskConnectionString(connectionString),\n poolConfig: {\n max: poolConfig.max,\n idleTimeout: poolConfig.idleTimeout,\n connectTimeout: DEFAULT_CONNECT_TIMEOUT,\n },\n retryConfig: {\n maxRetries: retryConfig.maxRetries,\n initialDelay: retryConfig.initialDelay,\n factor: retryConfig.factor,\n maxDelay: retryConfig.maxDelay,\n },\n }\n );\n\n throw new ConnectionError({\n message: `Failed to connect to database after ${retryConfig.maxRetries + 1} attempts: ${lastError.message}`\n });\n}\n\n/**\n * Check database connection health\n *\n * Uses the client's configured timeout settings (connect_timeout, etc.).\n * Executes a simple SELECT query to verify the connection is alive.\n *\n * @param client - PostgreSQL client to check\n * @returns true if connection is healthy, false otherwise\n *\n * @example\n * ```typescript\n * const isHealthy = await checkConnection(client);\n * if (!isHealthy) {\n * console.error('Database connection is down');\n * }\n * ```\n */\nexport async function checkConnection(client: Sql): Promise<boolean>\n{\n try\n {\n // Health check query\n // Uses client's default timeout settings\n await client`SELECT 1 as health_check`;\n\n return true;\n }\n catch (error)\n {\n const errorObj = fromPostgresError(error);\n\n dbLogger.error(\n 'Database health check failed',\n errorObj,\n { errorType: errorObj.name }\n );\n\n return false;\n }\n}","/**\n * Database Configuration\n *\n * Database connection and connection pool configuration.\n *\n * Features:\n * - Environment-specific connection pool configuration\n * - Retry configuration with exponential backoff\n * - Environment variable-based configuration\n * - Health check and monitoring configuration\n *\n * Related files:\n * - src/server/core/db/connection.ts (connection logic)\n * - src/server/core/db/index.ts (main exports)\n */\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\";\nimport type { Sql } from \"postgres\";\nimport { parseNumber, parseBoolean } from '@spfn/core/env';\n\nexport interface DatabaseClients\n{\n /** Primary database for writes (or both read/write if no replica) */\n write?: PostgresJsDatabase;\n /** Replica database for reads (optional, falls back to write) */\n read?: PostgresJsDatabase;\n /** Raw postgres client for write operations (for cleanup) */\n writeClient?: Sql;\n /** Raw postgres client for read operations (for cleanup) */\n readClient?: Sql;\n}\n\n/**\n * Health check configuration\n */\nexport interface HealthCheckConfig\n{\n enabled: boolean;\n interval: number;\n reconnect: boolean;\n maxRetries: number;\n retryInterval: number;\n}\n\n/**\n * Query performance monitoring configuration\n */\nexport interface MonitoringConfig\n{\n enabled: boolean;\n slowThreshold: number;\n logQueries: boolean;\n}\n\n/**\n * Database initialization options\n */\nexport interface DatabaseOptions\n{\n /**\n * Connection pool configuration\n * Overrides environment variables and defaults\n */\n pool?: Partial<PoolConfig>;\n\n /**\n * Health check configuration\n * Periodic checks to ensure database connection is alive\n */\n healthCheck?: Partial<HealthCheckConfig>;\n\n /**\n * Query performance monitoring configuration\n * Tracks slow queries and logs performance metrics\n */\n monitoring?: Partial<MonitoringConfig>;\n}\n\n/**\n * Connection pool configuration\n *\n * Controls the maximum number of connections and idle timeout behavior.\n */\nexport interface PoolConfig\n{\n /** Maximum number of connections in the pool */\n max: number;\n /** Idle connection timeout in seconds */\n idleTimeout: number;\n}\n\n/**\n * Retry configuration for exponential backoff algorithm\n *\n * Controls retry behavior when connection attempts fail.\n */\nexport interface RetryConfig\n{\n /** Maximum number of retry attempts */\n maxRetries: number;\n /** Initial delay between retries in milliseconds */\n initialDelay: number;\n /** Maximum delay cap in milliseconds */\n maxDelay: number;\n /** Exponential backoff factor (delay multiplier) */\n factor: number;\n}\n\n// ============================================================================\n// Environment Variable Parsing Utilities\n// ============================================================================\n\n/**\n * Parse environment variable as number with production/development defaults\n *\n * Uses @spfn/core/env parseNumber for consistent parsing across the codebase.\n *\n * @param key - Environment variable name\n * @param prodDefault - Default value for production\n * @param devDefault - Default value for development\n * @returns Parsed number or default based on NODE_ENV\n *\n * @example\n * ```typescript\n * const max = parseEnvNumber('DB_POOL_MAX', 20, 10);\n * // Production: 20, Development: 10, or parsed value from env\n * ```\n */\nfunction parseEnvNumber(\n key: string,\n prodDefault: number,\n devDefault: number\n): number\n{\n const isProduction = process.env.NODE_ENV === 'production';\n const defaultValue = isProduction ? prodDefault : devDefault;\n\n const value = process.env[key];\n\n if (value === undefined)\n {\n return defaultValue;\n }\n\n try\n {\n return parseNumber(value, { min: 0, integer: true });\n }\n catch (error)\n {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`${key}: ${message}`);\n }\n}\n\n/**\n * Parse environment variable as boolean with enhanced format support\n *\n * Uses @spfn/core/env parseBoolean for consistent parsing across the codebase.\n * Supports multiple truthy/falsy formats: true/false, 1/0, yes/no.\n *\n * @param key - Environment variable name\n * @param defaultValue - Default value if not set\n * @returns Boolean value\n *\n * @example\n * ```typescript\n * const enabled = parseEnvBoolean('DB_HEALTH_CHECK_ENABLED', true);\n * // Accepts: 'true', '1', 'yes' → true\n * // Accepts: 'false', '0', 'no' → false\n * ```\n */\nfunction parseEnvBoolean(key: string, defaultValue: boolean): boolean\n{\n const value = process.env[key];\n\n if (value === undefined)\n {\n return defaultValue;\n }\n\n try\n {\n return parseBoolean(value);\n }\n catch (error)\n {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`${key}: ${message}`);\n }\n}\n\n// ============================================================================\n// Configuration Builders\n// ============================================================================\n\n/**\n * Get connection pool configuration based on environment\n *\n * Configuration priority (highest to lowest):\n * 1. options parameter (passed from ServerConfig)\n * 2. Environment variables (DB_POOL_MAX, DB_POOL_IDLE_TIMEOUT)\n * 3. Default values (based on NODE_ENV)\n *\n * @param options - Optional pool configuration from ServerConfig\n * @returns Pool configuration\n *\n * @example\n * ```typescript\n * // 1. ServerConfig priority (highest)\n * const config = getPoolConfig({ max: 50, idleTimeout: 60 });\n *\n * // 2. Environment variable priority\n * // DB_POOL_MAX=30 DB_POOL_IDLE_TIMEOUT=45\n * const config = getPoolConfig();\n *\n * // 3. Default (lowest)\n * // Production: max=20, idleTimeout=30\n * // Development: max=10, idleTimeout=20\n * ```\n */\nexport function getPoolConfig(options?: Partial<PoolConfig>): PoolConfig\n{\n return {\n max: options?.max ?? parseEnvNumber('DB_POOL_MAX', 20, 10),\n idleTimeout: options?.idleTimeout ?? parseEnvNumber('DB_POOL_IDLE_TIMEOUT', 30, 20),\n };\n}\n\n/**\n * Get retry configuration based on environment\n *\n * Configuration priority (highest to lowest):\n * 1. Environment variables (DB_RETRY_MAX, DB_RETRY_INITIAL_DELAY, etc.)\n * 2. Default values (based on NODE_ENV)\n *\n * @returns Retry configuration\n *\n * @example\n * ```typescript\n * // Environment variables (highest priority)\n * // DB_RETRY_MAX=10\n * // DB_RETRY_INITIAL_DELAY=200\n * const config = getRetryConfig();\n *\n * // Defaults (lowest priority)\n * // Production: 5 retries, 100ms initial, 10s max, factor 2\n * // Development: 3 retries, 50ms initial, 5s max, factor 2\n * ```\n */\nexport function getRetryConfig(): RetryConfig\n{\n return {\n maxRetries: parseEnvNumber('DB_RETRY_MAX', 5, 3),\n initialDelay: parseEnvNumber('DB_RETRY_INITIAL_DELAY', 100, 50),\n maxDelay: parseEnvNumber('DB_RETRY_MAX_DELAY', 10000, 5000),\n factor: parseEnvNumber('DB_RETRY_FACTOR', 2, 2),\n };\n}\n\n/**\n * Build health check configuration with priority resolution\n *\n * Configuration priority (highest to lowest):\n * 1. options parameter\n * 2. Environment variables\n * 3. Default values\n *\n * @param options - Optional health check configuration\n * @returns Health check configuration\n *\n * @example\n * ```typescript\n * // Custom options (highest priority)\n * const config = buildHealthCheckConfig({ enabled: false });\n *\n * // Environment variables\n * // DB_HEALTH_CHECK_ENABLED=true\n * // DB_HEALTH_CHECK_INTERVAL=30000\n * const config = buildHealthCheckConfig();\n *\n * // Defaults (lowest priority)\n * // enabled: true, interval: 60000ms, reconnect: true\n * ```\n */\nexport function buildHealthCheckConfig(options?: Partial<HealthCheckConfig>): HealthCheckConfig\n{\n return {\n enabled: options?.enabled\n ?? parseEnvBoolean('DB_HEALTH_CHECK_ENABLED', true),\n interval: options?.interval\n ?? parseEnvNumber('DB_HEALTH_CHECK_INTERVAL', 60000, 60000),\n reconnect: options?.reconnect\n ?? parseEnvBoolean('DB_HEALTH_CHECK_RECONNECT', true),\n maxRetries: options?.maxRetries\n ?? parseEnvNumber('DB_HEALTH_CHECK_MAX_RETRIES', 3, 3),\n retryInterval: options?.retryInterval\n ?? parseEnvNumber('DB_HEALTH_CHECK_RETRY_INTERVAL', 5000, 5000),\n };\n}\n\n/**\n * Build monitoring configuration with priority resolution\n *\n * Configuration priority (highest to lowest):\n * 1. options parameter\n * 2. Environment variables\n * 3. Default values\n *\n * @param options - Optional monitoring configuration\n * @returns Monitoring configuration\n *\n * @example\n * ```typescript\n * // Custom options (highest priority)\n * const config = buildMonitoringConfig({ slowThreshold: 2000 });\n *\n * // Environment variables\n * // DB_MONITORING_ENABLED=true\n * // DB_MONITORING_SLOW_THRESHOLD=500\n * const config = buildMonitoringConfig();\n *\n * // Defaults (lowest priority)\n * // Development: enabled=true, slowThreshold=1000ms, logQueries=false\n * // Production: enabled=false, slowThreshold=1000ms, logQueries=false\n * ```\n */\nexport function buildMonitoringConfig(options?: Partial<MonitoringConfig>): MonitoringConfig\n{\n const isDevelopment = process.env.NODE_ENV !== 'production';\n\n return {\n enabled: options?.enabled\n ?? parseEnvBoolean('DB_MONITORING_ENABLED', isDevelopment),\n slowThreshold: options?.slowThreshold\n ?? parseEnvNumber('DB_MONITORING_SLOW_THRESHOLD', 1000, 1000),\n logQueries: options?.logQueries\n ?? parseEnvBoolean('DB_MONITORING_LOG_QUERIES', false),\n };\n}","/**\n * Database factory with automatic environment variable detection\n * Supports: Single primary, Primary + Replica\n */\n\nimport { drizzle } from 'drizzle-orm/postgres-js';\nimport type { Sql } from 'postgres';\n\nimport { env } from '@spfn/core/config';\nimport { logger } from '@spfn/core/logger';\nimport { createDatabaseConnection } from './connection';\nimport { getPoolConfig, getRetryConfig, type DatabaseOptions, type DatabaseClients, type PoolConfig, type RetryConfig } from './config';\n\nconst dbLogger = logger.child('@spfn/core:database');\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Database configuration pattern types\n *\n * Represents different ways to configure database connections via environment variables.\n */\ntype DatabasePattern =\n | { type: 'write-read'; write: string; read: string } // Explicit write/read separation\n | { type: 'single'; url: string } // Single database\n | { type: 'none' }; // No configuration\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Check if any database configuration exists in environment\n */\nfunction hasDatabaseConfig(): boolean\n{\n return env.DATABASE_URL !== undefined ||\n env.DATABASE_WRITE_URL !== undefined ||\n env.DATABASE_READ_URL !== undefined;\n}\n\n/**\n * Detect database configuration pattern from environment variables\n *\n * Priority order (highest to lowest):\n * 1. write-read: DATABASE_WRITE_URL + DATABASE_READ_URL (explicit separation)\n * 2. single: DATABASE_URL (most common)\n * 3. single: DATABASE_WRITE_URL (write-only, no replica)\n * 4. none: No configuration found\n *\n * @returns Detected database configuration pattern\n *\n * @example\n * ```typescript\n * const pattern = detectDatabasePattern();\n *\n * if (pattern.type === 'write-read') {\n * console.log(`Write: ${pattern.write}, Read: ${pattern.read}`);\n * }\n * ```\n */\nfunction detectDatabasePattern(): DatabasePattern\n{\n const DATABASE_WRITE_URL = env.DATABASE_WRITE_URL;\n const DATABASE_READ_URL = env.DATABASE_READ_URL;\n const DATABASE_URL = env.DATABASE_URL;\n\n // Priority 1: Explicit write/read separation (recommended)\n if (DATABASE_WRITE_URL && DATABASE_READ_URL)\n {\n return {\n type: 'write-read',\n write: DATABASE_WRITE_URL,\n read: DATABASE_READ_URL,\n };\n }\n\n // Priority 2: Single primary (most common)\n if (DATABASE_URL)\n {\n return {\n type: 'single',\n url: DATABASE_URL,\n };\n }\n\n // Priority 3: Write-only (no replica)\n if (DATABASE_WRITE_URL)\n {\n return {\n type: 'single',\n url: DATABASE_WRITE_URL,\n };\n }\n\n // No configuration found\n return { type: 'none' };\n}\n\n/**\n * Create write and read database clients\n *\n * Write connection is required and will throw if it fails.\n * Read connection is optional - if it fails, falls back to using write connection with a warning.\n *\n * @param writeUrl - Write database connection string\n * @param readUrl - Read database connection string\n * @param poolConfig - Connection pool configuration\n * @param retryConfig - Retry configuration\n * @returns Database clients\n * @throws Error if write connection fails\n */\nasync function createWriteReadClients(\n writeUrl: string,\n readUrl: string,\n poolConfig: PoolConfig,\n retryConfig: RetryConfig\n): Promise<DatabaseClients>\n{\n let writeClient: Sql | undefined;\n let readClient: Sql | undefined;\n\n try\n {\n // Write connection is required - must succeed\n writeClient = await createDatabaseConnection(writeUrl, poolConfig, retryConfig);\n }\n catch (error)\n {\n const errorObj = error instanceof Error ? error : new Error(String(error));\n dbLogger.error('Failed to connect to write database', errorObj);\n throw new Error(`Write database connection failed: ${errorObj.message}`, { cause: error });\n }\n\n // Read connection is optional - fallback to write if it fails\n try\n {\n readClient = await createDatabaseConnection(readUrl, poolConfig, retryConfig);\n\n return {\n write: drizzle(writeClient),\n read: drizzle(readClient),\n writeClient,\n readClient,\n };\n }\n catch (error)\n {\n const errorObj = error instanceof Error ? error : new Error(String(error));\n\n // Log warning but continue with write connection as fallback\n dbLogger.warn(\n 'Failed to connect to read database (replica). Falling back to write database for read operations.',\n {\n error: errorObj.message,\n readUrl: readUrl.replace(/:[^:@]+@/, ':***@'), // Mask password in logs\n fallbackBehavior: 'Using write connection for both read and write operations',\n }\n );\n\n // Use write connection for both read and write\n return {\n write: drizzle(writeClient),\n read: drizzle(writeClient),\n writeClient,\n readClient: writeClient,\n };\n }\n}\n\n/**\n * Create single database client (used for both read and write)\n *\n * @param url - Database connection string\n * @param poolConfig - Connection pool configuration\n * @param retryConfig - Retry configuration\n * @returns Database clients\n */\nasync function createSingleClient(\n url: string,\n poolConfig: PoolConfig,\n retryConfig: RetryConfig\n): Promise<DatabaseClients>\n{\n const client = await createDatabaseConnection(url, poolConfig, retryConfig);\n const db = drizzle(client);\n\n return {\n write: db,\n read: db,\n writeClient: client,\n readClient: client,\n };\n}\n\n/**\n * Create database client(s) from environment variables\n *\n * Supported patterns (priority order):\n * 1. Primary + Replica: DATABASE_WRITE_URL + DATABASE_READ_URL\n * 2. Single primary: DATABASE_URL\n *\n * @param options - Optional database configuration (pool settings, etc.)\n * @returns Database client(s)\n * @throws {Error} If no database configuration is found or connection fails\n *\n * @example\n * ```bash\n * # Single primary (most common)\n * DATABASE_URL=postgresql://localhost:5432/mydb\n *\n * # Primary + Replica\n * DATABASE_WRITE_URL=postgresql://primary:5432/mydb\n * DATABASE_READ_URL=postgresql://replica:5432/mydb\n * ```\n *\n * @example\n * ```typescript\n * // Custom pool configuration\n * const db = await createDatabaseFromEnv({\n * pool: { max: 50, idleTimeout: 60 }\n * });\n * ```\n */\nexport async function createDatabaseFromEnv(options?: DatabaseOptions): Promise<DatabaseClients>\n{\n // Quick exit if no database config\n if (!hasDatabaseConfig())\n {\n const error = new Error(\n 'No database configuration found. Please set DATABASE_URL, DATABASE_WRITE_URL, or DATABASE_READ_URL environment variable.'\n );\n\n dbLogger.error('No database configuration found', {\n cwd: process.cwd(),\n nodeEnv: env.NODE_ENV,\n checkedVars: ['DATABASE_URL', 'DATABASE_WRITE_URL', 'DATABASE_READ_URL'],\n });\n\n throw error;\n }\n\n try\n {\n const poolConfig = getPoolConfig(options?.pool);\n const retryConfig = getRetryConfig();\n const pattern = detectDatabasePattern();\n\n // Create database clients based on detected pattern\n switch (pattern.type)\n {\n case 'write-read':\n return await createWriteReadClients(\n pattern.write,\n pattern.read,\n poolConfig,\n retryConfig\n );\n\n case 'single':\n return await createSingleClient(pattern.url, poolConfig, retryConfig);\n }\n }\n catch (error)\n {\n const errorObj = error instanceof Error ? error : new Error(String(error));\n dbLogger.error(\n 'Failed to create database connection',\n errorObj,\n {\n stage: 'initialization',\n hasWriteUrl: process.env.DATABASE_WRITE_URL !== undefined,\n hasReadUrl: process.env.DATABASE_READ_URL !== undefined,\n hasUrl: process.env.DATABASE_URL !== undefined,\n }\n );\n\n throw new Error(`Database connection failed: ${errorObj.message}`, { cause: error });\n }\n\n throw new Error('No database pattern detected despite passing config check');\n}","/**\n * Global Database State Management\n *\n * Manages global database instances using globalThis for persistence across module reloads.\n * This is particularly useful in development with hot module replacement (HMR).\n *\n * The singleton pattern ensures database connections persist even when modules are reloaded\n * during development (e.g., with tsx watch mode).\n */\n\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport type { Sql } from 'postgres';\nimport type { MonitoringConfig } from './config';\n\n// ============================================================================\n// Global Type Declarations\n// ============================================================================\n\n/**\n * Extend globalThis with database-specific properties\n *\n * Using globalThis allows database instances to persist across module reloads,\n * which is essential for development environments with hot module replacement.\n */\ndeclare global\n{\n var __SPFN_DB_WRITE__: PostgresJsDatabase<Record<string, unknown>> | undefined;\n var __SPFN_DB_READ__: PostgresJsDatabase<Record<string, unknown>> | undefined;\n var __SPFN_DB_WRITE_CLIENT__: Sql | undefined;\n var __SPFN_DB_READ_CLIENT__: Sql | undefined;\n var __SPFN_DB_HEALTH_CHECK__: NodeJS.Timeout | undefined;\n var __SPFN_DB_MONITORING__: MonitoringConfig | undefined;\n}\n\n// ============================================================================\n// Database Instance Accessors\n// ============================================================================\n\n/**\n * Get write database instance from global state\n *\n * @internal - This is an internal API. Use getDatabase() from @spfn/core/db instead.\n */\nexport const getWriteInstance = (): PostgresJsDatabase<Record<string, unknown>> | undefined =>\n globalThis.__SPFN_DB_WRITE__;\n\n/**\n * Set write database instance in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setWriteInstance = (instance: PostgresJsDatabase<Record<string, unknown>> | undefined): void => {\n globalThis.__SPFN_DB_WRITE__ = instance;\n};\n\n/**\n * Get read database instance from global state\n *\n * @internal - This is an internal API. Use getDatabase() from @spfn/core/db instead.\n */\nexport const getReadInstance = (): PostgresJsDatabase<Record<string, unknown>> | undefined =>\n globalThis.__SPFN_DB_READ__;\n\n/**\n * Set read database instance in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setReadInstance = (instance: PostgresJsDatabase<Record<string, unknown>> | undefined): void => {\n globalThis.__SPFN_DB_READ__ = instance;\n};\n\n// ============================================================================\n// Raw Client Accessors\n// ============================================================================\n\n/**\n * Get write client from global state (for cleanup)\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const getWriteClient = (): Sql | undefined =>\n globalThis.__SPFN_DB_WRITE_CLIENT__;\n\n/**\n * Set write client in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setWriteClient = (client: Sql | undefined): void => {\n globalThis.__SPFN_DB_WRITE_CLIENT__ = client;\n};\n\n/**\n * Get read client from global state (for cleanup)\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const getReadClient = (): Sql | undefined =>\n globalThis.__SPFN_DB_READ_CLIENT__;\n\n/**\n * Set read client in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setReadClient = (client: Sql | undefined): void => {\n globalThis.__SPFN_DB_READ_CLIENT__ = client;\n};\n\n// ============================================================================\n// Health Check Accessors\n// ============================================================================\n\n/**\n * Get health check interval from global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const getHealthCheckInterval = (): NodeJS.Timeout | undefined =>\n globalThis.__SPFN_DB_HEALTH_CHECK__;\n\n/**\n * Set health check interval in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setHealthCheckInterval = (interval: NodeJS.Timeout | undefined): void => {\n globalThis.__SPFN_DB_HEALTH_CHECK__ = interval;\n};\n\n// ============================================================================\n// Monitoring Config Accessors\n// ============================================================================\n\n/**\n * Get monitoring configuration from global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const getMonitoringConfig = (): MonitoringConfig | undefined =>\n globalThis.__SPFN_DB_MONITORING__;\n\n/**\n * Set monitoring configuration in global state\n *\n * @internal - This is an internal API used by the database manager.\n */\nexport const setMonitoringConfig = (config: MonitoringConfig | undefined): void => {\n globalThis.__SPFN_DB_MONITORING__ = config;\n};","/**\n * Database Health Check\n *\n * Periodic health checks for database connections with automatic reconnection.\n * Monitors both write and read database instances and attempts recovery on failure.\n */\n\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\n\nimport { logger } from '@spfn/core/logger';\nimport { createDatabaseFromEnv } from './factory';\nimport type { DatabaseOptions, HealthCheckConfig } from './config';\nimport { buildMonitoringConfig } from './config';\nimport {\n getHealthCheckInterval,\n setHealthCheckInterval,\n setWriteInstance,\n setReadInstance,\n setWriteClient,\n setReadClient,\n setMonitoringConfig,\n} from './global-state';\nimport type { GetDatabaseFn } from './types';\n\nconst dbLogger = logger.child('@spfn/core:database');\n\n// ============================================================================\n// Helper Functions (Private)\n// ============================================================================\n\n/**\n * Test a single database connection\n *\n * @param db - Database instance to test\n * @throws Error if connection test fails\n * @internal\n */\nasync function testDatabaseConnection(\n db: PostgresJsDatabase<Record<string, unknown>>\n): Promise<void>\n{\n await db.execute('SELECT 1');\n}\n\n/**\n * Perform health check on database connections\n *\n * Tests both write and read connections.\n *\n * @param getDatabase - Function to get database instance\n * @throws Error if health check fails\n * @internal\n */\nasync function performHealthCheck(getDatabase: GetDatabaseFn): Promise<void>\n{\n const write = getDatabase('write');\n const read = getDatabase('read');\n\n await testDatabaseConnection(write);\n\n // Check read connection if different from write\n if (read !== write)\n {\n await testDatabaseConnection(read);\n }\n}\n\n/**\n * Reconnect database and restore instances\n *\n * Closes existing connections, creates new ones, tests them, and restores global state.\n *\n * @param options - Optional database configuration\n * @param closeDatabase - Function to close existing connections\n * @returns true if reconnection successful, false otherwise\n * @internal\n */\nasync function reconnectAndRestore(\n options: DatabaseOptions | undefined,\n closeDatabase: () => Promise<void>\n): Promise<boolean>\n{\n // Close existing connections\n await closeDatabase();\n\n // Create new connections\n const result = await createDatabaseFromEnv(options);\n\n if (!result.write)\n {\n return false;\n }\n\n // Test both connections before restoring\n await testDatabaseConnection(result.write);\n if (result.read && result.read !== result.write)\n {\n await testDatabaseConnection(result.read);\n }\n\n // Store instances\n setWriteInstance(result.write);\n setReadInstance(result.read);\n setWriteClient(result.writeClient);\n setReadClient(result.readClient);\n\n // Restore monitoring configuration\n const monConfig = buildMonitoringConfig(options?.monitoring);\n setMonitoringConfig(monConfig);\n\n return true;\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Start database health check\n *\n * Periodically checks database connection health and attempts reconnection if enabled.\n * Automatically started by initDatabase() when health check is enabled.\n *\n * @param config - Health check configuration\n * @param options - Optional database configuration (pool settings, etc.)\n * @param getDatabase - Function to get database instance (to avoid circular dependency)\n * @param closeDatabase - Function to close database (for reconnection)\n *\n * @example\n * ```typescript\n * import { startHealthCheck } from '@spfn/core/db/manager/health-check';\n *\n * startHealthCheck(\n * {\n * enabled: true,\n * interval: 30000, // 30 seconds\n * reconnect: true,\n * maxRetries: 5,\n * retryInterval: 10000, // 10 seconds\n * },\n * undefined,\n * getDatabase,\n * closeDatabase\n * );\n * ```\n */\nexport function startHealthCheck(\n config: HealthCheckConfig,\n options: DatabaseOptions | undefined,\n getDatabase: GetDatabaseFn,\n closeDatabase: () => Promise<void>\n): void\n{\n const healthCheck = getHealthCheckInterval();\n if (healthCheck)\n {\n dbLogger.debug('Health check already running');\n return;\n }\n\n dbLogger.info('Starting database health check', {\n interval: `${config.interval}ms`,\n reconnect: config.reconnect,\n });\n\n const interval = setInterval(async () =>\n {\n try\n {\n await performHealthCheck(getDatabase);\n // Health check passed - no need to log (only log failures)\n }\n catch (error: unknown)\n {\n const message = error instanceof Error ? error.message : 'Unknown error';\n dbLogger.error('Database health check failed', { error: message });\n\n // Attempt reconnection if enabled\n if (config.reconnect)\n {\n await attemptReconnection(config, options, closeDatabase);\n }\n }\n }, config.interval);\n\n setHealthCheckInterval(interval);\n}\n\n/**\n * Attempt database reconnection with retry logic\n *\n * Closes existing connections and attempts to reinitialize the database.\n * Retries multiple times with configurable delay between attempts.\n *\n * @param config - Health check configuration\n * @param options - Optional database configuration (pool settings, etc.)\n * @param closeDatabase - Function to close existing database connections\n */\nasync function attemptReconnection(\n config: HealthCheckConfig,\n options: DatabaseOptions | undefined,\n closeDatabase: () => Promise<void>\n): Promise<void>\n{\n dbLogger.warn('Attempting database reconnection', {\n maxRetries: config.maxRetries,\n retryInterval: `${config.retryInterval}ms`,\n });\n\n for (let attempt = 1; attempt <= config.maxRetries; attempt++)\n {\n try\n {\n dbLogger.debug(`Reconnection attempt ${attempt}/${config.maxRetries}`);\n\n // Wait before retry (skip for first attempt)\n if (attempt > 1)\n {\n await new Promise(resolve => setTimeout(resolve, config.retryInterval));\n }\n\n // Attempt reconnection\n const success = await reconnectAndRestore(options, closeDatabase);\n\n if (success)\n {\n dbLogger.info('Database reconnection successful', { attempt });\n return;\n }\n else\n {\n dbLogger.error(`Reconnection attempt ${attempt} failed: No write database instance created`);\n }\n }\n catch (error: unknown)\n {\n const message = error instanceof Error ? error.message : 'Unknown error';\n dbLogger.error(`Reconnection attempt ${attempt} failed`, {\n error: message,\n attempt,\n maxRetries: config.maxRetries,\n });\n }\n\n if (attempt === config.maxRetries)\n {\n dbLogger.error('Max reconnection attempts reached, giving up');\n }\n }\n}\n\n/**\n * Stop database health check\n *\n * Automatically called by closeDatabase().\n * Can also be called manually to stop health checks.\n *\n * @example\n * ```typescript\n * import { stopHealthCheck } from '@spfn/core/db/manager/health-check';\n *\n * stopHealthCheck();\n * ```\n */\nexport function stopHealthCheck(): void\n{\n const healthCheck = getHealthCheckInterval();\n if (healthCheck)\n {\n clearInterval(healthCheck);\n setHealthCheckInterval(undefined);\n dbLogger.info('Database health check stopped');\n }\n}","/**\n * Global Database instance manager\n * Provides singleton access to database across all modules\n * Supports Primary + Replica pattern with separate read/write instances\n */\n\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport type { Sql } from 'postgres';\n\nimport { logger } from '@spfn/core/logger';\nimport { createDatabaseFromEnv } from './factory';\nimport type { DatabaseOptions, MonitoringConfig } from \"./config.js\";\nimport { buildHealthCheckConfig, buildMonitoringConfig } from \"./config.js\";\nimport { env } from '@spfn/core/config';\nimport {\n getWriteInstance,\n setWriteInstance,\n getReadInstance,\n setReadInstance,\n getWriteClient,\n setWriteClient,\n getReadClient,\n setReadClient,\n getMonitoringConfig,\n setMonitoringConfig,\n} from './global-state';\nimport { startHealthCheck, stopHealthCheck } from './health-check';\nimport type { DbConnectionType } from './types';\n\nconst dbLogger = logger.child('@spfn/core:database');\n\n/**\n * Connection close timeout in seconds\n */\nconst DB_CONNECTION_CLOSE_TIMEOUT = 5;\n\n/**\n * Number of stack trace lines to skip when detecting caller\n */\nconst STACK_TRACE_SKIP_LINES = 3;\n\n/**\n * Regular expressions for parsing stack trace lines\n */\nconst STACK_TRACE_PATTERNS = {\n withParens: /\\((.+):(\\d+):(\\d+)\\)/,\n withoutParens: /at (.+):(\\d+):(\\d+)/,\n};\n\n/**\n * Initialization promise to prevent concurrent initialization\n */\nlet initPromise: Promise<{\n write?: PostgresJsDatabase<Record<string, unknown>>;\n read?: PostgresJsDatabase<Record<string, unknown>>;\n}> | null = null;\n\n/**\n * Close in progress flag to prevent concurrent closeDatabase calls\n */\nlet isClosing = false;\n\n// ============================================================================\n// Helper Functions (Private)\n// ============================================================================\n\n/**\n * Cleanup database connections\n *\n * Closes write and read client connections with timeout.\n * Ignores cleanup errors to ensure all cleanup attempts complete.\n *\n * @param writeClient - Write client to cleanup\n * @param readClient - Read client to cleanup\n * @internal\n */\nasync function cleanupDatabaseConnections(\n writeClient: Sql | undefined,\n readClient: Sql | undefined\n): Promise<void>\n{\n const cleanupPromises: Promise<void>[] = [];\n\n if (writeClient)\n {\n cleanupPromises.push(\n writeClient.end({ timeout: DB_CONNECTION_CLOSE_TIMEOUT }).catch((err) => {\n dbLogger.debug('Write client cleanup failed', { error: err });\n })\n );\n }\n\n if (readClient && readClient !== writeClient)\n {\n cleanupPromises.push(\n readClient.end({ timeout: DB_CONNECTION_CLOSE_TIMEOUT }).catch((err) => {\n dbLogger.debug('Read client cleanup failed', { error: err });\n })\n );\n }\n\n await Promise.allSettled(cleanupPromises);\n}\n\n/**\n * Close a single database client connection\n *\n * @param client - Database client to close\n * @param type - Connection type ('write' or 'read')\n * @internal\n */\nasync function closeDatabaseClient(client: Sql, type: 'write' | 'read'): Promise<void>\n{\n const typeName = type.charAt(0).toUpperCase() + type.slice(1);\n dbLogger.debug(`Closing ${type} connection...`);\n\n try\n {\n await client.end({ timeout: DB_CONNECTION_CLOSE_TIMEOUT });\n dbLogger.debug(`${typeName} connection closed`);\n }\n catch (err: unknown)\n {\n const error = err instanceof Error ? err : new Error(String(err));\n dbLogger.error(`Error closing ${type} connection`, error);\n }\n}\n\n/**\n * Test database connections\n *\n * Executes a simple SELECT 1 query on both write and read connections.\n *\n * @param write - Write database instance\n * @param read - Read database instance\n * @throws Error if connection test fails\n * @internal\n */\nasync function testDatabaseConnections(\n write: PostgresJsDatabase<Record<string, unknown>> | undefined,\n read: PostgresJsDatabase<Record<string, unknown>> | undefined\n): Promise<void>\n{\n if (write)\n {\n await write.execute('SELECT 1');\n\n // Test read connection if different from write\n if (read && read !== write)\n {\n await read.execute('SELECT 1');\n }\n }\n}\n\n/**\n * Get caller information from stack trace\n */\nfunction getCallerInfo(): string | undefined\n{\n try\n {\n const stack = new Error().stack;\n if (!stack) return undefined;\n\n const lines = stack.split('\\n');\n // Skip first 3 lines: Error, getCallerInfo, getDatabase\n for (let i = STACK_TRACE_SKIP_LINES; i < lines.length; i++)\n {\n const line = lines[i];\n // Find first meaningful caller (not node_modules/@spfn/core/db)\n if (!line.includes('node_modules') && !line.includes('/db/manager/'))\n {\n // Extract file:line from stack line\n const match = line.match(STACK_TRACE_PATTERNS.withParens) || line.match(STACK_TRACE_PATTERNS.withoutParens);\n if (match)\n {\n const fullPath = match[1];\n // Get relative path from project root\n const parts = fullPath.split('/');\n const srcIndex = parts.lastIndexOf('src');\n if (srcIndex !== -1)\n {\n const relativePath = parts.slice(srcIndex).join('/');\n return `${relativePath}:${match[2]}`;\n }\n return `${fullPath}:${match[2]}`;\n }\n break;\n }\n }\n }\n catch (error: unknown)\n {\n // Stack trace parsing failed - log for debugging\n dbLogger.debug('Failed to extract caller info from stack trace', {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n return undefined;\n}\n\n/**\n * Create database not initialized error message\n *\n * @param type - Database connection type ('read' or 'write')\n * @returns Error with descriptive message for uninitialized database\n *\n * @internal\n */\nfunction createNotInitializedError(type: DbConnectionType): Error\n{\n return new Error(\n `Database not initialized (type: ${type}). Call initDatabase() first or set DATABASE_URL environment variable.`\n );\n}\n\n/**\n * Get global database instance\n *\n * @param type - Connection type ('read' or 'write', defaults to 'write')\n * @returns Database instance (never undefined)\n * @throws Error if database is not initialized\n *\n * @example\n * ```typescript\n * import { getDatabase } from '@spfn/core/db';\n *\n * // Always returns a valid instance or throws\n * const db = getDatabase();\n * const users = await db.select().from(usersTable);\n *\n * // For read operations (uses replica if available, falls back to primary)\n * const dbRead = getDatabase('read');\n * const posts = await dbRead.select().from(postsTable);\n * ```\n */\nexport function getDatabase(type?: DbConnectionType): PostgresJsDatabase<Record<string, unknown>>\n{\n const writeInst = getWriteInstance();\n const readInst = getReadInstance();\n\n // Detailed debug logging with caller info (only if DB_DEBUG_TRACE is enabled in non-production)\n if (env.DB_DEBUG_TRACE && env.NODE_ENV !== 'production')\n {\n const caller = getCallerInfo();\n dbLogger.debug('getDatabase() called', {\n type: type ?? 'write',\n hasWrite: !!writeInst,\n hasRead: !!readInst,\n caller,\n });\n }\n\n if (type === 'read')\n {\n const db = readInst ?? writeInst;\n if (!db)\n {\n throw createNotInitializedError('read');\n }\n return db;\n }\n\n // Default: 'write' type\n if (!writeInst)\n {\n throw createNotInitializedError('write');\n }\n\n return writeInst;\n}\n\n/**\n * Set global database instances (for testing or manual configuration)\n *\n * This function directly sets database instances without creating connections\n * or performing validation. It's primarily intended for testing scenarios.\n *\n * @param write - Database write instance (pass undefined to clear)\n * @param read - Database read instance (optional, defaults to write, pass undefined to clear)\n *\n * @remarks\n * **Important:** To properly close database connections with cleanup, use `closeDatabase()` instead.\n * This function only updates the global instances without closing the underlying connections.\n * Setting both to undefined will clear the instances but leave connections open, which may cause resource leaks.\n *\n * @example\n * ```typescript\n * import { setDatabase } from '@spfn/core/db';\n * import { drizzle } from 'drizzle-orm/postgres-js';\n * import postgres from 'postgres';\n *\n * // Set custom database instances (testing)\n * const writeClient = postgres('postgresql://primary:5432/mydb');\n * const readClient = postgres('postgresql://replica:5432/mydb');\n * setDatabase(drizzle(writeClient), drizzle(readClient));\n *\n * // Clear instances (not recommended - use closeDatabase() instead)\n * setDatabase(undefined, undefined);\n * ```\n */\nexport function setDatabase(\n write: PostgresJsDatabase<Record<string, unknown>> | undefined,\n read?: PostgresJsDatabase<Record<string, unknown>> | undefined\n): void\n{\n setWriteInstance(write);\n setReadInstance(read ?? write);\n}\n\n/**\n * Initialize database from environment variables\n * Automatically called by server startup\n *\n * Supported environment variables:\n * - DATABASE_URL (single primary)\n * - DATABASE_WRITE_URL + DATABASE_READ_URL (primary + replica)\n * - DB_POOL_MAX (connection pool max size)\n * - DB_POOL_IDLE_TIMEOUT (connection idle timeout in seconds)\n * - DB_HEALTH_CHECK_ENABLED (enable health checks, default: true)\n * - DB_HEALTH_CHECK_INTERVAL (health check interval in ms, default: 60000)\n * - DB_HEALTH_CHECK_RECONNECT (enable auto-reconnect, default: true)\n * - DB_HEALTH_CHECK_MAX_RETRIES (max reconnection attempts, default: 3)\n * - DB_HEALTH_CHECK_RETRY_INTERVAL (retry interval in ms, default: 5000)\n * - DB_MONITORING_ENABLED (enable query monitoring, default: true in dev, false in prod)\n * - DB_MONITORING_SLOW_THRESHOLD (slow query threshold in ms, default: 1000)\n * - DB_MONITORING_LOG_QUERIES (log actual SQL queries, default: false)\n * - DB_DEBUG_TRACE (enable detailed getDatabase() call tracing with caller info, default: false)\n *\n * Configuration priority:\n * 1. options parameter (ServerConfig)\n * 2. Environment variables\n * 3. Defaults (based on NODE_ENV)\n *\n * @param options - Optional database configuration (pool settings, etc.)\n * @returns Object with write and read instances\n *\n * @example\n * ```typescript\n * import { initDatabase } from '@spfn/core/db';\n *\n * // Manual initialization (not needed if using server startup)\n * const { write, read } = await initDatabase();\n * if (write) {\n * console.log('Database connected');\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Custom pool configuration\n * const { write, read } = await initDatabase({\n * pool: { max: 50, idleTimeout: 60 }\n * });\n * ```\n */\nexport async function initDatabase(options?: DatabaseOptions): Promise<{\n write?: PostgresJsDatabase<Record<string, unknown>>;\n read?: PostgresJsDatabase<Record<string, unknown>>;\n}>\n{\n // Prevent initialization during close operation\n if (isClosing)\n {\n throw new Error('Cannot initialize database while closing');\n }\n\n // Already initialized\n const writeInst = getWriteInstance();\n if (writeInst)\n {\n dbLogger.debug('Database already initialized');\n return { write: writeInst, read: getReadInstance() };\n }\n\n // Initialization in progress - wait for it to complete\n if (initPromise)\n {\n dbLogger.debug('Database initialization in progress, waiting...');\n return await initPromise;\n }\n\n // Start initialization with lock\n initPromise = (async () =>\n {\n try\n {\n // Auto-detect from environment\n const result = await createDatabaseFromEnv(options);\n\n // Test connections\n try\n {\n await testDatabaseConnections(result.write, result.read);\n }\n catch (error: unknown)\n {\n // Connection test failed - cleanup and throw\n await cleanupDatabaseConnections(result.writeClient, result.readClient);\n\n const message = error instanceof Error ? error.message : 'Unknown error';\n throw new Error(`Database connection test failed: ${message}`);\n }\n\n // Check if database was closed during initialization\n if (isClosing)\n {\n dbLogger.warn('Database closed during initialization, cleaning up...');\n await cleanupDatabaseConnections(result.writeClient, result.readClient);\n throw new Error('Database closed during initialization');\n }\n\n // Store instances in globalThis\n setWriteInstance(result.write);\n setReadInstance(result.read);\n setWriteClient(result.writeClient);\n setReadClient(result.readClient);\n\n const hasReplica = result.read && result.read !== result.write;\n dbLogger.info(\n hasReplica\n ? 'Database connected (Primary + Replica)'\n : 'Database connected'\n );\n\n // Start health check (automatic)\n const healthCheckConfig = buildHealthCheckConfig(options?.healthCheck);\n if (healthCheckConfig.enabled)\n {\n startHealthCheck(healthCheckConfig, options, getDatabase, closeDatabase);\n }\n\n // Initialize monitoring configuration\n const monConfig = buildMonitoringConfig(options?.monitoring);\n setMonitoringConfig(monConfig);\n if (monConfig.enabled)\n {\n dbLogger.info('Database query monitoring enabled', {\n slowThreshold: `${monConfig.slowThreshold}ms`,\n logQueries: monConfig.logQueries,\n });\n }\n\n return { write: getWriteInstance(), read: getReadInstance() };\n }\n finally\n {\n // Clear lock after initialization completes (success or failure)\n initPromise = null;\n }\n })();\n\n return await initPromise;\n}\n\n/**\n * Close all database connections and cleanup\n *\n * Properly closes postgres connection pools with timeout.\n * Should be called during graceful shutdown or after tests.\n *\n * @example\n * ```typescript\n * import { closeDatabase } from '@spfn/core/db';\n *\n * // During graceful shutdown\n * process.on('SIGTERM', async () => {\n * await closeDatabase();\n * process.exit(0);\n * });\n *\n * // In tests\n * afterAll(async () => {\n * await closeDatabase();\n * });\n * ```\n */\nexport async function closeDatabase(): Promise<void>\n{\n // Prevent concurrent close operations\n if (isClosing)\n {\n dbLogger.debug('Database close already in progress');\n return;\n }\n\n // Set closing flag early to prevent new operations\n isClosing = true;\n\n // Wait for any in-progress initialization to complete before closing\n if (initPromise)\n {\n dbLogger.debug('Waiting for database initialization to complete before closing...');\n\n try\n {\n await initPromise;\n }\n catch (_error: unknown)\n {\n // Initialization failed, but we still need to cleanup any partial state\n dbLogger.debug('Initialization failed during close, proceeding with cleanup');\n }\n }\n\n const writeInst = getWriteInstance();\n const readInst = getReadInstance();\n if (!writeInst && !readInst)\n {\n dbLogger.debug('No database connections to close');\n isClosing = false;\n return;\n }\n\n try\n {\n // Stop health check\n stopHealthCheck();\n\n const closePromises: Promise<void>[] = [];\n\n // Close write client\n const writeC = getWriteClient();\n if (writeC)\n {\n closePromises.push(closeDatabaseClient(writeC, 'write'));\n }\n\n // Close read client (if different from write)\n const readC = getReadClient();\n if (readC && readC !== writeC)\n {\n closePromises.push(closeDatabaseClient(readC, 'read'));\n }\n\n // Wait for all connections to close (use allSettled to ensure all cleanup attempts complete)\n await Promise.allSettled(closePromises);\n\n dbLogger.info('All database connections closed');\n }\n finally\n {\n // Always clear instances and reset flag\n setWriteInstance(undefined);\n setReadInstance(undefined);\n setWriteClient(undefined);\n setReadClient(undefined);\n setMonitoringConfig(undefined);\n isClosing = false;\n }\n}\n\n/**\n * Get database connection info (for debugging)\n *\n * Returns the current state of database connections without throwing errors.\n * Useful for health checks, monitoring, and debugging initialization issues.\n *\n * @returns Connection status information\n * - `hasWrite`: Whether write database instance is initialized\n * - `hasRead`: Whether read database instance is initialized\n * - `isReplica`: Whether read and write are different instances (Primary + Replica setup)\n *\n * @example\n * ```typescript\n * import { getDatabaseInfo } from '@spfn/core/db';\n *\n * const info = getDatabaseInfo();\n * console.log(`Write: ${info.hasWrite}, Read: ${info.hasRead}, Replica: ${info.isReplica}`);\n *\n * // Check before using database\n * if (!info.hasWrite) {\n * console.warn('Database not initialized');\n * }\n *\n * // Detect Primary + Replica setup\n * if (info.isReplica) {\n * console.log('Using Primary + Replica configuration');\n * }\n * ```\n */\nexport function getDatabaseInfo(): {\n hasWrite: boolean;\n hasRead: boolean;\n isReplica: boolean;\n}\n{\n const writeInst = getWriteInstance();\n const readInst = getReadInstance();\n\n return {\n hasWrite: !!writeInst,\n hasRead: !!readInst,\n isReplica: !!(readInst && readInst !== writeInst),\n };\n}\n\n/**\n * Get current monitoring configuration\n *\n * Returns the monitoring configuration that was set during database initialization.\n * Used by Repository to determine if and how to monitor query performance.\n *\n * @returns Current monitoring configuration or undefined if database not initialized\n *\n * @example\n * ```typescript\n * import { getDatabaseMonitoringConfig } from '@spfn/core/db';\n *\n * const config = getDatabaseMonitoringConfig();\n * if (config?.enabled) {\n * console.log(`Slow query threshold: ${config.slowThreshold}ms`);\n * }\n * ```\n */\nexport function getDatabaseMonitoringConfig(): MonitoringConfig | undefined\n{\n return getMonitoringConfig();\n}","/**\n * Drizzle Kit configuration generator\n * Automatically generates drizzle.config.ts from environment variables\n */\n\nimport { existsSync, readdirSync, readFileSync, statSync } from 'fs';\nimport { join, dirname, basename } from 'path';\nimport { env } from '@spfn/core/config';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Index file patterns to exclude from schema discovery\n */\nconst INDEX_FILE_PATTERNS = [\n '/index',\n '/index.ts',\n '/index.js',\n '/index.mjs',\n '\\\\index',\n '\\\\index.ts',\n '\\\\index.js',\n '\\\\index.mjs',\n];\n\n/**\n * Supported file extensions for schema files\n * Only these extensions will be included in schema discovery\n */\nconst SUPPORTED_EXTENSIONS = ['.ts', '.js', '.mjs'];\n\n// ============================================================================\n// Helper Functions (Private)\n// ============================================================================\n\n/**\n * Check if a file path is an index file\n *\n * @param filePath - File path to check\n * @returns true if file is an index file\n * @internal\n */\nfunction isIndexFile(filePath: string): boolean\n{\n return INDEX_FILE_PATTERNS.some(pattern => filePath.endsWith(pattern));\n}\n\n/**\n * Check if a path is absolute\n *\n * @param path - Path to check\n * @returns true if path is absolute\n * @internal\n */\nfunction isAbsolutePath(path: string): boolean\n{\n // Unix absolute path (starts with /)\n if (path.startsWith('/')) return true;\n\n // Windows absolute path (C:\\ or C:/)\n return !!path.match(/^[A-Za-z]:[\\/\\\\]/);\n}\n\n/**\n * Check if a file has a supported extension\n *\n * @param filePath - File path to check\n * @returns true if file has supported extension\n * @internal\n */\nfunction hasSupportedExtension(filePath: string): boolean\n{\n // Exclude .d.ts files (TypeScript declaration files - not actual schemas)\n if (filePath.endsWith('.d.ts')) return false;\n\n return SUPPORTED_EXTENSIONS.some(ext => filePath.endsWith(ext));\n}\n\n/**\n * Filter out index files from file list\n *\n * @param files - Array of file paths\n * @returns Filtered array without index files\n * @internal\n */\nfunction filterIndexFiles(files: string[]): string[]\n{\n return files.filter(file => !isIndexFile(file));\n}\n\n/**\n * Scan directory recursively for files\n *\n * @param dir - Directory to scan\n * @param extension - Optional file extension filter\n * @returns Array of file paths\n * @internal\n */\nfunction scanDirectoryRecursive(dir: string, extension?: string): string[]\n{\n const files: string[] = [];\n\n if (!existsSync(dir)) return files;\n\n try\n {\n const entries = readdirSync(dir);\n\n for (const entry of entries)\n {\n const fullPath = join(dir, entry);\n\n try\n {\n const stat = statSync(fullPath);\n\n if (stat.isDirectory())\n {\n files.push(...scanDirectoryRecursive(fullPath, extension));\n }\n else if (stat.isFile())\n {\n // Check if file matches extension AND has supported extension\n if ((!extension || fullPath.endsWith(extension)) && hasSupportedExtension(fullPath))\n {\n files.push(fullPath);\n }\n }\n }\n catch (error: unknown)\n {\n // Skip files we can't stat (permission denied, etc.)\n // Silent skip is intentional - we don't want to fail on restricted files\n }\n }\n }\n catch (error: unknown)\n {\n // Skip directories we can't read (permission denied, etc.)\n // Silent skip is intentional - we don't want to fail on restricted directories\n }\n\n return files;\n}\n\n/**\n * Scan directory (single level) for files matching pattern\n *\n * @param dir - Directory to scan\n * @param filePattern - File pattern to match (e.g., \"*.js\")\n * @returns Array of file paths\n * @internal\n */\nfunction scanDirectorySingleLevel(dir: string, filePattern: string): string[]\n{\n const files: string[] = [];\n\n if (!existsSync(dir)) return files;\n\n try\n {\n const entries = readdirSync(dir);\n\n for (const entry of entries)\n {\n const fullPath = join(dir, entry);\n\n try\n {\n const stat = statSync(fullPath);\n\n if (stat.isFile())\n {\n // Simple pattern matching (*.js matches foo.js) AND check supported extensions\n if ((filePattern === '*' ||\n (filePattern.startsWith('*.') && entry.endsWith(filePattern.slice(1)))) &&\n hasSupportedExtension(fullPath))\n {\n files.push(fullPath);\n }\n }\n }\n catch (error: unknown)\n {\n // Skip files we can't stat\n }\n }\n }\n catch (error: unknown)\n {\n // Skip directories we can't read\n }\n\n return files;\n}\n\n// ============================================================================\n// Types & Interfaces\n// ============================================================================\n\nexport interface DrizzleConfigOptions\n{\n /** Database connection URL (defaults to process.env.DATABASE_URL) */\n databaseUrl?: string;\n\n /** Schema files glob pattern or array of patterns (defaults to './src/server/entities/\\*\\*\\/*.ts') */\n schema?: string | string[];\n\n /** Migration output directory (defaults to './src/server/drizzle') */\n out?: string;\n\n /** Database dialect (auto-detected from URL if not provided) */\n dialect?: 'postgresql' | 'mysql' | 'sqlite';\n\n /** Current working directory for discovering package schemas */\n cwd?: string;\n\n /** Disable automatic package schema discovery */\n disablePackageDiscovery?: boolean;\n\n /** Only include schemas from specific package (e.g., '@spfn/cms') */\n packageFilter?: string;\n\n /** Expand glob patterns to actual file paths (useful for Drizzle Studio) */\n expandGlobs?: boolean;\n\n /** PostgreSQL schema filter for push/introspect commands */\n schemaFilter?: string[];\n\n /** Auto-detect PostgreSQL schemas from entity files (requires expandGlobs: true) */\n autoDetectSchemas?: boolean;\n}\n\n/**\n * Detect PostgreSQL schemas from entity files\n * Scans files for pgSchema('...') or createSchema('...') patterns\n *\n * @param files - Array of file paths to scan\n * @returns Array of schema names (always includes 'public')\n * @internal\n */\nfunction detectSchemasFromFiles(files: string[]): string[]\n{\n const schemas = new Set<string>(['public']);\n\n // Patterns to match:\n // - pgSchema('schema_name')\n // - pgSchema(\"schema_name\")\n // - createSchema('@scope/name') -> converted to schema name\n const pgSchemaPattern = /pgSchema\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\n const createSchemaPattern = /createSchema\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\n\n for (const filePath of files)\n {\n try\n {\n const content = readFileSync(filePath, 'utf-8');\n\n // Find pgSchema patterns\n let match;\n while ((match = pgSchemaPattern.exec(content)) !== null)\n {\n schemas.add(match[1]);\n }\n\n // Find createSchema patterns and convert to schema name\n while ((match = createSchemaPattern.exec(content)) !== null)\n {\n const packageName = match[1];\n // Convert package name to schema name (e.g., '@spfn/ai' -> 'spfn_ai')\n const schemaName = packageName\n .replace(/@/g, '')\n .replace(/\\//g, '_')\n .replace(/-/g, '_');\n schemas.add(schemaName);\n }\n }\n catch\n {\n // Skip files we can't read\n }\n }\n\n return Array.from(schemas);\n}\n\n/**\n * Expand glob patterns to actual file paths\n * Handles patterns like:\n * - ./dist/entities/*.js → [./dist/entities/foo.js, ./dist/entities/bar.js]\n * - ./dist/entities/**\\/*.js → recursively finds all .js files\n *\n * @param pattern - Glob pattern or file path\n * @returns Array of expanded file paths\n */\nfunction expandGlobPattern(pattern: string): string[]\n{\n // If pattern doesn't contain wildcards, return as-is\n if (!pattern.includes('*'))\n {\n return existsSync(pattern) ? [pattern] : [];\n }\n\n // Handle /**/* pattern (recursive)\n if (pattern.includes('**'))\n {\n const [baseDir, ...rest] = pattern.split('**');\n const extension = rest.join('').replace(/[\\/\\\\]\\*\\./g, '').trim();\n const dir = baseDir.trim() || '.';\n\n return scanDirectoryRecursive(dir, extension || undefined);\n }\n\n // Handle /* pattern (single level)\n const dir = dirname(pattern);\n const filePattern = basename(pattern);\n\n return scanDirectorySingleLevel(dir, filePattern);\n}\n\n/**\n * Discover schema paths from installed packages\n * Only scans packages that:\n * 1. Are in @spfn scope\n * 2. Are direct dependencies with \"spfn\" keyword or \"spfn\" field in package.json\n */\nfunction discoverPackageSchemas(cwd: string): string[]\n{\n const schemas: string[] = [];\n const nodeModulesPath = join(cwd, 'node_modules');\n\n if (!existsSync(nodeModulesPath))\n {\n return schemas;\n }\n\n // Get direct dependencies from project's package.json\n const projectPkgPath = join(cwd, 'package.json');\n let directDeps: Set<string> = new Set();\n\n if (existsSync(projectPkgPath))\n {\n try\n {\n const projectPkg = JSON.parse(readFileSync(projectPkgPath, 'utf-8'));\n directDeps = new Set([\n ...Object.keys(projectPkg.dependencies || {}),\n ...Object.keys(projectPkg.devDependencies || {})\n ]);\n }\n catch (error: unknown)\n {\n // If we can't read project package.json, just scan @spfn packages\n // Silent skip is intentional - we continue with @spfn package discovery\n }\n }\n\n const checkPackage = (_pkgName: string, pkgPath: string) =>\n {\n const pkgJsonPath = join(pkgPath, 'package.json');\n\n if (!existsSync(pkgJsonPath)) return;\n\n try\n {\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));\n\n // Check if package has schema declarations\n if (pkgJson.spfn?.schemas)\n {\n const packageSchemas = Array.isArray(pkgJson.spfn.schemas)\n ? pkgJson.spfn.schemas\n : [pkgJson.spfn.schemas];\n\n // Convert to absolute paths from package root and expand globs\n for (const schema of packageSchemas)\n {\n const absolutePath = join(pkgPath, schema);\n\n // Expand glob patterns to actual file lists\n // This prevents drizzle-kit from hanging on glob patterns\n const expandedFiles = expandGlobPattern(absolutePath);\n\n // Filter out index files (they are re-exports, not schema definitions)\n const schemaFiles = filterIndexFiles(expandedFiles);\n\n schemas.push(...schemaFiles);\n }\n }\n }\n catch (error: unknown)\n {\n // Skip packages with invalid package.json\n // Silent skip is intentional - we continue checking other packages\n }\n };\n\n // 1. Always scan @spfn/* packages\n const spfnDir = join(nodeModulesPath, '@spfn');\n if (existsSync(spfnDir))\n {\n try\n {\n const spfnPackages = readdirSync(spfnDir);\n for (const pkg of spfnPackages)\n {\n checkPackage(`@spfn/${pkg}`, join(spfnDir, pkg));\n }\n }\n catch (error: unknown)\n {\n // Skip if can't read @spfn directory\n // Silent skip is intentional - we continue with direct dependencies\n }\n }\n\n // 2. Check direct dependencies for SPFN integration\n for (const depName of directDeps)\n {\n // Skip if already checked (@spfn/* packages)\n if (depName.startsWith('@spfn/')) continue;\n\n // Resolve package path (handle scoped packages)\n const pkgPath = depName.startsWith('@')\n ? join(nodeModulesPath, ...depName.split('/'))\n : join(nodeModulesPath, depName);\n\n checkPackage(depName, pkgPath);\n }\n\n return schemas;\n}\n\n/**\n * Detect database dialect from connection URL\n */\nexport function detectDialect(url: string): 'postgresql' | 'mysql' | 'sqlite'\n{\n if (url.startsWith('postgres://') || url.startsWith('postgresql://'))\n {\n return 'postgresql';\n }\n\n if (url.startsWith('mysql://'))\n {\n return 'mysql';\n }\n\n if (url.startsWith('sqlite://') || url.includes('.db') || url.includes('.sqlite'))\n {\n return 'sqlite';\n }\n\n throw new Error(\n `Unsupported database URL format: ${url}. Supported: postgresql://, mysql://, sqlite://`\n );\n}\n\n/**\n * Generate Drizzle Kit configuration\n *\n * @param options - Configuration options\n * @returns Drizzle Kit configuration object\n *\n * @example\n * ```ts\n * // Zero-config (reads from process.env.DATABASE_URL)\n * const config = getDrizzleConfig();\n *\n * // Custom config\n * const config = getDrizzleConfig({\n * databaseUrl: 'postgresql://localhost/mydb',\n * schema: './src/db/schema/*.ts',\n * out: './migrations',\n * });\n * ```\n */\nexport function getDrizzleConfig(options: DrizzleConfigOptions = {})\n{\n const databaseUrl = options.databaseUrl ?? env.DATABASE_URL;\n\n if (!databaseUrl)\n {\n throw new Error(\n 'DATABASE_URL is required. Set it in .env or pass it to getDrizzleConfig()'\n );\n }\n\n const dialect = options.dialect ?? detectDialect(databaseUrl);\n const out = options.out ?? './src/server/drizzle';\n\n // If packageFilter is specified, only include that package's schemas\n if (options.packageFilter)\n {\n const packageSchemas = options.disablePackageDiscovery\n ? []\n : discoverPackageSchemas(options.cwd ?? process.cwd());\n\n // Filter to only the specified package\n const filteredSchemas = packageSchemas.filter(schemaPath =>\n schemaPath.includes(`node_modules/${options.packageFilter}/`)\n );\n\n if (filteredSchemas.length === 0)\n {\n throw new Error(\n `No schemas found for package ${options.packageFilter}. ` +\n `Make sure the package is installed and has \"spfn.schemas\" in package.json.`\n );\n }\n\n const schema = filteredSchemas.length === 1 ? filteredSchemas[0] : filteredSchemas;\n\n return {\n schema,\n out,\n dialect,\n dbCredentials: getDbCredentials(dialect, databaseUrl),\n };\n }\n\n // Default: merge user schemas and all package schemas\n const userSchema = options.schema ?? './src/server/entities/**/*.ts'; // Support nested folders\n const userSchemas = Array.isArray(userSchema) ? userSchema : [userSchema];\n\n // Discover package schemas unless disabled\n const packageSchemas = options.disablePackageDiscovery\n ? []\n : discoverPackageSchemas(options.cwd ?? process.cwd());\n\n // Merge user schemas and package schemas\n let allSchemas = [...userSchemas, ...packageSchemas];\n\n // Expand glob patterns if requested (useful for Drizzle Studio and schema detection)\n const cwd = options.cwd ?? process.cwd();\n let expandedFiles: string[] = [];\n if (options.expandGlobs)\n {\n for (const schema of allSchemas)\n {\n // Convert relative path to absolute path based on cwd\n const absoluteSchema = isAbsolutePath(schema) ? schema : join(cwd, schema);\n const expanded = expandGlobPattern(absoluteSchema);\n\n // Filter out index files (they are re-exports, not schema definitions)\n const filtered = filterIndexFiles(expanded);\n\n expandedFiles.push(...filtered);\n }\n allSchemas = expandedFiles;\n }\n\n const schema = allSchemas.length === 1 ? allSchemas[0] : allSchemas;\n\n // Determine schemaFilter for PostgreSQL\n let schemaFilter: string[] | undefined;\n if (dialect === 'postgresql')\n {\n if (options.schemaFilter)\n {\n // Use explicitly provided schemaFilter\n schemaFilter = options.schemaFilter;\n }\n else if (options.autoDetectSchemas && expandedFiles.length > 0)\n {\n // Auto-detect schemas from files (already absolute paths from expandGlobs)\n schemaFilter = detectSchemasFromFiles(expandedFiles);\n }\n }\n\n return {\n schema,\n out,\n dialect,\n dbCredentials: getDbCredentials(dialect, databaseUrl),\n schemaFilter,\n };\n}\n\n/**\n * Get database credentials based on dialect\n */\nfunction getDbCredentials(dialect: string, url: string)\n{\n switch (dialect)\n {\n case 'postgresql':\n case 'mysql':\n return { url };\n\n case 'sqlite':\n // Extract file path from sqlite:// URL\n const dbPath = url.replace('sqlite://', '').replace('sqlite:', '');\n return { url: dbPath };\n\n default:\n throw new Error(`Unsupported dialect: ${dialect}`);\n }\n}\n\n/**\n * Generate drizzle.config.ts file content\n *\n * @param options - Configuration options\n * @returns File content as string\n */\nexport function generateDrizzleConfigFile(options: DrizzleConfigOptions = {}): string\n{\n const config = getDrizzleConfig(options);\n const cwd = options.cwd ?? process.cwd();\n\n // Convert schema paths to absolute paths for Drizzle Studio compatibility\n const normalizeSchemaPath = (schemaPath: string): string =>\n {\n // If already absolute, return as-is\n if (isAbsolutePath(schemaPath))\n {\n return schemaPath;\n }\n // Convert relative to absolute\n return join(cwd, schemaPath);\n };\n\n // Format schema value (handle both string and array)\n const schemaValue = Array.isArray(config.schema)\n ? `[\\n ${config.schema.map(s => `'${normalizeSchemaPath(s)}'`).join(',\\n ')}\\n ]`\n : `'${normalizeSchemaPath(config.schema as string)}'`;\n\n // Format schemaFilter if present\n const schemaFilterLine = config.schemaFilter && config.schemaFilter.length > 0\n ? `\\n schemaFilter: ${JSON.stringify(config.schemaFilter)},`\n : '';\n\n return `import { defineConfig } from 'drizzle-kit';\n\nexport default defineConfig({\n schema: ${schemaValue},\n out: '${config.out}',\n dialect: '${config.dialect}',\n dbCredentials: ${JSON.stringify(config.dbCredentials, null, 4)},${schemaFilterLine}\n});\n`;\n}","/**\n * Schema Helper Functions\n *\n * Common field patterns for Drizzle ORM entities to reduce boilerplate.\n *\n * @example\n * ```typescript\n * import { pgTable, text } from 'drizzle-orm/pg-core';\n * import { id, timestamps } from '@spfn/core';\n *\n * export const users = pgTable('users', {\n * id: id(),\n * email: text('email').unique(),\n * ...timestamps(),\n * });\n * ```\n */\n\nimport type { PgColumn } from 'drizzle-orm/pg-core';\nimport { bigserial, timestamp, text, uuid as pgUuid, jsonb } from 'drizzle-orm/pg-core';\n\n/**\n * Standard auto-incrementing primary key\n *\n * @returns bigserial primary key column\n *\n * @example\n * ```typescript\n * export const users = pgTable('users', {\n * id: id(),\n * // ...\n * });\n * ```\n */\nexport function id()\n{\n return bigserial('id', { mode: 'number' }).primaryKey();\n}\n\n/**\n * Standard timestamp fields (createdAt, updatedAt)\n *\n * Both fields are timezone-aware, auto-set to current time on creation.\n * updatedAt must be manually updated in your application code.\n *\n * @returns Object with createdAt and updatedAt columns\n *\n * @example\n * ```typescript\n * export const users = pgTable('users', {\n * id: id(),\n * email: text('email'),\n * ...timestamps(),\n * });\n *\n * // Manual update\n * await db.update(users)\n * .set({\n * email: 'new@example.com',\n * updatedAt: new Date()\n * })\n * .where(eq(users.id, userId));\n * ```\n */\nexport function timestamps()\n{\n return {\n createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' })\n .defaultNow()\n .notNull(),\n updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' })\n .defaultNow()\n .notNull(),\n };\n}\n\n/**\n * Foreign key reference to another table\n *\n * Creates a bigserial column with cascade delete.\n * Type-safe: ensures the reference points to a valid PostgreSQL column.\n *\n * @param name - Column name (e.g., 'author' creates 'author_id')\n * @param reference - Reference to parent table column\n * @param options - Optional foreign key options\n *\n * @example\n * ```typescript\n * import { users } from './users';\n *\n * export const posts = pgTable('posts', {\n * id: id(),\n * authorId: foreignKey('author', () => users.id),\n * ...timestamps(),\n * });\n * ```\n */\nexport function foreignKey<T extends PgColumn>(\n name: string,\n reference: () => T,\n options?: { onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action' }\n)\n{\n return bigserial(`${name}_id`, { mode: 'number' })\n .notNull()\n .references(reference, { onDelete: options?.onDelete ?? 'cascade' });\n}\n\n/**\n * Optional foreign key reference (nullable)\n *\n * Type-safe: ensures the reference points to a valid PostgreSQL column.\n *\n * @param name - Column name (e.g., 'author' creates 'author_id')\n * @param reference - Reference to parent table column\n * @param options - Optional foreign key options\n *\n * @example\n * ```typescript\n * export const posts = pgTable('posts', {\n * id: id(),\n * authorId: optionalForeignKey('author', () => users.id),\n * });\n * ```\n */\nexport function optionalForeignKey<T extends PgColumn>(\n name: string,\n reference: () => T,\n options?: { onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action' }\n)\n{\n return bigserial(`${name}_id`, { mode: 'number' })\n .references(reference, { onDelete: options?.onDelete ?? 'set null' });\n}\n\n/**\n * UUID primary key\n *\n * Creates a UUID column as primary key with automatic default value generation.\n * Useful for distributed systems or when you need globally unique identifiers.\n *\n * @returns uuid primary key column with gen_random_uuid() default\n *\n * @example\n * ```typescript\n * export const sessions = pgTable('sessions', {\n * id: uuid(),\n * userId: foreignKey('user', () => users.id),\n * ...timestamps(),\n * });\n * ```\n */\nexport function uuid()\n{\n return pgUuid('id').defaultRandom().primaryKey();\n}\n\n/**\n * Audit fields for tracking record creators and updaters\n *\n * Adds createdBy and updatedBy fields for user tracking.\n * Typically stores user IDs, emails, or usernames.\n *\n * @returns Object with createdBy and updatedBy columns\n *\n * @example\n * ```typescript\n * export const posts = pgTable('posts', {\n * id: id(),\n * title: text('title'),\n * ...timestamps(),\n * ...auditFields(),\n * });\n *\n * // Usage in route\n * await db.insert(posts).values({\n * title: 'New Post',\n * createdBy: currentUser.email,\n * });\n * ```\n */\nexport function auditFields()\n{\n return {\n createdBy: text('created_by'),\n updatedBy: text('updated_by'),\n };\n}\n\n/**\n * Publishing fields for content management\n *\n * Tracks when and by whom content was published.\n * Useful for CMS, blog posts, articles, etc.\n *\n * @returns Object with publishedAt and publishedBy columns\n *\n * @example\n * ```typescript\n * export const articles = pgTable('articles', {\n * id: id(),\n * title: text('title'),\n * status: text('status'), // draft/published/archived\n * ...publishingFields(),\n * ...timestamps(),\n * });\n *\n * // Publishing an article\n * await db.update(articles)\n * .set({\n * status: 'published',\n * publishedAt: new Date(),\n * publishedBy: currentUser.email,\n * })\n * .where(eq(articles.id, articleId));\n * ```\n */\nexport function publishingFields()\n{\n return {\n publishedAt: timestamp('published_at', { withTimezone: true, mode: 'date' }),\n publishedBy: text('published_by'),\n };\n}\n\n/**\n * Custom verification timestamp field\n *\n * Creates a nullable timestamp field for tracking verification status.\n * Useful for email verification, phone verification, etc.\n *\n * @param fieldName - Field name in camelCase (e.g., 'emailVerified', 'phoneVerified')\n * @returns Object with verification timestamp column (converts to snake_case + '_at')\n *\n * @example\n * ```typescript\n * export const users = pgTable('users', {\n * id: id(),\n * email: text('email'),\n * phone: text('phone'),\n * ...verificationTimestamp('emailVerified'), // emailVerifiedAt -> email_verified_at\n * ...verificationTimestamp('phoneVerified'), // phoneVerifiedAt -> phone_verified_at\n * ...timestamps(),\n * });\n *\n * // Verify email\n * await db.update(users)\n * .set({ emailVerifiedAt: new Date() })\n * .where(eq(users.email, userEmail));\n * ```\n */\nexport function verificationTimestamp(fieldName: string)\n{\n // Convert camelCase to snake_case and add '_at' suffix\n const columnName = fieldName\n .replace(/([A-Z])/g, '_$1')\n .toLowerCase()\n .replace(/^_/, '') + '_at';\n\n return {\n [fieldName + 'At']: timestamp(columnName, { withTimezone: true, mode: 'date' }),\n };\n}\n\n/**\n * Soft delete fields\n *\n * Adds deletedAt and deletedBy for logical deletion.\n * Records are marked as deleted instead of being physically removed.\n *\n * @returns Object with deletedAt and deletedBy columns\n *\n * @example\n * ```typescript\n * export const posts = pgTable('posts', {\n * id: id(),\n * title: text('title'),\n * ...timestamps(),\n * ...softDelete(),\n * });\n *\n * // Soft delete\n * await db.update(posts)\n * .set({\n * deletedAt: new Date(),\n * deletedBy: currentUser.email,\n * })\n * .where(eq(posts.id, postId));\n *\n * // Query only non-deleted records\n * const activePosts = await db.select()\n * .from(posts)\n * .where(isNull(posts.deletedAt));\n * ```\n */\nexport function softDelete()\n{\n return {\n deletedAt: timestamp('deleted_at', { withTimezone: true, mode: 'date' }),\n deletedBy: text('deleted_by'),\n };\n}\n\n/**\n * UTC timestamp field\n *\n * Creates a timezone-aware timestamp column (TIMESTAMPTZ) that stores values in UTC.\n * PostgreSQL automatically converts between client timezone and UTC.\n * Chain with .notNull(), .defaultNow(), etc. for additional constraints.\n *\n * @param fieldName - Database column name (in snake_case)\n * @param mode - Data type mode: 'date' (Date object) or 'string' (ISO string)\n * @returns Timestamp column with timezone support\n *\n * @example\n * ```typescript\n * export const users = pgTable('users', {\n * id: id(),\n * email: text('email'),\n *\n * // Nullable timestamp\n * emailVerifiedAt: utcTimestamp('email_verified_at'),\n *\n * // Required with default\n * lastLoginAt: utcTimestamp('last_login_at').defaultNow().notNull(),\n *\n * // String mode\n * processedAt: utcTimestamp('processed_at', 'string'),\n *\n * ...timestamps(),\n * });\n * ```\n */\nexport function utcTimestamp(\n fieldName: string,\n mode: 'date' | 'string' = 'date'\n) {\n return timestamp(fieldName, {\n withTimezone: true,\n mode\n });\n}\n\n/**\n * Type-safe enum text field\n *\n * Creates a text column with enum constraint.\n * Chain with .notNull(), .default(), etc. for additional constraints.\n *\n * @param fieldName - Database column name (e.g., 'status', 'role', 'provider')\n * @param values - Const array of allowed values\n * @returns Text column with enum constraint\n *\n * @example\n * ```typescript\n * export const USER_STATUSES = ['active', 'inactive', 'suspended'] as const;\n * export type UserStatus = typeof USER_STATUSES[number];\n *\n * export const SOCIAL_PROVIDERS = ['google', 'github', 'kakao'] as const;\n * export type SocialProvider = typeof SOCIAL_PROVIDERS[number];\n *\n * export const users = pgTable('users', {\n * id: id(),\n * // Nullable\n * role: enumText('role', USER_STATUSES),\n *\n * // Required\n * provider: enumText('provider', SOCIAL_PROVIDERS).notNull(),\n *\n * // Required with default\n * status: enumText('status', USER_STATUSES).default('active').notNull(),\n *\n * ...timestamps(),\n * });\n * ```\n */\nexport function enumText<T extends readonly [string, ...string[]]>(\n fieldName: string,\n values: T\n)\n{\n // readonly를 제거하되 타입 정보는 유지\n return text(fieldName, { enum: values as T & [string, ...string[]] });\n}\n\n/**\n * Type-safe JSONB field\n *\n * Creates a JSONB column with required type parameter to ensure type safety.\n * Prevents the common mistake of using jsonb without type annotation,\n * which would result in `unknown` type and require type assertions.\n *\n * Chain with .notNull(), .default(), etc. for additional constraints.\n *\n * @param fieldName - Database column name (in snake_case)\n * @returns JSONB column with specified type\n *\n * @example\n * ```typescript\n * // Define your types\n * type LabelValue =\n * | { type: 'text'; content: string }\n * | { type: 'image'; url: string; alt?: string };\n *\n * type CachedContent = Record<string, LabelValue>;\n *\n * export const cmsPublishedCache = pgTable('published_cache', {\n * id: id(),\n * section: text('section').notNull(),\n *\n * // Type-safe JSONB field - no more `as any` needed!\n * content: typedJsonb<CachedContent>('content').notNull(),\n *\n * ...timestamps(),\n * });\n *\n * // Usage in route - no type assertion needed\n * const cache = await db.select().from(cmsPublishedCache)...;\n * const labels = cache.content; // Type: CachedContent ✅\n *\n * // For simple objects\n * metadata: typedJsonb<Record<string, any>>('metadata'),\n *\n * // For arrays\n * tags: typedJsonb<string[]>('tags').notNull(),\n * ```\n */\nexport function typedJsonb<T>(fieldName: string)\n{\n return jsonb(fieldName).$type<T>();\n}\n","/**\n * Database Schema Helper\n *\n * Provides utilities for creating isolated PostgreSQL schemas for SPFN functions\n */\n\nimport { pgSchema } from 'drizzle-orm/pg-core';\n\n/**\n * Create a namespaced PostgreSQL schema for a function\n *\n * @param packageName - NPM package name (e.g., '@spfn/cms', 'spfn-auth')\n * @returns PostgreSQL schema object for creating tables\n *\n * @example\n * ```typescript\n * // @spfn/cms → spfn_cms schema\n * import { createSchema } from '@spfn/core/db';\n *\n * const schema = createSchema('@spfn/cms');\n *\n * export const labels = schema.table('labels', {\n * id: id(),\n * name: text('name').notNull(),\n * });\n * // Creates table: spfn_cms.labels\n * ```\n */\nexport function createSchema(packageName: string)\n{\n const schemaName = packageNameToSchema(packageName);\n return pgSchema(schemaName);\n}\n\n/**\n * Convert package name to PostgreSQL schema name\n *\n * @param packageName - NPM package name\n * @returns Schema name in PostgreSQL format\n *\n * @example\n * ```typescript\n * packageNameToSchema('@spfn/cms') // 'spfn_cms'\n * packageNameToSchema('@company/spfn-auth') // 'company_spfn_auth'\n * packageNameToSchema('spfn-storage') // 'spfn_storage'\n * ```\n */\nexport function packageNameToSchema(packageName: string): string\n{\n // Remove @ and replace / and - with _\n return packageName\n .replace(/@/g, '')\n .replace(/\\//g, '_')\n .replace(/-/g, '_');\n}\n\n/**\n * Get recommended schema name for a package\n *\n * @param packageName - NPM package name\n * @returns Object with schema name and whether it's scoped\n *\n * @example\n * ```typescript\n * getSchemaInfo('@spfn/cms')\n * // { schemaName: 'spfn_cms', isScoped: true, scope: 'spfn' }\n *\n * getSchemaInfo('spfn-auth')\n * // { schemaName: 'spfn_auth', isScoped: false, scope: null }\n * ```\n */\nexport function getSchemaInfo(packageName: string)\n{\n const isScoped = packageName.startsWith('@');\n const scope = isScoped ? packageName.split('/')[0].substring(1) : null;\n const schemaName = packageNameToSchema(packageName);\n\n return {\n schemaName,\n isScoped,\n scope,\n };\n}","/**\n * AsyncLocalStorage-based Transaction Context\n *\n * Uses Node.js AsyncLocalStorage to propagate transactions throughout the async call chain.\n *\n * Features:\n * - AsyncLocalStorage-based context management\n * - Type-safe transaction propagation across async chains\n * - Transaction ID tracking for debugging and tracing\n * - Nested transaction detection and logging\n * - Transaction nesting level tracking\n */\nimport { AsyncLocalStorage } from 'async_hooks';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport { logger } from '@spfn/core/logger'; // Assuming logger is accessible\n\n/**\n * Transaction database type\n * Uses Record<string, unknown> to accept any schema shape\n */\nexport type TransactionDB = PostgresJsDatabase<Record<string, unknown>>;\n\nconst txLogger = logger.child('@spfn/core:transaction');\n\n/**\n * Transaction context stored in AsyncLocalStorage\n */\nexport type TransactionContext = {\n /** The actual Drizzle transaction object */\n tx: TransactionDB;\n /** Unique transaction ID for logging and tracing */\n txId: string; // Add txId to the context\n level: number;\n};\n\n/**\n * Global AsyncLocalStorage instance for transaction context\n */\nexport const asyncContext = new AsyncLocalStorage<TransactionContext>();\n\n/**\n * Get current transaction object and metadata from AsyncLocalStorage\n *\n * @returns TransactionContext if available, null otherwise\n */\nexport function getTransactionContext(): TransactionContext | null\n{\n return asyncContext.getStore() ?? null;\n}\n\n/**\n * Get current transaction from AsyncLocalStorage\n *\n * @returns Transaction if available, null otherwise\n */\nexport function getTransaction(): TransactionDB | null\n{\n const context = getTransactionContext();\n return context?.tx ?? null;\n}\n\n/**\n * Get current transaction ID from AsyncLocalStorage\n *\n * @returns Transaction ID if available, null otherwise\n */\nexport function getTransactionId(): string | null\n{\n const context = getTransactionContext();\n return context?.txId ?? null;\n}\n\n/**\n * Run a function within a transaction context\n *\n * The transaction will be available to all async operations within the callback\n * via getTransaction().\n *\n * @param tx - Drizzle transaction object\n * @param txId - Unique ID for the transaction\n * @param callback - Function to run within transaction context\n * @returns Result of the callback\n */\nexport function runWithTransaction<T>(\n tx: TransactionDB,\n txId: string, // Add txId parameter\n callback: () => Promise<T>\n): Promise<T>\n{\n const existingContext = getTransactionContext();\n\n // Determine the current transaction nesting level\n const newLevel = existingContext ? existingContext.level + 1 : 1;\n\n if (existingContext)\n {\n // Nested transaction detected. This means Drizzle will use a SAVEPOINT.\n txLogger.info('Nested transaction started (SAVEPOINT)', {\n outerTxId: existingContext.txId,\n innerTxId: txId,\n level: newLevel,\n });\n }\n else\n {\n // Root transaction\n txLogger.debug('Root transaction context set', { txId, level: newLevel });\n }\n\n // Store transaction, new ID, and the current nesting level\n return asyncContext.run({ tx, txId, level: newLevel }, callback);\n}","/**\n * Transaction Runner\n *\n * Standalone transaction execution utility for scripts, migrations, and CLI commands.\n * Provides the same transaction management capabilities as the Transactional middleware\n * but without Hono dependency.\n *\n * Features:\n * - Automatic transaction management (start/commit/rollback)\n * - Transaction propagation via AsyncLocalStorage\n * - PostgreSQL-level timeout with automatic rollback guarantee\n * - Execution time tracking and slow transaction warnings\n * - UUID-based transaction IDs for debugging\n *\n * Timeout Implementation:\n * Uses PostgreSQL `SET LOCAL statement_timeout` to ensure database-level timeout\n * enforcement. This guarantees that long-running transactions are actually rolled\n * back at the database level, preventing data inconsistency.\n *\n * @example\n * ```typescript\n * import { runInTransaction } from '@spfn/core/db/transaction';\n * import { users } from './schema';\n *\n * // Simple usage\n * const user = await runInTransaction(async (tx) => {\n * const [user] = await tx.insert(users).values({ name: 'John' }).returning();\n * return user;\n * });\n *\n * // With options\n * await runInTransaction(\n * async (tx) => {\n * await tx.insert(users).values({ name: 'Jane' });\n * await tx.insert(profiles).values({ userId: 1 });\n * },\n * {\n * context: 'migration:add-user',\n * timeout: 60000,\n * slowThreshold: 2000,\n * }\n * );\n * ```\n */\nimport { randomUUID } from 'crypto';\nimport { sql } from 'drizzle-orm';\nimport { logger } from '@spfn/core/logger';\nimport { getDatabase } from '../manager';\nimport { runWithTransaction, getTransactionContext, type TransactionDB } from './context';\nimport { TransactionError } from '@spfn/core/errors';\nimport { env } from '@spfn/core/config';\n\n/**\n * PostgreSQL maximum timeout value (max int4)\n */\nconst MAX_TIMEOUT_MS = 2147483647;\nconst txLogger = logger.child('@spfn/core:transaction');\n\n/**\n * Transaction runner options\n */\nexport interface RunInTransactionOptions\n{\n /**\n * Slow transaction warning threshold in milliseconds\n * @default 1000 (1 second)\n */\n slowThreshold?: number;\n\n /**\n * Enable transaction logging\n * @default true\n */\n enableLogging?: boolean;\n\n /**\n * Transaction timeout in milliseconds\n *\n * Sets PostgreSQL `statement_timeout` to enforce database-level timeout.\n * If transaction exceeds this duration, PostgreSQL will automatically cancel\n * the query and rollback the transaction, ensuring data consistency.\n *\n * Behavior:\n * - `timeout: 0` - Disables timeout (unlimited execution time)\n * - `timeout: null` - Uses default (30s or TRANSACTION_TIMEOUT env var)\n * - `timeout: undefined` - Uses default (30s or TRANSACTION_TIMEOUT env var)\n * - `timeout: N` - Sets timeout to N milliseconds (1 to 2147483647)\n *\n * Note: Timeout is only applied to root transactions. Nested transactions\n * (SAVEPOINTs) inherit the timeout from the outer transaction.\n *\n * @default 30000 (30 seconds) or TRANSACTION_TIMEOUT environment variable\n *\n * @example\n * ```typescript\n * // Use default timeout (30s)\n * await runInTransaction(callback);\n *\n * // Disable timeout for long-running operations\n * await runInTransaction(callback, { timeout: 0 });\n *\n * // Set custom timeout (60s)\n * await runInTransaction(callback, { timeout: 60000 });\n * ```\n */\n timeout?: number;\n\n /**\n * Context string for logging (e.g., 'migration:add-user', 'script:cleanup')\n * @default 'transaction'\n */\n context?: string;\n}\n\n/**\n * Run a callback function within a database transaction\n *\n * Automatically manages transaction lifecycle:\n * - Commits on success\n * - Rolls back on error\n * - Tracks execution time\n * - Warns about slow transactions\n * - Enforces timeout if configured\n *\n * Errors are propagated to the caller without modification.\n * Caller is responsible for error handling and conversion.\n *\n * @param callback - Function to execute within transaction\n * @param options - Transaction options\n * @returns Result of callback function\n * @throws TransactionError if database not initialized or timeout exceeded\n * @throws Any error thrown by callback function\n */\nexport async function runInTransaction<T>(\n callback: (tx: TransactionDB) => Promise<T>,\n options: RunInTransactionOptions = {}\n): Promise<T>\n{\n // Get default timeout from environment variable (default: 30 seconds)\n const defaultTimeout = env.TRANSACTION_TIMEOUT;\n\n const {\n slowThreshold = 1000,\n enableLogging = true,\n context = 'transaction',\n } = options;\n\n // Handle timeout: null/undefined → default, 0 → disabled, N → N milliseconds\n const timeout = options.timeout ?? defaultTimeout;\n\n // Generate transaction ID for debugging\n const txId = `tx_${randomUUID()}`;\n\n /**\n * Helper function to validate parameters and throw TransactionError\n */\n const validateAndThrow = (\n condition: boolean,\n message: string,\n logMessage: string,\n metadata: Record<string, unknown>\n ): void =>\n {\n if (condition)\n {\n const error = new TransactionError({ message, statusCode: 400, details: metadata });\n\n if (enableLogging)\n {\n txLogger.error(logMessage, { ...metadata, error: error.message });\n }\n\n throw error;\n }\n };\n\n // Validate all input parameters before DB access (fail-fast pattern)\n\n // Validate callback is a function\n validateAndThrow(\n typeof callback !== 'function',\n 'Callback must be a function',\n 'Invalid callback type',\n { txId, context, callbackType: typeof callback }\n );\n\n // Validate slowThreshold\n validateAndThrow(\n !Number.isInteger(slowThreshold) || slowThreshold < 0,\n `Invalid slowThreshold value: ${slowThreshold}. Must be a non-negative integer.`,\n 'Invalid slowThreshold',\n { txId, context, slowThreshold }\n );\n\n // Validate timeout value for SQL safety\n validateAndThrow(\n !Number.isInteger(timeout),\n `Invalid timeout value: ${timeout}. Must be an integer.`,\n 'Invalid timeout type',\n { txId, context, timeout }\n );\n\n validateAndThrow(\n timeout < 0,\n `Invalid timeout value: ${timeout}. Timeout must be non-negative (0 to disable, or 1-${MAX_TIMEOUT_MS}ms).`,\n 'Invalid timeout range',\n { txId, context, timeout }\n );\n\n validateAndThrow(\n timeout > MAX_TIMEOUT_MS,\n `Invalid timeout value: ${timeout}. Maximum timeout is ${MAX_TIMEOUT_MS}ms.`,\n 'Timeout exceeds maximum',\n { txId, context, timeout, maxTimeout: MAX_TIMEOUT_MS }\n );\n\n // Get write database instance (after all input validations)\n const writeDb = getDatabase('write');\n if (!writeDb)\n {\n const error = new TransactionError({\n message: 'Database not initialized. Cannot start transaction.',\n statusCode: 500,\n details: { txId, context }\n });\n\n if (enableLogging)\n {\n txLogger.error('Database not initialized', {\n txId,\n context,\n error: error.message,\n });\n }\n\n throw error;\n }\n\n // Check if we're in a nested transaction\n const existingContext = getTransactionContext();\n const isNested = existingContext !== null;\n\n // Warn about nested transaction timeout\n if (isNested && timeout > 0 && enableLogging)\n {\n txLogger.warn('Timeout ignored in nested transaction', {\n txId,\n context,\n outerTxId: existingContext.txId,\n requestedTimeout: `${timeout}ms`,\n reason: 'SET LOCAL statement_timeout affects the entire outer transaction',\n });\n }\n\n // Log transaction start AFTER all validations pass\n if (enableLogging)\n {\n txLogger.debug('Transaction started', { txId, context });\n }\n\n // Start timing from actual transaction execution\n const startTime = Date.now();\n\n // Execute transaction within try-catch to capture all errors\n try\n {\n // Execute transaction with PostgreSQL-level timeout\n const result = await writeDb.transaction(async (tx: TransactionDB) =>\n {\n // Set PostgreSQL statement timeout only for root transactions\n // Nested transactions (SAVEPOINTs) would affect the entire outer transaction\n if (timeout > 0 && !isNested)\n {\n // Using sql.raw() because SET commands don't support parameter binding\n await tx.execute(sql.raw(`SET LOCAL statement_timeout = ${timeout}`));\n }\n\n // Store transaction in AsyncLocalStorage\n return await runWithTransaction(tx, txId, async () =>\n {\n // Execute callback\n return await callback(tx);\n });\n });\n\n // Transaction successful (committed)\n const duration = Date.now() - startTime;\n\n if (enableLogging)\n {\n if (duration >= slowThreshold)\n {\n txLogger.warn('Slow transaction committed', {\n txId,\n context,\n duration: `${duration}ms`,\n threshold: `${slowThreshold}ms`,\n });\n }\n else\n {\n txLogger.debug('Transaction committed', {\n txId,\n context,\n duration: `${duration}ms`,\n });\n }\n }\n\n return result;\n }\n catch (error)\n {\n // Transaction failed (rolled back)\n const duration = Date.now() - startTime;\n\n if (enableLogging)\n {\n if (duration >= slowThreshold)\n {\n txLogger.warn('Slow transaction rolled back', {\n txId,\n context,\n duration: `${duration}ms`,\n threshold: `${slowThreshold}ms`,\n error: error instanceof Error ? error.message : String(error),\n errorType: error instanceof Error ? error.name : 'Unknown',\n });\n }\n else\n {\n txLogger.error('Transaction rolled back', {\n txId,\n context,\n duration: `${duration}ms`,\n error: error instanceof Error ? error.message : String(error),\n errorType: error instanceof Error ? error.name : 'Unknown',\n });\n }\n }\n\n // Re-throw error for caller to handle\n throw error;\n }\n}","/**\n * Transactional Middleware\n *\n * Wraps route handlers in a database transaction.\n * Auto-commits on success, auto-rolls back on error.\n *\n * Features:\n * - Automatic transaction management (start/commit/rollback)\n * - Transaction propagation via AsyncLocalStorage\n * - Nested transaction detection and logging\n * - Hono Context error detection\n * - Transaction timeout with configurable threshold\n * - Execution time tracking and slow transaction warnings\n * - UUID-based transaction IDs for debugging\n * - PostgreSQL error conversion to custom errors\n */\nimport { createMiddleware } from 'hono/factory';\nimport { TransactionError, DatabaseError } from '@spfn/core/errors';\nimport { fromPostgresError } from '../postgres-errors';\nimport { runInTransaction } from './runner';\n\n/**\n * Transaction middleware options\n */\nexport interface TransactionalOptions\n{\n /**\n * Slow transaction warning threshold in milliseconds\n * @default 1000 (1 second)\n */\n slowThreshold?: number;\n\n /**\n * Enable transaction logging\n * @default true\n */\n enableLogging?: boolean;\n\n /**\n * Transaction timeout in milliseconds\n *\n * If transaction exceeds this duration, it will be aborted with TransactionError.\n *\n * @default 30000 (30 seconds) or TRANSACTION_TIMEOUT environment variable\n *\n * @example\n * ```typescript\n * // Default timeout (30s or TRANSACTION_TIMEOUT env var)\n * Transactional()\n *\n * // Custom timeout for specific route (60s)\n * Transactional({ timeout: 60000 })\n *\n * // Disable timeout\n * Transactional({ timeout: 0 })\n * ```\n */\n timeout?: number;\n}\n\n/**\n * Transaction middleware for Hono routes\n *\n * Automatically wraps route handlers in a database transaction.\n * Commits on success, rolls back on error.\n *\n * @example\n * ```typescript\n * // In your route file\n * export const middlewares = [Transactional()];\n *\n * export async function POST(c: RouteContext) {\n * // All DB operations run in a transaction\n * const [user] = await db.insert(users).values(body).returning();\n * await db.insert(profiles).values({ userId: user.id });\n * // Auto-commits on success\n * return c.json(user, 201);\n * }\n * ```\n *\n * @example\n * ```typescript\n * // With custom options\n * export const middlewares = [\n * Transactional({\n * slowThreshold: 2000, // Warn if transaction takes > 2s\n * enableLogging: false, // Disable logging\n * timeout: 60000, // 60 second timeout for long operations\n * })\n * ];\n * ```\n *\n * 🔄 Transaction behavior:\n * - Success: Auto-commit\n * - Error: Auto-rollback\n * - Detects context.error to trigger rollback\n *\n * 📊 Transaction logging:\n * - Auto-logs transaction start/commit/rollback\n * - Measures and records execution time\n * - Warns about slow transactions (default: > 1s)\n */\nexport function Transactional(options: TransactionalOptions = {})\n{\n return createMiddleware(async (c, next) =>\n {\n const route = `${c.req.method} ${c.req.path}`;\n\n try\n {\n // Run route handler within transaction\n await runInTransaction(\n async () =>\n {\n // Execute handler\n await next();\n\n // Detect if Hono caught an error and stored it in context.error\n // Context type doesn't officially define error property, so we extend it\n type ContextWithError = typeof c & { error?: Error };\n const contextWithError = c as ContextWithError;\n if (contextWithError.error)\n {\n // Throw to rollback transaction\n throw contextWithError.error;\n }\n },\n {\n context: route,\n ...options,\n }\n );\n }\n catch (error)\n {\n // DatabaseError 계열 (비즈니스 로직 에러)는 그대로 throw\n if (error instanceof DatabaseError)\n {\n throw error;\n }\n\n // TransactionError는 그대로 throw\n if (error instanceof TransactionError)\n {\n throw error;\n }\n\n // PostgreSQL 에러 코드가 있으면 변환\n if (error && typeof error === 'object' && 'code' in error && typeof error.code === 'string')\n {\n throw fromPostgresError(error);\n }\n\n // 그 외 모든 에러는 그대로 throw (InvalidCredentialsError 등 비즈니스 로직 에러)\n throw error;\n }\n });\n}","/**\n * Query Utility Functions\n *\n * Common utilities for building database queries.\n * Used by both helpers.ts and repository.ts to avoid code duplication.\n *\n * @internal\n */\n\nimport type { SQL } from 'drizzle-orm';\nimport { eq, and } from 'drizzle-orm';\nimport type { PgTable } from 'drizzle-orm/pg-core';\n\n/**\n * Check if value is a Drizzle SQL wrapper\n *\n * @param value - Value to check\n * @returns true if value is a SQL wrapper\n *\n * @internal\n */\nexport function isSQLWrapper(value: unknown): value is SQL\n{\n return value !== null &&\n typeof value === 'object' &&\n 'queryChunks' in value;\n}\n\n/**\n * Build SQL WHERE clause from plain object\n *\n * Converts an object like `{ id: 1, name: 'test' }` into\n * SQL condition `id = 1 AND name = 'test'`.\n *\n * @param table - Drizzle table schema\n * @param where - Object with column-value pairs\n * @returns SQL condition or undefined if no valid conditions\n *\n * @internal\n */\nexport function buildWhereFromObject<T extends PgTable>(\n table: T,\n where: Record<string, unknown>\n): SQL | undefined\n{\n const entries = Object.entries(where).filter(([_, value]) => value !== undefined);\n\n if (entries.length === 0)\n {\n return undefined;\n }\n\n const conditions = entries.map(([key, value]) =>\n eq((table as any)[key], value)\n );\n\n return conditions.length === 1 ? conditions[0] : and(...conditions);\n}\n","/**\n * Database Helper Functions\n *\n * Type-safe helper functions for common database operations.\n * Automatically handles:\n * - Transaction context detection\n * - Read/Write database separation\n * - Type inference from table schema\n *\n * @example\n * ```typescript\n * // Simple object-based where\n * const user = await findOne(users, { id: 1 });\n * const labels = await findMany(cmsLabels, { section: 'hero' });\n *\n * // Complex SQL-based where\n * const user = await findOne(users, and(eq(users.id, 1), gt(users.age, 18)));\n * const labels = await findMany(cmsLabels, {\n * where: or(like(cmsLabels.key, 'hero.%'), eq(cmsLabels.section, 'footer')),\n * limit: 10\n * });\n * ```\n */\n\nimport type { SQL } from 'drizzle-orm';\nimport { count as sqlCount } from 'drizzle-orm';\nimport type { PgTable, PgColumn } from 'drizzle-orm/pg-core';\nimport { getDatabase } from './manager';\nimport { isSQLWrapper, buildWhereFromObject } from './query-utils';\n\n/**\n * Infer SELECT model from PgTable\n */\ntype InferSelectModel<T extends PgTable> = T['$inferSelect'];\n\n/**\n * Infer INSERT model from PgTable\n */\ntype InferInsertModel<T extends PgTable> = T['$inferInsert'];\n\n/**\n * Object-based where condition (AND only, equality only)\n */\ntype WhereObject<T> = {\n [K in keyof T]?: T[K];\n};\n\n/**\n * Find a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Single record or null\n *\n * @example\n * ```typescript\n * // Object-based\n * const user = await findOne(users, { id: 1 });\n * const label = await findOne(cmsLabels, { key: 'hero.title', section: 'hero' });\n *\n * // SQL-based\n * const user = await findOne(users, and(eq(users.id, 1), gt(users.age, 18)));\n * ```\n */\nexport async function findOne<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>>\n): Promise<InferSelectModel<T> | null>;\n\nexport async function findOne<T extends PgTable>(\n table: T,\n where: SQL | undefined\n): Promise<InferSelectModel<T> | null>;\n\nexport async function findOne<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>> | SQL | undefined\n): Promise<InferSelectModel<T> | null>\n{\n const db = getDatabase('read');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('findOne requires at least one where condition');\n }\n\n const results = await db.select().from(table as PgTable).where(whereClause).limit(1);\n return (results[0] as InferSelectModel<T>) ?? null;\n}\n\n/**\n * Find multiple records\n *\n * @param table - Drizzle table schema\n * @param options - Query options (where, orderBy, limit, offset)\n * @returns Array of records\n *\n * @example\n * ```typescript\n * // Simple object where\n * const labels = await findMany(cmsLabels, { section: 'hero' });\n *\n * // With options\n * const labels = await findMany(cmsLabels, {\n * where: { section: 'hero' },\n * orderBy: desc(cmsLabels.updatedAt),\n * limit: 10,\n * offset: 0\n * });\n *\n * // Complex SQL where\n * const labels = await findMany(cmsLabels, {\n * where: and(\n * like(cmsLabels.key, 'hero.%'),\n * eq(cmsLabels.section, 'hero')\n * ),\n * limit: 10\n * });\n * ```\n */\nexport async function findMany<T extends PgTable>(\n table: T,\n options?: {\n where?: WhereObject<InferSelectModel<T>> | SQL | undefined;\n orderBy?: SQL | SQL[];\n limit?: number;\n offset?: number;\n }\n): Promise<InferSelectModel<T>[]>\n{\n const db = getDatabase('read');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n let query = db.select().from(table as PgTable);\n\n // Apply where\n if (options?.where)\n {\n const whereClause = isSQLWrapper(options.where)\n ? options.where\n : options.where ? buildWhereFromObject(table, options.where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (whereClause)\n {\n query = query.where(whereClause) as any;\n }\n }\n\n // Apply orderBy\n if (options?.orderBy)\n {\n const orderByArray = Array.isArray(options.orderBy) ? options.orderBy : [options.orderBy];\n query = query.orderBy(...orderByArray) as any;\n }\n\n // Apply limit\n if (options?.limit)\n {\n query = query.limit(options.limit) as any;\n }\n\n // Apply offset\n if (options?.offset)\n {\n query = query.offset(options.offset) as any;\n }\n\n return query as Promise<InferSelectModel<T>[]>;\n}\n\n/**\n * Create a new record\n *\n * @param table - Drizzle table schema\n * @param data - Insert data\n * @returns Created record\n *\n * @example\n * ```typescript\n * const user = await create(users, {\n * email: 'test@example.com',\n * name: 'Test User'\n * });\n * ```\n */\nexport async function create<T extends PgTable>(\n table: T,\n data: InferInsertModel<T>\n): Promise<InferSelectModel<T>>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const [result] = await db.insert(table).values(data).returning();\n return result as InferSelectModel<T>;\n}\n\n/**\n * Create multiple records\n *\n * @param table - Drizzle table schema\n * @param data - Array of insert data\n * @returns Array of created records\n *\n * @example\n * ```typescript\n * const users = await createMany(users, [\n * { email: 'user1@example.com', name: 'User 1' },\n * { email: 'user2@example.com', name: 'User 2' }\n * ]);\n * ```\n */\nexport async function createMany<T extends PgTable>(\n table: T,\n data: InferInsertModel<T>[]\n): Promise<InferSelectModel<T>[]>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const results = await db.insert(table).values(data).returning();\n return results as InferSelectModel<T>[];\n}\n\n/**\n * Upsert a record (INSERT or UPDATE on conflict)\n *\n * @param table - Drizzle table schema\n * @param data - Insert data\n * @param options - Conflict resolution options\n * @returns Upserted record\n *\n * @example\n * ```typescript\n * // Basic upsert\n * const cache = await upsert(cmsPublishedCache, {\n * section: 'home',\n * locale: 'ko',\n * content: {...}\n * }, {\n * target: [cmsPublishedCache.section, cmsPublishedCache.locale],\n * set: {\n * content: data.content,\n * updatedAt: new Date()\n * }\n * });\n *\n * // With SQL expression\n * const cache = await upsert(cmsPublishedCache, data, {\n * target: [cmsPublishedCache.section, cmsPublishedCache.locale],\n * set: {\n * content: data.content,\n * version: sql`${cmsPublishedCache.version} + 1`\n * }\n * });\n * ```\n */\nexport async function upsert<T extends PgTable>(\n table: T,\n data: InferInsertModel<T>,\n options: {\n target: PgColumn[];\n set?: Partial<InferInsertModel<T>> | Record<string, SQL | any>;\n }\n): Promise<InferSelectModel<T>>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const [result] = await db\n .insert(table)\n .values(data)\n .onConflictDoUpdate({\n target: options.target,\n set: options.set || data,\n })\n .returning();\n\n return result as InferSelectModel<T>;\n}\n\n/**\n * Update a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @param data - Update data\n * @returns Updated record or null\n *\n * @example\n * ```typescript\n * // Object-based where\n * const user = await updateOne(users, { id: 1 }, { name: 'Updated Name' });\n *\n * // SQL-based where\n * const user = await updateOne(users, eq(users.id, 1), { name: 'Updated Name' });\n * ```\n */\nexport async function updateOne<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>> | SQL | undefined,\n data: Partial<InferInsertModel<T>>\n): Promise<InferSelectModel<T> | null>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('updateOne requires at least one where condition');\n }\n\n const [result] = await db.update(table).set(data).where(whereClause).returning();\n return (result as InferSelectModel<T>) ?? null;\n}\n\n/**\n * Update multiple records\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @param data - Update data\n * @returns Array of updated records\n *\n * @example\n * ```typescript\n * const users = await updateMany(users,\n * { role: 'user' },\n * { verified: true }\n * );\n * ```\n */\nexport async function updateMany<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>> | SQL | undefined,\n data: Partial<InferInsertModel<T>>\n): Promise<InferSelectModel<T>[]>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('updateMany requires at least one where condition');\n }\n\n const results = await db.update(table).set(data).where(whereClause).returning();\n return results as InferSelectModel<T>[];\n}\n\n/**\n * Delete a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Deleted record or null\n *\n * @example\n * ```typescript\n * // Object-based where\n * const user = await deleteOne(users, { id: 1 });\n *\n * // SQL-based where\n * const user = await deleteOne(users, eq(users.id, 1));\n * ```\n */\nexport async function deleteOne<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>> | SQL | undefined\n): Promise<InferSelectModel<T> | null>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('deleteOne requires at least one where condition');\n }\n\n const [result] = await db.delete(table).where(whereClause).returning();\n return (result as InferSelectModel<T>) ?? null;\n}\n\n/**\n * Delete multiple records\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Array of deleted records\n *\n * @example\n * ```typescript\n * const users = await deleteMany(users, { verified: false });\n * ```\n */\nexport async function deleteMany<T extends PgTable>(\n table: T,\n where: WhereObject<InferSelectModel<T>> | SQL | undefined\n): Promise<InferSelectModel<T>[]>\n{\n const db = getDatabase('write');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('deleteMany requires at least one where condition');\n }\n\n const results = await db.delete(table).where(whereClause).returning();\n return results as InferSelectModel<T>[];\n}\n\n/**\n * Count records\n *\n * @param table - Drizzle table schema\n * @param where - Optional object or SQL condition\n * @returns Number of records\n *\n * @example\n * ```typescript\n * const total = await count(users);\n * const activeUsers = await count(users, { active: true });\n * const adults = await count(users, gt(users.age, 18));\n * ```\n */\nexport async function count<T extends PgTable>(\n table: T,\n where?: WhereObject<InferSelectModel<T>> | SQL | undefined\n): Promise<number>\n{\n const db = getDatabase('read');\n if (!db)\n {\n throw new Error('Database not initialized. Call initDatabase() first.');\n }\n\n let query = db.select({ count: sqlCount() }).from(table as PgTable);\n\n if (where)\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as WhereObject<InferSelectModel<T>>) : undefined;\n\n if (whereClause)\n {\n query = query.where(whereClause) as any;\n }\n }\n\n const [result] = await query;\n return Number(result?.count ?? 0);\n}\n","/**\n * Base Repository Pattern\n *\n * Provides automatic database instance management with transaction context support.\n * Eliminates the need for manual `getDatabaseOrThrow()` calls in repository classes.\n *\n * Features:\n * - Automatic transaction context detection and usage\n * - Read/Write connection separation (with replica support)\n * - Type-safe schema generics\n * - Consistent database access pattern across all repositories\n * - Enhanced error tracking with repository context\n *\n * @example Basic Repository\n * ```typescript\n * import { BaseRepository } from '@spfn/core/db';\n * import { users } from './schema';\n * import { eq } from 'drizzle-orm';\n *\n * export class UserRepository extends BaseRepository {\n * async findById(id: string) {\n * // Uses read replica when available\n * return await this.readDb\n * .select()\n * .from(users)\n * .where(eq(users.id, id));\n * }\n *\n * async create(data: NewUser) {\n * // Uses write primary\n * return await this.db\n * .insert(users)\n * .values(data)\n * .returning();\n * }\n * }\n * ```\n *\n * @example With Transactions\n * ```typescript\n * import { runWithTransaction } from '@spfn/core/db';\n *\n * const userRepo = new UserRepository();\n *\n * await runWithTransaction(async () => {\n * // Both db and readDb automatically use the transaction context\n * const user = await userRepo.create({ name: 'John' });\n * await userRepo.findById(user.id); // Uses same transaction\n * });\n * ```\n *\n * @example With Custom Schema Type\n * ```typescript\n * import type { AppSchema } from './schema';\n *\n * export class UserRepository extends BaseRepository<AppSchema> {\n * // Now this.db and this.readDb are typed with AppSchema\n * }\n * ```\n *\n * @example With Enhanced Error Tracking\n * ```typescript\n * export class UserRepository extends BaseRepository {\n * async updateStatus(id: string, status: string) {\n * // Errors will include repository context automatically\n * return await this.db\n * .update(users)\n * .set({ status })\n * .where(eq(users.id, id))\n * .returning();\n * }\n * }\n * // On error: logs will show \"UserRepository\" context\n * ```\n */\n\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport type { SQL } from 'drizzle-orm';\nimport { count as sqlCount } from 'drizzle-orm';\nimport type { PgTable, PgColumn } from 'drizzle-orm/pg-core';\nimport { getDatabase } from './manager';\nimport { getTransaction } from './transaction';\nimport { isSQLWrapper, buildWhereFromObject } from './query-utils';\n\n/**\n * Enhanced error class that includes repository context\n */\nexport class RepositoryError extends Error\n{\n constructor(\n message: string,\n public readonly repository: string,\n public readonly method?: string,\n public readonly table?: string,\n public readonly originalError?: Error\n )\n {\n super(message);\n this.name = 'RepositoryError';\n\n // Preserve original stack trace if available\n if (originalError?.stack)\n {\n this.stack = originalError.stack;\n }\n }\n}\n\n/**\n * Base Repository class for database operations\n *\n * Provides automatic database instance management with transaction support.\n * Extend this class to create domain-specific repositories.\n *\n * The repository automatically detects if running within a transaction context\n * and uses the appropriate database instance:\n * - Inside transaction: Uses transaction DB\n * - Outside transaction: Uses global DB instance (with read/write separation)\n *\n * @template TSchema - Database schema type (defaults to Record<string, unknown>)\n */\nexport abstract class BaseRepository<TSchema extends Record<string, unknown> = Record<string, unknown>>\n{\n /**\n * Write database instance\n *\n * Automatically resolves to:\n * - Transaction DB if running within transaction context\n * - Global write (primary) instance otherwise\n *\n * Use this for INSERT, UPDATE, DELETE operations.\n *\n * @example\n * ```typescript\n * async create(data: NewUser) {\n * return await this.db.insert(users).values(data).returning();\n * }\n * ```\n */\n protected get db(): PostgresJsDatabase<TSchema>\n {\n // Transaction context takes precedence\n const txDb = getTransaction();\n if (txDb)\n {\n return txDb as PostgresJsDatabase<TSchema>;\n }\n\n // Fall back to global write instance\n return getDatabase('write') as PostgresJsDatabase<TSchema>;\n }\n\n /**\n * Read database instance\n *\n * Automatically resolves to:\n * - Transaction DB if running within transaction context\n * - Global read (replica) instance otherwise\n *\n * Use this for SELECT operations to leverage read replicas\n * and reduce load on the primary database.\n *\n * @example\n * ```typescript\n * async findById(id: string) {\n * return await this.readDb\n * .select()\n * .from(users)\n * .where(eq(users.id, id));\n * }\n * ```\n */\n protected get readDb(): PostgresJsDatabase<TSchema>\n {\n // Transaction context takes precedence\n const txDb = getTransaction();\n if (txDb)\n {\n return txDb as PostgresJsDatabase<TSchema>;\n }\n\n // Fall back to global read instance (uses replica if configured)\n return getDatabase('read') as PostgresJsDatabase<TSchema>;\n }\n\n /**\n * Wrap query execution with repository context\n *\n * Enhances error messages with repository information to make debugging easier.\n * When an error occurs, it will include:\n * - Repository class name\n * - Method name\n * - Table name (if provided)\n * - Original error details\n *\n * @param queryFn - Query function to execute\n * @param context - Context information (operation name, table name, etc.)\n * @returns Query result\n * @throws RepositoryError with enhanced context\n *\n * @example\n * ```typescript\n * async findById(id: number) {\n * return await this.withContext(\n * () => this.readDb.select().from(users).where(eq(users.id, id)),\n * { method: 'findById', table: 'users' }\n * );\n * }\n * ```\n */\n protected async withContext<T>(\n queryFn: () => Promise<T>,\n context: { method?: string; table?: string } = {}\n ): Promise<T>\n {\n try\n {\n return await queryFn();\n }\n catch (error)\n {\n const err = error instanceof Error ? error : new Error(String(error));\n const repositoryName = this.constructor.name;\n\n // Create enhanced error with repository context\n throw new RepositoryError(\n err.message,\n repositoryName,\n context.method,\n context.table,\n err\n );\n }\n }\n\n // ============================================================================\n // CRUD Methods\n // ============================================================================\n\n /**\n * Find a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Single record or null\n *\n * @example\n * ```typescript\n * // Object-based\n * const user = await this._findOne(users, { id: 1 });\n *\n * // SQL-based\n * const user = await this._findOne(users, eq(users.id, 1));\n * ```\n */\n protected async _findOne<T extends PgTable>(\n table: T,\n where: Record<string, any> | SQL | undefined\n ): Promise<T['$inferSelect'] | null>\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('findOne requires at least one where condition');\n }\n\n const results = await this.readDb.select().from(table as PgTable).where(whereClause).limit(1);\n return (results[0] as T['$inferSelect']) ?? null;\n }\n\n /**\n * Find multiple records\n *\n * @param table - Drizzle table schema\n * @param options - Query options\n * @returns Array of records\n *\n * @example\n * ```typescript\n * const users = await this._findMany(users, {\n * where: { active: true },\n * orderBy: desc(users.createdAt),\n * limit: 10\n * });\n * ```\n */\n protected async _findMany<T extends PgTable>(\n table: T,\n options?: {\n where?: Record<string, any> | SQL | undefined;\n orderBy?: SQL | SQL[];\n limit?: number;\n offset?: number;\n }\n ): Promise<T['$inferSelect'][]>\n {\n let query = this.readDb.select().from(table as PgTable);\n\n // Apply where\n if (options?.where)\n {\n const whereClause = isSQLWrapper(options.where)\n ? options.where\n : options.where ? buildWhereFromObject(table, options.where as Record<string, any>) : undefined;\n\n if (whereClause)\n {\n query = query.where(whereClause) as any;\n }\n }\n\n // Apply orderBy\n if (options?.orderBy)\n {\n const orderByArray = Array.isArray(options.orderBy) ? options.orderBy : [options.orderBy];\n query = query.orderBy(...orderByArray) as any;\n }\n\n // Apply limit\n if (options?.limit)\n {\n query = query.limit(options.limit) as any;\n }\n\n // Apply offset\n if (options?.offset)\n {\n query = query.offset(options.offset) as any;\n }\n\n return query as Promise<T['$inferSelect'][]>;\n }\n\n /**\n * Create a new record\n *\n * @param table - Drizzle table schema\n * @param data - Insert data\n * @returns Created record\n *\n * @example\n * ```typescript\n * const user = await this._create(users, {\n * email: 'test@example.com',\n * name: 'Test User'\n * });\n * ```\n */\n protected async _create<T extends PgTable>(\n table: T,\n data: T['$inferInsert']\n ): Promise<T['$inferSelect']>\n {\n const [result] = await this.db.insert(table).values(data).returning();\n return result as T['$inferSelect'];\n }\n\n /**\n * Create multiple records\n *\n * @param table - Drizzle table schema\n * @param data - Array of insert data\n * @returns Array of created records\n *\n * @example\n * ```typescript\n * const users = await this._createMany(users, [\n * { email: 'user1@example.com', name: 'User 1' },\n * { email: 'user2@example.com', name: 'User 2' }\n * ]);\n * ```\n */\n protected async _createMany<T extends PgTable>(\n table: T,\n data: T['$inferInsert'][]\n ): Promise<T['$inferSelect'][]>\n {\n const results = await this.db.insert(table).values(data).returning();\n return results as T['$inferSelect'][];\n }\n\n /**\n * Upsert a record (INSERT or UPDATE on conflict)\n *\n * @param table - Drizzle table schema\n * @param data - Insert data\n * @param options - Conflict resolution options\n * @returns Upserted record\n *\n * @example\n * ```typescript\n * const cache = await this._upsert(cache, {\n * key: 'config',\n * value: {...}\n * }, {\n * target: [cache.key],\n * set: { value: data.value, updatedAt: new Date() }\n * });\n * ```\n */\n protected async _upsert<T extends PgTable>(\n table: T,\n data: T['$inferInsert'],\n options: {\n target: PgColumn[];\n set?: Partial<T['$inferInsert']> | Record<string, SQL | any>;\n }\n ): Promise<T['$inferSelect']>\n {\n const [result] = await this.db\n .insert(table)\n .values(data)\n .onConflictDoUpdate({\n target: options.target,\n set: options.set || data,\n })\n .returning();\n\n return result as T['$inferSelect'];\n }\n\n /**\n * Update a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @param data - Update data\n * @returns Updated record or null\n *\n * @example\n * ```typescript\n * const user = await this._updateOne(users,\n * { id: 1 },\n * { name: 'Updated Name' }\n * );\n * ```\n */\n protected async _updateOne<T extends PgTable>(\n table: T,\n where: Record<string, any> | SQL | undefined,\n data: Partial<T['$inferInsert']>\n ): Promise<T['$inferSelect'] | null>\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('updateOne requires at least one where condition');\n }\n\n const [result] = await this.db.update(table).set(data).where(whereClause).returning();\n return (result as T['$inferSelect']) ?? null;\n }\n\n /**\n * Update multiple records\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @param data - Update data\n * @returns Array of updated records\n *\n * @example\n * ```typescript\n * const users = await this._updateMany(users,\n * { role: 'user' },\n * { verified: true }\n * );\n * ```\n */\n protected async _updateMany<T extends PgTable>(\n table: T,\n where: Record<string, any> | SQL | undefined,\n data: Partial<T['$inferInsert']>\n ): Promise<T['$inferSelect'][]>\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('updateMany requires at least one where condition');\n }\n\n const results = await this.db.update(table).set(data).where(whereClause).returning();\n return results as T['$inferSelect'][];\n }\n\n /**\n * Delete a single record\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Deleted record or null\n *\n * @example\n * ```typescript\n * const user = await this._deleteOne(users, { id: 1 });\n * ```\n */\n protected async _deleteOne<T extends PgTable>(\n table: T,\n where: Record<string, any> | SQL | undefined\n ): Promise<T['$inferSelect'] | null>\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('deleteOne requires at least one where condition');\n }\n\n const [result] = await this.db.delete(table).where(whereClause).returning();\n return (result as T['$inferSelect']) ?? null;\n }\n\n /**\n * Delete multiple records\n *\n * @param table - Drizzle table schema\n * @param where - Object or SQL condition\n * @returns Array of deleted records\n *\n * @example\n * ```typescript\n * const users = await this._deleteMany(users, { verified: false });\n * ```\n */\n protected async _deleteMany<T extends PgTable>(\n table: T,\n where: Record<string, any> | SQL | undefined\n ): Promise<T['$inferSelect'][]>\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (!whereClause)\n {\n throw new Error('deleteMany requires at least one where condition');\n }\n\n const results = await this.db.delete(table).where(whereClause).returning();\n return results as T['$inferSelect'][];\n }\n\n /**\n * Count records\n *\n * @param table - Drizzle table schema\n * @param where - Optional object or SQL condition\n * @returns Number of records\n *\n * @example\n * ```typescript\n * const total = await this._count(users);\n * const activeUsers = await this._count(users, { active: true });\n * ```\n */\n protected async _count<T extends PgTable>(\n table: T,\n where?: Record<string, any> | SQL | undefined\n ): Promise<number>\n {\n let query = this.readDb.select({ count: sqlCount() }).from(table as PgTable);\n\n if (where)\n {\n const whereClause = isSQLWrapper(where)\n ? where\n : where ? buildWhereFromObject(table, where as Record<string, any>) : undefined;\n\n if (whereClause)\n {\n query = query.where(whereClause) as any;\n }\n }\n\n const [result] = await query;\n return Number(result?.count ?? 0);\n }\n}"]}