stock-bot/libs/core/config/src/index.ts
2025-06-25 08:29:53 -04:00

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';