@spfn/core 0.1.0-alpha.7 → 0.1.0-alpha.72

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.
Files changed (59) hide show
  1. package/README.md +168 -195
  2. package/dist/auto-loader-JFaZ9gON.d.ts +80 -0
  3. package/dist/cache/index.d.ts +211 -0
  4. package/dist/cache/index.js +992 -0
  5. package/dist/cache/index.js.map +1 -0
  6. package/dist/client/index.d.ts +92 -92
  7. package/dist/client/index.js +80 -85
  8. package/dist/client/index.js.map +1 -1
  9. package/dist/codegen/generators/index.d.ts +19 -0
  10. package/dist/codegen/generators/index.js +1491 -0
  11. package/dist/codegen/generators/index.js.map +1 -0
  12. package/dist/codegen/index.d.ts +76 -60
  13. package/dist/codegen/index.js +1479 -736
  14. package/dist/codegen/index.js.map +1 -1
  15. package/dist/database-errors-BNNmLTJE.d.ts +86 -0
  16. package/dist/db/index.d.ts +844 -44
  17. package/dist/db/index.js +1262 -1309
  18. package/dist/db/index.js.map +1 -1
  19. package/dist/env/index.d.ts +508 -0
  20. package/dist/env/index.js +1106 -0
  21. package/dist/env/index.js.map +1 -0
  22. package/dist/error-handler-wjLL3v-a.d.ts +44 -0
  23. package/dist/errors/index.d.ts +136 -0
  24. package/dist/errors/index.js +172 -0
  25. package/dist/errors/index.js.map +1 -0
  26. package/dist/index-DHiAqhKv.d.ts +101 -0
  27. package/dist/index.d.ts +3 -374
  28. package/dist/index.js +2394 -2176
  29. package/dist/index.js.map +1 -1
  30. package/dist/logger/index.d.ts +94 -0
  31. package/dist/logger/index.js +774 -0
  32. package/dist/logger/index.js.map +1 -0
  33. package/dist/middleware/index.d.ts +33 -0
  34. package/dist/middleware/index.js +890 -0
  35. package/dist/middleware/index.js.map +1 -0
  36. package/dist/route/index.d.ts +21 -53
  37. package/dist/route/index.js +1234 -219
  38. package/dist/route/index.js.map +1 -1
  39. package/dist/server/index.d.ts +18 -0
  40. package/dist/server/index.js +2390 -2058
  41. package/dist/server/index.js.map +1 -1
  42. package/dist/types-Dzggq1Yb.d.ts +170 -0
  43. package/package.json +59 -15
  44. package/dist/auto-loader-C44TcLmM.d.ts +0 -125
  45. package/dist/bind-pssq1NRT.d.ts +0 -34
  46. package/dist/postgres-errors-CY_Es8EJ.d.ts +0 -1703
  47. package/dist/scripts/index.d.ts +0 -24
  48. package/dist/scripts/index.js +0 -1201
  49. package/dist/scripts/index.js.map +0 -1
  50. package/dist/scripts/templates/api-index.template.txt +0 -10
  51. package/dist/scripts/templates/api-tag.template.txt +0 -11
  52. package/dist/scripts/templates/contract.template.txt +0 -87
  53. package/dist/scripts/templates/entity-type.template.txt +0 -31
  54. package/dist/scripts/templates/entity.template.txt +0 -19
  55. package/dist/scripts/templates/index.template.txt +0 -10
  56. package/dist/scripts/templates/repository.template.txt +0 -37
  57. package/dist/scripts/templates/routes-id.template.txt +0 -59
  58. package/dist/scripts/templates/routes-index.template.txt +0 -44
  59. package/dist/types-SlzTr8ZO.d.ts +0 -143
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/scripts/migrate.ts","../../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","../../src/scripts/generate-client.ts"],"names":["join","dirname","config","resolve","chokidarWatch"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Database Migration Script\n *\n * 프로덕션 배포 시 마이그레이션 파일을 실제 DB에 적용\n *\n * 사용법:\n * ```bash\n * npm run db:migrate\n * # 또는\n * tsx src/server/scripts/migrate.ts\n * ```\n *\n * 동작:\n * 1. drizzle/ 폴더의 마이그레이션 파일 읽기\n * 2. 적용되지 않은 마이그레이션만 순차 실행\n * 3. 성공 시 마이그레이션 히스토리 기록\n * 4. 실패 시 롤백 및 에러 로그\n *\n * 환경변수:\n * - DATABASE_URL: PostgreSQL 연결 문자열 (필수)\n */\n\nimport { drizzle } from 'drizzle-orm/postgres-js';\nimport { migrate } from 'drizzle-orm/postgres-js/migrator';\nimport postgres from 'postgres';\nimport { config } from 'dotenv';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\n// .env.local 로드\nconfig({ path: '.env.local' });\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst projectRoot = join(__dirname, '../../..');\n\nconst DATABASE_URL = process.env.DATABASE_URL;\n\nif (!DATABASE_URL)\n{\n console.error('❌ DATABASE_URL environment variable is required');\n process.exit(1);\n}\n\nasync function runMigrations()\n{\n console.log('🔄 Starting database migration...');\n console.log(`📂 Migrations folder: ${join(projectRoot, 'drizzle')}`);\n\n // Connection for migration (max 1 connection)\n const migrationConnection = postgres(DATABASE_URL!, { max: 1 });\n const db = drizzle(migrationConnection);\n\n try\n {\n console.log('⏳ Applying migrations...');\n\n await migrate(db, {\n migrationsFolder: join(projectRoot, 'drizzle'),\n });\n\n console.log('✅ Migration completed successfully');\n }\n catch (error)\n {\n console.error('❌ Migration failed:', error);\n throw error;\n }\n finally\n {\n // Close connection\n await migrationConnection.end();\n console.log('🔌 Database connection closed');\n }\n}\n\n// Run migrations\nrunMigrations()\n .then(() =>\n {\n console.log('🎉 All migrations applied');\n process.exit(0);\n })\n .catch((error) =>\n {\n console.error('💥 Migration process failed:', error);\n process.exit(1);\n });","/**\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: Error | null | undefined) =>\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: Error | null | undefined) =>\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 { watch as chokidarWatch } from 'chokidar';\nimport { scanContracts } from './contract-scanner.js';\nimport { generateClient } from './client-generator.js';\nimport { logger } from '../logger';\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.ts) */\n outputPath?: string;\n\n /** Base URL for API client */\n baseUrl?: string;\n\n /** Enable debug logging */\n debug?: boolean;\n\n /** Watch mode (default: true) */\n watch?: boolean;\n}\n\n/**\n * Generate client once\n */\nasync function generateOnce(options: WatchGenerateOptions): Promise<GenerationStats | null> {\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.ts');\n\n try {\n // Scan contracts\n const contracts = await scanContracts(routesDir);\n\n if (contracts.length === 0)\n {\n if (options.debug)\n {\n codegenLogger.warn('No contracts found');\n }\n return null;\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 (options.debug)\n {\n codegenLogger.info('Client generated', {\n endpoints: stats.methodsGenerated,\n resources: stats.resourcesGenerated,\n duration: stats.duration\n });\n }\n\n return stats;\n }\n catch (error)\n {\n codegenLogger.error(\n 'Generation failed',\n error instanceof Error ? error : new Error(String(error))\n );\n return null;\n }\n}\n\n/**\n * Watch contracts and generate client code\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.ts');\n const watchMode = options.watch !== false;\n\n if (options.debug)\n {\n codegenLogger.info('Contract Watcher Started', { routesDir, outputPath, watch: watchMode });\n }\n\n // Initial generation\n await generateOnce(options);\n\n // Watch mode\n if (watchMode) {\n let isGenerating = false;\n let pendingRegeneration = false;\n\n const watcher = chokidarWatch(routesDir, {\n ignored: /(^|[\\/\\\\])\\../, // ignore dotfiles\n persistent: true,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 100,\n pollInterval: 50\n }\n });\n\n const regenerate = async () => {\n if (isGenerating) {\n pendingRegeneration = true;\n return;\n }\n\n isGenerating = true;\n pendingRegeneration = false;\n\n if (options.debug) {\n codegenLogger.info('Contracts changed, regenerating...');\n }\n\n await generateOnce(options);\n\n isGenerating = false;\n\n if (pendingRegeneration) {\n await regenerate();\n }\n };\n\n watcher\n .on('add', regenerate)\n .on('change', regenerate)\n .on('unlink', regenerate);\n\n // Keep process alive\n process.on('SIGINT', () => {\n watcher.close();\n process.exit(0);\n });\n\n // Keep the process alive\n await new Promise(() => {});\n }\n}\n\n// Auto-run if executed directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n watchAndGenerate({ debug: true });\n}","/**\n * Generate Client CLI Command\n *\n * Generates type-safe API client from route contracts\n *\n * Usage:\n * node dist/scripts/generate-client.js\n * node dist/scripts/generate-client.js --watch\n */\n\nimport { resolve } from 'path';\nimport { scanContracts, generateClient } from '../codegen';\nimport type { ClientGenerationOptions } from '../codegen';\nimport chalk from 'chalk';\nimport { watch } from 'chokidar';\n\n/**\n * CLI options\n */\ninterface GenerateClientOptions\n{\n contractsDir?: string;\n output?: string;\n baseUrl?: string;\n watch?: boolean;\n}\n\n/**\n * Main generate client command\n */\nexport async function generateClientCommand(options: GenerateClientOptions = {}): Promise<void>\n{\n const contractsDir = options.contractsDir || resolve(process.cwd(), 'src/server/contracts');\n const outputPath = options.output || resolve(process.cwd(), 'src/generated/api-client.ts');\n\n const generationOptions: ClientGenerationOptions = {\n routesDir: contractsDir, // Using routesDir field for backward compatibility\n outputPath: outputPath,\n baseUrl: options.baseUrl,\n includeTypes: true,\n includeJsDoc: true\n };\n\n console.log(chalk.blue('🔍 Scanning contracts...'));\n console.log(chalk.gray(` Contracts directory: ${contractsDir}`));\n\n try\n {\n await generateClientOnce(generationOptions, contractsDir);\n\n if (options.watch)\n {\n console.log(chalk.blue('\\n👀 Watching for changes...'));\n await watchContracts(generationOptions, contractsDir);\n }\n }\n catch (error)\n {\n console.error(chalk.red('❌ Generation failed:'));\n console.error(error);\n process.exit(1);\n }\n}\n\n/**\n * Generate client once\n */\nasync function generateClientOnce(options: ClientGenerationOptions, contractsDir: string): Promise<void>\n{\n const startTime = Date.now();\n\n // Scan contracts\n const mappings = await scanContracts(contractsDir);\n\n if (mappings.length === 0)\n {\n console.log(chalk.yellow('⚠️ No contracts found'));\n console.log(chalk.gray(' Make sure your contracts include method and path'));\n return;\n }\n\n console.log(chalk.green(`✅ Found ${mappings.length} contracts`));\n\n // Show some details\n const uniqueContracts = new Set(mappings.map(m => m.contractName)).size;\n const uniquePaths = new Set(mappings.map(m => m.contractImportPath)).size;\n\n console.log(chalk.gray(` Contracts: ${uniqueContracts}`));\n console.log(chalk.gray(` Contract files: ${uniquePaths}`));\n\n // Generate client\n console.log(chalk.blue('\\n📝 Generating client...'));\n\n const stats = await generateClient(mappings, options);\n\n const elapsed = Date.now() - startTime;\n\n console.log(chalk.green(`\\n✨ Client generated successfully!`));\n console.log(chalk.gray(` Output: ${options.outputPath}`));\n console.log(chalk.gray(` Resources: ${stats.resourcesGenerated}`));\n console.log(chalk.gray(` Methods: ${stats.methodsGenerated}`));\n console.log(chalk.gray(` Time: ${elapsed}ms`));\n}\n\n/**\n * Watch contracts for changes\n */\nasync function watchContracts(options: ClientGenerationOptions, contractsDir: string): Promise<void>\n{\n const watcher = watch(contractsDir, {\n ignored: /(^|[\\/\\\\])\\../, // ignore dotfiles\n persistent: true,\n ignoreInitial: true\n });\n\n let isGenerating = false;\n let pendingRegeneration = false;\n\n const regenerate = async () =>\n {\n if (isGenerating)\n {\n pendingRegeneration = true;\n return;\n }\n\n isGenerating = true;\n pendingRegeneration = false;\n\n try\n {\n console.log(chalk.blue('\\n🔄 Contracts changed, regenerating...'));\n await generateClientOnce(options, contractsDir);\n }\n catch (error)\n {\n console.error(chalk.red('❌ Regeneration failed:'));\n console.error(error);\n }\n finally\n {\n isGenerating = false;\n\n if (pendingRegeneration)\n {\n await regenerate();\n }\n }\n };\n\n watcher\n .on('add', (path) =>\n {\n console.log(chalk.gray(` File added: ${path}`));\n regenerate();\n })\n .on('change', (path) =>\n {\n console.log(chalk.gray(` File changed: ${path}`));\n regenerate();\n })\n .on('unlink', (path) =>\n {\n console.log(chalk.gray(` File removed: ${path}`));\n regenerate();\n })\n .on('error', (error) =>\n {\n console.error(chalk.red('❌ Watch error:'), error);\n });\n\n // Keep process alive\n process.on('SIGINT', () =>\n {\n console.log(chalk.blue('\\n\\n👋 Stopping watch mode...'));\n watcher.close();\n process.exit(0);\n });\n}\n\n/**\n * Parse CLI arguments\n */\nfunction parseArgs(): GenerateClientOptions\n{\n const args = process.argv.slice(2);\n const options: GenerateClientOptions = {};\n\n for (let i = 0; i < args.length; i++)\n {\n const arg = args[i];\n\n if (arg === '--watch' || arg === '-w')\n {\n options.watch = true;\n }\n else if (arg === '--contracts' || arg === '-c')\n {\n options.contractsDir = args[++i];\n }\n else if (arg === '--output' || arg === '-o')\n {\n options.output = args[++i];\n }\n else if (arg === '--base-url' || arg === '-b')\n {\n options.baseUrl = args[++i];\n }\n else if (arg === '--help' || arg === '-h')\n {\n printHelp();\n process.exit(0);\n }\n }\n\n return options;\n}\n\n/**\n * Print help message\n */\nfunction printHelp(): void\n{\n console.log(`\n${chalk.bold('Generate API Client from Contracts')}\n\n${chalk.bold('USAGE')}\n node dist/scripts/generate-client.js [options]\n\n${chalk.bold('OPTIONS')}\n -c, --contracts <dir> Contracts directory (default: src/server/contracts)\n -o, --output <file> Output file path (default: src/generated/api-client.ts)\n -b, --base-url <url> Base URL for API client\n -w, --watch Watch for changes and regenerate\n -h, --help Show this help message\n\n${chalk.bold('EXAMPLES')}\n # Generate once\n node dist/scripts/generate-client.js\n\n # Watch mode\n node dist/scripts/generate-client.js --watch\n\n # Custom paths\n node dist/scripts/generate-client.js --contracts ./contracts --output ./client.ts\n\n # With base URL\n node dist/scripts/generate-client.js --base-url https://api.example.com\n`);\n}\n\n// Run if called directly\nif (import.meta.url === `file://${process.argv[1]}`)\n{\n const options = parseArgs();\n generateClientCommand(options);\n}"]}
@@ -1,10 +0,0 @@
1
- /**
2
- * 🤖 자동 생성된 API 클라이언트 - Index
3
- *
4
- * ⚠️ 이 파일을 직접 수정하지 마세요!
5
- * 변경사항은 npm run generate:api 실행 시 덮어씌워집니다.
6
- *
7
- * @generated {{TIMESTAMP}}
8
- */
9
-
10
- {{EXPORTS}}
@@ -1,11 +0,0 @@
1
- /**
2
- * 🤖 자동 생성된 API 클라이언트 - {{TAG_NAME}}
3
- *
4
- * ⚠️ 이 파일을 직접 수정하지 마세요!
5
- * 변경사항은 npm run generate:api 실행 시 덮어씌워집니다.
6
- *
7
- * @generated {{TIMESTAMP}}
8
- */
9
- import { get, post, patch, del } from '@spfn/core/client';
10
- {{IMPORTS}}
11
- {{FUNCTIONS}}
@@ -1,87 +0,0 @@
1
- /**
2
- * {{ENTITY_NAME_PASCAL}} Contracts
3
- *
4
- * Generated from entity: {{ENTITY_NAME}}
5
- *
6
- * Type-safe API contracts with automatic validation using drizzle-typebox.
7
- * Schemas are automatically generated from Drizzle ORM entity definitions.
8
- *
9
- * @generated {{TIMESTAMP}}
10
- */
11
- import { Type } from '@sinclair/typebox';
12
- import { createInsertSchema, createSelectSchema } from 'drizzle-typebox';
13
- import { {{ENTITY_NAME}} } from '../../entities/{{ENTITY_NAME}}.js';
14
-
15
- /**
16
- * Generated TypeBox schemas from Drizzle entity
17
- */
18
- export const insert{{ENTITY_NAME_PASCAL}}Schema = createInsertSchema({{ENTITY_NAME}});
19
- export const select{{ENTITY_NAME_PASCAL}}Schema = createSelectSchema({{ENTITY_NAME}});
20
- export const update{{ENTITY_NAME_PASCAL}}Schema = Type.Partial(insert{{ENTITY_NAME_PASCAL}}Schema);
21
-
22
- /**
23
- * GET /{{ENTITY_NAME}} - List {{ENTITY_NAME}} with pagination
24
- */
25
- export const get{{ENTITY_NAME_PASCAL}}ListContract = {
26
- method: 'GET' as const,
27
- path: '/',
28
- query: Type.Object({
29
- page: Type.Optional(Type.Number({ minimum: 1 })),
30
- limit: Type.Optional(Type.Number({ minimum: 1, maximum: 100 })),
31
- }),
32
- response: Type.Object({
33
- items: Type.Array(select{{ENTITY_NAME_PASCAL}}Schema),
34
- total: Type.Number(),
35
- page: Type.Number(),
36
- limit: Type.Number(),
37
- })
38
- };
39
-
40
- /**
41
- * POST /{{ENTITY_NAME}} - Create new {{ENTITY_NAME_SINGULAR}}
42
- */
43
- export const create{{ENTITY_NAME_PASCAL_SINGULAR}}Contract = {
44
- method: 'POST' as const,
45
- path: '/',
46
- body: insert{{ENTITY_NAME_PASCAL}}Schema,
47
- response: select{{ENTITY_NAME_PASCAL}}Schema
48
- };
49
-
50
- /**
51
- * GET /{{ENTITY_NAME}}/:id - Get {{ENTITY_NAME_SINGULAR}} by ID
52
- */
53
- export const get{{ENTITY_NAME_PASCAL_SINGULAR}}Contract = {
54
- method: 'GET' as const,
55
- path: '/:id',
56
- params: Type.Object({
57
- id: Type.String()
58
- }),
59
- response: select{{ENTITY_NAME_PASCAL}}Schema
60
- };
61
-
62
- /**
63
- * PUT /{{ENTITY_NAME}}/:id - Update {{ENTITY_NAME_SINGULAR}}
64
- */
65
- export const update{{ENTITY_NAME_PASCAL_SINGULAR}}Contract = {
66
- method: 'PUT' as const,
67
- path: '/:id',
68
- params: Type.Object({
69
- id: Type.String()
70
- }),
71
- body: update{{ENTITY_NAME_PASCAL}}Schema,
72
- response: select{{ENTITY_NAME_PASCAL}}Schema
73
- };
74
-
75
- /**
76
- * DELETE /{{ENTITY_NAME}}/:id - Delete {{ENTITY_NAME_SINGULAR}}
77
- */
78
- export const delete{{ENTITY_NAME_PASCAL_SINGULAR}}Contract = {
79
- method: 'DELETE' as const,
80
- path: '/:id',
81
- params: Type.Object({
82
- id: Type.String()
83
- }),
84
- response: Type.Object({
85
- success: Type.Boolean()
86
- })
87
- };
@@ -1,31 +0,0 @@
1
- /**
2
- * 🤖 AUTO-GENERATED - DO NOT EDIT
3
- *
4
- * Generated from: src/server/entities/{{ENTITY_NAME}}.ts
5
- *
6
- * ⚠️ 이 파일을 직접 수정하지 마세요!
7
- * 변경사항은 npm run generate:types 실행 시 덮어씌워집니다.
8
- *
9
- * @generated {{TIMESTAMP}}
10
- */
11
- import type { {{TYPE_NAME}} as {{TYPE_NAME}}Entity, Insert{{TYPE_NAME}} } from '@/server/entities/{{ENTITY_NAME}}';
12
-
13
- /**
14
- * {{TYPE_NAME}} 타입 (API 응답용)
15
- * - Date 필드가 string으로 직렬화됨
16
- */
17
- export type {{TYPE_NAME}} = {
18
- [K in keyof {{TYPE_NAME}}Entity]: {{TYPE_NAME}}Entity[K] extends Date
19
- ? string
20
- : {{TYPE_NAME}}Entity[K];
21
- };
22
-
23
- /**
24
- * {{TYPE_NAME}} 생성 DTO
25
- */
26
- export type Create{{TYPE_NAME}}Dto = Omit<Insert{{TYPE_NAME}}, 'id' | 'createdAt' | 'updatedAt'>;
27
-
28
- /**
29
- * {{TYPE_NAME}} 수정 DTO
30
- */
31
- export type Update{{TYPE_NAME}}Dto = Partial<Create{{TYPE_NAME}}Dto>;
@@ -1,19 +0,0 @@
1
- import { pgTable, text } from 'drizzle-orm/pg-core';
2
- import { id, timestamps } from '@spfn/core';
3
-
4
- /**
5
- * {{ENTITY_NAME_PASCAL}} Entity
6
- *
7
- * TODO: Add your custom fields below
8
- * Example:
9
- * email: text('email').notNull().unique(),
10
- * name: text('name'),
11
- */
12
- export const {{ENTITY_NAME}} = pgTable('{{ENTITY_NAME}}', {
13
- id: id(),
14
- // Add your fields here
15
- ...timestamps(),
16
- });
17
-
18
- export type {{ENTITY_NAME_PASCAL}} = typeof {{ENTITY_NAME}}.$inferSelect;
19
- export type New{{ENTITY_NAME_PASCAL}} = typeof {{ENTITY_NAME}}.$inferInsert;
@@ -1,10 +0,0 @@
1
- /**
2
- * 🤖 AUTO-GENERATED - DO NOT EDIT
3
- *
4
- * ⚠️ 이 파일을 직접 수정하지 마세요!
5
- * 변경사항은 npm run generate:types 실행 시 덮어씌워집니다.
6
- *
7
- * @generated {{TIMESTAMP}}
8
- */
9
-
10
- {{EXPORTS}}
@@ -1,37 +0,0 @@
1
- /**
2
- * {{ENTITY_NAME_PASCAL}} Repository
3
- *
4
- * Generated from entity: {{ENTITY_NAME}}
5
- *
6
- * This file provides a type-safe repository helper for {{ENTITY_NAME}} CRUD operations.
7
- * Creates Repository instance with transaction support via getDb().
8
- *
9
- * @generated {{TIMESTAMP}}
10
- */
11
- import { Repository, getDb } from '@spfn/core/db';
12
- import { {{ENTITY_NAME}} } from '../entities/{{ENTITY_NAME}}.js';
13
-
14
- type {{TYPE_SELECT}} = typeof {{ENTITY_NAME}}.$inferSelect;
15
- type {{TYPE_INSERT}} = typeof {{ENTITY_NAME}}.$inferInsert;
16
-
17
- /**
18
- * Get {{ENTITY_NAME}} repository with transaction support
19
- *
20
- * Available methods:
21
- * - findById(id: number): Promise<{{TYPE_SELECT}} | undefined>
22
- * - findAll(options?): Promise<{{TYPE_SELECT}}[]>
23
- * - findPage(options): Promise<{ items: {{TYPE_SELECT}}[], total: number, page: number, limit: number }>
24
- * - save(data: Partial<{{TYPE_INSERT}}>): Promise<{{TYPE_SELECT}}>
25
- * - update(id: number, data: Partial<{{TYPE_INSERT}}>): Promise<{{TYPE_SELECT}}>
26
- * - delete(id: number): Promise<void>
27
- *
28
- * Usage:
29
- * ```typescript
30
- * const repo = get{{ENTITY_NAME_PASCAL}}Repository();
31
- * const items = await repo.findAll();
32
- * ```
33
- */
34
- export function get{{ENTITY_NAME_PASCAL}}Repository() {
35
- const db = getDb();
36
- return db.for({{ENTITY_NAME}});
37
- }
@@ -1,59 +0,0 @@
1
- /**
2
- * {{ENTITY_NAME_PASCAL}} Routes - Item Endpoints
3
- *
4
- * Generated from entity: {{ENTITY_NAME}}
5
- *
6
- * Handles item operations: get, update, delete by ID
7
- * Uses Repository pattern for database operations
8
- *
9
- * @generated {{TIMESTAMP}}
10
- */
11
- import { createApp } from '@spfn/core/route';
12
- import { NotFoundError } from '@spfn/core';
13
- import { get{{ENTITY_NAME_PASCAL}}Repository } from '../../../repositories/{{ENTITY_NAME}}.repository.js';
14
- import {
15
- get{{ENTITY_NAME_PASCAL_SINGULAR}}Contract,
16
- update{{ENTITY_NAME_PASCAL_SINGULAR}}Contract,
17
- delete{{ENTITY_NAME_PASCAL_SINGULAR}}Contract
18
- } from '../contract.js';
19
-
20
- const app = createApp();
21
-
22
- /**
23
- * GET /{{ENTITY_NAME}}/:id - Get {{ENTITY_NAME_SINGULAR}} by ID
24
- */
25
- app.bind(get{{ENTITY_NAME_PASCAL_SINGULAR}}Contract, async (c) => {
26
- const { id } = c.params;
27
- const repo = get{{ENTITY_NAME_PASCAL}}Repository();
28
- const {{ENTITY_NAME_SINGULAR}} = await repo.findById(Number(id));
29
-
30
- if (!{{ENTITY_NAME_SINGULAR}}) {
31
- throw new NotFoundError('{{ENTITY_NAME_PASCAL_SINGULAR}}', id);
32
- }
33
-
34
- return c.json({{ENTITY_NAME_SINGULAR}});
35
- });
36
-
37
- /**
38
- * PUT /{{ENTITY_NAME}}/:id - Update {{ENTITY_NAME_SINGULAR}}
39
- */
40
- app.bind(update{{ENTITY_NAME_PASCAL_SINGULAR}}Contract, async (c) => {
41
- const { id } = c.params;
42
- const body = await c.data();
43
-
44
- const repo = get{{ENTITY_NAME_PASCAL}}Repository();
45
- const updated = await repo.update(Number(id), body);
46
- return c.json(updated);
47
- });
48
-
49
- /**
50
- * DELETE /{{ENTITY_NAME}}/:id - Delete {{ENTITY_NAME_SINGULAR}}
51
- */
52
- app.bind(delete{{ENTITY_NAME_PASCAL_SINGULAR}}Contract, async (c) => {
53
- const { id } = c.params;
54
- const repo = get{{ENTITY_NAME_PASCAL}}Repository();
55
- await repo.delete(Number(id));
56
- return c.json({ success: true });
57
- });
58
-
59
- export default app;
@@ -1,44 +0,0 @@
1
- /**
2
- * {{ENTITY_NAME_PASCAL}} Routes - Collection Endpoints
3
- *
4
- * Generated from entity: {{ENTITY_NAME}}
5
- *
6
- * Handles collection operations: list and create
7
- * Uses Repository pattern for database operations
8
- *
9
- * @generated {{TIMESTAMP}}
10
- */
11
- import { createApp } from '@spfn/core/route';
12
- import { get{{ENTITY_NAME_PASCAL}}Repository } from '../../repositories/{{ENTITY_NAME}}.repository.js';
13
- import {
14
- get{{ENTITY_NAME_PASCAL}}ListContract,
15
- create{{ENTITY_NAME_PASCAL_SINGULAR}}Contract
16
- } from './contract.js';
17
-
18
- const app = createApp();
19
-
20
- /**
21
- * GET /{{ENTITY_NAME}} - List {{ENTITY_NAME}} with pagination
22
- */
23
- app.bind(get{{ENTITY_NAME_PASCAL}}ListContract, async (c) => {
24
- const { page = 1, limit = 10 } = c.query;
25
-
26
- const repo = get{{ENTITY_NAME_PASCAL}}Repository();
27
- const result = await repo.findPage({
28
- pagination: { page, limit }
29
- });
30
-
31
- return c.json(result);
32
- });
33
-
34
- /**
35
- * POST /{{ENTITY_NAME}} - Create new {{ENTITY_NAME_SINGULAR}}
36
- */
37
- app.bind(create{{ENTITY_NAME_PASCAL_SINGULAR}}Contract, async (c) => {
38
- const body = await c.data();
39
- const repo = get{{ENTITY_NAME_PASCAL}}Repository();
40
- const new{{ENTITY_NAME_PASCAL_SINGULAR}} = await repo.save(body);
41
- return c.json(new{{ENTITY_NAME_PASCAL_SINGULAR}}, 201);
42
- });
43
-
44
- export default app;