@dangao/bun-server 1.7.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +129 -21
  2. package/dist/di/decorators.d.ts +37 -0
  3. package/dist/di/decorators.d.ts.map +1 -1
  4. package/dist/di/index.d.ts +1 -1
  5. package/dist/di/index.d.ts.map +1 -1
  6. package/dist/di/module-registry.d.ts +17 -0
  7. package/dist/di/module-registry.d.ts.map +1 -1
  8. package/dist/events/decorators.d.ts +52 -0
  9. package/dist/events/decorators.d.ts.map +1 -0
  10. package/dist/events/event-module.d.ts +97 -0
  11. package/dist/events/event-module.d.ts.map +1 -0
  12. package/dist/events/index.d.ts +5 -0
  13. package/dist/events/index.d.ts.map +1 -0
  14. package/dist/events/service.d.ts +76 -0
  15. package/dist/events/service.d.ts.map +1 -0
  16. package/dist/events/types.d.ts +184 -0
  17. package/dist/events/types.d.ts.map +1 -0
  18. package/dist/index.d.ts +5 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1511 -11
  21. package/dist/security/filter.d.ts +23 -0
  22. package/dist/security/filter.d.ts.map +1 -1
  23. package/dist/security/guards/builtin/auth-guard.d.ts +44 -0
  24. package/dist/security/guards/builtin/auth-guard.d.ts.map +1 -0
  25. package/dist/security/guards/builtin/index.d.ts +3 -0
  26. package/dist/security/guards/builtin/index.d.ts.map +1 -0
  27. package/dist/security/guards/builtin/roles-guard.d.ts +66 -0
  28. package/dist/security/guards/builtin/roles-guard.d.ts.map +1 -0
  29. package/dist/security/guards/decorators.d.ts +50 -0
  30. package/dist/security/guards/decorators.d.ts.map +1 -0
  31. package/dist/security/guards/execution-context.d.ts +56 -0
  32. package/dist/security/guards/execution-context.d.ts.map +1 -0
  33. package/dist/security/guards/guard-registry.d.ts +67 -0
  34. package/dist/security/guards/guard-registry.d.ts.map +1 -0
  35. package/dist/security/guards/index.d.ts +7 -0
  36. package/dist/security/guards/index.d.ts.map +1 -0
  37. package/dist/security/guards/reflector.d.ts +57 -0
  38. package/dist/security/guards/reflector.d.ts.map +1 -0
  39. package/dist/security/guards/types.d.ts +126 -0
  40. package/dist/security/guards/types.d.ts.map +1 -0
  41. package/dist/security/index.d.ts +1 -0
  42. package/dist/security/index.d.ts.map +1 -1
  43. package/dist/security/security-module.d.ts +20 -0
  44. package/dist/security/security-module.d.ts.map +1 -1
  45. package/dist/validation/class-validator.d.ts +108 -0
  46. package/dist/validation/class-validator.d.ts.map +1 -0
  47. package/dist/validation/custom-validator.d.ts +130 -0
  48. package/dist/validation/custom-validator.d.ts.map +1 -0
  49. package/dist/validation/errors.d.ts +22 -2
  50. package/dist/validation/errors.d.ts.map +1 -1
  51. package/dist/validation/index.d.ts +7 -1
  52. package/dist/validation/index.d.ts.map +1 -1
  53. package/dist/validation/rules/array.d.ts +33 -0
  54. package/dist/validation/rules/array.d.ts.map +1 -0
  55. package/dist/validation/rules/common.d.ts +90 -0
  56. package/dist/validation/rules/common.d.ts.map +1 -0
  57. package/dist/validation/rules/conditional.d.ts +30 -0
  58. package/dist/validation/rules/conditional.d.ts.map +1 -0
  59. package/dist/validation/rules/index.d.ts +5 -0
  60. package/dist/validation/rules/index.d.ts.map +1 -0
  61. package/dist/validation/rules/object.d.ts +30 -0
  62. package/dist/validation/rules/object.d.ts.map +1 -0
  63. package/dist/validation/types.d.ts +52 -1
  64. package/dist/validation/types.d.ts.map +1 -1
  65. package/docs/events.md +494 -0
  66. package/docs/guards.md +376 -0
  67. package/docs/guide.md +309 -1
  68. package/docs/request-lifecycle.md +444 -0
  69. package/docs/validation.md +407 -0
  70. package/docs/zh/events.md +494 -0
  71. package/docs/zh/guards.md +376 -0
  72. package/docs/zh/guide.md +309 -1
  73. package/docs/zh/request-lifecycle.md +444 -0
  74. package/docs/zh/validation.md +407 -0
  75. package/package.json +1 -1
  76. package/src/di/decorators.ts +46 -0
  77. package/src/di/index.ts +10 -1
  78. package/src/di/module-registry.ts +39 -0
  79. package/src/events/decorators.ts +103 -0
  80. package/src/events/event-module.ts +272 -0
  81. package/src/events/index.ts +32 -0
  82. package/src/events/service.ts +352 -0
  83. package/src/events/types.ts +223 -0
  84. package/src/index.ts +133 -1
  85. package/src/security/filter.ts +88 -8
  86. package/src/security/guards/builtin/auth-guard.ts +68 -0
  87. package/src/security/guards/builtin/index.ts +3 -0
  88. package/src/security/guards/builtin/roles-guard.ts +165 -0
  89. package/src/security/guards/decorators.ts +124 -0
  90. package/src/security/guards/execution-context.ts +152 -0
  91. package/src/security/guards/guard-registry.ts +164 -0
  92. package/src/security/guards/index.ts +7 -0
  93. package/src/security/guards/reflector.ts +99 -0
  94. package/src/security/guards/types.ts +144 -0
  95. package/src/security/index.ts +1 -0
  96. package/src/security/security-module.ts +72 -2
  97. package/src/validation/class-validator.ts +322 -0
  98. package/src/validation/custom-validator.ts +289 -0
  99. package/src/validation/errors.ts +50 -2
  100. package/src/validation/index.ts +103 -1
  101. package/src/validation/rules/array.ts +118 -0
  102. package/src/validation/rules/common.ts +286 -0
  103. package/src/validation/rules/conditional.ts +52 -0
  104. package/src/validation/rules/index.ts +51 -0
  105. package/src/validation/rules/object.ts +86 -0
  106. package/src/validation/types.ts +61 -1
  107. package/tests/di/global-module.test.ts +487 -0
  108. package/tests/events/event-decorators.test.ts +173 -0
  109. package/tests/events/event-emitter.test.ts +373 -0
  110. package/tests/events/event-module.test.ts +373 -0
  111. package/tests/security/guards/guards-integration.test.ts +371 -0
  112. package/tests/security/guards/guards.test.ts +775 -0
  113. package/tests/security/security-module.test.ts +2 -2
  114. package/tests/validation/class-validator.test.ts +349 -0
  115. package/tests/validation/custom-validator.test.ts +335 -0
  116. package/tests/validation/rules.test.ts +543 -0
@@ -0,0 +1,376 @@
1
+ # 守卫(Guards)
2
+
3
+ 守卫是控制应用程序路由访问的强大机制。它们在路由处理器之前执行,决定请求是否应该被处理。
4
+
5
+ ## 概述
6
+
7
+ 守卫实现 `CanActivate` 接口,返回一个布尔值来指示请求是否应该被允许继续。与中间件不同,守卫可以访问 `ExecutionContext`,它提供了当前请求上下文的丰富信息。
8
+
9
+ ### 何时使用守卫
10
+
11
+ - **认证**:验证用户是否已认证
12
+ - **授权**:检查用户是否具有所需的角色或权限
13
+ - **限流**:实现自定义限流逻辑
14
+ - **功能开关**:根据条件启用/禁用功能
15
+ - **请求验证**:在处理前验证请求元数据
16
+
17
+ ## 基本用法
18
+
19
+ ### 创建守卫
20
+
21
+ ```typescript
22
+ import { Injectable } from '@dangao/bun-server';
23
+ import type { CanActivate, ExecutionContext } from '@dangao/bun-server';
24
+
25
+ @Injectable()
26
+ class AuthGuard implements CanActivate {
27
+ canActivate(context: ExecutionContext): boolean | Promise<boolean> {
28
+ const request = context.switchToHttp().getRequest();
29
+ const token = request.getHeader('authorization');
30
+
31
+ // 验证 token 并返回 true/false
32
+ return !!token;
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### 应用守卫
38
+
39
+ 守卫可以在不同级别应用:
40
+
41
+ #### 控制器级别
42
+
43
+ ```typescript
44
+ import { Controller, GET, UseGuards } from '@dangao/bun-server';
45
+
46
+ @Controller('/api/users')
47
+ @UseGuards(AuthGuard)
48
+ class UserController {
49
+ @GET('/')
50
+ getUsers() {
51
+ return { users: [] };
52
+ }
53
+ }
54
+ ```
55
+
56
+ #### 方法级别
57
+
58
+ ```typescript
59
+ @Controller('/api')
60
+ class ApiController {
61
+ @GET('/public')
62
+ publicEndpoint() {
63
+ return { message: '公开' };
64
+ }
65
+
66
+ @GET('/private')
67
+ @UseGuards(AuthGuard)
68
+ privateEndpoint() {
69
+ return { message: '私有' };
70
+ }
71
+ }
72
+ ```
73
+
74
+ #### 全局守卫
75
+
76
+ ```typescript
77
+ import { SecurityModule } from '@dangao/bun-server';
78
+
79
+ SecurityModule.forRoot({
80
+ jwt: { secret: 'your-secret' },
81
+ globalGuards: [AuthGuard, RolesGuard],
82
+ });
83
+ ```
84
+
85
+ ## 执行顺序
86
+
87
+ 守卫按以下顺序执行:
88
+
89
+ 1. **全局守卫**(按注册顺序)
90
+ 2. **控制器守卫**(按装饰器顺序)
91
+ 3. **方法守卫**(按装饰器顺序)
92
+
93
+ ```
94
+ HTTP 请求
95
+
96
+ 中间件管道
97
+
98
+ 安全过滤器(Token 提取和认证)
99
+
100
+ 守卫(全局 → 控制器 → 方法)
101
+
102
+ 拦截器(前置)
103
+
104
+ 路由处理器
105
+
106
+ 拦截器(后置)
107
+
108
+ HTTP 响应
109
+ ```
110
+
111
+ ## 内置守卫
112
+
113
+ ### AuthGuard
114
+
115
+ 检查用户是否已认证:
116
+
117
+ ```typescript
118
+ import { Controller, GET, UseGuards, AuthGuard } from '@dangao/bun-server';
119
+
120
+ @Controller('/api/profile')
121
+ @UseGuards(AuthGuard)
122
+ class ProfileController {
123
+ @GET('/')
124
+ getProfile() {
125
+ // 只有已认证的用户可以访问
126
+ return { profile: {} };
127
+ }
128
+ }
129
+ ```
130
+
131
+ ### OptionalAuthGuard
132
+
133
+ 允许未认证访问,但如果有 token 会进行验证:
134
+
135
+ ```typescript
136
+ import { Controller, GET, UseGuards, OptionalAuthGuard } from '@dangao/bun-server';
137
+
138
+ @Controller('/api/posts')
139
+ class PostController {
140
+ @GET('/')
141
+ @UseGuards(OptionalAuthGuard)
142
+ getPosts() {
143
+ // 无论是否认证都允许访问
144
+ return { posts: [] };
145
+ }
146
+ }
147
+ ```
148
+
149
+ ### RolesGuard
150
+
151
+ 检查用户是否具有所需角色:
152
+
153
+ ```typescript
154
+ import { Controller, GET, UseGuards, AuthGuard, RolesGuard, Roles } from '@dangao/bun-server';
155
+
156
+ @Controller('/api/admin')
157
+ @UseGuards(AuthGuard, RolesGuard)
158
+ class AdminController {
159
+ @GET('/dashboard')
160
+ @Roles('admin')
161
+ dashboard() {
162
+ return { message: '管理员仪表板' };
163
+ }
164
+
165
+ @GET('/super')
166
+ @Roles('admin', 'superadmin') // 任一角色即可访问
167
+ superAdmin() {
168
+ return { message: '超级管理员' };
169
+ }
170
+ }
171
+ ```
172
+
173
+ ## 自定义守卫
174
+
175
+ ### 基本自定义守卫
176
+
177
+ ```typescript
178
+ import { Injectable } from '@dangao/bun-server';
179
+ import type { CanActivate, ExecutionContext } from '@dangao/bun-server';
180
+
181
+ @Injectable()
182
+ class ApiKeyGuard implements CanActivate {
183
+ private readonly validApiKeys = ['key1', 'key2'];
184
+
185
+ canActivate(context: ExecutionContext): boolean {
186
+ const request = context.switchToHttp().getRequest();
187
+ const apiKey = request.getHeader('x-api-key');
188
+
189
+ return this.validApiKeys.includes(apiKey || '');
190
+ }
191
+ }
192
+ ```
193
+
194
+ ### 异步守卫
195
+
196
+ ```typescript
197
+ @Injectable()
198
+ class SubscriptionGuard implements CanActivate {
199
+ constructor(private readonly subscriptionService: SubscriptionService) {}
200
+
201
+ async canActivate(context: ExecutionContext): Promise<boolean> {
202
+ const request = context.switchToHttp().getRequest();
203
+ const userId = request.auth?.user?.id;
204
+
205
+ if (!userId) return false;
206
+
207
+ const subscription = await this.subscriptionService.getSubscription(userId);
208
+ return subscription?.isActive ?? false;
209
+ }
210
+ }
211
+ ```
212
+
213
+ ### 访问元数据的守卫
214
+
215
+ ```typescript
216
+ @Injectable()
217
+ class FeatureFlagGuard implements CanActivate {
218
+ constructor(private readonly reflector: Reflector) {}
219
+
220
+ canActivate(context: ExecutionContext): boolean {
221
+ const feature = this.reflector.getAllAndOverride<string>(
222
+ 'feature',
223
+ context.getClass(),
224
+ context.getMethodName(),
225
+ );
226
+
227
+ if (!feature) return true;
228
+
229
+ return this.isFeatureEnabled(feature);
230
+ }
231
+
232
+ private isFeatureEnabled(feature: string): boolean {
233
+ // 检查功能开关状态
234
+ return true;
235
+ }
236
+ }
237
+ ```
238
+
239
+ ## ExecutionContext
240
+
241
+ `ExecutionContext` 提供以下访问能力:
242
+
243
+ ### HTTP 上下文
244
+
245
+ ```typescript
246
+ const httpHost = context.switchToHttp();
247
+ const request = httpHost.getRequest(); // Context 对象
248
+ const response = httpHost.getResponse(); // ResponseBuilder(如果可用)
249
+ ```
250
+
251
+ ### 控制器和方法信息
252
+
253
+ ```typescript
254
+ const controllerClass = context.getClass(); // 控制器类
255
+ const handler = context.getHandler(); // 方法函数
256
+ const methodName = context.getMethodName(); // 方法名字符串
257
+ ```
258
+
259
+ ### 元数据访问
260
+
261
+ ```typescript
262
+ const metadata = context.getMetadata<string[]>('roles');
263
+ // 先检查方法,再检查类
264
+ ```
265
+
266
+ ## Reflector 工具类
267
+
268
+ `Reflector` 类帮助检索元数据:
269
+
270
+ ```typescript
271
+ import { Reflector, REFLECTOR_TOKEN } from '@dangao/bun-server';
272
+
273
+ @Injectable()
274
+ class MyGuard implements CanActivate {
275
+ constructor(@Inject(REFLECTOR_TOKEN) private readonly reflector: Reflector) {}
276
+
277
+ canActivate(context: ExecutionContext): boolean {
278
+ // 获取元数据,方法优先
279
+ const roles = this.reflector.getAllAndOverride<string[]>(
280
+ ROLES_METADATA_KEY,
281
+ context.getClass(),
282
+ context.getMethodName(),
283
+ );
284
+
285
+ // 合并类和方法的元数据
286
+ const permissions = this.reflector.getAllAndMerge<string[]>(
287
+ 'permissions',
288
+ context.getClass(),
289
+ context.getMethodName(),
290
+ );
291
+
292
+ return true;
293
+ }
294
+ }
295
+ ```
296
+
297
+ ## 自定义角色守卫工厂
298
+
299
+ 创建自定义的角色守卫:
300
+
301
+ ```typescript
302
+ import { createRolesGuard } from '@dangao/bun-server';
303
+
304
+ // 要求所有角色而不是任一角色
305
+ const AllRolesGuard = createRolesGuard({ matchAll: true });
306
+
307
+ // 自定义角色提取
308
+ const CustomRolesGuard = createRolesGuard({
309
+ getRoles: (context) => {
310
+ const request = context.switchToHttp().getRequest();
311
+ return request.auth?.user?.permissions || [];
312
+ },
313
+ });
314
+ ```
315
+
316
+ ## 错误处理
317
+
318
+ 守卫可以抛出异常来拒绝请求:
319
+
320
+ ```typescript
321
+ import { ForbiddenException, UnauthorizedException } from '@dangao/bun-server';
322
+
323
+ @Injectable()
324
+ class StrictAuthGuard implements CanActivate {
325
+ canActivate(context: ExecutionContext): boolean {
326
+ const request = context.switchToHttp().getRequest();
327
+
328
+ if (!request.auth?.isAuthenticated) {
329
+ throw new UnauthorizedException('需要认证');
330
+ }
331
+
332
+ if (!this.hasPermission(request.auth.user)) {
333
+ throw new ForbiddenException('权限不足');
334
+ }
335
+
336
+ return true;
337
+ }
338
+ }
339
+ ```
340
+
341
+ ## 最佳实践
342
+
343
+ 1. **保持守卫专注**:每个守卫应该只处理一个关注点
344
+ 2. **使用依赖注入**:对于复杂逻辑,注入服务
345
+ 3. **优先抛出异常**:比返回 false 提供更好的错误消息
346
+ 4. **顺序很重要**:在 RolesGuard 之前应用 AuthGuard
347
+ 5. **使用内置守卫**:尽可能使用 AuthGuard 和 RolesGuard
348
+ 6. **测试你的守卫**:为守卫逻辑编写单元测试
349
+
350
+ ## 与 SecurityModule 集成
351
+
352
+ 守卫与 SecurityModule 无缝配合:
353
+
354
+ ```typescript
355
+ import { Application, SecurityModule, AuthGuard, RolesGuard } from '@dangao/bun-server';
356
+
357
+ const app = new Application();
358
+
359
+ app.registerModule(
360
+ SecurityModule.forRoot({
361
+ jwt: {
362
+ secret: 'your-jwt-secret',
363
+ accessTokenExpiresIn: 3600,
364
+ },
365
+ excludePaths: ['/public', '/health'],
366
+ globalGuards: [AuthGuard], // 应用于所有路由
367
+ }),
368
+ );
369
+ ```
370
+
371
+ ## 参见
372
+
373
+ - [请求生命周期](./request-lifecycle.md)
374
+ - [安全模块](./guide.md#security-module)
375
+ - [自定义装饰器](./custom-decorators.md)
376
+
package/docs/zh/guide.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  涵盖从零开始构建 Bun Server 应用的关键步骤。
4
4
 
5
+ ## 请求生命周期概览
6
+
7
+ 在深入实现细节之前,了解 Bun Server 如何处理请求会很有帮助:
8
+
9
+ ```
10
+ HTTP 请求 → 中间件 → 安全 → 路由 → 拦截器(前置) → 验证 → 处理器 → 拦截器(后置) → 异常过滤器 → HTTP 响应
11
+ ```
12
+
13
+ 详细的生命周期文档请参阅 [请求生命周期](./request-lifecycle.md)。
14
+
5
15
  ## 1. 初始化应用
6
16
 
7
17
  ```ts
@@ -357,7 +367,305 @@ app.listen();
357
367
 
358
368
  这种模式特别适合大型项目,可以轻松替换实现而不影响使用方代码。
359
369
 
360
- ## 9. 测试建议
370
+ ## 9. 守卫(Guards)
371
+
372
+ 守卫提供对路由的细粒度访问控制。它们在中间件之后、拦截器之前执行,决定请求是否应该继续。
373
+
374
+ ### 内置守卫
375
+
376
+ ```ts
377
+ import {
378
+ AuthGuard,
379
+ Controller,
380
+ GET,
381
+ Roles,
382
+ RolesGuard,
383
+ UseGuards,
384
+ } from "@dangao/bun-server";
385
+
386
+ @Controller("/api/admin")
387
+ @UseGuards(AuthGuard, RolesGuard)
388
+ class AdminController {
389
+ @GET("/dashboard")
390
+ @Roles("admin")
391
+ public dashboard() {
392
+ return { message: "管理员仪表板" };
393
+ }
394
+
395
+ @GET("/users")
396
+ @Roles("admin", "moderator") // 任一角色即可访问
397
+ public listUsers() {
398
+ return { users: [] };
399
+ }
400
+ }
401
+ ```
402
+
403
+ ### 自定义守卫
404
+
405
+ ```ts
406
+ import { Injectable } from "@dangao/bun-server";
407
+ import type { CanActivate, ExecutionContext } from "@dangao/bun-server";
408
+
409
+ @Injectable()
410
+ class ApiKeyGuard implements CanActivate {
411
+ canActivate(context: ExecutionContext): boolean {
412
+ const request = context.switchToHttp().getRequest();
413
+ const apiKey = request.getHeader("x-api-key");
414
+ return apiKey === "valid-api-key";
415
+ }
416
+ }
417
+
418
+ @Controller("/api/external")
419
+ @UseGuards(ApiKeyGuard)
420
+ class ExternalApiController {
421
+ @GET("/data")
422
+ public getData() {
423
+ return { data: [] };
424
+ }
425
+ }
426
+ ```
427
+
428
+ ### 全局守卫
429
+
430
+ ```ts
431
+ SecurityModule.forRoot({
432
+ jwt: { secret: "your-secret" },
433
+ globalGuards: [AuthGuard], // 应用于所有路由
434
+ });
435
+ ```
436
+
437
+ 详细文档请参阅 [守卫](./guards.md)。
438
+
439
+ ## 10. 事件系统
440
+
441
+ 事件模块提供了强大的事件驱动架构,用于构建松耦合的应用。
442
+
443
+ ### 基本用法
444
+
445
+ ```ts
446
+ import {
447
+ EventModule,
448
+ Injectable,
449
+ Inject,
450
+ OnEvent,
451
+ EVENT_EMITTER_TOKEN,
452
+ } from "@dangao/bun-server";
453
+ import type { EventEmitter } from "@dangao/bun-server";
454
+
455
+ // 定义事件
456
+ const USER_CREATED = Symbol("user.created");
457
+
458
+ interface UserCreatedEvent {
459
+ userId: string;
460
+ email: string;
461
+ }
462
+
463
+ // 发布事件的服务
464
+ @Injectable()
465
+ class UserService {
466
+ public constructor(
467
+ @Inject(EVENT_EMITTER_TOKEN) private readonly eventEmitter: EventEmitter,
468
+ ) {}
469
+
470
+ public async createUser(email: string) {
471
+ const userId = "user-123";
472
+
473
+ // 发布事件
474
+ this.eventEmitter.emit<UserCreatedEvent>(USER_CREATED, {
475
+ userId,
476
+ email,
477
+ });
478
+
479
+ return { userId, email };
480
+ }
481
+ }
482
+
483
+ // 监听事件的服务
484
+ @Injectable()
485
+ class NotificationService {
486
+ @OnEvent(USER_CREATED)
487
+ public handleUserCreated(payload: UserCreatedEvent) {
488
+ console.log(`欢迎邮件已发送至 ${payload.email}`);
489
+ }
490
+
491
+ @OnEvent(USER_CREATED, { async: true, priority: 10 })
492
+ public async trackUserCreation(payload: UserCreatedEvent) {
493
+ await this.analytics.track("user_created", payload);
494
+ }
495
+ }
496
+ ```
497
+
498
+ ### 模块配置
499
+
500
+ ```ts
501
+ EventModule.forRoot({
502
+ wildcard: true, // 启用通配符匹配
503
+ maxListeners: 20, // 每个事件的最大监听器数量
504
+ onError: (error, event, payload) => {
505
+ console.error(`事件 ${String(event)} 发生错误:`, error);
506
+ },
507
+ });
508
+
509
+ // 注册监听器类
510
+ EventModule.registerListeners([NotificationService, AnalyticsService]);
511
+
512
+ @Module({
513
+ imports: [EventModule],
514
+ providers: [UserService, NotificationService, AnalyticsService],
515
+ })
516
+ class AppModule {}
517
+
518
+ const app = new Application();
519
+ app.registerModule(AppModule);
520
+
521
+ // 模块注册后初始化事件监听器
522
+ EventModule.initializeListeners(app.getContainer());
523
+ ```
524
+
525
+ ### 通配符事件
526
+
527
+ ```ts
528
+ // 匹配任何用户事件: user.created, user.updated, user.deleted
529
+ @OnEvent("user.*")
530
+ handleAnyUserEvent(payload: unknown) {}
531
+
532
+ // 匹配嵌套事件: order.created, order.item.added, order.payment.completed
533
+ @OnEvent("order.**")
534
+ handleAllOrderEvents(payload: unknown) {}
535
+ ```
536
+
537
+ ### 异步事件发布
538
+
539
+ ```ts
540
+ // 触发即忘(异步监听器被触发但不等待)
541
+ this.eventEmitter.emit("order.created", orderData);
542
+
543
+ // 等待所有监听器完成
544
+ await this.eventEmitter.emitAsync("order.created", orderData);
545
+ ```
546
+
547
+ 详细文档请参阅 [事件系统](./events.md)。
548
+
549
+ ## 11. 全局模块
550
+
551
+ 全局模块允许您在所有模块之间共享提供者,无需显式导入。这对于常用的服务(如配置、日志或缓存)非常有用。
552
+
553
+ ### 创建全局模块
554
+
555
+ 使用 `@Global()` 装饰器将模块标记为全局模块:
556
+
557
+ ```ts
558
+ import { Global, Injectable, Module } from "@dangao/bun-server";
559
+
560
+ const CONFIG_TOKEN = Symbol("config");
561
+
562
+ @Injectable()
563
+ class ConfigService {
564
+ public get(key: string): string {
565
+ return `config:${key}`;
566
+ }
567
+ }
568
+
569
+ @Global()
570
+ @Module({
571
+ providers: [
572
+ {
573
+ provide: CONFIG_TOKEN,
574
+ useClass: ConfigService,
575
+ },
576
+ ],
577
+ exports: [CONFIG_TOKEN],
578
+ })
579
+ class GlobalConfigModule {}
580
+ ```
581
+
582
+ ### 使用全局模块导出
583
+
584
+ 其他模块可以使用导出的提供者,无需导入全局模块:
585
+
586
+ ```ts
587
+ @Injectable()
588
+ class UserService {
589
+ public constructor(
590
+ @Inject(CONFIG_TOKEN) private readonly config: ConfigService,
591
+ ) {}
592
+
593
+ public getAppName(): string {
594
+ return this.config.get("app.name");
595
+ }
596
+ }
597
+
598
+ // UserModule 不需要导入 GlobalConfigModule
599
+ @Module({
600
+ providers: [UserService],
601
+ })
602
+ class UserModule {}
603
+ ```
604
+
605
+ ### 注册全局模块
606
+
607
+ 全局模块必须在应用中注册,通常在根模块中:
608
+
609
+ ```ts
610
+ @Module({
611
+ imports: [
612
+ GlobalConfigModule, // 只需注册一次全局模块
613
+ GlobalLoggerModule,
614
+ UserModule, // UserModule 可以使用 ConfigService,无需导入它
615
+ ProductModule,
616
+ ],
617
+ })
618
+ class AppModule {}
619
+
620
+ const app = new Application();
621
+ app.registerModule(AppModule);
622
+ ```
623
+
624
+ ### 关键要点
625
+
626
+ - **单次注册**:全局模块只需要注册一次(通常在根模块中)
627
+ - **自动可用**:全局模块的导出对所有其他模块自动可用
628
+ - **单例共享**:全局模块提供者在整个应用中保持单例行为
629
+ - **无需导入**:其他模块不需要将全局模块添加到其 `imports` 数组中
630
+
631
+ ### 使用场景
632
+
633
+ 全局模块非常适合:
634
+
635
+ - **配置服务**:全应用范围的配置访问
636
+ - **日志服务**:集中式日志记录
637
+ - **缓存服务**:共享缓存层
638
+ - **数据库连接**:共享数据库访问
639
+ - **事件发射器**:应用范围的事件总线
640
+
641
+ ### 示例:多个全局模块
642
+
643
+ ```ts
644
+ @Global()
645
+ @Module({
646
+ providers: [{ provide: LOGGER_TOKEN, useClass: LoggerService }],
647
+ exports: [LOGGER_TOKEN],
648
+ })
649
+ class GlobalLoggerModule {}
650
+
651
+ @Global()
652
+ @Module({
653
+ providers: [{ provide: CACHE_TOKEN, useClass: CacheService }],
654
+ exports: [CACHE_TOKEN],
655
+ })
656
+ class GlobalCacheModule {}
657
+
658
+ // AppService 可以使用两者,无需显式导入
659
+ @Injectable()
660
+ class AppService {
661
+ public constructor(
662
+ @Inject(LOGGER_TOKEN) private readonly logger: LoggerService,
663
+ @Inject(CACHE_TOKEN) private readonly cache: CacheService,
664
+ ) {}
665
+ }
666
+ ```
667
+
668
+ ## 12. 测试建议
361
669
 
362
670
  - 使用 `tests/utils/test-port.ts` 获取自增端口,避免本地冲突。
363
671
  - 在 `afterEach` 钩子中调用 `RouteRegistry.getInstance().clear()` 和