@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.
- package/dist/ai/types.d.ts +4 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/auth/types.d.ts +4 -0
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/cache/interceptors.d.ts +3 -3
- package/dist/cache/interceptors.d.ts.map +1 -1
- package/dist/cache/service.d.ts +6 -6
- package/dist/cache/service.d.ts.map +1 -1
- package/dist/cache/types.d.ts +12 -12
- package/dist/cache/types.d.ts.map +1 -1
- package/dist/config/service.d.ts +6 -4
- package/dist/config/service.d.ts.map +1 -1
- package/dist/core/application.d.ts +4 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/context.d.ts +4 -2
- package/dist/core/context.d.ts.map +1 -1
- package/dist/database/sqlite-adapter.d.ts +4 -2
- package/dist/database/sqlite-adapter.d.ts.map +1 -1
- package/dist/di/container.d.ts +2 -0
- package/dist/di/container.d.ts.map +1 -1
- package/dist/di/module-registry.d.ts.map +1 -1
- package/dist/di/module.d.ts +11 -1
- package/dist/di/module.d.ts.map +1 -1
- package/dist/di/types.d.ts +1 -1
- package/dist/di/types.d.ts.map +1 -1
- package/dist/error/handler.d.ts.map +1 -1
- package/dist/error/http-exception.d.ts +8 -8
- package/dist/error/http-exception.d.ts.map +1 -1
- package/dist/error/index.d.ts +1 -0
- package/dist/error/index.d.ts.map +1 -1
- package/dist/events/service.d.ts +2 -2
- package/dist/events/service.d.ts.map +1 -1
- package/dist/events/types.d.ts +12 -3
- package/dist/events/types.d.ts.map +1 -1
- package/dist/index.js +63 -25
- package/dist/index.node.mjs +63 -25
- package/dist/interceptor/base-interceptor.d.ts +3 -3
- package/dist/interceptor/base-interceptor.d.ts.map +1 -1
- package/dist/interceptor/builtin/log-interceptor.d.ts +1 -1
- package/dist/interceptor/builtin/log-interceptor.d.ts.map +1 -1
- package/dist/interceptor/builtin/permission-interceptor.d.ts +1 -1
- package/dist/interceptor/builtin/permission-interceptor.d.ts.map +1 -1
- package/dist/interceptor/interceptor-chain.d.ts +1 -1
- package/dist/interceptor/interceptor-chain.d.ts.map +1 -1
- package/dist/interceptor/interceptor-registry.d.ts +3 -1
- package/dist/interceptor/interceptor-registry.d.ts.map +1 -1
- package/dist/interceptor/types.d.ts +6 -1
- package/dist/interceptor/types.d.ts.map +1 -1
- package/dist/microservice/service-client/types.d.ts +1 -0
- package/dist/microservice/service-client/types.d.ts.map +1 -1
- package/dist/microservice/tracing/tracer.d.ts +1 -0
- package/dist/microservice/tracing/tracer.d.ts.map +1 -1
- package/dist/middleware/builtin/file-upload.d.ts +2 -0
- package/dist/middleware/builtin/file-upload.d.ts.map +1 -1
- package/dist/middleware/builtin/rate-limit.d.ts +9 -1
- package/dist/middleware/builtin/rate-limit.d.ts.map +1 -1
- package/dist/queue/service.d.ts +2 -2
- package/dist/queue/service.d.ts.map +1 -1
- package/dist/queue/types.d.ts +25 -1
- package/dist/queue/types.d.ts.map +1 -1
- package/dist/router/decorators.d.ts +1 -2
- package/dist/router/decorators.d.ts.map +1 -1
- package/dist/security/guards/types.d.ts +1 -0
- package/dist/security/guards/types.d.ts.map +1 -1
- package/dist/security/types.d.ts +1 -1
- package/dist/security/types.d.ts.map +1 -1
- package/dist/session/types.d.ts +8 -0
- package/dist/session/types.d.ts.map +1 -1
- package/dist/swagger/decorators.d.ts +1 -1
- package/dist/swagger/decorators.d.ts.map +1 -1
- package/dist/swagger/types.d.ts +1 -1
- package/dist/swagger/types.d.ts.map +1 -1
- package/dist/testing/harness.d.ts +1 -1
- package/dist/testing/harness.d.ts.map +1 -1
- package/dist/testing/test-client.d.ts +1 -1
- package/dist/testing/test-client.d.ts.map +1 -1
- package/dist/testing/testing-module.d.ts +2 -2
- package/dist/testing/testing-module.d.ts.map +1 -1
- package/dist/validation/errors.d.ts +5 -1
- package/dist/validation/errors.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/ai/types.ts +5 -0
- package/src/auth/types.ts +4 -1
- package/src/cache/interceptors.ts +6 -6
- package/src/cache/service-proxy.ts +2 -2
- package/src/cache/service.ts +17 -8
- package/src/cache/types.ts +12 -12
- package/src/config/service.ts +8 -6
- package/src/core/application.ts +7 -1
- package/src/core/context.ts +6 -3
- package/src/database/sqlite-adapter.ts +4 -3
- package/src/di/container.ts +13 -0
- package/src/di/module-registry.ts +2 -3
- package/src/di/module.ts +21 -2
- package/src/di/types.ts +1 -2
- package/src/error/handler.ts +3 -4
- package/src/error/http-exception.ts +11 -11
- package/src/error/index.ts +1 -1
- package/src/events/service.ts +4 -2
- package/src/events/types.ts +14 -3
- package/src/interceptor/base-interceptor.ts +5 -6
- package/src/interceptor/builtin/log-interceptor.ts +2 -3
- package/src/interceptor/builtin/permission-interceptor.ts +2 -3
- package/src/interceptor/interceptor-chain.ts +6 -7
- package/src/interceptor/interceptor-registry.ts +5 -3
- package/src/interceptor/types.ts +9 -4
- package/src/microservice/service-client/types.ts +1 -1
- package/src/microservice/tracing/tracer.ts +15 -3
- package/src/middleware/builtin/file-upload.ts +3 -2
- package/src/middleware/builtin/rate-limit.ts +22 -5
- package/src/queue/service.ts +1 -1
- package/src/queue/types.ts +40 -1
- package/src/router/decorators.ts +2 -3
- package/src/security/guards/types.ts +2 -1
- package/src/security/types.ts +1 -2
- package/src/session/service.ts +1 -1
- package/src/session/types.ts +10 -0
- package/src/swagger/decorators.ts +15 -4
- package/src/swagger/generator.ts +2 -3
- package/src/swagger/types.ts +1 -2
- package/src/testing/harness.ts +1 -2
- package/src/testing/test-client.ts +2 -2
- package/src/testing/testing-module.ts +5 -5
- package/src/validation/errors.ts +6 -2
- package/tests/bun-test-shim.d.ts +11 -0
- package/tests/controller/context-decorator.test.ts +1 -2
- package/tests/di/module.test.ts +199 -1
- package/tests/events/event-emitter.test.ts +2 -2
- package/tests/global.d.ts +30 -0
- package/tests/queue/queue-service.test.ts +14 -0
- 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:
|
|
95
|
-
args:
|
|
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:
|
|
168
|
-
args:
|
|
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:
|
|
242
|
-
args:
|
|
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:
|
|
90
|
+
const originalMethod = prototypeMethod as (...args: any[]) => unknown;
|
|
91
91
|
|
|
92
|
-
return async function (this: T, ...args:
|
|
92
|
+
return async function (this: T, ...args: any[]): Promise<unknown> {
|
|
93
93
|
// 按优先级执行拦截器:CacheEvict (beforeInvocation) -> Cacheable/CachePut -> CacheEvict (afterInvocation)
|
|
94
94
|
|
|
95
95
|
// 如果有 @CacheEvict 且配置了 beforeInvocation
|
package/src/cache/service.ts
CHANGED
|
@@ -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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
+
}
|
package/src/cache/types.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface CacheStore {
|
|
|
7
7
|
* @param key - 缓存键
|
|
8
8
|
* @returns 缓存值,如果不存在则返回 undefined
|
|
9
9
|
*/
|
|
10
|
-
get<T =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
328
|
+
public async setMany<T = any>(
|
|
329
329
|
entries: Array<{ key: string; value: T }>,
|
|
330
330
|
ttl?: number,
|
|
331
331
|
): Promise<boolean> {
|
package/src/config/service.ts
CHANGED
|
@@ -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(
|
|
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
|
-
|
package/src/core/application.ts
CHANGED
|
@@ -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
|
-
|
package/src/core/context.ts
CHANGED
|
@@ -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
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
package/src/di/container.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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?:
|
|
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
|
-
|
package/src/error/handler.ts
CHANGED
|
@@ -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
|
|
55
|
-
const
|
|
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
|
-
|
package/src/error/index.ts
CHANGED
|
@@ -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
|
|
package/src/events/service.ts
CHANGED
|
@@ -36,7 +36,7 @@ export class EventEmitterService implements EventEmitter {
|
|
|
36
36
|
/**
|
|
37
37
|
* 发布事件(同步触发所有监听器,不等待异步监听器完成)
|
|
38
38
|
*/
|
|
39
|
-
public emit<T>(event: string | symbol, payload
|
|
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
|
|
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)}":`,
|
package/src/events/types.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @template T - 事件负载类型
|
|
4
4
|
*/
|
|
5
5
|
export interface EventListener<T = unknown> {
|
|
6
|
-
(payload: T):
|
|
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
|
|
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
|
|
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 装饰器的类
|