npm package: @jamx-framework/events
Description: JAMX Framework â€” Typed event bus
Author: Stiven-21
Latest version: 1.0.0

# @jamx-framework/events

## Descripción
Sistema de eventos (Event Bus) para JAMX Framework. Proporciona un mecanismo de comunicación desacoplada entre componentes de la aplicación mediante publicación/suscripción (pub/sub). Permite que diferentes partes de la aplicación se comuniquen sin tener dependencias directas, ideal para arquitecturas modulares y microservicios.

## Cómo funciona
El `EventBus` implementa el patrón pub/sub:

1. **Registro de listeners**: Los componentes se suscriben a eventos específicos con un callback.
2. **Emisión de eventos**: Cualquier componente puede publicar un evento en el bus.
3. **Distribución**: El bus invoca todos los listeners registrados para ese tipo de evento.
4. **Filtrado**: Soporta filtros por tipo de evento y datos adicionales.
5. **Async por defecto**: Los listeners pueden ser síncronos o asíncronos (retornan Promise).

## Componentes principales
- **src/event-bus.ts**: Clase `EventBus` que gestiona suscripciones y emisión
- **src/index.ts**: Punto de exportación

## Uso básico
```typescript
import { EventBus } from '@jamx-framework/events';

// Crear instancia global
const bus = new EventBus();

// Suscribirse a un evento
bus.on('user.created', (data) => {
  console.log('Usuario creado:', data.userId);
});

// Suscribirse una sola vez
bus.once('order.completed', (data) => {
  console.log('Orden completada:', data.orderId);
});

// Emitir evento
bus.emit('user.created', { userId: 123, email: 'user@example.com' });

// Emitir evento async
await bus.emitAsync('order.processing', { orderId: 456 });
```

## Ejemplos
### Comunicación entre módulos
```typescript
// En módulo de usuarios
bus.emit('user.registered', { userId: 1, email: 'juan@example.com' });

// En módulo de notificaciones
bus.on('user.registered', async (data) => {
  await mailer.sendWelcomeEmail(data.email);
});

// En módulo de analytics
bus.on('user.registered', (data) => {
  analytics.track('signup', { userId: data.userId });
});
```

### Eventos con datos estructurados
```typescript
// Definir tipo para evento
interface UserCreatedEvent {
  userId: number;
  email: string;
  timestamp: Date;
}

// Emitir con tipo
bus.emit<UserCreatedEvent>('user.created', {
  userId: 1,
  email: 'juan@example.com',
  timestamp: new Date(),
});

// Escuchar con tipo
bus.on('user.created', (event) => {
  console.log(`Usuario ${event.userId} registrado a las ${event.timestamp}`);
});
```

### Manejo de errores en listeners
```typescript
bus.on('payment.processed', async (data) => {
  try {
    await processPayment(data);
  } catch (error) {
    console.error('Error procesando pago:', error);
    // Opcional: emitir evento de error
    bus.emit('payment.error', { orderId: data.orderId, error });
  }
});
```

### Remover listeners
```typescript
// Suscribirse y guardar referencia
const handler = (data) => console.log(data);
bus.on('user.updated', handler);

// Remover listener específico
bus.off('user.updated', handler);

// Remover todos los listeners de un evento
bus.off('user.updated');

// Remover todos los listeners de todos los eventos
bus.removeAllListeners();
```

### Eventos con prioridad
```typescript
// Añadir listener con prioridad (menor número = mayor prioridad)
bus.on('critical.event', (data) => {
  // Se ejecuta primero
}, { priority: 1 });

bus.on('critical.event', (data) => {
  // Se ejecuta después
}, { priority: 10 });
```

### Eventos con wildcard
```typescript
// Suscribirse a todos los eventos de usuarios
bus.on('user.*', (eventName, data) => {
  console.log(`Evento de usuario: ${eventName}`, data);
});

// Suscribirse a eventos de una jerarquía
bus.on('order.**', (eventName, data) => {
  // Captura order.created, order.updated, order.cancelled, etc.
});
```

## Flujo interno
1. **Registro**: `on(event, callback, options?)` añade el callback a un array de listeners para ese evento.
2. **Emisión**: `emit(event, data)` recorre todos los listeners del evento y los ejecuta en orden de registro (o prioridad).
3. **Async**: Si un listener retorna una Promise, se espera a que se resuelva (en `emitAsync`).
4. **Filtrado**: Antes de ejecutar, se pueden aplicar filtros por tipo de evento o datos.
5. **Error handling**: Los errores en listeners no detienen la ejecución de otros listeners (se capturan y se emiten opcionalmente en `error` event).
6. **Memory management**: `off()` y `removeAllListeners()` permiten limpiar listeners para evitar memory leaks.

## API Reference (Resumen)
### EventBus
- `on(event: string, callback: Function, options?: ListenerOptions): () => void`
- `once(event: string, callback: Function, options?: ListenerOptions): () => void`
- `off(event: string, callback?: Function): void`
- `emit(event: string, data?: any): void`
- `emitAsync(event: string, data?: any): Promise<void>`
- `removeAllListeners(event?: string): void`
- `listenerCount(event: string): number`
- `eventNames(): string[]`

### ListenerOptions
- `priority?: number` — Orden de ejecución (default: 0)
- `once?: boolean` — Se ejecuta solo una vez (alternativa a `once()`)
- `async?: boolean` — Si se debe esperar a que termine (default: true)

## Performance Considerations
- **Listener lookup**: Los listeners se almacenan en un Map por evento, O(1) para búsqueda.
- **Async execution**: `emitAsync` espera todos los listeners; `emit` no espera.
- **Wildcard matching**: Los wildcards (`*`, `**`) se evalúan con regex y pueden ser costosos con muchos listeners.
- **Memory leaks**: Los listeners deben removerse explícitamente cuando el componente se destruye.

## Testing
Tests en `packages/events/tests/unit/event-bus.test.ts`:

```bash
pnpm test
```

Cubre:
- Registro y desregistración de listeners
- Emisión síncrona y asíncrona
- Eventos con wildcard
- Prioridades de listeners
- Manejo de errores
- Conteo de listeners

## Compatibility
- Compatible con Node.js 18+
- Funciona en navegadores (si se polyfill)
- No requiere dependencias externas
- Type-safe con genéricos

## Use Cases
- **Comunicación entre módulos**: Desacoplar módulos que necesitan comunicarse
- **Eventos de dominio**: UserCreated, OrderCompleted, PaymentProcessed
- **Hooks del sistema**: beforeStart, afterInit, onShutdown
- **Logging y auditoría**: Capturar eventos para registro
- **Reacción a cambios**: Actualizar UI cuando cambian datos

## Best Practices
1. **Usar nombres de evento consistentes**: `module.action` (ej: `user.created`, `order.updated`)
2. **Estructurar datos de eventos**: Objetos con campos claros y tipados
3. **Limpiar listeners**: En componentes con ciclo de vida, remover listeners al destruir
4. **No abusar**: Para comunicación directa entre clases cercanas, usa inyección de dependencias
5. **Documentar eventos**: Mantener un registro de eventos que emite cada módulo

This event bus provides a lightweight, type-safe pub/sub system for JAMX applications, enabling loose coupling and reactive architectures with minimal overhead.