@jamx-framework/core
v1.0.0
Published
JAMX Framework — Core IoC Container and Utilities
Maintainers
Readme
@jamjx-framework/core
Descripción
Núcleo de JAMX Framework: contenedor de Inversión de Control (IoC), utilidades básicas, decoradores, bootstrap y sistemas de plugins. Este paquete provee la infraestructura fundamental que permite la modularidad, la inyección de dependencias y la arquitectura de extensibilidad de JAMX. Es el pilar sobre el cual se construyen todos los demás módulos del framework.
Cómo funciona
El núcleo de JAMX está diseñado alrededor de tres conceptos clave:
- Container: Sistema de registro y resolución de dependencias con soporte para scopes (
singleton,transient,scoped) y detección de dependencias circulares. - Decorators:
@injectable(),@inject()y@module()que permiten marcar clases y métodos para que el contenedor los gestione automáticamente. - Bootstrap: Función
bootstrap()que inicia la aplicación, carga configuración, inicializa módulos y arranca servidores de manera ordenada.
Además, el núcleo incluye utilidades para:
- Generación de documentación (
DocGenerator) - Manejo de excepciones (
HttpExceptiony subclasses) - Registro de plugins (
PluginRegistry) - Tipos y utilidades comunes (
Result,PaginationOptions,Brand, etc.)
Componentes principales
- src/container/container.ts: Clase
Containerque gestiona el registro y resolución de dependencias. - src/container/decorators.ts: Decoradores
@injectable()y@inject()para marcar clases y parámetros. - src/container/tokens.ts: Definiciones de
Token,InjectionTokenytokenKey()para identificar dependencias. - src/bootstrap/app.ts: Función
bootstrap()que orquesta el arranque de la aplicación. - src/docs/doc-generator.ts: Clase
DocGeneratorpara generar documentación en Markdown y OpenAPI. - src/exceptions/http.ts: Jerarquía de excepciones HTTP (
BadRequestException,UnauthorizedException, etc.). - src/module/module.ts: Decorador
@module()para definir módulos y sus dependencias. - src/plugins/registry.ts:
PluginRegistrypara gestionar plugins con dependencias y ciclo de vida. - src/types/common.ts: Tipos compartidos como
Result,PaginationOptions,Brand, etc. - src/index.ts: Punto de exportación que reúne todos los componentes del núcleo.
Uso básico
import { Container, token, injectable, inject } from '@jamx-framework/core';
// Definir tokens
const DB_TOKEN = token<Database>('Database');
// Clase inyectable
@injectable()
class Database {
constructor(@inject(DB_TOKEN) private driver: DatabaseDriver) {}
}
// Registrar en el contenedor global
Container.registerClass(Database);
// Resolver dependencias
const db = Container.resolve(Database);Registro de servicios
// Registrar una clase como singleton
Container.registerClass(UserRepository);
// Registrar un valor directo
const CONFIG_TOKEN = token<Config>('Config');
Container.register(COFIG_TOKEN, { useValue: myConfig });
// Registrar una fábrica
Container.registerClass(Logger, [Database], 'singleton');Inyección de dependencias
@injectable()
class UsersService {
constructor(@inject(UserRepository) private repo: UserRepository) {}
async findAll() {
return this.repo.findAll();
}
}
// Al resolver UsersService, el contenedor inyecta automáticamente UserRepository
const service = Container.resolve(UsersService);Módulos
@module({
imports: [DatabaseModule],
providers: [UsersService],
controllers: [UsersController],
exports: [UsersService],
})
class UsersModule {}Bootstrap
import { bootstrap } from '@jamx-framework/core';
const app = await bootstrap({
root: process.cwd(),
hooks: {
afterStart: ({ baseUrl }) => console.log(`Server ready at ${baseUrl}`),
},
});
app.stop(); // Graceful shutdownEjemplos
Registro y resolución con scopes
// Singleton (por defecto)
Container.registerClass(UserService);
// Transient (nueva instancia cada resolución)
Container.register(UserService, { scope: 'transient' });
// Scoped (una instancia por scope)
const scopeId = Container.beginScope();
const instance1 = Container.resolve(UserService, scopeId);
const instance2 = Container.resolve(UserService, scopeId);
expect(instance1).toBe(instance2);
Container.endScope(scopeId);Uso de decoradores
// Clase inyectable con dependencias
@injectable()
class AuthService {
constructor(@inject(PasswordHasher) private hasher: PasswordHasher) {}
}
// Parámetro inyectable
class LoginController {
constructor(@inject(AuthService) private auth: AuthService) {}
async login(email: string, password: string) {
const hashed = await this.auth.hasher.verify(password, storedHash);
if (!hashed) throw new UnauthorizedException('Invalid credentials');
return { token: await this.auth.createToken({ email }) };
}
}Bootstrap con hooks
import { bootstrap } from '@jamx-framework/core';
await bootstrap({
silent: false,
hooks: {
beforeConfig: () => console.log('Cargando configuración...'),
afterConfig: (config) => console.log(`Modo: ${config.env}`),
afterStart: ({ baseUrl }) => console.log(`🚀 Servidor escuchando en ${baseUrl}`),
onShutdown: async () => {
await someCleanupTask();
console.log('🔌 Conexiones cerradas');
},
},
});Flujo interno
- Inicialización del Container: Se crea una instancia global de
Container. - Registro de dependencias: Los módulos y decoradores registran providers (
ClassProvider,ValueProvider,FactoryProvider). - Resolución: Cuando se llama a
Container.resolve(), se crea la instancia resolviendo dependencias recursivamente. - Manejo de scopes: Los scopes permiten instancias aisladas para requests HTTP o transacciones.
- Detección de ciclos: Se lanza
CircularDependencyErrorsi se detecta un ciclo de dependencias. - Bootstrap: La función
bootstrap()carga configuración, inicializa módulos y arranca servidores mediante hooks. - Plugins:
PluginRegistrygestiona plugins con dependencias y permite ordenar su ejecución mediante topological sort. - Documentación:
DocGeneratorpuede generar documentación a partir de endpoints registrados.
Plugin Development
Para crear un plugin personalizado:
- Implementa una clase que exponga
meta(nombre, dependencias) y métodossetup(ctx)yteardown?(ctx). - Regístralo en
PluginRegistry. - Asegúrate de que
setup()reciba el contexto adecuado (por ejemplo,Container).
Ejemplo mínimo:
import type { Plugin, PluginContext } from '@jamx-framework/core';
export class LoggingPlugin implements Plugin<PluginContext> {
meta = { name: 'logging' };
async setup(ctx: PluginContext) {
console.log('[Plugin] Logging initialized');
}
}
// Registro
Container.registerPlugin(LoggingPlugin);Testing
El proyecto incluye tests unitarios en packages/core/tests/unit/. Para ejecutarlos:
pnpm test
# o
npm run testLos tests cubren:
- Registro y resolución de dependencias
- Manejo de scopes y ciclos
- Decoradores
@injectable()y@inject() - Funcionalidad de
bootstrap()con hooks - Integración con
PluginRegistry
Compatibility
- Compatible con Node.js 18+ y TypeScript 5.x
- Funciona en Windows, macOS y Linux
- No tiene dependencias de runtime; solo devDependencies para testing
- Diseñado para ser usado como base de cualquier aplicación JAMX
Configuration Options
El núcleo no requiere configuración explícita. Sin embargo, puedes personalizar el comportamiento mediante:
- Hooks en bootstrap: Personaliza el ciclo de vida de la aplicación.
- Middlewares: Añade lógica antes/durante/después de los handlers.
- Transformación de tokens: Modifica cómo se identifican las dependencias.
CLI Integration
Este paquete se integra automáticamente con el CLI de JAMX:
jamx build: Compila el código fuente adist/.jamx dev: Inicia un entorno de desarrollo que simula el bootstrap.jamx check: Verifica que el proyecto tenga la configuración mínima (jamx.config.ts).
License
MIT © Stiven-21
This core package provides the foundational building blocks for building modular, type-safe applications with JAMX Framework, enabling developers to manage dependencies cleanly, extend functionality through plugins, and bootstrap applications with a consistent lifecycle.
