web-app/src/core/di-container.ts
padreug 8d4c389f71 Add BaseService and refactor ChatService for improved dependency management
- Introduce BaseService as a foundational class for services, providing standardized dependency injection and initialization logic.
- Refactor ChatService to extend BaseService, enhancing its initialization process and dependency handling.
- Implement service metadata and structured initialization in ChatService, allowing for better tracking and error handling during service setup.
- Update chat module to initialize ChatService with dependency management, ensuring readiness before use.
2025-09-05 06:19:08 +02:00

139 lines
No EOL
3.2 KiB
TypeScript

import type { DIContainer, ServiceToken } from './types'
export type { ServiceToken } from './types'
interface ServiceRegistration {
service: any
scope: 'singleton' | 'transient'
instance?: any
}
/**
* Dependency Injection Container
* Manages service registration and injection across modules
*/
export class DIContainerImpl implements DIContainer {
private services = new Map<ServiceToken, ServiceRegistration>()
/**
* Register a service in the container
*/
provide<T>(token: ServiceToken, service: T, scope: 'singleton' | 'transient' = 'singleton'): void {
this.services.set(token, {
service,
scope,
instance: scope === 'singleton' ? service : undefined
})
}
/**
* Inject a service from the container
*/
inject<T>(token: ServiceToken): T | undefined {
const registration = this.services.get(token)
if (!registration) {
return undefined
}
if (registration.scope === 'singleton') {
return registration.instance as T
}
// For transient services, create new instance
// Note: This assumes the service is a constructor function
if (typeof registration.service === 'function') {
try {
return new registration.service() as T
} catch (error) {
console.error(`Error creating transient service for token ${String(token)}:`, error)
return undefined
}
}
return registration.service as T
}
/**
* Remove a service from the container
*/
remove(token: ServiceToken): boolean {
return this.services.delete(token)
}
/**
* Clear all services
*/
clear(): void {
this.services.clear()
}
/**
* Get all registered service tokens
*/
getRegisteredTokens(): ServiceToken[] {
return Array.from(this.services.keys())
}
/**
* Check if a service is registered
*/
has(token: ServiceToken): boolean {
return this.services.has(token)
}
/**
* Get service registration info
*/
getServiceInfo(token: ServiceToken): { scope: string; hasInstance: boolean } | undefined {
const registration = this.services.get(token)
if (!registration) {
return undefined
}
return {
scope: registration.scope,
hasInstance: registration.instance !== undefined
}
}
}
// Global DI container instance
export const container = new DIContainerImpl()
// Service token constants
export const SERVICE_TOKENS = {
// Core services
EVENT_BUS: Symbol('eventBus'),
ROUTER: Symbol('router'),
// Nostr services
RELAY_HUB: Symbol('relayHub'),
NOSTR_CLIENT_HUB: Symbol('nostrClientHub'),
// Auth services
AUTH_SERVICE: Symbol('authService'),
// Market services
MARKET_STORE: Symbol('marketStore'),
PAYMENT_MONITOR: Symbol('paymentMonitor'),
// Chat services
CHAT_SERVICE: Symbol('chatService'),
// Events services
EVENTS_SERVICE: Symbol('eventsService'),
} as const
// Type-safe injection helpers
export function injectService<T>(token: ServiceToken): T {
const service = container.inject<T>(token)
if (!service) {
throw new Error(`Service not found for token: ${String(token)}`)
}
return service
}
export function tryInjectService<T>(token: ServiceToken): T | undefined {
return container.inject<T>(token)
}