vafast 0.2.3 → 0.3.1
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/README.md +437 -143
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/node-server/index.d.ts +22 -0
- package/dist/node-server/index.js +21 -0
- package/dist/node-server/request.d.ts +11 -0
- package/dist/node-server/request.js +157 -0
- package/dist/node-server/response.d.ts +15 -0
- package/dist/node-server/response.js +98 -0
- package/dist/node-server/serve.d.ts +52 -0
- package/dist/node-server/serve.js +88 -0
- package/dist/router/radix-tree.d.ts +12 -0
- package/dist/router/radix-tree.js +37 -1
- package/dist/serve.d.ts +12 -0
- package/dist/serve.js +11 -0
- package/dist/server/server.d.ts +9 -0
- package/dist/server/server.js +26 -1
- package/dist/types/types.d.ts +6 -1
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/parsers.d.ts +19 -1
- package/dist/utils/parsers.js +93 -9
- package/dist/utils/response.js +4 -3
- package/dist/utils/validators/validators.d.ts +36 -1
- package/dist/utils/validators/validators.js +83 -3
- package/package.json +9 -2
package/dist/utils/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 工具函数模块导出
|
|
3
3
|
*/
|
|
4
4
|
export { createHandler, createHandlerWithExtra, simpleHandler, } from "./create-handler";
|
|
5
|
-
export { parseBody, parseQuery, parseHeaders, parseCookies } from "./parsers";
|
|
5
|
+
export { parseBody, parseQuery, parseQueryFast, parseHeaders, getHeader, parseCookies, parseCookiesFast, getCookie, } from "./parsers";
|
|
6
6
|
export { json, text, html, redirect, empty, stream } from "./response";
|
|
7
7
|
export { goAwait } from "./go-await";
|
|
8
8
|
export { base64urlEncode, base64urlDecode } from "./base64url";
|
|
@@ -10,3 +10,4 @@ export { setLocals, getLocals } from "./handle";
|
|
|
10
10
|
export { parseRequest, validateRequest, parseAndValidateRequest, createRequestValidator, } from "./request-validator";
|
|
11
11
|
export { HtmlRenderer } from "./html-renderer";
|
|
12
12
|
export { DependencyManager } from "./dependency-manager";
|
|
13
|
+
export { validateSchema, createValidator, validateFast, precompileSchemas, getValidatorCacheStats, } from "./validators/validators";
|
package/dist/utils/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// 处理器工厂
|
|
5
5
|
export { createHandler, createHandlerWithExtra, simpleHandler, } from "./create-handler";
|
|
6
6
|
// 请求解析
|
|
7
|
-
export { parseBody, parseQuery, parseHeaders, parseCookies } from "./parsers";
|
|
7
|
+
export { parseBody, parseQuery, parseQueryFast, parseHeaders, getHeader, parseCookies, parseCookiesFast, getCookie, } from "./parsers";
|
|
8
8
|
// 响应工具
|
|
9
9
|
export { json, text, html, redirect, empty, stream } from "./response";
|
|
10
10
|
// Go 风格错误处理
|
|
@@ -19,3 +19,5 @@ export { parseRequest, validateRequest, parseAndValidateRequest, createRequestVa
|
|
|
19
19
|
export { HtmlRenderer } from "./html-renderer";
|
|
20
20
|
// 依赖管理
|
|
21
21
|
export { DependencyManager } from "./dependency-manager";
|
|
22
|
+
// 验证器(JIT 编译)
|
|
23
|
+
export { validateSchema, createValidator, validateFast, precompileSchemas, getValidatorCacheStats, } from "./validators/validators";
|
package/dist/utils/parsers.d.ts
CHANGED
|
@@ -29,8 +29,26 @@ export declare function parseFormData(req: Request): Promise<FormData>;
|
|
|
29
29
|
*/
|
|
30
30
|
export declare function parseFile(req: Request): Promise<FileInfo>;
|
|
31
31
|
/** 获取查询字符串,直接返回对象 */
|
|
32
|
-
export declare function parseQuery(req: Request): Record<string,
|
|
32
|
+
export declare function parseQuery(req: Request): Record<string, unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* 快速解析简单查询字符串(不支持嵌套,但更快)
|
|
35
|
+
* 适用于简单的 key=value&key2=value2 场景
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseQueryFast(req: Request): Record<string, string>;
|
|
33
38
|
/** 解析请求头,返回对象 */
|
|
34
39
|
export declare function parseHeaders(req: Request): Record<string, string>;
|
|
40
|
+
/**
|
|
41
|
+
* 获取单个请求头(避免解析全部)
|
|
42
|
+
*/
|
|
43
|
+
export declare function getHeader(req: Request, name: string): string | null;
|
|
35
44
|
/** 使用cookie库解析Cookie,保证可靠性 */
|
|
36
45
|
export declare function parseCookies(req: Request): Record<string, string>;
|
|
46
|
+
/**
|
|
47
|
+
* 快速解析 Cookie(简化版,不使用外部库)
|
|
48
|
+
* 适用于简单的 cookie 场景
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseCookiesFast(req: Request): Record<string, string>;
|
|
51
|
+
/**
|
|
52
|
+
* 获取单个 Cookie 值(避免解析全部)
|
|
53
|
+
*/
|
|
54
|
+
export declare function getCookie(req: Request, name: string): string | null;
|
package/dist/utils/parsers.js
CHANGED
|
@@ -87,21 +87,62 @@ export async function parseFile(req) {
|
|
|
87
87
|
}
|
|
88
88
|
return formData.files[fileKeys[0]];
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* 快速提取 query string(避免创建 URL 对象)
|
|
92
|
+
*/
|
|
93
|
+
function extractQueryString(url) {
|
|
94
|
+
const qIndex = url.indexOf("?");
|
|
95
|
+
if (qIndex === -1)
|
|
96
|
+
return "";
|
|
97
|
+
const hashIndex = url.indexOf("#", qIndex);
|
|
98
|
+
return hashIndex === -1
|
|
99
|
+
? url.substring(qIndex + 1)
|
|
100
|
+
: url.substring(qIndex + 1, hashIndex);
|
|
101
|
+
}
|
|
90
102
|
/** 获取查询字符串,直接返回对象 */
|
|
91
103
|
export function parseQuery(req) {
|
|
92
|
-
const
|
|
93
|
-
|
|
104
|
+
const queryString = extractQueryString(req.url);
|
|
105
|
+
if (!queryString)
|
|
106
|
+
return {};
|
|
107
|
+
return qs.parse(queryString);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 快速解析简单查询字符串(不支持嵌套,但更快)
|
|
111
|
+
* 适用于简单的 key=value&key2=value2 场景
|
|
112
|
+
*/
|
|
113
|
+
export function parseQueryFast(req) {
|
|
114
|
+
const queryString = extractQueryString(req.url);
|
|
115
|
+
if (!queryString)
|
|
116
|
+
return {};
|
|
117
|
+
const result = Object.create(null);
|
|
118
|
+
const pairs = queryString.split("&");
|
|
119
|
+
for (const pair of pairs) {
|
|
120
|
+
const eqIndex = pair.indexOf("=");
|
|
121
|
+
if (eqIndex === -1) {
|
|
122
|
+
result[decodeURIComponent(pair)] = "";
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const key = decodeURIComponent(pair.substring(0, eqIndex));
|
|
126
|
+
const value = decodeURIComponent(pair.substring(eqIndex + 1));
|
|
127
|
+
result[key] = value;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
94
131
|
}
|
|
95
132
|
/** 解析请求头,返回对象 */
|
|
96
133
|
export function parseHeaders(req) {
|
|
97
|
-
const headers =
|
|
134
|
+
const headers = Object.create(null);
|
|
98
135
|
req.headers.forEach((value, key) => {
|
|
99
|
-
|
|
100
|
-
headers[key] = value;
|
|
101
|
-
}
|
|
136
|
+
headers[key] = value;
|
|
102
137
|
});
|
|
103
138
|
return headers;
|
|
104
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* 获取单个请求头(避免解析全部)
|
|
142
|
+
*/
|
|
143
|
+
export function getHeader(req, name) {
|
|
144
|
+
return req.headers.get(name);
|
|
145
|
+
}
|
|
105
146
|
/** 使用cookie库解析Cookie,保证可靠性 */
|
|
106
147
|
export function parseCookies(req) {
|
|
107
148
|
const cookieHeader = req.headers.get("cookie");
|
|
@@ -118,9 +159,52 @@ export function parseCookies(req) {
|
|
|
118
159
|
}
|
|
119
160
|
return result;
|
|
120
161
|
}
|
|
121
|
-
catch
|
|
122
|
-
console.error("Cookie解析失败:", error);
|
|
123
|
-
console.error("原始Cookie字符串:", cookieHeader);
|
|
162
|
+
catch {
|
|
124
163
|
return {};
|
|
125
164
|
}
|
|
126
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* 快速解析 Cookie(简化版,不使用外部库)
|
|
168
|
+
* 适用于简单的 cookie 场景
|
|
169
|
+
*/
|
|
170
|
+
export function parseCookiesFast(req) {
|
|
171
|
+
const cookieHeader = req.headers.get("cookie");
|
|
172
|
+
if (!cookieHeader)
|
|
173
|
+
return {};
|
|
174
|
+
const result = Object.create(null);
|
|
175
|
+
const pairs = cookieHeader.split(";");
|
|
176
|
+
for (const pair of pairs) {
|
|
177
|
+
const trimmed = pair.trim();
|
|
178
|
+
const eqIndex = trimmed.indexOf("=");
|
|
179
|
+
if (eqIndex > 0) {
|
|
180
|
+
const key = trimmed.substring(0, eqIndex).trim();
|
|
181
|
+
const value = trimmed.substring(eqIndex + 1).trim();
|
|
182
|
+
// 移除引号
|
|
183
|
+
result[key] =
|
|
184
|
+
value.startsWith('"') && value.endsWith('"')
|
|
185
|
+
? value.slice(1, -1)
|
|
186
|
+
: value;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 获取单个 Cookie 值(避免解析全部)
|
|
193
|
+
*/
|
|
194
|
+
export function getCookie(req, name) {
|
|
195
|
+
const cookieHeader = req.headers.get("cookie");
|
|
196
|
+
if (!cookieHeader)
|
|
197
|
+
return null;
|
|
198
|
+
const prefix = `${name}=`;
|
|
199
|
+
const pairs = cookieHeader.split(";");
|
|
200
|
+
for (const pair of pairs) {
|
|
201
|
+
const trimmed = pair.trim();
|
|
202
|
+
if (trimmed.startsWith(prefix)) {
|
|
203
|
+
const value = trimmed.substring(prefix.length).trim();
|
|
204
|
+
return value.startsWith('"') && value.endsWith('"')
|
|
205
|
+
? value.slice(1, -1)
|
|
206
|
+
: value;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return null;
|
|
210
|
+
}
|
package/dist/utils/response.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// src/response.ts
|
|
2
2
|
/** 生成 JSON 响应 */
|
|
3
3
|
export function json(data, status = 200, headers = {}) {
|
|
4
|
+
const body = JSON.stringify(data);
|
|
4
5
|
// 优化:只在有自定义 headers 时才创建 Headers 对象
|
|
5
6
|
if (Object.keys(headers).length === 0) {
|
|
6
|
-
return new Response(
|
|
7
|
+
return new Response(body, {
|
|
7
8
|
status,
|
|
8
9
|
headers: { "Content-Type": "application/json" },
|
|
9
10
|
});
|
|
@@ -13,7 +14,7 @@ export function json(data, status = 200, headers = {}) {
|
|
|
13
14
|
"Content-Type": "application/json",
|
|
14
15
|
...headers,
|
|
15
16
|
});
|
|
16
|
-
return new Response(
|
|
17
|
+
return new Response(body, {
|
|
17
18
|
status,
|
|
18
19
|
headers: h,
|
|
19
20
|
});
|
|
@@ -55,7 +56,7 @@ export function mapResponse(response) {
|
|
|
55
56
|
if (response instanceof Promise) {
|
|
56
57
|
return response.then(mapResponse);
|
|
57
58
|
}
|
|
58
|
-
//
|
|
59
|
+
// 其他情况使用 JSON 序列化
|
|
59
60
|
return new Response(JSON.stringify(response), { headers: JSON_HEADERS });
|
|
60
61
|
}
|
|
61
62
|
}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 高性能 Schema 验证器
|
|
3
|
+
*
|
|
4
|
+
* 使用 TypeBox TypeCompiler 进行 JIT 编译
|
|
5
|
+
* 编译后的验证器会被缓存,避免重复编译开销
|
|
6
|
+
*
|
|
7
|
+
* @version 2.0.0 - 添加预编译缓存
|
|
8
|
+
*/
|
|
1
9
|
import { Type } from "@sinclair/typebox";
|
|
2
10
|
import type { Static, TSchema } from "@sinclair/typebox";
|
|
3
11
|
/** 验证错误接口 */
|
|
@@ -21,10 +29,37 @@ export interface ValidationSuccess<T> {
|
|
|
21
29
|
/** 验证结果联合类型 */
|
|
22
30
|
export type ValidationResult<T = unknown> = ValidationSuccess<T> | ValidationFailure;
|
|
23
31
|
/**
|
|
24
|
-
*
|
|
32
|
+
* 预编译 Schema(在启动时调用,避免首次请求的编译开销)
|
|
33
|
+
* @param schemas 要预编译的 Schema 数组
|
|
34
|
+
*/
|
|
35
|
+
export declare function precompileSchemas(schemas: TSchema[]): void;
|
|
36
|
+
/**
|
|
37
|
+
* 使用TypeBox Schema验证数据(带缓存优化)
|
|
25
38
|
* @param schema TypeBox Schema
|
|
26
39
|
* @param data 要验证的数据
|
|
27
40
|
* @returns 验证结果,包含类型安全的数据或详细错误信息
|
|
28
41
|
*/
|
|
29
42
|
export declare function validateSchema<T extends TSchema>(schema: T, data: unknown): ValidationResult<Static<T>>;
|
|
43
|
+
/**
|
|
44
|
+
* 创建类型特化的验证器(最高性能)
|
|
45
|
+
* 适用于频繁验证同一 Schema 的场景
|
|
46
|
+
* @param schema TypeBox Schema
|
|
47
|
+
* @returns 类型安全的验证函数
|
|
48
|
+
*/
|
|
49
|
+
export declare function createValidator<T extends TSchema>(schema: T): (data: unknown) => ValidationResult<Static<T>>;
|
|
50
|
+
/**
|
|
51
|
+
* 快速验证(只返回布尔值,不收集错误)
|
|
52
|
+
* 适用于只需要知道验证结果的场景
|
|
53
|
+
* @param schema TypeBox Schema
|
|
54
|
+
* @param data 要验证的数据
|
|
55
|
+
* @returns 验证是否通过
|
|
56
|
+
*/
|
|
57
|
+
export declare function validateFast<T extends TSchema>(schema: T, data: unknown): data is Static<T>;
|
|
58
|
+
/**
|
|
59
|
+
* 获取缓存统计信息(用于调试)
|
|
60
|
+
*/
|
|
61
|
+
export declare function getValidatorCacheStats(): {
|
|
62
|
+
cacheType: string;
|
|
63
|
+
note: string;
|
|
64
|
+
};
|
|
30
65
|
export { Type, Static, TSchema };
|
|
@@ -1,16 +1,51 @@
|
|
|
1
1
|
// src/utils/validators.ts
|
|
2
|
+
/**
|
|
3
|
+
* 高性能 Schema 验证器
|
|
4
|
+
*
|
|
5
|
+
* 使用 TypeBox TypeCompiler 进行 JIT 编译
|
|
6
|
+
* 编译后的验证器会被缓存,避免重复编译开销
|
|
7
|
+
*
|
|
8
|
+
* @version 2.0.0 - 添加预编译缓存
|
|
9
|
+
*/
|
|
2
10
|
import { Type } from "@sinclair/typebox";
|
|
3
11
|
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
4
12
|
/**
|
|
5
|
-
*
|
|
13
|
+
* 编译器缓存
|
|
14
|
+
* 使用 WeakMap 避免内存泄漏(Schema 对象被垃圾回收时,缓存也会自动清理)
|
|
15
|
+
*/
|
|
16
|
+
const compilerCache = new WeakMap();
|
|
17
|
+
/**
|
|
18
|
+
* 获取或创建编译后的验证器
|
|
19
|
+
* @param schema TypeBox Schema
|
|
20
|
+
* @returns 编译后的验证器
|
|
21
|
+
*/
|
|
22
|
+
function getCompiledValidator(schema) {
|
|
23
|
+
let compiler = compilerCache.get(schema);
|
|
24
|
+
if (!compiler) {
|
|
25
|
+
compiler = TypeCompiler.Compile(schema);
|
|
26
|
+
compilerCache.set(schema, compiler);
|
|
27
|
+
}
|
|
28
|
+
return compiler;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 预编译 Schema(在启动时调用,避免首次请求的编译开销)
|
|
32
|
+
* @param schemas 要预编译的 Schema 数组
|
|
33
|
+
*/
|
|
34
|
+
export function precompileSchemas(schemas) {
|
|
35
|
+
for (const schema of schemas) {
|
|
36
|
+
getCompiledValidator(schema);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 使用TypeBox Schema验证数据(带缓存优化)
|
|
6
41
|
* @param schema TypeBox Schema
|
|
7
42
|
* @param data 要验证的数据
|
|
8
43
|
* @returns 验证结果,包含类型安全的数据或详细错误信息
|
|
9
44
|
*/
|
|
10
45
|
export function validateSchema(schema, data) {
|
|
11
46
|
try {
|
|
12
|
-
//
|
|
13
|
-
const compiler =
|
|
47
|
+
// 从缓存获取或编译验证器
|
|
48
|
+
const compiler = getCompiledValidator(schema);
|
|
14
49
|
if (compiler.Check(data)) {
|
|
15
50
|
return {
|
|
16
51
|
success: true,
|
|
@@ -50,5 +85,50 @@ export function validateSchema(schema, data) {
|
|
|
50
85
|
};
|
|
51
86
|
}
|
|
52
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* 创建类型特化的验证器(最高性能)
|
|
90
|
+
* 适用于频繁验证同一 Schema 的场景
|
|
91
|
+
* @param schema TypeBox Schema
|
|
92
|
+
* @returns 类型安全的验证函数
|
|
93
|
+
*/
|
|
94
|
+
export function createValidator(schema) {
|
|
95
|
+
const compiler = getCompiledValidator(schema);
|
|
96
|
+
return (data) => {
|
|
97
|
+
if (compiler.Check(data)) {
|
|
98
|
+
return { success: true, data: data };
|
|
99
|
+
}
|
|
100
|
+
const errors = [];
|
|
101
|
+
for (const error of compiler.Errors(data)) {
|
|
102
|
+
errors.push({
|
|
103
|
+
path: error.path,
|
|
104
|
+
message: error.message,
|
|
105
|
+
code: "VALIDATION_FAILED",
|
|
106
|
+
value: error.value,
|
|
107
|
+
schema: error.schema,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return { success: false, errors };
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 快速验证(只返回布尔值,不收集错误)
|
|
115
|
+
* 适用于只需要知道验证结果的场景
|
|
116
|
+
* @param schema TypeBox Schema
|
|
117
|
+
* @param data 要验证的数据
|
|
118
|
+
* @returns 验证是否通过
|
|
119
|
+
*/
|
|
120
|
+
export function validateFast(schema, data) {
|
|
121
|
+
const compiler = getCompiledValidator(schema);
|
|
122
|
+
return compiler.Check(data);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 获取缓存统计信息(用于调试)
|
|
126
|
+
*/
|
|
127
|
+
export function getValidatorCacheStats() {
|
|
128
|
+
return {
|
|
129
|
+
cacheType: "WeakMap",
|
|
130
|
+
note: "WeakMap 不支持 size 属性,缓存会随 Schema 对象自动清理",
|
|
131
|
+
};
|
|
132
|
+
}
|
|
53
133
|
// 导出常用的TypeBox类型,方便使用
|
|
54
134
|
export { Type };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vafast",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "极简结构化Web框架,支持 Bun 和 Node.js。Go风格,函数优先。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -23,6 +23,12 @@
|
|
|
23
23
|
"require": "./dist/index.js",
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"default": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./node-server": {
|
|
28
|
+
"import": "./dist/node-server/index.js",
|
|
29
|
+
"require": "./dist/node-server/index.js",
|
|
30
|
+
"types": "./dist/node-server/index.d.ts",
|
|
31
|
+
"default": "./dist/node-server/index.js"
|
|
26
32
|
}
|
|
27
33
|
},
|
|
28
34
|
"types": "./dist/index.d.ts",
|
|
@@ -53,6 +59,7 @@
|
|
|
53
59
|
},
|
|
54
60
|
"keywords": [
|
|
55
61
|
"bun",
|
|
62
|
+
"node",
|
|
56
63
|
"framework",
|
|
57
64
|
"minimal",
|
|
58
65
|
"router",
|