Overview

The events-default plugin provides an in-memory event bus that routes messages between service plugins. All BSB implementations support the same event patterns.

Note: This plugin only works within a single process. For distributed deployments, use events-rabbitmq, events-kafka, or another distributed events plugin.

Event Patterns

BSB defines four standard event patterns that work consistently across all implementations:

Fire-and-Forget

Send event to first listener, don't wait for response

Request-Response

Send event, wait for and return response

Broadcast

Send event to ALL registered listeners

Streaming

Bidirectional streaming between services

Events Interface

  • emitEvent / onEvent - Fire-and-forget
  • emitEventAndReturn / onReturnableEvent - Request-response
  • emitBroadcast / onBroadcast - Broadcast to all
  • emitStreamAndReceiveStream / onReceiveStreamAndStream - Streaming

Usage

Fire-and-Forget

Send an event to the first registered listener. The sender doesn't wait for a response.

// Sender - emits and continues immediately
await this.events.emitEvent("order.created", {
  orderId: "12345",
  items: [{ sku: "ABC", qty: 2 }]
});

// Listener - handles the event
await this.events.onEvent(
  "order.created",
  async (data) => {
    await processOrder(data.orderId, data.items);
  }
);

Request-Response

Send an event and wait for a response from the handler.

// Sender - waits for response
const result = await this.events.emitEventAndReturn(
  "user.validate",
  { email: "user@example.com" },
  5000  // timeout in milliseconds
);
console.log(result.valid); // true or false

// Handler - returns response
await this.events.onReturnableEvent(
  "user.validate",
  async (data) => {
    const isValid = await checkEmail(data.email);
    return { valid: isValid };
  }
);

Broadcast

Send an event to ALL registered listeners.

// Sender - broadcasts to all listeners
await this.events.emitBroadcast("cache.invalidate", {
  keys: ["user:123", "session:abc"]
});

// Listeners - all instances receive the event
await this.events.onBroadcast(
  "cache.invalidate",
  async (data) => {
    for (const key of data.keys) {
      await localCache.delete(key);
    }
  }
);

Type-Safe Events with Zod

Define event schemas for compile-time and runtime type safety:

import { z } from "zod";

// Define event schemas
const OrderCreatedSchema = z.object({
  orderId: z.string(),
  userId: z.string(),
  items: z.array(z.object({
    sku: z.string(),
    quantity: z.number()
  }))
});

const OrderResultSchema = z.object({
  success: z.boolean(),
  orderId: z.string()
});

// Type-safe event handling
await this.events.onReturnableEvent(
  "order.create",
  OrderCreatedSchema,   // input validation
  OrderResultSchema,    // output validation
  async (data) => {
    // data is fully typed as z.infer<typeof OrderCreatedSchema>
    return {
      success: true,
      orderId: data.orderId
    };
  }
);

Go implementation coming soon.

Rust implementation coming soon.

Python implementation coming soon.

When to Replace

Replace events-default when you need:

  • Multiple containers or processes to communicate
  • Message persistence and delivery guarantees
  • Dead letter queues and retry logic
  • Event replay capabilities