@dangao/bun-server 1.7.0 → 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 (144) hide show
  1. package/README.md +196 -19
  2. package/dist/cache/cache-module.d.ts +18 -0
  3. package/dist/cache/cache-module.d.ts.map +1 -1
  4. package/dist/cache/index.d.ts +3 -1
  5. package/dist/cache/index.d.ts.map +1 -1
  6. package/dist/cache/interceptors.d.ts +41 -0
  7. package/dist/cache/interceptors.d.ts.map +1 -0
  8. package/dist/cache/service-proxy.d.ts +62 -0
  9. package/dist/cache/service-proxy.d.ts.map +1 -0
  10. package/dist/controller/controller.d.ts +8 -0
  11. package/dist/controller/controller.d.ts.map +1 -1
  12. package/dist/core/application.d.ts +5 -0
  13. package/dist/core/application.d.ts.map +1 -1
  14. package/dist/di/container.d.ts +18 -1
  15. package/dist/di/container.d.ts.map +1 -1
  16. package/dist/di/decorators.d.ts +37 -0
  17. package/dist/di/decorators.d.ts.map +1 -1
  18. package/dist/di/index.d.ts +2 -2
  19. package/dist/di/index.d.ts.map +1 -1
  20. package/dist/di/module-registry.d.ts +17 -0
  21. package/dist/di/module-registry.d.ts.map +1 -1
  22. package/dist/di/types.d.ts +22 -0
  23. package/dist/di/types.d.ts.map +1 -1
  24. package/dist/events/decorators.d.ts +52 -0
  25. package/dist/events/decorators.d.ts.map +1 -0
  26. package/dist/events/event-module.d.ts +97 -0
  27. package/dist/events/event-module.d.ts.map +1 -0
  28. package/dist/events/index.d.ts +5 -0
  29. package/dist/events/index.d.ts.map +1 -0
  30. package/dist/events/service.d.ts +76 -0
  31. package/dist/events/service.d.ts.map +1 -0
  32. package/dist/events/types.d.ts +184 -0
  33. package/dist/events/types.d.ts.map +1 -0
  34. package/dist/index.d.ts +6 -4
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +4641 -2840
  37. package/dist/security/filter.d.ts +23 -0
  38. package/dist/security/filter.d.ts.map +1 -1
  39. package/dist/security/guards/builtin/auth-guard.d.ts +44 -0
  40. package/dist/security/guards/builtin/auth-guard.d.ts.map +1 -0
  41. package/dist/security/guards/builtin/index.d.ts +3 -0
  42. package/dist/security/guards/builtin/index.d.ts.map +1 -0
  43. package/dist/security/guards/builtin/roles-guard.d.ts +66 -0
  44. package/dist/security/guards/builtin/roles-guard.d.ts.map +1 -0
  45. package/dist/security/guards/decorators.d.ts +50 -0
  46. package/dist/security/guards/decorators.d.ts.map +1 -0
  47. package/dist/security/guards/execution-context.d.ts +56 -0
  48. package/dist/security/guards/execution-context.d.ts.map +1 -0
  49. package/dist/security/guards/guard-registry.d.ts +67 -0
  50. package/dist/security/guards/guard-registry.d.ts.map +1 -0
  51. package/dist/security/guards/index.d.ts +7 -0
  52. package/dist/security/guards/index.d.ts.map +1 -0
  53. package/dist/security/guards/reflector.d.ts +57 -0
  54. package/dist/security/guards/reflector.d.ts.map +1 -0
  55. package/dist/security/guards/types.d.ts +126 -0
  56. package/dist/security/guards/types.d.ts.map +1 -0
  57. package/dist/security/index.d.ts +1 -0
  58. package/dist/security/index.d.ts.map +1 -1
  59. package/dist/security/security-module.d.ts +20 -0
  60. package/dist/security/security-module.d.ts.map +1 -1
  61. package/dist/validation/class-validator.d.ts +108 -0
  62. package/dist/validation/class-validator.d.ts.map +1 -0
  63. package/dist/validation/custom-validator.d.ts +130 -0
  64. package/dist/validation/custom-validator.d.ts.map +1 -0
  65. package/dist/validation/errors.d.ts +22 -2
  66. package/dist/validation/errors.d.ts.map +1 -1
  67. package/dist/validation/index.d.ts +7 -1
  68. package/dist/validation/index.d.ts.map +1 -1
  69. package/dist/validation/rules/array.d.ts +33 -0
  70. package/dist/validation/rules/array.d.ts.map +1 -0
  71. package/dist/validation/rules/common.d.ts +90 -0
  72. package/dist/validation/rules/common.d.ts.map +1 -0
  73. package/dist/validation/rules/conditional.d.ts +30 -0
  74. package/dist/validation/rules/conditional.d.ts.map +1 -0
  75. package/dist/validation/rules/index.d.ts +5 -0
  76. package/dist/validation/rules/index.d.ts.map +1 -0
  77. package/dist/validation/rules/object.d.ts +30 -0
  78. package/dist/validation/rules/object.d.ts.map +1 -0
  79. package/dist/validation/types.d.ts +52 -1
  80. package/dist/validation/types.d.ts.map +1 -1
  81. package/docs/events.md +494 -0
  82. package/docs/guards.md +376 -0
  83. package/docs/guide.md +309 -1
  84. package/docs/request-lifecycle.md +444 -0
  85. package/docs/symbol-interface-pattern.md +431 -0
  86. package/docs/validation.md +407 -0
  87. package/docs/zh/events.md +494 -0
  88. package/docs/zh/guards.md +376 -0
  89. package/docs/zh/guide.md +309 -1
  90. package/docs/zh/request-lifecycle.md +444 -0
  91. package/docs/zh/symbol-interface-pattern.md +431 -0
  92. package/docs/zh/validation.md +407 -0
  93. package/package.json +1 -1
  94. package/src/cache/cache-module.ts +37 -0
  95. package/src/cache/index.ts +16 -1
  96. package/src/cache/interceptors.ts +295 -0
  97. package/src/cache/service-proxy.ts +219 -0
  98. package/src/controller/controller.ts +30 -6
  99. package/src/core/application.ts +25 -1
  100. package/src/di/container.ts +57 -7
  101. package/src/di/decorators.ts +46 -0
  102. package/src/di/index.ts +17 -2
  103. package/src/di/module-registry.ts +39 -0
  104. package/src/di/types.ts +29 -0
  105. package/src/events/decorators.ts +103 -0
  106. package/src/events/event-module.ts +272 -0
  107. package/src/events/index.ts +32 -0
  108. package/src/events/service.ts +352 -0
  109. package/src/events/types.ts +223 -0
  110. package/src/index.ts +140 -1
  111. package/src/security/filter.ts +88 -8
  112. package/src/security/guards/builtin/auth-guard.ts +68 -0
  113. package/src/security/guards/builtin/index.ts +3 -0
  114. package/src/security/guards/builtin/roles-guard.ts +165 -0
  115. package/src/security/guards/decorators.ts +124 -0
  116. package/src/security/guards/execution-context.ts +152 -0
  117. package/src/security/guards/guard-registry.ts +164 -0
  118. package/src/security/guards/index.ts +7 -0
  119. package/src/security/guards/reflector.ts +99 -0
  120. package/src/security/guards/types.ts +144 -0
  121. package/src/security/index.ts +1 -0
  122. package/src/security/security-module.ts +72 -2
  123. package/src/validation/class-validator.ts +322 -0
  124. package/src/validation/custom-validator.ts +289 -0
  125. package/src/validation/errors.ts +50 -2
  126. package/src/validation/index.ts +103 -1
  127. package/src/validation/rules/array.ts +118 -0
  128. package/src/validation/rules/common.ts +286 -0
  129. package/src/validation/rules/conditional.ts +52 -0
  130. package/src/validation/rules/index.ts +51 -0
  131. package/src/validation/rules/object.ts +86 -0
  132. package/src/validation/types.ts +61 -1
  133. package/tests/cache/cache-decorators.test.ts +284 -0
  134. package/tests/controller/path-combination.test.ts +353 -0
  135. package/tests/di/global-module.test.ts +487 -0
  136. package/tests/events/event-decorators.test.ts +173 -0
  137. package/tests/events/event-emitter.test.ts +373 -0
  138. package/tests/events/event-module.test.ts +373 -0
  139. package/tests/security/guards/guards-integration.test.ts +371 -0
  140. package/tests/security/guards/guards.test.ts +775 -0
  141. package/tests/security/security-module.test.ts +2 -2
  142. package/tests/validation/class-validator.test.ts +349 -0
  143. package/tests/validation/custom-validator.test.ts +335 -0
  144. package/tests/validation/rules.test.ts +543 -0
@@ -1,6 +1,8 @@
1
1
  import "reflect-metadata";
2
2
  import {
3
3
  type DependencyMetadata,
4
+ type InstancePostProcessor,
5
+ INSTANCE_POST_PROCESSOR_TOKEN,
4
6
  Lifecycle,
5
7
  type ProviderConfig,
6
8
  } from "./types";
@@ -59,6 +61,11 @@ export class Container {
59
61
  DependencyPlan
60
62
  >();
61
63
 
64
+ /**
65
+ * 实例后处理器列表
66
+ */
67
+ private readonly postProcessors: InstancePostProcessor[] = [];
68
+
62
69
  /**
63
70
  * 注册提供者
64
71
  * @param token - 提供者标识符(类构造函数或 token)
@@ -112,6 +119,45 @@ export class Container {
112
119
  });
113
120
  }
114
121
 
122
+ /**
123
+ * 注册实例后处理器
124
+ * @param processor - 后处理器实例
125
+ */
126
+ public registerPostProcessor(processor: InstancePostProcessor): void {
127
+ this.postProcessors.push(processor);
128
+ // 按优先级排序(数字越小优先级越高)
129
+ this.postProcessors.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
130
+ }
131
+
132
+ /**
133
+ * 应用所有后处理器(包括父容器的后处理器)
134
+ * @param instance - 原始实例
135
+ * @param constructor - 构造函数
136
+ * @param originContainer - 原始调用容器(用于后处理器解析依赖)
137
+ * @returns 处理后的实例
138
+ */
139
+ private applyPostProcessors<T>(
140
+ instance: T,
141
+ constructor: Constructor<T>,
142
+ originContainer?: Container,
143
+ ): T {
144
+ // 使用原始容器或当前容器
145
+ const containerForProcessors = originContainer ?? this;
146
+ let result = instance;
147
+
148
+ // 先应用父容器的后处理器
149
+ if (this.parent) {
150
+ result = (this.parent as Container).applyPostProcessors(result, constructor, containerForProcessors);
151
+ }
152
+
153
+ // 再应用本容器的后处理器
154
+ // 传递原始调用容器,而不是当前容器
155
+ for (const processor of this.postProcessors) {
156
+ result = processor.postProcess(result, constructor, containerForProcessors);
157
+ }
158
+ return result;
159
+ }
160
+
115
161
  /**
116
162
  * 解析依赖
117
163
  * @param token - 提供者标识符
@@ -321,16 +367,19 @@ export class Container {
321
367
  private instantiate<T>(constructor: Constructor<T>): T {
322
368
  const plan = this.getDependencyPlan(constructor);
323
369
 
370
+ let instance: T;
324
371
  if (plan.paramLength === 0) {
325
- return new constructor();
326
- }
327
-
328
- const dependencies = new Array(plan.paramLength);
329
- for (let index = 0; index < plan.paramLength; index++) {
330
- dependencies[index] = this.resolveFromPlan(constructor, plan, index);
372
+ instance = new constructor();
373
+ } else {
374
+ const dependencies = new Array(plan.paramLength);
375
+ for (let index = 0; index < plan.paramLength; index++) {
376
+ dependencies[index] = this.resolveFromPlan(constructor, plan, index);
377
+ }
378
+ instance = new constructor(...dependencies);
331
379
  }
332
380
 
333
- return new constructor(...dependencies);
381
+ // 应用后处理器
382
+ return this.applyPostProcessors(instance, constructor);
334
383
  }
335
384
 
336
385
  /**
@@ -356,6 +405,7 @@ export class Container {
356
405
  this.singletons.clear();
357
406
  this.typeToToken.clear();
358
407
  this.dependencyPlans.clear();
408
+ this.postProcessors.length = 0;
359
409
  // scopedInstances 使用 WeakMap,当 Context 对象被 GC 时会自动清理
360
410
  }
361
411
 
@@ -9,6 +9,11 @@ import type { Constructor } from "@/core/types";
9
9
  const DEPENDENCY_METADATA_KEY = Symbol("dependency:metadata");
10
10
  const INJECTABLE_METADATA_KEY = Symbol("injectable");
11
11
 
12
+ /**
13
+ * 全局模块元数据键
14
+ */
15
+ export const GLOBAL_MODULE_METADATA_KEY = Symbol("@dangao/bun-server:global-module");
16
+
12
17
  /**
13
18
  * 类型引用映射(用于保存构造函数类型,避免 Reflect.defineMetadata 序列化问题)
14
19
  */
@@ -226,3 +231,44 @@ export function getTypeReference(
226
231
  }
227
232
  return undefined as unknown as Constructor<unknown>;
228
233
  }
234
+
235
+ /**
236
+ * Global 装饰器
237
+ * 标记模块为全局模块,其导出的提供者可在任何模块中使用,无需显式导入
238
+ *
239
+ * @example
240
+ * ```typescript
241
+ * @Global()
242
+ * @Module({
243
+ * providers: [ConfigService],
244
+ * exports: [ConfigService],
245
+ * })
246
+ * class GlobalConfigModule {}
247
+ *
248
+ * // 其他模块无需导入 GlobalConfigModule 即可使用 ConfigService
249
+ * @Module({
250
+ * controllers: [UserController],
251
+ * providers: [UserService],
252
+ * })
253
+ * class UserModule {}
254
+ *
255
+ * @Injectable()
256
+ * class UserService {
257
+ * constructor(private readonly config: ConfigService) {}
258
+ * }
259
+ * ```
260
+ */
261
+ export function Global(): ClassDecorator {
262
+ return (target) => {
263
+ Reflect.defineMetadata(GLOBAL_MODULE_METADATA_KEY, true, target);
264
+ };
265
+ }
266
+
267
+ /**
268
+ * 检查模块是否为全局模块
269
+ * @param target - 目标模块类
270
+ * @returns 是否为全局模块
271
+ */
272
+ export function isGlobalModule(target: Constructor<unknown>): boolean {
273
+ return Reflect.getMetadata(GLOBAL_MODULE_METADATA_KEY, target) === true;
274
+ }
package/src/di/index.ts CHANGED
@@ -1,4 +1,19 @@
1
1
  export { Container } from './container';
2
- export { Injectable, Inject, getDependencyMetadata, isInjectable, getLifecycle } from './decorators';
3
- export { Lifecycle, type ProviderConfig, type DependencyMetadata } from './types';
2
+ export {
3
+ Injectable,
4
+ Inject,
5
+ getDependencyMetadata,
6
+ isInjectable,
7
+ getLifecycle,
8
+ Global,
9
+ isGlobalModule,
10
+ GLOBAL_MODULE_METADATA_KEY,
11
+ } from './decorators';
12
+ export {
13
+ Lifecycle,
14
+ INSTANCE_POST_PROCESSOR_TOKEN,
15
+ type ProviderConfig,
16
+ type DependencyMetadata,
17
+ type InstancePostProcessor,
18
+ } from './types';
4
19
 
@@ -2,6 +2,7 @@ import { ControllerRegistry } from '../controller/controller';
2
2
  import { Container } from './container';
3
3
  import { Lifecycle } from './types';
4
4
  import { getModuleMetadata, type ModuleClass, type ModuleProvider, type ProviderToken } from './module';
5
+ import { isGlobalModule } from './decorators';
5
6
  import type { Constructor } from '@/core/types';
6
7
  import type { ApplicationExtension } from '../extensions/types';
7
8
  import type { Middleware } from '../middleware';
@@ -14,6 +15,10 @@ interface ModuleRef {
14
15
  attachedParents: Set<Container>;
15
16
  extensions: ApplicationExtension[];
16
17
  middlewares: Middleware[];
18
+ /**
19
+ * 是否为全局模块
20
+ */
21
+ isGlobal: boolean;
17
22
  }
18
23
 
19
24
  export class ModuleRegistry {
@@ -21,6 +26,10 @@ export class ModuleRegistry {
21
26
  private readonly moduleRefs = new Map<ModuleClass, ModuleRef>();
22
27
  private readonly processing = new Set<ModuleClass>();
23
28
  private rootContainer?: Container;
29
+ /**
30
+ * 存储全局模块列表,用于在其他模块注册时自动附加全局 exports
31
+ */
32
+ private readonly globalModules = new Set<ModuleClass>();
24
33
 
25
34
  public static getInstance(): ModuleRegistry {
26
35
  if (!ModuleRegistry.instance) {
@@ -43,9 +52,17 @@ export class ModuleRegistry {
43
52
  public clear(): void {
44
53
  this.moduleRefs.clear();
45
54
  this.processing.clear();
55
+ this.globalModules.clear();
46
56
  this.rootContainer = undefined;
47
57
  }
48
58
 
59
+ /**
60
+ * 获取所有全局模块
61
+ */
62
+ public getGlobalModules(): ModuleClass[] {
63
+ return Array.from(this.globalModules);
64
+ }
65
+
49
66
  private processModule(moduleClass: ModuleClass, parentContainer: Container): ModuleRef {
50
67
  if (this.processing.has(moduleClass)) {
51
68
  throw new Error(`Circular module dependency detected for ${moduleClass.name}`);
@@ -69,6 +86,7 @@ export class ModuleRegistry {
69
86
  throw new Error('ModuleRegistry is not initialized with a root container');
70
87
  }
71
88
  const metadata = getModuleMetadata(moduleClass);
89
+ const isGlobal = isGlobalModule(moduleClass);
72
90
  const container = new Container({ parent: this.rootContainer });
73
91
  this.registerProviders(container, metadata.providers);
74
92
  ref = {
@@ -79,12 +97,33 @@ export class ModuleRegistry {
79
97
  attachedParents: new Set<Container>(),
80
98
  extensions: metadata.extensions ?? [],
81
99
  middlewares: metadata.middlewares ?? [],
100
+ isGlobal,
82
101
  };
83
102
  this.registerControllers(ref);
84
103
  this.moduleRefs.set(moduleClass, ref);
104
+
105
+ // 如果是全局模块,注册到根容器并记录
106
+ if (isGlobal) {
107
+ this.globalModules.add(moduleClass);
108
+ this.registerGlobalExports(ref);
109
+ }
110
+
85
111
  return ref;
86
112
  }
87
113
 
114
+ /**
115
+ * 将全局模块的 exports 注册到根容器
116
+ * 这样所有模块都可以访问全局模块导出的提供者
117
+ */
118
+ private registerGlobalExports(moduleRef: ModuleRef): void {
119
+ if (!this.rootContainer) {
120
+ return;
121
+ }
122
+ for (const exportedToken of moduleRef.metadata.exports) {
123
+ this.registerExport(this.rootContainer, moduleRef, exportedToken);
124
+ }
125
+ }
126
+
88
127
  private registerProviders(container: Container, providers: ModuleProvider[]): void {
89
128
  for (const provider of providers) {
90
129
  if (typeof provider === 'function') {
package/src/di/types.ts CHANGED
@@ -1,5 +1,34 @@
1
1
  import type { Constructor } from '@/core/types'
2
2
 
3
+ /**
4
+ * 实例后处理器接口
5
+ * 用于在 DI 容器创建实例后进行处理(如创建代理、注入额外依赖等)
6
+ */
7
+ export interface InstancePostProcessor {
8
+ /**
9
+ * 处理新创建的实例
10
+ * @param instance - 原始实例
11
+ * @param constructor - 构造函数
12
+ * @param container - DI 容器引用
13
+ * @returns 处理后的实例(可以是代理)
14
+ */
15
+ postProcess<T>(
16
+ instance: T,
17
+ constructor: Constructor<T>,
18
+ container: unknown,
19
+ ): T;
20
+
21
+ /**
22
+ * 优先级(数字越小优先级越高,默认 100)
23
+ */
24
+ priority?: number;
25
+ }
26
+
27
+ /**
28
+ * 实例后处理器注册表 Token
29
+ */
30
+ export const INSTANCE_POST_PROCESSOR_TOKEN = Symbol('@dangao/bun-server:di:post-processor');
31
+
3
32
  /**
4
33
  * 依赖生命周期类型
5
34
  */
@@ -0,0 +1,103 @@
1
+ import 'reflect-metadata';
2
+ import {
3
+ ON_EVENT_METADATA_KEY,
4
+ EVENT_LISTENER_CLASS_METADATA_KEY,
5
+ type OnEventMethodMetadata,
6
+ } from './types';
7
+
8
+ /**
9
+ * OnEvent 装饰器选项
10
+ */
11
+ export interface OnEventOptions {
12
+ /**
13
+ * 是否异步处理
14
+ * @default false
15
+ */
16
+ async?: boolean;
17
+
18
+ /**
19
+ * 监听器优先级(数值越大优先级越高)
20
+ * @default 0
21
+ */
22
+ priority?: number;
23
+ }
24
+
25
+ /**
26
+ * 事件监听器装饰器
27
+ * 用于标记方法为事件监听器
28
+ *
29
+ * @param event - 事件名称或标识符
30
+ * @param options - 监听选项
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * @Injectable()
35
+ * class NotificationService {
36
+ * @OnEvent('user.created')
37
+ * handleUserCreated(payload: UserCreatedEvent) {
38
+ * console.log('User created:', payload.userId);
39
+ * }
40
+ *
41
+ * @OnEvent(USER_DELETED, { async: true, priority: 10 })
42
+ * async handleUserDeleted(payload: UserDeletedEvent) {
43
+ * await this.cleanup(payload.userId);
44
+ * }
45
+ * }
46
+ * ```
47
+ */
48
+ export function OnEvent(
49
+ event: string | symbol,
50
+ options: OnEventOptions = {},
51
+ ): MethodDecorator {
52
+ return (
53
+ target: object,
54
+ propertyKey: string | symbol,
55
+ descriptor: PropertyDescriptor,
56
+ ): PropertyDescriptor => {
57
+ const methodName = String(propertyKey);
58
+ const constructor = target.constructor;
59
+
60
+ // 获取类上已有的事件监听器元数据
61
+ const existingMetadata: OnEventMethodMetadata[] =
62
+ Reflect.getMetadata(ON_EVENT_METADATA_KEY, constructor) || [];
63
+
64
+ // 添加新的监听器元数据
65
+ const metadata: OnEventMethodMetadata = {
66
+ methodName,
67
+ event,
68
+ async: options.async ?? false,
69
+ priority: options.priority ?? 0,
70
+ };
71
+
72
+ Reflect.defineMetadata(
73
+ ON_EVENT_METADATA_KEY,
74
+ [...existingMetadata, metadata],
75
+ constructor,
76
+ );
77
+
78
+ // 标记类为事件监听器类
79
+ Reflect.defineMetadata(EVENT_LISTENER_CLASS_METADATA_KEY, true, constructor);
80
+
81
+ return descriptor;
82
+ };
83
+ }
84
+
85
+ /**
86
+ * 获取类的事件监听器元数据
87
+ * @param target - 目标类
88
+ */
89
+ export function getOnEventMetadata(
90
+ target: Function,
91
+ ): OnEventMethodMetadata[] | undefined {
92
+ return Reflect.getMetadata(ON_EVENT_METADATA_KEY, target);
93
+ }
94
+
95
+ /**
96
+ * 检查类是否为事件监听器类
97
+ * @param target - 目标类
98
+ */
99
+ export function isEventListenerClass(target: Function): boolean {
100
+ return (
101
+ Reflect.getMetadata(EVENT_LISTENER_CLASS_METADATA_KEY, target) === true
102
+ );
103
+ }
@@ -0,0 +1,272 @@
1
+ import 'reflect-metadata';
2
+ import { Module, MODULE_METADATA_KEY, type ModuleProvider } from '../di/module';
3
+ import type { Container } from '../di/container';
4
+ import { ModuleRegistry } from '../di/module-registry';
5
+
6
+ import { EventEmitterService } from './service';
7
+ import { getOnEventMetadata, isEventListenerClass } from './decorators';
8
+ import {
9
+ EVENT_EMITTER_TOKEN,
10
+ EVENT_OPTIONS_TOKEN,
11
+ type EventModuleOptions,
12
+ type EventEmitter,
13
+ } from './types';
14
+
15
+ /**
16
+ * 事件监听器扫描器
17
+ * 负责扫描和注册带有 @OnEvent() 装饰器的方法
18
+ */
19
+ export class EventListenerScanner {
20
+ /**
21
+ * 构造函数
22
+ * @param eventEmitter - 事件发射器服务
23
+ * @param container - DI 容器
24
+ */
25
+ public constructor(
26
+ private readonly eventEmitter: EventEmitter,
27
+ private readonly container: Container,
28
+ ) {}
29
+
30
+ /**
31
+ * 扫描并注册监听器类
32
+ * @param listenerClasses - 监听器类数组
33
+ */
34
+ public scanAndRegister(listenerClasses: Function[]): void {
35
+ for (const listenerClass of listenerClasses) {
36
+ this.registerListenerClass(listenerClass);
37
+ }
38
+ }
39
+
40
+ /**
41
+ * 注册单个监听器类
42
+ * @param listenerClass - 监听器类
43
+ */
44
+ public registerListenerClass(listenerClass: Function): void {
45
+ if (!isEventListenerClass(listenerClass)) {
46
+ return;
47
+ }
48
+
49
+ const metadata = getOnEventMetadata(listenerClass);
50
+ if (!metadata || metadata.length === 0) {
51
+ return;
52
+ }
53
+
54
+ // 从容器获取监听器实例
55
+ const instance = this.container.resolve<Record<string, Function>>(
56
+ listenerClass as any,
57
+ );
58
+
59
+ if (!instance) {
60
+ console.warn(
61
+ `[EventModule] Failed to resolve listener class: ${listenerClass.name}. ` +
62
+ 'Make sure it is registered as a provider.',
63
+ );
64
+ return;
65
+ }
66
+
67
+ // 注册所有监听器方法
68
+ for (const listenerMetadata of metadata) {
69
+ const method = instance[listenerMetadata.methodName];
70
+ if (typeof method !== 'function') {
71
+ console.warn(
72
+ `[EventModule] Method "${listenerMetadata.methodName}" not found on ${listenerClass.name}`,
73
+ );
74
+ continue;
75
+ }
76
+
77
+ // 绑定方法到实例
78
+ const boundMethod = method.bind(instance);
79
+
80
+ // 注册到事件发射器
81
+ this.eventEmitter.on(listenerMetadata.event, boundMethod, {
82
+ async: listenerMetadata.async,
83
+ priority: listenerMetadata.priority,
84
+ });
85
+ }
86
+ }
87
+ }
88
+
89
+ /**
90
+ * 事件监听器扫描器 Token
91
+ */
92
+ export const EVENT_LISTENER_SCANNER_TOKEN = Symbol(
93
+ '@dangao/bun-server:events:scanner',
94
+ );
95
+
96
+ @Module({
97
+ providers: [],
98
+ })
99
+ export class EventModule {
100
+ /**
101
+ * 已注册的监听器类(用于模块初始化后扫描)
102
+ */
103
+ private static listenerClasses: Function[] = [];
104
+
105
+ /**
106
+ * 创建事件模块
107
+ * @param options - 模块配置
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * @Module({
112
+ * imports: [
113
+ * EventModule.forRoot({
114
+ * wildcard: true,
115
+ * maxListeners: 20,
116
+ * }),
117
+ * ],
118
+ * providers: [NotificationService, AnalyticsService],
119
+ * })
120
+ * class AppModule {}
121
+ * ```
122
+ */
123
+ public static forRoot(options: EventModuleOptions = {}): typeof EventModule {
124
+ const providers: ModuleProvider[] = [];
125
+
126
+ // 创建事件发射器服务
127
+ const eventEmitter = new EventEmitterService(options);
128
+
129
+ // 注册选项
130
+ providers.push({
131
+ provide: EVENT_OPTIONS_TOKEN,
132
+ useValue: options,
133
+ });
134
+
135
+ // 注册事件发射器服务
136
+ providers.push({
137
+ provide: EVENT_EMITTER_TOKEN,
138
+ useValue: eventEmitter,
139
+ });
140
+
141
+ // 更新模块元数据
142
+ const existingMetadata =
143
+ Reflect.getMetadata(MODULE_METADATA_KEY, EventModule) || {};
144
+ const metadata = {
145
+ ...existingMetadata,
146
+ providers: [...(existingMetadata.providers || []), ...providers],
147
+ exports: [
148
+ ...(existingMetadata.exports || []),
149
+ EVENT_EMITTER_TOKEN,
150
+ EVENT_OPTIONS_TOKEN,
151
+ ],
152
+ };
153
+ Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, EventModule);
154
+
155
+ // 清空监听器类列表
156
+ EventModule.listenerClasses = [];
157
+
158
+ return EventModule;
159
+ }
160
+
161
+ /**
162
+ * 注册监听器类
163
+ * 用于在模块配置后手动注册监听器类
164
+ *
165
+ * @param listenerClasses - 监听器类数组
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * EventModule.registerListeners([NotificationService, AnalyticsService]);
170
+ * ```
171
+ */
172
+ public static registerListeners(listenerClasses: Function[]): void {
173
+ EventModule.listenerClasses.push(...listenerClasses);
174
+ }
175
+
176
+ /**
177
+ * 初始化事件监听器扫描
178
+ * 在应用启动时调用,扫描并注册所有监听器
179
+ *
180
+ * @param listenerContainer - 用于解析监听器服务的 DI 容器(通常是应用模块的容器)
181
+ * @param additionalListeners - 额外的监听器类
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * // 在 registerModule 之后调用
186
+ * app.registerModule(RootModule);
187
+ *
188
+ * // 方式1:传入监听器所在模块的容器(推荐)
189
+ * const moduleRef = ModuleRegistry.getInstance().getModuleRef(RootModule);
190
+ * EventModule.initializeListeners(moduleRef?.container, [NotificationService]);
191
+ *
192
+ * // 方式2:如果监听器在 EventModule 的 providers 中注册,可以不传容器
193
+ * EventModule.initializeListeners(undefined, [NotificationService]);
194
+ * ```
195
+ */
196
+ public static initializeListeners(
197
+ listenerContainer?: Container,
198
+ additionalListeners: Function[] = [],
199
+ ): void {
200
+ // 从 EventModule 自身的容器获取 EventEmitter
201
+ const registry = ModuleRegistry.getInstance();
202
+ const eventModuleRef = registry.getModuleRef(EventModule);
203
+
204
+ let eventEmitter: EventEmitter | undefined;
205
+
206
+ if (eventModuleRef) {
207
+ try {
208
+ eventEmitter = eventModuleRef.container.resolve<EventEmitter>(EVENT_EMITTER_TOKEN);
209
+ } catch {
210
+ // 忽略错误
211
+ }
212
+ }
213
+
214
+ if (!eventEmitter) {
215
+ console.warn(
216
+ '[EventModule] EventEmitter not found. Make sure EventModule.forRoot() is called and the module is registered.',
217
+ );
218
+ return;
219
+ }
220
+
221
+ // 确定用于解析监听器的容器
222
+ // 优先使用传入的容器,否则使用 EventModule 的容器
223
+ const resolveContainer = listenerContainer ?? eventModuleRef?.container;
224
+
225
+ if (!resolveContainer) {
226
+ console.warn(
227
+ '[EventModule] No container available to resolve listeners.',
228
+ );
229
+ return;
230
+ }
231
+
232
+ const scanner = new EventListenerScanner(eventEmitter, resolveContainer);
233
+
234
+ // 扫描所有注册的监听器类
235
+ const allListeners = [
236
+ ...EventModule.listenerClasses,
237
+ ...additionalListeners,
238
+ ];
239
+ scanner.scanAndRegister(allListeners);
240
+ }
241
+
242
+ /**
243
+ * 获取事件发射器服务(静态方法)
244
+ * 用于在模块配置后获取事件发射器
245
+ *
246
+ * @param container - DI 容器(可选,如果不提供则从 EventModule 自身的容器获取)
247
+ */
248
+ public static getEventEmitter(container?: Container): EventEmitter | undefined {
249
+ // 优先从 EventModule 自身的容器获取
250
+ const registry = ModuleRegistry.getInstance();
251
+ const moduleRef = registry.getModuleRef(EventModule);
252
+
253
+ if (moduleRef) {
254
+ try {
255
+ return moduleRef.container.resolve<EventEmitter>(EVENT_EMITTER_TOKEN);
256
+ } catch {
257
+ // 忽略错误,尝试从传入的容器获取
258
+ }
259
+ }
260
+
261
+ // 尝试从传入的容器获取
262
+ if (container) {
263
+ try {
264
+ return container.resolve<EventEmitter>(EVENT_EMITTER_TOKEN);
265
+ } catch {
266
+ // 忽略错误
267
+ }
268
+ }
269
+
270
+ return undefined;
271
+ }
272
+ }
@@ -0,0 +1,32 @@
1
+ // 类型导出
2
+ export {
3
+ EVENT_EMITTER_TOKEN,
4
+ EVENT_OPTIONS_TOKEN,
5
+ ON_EVENT_METADATA_KEY,
6
+ EVENT_LISTENER_CLASS_METADATA_KEY,
7
+ type EventEmitter,
8
+ type EventListener,
9
+ type EventMetadata,
10
+ type EventModuleOptions,
11
+ type ListenerOptions,
12
+ type OnEventMethodMetadata,
13
+ type RegisteredListener,
14
+ } from './types';
15
+
16
+ // 服务导出
17
+ export { EventEmitterService } from './service';
18
+
19
+ // 装饰器导出
20
+ export {
21
+ OnEvent,
22
+ getOnEventMetadata,
23
+ isEventListenerClass,
24
+ type OnEventOptions,
25
+ } from './decorators';
26
+
27
+ // 模块导出
28
+ export {
29
+ EventModule,
30
+ EventListenerScanner,
31
+ EVENT_LISTENER_SCANNER_TOKEN,
32
+ } from './event-module';