@454creative/easy-events
v2.0.17
Published
A minimal event engine for Node.js and NestJS, wrapping Emmett for lightweight in-process event handling
Readme
@454creative/easy-events
A lightweight, in-process event engine for Node.js and NestJS applications. Built on top of Emmett with optional observability and storage capabilities.
🚀 Quick Start
Basic Usage (Zero Configuration)
import { Events } from '@454creative/easy-events';
// Emit events
Events.emit('user.created', { id: 1, name: 'John' });
// Handle events
Events.on('user.created', (payload) => {
console.log('User created:', payload);
});
// Handle events once (auto-removes after execution)
Events.once('app.initialized', (payload) => {
console.log('App initialized:', payload);
});
// Remove specific handler
const handler = (payload) => console.log(payload);
Events.on('user.updated', handler);
Events.off('user.updated', handler);
// Check if event has listeners
if (Events.hasListeners('user.created')) {
console.log('User creation is being monitored');
}
// Get listener count
const count = Events.listeners('user.created');
console.log(`${count} handlers listening to user.created`);
// Remove all listeners for an event
Events.removeAllListeners('user.created');
// Clear all listeners
Events.clear();With Observability (Optional)
import { Events, DefaultObservabilityEngine } from '@454creative/easy-events';
// Configure observability
const observability = new DefaultObservabilityEngine({
enableMetrics: true,
enableAuditing: true,
logLevel: 'info'
});
Events.setObservability(observability);
// Your events now include metrics and audit logs
Events.emit('user.created', { id: 1 });
// Get metrics
const metrics = observability.getMetrics();
console.log('Total events:', metrics.totalEvents);
// Get audit logs
const logs = observability.getAuditLogs();
console.log('Recent events:', logs);📚 Documentation
Getting Started
- Quick Start Guide - Complete setup and examples
- API Reference - Complete method documentation and examples
- Migration Guide 1.x → 2.x - Breaking changes and migration steps
- Architecture Guide 2.0 - New modular architecture overview
- Observability Guide - Metrics, auditing, and monitoring
- Observability Examples - Working observability examples
- Logging Examples - Custom logging and Winston integration
Best Practices & Architecture
- Event-Driven Best Practices - Architecture patterns and guidelines
- Cost-Effective Message Brokers - Migration from in-process to distributed events
Publishing & Deployment
- Publishing Guide - How to publish to npm registry
🏗️ Architecture Overview
Easy-Events 2.0 features a modular architecture with clear separation of concerns:
Core Components
// 1. Core Event Engine (Required)
import { Events, EmmettEngine } from '@454creative/easy-events';
// 2. Observability Engine (Optional)
import { DefaultObservabilityEngine } from '@454creative/easy-events';
// 3. Storage Engine (Optional)
import { MemoryStorageEngine, FileStorageEngine } from '@454creative/events';
// 4. Event Sourcing (Optional - Phase 3)
import { EmmettEngine } from '@454creative/easy-events';
// Event sourcing features are automatically available with storage
// 5. Distributed Events (Optional - Phase 4)
import { createDistributedEventEngine } from '@454creative/easy-events';Usage Patterns
Pattern 1: Simple Event Handling
import { Events } from '@454creative/easy-events';
// Lightweight, no overhead
Events.emit('order.placed', { orderId: '123' });
Events.on('order.placed', (order) => {
// Process order
});Pattern 2: With Observability
import { Events, DefaultObservabilityEngine } from '@454creative/easy-events';
const observability = new DefaultObservabilityEngine();
Events.setObservability(observability);
// Events are automatically tracked
Events.emit('payment.processed', { amount: 100 });Pattern 3: With Custom Storage
import { Events, DefaultObservabilityEngine, FileStorageEngine } from '@454creative/easy-events';
const storage = new FileStorageEngine({ path: './logs' });
const observability = new DefaultObservabilityEngine({ storage });
Events.setObservability(observability);Pattern 4: NestJS Integration (2.0)
// For basic usage (recommended)
import { EasyEventsProvider } from '@454creative/easy-events';
@Module({
providers: [EasyEventsProvider],
exports: [EasyEventsProvider],
})
export class EventsModule {}
// In your service
@Injectable()
export class UserService {
constructor(@Inject('EVENTS') private readonly events) {}
createUser() {
this.events.emit('user.created', { id: 1 });
}
}Pattern 5: Event Sourcing (Phase 3)
import { EmmettEngine } from '@454creative/easy-events';
import { createStorageEngine } from '@454creative/easy-events';
const storage = createStorageEngine({ type: 'file', path: './events' });
const engine = new EmmettEngine(undefined, storage);
// Events are automatically persisted with full event sourcing
await engine.emit('user.created', { userId: '123' });
// Replay events from storage
const events = await engine.replayEvents();Pattern 6: Distributed Events (Phase 4)
import { createDistributedEventEngine } from '@454creative/easy-events';
const engine = createDistributedEventEngine(undefined, {
mode: 'hybrid',
instanceId: 'app-1',
clusterName: 'production-cluster'
});
// Events can be local or distributed based on routing rules
await engine.emitWithRouting('user.created', { userId: '123' }, 'distributed');📖 See NestJS Integration Guide for detailed setup and error handling.
📦 Installation
For Development (Local Path)
{
"dependencies": {
"@454creative/easy-events": "file:../path/to/easy-events"
}
}For Production (npm Registry)
npm install @454creative/easy-events🎯 Key Features
✅ Zero Configuration Required
- Works out of the box with minimal setup
- Optional observability and storage
- Lightweight bundle size
✅ Flexible Architecture
- In-process event handling for local development
- Easy migration to distributed message brokers
- Custom storage and observability engines
✅ Developer Experience
- TypeScript support
- Comprehensive examples
- Clear documentation
- NestJS integration ready
✅ Production Ready
- Error handling and recovery
- Performance monitoring
- Audit logging
- Custom logging support
✅ Complete Event Emitter API
- Full Node.js EventEmitter compatibility
- Memory leak prevention with
once()handlers - Comprehensive listener management
- Debugging and monitoring tools
🚀 New in 2.0
✅ Event Sourcing (Phase 3)
- Event Versioning: Schema evolution and migration support
- Event Snapshots: Optimized replay with snapshot strategies
- Enhanced Replay: Advanced filtering and transformation
- Event Persistence: Automatic event storage and retrieval
✅ Distributed Events (Phase 4)
- Hybrid Mode: Seamless local/distributed event handling
- Event Distribution: Cross-instance event emission
- Instance Discovery: Multiple discovery mechanisms
- Conflict Resolution: Multiple resolution strategies
- Cluster Management: Multi-instance cluster support
✅ Modular Architecture
- Clean Separation: Clear module boundaries and dependencies
- Optional Dependencies: Feature flags for external packages
- Factory Functions: Pre-configured engines and presets
- Performance Optimized: Minimal overhead, maximum flexibility
🔧 Configuration Options
Observability Configuration
const observability = new DefaultObservabilityEngine({
enableMetrics: true, // Track event metrics
enableAuditing: true, // Log all events
enableTracing: true, // Include correlation IDs
enablePerformanceMonitoring: true, // Track processing times
logLevel: 'info', // 'debug' | 'info' | 'warn' | 'error'
auditRetentionDays: 30, // How long to keep audit logs
metricsRetentionDays: 7, // How long to keep metrics
customAuditLogger: (audit) => {
// Custom audit logging
}
});Storage Configuration
const storage = new FileStorageEngine({
type: 'file',
path: './logs', // Where to store logs
maxLogs: 10000, // Maximum logs to keep
retentionDays: 30 // How long to keep logs
});📋 Complete API Reference
Core Event Methods
emit<T>(event: string, payload: T, tracing?: EventTracing): void
Emit an event with optional tracing information.
Events.emit('user.created', { id: 1, name: 'John' });
Events.emit('payment.processed', { amount: 100 }, {
traceId: 'trace-123',
userId: 'user-456'
});on<T>(event: string, handler: (payload: T) => void): void
Register a handler for an event. Handlers persist until manually removed.
Events.on('user.created', (user) => {
console.log('User created:', user);
});once<T>(event: string, handler: (payload: T) => void): void
Register a handler that executes only once and automatically removes itself. Perfect for one-time events.
Events.once('app.initialized', (config) => {
console.log('App initialized with config:', config);
});
Events.once('database.connected', () => {
console.log('Database connection established');
});off(event?: string, handler?: (payload: any) => void): void
Remove event handlers. Supports multiple removal patterns.
// Remove specific handler for specific event
const handler = (user) => console.log(user);
Events.on('user.created', handler);
Events.off('user.created', handler);
// Remove all handlers for specific event
Events.off('user.created');
// Remove specific handler from all events
Events.off(undefined, handler);
// Remove all handlers from all events
Events.off();Listener Management
listeners(event: string): number
Get the number of listeners for a specific event.
const count = Events.listeners('user.created');
console.log(`${count} handlers listening to user.created`);listenerCount(event: string): number
Alias for listeners(event) - follows Node.js EventEmitter naming.
const count = Events.listenerCount('user.created');hasListeners(event: string): boolean
Check if an event has any listeners.
if (Events.hasListeners('user.created')) {
console.log('User creation is being monitored');
}eventNames(): string[]
Get an array of all registered event names.
const events = Events.eventNames();
console.log('Active events:', events);
// Output: ['user.created', 'payment.processed', 'app.initialized']Bulk Operations
removeAllListeners(event?: string): void
Remove all listeners for a specific event (or all events if no event specified).
// Remove all handlers for specific event
Events.removeAllListeners('user.created');
// Remove all handlers from all events
Events.removeAllListeners();clear(): void
Remove all listeners from all events. Shorter alias for removeAllListeners().
Events.clear(); // Removes all listenersAdvanced Features
prependListener<T>(event: string, handler: (payload: T) => void): void
Add a listener to the beginning of the listeners array (executes first). Note: Emmett doesn't support true prepend, so this acts like on().
Events.prependListener('user.created', (user) => {
console.log('First handler to execute');
});rawListeners(event: string): Function[]
Get the raw listener functions (including wrapper functions used internally).
const rawListeners = Events.rawListeners('user.created');
console.log('Raw listener functions:', rawListeners);Memory Management
setMaxListeners(n: number): void
Set maximum number of listeners per event. Warns when exceeded.
Events.setMaxListeners(5); // Allow max 5 listeners per eventgetMaxListeners(): number
Get the current maximum listeners setting.
const max = Events.getMaxListeners();
console.log(`Max listeners per event: ${max}`);Observability Methods
setObservability(observability: ObservabilityEngine): void
Set the observability engine for metrics and audit logging.
const observability = new DefaultObservabilityEngine();
Events.setObservability(observability);getObservability(): ObservabilityEngine | undefined
Get the current observability engine.
const obs = Events.getObservability();
if (obs) {
const metrics = obs.getMetrics();
}🚀 Examples
Run All Examples
# Basic observability
npx ts-node examples/basic-observability-example.ts
# Simple observability
npx ts-node examples/simple-observability-example.ts
# Full observability
npx ts-node examples/observability-example.ts
# Custom logging
npx ts-node examples/custom-logging-example.ts
# Winston integration
npx ts-node examples/winston-integration-example.ts
# Storage examples
npx ts-node examples/storage-example.ts
npx ts-node examples/simple-storage-demo.ts
# Email examples
npx ts-node examples/nestjs-email-example/src/simple-app.ts
npx ts-node examples/nestjs-email-example/src/easy-events-demo.ts
npx ts-node examples/nestjs-email-example/src/email-with-observability.ts📊 Observability Features
Metrics
- Total events processed
- Events by type
- Average processing time
- Error count
- Active handlers
Audit Logging
- Event ID and type
- Timestamp and payload
- Correlation ID
- User ID and source
- Processing time
- Success/error status
Tracing
- Correlation IDs for request tracking
- User context
- Source identification
- Performance monitoring
🔄 Migration Path
Development → Production
- Start Simple: Use in-process events for local development
- Add Observability: Enable metrics and audit logging
- Add Storage: Persist logs to file or database
- Scale Up: Migrate to distributed message brokers (Kafka, Redis, etc.)
🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
📄 License
MIT License - see LICENSE for details.
🆘 Support
- Documentation: docs/
- Examples: examples/
- Issues: Bitbucket Issues
Built with ❤️ by 454 Creative
