# @stock-bot/config A robust, type-safe configuration library for the Stock Bot application. Built with Zod for validation and supports multiple configuration sources with proper precedence. ## Features - **Type-safe configuration** with Zod schemas - **Multiple configuration sources**: JSON files and environment variables - **Environment-specific overrides** (development, test, production) - **Dynamic provider configurations** - **No circular dependencies** - designed to be used by all other libraries - **Clear error messages** with validation - **Runtime configuration updates** (useful for testing) - **Singleton pattern** for global configuration access ## Installation ```bash bun add @stock-bot/config ``` ## Usage ### Basic Usage ```typescript import { initializeConfig, getConfig } from '@stock-bot/config'; // Initialize configuration (call once at app startup) await initializeConfig(); // Get configuration const config = getConfig(); console.log(config.database.postgres.host); // Use convenience functions import { getDatabaseConfig, isProduction } from '@stock-bot/config'; const dbConfig = getDatabaseConfig(); if (isProduction()) { // Production-specific logic } ``` ### Custom Configuration ```typescript import { ConfigManager } from '@stock-bot/config'; import { z } from 'zod'; // Define your schema const myConfigSchema = z.object({ app: z.object({ name: z.string(), version: z.string(), }), features: z.object({ enableBeta: z.boolean().default(false), }), }); // Create config manager const configManager = new ConfigManager({ configPath: './my-config', }); // Initialize with schema const config = await configManager.initialize(myConfigSchema); ``` ### Provider-Specific Configuration ```typescript import { getProviderConfig } from '@stock-bot/config'; // Get provider configuration const eodConfig = getProviderConfig('eod'); console.log(eodConfig.apiKey); // Check if provider is enabled if (eodConfig.enabled) { // Use EOD provider } ``` ### Environment Variables Environment variables are loaded with the `STOCKBOT_` prefix and follow a naming convention: ```bash # Database configuration STOCKBOT_DATABASE_POSTGRES_HOST=localhost STOCKBOT_DATABASE_POSTGRES_PORT=5432 # Provider configuration STOCKBOT_PROVIDERS_EOD_API_KEY=your_api_key STOCKBOT_PROVIDERS_EOD_ENABLED=true # Service configuration STOCKBOT_SERVICE_PORT=3000 STOCKBOT_LOGGING_LEVEL=debug ``` ### Configuration Precedence Configuration is loaded in the following order (later sources override earlier ones): 1. `config/default.json` - Base configuration 2. `config/{environment}.json` - Environment-specific overrides 3. Environment variables - Highest priority ### Advanced Usage ```typescript import { getConfigManager } from '@stock-bot/config'; const manager = getConfigManager(); // Get specific value by path const port = manager.getValue('service.port'); // Check if configuration exists if (manager.has('providers.ib')) { // IB provider is configured } // Update configuration at runtime (useful for testing) manager.set({ logging: { level: 'debug' } }); // Create typed getter const getQueueConfig = manager.createTypedGetter(queueConfigSchema); const queueConfig = getQueueConfig(); ``` ## Configuration Schema The library provides pre-defined schemas for common configurations: ### Base Configuration - `environment` - Current environment (development/test/production) - `name` - Application name - `version` - Application version - `debug` - Debug mode flag ### Service Configuration - `name` - Service name - `port` - Service port - `host` - Service host - `healthCheckPath` - Health check endpoint - `cors` - CORS configuration ### Database Configuration - `postgres` - PostgreSQL configuration - `questdb` - QuestDB configuration - `mongodb` - MongoDB configuration - `dragonfly` - Dragonfly/Redis configuration ### Provider Configuration - `eod` - EOD Historical Data provider - `ib` - Interactive Brokers provider - `qm` - QuoteMedia provider - `yahoo` - Yahoo Finance provider ## Testing ```typescript import { resetConfig, initializeConfig } from '@stock-bot/config'; beforeEach(() => { resetConfig(); }); test('custom config', async () => { process.env.NODE_ENV = 'test'; process.env.STOCKBOT_SERVICE_PORT = '4000'; await initializeConfig(); const config = getConfig(); expect(config.service.port).toBe(4000); }); ``` ## Custom Loaders You can create custom configuration loaders: ```typescript import { ConfigLoader } from '@stock-bot/config'; class ApiConfigLoader implements ConfigLoader { readonly priority = 75; // Between file (50) and env (100) async load(): Promise> { // Fetch configuration from API const response = await fetch('https://api.example.com/config'); return response.json(); } } // Use custom loader const configManager = new ConfigManager({ loaders: [ new FileLoader('./config', 'production'), new ApiConfigLoader(), new EnvLoader('STOCKBOT_'), ], }); ``` ## Error Handling The library provides specific error types: ```typescript import { ConfigError, ConfigValidationError } from '@stock-bot/config'; try { await initializeConfig(); } catch (error) { if (error instanceof ConfigValidationError) { console.error('Validation failed:', error.errors); } else if (error instanceof ConfigError) { console.error('Configuration error:', error.message); } } ``` ## Best Practices 1. **Initialize once**: Call `initializeConfig()` once at application startup 2. **Use schemas**: Always define and validate configurations with Zod schemas 3. **Environment variables**: Use the `STOCKBOT_` prefix for all env vars 4. **Type safety**: Leverage TypeScript types from the schemas 5. **Testing**: Reset configuration between tests with `resetConfig()` ## License MIT