@dangao/bun-server 1.0.3 → 1.1.2
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/controller/controller.d.ts +1 -1
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/core/application.d.ts.map +1 -1
- package/dist/database/database-extension.d.ts.map +1 -1
- package/dist/database/database-module.d.ts.map +1 -1
- package/dist/database/orm/transaction-decorator.d.ts +1 -0
- package/dist/database/orm/transaction-decorator.d.ts.map +1 -1
- package/dist/database/orm/transaction-interceptor.d.ts +12 -3
- package/dist/database/orm/transaction-interceptor.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +678 -310
- package/dist/interceptor/base-interceptor.d.ts +94 -0
- package/dist/interceptor/base-interceptor.d.ts.map +1 -0
- package/dist/interceptor/builtin/cache-interceptor.d.ts +69 -0
- package/dist/interceptor/builtin/cache-interceptor.d.ts.map +1 -0
- package/dist/interceptor/builtin/index.d.ts +4 -0
- package/dist/interceptor/builtin/index.d.ts.map +1 -0
- package/dist/interceptor/builtin/log-interceptor.d.ts +56 -0
- package/dist/interceptor/builtin/log-interceptor.d.ts.map +1 -0
- package/dist/interceptor/builtin/permission-interceptor.d.ts +70 -0
- package/dist/interceptor/builtin/permission-interceptor.d.ts.map +1 -0
- package/dist/interceptor/index.d.ts +7 -0
- package/dist/interceptor/index.d.ts.map +1 -0
- package/dist/interceptor/interceptor-chain.d.ts +22 -0
- package/dist/interceptor/interceptor-chain.d.ts.map +1 -0
- package/dist/interceptor/interceptor-registry.d.ts +59 -0
- package/dist/interceptor/interceptor-registry.d.ts.map +1 -0
- package/dist/interceptor/metadata.d.ts +12 -0
- package/dist/interceptor/metadata.d.ts.map +1 -0
- package/dist/interceptor/types.d.ts +42 -0
- package/dist/interceptor/types.d.ts.map +1 -0
- package/dist/middleware/decorators.d.ts +2 -1
- package/dist/middleware/decorators.d.ts.map +1 -1
- package/dist/router/decorators.d.ts.map +1 -1
- package/dist/router/registry.d.ts +2 -1
- package/dist/router/registry.d.ts.map +1 -1
- package/dist/router/route.d.ts +3 -2
- package/dist/router/route.d.ts.map +1 -1
- package/dist/router/router.d.ts +2 -1
- package/dist/router/router.d.ts.map +1 -1
- package/dist/websocket/decorators.d.ts +2 -1
- package/dist/websocket/decorators.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/controller/controller.ts +41 -14
- package/src/core/application.ts +7 -1
- package/src/database/database-extension.ts +23 -2
- package/src/database/database-module.ts +6 -0
- package/src/database/orm/transaction-decorator.ts +33 -2
- package/src/database/orm/transaction-interceptor.ts +31 -11
- package/src/index.ts +22 -0
- package/src/interceptor/base-interceptor.ts +203 -0
- package/src/interceptor/builtin/cache-interceptor.ts +169 -0
- package/src/interceptor/builtin/index.ts +28 -0
- package/src/interceptor/builtin/log-interceptor.ts +178 -0
- package/src/interceptor/builtin/permission-interceptor.ts +173 -0
- package/src/interceptor/index.ts +26 -0
- package/src/interceptor/interceptor-chain.ts +79 -0
- package/src/interceptor/interceptor-registry.ts +132 -0
- package/src/interceptor/metadata.ts +40 -0
- package/src/interceptor/types.ts +52 -0
- package/src/middleware/decorators.ts +2 -1
- package/src/router/decorators.ts +44 -43
- package/src/router/registry.ts +2 -1
- package/src/router/route.ts +3 -2
- package/src/router/router.ts +2 -1
- package/src/websocket/decorators.ts +3 -1
- package/tests/controller/path-combination.test.ts +207 -0
- package/tests/interceptor/builtin/cache-interceptor.test.ts +137 -0
- package/tests/interceptor/builtin/permission-interceptor.test.ts +182 -0
- package/tests/interceptor/interceptor-advanced-integration.test.ts +592 -0
- package/tests/interceptor/interceptor-arg-modification.test.ts +76 -0
- package/tests/interceptor/interceptor-chain.test.ts +199 -0
- package/tests/interceptor/interceptor-integration.test.ts +230 -0
- package/tests/interceptor/interceptor-registry.test.ts +200 -0
- package/tests/interceptor/perf/interceptor-performance.test.ts +341 -0
- package/tests/router/decorators.test.ts +13 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dangao/bun-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"reflect-metadata": "^0.2.2",
|
|
59
|
-
"@dangao/logsmith": "0.1.
|
|
59
|
+
"@dangao/logsmith": "0.1.1"
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -8,7 +8,13 @@ import { getClassMiddlewares, getMethodMiddlewares } from '../middleware';
|
|
|
8
8
|
import type { Middleware } from '../middleware';
|
|
9
9
|
import { getValidationMetadata, validateParameters, ValidationError } from '../validation';
|
|
10
10
|
import { HttpException } from '../error';
|
|
11
|
-
import type { Constructor } from '@/core/types'
|
|
11
|
+
import type { Constructor } from '@/core/types';
|
|
12
|
+
import {
|
|
13
|
+
type InterceptorRegistry,
|
|
14
|
+
INTERCEPTOR_REGISTRY_TOKEN,
|
|
15
|
+
InterceptorChain,
|
|
16
|
+
scanInterceptorMetadata,
|
|
17
|
+
} from '../interceptor';
|
|
12
18
|
|
|
13
19
|
/**
|
|
14
20
|
* 控制器元数据键
|
|
@@ -27,7 +33,7 @@ export interface ControllerMetadata {
|
|
|
27
33
|
/**
|
|
28
34
|
* 控制器类
|
|
29
35
|
*/
|
|
30
|
-
target:
|
|
36
|
+
target: Constructor<unknown>;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
/**
|
|
@@ -49,7 +55,7 @@ export function Controller(path: string = '') {
|
|
|
49
55
|
export class ControllerRegistry {
|
|
50
56
|
private static instance: ControllerRegistry;
|
|
51
57
|
private readonly container: Container;
|
|
52
|
-
private readonly controllers = new Map<
|
|
58
|
+
private readonly controllers = new Map<Constructor<unknown>, unknown>();
|
|
53
59
|
private readonly controllerContainers = new Map<Constructor<unknown>, Container>();
|
|
54
60
|
|
|
55
61
|
private constructor() {
|
|
@@ -142,35 +148,56 @@ export class ControllerRegistry {
|
|
|
142
148
|
|
|
143
149
|
// 调用控制器方法
|
|
144
150
|
// 优先从实例获取,如果不存在则从原型获取
|
|
151
|
+
// 注意:prototype 已在上面声明(第 140 行),因为后续扫描拦截器元数据时需要用到
|
|
145
152
|
let method = (controllerInstance as Record<string, (...args: unknown[]) => unknown>)[propertyKey!];
|
|
146
153
|
if (!method || typeof method !== 'function') {
|
|
147
154
|
// 从构造函数原型获取方法
|
|
148
|
-
const prototype = controllerClass.prototype;
|
|
149
155
|
method = prototype[propertyKey!];
|
|
150
156
|
}
|
|
151
157
|
if (!method || typeof method !== 'function') {
|
|
152
158
|
throw new Error(`Method ${propertyKey} not found on controller ${controllerClass.name}`);
|
|
153
159
|
}
|
|
154
160
|
|
|
155
|
-
//
|
|
156
|
-
let
|
|
161
|
+
// 获取拦截器注册表
|
|
162
|
+
let interceptorRegistry: InterceptorRegistry | undefined;
|
|
157
163
|
try {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
+
interceptorRegistry = controllerContainer.resolve<InterceptorRegistry>(
|
|
165
|
+
INTERCEPTOR_REGISTRY_TOKEN,
|
|
166
|
+
);
|
|
167
|
+
} catch (error) {
|
|
168
|
+
// 如果拦截器注册表未注册,继续执行(向后兼容)
|
|
169
|
+
interceptorRegistry = undefined;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 执行拦截器链或直接调用方法
|
|
173
|
+
let result: unknown;
|
|
174
|
+
if (interceptorRegistry) {
|
|
175
|
+
// 扫描方法上的所有拦截器元数据
|
|
176
|
+
const interceptors = scanInterceptorMetadata(
|
|
177
|
+
prototype,
|
|
178
|
+
propertyKey!,
|
|
179
|
+
interceptorRegistry,
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
if (interceptors.length > 0) {
|
|
183
|
+
// 执行拦截器链
|
|
184
|
+
// 注意:传递 controllerInstance 以确保 originalMethod.apply 的 this 绑定正确
|
|
185
|
+
// getMetadata 方法已经修复以支持从原型链查找元数据
|
|
186
|
+
result = await InterceptorChain.execute(
|
|
187
|
+
interceptors,
|
|
188
|
+
controllerInstance,
|
|
164
189
|
propertyKey!,
|
|
165
190
|
method,
|
|
166
191
|
params,
|
|
167
192
|
controllerContainer,
|
|
193
|
+
context,
|
|
168
194
|
);
|
|
169
195
|
} else {
|
|
196
|
+
// 没有拦截器,直接执行方法
|
|
170
197
|
result = method.apply(controllerInstance, params);
|
|
171
198
|
}
|
|
172
|
-
}
|
|
173
|
-
//
|
|
199
|
+
} else {
|
|
200
|
+
// 拦截器注册表未注册,直接执行方法(向后兼容)
|
|
174
201
|
result = method.apply(controllerInstance, params);
|
|
175
202
|
}
|
|
176
203
|
|
package/src/core/application.ts
CHANGED
|
@@ -10,7 +10,8 @@ import type { ApplicationExtension } from '../extensions/types';
|
|
|
10
10
|
import { LoggerExtension } from '../extensions/logger-extension';
|
|
11
11
|
import { ModuleRegistry } from '../di/module-registry';
|
|
12
12
|
import type { ModuleClass } from '../di/module';
|
|
13
|
-
import type { Constructor } from './types'
|
|
13
|
+
import type { Constructor } from './types';
|
|
14
|
+
import { InterceptorRegistry, INTERCEPTOR_REGISTRY_TOKEN } from '../interceptor';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* 应用配置选项
|
|
@@ -48,6 +49,11 @@ export class Application {
|
|
|
48
49
|
ControllerRegistry.getInstance().clear();
|
|
49
50
|
ModuleRegistry.getInstance().clear();
|
|
50
51
|
|
|
52
|
+
// 注册 InterceptorRegistry 到 DI 容器
|
|
53
|
+
const container = ControllerRegistry.getInstance().getContainer();
|
|
54
|
+
const interceptorRegistry = new InterceptorRegistry();
|
|
55
|
+
container.registerInstance(INTERCEPTOR_REGISTRY_TOKEN, interceptorRegistry);
|
|
56
|
+
|
|
51
57
|
// 默认注册 Logger(如果通过模块注册,会被覆盖)
|
|
52
58
|
this.registerExtension(new LoggerExtension());
|
|
53
59
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { Container } from '../di/container';
|
|
2
2
|
import type { ApplicationExtension } from '../extensions/types';
|
|
3
|
+
import {
|
|
4
|
+
InterceptorRegistry,
|
|
5
|
+
INTERCEPTOR_REGISTRY_TOKEN,
|
|
6
|
+
} from '../interceptor';
|
|
3
7
|
|
|
8
|
+
import { TransactionInterceptor } from './orm/transaction-interceptor';
|
|
9
|
+
import { TRANSACTION_METADATA_KEY } from './orm/transaction-decorator';
|
|
4
10
|
import { DATABASE_SERVICE_TOKEN } from './types';
|
|
5
11
|
import type { DatabaseService } from './service';
|
|
6
12
|
|
|
@@ -10,8 +16,23 @@ import type { DatabaseService } from './service';
|
|
|
10
16
|
*/
|
|
11
17
|
export class DatabaseExtension implements ApplicationExtension {
|
|
12
18
|
public register(container: Container): void {
|
|
13
|
-
//
|
|
14
|
-
|
|
19
|
+
// 注册事务拦截器到拦截器注册表
|
|
20
|
+
try {
|
|
21
|
+
const interceptorRegistry = container.resolve<InterceptorRegistry>(
|
|
22
|
+
INTERCEPTOR_REGISTRY_TOKEN,
|
|
23
|
+
);
|
|
24
|
+
const transactionInterceptor = new TransactionInterceptor();
|
|
25
|
+
// 使用 TRANSACTION_METADATA_KEY 作为元数据键
|
|
26
|
+
// 优先级设置为 50,确保事务拦截器在其他业务拦截器之前执行
|
|
27
|
+
interceptorRegistry.register(
|
|
28
|
+
TRANSACTION_METADATA_KEY,
|
|
29
|
+
transactionInterceptor,
|
|
30
|
+
50,
|
|
31
|
+
);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
// 如果拦截器注册表未注册,忽略错误(向后兼容)
|
|
34
|
+
// 这意味着拦截器机制可能未启用
|
|
35
|
+
}
|
|
15
36
|
}
|
|
16
37
|
|
|
17
38
|
/**
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { Module, MODULE_METADATA_KEY, type ModuleProvider } from '../di/module';
|
|
2
2
|
import type { ApplicationExtension } from '../extensions/types';
|
|
3
|
+
import {
|
|
4
|
+
InterceptorRegistry,
|
|
5
|
+
INTERCEPTOR_REGISTRY_TOKEN,
|
|
6
|
+
} from '../interceptor';
|
|
3
7
|
|
|
4
8
|
import { DatabaseExtension } from './database-extension';
|
|
5
9
|
import { DatabaseHealthIndicator } from './health-indicator';
|
|
6
10
|
import { OrmService } from './orm/service';
|
|
7
11
|
import { TransactionManager } from './orm/transaction-manager';
|
|
12
|
+
import { TransactionInterceptor } from './orm/transaction-interceptor';
|
|
13
|
+
import { TRANSACTION_METADATA_KEY } from './orm/transaction-decorator';
|
|
8
14
|
import { DatabaseService } from './service';
|
|
9
15
|
import {
|
|
10
16
|
DATABASE_OPTIONS_TOKEN,
|
|
@@ -33,13 +33,44 @@ export function Transactional(options?: TransactionOptions): MethodDecorator {
|
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* 获取 Transaction 元数据
|
|
36
|
+
* 支持从实例或原型上获取元数据(元数据通常存储在原型上)
|
|
36
37
|
*/
|
|
37
38
|
export function getTransactionMetadata(
|
|
38
39
|
target: unknown,
|
|
39
40
|
propertyKey: string | symbol,
|
|
40
41
|
): TransactionOptions | undefined {
|
|
41
|
-
if (typeof target
|
|
42
|
-
return
|
|
42
|
+
if (typeof target !== 'object' || target === null) {
|
|
43
|
+
return undefined;
|
|
43
44
|
}
|
|
45
|
+
|
|
46
|
+
// 首先尝试直接从 target 获取(如果 target 是原型)
|
|
47
|
+
let metadata = Reflect.getMetadata(TRANSACTION_METADATA_KEY, target, propertyKey) as TransactionOptions | undefined;
|
|
48
|
+
if (metadata !== undefined) {
|
|
49
|
+
return metadata;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 如果 target 是实例,尝试从原型获取
|
|
53
|
+
// 装饰器元数据通常存储在原型上,而不是实例上
|
|
54
|
+
const prototype = Object.getPrototypeOf(target);
|
|
55
|
+
if (prototype && prototype !== Object.prototype) {
|
|
56
|
+
metadata = Reflect.getMetadata(TRANSACTION_METADATA_KEY, prototype, propertyKey) as TransactionOptions | undefined;
|
|
57
|
+
if (metadata !== undefined) {
|
|
58
|
+
return metadata;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 如果仍然找不到,尝试从构造函数原型获取
|
|
63
|
+
// 这处理了 target 是实例但原型链查找失败的情况
|
|
64
|
+
const constructor = (target as any).constructor;
|
|
65
|
+
if (constructor && typeof constructor === 'function') {
|
|
66
|
+
// 如果 target 本身不是构造函数原型,尝试从构造函数原型获取
|
|
67
|
+
if (target !== constructor.prototype) {
|
|
68
|
+
metadata = Reflect.getMetadata(TRANSACTION_METADATA_KEY, constructor.prototype, propertyKey) as TransactionOptions | undefined;
|
|
69
|
+
if (metadata !== undefined) {
|
|
70
|
+
return metadata;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
44
75
|
return undefined;
|
|
45
76
|
}
|
|
@@ -1,23 +1,28 @@
|
|
|
1
|
-
import { Container } from '../../di/container';
|
|
1
|
+
import type { Container } from '../../di/container';
|
|
2
|
+
import type { Context } from '../../core/context';
|
|
3
|
+
import type { Interceptor } from '../../interceptor';
|
|
2
4
|
import { TRANSACTION_SERVICE_TOKEN } from './transaction-types';
|
|
3
5
|
import { TransactionManager } from './transaction-manager';
|
|
4
|
-
import { getTransactionMetadata } from './transaction-decorator';
|
|
6
|
+
import { getTransactionMetadata, TRANSACTION_METADATA_KEY } from './transaction-decorator';
|
|
5
7
|
import { Propagation, TransactionStatus } from './transaction-types';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* 事务拦截器
|
|
9
11
|
* 在方法调用时检查 @Transactional() 装饰器并执行事务逻辑
|
|
12
|
+
* 实现 Interceptor 接口,通过拦截器机制注册和执行
|
|
10
13
|
*/
|
|
11
|
-
export class TransactionInterceptor {
|
|
14
|
+
export class TransactionInterceptor implements Interceptor {
|
|
12
15
|
/**
|
|
13
|
-
*
|
|
16
|
+
* 执行拦截器逻辑
|
|
17
|
+
* 实现 Interceptor 接口
|
|
14
18
|
*/
|
|
15
|
-
public
|
|
19
|
+
public async execute<T>(
|
|
16
20
|
target: unknown,
|
|
17
21
|
propertyKey: string | symbol,
|
|
18
22
|
originalMethod: (...args: unknown[]) => T | Promise<T>,
|
|
19
23
|
args: unknown[],
|
|
20
24
|
container: Container,
|
|
25
|
+
context?: Context,
|
|
21
26
|
): Promise<T> {
|
|
22
27
|
const transactionMetadata = getTransactionMetadata(target, propertyKey);
|
|
23
28
|
|
|
@@ -46,7 +51,7 @@ export class TransactionInterceptor {
|
|
|
46
51
|
case Propagation.REQUIRED:
|
|
47
52
|
if (currentTransaction) {
|
|
48
53
|
// 加入现有事务
|
|
49
|
-
return await
|
|
54
|
+
return await TransactionInterceptor.executeInExistingTransaction(
|
|
50
55
|
originalMethod,
|
|
51
56
|
target,
|
|
52
57
|
args,
|
|
@@ -55,7 +60,7 @@ export class TransactionInterceptor {
|
|
|
55
60
|
);
|
|
56
61
|
} else {
|
|
57
62
|
// 创建新事务
|
|
58
|
-
return await
|
|
63
|
+
return await TransactionInterceptor.executeInNewTransaction(
|
|
59
64
|
originalMethod,
|
|
60
65
|
target,
|
|
61
66
|
args,
|
|
@@ -66,7 +71,7 @@ export class TransactionInterceptor {
|
|
|
66
71
|
|
|
67
72
|
case Propagation.REQUIRES_NEW:
|
|
68
73
|
// 总是创建新事务
|
|
69
|
-
return await
|
|
74
|
+
return await TransactionInterceptor.executeInNewTransaction(
|
|
70
75
|
originalMethod,
|
|
71
76
|
target,
|
|
72
77
|
args,
|
|
@@ -77,7 +82,7 @@ export class TransactionInterceptor {
|
|
|
77
82
|
case Propagation.SUPPORTS:
|
|
78
83
|
if (currentTransaction) {
|
|
79
84
|
// 加入现有事务
|
|
80
|
-
return await
|
|
85
|
+
return await TransactionInterceptor.executeInExistingTransaction(
|
|
81
86
|
originalMethod,
|
|
82
87
|
target,
|
|
83
88
|
args,
|
|
@@ -104,7 +109,7 @@ export class TransactionInterceptor {
|
|
|
104
109
|
case Propagation.NESTED:
|
|
105
110
|
if (currentTransaction) {
|
|
106
111
|
// 创建嵌套事务(保存点)
|
|
107
|
-
return await
|
|
112
|
+
return await TransactionInterceptor.executeInNestedTransaction(
|
|
108
113
|
originalMethod,
|
|
109
114
|
target,
|
|
110
115
|
args,
|
|
@@ -114,7 +119,7 @@ export class TransactionInterceptor {
|
|
|
114
119
|
);
|
|
115
120
|
} else {
|
|
116
121
|
// 创建新事务
|
|
117
|
-
return await
|
|
122
|
+
return await TransactionInterceptor.executeInNewTransaction(
|
|
118
123
|
originalMethod,
|
|
119
124
|
target,
|
|
120
125
|
args,
|
|
@@ -128,6 +133,21 @@ export class TransactionInterceptor {
|
|
|
128
133
|
}
|
|
129
134
|
}
|
|
130
135
|
|
|
136
|
+
/**
|
|
137
|
+
* 执行带事务的方法(静态方法,保持向后兼容)
|
|
138
|
+
* @deprecated 使用拦截器机制,此方法保留用于向后兼容
|
|
139
|
+
*/
|
|
140
|
+
public static async executeWithTransaction<T>(
|
|
141
|
+
target: unknown,
|
|
142
|
+
propertyKey: string | symbol,
|
|
143
|
+
originalMethod: (...args: unknown[]) => T | Promise<T>,
|
|
144
|
+
args: unknown[],
|
|
145
|
+
container: Container,
|
|
146
|
+
): Promise<T> {
|
|
147
|
+
const interceptor = new TransactionInterceptor();
|
|
148
|
+
return await interceptor.execute(target, propertyKey, originalMethod, args, container);
|
|
149
|
+
}
|
|
150
|
+
|
|
131
151
|
/**
|
|
132
152
|
* 在新事务中执行方法
|
|
133
153
|
*/
|
package/src/index.ts
CHANGED
|
@@ -17,6 +17,28 @@ export {
|
|
|
17
17
|
type ModuleClass,
|
|
18
18
|
} from './di/module';
|
|
19
19
|
export { ModuleRegistry } from './di/module-registry';
|
|
20
|
+
export {
|
|
21
|
+
InterceptorRegistry,
|
|
22
|
+
InterceptorChain,
|
|
23
|
+
scanInterceptorMetadata,
|
|
24
|
+
BaseInterceptor,
|
|
25
|
+
Cache,
|
|
26
|
+
CacheInterceptor,
|
|
27
|
+
Permission,
|
|
28
|
+
PermissionInterceptor,
|
|
29
|
+
Log,
|
|
30
|
+
LogInterceptor,
|
|
31
|
+
INTERCEPTOR_REGISTRY_TOKEN,
|
|
32
|
+
CACHE_METADATA_KEY,
|
|
33
|
+
PERMISSION_METADATA_KEY,
|
|
34
|
+
LOG_METADATA_KEY,
|
|
35
|
+
type Interceptor,
|
|
36
|
+
type InterceptorMetadata,
|
|
37
|
+
type CacheOptions,
|
|
38
|
+
type PermissionOptions,
|
|
39
|
+
type PermissionService,
|
|
40
|
+
type LogOptions,
|
|
41
|
+
} from './interceptor';
|
|
20
42
|
export { UseMiddleware, RateLimit, MiddlewarePipeline } from './middleware';
|
|
21
43
|
export type { Middleware, NextFunction } from './middleware';
|
|
22
44
|
export {
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import type { Interceptor } from './types';
|
|
2
|
+
import type { Container } from '../di/container';
|
|
3
|
+
import type { Context } from '../core/context';
|
|
4
|
+
import 'reflect-metadata';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 拦截器基类
|
|
8
|
+
* 提供便捷的前置处理、后置处理和错误处理方法
|
|
9
|
+
*/
|
|
10
|
+
export abstract class BaseInterceptor implements Interceptor {
|
|
11
|
+
/**
|
|
12
|
+
* 执行拦截器逻辑
|
|
13
|
+
* 子类必须实现此方法
|
|
14
|
+
*/
|
|
15
|
+
public abstract execute<T>(
|
|
16
|
+
target: unknown,
|
|
17
|
+
propertyKey: string | symbol,
|
|
18
|
+
originalMethod: (...args: unknown[]) => T | Promise<T>,
|
|
19
|
+
args: unknown[],
|
|
20
|
+
container: Container,
|
|
21
|
+
context?: Context,
|
|
22
|
+
): Promise<T>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 前置处理(可选)
|
|
26
|
+
* 在方法执行前调用,子类可以覆盖此方法
|
|
27
|
+
* @param target - 目标对象
|
|
28
|
+
* @param propertyKey - 方法名
|
|
29
|
+
* @param args - 方法参数
|
|
30
|
+
* @param container - DI 容器
|
|
31
|
+
* @param context - 请求上下文(可选)
|
|
32
|
+
*/
|
|
33
|
+
protected async before(
|
|
34
|
+
target: unknown,
|
|
35
|
+
propertyKey: string | symbol,
|
|
36
|
+
args: unknown[],
|
|
37
|
+
container: Container,
|
|
38
|
+
context?: Context,
|
|
39
|
+
): Promise<void> {
|
|
40
|
+
// 默认空实现,子类可覆盖
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 后置处理(可选)
|
|
45
|
+
* 在方法执行后调用,子类可以覆盖此方法
|
|
46
|
+
* @param target - 目标对象
|
|
47
|
+
* @param propertyKey - 方法名
|
|
48
|
+
* @param result - 方法执行结果
|
|
49
|
+
* @param container - DI 容器
|
|
50
|
+
* @param context - 请求上下文(可选)
|
|
51
|
+
* @returns 处理后的结果(默认返回原结果)
|
|
52
|
+
*/
|
|
53
|
+
protected async after<T>(
|
|
54
|
+
target: unknown,
|
|
55
|
+
propertyKey: string | symbol,
|
|
56
|
+
result: T,
|
|
57
|
+
container: Container,
|
|
58
|
+
context?: Context,
|
|
59
|
+
): Promise<T> {
|
|
60
|
+
// 默认返回原结果,子类可覆盖
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 错误处理(可选)
|
|
66
|
+
* 在方法执行出错时调用,子类可以覆盖此方法
|
|
67
|
+
* @param target - 目标对象
|
|
68
|
+
* @param propertyKey - 方法名
|
|
69
|
+
* @param error - 错误对象
|
|
70
|
+
* @param container - DI 容器
|
|
71
|
+
* @param context - 请求上下文(可选)
|
|
72
|
+
* @returns 永远不会返回(总是抛出错误)
|
|
73
|
+
* @throws 重新抛出错误或抛出新的错误
|
|
74
|
+
*/
|
|
75
|
+
protected async onError(
|
|
76
|
+
target: unknown,
|
|
77
|
+
propertyKey: string | symbol,
|
|
78
|
+
error: unknown,
|
|
79
|
+
container: Container,
|
|
80
|
+
context?: Context,
|
|
81
|
+
): Promise<never> {
|
|
82
|
+
// 默认重新抛出错误,子类可覆盖
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 获取元数据
|
|
88
|
+
* 从目标对象的方法上获取指定元数据键的元数据
|
|
89
|
+
* 支持从实例或原型上获取元数据(元数据通常存储在原型上)
|
|
90
|
+
* @param target - 目标对象(可能是实例或原型)
|
|
91
|
+
* @param propertyKey - 方法名
|
|
92
|
+
* @param metadataKey - 元数据键
|
|
93
|
+
* @returns 元数据值,如果不存在则返回 undefined
|
|
94
|
+
*/
|
|
95
|
+
protected getMetadata<T = unknown>(
|
|
96
|
+
target: unknown,
|
|
97
|
+
propertyKey: string | symbol,
|
|
98
|
+
metadataKey: symbol,
|
|
99
|
+
): T | undefined {
|
|
100
|
+
if (typeof target !== 'object' || target === null) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 首先尝试直接从 target 获取(如果 target 是原型)
|
|
105
|
+
let metadata = Reflect.getMetadata(metadataKey, target, propertyKey) as T | undefined;
|
|
106
|
+
if (metadata !== undefined) {
|
|
107
|
+
return metadata;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 如果 target 是实例,尝试从原型获取
|
|
111
|
+
// 装饰器元数据通常存储在原型上,而不是实例上
|
|
112
|
+
const prototype = Object.getPrototypeOf(target);
|
|
113
|
+
if (prototype && prototype !== Object.prototype) {
|
|
114
|
+
metadata = Reflect.getMetadata(metadataKey, prototype, propertyKey) as T | undefined;
|
|
115
|
+
if (metadata !== undefined) {
|
|
116
|
+
return metadata;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 如果仍然找不到,尝试从构造函数原型获取
|
|
121
|
+
// 这处理了 target 是实例但原型链查找失败的情况
|
|
122
|
+
const constructor = (target as any).constructor;
|
|
123
|
+
if (constructor && typeof constructor === 'function') {
|
|
124
|
+
// 如果 target 本身不是构造函数原型,尝试从构造函数原型获取
|
|
125
|
+
if (target !== constructor.prototype) {
|
|
126
|
+
metadata = Reflect.getMetadata(metadataKey, constructor.prototype, propertyKey) as T | undefined;
|
|
127
|
+
if (metadata !== undefined) {
|
|
128
|
+
return metadata;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 从容器解析服务
|
|
138
|
+
* @param container - DI 容器
|
|
139
|
+
* @param token - 服务标识符
|
|
140
|
+
* @returns 服务实例
|
|
141
|
+
*/
|
|
142
|
+
protected resolveService<T>(
|
|
143
|
+
container: Container,
|
|
144
|
+
token: (new (...args: unknown[]) => T) | string | symbol,
|
|
145
|
+
): T {
|
|
146
|
+
return container.resolve<T>(token);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 从上下文获取值
|
|
151
|
+
* @param context - 请求上下文
|
|
152
|
+
* @param key - 键名
|
|
153
|
+
* @returns 值,如果不存在则返回 undefined
|
|
154
|
+
*/
|
|
155
|
+
protected getContextValue<T = unknown>(context: Context | undefined, key: string): T | undefined {
|
|
156
|
+
if (!context) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
// Context 没有直接的存储机制,可以通过 headers 或其他方式获取
|
|
160
|
+
// 这里提供一个基础实现,子类可以根据需要扩展
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 从上下文获取请求头
|
|
166
|
+
* @param context - 请求上下文
|
|
167
|
+
* @param headerName - 请求头名称
|
|
168
|
+
* @returns 请求头值,如果不存在则返回 null
|
|
169
|
+
*/
|
|
170
|
+
protected getHeader(context: Context | undefined, headerName: string): string | null {
|
|
171
|
+
if (!context) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
return context.getHeader(headerName);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 从上下文获取查询参数
|
|
179
|
+
* @param context - 请求上下文
|
|
180
|
+
* @param paramName - 参数名称
|
|
181
|
+
* @returns 参数值,如果不存在则返回 null
|
|
182
|
+
*/
|
|
183
|
+
protected getQuery(context: Context | undefined, paramName: string): string | null {
|
|
184
|
+
if (!context) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
return context.getQuery(paramName);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 从上下文获取路径参数
|
|
192
|
+
* @param context - 请求上下文
|
|
193
|
+
* @param paramName - 参数名称
|
|
194
|
+
* @returns 参数值,如果不存在则返回 undefined
|
|
195
|
+
*/
|
|
196
|
+
protected getParam(context: Context | undefined, paramName: string): string | undefined {
|
|
197
|
+
if (!context) {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
return context.getParam(paramName);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|