- Introduce NOSTRMARKET_SERVICE token in the DI container for better service management. - Update market module to create and register NostrmarketService instance using the new DI pattern. - Refactor components and composables to inject NostrmarketService via the DI container, enhancing modularity and testability. These changes improve the architecture by ensuring consistent service injection and eliminating legacy singleton references, aligning with the overall dependency injection strategy.
156 lines
No EOL
3.6 KiB
TypeScript
156 lines
No EOL
3.6 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'),
|
|
|
|
// Auth services
|
|
AUTH_SERVICE: Symbol('authService'),
|
|
|
|
// Payment services
|
|
PAYMENT_SERVICE: Symbol('paymentService'),
|
|
|
|
// Visibility services
|
|
VISIBILITY_SERVICE: Symbol('visibilityService'),
|
|
|
|
// Storage services
|
|
STORAGE_SERVICE: Symbol('storageService'),
|
|
|
|
// Toast services
|
|
TOAST_SERVICE: Symbol('toastService'),
|
|
|
|
// Market services
|
|
MARKET_STORE: Symbol('marketStore'),
|
|
PAYMENT_MONITOR: Symbol('paymentMonitor'),
|
|
|
|
// Chat services
|
|
CHAT_SERVICE: Symbol('chatService'),
|
|
|
|
// Events services
|
|
EVENTS_SERVICE: Symbol('eventsService'),
|
|
|
|
// Invoice services
|
|
INVOICE_SERVICE: Symbol('invoiceService'),
|
|
|
|
// Nostrmarket services
|
|
NOSTRMARKET_SERVICE: Symbol('nostrmarketService'),
|
|
} 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)
|
|
} |