added working config lib

This commit is contained in:
Bojan Kucera 2025-06-03 14:09:31 -04:00
parent f8576c0d93
commit def9bce8dc
33 changed files with 2896 additions and 1485 deletions

View file

@ -1,10 +1,8 @@
/**
* Core configuration module for the Stock Bot platform
* Core configuration module for the Stock Bot platform using envalid
*/
import { config as dotenvConfig } from 'dotenv';
import path from 'node:path';
import { z } from 'zod';
import { Environment } from './types';
/**
* Represents an error related to configuration validation
@ -16,6 +14,16 @@ export class ConfigurationError extends Error {
}
}
/**
* Environment types
*/
export enum Environment {
Development = 'development',
Testing = 'testing',
Staging = 'staging',
Production = 'production'
}
/**
* Loads environment variables from .env files based on the current environment
*/
@ -57,106 +65,3 @@ export function getEnvironment(): Environment {
return Environment.Development;
}
}
/**
* Validates configuration using Zod schema
*/
export function validateConfig<T>(config: unknown, schema: z.ZodSchema<T>): T {
try {
return schema.parse(config);
} catch (error) {
if (error instanceof z.ZodError) {
const issues = error.issues.map(issue =>
`${issue.path.join('.')}: ${issue.message}`
).join('\n');
throw new ConfigurationError(`Configuration validation failed:\n${issues}`);
}
throw new ConfigurationError('Invalid configuration');
}
}
/**
* Retrieves an environment variable with validation
*/
export function getEnvVar(key: string, required: boolean = false): string | undefined {
const value = process.env[key];
if (required && (value === undefined || value === '')) {
throw new ConfigurationError(`Required environment variable ${key} is missing`);
}
return value;
}
/**
* Retrieves a numeric environment variable with validation
*/
export function getNumericEnvVar(key: string, defaultValue?: number): number {
const value = process.env[key];
if (value === undefined || value === '') {
if (defaultValue !== undefined) {
return defaultValue;
}
throw new ConfigurationError(`Required numeric environment variable ${key} is missing`);
}
const numValue = Number(value);
if (isNaN(numValue)) {
throw new ConfigurationError(`Environment variable ${key} is not a valid number`);
}
return numValue;
}
/**
* Retrieves a boolean environment variable with validation
*/
export function getBooleanEnvVar(key: string, defaultValue?: boolean): boolean {
const value = process.env[key];
if (value === undefined || value === '') {
if (defaultValue !== undefined) {
return defaultValue;
}
throw new ConfigurationError(`Required boolean environment variable ${key} is missing`);
}
return value.toLowerCase() === 'true' || value === '1';
}
/**
* Creates a typed dynamic configuration loader for a specific service
*/
export function createConfigLoader<T>(
serviceName: string,
schema: z.ZodSchema<T>,
defaultConfig: Partial<T> = {}
): () => T {
return (): T => {
try {
loadEnvVariables();
const configEnvVar = `${serviceName.toUpperCase()}_CONFIG`;
let config = { ...defaultConfig } as unknown as T;
// Try to load JSON from environment variable if available
const configJson = process.env[configEnvVar];
if (configJson) {
try {
const parsedConfig = JSON.parse(configJson);
config = { ...config, ...parsedConfig };
} catch (error) {
throw new ConfigurationError(`Invalid JSON in ${configEnvVar} environment variable`);
}
}
// Validate and return the config
return validateConfig(config, schema);
} catch (error) {
if (error instanceof ConfigurationError) {
throw error;
}
throw new ConfigurationError(`Failed to load configuration for service ${serviceName}: ${error}`);
}
};
}