@spfn/core 0.2.0-beta.3 → 0.2.0-beta.4
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/dist/config/index.d.ts +36 -0
- package/dist/config/index.js +15 -6
- package/dist/config/index.js.map +1 -1
- package/dist/env/index.d.ts +29 -3
- package/dist/env/index.js +13 -13
- package/dist/env/index.js.map +1 -1
- package/dist/env/loader.d.ts +87 -0
- package/dist/env/loader.js +70 -0
- package/dist/env/loader.js.map +1 -0
- package/dist/event/index.d.ts +3 -70
- package/dist/event/index.js +10 -1
- package/dist/event/index.js.map +1 -1
- package/dist/event/sse/client.d.ts +82 -0
- package/dist/event/sse/client.js +115 -0
- package/dist/event/sse/client.js.map +1 -0
- package/dist/event/sse/index.d.ts +40 -0
- package/dist/event/sse/index.js +92 -0
- package/dist/event/sse/index.js.map +1 -0
- package/dist/job/index.js +13 -4
- package/dist/job/index.js.map +1 -1
- package/dist/nextjs/index.d.ts +2 -2
- package/dist/nextjs/index.js +1 -1
- package/dist/nextjs/index.js.map +1 -1
- package/dist/nextjs/server.d.ts +1 -1
- package/dist/nextjs/server.js +4 -1
- package/dist/nextjs/server.js.map +1 -1
- package/dist/route/index.d.ts +11 -2
- package/dist/route/index.js +11 -5
- package/dist/route/index.js.map +1 -1
- package/dist/router-Di7ENoah.d.ts +151 -0
- package/dist/server/index.d.ts +76 -0
- package/dist/server/index.js +171 -10
- package/dist/server/index.js.map +1 -1
- package/dist/types-B-e_f2dQ.d.ts +121 -0
- package/dist/{types-BVxUIkcU.d.ts → types-D_N_U-Py.d.ts} +47 -1
- package/package.json +17 -2
package/dist/env/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/env/validator.ts","../../src/env/schema.ts","../../src/env/registry.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Environment Variable Management - Parsers\n *\n * Parser functions that transform and validate environment variable strings.\n * All parsers follow the pattern: (value: string) => T or throw Error\n */\n\n// ============================================================================\n// Core Types\n// ============================================================================\n\n/**\n * Parser function that transforms and validates a string value\n * @throws Error if validation fails\n */\nexport type Parser<T> = (value: string) => T;\n\n// ============================================================================\n// String Parsers\n// ============================================================================\n\n/**\n * Parse a non-empty string\n *\n * @param value - Value to parse\n * @returns Trimmed string\n * @throws Error if string is empty after trimming\n *\n * @example\n * ```typescript\n * const name = getEnvVar('APP_NAME', {\n * validator: parseString,\n * });\n * ```\n */\nexport function parseString(value: string): string\n{\n const trimmed = value.trim();\n\n if (trimmed.length === 0)\n {\n throw new Error('Value cannot be empty');\n }\n\n return trimmed;\n}\n\n/**\n * Create a string parser with validation rules\n *\n * @param options - Validation options\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const apiKey = getEnvVar('API_KEY', {\n * validator: createStringParser({\n * minLength: 32,\n * pattern: /^[A-Za-z0-9_-]+$/,\n * }),\n * });\n * ```\n */\nexport function createStringParser(\n options: {\n minLength?: number;\n maxLength?: number;\n pattern?: RegExp;\n trim?: boolean;\n } = {}\n): Parser<string>\n{\n return (value: string): string =>\n {\n const { minLength, maxLength, pattern, trim = true } = options;\n\n let result = trim ? value.trim() : value;\n\n // Empty check\n if (result.length === 0)\n {\n throw new Error('Value cannot be empty');\n }\n\n // Length validation\n if (minLength !== undefined && result.length < minLength)\n {\n throw new Error(`Must be at least ${minLength} characters long (current: ${result.length})`);\n }\n\n if (maxLength !== undefined && result.length > maxLength)\n {\n throw new Error(`Must be at most ${maxLength} characters long (current: ${result.length})`);\n }\n\n // Pattern validation\n if (pattern && !pattern.test(result))\n {\n throw new Error(`Must match pattern ${pattern}`);\n }\n\n return result;\n };\n}\n\n// ============================================================================\n// Boolean Parser\n// ============================================================================\n\n/**\n * Parse a boolean environment variable\n *\n * Accepts: 'true', '1', 'yes' (case-insensitive) → true\n * 'false', '0', 'no' (case-insensitive) → false\n *\n * @param value - Value to parse\n * @returns Boolean value\n * @throws Error if value is not a valid boolean string\n *\n * @example\n * ```typescript\n * const debug = getEnvVar('DEBUG', {\n * default: 'false',\n * validator: parseBoolean,\n * });\n * ```\n */\nexport function parseBoolean(value: string): boolean\n{\n const normalized = value.toLowerCase().trim();\n\n if (['true', '1', 'yes'].includes(normalized))\n {\n return true;\n }\n\n if (['false', '0', 'no'].includes(normalized))\n {\n return false;\n }\n\n throw new Error(\n `Must be a boolean value (true/false, 1/0, yes/no), got: ${value}`\n );\n}\n\n// ============================================================================\n// Number Parsers\n// ============================================================================\n\n/**\n * Parse and validate number\n *\n * @param value - Value to parse\n * @param options - Validation options\n * @returns Parsed number\n * @throws Error if invalid number or constraint violation\n *\n * @example\n * ```typescript\n * const port = getEnvVar('PORT', {\n * default: '3000',\n * validator: (val) => parseNumber(val, { min: 1, max: 65535, integer: true }),\n * });\n * ```\n */\nexport function parseNumber(\n value: string,\n options: { min?: number; max?: number; integer?: boolean } = {}\n): number\n{\n const { min, max, integer = false } = options;\n\n // Reject empty strings\n if (value.trim() === '')\n {\n throw new Error('Value cannot be empty');\n }\n\n const num = Number(value);\n\n if (isNaN(num))\n {\n throw new Error(`Must be a valid number, got: ${value}`);\n }\n\n if (integer && !Number.isInteger(num))\n {\n throw new Error(`Must be an integer, got: ${value}`);\n }\n\n if (min !== undefined && num < min)\n {\n throw new Error(`Must be at least ${min}, got: ${num}`);\n }\n\n if (max !== undefined && num > max)\n {\n throw new Error(`Must be at most ${max}, got: ${num}`);\n }\n\n return num;\n}\n\n/**\n * Create a number parser with specific constraints\n *\n * @param options - Validation constraints\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const port = getEnvVar('PORT', {\n * default: '3000',\n * validator: createNumberParser({ min: 1, max: 65535, integer: true }),\n * });\n * ```\n */\nexport function createNumberParser(\n options: { min?: number; max?: number; integer?: boolean } = {}\n): Parser<number>\n{\n return (value: string) => parseNumber(value, options);\n}\n\n/**\n * Parse integer with optional constraints\n *\n * @param value - Value to parse\n * @param options - Min/max constraints\n * @returns Parsed integer\n * @throws Error if invalid or out of range\n *\n * @example\n * ```typescript\n * const retries = getEnvVar('MAX_RETRIES', {\n * default: '3',\n * validator: (val) => parseInteger(val, { min: 1, max: 10 }),\n * });\n * ```\n */\nexport function parseInteger(\n value: string,\n options: { min?: number; max?: number } = {}\n): number\n{\n return parseNumber(value, { ...options, integer: true });\n}\n\n/**\n * Parse float/decimal number with optional constraints\n *\n * @param value - Value to parse\n * @param options - Min/max constraints\n * @returns Parsed decimal number\n * @throws Error if invalid or out of range\n *\n * @example\n * ```typescript\n * const ratio = getEnvVar('CACHE_RATIO', {\n * default: '0.75',\n * validator: (val) => parseDecimal(val, { min: 0, max: 1 }),\n * });\n * ```\n */\nexport function parseDecimal(\n value: string,\n options: { min?: number; max?: number } = {}\n): number\n{\n return parseNumber(value, { ...options, integer: false });\n}\n\n// ============================================================================\n// URL Parsers\n// ============================================================================\n\n/**\n * Parse and validate URL\n *\n * @param value - Value to parse\n * @param options - Validation options\n * @returns Validated URL string\n * @throws Error if invalid URL or protocol mismatch\n *\n * @example\n * ```typescript\n * const apiUrl = getEnvVar('API_URL', {\n * validator: (val) => parseUrl(val, { protocol: 'https' }),\n * });\n * ```\n */\nexport function parseUrl(\n value: string,\n options: { protocol?: 'http' | 'https' | 'any' } = {}\n): string\n{\n const { protocol = 'any' } = options;\n\n // Parse URL (may throw TypeError)\n let url: URL;\n try\n {\n url = new URL(value);\n }\n catch (error)\n {\n if (error instanceof TypeError)\n {\n throw new Error(`Invalid URL: ${value}`);\n }\n throw error;\n }\n\n // Validate protocol\n if (protocol === 'http' && url.protocol !== 'http:')\n {\n throw new Error(`URL must use HTTP protocol, got ${url.protocol}`);\n }\n\n if (protocol === 'https' && url.protocol !== 'https:')\n {\n throw new Error(`URL must use HTTPS protocol, got ${url.protocol}`);\n }\n\n return value;\n}\n\n/**\n * Create a URL parser with specific protocol requirement\n *\n * @param protocol - Required protocol ('http', 'https', or 'any')\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const apiUrl = getEnvVar('API_URL', {\n * validator: createUrlParser('https'),\n * });\n * ```\n */\nexport function createUrlParser(protocol: 'http' | 'https' | 'any' = 'any'): Parser<string>\n{\n return (value: string) => parseUrl(value, { protocol });\n}\n\n/**\n * Parse PostgreSQL connection string\n *\n * @param value - Value to parse\n * @returns Validated PostgreSQL URL string\n * @throws Error if invalid PostgreSQL URL\n *\n * @example\n * ```typescript\n * const dbUrl = getEnvVar('DATABASE_URL', {\n * required: true,\n * validator: parsePostgresUrl,\n * });\n * ```\n */\nexport function parsePostgresUrl(value: string): string\n{\n // Parse URL (may throw TypeError)\n let url: URL;\n try\n {\n url = new URL(value);\n }\n catch (error)\n {\n if (error instanceof TypeError)\n {\n throw new Error(`Invalid PostgreSQL URL: ${value}`);\n }\n throw error;\n }\n\n // Validate protocol\n if (url.protocol !== 'postgres:' && url.protocol !== 'postgresql:')\n {\n throw new Error(\n `Must be a PostgreSQL URL (postgres:// or postgresql://), got ${url.protocol}`\n );\n }\n\n return value;\n}\n\n/**\n * Parse Redis connection string\n *\n * @param value - Value to parse\n * @returns Validated Redis URL string\n * @throws Error if invalid Redis URL\n *\n * @example\n * ```typescript\n * const redisUrl = getEnvVar('REDIS_URL', {\n * required: true,\n * validator: parseRedisUrl,\n * });\n * ```\n */\nexport function parseRedisUrl(value: string): string\n{\n // Parse URL (may throw TypeError)\n let url: URL;\n try\n {\n url = new URL(value);\n }\n catch (error)\n {\n if (error instanceof TypeError)\n {\n throw new Error(`Invalid Redis URL: ${value}`);\n }\n throw error;\n }\n\n // Validate protocol\n if (url.protocol !== 'redis:' && url.protocol !== 'rediss:')\n {\n throw new Error(\n `Must be a Redis URL (redis:// or rediss://), got ${url.protocol}`\n );\n }\n\n return value;\n}\n\n// ============================================================================\n// Enum Parser\n// ============================================================================\n\n/**\n * Parse and validate enum value\n *\n * @param value - Value to parse\n * @param allowed - Array of allowed values\n * @param caseInsensitive - Whether to perform case-insensitive comparison\n * @returns Validated enum value\n * @throws Error if value not in allowed list\n *\n * @example\n * ```typescript\n * const env = getEnvVar('NODE_ENV', {\n * validator: (val) => parseEnum(val, ['development', 'production', 'test']),\n * });\n * ```\n */\nexport function parseEnum(\n value: string,\n allowed: string[],\n caseInsensitive = false\n): string\n{\n if (caseInsensitive)\n {\n const normalizedValue = value.toLowerCase();\n const normalizedAllowed = allowed.map((v) => v.toLowerCase());\n const index = normalizedAllowed.indexOf(normalizedValue);\n\n if (index === -1)\n {\n throw new Error(\n `Must be one of [${allowed.join(', ')}], got: ${value}`\n );\n }\n\n return allowed[index]; // Return original case from allowed list\n }\n\n if (!allowed.includes(value))\n {\n throw new Error(\n `Must be one of [${allowed.join(', ')}], got: ${value}`\n );\n }\n\n return value;\n}\n\n/**\n * Create an enum parser with specific allowed values\n *\n * @param allowed - Array of allowed values\n * @param caseInsensitive - Whether to perform case-insensitive comparison\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const logLevel = getEnvVar('LOG_LEVEL', {\n * default: 'info',\n * validator: createEnumParser(['debug', 'info', 'warn', 'error']),\n * });\n * ```\n */\nexport function createEnumParser(allowed: string[], caseInsensitive = false): Parser<string>\n{\n return (value: string) => parseEnum(value, allowed, caseInsensitive);\n}\n\n// ============================================================================\n// JSON Parser\n// ============================================================================\n\n/**\n * Parse JSON string\n *\n * @param value - JSON string to parse\n * @returns Parsed JSON value\n * @throws Error if invalid JSON\n *\n * @example\n * ```typescript\n * const config = getEnvVar('CONFIG_JSON', {\n * validator: parseJson,\n * });\n * ```\n */\nexport function parseJson<T = any>(value: string): T\n{\n try\n {\n return JSON.parse(value) as T;\n }\n catch (error)\n {\n throw new Error(\n `Invalid JSON: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n}\n\n/**\n * Create a typed JSON parser\n *\n * @returns Parser function\n *\n * @example\n * ```typescript\n * interface Config {\n * host: string;\n * port: number;\n * }\n *\n * const config = getEnvVar('CONFIG_JSON', {\n * validator: createJsonParser<Config>(),\n * });\n * ```\n */\nexport function createJsonParser<T>(): Parser<T>\n{\n return (value: string) => parseJson<T>(value);\n}\n\n// ============================================================================\n// Array Parser\n// ============================================================================\n\n/**\n * Parse comma-separated values into array\n *\n * @param value - Comma-separated string\n * @param options - Parser options\n * @returns Array of strings\n *\n * @example\n * ```typescript\n * const hosts = getEnvVar('ALLOWED_HOSTS', {\n * validator: parseArray,\n * });\n * // \"localhost,example.com,api.example.com\" → ['localhost', 'example.com', 'api.example.com']\n * ```\n */\nexport function parseArray(\n value: string,\n options: {\n separator?: string;\n trim?: boolean;\n filter?: (item: string) => boolean;\n } = {}\n): string[]\n{\n const { separator = ',', trim = true, filter } = options;\n\n if (value.trim() === '')\n {\n return [];\n }\n\n let items = value.split(separator);\n\n if (trim)\n {\n items = items.map((item) => item.trim());\n }\n\n if (filter)\n {\n items = items.filter(filter);\n }\n\n return items;\n}\n\n/**\n * Create an array parser with item parser\n *\n * @param itemParser - Parser to apply to each array item\n * @param options - Array parsing options\n * @returns Parser function\n *\n * @example\n * ```typescript\n * // Parse comma-separated ports\n * const ports = getEnvVar('PORTS', {\n * validator: createArrayParser(\n * createNumberParser({ min: 1, max: 65535, integer: true })\n * ),\n * });\n * // \"3000,4000,5000\" → [3000, 4000, 5000]\n * ```\n */\nexport function createArrayParser<T>(\n itemParser: Parser<T>,\n options: { separator?: string } = {}\n): Parser<T[]>\n{\n return (value: string): T[] =>\n {\n const items = parseArray(value, options);\n\n return items.map((item, index) =>\n {\n try\n {\n return itemParser(item);\n }\n catch (error)\n {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Invalid item at index ${index}: ${message}`);\n }\n });\n };\n}\n\n// ============================================================================\n// Secure Secret Parser\n// ============================================================================\n\n/**\n * Calculate Shannon entropy of a string\n * Returns entropy in bits per character\n *\n * @param str - String to calculate entropy for\n * @returns Entropy value (0 to ~6.6 bits for printable ASCII)\n *\n * @example\n * ```typescript\n * const entropy = calculateEntropy('my-secret-key');\n * // Higher entropy = more random\n * // - Random lowercase: ~4.7 bits/char\n * // - Random alphanumeric: ~5.2 bits/char\n * // - Random printable ASCII: ~6.6 bits/char\n * // - \"aaaaaaa...\": ~0 bits/char\n * ```\n */\nfunction calculateEntropy(str: string): number\n{\n const len = str.length;\n const frequencies = new Map<string, number>();\n\n // Count character frequencies\n for (const char of str)\n {\n frequencies.set(char, (frequencies.get(char) || 0) + 1);\n }\n\n // Calculate Shannon entropy\n let entropy = 0;\n for (const count of frequencies.values())\n {\n const probability = count / len;\n entropy -= probability * Math.log2(probability);\n }\n\n return entropy;\n}\n\n/**\n * Create a secure secret parser with entropy validation\n *\n * Validates cryptographic secrets for sufficient length, character diversity, and randomness.\n * Uses Shannon entropy to measure randomness quality.\n *\n * @param options - Validation options\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const sessionSecret = getEnvVar('SESSION_SECRET', {\n * validator: createSecureSecretParser({\n * minLength: 32, // Minimum 256-bit\n * minUniqueChars: 16, // Character diversity\n * minEntropy: 3.5, // Shannon entropy (bits/char)\n * }),\n * });\n * ```\n */\nexport function createSecureSecretParser(\n options: {\n minLength?: number;\n minUniqueChars?: number;\n minEntropy?: number;\n } = {}\n): Parser<string>\n{\n const {\n minLength = 32,\n minUniqueChars = 16,\n minEntropy = 3.5,\n } = options;\n\n return (value: string): string =>\n {\n const length = value.length;\n const uniqueChars = new Set(value).size;\n const entropy = calculateEntropy(value);\n\n // Check length (minimum for cryptographic strength)\n if (length < minLength)\n {\n throw new Error(\n `Secret too short: ${length} characters (minimum: ${minLength})`\n );\n }\n\n // Check unique character diversity\n if (uniqueChars < minUniqueChars)\n {\n throw new Error(\n `Secret has low diversity: ${uniqueChars} unique characters (minimum: ${minUniqueChars})`\n );\n }\n\n // Check Shannon entropy (randomness quality)\n // Reference values:\n // - Random lowercase: ~4.7 bits/char\n // - Random alphanumeric: ~5.2 bits/char\n // - Random printable ASCII: ~6.6 bits/char\n // - \"aaaaaaa...\": ~0 bits/char\n // - \"abcabcabc...\": ~1.58 bits/char\n if (entropy < minEntropy)\n {\n throw new Error(\n `Secret has low entropy: ${entropy.toFixed(2)} bits/char (minimum: ${minEntropy}). Use a more random secret.`\n );\n }\n\n return value;\n };\n}\n\n// ============================================================================\n// Password Parser\n// ============================================================================\n\n/**\n * Create a password strength parser\n *\n * Validates password strength based on configurable requirements.\n * Useful for enforcing password policies in environment variables or user input.\n *\n * @param options - Validation options\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const adminPassword = getEnvVar('ADMIN_PASSWORD', {\n * validator: createPasswordParser({\n * minLength: 12,\n * requireUppercase: true,\n * requireLowercase: true,\n * requireNumber: true,\n * requireSpecial: true,\n * }),\n * });\n * ```\n */\nexport function createPasswordParser(\n options: {\n minLength?: number;\n requireUppercase?: boolean;\n requireLowercase?: boolean;\n requireNumber?: boolean;\n requireSpecial?: boolean;\n } = {}\n): Parser<string>\n{\n const {\n minLength = 8,\n requireUppercase = true,\n requireLowercase = true,\n requireNumber = true,\n requireSpecial = true,\n } = options;\n\n return (value: string): string =>\n {\n const errors: string[] = [];\n\n // Length check\n if (value.length < minLength)\n {\n errors.push(`Must be at least ${minLength} characters`);\n }\n\n // Uppercase check\n if (requireUppercase && !/[A-Z]/.test(value))\n {\n errors.push('Must contain at least one uppercase letter');\n }\n\n // Lowercase check\n if (requireLowercase && !/[a-z]/.test(value))\n {\n errors.push('Must contain at least one lowercase letter');\n }\n\n // Number check\n if (requireNumber && !/[0-9]/.test(value))\n {\n errors.push('Must contain at least one number');\n }\n\n // Special character check\n if (requireSpecial && !/[^A-Za-z0-9]/.test(value))\n {\n errors.push('Must contain at least one special character');\n }\n\n if (errors.length > 0)\n {\n throw new Error(`Password validation failed: ${errors.join(', ')}`);\n }\n\n return value;\n };\n}\n\n// ============================================================================\n// Parser Composition\n// ============================================================================\n\n/**\n * Chain multiple parsers sequentially\n *\n * Each parser receives the output of the previous parser.\n * Useful for multi-step validation/transformation.\n *\n * @param parsers - Array of parser functions\n * @returns Combined parser function\n *\n * @example\n * ```typescript\n * const apiKey = getEnvVar('API_KEY', {\n * validator: chain(\n * parseString,\n * createStringParser({ minLength: 32, pattern: /^[A-Za-z0-9_-]+$/ }),\n * ),\n * });\n * ```\n */\nexport function chain<T>(...parsers: Array<Parser<T>>): Parser<T>\n{\n return (value: string): T =>\n {\n let result = value as any;\n\n for (const parser of parsers)\n {\n result = parser(result);\n }\n\n return result;\n };\n}\n\n/**\n * Apply parser with fallback value\n *\n * If parser throws, returns fallback instead.\n * Useful for optional environment variables with complex parsing.\n *\n * @param parser - Parser to attempt\n * @param fallback - Fallback value if parsing fails\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const config = getEnvVar('CONFIG_JSON', {\n * validator: withFallback(parseJson, { host: 'localhost', port: 3000 }),\n * });\n * ```\n */\nexport function withFallback<T>(parser: Parser<T>, fallback: T): Parser<T>\n{\n return (value: string): T =>\n {\n try\n {\n return parser(value);\n }\n catch\n {\n return fallback;\n }\n };\n}\n\n/**\n * Make parser optional\n *\n * Returns undefined for empty strings instead of throwing.\n *\n * @param parser - Parser to make optional\n * @returns Parser function that returns T | undefined\n *\n * @example\n * ```typescript\n * const redisUrl = getEnvVar('REDIS_URL', {\n * validator: optional(parseRedisUrl),\n * });\n * // Empty string → undefined\n * // Valid URL → parsed URL\n * // Invalid URL → throws\n * ```\n */\nexport function optional<T>(parser: Parser<T>): Parser<T | undefined>\n{\n return (value: string): T | undefined =>\n {\n if (value.trim() === '')\n {\n return undefined;\n }\n\n return parser(value);\n };\n}","/**\n * Environment Variable Schema Definition System\n *\n * 환경변수에 메타데이터를 정의하여 중앙 관리, 문서화, 검증을 지원합니다.\n *\n * @example\n * ```typescript\n * const schema = defineEnvSchema({\n * DATABASE_URL: envUrl({\n * description: 'Database connection',\n * required: true,\n * validator: parsePostgresUrl,\n * sensitive: true,\n * })\n * });\n * ```\n *\n * @module env/schema\n */\n\nimport { parseBoolean, parseNumber, parseJson } from './validator';\n\n/**\n * 환경변수 스키마 정의\n */\nexport interface EnvVarSchema<T = string>\n{\n /** 환경변수 키 */\n key: string;\n\n /** 설명 (목적, 사용처) */\n description: string;\n\n /** 타입 */\n type: 'string' | 'number' | 'boolean' | 'url' | 'enum' | 'json';\n\n /** 필수 여부 */\n required?: boolean;\n\n /** 기본값 */\n default?: T;\n\n /** 검증/변환 함수 */\n validator?: (value: string) => T;\n\n // === 검증 옵션 ===\n\n /** Fallback 환경변수 키들 (backward compatibility) */\n fallbackKeys?: string[];\n\n /** 최소 길이 (문자열 타입) */\n minLength?: number;\n\n // === 메타데이터 ===\n\n /** 민감정보 여부 (로깅 시 마스킹) */\n sensitive?: boolean;\n\n /** 예시 값들 (타입과 일치해야 함) */\n examples?: T[];\n}\n\n/**\n * 스키마 컬렉션 타입\n */\nexport type EnvSchemaCollection = Record<string, EnvVarSchema<any>>;\n\n/**\n * Helper type: Check if field has default value\n */\ntype HasDefault<T> = T extends { default: any } ? true : false;\n\n/**\n * Helper type: Check if field is explicitly required\n */\ntype IsRequired<T> = T extends { required: true } ? true : false;\n\n/**\n * Helper type: Check if field should be required (has default OR required: true)\n */\ntype ShouldBeRequired<T> = HasDefault<T> extends true ? true : IsRequired<T>;\n\n/**\n * 스키마로부터 타입 추출\n *\n * required: true 또는 default가 있는 필드 → 필수\n * required: false 또는 미지정 → optional (| undefined)\n */\nexport type InferEnvType<T extends EnvSchemaCollection> = {\n // Required fields (required: true OR has default)\n [K in keyof T as ShouldBeRequired<T[K]> extends true ? K : never]:\n T[K] extends EnvVarSchema<infer U> ? U : string;\n} & {\n // Optional fields (required: false OR not specified)\n [K in keyof T as ShouldBeRequired<T[K]> extends true ? never : K]?:\n T[K] extends EnvVarSchema<infer U> ? U | undefined : string | undefined;\n};\n\n/**\n * 스키마 정의 헬퍼 (타입 추론 지원)\n *\n * Automatically fills in the `key` property from object keys.\n *\n * @example\n * ```typescript\n * const schema = defineEnvSchema({\n * DATABASE_URL: envString({ description: 'Database URL', required: true })\n * });\n * // Automatically adds key: 'DATABASE_URL'\n * ```\n */\nexport function defineEnvSchema<T extends Record<string, any>>(\n schema: T\n): { [K in keyof T]: T[K] & { key: K } }\n{\n const result: any = {};\n\n for (const key in schema)\n {\n result[key] = {\n ...schema[key],\n key,\n };\n }\n\n return result;\n}\n\n/**\n * 문자열 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * API_KEY: {\n * ...envString({\n * description: 'API authentication key',\n * required: true,\n * sensitive: true,\n * }),\n * key: 'API_KEY',\n * }\n * };\n * ```\n */\nexport function envString<T extends Omit<EnvVarSchema, 'key' | 'type'>>(\n options: T\n): T & { type: 'string' }\n{\n return {\n ...options,\n type: 'string',\n };\n}\n\n/**\n * 숫자 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * PORT: {\n * ...envNumber({\n * description: 'Server port',\n * default: 3000,\n * validator: createNumberParser({ min: 1, max: 65535 }),\n * }),\n * key: 'PORT',\n * }\n * };\n * ```\n */\nexport function envNumber<T extends Omit<EnvVarSchema<number>, 'key' | 'type'>>(\n options: T\n): T & { type: 'number'; validator: (value: string) => number }\n{\n return {\n ...options,\n type: 'number',\n validator: options.validator || parseNumber,\n };\n}\n\n/**\n * Boolean 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * DEBUG: {\n * ...envBoolean({\n * description: 'Enable debug mode',\n * default: false,\n * }),\n * key: 'DEBUG',\n * }\n * };\n * ```\n */\nexport function envBoolean<T extends Omit<EnvVarSchema<boolean>, 'key' | 'type'>>(\n options: T\n): T & { type: 'boolean'; validator: (value: string) => boolean }\n{\n return {\n ...options,\n type: 'boolean',\n validator: options.validator || parseBoolean,\n };\n}\n\n/**\n * URL 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * DATABASE_URL: {\n * ...envUrl({\n * description: 'Database connection URL',\n * required: true,\n * validator: parsePostgresUrl,\n * }),\n * key: 'DATABASE_URL',\n * }\n * };\n * ```\n */\nexport function envUrl<T extends Omit<EnvVarSchema, 'key' | 'type'>>(\n options: T\n): T & { type: 'url' }\n{\n return {\n ...options,\n type: 'url',\n };\n}\n\n/**\n * Enum 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * LOG_LEVEL: {\n * ...envEnum(['debug', 'info', 'warn', 'error'] as const, {\n * description: 'Logging level',\n * default: 'info',\n * }),\n * key: 'LOG_LEVEL',\n * }\n * };\n * ```\n */\nexport function envEnum<\n T extends string,\n O extends Omit<EnvVarSchema<T>, 'key' | 'type' | 'validator'>\n>(\n allowed: readonly T[],\n options: O\n): O & { type: 'enum'; validator: (val: string) => T }\n{\n return {\n ...options,\n type: 'enum',\n validator: (val: string): T =>\n {\n if (!allowed.includes(val as T))\n {\n throw new Error(`Must be one of: ${allowed.join(', ')}, got: ${val}`);\n }\n\n return val as T;\n },\n };\n}\n\n/**\n * JSON 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * CONFIG_JSON: {\n * ...envJson<{ host: string; port: number }>({\n * description: 'JSON configuration object',\n * required: true,\n * }),\n * key: 'CONFIG_JSON',\n * }\n * };\n * ```\n */\nexport function envJson<\n T = any,\n O extends Omit<EnvVarSchema<T>, 'key' | 'type' | 'validator'> = Omit<EnvVarSchema<T>, 'key' | 'type' | 'validator'>\n>(\n options: O\n): O & { type: 'json'; validator: (val: string) => T }\n{\n return {\n ...options,\n type: 'json',\n validator: (val: string) => parseJson<T>(val),\n };\n}\n\n/**\n * 환경변수가 클라이언트에서 접근 가능한지 확인\n * (NEXT_PUBLIC_ 접두사로 판단)\n *\n * @param key - 환경변수 키\n * @returns 클라이언트에서 접근 가능하면 true\n *\n * @example\n * ```typescript\n * isClientAccessible('NEXT_PUBLIC_API_URL'); // true\n * isClientAccessible('DATABASE_URL'); // false\n * ```\n */\nexport function isClientAccessible(key: string): boolean\n{\n return key.startsWith('NEXT_PUBLIC_');\n}\n\n/**\n * 환경변수가 서버 전용인지 확인\n * (NEXT_PUBLIC_ 접두사가 없으면 서버 전용)\n *\n * @param key - 환경변수 키\n * @returns 서버 전용이면 true\n *\n * @example\n * ```typescript\n * isServerOnly('DATABASE_URL'); // true\n * isServerOnly('NEXT_PUBLIC_API_URL'); // false\n * ```\n */\nexport function isServerOnly(key: string): boolean\n{\n return !isClientAccessible(key);\n}","/**\n * Environment Variable Registry\n *\n * 환경변수 스키마를 등록하고 타입 안전하게 접근할 수 있는 레지스트리\n *\n * @example\n * ```typescript\n * const schema = defineEnvSchema({\n * DATABASE_URL: envString({ description: 'Database URL', required: true })\n * });\n *\n * const registry = createEnvRegistry(schema);\n * const env = registry.validate(); // 검증 + env 반환\n * console.log(env.DATABASE_URL);\n * ```\n *\n * @module env/registry\n */\nimport type { EnvVarSchema, EnvSchemaCollection, InferEnvType } from './schema';\nimport { isClientAccessible } from './schema';\nimport { logger } from '@spfn/core/logger';\n\nconst envLogger = logger.child('@spfn/core:env-registry')\n\n\n/**\n * 환경변수 레지스트리\n *\n * 스키마 기반 환경변수 관리 및 검증\n */\nexport class EnvRegistry<T extends EnvSchemaCollection = EnvSchemaCollection>\n{\n private schemas = new Map<string, EnvVarSchema>();\n private hasValidated = false;\n private valueCache = new Map<string, any>();\n\n constructor(schemas?: T)\n {\n if (schemas)\n {\n this.registerMultiple(schemas);\n }\n }\n\n /**\n * 스키마 등록\n */\n register(schema: EnvVarSchema): void\n {\n this.schemas.set(schema.key, schema);\n }\n\n /**\n * 여러 스키마 등록\n */\n registerMultiple(schemas: EnvSchemaCollection): void\n {\n for (const [key, schema] of Object.entries(schemas))\n {\n this.register({ ...schema, key });\n }\n }\n\n /**\n * 캐시 및 검증 상태 리셋 (테스트용)\n */\n reset(): void\n {\n this.valueCache.clear();\n this.hasValidated = false;\n }\n\n /**\n * 환경변수 원시값 가져오기 (fallback 지원)\n */\n private getRawValue(key: string, fallbackKeys?: string[]): string | undefined\n {\n let value = process.env[key];\n\n if (!value && fallbackKeys)\n {\n for (const fallbackKey of fallbackKeys)\n {\n value = process.env[fallbackKey];\n if (value)\n {\n break;\n }\n }\n }\n\n return value;\n }\n\n /**\n * 값에 validator 적용\n */\n private applyValidator<U>(\n value: string,\n schema: EnvVarSchema<U>\n ): U\n {\n if (schema.validator)\n {\n return schema.validator(value) as U;\n }\n\n return value as U;\n }\n\n /**\n * 스키마 검증 수행 (값 읽기 없이)\n *\n * @internal\n */\n private validateSchemas(): void\n {\n // Skip if already validated\n if (this.hasValidated)\n {\n return;\n }\n\n const warnings: string[] = [];\n\n // 클라이언트 변수 중 민감정보 경고\n for (const [key, schema] of this.schemas)\n {\n if (isClientAccessible(key) && schema.sensitive)\n {\n warnings.push(\n `${key} is marked as sensitive but accessible from client (NEXT_PUBLIC_*). Remove NEXT_PUBLIC_ prefix or unmark as sensitive.`\n );\n }\n }\n\n // Log warnings\n if (warnings.length > 0)\n {\n envLogger.warn('Environment validation warnings:');\n warnings.forEach(w => envLogger.warn(` - ${w}`));\n }\n\n this.hasValidated = true;\n }\n\n /**\n * 실제 접근 시점에 환경변수 값 가져오기 및 검증\n *\n * @internal\n */\n private getAndValidate(key: string): any\n {\n // Check cache first\n if (this.valueCache.has(key))\n {\n return this.valueCache.get(key);\n }\n\n const schema = this.schemas.get(key);\n if (!schema)\n {\n return undefined;\n }\n\n // Get raw value using common helper\n const value = this.getRawValue(key, schema.fallbackKeys);\n\n // Check if required\n if (schema.required && !value)\n {\n const fallbackHint = schema.fallbackKeys\n ? ` (or ${schema.fallbackKeys.join(', ')})`\n : '';\n\n const errorMsg = `${key}${fallbackHint} is required but not set. ${schema.description || ''}`;\n envLogger.error(`Environment validation failed:\\n - ${errorMsg}`);\n throw new Error('Environment validation failed');\n }\n\n // If no value and not required, use default\n if (!value)\n {\n const result = schema.default;\n this.valueCache.set(key, result);\n return result;\n }\n\n // Check minLength\n if (schema.minLength !== undefined && value.length < schema.minLength)\n {\n const errorMsg = `${key} must be at least ${schema.minLength} characters long (current: ${value.length})`;\n envLogger.error(`Environment validation failed:\\n - ${errorMsg}`);\n throw new Error('Environment validation failed');\n }\n\n // Apply validator and cache result\n try\n {\n const result = this.applyValidator(value, schema);\n this.valueCache.set(key, result);\n return result;\n }\n catch (error)\n {\n const errorMsg = `${key} validation failed: ${error instanceof Error ? error.message : String(error)}`;\n envLogger.error(`Environment validation failed:\\n - ${errorMsg}`);\n throw new Error('Environment validation failed');\n }\n }\n\n /**\n * 환경변수 검증 및 타입 안전한 env 객체 반환\n *\n * Proxy 기반으로 구현되어 실제 환경변수 접근 시점에 값을 읽고 검증합니다.\n * 이를 통해 dotenv 로딩 타이밍과 무관하게 최신 환경변수 값을 가져올 수 있습니다.\n *\n * @returns 검증된 환경변수 객체 (Proxy)\n * @throws {Error} 필수 변수 누락 또는 검증 실패 시\n *\n * @example\n * ```typescript\n * const registry = createEnvRegistry(schema);\n * const env = registry.validate(); // 스키마만 검증\n * // ... dotenv 로딩 ...\n * console.log(env.DATABASE_URL); // 이 시점에 실제 값 읽기\n * ```\n */\n validate(): InferEnvType<T>\n {\n // Perform schema-level validation (without reading values)\n this.validateSchemas();\n\n // Return Proxy that lazily reads and validates on access\n return new Proxy({} as InferEnvType<T>, {\n get: (_target, prop: string) =>\n {\n return this.getAndValidate(prop);\n },\n\n ownKeys: () =>\n {\n return Array.from(this.schemas.keys());\n },\n\n getOwnPropertyDescriptor: (_target, prop: string) =>\n {\n if (this.schemas.has(prop))\n {\n return {\n enumerable: true,\n configurable: true,\n get: () => this.getAndValidate(prop)\n };\n }\n\n return undefined;\n },\n\n has: (_target, prop: string) =>\n {\n return this.schemas.has(prop);\n }\n });\n }\n}\n\n/**\n * 레지스트리 생성 헬퍼\n *\n * @example\n * ```typescript\n * const schema = defineEnvSchema({\n * DATABASE_URL: envString({ description: 'Database URL', required: true })\n * });\n *\n * const registry = createEnvRegistry(schema);\n * const env = registry.validate();\n * ```\n */\nexport function createEnvRegistry<T extends EnvSchemaCollection>(\n schemas: T\n): EnvRegistry<T>\n{\n return new EnvRegistry(schemas);\n}"]}
|
|
1
|
+
{"version":3,"sources":["../../src/env/validator.ts","../../src/env/schema.ts","../../src/env/registry.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Environment Variable Management - Parsers\n *\n * Parser functions that transform and validate environment variable strings.\n * All parsers follow the pattern: (value: string) => T or throw Error\n */\n\n// ============================================================================\n// Core Types\n// ============================================================================\n\n/**\n * Parser function that transforms and validates a string value\n * @throws Error if validation fails\n */\nexport type Parser<T> = (value: string) => T;\n\n// ============================================================================\n// String Parsers\n// ============================================================================\n\n/**\n * Parse a non-empty string\n *\n * @param value - Value to parse\n * @returns Trimmed string\n * @throws Error if string is empty after trimming\n *\n * @example\n * ```typescript\n * const name = getEnvVar('APP_NAME', {\n * validator: parseString,\n * });\n * ```\n */\nexport function parseString(value: string): string\n{\n const trimmed = value.trim();\n\n if (trimmed.length === 0)\n {\n throw new Error('Value cannot be empty');\n }\n\n return trimmed;\n}\n\n/**\n * Create a string parser with validation rules\n *\n * @param options - Validation options\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const apiKey = getEnvVar('API_KEY', {\n * validator: createStringParser({\n * minLength: 32,\n * pattern: /^[A-Za-z0-9_-]+$/,\n * }),\n * });\n * ```\n */\nexport function createStringParser(\n options: {\n minLength?: number;\n maxLength?: number;\n pattern?: RegExp;\n trim?: boolean;\n } = {}\n): Parser<string>\n{\n return (value: string): string =>\n {\n const { minLength, maxLength, pattern, trim = true } = options;\n\n let result = trim ? value.trim() : value;\n\n // Empty check\n if (result.length === 0)\n {\n throw new Error('Value cannot be empty');\n }\n\n // Length validation\n if (minLength !== undefined && result.length < minLength)\n {\n throw new Error(`Must be at least ${minLength} characters long (current: ${result.length})`);\n }\n\n if (maxLength !== undefined && result.length > maxLength)\n {\n throw new Error(`Must be at most ${maxLength} characters long (current: ${result.length})`);\n }\n\n // Pattern validation\n if (pattern && !pattern.test(result))\n {\n throw new Error(`Must match pattern ${pattern}`);\n }\n\n return result;\n };\n}\n\n// ============================================================================\n// Boolean Parser\n// ============================================================================\n\n/**\n * Parse a boolean environment variable\n *\n * Accepts: 'true', '1', 'yes' (case-insensitive) → true\n * 'false', '0', 'no' (case-insensitive) → false\n *\n * @param value - Value to parse\n * @returns Boolean value\n * @throws Error if value is not a valid boolean string\n *\n * @example\n * ```typescript\n * const debug = getEnvVar('DEBUG', {\n * default: 'false',\n * validator: parseBoolean,\n * });\n * ```\n */\nexport function parseBoolean(value: string): boolean\n{\n const normalized = value.toLowerCase().trim();\n\n if (['true', '1', 'yes'].includes(normalized))\n {\n return true;\n }\n\n if (['false', '0', 'no'].includes(normalized))\n {\n return false;\n }\n\n throw new Error(\n `Must be a boolean value (true/false, 1/0, yes/no), got: ${value}`\n );\n}\n\n// ============================================================================\n// Number Parsers\n// ============================================================================\n\n/**\n * Parse and validate number\n *\n * @param value - Value to parse\n * @param options - Validation options\n * @returns Parsed number\n * @throws Error if invalid number or constraint violation\n *\n * @example\n * ```typescript\n * const port = getEnvVar('PORT', {\n * default: '3000',\n * validator: (val) => parseNumber(val, { min: 1, max: 65535, integer: true }),\n * });\n * ```\n */\nexport function parseNumber(\n value: string,\n options: { min?: number; max?: number; integer?: boolean } = {}\n): number\n{\n const { min, max, integer = false } = options;\n\n // Reject empty strings\n if (value.trim() === '')\n {\n throw new Error('Value cannot be empty');\n }\n\n const num = Number(value);\n\n if (isNaN(num))\n {\n throw new Error(`Must be a valid number, got: ${value}`);\n }\n\n if (integer && !Number.isInteger(num))\n {\n throw new Error(`Must be an integer, got: ${value}`);\n }\n\n if (min !== undefined && num < min)\n {\n throw new Error(`Must be at least ${min}, got: ${num}`);\n }\n\n if (max !== undefined && num > max)\n {\n throw new Error(`Must be at most ${max}, got: ${num}`);\n }\n\n return num;\n}\n\n/**\n * Create a number parser with specific constraints\n *\n * @param options - Validation constraints\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const port = getEnvVar('PORT', {\n * default: '3000',\n * validator: createNumberParser({ min: 1, max: 65535, integer: true }),\n * });\n * ```\n */\nexport function createNumberParser(\n options: { min?: number; max?: number; integer?: boolean } = {}\n): Parser<number>\n{\n return (value: string) => parseNumber(value, options);\n}\n\n/**\n * Parse integer with optional constraints\n *\n * @param value - Value to parse\n * @param options - Min/max constraints\n * @returns Parsed integer\n * @throws Error if invalid or out of range\n *\n * @example\n * ```typescript\n * const retries = getEnvVar('MAX_RETRIES', {\n * default: '3',\n * validator: (val) => parseInteger(val, { min: 1, max: 10 }),\n * });\n * ```\n */\nexport function parseInteger(\n value: string,\n options: { min?: number; max?: number } = {}\n): number\n{\n return parseNumber(value, { ...options, integer: true });\n}\n\n/**\n * Parse float/decimal number with optional constraints\n *\n * @param value - Value to parse\n * @param options - Min/max constraints\n * @returns Parsed decimal number\n * @throws Error if invalid or out of range\n *\n * @example\n * ```typescript\n * const ratio = getEnvVar('CACHE_RATIO', {\n * default: '0.75',\n * validator: (val) => parseDecimal(val, { min: 0, max: 1 }),\n * });\n * ```\n */\nexport function parseDecimal(\n value: string,\n options: { min?: number; max?: number } = {}\n): number\n{\n return parseNumber(value, { ...options, integer: false });\n}\n\n// ============================================================================\n// URL Parsers\n// ============================================================================\n\n/**\n * Parse and validate URL\n *\n * @param value - Value to parse\n * @param options - Validation options\n * @returns Validated URL string\n * @throws Error if invalid URL or protocol mismatch\n *\n * @example\n * ```typescript\n * const apiUrl = getEnvVar('API_URL', {\n * validator: (val) => parseUrl(val, { protocol: 'https' }),\n * });\n * ```\n */\nexport function parseUrl(\n value: string,\n options: { protocol?: 'http' | 'https' | 'any' } = {}\n): string\n{\n const { protocol = 'any' } = options;\n\n // Parse URL (may throw TypeError)\n let url: URL;\n try\n {\n url = new URL(value);\n }\n catch (error)\n {\n if (error instanceof TypeError)\n {\n throw new Error(`Invalid URL: ${value}`);\n }\n throw error;\n }\n\n // Validate protocol\n if (protocol === 'http' && url.protocol !== 'http:')\n {\n throw new Error(`URL must use HTTP protocol, got ${url.protocol}`);\n }\n\n if (protocol === 'https' && url.protocol !== 'https:')\n {\n throw new Error(`URL must use HTTPS protocol, got ${url.protocol}`);\n }\n\n return value;\n}\n\n/**\n * Create a URL parser with specific protocol requirement\n *\n * @param protocol - Required protocol ('http', 'https', or 'any')\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const apiUrl = getEnvVar('API_URL', {\n * validator: createUrlParser('https'),\n * });\n * ```\n */\nexport function createUrlParser(protocol: 'http' | 'https' | 'any' = 'any'): Parser<string>\n{\n return (value: string) => parseUrl(value, { protocol });\n}\n\n/**\n * Parse PostgreSQL connection string\n *\n * @param value - Value to parse\n * @returns Validated PostgreSQL URL string\n * @throws Error if invalid PostgreSQL URL\n *\n * @example\n * ```typescript\n * const dbUrl = getEnvVar('DATABASE_URL', {\n * required: true,\n * validator: parsePostgresUrl,\n * });\n * ```\n */\nexport function parsePostgresUrl(value: string): string\n{\n // Parse URL (may throw TypeError)\n let url: URL;\n try\n {\n url = new URL(value);\n }\n catch (error)\n {\n if (error instanceof TypeError)\n {\n throw new Error(`Invalid PostgreSQL URL: ${value}`);\n }\n throw error;\n }\n\n // Validate protocol\n if (url.protocol !== 'postgres:' && url.protocol !== 'postgresql:')\n {\n throw new Error(\n `Must be a PostgreSQL URL (postgres:// or postgresql://), got ${url.protocol}`\n );\n }\n\n return value;\n}\n\n/**\n * Parse Redis connection string\n *\n * @param value - Value to parse\n * @returns Validated Redis URL string\n * @throws Error if invalid Redis URL\n *\n * @example\n * ```typescript\n * const redisUrl = getEnvVar('REDIS_URL', {\n * required: true,\n * validator: parseRedisUrl,\n * });\n * ```\n */\nexport function parseRedisUrl(value: string): string\n{\n // Parse URL (may throw TypeError)\n let url: URL;\n try\n {\n url = new URL(value);\n }\n catch (error)\n {\n if (error instanceof TypeError)\n {\n throw new Error(`Invalid Redis URL: ${value}`);\n }\n throw error;\n }\n\n // Validate protocol\n if (url.protocol !== 'redis:' && url.protocol !== 'rediss:')\n {\n throw new Error(\n `Must be a Redis URL (redis:// or rediss://), got ${url.protocol}`\n );\n }\n\n return value;\n}\n\n// ============================================================================\n// Enum Parser\n// ============================================================================\n\n/**\n * Parse and validate enum value\n *\n * @param value - Value to parse\n * @param allowed - Array of allowed values\n * @param caseInsensitive - Whether to perform case-insensitive comparison\n * @returns Validated enum value\n * @throws Error if value not in allowed list\n *\n * @example\n * ```typescript\n * const env = getEnvVar('NODE_ENV', {\n * validator: (val) => parseEnum(val, ['development', 'production', 'test']),\n * });\n * ```\n */\nexport function parseEnum(\n value: string,\n allowed: string[],\n caseInsensitive = false\n): string\n{\n if (caseInsensitive)\n {\n const normalizedValue = value.toLowerCase();\n const normalizedAllowed = allowed.map((v) => v.toLowerCase());\n const index = normalizedAllowed.indexOf(normalizedValue);\n\n if (index === -1)\n {\n throw new Error(\n `Must be one of [${allowed.join(', ')}], got: ${value}`\n );\n }\n\n return allowed[index]; // Return original case from allowed list\n }\n\n if (!allowed.includes(value))\n {\n throw new Error(\n `Must be one of [${allowed.join(', ')}], got: ${value}`\n );\n }\n\n return value;\n}\n\n/**\n * Create an enum parser with specific allowed values\n *\n * @param allowed - Array of allowed values\n * @param caseInsensitive - Whether to perform case-insensitive comparison\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const logLevel = getEnvVar('LOG_LEVEL', {\n * default: 'info',\n * validator: createEnumParser(['debug', 'info', 'warn', 'error']),\n * });\n * ```\n */\nexport function createEnumParser(allowed: string[], caseInsensitive = false): Parser<string>\n{\n return (value: string) => parseEnum(value, allowed, caseInsensitive);\n}\n\n// ============================================================================\n// JSON Parser\n// ============================================================================\n\n/**\n * Parse JSON string\n *\n * @param value - JSON string to parse\n * @returns Parsed JSON value\n * @throws Error if invalid JSON\n *\n * @example\n * ```typescript\n * const config = getEnvVar('CONFIG_JSON', {\n * validator: parseJson,\n * });\n * ```\n */\nexport function parseJson<T = any>(value: string): T\n{\n try\n {\n return JSON.parse(value) as T;\n }\n catch (error)\n {\n throw new Error(\n `Invalid JSON: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n}\n\n/**\n * Create a typed JSON parser\n *\n * @returns Parser function\n *\n * @example\n * ```typescript\n * interface Config {\n * host: string;\n * port: number;\n * }\n *\n * const config = getEnvVar('CONFIG_JSON', {\n * validator: createJsonParser<Config>(),\n * });\n * ```\n */\nexport function createJsonParser<T>(): Parser<T>\n{\n return (value: string) => parseJson<T>(value);\n}\n\n// ============================================================================\n// Array Parser\n// ============================================================================\n\n/**\n * Parse comma-separated values into array\n *\n * @param value - Comma-separated string\n * @param options - Parser options\n * @returns Array of strings\n *\n * @example\n * ```typescript\n * const hosts = getEnvVar('ALLOWED_HOSTS', {\n * validator: parseArray,\n * });\n * // \"localhost,example.com,api.example.com\" → ['localhost', 'example.com', 'api.example.com']\n * ```\n */\nexport function parseArray(\n value: string,\n options: {\n separator?: string;\n trim?: boolean;\n filter?: (item: string) => boolean;\n } = {}\n): string[]\n{\n const { separator = ',', trim = true, filter } = options;\n\n if (value.trim() === '')\n {\n return [];\n }\n\n let items = value.split(separator);\n\n if (trim)\n {\n items = items.map((item) => item.trim());\n }\n\n if (filter)\n {\n items = items.filter(filter);\n }\n\n return items;\n}\n\n/**\n * Create an array parser with item parser\n *\n * @param itemParser - Parser to apply to each array item\n * @param options - Array parsing options\n * @returns Parser function\n *\n * @example\n * ```typescript\n * // Parse comma-separated ports\n * const ports = getEnvVar('PORTS', {\n * validator: createArrayParser(\n * createNumberParser({ min: 1, max: 65535, integer: true })\n * ),\n * });\n * // \"3000,4000,5000\" → [3000, 4000, 5000]\n * ```\n */\nexport function createArrayParser<T>(\n itemParser: Parser<T>,\n options: { separator?: string } = {}\n): Parser<T[]>\n{\n return (value: string): T[] =>\n {\n const items = parseArray(value, options);\n\n return items.map((item, index) =>\n {\n try\n {\n return itemParser(item);\n }\n catch (error)\n {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Invalid item at index ${index}: ${message}`);\n }\n });\n };\n}\n\n// ============================================================================\n// Secure Secret Parser\n// ============================================================================\n\n/**\n * Calculate Shannon entropy of a string\n * Returns entropy in bits per character\n *\n * @param str - String to calculate entropy for\n * @returns Entropy value (0 to ~6.6 bits for printable ASCII)\n *\n * @example\n * ```typescript\n * const entropy = calculateEntropy('my-secret-key');\n * // Higher entropy = more random\n * // - Random lowercase: ~4.7 bits/char\n * // - Random alphanumeric: ~5.2 bits/char\n * // - Random printable ASCII: ~6.6 bits/char\n * // - \"aaaaaaa...\": ~0 bits/char\n * ```\n */\nfunction calculateEntropy(str: string): number\n{\n const len = str.length;\n const frequencies = new Map<string, number>();\n\n // Count character frequencies\n for (const char of str)\n {\n frequencies.set(char, (frequencies.get(char) || 0) + 1);\n }\n\n // Calculate Shannon entropy\n let entropy = 0;\n for (const count of frequencies.values())\n {\n const probability = count / len;\n entropy -= probability * Math.log2(probability);\n }\n\n return entropy;\n}\n\n/**\n * Create a secure secret parser with entropy validation\n *\n * Validates cryptographic secrets for sufficient length, character diversity, and randomness.\n * Uses Shannon entropy to measure randomness quality.\n *\n * @param options - Validation options\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const sessionSecret = getEnvVar('SESSION_SECRET', {\n * validator: createSecureSecretParser({\n * minLength: 32, // Minimum 256-bit\n * minUniqueChars: 16, // Character diversity\n * minEntropy: 3.5, // Shannon entropy (bits/char)\n * }),\n * });\n * ```\n */\nexport function createSecureSecretParser(\n options: {\n minLength?: number;\n minUniqueChars?: number;\n minEntropy?: number;\n } = {}\n): Parser<string>\n{\n const {\n minLength = 32,\n minUniqueChars = 16,\n minEntropy = 3.5,\n } = options;\n\n return (value: string): string =>\n {\n const length = value.length;\n const uniqueChars = new Set(value).size;\n const entropy = calculateEntropy(value);\n\n // Check length (minimum for cryptographic strength)\n if (length < minLength)\n {\n throw new Error(\n `Secret too short: ${length} characters (minimum: ${minLength})`\n );\n }\n\n // Check unique character diversity\n if (uniqueChars < minUniqueChars)\n {\n throw new Error(\n `Secret has low diversity: ${uniqueChars} unique characters (minimum: ${minUniqueChars})`\n );\n }\n\n // Check Shannon entropy (randomness quality)\n // Reference values:\n // - Random lowercase: ~4.7 bits/char\n // - Random alphanumeric: ~5.2 bits/char\n // - Random printable ASCII: ~6.6 bits/char\n // - \"aaaaaaa...\": ~0 bits/char\n // - \"abcabcabc...\": ~1.58 bits/char\n if (entropy < minEntropy)\n {\n throw new Error(\n `Secret has low entropy: ${entropy.toFixed(2)} bits/char (minimum: ${minEntropy}). Use a more random secret.`\n );\n }\n\n return value;\n };\n}\n\n// ============================================================================\n// Password Parser\n// ============================================================================\n\n/**\n * Create a password strength parser\n *\n * Validates password strength based on configurable requirements.\n * Useful for enforcing password policies in environment variables or user input.\n *\n * @param options - Validation options\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const adminPassword = getEnvVar('ADMIN_PASSWORD', {\n * validator: createPasswordParser({\n * minLength: 12,\n * requireUppercase: true,\n * requireLowercase: true,\n * requireNumber: true,\n * requireSpecial: true,\n * }),\n * });\n * ```\n */\nexport function createPasswordParser(\n options: {\n minLength?: number;\n requireUppercase?: boolean;\n requireLowercase?: boolean;\n requireNumber?: boolean;\n requireSpecial?: boolean;\n } = {}\n): Parser<string>\n{\n const {\n minLength = 8,\n requireUppercase = true,\n requireLowercase = true,\n requireNumber = true,\n requireSpecial = true,\n } = options;\n\n return (value: string): string =>\n {\n const errors: string[] = [];\n\n // Length check\n if (value.length < minLength)\n {\n errors.push(`Must be at least ${minLength} characters`);\n }\n\n // Uppercase check\n if (requireUppercase && !/[A-Z]/.test(value))\n {\n errors.push('Must contain at least one uppercase letter');\n }\n\n // Lowercase check\n if (requireLowercase && !/[a-z]/.test(value))\n {\n errors.push('Must contain at least one lowercase letter');\n }\n\n // Number check\n if (requireNumber && !/[0-9]/.test(value))\n {\n errors.push('Must contain at least one number');\n }\n\n // Special character check\n if (requireSpecial && !/[^A-Za-z0-9]/.test(value))\n {\n errors.push('Must contain at least one special character');\n }\n\n if (errors.length > 0)\n {\n throw new Error(`Password validation failed: ${errors.join(', ')}`);\n }\n\n return value;\n };\n}\n\n// ============================================================================\n// Parser Composition\n// ============================================================================\n\n/**\n * Chain multiple parsers sequentially\n *\n * Each parser receives the output of the previous parser.\n * Useful for multi-step validation/transformation.\n *\n * @param parsers - Array of parser functions\n * @returns Combined parser function\n *\n * @example\n * ```typescript\n * const apiKey = getEnvVar('API_KEY', {\n * validator: chain(\n * parseString,\n * createStringParser({ minLength: 32, pattern: /^[A-Za-z0-9_-]+$/ }),\n * ),\n * });\n * ```\n */\nexport function chain<T>(...parsers: Array<Parser<T>>): Parser<T>\n{\n return (value: string): T =>\n {\n let result = value as any;\n\n for (const parser of parsers)\n {\n result = parser(result);\n }\n\n return result;\n };\n}\n\n/**\n * Apply parser with fallback value\n *\n * If parser throws, returns fallback instead.\n * Useful for optional environment variables with complex parsing.\n *\n * @param parser - Parser to attempt\n * @param fallback - Fallback value if parsing fails\n * @returns Parser function\n *\n * @example\n * ```typescript\n * const config = getEnvVar('CONFIG_JSON', {\n * validator: withFallback(parseJson, { host: 'localhost', port: 3000 }),\n * });\n * ```\n */\nexport function withFallback<T>(parser: Parser<T>, fallback: T): Parser<T>\n{\n return (value: string): T =>\n {\n try\n {\n return parser(value);\n }\n catch\n {\n return fallback;\n }\n };\n}\n\n/**\n * Make parser optional\n *\n * Returns undefined for empty strings instead of throwing.\n *\n * @param parser - Parser to make optional\n * @returns Parser function that returns T | undefined\n *\n * @example\n * ```typescript\n * const redisUrl = getEnvVar('REDIS_URL', {\n * validator: optional(parseRedisUrl),\n * });\n * // Empty string → undefined\n * // Valid URL → parsed URL\n * // Invalid URL → throws\n * ```\n */\nexport function optional<T>(parser: Parser<T>): Parser<T | undefined>\n{\n return (value: string): T | undefined =>\n {\n if (value.trim() === '')\n {\n return undefined;\n }\n\n return parser(value);\n };\n}","/**\n * Environment Variable Schema Definition System\n *\n * 환경변수에 메타데이터를 정의하여 중앙 관리, 문서화, 검증을 지원합니다.\n *\n * @example\n * ```typescript\n * const schema = defineEnvSchema({\n * DATABASE_URL: envUrl({\n * description: 'Database connection',\n * required: true,\n * validator: parsePostgresUrl,\n * sensitive: true,\n * })\n * });\n * ```\n *\n * @module env/schema\n */\n\nimport { parseBoolean, parseNumber, parseJson } from './validator';\n\n/**\n * 환경변수 스키마 정의\n */\nexport interface EnvVarSchema<T = string>\n{\n /** 환경변수 키 */\n key: string;\n\n /** 설명 (목적, 사용처) */\n description: string;\n\n /** 타입 */\n type: 'string' | 'number' | 'boolean' | 'url' | 'enum' | 'json';\n\n /** 필수 여부 */\n required?: boolean;\n\n /** 기본값 */\n default?: T;\n\n /** 검증/변환 함수 */\n validator?: (value: string) => T;\n\n // === 검증 옵션 ===\n\n /** Fallback 환경변수 키들 (backward compatibility) */\n fallbackKeys?: string[];\n\n /** 최소 길이 (문자열 타입) */\n minLength?: number;\n\n // === 메타데이터 ===\n\n /** 민감정보 여부 (로깅 시 마스킹) */\n sensitive?: boolean;\n\n /** 예시 값들 (타입과 일치해야 함) */\n examples?: T[];\n\n // === 파일 분리 ===\n\n /**\n * Next.js 프로세스에서 사용 여부\n *\n * - true: .env.local에 존재해야 함 (Next.js 서버 컴포넌트에서 접근 가능)\n * - false: .env.server.local에만 존재해야 함 (SPFN 서버에서만 접근)\n *\n * @default NEXT_PUBLIC_* 이면 true, 아니면 false\n */\n nextjs?: boolean;\n}\n\n/**\n * 스키마 컬렉션 타입\n */\nexport type EnvSchemaCollection = Record<string, EnvVarSchema<any>>;\n\n/**\n * Helper type: Check if field has default value\n */\ntype HasDefault<T> = T extends { default: any } ? true : false;\n\n/**\n * Helper type: Check if field is explicitly required\n */\ntype IsRequired<T> = T extends { required: true } ? true : false;\n\n/**\n * Helper type: Check if field should be required (has default OR required: true)\n */\ntype ShouldBeRequired<T> = HasDefault<T> extends true ? true : IsRequired<T>;\n\n/**\n * 스키마로부터 타입 추출\n *\n * required: true 또는 default가 있는 필드 → 필수\n * required: false 또는 미지정 → optional (| undefined)\n */\nexport type InferEnvType<T extends EnvSchemaCollection> = {\n // Required fields (required: true OR has default)\n [K in keyof T as ShouldBeRequired<T[K]> extends true ? K : never]:\n T[K] extends EnvVarSchema<infer U> ? U : string;\n} & {\n // Optional fields (required: false OR not specified)\n [K in keyof T as ShouldBeRequired<T[K]> extends true ? never : K]?:\n T[K] extends EnvVarSchema<infer U> ? U | undefined : string | undefined;\n};\n\n/**\n * 스키마 정의 헬퍼 (타입 추론 지원)\n *\n * Automatically fills in the `key` property from object keys.\n *\n * @example\n * ```typescript\n * const schema = defineEnvSchema({\n * DATABASE_URL: envString({ description: 'Database URL', required: true })\n * });\n * // Automatically adds key: 'DATABASE_URL'\n * ```\n */\nexport function defineEnvSchema<T extends Record<string, any>>(\n schema: T\n): { [K in keyof T]: T[K] & { key: K } }\n{\n const result: any = {};\n\n for (const key in schema)\n {\n result[key] = {\n ...schema[key],\n key,\n };\n }\n\n return result;\n}\n\n/**\n * 문자열 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * API_KEY: {\n * ...envString({\n * description: 'API authentication key',\n * required: true,\n * sensitive: true,\n * }),\n * key: 'API_KEY',\n * }\n * };\n * ```\n */\nexport function envString<T extends Omit<EnvVarSchema, 'key' | 'type'>>(\n options: T\n): T & { type: 'string' }\n{\n return {\n ...options,\n type: 'string',\n };\n}\n\n/**\n * 숫자 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * PORT: {\n * ...envNumber({\n * description: 'Server port',\n * default: 3000,\n * validator: createNumberParser({ min: 1, max: 65535 }),\n * }),\n * key: 'PORT',\n * }\n * };\n * ```\n */\nexport function envNumber<T extends Omit<EnvVarSchema<number>, 'key' | 'type'>>(\n options: T\n): T & { type: 'number'; validator: (value: string) => number }\n{\n return {\n ...options,\n type: 'number',\n validator: options.validator || parseNumber,\n };\n}\n\n/**\n * Boolean 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * DEBUG: {\n * ...envBoolean({\n * description: 'Enable debug mode',\n * default: false,\n * }),\n * key: 'DEBUG',\n * }\n * };\n * ```\n */\nexport function envBoolean<T extends Omit<EnvVarSchema<boolean>, 'key' | 'type'>>(\n options: T\n): T & { type: 'boolean'; validator: (value: string) => boolean }\n{\n return {\n ...options,\n type: 'boolean',\n validator: options.validator || parseBoolean,\n };\n}\n\n/**\n * URL 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * DATABASE_URL: {\n * ...envUrl({\n * description: 'Database connection URL',\n * required: true,\n * validator: parsePostgresUrl,\n * }),\n * key: 'DATABASE_URL',\n * }\n * };\n * ```\n */\nexport function envUrl<T extends Omit<EnvVarSchema, 'key' | 'type'>>(\n options: T\n): T & { type: 'url' }\n{\n return {\n ...options,\n type: 'url',\n };\n}\n\n/**\n * Enum 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * LOG_LEVEL: {\n * ...envEnum(['debug', 'info', 'warn', 'error'] as const, {\n * description: 'Logging level',\n * default: 'info',\n * }),\n * key: 'LOG_LEVEL',\n * }\n * };\n * ```\n */\nexport function envEnum<\n T extends string,\n O extends Omit<EnvVarSchema<T>, 'key' | 'type' | 'validator'>\n>(\n allowed: readonly T[],\n options: O\n): O & { type: 'enum'; validator: (val: string) => T }\n{\n return {\n ...options,\n type: 'enum',\n validator: (val: string): T =>\n {\n if (!allowed.includes(val as T))\n {\n throw new Error(`Must be one of: ${allowed.join(', ')}, got: ${val}`);\n }\n\n return val as T;\n },\n };\n}\n\n/**\n * JSON 스키마 헬퍼\n *\n * @example\n * ```typescript\n * const schema = {\n * CONFIG_JSON: {\n * ...envJson<{ host: string; port: number }>({\n * description: 'JSON configuration object',\n * required: true,\n * }),\n * key: 'CONFIG_JSON',\n * }\n * };\n * ```\n */\nexport function envJson<\n T = any,\n O extends Omit<EnvVarSchema<T>, 'key' | 'type' | 'validator'> = Omit<EnvVarSchema<T>, 'key' | 'type' | 'validator'>\n>(\n options: O\n): O & { type: 'json'; validator: (val: string) => T }\n{\n return {\n ...options,\n type: 'json',\n validator: (val: string) => parseJson<T>(val),\n };\n}\n\n/**\n * 환경변수가 클라이언트에서 접근 가능한지 확인\n * (NEXT_PUBLIC_ 접두사로 판단)\n *\n * @param key - 환경변수 키\n * @returns 클라이언트에서 접근 가능하면 true\n *\n * @example\n * ```typescript\n * isClientAccessible('NEXT_PUBLIC_API_URL'); // true\n * isClientAccessible('DATABASE_URL'); // false\n * ```\n */\nexport function isClientAccessible(key: string): boolean\n{\n return key.startsWith('NEXT_PUBLIC_');\n}\n\n/**\n * 환경변수가 서버 전용인지 확인\n * (NEXT_PUBLIC_ 접두사가 없으면 서버 전용)\n *\n * @param key - 환경변수 키\n * @returns 서버 전용이면 true\n *\n * @example\n * ```typescript\n * isServerOnly('DATABASE_URL'); // true\n * isServerOnly('NEXT_PUBLIC_API_URL'); // false\n * ```\n */\nexport function isServerOnly(key: string): boolean\n{\n return !isClientAccessible(key);\n}\n\n/**\n * 스키마의 nextjs 옵션 값 결정\n *\n * 명시적으로 지정되지 않은 경우:\n * - NEXT_PUBLIC_* → true\n * - 그 외 → false\n *\n * @param schema - 환경변수 스키마\n * @returns Next.js 프로세스에서 사용 가능 여부\n */\nexport function isNextjsAccessible(schema: EnvVarSchema): boolean\n{\n if (schema.nextjs !== undefined)\n {\n return schema.nextjs;\n }\n\n return isClientAccessible(schema.key);\n}\n\n/**\n * 스키마가 SPFN 서버 전용인지 확인\n *\n * @param schema - 환경변수 스키마\n * @returns SPFN 서버에서만 사용되면 true\n */\nexport function isSpfnServerOnly(schema: EnvVarSchema): boolean\n{\n return !isNextjsAccessible(schema);\n}","/**\n * Environment Variable Registry\n *\n * 환경변수 스키마를 등록하고 타입 안전하게 접근할 수 있는 레지스트리\n *\n * @example\n * ```typescript\n * const schema = defineEnvSchema({\n * DATABASE_URL: envString({ description: 'Database URL', required: true })\n * });\n *\n * const registry = createEnvRegistry(schema);\n * const env = registry.validate(); // 검증 + env 반환\n * console.log(env.DATABASE_URL);\n * ```\n *\n * @module env/registry\n */\nimport type { EnvVarSchema, EnvSchemaCollection, InferEnvType } from './schema';\nimport { isClientAccessible } from './schema';\nimport { logger } from '@spfn/core/logger';\n\nconst envLogger = logger.child('@spfn/core:env-registry')\n\n\n/**\n * 환경변수 레지스트리\n *\n * 스키마 기반 환경변수 관리 및 검증\n */\nexport class EnvRegistry<T extends EnvSchemaCollection = EnvSchemaCollection>\n{\n private schemas = new Map<string, EnvVarSchema>();\n private hasValidated = false;\n\n constructor(schemas?: T)\n {\n if (schemas)\n {\n this.registerMultiple(schemas);\n }\n }\n\n /**\n * 스키마 등록\n */\n register(schema: EnvVarSchema): void\n {\n this.schemas.set(schema.key, schema);\n }\n\n /**\n * 여러 스키마 등록\n */\n registerMultiple(schemas: EnvSchemaCollection): void\n {\n for (const [key, schema] of Object.entries(schemas))\n {\n this.register({ ...schema, key });\n }\n }\n\n /**\n * 검증 상태 리셋 (테스트용)\n */\n reset(): void\n {\n this.hasValidated = false;\n }\n\n /**\n * 환경변수 원시값 가져오기 (fallback 지원)\n */\n private getRawValue(key: string, fallbackKeys?: string[]): string | undefined\n {\n let value = process.env[key];\n\n if (!value && fallbackKeys)\n {\n for (const fallbackKey of fallbackKeys)\n {\n value = process.env[fallbackKey];\n if (value)\n {\n break;\n }\n }\n }\n\n return value;\n }\n\n /**\n * 값에 validator 적용\n */\n private applyValidator<U>(\n value: string,\n schema: EnvVarSchema<U>\n ): U\n {\n if (schema.validator)\n {\n return schema.validator(value) as U;\n }\n\n return value as U;\n }\n\n /**\n * 스키마 검증 수행 (값 읽기 없이)\n *\n * @internal\n */\n private validateSchemas(): void\n {\n // Skip if already validated\n if (this.hasValidated)\n {\n return;\n }\n\n const warnings: string[] = [];\n\n // 클라이언트 변수 중 민감정보 경고\n for (const [key, schema] of this.schemas)\n {\n if (isClientAccessible(key) && schema.sensitive)\n {\n warnings.push(\n `${key} is marked as sensitive but accessible from client (NEXT_PUBLIC_*). Remove NEXT_PUBLIC_ prefix or unmark as sensitive.`\n );\n }\n }\n\n // Log warnings\n if (warnings.length > 0)\n {\n envLogger.warn('Environment validation warnings:');\n warnings.forEach(w => envLogger.warn(` - ${w}`));\n }\n\n this.hasValidated = true;\n }\n\n /**\n * 실제 접근 시점에 환경변수 값 가져오기 및 검증\n *\n * @internal\n */\n private getAndValidate(key: string): any\n {\n const schema = this.schemas.get(key);\n if (!schema)\n {\n return undefined;\n }\n\n // Get raw value using common helper\n const value = this.getRawValue(key, schema.fallbackKeys);\n\n // Check if required\n if (schema.required && !value)\n {\n const fallbackHint = schema.fallbackKeys\n ? ` (or ${schema.fallbackKeys.join(', ')})`\n : '';\n\n const errorMsg = `${key}${fallbackHint} is required but not set. ${schema.description || ''}`;\n envLogger.error(`Environment validation failed:\\n - ${errorMsg}`);\n throw new Error('Environment validation failed');\n }\n\n // If no value and not required, use default\n if (!value)\n {\n return schema.default;\n }\n\n // Check minLength\n if (schema.minLength !== undefined && value.length < schema.minLength)\n {\n const errorMsg = `${key} must be at least ${schema.minLength} characters long (current: ${value.length})`;\n envLogger.error(`Environment validation failed:\\n - ${errorMsg}`);\n throw new Error('Environment validation failed');\n }\n\n // Apply validator\n try\n {\n return this.applyValidator(value, schema);\n }\n catch (error)\n {\n const errorMsg = `${key} validation failed: ${error instanceof Error ? error.message : String(error)}`;\n envLogger.error(`Environment validation failed:\\n - ${errorMsg}`);\n throw new Error('Environment validation failed');\n }\n }\n\n /**\n * 환경변수 검증 및 타입 안전한 env 객체 반환\n *\n * Proxy 기반으로 구현되어 실제 환경변수 접근 시점에 값을 읽고 검증합니다.\n * 이를 통해 dotenv 로딩 타이밍과 무관하게 최신 환경변수 값을 가져올 수 있습니다.\n *\n * @returns 검증된 환경변수 객체 (Proxy)\n * @throws {Error} 필수 변수 누락 또는 검증 실패 시\n *\n * @example\n * ```typescript\n * const registry = createEnvRegistry(schema);\n * const env = registry.validate(); // 스키마만 검증\n * // ... dotenv 로딩 ...\n * console.log(env.DATABASE_URL); // 이 시점에 실제 값 읽기\n * ```\n */\n validate(): InferEnvType<T>\n {\n // Perform schema-level validation (without reading values)\n this.validateSchemas();\n\n // Return Proxy that lazily reads and validates on access\n return new Proxy({} as InferEnvType<T>, {\n get: (_target, prop: string) =>\n {\n return this.getAndValidate(prop);\n },\n\n ownKeys: () =>\n {\n return Array.from(this.schemas.keys());\n },\n\n getOwnPropertyDescriptor: (_target, prop: string) =>\n {\n if (this.schemas.has(prop))\n {\n return {\n enumerable: true,\n configurable: true,\n get: () => this.getAndValidate(prop)\n };\n }\n\n return undefined;\n },\n\n has: (_target, prop: string) =>\n {\n return this.schemas.has(prop);\n }\n });\n }\n}\n\n/**\n * 레지스트리 생성 헬퍼\n *\n * @example\n * ```typescript\n * const schema = defineEnvSchema({\n * DATABASE_URL: envString({ description: 'Database URL', required: true })\n * });\n *\n * const registry = createEnvRegistry(schema);\n * const env = registry.validate();\n * ```\n */\nexport function createEnvRegistry<T extends EnvSchemaCollection>(\n schemas: T\n): EnvRegistry<T>\n{\n return new EnvRegistry(schemas);\n}"]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Variable Loader
|
|
3
|
+
*
|
|
4
|
+
* Next.js 스타일의 환경변수 파일 로딩
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { loadEnv } from '@spfn/core/env/loader';
|
|
9
|
+
*
|
|
10
|
+
* // SPFN 서버 진입점에서 호출
|
|
11
|
+
* loadEnv();
|
|
12
|
+
*
|
|
13
|
+
* // 이후 스키마 검증
|
|
14
|
+
* const env = createEnvRegistry(envSchema).validate();
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @module env/loader
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* loadEnv 옵션
|
|
21
|
+
*/
|
|
22
|
+
interface LoadEnvOptions {
|
|
23
|
+
/**
|
|
24
|
+
* 프로젝트 루트 경로
|
|
25
|
+
* @default process.cwd()
|
|
26
|
+
*/
|
|
27
|
+
cwd?: string;
|
|
28
|
+
/**
|
|
29
|
+
* 디버그 모드 (로드된 파일 로깅)
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
debug?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* 기존 process.env 값 덮어쓰기 허용
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
override?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 환경변수 로드 결과
|
|
41
|
+
*/
|
|
42
|
+
interface LoadEnvResult {
|
|
43
|
+
/**
|
|
44
|
+
* 로드된 파일 목록
|
|
45
|
+
*/
|
|
46
|
+
loadedFiles: string[];
|
|
47
|
+
/**
|
|
48
|
+
* 로드된 환경변수 키 목록
|
|
49
|
+
*/
|
|
50
|
+
loadedKeys: string[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 프로젝트 루트의 환경변수 파일들을 규칙에 따라 로드
|
|
54
|
+
*
|
|
55
|
+
* Next.js 스타일의 우선순위를 따름:
|
|
56
|
+
* - .env → .env.local → .env.server → .env.server.local
|
|
57
|
+
* - 나중에 로드된 값이 이전 값을 덮어씀
|
|
58
|
+
*
|
|
59
|
+
* @param options - 로드 옵션
|
|
60
|
+
* @returns 로드 결과 (로드된 파일, 키 목록)
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* // 기본 사용
|
|
65
|
+
* loadEnv();
|
|
66
|
+
*
|
|
67
|
+
* // 커스텀 경로
|
|
68
|
+
* loadEnv({ cwd: '/path/to/project' });
|
|
69
|
+
*
|
|
70
|
+
* // 디버그 모드
|
|
71
|
+
* loadEnv({ debug: true });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
declare function loadEnv(options?: LoadEnvOptions): LoadEnvResult;
|
|
75
|
+
/**
|
|
76
|
+
* 환경변수를 한 번만 로드 (중복 호출 방지)
|
|
77
|
+
*
|
|
78
|
+
* @param options - 로드 옵션
|
|
79
|
+
* @returns 로드 결과 (이미 로드된 경우 빈 결과)
|
|
80
|
+
*/
|
|
81
|
+
declare function loadEnvOnce(options?: LoadEnvOptions): LoadEnvResult;
|
|
82
|
+
/**
|
|
83
|
+
* 환경변수 로드 상태 리셋 (테스트용)
|
|
84
|
+
*/
|
|
85
|
+
declare function resetEnvLoadState(): void;
|
|
86
|
+
|
|
87
|
+
export { type LoadEnvOptions, type LoadEnvResult, loadEnv, loadEnvOnce, resetEnvLoadState };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { parse } from 'dotenv';
|
|
4
|
+
import { logger } from '@spfn/core/logger';
|
|
5
|
+
|
|
6
|
+
// src/env/loader.ts
|
|
7
|
+
var envLogger = logger.child("@spfn/core:env-loader");
|
|
8
|
+
var ENV_FILES = [
|
|
9
|
+
".env",
|
|
10
|
+
".env.local",
|
|
11
|
+
".env.server",
|
|
12
|
+
".env.server.local"
|
|
13
|
+
];
|
|
14
|
+
function parseEnvFile(filePath) {
|
|
15
|
+
if (!existsSync(filePath)) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const content = readFileSync(filePath, "utf-8");
|
|
19
|
+
return parse(content);
|
|
20
|
+
}
|
|
21
|
+
function loadEnv(options = {}) {
|
|
22
|
+
const {
|
|
23
|
+
cwd = process.cwd(),
|
|
24
|
+
debug = false,
|
|
25
|
+
override = false
|
|
26
|
+
} = options;
|
|
27
|
+
const loadedFiles = [];
|
|
28
|
+
const loadedKeys = /* @__PURE__ */ new Set();
|
|
29
|
+
for (const fileName of ENV_FILES) {
|
|
30
|
+
const filePath = resolve(cwd, fileName);
|
|
31
|
+
const parsed = parseEnvFile(filePath);
|
|
32
|
+
if (parsed === null) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
loadedFiles.push(fileName);
|
|
36
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
37
|
+
if (!override && process.env[key] !== void 0) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
process.env[key] = value;
|
|
41
|
+
loadedKeys.add(key);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (debug && loadedFiles.length > 0) {
|
|
45
|
+
envLogger.debug(`Loaded env files: ${loadedFiles.join(", ")}`);
|
|
46
|
+
envLogger.debug(`Loaded ${loadedKeys.size} environment variables`);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
loadedFiles,
|
|
50
|
+
loadedKeys: Array.from(loadedKeys)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
var isEnvLoaded = false;
|
|
54
|
+
function loadEnvOnce(options = {}) {
|
|
55
|
+
if (isEnvLoaded) {
|
|
56
|
+
return {
|
|
57
|
+
loadedFiles: [],
|
|
58
|
+
loadedKeys: []
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
isEnvLoaded = true;
|
|
62
|
+
return loadEnv(options);
|
|
63
|
+
}
|
|
64
|
+
function resetEnvLoadState() {
|
|
65
|
+
isEnvLoaded = false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { loadEnv, loadEnvOnce, resetEnvLoadState };
|
|
69
|
+
//# sourceMappingURL=loader.js.map
|
|
70
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/env/loader.ts"],"names":[],"mappings":";;;;;;AAwBA,IAAM,SAAA,GAAY,MAAA,CAAO,KAAA,CAAM,uBAAuB,CAAA;AAkCtD,IAAM,SAAA,GAAY;AAAA,EACd,MAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA;AACJ,CAAA;AAKA,SAAS,aAAa,QAAA,EACtB;AACI,EAAA,IAAI,CAAC,UAAA,CAAW,QAAQ,CAAA,EACxB;AACI,IAAA,OAAO,IAAA;AAAA,EACX;AAEA,EAAA,MAAM,OAAA,GAAU,YAAA,CAAa,QAAA,EAAU,OAAO,CAAA;AAC9C,EAAA,OAAO,MAAM,OAAO,CAAA;AACxB;AAwCO,SAAS,OAAA,CAAQ,OAAA,GAA0B,EAAC,EACnD;AACI,EAAA,MAAM;AAAA,IACF,GAAA,GAAM,QAAQ,GAAA,EAAI;AAAA,IAClB,KAAA,GAAQ,KAAA;AAAA,IACR,QAAA,GAAW;AAAA,GACf,GAAI,OAAA;AAEJ,EAAA,MAAM,cAAwB,EAAC;AAC/B,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAY;AAEnC,EAAA,KAAA,MAAW,YAAY,SAAA,EACvB;AACI,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,EAAK,QAAQ,CAAA;AACtC,IAAA,MAAM,MAAA,GAAS,aAAa,QAAQ,CAAA;AAEpC,IAAA,IAAI,WAAW,IAAA,EACf;AACI,MAAA;AAAA,IACJ;AAEA,IAAA,WAAA,CAAY,KAAK,QAAQ,CAAA;AAEzB,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAChD;AAEI,MAAA,IAAI,CAAC,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,GAAG,MAAM,MAAA,EACtC;AACI,QAAA;AAAA,MACJ;AAEA,MAAA,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,GAAI,KAAA;AACnB,MAAA,UAAA,CAAW,IAAI,GAAG,CAAA;AAAA,IACtB;AAAA,EACJ;AAEA,EAAA,IAAI,KAAA,IAAS,WAAA,CAAY,MAAA,GAAS,CAAA,EAClC;AACI,IAAA,SAAA,CAAU,MAAM,CAAA,kBAAA,EAAqB,WAAA,CAAY,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAC7D,IAAA,SAAA,CAAU,KAAA,CAAM,CAAA,OAAA,EAAU,UAAA,CAAW,IAAI,CAAA,sBAAA,CAAwB,CAAA;AAAA,EACrE;AAEA,EAAA,OAAO;AAAA,IACH,WAAA;AAAA,IACA,UAAA,EAAY,KAAA,CAAM,IAAA,CAAK,UAAU;AAAA,GACrC;AACJ;AAKA,IAAI,WAAA,GAAc,KAAA;AAQX,SAAS,WAAA,CAAY,OAAA,GAA0B,EAAC,EACvD;AACI,EAAA,IAAI,WAAA,EACJ;AACI,IAAA,OAAO;AAAA,MACH,aAAa,EAAC;AAAA,MACd,YAAY;AAAC,KACjB;AAAA,EACJ;AAEA,EAAA,WAAA,GAAc,IAAA;AACd,EAAA,OAAO,QAAQ,OAAO,CAAA;AAC1B;AAKO,SAAS,iBAAA,GAChB;AACI,EAAA,WAAA,GAAc,KAAA;AAClB","file":"loader.js","sourcesContent":["/**\n * Environment Variable Loader\n *\n * Next.js 스타일의 환경변수 파일 로딩\n *\n * @example\n * ```typescript\n * import { loadEnv } from '@spfn/core/env/loader';\n *\n * // SPFN 서버 진입점에서 호출\n * loadEnv();\n *\n * // 이후 스키마 검증\n * const env = createEnvRegistry(envSchema).validate();\n * ```\n *\n * @module env/loader\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { parse } from 'dotenv';\nimport { logger } from '@spfn/core/logger';\n\nconst envLogger = logger.child('@spfn/core:env-loader');\n\n/**\n * loadEnv 옵션\n */\nexport interface LoadEnvOptions\n{\n /**\n * 프로젝트 루트 경로\n * @default process.cwd()\n */\n cwd?: string;\n\n /**\n * 디버그 모드 (로드된 파일 로깅)\n * @default false\n */\n debug?: boolean;\n\n /**\n * 기존 process.env 값 덮어쓰기 허용\n * @default false\n */\n override?: boolean;\n}\n\n/**\n * 환경변수 파일 로딩 순서 (우선순위 낮음 → 높음)\n *\n * 1. .env - 기본값 (커밋 O)\n * 2. .env.local - 로컬 오버라이드 (커밋 X)\n * 3. .env.server - 서버 전용 기본값 (커밋 O)\n * 4. .env.server.local - 서버 전용 민감정보 (커밋 X)\n */\nconst ENV_FILES = [\n '.env',\n '.env.local',\n '.env.server',\n '.env.server.local',\n] as const;\n\n/**\n * 단일 .env 파일 파싱\n */\nfunction parseEnvFile(filePath: string): Record<string, string> | null\n{\n if (!existsSync(filePath))\n {\n return null;\n }\n\n const content = readFileSync(filePath, 'utf-8');\n return parse(content);\n}\n\n/**\n * 환경변수 로드 결과\n */\nexport interface LoadEnvResult\n{\n /**\n * 로드된 파일 목록\n */\n loadedFiles: string[];\n\n /**\n * 로드된 환경변수 키 목록\n */\n loadedKeys: string[];\n}\n\n/**\n * 프로젝트 루트의 환경변수 파일들을 규칙에 따라 로드\n *\n * Next.js 스타일의 우선순위를 따름:\n * - .env → .env.local → .env.server → .env.server.local\n * - 나중에 로드된 값이 이전 값을 덮어씀\n *\n * @param options - 로드 옵션\n * @returns 로드 결과 (로드된 파일, 키 목록)\n *\n * @example\n * ```typescript\n * // 기본 사용\n * loadEnv();\n *\n * // 커스텀 경로\n * loadEnv({ cwd: '/path/to/project' });\n *\n * // 디버그 모드\n * loadEnv({ debug: true });\n * ```\n */\nexport function loadEnv(options: LoadEnvOptions = {}): LoadEnvResult\n{\n const {\n cwd = process.cwd(),\n debug = false,\n override = false,\n } = options;\n\n const loadedFiles: string[] = [];\n const loadedKeys = new Set<string>();\n\n for (const fileName of ENV_FILES)\n {\n const filePath = resolve(cwd, fileName);\n const parsed = parseEnvFile(filePath);\n\n if (parsed === null)\n {\n continue;\n }\n\n loadedFiles.push(fileName);\n\n for (const [key, value] of Object.entries(parsed))\n {\n // 기존 값이 있고 override가 false면 스킵\n if (!override && process.env[key] !== undefined)\n {\n continue;\n }\n\n process.env[key] = value;\n loadedKeys.add(key);\n }\n }\n\n if (debug && loadedFiles.length > 0)\n {\n envLogger.debug(`Loaded env files: ${loadedFiles.join(', ')}`);\n envLogger.debug(`Loaded ${loadedKeys.size} environment variables`);\n }\n\n return {\n loadedFiles,\n loadedKeys: Array.from(loadedKeys),\n };\n}\n\n/**\n * 환경변수가 이미 로드되었는지 확인하는 플래그\n */\nlet isEnvLoaded = false;\n\n/**\n * 환경변수를 한 번만 로드 (중복 호출 방지)\n *\n * @param options - 로드 옵션\n * @returns 로드 결과 (이미 로드된 경우 빈 결과)\n */\nexport function loadEnvOnce(options: LoadEnvOptions = {}): LoadEnvResult\n{\n if (isEnvLoaded)\n {\n return {\n loadedFiles: [],\n loadedKeys: [],\n };\n }\n\n isEnvLoaded = true;\n return loadEnv(options);\n}\n\n/**\n * 환경변수 로드 상태 리셋 (테스트용)\n */\nexport function resetEnvLoadState(): void\n{\n isEnvLoaded = false;\n}\n"]}
|
package/dist/event/index.d.ts
CHANGED
|
@@ -1,73 +1,6 @@
|
|
|
1
1
|
import { TSchema, Static } from '@sinclair/typebox';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Event System Types
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Pub/Sub capable cache interface for multi-instance events
|
|
9
|
-
*/
|
|
10
|
-
interface PubSubCache {
|
|
11
|
-
/**
|
|
12
|
-
* Publish a message to a channel
|
|
13
|
-
*/
|
|
14
|
-
publish(channel: string, message: unknown): Promise<void>;
|
|
15
|
-
/**
|
|
16
|
-
* Subscribe to a channel
|
|
17
|
-
*/
|
|
18
|
-
subscribe(channel: string, handler: (message: unknown) => void | Promise<void>): Promise<void>;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Event handler function type
|
|
22
|
-
*/
|
|
23
|
-
type EventHandler<TPayload> = (payload: TPayload) => void | Promise<void>;
|
|
24
|
-
/**
|
|
25
|
-
* Job queue sender function type (used by job module)
|
|
26
|
-
*/
|
|
27
|
-
type JobQueueSender = (queueName: string, payload: unknown) => Promise<void>;
|
|
28
|
-
/**
|
|
29
|
-
* Event definition interface
|
|
30
|
-
*/
|
|
31
|
-
interface EventDef<TPayload = void> {
|
|
32
|
-
/**
|
|
33
|
-
* Unique event name
|
|
34
|
-
*/
|
|
35
|
-
readonly name: string;
|
|
36
|
-
/**
|
|
37
|
-
* TypeBox payload schema (optional)
|
|
38
|
-
*/
|
|
39
|
-
readonly schema?: TSchema;
|
|
40
|
-
/**
|
|
41
|
-
* Subscribe to this event (in-memory handler)
|
|
42
|
-
*/
|
|
43
|
-
subscribe: (handler: EventHandler<TPayload>) => () => void;
|
|
44
|
-
/**
|
|
45
|
-
* Unsubscribe all handlers
|
|
46
|
-
*/
|
|
47
|
-
unsubscribeAll: () => void;
|
|
48
|
-
/**
|
|
49
|
-
* Emit the event (triggers all subscribers and queued jobs)
|
|
50
|
-
*/
|
|
51
|
-
emit: TPayload extends void ? () => Promise<void> : (payload: TPayload) => Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
* Enable cache-based pub/sub for multi-instance support
|
|
54
|
-
* Must await before emitting events to ensure subscription is ready
|
|
55
|
-
*/
|
|
56
|
-
useCache: (cache: PubSubCache) => Promise<EventDef<TPayload>>;
|
|
57
|
-
/**
|
|
58
|
-
* Internal: Register a job queue to receive this event
|
|
59
|
-
* Called by job registration system
|
|
60
|
-
*/
|
|
61
|
-
_registerJobQueue: (queueName: string, sender: JobQueueSender) => void;
|
|
62
|
-
/**
|
|
63
|
-
* Type inference helper
|
|
64
|
-
*/
|
|
65
|
-
_payload: TPayload;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Infer payload type from EventDef
|
|
69
|
-
*/
|
|
70
|
-
type InferEventPayload<TEvent> = TEvent extends EventDef<infer TPayload> ? TPayload : never;
|
|
2
|
+
import { a as EventDef } from '../router-Di7ENoah.js';
|
|
3
|
+
export { e as EventHandler, E as EventRouterDef, I as InferEventNames, f as InferEventPayload, c as InferEventPayloads, b as InferRouterEventPayload, J as JobQueueSender, P as PubSubCache, d as defineEventRouter } from '../router-Di7ENoah.js';
|
|
71
4
|
|
|
72
5
|
/**
|
|
73
6
|
* Event System
|
|
@@ -105,4 +38,4 @@ declare function defineEvent(name: string): EventDef<void>;
|
|
|
105
38
|
*/
|
|
106
39
|
declare function defineEvent<T extends TSchema>(name: string, schema: T): EventDef<Static<T>>;
|
|
107
40
|
|
|
108
|
-
export {
|
|
41
|
+
export { EventDef, defineEvent };
|
package/dist/event/index.js
CHANGED
|
@@ -117,6 +117,15 @@ function defineEvent(name, schema) {
|
|
|
117
117
|
return createEventImpl(name);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
// src/event/router.ts
|
|
121
|
+
function defineEventRouter(events) {
|
|
122
|
+
return {
|
|
123
|
+
events,
|
|
124
|
+
eventNames: Object.keys(events),
|
|
125
|
+
_types: {}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { defineEvent, defineEventRouter };
|
|
121
130
|
//# sourceMappingURL=index.js.map
|
|
122
131
|
//# sourceMappingURL=index.js.map
|
package/dist/event/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/event/event.ts"],"names":[],"mappings":";;;AA+BA,IAAM,WAAA,GAAc,MAAA,CAAO,KAAA,CAAM,kBAAkB,CAAA;AAKnD,SAAS,eAAA,CAAgB,WAAmB,KAAA,EAC5C;AACI,EAAA,WAAA,CAAY,KAAA,CAAM,CAAA,qBAAA,EAAwB,SAAS,CAAA,CAAA,EAAI;AAAA,IACnD,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK;AAAA,GAC/D,CAAA;AACL;AAKA,SAAS,gBAAA,CAAiB,WAAmB,KAAA,EAC7C;AACI,EAAA,WAAA,CAAY,KAAA,CAAM,CAAA,mCAAA,EAAsC,SAAS,CAAA,CAAA,EAAI;AAAA,IACjE,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK;AAAA,GAC/D,CAAA;AACL;AAKA,SAAS,qBAA+B,IAAA,EACxC;AACI,EAAA,MAAM,QAAA,uBAA4C,GAAA,EAAI;AAEtD,EAAA,OAAO;AAAA,IACH,GAAA,EAAK,CAAC,OAAA,KACN;AACI,MAAA,QAAA,CAAS,IAAI,OAAO,CAAA;AACpB,MAAA,WAAA,CAAY,KAAA,CAAM,wBAAwB,IAAI,CAAA,CAAA,EAAI,EAAE,YAAA,EAAc,QAAA,CAAS,MAAM,CAAA;AAEjF,MAAA,OAAO,MACP;AACI,QAAA,QAAA,CAAS,OAAO,OAAO,CAAA;AACvB,QAAA,WAAA,CAAY,KAAA,CAAM,4BAA4B,IAAI,CAAA,CAAA,EAAI,EAAE,YAAA,EAAc,QAAA,CAAS,MAAM,CAAA;AAAA,MACzF,CAAA;AAAA,IACJ,CAAA;AAAA,IAEA,OAAO,MACP;AACI,MAAA,QAAA,CAAS,KAAA,EAAM;AACf,MAAA,WAAA,CAAY,KAAA,CAAM,CAAA,6BAAA,EAAgC,IAAI,CAAA,CAAE,CAAA;AAAA,IAC5D,CAAA;AAAA,IAEA,OAAA,EAAS,OAAO,OAAA,KAChB;AACI,MAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,UAAA;AAAA,QAC1B,CAAC,GAAG,QAAQ,CAAA,CAAE,IAAI,CAAC,OAAA,KAAY,OAAA,CAAQ,OAAO,CAAC;AAAA,OACnD;AAEA,MAAA,KAAA,MAAW,UAAU,OAAA,EACrB;AACI,QAAA,IAAI,MAAA,CAAO,WAAW,UAAA,EACtB;AACI,UAAA,eAAA,CAAgB,IAAA,EAAM,OAAO,MAAM,CAAA;AAAA,QACvC;AAAA,MACJ;AAAA,IACJ;AAAA,GACJ;AACJ;AAKA,SAAS,sBAAsB,IAAA,EAC/B;AACI,EAAA,MAAM,SAAA,uBAA6C,GAAA,EAAI;AAEvD,EAAA,OAAO;AAAA,IACH,QAAA,EAAU,CAAC,SAAA,EAAmB,MAAA,KAC9B;AACI,MAAA,SAAA,CAAU,GAAA,CAAI,WAAW,MAAM,CAAA;AAC/B,MAAA,WAAA,CAAY,MAAM,CAAA,gCAAA,EAAmC,IAAI,CAAA,CAAA,EAAI,EAAE,WAAW,CAAA;AAAA,IAC9E,CAAA;AAAA,IAEA,IAAA,EAAM,OAAO,OAAA,KACb;AACI,MAAA,IAAI,SAAA,CAAU,SAAS,CAAA,EACvB;AACI,QAAA;AAAA,MACJ;AAEA,MAAA,MAAM,OAAA,GAAU,CAAC,GAAG,SAAA,CAAU,SAAS,CAAA;AACvC,MAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,UAAA;AAAA,QAC1B,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAC,SAAA,EAAW,MAAM,CAAA,KAAM,MAAA,CAAO,SAAA,EAAW,OAAO,CAAC;AAAA,OACnE;AAEA,MAAA,KAAA,MAAW,CAAC,CAAA,EAAG,MAAM,CAAA,IAAK,OAAA,CAAQ,SAAQ,EAC1C;AACI,QAAA,IAAI,MAAA,CAAO,WAAW,UAAA,EACtB;AACI,UAAA,gBAAA,CAAiB,QAAQ,CAAC,CAAA,CAAE,CAAC,CAAA,EAAG,OAAO,MAAM,CAAA;AAAA,QACjD;AAAA,MACJ;AAAA,IACJ,CAAA;AAAA,IAEA,IAAI,IAAA,GACJ;AACI,MAAA,OAAO,SAAA,CAAU,IAAA;AAAA,IACrB;AAAA,GACJ;AACJ;AAKA,SAAS,eAAA,CACL,MACA,MAAA,EAEJ;AACI,EAAA,MAAM,cAAA,GAAiB,qBAA+B,IAAI,CAAA;AAC1D,EAAA,MAAM,eAAA,GAAkB,sBAAsB,IAAI,CAAA;AAClD,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI,eAAA,GAAkB,KAAA;AAEtB,EAAA,MAAM,IAAA,GAAO,OAAO,OAAA,KACpB;AACI,IAAA,WAAA,CAAY,KAAA,CAAM,CAAA,gBAAA,EAAmB,IAAI,CAAA,CAAA,EAAI;AAAA,MACzC,OAAA;AAAA,MACA,QAAA,EAAU,CAAC,CAAC,KAAA;AAAA,MACZ,eAAe,eAAA,CAAgB;AAAA,KAClC,CAAA;AAED,IAAA,IAAI,KAAA,EACJ;AACI,MAAA,MAAM,KAAA,CAAM,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA;AAAA,IACrC,CAAA,MAEA;AACI,MAAA,MAAM,cAAA,CAAe,QAAQ,OAAmB,CAAA;AAAA,IACpD;AAEA,IAAA,MAAM,eAAA,CAAgB,KAAK,OAAO,CAAA;AAClC,IAAA,WAAA,CAAY,KAAA,CAAM,CAAA,eAAA,EAAkB,IAAI,CAAA,CAAE,CAAA;AAAA,EAC9C,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW,OAAO,QAAA,KACxB;AACI,IAAA,IAAI,eAAA,EACJ;AACI,MAAA,WAAA,CAAY,IAAA,CAAK,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAE,CAAA;AAC9D,MAAA,OAAO,IAAA;AAAA,IACX;AAEA,IAAA,KAAA,GAAQ,QAAA;AACR,IAAA,eAAA,GAAkB,IAAA;AAElB,IAAA,MAAM,QAAA,CAAS,SAAA,CAAU,IAAA,EAAM,OAAO,OAAA,KACtC;AACI,MAAA,WAAA,CAAY,KAAA,CAAM,CAAA,2BAAA,EAA8B,IAAI,CAAA,CAAE,CAAA;AACtD,MAAA,MAAM,cAAA,CAAe,QAAQ,OAAmB,CAAA;AAAA,IACpD,CAAC,CAAA;AAED,IAAA,WAAA,CAAY,KAAA,CAAM,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAE,CAAA;AAC/D,IAAA,OAAO,IAAA;AAAA,EACX,CAAA;AAEA,EAAA,MAAM,IAAA,GAA2B;AAAA,IAC7B,IAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAW,cAAA,CAAe,GAAA;AAAA,IAC1B,gBAAgB,cAAA,CAAe,KAAA;AAAA,IAC/B,IAAA;AAAA,IACA,QAAA;AAAA,IACA,mBAAmB,eAAA,CAAgB,QAAA;AAAA,IACnC,QAAA,EAAU;AAAA,GACd;AAEA,EAAA,OAAO,IAAA;AACX;AAyCO,SAAS,WAAA,CACZ,MACA,MAAA,EAEJ;AACI,EAAA,IAAI,MAAA,EACJ;AACI,IAAA,OAAO,eAAA,CAA2B,MAAM,MAAM,CAAA;AAAA,EAClD;AAEA,EAAA,OAAO,gBAAsB,IAAI,CAAA;AACrC","file":"index.js","sourcesContent":["/**\n * Event System\n *\n * Decoupled pub/sub event system with optional cache integration for multi-instance support\n *\n * @example\n * ```typescript\n * // Define event\n * const userCreated = defineEvent('user.created', Type.Object({\n * userId: Type.String(),\n * }));\n *\n * // Subscribe (in-memory)\n * userCreated.subscribe((payload) => {\n * console.log('User created:', payload.userId);\n * });\n *\n * // Emit\n * await userCreated.emit({ userId: '123' });\n *\n * // With cache for multi-instance\n * const event = defineEvent('user.created', schema);\n * await event.useCache(cache); // Must await before emitting\n * await event.emit({ userId: '123' }); // Broadcast to all instances\n * ```\n */\n\nimport type { TSchema, Static } from '@sinclair/typebox';\nimport { logger } from '@spfn/core/logger';\nimport type { EventDef, EventHandler, JobQueueSender, PubSubCache } from './types';\n\nconst eventLogger = logger.child('@spfn/core:event');\n\n/**\n * Log handler error with consistent format\n */\nfunction logHandlerError(eventName: string, error: unknown): void\n{\n eventLogger.error(`Event handler error: ${eventName}`, {\n error: error instanceof Error ? error.message : String(error),\n });\n}\n\n/**\n * Log job queue error with consistent format\n */\nfunction logJobQueueError(queueName: string, error: unknown): void\n{\n eventLogger.error(`Failed to send event to job queue: ${queueName}`, {\n error: error instanceof Error ? error.message : String(error),\n });\n}\n\n/**\n * Create handler subscription manager\n */\nfunction createHandlerManager<TPayload>(name: string)\n{\n const handlers: Set<EventHandler<TPayload>> = new Set();\n\n return {\n add: (handler: EventHandler<TPayload>): (() => void) =>\n {\n handlers.add(handler);\n eventLogger.debug(`Subscribed to event: ${name}`, { handlerCount: handlers.size });\n\n return () =>\n {\n handlers.delete(handler);\n eventLogger.debug(`Unsubscribed from event: ${name}`, { handlerCount: handlers.size });\n };\n },\n\n clear: (): void =>\n {\n handlers.clear();\n eventLogger.debug(`Unsubscribed all from event: ${name}`);\n },\n\n trigger: async (payload: TPayload): Promise<void> =>\n {\n const results = await Promise.allSettled(\n [...handlers].map((handler) => handler(payload))\n );\n\n for (const result of results)\n {\n if (result.status === 'rejected')\n {\n logHandlerError(name, result.reason);\n }\n }\n },\n };\n}\n\n/**\n * Create job queue manager\n */\nfunction createJobQueueManager(name: string)\n{\n const jobQueues: Map<string, JobQueueSender> = new Map();\n\n return {\n register: (queueName: string, sender: JobQueueSender): void =>\n {\n jobQueues.set(queueName, sender);\n eventLogger.debug(`Registered job queue for event: ${name}`, { queueName });\n },\n\n send: async (payload: unknown): Promise<void> =>\n {\n if (jobQueues.size === 0)\n {\n return;\n }\n\n const entries = [...jobQueues.entries()];\n const results = await Promise.allSettled(\n entries.map(([queueName, sender]) => sender(queueName, payload))\n );\n\n for (const [i, result] of results.entries())\n {\n if (result.status === 'rejected')\n {\n logJobQueueError(entries[i][0], result.reason);\n }\n }\n },\n\n get size(): number\n {\n return jobQueues.size;\n },\n };\n}\n\n/**\n * Internal: Create event implementation\n */\nfunction createEventImpl<TPayload>(\n name: string,\n schema?: TSchema\n): EventDef<TPayload>\n{\n const handlerManager = createHandlerManager<TPayload>(name);\n const jobQueueManager = createJobQueueManager(name);\n let cache: PubSubCache | undefined;\n let cacheSubscribed = false;\n\n const emit = async (payload?: TPayload): Promise<void> =>\n {\n eventLogger.debug(`Emitting event: ${name}`, {\n payload,\n hasCache: !!cache,\n jobQueueCount: jobQueueManager.size,\n });\n\n if (cache)\n {\n await cache.publish(name, payload);\n }\n else\n {\n await handlerManager.trigger(payload as TPayload);\n }\n\n await jobQueueManager.send(payload);\n eventLogger.debug(`Event emitted: ${name}`);\n };\n\n const useCache = async (newCache: PubSubCache): Promise<EventDef<TPayload>> =>\n {\n if (cacheSubscribed)\n {\n eventLogger.warn(`Cache already configured for event: ${name}`);\n return self;\n }\n\n cache = newCache;\n cacheSubscribed = true;\n\n await newCache.subscribe(name, async (message: unknown) =>\n {\n eventLogger.debug(`Received event from cache: ${name}`);\n await handlerManager.trigger(message as TPayload);\n });\n\n eventLogger.debug(`Cache subscription ready for event: ${name}`);\n return self;\n };\n\n const self: EventDef<TPayload> = {\n name,\n schema,\n subscribe: handlerManager.add,\n unsubscribeAll: handlerManager.clear,\n emit: emit as EventDef<TPayload>['emit'],\n useCache,\n _registerJobQueue: jobQueueManager.register,\n _payload: undefined as unknown as TPayload,\n };\n\n return self;\n}\n\n/**\n * Define an event without payload\n */\nexport function defineEvent(name: string): EventDef<void>;\n\n/**\n * Define an event with typed payload\n */\nexport function defineEvent<T extends TSchema>(\n name: string,\n schema: T\n): EventDef<Static<T>>;\n\n/**\n * Define an event for decoupled pub/sub\n *\n * @example\n * ```typescript\n * // Define event with payload\n * export const userCreated = defineEvent('user.created', Type.Object({\n * userId: Type.String(),\n * }));\n *\n * // Subscribe to event (in-memory)\n * const unsubscribe = userCreated.subscribe((payload) => {\n * console.log('User created:', payload.userId);\n * });\n *\n * // Emit event\n * await userCreated.emit({ userId: '123' });\n *\n * // Unsubscribe when done\n * unsubscribe();\n *\n * // Multi-instance with cache\n * await userCreated.useCache(cache);\n * await userCreated.emit({ userId: '123' }); // Broadcast to all instances\n * ```\n */\nexport function defineEvent<T extends TSchema>(\n name: string,\n schema?: T\n): EventDef<Static<T>> | EventDef\n{\n if (schema)\n {\n return createEventImpl<Static<T>>(name, schema);\n }\n\n return createEventImpl<void>(name);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/event/event.ts","../../src/event/router.ts"],"names":[],"mappings":";;;AA+BA,IAAM,WAAA,GAAc,MAAA,CAAO,KAAA,CAAM,kBAAkB,CAAA;AAKnD,SAAS,eAAA,CAAgB,WAAmB,KAAA,EAC5C;AACI,EAAA,WAAA,CAAY,KAAA,CAAM,CAAA,qBAAA,EAAwB,SAAS,CAAA,CAAA,EAAI;AAAA,IACnD,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK;AAAA,GAC/D,CAAA;AACL;AAKA,SAAS,gBAAA,CAAiB,WAAmB,KAAA,EAC7C;AACI,EAAA,WAAA,CAAY,KAAA,CAAM,CAAA,mCAAA,EAAsC,SAAS,CAAA,CAAA,EAAI;AAAA,IACjE,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK;AAAA,GAC/D,CAAA;AACL;AAKA,SAAS,qBAA+B,IAAA,EACxC;AACI,EAAA,MAAM,QAAA,uBAA4C,GAAA,EAAI;AAEtD,EAAA,OAAO;AAAA,IACH,GAAA,EAAK,CAAC,OAAA,KACN;AACI,MAAA,QAAA,CAAS,IAAI,OAAO,CAAA;AACpB,MAAA,WAAA,CAAY,KAAA,CAAM,wBAAwB,IAAI,CAAA,CAAA,EAAI,EAAE,YAAA,EAAc,QAAA,CAAS,MAAM,CAAA;AAEjF,MAAA,OAAO,MACP;AACI,QAAA,QAAA,CAAS,OAAO,OAAO,CAAA;AACvB,QAAA,WAAA,CAAY,KAAA,CAAM,4BAA4B,IAAI,CAAA,CAAA,EAAI,EAAE,YAAA,EAAc,QAAA,CAAS,MAAM,CAAA;AAAA,MACzF,CAAA;AAAA,IACJ,CAAA;AAAA,IAEA,OAAO,MACP;AACI,MAAA,QAAA,CAAS,KAAA,EAAM;AACf,MAAA,WAAA,CAAY,KAAA,CAAM,CAAA,6BAAA,EAAgC,IAAI,CAAA,CAAE,CAAA;AAAA,IAC5D,CAAA;AAAA,IAEA,OAAA,EAAS,OAAO,OAAA,KAChB;AACI,MAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,UAAA;AAAA,QAC1B,CAAC,GAAG,QAAQ,CAAA,CAAE,IAAI,CAAC,OAAA,KAAY,OAAA,CAAQ,OAAO,CAAC;AAAA,OACnD;AAEA,MAAA,KAAA,MAAW,UAAU,OAAA,EACrB;AACI,QAAA,IAAI,MAAA,CAAO,WAAW,UAAA,EACtB;AACI,UAAA,eAAA,CAAgB,IAAA,EAAM,OAAO,MAAM,CAAA;AAAA,QACvC;AAAA,MACJ;AAAA,IACJ;AAAA,GACJ;AACJ;AAKA,SAAS,sBAAsB,IAAA,EAC/B;AACI,EAAA,MAAM,SAAA,uBAA6C,GAAA,EAAI;AAEvD,EAAA,OAAO;AAAA,IACH,QAAA,EAAU,CAAC,SAAA,EAAmB,MAAA,KAC9B;AACI,MAAA,SAAA,CAAU,GAAA,CAAI,WAAW,MAAM,CAAA;AAC/B,MAAA,WAAA,CAAY,MAAM,CAAA,gCAAA,EAAmC,IAAI,CAAA,CAAA,EAAI,EAAE,WAAW,CAAA;AAAA,IAC9E,CAAA;AAAA,IAEA,IAAA,EAAM,OAAO,OAAA,KACb;AACI,MAAA,IAAI,SAAA,CAAU,SAAS,CAAA,EACvB;AACI,QAAA;AAAA,MACJ;AAEA,MAAA,MAAM,OAAA,GAAU,CAAC,GAAG,SAAA,CAAU,SAAS,CAAA;AACvC,MAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,UAAA;AAAA,QAC1B,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAC,SAAA,EAAW,MAAM,CAAA,KAAM,MAAA,CAAO,SAAA,EAAW,OAAO,CAAC;AAAA,OACnE;AAEA,MAAA,KAAA,MAAW,CAAC,CAAA,EAAG,MAAM,CAAA,IAAK,OAAA,CAAQ,SAAQ,EAC1C;AACI,QAAA,IAAI,MAAA,CAAO,WAAW,UAAA,EACtB;AACI,UAAA,gBAAA,CAAiB,QAAQ,CAAC,CAAA,CAAE,CAAC,CAAA,EAAG,OAAO,MAAM,CAAA;AAAA,QACjD;AAAA,MACJ;AAAA,IACJ,CAAA;AAAA,IAEA,IAAI,IAAA,GACJ;AACI,MAAA,OAAO,SAAA,CAAU,IAAA;AAAA,IACrB;AAAA,GACJ;AACJ;AAKA,SAAS,eAAA,CACL,MACA,MAAA,EAEJ;AACI,EAAA,MAAM,cAAA,GAAiB,qBAA+B,IAAI,CAAA;AAC1D,EAAA,MAAM,eAAA,GAAkB,sBAAsB,IAAI,CAAA;AAClD,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI,eAAA,GAAkB,KAAA;AAEtB,EAAA,MAAM,IAAA,GAAO,OAAO,OAAA,KACpB;AACI,IAAA,WAAA,CAAY,KAAA,CAAM,CAAA,gBAAA,EAAmB,IAAI,CAAA,CAAA,EAAI;AAAA,MACzC,OAAA;AAAA,MACA,QAAA,EAAU,CAAC,CAAC,KAAA;AAAA,MACZ,eAAe,eAAA,CAAgB;AAAA,KAClC,CAAA;AAED,IAAA,IAAI,KAAA,EACJ;AACI,MAAA,MAAM,KAAA,CAAM,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA;AAAA,IACrC,CAAA,MAEA;AACI,MAAA,MAAM,cAAA,CAAe,QAAQ,OAAmB,CAAA;AAAA,IACpD;AAEA,IAAA,MAAM,eAAA,CAAgB,KAAK,OAAO,CAAA;AAClC,IAAA,WAAA,CAAY,KAAA,CAAM,CAAA,eAAA,EAAkB,IAAI,CAAA,CAAE,CAAA;AAAA,EAC9C,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW,OAAO,QAAA,KACxB;AACI,IAAA,IAAI,eAAA,EACJ;AACI,MAAA,WAAA,CAAY,IAAA,CAAK,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAE,CAAA;AAC9D,MAAA,OAAO,IAAA;AAAA,IACX;AAEA,IAAA,KAAA,GAAQ,QAAA;AACR,IAAA,eAAA,GAAkB,IAAA;AAElB,IAAA,MAAM,QAAA,CAAS,SAAA,CAAU,IAAA,EAAM,OAAO,OAAA,KACtC;AACI,MAAA,WAAA,CAAY,KAAA,CAAM,CAAA,2BAAA,EAA8B,IAAI,CAAA,CAAE,CAAA;AACtD,MAAA,MAAM,cAAA,CAAe,QAAQ,OAAmB,CAAA;AAAA,IACpD,CAAC,CAAA;AAED,IAAA,WAAA,CAAY,KAAA,CAAM,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAE,CAAA;AAC/D,IAAA,OAAO,IAAA;AAAA,EACX,CAAA;AAEA,EAAA,MAAM,IAAA,GAA2B;AAAA,IAC7B,IAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAW,cAAA,CAAe,GAAA;AAAA,IAC1B,gBAAgB,cAAA,CAAe,KAAA;AAAA,IAC/B,IAAA;AAAA,IACA,QAAA;AAAA,IACA,mBAAmB,eAAA,CAAgB,QAAA;AAAA,IACnC,QAAA,EAAU;AAAA,GACd;AAEA,EAAA,OAAO,IAAA;AACX;AAyCO,SAAS,WAAA,CACZ,MACA,MAAA,EAEJ;AACI,EAAA,IAAI,MAAA,EACJ;AACI,IAAA,OAAO,eAAA,CAA2B,MAAM,MAAM,CAAA;AAAA,EAClD;AAEA,EAAA,OAAO,gBAAsB,IAAI,CAAA;AACrC;;;ACtKO,SAAS,kBAEd,MAAA,EACF;AACI,EAAA,OAAO;AAAA,IACH,MAAA;AAAA,IACA,UAAA,EAAY,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA;AAAA,IAC9B,QAAQ;AAAC,GACb;AACJ","file":"index.js","sourcesContent":["/**\n * Event System\n *\n * Decoupled pub/sub event system with optional cache integration for multi-instance support\n *\n * @example\n * ```typescript\n * // Define event\n * const userCreated = defineEvent('user.created', Type.Object({\n * userId: Type.String(),\n * }));\n *\n * // Subscribe (in-memory)\n * userCreated.subscribe((payload) => {\n * console.log('User created:', payload.userId);\n * });\n *\n * // Emit\n * await userCreated.emit({ userId: '123' });\n *\n * // With cache for multi-instance\n * const event = defineEvent('user.created', schema);\n * await event.useCache(cache); // Must await before emitting\n * await event.emit({ userId: '123' }); // Broadcast to all instances\n * ```\n */\n\nimport type { TSchema, Static } from '@sinclair/typebox';\nimport { logger } from '@spfn/core/logger';\nimport type { EventDef, EventHandler, JobQueueSender, PubSubCache } from './types';\n\nconst eventLogger = logger.child('@spfn/core:event');\n\n/**\n * Log handler error with consistent format\n */\nfunction logHandlerError(eventName: string, error: unknown): void\n{\n eventLogger.error(`Event handler error: ${eventName}`, {\n error: error instanceof Error ? error.message : String(error),\n });\n}\n\n/**\n * Log job queue error with consistent format\n */\nfunction logJobQueueError(queueName: string, error: unknown): void\n{\n eventLogger.error(`Failed to send event to job queue: ${queueName}`, {\n error: error instanceof Error ? error.message : String(error),\n });\n}\n\n/**\n * Create handler subscription manager\n */\nfunction createHandlerManager<TPayload>(name: string)\n{\n const handlers: Set<EventHandler<TPayload>> = new Set();\n\n return {\n add: (handler: EventHandler<TPayload>): (() => void) =>\n {\n handlers.add(handler);\n eventLogger.debug(`Subscribed to event: ${name}`, { handlerCount: handlers.size });\n\n return () =>\n {\n handlers.delete(handler);\n eventLogger.debug(`Unsubscribed from event: ${name}`, { handlerCount: handlers.size });\n };\n },\n\n clear: (): void =>\n {\n handlers.clear();\n eventLogger.debug(`Unsubscribed all from event: ${name}`);\n },\n\n trigger: async (payload: TPayload): Promise<void> =>\n {\n const results = await Promise.allSettled(\n [...handlers].map((handler) => handler(payload))\n );\n\n for (const result of results)\n {\n if (result.status === 'rejected')\n {\n logHandlerError(name, result.reason);\n }\n }\n },\n };\n}\n\n/**\n * Create job queue manager\n */\nfunction createJobQueueManager(name: string)\n{\n const jobQueues: Map<string, JobQueueSender> = new Map();\n\n return {\n register: (queueName: string, sender: JobQueueSender): void =>\n {\n jobQueues.set(queueName, sender);\n eventLogger.debug(`Registered job queue for event: ${name}`, { queueName });\n },\n\n send: async (payload: unknown): Promise<void> =>\n {\n if (jobQueues.size === 0)\n {\n return;\n }\n\n const entries = [...jobQueues.entries()];\n const results = await Promise.allSettled(\n entries.map(([queueName, sender]) => sender(queueName, payload))\n );\n\n for (const [i, result] of results.entries())\n {\n if (result.status === 'rejected')\n {\n logJobQueueError(entries[i][0], result.reason);\n }\n }\n },\n\n get size(): number\n {\n return jobQueues.size;\n },\n };\n}\n\n/**\n * Internal: Create event implementation\n */\nfunction createEventImpl<TPayload>(\n name: string,\n schema?: TSchema\n): EventDef<TPayload>\n{\n const handlerManager = createHandlerManager<TPayload>(name);\n const jobQueueManager = createJobQueueManager(name);\n let cache: PubSubCache | undefined;\n let cacheSubscribed = false;\n\n const emit = async (payload?: TPayload): Promise<void> =>\n {\n eventLogger.debug(`Emitting event: ${name}`, {\n payload,\n hasCache: !!cache,\n jobQueueCount: jobQueueManager.size,\n });\n\n if (cache)\n {\n await cache.publish(name, payload);\n }\n else\n {\n await handlerManager.trigger(payload as TPayload);\n }\n\n await jobQueueManager.send(payload);\n eventLogger.debug(`Event emitted: ${name}`);\n };\n\n const useCache = async (newCache: PubSubCache): Promise<EventDef<TPayload>> =>\n {\n if (cacheSubscribed)\n {\n eventLogger.warn(`Cache already configured for event: ${name}`);\n return self;\n }\n\n cache = newCache;\n cacheSubscribed = true;\n\n await newCache.subscribe(name, async (message: unknown) =>\n {\n eventLogger.debug(`Received event from cache: ${name}`);\n await handlerManager.trigger(message as TPayload);\n });\n\n eventLogger.debug(`Cache subscription ready for event: ${name}`);\n return self;\n };\n\n const self: EventDef<TPayload> = {\n name,\n schema,\n subscribe: handlerManager.add,\n unsubscribeAll: handlerManager.clear,\n emit: emit as EventDef<TPayload>['emit'],\n useCache,\n _registerJobQueue: jobQueueManager.register,\n _payload: undefined as unknown as TPayload,\n };\n\n return self;\n}\n\n/**\n * Define an event without payload\n */\nexport function defineEvent(name: string): EventDef<void>;\n\n/**\n * Define an event with typed payload\n */\nexport function defineEvent<T extends TSchema>(\n name: string,\n schema: T\n): EventDef<Static<T>>;\n\n/**\n * Define an event for decoupled pub/sub\n *\n * @example\n * ```typescript\n * // Define event with payload\n * export const userCreated = defineEvent('user.created', Type.Object({\n * userId: Type.String(),\n * }));\n *\n * // Subscribe to event (in-memory)\n * const unsubscribe = userCreated.subscribe((payload) => {\n * console.log('User created:', payload.userId);\n * });\n *\n * // Emit event\n * await userCreated.emit({ userId: '123' });\n *\n * // Unsubscribe when done\n * unsubscribe();\n *\n * // Multi-instance with cache\n * await userCreated.useCache(cache);\n * await userCreated.emit({ userId: '123' }); // Broadcast to all instances\n * ```\n */\nexport function defineEvent<T extends TSchema>(\n name: string,\n schema?: T\n): EventDef<Static<T>> | EventDef\n{\n if (schema)\n {\n return createEventImpl<Static<T>>(name, schema);\n }\n\n return createEventImpl<void>(name);\n}\n","/**\n * Event Router\n *\n * Type-safe event router for SSE subscription\n *\n * @example\n * ```typescript\n * import { defineEvent, defineEventRouter } from '@spfn/core/event';\n * import { Type } from '@sinclair/typebox';\n *\n * const userCreated = defineEvent('user.created', Type.Object({\n * userId: Type.String(),\n * }));\n *\n * const orderPlaced = defineEvent('order.placed', Type.Object({\n * orderId: Type.String(),\n * amount: Type.Number(),\n * }));\n *\n * export const eventRouter = defineEventRouter({\n * userCreated,\n * orderPlaced,\n * });\n *\n * export type EventRouter = typeof eventRouter;\n * ```\n */\n\nimport type { EventDef } from './types';\n\n/**\n * Event Router Definition\n */\nexport interface EventRouterDef<TEvents extends Record<string, EventDef<any>>>\n{\n /**\n * Event definitions\n */\n readonly events: TEvents;\n\n /**\n * Event names as array\n */\n readonly eventNames: (keyof TEvents)[];\n\n /**\n * Type inference helper - payload types by event name\n */\n readonly _types: {\n [K in keyof TEvents]: TEvents[K]['_payload'];\n };\n}\n\n/**\n * Infer event names from EventRouter\n */\nexport type InferEventNames<T> = T extends EventRouterDef<infer E>\n ? keyof E & string\n : never;\n\n/**\n * Infer payload type for specific event\n */\nexport type InferEventPayload<\n T extends EventRouterDef<any>,\n K extends InferEventNames<T>\n> = T['_types'][K];\n\n/**\n * Infer all event payloads map\n */\nexport type InferEventPayloads<T extends EventRouterDef<any>> = T['_types'];\n\n/**\n * Define an event router for SSE subscription\n *\n * @example\n * ```typescript\n * export const eventRouter = defineEventRouter({\n * userCreated,\n * orderPlaced,\n * });\n *\n * // Type inference\n * type Names = InferEventNames<typeof eventRouter>;\n * // 'userCreated' | 'orderPlaced'\n *\n * type Payload = InferEventPayload<typeof eventRouter, 'userCreated'>;\n * // { userId: string }\n * ```\n */\nexport function defineEventRouter<\n TEvents extends Record<string, EventDef<any>>\n>(events: TEvents): EventRouterDef<TEvents>\n{\n return {\n events,\n eventNames: Object.keys(events) as (keyof TEvents)[],\n _types: {} as EventRouterDef<TEvents>['_types'],\n };\n}"]}
|