final config changes

This commit is contained in:
Bojan Kucera 2025-06-03 14:18:03 -04:00
parent 718ace05b0
commit 19f05a2a69
7 changed files with 311 additions and 51 deletions

View file

@ -8,7 +8,7 @@ This guide shows how to use the envalid-based configuration system in the Stock
import { databaseConfig, loggingConfig, riskConfig, dataProvidersConfig } from '@stock-bot/config';
// Access individual values
console.log(`Database: ${databaseConfig.DB_HOST}:${databaseConfig.DB_PORT}`);
console.log(`Database: ${databaseConfig.POSTGRES_HOST}:${databaseConfig.POSTGRES_PORT}`);
console.log(`Log level: ${loggingConfig.LOG_LEVEL}`);
console.log(`Max position size: ${riskConfig.RISK_MAX_POSITION_SIZE}`);
```
@ -68,9 +68,9 @@ import type { DatabaseConfig, LoggingConfig, RiskConfig } from '@stock-bot/confi
function setupDatabase(config: DatabaseConfig) {
// TypeScript knows all the available properties
return {
host: config.DB_HOST,
port: config.DB_PORT, // number
ssl: config.DB_SSL, // boolean
host: config.POSTGRES_HOST,
port: config.POSTGRES_PORT, // number
ssl: config.POSTGRES_SSL, // boolean
};
}
```

View file

@ -15,15 +15,19 @@ import {
} from './core';
import {
// Database configuration
// PostgreSQL configuration
postgresConfig,
PostgresConfig,
POSTGRES_HOST,
POSTGRES_PORT,
POSTGRES_DATABASE,
POSTGRES_USERNAME,
POSTGRES_PASSWORD,
// Backwards compatibility
databaseConfig,
DatabaseConfig,
DB_HOST,
DB_PORT,
DB_NAME,
DB_USER,
DB_PASSWORD,
} from './database';
} from './postgres';
import {
// QuestDB configuration
@ -119,18 +123,17 @@ function basicUsageExample() {
// Get the current environment
const env = getEnvironment();
console.log(`Current environment: ${env}`);
// Access individual configuration values
console.log(`Database host: ${DB_HOST}`);
console.log(`Database port: ${DB_PORT}`);
console.log(`Database host: ${POSTGRES_HOST}`);
console.log(`Database port: ${POSTGRES_PORT}`);
console.log(`Log level: ${LOG_LEVEL}`);
// Access full configuration objects
// Access full database config objects
console.log(`Full database config:`, {
host: databaseConfig.DB_HOST,
port: databaseConfig.DB_PORT,
name: databaseConfig.DB_NAME,
ssl: databaseConfig.DB_SSL,
host: postgresConfig.POSTGRES_HOST,
port: postgresConfig.POSTGRES_PORT,
name: postgresConfig.POSTGRES_DATABASE,
ssl: postgresConfig.POSTGRES_SSL,
});
}
@ -142,27 +145,27 @@ async function databaseConnectionExample() {
try {
// Use the database configuration to create a connection string
const connectionString = `postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}`;
const connectionString = `postgresql://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DATABASE}`;
console.log('Database connection settings:');
console.log(`- Host: ${databaseConfig.DB_HOST}`);
console.log(`- Port: ${databaseConfig.DB_PORT}`);
console.log(`- Database: ${databaseConfig.DB_NAME}`);
console.log(`- SSL enabled: ${databaseConfig.DB_SSL}`);
console.log(`- Pool max connections: ${databaseConfig.DB_POOL_MAX}`);
console.log(`- Query timeout: ${databaseConfig.DB_QUERY_TIMEOUT}ms`);
console.log(`- Host: ${databaseConfig.POSTGRES_HOST}`);
console.log(`- Port: ${databaseConfig.POSTGRES_PORT}`);
console.log(`- Database: ${databaseConfig.POSTGRES_NAME}`);
console.log(`- SSL enabled: ${databaseConfig.POSTGRES_SSL}`);
console.log(`- Pool max connections: ${databaseConfig.POSTGRES_POOL_MAX}`);
console.log(`- Query timeout: ${databaseConfig.POSTGRES_QUERY_TIMEOUT}ms`);
// Example pool configuration
const poolConfig = {
host: databaseConfig.DB_HOST,
port: databaseConfig.DB_PORT,
database: databaseConfig.DB_NAME,
user: databaseConfig.DB_USER,
password: databaseConfig.DB_PASSWORD,
ssl: databaseConfig.DB_SSL,
min: databaseConfig.DB_POOL_MIN,
max: databaseConfig.DB_POOL_MAX,
idleTimeoutMillis: databaseConfig.DB_POOL_IDLE_TIMEOUT,
host: databaseConfig.POSTGRES_HOST,
port: databaseConfig.POSTGRES_PORT,
database: databaseConfig.POSTGRES_NAME,
user: databaseConfig.POSTGRES_USER,
password: databaseConfig.POSTGRES_PASSWORD,
ssl: databaseConfig.POSTGRES_SSL,
min: databaseConfig.POSTGRES_POOL_MIN,
max: databaseConfig.POSTGRES_POOL_MAX,
idleTimeoutMillis: databaseConfig.POSTGRES_POOL_IDLE_TIMEOUT,
};
console.log('Pool configuration:', poolConfig);
@ -375,7 +378,7 @@ function configurationValidationExample() {
}
// Validate database connection settings
if (databaseConfig.DB_POOL_MAX < databaseConfig.DB_POOL_MIN) {
if (databaseConfig.POSTGRES_POOL_MAX < databaseConfig.POSTGRES_POOL_MIN) {
throw new ConfigurationError('Database max pool size must be greater than min pool size');
}
@ -626,16 +629,16 @@ function multiDatabaseServiceExample() {
// PostgreSQL for operational data
postgresql: {
host: databaseConfig.DB_HOST,
port: databaseConfig.DB_PORT,
database: databaseConfig.DB_NAME,
username: databaseConfig.DB_USER,
password: databaseConfig.DB_PASSWORD,
ssl: databaseConfig.DB_SSL,
host: databaseConfig.POSTGRES_HOST,
port: databaseConfig.POSTGRES_PORT,
database: databaseConfig.POSTGRES_NAME,
username: databaseConfig.POSTGRES_USER,
password: databaseConfig.POSTGRES_PASSWORD,
ssl: databaseConfig.POSTGRES_SSL,
pool: {
min: databaseConfig.DB_POOL_MIN,
max: databaseConfig.DB_POOL_MAX,
idleTimeout: databaseConfig.DB_POOL_IDLE_TIMEOUT,
min: databaseConfig.POSTGRES_POOL_MIN,
max: databaseConfig.POSTGRES_POOL_MAX,
idleTimeout: databaseConfig.POSTGRES_POOL_IDLE_TIMEOUT,
},
},
@ -712,10 +715,10 @@ function serviceConfigurationExample() {
environment: getEnvironment(),
},
database: {
host: databaseConfig.DB_HOST,
port: databaseConfig.DB_PORT,
name: databaseConfig.DB_NAME,
ssl: databaseConfig.DB_SSL,
host: databaseConfig.POSTGRES_HOST,
port: databaseConfig.POSTGRES_PORT,
name: databaseConfig.POSTGRES_NAME,
ssl: databaseConfig.POSTGRES_SSL,
}, logging: {
level: loggingConfig.LOG_LEVEL,
console: loggingConfig.LOG_CONSOLE,

View file

@ -8,7 +8,7 @@
export * from './core';
// Database configurations
export * from './database';
export * from './postgres';
export * from './questdb';
export * from './mongodb';
export * from './dragonfly';

View file

@ -0,0 +1,54 @@
/**
* PostgreSQL configuration using envalid
*/
import { cleanEnv, str, port, bool, num } from 'envalid';
/**
* PostgreSQL configuration with validation and defaults
*/
export const postgresConfig = cleanEnv(process.env, {
// PostgreSQL Connection Settings
POSTGRES_HOST: str({ default: 'localhost', desc: 'PostgreSQL host' }),
POSTGRES_PORT: port({ default: 5432, desc: 'PostgreSQL port' }),
POSTGRES_DATABASE: str({ default: 'stockbot', desc: 'PostgreSQL database name' }),
POSTGRES_USERNAME: str({ default: 'stockbot', desc: 'PostgreSQL username' }),
POSTGRES_PASSWORD: str({ default: '', desc: 'PostgreSQL password' }),
// Connection Pool Settings
POSTGRES_POOL_MIN: num({ default: 2, desc: 'Minimum pool connections' }),
POSTGRES_POOL_MAX: num({ default: 10, desc: 'Maximum pool connections' }),
POSTGRES_POOL_IDLE_TIMEOUT: num({ default: 30000, desc: 'Pool idle timeout in ms' }),
// SSL Configuration
POSTGRES_SSL: bool({ default: false, desc: 'Enable SSL for PostgreSQL connection' }),
POSTGRES_SSL_REJECT_UNAUTHORIZED: bool({ default: true, desc: 'Reject unauthorized SSL certificates' }),
// Additional Settings
POSTGRES_QUERY_TIMEOUT: num({ default: 30000, desc: 'Query timeout in ms' }),
POSTGRES_CONNECTION_TIMEOUT: num({ default: 5000, desc: 'Connection timeout in ms' }),
POSTGRES_STATEMENT_TIMEOUT: num({ default: 30000, desc: 'Statement timeout in ms' }),
POSTGRES_LOCK_TIMEOUT: num({ default: 10000, desc: 'Lock timeout in ms' }),
POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT: num({ default: 60000, desc: 'Idle in transaction timeout in ms' }),
});
// Export typed configuration object
export type PostgresConfig = typeof postgresConfig;
// Export individual config values for convenience
export const {
POSTGRES_HOST,
POSTGRES_PORT,
POSTGRES_DATABASE,
POSTGRES_USERNAME,
POSTGRES_PASSWORD,
POSTGRES_POOL_MIN,
POSTGRES_POOL_MAX,
POSTGRES_POOL_IDLE_TIMEOUT,
POSTGRES_SSL,
POSTGRES_SSL_REJECT_UNAUTHORIZED,
POSTGRES_QUERY_TIMEOUT,
POSTGRES_CONNECTION_TIMEOUT,
POSTGRES_STATEMENT_TIMEOUT,
POSTGRES_LOCK_TIMEOUT,
POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT,
} = postgresConfig;

View file

@ -0,0 +1,85 @@
import {
databaseConfig,
questdbConfig,
mongodbConfig,
dragonflyConfig,
prometheusConfig,
grafanaConfig,
lokiConfig,
loggingConfig
} from './dist/index.js';
// Set test environment variables
process.env.NODE_ENV = 'test';
process.env.PORT = '3001';
// Database configs
process.env.DB_HOST = 'localhost';
process.env.DB_PORT = '5432';
process.env.DB_NAME = 'test_db';
process.env.DB_USER = 'test_user';
process.env.DB_PASSWORD = 'test_pass';
// QuestDB configs
process.env.QUESTDB_HOST = 'localhost';
process.env.QUESTDB_HTTP_PORT = '9000';
process.env.QUESTDB_PG_PORT = '8812';
// MongoDB configs
process.env.MONGODB_HOST = 'localhost';
process.env.MONGODB_PORT = '27017';
process.env.MONGODB_DATABASE = 'test_db';
// Dragonfly configs
process.env.DRAGONFLY_HOST = 'localhost';
process.env.DRAGONFLY_PORT = '6379';
// Monitoring configs
process.env.PROMETHEUS_HOST = 'localhost';
process.env.PROMETHEUS_PORT = '9090';
process.env.GRAFANA_HOST = 'localhost';
process.env.GRAFANA_PORT = '3000';
// Loki configs
process.env.LOKI_HOST = 'localhost';
process.env.LOKI_PORT = '3100';
// Logging configs
process.env.LOG_LEVEL = 'info';
process.env.LOG_FORMAT = 'json';
console.log('🔍 Testing configuration modules...\n');
const configs = [
{ name: 'Database', config: databaseConfig },
{ name: 'QuestDB', config: questdbConfig },
{ name: 'MongoDB', config: mongodbConfig },
{ name: 'Dragonfly', config: dragonflyConfig },
{ name: 'Prometheus', config: prometheusConfig },
{ name: 'Grafana', config: grafanaConfig },
{ name: 'Loki', config: lokiConfig },
{ name: 'Logging', config: loggingConfig },
];
let successful = 0;
for (const { name, config } of configs) {
try {
if (config && typeof config === 'object' && Object.keys(config).length > 0) {
console.log(`${name}: Loaded successfully`);
successful++;
} else {
console.log(`${name}: Invalid config object`);
}
} catch (error) {
console.log(`${name}: ${error.message}`);
}
}
console.log(`\n📊 Test Summary: ${successful}/${configs.length} modules loaded successfully`);
if (successful === configs.length) {
console.log('🎉 All configuration modules working correctly!');
} else {
console.log('⚠️ Some configuration modules have issues.');
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,118 @@
#!/usr/bin/env node
/**
* Configuration Validation Script
* Tests that all configuration modules can be loaded and validated
*/
// Set test environment variables
process.env.NODE_ENV = 'test';
process.env.PORT = '3001';
// Database configs
process.env.DB_HOST = 'localhost';
process.env.DB_PORT = '5432';
process.env.DB_NAME = 'test_db';
process.env.DB_USER = 'test_user';
process.env.DB_PASSWORD = 'test_pass';
// QuestDB configs
process.env.QUESTDB_HOST = 'localhost';
process.env.QUESTDB_HTTP_PORT = '9000';
process.env.QUESTDB_PG_PORT = '8812';
// MongoDB configs
process.env.MONGODB_HOST = 'localhost';
process.env.MONGODB_PORT = '27017';
process.env.MONGODB_DATABASE = 'test_db';
// Dragonfly configs
process.env.DRAGONFLY_HOST = 'localhost';
process.env.DRAGONFLY_PORT = '6379';
// Monitoring configs
process.env.PROMETHEUS_HOST = 'localhost';
process.env.PROMETHEUS_PORT = '9090';
process.env.GRAFANA_HOST = 'localhost';
process.env.GRAFANA_PORT = '3000';
// Loki configs
process.env.LOKI_HOST = 'localhost';
process.env.LOKI_PORT = '3100';
// Logging configs
process.env.LOG_LEVEL = 'info';
process.env.LOG_FORMAT = 'json';
try {
console.log('🔍 Validating configuration modules...\n');
// Test each configuration module
const modules = [
{ name: 'Database', path: './dist/database.js' },
{ name: 'QuestDB', path: './dist/questdb.js' },
{ name: 'MongoDB', path: './dist/mongodb.js' },
{ name: 'Dragonfly', path: './dist/dragonfly.js' },
{ name: 'Monitoring', path: './dist/monitoring.js' },
{ name: 'Loki', path: './dist/loki.js' },
{ name: 'Logging', path: './dist/logging.js' },
];
const results = [];
for (const module of modules) {
try {
const config = require(module.path);
const configKeys = Object.keys(config);
if (configKeys.length === 0) {
throw new Error('No exported configuration found');
}
// Try to access the main config object
const mainConfig = config[configKeys[0]];
if (!mainConfig || typeof mainConfig !== 'object') {
throw new Error('Invalid configuration object');
}
console.log(`${module.name}: ${configKeys.length} config(s) loaded`);
results.push({ name: module.name, status: 'success', configs: configKeys });
} catch (error) {
console.log(`${module.name}: ${error.message}`);
results.push({ name: module.name, status: 'error', error: error.message });
}
}
// Test main index exports
try {
const indexExports = require('./dist/index.js');
const exportCount = Object.keys(indexExports).length;
console.log(`\n✅ Index exports: ${exportCount} modules exported`);
results.push({ name: 'Index', status: 'success', exports: exportCount });
} catch (error) {
console.log(`\n❌ Index exports: ${error.message}`);
results.push({ name: 'Index', status: 'error', error: error.message });
}
// Summary
const successful = results.filter(r => r.status === 'success').length;
const total = results.length;
console.log(`\n📊 Validation Summary:`);
console.log(` Total modules: ${total}`);
console.log(` Successful: ${successful}`);
console.log(` Failed: ${total - successful}`);
if (successful === total) {
console.log('\n🎉 All configuration modules validated successfully!');
process.exit(0);
} else {
console.log('\n⚠ Some configuration modules failed validation.');
process.exit(1);
}
} catch (error) {
console.error('❌ Validation script failed:', error.message);
process.exit(1);
}