Event System

Build reactive applications with MoroJS's powerful event system. Decouple components, enable real-time features, and create scalable architectures.

Basic Event Usage

Event Emitting and Listening

typescript

1import { createApp, getEventBus } from '@morojs/moro';
2
3const app = createApp();
4const events = getEventBus();
5
6// Emit events from route handlers
7app.post('/users', {
8  body: z.object({
9    email: z.string().email(),
10    name: z.string()
11  }),
12  handler: async ({ body }) => {
13    const user = await createUser(body);
14    
15    // Emit user creation event
16    await events.emit('user.created', {
17      user,
18      timestamp: new Date().toISOString()
19    });
20    
21    return user;
22  }
23});
24
25// Listen for events
26events.on('user.created', async (data) => {
27  console.log('New user created:', data.user.email);
28  
29  // Send welcome email
30  await sendWelcomeEmail(data.user.email);
31  
32  // Log to analytics
33  await trackUserSignup(data.user);
34});
35
36// One-time event listeners
37events.once('app.started', () => {
38  console.log('Application has started successfully');
39});
40
41// Remove event listeners
42const handler = (data) => console.log('User updated:', data);
43events.on('user.updated', handler);
44events.off('user.updated', handler);

Event System Benefits

  • • Decoupled component architecture
  • • Asynchronous processing capabilities
  • • Real-time feature support
  • • Module isolation and communication
  • • Scalable reactive patterns

Advanced Event Patterns

Event Decorators and Handlers

typescript

1// decorators/events.ts
2import { EventBus } from '@morojs/moro/events';
3
4export function EventHandler() {
5  return function (target: any) {
6    // Register class as event handler
7    const eventBus = getEventBus();
8    const instance = new target();
9    
10    // Register event handlers functionally
11    const methods = Object.getOwnPropertyNames(target.prototype);
12    methods.forEach(methodName => {
13      const method = target.prototype[methodName];
14      if (method.eventName) {
15        eventBus.on(method.eventName, method.bind(instance));
16      }
17    });
18    
19    return target;
20  };
21}
22
23export function OnEvent(eventName: string) {
24  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
25    descriptor.value.eventName = eventName;
26    return descriptor;
27  };
28}
29
30// Functional Event Handling
31export function createUserEventHandlers(services: any) {
32  return {
33    async handleUserCreated(data: { user: User }) {
34      console.log('Handling user creation:', data.user.id);
35      
36      // Send welcome email
37      if (services.emailService) {
38        await services.emailService.sendWelcomeEmail(data.user);
39      }
40      
41      // Create user profile
42      if (services.profileService) {
43        await services.profileService.createUserProfile(data.user);
44      }
45      
46      // Track analytics
47      if (services.analyticsService) {
48        await services.analyticsService.trackSignup(data.user);
49      }
50    },
51    
52    async handleUserUpdated(data: { user: User, changes: Partial<User> }) {
53      console.log('User updated:', data.user.id, data.changes);
54      
55      // Invalidate cache
56      if (services.cacheService) {
57        await services.cacheService.invalidateUserCache(data.user.id);
58      }
59      
60      // Notify connected clients
61      if (services.notificationService) {
62        await services.notificationService.notifyUserUpdate(data.user);
63      }
64    },
65    
66    async handleUserDeleted(data: { userId: string }) {
67      console.log('User deleted:', data.userId);
68      
69      // Clean up user data
70      if (services.cleanupService) {
71        await services.cleanupService.cleanupUserData(data.userId);
72      }
73      
74      // Archive user information
75      if (services.archiveService) {
76        await services.archiveService.archiveUser(data.userId);
77      }
78    }
79  };
80}
81  
82  private async sendWelcomeEmail(user: User) {
83    // Email service integration
84  }
85  
86  private async createUserProfile(user: User) {
87    // Profile creation logic
88  }
89  
90  private async trackSignup(user: User) {
91    // Analytics tracking
92  }
93}

Event Middleware & Processing

Event Processing Pipeline

typescript

1// Event middleware for processing
2const eventMiddleware = {
3  // Logging middleware
4  logging: (eventName: string, data: any, next: Function) => {
5    console.log(`Event emitted: ${eventName}`, { data, timestamp: new Date() });
6    next();
7  },
8  
9  // Validation middleware
10  validation: (eventName: string, data: any, next: Function) => {
11    // Validate event data structure
12    if (!data || typeof data !== 'object') {
13      throw new Error(`Invalid event data for ${eventName}`);
14    }
15    next();
16  },
17  
18  // Rate limiting middleware
19  rateLimiting: (eventName: string, data: any, next: Function) => {
20    const key = `event_rate:${eventName}`;
21    const count = getEventCount(key);
22    
23    if (count > 100) { // Max 100 events per minute
24      throw new Error(`Rate limit exceeded for event ${eventName}`);
25    }
26    
27    incrementEventCount(key);
28    next();
29  },
30  
31  // Error handling middleware
32  errorHandling: (eventName: string, data: any, next: Function) => {
33    try {
34      next();
35    } catch (error) {
36      console.error(`Event processing error for ${eventName}:`, error);
37      
38      // Emit error event
39      events.emit('event.error', {
40        originalEvent: eventName,
41        error: error.message,
42        data
43      });
44    }
45  }
46};
47
48// Apply middleware to event bus
49const events = getEventBus();
50events.use(eventMiddleware.logging);
51events.use(eventMiddleware.validation);
52events.use(eventMiddleware.rateLimiting);
53events.use(eventMiddleware.errorHandling);
54
55// Queue-based event processing
56import { Queue } from '@morojs/moro/queue';
57
58const eventQueue = new Queue({
59  name: 'events',
60  concurrency: 5,
61  retries: 3,
62  backoff: 'exponential'
63});
64
65// Process events asynchronously
66events.on('user.created', async (data) => {
67  // Add to queue for async processing
68  await eventQueue.add('process-user-creation', data, {
69    delay: 0,
70    priority: 10
71  });
72});
73
74eventQueue.process('process-user-creation', async (job) => {
75  const { user } = job.data;
76  
77  // Heavy processing that shouldn't block request
78  await generateUserRecommendations(user);
79  await sendWelcomeEmailSequence(user);
80  await createUserAnalyticsProfile(user);
81});

Next Steps