@spfn/core 0.3.0-beta.4 → 0.3.0-beta.6
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.
- package/README.md +183 -4
- package/dist/authz/index.js +1 -381
- package/dist/authz/index.js.map +1 -1
- package/dist/db/index.d.ts +173 -27
- package/dist/db/index.js +192 -57
- package/dist/db/index.js.map +1 -1
- package/dist/env/loader.js +24 -1
- package/dist/env/loader.js.map +1 -1
- package/dist/errors/index.js +1 -381
- package/dist/errors/index.js.map +1 -1
- package/dist/logger/index.js +0 -12
- package/dist/logger/index.js.map +1 -1
- package/dist/middleware/index.js +6 -387
- package/dist/middleware/index.js.map +1 -1
- package/dist/nextjs/index.d.ts +18 -1
- package/dist/nextjs/index.js +40 -1
- package/dist/nextjs/index.js.map +1 -1
- package/dist/nextjs/server.d.ts +34 -1
- package/dist/nextjs/server.js +14 -0
- package/dist/nextjs/server.js.map +1 -1
- package/dist/ops/index.d.ts +61 -6
- package/dist/ops/index.js +330 -30
- package/dist/ops/index.js.map +1 -1
- package/dist/server/index.js +24 -1
- package/dist/server/index.js.map +1 -1
- package/docs/file-upload.md +195 -333
- package/package.json +6 -5
- package/src/cache/README.md +330 -0
- package/src/codegen/README.md +516 -0
- package/src/config/README.md +326 -0
- package/src/contract/README.md +326 -0
- package/src/db/README.md +589 -0
- package/src/db/manager/README.md +500 -0
- package/src/db/schema/README.md +344 -0
- package/src/db/transaction/README.md +822 -0
- package/src/env/README.md +651 -0
- package/src/errors/README.md +429 -0
- package/src/event/README.md +736 -0
- package/src/job/README.md +514 -0
- package/src/logger/README.md +321 -0
- package/src/middleware/README.md +634 -0
- package/src/nextjs/README.md +608 -0
- package/src/route/README.md +738 -0
- package/src/security/README.md +100 -0
- package/src/server/README.md +704 -0
package/dist/authz/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/errors/error-registry.ts","../../src/logger/types.ts","../../src/logger/formatters.ts","../../src/logger/logger.ts","../../src/logger/transports/console.ts","../../src/logger/config.ts","../../src/logger/factory.ts","../../src/errors/serializable-error.ts","../../src/errors/http-errors.ts","../../src/errors/database-errors.ts","../../src/errors/index.ts","../../src/authz/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Error Registry\n *\n * Central registry for serializable error types.\n * Enables automatic error deserialization on the client side.\n */\n\nimport type { SerializableError } from './serializable-error';\n\n/**\n * Error constructor type\n */\nexport type SerializableErrorConstructor = new (data: any) => SerializableError;\n\n/**\n * Input type for ErrorRegistry constructor\n */\nexport type ErrorRegistryInput =\n | SerializableErrorConstructor\n | SerializableErrorConstructor[]\n | ErrorRegistry;\n\n/**\n * Error registry for serialization/deserialization\n *\n * @example\n * ```typescript\n * // Create registry with initial errors\n * const registry = new ErrorRegistry([\n * errorRegistry, // Another ErrorRegistry\n * PaymentFailedError, // Single error class\n * [RefundError, OrderError], // Array of error classes\n * ]);\n *\n * // Or create empty and append\n * const registry = new ErrorRegistry();\n * registry\n * .append(ValidationError)\n * .append([PaymentFailedError, RefundError]);\n *\n * // Deserialize from JSON\n * const error = registry.deserialize({\n * __type: 'PaymentFailedError',\n * message: 'Payment failed',\n * transactionId: 'tx_123',\n * reason: 'insufficient_funds'\n * });\n *\n * // error instanceof PaymentFailedError === true\n * ```\n */\nexport class ErrorRegistry\n{\n private errors = new Map<string, SerializableErrorConstructor>();\n\n constructor(initialErrors?: ErrorRegistryInput[])\n {\n if (initialErrors)\n {\n for (const input of initialErrors)\n {\n if (input instanceof ErrorRegistry)\n {\n this.concat(input);\n }\n else if (Array.isArray(input))\n {\n this.append(input);\n }\n else\n {\n this.append(input);\n }\n }\n }\n }\n\n /**\n * Append error class(es) to the registry\n *\n * @param ErrorClass - Single error constructor\n * @returns This registry for chaining\n */\n append(ErrorClass: SerializableErrorConstructor): this;\n\n /**\n * Append error class(es) to the registry\n *\n * @param ErrorClasses - Array of error constructors\n * @returns This registry for chaining\n */\n append(ErrorClasses: SerializableErrorConstructor[]): this;\n\n /**\n * Append error class(es) to the registry\n *\n * @param input - Error constructor or array of constructors\n * @returns This registry for chaining\n */\n append(input: SerializableErrorConstructor | SerializableErrorConstructor[]): this\n {\n if (Array.isArray(input))\n {\n for (const ErrorClass of input)\n {\n this.errors.set(ErrorClass.name, ErrorClass);\n }\n }\n else\n {\n this.errors.set(input.name, input);\n }\n\n return this;\n }\n\n /**\n * Concatenate another ErrorRegistry into this one\n *\n * @param registry - Another ErrorRegistry to merge\n * @returns This registry for chaining\n */\n concat(registry: ErrorRegistry): this\n {\n for (const [name, ErrorClass] of registry.errors)\n {\n this.errors.set(name, ErrorClass);\n }\n\n return this;\n }\n\n /**\n * Check if error type is registered\n *\n * @param name - Error class name\n */\n has(name: string): boolean\n {\n return this.errors.has(name);\n }\n\n /**\n * Deserialize error from JSON data\n *\n * @param data - Serialized error data with __type field\n * @returns Deserialized error instance\n * @throws Error if error type is not registered\n */\n deserialize(data: { __type: string; [key: string]: any }): SerializableError\n {\n const ErrorClass = this.errors.get(data.__type);\n\n if (!ErrorClass)\n {\n throw new Error(`Unknown error type: ${data.__type}`);\n }\n\n // `__type` routed this lookup and `error` is the response envelope: both\n // describe the response, not the error. The documented constructor shape\n // is Object.assign(this, data), which would otherwise copy them onto the\n // instance as reserved fields — and a reserved field refuses to serialize\n // the moment a server re-throws this error.\n const { __type: _type, error: _envelope, ...fields } = data;\n\n return new ErrorClass(fields);\n }\n\n /**\n * Try to deserialize error, return null if type unknown\n *\n * @param data - Serialized error data\n * @returns Deserialized error or null\n */\n tryDeserialize(data: { __type?: string; [key: string]: any }): SerializableError | null\n {\n if (!data.__type || !this.has(data.__type))\n {\n return null;\n }\n\n try\n {\n return this.deserialize(data as any);\n }\n catch\n {\n return null;\n }\n }\n\n /**\n * Get all registered error types\n */\n getRegisteredTypes(): string[]\n {\n return Array.from(this.errors.keys());\n }\n}\n","/**\n * Logger Type Definitions\n *\n * 로깅 시스템 타입 정의\n *\n * ✅ 구현 완료:\n * - LogLevel 타입 정의\n * - LogMetadata 인터페이스\n * - Transport 인터페이스\n * - 환경별 설정 타입\n *\n * 🔗 관련 파일:\n * - src/logger/logger.ts (Logger 클래스)\n * - src/logger/transports/ (Transport 구현체)\n * - src/logger/config.ts (설정)\n */\n\n/**\n * 로그 레벨\n * debug < info < warn < error < fatal\n */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';\n\n/**\n * 로그 레벨 우선순위\n */\nexport const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n fatal: 4,\n};\n\n/**\n * 로그 메타데이터\n */\nexport interface LogMetadata\n{\n timestamp: Date;\n level: LogLevel;\n message: string;\n module?: string;\n error?: Error;\n context?: Record<string, unknown>;\n}\n\n/**\n * Transport 인터페이스\n * 모든 Transport는 이 인터페이스를 구현해야 함\n */\nexport interface Transport\n{\n /**\n * Transport 이름\n */\n name: string;\n\n /**\n * 최소 로그 레벨 (이 레벨 이상만 처리)\n */\n level: LogLevel;\n\n /**\n * 활성화 여부\n */\n enabled: boolean;\n\n /**\n * 로그 처리 함수\n */\n log(metadata: LogMetadata): Promise<void>;\n\n /**\n * Transport 종료 (리소스 정리)\n */\n close?(): Promise<void>;\n}\n\n/**\n * Logger 설정\n */\nexport interface LoggerConfig\n{\n /**\n * 기본 로그 레벨\n */\n level: LogLevel;\n\n /**\n * 모듈명 (context)\n */\n module?: string;\n\n /**\n * Transport 리스트\n */\n transports: Transport[];\n}\n\n/**\n * Transport 설정 (공통)\n */\nexport interface TransportConfig\n{\n level: LogLevel;\n enabled: boolean;\n}\n\n/**\n * Console Transport 설정\n */\nexport interface ConsoleTransportConfig extends TransportConfig\n{\n colorize?: boolean;\n}\n","/**\n * Logger Formatters\n *\n * Log formatting utilities for console and JSON outputs with sensitive data masking.\n */\n\nimport type { LogLevel, LogMetadata } from './types';\n\n/**\n * 민감 정보로 간주되는 키 목록\n * 이 키들을 포함하는 필드는 자동으로 마스킹됨\n */\nconst SENSITIVE_KEYS = [\n 'password',\n 'passwd',\n 'pwd',\n 'secret',\n 'token',\n 'apikey',\n 'api_key',\n 'accesstoken',\n 'access_token',\n 'refreshtoken',\n 'refresh_token',\n 'authorization',\n 'auth',\n 'cookie',\n 'session',\n 'sessionid',\n 'session_id',\n 'privatekey',\n 'private_key',\n 'creditcard',\n 'credit_card',\n 'cardnumber',\n 'card_number',\n 'cvv',\n 'ssn',\n 'pin',\n];\n\n/**\n * 마스킹된 값\n */\nconst MASKED_VALUE = '***MASKED***';\n\n/**\n * 키가 민감 정보를 포함하는지 확인\n */\nfunction isSensitiveKey(key: string): boolean\n{\n const lowerKey = key.toLowerCase();\n\n return SENSITIVE_KEYS.some(sensitive => lowerKey.includes(sensitive));\n}\n\n/**\n * 민감 정보 마스킹\n * Context 객체에서 민감한 정보(비밀번호, 토큰 등)를 마스킹\n * Circular reference를 안전하게 처리\n *\n * @param data - 원본 데이터\n * @param seen - 순환 참조 감지용 WeakSet (내부 사용)\n * @returns 마스킹된 데이터\n */\nexport function maskSensitiveData(data: unknown, seen = new WeakSet<object>()): unknown\n{\n // null, undefined 처리\n if (data === null || data === undefined)\n {\n return data;\n }\n\n // 기본 타입은 그대로 반환\n if (typeof data !== 'object')\n {\n return data;\n }\n\n // Circular reference 감지\n if (seen.has(data as object))\n {\n return '[Circular]';\n }\n seen.add(data as object);\n\n // 배열 처리\n if (Array.isArray(data))\n {\n return data.map(item => maskSensitiveData(item, seen));\n }\n\n // 객체 처리\n const masked: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(data))\n {\n if (isSensitiveKey(key))\n {\n // 민감 정보 키는 마스킹\n masked[key] = MASKED_VALUE;\n }\n else if (typeof value === 'object' && value !== null)\n {\n // 중첩된 객체는 재귀 처리 (seen 전달)\n masked[key] = maskSensitiveData(value, seen);\n }\n else\n {\n // 일반 값은 그대로 유지\n masked[key] = value;\n }\n }\n\n return masked;\n}\n\n/**\n * ANSI 컬러 코드\n */\nconst COLORS = {\n reset: '\\x1b[0m',\n bright: '\\x1b[1m',\n dim: '\\x1b[2m',\n\n // 로그 레벨 컬러\n debug: '\\x1b[36m', // cyan\n info: '\\x1b[32m', // green\n warn: '\\x1b[33m', // yellow\n error: '\\x1b[31m', // red\n fatal: '\\x1b[35m', // magenta\n\n // 추가 컬러\n gray: '\\x1b[90m',\n};\n\n/**\n * 로그 레벨을 컬러 문자열로 변환\n */\nexport function colorizeLevel(level: LogLevel): string\n{\n const color = COLORS[level];\n const levelStr = level.toUpperCase().padEnd(5);\n\n return `${color}${levelStr}${COLORS.reset}`;\n}\n\n/**\n * 타임스탬프 포맷 (ISO 8601)\n */\nexport function formatTimestamp(date: Date): string\n{\n return date.toISOString();\n}\n\n/**\n * 타임스탬프 포맷 (사람이 읽기 쉬운 형식)\n */\nexport function formatTimestampHuman(date: Date): string\n{\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hours = String(date.getHours()).padStart(2, '0');\n const minutes = String(date.getMinutes()).padStart(2, '0');\n const seconds = String(date.getSeconds()).padStart(2, '0');\n const ms = String(date.getMilliseconds()).padStart(3, '0');\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`;\n}\n\n/**\n * 에러 객체를 문자열로 변환 (스택 트레이스 포함)\n */\nexport function formatError(error: Error): string\n{\n const lines: string[] = [];\n\n lines.push(`${error.name}: ${error.message}`);\n\n if (error.stack)\n {\n const stackLines = error.stack.split('\\n').slice(1);\n lines.push(...stackLines);\n }\n\n // Cause chain — surfaces original PG errors hidden by DrizzleQueryError\n if (error.cause instanceof Error)\n {\n lines.push(`Caused by: ${formatError(error.cause)}`);\n }\n else if (error.cause !== undefined)\n {\n lines.push(`Caused by: ${String(error.cause)}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Context 객체를 문자열로 변환\n */\nexport function formatContext(context: Record<string, unknown>): string\n{\n try\n {\n return JSON.stringify(context, null, 2);\n }\n catch (error)\n {\n return '[Context serialization failed]';\n }\n}\n\n/**\n * 콘솔용 컬러 포맷\n */\nexport function formatConsole(metadata: LogMetadata, colorize = true): string\n{\n const parts: string[] = [];\n\n // [타임스탬프]\n const timestamp = formatTimestampHuman(metadata.timestamp);\n if (colorize)\n {\n parts.push(`${COLORS.gray}[${timestamp}]${COLORS.reset}`);\n }\n else\n {\n parts.push(`[${timestamp}]`);\n }\n\n // [pid=12345]\n const pid = process.pid;\n if (colorize)\n {\n parts.push(`${COLORS.dim}[pid=${pid}]${COLORS.reset}`);\n }\n else\n {\n parts.push(`[pid=${pid}]`);\n }\n\n // [module=value]\n if (metadata.module)\n {\n if (colorize)\n {\n parts.push(`${COLORS.dim}[module=${metadata.module}]${COLORS.reset}`);\n }\n else\n {\n parts.push(`[module=${metadata.module}]`);\n }\n }\n\n // Context를 각각 [key=value] 형태로 추가\n if (metadata.context && Object.keys(metadata.context).length > 0)\n {\n Object.entries(metadata.context).forEach(([key, value]) =>\n {\n let valueStr: string;\n if (typeof value === 'string')\n {\n valueStr = value;\n }\n else if (typeof value === 'object' && value !== null)\n {\n try\n {\n valueStr = JSON.stringify(value);\n }\n catch (error)\n {\n valueStr = '[circular]';\n }\n }\n else\n {\n valueStr = String(value);\n }\n\n if (colorize)\n {\n parts.push(`${COLORS.dim}[${key}=${valueStr}]${COLORS.reset}`);\n }\n else\n {\n parts.push(`[${key}=${valueStr}]`);\n }\n });\n }\n\n // (LEVEL):\n const levelStr = metadata.level.toUpperCase();\n if (colorize)\n {\n const color = COLORS[metadata.level];\n parts.push(`${color}(${levelStr})${COLORS.reset}:`);\n }\n else\n {\n parts.push(`(${levelStr}):`);\n }\n\n // 메시지\n if (colorize)\n {\n parts.push(`${COLORS.bright}${metadata.message}${COLORS.reset}`);\n }\n else\n {\n parts.push(metadata.message);\n }\n\n let output = parts.join(' ');\n\n // 에러는 별도 줄로 추가\n if (metadata.error)\n {\n output += '\\n' + formatError(metadata.error);\n }\n\n return output;\n}\n\n/**\n * Error 객체를 cause 체인까지 포함한 직렬화 가능 객체로 변환\n */\nfunction formatErrorCauseChain(error: Error): Record<string, unknown>\n{\n const result: Record<string, unknown> = {\n name: error.name,\n message: error.message,\n stack: error.stack,\n };\n\n if (error.cause instanceof Error)\n {\n result.cause = formatErrorCauseChain(error.cause);\n }\n else if (error.cause !== undefined)\n {\n result.cause = String(error.cause);\n }\n\n return result;\n}\n\n/**\n * JSON 포맷 (파일 저장 및 전송용)\n */\nexport function formatJSON(metadata: LogMetadata): string\n{\n const obj: Record<string, unknown> = {\n timestamp: formatTimestamp(metadata.timestamp),\n level: metadata.level,\n message: metadata.message,\n };\n\n if (metadata.module)\n {\n obj.module = metadata.module;\n }\n\n if (metadata.context)\n {\n obj.context = metadata.context;\n }\n\n if (metadata.error)\n {\n obj.error = formatErrorCauseChain(metadata.error);\n }\n\n return JSON.stringify(obj);\n}\n\n/**\n * Drizzle ORM 에러에서 쿼리 정보 추출\n *\n * Drizzle ORM은 에러 메시지에 다음 형식으로 정보를 포함:\n * - \"Failed query: <QUERY>\\nparams: <PARAMS>\"\n * - \"Query: <QUERY>\"\n *\n * @param error - Error 객체\n * @returns 쿼리 정보 (query, params, table)\n */\nexport function extractQueryInfo(error: Error): {\n query?: string;\n params?: unknown;\n table?: string;\n} | null\n{\n const message = error.message;\n\n if (!message) return null;\n\n const result: {\n query?: string;\n params?: unknown;\n table?: string;\n } = {};\n\n // Extract query from \"Failed query: ...\" or \"Query: ...\"\n const queryMatch = message.match(/(?:Failed query:|Query:)\\s*([^\\n]+)/);\n if (queryMatch)\n {\n result.query = queryMatch[1].trim();\n\n // Extract table name from query (e.g., UPDATE \"table_name\" or INSERT INTO \"table_name\")\n const tableMatch = result.query.match(/(?:UPDATE|INSERT INTO|DELETE FROM|FROM)\\s+\"?([a-zA-Z_][a-zA-Z0-9_]*)\"?\\.\"?([a-zA-Z_][a-zA-Z0-9_]*)\"?|(?:UPDATE|INSERT INTO|DELETE FROM|FROM)\\s+\"?([a-zA-Z_][a-zA-Z0-9_]*)\"?/i);\n if (tableMatch)\n {\n // Schema.Table or just Table\n result.table = tableMatch[2] || tableMatch[3] || tableMatch[1];\n }\n }\n\n // Extract params from \"params: ...\"\n const paramsMatch = message.match(/params:\\s*(.+?)(?:\\n|$)/);\n if (paramsMatch)\n {\n const paramsStr = paramsMatch[1].trim();\n try\n {\n // Try to parse as comma-separated values\n result.params = paramsStr.split(',').map(p => p.trim());\n }\n catch (e)\n {\n result.params = paramsStr;\n }\n }\n\n return Object.keys(result).length > 0 ? result : null;\n}\n\n/**\n * Promise rejection의 호출 스택에서 실제 발생 위치 추출\n *\n * 스택 트레이스에서 다음 정보를 추출:\n * - 실제 에러 발생 파일 경로\n * - 라인 번호\n * - 함수명/메서드명\n * - Repository 정보 (있는 경우)\n *\n * @param error - Error 객체\n * @returns Promise context 정보\n */\nexport function extractPromiseContext(error: Error): Record<string, unknown>\n{\n const context: Record<string, unknown> = {};\n\n if (!error.stack) return context;\n\n const stackLines = error.stack.split('\\n');\n\n // Skip first line (error message) and find first meaningful stack frame\n // Ignore node_modules and internal Node.js paths\n for (let i = 1; i < stackLines.length; i++)\n {\n const line = stackLines[i].trim();\n\n // Skip node_modules and node internals\n if (line.includes('node_modules') || line.includes('node:internal')) continue;\n\n // Extract file, line number, and function name\n // Format: \"at ClassName.methodName (file.ts:line:col)\"\n // or: \"at functionName (file.ts:line:col)\"\n // or: \"at file.ts:line:col\"\n\n const match = line.match(/at\\s+(?:([a-zA-Z_$][\\w$]*(?:\\.[a-zA-Z_$][\\w$]*)*)\\s+)?\\(?([^)]+):(\\d+):(\\d+)\\)?/);\n\n if (match)\n {\n const [, functionName, filePath, lineNumber, columnNumber] = match;\n\n // Extract just the filename from the full path\n const fileNameMatch = filePath.match(/([^/\\\\]+)$/);\n const fileName = fileNameMatch ? fileNameMatch[1] : filePath;\n\n context.file = fileName;\n context.line = parseInt(lineNumber, 10);\n context.column = parseInt(columnNumber, 10);\n\n if (functionName)\n {\n // Check if it's a class method (e.g., \"ClassName.methodName\")\n const methodMatch = functionName.match(/^(.+)\\.([^.]+)$/);\n if (methodMatch)\n {\n const [, className, methodName] = methodMatch;\n\n context.class = className;\n context.method = methodName;\n\n // Check if it's a Repository\n if (className.includes('Repository'))\n {\n context.repository = className;\n }\n }\n else\n {\n context.function = functionName;\n }\n }\n\n // Found first relevant frame, stop here\n break;\n }\n }\n\n return context;\n}\n\n/**\n * Unhandled rejection 에러를 상세하게 포맷팅\n *\n * Promise context와 DB 쿼리 정보를 자동으로 추출하여\n * 에러 발생 위치와 원인을 명확하게 파악할 수 있도록 함\n *\n * @param reason - Rejection 원인 (Error 또는 기타)\n * @param promise - Promise 객체\n * @returns 상세 context 정보\n */\nexport function formatUnhandledRejection(reason: unknown, promise: Promise<unknown>): {\n error: Error;\n context: Record<string, unknown>;\n}\n{\n // Convert reason to Error if not already\n let error: Error;\n if (reason instanceof Error)\n {\n error = reason;\n }\n else if (typeof reason === 'string')\n {\n error = new Error(reason);\n }\n else\n {\n error = new Error(JSON.stringify(reason));\n }\n\n const context: Record<string, unknown> = {\n promise: String(promise),\n };\n\n // Extract promise context (file, line, function, etc.)\n const promiseContext = extractPromiseContext(error);\n if (Object.keys(promiseContext).length > 0)\n {\n context.promiseContext = promiseContext;\n }\n\n // Extract DB query info if available\n const queryInfo = extractQueryInfo(error);\n if (queryInfo)\n {\n context.queryInfo = queryInfo;\n }\n\n return { error, context };\n}\n","/**\n * Logger Class\n *\n * Central logging class with multiple transports, child loggers, and sensitive data masking.\n */\n\nimport { format } from 'node:util';\nimport type { LogLevel, LogMetadata, LoggerConfig, Transport } from './types';\nimport { LOG_LEVEL_PRIORITY } from './types';\nimport { maskSensitiveData } from './formatters';\n\nconst FORMAT_PATTERN = /%[sdifjoOc%]/;\n\n/**\n * Logger class\n */\nexport class Logger\n{\n private readonly config: LoggerConfig;\n private readonly module?: string;\n\n constructor(config: LoggerConfig)\n {\n this.config = config;\n this.module = config.module;\n }\n\n /**\n * Convert unknown error to Error object\n */\n private toError(error: unknown): Error\n {\n if (error instanceof Error) return error;\n if (typeof error === 'string') return new Error(error);\n if (typeof error === 'object' && error !== null)\n {\n return new Error(JSON.stringify(error));\n }\n\n return new Error(String(error));\n }\n\n /**\n * Check if value is a context object (not an error)\n */\n private isContext(value: unknown): value is Record<string, unknown>\n {\n if (typeof value !== 'object' || value === null) return false;\n if (value instanceof Error) return false;\n\n // Use stack as the primary indicator for error detection\n // - Almost all Error objects have stack (auto-generated by JS engines)\n // - Regular objects rarely use 'stack' as a property name\n // - This avoids false positives for objects with 'name' or 'message' properties\n const hasStack = 'stack' in value && typeof (value as any).stack === 'string';\n\n if (hasStack)\n {\n return false; // Likely an error object\n }\n\n // No stack -> treat as context\n // This allows {name: \"...\", method: \"...\"} to be treated as context\n return true;\n }\n\n /**\n * Get current log level\n */\n get level(): LogLevel\n {\n return this.config.level;\n }\n\n /**\n * Create child logger (per module)\n */\n child(module: string): Logger\n {\n return new Logger({\n ...this.config,\n module,\n });\n }\n\n /**\n * Common log method with error/context detection\n */\n private logWithLevel(\n level: LogLevel,\n message: string,\n errorOrContext?: Error | unknown | Record<string, unknown>,\n context?: Record<string, unknown>,\n ): void\n {\n // printf-style format string: logger.info('url: %s', value)\n if (errorOrContext !== undefined && FORMAT_PATTERN.test(message))\n {\n this.log(level, format(message, errorOrContext), undefined, context);\n\n return;\n }\n\n if (errorOrContext instanceof Error)\n {\n this.log(level, message, errorOrContext, context);\n }\n else if (errorOrContext !== undefined && typeof errorOrContext === 'object' && !this.isContext(errorOrContext))\n {\n this.log(level, message, this.toError(errorOrContext), context);\n }\n else if (typeof errorOrContext === 'string' || typeof errorOrContext === 'number' || typeof errorOrContext === 'boolean')\n {\n this.log(level, message, this.toError(errorOrContext), context);\n }\n else\n {\n this.log(level, message, undefined, errorOrContext as Record<string, unknown>);\n }\n }\n\n /**\n * Debug log\n */\n debug(message: string, context?: Record<string, unknown>): void;\n debug(message: string, formatArg: string | number | boolean): void;\n debug(message: string, error: Error | unknown, context?: Record<string, unknown>): void;\n debug(message: string, errorOrContext?: unknown, context?: Record<string, unknown>): void\n {\n this.logWithLevel('debug', message, errorOrContext, context);\n }\n\n /**\n * Info log\n */\n info(message: string, context?: Record<string, unknown>): void;\n info(message: string, formatArg: string | number | boolean): void;\n info(message: string, error: Error | unknown, context?: Record<string, unknown>): void;\n info(message: string, errorOrContext?: unknown, context?: Record<string, unknown>): void\n {\n this.logWithLevel('info', message, errorOrContext, context);\n }\n\n /**\n * Warn log\n */\n warn(message: string, context?: Record<string, unknown>): void;\n warn(message: string, formatArg: string | number | boolean): void;\n warn(message: string, error: Error | unknown, context?: Record<string, unknown>): void;\n warn(message: string, errorOrContext?: unknown, context?: Record<string, unknown>): void\n {\n this.logWithLevel('warn', message, errorOrContext, context);\n }\n\n /**\n * Error log\n */\n error(message: string, context?: Record<string, unknown>): void;\n error(message: string, formatArg: string | number | boolean): void;\n error(message: string, error: Error | unknown, context?: Record<string, unknown>): void;\n error(message: string, errorOrContext?: unknown, context?: Record<string, unknown>): void\n {\n this.logWithLevel('error', message, errorOrContext, context);\n }\n\n /**\n * Fatal log\n */\n fatal(message: string, context?: Record<string, unknown>): void;\n fatal(message: string, formatArg: string | number | boolean): void;\n fatal(message: string, error: Error | unknown, context?: Record<string, unknown>): void;\n fatal(message: string, errorOrContext?: unknown, context?: Record<string, unknown>): void\n {\n this.logWithLevel('fatal', message, errorOrContext, context);\n }\n\n /**\n * Log processing (internal)\n */\n private log(level: LogLevel, message: string, error?: Error, context?: Record<string, unknown>): void\n {\n // Early return if log level is below configured level\n // This prevents unnecessary metadata creation and processing\n if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.config.level])\n {\n return;\n }\n\n const metadata: LogMetadata = {\n timestamp: new Date(),\n level,\n message,\n module: this.module,\n error,\n // Mask sensitive information in context to prevent credential leaks\n context: context ? maskSensitiveData(context) as Record<string, unknown> : undefined,\n };\n\n // Pass to all enabled Transports\n this.processTransports(metadata);\n }\n\n /**\n * Process Transports\n */\n private processTransports(metadata: LogMetadata): void\n {\n const promises = this.config.transports\n .filter(transport => transport.enabled)\n .map(transport => this.safeTransportLog(transport, metadata));\n\n // Async processing to prevent Transport errors from blocking logs\n Promise.all(promises).catch(error =>\n {\n // Use stderr directly to avoid circular logging\n const errorMessage = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[Logger] Transport error: ${errorMessage}\\n`);\n });\n }\n\n /**\n * Transport log (error-safe)\n */\n private async safeTransportLog(transport: Transport, metadata: LogMetadata): Promise<void>\n {\n try\n {\n await transport.log(metadata);\n }\n catch (error)\n {\n // Use stderr directly to avoid circular logging\n const errorMessage = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[Logger] Transport \"${transport.name}\" failed: ${errorMessage}\\n`);\n }\n }\n\n /**\n * Close all Transports\n */\n async close(): Promise<void>\n {\n const closePromises = this.config.transports\n .filter(transport => transport.close)\n .map(transport => transport.close!());\n\n await Promise.all(closePromises);\n }\n}\n","/**\n * Console Transport\n *\n * 콘솔 출력 Transport\n *\n * ✅ 구현 완료:\n * - 콘솔 출력 (stdout/stderr)\n * - 컬러 출력 지원\n * - 로그 레벨별 스트림 분리 (warn/error/fatal → stderr)\n *\n * 🔗 관련 파일:\n * - src/logger/types.ts (Transport 인터페이스)\n * - src/logger/formatters.ts (포맷터)\n * - src/logger/config.ts (설정)\n */\n\nimport type { Transport, LogMetadata, LogLevel, ConsoleTransportConfig } from '../types';\nimport { LOG_LEVEL_PRIORITY } from '../types';\nimport { formatConsole } from '../formatters';\n\n/**\n * Console Transport\n */\nexport class ConsoleTransport implements Transport\n{\n public readonly name = 'console';\n public readonly level: LogLevel;\n public readonly enabled: boolean;\n private readonly colorize: boolean;\n\n constructor(config: ConsoleTransportConfig)\n {\n this.level = config.level;\n this.enabled = config.enabled;\n this.colorize = config.colorize ?? true;\n }\n\n async log(metadata: LogMetadata): Promise<void>\n {\n // Enabled 상태 체크\n if (!this.enabled)\n {\n return;\n }\n\n // 로그 레벨 체크\n if (LOG_LEVEL_PRIORITY[metadata.level] < LOG_LEVEL_PRIORITY[this.level])\n {\n return;\n }\n\n // 포맷팅\n const message = formatConsole(metadata, this.colorize);\n\n // warn/error/fatal은 stderr로, 나머지는 stdout으로\n if (metadata.level === 'warn' || metadata.level === 'error' || metadata.level === 'fatal')\n {\n console.error(message);\n }\n else\n {\n console.log(message);\n }\n }\n}\n","/**\n * Logger Configuration\n *\n * Environment-based logger configuration with validation for console transport.\n */\n\nimport type {\n ConsoleTransportConfig,\n} from './types';\n\n/**\n * Console Transport configuration\n */\nexport function getConsoleConfig(): ConsoleTransportConfig\n{\n const isProduction = process.env.NODE_ENV === 'production';\n\n return {\n level: 'debug',\n enabled: true,\n colorize: !isProduction, // Dev: colored output, Production: plain text\n };\n}\n\n/**\n * Validate environment variables\n */\nfunction validateEnvironment(): void\n{\n const nodeEnv = process.env.NODE_ENV;\n\n if (!nodeEnv)\n {\n process.stderr.write(\n '[Logger] Warning: NODE_ENV is not set. Defaulting to test environment.\\n',\n );\n }\n // Allow any NODE_ENV value (development, production, test, staging, local, etc.)\n // No validation needed - users can use custom environments\n}\n\n/**\n * Validate all logger configuration\n */\nexport function validateConfig(): void\n{\n validateEnvironment();\n}\n","/**\n * Logger Factory\n *\n * Creates and initializes the logger instance with configured transports\n */\n\nimport { Logger } from './logger';\nimport { ConsoleTransport } from './transports/console';\nimport { getConsoleConfig, validateConfig } from './config';\nimport type { LogLevel, Transport } from './types';\nimport { LOG_LEVEL_PRIORITY } from './types';\n\n/**\n * Initialize transports based on environment and configuration\n */\nfunction initializeTransports(): Transport[]\n{\n const transports: Transport[] = [];\n\n // Console Transport (always enabled)\n const consoleConfig = getConsoleConfig();\n transports.push(new ConsoleTransport(consoleConfig));\n\n // Future: Add more transports (Slack, Email, etc.)\n // if (config.slack?.enabled) {\n // transports.push(new SlackTransport(config.slack));\n // }\n\n return transports;\n}\n\n/**\n * Get validated log level from environment variables\n */\nfunction getLogLevel(): LogLevel\n{\n const envLevel = process.env.SPFN_LOG_LEVEL\n || process.env.NEXT_PUBLIC_SPFN_LOG_LEVEL\n || 'info';\n\n if (envLevel in LOG_LEVEL_PRIORITY)\n {\n return envLevel as LogLevel;\n }\n\n process.stderr.write(\n `[Logger] Invalid log level \"${envLevel}\", defaulting to \"info\"\\n`,\n );\n\n return 'info';\n}\n\n/**\n * Initialize logger with configuration validation\n */\nfunction initializeLogger(): Logger\n{\n // Validate configuration before creating logger\n validateConfig();\n\n // Create logger with configured transports\n return new Logger({\n level: getLogLevel(),\n transports: initializeTransports(),\n });\n}\n\n/**\n * Singleton Logger instance\n */\nexport const logger: Logger = initializeLogger();\n","/**\n * Serializable Error Base Class\n *\n * Base class for errors that can be serialized/deserialized across HTTP boundary.\n * Automatically serializes public fields for transmission to client.\n */\n\nimport { logger } from '../logger';\n\n/**\n * Serialized error format for JSON transmission\n */\nexport interface SerializedError\n{\n __type: string;\n message: string;\n [key: string]: unknown;\n}\n\n/**\n * Field names an error class may not use.\n *\n * Public fields are spread into the response body next to `__type`, `message`\n * and the `error` envelope the error handler attaches, so a field sharing one\n * of those names collides with the response shape every consumer reads: the\n * web client restores an error class from `__type` and a generated mobile\n * client reads `error.code`. Reserving the three names removes the collision\n * instead of picking a winner for it — either winner loses something the other\n * side needs.\n */\nconst RESERVED_RESPONSE_KEYS = new Set(['__type', 'message', 'error']);\n\n/**\n * Environments where a developer is watching and can still rename the class.\n * Anything else is a running deployment, `staging` included — there the throw\n * would replace a real failure with a failure about serializing it, and the\n * original error would never reach the log or the client.\n */\nconst AUTHORING_ENVIRONMENTS = new Set(['local', 'development', 'test']);\n\n/**\n * Answer a reserved field name: loudly while it can still be renamed, quietly\n * once a rename is no longer possible.\n *\n * While authoring, the throw is the point — the class is renamed the first time\n * a test serializes it.\n */\nfunction refuseReservedKey(className: string, key: string): never | void\n{\n const detail = `${className} declares the reserved field \"${key}\". `\n + `Reserved response keys: ${[...RESERVED_RESPONSE_KEYS].join(', ')}. Rename the field.`;\n\n if (AUTHORING_ENVIRONMENTS.has(process.env.NODE_ENV ?? 'local'))\n {\n throw new Error(detail);\n }\n\n logger.error(`[SerializableError] ${detail} The field is omitted from the response.`);\n}\n\n/**\n * Base class for all serializable errors\n *\n * Features:\n * - Auto-serialization of public fields via toJSON()\n * - Constructor accepts object with all fields\n * - Type-safe error handling with instanceof\n *\n * @example\n * ```typescript\n * class PaymentFailedError extends SerializableError\n * {\n * readonly statusCode = 402;\n * transactionId!: string;\n * reason!: 'insufficient_funds' | 'card_declined';\n *\n * constructor(data: {\n * message: string;\n * transactionId: string;\n * reason: 'insufficient_funds' | 'card_declined';\n * })\n * {\n * super(data.message);\n * this.name = 'PaymentFailedError';\n * Object.assign(this, data);\n * }\n * }\n * ```\n */\nexport abstract class SerializableError extends Error\n{\n /**\n * HTTP status code for this error type\n */\n abstract readonly statusCode: number;\n\n /**\n * Serialize error to JSON-compatible object\n *\n * Automatically includes:\n * - __type: Constructor name for deserialization\n * - message: Error message\n * - All public instance properties (except name, stack)\n */\n toJSON(): SerializedError\n {\n const json: SerializedError = {\n __type: this.constructor.name,\n message: this.message,\n };\n\n // Extract all public instance properties\n for (const key of Object.keys(this))\n {\n // Skip Error built-ins and statusCode (inferred from type)\n if (key === 'name' || key === 'stack' || key === 'statusCode')\n {\n continue;\n }\n\n if (RESERVED_RESPONSE_KEYS.has(key))\n {\n refuseReservedKey(this.constructor.name, key);\n continue;\n }\n\n json[key] = (this as unknown as Record<string, unknown>)[key];\n }\n\n return json;\n }\n}\n","/**\n * HTTP Error Classes\n *\n * Standard HTTP error classes for API responses\n * All errors are serializable for type-safe client-side error handling\n */\n\nimport { SerializableError } from './serializable-error';\n\n/**\n * Base HTTP Error\n *\n * Base class for all HTTP-related errors\n */\nexport class HttpError extends SerializableError\n{\n public readonly statusCode: number;\n public details?: Record<string, unknown>;\n\n constructor(data: {\n message: string;\n statusCode: number;\n details?: Record<string, unknown>;\n })\n {\n super(data.message);\n\n this.name = 'HttpError';\n this.statusCode = data.statusCode;\n\n if (data.details)\n {\n this.details = data.details;\n }\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Bad Request Error (400)\n *\n * Generic bad request - malformed syntax, invalid parameters, etc.\n */\nexport class BadRequestError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Bad request',\n statusCode: 400,\n details: data.details,\n });\n\n this.name = 'BadRequestError';\n }\n}\n\n/**\n * Validation Error (400)\n *\n * Input validation failure (request params, query, body)\n * Used by define-route system for automatic validation\n */\nexport class ValidationError extends HttpError\n{\n fields?: Array<{ path: string; message: string; value?: any }>;\n\n constructor(data: {\n message: string;\n fields?: Array<{ path: string; message: string; value?: any }>;\n details?: Record<string, any>;\n })\n {\n super({\n message: data.message,\n statusCode: 400,\n details: data.details,\n });\n\n this.name = 'ValidationError';\n\n if (data.fields)\n {\n this.fields = data.fields;\n }\n }\n}\n\n/**\n * Unauthorized Error (401)\n *\n * Authentication required or authentication failed\n */\nexport class UnauthorizedError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Authentication required',\n statusCode: 401,\n details: data.details,\n });\n\n this.name = 'UnauthorizedError';\n }\n}\n\n/**\n * Forbidden Error (403)\n *\n * Authenticated but lacks permission to access resource\n */\nexport class ForbiddenError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Access forbidden',\n statusCode: 403,\n details: data.details,\n });\n\n this.name = 'ForbiddenError';\n }\n}\n\n/**\n * Not Found Error (404)\n *\n * Requested resource does not exist\n */\nexport class NotFoundError extends HttpError\n{\n resource?: string;\n\n constructor(data: { message?: string; resource?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Resource not found',\n statusCode: 404,\n details: data.details,\n });\n\n this.name = 'NotFoundError';\n\n if (data.resource)\n {\n this.resource = data.resource;\n }\n }\n}\n\n/**\n * Conflict Error (409)\n *\n * Generic conflict - resource state conflict, concurrent modification, etc.\n */\nexport class ConflictError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Resource conflict',\n statusCode: 409,\n details: data.details,\n });\n\n this.name = 'ConflictError';\n }\n}\n\n/**\n * Gone Error (410)\n *\n * Resource permanently deleted and no longer available\n */\nexport class GoneError extends HttpError\n{\n resource?: string;\n\n constructor(data: { message?: string; resource?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Resource permanently deleted',\n statusCode: 410,\n details: data.details,\n });\n\n this.name = 'GoneError';\n\n if (data.resource)\n {\n this.resource = data.resource;\n }\n }\n}\n\n/**\n * Too Many Requests Error (429)\n *\n * Rate limit exceeded\n */\nexport class TooManyRequestsError extends HttpError\n{\n retryAfter?: number;\n\n constructor(data: {\n message?: string;\n retryAfter?: number;\n details?: Record<string, any>;\n } = {})\n {\n super({\n message: data.message || 'Too many requests',\n statusCode: 429,\n details: data.details,\n });\n\n this.name = 'TooManyRequestsError';\n\n if (data.retryAfter)\n {\n this.retryAfter = data.retryAfter;\n }\n }\n}\n\n/**\n * Internal Server Error (500)\n *\n * Generic server error when no specific error type applies\n */\nexport class InternalServerError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Internal server error',\n statusCode: 500,\n details: data.details,\n });\n\n this.name = 'InternalServerError';\n }\n}\n\n/**\n * Unsupported Media Type Error (415)\n *\n * Media type not supported - invalid file type, content type, etc.\n */\nexport class UnsupportedMediaTypeError extends HttpError\n{\n mediaType?: string;\n supportedTypes?: string[];\n\n constructor(data: {\n message?: string;\n mediaType?: string;\n supportedTypes?: string[];\n details?: Record<string, any>;\n } = {})\n {\n super({\n message: data.message || 'Unsupported media type',\n statusCode: 415,\n details: data.details,\n });\n\n this.name = 'UnsupportedMediaTypeError';\n\n if (data.mediaType)\n {\n this.mediaType = data.mediaType;\n }\n\n if (data.supportedTypes)\n {\n this.supportedTypes = data.supportedTypes;\n }\n }\n}\n\n/**\n * Unprocessable Entity Error (422)\n *\n * Request is well-formed but contains semantic errors\n */\nexport class UnprocessableEntityError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Unprocessable entity',\n statusCode: 422,\n details: data.details,\n });\n\n this.name = 'UnprocessableEntityError';\n }\n}\n\n/**\n * Service Unavailable Error (503)\n *\n * Service temporarily unavailable (maintenance, overload, etc.)\n */\nexport class ServiceUnavailableError extends HttpError\n{\n retryAfter?: number;\n\n constructor(data: {\n message?: string;\n retryAfter?: number;\n details?: Record<string, any>;\n } = {})\n {\n super({\n message: data.message || 'Service unavailable',\n statusCode: 503,\n details: data.details,\n });\n\n this.name = 'ServiceUnavailableError';\n\n if (data.retryAfter)\n {\n this.retryAfter = data.retryAfter;\n }\n }\n}\n","/**\n * Database Error Classes\n *\n * Type-safe error handling with custom error class hierarchy\n * Mapped to HTTP status codes for API responses\n * All errors extend SerializableError for consistent JSON serialization\n */\n\nimport { SerializableError } from './serializable-error';\n\n/**\n * Base Database Error\n *\n * Base class for all database-related errors\n */\nexport class DatabaseError<TDetails extends Record<string, unknown> = Record<string, unknown>>\n extends SerializableError\n{\n public readonly statusCode: number;\n public readonly details?: TDetails;\n\n constructor(data: {\n message: string;\n statusCode?: number;\n details?: TDetails;\n })\n {\n super(data.message);\n this.name = 'DatabaseError';\n this.statusCode = data.statusCode ?? 500;\n this.details = data.details;\n Error.captureStackTrace(this, this.constructor);\n }\n\n /**\n * Whether this error's message/details are derived from the raw database\n * driver (SQL text, table/column/constraint names, parameter values) and\n * therefore must NOT be exposed to clients in production. Defined as a\n * prototype getter so it is never serialized into the response by toJSON().\n * Subclasses with a safe, constructed message override this to `false`.\n */\n get internal(): boolean\n {\n return true;\n }\n}\n\n/**\n * Connection Error (503 Service Unavailable)\n *\n * Database connection failure, connection pool exhaustion, etc.\n */\nexport class ConnectionError extends DatabaseError\n{\n constructor(data: { message: string; details?: Record<string, unknown> })\n {\n super({ message: data.message, statusCode: 503, details: data.details });\n this.name = 'ConnectionError';\n }\n}\n\n/**\n * Query Error (500 Internal Server Error)\n *\n * SQL query execution failure, syntax errors, etc.\n */\nexport class QueryError extends DatabaseError\n{\n constructor(data: {\n message: string;\n statusCode?: number;\n details?: Record<string, unknown>;\n })\n {\n super({\n message: data.message,\n statusCode: data.statusCode ?? 500,\n details: data.details,\n });\n this.name = 'QueryError';\n }\n}\n\n/**\n * Entity Not Found Error (404 Not Found)\n *\n * Database entity does not exist\n */\nexport class EntityNotFoundError extends QueryError\n{\n public readonly resource: string;\n public readonly id: string | number;\n\n constructor(data: { resource: string; id: string | number })\n {\n super({\n message: `${data.resource} with id ${data.id} not found`,\n statusCode: 404,\n details: { resource: data.resource, id: data.id },\n });\n this.name = 'EntityNotFoundError';\n this.resource = data.resource;\n this.id = data.id;\n }\n\n // Message/details are constructed from the resource + id, not driver text\n override get internal(): boolean\n {\n return false;\n }\n}\n\n/**\n * Constraint Violation Error (400 Bad Request)\n *\n * Database constraint violation (NOT NULL, CHECK, FOREIGN KEY, etc.)\n * This is different from HTTP ValidationError which validates request input\n */\nexport class ConstraintViolationError extends QueryError\n{\n constructor(data: { message: string; details?: Record<string, unknown> })\n {\n super({ message: data.message, statusCode: 400, details: data.details });\n this.name = 'ConstraintViolationError';\n }\n}\n\n/**\n * Transaction Error (500 Internal Server Error)\n *\n * Transaction start/commit/rollback failure\n */\nexport class TransactionError extends DatabaseError\n{\n constructor(data: {\n message: string;\n statusCode?: number;\n details?: Record<string, unknown>;\n })\n {\n super({\n message: data.message,\n statusCode: data.statusCode ?? 500,\n details: data.details,\n });\n this.name = 'TransactionError';\n }\n}\n\n/**\n * Deadlock Error (409 Conflict)\n *\n * Database deadlock detected\n */\nexport class DeadlockError extends TransactionError\n{\n constructor(data: { message: string; details?: Record<string, unknown> })\n {\n super({ message: data.message, statusCode: 409, details: data.details });\n this.name = 'DeadlockError';\n }\n}\n\n/**\n * Duplicate Entry Error (409 Conflict)\n *\n * Unique constraint violation (e.g., duplicate email)\n */\nexport class DuplicateEntryError extends QueryError\n{\n public readonly field: string;\n public readonly value: string | number;\n\n constructor(data: { field: string; value: string | number })\n {\n // The client-facing message/details name the field but NOT the value: echoing\n // the value back (e.g. an email) confirms it exists, an enumeration aid. The\n // raw value stays on the instance for server-side handling/logging.\n super({\n message: `${data.field} already exists`,\n statusCode: 409,\n details: { field: data.field },\n });\n this.name = 'DuplicateEntryError';\n this.field = data.field;\n this.value = data.value;\n }\n\n // Field-only message/details — safe to surface to the client (not internal)\n override get internal(): boolean\n {\n return false;\n }\n}\n","/**\n * Error Module Exports\n *\n * Entry point for error handling module with serialization support\n */\n\n// Core Error Registry\n// Pre-configured registry with all built-in HTTP and Database errors\nimport { ErrorRegistry } from './error-registry';\nimport {\n HttpError,\n BadRequestError,\n ValidationError,\n UnauthorizedError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n GoneError,\n TooManyRequestsError,\n UnsupportedMediaTypeError,\n UnprocessableEntityError,\n InternalServerError,\n ServiceUnavailableError,\n} from './http-errors';\nimport {\n DatabaseError,\n ConnectionError,\n QueryError,\n EntityNotFoundError,\n ConstraintViolationError,\n TransactionError,\n DeadlockError,\n DuplicateEntryError,\n} from './database-errors';\n\n// Base Classes\nexport { SerializableError } from './serializable-error';\nexport type { SerializedError } from './serializable-error';\nexport { ErrorRegistry } from './error-registry';\nexport type { SerializableErrorConstructor, ErrorRegistryInput } from './error-registry';\n\n// Database Error Classes\nexport {\n DatabaseError,\n ConnectionError,\n QueryError,\n EntityNotFoundError,\n ConstraintViolationError,\n TransactionError,\n DeadlockError,\n DuplicateEntryError,\n} from './database-errors';\n\n// HTTP Error Classes\nexport {\n HttpError,\n BadRequestError,\n ValidationError,\n UnauthorizedError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n GoneError,\n TooManyRequestsError,\n UnsupportedMediaTypeError,\n UnprocessableEntityError,\n InternalServerError,\n ServiceUnavailableError,\n} from './http-errors';\n\n// Error Utilities\nexport {\n isDatabaseError,\n isHttpError,\n hasStatusCode,\n} from './error-utils';\n\nexport const errorRegistry = new ErrorRegistry();\n\n// HTTP Errors\nerrorRegistry.append([\n HttpError,\n BadRequestError,\n ValidationError,\n UnauthorizedError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n GoneError,\n TooManyRequestsError,\n UnsupportedMediaTypeError,\n UnprocessableEntityError,\n InternalServerError,\n ServiceUnavailableError,\n]);\n\n// Database Errors\nerrorRegistry.append([\n DatabaseError,\n ConnectionError,\n QueryError,\n EntityNotFoundError,\n ConstraintViolationError,\n TransactionError,\n DeadlockError,\n DuplicateEntryError,\n]);\n\nexport * as HttpErrors from './http-errors';\nexport * as DatabaseErrors from './database-errors';\n","/**\n * @spfn/core/authz - Authorization primitives\n *\n * Small, domain-agnostic guards for resource ownership. The point is to make the\n * \"load, then check it belongs to the requester\" step a single call so a handler\n * can't forget it and leak another user's data (IDOR).\n */\n\nimport { NotFoundError } from '../errors';\n\nexport interface RequireOwnerOptions<T>\n{\n /**\n * Property on the resource holding the owner id. Defaults to `'ownerId'`.\n * SPFN entities commonly use `userId` / `createdBy` — pass it explicitly:\n * `requireOwner(doc, userId, { ownerKey: 'userId' })`.\n */\n ownerKey?: keyof T;\n\n /** Message for the thrown NotFoundError. @default 'not found' */\n message?: string;\n}\n\n/**\n * Return the resource only if it exists and belongs to `ownerId`; otherwise throw\n * `NotFoundError`. Not-found and not-owned are deliberately the same response, so\n * the endpoint never reveals that a resource exists to a non-owner.\n *\n * Ids are compared as strings, so number/string/bigint ids interoperate. A\n * missing or null owner value never matches, so it throws.\n *\n * @example\n * ```ts\n * const chat = requireOwner(await chats.findById(id), userId, { ownerKey: 'userId' });\n * // chat is non-null here, narrowed from T | null\n * ```\n */\nexport function requireOwner<T extends object>(\n resource: T | null | undefined,\n ownerId: string | number | bigint,\n options: RequireOwnerOptions<T> = {},\n): T\n{\n const ownerKey = (options.ownerKey ?? 'ownerId') as keyof T;\n const value = resource ? (resource as Record<PropertyKey, unknown>)[ownerKey] : undefined;\n\n if (!resource || value === null || value === undefined || String(value) !== String(ownerId))\n {\n throw new NotFoundError({ message: options.message ?? 'not found' });\n }\n\n return resource;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/errors/error-registry.ts","../../src/errors/serializable-error.ts","../../src/errors/http-errors.ts","../../src/errors/database-errors.ts","../../src/errors/index.ts","../../src/authz/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Error Registry\n *\n * Central registry for serializable error types.\n * Enables automatic error deserialization on the client side.\n */\n\nimport type { SerializableError } from './serializable-error';\n\n/**\n * Error constructor type\n */\nexport type SerializableErrorConstructor = new (data: any) => SerializableError;\n\n/**\n * Input type for ErrorRegistry constructor\n */\nexport type ErrorRegistryInput =\n | SerializableErrorConstructor\n | SerializableErrorConstructor[]\n | ErrorRegistry;\n\n/**\n * Error registry for serialization/deserialization\n *\n * @example\n * ```typescript\n * // Create registry with initial errors\n * const registry = new ErrorRegistry([\n * errorRegistry, // Another ErrorRegistry\n * PaymentFailedError, // Single error class\n * [RefundError, OrderError], // Array of error classes\n * ]);\n *\n * // Or create empty and append\n * const registry = new ErrorRegistry();\n * registry\n * .append(ValidationError)\n * .append([PaymentFailedError, RefundError]);\n *\n * // Deserialize from JSON\n * const error = registry.deserialize({\n * __type: 'PaymentFailedError',\n * message: 'Payment failed',\n * transactionId: 'tx_123',\n * reason: 'insufficient_funds'\n * });\n *\n * // error instanceof PaymentFailedError === true\n * ```\n */\nexport class ErrorRegistry\n{\n private errors = new Map<string, SerializableErrorConstructor>();\n\n constructor(initialErrors?: ErrorRegistryInput[])\n {\n if (initialErrors)\n {\n for (const input of initialErrors)\n {\n if (input instanceof ErrorRegistry)\n {\n this.concat(input);\n }\n else if (Array.isArray(input))\n {\n this.append(input);\n }\n else\n {\n this.append(input);\n }\n }\n }\n }\n\n /**\n * Append error class(es) to the registry\n *\n * @param ErrorClass - Single error constructor\n * @returns This registry for chaining\n */\n append(ErrorClass: SerializableErrorConstructor): this;\n\n /**\n * Append error class(es) to the registry\n *\n * @param ErrorClasses - Array of error constructors\n * @returns This registry for chaining\n */\n append(ErrorClasses: SerializableErrorConstructor[]): this;\n\n /**\n * Append error class(es) to the registry\n *\n * @param input - Error constructor or array of constructors\n * @returns This registry for chaining\n */\n append(input: SerializableErrorConstructor | SerializableErrorConstructor[]): this\n {\n if (Array.isArray(input))\n {\n for (const ErrorClass of input)\n {\n this.errors.set(ErrorClass.name, ErrorClass);\n }\n }\n else\n {\n this.errors.set(input.name, input);\n }\n\n return this;\n }\n\n /**\n * Concatenate another ErrorRegistry into this one\n *\n * @param registry - Another ErrorRegistry to merge\n * @returns This registry for chaining\n */\n concat(registry: ErrorRegistry): this\n {\n for (const [name, ErrorClass] of registry.errors)\n {\n this.errors.set(name, ErrorClass);\n }\n\n return this;\n }\n\n /**\n * Check if error type is registered\n *\n * @param name - Error class name\n */\n has(name: string): boolean\n {\n return this.errors.has(name);\n }\n\n /**\n * Deserialize error from JSON data\n *\n * @param data - Serialized error data with __type field\n * @returns Deserialized error instance\n * @throws Error if error type is not registered\n */\n deserialize(data: { __type: string; [key: string]: any }): SerializableError\n {\n const ErrorClass = this.errors.get(data.__type);\n\n if (!ErrorClass)\n {\n throw new Error(`Unknown error type: ${data.__type}`);\n }\n\n // `__type` routed this lookup and `error` is the response envelope: both\n // describe the response, not the error. The documented constructor shape\n // is Object.assign(this, data), which would otherwise copy them onto the\n // instance as reserved fields — and a reserved field refuses to serialize\n // the moment a server re-throws this error.\n const { __type: _type, error: _envelope, ...fields } = data;\n\n return new ErrorClass(fields);\n }\n\n /**\n * Try to deserialize error, return null if type unknown\n *\n * @param data - Serialized error data\n * @returns Deserialized error or null\n */\n tryDeserialize(data: { __type?: string; [key: string]: any }): SerializableError | null\n {\n if (!data.__type || !this.has(data.__type))\n {\n return null;\n }\n\n try\n {\n return this.deserialize(data as any);\n }\n catch\n {\n return null;\n }\n }\n\n /**\n * Get all registered error types\n */\n getRegisteredTypes(): string[]\n {\n return Array.from(this.errors.keys());\n }\n}\n","/**\n * Serializable Error Base Class\n *\n * Base class for errors that can be serialized/deserialized across HTTP boundary.\n * Automatically serializes public fields for transmission to client.\n */\n\n// Package specifier, not '../logger': tsup marks `@spfn/*` external, so a\n// relative import would inline a SECOND logger singleton into this entrypoint's\n// bundle — and into every bundle that imports errors (issue #136).\nimport { logger } from '@spfn/core/logger';\n\n/**\n * Serialized error format for JSON transmission\n */\nexport interface SerializedError\n{\n __type: string;\n message: string;\n [key: string]: unknown;\n}\n\n/**\n * Field names an error class may not use.\n *\n * Public fields are spread into the response body next to `__type`, `message`\n * and the `error` envelope the error handler attaches, so a field sharing one\n * of those names collides with the response shape every consumer reads: the\n * web client restores an error class from `__type` and a generated mobile\n * client reads `error.code`. Reserving the three names removes the collision\n * instead of picking a winner for it — either winner loses something the other\n * side needs.\n */\nconst RESERVED_RESPONSE_KEYS = new Set(['__type', 'message', 'error']);\n\n/**\n * Environments where a developer is watching and can still rename the class.\n * Anything else is a running deployment, `staging` included — there the throw\n * would replace a real failure with a failure about serializing it, and the\n * original error would never reach the log or the client.\n */\nconst AUTHORING_ENVIRONMENTS = new Set(['local', 'development', 'test']);\n\n/**\n * Answer a reserved field name: loudly while it can still be renamed, quietly\n * once a rename is no longer possible.\n *\n * While authoring, the throw is the point — the class is renamed the first time\n * a test serializes it.\n */\nfunction refuseReservedKey(className: string, key: string): never | void\n{\n const detail = `${className} declares the reserved field \"${key}\". `\n + `Reserved response keys: ${[...RESERVED_RESPONSE_KEYS].join(', ')}. Rename the field.`;\n\n if (AUTHORING_ENVIRONMENTS.has(process.env.NODE_ENV ?? 'local'))\n {\n throw new Error(detail);\n }\n\n logger.error(`[SerializableError] ${detail} The field is omitted from the response.`);\n}\n\n/**\n * Base class for all serializable errors\n *\n * Features:\n * - Auto-serialization of public fields via toJSON()\n * - Constructor accepts object with all fields\n * - Type-safe error handling with instanceof\n *\n * @example\n * ```typescript\n * class PaymentFailedError extends SerializableError\n * {\n * readonly statusCode = 402;\n * transactionId!: string;\n * reason!: 'insufficient_funds' | 'card_declined';\n *\n * constructor(data: {\n * message: string;\n * transactionId: string;\n * reason: 'insufficient_funds' | 'card_declined';\n * })\n * {\n * super(data.message);\n * this.name = 'PaymentFailedError';\n * Object.assign(this, data);\n * }\n * }\n * ```\n */\nexport abstract class SerializableError extends Error\n{\n /**\n * HTTP status code for this error type\n */\n abstract readonly statusCode: number;\n\n /**\n * Serialize error to JSON-compatible object\n *\n * Automatically includes:\n * - __type: Constructor name for deserialization\n * - message: Error message\n * - All public instance properties (except name, stack)\n */\n toJSON(): SerializedError\n {\n const json: SerializedError = {\n __type: this.constructor.name,\n message: this.message,\n };\n\n // Extract all public instance properties\n for (const key of Object.keys(this))\n {\n // Skip Error built-ins and statusCode (inferred from type)\n if (key === 'name' || key === 'stack' || key === 'statusCode')\n {\n continue;\n }\n\n if (RESERVED_RESPONSE_KEYS.has(key))\n {\n refuseReservedKey(this.constructor.name, key);\n continue;\n }\n\n json[key] = (this as unknown as Record<string, unknown>)[key];\n }\n\n return json;\n }\n}\n","/**\n * HTTP Error Classes\n *\n * Standard HTTP error classes for API responses\n * All errors are serializable for type-safe client-side error handling\n */\n\nimport { SerializableError } from './serializable-error';\n\n/**\n * Base HTTP Error\n *\n * Base class for all HTTP-related errors\n */\nexport class HttpError extends SerializableError\n{\n public readonly statusCode: number;\n public details?: Record<string, unknown>;\n\n constructor(data: {\n message: string;\n statusCode: number;\n details?: Record<string, unknown>;\n })\n {\n super(data.message);\n\n this.name = 'HttpError';\n this.statusCode = data.statusCode;\n\n if (data.details)\n {\n this.details = data.details;\n }\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Bad Request Error (400)\n *\n * Generic bad request - malformed syntax, invalid parameters, etc.\n */\nexport class BadRequestError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Bad request',\n statusCode: 400,\n details: data.details,\n });\n\n this.name = 'BadRequestError';\n }\n}\n\n/**\n * Validation Error (400)\n *\n * Input validation failure (request params, query, body)\n * Used by define-route system for automatic validation\n */\nexport class ValidationError extends HttpError\n{\n fields?: Array<{ path: string; message: string; value?: any }>;\n\n constructor(data: {\n message: string;\n fields?: Array<{ path: string; message: string; value?: any }>;\n details?: Record<string, any>;\n })\n {\n super({\n message: data.message,\n statusCode: 400,\n details: data.details,\n });\n\n this.name = 'ValidationError';\n\n if (data.fields)\n {\n this.fields = data.fields;\n }\n }\n}\n\n/**\n * Unauthorized Error (401)\n *\n * Authentication required or authentication failed\n */\nexport class UnauthorizedError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Authentication required',\n statusCode: 401,\n details: data.details,\n });\n\n this.name = 'UnauthorizedError';\n }\n}\n\n/**\n * Forbidden Error (403)\n *\n * Authenticated but lacks permission to access resource\n */\nexport class ForbiddenError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Access forbidden',\n statusCode: 403,\n details: data.details,\n });\n\n this.name = 'ForbiddenError';\n }\n}\n\n/**\n * Not Found Error (404)\n *\n * Requested resource does not exist\n */\nexport class NotFoundError extends HttpError\n{\n resource?: string;\n\n constructor(data: { message?: string; resource?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Resource not found',\n statusCode: 404,\n details: data.details,\n });\n\n this.name = 'NotFoundError';\n\n if (data.resource)\n {\n this.resource = data.resource;\n }\n }\n}\n\n/**\n * Conflict Error (409)\n *\n * Generic conflict - resource state conflict, concurrent modification, etc.\n */\nexport class ConflictError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Resource conflict',\n statusCode: 409,\n details: data.details,\n });\n\n this.name = 'ConflictError';\n }\n}\n\n/**\n * Gone Error (410)\n *\n * Resource permanently deleted and no longer available\n */\nexport class GoneError extends HttpError\n{\n resource?: string;\n\n constructor(data: { message?: string; resource?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Resource permanently deleted',\n statusCode: 410,\n details: data.details,\n });\n\n this.name = 'GoneError';\n\n if (data.resource)\n {\n this.resource = data.resource;\n }\n }\n}\n\n/**\n * Too Many Requests Error (429)\n *\n * Rate limit exceeded\n */\nexport class TooManyRequestsError extends HttpError\n{\n retryAfter?: number;\n\n constructor(data: {\n message?: string;\n retryAfter?: number;\n details?: Record<string, any>;\n } = {})\n {\n super({\n message: data.message || 'Too many requests',\n statusCode: 429,\n details: data.details,\n });\n\n this.name = 'TooManyRequestsError';\n\n if (data.retryAfter)\n {\n this.retryAfter = data.retryAfter;\n }\n }\n}\n\n/**\n * Internal Server Error (500)\n *\n * Generic server error when no specific error type applies\n */\nexport class InternalServerError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Internal server error',\n statusCode: 500,\n details: data.details,\n });\n\n this.name = 'InternalServerError';\n }\n}\n\n/**\n * Unsupported Media Type Error (415)\n *\n * Media type not supported - invalid file type, content type, etc.\n */\nexport class UnsupportedMediaTypeError extends HttpError\n{\n mediaType?: string;\n supportedTypes?: string[];\n\n constructor(data: {\n message?: string;\n mediaType?: string;\n supportedTypes?: string[];\n details?: Record<string, any>;\n } = {})\n {\n super({\n message: data.message || 'Unsupported media type',\n statusCode: 415,\n details: data.details,\n });\n\n this.name = 'UnsupportedMediaTypeError';\n\n if (data.mediaType)\n {\n this.mediaType = data.mediaType;\n }\n\n if (data.supportedTypes)\n {\n this.supportedTypes = data.supportedTypes;\n }\n }\n}\n\n/**\n * Unprocessable Entity Error (422)\n *\n * Request is well-formed but contains semantic errors\n */\nexport class UnprocessableEntityError extends HttpError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Unprocessable entity',\n statusCode: 422,\n details: data.details,\n });\n\n this.name = 'UnprocessableEntityError';\n }\n}\n\n/**\n * Service Unavailable Error (503)\n *\n * Service temporarily unavailable (maintenance, overload, etc.)\n */\nexport class ServiceUnavailableError extends HttpError\n{\n retryAfter?: number;\n\n constructor(data: {\n message?: string;\n retryAfter?: number;\n details?: Record<string, any>;\n } = {})\n {\n super({\n message: data.message || 'Service unavailable',\n statusCode: 503,\n details: data.details,\n });\n\n this.name = 'ServiceUnavailableError';\n\n if (data.retryAfter)\n {\n this.retryAfter = data.retryAfter;\n }\n }\n}\n","/**\n * Database Error Classes\n *\n * Type-safe error handling with custom error class hierarchy\n * Mapped to HTTP status codes for API responses\n * All errors extend SerializableError for consistent JSON serialization\n */\n\nimport { SerializableError } from './serializable-error';\n\n/**\n * Base Database Error\n *\n * Base class for all database-related errors\n */\nexport class DatabaseError<TDetails extends Record<string, unknown> = Record<string, unknown>>\n extends SerializableError\n{\n public readonly statusCode: number;\n public readonly details?: TDetails;\n\n constructor(data: {\n message: string;\n statusCode?: number;\n details?: TDetails;\n })\n {\n super(data.message);\n this.name = 'DatabaseError';\n this.statusCode = data.statusCode ?? 500;\n this.details = data.details;\n Error.captureStackTrace(this, this.constructor);\n }\n\n /**\n * Whether this error's message/details are derived from the raw database\n * driver (SQL text, table/column/constraint names, parameter values) and\n * therefore must NOT be exposed to clients in production. Defined as a\n * prototype getter so it is never serialized into the response by toJSON().\n * Subclasses with a safe, constructed message override this to `false`.\n */\n get internal(): boolean\n {\n return true;\n }\n}\n\n/**\n * Connection Error (503 Service Unavailable)\n *\n * Database connection failure, connection pool exhaustion, etc.\n */\nexport class ConnectionError extends DatabaseError\n{\n constructor(data: { message: string; details?: Record<string, unknown> })\n {\n super({ message: data.message, statusCode: 503, details: data.details });\n this.name = 'ConnectionError';\n }\n}\n\n/**\n * Query Error (500 Internal Server Error)\n *\n * SQL query execution failure, syntax errors, etc.\n */\nexport class QueryError extends DatabaseError\n{\n constructor(data: {\n message: string;\n statusCode?: number;\n details?: Record<string, unknown>;\n })\n {\n super({\n message: data.message,\n statusCode: data.statusCode ?? 500,\n details: data.details,\n });\n this.name = 'QueryError';\n }\n}\n\n/**\n * Entity Not Found Error (404 Not Found)\n *\n * Database entity does not exist\n */\nexport class EntityNotFoundError extends QueryError\n{\n public readonly resource: string;\n public readonly id: string | number;\n\n constructor(data: { resource: string; id: string | number })\n {\n super({\n message: `${data.resource} with id ${data.id} not found`,\n statusCode: 404,\n details: { resource: data.resource, id: data.id },\n });\n this.name = 'EntityNotFoundError';\n this.resource = data.resource;\n this.id = data.id;\n }\n\n // Message/details are constructed from the resource + id, not driver text\n override get internal(): boolean\n {\n return false;\n }\n}\n\n/**\n * Constraint Violation Error (400 Bad Request)\n *\n * Database constraint violation (NOT NULL, CHECK, FOREIGN KEY, etc.)\n * This is different from HTTP ValidationError which validates request input\n */\nexport class ConstraintViolationError extends QueryError\n{\n constructor(data: { message: string; details?: Record<string, unknown> })\n {\n super({ message: data.message, statusCode: 400, details: data.details });\n this.name = 'ConstraintViolationError';\n }\n}\n\n/**\n * Transaction Error (500 Internal Server Error)\n *\n * Transaction start/commit/rollback failure\n */\nexport class TransactionError extends DatabaseError\n{\n constructor(data: {\n message: string;\n statusCode?: number;\n details?: Record<string, unknown>;\n })\n {\n super({\n message: data.message,\n statusCode: data.statusCode ?? 500,\n details: data.details,\n });\n this.name = 'TransactionError';\n }\n}\n\n/**\n * Deadlock Error (409 Conflict)\n *\n * Database deadlock detected\n */\nexport class DeadlockError extends TransactionError\n{\n constructor(data: { message: string; details?: Record<string, unknown> })\n {\n super({ message: data.message, statusCode: 409, details: data.details });\n this.name = 'DeadlockError';\n }\n}\n\n/**\n * Duplicate Entry Error (409 Conflict)\n *\n * Unique constraint violation (e.g., duplicate email)\n */\nexport class DuplicateEntryError extends QueryError\n{\n public readonly field: string;\n public readonly value: string | number;\n\n constructor(data: { field: string; value: string | number })\n {\n // The client-facing message/details name the field but NOT the value: echoing\n // the value back (e.g. an email) confirms it exists, an enumeration aid. The\n // raw value stays on the instance for server-side handling/logging.\n super({\n message: `${data.field} already exists`,\n statusCode: 409,\n details: { field: data.field },\n });\n this.name = 'DuplicateEntryError';\n this.field = data.field;\n this.value = data.value;\n }\n\n // Field-only message/details — safe to surface to the client (not internal)\n override get internal(): boolean\n {\n return false;\n }\n}\n","/**\n * Error Module Exports\n *\n * Entry point for error handling module with serialization support\n */\n\n// Core Error Registry\n// Pre-configured registry with all built-in HTTP and Database errors\nimport { ErrorRegistry } from './error-registry';\nimport {\n HttpError,\n BadRequestError,\n ValidationError,\n UnauthorizedError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n GoneError,\n TooManyRequestsError,\n UnsupportedMediaTypeError,\n UnprocessableEntityError,\n InternalServerError,\n ServiceUnavailableError,\n} from './http-errors';\nimport {\n DatabaseError,\n ConnectionError,\n QueryError,\n EntityNotFoundError,\n ConstraintViolationError,\n TransactionError,\n DeadlockError,\n DuplicateEntryError,\n} from './database-errors';\n\n// Base Classes\nexport { SerializableError } from './serializable-error';\nexport type { SerializedError } from './serializable-error';\nexport { ErrorRegistry } from './error-registry';\nexport type { SerializableErrorConstructor, ErrorRegistryInput } from './error-registry';\n\n// Database Error Classes\nexport {\n DatabaseError,\n ConnectionError,\n QueryError,\n EntityNotFoundError,\n ConstraintViolationError,\n TransactionError,\n DeadlockError,\n DuplicateEntryError,\n} from './database-errors';\n\n// HTTP Error Classes\nexport {\n HttpError,\n BadRequestError,\n ValidationError,\n UnauthorizedError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n GoneError,\n TooManyRequestsError,\n UnsupportedMediaTypeError,\n UnprocessableEntityError,\n InternalServerError,\n ServiceUnavailableError,\n} from './http-errors';\n\n// Error Utilities\nexport {\n isDatabaseError,\n isHttpError,\n hasStatusCode,\n} from './error-utils';\n\nexport const errorRegistry = new ErrorRegistry();\n\n// HTTP Errors\nerrorRegistry.append([\n HttpError,\n BadRequestError,\n ValidationError,\n UnauthorizedError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n GoneError,\n TooManyRequestsError,\n UnsupportedMediaTypeError,\n UnprocessableEntityError,\n InternalServerError,\n ServiceUnavailableError,\n]);\n\n// Database Errors\nerrorRegistry.append([\n DatabaseError,\n ConnectionError,\n QueryError,\n EntityNotFoundError,\n ConstraintViolationError,\n TransactionError,\n DeadlockError,\n DuplicateEntryError,\n]);\n\nexport * as HttpErrors from './http-errors';\nexport * as DatabaseErrors from './database-errors';\n","/**\n * @spfn/core/authz - Authorization primitives\n *\n * Small, domain-agnostic guards for resource ownership. The point is to make the\n * \"load, then check it belongs to the requester\" step a single call so a handler\n * can't forget it and leak another user's data (IDOR).\n */\n\nimport { NotFoundError } from '../errors';\n\nexport interface RequireOwnerOptions<T>\n{\n /**\n * Property on the resource holding the owner id. Defaults to `'ownerId'`.\n * SPFN entities commonly use `userId` / `createdBy` — pass it explicitly:\n * `requireOwner(doc, userId, { ownerKey: 'userId' })`.\n */\n ownerKey?: keyof T;\n\n /** Message for the thrown NotFoundError. @default 'not found' */\n message?: string;\n}\n\n/**\n * Return the resource only if it exists and belongs to `ownerId`; otherwise throw\n * `NotFoundError`. Not-found and not-owned are deliberately the same response, so\n * the endpoint never reveals that a resource exists to a non-owner.\n *\n * Ids are compared as strings, so number/string/bigint ids interoperate. A\n * missing or null owner value never matches, so it throws.\n *\n * @example\n * ```ts\n * const chat = requireOwner(await chats.findById(id), userId, { ownerKey: 'userId' });\n * // chat is non-null here, narrowed from T | null\n * ```\n */\nexport function requireOwner<T extends object>(\n resource: T | null | undefined,\n ownerId: string | number | bigint,\n options: RequireOwnerOptions<T> = {},\n): T\n{\n const ownerKey = (options.ownerKey ?? 'ownerId') as keyof T;\n const value = resource ? (resource as Record<PropertyKey, unknown>)[ownerKey] : undefined;\n\n if (!resource || value === null || value === undefined || String(value) !== String(ownerId))\n {\n throw new NotFoundError({ message: options.message ?? 'not found' });\n }\n\n return resource;\n}\n"]}
|
package/dist/db/index.d.ts
CHANGED
|
@@ -397,27 +397,6 @@ declare function getDatabaseInfo(): {
|
|
|
397
397
|
providerKind?: string;
|
|
398
398
|
};
|
|
399
399
|
|
|
400
|
-
/**
|
|
401
|
-
* Reconnect Trigger — Query-error driven pool rebuild
|
|
402
|
-
*
|
|
403
|
-
* Complements the periodic health check with a fast-path: when application
|
|
404
|
-
* queries start failing with connection-level errors, we do not wait up to
|
|
405
|
-
* DB_HEALTH_CHECK_INTERVAL (default 60s) to notice. A sliding-window counter
|
|
406
|
-
* trips a force-reconnect as soon as the failure rate crosses a threshold.
|
|
407
|
-
*
|
|
408
|
-
* Why this exists:
|
|
409
|
-
* - postgres.js transparently drops dead sockets and opens new ones on the
|
|
410
|
-
* next query. A single `SELECT 1` on the periodic interval can therefore
|
|
411
|
-
* false-pass while user-facing queries keep hitting the remaining dead
|
|
412
|
-
* sockets in the pool.
|
|
413
|
-
* - This module observes real query errors and, when it sees a burst of
|
|
414
|
-
* connection-level failures, calls triggerForceReconnect() which performs
|
|
415
|
-
* the same atomic-swap rebuild as the health check.
|
|
416
|
-
*
|
|
417
|
-
* Configuration (env vars, hardcoded defaults):
|
|
418
|
-
* - DB_RECONNECT_ERROR_THRESHOLD (default 3): errors needed in window
|
|
419
|
-
* - DB_RECONNECT_ERROR_WINDOW_MS (default 10000): sliding window size
|
|
420
|
-
*/
|
|
421
400
|
/**
|
|
422
401
|
* Determine whether an error looks like a pool/connection failure
|
|
423
402
|
*
|
|
@@ -1139,6 +1118,23 @@ type TransactionDB<TDatabase extends DrizzleDatabase = DefaultDatabase> = Databa
|
|
|
1139
1118
|
* afterCommit callback type
|
|
1140
1119
|
*/
|
|
1141
1120
|
type AfterCommitCallback = () => void | Promise<void>;
|
|
1121
|
+
/**
|
|
1122
|
+
* beforeCommit callback type
|
|
1123
|
+
*/
|
|
1124
|
+
type BeforeCommitCallback = () => void | Promise<void>;
|
|
1125
|
+
/**
|
|
1126
|
+
* afterRollback callback type
|
|
1127
|
+
*/
|
|
1128
|
+
type AfterRollbackCallback = () => void | Promise<void>;
|
|
1129
|
+
/**
|
|
1130
|
+
* Serializes the savepoint frames opened directly off one transaction context
|
|
1131
|
+
*
|
|
1132
|
+
* @see createNestedFrameGate
|
|
1133
|
+
*/
|
|
1134
|
+
type NestedFrameGate = {
|
|
1135
|
+
/** Run `frame` once every frame queued before it on this context has finished */
|
|
1136
|
+
run<T>(frame: () => Promise<T>): Promise<T>;
|
|
1137
|
+
};
|
|
1142
1138
|
/**
|
|
1143
1139
|
* Transaction context stored in AsyncLocalStorage
|
|
1144
1140
|
*/
|
|
@@ -1148,8 +1144,14 @@ type TransactionContext<TDatabase extends DrizzleDatabase = DrizzleDatabase> = {
|
|
|
1148
1144
|
/** Unique transaction ID for logging and tracing */
|
|
1149
1145
|
txId: string;
|
|
1150
1146
|
level: number;
|
|
1147
|
+
/** Callbacks to execute before the root transaction commits (still inside it) */
|
|
1148
|
+
beforeCommitCallbacks: BeforeCommitCallback[];
|
|
1151
1149
|
/** Callbacks to execute after root transaction commits */
|
|
1152
1150
|
afterCommitCallbacks: AfterCommitCallback[];
|
|
1151
|
+
/** Callbacks to execute after the root transaction rolled back */
|
|
1152
|
+
afterRollbackCallbacks: AfterRollbackCallback[];
|
|
1153
|
+
/** Serializes the savepoint frames opened directly off THIS context */
|
|
1154
|
+
nestedFrames: NestedFrameGate;
|
|
1153
1155
|
};
|
|
1154
1156
|
/**
|
|
1155
1157
|
* Get current transaction object and metadata from AsyncLocalStorage
|
|
@@ -1187,7 +1189,7 @@ callback: () => Promise<T>): Promise<T>;
|
|
|
1187
1189
|
*
|
|
1188
1190
|
* @example
|
|
1189
1191
|
* ```typescript
|
|
1190
|
-
* import { onAfterCommit } from '@spfn/core/db
|
|
1192
|
+
* import { onAfterCommit } from '@spfn/core/db';
|
|
1191
1193
|
*
|
|
1192
1194
|
* async function submit(spaceId: string, chatId: string)
|
|
1193
1195
|
* {
|
|
@@ -1201,6 +1203,77 @@ callback: () => Promise<T>): Promise<T>;
|
|
|
1201
1203
|
* ```
|
|
1202
1204
|
*/
|
|
1203
1205
|
declare function onAfterCommit(callback: AfterCommitCallback): void;
|
|
1206
|
+
/**
|
|
1207
|
+
* Register a callback to run just before the current transaction commits
|
|
1208
|
+
*
|
|
1209
|
+
* - Inside a transaction: queued and executed after the root callback resolves,
|
|
1210
|
+
* while the transaction is still open — the callback MAY run statements and
|
|
1211
|
+
* they are part of the same commit
|
|
1212
|
+
* - Outside a transaction: executed immediately with a WARNING (same rationale as
|
|
1213
|
+
* onAfterCommit — there is nothing left to commit), and the abort semantics
|
|
1214
|
+
* below do not apply: there is no transaction for a throw to roll back
|
|
1215
|
+
* - Nested transactions: callbacks bubble up to root transaction
|
|
1216
|
+
* - Callbacks run in registration order, inside the transaction context
|
|
1217
|
+
* (getTransaction() returns the live tx)
|
|
1218
|
+
* - The queue is snapshot before the pass, so a callback registered BY a
|
|
1219
|
+
* beforeCommit callback does not run for this commit — it would otherwise
|
|
1220
|
+
* grow the queue mid-iteration and loop forever inside the open transaction
|
|
1221
|
+
* - A throw ABORTS: later callbacks are skipped, the transaction rolls back,
|
|
1222
|
+
* the error propagates to the caller, and afterRollback callbacks fire
|
|
1223
|
+
*
|
|
1224
|
+
* @example
|
|
1225
|
+
* ```typescript
|
|
1226
|
+
* import { runInTransaction, onBeforeCommit } from '@spfn/core/db';
|
|
1227
|
+
*
|
|
1228
|
+
* async function transfer(fromId: string, toId: string, amount: number)
|
|
1229
|
+
* {
|
|
1230
|
+
* // The transaction is what gives the check teeth — registered outside one,
|
|
1231
|
+
* // the callback runs immediately and its throw aborts nothing.
|
|
1232
|
+
* await runInTransaction(async () =>
|
|
1233
|
+
* {
|
|
1234
|
+
* await accountRepo.debit(fromId, amount);
|
|
1235
|
+
* await accountRepo.credit(toId, amount);
|
|
1236
|
+
*
|
|
1237
|
+
* // Last-moment invariant check: a throw here rolls the whole transfer back.
|
|
1238
|
+
* onBeforeCommit(() => assertNoNegativeBalance(fromId));
|
|
1239
|
+
* });
|
|
1240
|
+
* }
|
|
1241
|
+
* ```
|
|
1242
|
+
*/
|
|
1243
|
+
declare function onBeforeCommit(callback: BeforeCommitCallback): void;
|
|
1244
|
+
/**
|
|
1245
|
+
* Register a callback to run after the current transaction rolled back
|
|
1246
|
+
*
|
|
1247
|
+
* - Inside a transaction: queued and executed after the ROOT transaction rolled
|
|
1248
|
+
* back, before the causing error leaves runInTransaction / the middleware
|
|
1249
|
+
* - Outside a transaction: no-op with a warning — there is no rollback to wait for
|
|
1250
|
+
* - Nested transactions: callbacks bubble up to root transaction. A nested
|
|
1251
|
+
* rollback that the root survives does NOT fire them; these hooks are about
|
|
1252
|
+
* the root transaction's fate, not a savepoint's
|
|
1253
|
+
* - Callbacks run outside the transaction context (new connection for DB access)
|
|
1254
|
+
* - Errors are logged but never thrown: the original error keeps propagating
|
|
1255
|
+
* unchanged, never replaced by a callback failure
|
|
1256
|
+
*
|
|
1257
|
+
* @example
|
|
1258
|
+
* ```typescript
|
|
1259
|
+
* import { runInTransaction, onAfterRollback } from '@spfn/core/db';
|
|
1260
|
+
*
|
|
1261
|
+
* async function importAvatar(userId: string, file: Blob)
|
|
1262
|
+
* {
|
|
1263
|
+
* // Upload first: external I/O never belongs inside the transaction.
|
|
1264
|
+
* const key = await objectStore.put(file);
|
|
1265
|
+
*
|
|
1266
|
+
* await runInTransaction(async () =>
|
|
1267
|
+
* {
|
|
1268
|
+
* await userRepo.updateAvatar(userId, key);
|
|
1269
|
+
*
|
|
1270
|
+
* // The upload cannot roll back on its own — undo it if the write never lands.
|
|
1271
|
+
* onAfterRollback(() => objectStore.delete(key));
|
|
1272
|
+
* });
|
|
1273
|
+
* }
|
|
1274
|
+
* ```
|
|
1275
|
+
*/
|
|
1276
|
+
declare function onAfterRollback(callback: AfterRollbackCallback): void;
|
|
1204
1277
|
|
|
1205
1278
|
/**
|
|
1206
1279
|
* Transaction middleware options
|
|
@@ -1245,6 +1318,21 @@ interface TransactionalOptions {
|
|
|
1245
1318
|
* @default 30000 (30s) or TRANSACTION_IDLE_TIMEOUT environment variable
|
|
1246
1319
|
*/
|
|
1247
1320
|
idleTimeout?: number;
|
|
1321
|
+
/**
|
|
1322
|
+
* Run in an independent transaction instead of joining an ambient one.
|
|
1323
|
+
*
|
|
1324
|
+
* Only bites when the middleware itself runs nested — a sub-app mounted
|
|
1325
|
+
* under a route that already applied `Transactional()`, or a handler invoked
|
|
1326
|
+
* from inside `runInTransaction`. By default that inner run takes a SAVEPOINT
|
|
1327
|
+
* on the outer transaction; `requiresNew: true` gives it a real `BEGIN` on a
|
|
1328
|
+
* second pooled connection, with its own timeouts and its own hook queues.
|
|
1329
|
+
*
|
|
1330
|
+
* See `RunInTransactionOptions.requiresNew` for the pool and self-deadlock
|
|
1331
|
+
* costs — they apply here unchanged.
|
|
1332
|
+
*
|
|
1333
|
+
* @default false
|
|
1334
|
+
*/
|
|
1335
|
+
requiresNew?: boolean;
|
|
1248
1336
|
}
|
|
1249
1337
|
/**
|
|
1250
1338
|
* Transaction middleware for Hono routes
|
|
@@ -1282,6 +1370,9 @@ interface TransactionalOptions {
|
|
|
1282
1370
|
* - Success: Auto-commit
|
|
1283
1371
|
* - Error: Auto-rollback
|
|
1284
1372
|
* - Detects context.error to trigger rollback
|
|
1373
|
+
* - Hooks: this delegates to runInTransaction, so onBeforeCommit, onAfterCommit
|
|
1374
|
+
* and onAfterRollback behave exactly as they do there. afterRollback callbacks
|
|
1375
|
+
* have already run by the time the error reaches the conversion below.
|
|
1285
1376
|
*
|
|
1286
1377
|
* 📊 Transaction logging:
|
|
1287
1378
|
* - Auto-logs transaction start/commit/rollback
|
|
@@ -1317,8 +1408,12 @@ interface RunInTransactionOptions {
|
|
|
1317
1408
|
* - `timeout: undefined` - Uses default (30s or TRANSACTION_TIMEOUT env var)
|
|
1318
1409
|
* - `timeout: N` - Sets timeout to N milliseconds (1 to 2147483647)
|
|
1319
1410
|
*
|
|
1320
|
-
* Note: Timeout is only applied to root transactions.
|
|
1321
|
-
*
|
|
1411
|
+
* Note: Timeout is only applied to root transactions. A nested call takes a
|
|
1412
|
+
* SAVEPOINT on the outer transaction's connection, where the outer
|
|
1413
|
+
* transaction's `SET LOCAL statement_timeout` is already in force — so the
|
|
1414
|
+
* nested call genuinely inherits it, and its own `timeout` is ignored (a
|
|
1415
|
+
* warning is logged when the caller passed one explicitly). A
|
|
1416
|
+
* `requiresNew: true` call is a root and gets its own.
|
|
1322
1417
|
*
|
|
1323
1418
|
* @default 30000 (30 seconds) or TRANSACTION_TIMEOUT environment variable
|
|
1324
1419
|
*
|
|
@@ -1355,6 +1450,48 @@ interface RunInTransactionOptions {
|
|
|
1355
1450
|
* @default 'transaction'
|
|
1356
1451
|
*/
|
|
1357
1452
|
context?: string;
|
|
1453
|
+
/**
|
|
1454
|
+
* Run in an independent transaction instead of joining an ambient one.
|
|
1455
|
+
*
|
|
1456
|
+
* By default a call made while another transaction is open takes a SAVEPOINT
|
|
1457
|
+
* on that transaction's connection: its writes commit or roll back with the
|
|
1458
|
+
* outer transaction. `requiresNew: true` opens a real `BEGIN` on a SECOND
|
|
1459
|
+
* pooled connection instead, so the work commits on its own and survives an
|
|
1460
|
+
* outer rollback — an audit trail or a failed-attempt record, for example.
|
|
1461
|
+
*
|
|
1462
|
+
* Being a root transaction, it gets its own `statement_timeout`,
|
|
1463
|
+
* `idle_in_transaction_session_timeout`, and its OWN hook queues:
|
|
1464
|
+
* `onBeforeCommit` / `onAfterCommit` / `onAfterRollback` registered inside it
|
|
1465
|
+
* fire on ITS outcome, not the outer transaction's.
|
|
1466
|
+
*
|
|
1467
|
+
* Two costs, both consequences of the second connection:
|
|
1468
|
+
* - It holds a second connection for its whole duration, so it counts twice
|
|
1469
|
+
* against the pool. Keep it short and don't fan it out.
|
|
1470
|
+
* - It cannot see the outer transaction's uncommitted writes, and it BLOCKS
|
|
1471
|
+
* on any row the outer transaction has locked. Since the outer transaction
|
|
1472
|
+
* is waiting for this call to return, that block is a self-deadlock that
|
|
1473
|
+
* only `statement_timeout` breaks. Never touch rows the outer transaction
|
|
1474
|
+
* wrote.
|
|
1475
|
+
*
|
|
1476
|
+
* @default false
|
|
1477
|
+
*
|
|
1478
|
+
* @example
|
|
1479
|
+
* ```typescript
|
|
1480
|
+
* await runInTransaction(async () =>
|
|
1481
|
+
* {
|
|
1482
|
+
* await orderRepo.create(order);
|
|
1483
|
+
*
|
|
1484
|
+
* // Lands even if the order below rolls the outer transaction back.
|
|
1485
|
+
* await runInTransaction(
|
|
1486
|
+
* () => auditRepo.record('order.attempted', order.id),
|
|
1487
|
+
* { requiresNew: true },
|
|
1488
|
+
* );
|
|
1489
|
+
*
|
|
1490
|
+
* await inventoryRepo.reserve(order.items); // may throw
|
|
1491
|
+
* });
|
|
1492
|
+
* ```
|
|
1493
|
+
*/
|
|
1494
|
+
requiresNew?: boolean;
|
|
1358
1495
|
}
|
|
1359
1496
|
/**
|
|
1360
1497
|
* Run a callback function within a database transaction
|
|
@@ -1366,6 +1503,15 @@ interface RunInTransactionOptions {
|
|
|
1366
1503
|
* - Warns about slow transactions
|
|
1367
1504
|
* - Enforces timeout if configured
|
|
1368
1505
|
*
|
|
1506
|
+
* Called with a transaction already open on the async call chain, it takes a
|
|
1507
|
+
* SAVEPOINT on that transaction rather than opening an independent one: the work
|
|
1508
|
+
* runs on the same connection, sees the outer transaction's uncommitted writes,
|
|
1509
|
+
* and commits with it. A throw that the caller catches unwinds to the SAVEPOINT
|
|
1510
|
+
* and leaves the outer transaction healthy; a throw that propagates rolls the
|
|
1511
|
+
* whole thing back. Nested calls off one transaction are serialized — see
|
|
1512
|
+
* `openTransaction` — so `Promise.all` over them runs them one at a time. Pass
|
|
1513
|
+
* `requiresNew: true` for an independent transaction on its own connection.
|
|
1514
|
+
*
|
|
1369
1515
|
* Errors are propagated to the caller without modification.
|
|
1370
1516
|
* Caller is responsible for error handling and conversion.
|
|
1371
1517
|
*
|
|
@@ -1680,11 +1826,11 @@ declare function count<T extends PgTable>(table: T, where?: WhereObject<InferSel
|
|
|
1680
1826
|
*
|
|
1681
1827
|
* @example With Transactions
|
|
1682
1828
|
* ```typescript
|
|
1683
|
-
* import {
|
|
1829
|
+
* import { runInTransaction } from '@spfn/core/db';
|
|
1684
1830
|
*
|
|
1685
1831
|
* const userRepo = new UserRepository();
|
|
1686
1832
|
*
|
|
1687
|
-
* await
|
|
1833
|
+
* await runInTransaction(async () => {
|
|
1688
1834
|
* // Both db and readDb automatically use the transaction context
|
|
1689
1835
|
* const user = await userRepo.create({ name: 'John' });
|
|
1690
1836
|
* await userRepo.findById(user.id); // Uses same transaction
|
|
@@ -2006,4 +2152,4 @@ declare abstract class BaseRepository<TRelations extends AnyRelations = EmptyRel
|
|
|
2006
2152
|
protected _count<T extends PgTable>(table: T, where?: Record<string, any> | SQL | undefined): Promise<number>;
|
|
2007
2153
|
}
|
|
2008
2154
|
|
|
2009
|
-
export { type AfterCommitCallback, BaseRepository, type DatabaseClients, type DatabaseInitOptions, type DatabaseOptions, type DatabaseProvider, type DatabaseTransaction, type DefaultDatabase, type DrizzleConfigOptions, type DrizzleDatabase, type FunctionMigrationEntry, type FunctionMigrationInfo, type MigrationStatus, type MigrationStatusDb, type MigrationTargetStatus, PROJECT_MIGRATIONS_TABLE, PROJECT_TARGET_NAME, type PoolConfig, RUN_MIGRATIONS_HINT, type RepositoryDatabase, RepositoryError, type RetryConfig, type RunInTransactionOptions, type TransactionContext, type TransactionDB, Transactional, type TransactionalOptions, auditFields, checkConnection, closeDatabase, collectMigrationStatus, count, countPendingMigrations, create, createDatabaseConnection, createDatabaseFromEnv, createMany, createSchema, deleteMany, deleteOne, detectDialect, discoverFunctionMigrations, enumText, filterPendingEntries, findMany, findOne, forceReconnectDatabase, foreignKey, formatPendingMigrations, fromPostgresError, functionMigrationsTable, generateDrizzleConfigFile, getDatabase, getDatabaseInfo, getDrizzleConfig, getSchemaInfo, getTransaction, getTransactionContext, hasMigrationTargets, id, initDatabase, isConnectionLevelError, migrationTargets, onAfterCommit, optionalForeignKey, packageNameToSchema, pendingMigrationTargets, pendingMigrationsSummary, projectMigrationsDir, publishingFields, readMigrationEntries, reportDatabaseError, resetConnectionErrorCounter, runInTransaction, runWithTransaction, setDatabase, setDatabaseProvider, softDelete, timestamps, typedJsonb, updateMany, updateOne, upsert, utcTimestamp, uuid, verificationTimestamp };
|
|
2155
|
+
export { type AfterCommitCallback, type AfterRollbackCallback, BaseRepository, type BeforeCommitCallback, type DatabaseClients, type DatabaseInitOptions, type DatabaseOptions, type DatabaseProvider, type DatabaseTransaction, type DefaultDatabase, type DrizzleConfigOptions, type DrizzleDatabase, type FunctionMigrationEntry, type FunctionMigrationInfo, type MigrationStatus, type MigrationStatusDb, type MigrationTargetStatus, type NestedFrameGate, PROJECT_MIGRATIONS_TABLE, PROJECT_TARGET_NAME, type PoolConfig, RUN_MIGRATIONS_HINT, type RepositoryDatabase, RepositoryError, type RetryConfig, type RunInTransactionOptions, type TransactionContext, type TransactionDB, Transactional, type TransactionalOptions, auditFields, checkConnection, closeDatabase, collectMigrationStatus, count, countPendingMigrations, create, createDatabaseConnection, createDatabaseFromEnv, createMany, createSchema, deleteMany, deleteOne, detectDialect, discoverFunctionMigrations, enumText, filterPendingEntries, findMany, findOne, forceReconnectDatabase, foreignKey, formatPendingMigrations, fromPostgresError, functionMigrationsTable, generateDrizzleConfigFile, getDatabase, getDatabaseInfo, getDrizzleConfig, getSchemaInfo, getTransaction, getTransactionContext, hasMigrationTargets, id, initDatabase, isConnectionLevelError, migrationTargets, onAfterCommit, onAfterRollback, onBeforeCommit, optionalForeignKey, packageNameToSchema, pendingMigrationTargets, pendingMigrationsSummary, projectMigrationsDir, publishingFields, readMigrationEntries, reportDatabaseError, resetConnectionErrorCounter, runInTransaction, runWithTransaction, setDatabase, setDatabaseProvider, softDelete, timestamps, typedJsonb, updateMany, updateOne, upsert, utcTimestamp, uuid, verificationTimestamp };
|