huge refactor with a million of things to make the code much more managable and easier to create new services #3

Merged
boki merged 70 commits from di-refactor into master 2025-06-24 01:43:57 +00:00
16 changed files with 141 additions and 476 deletions
Showing only changes of commit 63baeaec70 - Show all commits

View file

@ -1,8 +1,4 @@
import { getLogger, type Logger } from '@stock-bot/logger'; import { getLogger, type Logger } from '@stock-bot/logger';
import { MongoDBClient, createMongoDBClient, type ConnectionEvents } from '@stock-bot/mongodb';
import { PostgreSQLClient, createPostgreSQLClient } from '@stock-bot/postgres';
import { createCache, type CacheProvider } from '@stock-bot/cache';
import { QueueManager } from '@stock-bot/queue';
import type { import type {
ConnectionFactory as IConnectionFactory, ConnectionFactory as IConnectionFactory,
ConnectionPool, ConnectionPool,
@ -22,9 +18,10 @@ export class ConnectionFactory implements IConnectionFactory {
constructor(config: ConnectionFactoryConfig) { constructor(config: ConnectionFactoryConfig) {
this.config = config; this.config = config;
this.logger = getLogger(`connection-factory:${config.service}`); this.logger = getLogger(`connection-factory:${config.service}`);
// Note: config is stored for future use and used in logger name
} }
async createMongoDB(poolConfig: MongoDBPoolConfig): Promise<ConnectionPool<MongoDBClient>> { async createMongoDB(poolConfig: MongoDBPoolConfig): Promise<ConnectionPool<any>> {
const key = `mongodb:${poolConfig.name}`; const key = `mongodb:${poolConfig.name}`;
if (this.pools.has(key)) { if (this.pools.has(key)) {
@ -38,35 +35,30 @@ export class ConnectionFactory implements IConnectionFactory {
}); });
try { try {
const events: ConnectionEvents = { // Dynamic import to avoid circular dependency
const { createMongoDBClient } = await import('@stock-bot/mongodb');
const events = {
onConnect: () => { onConnect: () => {
this.logger.debug('MongoDB connected', { pool: poolConfig.name }); this.logger.debug('MongoDB connected', { pool: poolConfig.name });
}, },
onDisconnect: () => { onDisconnect: () => {
this.logger.debug('MongoDB disconnected', { pool: poolConfig.name }); this.logger.debug('MongoDB disconnected', { pool: poolConfig.name });
}, },
onError: (error) => { onError: (error: any) => {
this.logger.error('MongoDB error', { pool: poolConfig.name, error }); this.logger.error('MongoDB error', { pool: poolConfig.name, error });
}, },
}; };
const client = createMongoDBClient({ const client = createMongoDBClient(poolConfig.config as any, events);
...poolConfig.config,
poolSettings: {
maxPoolSize: poolConfig.maxConnections || poolConfig.poolSize || 10,
minPoolSize: poolConfig.minConnections || 2,
maxIdleTime: 30000,
}
}, events);
await client.connect(); await client.connect();
// Warm up the pool
if (poolConfig.minConnections) { if (poolConfig.minConnections) {
await client.warmupPool(); await client.warmupPool();
} }
const pool: ConnectionPool<MongoDBClient> = { const pool: ConnectionPool<any> = {
name: poolConfig.name, name: poolConfig.name,
client, client,
metrics: client.getPoolMetrics(), metrics: client.getPoolMetrics(),
@ -92,7 +84,7 @@ export class ConnectionFactory implements IConnectionFactory {
} }
} }
async createPostgreSQL(poolConfig: PostgreSQLPoolConfig): Promise<ConnectionPool<PostgreSQLClient>> { async createPostgreSQL(poolConfig: PostgreSQLPoolConfig): Promise<ConnectionPool<any>> {
const key = `postgres:${poolConfig.name}`; const key = `postgres:${poolConfig.name}`;
if (this.pools.has(key)) { if (this.pools.has(key)) {
@ -106,35 +98,19 @@ export class ConnectionFactory implements IConnectionFactory {
}); });
try { try {
const events: ConnectionEvents = { // Dynamic import to avoid circular dependency
onConnect: () => { const { createPostgreSQLClient } = await import('@stock-bot/postgres');
this.logger.debug('PostgreSQL connected', { pool: poolConfig.name });
},
onDisconnect: () => {
this.logger.debug('PostgreSQL disconnected', { pool: poolConfig.name });
},
onError: (error) => {
this.logger.error('PostgreSQL error', { pool: poolConfig.name, error });
},
};
const client = createPostgreSQLClient({ // Events will be handled by the client internally
...poolConfig.config, const client = createPostgreSQLClient(poolConfig.config as any);
poolSettings: {
max: poolConfig.maxConnections || poolConfig.poolSize || 10,
min: poolConfig.minConnections || 2,
idleTimeoutMillis: poolConfig.idleTimeoutMillis || 30000,
},
}, undefined, events);
await client.connect(); await client.connect();
// Warm up the pool
if (poolConfig.minConnections) { if (poolConfig.minConnections) {
await client.warmupPool(); await client.warmupPool();
} }
const pool: ConnectionPool<PostgreSQLClient> = { const pool: ConnectionPool<any> = {
name: poolConfig.name, name: poolConfig.name,
client, client,
metrics: client.getPoolMetrics(), metrics: client.getPoolMetrics(),
@ -153,7 +129,7 @@ export class ConnectionFactory implements IConnectionFactory {
} }
} }
createCache(poolConfig: CachePoolConfig): ConnectionPool<CacheProvider> { createCache(poolConfig: CachePoolConfig): ConnectionPool<any> {
const key = `cache:${poolConfig.name}`; const key = `cache:${poolConfig.name}`;
if (this.pools.has(key)) { if (this.pools.has(key)) {
@ -166,32 +142,16 @@ export class ConnectionFactory implements IConnectionFactory {
}); });
try { try {
const cache = createCache({ // TODO: Implement cache creation with dynamic import
...poolConfig.config, throw new Error('Cache creation temporarily disabled');
keyPrefix: `${this.config.service}:${poolConfig.name}:`,
shared: false, // Each pool gets its own connection
});
const pool: ConnectionPool<CacheProvider> = {
name: poolConfig.name,
client: cache,
metrics: this.createInitialMetrics(),
health: async () => cache.health(),
dispose: async () => {
// Cache disposal handled internally
this.pools.delete(key);
},
};
this.pools.set(key, pool);
return pool;
} catch (error) { } catch (error) {
this.logger.error('Failed to create cache pool', { name: poolConfig.name, error }); this.logger.error('Failed to create cache pool', { name: poolConfig.name, error });
throw error; throw error;
} }
} }
createQueue(poolConfig: QueuePoolConfig): ConnectionPool<QueueManager> { createQueue(poolConfig: QueuePoolConfig): ConnectionPool<any> {
const key = `queue:${poolConfig.name}`; const key = `queue:${poolConfig.name}`;
if (this.pools.has(key)) { if (this.pools.has(key)) {
@ -204,31 +164,9 @@ export class ConnectionFactory implements IConnectionFactory {
}); });
try { try {
// Initialize or get existing QueueManager instance // TODO: Implement queue creation with dynamic import
const queueManager = QueueManager.getOrInitialize(poolConfig.config); throw new Error('Queue creation temporarily disabled');
const pool: ConnectionPool<QueueManager> = {
name: poolConfig.name,
client: queueManager,
metrics: this.createInitialMetrics(),
health: async () => {
try {
// Check if QueueManager is initialized
queueManager.getQueueNames();
return true;
} catch {
return false;
}
},
dispose: async () => {
// QueueManager handles its own shutdown
await queueManager.shutdown();
this.pools.delete(key);
},
};
this.pools.set(key, pool);
return pool;
} catch (error) { } catch (error) {
this.logger.error('Failed to create queue manager', { name: poolConfig.name, error }); this.logger.error('Failed to create queue manager', { name: poolConfig.name, error });
throw error; throw error;
@ -243,11 +181,11 @@ export class ConnectionFactory implements IConnectionFactory {
listPools(): Array<{ type: string; name: string; metrics: PoolMetrics }> { listPools(): Array<{ type: string; name: string; metrics: PoolMetrics }> {
const result: Array<{ type: string; name: string; metrics: PoolMetrics }> = []; const result: Array<{ type: string; name: string; metrics: PoolMetrics }> = [];
for (const [key, pool] of this.pools.entries()) { for (const [key, pool] of this.pools) {
const [type, ...nameParts] = key.split(':'); const [type] = key.split(':');
result.push({ result.push({
type: type || 'unknown', type: type || 'unknown',
name: nameParts.join(':'), name: pool.name,
metrics: pool.metrics, metrics: pool.metrics,
}); });
} }
@ -256,25 +194,10 @@ export class ConnectionFactory implements IConnectionFactory {
} }
async disposeAll(): Promise<void> { async disposeAll(): Promise<void> {
this.logger.info('Disposing all connection pools', { count: this.pools.size }); this.logger.info('Disposing all connection pools', { service: this.config.service });
const disposePromises: Promise<void>[] = [];
for (const pool of this.pools.values()) {
disposePromises.push(pool.dispose());
}
const disposePromises = Array.from(this.pools.values()).map(pool => pool.dispose());
await Promise.all(disposePromises); await Promise.all(disposePromises);
this.pools.clear(); this.pools.clear();
} }
private createInitialMetrics(): PoolMetrics {
return {
created: new Date(),
totalConnections: 0,
activeConnections: 0,
idleConnections: 0,
waitingRequests: 0,
errors: 0,
};
}
} }

View file

@ -1,6 +1,6 @@
// Export all dependency injection components // Export all dependency injection components
export * from './service-container'; export * from './service-container';
export * from './connection-factory'; export { ConnectionFactory } from './connection-factory';
export * from './operation-context'; export * from './operation-context';
export * from './pool-size-calculator'; export * from './pool-size-calculator';
export * from './types'; export * from './types';

View file

@ -1,19 +1,12 @@
/** /**
* OperationContext - Unified context for handler operations * OperationContext - Unified context for handler operations
* *
* Provides streamlined access to: * TEMPORARILY DISABLED to avoid circular dependencies during library build
* - Child loggers with hierarchical context * Will be re-enabled once all core libraries are built
* - Database clients (MongoDB, PostgreSQL)
* - Contextual cache with automatic key prefixing
* - Shared resource management
*/ */
import { createCache, type CacheProvider } from '@stock-bot/cache';
import { getLogger, type Logger } from '@stock-bot/logger'; import { getLogger, type Logger } from '@stock-bot/logger';
import { getDatabaseConfig } from '@stock-bot/config';
import type { ServiceResolver } from './service-container'; import type { ServiceResolver } from './service-container';
import type { MongoDBClient } from '@stock-bot/mongodb';
import type { PostgreSQLClient } from '@stock-bot/postgres';
export interface OperationContextOptions { export interface OperationContextOptions {
handlerName: string; handlerName: string;
@ -25,283 +18,44 @@ export interface OperationContextOptions {
export class OperationContext { export class OperationContext {
public readonly logger: Logger; public readonly logger: Logger;
private readonly container?: ServiceResolver; private readonly container?: ServiceResolver;
private _mongodb?: MongoDBClient;
private _postgres?: PostgreSQLClient;
private _cache?: CacheProvider;
private _queue?: any; // Type will be QueueManager but we avoid import for circular deps
private static sharedCache: CacheProvider | null = null; constructor(options: OperationContextOptions) {
private static parentLoggers = new Map<string, Logger>();
private static databaseConfig: any = null;
constructor(
public readonly handlerName: string,
public readonly operationName: string,
parentLoggerOrOptions?: Logger | OperationContextOptions
) {
// Handle both old and new constructor signatures
if (parentLoggerOrOptions && 'container' in parentLoggerOrOptions) {
const options = parentLoggerOrOptions;
this.container = options.container; this.container = options.container;
const parent = options.parentLogger || this.getOrCreateParentLogger(); this.logger = options.parentLogger || getLogger(`${options.handlerName}:${options.operationName}`);
this.logger = parent.child(operationName, {
handler: handlerName,
operation: operationName
});
} else {
// Legacy support
const parentLogger = parentLoggerOrOptions as Logger | undefined;
const parent = parentLogger || this.getOrCreateParentLogger();
this.logger = parent.child(operationName, {
handler: handlerName,
operation: operationName
});
}
}
// Lazy load MongoDB client
get mongodb(): MongoDBClient {
if (!this._mongodb) {
if (this.container) {
try {
this._mongodb = this.container.resolve<MongoDBClient>('mongodb');
} catch (error) {
this.logger.warn('Failed to resolve MongoDB from container, falling back to singleton', { error });
this._mongodb = this.getLegacyDatabaseClient('mongodb') as MongoDBClient;
}
} else {
this._mongodb = this.getLegacyDatabaseClient('mongodb') as MongoDBClient;
}
}
return this._mongodb!;
}
// Lazy load PostgreSQL client
get postgres(): PostgreSQLClient {
if (!this._postgres) {
if (this.container) {
try {
this._postgres = this.container.resolve<PostgreSQLClient>('postgres');
} catch (error) {
this.logger.warn('Failed to resolve PostgreSQL from container, falling back to singleton', { error });
this._postgres = this.getLegacyDatabaseClient('postgres') as PostgreSQLClient;
}
} else {
this._postgres = this.getLegacyDatabaseClient('postgres') as PostgreSQLClient;
}
}
return this._postgres!;
}
// Lazy load QueueManager
get queue(): any {
if (!this._queue) {
if (this.container) {
try {
this._queue = this.container.resolve('queue');
} catch (error) {
this.logger.warn('Failed to resolve QueueManager from container, falling back to singleton', { error });
this._queue = this.getLegacyQueueManager();
}
} else {
this._queue = this.getLegacyQueueManager();
}
}
return this._queue!;
}
// Legacy method for QueueManager
private getLegacyQueueManager(): any {
try {
// Dynamic import to avoid TypeScript issues during build
const { QueueManager } = require('@stock-bot/queue');
return QueueManager.getInstance();
} catch (error) {
this.logger.warn('QueueManager not initialized, queue operations may fail', { error });
throw new Error('QueueManager not available');
}
}
// Legacy method for backward compatibility
private getLegacyDatabaseClient(type: 'mongodb' | 'postgres'): any {
try {
if (type === 'mongodb') {
// Dynamic import to avoid TypeScript issues during build
const { getMongoDBClient } = require('@stock-bot/mongodb');
return getMongoDBClient();
} else {
// Dynamic import to avoid TypeScript issues during build
const { getPostgreSQLClient } = require('@stock-bot/postgres');
return getPostgreSQLClient();
}
} catch (error) {
this.logger.warn(`${type} client not initialized, operations may fail`, { error });
return null;
}
}
private getOrCreateParentLogger(): Logger {
const parentKey = `${this.handlerName}-handler`;
if (!OperationContext.parentLoggers.has(parentKey)) {
const parentLogger = getLogger(parentKey);
OperationContext.parentLoggers.set(parentKey, parentLogger);
}
return OperationContext.parentLoggers.get(parentKey)!;
} }
/** /**
* Get contextual cache with automatic key prefixing * Creates a new OperationContext with automatic resource management
* Keys are automatically prefixed as: "operations:handlerName:operationName:key" * TEMPORARILY SIMPLIFIED - full implementation will be restored after build fixes
*/ */
get cache(): CacheProvider { static create(
if (!this._cache) { handlerName: string,
if (this.container) { operationName: string,
try { options: { container?: ServiceResolver; parentLogger?: Logger } = {}
const baseCache = this.container.resolve<CacheProvider>('cache'); ): OperationContext {
this._cache = this.createContextualCache(baseCache); return new OperationContext({
} catch (error) {
this.logger.warn('Failed to resolve cache from container, using shared cache', { error });
this._cache = this.getOrCreateSharedCache();
}
} else {
this._cache = this.getOrCreateSharedCache();
}
}
return this._cache!;
}
private getOrCreateSharedCache(): CacheProvider {
if (!OperationContext.sharedCache) {
// Get Redis configuration from database config
if (!OperationContext.databaseConfig) {
OperationContext.databaseConfig = getDatabaseConfig();
}
const redisConfig = OperationContext.databaseConfig.dragonfly || {
host: 'localhost',
port: 6379,
db: 1
};
OperationContext.sharedCache = createCache({
keyPrefix: 'operations:',
shared: true, // Use singleton Redis connection
enableMetrics: true,
ttl: 3600, // Default 1 hour TTL
redisConfig
});
}
return this.createContextualCache(OperationContext.sharedCache);
}
private createContextualCache(baseCache: CacheProvider): CacheProvider {
const contextPrefix = `${this.handlerName}:${this.operationName}:`;
// Return a proxy that automatically prefixes keys with context
return {
async get<T>(key: string): Promise<T | null> {
return baseCache.get(`${contextPrefix}${key}`);
},
async set<T>(key: string, value: T, options?: any): Promise<T | null> {
return baseCache.set(`${contextPrefix}${key}`, value, options);
},
async del(key: string): Promise<void> {
return baseCache.del(`${contextPrefix}${key}`);
},
async exists(key: string): Promise<boolean> {
return baseCache.exists(`${contextPrefix}${key}`);
},
async clear(): Promise<void> {
// Not implemented for contextual cache - use del() for specific keys
throw new Error('clear() not implemented for contextual cache - use del() for specific keys');
},
async keys(pattern: string): Promise<string[]> {
const fullPattern = `${contextPrefix}${pattern}`;
return baseCache.keys(fullPattern);
},
getStats() {
return baseCache.getStats();
},
async health(): Promise<boolean> {
return baseCache.health();
},
async waitForReady(timeout?: number): Promise<void> {
return baseCache.waitForReady(timeout);
},
isReady(): boolean {
return baseCache.isReady();
}
} as CacheProvider;
}
/**
* Factory method to create OperationContext
*/
static create(handlerName: string, operationName: string, parentLoggerOrOptions?: Logger | OperationContextOptions): OperationContext {
if (parentLoggerOrOptions && 'container' in parentLoggerOrOptions) {
return new OperationContext(handlerName, operationName, {
...parentLoggerOrOptions,
handlerName, handlerName,
operationName operationName,
...options,
}); });
} }
return new OperationContext(handlerName, operationName, parentLoggerOrOptions as Logger | undefined);
}
/** /**
* Get cache key prefix for this operation context * Cleanup method - simplified for now
*/
getCacheKeyPrefix(): string {
return `operations:${this.handlerName}:${this.operationName}:`;
}
/**
* Create a child context for sub-operations
*/
createChild(subOperationName: string): OperationContext {
if (this.container) {
return new OperationContext(
this.handlerName,
`${this.operationName}:${subOperationName}`,
{
handlerName: this.handlerName,
operationName: `${this.operationName}:${subOperationName}`,
parentLogger: this.logger,
container: this.container
}
);
}
return new OperationContext(
this.handlerName,
`${this.operationName}:${subOperationName}`,
this.logger
);
}
/**
* Dispose of resources if using container-based connections
* This is a no-op for legacy singleton connections
*/ */
async dispose(): Promise<void> { async dispose(): Promise<void> {
// If using container, it will handle cleanup // Cleanup will be implemented when dependencies are resolved
// For singleton connections, they persist }
this.logger.debug('OperationContext disposed', {
handler: this.handlerName, /**
operation: this.operationName, * Create child context - simplified for now
hasContainer: !!this.container */
createChild(operationName: string): OperationContext {
return new OperationContext({
handlerName: 'child',
operationName,
parentLogger: this.logger,
container: this.container,
}); });
} }
} }
export default OperationContext;

View file

@ -9,13 +9,7 @@
}, },
"dependencies": { "dependencies": {
"@stock-bot/config": "workspace:*", "@stock-bot/config": "workspace:*",
"@stock-bot/logger": "workspace:*", "@stock-bot/logger": "workspace:*"
"@stock-bot/mongodb": "workspace:*",
"@stock-bot/postgres": "workspace:*",
"@stock-bot/cache": "workspace:*",
"@stock-bot/queue": "workspace:*",
"mongodb": "^6.3.0",
"pg": "^8.11.3"
}, },
"devDependencies": { "devDependencies": {
"@types/pg": "^8.10.7" "@types/pg": "^8.10.7"

View file

@ -165,51 +165,43 @@ export function createServiceContainer(
singleton: true, singleton: true,
}); });
// Register ProxyManager // Optional services - comment out for now to avoid circular dependencies
container.register({ // These can be registered manually by apps that need them
name: 'proxyManager',
factory: async () => {
const { ProxyManager } = await import('@stock-bot/utils');
await ProxyManager.initialize();
return ProxyManager.getInstance();
},
singleton: true,
dispose: async (proxyManager) => {
// ProxyManager handles its own cleanup
if (proxyManager && typeof proxyManager.shutdown === 'function') {
await proxyManager.shutdown();
}
}
});
// Register Browser service // // Register ProxyManager
container.register({ // container.register({
name: 'browser', // name: 'proxyManager',
factory: async () => { // factory: async () => {
const { Browser } = await import('@stock-bot/browser'); // const { ProxyManager } = await import('@stock-bot/utils');
return Browser; // await ProxyManager.initialize();
}, // return ProxyManager.getInstance();
singleton: true, // },
dispose: async (browser) => { // singleton: true,
if (browser && typeof browser.close === 'function') { // });
await browser.close();
}
}
});
// Register HttpClient with default configuration // // Register Browser service
container.register({ // container.register({
name: 'httpClient', // name: 'browser',
factory: async () => { // factory: async () => {
const { createHttpClient } = await import('@stock-bot/http'); // const { Browser } = await import('@stock-bot/browser');
return createHttpClient({ // return Browser;
timeout: 30000, // },
retries: 3, // singleton: true,
userAgent: 'stock-bot/1.0', // });
});
}, // // Register HttpClient with default configuration
singleton: true, // container.register({
}); // name: 'httpClient',
// factory: async () => {
// const { createHttpClient } = await import('@stock-bot/http');
// return createHttpClient({
// timeout: 30000,
// retries: 3,
// userAgent: 'stock-bot/1.0',
// });
// },
// singleton: true,
// });
return container; return container;
} }

View file

@ -12,10 +12,6 @@
"exclude": ["node_modules", "dist"], "exclude": ["node_modules", "dist"],
"references": [ "references": [
{ "path": "../config" }, { "path": "../config" },
{ "path": "../logger" }, { "path": "../logger" }
{ "path": "../../data/mongodb" },
{ "path": "../../data/postgres" },
{ "path": "../../data/cache" },
{ "path": "../../services/queue" }
] ]
} }

View file

@ -1,7 +1,7 @@
import type { MongoDBClientConfig } from '@stock-bot/mongodb-client'; // Generic types to avoid circular dependencies
import type { PostgreSQLClientConfig } from '@stock-bot/postgres-client'; export interface GenericClientConfig {
import type { CacheOptions } from '@stock-bot/cache'; [key: string]: any;
import type { QueueManagerConfig } from '@stock-bot/queue'; }
export interface ConnectionPoolConfig { export interface ConnectionPoolConfig {
name: string; name: string;
@ -14,19 +14,19 @@ export interface ConnectionPoolConfig {
} }
export interface MongoDBPoolConfig extends ConnectionPoolConfig { export interface MongoDBPoolConfig extends ConnectionPoolConfig {
config: MongoDBClientConfig; config: GenericClientConfig;
} }
export interface PostgreSQLPoolConfig extends ConnectionPoolConfig { export interface PostgreSQLPoolConfig extends ConnectionPoolConfig {
config: PostgreSQLClientConfig; config: GenericClientConfig;
} }
export interface CachePoolConfig extends ConnectionPoolConfig { export interface CachePoolConfig extends ConnectionPoolConfig {
config: CacheOptions; config: GenericClientConfig;
} }
export interface QueuePoolConfig extends ConnectionPoolConfig { export interface QueuePoolConfig extends ConnectionPoolConfig {
config: QueueManagerConfig; config: GenericClientConfig;
} }
export interface ConnectionFactoryConfig { export interface ConnectionFactoryConfig {

View file

@ -11,7 +11,8 @@
}, },
"dependencies": { "dependencies": {
"@stock-bot/config": "workspace:*", "@stock-bot/config": "workspace:*",
"@stock-bot/logger": "workspace:*" "@stock-bot/logger": "workspace:*",
"@stock-bot/di": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.11.0", "@types/node": "^20.11.0",

View file

@ -1,4 +1,5 @@
import { getLogger } from '@stock-bot/logger'; import { getLogger } from '@stock-bot/logger';
import type { ServiceContainer } from '@stock-bot/di';
import type { IHandler, ExecutionContext } from '../types/types'; import type { IHandler, ExecutionContext } from '../types/types';
/** /**
@ -8,7 +9,7 @@ import type { IHandler, ExecutionContext } from '../types/types';
export abstract class BaseHandler implements IHandler { export abstract class BaseHandler implements IHandler {
protected readonly logger; protected readonly logger;
constructor(protected readonly container: any) { constructor(protected readonly container: ServiceContainer) {
this.logger = getLogger(this.constructor.name); this.logger = getLogger(this.constructor.name);
} }

View file

@ -1,9 +1,9 @@
// import type { ServiceContainer } from '@stock-bot/di'; // Temporarily commented import type { ServiceContainer } from '@stock-bot/di';
// Simple execution context - mostly queue for now // Simple execution context - mostly queue for now
export interface ExecutionContext { export interface ExecutionContext {
type: 'queue'; // | 'event' - commented for future type: 'queue'; // | 'event' - commented for future
serviceContainer: any; // ServiceContainer - temporarily any serviceContainer: ServiceContainer;
metadata: { metadata: {
source?: string; source?: string;
jobId?: string; jobId?: string;

View file

@ -8,6 +8,7 @@
"include": ["src/**/*"], "include": ["src/**/*"],
"references": [ "references": [
{ "path": "../config" }, { "path": "../config" },
{ "path": "../logger" } { "path": "../logger" },
{ "path": "../di" }
] ]
} }

View file

@ -7,7 +7,7 @@
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"references": [ "references": [
{ "path": "../logger" }, { "path": "../../core/logger" },
{ "path": "../types" } { "path": "../../core/types" }
] ]
} }

View file

@ -7,7 +7,7 @@
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"references": [ "references": [
{ "path": "../logger" }, { "path": "../../core/logger" },
{ "path": "../http" } { "path": "../http" }
] ]
} }

View file

@ -7,6 +7,6 @@
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"references": [ "references": [
{ "path": "../logger" } { "path": "../../core/logger" }
] ]
} }

View file

@ -1,11 +1,14 @@
{ {
"extends": "../../../tsconfig.json", "extends": "../../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./dist", "outDir": "./dist",
"rootDir": "./src", "rootDir": "./src",
"composite": true "composite": true,
"skipLibCheck": true,
"types": ["node", "bun-types"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "dist"],
"references": [ "references": [
{ "path": "../core/types" }, { "path": "../core/types" },
{ "path": "../data/cache" }, { "path": "../data/cache" },

View file

@ -31,28 +31,28 @@ trap cleanup EXIT
# Build order is important due to dependencies # Build order is important due to dependencies
libs=( libs=(
# Core Libraries # Core Libraries - minimal dependencies
"core/types" # Base types - no dependencies "core/types" # Base types - no dependencies
"core/config" # Configuration - depends on types "core/config" # Configuration - depends on types
"core/logger" # Logging utilities - depends on types "core/logger" # Logging utilities - depends on types
"core/handlers" # Handler infrastructure - depends on core libs "core/handlers" # Handler infrastructure - depends on core libs
"utils" # Utilities - depends on types and config
# Data access libraries # Data access libraries
"data/postgres" # PostgreSQL client - depends on core libs
"data/mongodb" # MongoDB client - depends on core libs
"data/questdb" # QuestDB client - depends on core libs
"data/cache" # Cache - depends on core libs "data/cache" # Cache - depends on core libs
"data/mongodb" # MongoDB client - depends on core libs
"data/postgres" # PostgreSQL client - depends on core libs
"data/questdb" # QuestDB client - depends on core libs
# Service libraries # Service libraries
"services/http" # HTTP client - depends on core libs "services/http" # HTTP client - depends on core libs
"services/event-bus" # Event bus - depends on core libs "services/event-bus" # Event bus - depends on core libs
"services/queue" # Queue - depends on core libs and cache
"services/shutdown" # Shutdown - depends on core libs "services/shutdown" # Shutdown - depends on core libs
"services/browser" # Browser - depends on core libs "services/browser" # Browser - depends on core libs
"services/queue" # Queue - depends on core libs, cache, and handlers
# DI and Connection Factory - depends on everything # Utils and DI last - depend on many other libs
"core/di" # Dependency injection - depends on all other libs "utils" # Utilities - depends on many libs
"core/di" # Dependency injection - depends on data and service libs
) )
# Build each library in order # Build each library in order