diff --git a/libs/config/README.md b/libs/config/README.md index 65802ad..d6551e3 100644 --- a/libs/config/README.md +++ b/libs/config/README.md @@ -61,7 +61,7 @@ The library automatically loads environment variables from `.env` files. You can ### Database Configuration -- `databaseConfig` - Database connection settings (Dragonfly, TimescaleDB) +- `databaseConfig` - Database connection settings (Dragonfly, QuestDB, MongoDB, PostgreSQL) ### Data Provider Configuration diff --git a/libs/config/src/core.test.ts b/libs/config/src/core.test.ts index b3ae9fe..74698b8 100644 --- a/libs/config/src/core.test.ts +++ b/libs/config/src/core.test.ts @@ -3,8 +3,7 @@ */ import { describe, expect, test, beforeAll, afterAll } from 'bun:test'; import { - getEnvironment, - Environment, + getEnvironment, validateConfig, ConfigurationError, loadEnvVariables, @@ -13,7 +12,7 @@ import { getBooleanEnvVar } from './core'; -import { databaseConfigSchema } from './types'; +import { Environment, databaseConfigSchema } from './types'; describe('Core configuration', () => { // Save original environment variables @@ -74,8 +73,7 @@ describe('Core configuration', () => { expect(getBooleanEnvVar('TEST_BOOL_FALSE')).toBe(false); expect(getBooleanEnvVar('NON_EXISTENT', true)).toBe(true); }); - - test('validateConfig validates against schema', () => { + test('validateConfig validates against schema', () => { // Valid config const validConfig = { dragonfly: { @@ -83,28 +81,53 @@ describe('Core configuration', () => { port: 6379, maxRetriesPerRequest: 3 }, - timescaleDB: { + questDB: { + host: 'localhost', + port: 8812, + database: 'stockbot', + user: 'admin', + httpPort: 9000 + }, + mongodb: { + uri: 'mongodb://localhost:27017', + database: 'stockbot' + }, + postgres: { host: 'localhost', port: 5432, database: 'stockbot', - user: 'postgres' + user: 'postgres', + poolSize: 10, + ssl: false } }; expect(() => validateConfig(validConfig, databaseConfigSchema)).not.toThrow(); - - // Invalid config (missing required field) + // Invalid config (missing required field) const invalidConfig = { dragonfly: { host: 'localhost', // missing port maxRetriesPerRequest: 3 }, - timescaleDB: { + questDB: { + host: 'localhost', + port: 8812, + database: 'stockbot', + user: 'admin', + httpPort: 9000 + }, + mongodb: { + uri: 'mongodb://localhost:27017', + database: 'stockbot' + }, + postgres: { host: 'localhost', port: 5432, database: 'stockbot', - user: 'postgres' + user: 'postgres', + poolSize: 10, + ssl: false } }; diff --git a/libs/config/src/core.ts b/libs/config/src/core.ts index 65facb4..924215e 100644 --- a/libs/config/src/core.ts +++ b/libs/config/src/core.ts @@ -2,7 +2,7 @@ * Core configuration module for the Stock Bot platform */ import { config as dotenvConfig } from 'dotenv'; -import path from 'path'; +import path from 'node:path'; import { z } from 'zod'; import { Environment } from './types'; diff --git a/libs/config/src/database.ts b/libs/config/src/database.ts index 72d4474..8a45ad0 100644 --- a/libs/config/src/database.ts +++ b/libs/config/src/database.ts @@ -14,11 +14,24 @@ const defaultDatabaseConfig: DatabaseConfig = { port: 6379, maxRetriesPerRequest: 3 }, - timescaleDB: { + questDB: { + host: 'localhost', + port: 8812, + database: 'stockbot', + user: 'admin', + httpPort: 9000 + }, + mongodb: { + uri: 'mongodb://localhost:27017', + database: 'stockbot' + }, + postgres: { host: 'localhost', port: 5432, database: 'stockbot', - user: 'postgres' + user: 'postgres', + poolSize: 10, + ssl: false } }; @@ -26,7 +39,7 @@ const defaultDatabaseConfig: DatabaseConfig = { * Load database configuration from environment variables */ export function loadDatabaseConfig(): DatabaseConfig { - const config: DatabaseConfig = { + const config = { dragonfly: { host: getEnvVar('DRAGONFLY_HOST') || defaultDatabaseConfig.dragonfly.host, port: getNumericEnvVar('DRAGONFLY_PORT', defaultDatabaseConfig.dragonfly.port), @@ -34,12 +47,29 @@ export function loadDatabaseConfig(): DatabaseConfig { maxRetriesPerRequest: getNumericEnvVar('DRAGONFLY_MAX_RETRIES_PER_REQUEST', defaultDatabaseConfig.dragonfly.maxRetriesPerRequest) }, - timescaleDB: { - host: getEnvVar('TIMESCALE_HOST') || defaultDatabaseConfig.timescaleDB.host, - port: getNumericEnvVar('TIMESCALE_PORT', defaultDatabaseConfig.timescaleDB.port), - database: getEnvVar('TIMESCALE_DB') || defaultDatabaseConfig.timescaleDB.database, - user: getEnvVar('TIMESCALE_USER') || defaultDatabaseConfig.timescaleDB.user, - password: getEnvVar('TIMESCALE_PASSWORD') + questDB: { + host: getEnvVar('QUESTDB_HOST') || defaultDatabaseConfig.questDB.host, + port: getNumericEnvVar('QUESTDB_PORT', defaultDatabaseConfig.questDB.port), + database: getEnvVar('QUESTDB_DB') || defaultDatabaseConfig.questDB.database, + user: getEnvVar('QUESTDB_USER') || defaultDatabaseConfig.questDB.user, + password: getEnvVar('QUESTDB_PASSWORD'), + httpPort: getNumericEnvVar('QUESTDB_HTTP_PORT', defaultDatabaseConfig.questDB.httpPort) + }, + mongodb: { + uri: getEnvVar('MONGODB_URI') || defaultDatabaseConfig.mongodb.uri, + database: getEnvVar('MONGODB_DATABASE') || defaultDatabaseConfig.mongodb.database, + username: getEnvVar('MONGODB_USERNAME'), + password: getEnvVar('MONGODB_PASSWORD'), + options: process.env.MONGODB_OPTIONS ? JSON.parse(process.env.MONGODB_OPTIONS) : undefined + }, + postgres: { + host: getEnvVar('POSTGRES_HOST') || defaultDatabaseConfig.postgres.host, + port: getNumericEnvVar('POSTGRES_PORT', defaultDatabaseConfig.postgres.port), + database: getEnvVar('POSTGRES_DB') || defaultDatabaseConfig.postgres.database, + user: getEnvVar('POSTGRES_USER') || defaultDatabaseConfig.postgres.user, + password: getEnvVar('POSTGRES_PASSWORD'), + ssl: process.env.POSTGRES_SSL === 'true', + poolSize: getNumericEnvVar('POSTGRES_POOL_SIZE', defaultDatabaseConfig.postgres.poolSize) } }; diff --git a/libs/config/src/example.ts b/libs/config/src/example.ts index 0370d66..05054ae 100644 --- a/libs/config/src/example.ts +++ b/libs/config/src/example.ts @@ -20,17 +20,24 @@ export function printCurrentConfig(): void { console.log('\n=== Stock Bot Configuration ==='); console.log('\nEnvironment:', getEnvironment()); - - console.log('\n--- Database Config ---'); + console.log('\n--- Database Config ---'); console.log('Dragonfly Host:', databaseConfig.dragonfly.host); console.log('Dragonfly Port:', databaseConfig.dragonfly.port); - console.log('TimescaleDB Host:', databaseConfig.timescaleDB.host); - console.log('TimescaleDB Database:', databaseConfig.timescaleDB.database); - - console.log('\n--- Data Provider Config ---'); + console.log('QuestDB Host:', databaseConfig.questDB.host); + console.log('QuestDB Database:', databaseConfig.questDB.database); + console.log('MongoDB URI:', databaseConfig.mongodb.uri); + console.log('MongoDB Database:', databaseConfig.mongodb.database); + console.log('PostgreSQL Host:', databaseConfig.postgres.host); + console.log('PostgreSQL Database:', databaseConfig.postgres.database); + console.log('\n--- Data Provider Config ---'); console.log('Default Provider:', dataProviderConfigs.defaultProvider); console.log('Providers:'); - dataProviderConfigs.providers.forEach(provider => { + dataProviderConfigs.providers.forEach((provider: { + name: string; + type: string; + baseUrl?: string; + wsUrl?: string; + }) => { console.log(` - ${provider.name} (${provider.type})`); if (provider.baseUrl) console.log(` URL: ${provider.baseUrl}`); if (provider.wsUrl) console.log(` WebSocket: ${provider.wsUrl}`); @@ -59,14 +66,15 @@ export function printCurrentConfig(): void { } // Execute example if this file is run directly -if (require.main === module) { - try { +if (require.main === module) { try { printCurrentConfig(); - } catch (error) { + } catch (error: unknown) { if (error instanceof ConfigurationError) { console.error('Configuration Error:', error.message); + } else if (error instanceof Error) { + console.error('Error:', error.message); } else { - console.error('Error:', error); + console.error('Unknown error:', error); } process.exit(1); } diff --git a/libs/config/src/index.ts b/libs/config/src/index.ts index 2ce4b96..d56269a 100644 --- a/libs/config/src/index.ts +++ b/libs/config/src/index.ts @@ -21,4 +21,4 @@ export * from './risk'; export * from './logging'; // Service-specific configurations -export * from './services'; +export * from './services/index'; diff --git a/libs/config/src/services/market-data-gateway.ts b/libs/config/src/services/market-data-gateway.ts index 16a44e0..d444968 100644 --- a/libs/config/src/services/market-data-gateway.ts +++ b/libs/config/src/services/market-data-gateway.ts @@ -2,9 +2,9 @@ * Market Data Gateway service configuration */ import { z } from 'zod'; -import { getEnvVar, getNumericEnvVar, getBooleanEnvVar, createConfigLoader } from './core'; -import { Environment, BaseConfig } from './types'; -import { getEnvironment } from './core'; +import { getEnvVar, getNumericEnvVar, getBooleanEnvVar, createConfigLoader } from '../core'; +import { Environment, BaseConfig } from '../types'; +import { getEnvironment } from '../core'; /** * Market Data Gateway specific configuration schema diff --git a/libs/config/src/types.ts b/libs/config/src/types.ts index 0a5ff5f..9308167 100644 --- a/libs/config/src/types.ts +++ b/libs/config/src/types.ts @@ -36,12 +36,29 @@ export const databaseConfigSchema = z.object({ password: z.string().optional(), maxRetriesPerRequest: z.number().default(3) }), - timescaleDB: z.object({ + questDB: z.object({ + host: z.string().default('localhost'), + port: z.number().default(8812), + database: z.string().default('stockbot'), + user: z.string().default('admin'), + password: z.string().optional(), + httpPort: z.number().default(9000) + }), + mongodb: z.object({ + uri: z.string().default('mongodb://localhost:27017'), + database: z.string().default('stockbot'), + username: z.string().optional(), + password: z.string().optional(), + options: z.record(z.string(), z.any()).optional() + }), + postgres: z.object({ host: z.string().default('localhost'), port: z.number().default(5432), database: z.string().default('stockbot'), user: z.string().default('postgres'), - password: z.string().optional() + password: z.string().optional(), + ssl: z.boolean().default(false), + poolSize: z.number().default(10) }) }); diff --git a/libs/config/tsconfig.json b/libs/config/tsconfig.json index 51e0ff4..a83c7a2 100644 --- a/libs/config/tsconfig.json +++ b/libs/config/tsconfig.json @@ -3,7 +3,10 @@ "compilerOptions": { "outDir": "./dist", "rootDir": "./src", - "declaration": true + "declaration": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": false, + "module": "ESNext", }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "**/*.test.ts"] diff --git a/tsconfig.json b/tsconfig.json index 42b9f5b..39a3fec 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,9 +5,10 @@ "target": "ES2022", // Module configuration for different project types - "module": "NodeNext", - "moduleResolution": "NodeNext", - + "module": "ESNext", + "moduleResolution": "bundler", + "composite": true, + // Type checking "strict": true, "noImplicitAny": true,