Event Manager Module (node-yalc/event-manager)
The Event Manager module wraps eventemitter2 to provide a robust, enterprise-grade publish/subscribe (PubSub) mechanism for the Ferrox-Node Framework.
Overview
In microservices or complex monoliths, modules often need to react to changes without being tightly coupled. The Event Manager provides a Global Event Emitter that allows modules to broadcast events (e.g. user.created, order.shipped) and other modules to asynchronously react to them.
Key features provided by this wrapper:
- Wildcard Routing: Listeners can subscribe to namespaces (e.g.,
user.*to catch bothuser.createdanduser.deleted). - Data Masking: Before events are emitted, sensitive payloads (passwords, credit cards) can be stripped or masked to prevent leaks in logs or downstream listeners.
- Promise Tracking: Support for
emitAsync, allowing the emitter to track asynchronous listeners and wait for their completion, which is critical during graceful shutdowns or serverless executions.
Usage Example
1. Setting up Listeners
import { getYalcGlobalEventEmitter } from '@node-yalc/event-manager';
const emitter = getYalcGlobalEventEmitter();
// Listen to a specific event
emitter.on('user.created', (payload) => {
console.log('Welcome email sent to:', payload.email);
});
// Listen to a wildcard event
emitter.on('payment.*', (payload) => {
console.log('Payment event received for amount:', payload.amount);
});
2. Emitting Events
You can use the helper emitEvent which provides advanced capabilities like masking and asynchronous promise tracking.
import { emitEvent, getYalcGlobalEventEmitter } from '@node-yalc/event-manager';
const emitter = getYalcGlobalEventEmitter();
await emitEvent(
emitter,
'user.created',
{ id: 1, email: 'john@example.com', passwordHash: 'SECRET123' },
{
mask: ['passwordHash'], // Will replace passwordHash with '***' before sending to listeners
await: true // Waits for all async listeners to resolve before continuing
}
);
Naming Conventions
The framework exports standard formatters to enforce consistent naming. For example, versionedDomainActionFormatter enforces the schema:
{version}.{domain}.{action}.{lifecycle} -> v1.users.create.onProcess
Using standard formatters prevents typos and ensures scalable event routing.