@dangao/bun-server 3.1.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/connection-manager.d.ts +2 -2
- package/dist/database/connection-manager.d.ts.map +1 -1
- package/dist/database/connection-pool.d.ts +4 -4
- package/dist/database/connection-pool.d.ts.map +1 -1
- package/dist/database/database-module.d.ts.map +1 -1
- package/dist/database/db-proxy.d.ts.map +1 -1
- package/dist/database/driver.d.ts +83 -0
- package/dist/database/driver.d.ts.map +1 -0
- package/dist/database/index.d.ts +2 -1
- package/dist/database/index.d.ts.map +1 -1
- package/dist/database/service.d.ts +0 -10
- package/dist/database/service.d.ts.map +1 -1
- package/dist/database/sql-manager.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/database/types.d.ts +26 -0
- package/dist/database/types.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 +5951 -5820
- package/dist/index.node.mjs +310 -139
- 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/docs/database.md +44 -0
- package/docs/zh/database.md +44 -0
- 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/connection-manager.ts +5 -46
- package/src/database/connection-pool.ts +26 -49
- package/src/database/database-module.ts +6 -0
- package/src/database/db-proxy.ts +3 -2
- package/src/database/driver.ts +368 -0
- package/src/database/index.ts +8 -0
- package/src/database/service.ts +3 -74
- package/src/database/sql-manager.ts +38 -24
- package/src/database/sqlite-adapter.ts +4 -3
- package/src/database/types.ts +27 -2
- 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/database/database-module.test.ts +4 -0
- package/tests/database/driver-mysql2.test.ts +95 -0
- package/tests/database/driver.test.ts +234 -0
- package/tests/database/orm.test.ts +4 -0
- 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
package/src/database/types.ts
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type DatabaseType = 'sqlite' | 'postgres' | 'mysql';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* SQL 驱动选择
|
|
8
|
+
*
|
|
9
|
+
* 与运行时平台(fs/crypto/http server 等)解耦,仅决定 Postgres/MySQL 连接走哪套底层驱动。
|
|
10
|
+
*
|
|
11
|
+
* - `'auto'`(默认):Bun 运行时使用内建 `Bun.SQL`,Node.js 运行时使用 `mysql2` / `postgres` 纯 JS 驱动(保持历史行为)。
|
|
12
|
+
* - `'mysql2'`:无论运行时是 Bun 还是 Node,都使用 `mysql2`(仅适用于 `type: 'mysql'`)。
|
|
13
|
+
* 适合 `bun build --compile` 场景,绕开编译二进制内焊死的 `Bun.SQL` MySQL 适配 bug。
|
|
14
|
+
* - `'postgres'`:无论运行时如何,都使用 `postgres` 纯 JS 驱动(仅适用于 `type: 'postgres'`)。
|
|
15
|
+
* - `'bun-sql'`:强制使用 `Bun.SQL`(仅在 Bun 运行时合法,Node.js 下会抛出清晰错误)。
|
|
16
|
+
*/
|
|
17
|
+
export type DatabaseDriver = 'auto' | 'bun-sql' | 'mysql2' | 'postgres';
|
|
18
|
+
|
|
6
19
|
/**
|
|
7
20
|
* SQLite 配置
|
|
8
21
|
*/
|
|
@@ -72,11 +85,13 @@ export interface MysqlConfig {
|
|
|
72
85
|
|
|
73
86
|
/**
|
|
74
87
|
* 数据库配置(联合类型)
|
|
88
|
+
*
|
|
89
|
+
* Postgres/MySQL 支持可选的 `driver` 字段,用于显式选择底层驱动(与运行时平台解耦)。
|
|
75
90
|
*/
|
|
76
91
|
export type DatabaseConfig =
|
|
77
92
|
| { type: 'sqlite'; config: SqliteConfig }
|
|
78
|
-
| { type: 'postgres'; config: PostgresConfig }
|
|
79
|
-
| { type: 'mysql'; config: MysqlConfig };
|
|
93
|
+
| { type: 'postgres'; config: PostgresConfig; driver?: DatabaseDriver }
|
|
94
|
+
| { type: 'mysql'; config: MysqlConfig; driver?: DatabaseDriver };
|
|
80
95
|
|
|
81
96
|
/**
|
|
82
97
|
* Bun.SQL 连接池配置
|
|
@@ -111,6 +126,11 @@ export interface BunSQLConfig {
|
|
|
111
126
|
type: 'postgres' | 'mysql';
|
|
112
127
|
url: string;
|
|
113
128
|
pool?: BunSQLPoolOptions;
|
|
129
|
+
/**
|
|
130
|
+
* 显式选择底层驱动(与运行时平台解耦)。
|
|
131
|
+
* @default 'auto'
|
|
132
|
+
*/
|
|
133
|
+
driver?: DatabaseDriver;
|
|
114
134
|
}
|
|
115
135
|
|
|
116
136
|
/**
|
|
@@ -183,6 +203,11 @@ export interface DatabaseModuleOptions {
|
|
|
183
203
|
* 单租户:数据库类型(V2)
|
|
184
204
|
*/
|
|
185
205
|
type?: DatabaseType;
|
|
206
|
+
/**
|
|
207
|
+
* 单租户:显式选择底层驱动(V2,与运行时平台解耦)
|
|
208
|
+
* @default 'auto'
|
|
209
|
+
*/
|
|
210
|
+
driver?: DatabaseDriver;
|
|
186
211
|
/**
|
|
187
212
|
* 单租户:Postgres/MySQL URL(V2)
|
|
188
213
|
*/
|
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 装饰器的类
|
|
@@ -15,11 +15,11 @@ export abstract class BaseInterceptor implements Interceptor {
|
|
|
15
15
|
public abstract execute<T>(
|
|
16
16
|
target: unknown,
|
|
17
17
|
propertyKey: string | symbol,
|
|
18
|
-
originalMethod: (...args:
|
|
19
|
-
args:
|
|
18
|
+
originalMethod: (...args: any[]) => T | Promise<T>,
|
|
19
|
+
args: any[],
|
|
20
20
|
container: Container,
|
|
21
21
|
context?: Context,
|
|
22
|
-
): Promise<
|
|
22
|
+
): Promise<any>;
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* 前置处理(可选)
|
|
@@ -33,7 +33,7 @@ export abstract class BaseInterceptor implements Interceptor {
|
|
|
33
33
|
protected async before(
|
|
34
34
|
target: unknown,
|
|
35
35
|
propertyKey: string | symbol,
|
|
36
|
-
args:
|
|
36
|
+
args: any[],
|
|
37
37
|
container: Container,
|
|
38
38
|
context?: Context,
|
|
39
39
|
): Promise<void> {
|
|
@@ -141,7 +141,7 @@ export abstract class BaseInterceptor implements Interceptor {
|
|
|
141
141
|
*/
|
|
142
142
|
protected resolveService<T>(
|
|
143
143
|
container: Container,
|
|
144
|
-
token: (new (...args:
|
|
144
|
+
token: (new (...args: any[]) => T) | string | symbol,
|
|
145
145
|
): T {
|
|
146
146
|
return container.resolve<T>(token);
|
|
147
147
|
}
|
|
@@ -200,4 +200,3 @@ export abstract class BaseInterceptor implements Interceptor {
|
|
|
200
200
|
return context.getParam(paramName);
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
-
|
|
@@ -84,8 +84,8 @@ export class LogInterceptor extends BaseInterceptor {
|
|
|
84
84
|
public async execute<T>(
|
|
85
85
|
target: unknown,
|
|
86
86
|
propertyKey: string | symbol,
|
|
87
|
-
originalMethod: (...args:
|
|
88
|
-
args:
|
|
87
|
+
originalMethod: (...args: any[]) => T | Promise<T>,
|
|
88
|
+
args: any[],
|
|
89
89
|
container: Container,
|
|
90
90
|
context?: Context,
|
|
91
91
|
): Promise<T> {
|
|
@@ -175,4 +175,3 @@ export class LogInterceptor extends BaseInterceptor {
|
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
|
-
|
|
@@ -91,8 +91,8 @@ export class PermissionInterceptor 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> {
|
|
@@ -170,4 +170,3 @@ export class PermissionInterceptor extends BaseInterceptor {
|
|
|
170
170
|
return null;
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
|
-
|
|
@@ -22,8 +22,8 @@ export class InterceptorChain {
|
|
|
22
22
|
interceptors: Interceptor[],
|
|
23
23
|
target: unknown,
|
|
24
24
|
propertyKey: string | symbol,
|
|
25
|
-
originalMethod: (...args:
|
|
26
|
-
args:
|
|
25
|
+
originalMethod: (...args: any[]) => T | Promise<T>,
|
|
26
|
+
args: any[],
|
|
27
27
|
container: Container,
|
|
28
28
|
context?: Context,
|
|
29
29
|
): Promise<T> {
|
|
@@ -36,7 +36,7 @@ export class InterceptorChain {
|
|
|
36
36
|
let index = 0;
|
|
37
37
|
let currentArgs = args; // Track arguments that might be modified by interceptors
|
|
38
38
|
|
|
39
|
-
const next = async (modifiedArgs?:
|
|
39
|
+
const next = async (modifiedArgs?: any[]): Promise<T> => {
|
|
40
40
|
// 如果拦截器传递了新参数,使用新参数;否则使用当前参数
|
|
41
41
|
if (modifiedArgs && modifiedArgs.length > 0) {
|
|
42
42
|
currentArgs = modifiedArgs;
|
|
@@ -50,11 +50,11 @@ export class InterceptorChain {
|
|
|
50
50
|
const interceptor = interceptors[index++];
|
|
51
51
|
|
|
52
52
|
// 执行当前拦截器,传递 next 作为下一个执行函数
|
|
53
|
-
// 注意:拦截器接口要求 originalMethod 的类型是 (...args:
|
|
53
|
+
// 注意:拦截器接口要求 originalMethod 的类型是 (...args: any[]) => T | Promise<T>
|
|
54
54
|
// 这允许原始方法可以是同步(返回 T)或异步(返回 Promise<T>)
|
|
55
55
|
// 虽然 next 函数是异步的(总是返回 Promise<T>),但我们保持类型签名为 T | Promise<T>
|
|
56
56
|
// 以符合拦截器接口的要求。拦截器应该使用 Promise.resolve() 来统一处理同步和异步返回值
|
|
57
|
-
const wrappedNext = (...nextArgs:
|
|
57
|
+
const wrappedNext = (...nextArgs: any[]): T | Promise<T> => {
|
|
58
58
|
// 如果拦截器传递了新参数,传递给 next;否则传递 undefined(使用当前参数)
|
|
59
59
|
// next 是异步函数,总是返回 Promise<T>,但类型签名允许 T | Promise<T>
|
|
60
60
|
const result = next(nextArgs.length > 0 ? nextArgs : undefined);
|
|
@@ -70,10 +70,9 @@ export class InterceptorChain {
|
|
|
70
70
|
currentArgs, // Pass current args to the interceptor
|
|
71
71
|
container,
|
|
72
72
|
context,
|
|
73
|
-
);
|
|
73
|
+
) as T;
|
|
74
74
|
};
|
|
75
75
|
|
|
76
76
|
return await next();
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
|
|
@@ -22,8 +22,11 @@ export class InterceptorRegistry {
|
|
|
22
22
|
public register(
|
|
23
23
|
metadataKey: symbol,
|
|
24
24
|
interceptor: Interceptor,
|
|
25
|
-
priority: number = 100,
|
|
25
|
+
priority: number | { priority?: number } = 100,
|
|
26
26
|
): void {
|
|
27
|
+
const resolvedPriority = typeof priority === 'number'
|
|
28
|
+
? priority
|
|
29
|
+
: priority.priority ?? 100;
|
|
27
30
|
if (!this.interceptors.has(metadataKey)) {
|
|
28
31
|
this.interceptors.set(metadataKey, []);
|
|
29
32
|
}
|
|
@@ -39,7 +42,7 @@ export class InterceptorRegistry {
|
|
|
39
42
|
metadataList.push({
|
|
40
43
|
metadataKey,
|
|
41
44
|
interceptor,
|
|
42
|
-
priority,
|
|
45
|
+
priority: resolvedPriority,
|
|
43
46
|
});
|
|
44
47
|
|
|
45
48
|
// 按优先级排序(数字越小优先级越高)
|
|
@@ -129,4 +132,3 @@ export class InterceptorRegistry {
|
|
|
129
132
|
return total;
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
|
-
|
package/src/interceptor/types.ts
CHANGED
|
@@ -6,6 +6,12 @@ import type { Context } from '../core/context';
|
|
|
6
6
|
* 定义拦截器的核心执行方法
|
|
7
7
|
*/
|
|
8
8
|
export interface Interceptor {
|
|
9
|
+
/**
|
|
10
|
+
* Optional priority used by registries/tests that carry interceptor metadata
|
|
11
|
+
* alongside the executable interceptor instance.
|
|
12
|
+
*/
|
|
13
|
+
priority?: number;
|
|
14
|
+
|
|
9
15
|
/**
|
|
10
16
|
* 执行拦截器逻辑
|
|
11
17
|
* @param target - 目标对象(控制器实例的原型)
|
|
@@ -19,11 +25,11 @@ export interface Interceptor {
|
|
|
19
25
|
execute<T>(
|
|
20
26
|
target: unknown,
|
|
21
27
|
propertyKey: string | symbol,
|
|
22
|
-
originalMethod: (...args:
|
|
23
|
-
args:
|
|
28
|
+
originalMethod: (...args: any[]) => T | Promise<T>,
|
|
29
|
+
args: any[],
|
|
24
30
|
container: Container,
|
|
25
31
|
context?: Context,
|
|
26
|
-
): Promise<
|
|
32
|
+
): Promise<any>;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
/**
|
|
@@ -49,4 +55,3 @@ export interface InterceptorMetadata {
|
|
|
49
55
|
* 拦截器注册表 Token
|
|
50
56
|
*/
|
|
51
57
|
export const INTERCEPTOR_REGISTRY_TOKEN = Symbol('@dangao/bun-server:interceptor-registry');
|
|
52
|
-
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ServiceInstance } from '../service-registry/types';
|
|
2
|
+
export type { ServiceInstance } from '../service-registry/types';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* 负载均衡策略类型
|
|
@@ -183,4 +184,3 @@ export class ServiceCallError extends Error {
|
|
|
183
184
|
this.name = 'ServiceCallError';
|
|
184
185
|
}
|
|
185
186
|
}
|
|
186
|
-
|
|
@@ -172,14 +172,27 @@ export class Tracer {
|
|
|
172
172
|
/**
|
|
173
173
|
* 添加 Span 事件
|
|
174
174
|
*/
|
|
175
|
-
public addSpanEvent(
|
|
175
|
+
public addSpanEvent(
|
|
176
|
+
spanId: SpanId,
|
|
177
|
+
event: string,
|
|
178
|
+
attributes?: Record<string, string | number | boolean>,
|
|
179
|
+
): void;
|
|
180
|
+
public addSpanEvent(spanId: SpanId, event: Omit<SpanEvent, 'timestamp'>): void;
|
|
181
|
+
public addSpanEvent(
|
|
182
|
+
spanId: SpanId,
|
|
183
|
+
event: string | Omit<SpanEvent, 'timestamp'>,
|
|
184
|
+
attributes?: Record<string, string | number | boolean>,
|
|
185
|
+
): void {
|
|
176
186
|
const span = this.activeSpans.get(spanId);
|
|
177
187
|
if (span) {
|
|
178
188
|
if (!span.events) {
|
|
179
189
|
span.events = [];
|
|
180
190
|
}
|
|
191
|
+
const spanEvent = typeof event === 'string'
|
|
192
|
+
? { name: event, attributes }
|
|
193
|
+
: event;
|
|
181
194
|
span.events.push({
|
|
182
|
-
...
|
|
195
|
+
...spanEvent,
|
|
183
196
|
timestamp: Date.now(),
|
|
184
197
|
});
|
|
185
198
|
}
|
|
@@ -290,4 +303,3 @@ export class Tracer {
|
|
|
290
303
|
this.activeSpans.clear();
|
|
291
304
|
}
|
|
292
305
|
}
|
|
293
|
-
|
|
@@ -3,13 +3,15 @@ import { FileHandler } from '../../request/file-handler';
|
|
|
3
3
|
|
|
4
4
|
export interface FileUploadOptions {
|
|
5
5
|
maxSize?: number;
|
|
6
|
+
maxFileSize?: number;
|
|
7
|
+
uploadDir?: string;
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* 简单的文件上传中间件:解析 multipart/form-data 并将文件附加到 context.body
|
|
10
12
|
*/
|
|
11
13
|
export function createFileUploadMiddleware(options: FileUploadOptions = {}): Middleware {
|
|
12
|
-
const maxSize = options.maxSize ?? 10 * 1024 * 1024;
|
|
14
|
+
const maxSize = options.maxSize ?? options.maxFileSize ?? 10 * 1024 * 1024;
|
|
13
15
|
|
|
14
16
|
return async (context, next) => {
|
|
15
17
|
const contentType = context.getHeader('Content-Type');
|
|
@@ -39,4 +41,3 @@ export function createFileUploadMiddleware(options: FileUploadOptions = {}): Mid
|
|
|
39
41
|
};
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
|