192 lines
5 KiB
TypeScript
192 lines
5 KiB
TypeScript
// Import necessary types
|
|
import { z } from 'zod';
|
|
import { EnvLoader } from './loaders/env.loader';
|
|
import { FileLoader } from './loaders/file.loader';
|
|
import { ConfigManager } from './config-manager';
|
|
import { ConfigError } from './errors';
|
|
import type { BaseAppConfig } from './schemas';
|
|
import { baseAppSchema } from './schemas';
|
|
|
|
// Legacy singleton instance for backward compatibility
|
|
let configInstance: ConfigManager<BaseAppConfig> | 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 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(): BaseAppConfig {
|
|
if (!configInstance) {
|
|
const environment = process.env.NODE_ENV || 'development';
|
|
configInstance = new ConfigManager<BaseAppConfig>({
|
|
loaders: [
|
|
new FileLoader('../../config', environment), // Root config
|
|
new FileLoader('./config', environment), // Service config
|
|
new EnvLoader(''), // Environment variables
|
|
],
|
|
});
|
|
}
|
|
return configInstance.initialize(baseAppSchema);
|
|
}
|
|
|
|
/**
|
|
* Get the current configuration
|
|
*/
|
|
export function getConfig(): BaseAppConfig {
|
|
if (!configInstance) {
|
|
throw new ConfigError('Configuration not initialized. Call initializeConfig() first.');
|
|
}
|
|
return configInstance.get();
|
|
}
|
|
|
|
/**
|
|
* Get configuration manager instance
|
|
*/
|
|
export function getConfigManager(): ConfigManager<BaseAppConfig> {
|
|
if (!configInstance) {
|
|
throw new ConfigError('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;
|
|
}
|
|
|
|
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';
|
|
}
|
|
|
|
/**
|
|
* Generic config builder for creating app-specific configurations
|
|
* @param schema - Zod schema for your app config
|
|
* @param options - Config manager options
|
|
* @returns Initialized config manager instance
|
|
*/
|
|
export function createAppConfig<T extends z.ZodSchema>(
|
|
schema: T,
|
|
options?: {
|
|
configPath?: string;
|
|
environment?: 'development' | 'test' | 'production';
|
|
loaders?: any[];
|
|
}
|
|
): ConfigManager<z.infer<T>> {
|
|
const manager = new ConfigManager<z.infer<T>>(options);
|
|
return manager;
|
|
}
|
|
|
|
/**
|
|
* Create and initialize app config in one step
|
|
*/
|
|
export function initializeAppConfig<T extends z.ZodSchema>(
|
|
schema: T,
|
|
options?: {
|
|
configPath?: string;
|
|
environment?: 'development' | 'test' | 'production';
|
|
loaders?: any[];
|
|
}
|
|
): z.infer<T> {
|
|
const manager = createAppConfig(schema, options);
|
|
return manager.initialize(schema);
|
|
}
|
|
|
|
// 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';
|