// Import necessary types for singleton import { EnvLoader } from './loaders/env.loader'; import { FileLoader } from './loaders/file.loader'; import { ConfigManager } from './config-manager'; import { AppConfig, appConfigSchema } from './schemas'; // Create singleton instance let configInstance: ConfigManager | null = null; // Synchronously load critical env vars for early initialization function loadCriticalEnvVarsSync(): void { // Load .env file synchronously if it exists try { const fs = require('fs'); const path = require('path'); const envPath = path.resolve(process.cwd(), '.env'); if (fs.existsSync(envPath)) { const envContent = fs.readFileSync(envPath, 'utf-8'); const lines = envContent.split('\n'); for (const line of lines) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('#')) { continue; } const equalIndex = trimmed.indexOf('='); if (equalIndex === -1) { continue; } const key = trimmed.substring(0, equalIndex).trim(); let value = trimmed.substring(equalIndex + 1).trim(); // Remove surrounding quotes if ( (value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")) ) { value = value.slice(1, -1); } // Only set if not already set if (!(key in process.env)) { process.env[key] = value; } } } } catch { // Ignore errors - env file is optional } } // Load critical env vars immediately loadCriticalEnvVarsSync(); /** * Initialize the global configuration synchronously. * * This loads configuration from all sources in the correct hierarchy: * 1. Schema defaults (lowest priority) * 2. default.json * 3. [environment].json (e.g., development.json) * 4. .env file values * 5. process.env values (highest priority) */ export function initializeConfig(configPath?: string): AppConfig { if (!configInstance) { configInstance = new ConfigManager({ configPath, }); } return configInstance.initialize(appConfigSchema); } /** * Initialize configuration for a service in a monorepo. * Automatically loads configs from: * 1. Root config directory (../../config) * 2. Service-specific config directory (./config) * 3. Environment variables */ export function initializeServiceConfig(): AppConfig { if (!configInstance) { const environment = process.env.NODE_ENV || 'development'; configInstance = new ConfigManager({ loaders: [ new FileLoader('../../config', environment), // Root config new FileLoader('./config', environment), // Service config new EnvLoader(''), // Environment variables ], }); } return configInstance.initialize(appConfigSchema); } /** * Get the current configuration */ export function getConfig(): AppConfig { if (!configInstance) { throw new Error('Configuration not initialized. Call initializeConfig() first.'); } return configInstance.get(); } /** * Get configuration manager instance */ export function getConfigManager(): ConfigManager { if (!configInstance) { throw new Error('Configuration not initialized. Call initializeConfig() first.'); } return configInstance; } /** * Reset configuration (useful for testing) */ export function resetConfig(): void { if (configInstance) { configInstance.reset(); configInstance = null; } } // Export convenience functions for common configs export function getDatabaseConfig() { return getConfig().database; } export function getServiceConfig() { return getConfig().service; } export function getLogConfig() { return getConfig().log; } // Deprecated alias for backward compatibility export function getLoggingConfig() { return getConfig().log; } export function getProviderConfig(provider: string) { const providers = getConfig().providers; if (!providers || !(provider in providers)) { throw new Error(`Provider configuration not found: ${provider}`); } return (providers as Record)[provider]; } export function getQueueConfig() { return getConfig().queue; } // Export environment helpers export function isDevelopment(): boolean { return getConfig().environment === 'development'; } export function isProduction(): boolean { return getConfig().environment === 'production'; } export function isTest(): boolean { return getConfig().environment === 'test'; } // Export all schemas export * from './schemas'; // Export types export * from './types'; // Export errors export * from './errors'; // Export loaders export { EnvLoader } from './loaders/env.loader'; export { FileLoader } from './loaders/file.loader'; // Export ConfigManager export { ConfigManager } from './config-manager'; // Export utilities export * from './utils/secrets'; export * from './utils/validation';