@dangao/bun-server 1.8.2 → 1.9.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.
@@ -1 +1 @@
1
- {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../../src/middleware/builtin/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAOhD,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAE7E;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,mBAAwB,GAChC,UAAU,CA4DZ"}
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../../src/middleware/builtin/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAOhD,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAE7E;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,mBAAwB,GAChC,UAAU,CAsEZ"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/middleware/builtin/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAEtE;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,uBAA4B,GACpC,UAAU,CAsBZ;AAED,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACpE;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,GAAE,qBAA0B,GAClC,UAAU,CAkCZ"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/middleware/builtin/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAEtE;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,uBAA4B,GACpC,UAAU,CA8BZ;AAED,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACpE;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,GAAE,qBAA0B,GAClC,UAAU,CA2CZ"}
@@ -19,27 +19,27 @@ export interface RouteMetadata {
19
19
  }
20
20
  /**
21
21
  * GET 路由装饰器
22
- * @param path - 路由路径
22
+ * @param path - 路由路径(可选,默认 '',即 @GET() 映射到控制器基础路径或 /)
23
23
  */
24
- export declare function GET(path: string): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
24
+ export declare function GET(path?: string): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
25
25
  /**
26
26
  * POST 路由装饰器
27
- * @param path - 路由路径
27
+ * @param path - 路由路径(可选,默认 '')
28
28
  */
29
- export declare function POST(path: string): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
29
+ export declare function POST(path?: string): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
30
30
  /**
31
31
  * PUT 路由装饰器
32
- * @param path - 路由路径
32
+ * @param path - 路由路径(可选,默认 '')
33
33
  */
34
- export declare function PUT(path: string): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
34
+ export declare function PUT(path?: string): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
35
35
  /**
36
36
  * DELETE 路由装饰器
37
- * @param path - 路由路径
37
+ * @param path - 路由路径(可选,默认 '')
38
38
  */
39
- export declare function DELETE(path: string): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
39
+ export declare function DELETE(path?: string): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
40
40
  /**
41
41
  * PATCH 路由装饰器
42
- * @param path - 路由路径
42
+ * @param path - 路由路径(可选,默认 '')
43
43
  */
44
- export declare function PATCH(path: string): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
44
+ export declare function PATCH(path?: string): (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
45
45
  //# sourceMappingURL=decorators.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/router/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C;;GAEG;AACH,eAAO,MAAM,kBAAkB,eAAkB,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;IACtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA8DD;;;GAGG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,YAzDL,GAAG,eAAe,MAAM,GAAG,MAAM,cAAc,kBAAkB,UA2D3F;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,YAjEN,GAAG,eAAe,MAAM,GAAG,MAAM,cAAc,kBAAkB,UAmE3F;AAED;;;GAGG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,YAzEL,GAAG,eAAe,MAAM,GAAG,MAAM,cAAc,kBAAkB,UA2E3F;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,YAjFR,GAAG,eAAe,MAAM,GAAG,MAAM,cAAc,kBAAkB,UAmF3F;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,YAzFP,GAAG,eAAe,MAAM,GAAG,MAAM,cAAc,kBAAkB,UA2F3F"}
1
+ {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/router/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C;;GAEG;AACH,eAAO,MAAM,kBAAkB,eAAkB,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;IACtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA8DD;;;GAGG;AACH,wBAAgB,GAAG,CAAC,IAAI,GAAE,MAAW,YAzDV,GAAG,eAAe,MAAM,GAAG,MAAM,cAAc,kBAAkB,UA2D3F;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,IAAI,GAAE,MAAW,YAjEX,GAAG,eAAe,MAAM,GAAG,MAAM,cAAc,kBAAkB,UAmE3F;AAED;;;GAGG;AACH,wBAAgB,GAAG,CAAC,IAAI,GAAE,MAAW,YAzEV,GAAG,eAAe,MAAM,GAAG,MAAM,cAAc,kBAAkB,UA2E3F;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,IAAI,GAAE,MAAW,YAjFb,GAAG,eAAe,MAAM,GAAG,MAAM,cAAc,kBAAkB,UAmF3F;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,IAAI,GAAE,MAAW,YAzFZ,GAAG,eAAe,MAAM,GAAG,MAAM,cAAc,kBAAkB,UA2F3F"}
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,qBAAa,MAAM;IACjB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4B;IACzD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAE7C;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0D;IAErF;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;;;;OAQG;IACI,QAAQ,CACb,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,WAAW,GAAE,UAAU,EAAO,EAC9B,eAAe,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,EACtC,UAAU,CAAC,EAAE,MAAM,GAClB,IAAI;IAgBP;;;;OAIG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIrF;;;;OAIG;IACI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAItF;;;;OAIG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIrF;;;;OAIG;IACI,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIxF;;;;OAIG;IACI,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIvF;;;;;OAKG;IACI,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAKrE;;;;;OAKG;IACI,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,GAAG,SAAS;IAmC5G;;;OAGG;IACU,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBvD;;;;OAIG;IACU,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IA4BpE;;;OAGG;IACI,SAAS,IAAI,SAAS,KAAK,EAAE;IAIpC;;OAEG;IACI,KAAK,IAAI,IAAI;CAMrB"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD;;;GAGG;AACH,qBAAa,MAAM;IACjB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4B;IACzD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAE7C;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0D;IAErF;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;;;;OAQG;IACI,QAAQ,CACb,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,WAAW,GAAE,UAAU,EAAO,EAC9B,eAAe,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,EACtC,UAAU,CAAC,EAAE,MAAM,GAClB,IAAI;IAgBP;;;;OAIG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIrF;;;;OAIG;IACI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAItF;;;;OAIG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIrF;;;;OAIG;IACI,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIxF;;;;OAIG;IACI,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,GAAE,UAAU,EAAO,GAAG,IAAI;IAIvF;;;;;OAKG;IACI,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAKrE;;;;;OAKG;IACI,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,GAAG,SAAS;IAmC5G;;;OAGG;IACU,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCvD;;;;OAIG;IACU,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAmCpE;;;OAGG;IACI,SAAS,IAAI,SAAS,KAAK,EAAE;IAIpC;;OAEG;IACI,KAAK,IAAI,IAAI;CAMrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dangao/bun-server",
3
- "version": "1.8.2",
3
+ "version": "1.9.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -15,6 +15,7 @@ import {
15
15
  InterceptorChain,
16
16
  scanInterceptorMetadata,
17
17
  } from '../interceptor';
18
+ import { LoggerManager } from '@dangao/logsmith';
18
19
 
19
20
  /**
20
21
  * 控制器元数据键
@@ -212,6 +213,13 @@ export class ControllerRegistry {
212
213
  // 创建响应
213
214
  return context.createResponse(responseData);
214
215
  } catch (error) {
216
+ LoggerManager.getLogger().debug('Controller handler error', {
217
+ controller: controllerClass.name,
218
+ method: propertyKey,
219
+ path: context.path,
220
+ errorMessage: error instanceof Error ? error.message : String(error),
221
+ stack: error instanceof Error ? error.stack : undefined,
222
+ });
215
223
  // 使用全局错误处理器,确保错误码和国际化正确应用
216
224
  const { handleError } = await import('../error/handler');
217
225
  return await handleError(error, context);
@@ -258,8 +266,8 @@ export class ControllerRegistry {
258
266
  base = '/';
259
267
  }
260
268
 
261
- // 规范化 methodPath:移除前导斜杠
262
- const method = methodPath.replace(/^\/+/, '');
269
+ // 规范化 methodPath:移除前导斜杠(支持 undefined,如 @GET() 无参)
270
+ const method = (methodPath ?? '').replace(/^\/+/, '');
263
271
 
264
272
  if (!method) {
265
273
  // 如果方法路径为空,返回基础路径
@@ -18,6 +18,7 @@ import { ConfigService } from '../config/service';
18
18
  import { ConfigModule } from '../config/config-module';
19
19
  import { CacheModule, CACHE_POST_PROCESSOR_TOKEN } from '../cache';
20
20
  import { LoggerManager } from '@dangao/logsmith';
21
+ import { EventModule } from '../events/event-module';
21
22
 
22
23
  /**
23
24
  * 应用配置选项
@@ -102,6 +103,9 @@ export class Application {
102
103
  // 初始化配置中心集成(在所有模块注册完成后)
103
104
  await this.initializeConfigCenter();
104
105
 
106
+ // 自动初始化事件监听器(如果 EventModule 已注册且启用了 autoScan)
107
+ this.initializeEventListeners();
108
+
105
109
  const finalPort = port ?? this.options.port ?? 3000;
106
110
  const finalHostname = hostname ?? this.options.hostname;
107
111
 
@@ -178,6 +182,31 @@ export class Application {
178
182
  }
179
183
  }
180
184
 
185
+ /**
186
+ * 初始化事件监听器
187
+ * 在所有模块注册完成后调用,自动扫描并注册使用 @OnEvent 装饰器的类
188
+ */
189
+ private initializeEventListeners(): void {
190
+ const container = this.getContainer();
191
+
192
+ // 检查 EventModule 是否已注册
193
+ const registry = ModuleRegistry.getInstance();
194
+ const eventModuleRef = registry.getModuleRef(EventModule);
195
+
196
+ if (!eventModuleRef) {
197
+ // EventModule 未注册,跳过
198
+ return;
199
+ }
200
+
201
+ // 调用自动初始化
202
+ const initialized = EventModule.autoInitialize(container);
203
+
204
+ if (initialized) {
205
+ const logger = LoggerManager.getLogger();
206
+ logger.debug('[Application] Event listeners initialized automatically');
207
+ }
208
+ }
209
+
181
210
  /**
182
211
  * 停止应用(立即停止,不等待请求完成)
183
212
  */
@@ -242,6 +271,13 @@ export class Application {
242
271
  * @returns 响应对象
243
272
  */
244
273
  private async handleRequest(context: Context): Promise<Response> {
274
+ const logger = LoggerManager.getLogger();
275
+ logger.debug('[Request] Incoming', {
276
+ method: context.method,
277
+ path: context.path,
278
+ url: context.url?.href,
279
+ });
280
+
245
281
  // 使用 AsyncLocalStorage 包裹请求处理,确保所有中间件和控制器都在请求上下文中执行
246
282
  return await contextStore.run(context, async () => {
247
283
  // 对于 POST、PUT、PATCH 请求,提前解析 body 并缓存
@@ -265,6 +301,10 @@ export class Application {
265
301
  return response;
266
302
  }
267
303
 
304
+ logger.debug('[Router] No route matched', {
305
+ method: context.method,
306
+ path: context.path,
307
+ });
268
308
  context.setStatus(404);
269
309
  return context.createResponse({ error: 'Not Found' });
270
310
  });
@@ -3,6 +3,7 @@ import { HttpException } from './http-exception';
3
3
  import { ExceptionFilterRegistry } from './filter';
4
4
  import { ValidationError } from '../validation';
5
5
  import { ErrorMessageI18n } from './i18n';
6
+ import { LoggerManager } from '@dangao/logsmith';
6
7
 
7
8
  /**
8
9
  * 全局错误处理
@@ -16,6 +17,15 @@ export async function handleError(error: unknown, context: Context): Promise<Res
16
17
 
17
18
  if (error instanceof HttpException) {
18
19
  context.setStatus(error.status);
20
+ if (error.status >= 400) {
21
+ LoggerManager.getLogger().debug('HttpException', {
22
+ method: context.method,
23
+ path: context.path,
24
+ status: error.status,
25
+ code: error.code,
26
+ message: error.message,
27
+ });
28
+ }
19
29
 
20
30
  // 如果异常有错误码,尝试国际化消息
21
31
  let errorMessage = error.message;
@@ -56,7 +66,14 @@ export async function handleError(error: unknown, context: Context): Promise<Res
56
66
  }
57
67
 
58
68
  const message = error instanceof Error ? error.message : String(error);
69
+ const stack = error instanceof Error ? error.stack : undefined;
59
70
  context.setStatus(500);
71
+ LoggerManager.getLogger().debug('Internal error (500)', {
72
+ method: context.method,
73
+ path: context.path,
74
+ message,
75
+ stack,
76
+ });
60
77
  return context.createResponse({
61
78
  error: 'Internal Server Error',
62
79
  details: process.env.NODE_ENV === 'production' ? undefined : message,
@@ -102,6 +102,11 @@ export class EventModule {
102
102
  */
103
103
  private static listenerClasses: Function[] = [];
104
104
 
105
+ /**
106
+ * 模块选项
107
+ */
108
+ private static options: EventModuleOptions & { autoScan?: boolean } = {};
109
+
105
110
  /**
106
111
  * 创建事件模块
107
112
  * @param options - 模块配置
@@ -121,6 +126,12 @@ export class EventModule {
121
126
  * ```
122
127
  */
123
128
  public static forRoot(options: EventModuleOptions = {}): typeof EventModule {
129
+ // 保存选项(默认启用自动扫描)
130
+ EventModule.options = {
131
+ ...options,
132
+ autoScan: options.autoScan ?? true,
133
+ };
134
+
124
135
  const providers: ModuleProvider[] = [];
125
136
 
126
137
  // 创建事件发射器服务
@@ -269,4 +280,101 @@ export class EventModule {
269
280
 
270
281
  return undefined;
271
282
  }
283
+
284
+ /**
285
+ * 自动初始化事件监听器
286
+ * 由框架在应用启动时自动调用,扫描所有模块中使用 @OnEvent 装饰器的类并注册
287
+ *
288
+ * @param rootContainer - 根容器
289
+ * @returns 是否成功初始化
290
+ *
291
+ * @internal 此方法由框架内部调用,用户通常不需要手动调用
292
+ */
293
+ public static autoInitialize(rootContainer: Container): boolean {
294
+ // 检查是否启用自动扫描
295
+ if (EventModule.options.autoScan === false) {
296
+ return false;
297
+ }
298
+
299
+ // 获取 EventEmitter
300
+ const registry = ModuleRegistry.getInstance();
301
+ const eventModuleRef = registry.getModuleRef(EventModule);
302
+
303
+ if (!eventModuleRef) {
304
+ return false;
305
+ }
306
+
307
+ let eventEmitter: EventEmitter | undefined;
308
+ try {
309
+ eventEmitter = eventModuleRef.container.resolve<EventEmitter>(EVENT_EMITTER_TOKEN);
310
+ } catch {
311
+ return false;
312
+ }
313
+
314
+ if (!eventEmitter) {
315
+ return false;
316
+ }
317
+
318
+ // 收集所有监听器类
319
+ const listenerClasses = new Set<Function>();
320
+
321
+ // 1. 添加通过 registerListeners 注册的类
322
+ for (const listenerClass of EventModule.listenerClasses) {
323
+ listenerClasses.add(listenerClass);
324
+ }
325
+
326
+ // 2. 添加通过选项配置的强制包含类
327
+ if (EventModule.options.includeListeners) {
328
+ for (const listenerClass of EventModule.options.includeListeners) {
329
+ listenerClasses.add(listenerClass);
330
+ }
331
+ }
332
+
333
+ // 3. 自动扫描所有模块的 providers,并从对应的模块容器中解析实例
334
+ const shouldAutoScan = EventModule.options.autoScan ?? true;
335
+ if (shouldAutoScan === true) {
336
+ const allModuleRefs = Array.from(registry['moduleRefs'].values());
337
+
338
+ for (const moduleRef of allModuleRefs) {
339
+ for (const provider of moduleRef.metadata.providers) {
340
+ // 提取提供者类
341
+ let providerClass: Function | undefined;
342
+
343
+ if (typeof provider === 'function') {
344
+ providerClass = provider;
345
+ } else if ('useClass' in provider && provider.useClass) {
346
+ providerClass = provider.useClass;
347
+ }
348
+
349
+ // 检查是否是事件监听器类
350
+ if (providerClass && isEventListenerClass(providerClass)) {
351
+ // 检查是否被排除
352
+ const isExcluded = EventModule.options.excludeListeners?.includes(providerClass);
353
+ if (!isExcluded) {
354
+ // 使用模块容器创建 scanner 并注册监听器
355
+ // 这样可以确保解析的实例和控制器中注入的是同一个
356
+ const scanner = new EventListenerScanner(eventEmitter, moduleRef.container);
357
+ scanner.registerListenerClass(providerClass);
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+
364
+ // 4. 注册通过选项配置的强制包含类(使用根容器)
365
+ if (EventModule.options.includeListeners) {
366
+ const scanner = new EventListenerScanner(eventEmitter, rootContainer);
367
+ for (const listenerClass of EventModule.options.includeListeners) {
368
+ scanner.registerListenerClass(listenerClass);
369
+ }
370
+ }
371
+
372
+ // 5. 注册通过 registerListeners 注册的类(使用根容器)
373
+ if (EventModule.listenerClasses.length > 0) {
374
+ const scanner = new EventListenerScanner(eventEmitter, rootContainer);
375
+ scanner.scanAndRegister(EventModule.listenerClasses);
376
+ }
377
+
378
+ return true;
379
+ }
272
380
  }
@@ -173,6 +173,25 @@ export interface EventModuleOptions {
173
173
  * @param payload - 事件负载
174
174
  */
175
175
  onError?: (error: Error, event: string | symbol, payload: unknown) => void;
176
+
177
+ /**
178
+ * 是否自动扫描和注册事件监听器
179
+ * 当设置为 true 时,框架会在应用启动时自动扫描所有模块中使用 @OnEvent 装饰器的类
180
+ * @default true
181
+ */
182
+ autoScan?: boolean;
183
+
184
+ /**
185
+ * 需要排除的监听器类(不自动注册)
186
+ * 用于在自动扫描时排除某些类
187
+ */
188
+ excludeListeners?: Function[];
189
+
190
+ /**
191
+ * 额外的监听器类(强制注册)
192
+ * 即使 autoScan 为 false,这些类也会被注册
193
+ */
194
+ includeListeners?: Function[];
176
195
  }
177
196
 
178
197
  /**
@@ -41,12 +41,22 @@ export function createErrorHandlingMiddleware(
41
41
  try {
42
42
  return await next();
43
43
  } catch (error) {
44
+ const routeHandler = (context as { routeHandler?: { controller?: { name?: string }; method?: string } }).routeHandler;
44
45
  log(error, { method: context.method, path: context.path });
45
46
  logger.error("Unhandled error", {
46
47
  method: context.method,
47
48
  path: context.path,
48
49
  error,
49
50
  });
51
+ logger.debug("Unhandled error details", {
52
+ method: context.method,
53
+ path: context.path,
54
+ routeHandler: routeHandler
55
+ ? `${routeHandler.controller?.name ?? 'unknown'}.${routeHandler.method ?? 'unknown'}`
56
+ : undefined,
57
+ errorMessage: error instanceof Error ? error.message : String(error),
58
+ stack: error instanceof Error ? error.stack : undefined,
59
+ });
50
60
 
51
61
  if (error instanceof Response) {
52
62
  return error as Response;
@@ -38,6 +38,14 @@ export function createLoggerMiddleware(
38
38
  } finally {
39
39
  const status = response?.status ?? context.statusCode ?? 200;
40
40
  log(`${prefix} ${context.method} ${context.path} ${status}`);
41
+ if (status >= 400) {
42
+ const logger = LoggerManager.getLogger();
43
+ logger.debug(`${prefix} Error response`, {
44
+ method: context.method,
45
+ path: context.path,
46
+ statusCode: status,
47
+ });
48
+ }
41
49
  }
42
50
  };
43
51
  }
@@ -85,6 +93,15 @@ export function createRequestLoggingMiddleware(
85
93
  }ms`,
86
94
  error instanceof Error ? { error: error.message } : undefined,
87
95
  );
96
+ if (error instanceof Error) {
97
+ LoggerManager.getLogger().debug(`${prefix} Request error details`, {
98
+ method: context.method,
99
+ path: context.path,
100
+ durationMs: duration.toFixed(2),
101
+ message: error.message,
102
+ stack: error.stack,
103
+ });
104
+ }
88
105
  throw error;
89
106
  }
90
107
  };
@@ -25,10 +25,10 @@ export interface RouteMetadata {
25
25
  /**
26
26
  * 路由装饰器工厂
27
27
  * @param method - HTTP 方法
28
- * @param path - 路由路径
28
+ * @param path - 路由路径(可选,默认 '',即 @GET() 等价于根路径)
29
29
  * @returns 方法装饰器
30
30
  */
31
- function createRouteDecorator(method: HttpMethod, path: string) {
31
+ function createRouteDecorator(method: HttpMethod, path: string = '') {
32
32
  return function (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) {
33
33
  // 注意:装饰器应用顺序问题
34
34
  // 方法装饰器(@GET)在类装饰器(@Controller)之前应用
@@ -72,9 +72,9 @@ function createRouteDecorator(method: HttpMethod, path: string) {
72
72
  }
73
73
  }
74
74
 
75
- existingRoutes.push({
76
- method,
77
- path,
75
+ existingRoutes.push({
76
+ method,
77
+ path: path ?? '',
78
78
  handler: descriptor.value as RouteHandler,
79
79
  propertyKey: propertyKeyStr || undefined,
80
80
  });
@@ -84,40 +84,40 @@ function createRouteDecorator(method: HttpMethod, path: string) {
84
84
 
85
85
  /**
86
86
  * GET 路由装饰器
87
- * @param path - 路由路径
87
+ * @param path - 路由路径(可选,默认 '',即 @GET() 映射到控制器基础路径或 /)
88
88
  */
89
- export function GET(path: string) {
89
+ export function GET(path: string = '') {
90
90
  return createRouteDecorator('GET', path);
91
91
  }
92
92
 
93
93
  /**
94
94
  * POST 路由装饰器
95
- * @param path - 路由路径
95
+ * @param path - 路由路径(可选,默认 '')
96
96
  */
97
- export function POST(path: string) {
97
+ export function POST(path: string = '') {
98
98
  return createRouteDecorator('POST', path);
99
99
  }
100
100
 
101
101
  /**
102
102
  * PUT 路由装饰器
103
- * @param path - 路由路径
103
+ * @param path - 路由路径(可选,默认 '')
104
104
  */
105
- export function PUT(path: string) {
105
+ export function PUT(path: string = '') {
106
106
  return createRouteDecorator('PUT', path);
107
107
  }
108
108
 
109
109
  /**
110
110
  * DELETE 路由装饰器
111
- * @param path - 路由路径
111
+ * @param path - 路由路径(可选,默认 '')
112
112
  */
113
- export function DELETE(path: string) {
113
+ export function DELETE(path: string = '') {
114
114
  return createRouteDecorator('DELETE', path);
115
115
  }
116
116
 
117
117
  /**
118
118
  * PATCH 路由装饰器
119
- * @param path - 路由路径
119
+ * @param path - 路由路径(可选,默认 '')
120
120
  */
121
- export function PATCH(path: string) {
121
+ export function PATCH(path: string = '') {
122
122
  return createRouteDecorator('PATCH', path);
123
123
  }
@@ -3,6 +3,7 @@ import type { Constructor } from '../core/types';
3
3
  import { Route } from './route';
4
4
  import type { HttpMethod, RouteHandler, RouteMatch } from './types';
5
5
  import type { Middleware } from '../middleware';
6
+ import { LoggerManager } from '@dangao/logsmith';
6
7
 
7
8
  /**
8
9
  * 路由器类
@@ -168,14 +169,23 @@ export class Router {
168
169
  public async preHandle(context: Context): Promise<void> {
169
170
  const method = context.method as HttpMethod;
170
171
  const path = this.normalizePath(context.path);
172
+ const logger = LoggerManager.getLogger();
171
173
 
172
174
  // 使用 findRouteWithMatch 避免重复匹配
173
175
  const result = this.findRouteWithMatch(method, path);
174
176
  if (!result) {
177
+ logger.debug('[Router] Route not matched', { method, path });
175
178
  return;
176
179
  }
177
180
 
178
181
  const { route, match } = result;
182
+ logger.debug('[Router] Route matched', {
183
+ method,
184
+ path,
185
+ routePath: route.path,
186
+ controller: route.controllerClass?.name,
187
+ methodName: route.methodName,
188
+ });
179
189
  if (match.matched) {
180
190
  context.params = match.params;
181
191
  }
@@ -196,6 +206,7 @@ export class Router {
196
206
  public async handle(context: Context): Promise<Response | undefined> {
197
207
  const method = context.method as HttpMethod;
198
208
  const path = this.normalizePath(context.path);
209
+ const logger = LoggerManager.getLogger();
199
210
 
200
211
  // 使用 findRouteWithMatch 获取路由和匹配结果
201
212
  const result = this.findRouteWithMatch(method, path);
@@ -204,7 +215,13 @@ export class Router {
204
215
  }
205
216
 
206
217
  const { route, match } = result;
207
-
218
+
219
+ logger.debug('[Router] Executing handler', {
220
+ path: route.path,
221
+ controller: route.controllerClass?.name,
222
+ methodName: route.methodName,
223
+ });
224
+
208
225
  // 设置路径参数
209
226
  if (match.matched) {
210
227
  context.params = match.params;