@dangao/bun-server 3.2.0 → 3.3.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 (131) hide show
  1. package/dist/ai/types.d.ts +4 -0
  2. package/dist/ai/types.d.ts.map +1 -1
  3. package/dist/auth/types.d.ts +4 -0
  4. package/dist/auth/types.d.ts.map +1 -1
  5. package/dist/cache/interceptors.d.ts +3 -3
  6. package/dist/cache/interceptors.d.ts.map +1 -1
  7. package/dist/cache/service.d.ts +6 -6
  8. package/dist/cache/service.d.ts.map +1 -1
  9. package/dist/cache/types.d.ts +12 -12
  10. package/dist/cache/types.d.ts.map +1 -1
  11. package/dist/config/service.d.ts +6 -4
  12. package/dist/config/service.d.ts.map +1 -1
  13. package/dist/core/application.d.ts +4 -0
  14. package/dist/core/application.d.ts.map +1 -1
  15. package/dist/core/context.d.ts +4 -2
  16. package/dist/core/context.d.ts.map +1 -1
  17. package/dist/database/sqlite-adapter.d.ts +4 -2
  18. package/dist/database/sqlite-adapter.d.ts.map +1 -1
  19. package/dist/di/container.d.ts +2 -0
  20. package/dist/di/container.d.ts.map +1 -1
  21. package/dist/di/module-registry.d.ts.map +1 -1
  22. package/dist/di/module.d.ts +11 -1
  23. package/dist/di/module.d.ts.map +1 -1
  24. package/dist/di/types.d.ts +1 -1
  25. package/dist/di/types.d.ts.map +1 -1
  26. package/dist/error/handler.d.ts.map +1 -1
  27. package/dist/error/http-exception.d.ts +8 -8
  28. package/dist/error/http-exception.d.ts.map +1 -1
  29. package/dist/error/index.d.ts +1 -0
  30. package/dist/error/index.d.ts.map +1 -1
  31. package/dist/events/service.d.ts +2 -2
  32. package/dist/events/service.d.ts.map +1 -1
  33. package/dist/events/types.d.ts +12 -3
  34. package/dist/events/types.d.ts.map +1 -1
  35. package/dist/index.js +63 -25
  36. package/dist/index.node.mjs +63 -25
  37. package/dist/interceptor/base-interceptor.d.ts +3 -3
  38. package/dist/interceptor/base-interceptor.d.ts.map +1 -1
  39. package/dist/interceptor/builtin/log-interceptor.d.ts +1 -1
  40. package/dist/interceptor/builtin/log-interceptor.d.ts.map +1 -1
  41. package/dist/interceptor/builtin/permission-interceptor.d.ts +1 -1
  42. package/dist/interceptor/builtin/permission-interceptor.d.ts.map +1 -1
  43. package/dist/interceptor/interceptor-chain.d.ts +1 -1
  44. package/dist/interceptor/interceptor-chain.d.ts.map +1 -1
  45. package/dist/interceptor/interceptor-registry.d.ts +3 -1
  46. package/dist/interceptor/interceptor-registry.d.ts.map +1 -1
  47. package/dist/interceptor/types.d.ts +6 -1
  48. package/dist/interceptor/types.d.ts.map +1 -1
  49. package/dist/microservice/service-client/types.d.ts +1 -0
  50. package/dist/microservice/service-client/types.d.ts.map +1 -1
  51. package/dist/microservice/tracing/tracer.d.ts +1 -0
  52. package/dist/microservice/tracing/tracer.d.ts.map +1 -1
  53. package/dist/middleware/builtin/file-upload.d.ts +2 -0
  54. package/dist/middleware/builtin/file-upload.d.ts.map +1 -1
  55. package/dist/middleware/builtin/rate-limit.d.ts +9 -1
  56. package/dist/middleware/builtin/rate-limit.d.ts.map +1 -1
  57. package/dist/queue/service.d.ts +2 -2
  58. package/dist/queue/service.d.ts.map +1 -1
  59. package/dist/queue/types.d.ts +25 -1
  60. package/dist/queue/types.d.ts.map +1 -1
  61. package/dist/router/decorators.d.ts +1 -2
  62. package/dist/router/decorators.d.ts.map +1 -1
  63. package/dist/security/guards/types.d.ts +1 -0
  64. package/dist/security/guards/types.d.ts.map +1 -1
  65. package/dist/security/types.d.ts +1 -1
  66. package/dist/security/types.d.ts.map +1 -1
  67. package/dist/session/types.d.ts +8 -0
  68. package/dist/session/types.d.ts.map +1 -1
  69. package/dist/swagger/decorators.d.ts +1 -1
  70. package/dist/swagger/decorators.d.ts.map +1 -1
  71. package/dist/swagger/types.d.ts +1 -1
  72. package/dist/swagger/types.d.ts.map +1 -1
  73. package/dist/testing/harness.d.ts +1 -1
  74. package/dist/testing/harness.d.ts.map +1 -1
  75. package/dist/testing/test-client.d.ts +1 -1
  76. package/dist/testing/test-client.d.ts.map +1 -1
  77. package/dist/testing/testing-module.d.ts +2 -2
  78. package/dist/testing/testing-module.d.ts.map +1 -1
  79. package/dist/validation/errors.d.ts +5 -1
  80. package/dist/validation/errors.d.ts.map +1 -1
  81. package/package.json +3 -3
  82. package/src/ai/types.ts +5 -0
  83. package/src/auth/types.ts +4 -1
  84. package/src/cache/interceptors.ts +6 -6
  85. package/src/cache/service-proxy.ts +2 -2
  86. package/src/cache/service.ts +17 -8
  87. package/src/cache/types.ts +12 -12
  88. package/src/config/service.ts +8 -6
  89. package/src/core/application.ts +7 -1
  90. package/src/core/context.ts +6 -3
  91. package/src/database/sqlite-adapter.ts +4 -3
  92. package/src/di/container.ts +13 -0
  93. package/src/di/module-registry.ts +2 -3
  94. package/src/di/module.ts +21 -2
  95. package/src/di/types.ts +1 -2
  96. package/src/error/handler.ts +3 -4
  97. package/src/error/http-exception.ts +11 -11
  98. package/src/error/index.ts +1 -1
  99. package/src/events/service.ts +4 -2
  100. package/src/events/types.ts +14 -3
  101. package/src/interceptor/base-interceptor.ts +5 -6
  102. package/src/interceptor/builtin/log-interceptor.ts +2 -3
  103. package/src/interceptor/builtin/permission-interceptor.ts +2 -3
  104. package/src/interceptor/interceptor-chain.ts +6 -7
  105. package/src/interceptor/interceptor-registry.ts +5 -3
  106. package/src/interceptor/types.ts +9 -4
  107. package/src/microservice/service-client/types.ts +1 -1
  108. package/src/microservice/tracing/tracer.ts +15 -3
  109. package/src/middleware/builtin/file-upload.ts +3 -2
  110. package/src/middleware/builtin/rate-limit.ts +22 -5
  111. package/src/queue/service.ts +1 -1
  112. package/src/queue/types.ts +40 -1
  113. package/src/router/decorators.ts +2 -3
  114. package/src/security/guards/types.ts +2 -1
  115. package/src/security/types.ts +1 -2
  116. package/src/session/service.ts +1 -1
  117. package/src/session/types.ts +10 -0
  118. package/src/swagger/decorators.ts +15 -4
  119. package/src/swagger/generator.ts +2 -3
  120. package/src/swagger/types.ts +1 -2
  121. package/src/testing/harness.ts +1 -2
  122. package/src/testing/test-client.ts +2 -2
  123. package/src/testing/testing-module.ts +5 -5
  124. package/src/validation/errors.ts +6 -2
  125. package/tests/bun-test-shim.d.ts +11 -0
  126. package/tests/controller/context-decorator.test.ts +1 -2
  127. package/tests/di/module.test.ts +199 -1
  128. package/tests/events/event-emitter.test.ts +2 -2
  129. package/tests/global.d.ts +30 -0
  130. package/tests/queue/queue-service.test.ts +14 -0
  131. package/tests/testing/testing-module.test.ts +20 -0
@@ -91,8 +91,8 @@ export class CacheableInterceptor extends BaseInterceptor {
91
91
  public async execute<T>(
92
92
  target: unknown,
93
93
  propertyKey: string | symbol,
94
- originalMethod: (...args: unknown[]) => T | Promise<T>,
95
- args: unknown[],
94
+ originalMethod: (...args: any[]) => T | Promise<T>,
95
+ args: any[],
96
96
  container: Container,
97
97
  context?: Context,
98
98
  ): Promise<T> {
@@ -164,8 +164,8 @@ export class CacheEvictInterceptor extends BaseInterceptor {
164
164
  public async execute<T>(
165
165
  target: unknown,
166
166
  propertyKey: string | symbol,
167
- originalMethod: (...args: unknown[]) => T | Promise<T>,
168
- args: unknown[],
167
+ originalMethod: (...args: any[]) => T | Promise<T>,
168
+ args: any[],
169
169
  container: Container,
170
170
  context?: Context,
171
171
  ): Promise<T> {
@@ -238,8 +238,8 @@ export class CachePutInterceptor extends BaseInterceptor {
238
238
  public async execute<T>(
239
239
  target: unknown,
240
240
  propertyKey: string | symbol,
241
- originalMethod: (...args: unknown[]) => T | Promise<T>,
242
- args: unknown[],
241
+ originalMethod: (...args: any[]) => T | Promise<T>,
242
+ args: any[],
243
243
  container: Container,
244
244
  context?: Context,
245
245
  ): Promise<T> {
@@ -87,9 +87,9 @@ export class CacheServiceProxy {
87
87
 
88
88
  // 返回包装后的方法
89
89
  // 使用原型方法以确保拦截器能获取到正确的元数据
90
- const originalMethod = prototypeMethod as (...args: unknown[]) => unknown;
90
+ const originalMethod = prototypeMethod as (...args: any[]) => unknown;
91
91
 
92
- return async function (this: T, ...args: unknown[]): Promise<unknown> {
92
+ return async function (this: T, ...args: any[]): Promise<unknown> {
93
93
  // 按优先级执行拦截器:CacheEvict (beforeInvocation) -> Cacheable/CachePut -> CacheEvict (afterInvocation)
94
94
 
95
95
  // 如果有 @CacheEvict 且配置了 beforeInvocation
@@ -13,11 +13,14 @@ export class CacheService {
13
13
  private keyPrefix: string;
14
14
 
15
15
  public constructor(
16
- @Inject(CACHE_OPTIONS_TOKEN) options: CacheModuleOptions,
16
+ @Inject(CACHE_OPTIONS_TOKEN) options: CacheModuleOptions | CacheStore,
17
17
  ) {
18
- this.store = options.store!;
19
- this.defaultTtl = options.defaultTtl ?? 3600000; // 1 小时
20
- this.keyPrefix = options.keyPrefix ?? '';
18
+ const resolvedOptions: CacheModuleOptions = isCacheStore(options)
19
+ ? { store: options }
20
+ : options;
21
+ this.store = resolvedOptions.store!;
22
+ this.defaultTtl = resolvedOptions.defaultTtl ?? 3600000; // 1 小时
23
+ this.keyPrefix = resolvedOptions.keyPrefix ?? '';
21
24
  }
22
25
 
23
26
  /**
@@ -25,7 +28,7 @@ export class CacheService {
25
28
  * @param key - 缓存键
26
29
  * @returns 缓存值,如果不存在则返回 undefined
27
30
  */
28
- public async get<T = unknown>(key: string): Promise<T | undefined> {
31
+ public async get<T = any>(key: string): Promise<T | undefined> {
29
32
  return this.store.get<T>(this.getKey(key));
30
33
  }
31
34
 
@@ -36,7 +39,7 @@ export class CacheService {
36
39
  * @param ttl - 过期时间(毫秒),0 表示永不过期,undefined 使用默认 TTL
37
40
  * @returns 是否设置成功
38
41
  */
39
- public async set<T = unknown>(
42
+ public async set<T = any>(
40
43
  key: string,
41
44
  value: T,
42
45
  ttl?: number,
@@ -76,7 +79,7 @@ export class CacheService {
76
79
  * @param keys - 缓存键数组
77
80
  * @returns 缓存值映射
78
81
  */
79
- public async getMany<T = unknown>(
82
+ public async getMany<T = any>(
80
83
  keys: string[],
81
84
  ): Promise<Map<string, T>> {
82
85
  const prefixedKeys = keys.map((k) => this.getKey(k));
@@ -97,7 +100,7 @@ export class CacheService {
97
100
  * @param ttl - 过期时间(毫秒),0 表示永不过期,undefined 使用默认 TTL
98
101
  * @returns 是否设置成功
99
102
  */
100
- public async setMany<T = unknown>(
103
+ public async setMany<T = any>(
101
104
  entries: Array<{ key: string; value: T }>,
102
105
  ttl?: number,
103
106
  ): Promise<boolean> {
@@ -149,3 +152,9 @@ export class CacheService {
149
152
  return this.keyPrefix ? `${this.keyPrefix}${key}` : key;
150
153
  }
151
154
  }
155
+
156
+ function isCacheStore(value: CacheModuleOptions | CacheStore): value is CacheStore {
157
+ return typeof (value as CacheStore).get === 'function' &&
158
+ typeof (value as CacheStore).set === 'function' &&
159
+ typeof (value as CacheStore).delete === 'function';
160
+ }
@@ -7,7 +7,7 @@ export interface CacheStore {
7
7
  * @param key - 缓存键
8
8
  * @returns 缓存值,如果不存在则返回 undefined
9
9
  */
10
- get<T = unknown>(key: string): Promise<T | undefined>;
10
+ get<T = any>(key: string): Promise<T | undefined>;
11
11
 
12
12
  /**
13
13
  * 设置缓存值
@@ -16,7 +16,7 @@ export interface CacheStore {
16
16
  * @param ttl - 过期时间(毫秒),0 表示永不过期
17
17
  * @returns 是否设置成功
18
18
  */
19
- set<T = unknown>(key: string, value: T, ttl?: number): Promise<boolean>;
19
+ set<T = any>(key: string, value: T, ttl?: number): Promise<boolean>;
20
20
 
21
21
  /**
22
22
  * 删除缓存
@@ -43,7 +43,7 @@ export interface CacheStore {
43
43
  * @param keys - 缓存键数组
44
44
  * @returns 缓存值映射
45
45
  */
46
- getMany<T = unknown>(keys: string[]): Promise<Map<string, T>>;
46
+ getMany<T = any>(keys: string[]): Promise<Map<string, T>>;
47
47
 
48
48
  /**
49
49
  * 设置多个缓存值
@@ -51,7 +51,7 @@ export interface CacheStore {
51
51
  * @param ttl - 过期时间(毫秒),0 表示永不过期
52
52
  * @returns 是否设置成功
53
53
  */
54
- setMany<T = unknown>(
54
+ setMany<T = any>(
55
55
  entries: Array<{ key: string; value: T }>,
56
56
  ttl?: number,
57
57
  ): Promise<boolean>;
@@ -84,7 +84,7 @@ export class MemoryCacheStore implements CacheStore {
84
84
  }
85
85
  }
86
86
 
87
- public async get<T = unknown>(key: string): Promise<T | undefined> {
87
+ public async get<T = any>(key: string): Promise<T | undefined> {
88
88
  const entry = this.store.get(key);
89
89
  if (!entry) {
90
90
  return undefined;
@@ -99,7 +99,7 @@ export class MemoryCacheStore implements CacheStore {
99
99
  return entry.value as T;
100
100
  }
101
101
 
102
- public async set<T = unknown>(
102
+ public async set<T = any>(
103
103
  key: string,
104
104
  value: T,
105
105
  ttl?: number,
@@ -133,7 +133,7 @@ export class MemoryCacheStore implements CacheStore {
133
133
  return true;
134
134
  }
135
135
 
136
- public async getMany<T = unknown>(
136
+ public async getMany<T = any>(
137
137
  keys: string[],
138
138
  ): Promise<Map<string, T>> {
139
139
  const result = new Map<string, T>();
@@ -154,7 +154,7 @@ export class MemoryCacheStore implements CacheStore {
154
154
  return result;
155
155
  }
156
156
 
157
- public async setMany<T = unknown>(
157
+ public async setMany<T = any>(
158
158
  entries: Array<{ key: string; value: T }>,
159
159
  ttl?: number,
160
160
  ): Promise<boolean> {
@@ -239,7 +239,7 @@ export class RedisCacheStore implements CacheStore {
239
239
  return `${this.keyPrefix}${key}`;
240
240
  }
241
241
 
242
- public async get<T = unknown>(key: string): Promise<T | undefined> {
242
+ public async get<T = any>(key: string): Promise<T | undefined> {
243
243
  const value = await this.client.get(this.getKey(key));
244
244
  if (value === null) {
245
245
  return undefined;
@@ -251,7 +251,7 @@ export class RedisCacheStore implements CacheStore {
251
251
  }
252
252
  }
253
253
 
254
- public async set<T = unknown>(
254
+ public async set<T = any>(
255
255
  key: string,
256
256
  value: T,
257
257
  ttl?: number,
@@ -296,7 +296,7 @@ export class RedisCacheStore implements CacheStore {
296
296
  }
297
297
  }
298
298
 
299
- public async getMany<T = unknown>(
299
+ public async getMany<T = any>(
300
300
  keys: string[],
301
301
  ): Promise<Map<string, T>> {
302
302
  const result = new Map<string, T>();
@@ -325,7 +325,7 @@ export class RedisCacheStore implements CacheStore {
325
325
  return result;
326
326
  }
327
327
 
328
- public async setMany<T = unknown>(
328
+ public async setMany<T = any>(
329
329
  entries: Array<{ key: string; value: T }>,
330
330
  ttl?: number,
331
331
  ): Promise<boolean> {
@@ -67,12 +67,12 @@ export class ConfigService<TConfig extends Record<string, unknown> = Record<stri
67
67
  * 更新配置(用于配置中心动态刷新)
68
68
  * @param newConfig - 新配置对象
69
69
  */
70
- public updateConfig(newConfig: TConfig): void {
71
- this.config = newConfig;
70
+ public updateConfig(newConfig: TConfig | Record<string, unknown>): void {
71
+ this.config = newConfig as TConfig;
72
72
  // 通知所有监听器
73
73
  for (const listener of this.configUpdateListeners) {
74
74
  try {
75
- listener(newConfig);
75
+ listener(this.config);
76
76
  } catch (error) {
77
77
  console.error('[ConfigService] Error in config update listener:', error);
78
78
  }
@@ -83,7 +83,7 @@ export class ConfigService<TConfig extends Record<string, unknown> = Record<stri
83
83
  * 合并配置(用于配置中心增量更新)
84
84
  * @param partialConfig - 部分配置对象
85
85
  */
86
- public mergeConfig(partialConfig: Partial<TConfig>): void {
86
+ public mergeConfig(partialConfig: Partial<TConfig> | Record<string, unknown>): void {
87
87
  this.config = {
88
88
  ...this.config,
89
89
  ...partialConfig,
@@ -125,6 +125,8 @@ export class ConfigService<TConfig extends Record<string, unknown> = Record<stri
125
125
  * @param key - 配置键(如 "db.host")
126
126
  * @param defaultValue - 默认值(可选)
127
127
  */
128
+ public get(key: string): any;
129
+ public get<T>(key: string, defaultValue?: T): T | undefined;
128
130
  public get<T = unknown>(key: string, defaultValue?: T): T | undefined {
129
131
  const namespacedKey = this.applyNamespace(key);
130
132
  const value = this.getValueByPath(this.config, namespacedKey);
@@ -138,6 +140,8 @@ export class ConfigService<TConfig extends Record<string, unknown> = Record<stri
138
140
  * 获取必需的配置值,如果不存在则抛出错误
139
141
  * @param key - 配置键
140
142
  */
143
+ public getRequired(key: string): any;
144
+ public getRequired<T>(key: string): T;
141
145
  public getRequired<T = unknown>(key: string): T {
142
146
  const value = this.get<T>(key);
143
147
  if (value === undefined) {
@@ -191,5 +195,3 @@ export class ConfigService<TConfig extends Record<string, unknown> = Record<stri
191
195
  return current;
192
196
  }
193
197
  }
194
-
195
-
@@ -490,6 +490,13 @@ export class Application {
490
490
  return this.server;
491
491
  }
492
492
 
493
+ /**
494
+ * 获取底层平台服务器实例
495
+ */
496
+ public getNativeServer(): unknown {
497
+ return this.server?.getNativeServer();
498
+ }
499
+
493
500
  /**
494
501
  * 自动注册服务到注册中心
495
502
  * 扫描所有使用 @ServiceRegistry 装饰器的控制器,自动注册服务
@@ -639,4 +646,3 @@ export class Application {
639
646
  this.signalHandlersInstalled = false;
640
647
  }
641
648
  }
642
-
@@ -1,5 +1,6 @@
1
1
  import { BodyParser } from '../request/body-parser';
2
2
  import type { UploadedFileInfo } from '../files';
3
+ import type { Container } from '../di/container';
3
4
  import type { BodyInit } from 'bun'
4
5
  import { type URLSearchParams, URL } from 'url';
5
6
 
@@ -32,7 +33,7 @@ export class Context {
32
33
  /**
33
34
  * 请求路径
34
35
  */
35
- public readonly path: string;
36
+ public path: string;
36
37
 
37
38
  /**
38
39
  * 查询参数
@@ -80,8 +81,11 @@ export class Context {
80
81
  */
81
82
  public readonly signal: AbortSignal;
82
83
 
83
- public constructor(request: Request) {
84
+ public readonly container?: Container;
85
+
86
+ public constructor(request: Request, container?: Container) {
84
87
  this.request = request;
88
+ this.container = container;
85
89
  this.url = new URL(request.url);
86
90
  this.method = request.method;
87
91
  this.path = this.url.pathname;
@@ -304,4 +308,3 @@ export class Context {
304
308
  return sanitized;
305
309
  }
306
310
  }
307
-
@@ -1,6 +1,8 @@
1
1
  import type { SqliteV2Config } from './types';
2
2
  import { getRuntime } from '../platform/runtime';
3
3
 
4
+ type SqliteV2InputConfig = SqliteV2Config | Omit<SqliteV2Config, 'type'>;
5
+
4
6
  export interface DisposableLock {
5
7
  [Symbol.dispose](): void;
6
8
  }
@@ -47,7 +49,7 @@ export class SqliteAdapter {
47
49
  public readonly semaphore: Semaphore;
48
50
  private readonly isBun: boolean;
49
51
 
50
- public constructor(config: SqliteV2Config) {
52
+ public constructor(config: SqliteV2InputConfig) {
51
53
  this.isBun = getRuntime().engine === 'bun';
52
54
 
53
55
  if (this.isBun) {
@@ -119,7 +121,7 @@ export class SqliteManager {
119
121
  private readonly instances = new Map<string, SqliteAdapter>();
120
122
  private defaultTenantId = 'default';
121
123
 
122
- public getOrCreate(tenantId: string, config: SqliteV2Config): SqliteAdapter {
124
+ public getOrCreate(tenantId: string, config: SqliteV2InputConfig): SqliteAdapter {
123
125
  const existing = this.instances.get(tenantId);
124
126
  if (existing) {
125
127
  return existing;
@@ -167,4 +169,3 @@ export class SqliteManager {
167
169
  }
168
170
  }
169
171
  }
170
-
@@ -78,10 +78,21 @@ export class Container {
78
78
  * @param token - 提供者标识符(类构造函数或 token)
79
79
  * @param config - 提供者配置
80
80
  */
81
+ public register<T>(
82
+ token: Constructor<T> | string | symbol,
83
+ implementation: Constructor<unknown>,
84
+ ): void;
81
85
  public register<T>(
82
86
  token: Constructor<T> | string | symbol,
83
87
  config?: ProviderConfig,
88
+ ): void;
89
+ public register<T>(
90
+ token: Constructor<T> | string | symbol,
91
+ configOrImplementation?: ProviderConfig | Constructor<unknown>,
84
92
  ): void {
93
+ const config: ProviderConfig | undefined = typeof configOrImplementation === 'function'
94
+ ? { implementation: configOrImplementation }
95
+ : configOrImplementation;
85
96
  const tokenKey = this.getTokenKey(token);
86
97
 
87
98
  // 如果配置中没有指定生命周期,尝试从装饰器元数据获取
@@ -170,6 +181,8 @@ export class Container {
170
181
  * @param token - 提供者标识符
171
182
  * @returns 解析后的实例
172
183
  */
184
+ public resolve(token: string | symbol): any;
185
+ public resolve<T>(token: Constructor<T> | string | symbol): T;
173
186
  public resolve<T>(token: Constructor<T> | string | symbol): T {
174
187
  const tokenKey = this.getTokenKey(token);
175
188
  const provider = this.providers.get(tokenKey);
@@ -1,7 +1,7 @@
1
1
  import { ControllerRegistry } from '../controller/controller';
2
2
  import { Container } from './container';
3
3
  import { Lifecycle } from './types';
4
- import { getModuleMetadata, type ModuleClass, type ModuleProvider, type ProviderToken } from './module';
4
+ import { getModuleMetadata, invokeFactoryProvider, type ModuleClass, type ModuleProvider, type ProviderToken } from './module';
5
5
  import { isGlobalModule } from './decorators';
6
6
  import type { Constructor } from '@/core/types';
7
7
  import type { ApplicationExtension } from '../extensions/types';
@@ -160,7 +160,7 @@ export class ModuleRegistry {
160
160
  if ('useFactory' in provider) {
161
161
  container.register(provider.provide, {
162
162
  lifecycle: provider.lifecycle ?? Lifecycle.Singleton,
163
- factory: () => provider.useFactory(container),
163
+ factory: () => invokeFactoryProvider(provider, container),
164
164
  });
165
165
  continue;
166
166
  }
@@ -378,4 +378,3 @@ export class ModuleRegistry {
378
378
  });
379
379
  }
380
380
  }
381
-
package/src/di/module.ts CHANGED
@@ -22,10 +22,30 @@ export interface ValueProvider {
22
22
 
23
23
  export interface FactoryProvider {
24
24
  provide: ProviderToken;
25
- useFactory: (container: Container) => unknown;
25
+ /**
26
+ * 同步工厂函数。
27
+ * - 当 inject 存在且非空时,按 inject 顺序解析 token,并作为位置参数传入。
28
+ * - 当 inject 缺省或为空时,为保持向后兼容,将当前 Container 作为唯一参数传入。
29
+ */
30
+ useFactory: (...args: any[]) => unknown;
31
+ /**
32
+ * 可选的依赖 token 列表。依赖会在工厂被调用时按容器规则惰性解析。
33
+ */
34
+ inject?: ProviderToken[];
26
35
  lifecycle?: Lifecycle;
27
36
  }
28
37
 
38
+ export function invokeFactoryProvider(
39
+ provider: FactoryProvider,
40
+ container: Container,
41
+ ): unknown {
42
+ const inject = provider.inject ?? [];
43
+ if (inject.length > 0) {
44
+ return provider.useFactory(...inject.map((token) => container.resolve(token)));
45
+ }
46
+ return provider.useFactory(container);
47
+ }
48
+
29
49
  /**
30
50
  * NestJS 风格别名:`provide` 解析为已注册的 `useExisting` 同一实例(不新建)。
31
51
  */
@@ -76,4 +96,3 @@ export function getModuleMetadata(moduleClass: ModuleClass): Required<Omit<Modul
76
96
  middlewares: metadata.middlewares ?? [],
77
97
  };
78
98
  }
79
-
package/src/di/types.ts CHANGED
@@ -71,7 +71,7 @@ export interface ProviderConfig {
71
71
  /**
72
72
  * 实际实现类(当 token 为 string/symbol 时用于实例化)
73
73
  */
74
- implementation?: new (...args: unknown[]) => unknown;
74
+ implementation?: Constructor<unknown>;
75
75
  }
76
76
 
77
77
  /**
@@ -93,4 +93,3 @@ export interface DependencyMetadata {
93
93
  */
94
94
  token?: string | symbol;
95
95
  }
96
-
@@ -4,6 +4,7 @@ import { ExceptionFilterRegistry } from './filter';
4
4
  import { ValidationError } from '../validation';
5
5
  import { ErrorMessageI18n } from './i18n';
6
6
  import { LoggerManager } from '@dangao/logsmith';
7
+ import { ERROR_CODE_MESSAGES, type ErrorCode } from './error-codes';
7
8
 
8
9
  /**
9
10
  * 全局错误处理
@@ -29,12 +30,12 @@ export async function handleError(error: unknown, context: Context): Promise<Res
29
30
 
30
31
  // 如果异常有错误码,尝试国际化消息
31
32
  let errorMessage = error.message;
32
- if (error.code) {
33
+ if (error.code && error.code in ERROR_CODE_MESSAGES) {
33
34
  const acceptLanguage = context.getHeader('accept-language');
34
35
  const language = ErrorMessageI18n.parseLanguageFromHeader(acceptLanguage);
35
36
  // 如果提供了消息模板参数,使用参数替换占位符
36
37
  errorMessage = ErrorMessageI18n.getMessage(
37
- error.code,
38
+ error.code as ErrorCode,
38
39
  language,
39
40
  error.messageParams,
40
41
  );
@@ -79,5 +80,3 @@ export async function handleError(error: unknown, context: Context): Promise<Res
79
80
  details: process.env.NODE_ENV === 'production' ? undefined : message,
80
81
  });
81
82
  }
82
-
83
-
@@ -6,7 +6,7 @@ import type { MessageParams } from './i18n';
6
6
  */
7
7
  export class HttpException extends Error {
8
8
  public readonly status: number;
9
- public readonly code?: ErrorCode;
9
+ public readonly code?: ErrorCode | string;
10
10
  public readonly details?: unknown;
11
11
  public readonly messageParams?: MessageParams;
12
12
 
@@ -14,7 +14,7 @@ export class HttpException extends Error {
14
14
  status: number,
15
15
  message: string,
16
16
  details?: unknown,
17
- code?: ErrorCode,
17
+ code?: ErrorCode | string,
18
18
  messageParams?: MessageParams,
19
19
  ) {
20
20
  super(message);
@@ -46,13 +46,14 @@ export class HttpException extends Error {
46
46
  * ```
47
47
  */
48
48
  public static withCode(
49
- code: ErrorCode,
49
+ code: ErrorCode | string,
50
50
  message?: string,
51
51
  details?: unknown,
52
52
  messageParams?: MessageParams,
53
53
  ): HttpException {
54
- const status = ERROR_CODE_TO_STATUS[code] || 500;
55
- const finalMessage = message || ERROR_CODE_MESSAGES[code] || 'Internal Server Error';
54
+ const knownCode = code as ErrorCode;
55
+ const status = ERROR_CODE_TO_STATUS[knownCode] || 500;
56
+ const finalMessage = message || ERROR_CODE_MESSAGES[knownCode] || 'Internal Server Error';
56
57
  return new HttpException(status, finalMessage, details, code, messageParams);
57
58
  }
58
59
  }
@@ -61,7 +62,7 @@ export class BadRequestException extends HttpException {
61
62
  public constructor(
62
63
  message: string = 'Bad Request',
63
64
  details?: unknown,
64
- code?: ErrorCode,
65
+ code?: ErrorCode | string,
65
66
  messageParams?: MessageParams,
66
67
  ) {
67
68
  super(400, message, details, code, messageParams);
@@ -72,7 +73,7 @@ export class UnauthorizedException extends HttpException {
72
73
  public constructor(
73
74
  message: string = 'Unauthorized',
74
75
  details?: unknown,
75
- code?: ErrorCode,
76
+ code?: ErrorCode | string,
76
77
  messageParams?: MessageParams,
77
78
  ) {
78
79
  super(401, message, details, code, messageParams);
@@ -83,7 +84,7 @@ export class ForbiddenException extends HttpException {
83
84
  public constructor(
84
85
  message: string = 'Forbidden',
85
86
  details?: unknown,
86
- code?: ErrorCode,
87
+ code?: ErrorCode | string,
87
88
  messageParams?: MessageParams,
88
89
  ) {
89
90
  super(403, message, details, code, messageParams);
@@ -94,7 +95,7 @@ export class NotFoundException extends HttpException {
94
95
  public constructor(
95
96
  message: string = 'Not Found',
96
97
  details?: unknown,
97
- code?: ErrorCode,
98
+ code?: ErrorCode | string,
98
99
  messageParams?: MessageParams,
99
100
  ) {
100
101
  super(404, message, details, code, messageParams);
@@ -105,11 +106,10 @@ export class InternalServerErrorException extends HttpException {
105
106
  public constructor(
106
107
  message: string = 'Internal Server Error',
107
108
  details?: unknown,
108
- code?: ErrorCode,
109
+ code?: ErrorCode | string,
109
110
  messageParams?: MessageParams,
110
111
  ) {
111
112
  super(500, message, details, code, messageParams);
112
113
  }
113
114
  }
114
115
 
115
-
@@ -12,5 +12,5 @@ export { handleError } from './handler';
12
12
  export { ErrorCode, ERROR_CODE_MESSAGES, ERROR_CODE_TO_STATUS } from './error-codes';
13
13
  export { ErrorMessageI18n } from './i18n';
14
14
  export type { SupportedLanguage, MessageParams } from './i18n';
15
-
15
+ export type { Context } from '../core/context';
16
16
 
@@ -36,7 +36,7 @@ export class EventEmitterService implements EventEmitter {
36
36
  /**
37
37
  * 发布事件(同步触发所有监听器,不等待异步监听器完成)
38
38
  */
39
- public emit<T>(event: string | symbol, payload: T): void {
39
+ public emit<T = undefined>(event: string | symbol, payload?: T): void {
40
40
  const eventName = this.resolveEventName(event);
41
41
  const matchedListeners = this.getMatchedListeners(eventName);
42
42
 
@@ -70,7 +70,7 @@ export class EventEmitterService implements EventEmitter {
70
70
  /**
71
71
  * 异步发布事件(等待所有监听器完成)
72
72
  */
73
- public async emitAsync<T>(event: string | symbol, payload: T): Promise<void> {
73
+ public async emitAsync<T = undefined>(event: string | symbol, payload?: T): Promise<void> {
74
74
  const eventName = this.resolveEventName(event);
75
75
  const matchedListeners = this.getMatchedListeners(eventName);
76
76
 
@@ -342,6 +342,8 @@ export class EventEmitterService implements EventEmitter {
342
342
  ): void {
343
343
  if (this.options.onError) {
344
344
  this.options.onError(error, event, payload);
345
+ } else if (this.options.errorHandler) {
346
+ this.options.errorHandler(String(event), error, payload);
345
347
  } else {
346
348
  console.error(
347
349
  `[EventEmitter] Error in listener for event "${String(event)}":`,
@@ -3,7 +3,7 @@
3
3
  * @template T - 事件负载类型
4
4
  */
5
5
  export interface EventListener<T = unknown> {
6
- (payload: T): void | Promise<void>;
6
+ (payload: T): unknown | Promise<unknown>;
7
7
  }
8
8
 
9
9
  /**
@@ -62,14 +62,14 @@ export interface EventEmitter {
62
62
  * @param event - 事件名称或标识符
63
63
  * @param payload - 事件负载
64
64
  */
65
- emit<T>(event: string | symbol, payload: T): void;
65
+ emit<T = undefined>(event: string | symbol, payload?: T): void;
66
66
 
67
67
  /**
68
68
  * 异步发布事件(等待所有监听器完成)
69
69
  * @param event - 事件名称或标识符
70
70
  * @param payload - 事件负载
71
71
  */
72
- emitAsync<T>(event: string | symbol, payload: T): Promise<void>;
72
+ emitAsync<T = undefined>(event: string | symbol, payload?: T): Promise<void>;
73
73
 
74
74
  /**
75
75
  * 订阅事件
@@ -166,6 +166,12 @@ export interface EventModuleOptions {
166
166
  */
167
167
  maxListeners?: number;
168
168
 
169
+ /**
170
+ * 默认是否异步处理监听器,兼容早期模块配置。
171
+ * @default false
172
+ */
173
+ async?: boolean;
174
+
169
175
  /**
170
176
  * 错误处理函数
171
177
  * @param error - 错误对象
@@ -174,6 +180,11 @@ export interface EventModuleOptions {
174
180
  */
175
181
  onError?: (error: Error, event: string | symbol, payload: unknown) => void;
176
182
 
183
+ /**
184
+ * 错误处理函数别名,参数顺序为 (event, error)。
185
+ */
186
+ errorHandler?: (event: string, error: Error, payload: unknown) => void;
187
+
177
188
  /**
178
189
  * 是否自动扫描和注册事件监听器
179
190
  * 当设置为 true 时,框架会在应用启动时自动扫描所有模块中使用 @OnEvent 装饰器的类