| 9 | * Uses EventEmitter for reactive updates across the application |
| 10 | */ |
| 11 | export class ServiceContainer extends EventEmitter { |
| 12 | private services = new Map<string, ServiceResult<any>>(); |
| 13 | private factories = new Map<string, () => Promise<any>>(); |
| 14 | private dependencies = new Map<string, string[]>(); |
| 15 | |
| 16 | constructor() { |
| 17 | super(); |
| 18 | // Increase max listeners to handle multiple UI components |
| 19 | this.setMaxListeners(50); |
| 20 | } |
| 21 | |
| 22 | /** |
| 23 | * Register a service factory with optional dependencies |
| 24 | */ |
| 25 | register<T>( |
| 26 | serviceName: string, |
| 27 | factory: () => Promise<T>, |
| 28 | deps: string[] = [], |
| 29 | ): void { |
| 30 | this.factories.set(serviceName, factory); |
| 31 | this.dependencies.set(serviceName, deps); |
| 32 | |
| 33 | // Only initialize with idle state if the service doesn't already exist |
| 34 | // This prevents overwriting services that were registered with registerValue |
| 35 | if (!this.services.has(serviceName)) { |
| 36 | this.services.set(serviceName, { |
| 37 | value: null, |
| 38 | state: "idle", |
| 39 | error: null, |
| 40 | }); |
| 41 | } |
| 42 | |
| 43 | logger.debug(`Registered service: ${serviceName}`, { dependencies: deps }); |
| 44 | } |
| 45 | |
| 46 | /** |
| 47 | * Register a service with an immediate value (no factory needed) |
| 48 | * Used when the service is already initialized |
| 49 | */ |
| 50 | registerValue<T>(serviceName: string, value: T): void { |
| 51 | // Set the service as ready with the provided value |
| 52 | this.services.set(serviceName, { |
| 53 | value, |
| 54 | state: "ready", |
| 55 | error: null, |
| 56 | lastUpdated: new Date(), |
| 57 | }); |
| 58 | |
| 59 | // Emit ready event |
| 60 | this.emit(`${serviceName}:ready`, value); |
| 61 | |
| 62 | logger.debug(`Registered service with immediate value: ${serviceName}`, { |
| 63 | state: "ready", |
| 64 | hasValue: value !== null, |
| 65 | serviceMapSize: this.services.size, |
| 66 | }); |
| 67 | } |
| 68 |
nothing calls this directly
no outgoing calls
no test coverage detected