|
| 1 | +/** |
| 2 | + * Environment Variable Loader |
| 3 | + * Loads and validates environment variables for server configuration |
| 4 | + */ |
| 5 | + |
| 6 | +import { config as loadDotenv } from "dotenv"; |
| 7 | + |
| 8 | +/** |
| 9 | + * Environment variable schema |
| 10 | + */ |
| 11 | +export interface EnvConfig { |
| 12 | + // Server |
| 13 | + SERVER_NAME?: string; |
| 14 | + SERVER_VERSION?: string; |
| 15 | + |
| 16 | + // Logging |
| 17 | + LOG_LEVEL?: "debug" | "info" | "warn" | "error"; |
| 18 | + LOG_TO_FILE?: string; |
| 19 | + LOG_FILE_PATH?: string; |
| 20 | + |
| 21 | + // Storage |
| 22 | + MAX_STORAGE_SIZE?: string; |
| 23 | + |
| 24 | + // Performance |
| 25 | + ENABLE_METRICS?: string; |
| 26 | + METRICS_INTERVAL?: string; |
| 27 | + |
| 28 | + // Optional |
| 29 | + DEBUG_MODE?: string; |
| 30 | + MAX_CONCURRENT_OPS?: string; |
| 31 | + OPERATION_TIMEOUT?: string; |
| 32 | + |
| 33 | + // Future SDK integration |
| 34 | + LIGHTHOUSE_API_KEY?: string; |
| 35 | + KAVACH_ENDPOINT?: string; |
| 36 | + USE_REAL_SDK?: string; |
| 37 | +} |
| 38 | + |
| 39 | +/** |
| 40 | + * Server configuration interface (subset for env loading) |
| 41 | + */ |
| 42 | +export interface ServerConfig { |
| 43 | + name?: string; |
| 44 | + version?: string; |
| 45 | + logLevel?: "debug" | "info" | "warn" | "error"; |
| 46 | + maxStorageSize?: number; |
| 47 | + enableMetrics?: boolean; |
| 48 | + metricsInterval?: number; |
| 49 | +} |
| 50 | + |
| 51 | +export class EnvLoader { |
| 52 | + /** |
| 53 | + * Load environment variables from .env file |
| 54 | + */ |
| 55 | + static load(envPath?: string): void { |
| 56 | + const result = loadDotenv({ path: envPath }); |
| 57 | + |
| 58 | + if (result.error) { |
| 59 | + // .env file not found is OK, we'll use defaults |
| 60 | + if (result.error.message.includes("ENOENT")) { |
| 61 | + return; |
| 62 | + } |
| 63 | + throw result.error; |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * Parse environment variables into ServerConfig |
| 69 | + */ |
| 70 | + static parseConfig(): Partial<ServerConfig> { |
| 71 | + const env = process.env as EnvConfig; |
| 72 | + const config: Partial<ServerConfig> = {}; |
| 73 | + |
| 74 | + // Server configuration |
| 75 | + if (env.SERVER_NAME) { |
| 76 | + config.name = env.SERVER_NAME; |
| 77 | + } |
| 78 | + |
| 79 | + if (env.SERVER_VERSION) { |
| 80 | + config.version = env.SERVER_VERSION; |
| 81 | + } |
| 82 | + |
| 83 | + // Logging configuration |
| 84 | + if (env.LOG_LEVEL) { |
| 85 | + const validLevels = ["debug", "info", "warn", "error"]; |
| 86 | + if (validLevels.includes(env.LOG_LEVEL)) { |
| 87 | + config.logLevel = env.LOG_LEVEL as any; |
| 88 | + } else { |
| 89 | + console.warn(`Invalid LOG_LEVEL: ${env.LOG_LEVEL}. Using default 'info'.`); |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + // Storage configuration |
| 94 | + if (env.MAX_STORAGE_SIZE) { |
| 95 | + const size = parseInt(env.MAX_STORAGE_SIZE, 10); |
| 96 | + if (!isNaN(size) && size > 0) { |
| 97 | + config.maxStorageSize = size; |
| 98 | + } else { |
| 99 | + console.warn(`Invalid MAX_STORAGE_SIZE: ${env.MAX_STORAGE_SIZE}. Using default.`); |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + // Performance configuration |
| 104 | + if (env.ENABLE_METRICS !== undefined) { |
| 105 | + config.enableMetrics = env.ENABLE_METRICS.toLowerCase() === "true"; |
| 106 | + } |
| 107 | + |
| 108 | + if (env.METRICS_INTERVAL) { |
| 109 | + const interval = parseInt(env.METRICS_INTERVAL, 10); |
| 110 | + if (!isNaN(interval) && interval > 0) { |
| 111 | + config.metricsInterval = interval; |
| 112 | + } else { |
| 113 | + console.warn(`Invalid METRICS_INTERVAL: ${env.METRICS_INTERVAL}. Using default.`); |
| 114 | + } |
| 115 | + } |
| 116 | + |
| 117 | + return config; |
| 118 | + } |
| 119 | + |
| 120 | + /** |
| 121 | + * Load and parse configuration from environment |
| 122 | + */ |
| 123 | + static loadConfig(envPath?: string): Partial<ServerConfig> { |
| 124 | + this.load(envPath); |
| 125 | + return this.parseConfig(); |
| 126 | + } |
| 127 | + |
| 128 | + /** |
| 129 | + * Get environment variable with fallback |
| 130 | + */ |
| 131 | + static get(key: string, defaultValue?: string): string | undefined { |
| 132 | + return process.env[key] || defaultValue; |
| 133 | + } |
| 134 | + |
| 135 | + /** |
| 136 | + * Get boolean environment variable |
| 137 | + */ |
| 138 | + static getBoolean(key: string, defaultValue = false): boolean { |
| 139 | + const value = process.env[key]; |
| 140 | + if (value === undefined) return defaultValue; |
| 141 | + return value.toLowerCase() === "true"; |
| 142 | + } |
| 143 | + |
| 144 | + /** |
| 145 | + * Get number environment variable |
| 146 | + */ |
| 147 | + static getNumber(key: string, defaultValue?: number): number | undefined { |
| 148 | + const value = process.env[key]; |
| 149 | + if (value === undefined) return defaultValue; |
| 150 | + const parsed = parseInt(value, 10); |
| 151 | + return isNaN(parsed) ? defaultValue : parsed; |
| 152 | + } |
| 153 | + |
| 154 | + /** |
| 155 | + * Validate required environment variables |
| 156 | + */ |
| 157 | + static validateRequired(requiredVars: string[]): void { |
| 158 | + const missing = requiredVars.filter((key) => !process.env[key]); |
| 159 | + |
| 160 | + if (missing.length > 0) { |
| 161 | + throw new Error( |
| 162 | + `Missing required environment variables: ${missing.join(", ")}\n` + |
| 163 | + `Please check your .env file or set these variables.`, |
| 164 | + ); |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + /** |
| 169 | + * Display current configuration (for debugging) |
| 170 | + */ |
| 171 | + static displayConfig(config: Partial<ServerConfig>): void { |
| 172 | + console.log("\n📋 Server Configuration:"); |
| 173 | + console.log(" Name:", config.name || "default"); |
| 174 | + console.log(" Version:", config.version || "default"); |
| 175 | + console.log(" Log Level:", config.logLevel || "default"); |
| 176 | + console.log( |
| 177 | + " Max Storage:", |
| 178 | + config.maxStorageSize ? `${(config.maxStorageSize / 1024 / 1024).toFixed(2)} MB` : "default", |
| 179 | + ); |
| 180 | + console.log( |
| 181 | + " Metrics:", |
| 182 | + config.enableMetrics !== undefined ? config.enableMetrics : "default", |
| 183 | + ); |
| 184 | + console.log( |
| 185 | + " Metrics Interval:", |
| 186 | + config.metricsInterval ? `${config.metricsInterval / 1000}s` : "default", |
| 187 | + ); |
| 188 | + console.log(""); |
| 189 | + } |
| 190 | +} |
0 commit comments