bun-server-events by dangaogit/bun-server-skills
npx skills add https://github.com/dangaogit/bun-server-skills --skill bun-server-eventsimport { Module, EventModule } from "@dangao/bun-server";
// 在模块定义前进行配置
EventModule.forRoot({
wildcard: true, // 启用通配符事件 (user.*)
maxListeners: 20, // 每个事件的最大监听器数量
onError: (error, event, payload) => {
console.error(`事件错误 [${event}]:`, error);
},
});
@Module({
imports: [EventModule],
})
class AppModule {}
import { Injectable, OnEvent } from "@dangao/bun-server";
@Injectable()
class NotificationListener {
@OnEvent("user.created")
async handleUserCreated(payload: { userId: string; email: string }) {
console.log("新用户:", payload.userId);
await this.sendWelcomeEmail(payload.email);
}
@OnEvent("user.*") // 通配符: 匹配 user.created, user.updated 等
handleAllUserEvents(payload: any) {
console.log("收到用户事件:", payload);
}
@OnEvent("order.completed", { async: true })
async handleOrderCompleted(payload: { orderId: string }) {
// 异步处理器 - 不会阻塞发射器
await this.processOrder(payload.orderId);
}
}
重要 : 必须在 registerModule 之后调用 :
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
initializeListenersimport { Application, EventModule, ModuleRegistry } from "@dangao/bun-server";
const app = new Application({ port: 3100 });
app.registerModule(AppModule);
// 初始化事件监听器
const rootModuleRef = ModuleRegistry.getInstance().getModuleRef(AppModule);
if (rootModuleRef?.container) {
EventModule.initializeListeners(
rootModuleRef.container,
[NotificationListener, AuditListener], // 所有 @OnEvent 类
);
}
app.listen();
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);
// 触发事件
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;
}
}
替代 @OnEvent 装饰器的方法:
@Injectable()
class AuditService {
constructor(
@Inject(EVENT_EMITTER_TOKEN) private readonly eventEmitter: EventEmitter
) {
// 手动注册监听器
this.eventEmitter.on("user.created", this.logUserCreation.bind(this));
this.eventEmitter.on("order.*", this.logOrderEvent.bind(this));
}
private logUserCreation(payload: any) {
console.log("[审计] 用户创建:", payload);
}
private logOrderEvent(payload: any) {
console.log("[审计] 订单事件:", payload);
}
}
@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;
}
}
}
// 定义事件类型
interface UserEvents {
"user.created": { userId: string; email: string };
"user.updated": { userId: string; changes: Record<string, any> };
"user.deleted": { userId: string };
}
// 类型安全的监听器
@OnEvent("user.created")
handleUserCreated(payload: UserEvents["user.created"]) {
console.log(payload.userId, payload.email);
}
确保调用了 EventModule.forRoot():
// ❌ 错误
@Module({ imports: [EventModule] })
// ✅ 正确
EventModule.forRoot({ wildcard: true });
@Module({ imports: [EventModule] })
确保使用所有监听器类调用了 initializeListeners。
每周安装量
1
仓库
GitHub 星标数
1
首次出现
2026年2月4日
安装于
trae1
qoder1
trae-cn1
cursor1
claude-code1
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 {}
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);
}
}
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();
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;
}
}
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);
}
}
@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;
}
}
}
// 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);
}
Ensure EventModule.forRoot() is called:
// ❌ Wrong
@Module({ imports: [EventModule] })
// ✅ Correct
EventModule.forRoot({ wildcard: true });
@Module({ imports: [EventModule] })
Ensure initializeListeners is called with all listener classes.
Weekly Installs
1
Repository
GitHub Stars
1
First Seen
Feb 4, 2026
Installed on
trae1
qoder1
trae-cn1
cursor1
claude-code1
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
109,600 周安装