mayr_events 2.0.0 copy "mayr_events: ^2.0.0" to clipboard
mayr_events: ^2.0.0 copied to clipboard

A lightweight, expressive event and listener system for Dart, inspired by Laravel's event architecture.

License Platform

Pub Version Pub.dev Score Pub Likes

mayr_events #

A lightweight, expressive event and listener system for Dart β€” inspired by Laravel's event architecture.

Mayr Events helps you decouple logic in your app using an elegant, easy-to-read syntax while supporting async listeners, isolates, middleware hooks, and more.


πŸš€ Features #

  • βœ… Simple functional API - no class extension needed
  • βœ… Event-level hooks (beforeHandle, shouldHandle, onError)
  • βœ… Global keyed handlers for cross-cutting concerns
  • βœ… Async listeners with isolate support
  • βœ… Queued listeners with retry and timeout support
  • βœ… Once-only listeners
  • βœ… Pure Dart - works everywhere

🧩 Installation #

Add to your pubspec.yaml:

dependencies:
  mayr_events: ^2.0.0

Then import:

import 'package:mayr_events/mayr_events.dart';

πŸ’‘ New to mayr_events? Check out the Quick Start Guide for a 5-minute tutorial!


βš™οΈ Setup #

Create a function to register your listeners and handlers:

void setupEvents() {
  // Register listeners
  MayrEvents.on<UserRegisteredEvent>(SendWelcomeEmailListener());
  MayrEvents.on<OrderPlacedEvent>(ProcessOrderListener());

  // Add global handlers
  MayrEvents.beforeHandle('logger', (event, listener) async {
    print('Handling ${event.runtimeType}');
  });

  MayrEvents.onError('error_logger', (event, error, stack) async {
    print('Error: $error');
  });

  MayrEvents.shouldHandle('validator', (event) {
    // Return false to prevent listener execution
    return true;
  });
}

Call this function before firing any events (typically in main()):

void main() {
  setupEvents();
  runApp(MyApp());
}

🧠 Defining Events #

Events are simple data classes extending MayrEvent:

class UserRegisteredEvent extends MayrEvent {
  final String userId;
  final String email;

  const UserRegisteredEvent(this.userId, this.email);
}

Event-Level Hooks #

Events can define their own hooks:

class UserRegisteredEvent extends MayrEvent {
  final String userId;
  final String email;

  const UserRegisteredEvent(this.userId, this.email);

  @override
  Future<void> Function(MayrEvent, MayrListener)? get beforeHandle =>
      (event, listener) async {
        print('About to handle user registration');
      };

  @override
  bool Function(MayrEvent)? get shouldHandle =>
      (event) => (event as UserRegisteredEvent).userId.isNotEmpty;

  @override
  Future<void> Function(MayrEvent, Object, StackTrace)? get onError =>
      (event, error, stack) async {
        print('Registration failed: $error');
      };
}

πŸ‘‚ Defining Listeners #

Listeners handle events:

class SendWelcomeEmailListener extends MayrListener<UserRegisteredEvent> {
  @override
  Future<void> handle(UserRegisteredEvent event) async {
    await EmailService.sendWelcome(event.userId);
    print('Welcome email sent to ${event.email}');
  }
}

Once-Only Listeners #

class TrackAppLaunchListener extends MayrListener<AppLaunchedEvent> {
  @override
  bool get once => true;

  @override
  Future<void> handle(AppLaunchedEvent event) async {
    print('This listener runs only once.');
  }
}

πŸš€ Firing Events #

Anywhere in your app:

await MayrEvents.fire(UserRegisteredEvent('U123', 'user@example.com'));

πŸ”§ Advanced Features #

Global Handlers with Keys #

Register multiple handlers using unique keys:

// Add handlers
MayrEvents.beforeHandle('logger', loggerCallback);
MayrEvents.beforeHandle('metrics', metricsCallback);
MayrEvents.onError('sentry', sentryCallback);
MayrEvents.shouldHandle('rate_limiter', rateLimitCallback);

// Remove specific handlers
MayrEvents.removeBeforeHandler('logger');
MayrEvents.removeErrorHandler('sentry');
MayrEvents.removeShouldHandle('rate_limiter');

Listener Management #

// Remove specific listener
final listener = SendWelcomeEmailListener();
MayrEvents.on<UserRegisteredEvent>(listener);
MayrEvents.remove<UserRegisteredEvent>(listener);

// Remove all listeners for an event
MayrEvents.removeAll<UserRegisteredEvent>();

// Clear everything
MayrEvents.clear();

// Check listeners
bool hasListeners = MayrEvents.hasListeners<UserRegisteredEvent>();
int count = MayrEvents.listenerCount<UserRegisteredEvent>();

Run Listeners in Isolates #

For CPU-intensive operations:

class HeavyProcessingListener extends MayrListener<DataEvent> {
  @override
  bool get runInIsolate => true;

  @override
  Future<void> handle(DataEvent event) async {
    // CPU-intensive work runs in separate isolate
  }
}

Queued Listeners #

Queue listeners for background processing with automatic retry and timeout support:

void setupEvents() {
  // Setup queue system first
  MayrEvents.setupQueue(
    fallbackQueue: 'default',
    queues: ['emails', 'notifications', 'orders'],
    defaultTimeout: Duration(seconds: 60),
  );

  // Register queued listeners
  MayrEvents.on<OrderPlacedEvent>(ProcessOrderListener());
}

class ProcessOrderListener extends MayrListener<OrderPlacedEvent> {
  @override
  bool get queued => true;  // Enable queuing

  @override
  String get queue => 'orders';  // Specify queue name

  @override
  Duration get timeout => Duration(seconds: 60);  // Job timeout

  @override
  int get retries => 5;  // Max retries (capped at 30)

  @override
  Future<void> handle(OrderPlacedEvent event) async {
    // This runs asynchronously in the background
    await processOrder(event.orderId);
  }
}

Queue Features:

  • Multiple named queues for organizing different types of jobs
  • Automatic fallback queue for undefined queue names
  • Configurable timeout per listener
  • Automatic retry with configurable retry count (max 30)
  • Queue workers auto-cleanup when empty
  • Mix queued and non-queued listeners for the same event

πŸ“š Complete Example #

import 'package:mayr_events/mayr_events.dart';

// Define event
class OrderPlacedEvent extends MayrEvent {
  final String orderId;
  final double total;
  const OrderPlacedEvent(this.orderId, this.total);
}

// Define listener
class ProcessOrderListener extends MayrListener<OrderPlacedEvent> {
  @override
  Future<void> handle(OrderPlacedEvent event) async {
    print('Processing order ${event.orderId}');
  }
}

void setupEvents() {
  MayrEvents.on<OrderPlacedEvent>(ProcessOrderListener());
  
  MayrEvents.beforeHandle('logger', (event, listener) async {
    print('[${DateTime.now()}] Event fired');
  });
}

void main() async {
  setupEvents();
  await MayrEvents.fire(OrderPlacedEvent('ORD_123', 99.99));
}

πŸ”„ Migration from v1.x #

See MIGRATION.md for detailed upgrade instructions.

Key Changes in v2.0:

  • No class extension required - use functional API
  • Event-level hooks available
  • Keyed handler system for better control
  • Pure Dart package (no Flutter dependency)

πŸ“– Documentation #


🀝 Contributing #

Contributions are welcome! See CONTRIBUTING.md for guidelines.


πŸ“„ License #

MIT License - see LICENSE for details.


0
likes
160
points
154
downloads

Publisher

verified publishermayrlabs.com

Weekly Downloads

A lightweight, expressive event and listener system for Dart, inspired by Laravel's event architecture.

Homepage
Repository (GitHub)
View/report issues
Contributing

Topics

#event #listener #architecture #dart #pub

Documentation

Documentation
API reference

License

MIT (license)

More

Packages that depend on mayr_events