stock-bot/libs/core/config
2025-06-26 16:11:58 -04:00
..
config work on ceo 2025-06-24 18:09:32 -04:00
src fixed some lint issues 2025-06-26 16:11:58 -04:00
test fixed some lint issues 2025-06-26 16:11:58 -04:00
.env.example moved folders around 2025-06-21 18:27:00 -04:00
package.json cleanup 2025-06-23 22:32:51 -04:00
README.md moved folders around 2025-06-21 18:27:00 -04:00
tsconfig.json format 2025-06-22 17:55:51 -04:00
turbo.json moved folders around 2025-06-21 18:27:00 -04:00

@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

bun add @stock-bot/config

Usage

Basic Usage

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

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

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:

# 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

import { getConfigManager } from '@stock-bot/config';

const manager = getConfigManager();

// Get specific value by path
const port = manager.getValue<number>('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

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:

import { ConfigLoader } from '@stock-bot/config';

class ApiConfigLoader implements ConfigLoader {
  readonly priority = 75; // Between file (50) and env (100)
  
  async load(): Promise<Record<string, unknown>> {
    // 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:

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