@thinkbun/middleware 1.0.0 → 1.0.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/CHANGELOG.md +17 -0
- package/package.json +2 -2
- package/src/index.ts +0 -4
- package/tsconfig.json +4 -1
- package/src/middlewares/validator.ts +0 -187
package/CHANGELOG.md
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thinkbun/middleware",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"module": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"devDependencies": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"picocolors": "^1.1.1",
|
|
14
|
-
"@thinkbun/core": "
|
|
14
|
+
"@thinkbun/core": "1.0.4"
|
|
15
15
|
},
|
|
16
16
|
"publishConfig": {
|
|
17
17
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -3,15 +3,12 @@ import { cors as _cors, type CorsOptions } from './middlewares/cors';
|
|
|
3
3
|
import { errorHandler as _errorHandler, type ErrorHandlerOptions } from './middlewares/errorHandler';
|
|
4
4
|
import { logger as _logger, type LoggerOptions } from './middlewares/logger';
|
|
5
5
|
import { staticServe as _staticServe, type StaticOptions } from './middlewares/static';
|
|
6
|
-
import { validator as _validator, type ValidatorOptions, type ValidationRule } from './middlewares/validator';
|
|
7
6
|
|
|
8
7
|
// 重新导出各个中间件
|
|
9
8
|
export { _errorHandler as errorHandler };
|
|
10
9
|
export type { ErrorHandlerOptions };
|
|
11
10
|
export { _logger as logger };
|
|
12
11
|
export type { LoggerOptions };
|
|
13
|
-
export { _validator as validator };
|
|
14
|
-
export type { ValidatorOptions, ValidationRule };
|
|
15
12
|
export { _cors as cors };
|
|
16
13
|
export type { CorsOptions };
|
|
17
14
|
export { _staticServe as staticServe };
|
|
@@ -24,7 +21,6 @@ export type { Middleware, Context } from '@thinkbun/core';
|
|
|
24
21
|
export const middlewares = {
|
|
25
22
|
errorHandler: _errorHandler,
|
|
26
23
|
logger: _logger,
|
|
27
|
-
validator: _validator,
|
|
28
24
|
cors: _cors,
|
|
29
25
|
staticServe: _staticServe,
|
|
30
26
|
};
|
package/tsconfig.json
CHANGED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import { BadRequestError, type Context, type Middleware, type RouteSchema } from '@thinkbun/core';
|
|
2
|
-
import Ajv from 'ajv';
|
|
3
|
-
import addFormats from 'ajv-formats';
|
|
4
|
-
|
|
5
|
-
// 使用与核心框架相同的Ajv配置
|
|
6
|
-
const ajv = addFormats(
|
|
7
|
-
new Ajv({
|
|
8
|
-
coerceTypes: true, // 自动类型转换
|
|
9
|
-
useDefaults: true, // 使用默认值
|
|
10
|
-
removeAdditional: false, // 保留额外属性
|
|
11
|
-
allErrors: true, // 返回所有错误
|
|
12
|
-
}),
|
|
13
|
-
[
|
|
14
|
-
'date-time',
|
|
15
|
-
'time',
|
|
16
|
-
'date',
|
|
17
|
-
'email',
|
|
18
|
-
'hostname',
|
|
19
|
-
'ipv4',
|
|
20
|
-
'ipv6',
|
|
21
|
-
'uri',
|
|
22
|
-
'uri-reference',
|
|
23
|
-
'uuid',
|
|
24
|
-
'uri-template',
|
|
25
|
-
'json-pointer',
|
|
26
|
-
'relative-json-pointer',
|
|
27
|
-
'regex',
|
|
28
|
-
],
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
export interface ValidationRule {
|
|
32
|
-
/**
|
|
33
|
-
* 路由路径
|
|
34
|
-
* @example '/api/users'
|
|
35
|
-
*/
|
|
36
|
-
path: string;
|
|
37
|
-
/**
|
|
38
|
-
* HTTP方法
|
|
39
|
-
* @example 'POST'
|
|
40
|
-
*/
|
|
41
|
-
method: string;
|
|
42
|
-
/**
|
|
43
|
-
* 验证模式
|
|
44
|
-
*/
|
|
45
|
-
schema: RouteSchema;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface ValidatorOptions {
|
|
49
|
-
/**
|
|
50
|
-
* 验证规则列表
|
|
51
|
-
*/
|
|
52
|
-
rules: ValidationRule[];
|
|
53
|
-
/**
|
|
54
|
-
* 自定义错误处理函数
|
|
55
|
-
* @param error 验证错误
|
|
56
|
-
* @param ctx 请求上下文
|
|
57
|
-
* @returns 返回自定义的Response对象或抛出错误使用默认处理
|
|
58
|
-
*/
|
|
59
|
-
errorHandler?: (error: Error, ctx: Context) => Response | never;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function validator(options: ValidatorOptions): Middleware {
|
|
63
|
-
if (!options.rules || options.rules.length === 0) {
|
|
64
|
-
throw new Error('Validator middleware requires at least one validation rule');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// 编译所有验证规则
|
|
68
|
-
const compiledRules = options.rules.map((rule) => {
|
|
69
|
-
const compiled: any = {};
|
|
70
|
-
|
|
71
|
-
if (rule.schema.query) {
|
|
72
|
-
compiled.query = ajv.compile(rule.schema.query);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (rule.schema.body) {
|
|
76
|
-
compiled.body = ajv.compile(rule.schema.body);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (rule.schema.params) {
|
|
80
|
-
compiled.params = ajv.compile(rule.schema.params);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (rule.schema.headers) {
|
|
84
|
-
compiled.headers = ajv.compile(rule.schema.headers);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
...rule,
|
|
89
|
-
compiled,
|
|
90
|
-
};
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
return async (ctx: Context, next: () => Promise<Response | Context | void>): Promise<Response | Context | void> => {
|
|
94
|
-
// 查找匹配的验证规则
|
|
95
|
-
const matchingRules = compiledRules.filter(
|
|
96
|
-
(rule) => rule.path === ctx.path && rule.method.toUpperCase() === ctx.method.toUpperCase(),
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
if (matchingRules.length === 0) {
|
|
100
|
-
// 没有匹配的验证规则,继续执行后续中间件
|
|
101
|
-
return await next();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// 使用第一个匹配的规则
|
|
105
|
-
const rule = matchingRules[0]!; // 类型断言,因为已经确保matchingRules.length > 0
|
|
106
|
-
const errors: any[] = [];
|
|
107
|
-
|
|
108
|
-
// 验证查询参数
|
|
109
|
-
if (rule.compiled.query) {
|
|
110
|
-
const query = Object.fromEntries(ctx.url.searchParams);
|
|
111
|
-
if (!rule.compiled.query(query)) {
|
|
112
|
-
errors.push(
|
|
113
|
-
...rule.compiled.query.errors!.map((err: any) => ({
|
|
114
|
-
...err,
|
|
115
|
-
source: 'query',
|
|
116
|
-
})),
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// 验证路由参数
|
|
122
|
-
if (rule.compiled.params) {
|
|
123
|
-
if (!rule.compiled.params(ctx.params)) {
|
|
124
|
-
errors.push(
|
|
125
|
-
...rule.compiled.params.errors!.map((err: any) => ({
|
|
126
|
-
...err,
|
|
127
|
-
source: 'params',
|
|
128
|
-
})),
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// 验证请求头
|
|
134
|
-
if (rule.compiled.headers) {
|
|
135
|
-
const headers = Object.fromEntries(ctx.headers);
|
|
136
|
-
if (!rule.compiled.headers(headers)) {
|
|
137
|
-
errors.push(
|
|
138
|
-
...rule.compiled.headers.errors!.map((err: any) => ({
|
|
139
|
-
...err,
|
|
140
|
-
source: 'headers',
|
|
141
|
-
})),
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// 验证请求体
|
|
147
|
-
if (rule.compiled.body && ctx.method !== 'GET' && ctx.method !== 'HEAD') {
|
|
148
|
-
try {
|
|
149
|
-
const body = await ctx.body();
|
|
150
|
-
if (!rule.compiled.body(body)) {
|
|
151
|
-
errors.push(
|
|
152
|
-
...rule.compiled.body.errors!.map((err: any) => ({
|
|
153
|
-
...err,
|
|
154
|
-
source: 'body',
|
|
155
|
-
})),
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
} catch (error) {
|
|
159
|
-
// 如果无法解析请求体,添加错误信息
|
|
160
|
-
errors.push({
|
|
161
|
-
keyword: 'invalid_body',
|
|
162
|
-
message: 'Invalid request body',
|
|
163
|
-
source: 'body',
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// 如果有验证错误
|
|
169
|
-
if (errors.length > 0) {
|
|
170
|
-
const error = new BadRequestError(errors);
|
|
171
|
-
|
|
172
|
-
// 使用自定义错误处理(如果提供)
|
|
173
|
-
if (options.errorHandler) {
|
|
174
|
-
const response = options.errorHandler(error, ctx);
|
|
175
|
-
if (response) {
|
|
176
|
-
return response;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// 抛出错误,由错误处理中间件处理
|
|
181
|
-
throw error;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// 验证通过,继续执行后续中间件
|
|
185
|
-
return await next();
|
|
186
|
-
};
|
|
187
|
-
}
|