UNPKG

@454creative/easy-events

Version:

A minimal event engine for Node.js and NestJS, wrapping Emmett for lightweight in-process event handling

493 lines (370 loc) • 12.9 kB
# @454creative/easy-events A lightweight, in-process event engine for Node.js and NestJS applications. Built on top of [Emmett](https://github.com/event-driven-io/emmett) with optional observability and storage capabilities. ## šŸš€ Quick Start ### Basic Usage (Zero Configuration) ```ts 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) ```ts 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](docs/quick-start-guide.md)** - Complete setup and examples - **[API Reference](docs/api-reference.md)** - Complete method documentation and examples - **[Migration Guide](docs/migration-guide.md)** - Solving duplicate events and memory leaks - **[Observability Guide](docs/observability-guide.md)** - Metrics, auditing, and monitoring - **[Observability Examples](docs/observability-examples-guide.md)** - Working observability examples - **[Logging Examples](docs/logging-examples-guide.md)** - Custom logging and Winston integration ### Best Practices & Architecture - **[Event-Driven Best Practices](docs/event-driven-best-practices.md)** - Architecture patterns and guidelines - **[Cost-Effective Message Brokers](docs/cost-effective-message-brokers.md)** - Migration from in-process to distributed events ### Publishing & Deployment - **[Publishing Guide](docs/publishing-guide.md)** - How to publish to npm registry ## šŸ—ļø Architecture Overview ### Core Components ```ts // 1. 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/easy-events'; ``` ### Usage Patterns #### Pattern 1: Simple Event Handling ```ts 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 ```ts 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 ```ts 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 (Improved) ```ts // For basic usage (recommended) import { SimpleEasyEventsProvider } from '@454creative/easy-events'; @Module({ providers: [SimpleEasyEventsProvider], exports: [SimpleEasyEventsProvider], }) export class EventsModule {} // For production with observability import { EnhancedEasyEventsProvider } from '@454creative/easy-events'; @Module({ providers: [EnhancedEasyEventsProvider], exports: [EnhancedEasyEventsProvider], }) export class EventsModule {} // In your service @Injectable() export class UserService { constructor(@Inject('SIMPLE_EVENTS') private readonly events) {} createUser() { this.events.emit('user.created', { id: 1 }); } } ``` šŸ“– **See [NestJS Integration Guide](docs/nestjs-integration-guide.md) for detailed setup and error handling.** ## šŸ“¦ Installation ### For Development (Local Path) ```json { "dependencies": { "@454creative/easy-events": "file:../path/to/easy-events" } } ``` ### For Production (npm Registry) ```bash 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 ## šŸ”§ Configuration Options ### Observability Configuration ```ts 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 ```ts 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. ```ts 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. ```ts 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. ```ts 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. ```ts // 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. ```ts 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. ```ts const count = Events.listenerCount('user.created'); ``` #### `hasListeners(event: string): boolean` Check if an event has any listeners. ```ts if (Events.hasListeners('user.created')) { console.log('User creation is being monitored'); } ``` #### `eventNames(): string[]` Get an array of all registered event names. ```ts 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). ```ts // 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()`. ```ts Events.clear(); // Removes all listeners ``` ### Advanced 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()`. ```ts 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). ```ts 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. ```ts Events.setMaxListeners(5); // Allow max 5 listeners per event ``` #### `getMaxListeners(): number` Get the current maximum listeners setting. ```ts 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. ```ts const observability = new DefaultObservabilityEngine(); Events.setObservability(observability); ``` #### `getObservability(): ObservabilityEngine | undefined` Get the current observability engine. ```ts const obs = Events.getObservability(); if (obs) { const metrics = obs.getMetrics(); } ``` ## šŸš€ Examples ### Run All Examples ```bash # 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 1. **Start Simple**: Use in-process events for local development 2. **Add Observability**: Enable metrics and audit logging 3. **Add Storage**: Persist logs to file or database 4. **Scale Up**: Migrate to distributed message brokers (Kafka, Redis, etc.) ## šŸ¤ Contributing 1. Fork the repository 2. Create a feature branch 3. Make your changes 4. Add tests 5. Submit a pull request ## šŸ“„ License MIT License - see [LICENSE](LICENSE) for details. ## šŸ†˜ Support - **Documentation**: [docs/](docs/) - **Examples**: [examples/](examples/) - **Issues**: [Bitbucket Issues](https://bitbucket.org/454creative/easy-events/issues) --- **Built with ā¤ļø by [454 Creative](https://454creative.com)**