@spfn/core 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +580 -0
- package/dist/auto-loader-C44TcLmM.d.ts +125 -0
- package/dist/bind-pssq1NRT.d.ts +34 -0
- package/dist/client/index.d.ts +174 -0
- package/dist/client/index.js +179 -0
- package/dist/client/index.js.map +1 -0
- package/dist/codegen/index.d.ts +126 -0
- package/dist/codegen/index.js +970 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/db/index.d.ts +83 -0
- package/dist/db/index.js +2099 -0
- package/dist/db/index.js.map +1 -0
- package/dist/index.d.ts +379 -0
- package/dist/index.js +13042 -0
- package/dist/index.js.map +1 -0
- package/dist/postgres-errors-CY_Es8EJ.d.ts +1703 -0
- package/dist/route/index.d.ts +72 -0
- package/dist/route/index.js +442 -0
- package/dist/route/index.js.map +1 -0
- package/dist/scripts/index.d.ts +24 -0
- package/dist/scripts/index.js +1157 -0
- package/dist/scripts/index.js.map +1 -0
- package/dist/scripts/templates/api-index.template.txt +10 -0
- package/dist/scripts/templates/api-tag.template.txt +11 -0
- package/dist/scripts/templates/contract.template.txt +87 -0
- package/dist/scripts/templates/entity-type.template.txt +31 -0
- package/dist/scripts/templates/entity.template.txt +19 -0
- package/dist/scripts/templates/index.template.txt +10 -0
- package/dist/scripts/templates/repository.template.txt +37 -0
- package/dist/scripts/templates/routes-id.template.txt +59 -0
- package/dist/scripts/templates/routes-index.template.txt +44 -0
- package/dist/server/index.d.ts +303 -0
- package/dist/server/index.js +12923 -0
- package/dist/server/index.js.map +1 -0
- package/dist/types-SlzTr8ZO.d.ts +143 -0
- package/package.json +119 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/codegen/contract-scanner.ts","../../src/codegen/route-scanner.ts","../../src/codegen/client-generator.ts","../../src/logger/adapters/pino.ts","../../src/logger/logger.ts","../../src/logger/types.ts","../../src/logger/formatters.ts","../../src/logger/transports/console.ts","../../src/logger/transports/file.ts","../../src/logger/config.ts","../../src/logger/adapters/custom.ts","../../src/logger/adapter-factory.ts","../../src/codegen/watch-generate.ts"],"names":["join"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Contract Scanner\n *\n * Scans server/contracts directory and extracts exported contracts\n */\n\nimport { readdir, stat } from 'fs/promises';\nimport { join } from 'path';\nimport * as ts from 'typescript';\nimport { readFileSync } from 'fs';\nimport type { RouteContractMapping, HttpMethod } from './types.js';\n\n/**\n * Scan routes directory for contract.ts files and extract contract exports\n *\n * @param routesDir - Path to server/routes directory\n * @returns Array of contract-to-route mappings\n */\nexport async function scanContracts(routesDir: string): Promise<RouteContractMapping[]>\n{\n const contractFiles = await scanContractFiles(routesDir);\n const mappings: RouteContractMapping[] = [];\n\n for (let i = 0; i < contractFiles.length; i++)\n {\n const filePath = contractFiles[i];\n const exports = extractContractExports(filePath);\n\n // Calculate base path from file location: routes/posts/contract.ts โ /posts\n const basePath = getBasePathFromFile(filePath, routesDir);\n\n for (let j = 0; j < exports.length; j++)\n {\n const contractExport = exports[j];\n\n // Combine base path with contract path: /posts + / โ /posts\n const fullPath = combinePaths(basePath, contractExport.path);\n\n mappings.push({\n method: contractExport.method,\n path: fullPath,\n contractName: contractExport.name,\n contractImportPath: getImportPathFromRoutes(filePath, routesDir),\n routeFile: '', // Not needed anymore\n contractFile: filePath\n });\n }\n }\n\n return mappings;\n}\n\n/**\n * Recursively scan for contract.ts files in routes directory\n */\nasync function scanContractFiles(dir: string, files: string[] = []): Promise<string[]>\n{\n try\n {\n const entries = await readdir(dir);\n\n for (let i = 0; i < entries.length; i++)\n {\n const entry = entries[i];\n const fullPath = join(dir, entry);\n const fileStat = await stat(fullPath);\n\n if (fileStat.isDirectory())\n {\n await scanContractFiles(fullPath, files);\n }\n else if (entry === 'contract.ts')\n {\n files.push(fullPath);\n }\n }\n }\n catch (error)\n {\n // Directory doesn't exist or not readable\n }\n\n return files;\n}\n\n/**\n * Contract export information\n */\ninterface ContractExport\n{\n name: string;\n method: HttpMethod;\n path: string;\n}\n\n/**\n * Extract contract exports from a TypeScript file\n *\n * Looks for exports with structure:\n * export const xxxContract = {\n * method: 'GET',\n * path: '/users',\n * ...\n * }\n */\nfunction extractContractExports(filePath: string): ContractExport[]\n{\n const sourceCode = readFileSync(filePath, 'utf-8');\n const sourceFile = ts.createSourceFile(\n filePath,\n sourceCode,\n ts.ScriptTarget.Latest,\n true\n );\n\n const exports: ContractExport[] = [];\n\n function visit(node: ts.Node): void\n {\n // Look for: export const xxxContract = { ... }\n if (ts.isVariableStatement(node))\n {\n // Check if it has export modifier\n const hasExport = node.modifiers?.some(\n m => m.kind === ts.SyntaxKind.ExportKeyword\n );\n\n if (hasExport && node.declarationList.declarations.length > 0)\n {\n const declaration = node.declarationList.declarations[0];\n\n if (\n ts.isVariableDeclaration(declaration) &&\n ts.isIdentifier(declaration.name) &&\n declaration.initializer &&\n ts.isObjectLiteralExpression(declaration.initializer)\n )\n {\n const name = declaration.name.text;\n\n // Check if name looks like a contract\n if (isContractName(name))\n {\n const contractData = extractContractData(declaration.initializer);\n\n if (contractData.method && contractData.path)\n {\n exports.push({\n name,\n method: contractData.method,\n path: contractData.path\n });\n }\n }\n }\n }\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return exports;\n}\n\n/**\n * Extract method and path from contract object literal\n */\nfunction extractContractData(objectLiteral: ts.ObjectLiteralExpression): {\n method?: HttpMethod;\n path?: string;\n}\n{\n const result: { method?: HttpMethod; path?: string } = {};\n\n for (let i = 0; i < objectLiteral.properties.length; i++)\n {\n const prop = objectLiteral.properties[i];\n\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name)\n )\n {\n const propName = prop.name.text;\n\n if (propName === 'method')\n {\n // Handle both 'GET' and 'GET' as const\n let value: string | undefined;\n if (ts.isStringLiteral(prop.initializer))\n {\n value = prop.initializer.text;\n }\n else if (ts.isAsExpression(prop.initializer) && ts.isStringLiteral(prop.initializer.expression))\n {\n value = prop.initializer.expression.text;\n }\n if (value) result.method = value as HttpMethod;\n }\n else if (propName === 'path')\n {\n // Handle both '/path' and '/path' as const\n let value: string | undefined;\n if (ts.isStringLiteral(prop.initializer))\n {\n value = prop.initializer.text;\n }\n else if (ts.isAsExpression(prop.initializer) && ts.isStringLiteral(prop.initializer.expression))\n {\n value = prop.initializer.expression.text;\n }\n if (value) result.path = value;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Check if a name looks like a contract\n */\nfunction isContractName(name: string): boolean\n{\n return (\n name.indexOf('Contract') !== -1 ||\n name.indexOf('contract') !== -1 ||\n name.endsWith('Schema') ||\n name.endsWith('schema')\n );\n}\n\n/**\n * Get base URL path from contract file location\n *\n * @example\n * routes/posts/contract.ts โ /posts\n * routes/users/[id]/contract.ts โ /users/:id\n * routes/index/contract.ts โ /\n */\nfunction getBasePathFromFile(filePath: string, routesDir: string): string\n{\n // Get relative path from routes dir\n let relativePath = filePath.replace(routesDir, '');\n\n // Remove leading slash\n if (relativePath.startsWith('/'))\n {\n relativePath = relativePath.slice(1);\n }\n\n // Remove /contract.ts\n relativePath = relativePath.replace('/contract.ts', '');\n\n // Handle index โ /\n if (relativePath === 'index' || relativePath === '')\n {\n return '/';\n }\n\n // Split into segments\n const segments = relativePath.split('/');\n const transformed: string[] = [];\n\n for (let i = 0; i < segments.length; i++)\n {\n const seg = segments[i];\n\n // Skip 'index' segments (routes/index/contract.ts โ /, routes/posts/index/contract.ts โ /posts)\n if (seg === 'index')\n {\n continue;\n }\n\n // Dynamic parameter: [id] โ :id\n if (seg.startsWith('[') && seg.endsWith(']'))\n {\n transformed.push(':' + seg.slice(1, -1));\n }\n // Static segment\n else\n {\n transformed.push(seg);\n }\n }\n\n // If no segments remain, return root\n if (transformed.length === 0)\n {\n return '/';\n }\n\n return '/' + transformed.join('/');\n}\n\n/**\n * Combine base path with contract path\n *\n * @example\n * combinePaths('/posts', '/') โ /posts\n * combinePaths('/posts', '/:id') โ /posts/:id\n * combinePaths('/', '/health') โ /health\n */\nfunction combinePaths(basePath: string, contractPath: string): string\n{\n // Normalize paths\n basePath = basePath || '/';\n contractPath = contractPath || '/';\n\n // Remove trailing slash from base\n if (basePath.endsWith('/') && basePath !== '/')\n {\n basePath = basePath.slice(0, -1);\n }\n\n // If contract path is absolute, use it as is\n if (contractPath.startsWith('/') && contractPath !== '/')\n {\n // If base is /, just use contract path\n if (basePath === '/')\n {\n return contractPath;\n }\n // Otherwise combine: /posts + /sub โ /posts/sub\n return basePath + contractPath;\n }\n\n // Contract path is / or relative\n if (contractPath === '/')\n {\n return basePath;\n }\n\n // Combine: /posts + id โ /posts/id\n return basePath + '/' + contractPath;\n}\n\n/**\n * Get import path for contract file\n *\n * @example\n * routes/posts/contract.ts โ @/server/routes/posts/contract\n * routes/users/[id]/contract.ts โ @/server/routes/users/[id]/contract\n */\nfunction getImportPathFromRoutes(filePath: string, routesDir: string): string\n{\n // Get relative path from routes dir\n let relativePath = filePath.replace(routesDir, '');\n\n // Remove leading slash\n if (relativePath.startsWith('/'))\n {\n relativePath = relativePath.slice(1);\n }\n\n // Remove .ts extension\n if (relativePath.endsWith('.ts'))\n {\n relativePath = relativePath.slice(0, -3);\n }\n\n // Return as module path\n return '@/server/routes/' + relativePath;\n}","/**\n * Route Scanner Utilities\n *\n * Helper functions for grouping and organizing route-contract mappings\n */\n\nimport type { RouteContractMapping } from './types.js';\n\n/**\n * Group mappings by resource\n */\nexport function groupByResource(mappings: RouteContractMapping[]): Record<string, RouteContractMapping[]>\n{\n const grouped: Record<string, RouteContractMapping[]> = {};\n\n for (let i = 0; i < mappings.length; i++)\n {\n const mapping = mappings[i];\n const resource = extractResourceName(mapping.path);\n\n if (!grouped[resource])\n {\n grouped[resource] = [];\n }\n\n grouped[resource].push(mapping);\n }\n\n return grouped;\n}\n\n/**\n * Extract resource name from path\n *\n * Examples:\n * - /users โ users\n * - /users/:id โ users\n * - /users/:id/posts โ usersPosts\n */\nfunction extractResourceName(path: string): string\n{\n // Remove leading slash\n const segments = path.slice(1).split('/').filter(s => s && s !== '*');\n\n // Remove dynamic segments\n const staticSegments: string[] = [];\n for (let i = 0; i < segments.length; i++)\n {\n const seg = segments[i];\n if (!seg.startsWith(':'))\n {\n staticSegments.push(seg);\n }\n }\n\n // Join with camelCase\n if (staticSegments.length === 0)\n {\n return 'root';\n }\n if (staticSegments.length === 1)\n {\n return staticSegments[0];\n }\n\n // Convert to camelCase: users/posts โ usersPosts\n const result: string[] = [staticSegments[0]];\n for (let i = 1; i < staticSegments.length; i++)\n {\n const seg = staticSegments[i];\n result.push(seg.charAt(0).toUpperCase() + seg.slice(1));\n }\n\n return result.join('');\n}","/**\n * Client Code Generator\n *\n * Generates type-safe API client code from route-contract mappings\n */\n\nimport { writeFile, mkdir } from 'fs/promises';\nimport { dirname } from 'path';\nimport { groupByResource } from './route-scanner.js';\nimport type { RouteContractMapping, GenerationStats, ClientGenerationOptions } from './types.js';\n\n/**\n * Generate API client code\n */\nexport async function generateClient(\n mappings: RouteContractMapping[],\n options: ClientGenerationOptions\n): Promise<GenerationStats>\n{\n const startTime = Date.now();\n\n // Group by resource\n const grouped = groupByResource(mappings);\n const resourceNames = Object.keys(grouped);\n\n // Generate code\n const code = generateClientCode(mappings, grouped, options);\n\n // Ensure output directory exists\n await mkdir(dirname(options.outputPath), { recursive: true });\n\n // Write file\n await writeFile(options.outputPath, code, 'utf-8');\n\n // Calculate stats\n const stats: GenerationStats = {\n routesScanned: mappings.length,\n contractsFound: mappings.length,\n contractFiles: countUniqueContractFiles(mappings),\n resourcesGenerated: resourceNames.length,\n methodsGenerated: mappings.length,\n duration: Date.now() - startTime\n };\n\n return stats;\n}\n\n/**\n * Generate the actual client code\n */\nfunction generateClientCode(\n mappings: RouteContractMapping[],\n grouped: Record<string, RouteContractMapping[]>,\n options: ClientGenerationOptions\n): string\n{\n let code = '';\n\n // Header\n code += generateHeader();\n\n // Imports\n code += generateImports(mappings, options);\n\n // API object\n code += generateApiObject(grouped, options);\n\n // Footer\n code += generateFooter();\n\n return code;\n}\n\n/**\n * Generate file header\n */\nfunction generateHeader(): string\n{\n return `/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated ${new Date().toISOString()}\n */\n\n`;\n}\n\n/**\n * Generate imports section\n */\nfunction generateImports(mappings: RouteContractMapping[], options: ClientGenerationOptions): string\n{\n let code = '';\n\n // Core imports - use singleton client\n code += `import { client } from '@spfn/core/client';\\n`;\n\n if (options.includeTypes !== false)\n {\n code += `import type { InferContract } from '@spfn/core';\\n`;\n }\n\n code += `\\n`;\n\n // Contract imports (group by import path)\n const importGroups = groupContractsByImportPath(mappings);\n const importPaths = Object.keys(importGroups);\n\n for (let i = 0; i < importPaths.length; i++)\n {\n const importPath = importPaths[i];\n const contracts = importGroups[importPath];\n\n code += `import { ${contracts.join(', ')} } from '${importPath}';\\n`;\n }\n\n code += `\\n`;\n\n return code;\n}\n\n/**\n * Group contracts by their import path\n */\nfunction groupContractsByImportPath(mappings: RouteContractMapping[]): Record<string, string[]>\n{\n const groups: Record<string, Set<string>> = {};\n\n for (let i = 0; i < mappings.length; i++)\n {\n const mapping = mappings[i];\n const path = mapping.contractImportPath;\n\n if (!groups[path])\n {\n groups[path] = new Set();\n }\n\n groups[path].add(mapping.contractName);\n }\n\n // Convert Set to Array\n const result: Record<string, string[]> = {};\n const keys = Object.keys(groups);\n\n for (let i = 0; i < keys.length; i++)\n {\n const key = keys[i];\n result[key] = Array.from(groups[key]);\n }\n\n return result;\n}\n\n/**\n * Generate API object with all methods\n */\nfunction generateApiObject(\n grouped: Record<string, RouteContractMapping[]>,\n options: ClientGenerationOptions\n): string\n{\n let code = '';\n\n code += `/**\n * Type-safe API client\n */\nexport const api = {\\n`;\n\n const resourceNames = Object.keys(grouped);\n\n for (let i = 0; i < resourceNames.length; i++)\n {\n const resourceName = resourceNames[i];\n const routes = grouped[resourceName];\n\n code += ` ${resourceName}: {\\n`;\n\n for (let j = 0; j < routes.length; j++)\n {\n const route = routes[j];\n code += generateMethodCode(route, options);\n }\n\n code += ` }`;\n\n if (i < resourceNames.length - 1)\n {\n code += `,`;\n }\n\n code += `\\n`;\n }\n\n code += `} as const;\\n\\n`;\n\n return code;\n}\n\n/**\n * Generate a single method\n */\nfunction generateMethodCode(mapping: RouteContractMapping, options: ClientGenerationOptions): string\n{\n const methodName = generateMethodName(mapping);\n const contractType = `typeof ${mapping.contractName}`;\n const hasParams = mapping.path.includes(':');\n const hasQuery = false; // TODO: detect from contract\n const hasBody = ['POST', 'PUT', 'PATCH'].indexOf(mapping.method) !== -1;\n\n let code = '';\n\n // JSDoc\n if (options.includeJsDoc !== false)\n {\n code += ` /**\\n`;\n code += ` * ${mapping.method} ${mapping.path}\\n`;\n code += ` */\\n`;\n }\n\n // Method signature\n code += ` ${methodName}: (`;\n\n // Parameters\n const params: string[] = [];\n\n if (hasParams)\n {\n params.push(`params: InferContract<${contractType}>['params']`);\n }\n\n if (hasQuery)\n {\n params.push(`query?: InferContract<${contractType}>['query']`);\n }\n\n if (hasBody)\n {\n params.push(`body: InferContract<${contractType}>['body']`);\n }\n\n if (params.length > 0)\n {\n code += `options: { ${params.join(', ')} }`;\n }\n\n code += `) => `;\n\n // Return type\n code += `client.call('${mapping.path}', ${mapping.contractName}, `;\n\n if (params.length > 0)\n {\n code += `options`;\n }\n else\n {\n code += `{}`;\n }\n\n code += `),\\n`;\n\n return code;\n}\n\n/**\n * Generate method name from route\n */\nfunction generateMethodName(mapping: RouteContractMapping): string\n{\n const method = mapping.method.toLowerCase();\n\n // For index routes\n if (mapping.path === '/' || mapping.path.match(/^\\/[\\w-]+$/))\n {\n // Simple path like /users -> get, create, update\n if (method === 'get')\n {\n return 'list';\n }\n if (method === 'post')\n {\n return 'create';\n }\n }\n\n // For dynamic routes like /users/:id\n if (mapping.path.includes(':'))\n {\n if (method === 'get')\n {\n return 'getById';\n }\n if (method === 'put' || method === 'patch')\n {\n return 'update';\n }\n if (method === 'delete')\n {\n return 'delete';\n }\n }\n\n // Default: method name\n return method;\n}\n\n/**\n * Generate footer\n */\nfunction generateFooter(): string\n{\n return `/**\n * Export client instance for advanced usage\n *\n * Use this to add interceptors or customize the client:\n *\n * @example\n * \\`\\`\\`ts\n * import { client } from './api';\n * import { createAuthInterceptor } from '@spfn/auth/nextjs';\n * import { NextJSCookieProvider } from '@spfn/auth/nextjs';\n *\n * client.use(createAuthInterceptor({\n * cookieProvider: new NextJSCookieProvider(),\n * encryptionKey: process.env.ENCRYPTION_KEY!\n * }));\n * \\`\\`\\`\n */\nexport { client };\n`;\n}\n\n/**\n * Count unique contract files\n */\nfunction countUniqueContractFiles(mappings: RouteContractMapping[]): number\n{\n const files = new Set<string>();\n\n for (let i = 0; i < mappings.length; i++)\n {\n if (mappings[i].contractFile)\n {\n files.add(mappings[i].contractFile as string);\n }\n }\n\n return files.size;\n}","/**\n * Pino Logger Adapter\n *\n * Pino๋ฅผ ์ฌ์ฉํ๋ Logger Adapter ๊ตฌํ\n *\n * โ
๊ตฌํ ์๋ฃ:\n * - Pino ๊ธฐ๋ฐ ๋ก๊น
\n * - Child logger ์ง์\n * - Error ๊ฐ์ฒด ์ฒ๋ฆฌ (err ํ๋)\n * - Context ๋ณํฉ\n * - ํ๊ฒฝ๋ณ ์ค์ (pretty print)\n * - ํ์ผ ๋ก๊น
with Rotation (์์ฒด ๊ตฌ์ถ์ฉ)\n *\n * ๐ก ๋ฐฐํฌ ์๋๋ฆฌ์ค:\n * - K8s: Stdout๋ง (๋ก๊ทธ ์์ง๊ธฐ๊ฐ ์ฒ๋ฆฌ)\n * - ์์ฒด ๊ตฌ์ถ: Stdout + File with Rotation\n *\n * ๐ก ํน์ง:\n * - ๊ณ ์ฑ๋ฅ (Winston๋ณด๋ค 5-10๋ฐฐ ๋น ๋ฆ)\n * - JSON ๊ธฐ๋ณธ ํฌ๋งท\n * - ํ๋ก๋์
๊ฒ์ฆ๋จ (Netflix, Elastic ์ฌ์ฉ)\n *\n * ๐ ๊ด๋ จ ํ์ผ:\n * - src/logger/adapters/types.ts (์ธํฐํ์ด์ค)\n * - src/logger/index.ts (Adapter ์ ํ)\n * - src/logger/config.ts (์ค์ )\n */\n\nimport pino from 'pino';\nimport type { LoggerAdapter, AdapterConfig, LogLevel } from './types';\n\n/**\n * Pino Logger Adapter\n */\nexport class PinoAdapter implements LoggerAdapter\n{\n private logger: pino.Logger;\n\n constructor(config: AdapterConfig)\n {\n const isProduction = process.env.NODE_ENV === 'production';\n const isDevelopment = process.env.NODE_ENV === 'development';\n const fileLoggingEnabled = process.env.LOGGER_FILE_ENABLED === 'true';\n\n // Transport ์ค์ \n const targets: pino.TransportTargetOptions[] = [];\n\n // 1. Stdout Transport (ํญ์)\n if (!isProduction && isDevelopment)\n {\n // ๊ฐ๋ฐ: Pretty Print\n targets.push({\n target: 'pino-pretty',\n level: 'debug',\n options: {\n colorize: true,\n translateTime: 'SYS:yyyy-mm-dd HH:MM:ss.l',\n ignore: 'pid,hostname',\n },\n });\n }\n else\n {\n // ํ๋ก๋์
: JSON (๊ธฐ๋ณธ stdout)\n // targets๊ฐ ๋น์ด์์ผ๋ฉด ์๋์ผ๋ก stdout JSON ์ฌ์ฉ\n }\n\n // 2. File Transport (์์ฒด ๊ตฌ์ถ ์)\n if (fileLoggingEnabled && isProduction)\n {\n const logDir = process.env.LOG_DIR || './logs';\n const maxFileSize = process.env.LOG_MAX_FILE_SIZE || '10M';\n const maxFiles = parseInt(process.env.LOG_MAX_FILES || '10', 10);\n\n targets.push({\n target: 'pino-roll',\n level: 'info',\n options: {\n file: `${logDir}/app.log`,\n frequency: 'daily',\n size: maxFileSize,\n limit: { count: maxFiles },\n mkdir: true,\n },\n });\n }\n\n this.logger = pino({\n level: config.level,\n\n // Transport ์ค์ (targets๊ฐ ์์ผ๋ฉด ์ฌ์ฉ, ์์ผ๋ฉด ๊ธฐ๋ณธ stdout)\n transport: targets.length > 0 ? { targets } : undefined,\n\n // ๊ธฐ๋ณธ ํ๋\n base: config.module ? { module: config.module } : undefined,\n });\n }\n\n child(module: string): LoggerAdapter\n {\n const childLogger = new PinoAdapter({ level: this.logger.level as LogLevel, module });\n childLogger.logger = this.logger.child({ module });\n return childLogger;\n }\n\n debug(message: string, context?: Record<string, unknown>): void\n {\n this.logger.debug(context || {}, message);\n }\n\n info(message: string, context?: Record<string, unknown>): void\n {\n this.logger.info(context || {}, message);\n }\n\n warn(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.warn({ err: errorOrContext, ...context }, message);\n }\n else\n {\n this.logger.warn(errorOrContext || {}, message);\n }\n }\n\n error(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.error({ err: errorOrContext, ...context }, message);\n }\n else\n {\n this.logger.error(errorOrContext || {}, message);\n }\n }\n\n fatal(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.fatal({ err: errorOrContext, ...context }, message);\n }\n else\n {\n this.logger.fatal(errorOrContext || {}, message);\n }\n }\n\n async close(): Promise<void>\n {\n // Pino๋ ์๋์ผ๋ก flush๋จ\n // ํ์์ pino.final() ์ฌ์ฉ ๊ฐ๋ฅ\n }\n}","/**\n * Logger Class\n *\n * Main logger class\n *\n * โ
Implemented:\n * - 5 log level methods (debug, info, warn, error, fatal)\n * - Child logger creation (per module)\n * - Multiple Transport support\n * - Context object support\n * - Automatic Error object handling\n *\n * ๐ก Future considerations:\n * - Log sampling (limit high-frequency logs)\n * - Async batch processing\n * - Memory usage monitoring\n *\n * ๐ Related files:\n * - src/logger/types.ts (Type definitions)\n * - src/logger/transports/ (Transport implementations)\n * - src/logger/adapter-factory.ts (Singleton instance)\n */\n\nimport type { LogLevel, LogMetadata, LoggerConfig, Transport } from './types';\n\n/**\n * Logger class\n */\nexport class Logger\n{\n private config: LoggerConfig;\n private module?: string;\n\n constructor(config: LoggerConfig)\n {\n this.config = config;\n this.module = config.module;\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 * Debug log\n */\n debug(message: string, context?: Record<string, unknown>): void\n {\n this.log('debug', message, undefined, context);\n }\n\n /**\n * Info log\n */\n info(message: string, context?: Record<string, unknown>): void\n {\n this.log('info', message, undefined, context);\n }\n\n /**\n * Warn log\n */\n warn(message: string, context?: Record<string, unknown>): void;\n warn(message: string, error: Error, context?: Record<string, unknown>): void;\n warn(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.log('warn', message, errorOrContext, context);\n }\n else\n {\n this.log('warn', message, undefined, errorOrContext);\n }\n }\n\n /**\n * Error log\n */\n error(message: string, context?: Record<string, unknown>): void;\n error(message: string, error: Error, context?: Record<string, unknown>): void;\n error(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.log('error', message, errorOrContext, context);\n }\n else\n {\n this.log('error', message, undefined, errorOrContext);\n }\n }\n\n /**\n * Fatal log\n */\n fatal(message: string, context?: Record<string, unknown>): void;\n fatal(message: string, error: Error, context?: Record<string, unknown>): void;\n fatal(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.log('fatal', message, errorOrContext, context);\n }\n else\n {\n this.log('fatal', message, undefined, errorOrContext);\n }\n }\n\n /**\n * Log processing (internal)\n */\n private log(level: LogLevel, message: string, error?: Error, context?: Record<string, unknown>): void\n {\n const metadata: LogMetadata = {\n timestamp: new Date(),\n level,\n message,\n module: this.module,\n error,\n context,\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 * 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/**\n * File Transport ์ค์ \n */\nexport interface FileTransportConfig extends TransportConfig\n{\n logDir: string;\n maxFileSize?: number; // bytes\n maxFiles?: number; // ์ต๋ ๋ก๊ทธ ํ์ผ ๊ฐ์\n}\n\n/**\n * Slack Transport ์ค์ \n */\nexport interface SlackTransportConfig extends TransportConfig\n{\n webhookUrl: string;\n channel?: string;\n username?: string;\n}\n\n/**\n * Email Transport ์ค์ \n */\nexport interface EmailTransportConfig extends TransportConfig\n{\n from: string;\n to: string[];\n smtpHost: string;\n smtpPort: number;\n smtpUser?: string;\n smtpPassword?: string;\n}","/**\n * Logger Formatters\n *\n * ๋ก๊ทธ ํฌ๋งทํ
์ ํธ๋ฆฌํฐ\n *\n * โ
๊ตฌํ ์๋ฃ:\n * - ์ปฌ๋ฌ ํฌ๋งทํฐ (์ฝ์ ์ถ๋ ฅ์ฉ)\n * - JSON ํฌ๋งทํฐ (ํ์ผ/์ ์ก์ฉ)\n * - ํ์์คํฌํ ํฌ๋งทํฐ\n * - ์๋ฌ ์คํ ํธ๋ ์ด์ค ํฌ๋งทํ
\n *\n * ๐ ๊ด๋ จ ํ์ผ:\n * - src/logger/types.ts (ํ์
์ ์)\n * - src/logger/transports/ (Transport ๊ตฌํ์ฒด)\n */\n\nimport type { LogLevel, LogMetadata } from './types';\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 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 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 // ๋ก๊ทธ ๋ ๋ฒจ\n if (colorize)\n {\n parts.push(colorizeLevel(metadata.level));\n }\n else\n {\n parts.push(metadata.level.toUpperCase().padEnd(5));\n }\n\n // ๋ชจ๋๋ช
\n if (metadata.module)\n {\n if (colorize)\n {\n parts.push(`${COLORS.dim}[${metadata.module}]${COLORS.reset}`);\n }\n else\n {\n parts.push(`[${metadata.module}]`);\n }\n }\n\n // ๋ฉ์์ง\n parts.push(metadata.message);\n\n let output = parts.join(' ');\n\n // Context ์ถ๊ฐ\n if (metadata.context && Object.keys(metadata.context).length > 0)\n {\n output += '\\n' + formatContext(metadata.context);\n }\n\n // ์๋ฌ ์ถ๊ฐ\n if (metadata.error)\n {\n output += '\\n' + formatError(metadata.error);\n }\n\n return output;\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 = {\n name: metadata.error.name,\n message: metadata.error.message,\n stack: metadata.error.stack,\n };\n }\n\n return JSON.stringify(obj);\n}\n\n/**\n * Slack ๋ฉ์์ง ํฌ๋งท\n */\nexport function formatSlack(metadata: LogMetadata): string\n{\n const emoji = {\n debug: ':bug:',\n info: ':information_source:',\n warn: ':warning:',\n error: ':x:',\n fatal: ':fire:',\n };\n\n const parts: string[] = [];\n\n parts.push(`${emoji[metadata.level]} *${metadata.level.toUpperCase()}*`);\n\n if (metadata.module)\n {\n parts.push(`\\`[${metadata.module}]\\``);\n }\n\n parts.push(metadata.message);\n\n let message = parts.join(' ');\n\n if (metadata.context)\n {\n message += '\\n```\\n' + JSON.stringify(metadata.context, null, 2) + '\\n```';\n }\n\n if (metadata.error)\n {\n message += '\\n```\\n' + formatError(metadata.error) + '\\n```';\n }\n\n return message;\n}\n\n/**\n * Email ์ ๋ชฉ ์์ฑ\n */\nexport function formatEmailSubject(metadata: LogMetadata): string\n{\n const prefix = `[${metadata.level.toUpperCase()}]`;\n const module = metadata.module ? `[${metadata.module}]` : '';\n\n return `${prefix}${module} ${metadata.message}`;\n}\n\n/**\n * Email ๋ณธ๋ฌธ ์์ฑ (HTML)\n */\nexport function formatEmailBody(metadata: LogMetadata): string\n{\n const parts: string[] = [];\n\n parts.push('<html>');\n parts.push('<body style=\"font-family: monospace; padding: 20px;\">');\n\n // ํค๋\n parts.push(`<h2 style=\"color: ${getEmailColor(metadata.level)};\">`);\n parts.push(`${metadata.level.toUpperCase()}`);\n parts.push('</h2>');\n\n // ์๊ฐ\n parts.push('<p>');\n parts.push(`<strong>Timestamp:</strong> ${formatTimestamp(metadata.timestamp)}`);\n parts.push('</p>');\n\n // ๋ชจ๋\n if (metadata.module)\n {\n parts.push('<p>');\n parts.push(`<strong>Module:</strong> ${metadata.module}`);\n parts.push('</p>');\n }\n\n // ๋ฉ์์ง\n parts.push('<p>');\n parts.push(`<strong>Message:</strong> ${metadata.message}`);\n parts.push('</p>');\n\n // Context\n if (metadata.context)\n {\n parts.push('<h3>Context</h3>');\n parts.push('<pre style=\"background: #f4f4f4; padding: 10px; border-radius: 4px;\">');\n parts.push(JSON.stringify(metadata.context, null, 2));\n parts.push('</pre>');\n }\n\n // ์๋ฌ\n if (metadata.error)\n {\n parts.push('<h3>Error Stack Trace</h3>');\n parts.push('<pre style=\"background: #fff0f0; padding: 10px; border-radius: 4px;\">');\n parts.push(formatError(metadata.error));\n parts.push('</pre>');\n }\n\n parts.push('</body>');\n parts.push('</html>');\n\n return parts.join('\\n');\n}\n\n/**\n * Email ๋ ๋ฒจ๋ณ ์ปฌ๋ฌ\n */\nfunction getEmailColor(level: LogLevel): string\n{\n const colors: Record<LogLevel, string> = {\n debug: '#00BCD4',\n info: '#4CAF50',\n warn: '#FF9800',\n error: '#F44336',\n fatal: '#9C27B0',\n };\n\n return colors[level];\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\n private 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 * File Transport\n *\n * ํ์ผ ์ถ๋ ฅ Transport\n *\n * โ
๊ตฌํ ์๋ฃ:\n * - ๋ ์ง๋ณ ๋ก๊ทธ ํ์ผ ์์ฑ\n * - JSON ํฌ๋งท ์ ์ฅ\n * - ๋ก๊ทธ ๋๋ ํ ๋ฆฌ ์๋ ์์ฑ\n * - ๋น๋๊ธฐ ์ฐ๊ธฐ (createWriteStream)\n * - ๋ ์ง ๋ณ๊ฒฝ ์ ์๋ ์คํธ๋ฆผ ๊ต์ฒด\n *\n * โ ๏ธ ๊ฐ์ ํ์:\n * - ํ์ผ ํฌ๊ธฐ ๊ธฐ๋ฐ ๋กํ
์ด์
\n * - ์ค๋๋ ํ์ผ ์๋ ์ญ์ \n *\n * ๐ก ํฅํ ๊ณ ๋ ค์ฌํญ:\n * - ์์ถ๋ ๋ก๊ทธ ์์นด์ด๋น\n * - ์ธ๋ถ ์คํ ๋ฆฌ์ง ์ ์ก (S3 ๋ฑ)\n *\n * ๐ ๊ด๋ จ ํ์ผ:\n * - src/logger/types.ts (Transport ์ธํฐํ์ด์ค)\n * - src/logger/formatters.ts (ํฌ๋งทํฐ)\n * - src/logger/config.ts (์ค์ )\n */\n\nimport { createWriteStream, existsSync, mkdirSync } from 'fs';\nimport type { WriteStream } from 'fs';\nimport { join } from 'path';\nimport type { Transport, LogMetadata, LogLevel, FileTransportConfig } from '../types';\nimport { LOG_LEVEL_PRIORITY } from '../types';\nimport { formatJSON } from '../formatters';\n\n/**\n * File Transport\n */\nexport class FileTransport implements Transport\n{\n public readonly name = 'file';\n public readonly level: LogLevel;\n public readonly enabled: boolean;\n\n private logDir: string;\n private currentStream: WriteStream | null = null;\n private currentFilename: string | null = null;\n\n constructor(config: FileTransportConfig)\n {\n this.level = config.level;\n this.enabled = config.enabled;\n this.logDir = config.logDir;\n\n // TODO: ํฅํ ํ์ผ ๋กํ
์ด์
๊ตฌํ ์ ์ฌ์ฉ\n // this.maxFileSize = config.maxFileSize ?? 10 * 1024 * 1024; // 10MB\n // this.maxFiles = config.maxFiles ?? 10;\n\n // ๋ก๊ทธ ๋๋ ํ ๋ฆฌ๊ฐ ์์ผ๋ฉด ์์ฑ\n if (!existsSync(this.logDir))\n {\n mkdirSync(this.logDir, { recursive: true });\n }\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 // JSON ํฌ๋งท์ผ๋ก ๋ณํ\n const message = formatJSON(metadata);\n\n // ํ์ผ๋ช
: YYYY-MM-DD.log\n const filename = this.getLogFilename(metadata.timestamp);\n\n // ๋ ์ง๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์คํธ๋ฆผ ๊ต์ฒด\n if (this.currentFilename !== filename)\n {\n await this.rotateStream(filename);\n }\n\n // ์คํธ๋ฆผ์ ์ฐ๊ธฐ\n if (this.currentStream)\n {\n return new Promise((resolve, reject) =>\n {\n this.currentStream!.write(message + '\\n', 'utf-8', (error) =>\n {\n if (error)\n {\n // ํ์ผ ์ฐ๊ธฐ ์คํจ ์ stderr๋ก ์ถ๋ ฅ (fallback)\n process.stderr.write(`[FileTransport] Failed to write log: ${error.message}\\n`);\n reject(error);\n }\n else\n {\n resolve();\n }\n });\n });\n }\n }\n\n /**\n * ์คํธ๋ฆผ ๊ต์ฒด (๋ ์ง ๋ณ๊ฒฝ ์)\n */\n private async rotateStream(filename: string): Promise<void>\n {\n // ๊ธฐ์กด ์คํธ๋ฆผ ๋ซ๊ธฐ\n if (this.currentStream)\n {\n await this.closeStream();\n }\n\n // ์ ์คํธ๋ฆผ ์์ฑ\n const filepath = join(this.logDir, filename);\n\n this.currentStream = createWriteStream(filepath, {\n flags: 'a', // append mode\n encoding: 'utf-8',\n });\n\n this.currentFilename = filename;\n\n // ์คํธ๋ฆผ ์๋ฌ ํธ๋ค๋ง\n this.currentStream.on('error', (error) =>\n {\n process.stderr.write(`[FileTransport] Stream error: ${error.message}\\n`);\n // ์๋ฌ ๋ฐ์ ์ ์คํธ๋ฆผ ์ด๊ธฐํ\n this.currentStream = null;\n this.currentFilename = null;\n });\n }\n\n /**\n * ํ์ฌ ์คํธ๋ฆผ ๋ซ๊ธฐ\n */\n private async closeStream(): Promise<void>\n {\n if (!this.currentStream)\n {\n return;\n }\n\n return new Promise((resolve, reject) =>\n {\n this.currentStream!.end((error) =>\n {\n if (error)\n {\n reject(error);\n }\n else\n {\n this.currentStream = null;\n this.currentFilename = null;\n resolve();\n }\n });\n });\n }\n\n /**\n * ๋ ์ง๋ณ ๋ก๊ทธ ํ์ผ๋ช
์์ฑ\n */\n private getLogFilename(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\n return `${year}-${month}-${day}.log`;\n }\n\n async close(): Promise<void>\n {\n // ์คํธ๋ฆผ ์ ๋ฆฌ\n await this.closeStream();\n }\n}","/**\n * Logger Configuration\n *\n * Logger configuration by environment\n *\n * โ
Implemented:\n * - Environment-specific log level configuration\n * - Console Transport configuration\n * - File Transport configuration (for self-hosted)\n * - File rotation configuration\n * - Slack Transport configuration (environment variable based)\n * - Email Transport configuration (environment variable based)\n *\n * ๐ก Deployment scenarios:\n * - K8s: Disable file logging (Stdout only)\n * - Self-hosted: LOGGER_FILE_ENABLED=true\n *\n * ๐ Related files:\n * - src/logger/types.ts (Type definitions)\n * - src/logger/index.ts (Main export)\n * - .env.local (Environment variables)\n */\n\nimport type {\n LogLevel,\n ConsoleTransportConfig,\n FileTransportConfig,\n SlackTransportConfig,\n EmailTransportConfig,\n} from './types';\n\n/**\n * Check if file logging is enabled (for self-hosted)\n */\nexport function isFileLoggingEnabled(): boolean\n{\n return process.env.LOGGER_FILE_ENABLED === 'true';\n}\n\n/**\n * Get default log level by environment\n */\nexport function getDefaultLogLevel(): LogLevel\n{\n const isProduction = process.env.NODE_ENV === 'production';\n const isDevelopment = process.env.NODE_ENV === 'development';\n\n if (isDevelopment)\n {\n return 'debug';\n }\n\n if (isProduction)\n {\n return 'info';\n }\n\n // Test environment\n return 'warn';\n}\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 * File Transport configuration\n */\nexport function getFileConfig(): FileTransportConfig\n{\n const isProduction = process.env.NODE_ENV === 'production';\n\n return {\n level: 'info',\n enabled: isProduction, // File logging in production only\n logDir: process.env.LOG_DIR || './logs',\n maxFileSize: 10 * 1024 * 1024, // 10MB\n maxFiles: 10,\n };\n}\n\n/**\n * Slack Transport configuration\n */\nexport function getSlackConfig(): SlackTransportConfig | null\n{\n const webhookUrl = process.env.SLACK_WEBHOOK_URL;\n\n if (!webhookUrl)\n {\n return null; // Disabled if not configured\n }\n\n const isProduction = process.env.NODE_ENV === 'production';\n\n return {\n level: 'error', // Send error and above to Slack\n enabled: isProduction, // Enabled in production only\n webhookUrl,\n channel: process.env.SLACK_CHANNEL,\n username: process.env.SLACK_USERNAME || 'Logger Bot',\n };\n}\n\n/**\n * Email Transport configuration\n */\nexport function getEmailConfig(): EmailTransportConfig | null\n{\n const smtpHost = process.env.SMTP_HOST;\n const smtpPort = process.env.SMTP_PORT;\n const emailFrom = process.env.EMAIL_FROM;\n const emailTo = process.env.EMAIL_TO;\n\n // Disabled if required settings are missing\n if (!smtpHost || !smtpPort || !emailFrom || !emailTo)\n {\n return null;\n }\n\n const isProduction = process.env.NODE_ENV === 'production';\n\n return {\n level: 'fatal', // Send fatal level only via email\n enabled: isProduction, // Enabled in production only\n from: emailFrom,\n to: emailTo.split(',').map(email => email.trim()),\n smtpHost,\n smtpPort: parseInt(smtpPort, 10),\n smtpUser: process.env.SMTP_USER,\n smtpPassword: process.env.SMTP_PASSWORD,\n };\n}","/**\n * Custom Logger Adapter\n *\n * ์์ฒด ๊ตฌํํ Logger๋ฅผ ์ฌ์ฉํ๋ Adapter\n *\n * โ
๊ตฌํ ์๋ฃ:\n * - ๊ธฐ์กด Logger ํด๋์ค ๋ํ\n * - Transport ์์คํ
(Console, File)\n * - Child logger ์ง์\n *\n * ๐ก ์ฉ๋:\n * - Pino ์์กด์ฑ ์ ๊ฑฐ ํ์์\n * - ์ปค์คํ
Transport ํ์์\n * - ์์ ํ ์ ์ด๊ฐ ํ์ํ ๊ฒฝ์ฐ\n *\n * ๐ ๊ด๋ จ ํ์ผ:\n * - src/logger/logger.ts (Logger ํด๋์ค)\n * - src/logger/transports/ (Transport ๊ตฌํ)\n * - src/logger/adapters/types.ts (์ธํฐํ์ด์ค)\n */\n\nimport { Logger } from '../logger';\nimport { ConsoleTransport } from '../transports/console';\nimport { FileTransport } from '../transports/file';\nimport { getConsoleConfig, getFileConfig } from '../config';\nimport type { LoggerAdapter, AdapterConfig } from './types';\nimport type { Transport } from '../types';\n\n/**\n * Transport ์ด๊ธฐํ\n */\nfunction initializeTransports(): Transport[]\n{\n const transports: Transport[] = [];\n\n // Console Transport (ํญ์ ํ์ฑํ)\n const consoleConfig = getConsoleConfig();\n transports.push(new ConsoleTransport(consoleConfig));\n\n // File Transport (ํ๋ก๋์
์์๋ง ํ์ฑํ)\n const fileConfig = getFileConfig();\n if (fileConfig.enabled)\n {\n transports.push(new FileTransport(fileConfig));\n }\n\n return transports;\n}\n\n/**\n * Custom Logger Adapter\n */\nexport class CustomAdapter implements LoggerAdapter\n{\n private logger: Logger;\n\n constructor(config: AdapterConfig)\n {\n this.logger = new Logger({\n level: config.level,\n module: config.module,\n transports: initializeTransports(),\n });\n }\n\n child(module: string): LoggerAdapter\n {\n const adapter = new CustomAdapter({ level: this.logger.level, module });\n adapter.logger = this.logger.child(module);\n return adapter;\n }\n\n debug(message: string, context?: Record<string, unknown>): void\n {\n this.logger.debug(message, context);\n }\n\n info(message: string, context?: Record<string, unknown>): void\n {\n this.logger.info(message, context);\n }\n\n warn(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.warn(message, errorOrContext, context);\n }\n else\n {\n this.logger.warn(message, errorOrContext);\n }\n }\n\n error(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.error(message, errorOrContext, context);\n }\n else\n {\n this.logger.error(message, errorOrContext);\n }\n }\n\n fatal(message: string, errorOrContext?: Error | Record<string, unknown>, context?: Record<string, unknown>): void\n {\n if (errorOrContext instanceof Error)\n {\n this.logger.fatal(message, errorOrContext, context);\n }\n else\n {\n this.logger.fatal(message, errorOrContext);\n }\n }\n\n async close(): Promise<void>\n {\n await this.logger.close();\n }\n}","/**\n * Logger Adapter Factory\n *\n * Adapter creation and initialization logic\n */\n\nimport { PinoAdapter } from './adapters/pino.js';\nimport { CustomAdapter } from './adapters/custom.js';\nimport { getDefaultLogLevel } from './config.js';\nimport type { LoggerAdapter } from './adapters/types.js';\n\n/**\n * Adapter type\n */\ntype AdapterType = 'pino' | 'custom';\n\n/**\n * Create adapter instance\n */\nfunction createAdapter(type: AdapterType): LoggerAdapter\n{\n const level = getDefaultLogLevel();\n\n switch (type)\n {\n case 'pino':\n return new PinoAdapter({ level });\n\n case 'custom':\n return new CustomAdapter({ level });\n\n default:\n return new PinoAdapter({ level });\n }\n}\n\n/**\n * Read adapter type from environment variable\n */\nfunction getAdapterType(): AdapterType\n{\n const adapterEnv = process.env.LOGGER_ADAPTER as AdapterType;\n\n if (adapterEnv === 'custom' || adapterEnv === 'pino')\n {\n return adapterEnv;\n }\n\n // Default: pino\n return 'pino';\n}\n\n/**\n * Singleton Logger instance\n */\nexport const logger: LoggerAdapter = createAdapter(getAdapterType());","/**\n * Contract Watcher & Client Generator\n *\n * Watches contract files and regenerates client code\n */\n\nimport { join } from 'path';\nimport { scanContracts } from './contract-scanner.js';\nimport { generateClient } from './client-generator.js';\nimport { logger } from '../logger/index.js';\nimport type { GenerationStats } from './types.js';\n\nconst codegenLogger = logger.child('codegen');\n\nexport interface WatchGenerateOptions {\n /** Routes directory (default: src/server/routes) */\n routesDir?: string;\n\n /** Output path for generated client (default: src/lib/api/client.ts) */\n outputPath?: string;\n\n /** Base URL for API client */\n baseUrl?: string;\n\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Watch contracts and generate client code\n *\n * This file is meant to be run with tsx --watch\n */\nexport async function watchAndGenerate(options: WatchGenerateOptions = {}): Promise<void> {\n const cwd = process.cwd();\n const routesDir = options.routesDir ?? join(cwd, 'src', 'server', 'routes');\n const outputPath = options.outputPath ?? join(cwd, 'src', 'lib', 'api', 'client.ts');\n const debug = options.debug ?? false;\n\n if (debug)\n {\n codegenLogger.info('Contract Watcher Started', { routesDir, outputPath });\n }\n\n try {\n // Scan contracts\n const contracts = await scanContracts(routesDir);\n\n if (contracts.length === 0)\n {\n if (debug)\n {\n codegenLogger.warn('No contracts found');\n }\n return;\n }\n\n // Generate client\n const stats: GenerationStats = await generateClient(contracts, {\n routesDir,\n outputPath,\n baseUrl: options.baseUrl,\n includeTypes: true,\n includeJsDoc: true\n });\n\n // Log stats\n if (debug)\n {\n codegenLogger.info('Client generated', {\n endpoints: stats.methodsGenerated,\n resources: stats.resourcesGenerated,\n duration: stats.duration\n });\n }\n }\n catch (error)\n {\n codegenLogger.error(\n 'Generation failed',\n error instanceof Error ? error : new Error(String(error))\n );\n throw error;\n }\n}\n\n// Auto-run if executed directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n watchAndGenerate({ debug: true });\n}"]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { P as PoolConfig, R as RetryConfig } from '../postgres-errors-CY_Es8EJ.js';
|
|
2
|
+
export { h as DatabaseClients, D as DbConnectionType, m as DrizzleConfigOptions, y as Page, x as Pageable, Q as QueryBuilder, n as Repository, t as RepositoryScope, G as TransactionContext, H as TransactionDB, T as Transactional, I as TransactionalOptions, W as WrappedDb, p as clearRepositoryCache, e as closeDatabase, c as createDatabaseFromEnv, d as db, k as detectDialect, B as foreignKey, J as fromPostgresError, l as generateDrizzleConfigFile, b as getDatabase, f as getDatabaseInfo, a as getDb, j as getDrizzleConfig, g as getRawDb, o as getRepository, q as getRepositoryCacheSize, u as getScopedCacheSize, r as getScopedRepository, E as getTransaction, z as id, i as initDatabase, v as isInRepositoryScope, C as optionalForeignKey, F as runWithTransaction, s as setDatabase, A as timestamps, w as withRepositoryScope } from '../postgres-errors-CY_Es8EJ.js';
|
|
3
|
+
import postgres__default from 'postgres';
|
|
4
|
+
import { PgTable } from 'drizzle-orm/pg-core';
|
|
5
|
+
import 'drizzle-orm/postgres-js';
|
|
6
|
+
import 'hono';
|
|
7
|
+
import 'drizzle-orm/pg-core/query-builders/raw';
|
|
8
|
+
import 'drizzle-orm';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Table Name Utilities
|
|
12
|
+
*
|
|
13
|
+
* Helper functions for extracting table names from Drizzle table objects.
|
|
14
|
+
* Used by Repository for accessing db.query API with dynamic table names.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get table name from Drizzle table object
|
|
19
|
+
*
|
|
20
|
+
* Uses WeakMap cache to avoid repeated Symbol lookups for better performance.
|
|
21
|
+
*
|
|
22
|
+
* @param table - Drizzle table schema
|
|
23
|
+
* @returns Table name string
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import { users } from './schema';
|
|
28
|
+
* const name = getTableName(users); // 'users'
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare function getTableName(table: PgTable): string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Database Connection Logic
|
|
35
|
+
*
|
|
36
|
+
* DB ์ฐ๊ฒฐ ์์ฑ ๋ฐ ์ฌ์๋ ๋ก์ง
|
|
37
|
+
*
|
|
38
|
+
* โ
๊ตฌํ ์๋ฃ:
|
|
39
|
+
* - Exponential Backoff ์ฌ์๋ ๋ก์ง
|
|
40
|
+
* - ์ฐ๊ฒฐ ํ
์คํธ ์ฟผ๋ฆฌ
|
|
41
|
+
* - ์์ธํ ์๋ฌ ๋ก๊น
|
|
42
|
+
* - ์ฐ๊ฒฐ ์ฑ๊ณต/์คํจ ๋ก๊น
|
|
43
|
+
* - Logger ์ ์ฉ (console.log ๋์ฒด)
|
|
44
|
+
*
|
|
45
|
+
* โ ๏ธ ๊ฐ์ ํ์:
|
|
46
|
+
* - ์๋ฌ ํ์
๋ณ ์ฒ๋ฆฌ (๋คํธ์ํฌ vs ์ธ์ฆ)
|
|
47
|
+
* - Graceful Shutdown ๋ก์ง
|
|
48
|
+
*
|
|
49
|
+
* ๐ก ํฅํ ๊ณ ๋ ค์ฌํญ:
|
|
50
|
+
* - ์ฐ๊ฒฐ ํ ์ด๋ฒคํธ ๋ฆฌ์ค๋
|
|
51
|
+
* - ์ฐ๊ฒฐ ์ํ ๋ฉํธ๋ฆญ ์์ง
|
|
52
|
+
* - ์ฐ๊ฒฐ ํ ๋์ ์กฐ์
|
|
53
|
+
*
|
|
54
|
+
* ๐ ๊ด๋ จ ํ์ผ:
|
|
55
|
+
* - src/server/core/db/config.ts (์ค์ )
|
|
56
|
+
* - src/server/core/db/index.ts (๋ฉ์ธ export)
|
|
57
|
+
* - src/server/core/logger/ (Logger)
|
|
58
|
+
*
|
|
59
|
+
* ๐ TODO: improvements.md ์ฐธ๊ณ
|
|
60
|
+
* - #7: Connection Pool ๋ชจ๋ํฐ๋ง (Pool ์ด๋ฒคํธ ๋ฆฌ์ค๋, ํ์ฑ/์ ํด ์ฐ๊ฒฐ ์ถ์ )
|
|
61
|
+
* - #9: Slow Query ๋ก๊น
(์ฟผ๋ฆฌ ์คํ ์๊ฐ ์ธก์ ๋ฐ ์๊ณ๊ฐ ๋ก๊น
)
|
|
62
|
+
* - #10: Graceful Shutdown (SIGTERM ์ฒ๋ฆฌ, ์งํ ์ค์ธ ์ฟผ๋ฆฌ ์๋ฃ ๋๊ธฐ)
|
|
63
|
+
* - #11: Read Replica ์ง์ (์ฝ๊ธฐ/์ฐ๊ธฐ ๋ถ๋ฆฌ)
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Exponential Backoff๋ก DB ์ฐ๊ฒฐ ์์ฑ
|
|
68
|
+
*
|
|
69
|
+
* @param connectionString - PostgreSQL ์ฐ๊ฒฐ ๋ฌธ์์ด
|
|
70
|
+
* @param poolConfig - Connection Pool ์ค์
|
|
71
|
+
* @param retryConfig - ์ฌ์๋ ์ค์
|
|
72
|
+
* @returns PostgreSQL ํด๋ผ์ด์ธํธ
|
|
73
|
+
*/
|
|
74
|
+
declare function createDatabaseConnection(connectionString: string, poolConfig: PoolConfig, retryConfig: RetryConfig): Promise<postgres__default.Sql<{}>>;
|
|
75
|
+
/**
|
|
76
|
+
* DB ์ฐ๊ฒฐ ์ํ ํ์ธ
|
|
77
|
+
*
|
|
78
|
+
* @param client - PostgreSQL ํด๋ผ์ด์ธํธ
|
|
79
|
+
* @returns ์ฐ๊ฒฐ ๊ฐ๋ฅ ์ฌ๋ถ
|
|
80
|
+
*/
|
|
81
|
+
declare function checkConnection(client: ReturnType<typeof postgres__default>): Promise<boolean>;
|
|
82
|
+
|
|
83
|
+
export { PoolConfig, RetryConfig, checkConnection, createDatabaseConnection, getTableName };
|