Implement modular architecture with core services and Nostr integration

- Introduce a modular application structure with a new app configuration file to manage module settings and features.
- Implement a dependency injection container for service management across modules.
- Create a plugin manager to handle module registration, installation, and lifecycle management.
- Develop a global event bus for inter-module communication, enhancing loose coupling between components.
- Add core modules including base functionalities, Nostr feed, and PWA services, with support for dynamic loading and configuration.
- Establish a Nostr client hub for managing WebSocket connections and event handling.
- Enhance user experience with a responsive Nostr feed component, integrating admin announcements and community posts.
- Refactor existing components to align with the new modular architecture, improving maintainability and scalability.
This commit is contained in:
padreug 2025-09-04 23:43:33 +02:00
parent 2d8215a35e
commit 519a9003d4
16 changed files with 2520 additions and 14 deletions

137
src/core/di-container.ts Normal file
View file

@ -0,0 +1,137 @@
import type { DIContainer, 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)
}