bun-server-events

📁 dangaogit/bun-server-skills 📅 9 days ago
1
总安装量
1
周安装量
#53237
全站排名
安装命令
npx skills add https://github.com/dangaogit/bun-server-skills --skill bun-server-events

Agent 安装分布

trae 1
qoder 1
trae-cn 1
cursor 1
claude-code 1

Skill 文档

Bun Server Event System

Setup EventModule

import { Module, EventModule } from "@dangao/bun-server";

// Configure before module definition
EventModule.forRoot({
  wildcard: true,      // Enable wildcard events (user.*)
  maxListeners: 20,    // Max listeners per event
  onError: (error, event, payload) => {
    console.error(`Event error [${event}]:`, error);
  },
});

@Module({
  imports: [EventModule],
})
class AppModule {}

Event Listeners with @OnEvent

import { Injectable, OnEvent } from "@dangao/bun-server";

@Injectable()
class NotificationListener {
  @OnEvent("user.created")
  async handleUserCreated(payload: { userId: string; email: string }) {
    console.log("New user:", payload.userId);
    await this.sendWelcomeEmail(payload.email);
  }

  @OnEvent("user.*") // Wildcard: matches user.created, user.updated, etc.
  handleAllUserEvents(payload: any) {
    console.log("User event received:", payload);
  }

  @OnEvent("order.completed", { async: true })
  async handleOrderCompleted(payload: { orderId: string }) {
    // Async handler - won't block emitter
    await this.processOrder(payload.orderId);
  }
}

Initialize Listeners

Critical: Must call initializeListeners after registerModule:

import { Application, EventModule, ModuleRegistry } from "@dangao/bun-server";

const app = new Application({ port: 3100 });
app.registerModule(AppModule);

// Initialize event listeners
const rootModuleRef = ModuleRegistry.getInstance().getModuleRef(AppModule);
if (rootModuleRef?.container) {
  EventModule.initializeListeners(
    rootModuleRef.container,
    [NotificationListener, AuditListener], // All @OnEvent classes
  );
}

app.listen();

Emit Events

import { Injectable, Inject, EVENT_EMITTER_TOKEN, EventEmitter } from "@dangao/bun-server";

@Injectable()
class UserService {
  constructor(
    @Inject(EVENT_EMITTER_TOKEN) private readonly eventEmitter: EventEmitter
  ) {}

  async createUser(data: CreateUserDto) {
    const user = await this.db.createUser(data);

    // Emit event
    this.eventEmitter.emit("user.created", {
      userId: user.id,
      email: user.email,
    });

    return user;
  }

  async updateUser(id: string, data: UpdateUserDto) {
    const user = await this.db.updateUser(id, data);

    this.eventEmitter.emit("user.updated", {
      userId: user.id,
      changes: data,
    });

    return user;
  }
}

Manual Event Registration

Alternative to @OnEvent decorator:

@Injectable()
class AuditService {
  constructor(
    @Inject(EVENT_EMITTER_TOKEN) private readonly eventEmitter: EventEmitter
  ) {
    // Register listeners manually
    this.eventEmitter.on("user.created", this.logUserCreation.bind(this));
    this.eventEmitter.on("order.*", this.logOrderEvent.bind(this));
  }

  private logUserCreation(payload: any) {
    console.log("[AUDIT] User created:", payload);
  }

  private logOrderEvent(payload: any) {
    console.log("[AUDIT] Order event:", payload);
  }
}

Event Patterns

Request-scoped Events

@Injectable()
class OrderService {
  constructor(
    @Inject(EVENT_EMITTER_TOKEN) private readonly eventEmitter: EventEmitter
  ) {}

  async processOrder(order: Order) {
    this.eventEmitter.emit("order.processing", { orderId: order.id });

    try {
      await this.chargePayment(order);
      this.eventEmitter.emit("order.payment.success", { orderId: order.id });

      await this.fulfillOrder(order);
      this.eventEmitter.emit("order.completed", { orderId: order.id });
    } catch (error) {
      this.eventEmitter.emit("order.failed", {
        orderId: order.id,
        error: error.message,
      });
      throw error;
    }
  }
}

Typed Events

// Define event types
interface UserEvents {
  "user.created": { userId: string; email: string };
  "user.updated": { userId: string; changes: Record<string, any> };
  "user.deleted": { userId: string };
}

// Type-safe listener
@OnEvent("user.created")
handleUserCreated(payload: UserEvents["user.created"]) {
  console.log(payload.userId, payload.email);
}

Common Issues

“Provider not found for token” Error

Ensure EventModule.forRoot() is called:

// ❌ Wrong
@Module({ imports: [EventModule] })

// ✅ Correct
EventModule.forRoot({ wildcard: true });
@Module({ imports: [EventModule] })

@OnEvent Not Triggering

Ensure initializeListeners is called with all listener classes.

Related Resources