// @eyjs/bootstrap - Application Bootstrap Package import type { BootstrapOptions } from '../@eyjs-di' import path from 'path' import { fileURLToPath } from 'url' import { container } from '../@eyjs-di' import { logger } from '../@eyjs-logger' import { BootstrapBase } from './bootstrap-base' import { ServiceLoader } from './service-loader' // Importar servicios del core para registrarlos automáticamente import { EyJsConfig } from '../@eyjs-env' import { Logger } from '../@eyjs-logger' export class Bootstrap { static async start( callerMetaUrl: string, options: BootstrapOptions = {}, ): Promise { // 0. Registrar servicios del core automáticamente await this.registerCoreServices() // 1. Resolver rootDir const rootDir = options.rootDir || path.dirname(fileURLToPath(callerMetaUrl)) // 2. Por defecto incluir packages const extraDirs = options.extraDirs ?? [ path.resolve(process.cwd(), 'packages'), ] // Use the core logger instead of console // 3. Cargar archivos con decoradores const relativeRootDir = path.relative(process.cwd(), rootDir) || '/' const relativeExtraDirs = extraDirs.map( (dir) => path.relative(process.cwd(), dir) || '/', ) logger.debug('bootstrap', `📦 Loading decorated files from: ${relativeRootDir}`) logger.debug('bootstrap', `📦 Extra directories: ${relativeExtraDirs.join(', ')}`) const loadResult = await ServiceLoader.load({ rootDir, extraDirs }) // 4. Mostrar estadísticas de carga // logger.info(`📊 Loaded ${loadResult.loadedCount} files`) if (loadResult.errorCount > 0) { logger.warn(`⚠️ ${loadResult.errorCount} files failed to load`) } // 5. Mostrar servicios registrados por tipo // const decoratorStores = container.getDecoratorStores() // for (const [decoratorType, services] of decoratorStores) { // logger.debug('services', // `🔧 Registered ${services.length} ${decoratorType} services`, // ) // } // 6. Iniciar servicios de bootstrap automáticamente await this.startBootstrapServices(logger) return container } /** * Registra automáticamente todos los servicios del core */ private static async registerCoreServices(): Promise { try { // Registrar Logger container.register(Logger, 'singleton', false, [], 'core') // Registrar EyJsConfig (ConfigService) container.register(EyJsConfig, 'singleton', false, [], 'core') logger.debug('bootstrap', '✅ Core services registered automatically') } catch (error) { logger.error('❌ Failed to register core services:', error as Record) throw error } } private static async startBootstrapServices(logger: any): Promise { // Obtener servicios que extienden BootstrapBase const bootstrapServices = this.getBootstrapServices() for (const BootstrapService of bootstrapServices) { try { const instance = container.get(BootstrapService) if ( instance instanceof BootstrapBase && typeof instance.bootstrap === 'function' ) { await instance.bootstrap() logger.debug('services', `✅ Bootstraped: ${BootstrapService.name}`) } } catch (err) { logger.error(`❌ Bootstrap failed: ${BootstrapService.name}`, err) } } } private static getBootstrapServices(): any[] { // Obtener todas las clases registradas en el contenedor const allServices = container.getAllServices() // Filtrar solo las que extienden BootstrapBase return allServices.filter((service) => { try { const instance = container.get(service) return instance instanceof BootstrapBase } catch { return false } }) } // Método para obtener servicios por tipo static getServicesByType(decoratorType: string): any[] { return container.getInstancesByDecorator(decoratorType) } // Método para obtener todos los servicios static getAllServices(): any[] { return container.getAllServices() } // Método para obtener estadísticas static getStats(): { totalServices: number servicesByType: Record } { const decoratorStores = container.getDecoratorStores() const servicesByType: Record = {} for (const [decoratorType, services] of decoratorStores) { servicesByType[decoratorType] = services.length } return { totalServices: container.getAllServices().length, servicesByType, } } }