vafast 0.1.11 → 0.1.13
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/auth/token.d.ts +40 -0
- package/dist/auth/token.js +124 -0
- package/dist/defineRoute.d.ts +2 -0
- package/dist/defineRoute.js +3 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/auth.d.ts +14 -0
- package/dist/middleware/auth.js +106 -0
- package/dist/middleware/authMiddleware.d.ts +2 -0
- package/dist/middleware/authMiddleware.js +13 -0
- package/dist/middleware/component-renderer.d.ts +6 -0
- package/dist/middleware/component-renderer.js +136 -0
- package/dist/middleware/component-router.d.ts +10 -0
- package/dist/middleware/component-router.js +39 -0
- package/dist/middleware/cors.d.ts +9 -0
- package/dist/middleware/cors.js +30 -0
- package/dist/middleware/rateLimit.d.ts +8 -0
- package/dist/middleware/rateLimit.js +33 -0
- package/dist/middleware.d.ts +18 -0
- package/dist/middleware.js +51 -0
- package/dist/monitoring/index.d.ts +29 -0
- package/dist/monitoring/index.js +24 -0
- package/dist/monitoring/native-monitor.d.ts +38 -0
- package/dist/monitoring/native-monitor.js +176 -0
- package/dist/monitoring/types.d.ts +146 -0
- package/dist/monitoring/types.js +8 -0
- package/dist/router.d.ts +17 -0
- package/dist/router.js +74 -0
- package/dist/server/base-server.d.ts +38 -0
- package/dist/server/base-server.js +167 -0
- package/dist/server/component-server.d.ts +32 -0
- package/dist/server/component-server.js +146 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.js +9 -0
- package/dist/server/server-factory.d.ts +42 -0
- package/dist/server/server-factory.js +70 -0
- package/dist/server/server.d.ts +7 -0
- package/dist/server/server.js +73 -0
- package/dist/types/component-route.d.ts +25 -0
- package/dist/types/component-route.js +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +3 -0
- package/dist/types/route.d.ts +39 -0
- package/dist/types/route.js +11 -0
- package/dist/types/types.d.ts +18 -0
- package/dist/types/types.js +1 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.js +1 -0
- package/dist/utils/base64url.d.ts +2 -0
- package/dist/utils/base64url.js +11 -0
- package/dist/utils/dependency-manager.d.ts +23 -0
- package/dist/utils/dependency-manager.js +67 -0
- package/dist/utils/go-await.d.ts +26 -0
- package/dist/utils/go-await.js +33 -0
- package/dist/utils/handle.d.ts +10 -0
- package/dist/utils/handle.js +24 -0
- package/dist/utils/html-renderer.d.ts +18 -0
- package/dist/utils/html-renderer.js +64 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.js +11 -0
- package/dist/utils/parsers.d.ts +36 -0
- package/dist/utils/parsers.js +126 -0
- package/dist/utils/path-matcher.d.ts +23 -0
- package/dist/utils/path-matcher.js +82 -0
- package/dist/utils/request-validator.d.ts +63 -0
- package/dist/utils/request-validator.js +94 -0
- package/dist/utils/response.d.ts +12 -0
- package/dist/utils/response.js +69 -0
- package/dist/utils/route-handler-factory.d.ts +50 -0
- package/dist/utils/route-handler-factory.js +182 -0
- package/dist/utils/validators/schema-validator.d.ts +66 -0
- package/dist/utils/validators/schema-validator.js +222 -0
- package/dist/utils/validators/schema-validators-ultra.d.ts +51 -0
- package/dist/utils/validators/schema-validators-ultra.js +289 -0
- package/dist/utils/validators/validators.d.ts +30 -0
- package/dist/utils/validators/validators.js +54 -0
- package/package.json +3 -4
- package/dist/index.cjs +0 -51
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -460
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface TokenPayload {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
exp?: number;
|
|
4
|
+
iat?: number;
|
|
5
|
+
sub?: string;
|
|
6
|
+
aud?: string;
|
|
7
|
+
iss?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface TokenResult {
|
|
10
|
+
payload: TokenPayload;
|
|
11
|
+
token: string;
|
|
12
|
+
expiresAt: number;
|
|
13
|
+
}
|
|
14
|
+
export interface TokenOptions {
|
|
15
|
+
expiresIn?: number;
|
|
16
|
+
issuer?: string;
|
|
17
|
+
audience?: string;
|
|
18
|
+
subject?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare class TokenError extends Error {
|
|
21
|
+
code: "INVALID_TOKEN" | "EXPIRED_TOKEN" | "INVALID_SIGNATURE" | "MALFORMED_TOKEN" | "INVALID_PAYLOAD";
|
|
22
|
+
constructor(message: string, code: "INVALID_TOKEN" | "EXPIRED_TOKEN" | "INVALID_SIGNATURE" | "MALFORMED_TOKEN" | "INVALID_PAYLOAD");
|
|
23
|
+
}
|
|
24
|
+
/** 生成令牌 */
|
|
25
|
+
export declare function generateToken(payload: TokenPayload, secret: string, options?: TokenOptions): Promise<TokenResult>;
|
|
26
|
+
/** 验证令牌 */
|
|
27
|
+
export declare function verifyToken(token: string, secret: string): Promise<TokenPayload | null>;
|
|
28
|
+
/** 解析令牌(不验证签名) */
|
|
29
|
+
export declare function parseToken(token: string): TokenPayload | null;
|
|
30
|
+
/** 检查令牌是否过期 */
|
|
31
|
+
export declare function isTokenExpired(token: string): boolean;
|
|
32
|
+
/** 获取令牌剩余有效时间(秒) */
|
|
33
|
+
export declare function getTokenTimeRemaining(token: string): number;
|
|
34
|
+
/** 刷新令牌 */
|
|
35
|
+
export declare function refreshToken(token: string, secret: string, options?: TokenOptions): Promise<TokenResult | null>;
|
|
36
|
+
/** 创建访问令牌和刷新令牌对 */
|
|
37
|
+
export declare function createTokenPair(payload: TokenPayload, secret: string, options?: TokenOptions): Promise<{
|
|
38
|
+
accessToken: TokenResult;
|
|
39
|
+
refreshToken: TokenResult;
|
|
40
|
+
}>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// src/auth/token.ts
|
|
2
|
+
import { base64urlEncode, base64urlDecode } from "../utils/base64url";
|
|
3
|
+
export class TokenError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
constructor(message, code) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.name = "TokenError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const encoder = new TextEncoder();
|
|
12
|
+
/** 使用 HMAC-SHA256 进行签名 */
|
|
13
|
+
async function sign(data, secret) {
|
|
14
|
+
const key = await crypto.subtle.importKey("raw", encoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
15
|
+
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(data));
|
|
16
|
+
return btoa(String.fromCharCode.apply(null, Array.from(new Uint8Array(signature))));
|
|
17
|
+
}
|
|
18
|
+
/** 生成令牌 */
|
|
19
|
+
export async function generateToken(payload, secret, options = {}) {
|
|
20
|
+
const { expiresIn = 3600, issuer, audience, subject } = options;
|
|
21
|
+
// 创建令牌载荷,强制使用当前时间
|
|
22
|
+
const now = Math.floor(Date.now() / 1000);
|
|
23
|
+
const tokenPayload = {
|
|
24
|
+
...payload,
|
|
25
|
+
iat: now,
|
|
26
|
+
exp: now + expiresIn,
|
|
27
|
+
};
|
|
28
|
+
// 添加可选字段
|
|
29
|
+
if (issuer)
|
|
30
|
+
tokenPayload.iss = issuer;
|
|
31
|
+
if (audience)
|
|
32
|
+
tokenPayload.aud = audience;
|
|
33
|
+
if (subject)
|
|
34
|
+
tokenPayload.sub = subject;
|
|
35
|
+
const data = base64urlEncode(JSON.stringify(tokenPayload));
|
|
36
|
+
const sig = await sign(data, secret);
|
|
37
|
+
const token = `${data}.${base64urlEncode(sig)}`;
|
|
38
|
+
return {
|
|
39
|
+
payload: tokenPayload,
|
|
40
|
+
token,
|
|
41
|
+
expiresAt: tokenPayload.exp * 1000, // 转换为毫秒
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** 验证令牌 */
|
|
45
|
+
export async function verifyToken(token, secret) {
|
|
46
|
+
try {
|
|
47
|
+
const [data, sig] = token.split(".");
|
|
48
|
+
if (!data || !sig) {
|
|
49
|
+
throw new TokenError("令牌格式无效", "MALFORMED_TOKEN");
|
|
50
|
+
}
|
|
51
|
+
const expectedSig = await sign(data, secret);
|
|
52
|
+
const expected = base64urlEncode(expectedSig);
|
|
53
|
+
if (sig !== expected) {
|
|
54
|
+
throw new TokenError("令牌签名无效", "INVALID_SIGNATURE");
|
|
55
|
+
}
|
|
56
|
+
const payload = JSON.parse(base64urlDecode(data));
|
|
57
|
+
// 检查过期时间
|
|
58
|
+
if (payload.exp && Date.now() / 1000 > payload.exp) {
|
|
59
|
+
throw new TokenError("令牌已过期", "EXPIRED_TOKEN");
|
|
60
|
+
}
|
|
61
|
+
return payload;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error instanceof TokenError) {
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
throw new TokenError("令牌验证失败", "INVALID_TOKEN");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** 解析令牌(不验证签名) */
|
|
71
|
+
export function parseToken(token) {
|
|
72
|
+
try {
|
|
73
|
+
const [data] = token.split(".");
|
|
74
|
+
if (!data)
|
|
75
|
+
return null;
|
|
76
|
+
return JSON.parse(base64urlDecode(data));
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** 检查令牌是否过期 */
|
|
83
|
+
export function isTokenExpired(token) {
|
|
84
|
+
const payload = parseToken(token);
|
|
85
|
+
if (!payload || !payload.exp)
|
|
86
|
+
return true;
|
|
87
|
+
return Date.now() / 1000 > payload.exp;
|
|
88
|
+
}
|
|
89
|
+
/** 获取令牌剩余有效时间(秒) */
|
|
90
|
+
export function getTokenTimeRemaining(token) {
|
|
91
|
+
const payload = parseToken(token);
|
|
92
|
+
if (!payload || !payload.exp)
|
|
93
|
+
return 0;
|
|
94
|
+
const remaining = payload.exp - Date.now() / 1000;
|
|
95
|
+
return Math.max(0, Math.floor(remaining));
|
|
96
|
+
}
|
|
97
|
+
/** 刷新令牌 */
|
|
98
|
+
export async function refreshToken(token, secret, options = {}) {
|
|
99
|
+
try {
|
|
100
|
+
const payload = await verifyToken(token, secret);
|
|
101
|
+
if (!payload)
|
|
102
|
+
return null;
|
|
103
|
+
// 移除时间相关字段,重新生成
|
|
104
|
+
const { exp, iat, ...cleanPayload } = payload;
|
|
105
|
+
// 添加延迟确保时间戳不同
|
|
106
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
107
|
+
return await generateToken(cleanPayload, secret, options);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** 创建访问令牌和刷新令牌对 */
|
|
114
|
+
export async function createTokenPair(payload, secret, options = {}) {
|
|
115
|
+
const accessToken = await generateToken(payload, secret, {
|
|
116
|
+
...options,
|
|
117
|
+
expiresIn: options.expiresIn || 3600, // 1小时
|
|
118
|
+
});
|
|
119
|
+
const refreshToken = await generateToken(payload, secret, {
|
|
120
|
+
...options,
|
|
121
|
+
expiresIn: 7 * 24 * 3600, // 7天
|
|
122
|
+
});
|
|
123
|
+
return { accessToken, refreshToken };
|
|
124
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./server";
|
|
2
|
+
export * from "./middleware";
|
|
3
|
+
export * from "./utils";
|
|
4
|
+
export * from "./router";
|
|
5
|
+
export * from "./middleware/authMiddleware";
|
|
6
|
+
export * from "./middleware/rateLimit";
|
|
7
|
+
export * from "./middleware/cors";
|
|
8
|
+
export * from "./auth/token";
|
|
9
|
+
export * from "./middleware/auth";
|
|
10
|
+
export * from "./defineRoute";
|
|
11
|
+
export * from "./types/index";
|
|
12
|
+
export { Type } from "@sinclair/typebox";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./server";
|
|
2
|
+
export * from "./middleware";
|
|
3
|
+
export * from "./utils";
|
|
4
|
+
export * from "./router";
|
|
5
|
+
export * from "./middleware/authMiddleware";
|
|
6
|
+
export * from "./middleware/rateLimit";
|
|
7
|
+
export * from "./middleware/cors";
|
|
8
|
+
export * from "./auth/token";
|
|
9
|
+
export * from "./middleware/auth";
|
|
10
|
+
export * from "./defineRoute";
|
|
11
|
+
export * from "./types/index";
|
|
12
|
+
// 重新导出 Type 以便用户使用
|
|
13
|
+
export { Type } from "@sinclair/typebox";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["flattened: FlattenedRoute[]","params: Record<string, string>","stream","errorHandler: Middleware","params: Record<string, string>","availableMethods: string[]","params: Record<string, string>","matched: FlattenedRoute | undefined","params: Record<string, string>","availableMethods: string[]","handler: Handler","req","flattened: FlattenedComponentRoute[]","status: Record<string, boolean>","matchedRoute: FlattenedComponentRoute | null","html","status: Record<string, { type: string; routes: number }>","text","result: FormData","headers: Record<string, string>","result: Record<string, string>","requireAuth: Middleware","code:\n | \"INVALID_TOKEN\"\n | \"EXPIRED_TOKEN\"\n | \"INVALID_SIGNATURE\"\n | \"MALFORMED_TOKEN\"\n | \"INVALID_PAYLOAD\"","tokenPayload: TokenPayload","refreshToken","errorPool: Error[]","defaultValidationErrorHandler: ValidationErrorHandler","errorHandler","queryObj: TQuery","headers: THeaders","cookies: TCookies","body: TBody","params: TParams"],"sources":["../src/router.ts","../src/utils/response.ts","../src/middleware.ts","../src/server/base-server.ts","../src/utils/path-matcher.ts","../src/server/server.ts","../src/middleware/component-router.ts","../src/utils/html-renderer.ts","../src/utils/dependency-manager.ts","../src/server/component-server.ts","../src/server/server-factory.ts","../src/utils/parsers.ts","../src/utils/handle.ts","../src/middleware/authMiddleware.ts","../src/middleware/rateLimit.ts","../src/middleware/cors.ts","../src/utils/base64url.ts","../src/auth/token.ts","../src/middleware/auth.ts","../src/defineRoute.ts","../src/utils/go-await.ts","../src/utils/validators/schema-validators-ultra.ts","../src/utils/route-handler-factory.ts"],"sourcesContent":["import type { Route, NestedRoute, FlattenedRoute } from \"./types\";\n\nexport interface MatchResult {\n matched: boolean;\n params: Record<string, string>;\n}\n\n/**\n * 扁平化嵌套路由,计算完整路径和中间件链\n */\nexport function flattenNestedRoutes(routes: (Route | NestedRoute)[]): FlattenedRoute[] {\n const flattened: FlattenedRoute[] = [];\n \n function processRoute(\n route: Route | NestedRoute, \n parentPath: string = \"\", \n parentMiddleware: any[] = []\n ) {\n const currentPath = parentPath + route.path;\n const currentMiddleware = [...parentMiddleware, ...(route.middleware || [])];\n \n if ('method' in route && 'handler' in route) {\n // 这是一个叶子路由(有处理函数)\n flattened.push({\n ...route,\n fullPath: currentPath,\n middlewareChain: currentMiddleware\n });\n } else if ('children' in route && route.children) {\n // 这是一个分组路由,处理子路由\n for (const child of route.children) {\n processRoute(child, currentPath, currentMiddleware);\n }\n }\n }\n \n for (const route of routes) {\n processRoute(route);\n }\n \n return flattened;\n}\n\n/**\n * 标准化路径:去重斜杠、解码URL、处理结尾斜杠\n */\nexport function normalizePath(path: string): string {\n // 解码 URL 编码的字符\n let normalized = decodeURIComponent(path);\n \n // 去重连续的斜杠\n normalized = normalized.replace(/\\/+/g, \"/\");\n \n // 处理根路径\n if (normalized === \"\") normalized = \"/\";\n \n // 去掉结尾斜杠(除非是根路径)\n if (normalized !== \"/\" && normalized.endsWith(\"/\")) {\n normalized = normalized.slice(0, -1);\n }\n \n return normalized;\n}\n\n/**\n * 匹配函数:支持动态路由和路径标准化\n */\nexport function matchPath(pattern: string, path: string): MatchResult {\n // 标准化输入路径\n const normalizedPath = normalizePath(path);\n const patternParts = pattern.split(\"/\").filter(Boolean);\n const pathParts = normalizedPath.split(\"/\").filter(Boolean);\n\n const params: Record<string, string> = {};\n\n for (let i = 0; i < patternParts.length; i++) {\n const pat = patternParts[i];\n const part = pathParts[i];\n\n if (pat === \"*\") {\n params[\"*\"] = pathParts.slice(i).join(\"/\");\n return { matched: true, params };\n }\n\n if (pat.startsWith(\":\")) {\n if (!part) return { matched: false, params: {} };\n params[pat.slice(1)] = part;\n continue;\n }\n\n if (pat !== part) return { matched: false, params: {} };\n }\n\n if (patternParts.length !== pathParts.length) return { matched: false, params: {} };\n\n return { matched: true, params };\n}\n","// src/response.ts\n\n/** 生成 JSON 响应 */\nexport function json(\n data: unknown,\n status = 200,\n headers: HeadersInit = {}\n): Response {\n // 优化:只在有自定义 headers 时才创建 Headers 对象\n if (Object.keys(headers).length === 0) {\n return new Response(JSON.stringify(data), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n // 有自定义 headers 时才创建 Headers 对象\n const h = new Headers({\n \"Content-Type\": \"application/json\",\n ...headers,\n });\n\n return new Response(JSON.stringify(data), {\n status,\n headers: h,\n });\n}\n\n/** 生成重定向响应 */\nexport function redirect(location: string, status: 301 | 302 = 302): Response {\n return new Response(null, {\n status,\n headers: {\n Location: location,\n },\n });\n}\n\n/** 生成纯文本响应 */\nexport function text(\n content: string,\n status = 200,\n headers: HeadersInit = {}\n): Response {\n const h = new Headers({\n \"Content-Type\": \"text/plain; charset=utf-8\",\n ...headers,\n });\n\n return new Response(content, {\n status,\n headers: h,\n });\n}\n\n/** 生成HTML响应 */\nexport function html(\n content: string,\n status = 200,\n headers: HeadersInit = {}\n): Response {\n const h = new Headers({\n \"Content-Type\": \"text/html; charset=utf-8\",\n ...headers,\n });\n\n return new Response(content, {\n status,\n headers: h,\n });\n}\n\n/** 生成空响应(204 No Content) */\nexport function empty(status = 204, headers: HeadersInit = {}): Response {\n return new Response(null, {\n status,\n headers,\n });\n}\n\n/** 生成流式响应 */\nexport function stream(\n stream: ReadableStream,\n status = 200,\n headers: HeadersInit = {}\n): Response {\n const h = new Headers({\n \"Content-Type\": \"application/octet-stream\",\n ...headers,\n });\n\n return new Response(stream, {\n status,\n headers: h,\n });\n}\n","// src/middleware.ts\n\nimport { json } from \"./utils/response\";\n\nimport type { Handler, Middleware } from \"./types\";\n/** 中间件类型:使用 next() 传递给下一个处理 */\n\n/** Vafast 自定义错误类型 */\nexport class VafastError extends Error {\n status: number;\n type: string;\n expose: boolean;\n\n constructor(\n message: string,\n options: {\n status?: number;\n type?: string;\n expose?: boolean;\n cause?: unknown;\n } = {}\n ) {\n super(message);\n this.name = \"VafastError\";\n this.status = options.status ?? 500;\n this.type = options.type ?? \"internal_error\";\n this.expose = options.expose ?? false;\n if (options.cause) (this as any).cause = options.cause;\n }\n}\n\n/**\n * 组合类型: 自动注入错误处理器进行中间件组合\n */\nexport function composeMiddleware(\n middleware: Middleware[],\n finalHandler: Handler\n): Handler {\n const all = [errorHandler, ...middleware];\n\n return function composedHandler(req: Request): Promise<Response> {\n let i = -1;\n\n const dispatch = (index: number): Promise<Response> => {\n if (index <= i)\n return Promise.reject(new Error(\"next() called multiple times\"));\n i = index;\n const fn = index < all.length ? all[index] : finalHandler;\n return Promise.resolve(\n fn(req, (() => dispatch(index + 1)) as unknown as Record<\n string,\n string\n > &\n (() => Promise<Response>))\n );\n };\n\n return dispatch(0);\n };\n}\n\n/** 默认包含的全局错误处理器 */\nconst errorHandler: Middleware = async (req, next) => {\n try {\n return await next();\n } catch (err) {\n console.error(\"未处理的错误:\", err);\n\n if (err instanceof VafastError) {\n return json(\n {\n error: err.type,\n message: err.expose ? err.message : \"发生了一个错误\",\n },\n err.status\n );\n }\n\n return json({ error: \"internal_error\", message: \"出现了一些问题\" }, 500);\n }\n};\n","import type { Middleware } from \"../types\";\n\n/**\n * 服务器基类\n * 包含所有服务器类型的公共逻辑\n */\nexport abstract class BaseServer {\n protected globalMiddleware: Middleware[] = [];\n\n use(mw: Middleware) {\n this.globalMiddleware.push(mw);\n }\n\n /**\n * 打印扁平化后的路由信息,用于调试\n */\n protected logFlattenedRoutes(routes: any[], type: string = \"路由\"): void {\n console.log(`🚀 扁平化后的${type}:`);\n for (const route of routes) {\n const method = route.method || \"GET\";\n const path = route.fullPath || route.path;\n console.log(` ${method} ${path}`);\n if (route.middlewareChain && route.middlewareChain.length > 0) {\n console.log(` 中间件链: ${route.middlewareChain.length} 个`);\n }\n }\n console.log(\"\");\n }\n\n /**\n * 检测路由冲突\n * 检查是否有路径相同但方法不同的路由,以及潜在的路径冲突\n */\n protected detectRouteConflicts(routes: any[]): void {\n const pathGroups = new Map<string, any[]>();\n\n // 按路径分组\n for (const route of routes) {\n const path = route.fullPath || route.path;\n const method = route.method || \"GET\";\n if (!pathGroups.has(path)) {\n pathGroups.set(path, []);\n }\n pathGroups.get(path)!.push({ ...route, method });\n }\n\n // 检查冲突\n for (const [path, routeList] of pathGroups) {\n if (routeList.length > 1) {\n const methods = routeList.map((r) => r.method);\n const uniqueMethods = [...new Set(methods)];\n\n if (uniqueMethods.length === 1) {\n // 相同路径、相同方法 - 这是冲突!\n console.warn(\n `⚠️ 路由冲突: ${uniqueMethods[0]} ${path} 定义了 ${routeList.length} 次`\n );\n routeList.forEach((route, index) => {\n console.warn(` ${index + 1}. ${route.method} ${path}`);\n });\n } else {\n // 相同路径、不同方法 - 这是正常的\n console.log(`ℹ️ 路径 ${path} 支持方法: ${uniqueMethods.join(\", \")}`);\n }\n }\n }\n\n // 检查潜在的路径冲突(动态路由可能冲突)\n this.detectDynamicRouteConflicts(routes);\n }\n\n /**\n * 检测动态路由的潜在冲突\n */\n private detectDynamicRouteConflicts(routes: any[]): void {\n const dynamicRoutes = routes.filter(\n (r) => {\n const path = r.fullPath || r.path;\n return path.includes(\":\") || path.includes(\"*\");\n }\n );\n\n for (let i = 0; i < dynamicRoutes.length; i++) {\n for (let j = i + 1; j < dynamicRoutes.length; j++) {\n const route1 = dynamicRoutes[i];\n const route2 = dynamicRoutes[j];\n const method1 = route1.method || \"GET\";\n const method2 = route2.method || \"GET\";\n\n if (method1 === method2) {\n const path1 = route1.fullPath || route1.path;\n const path2 = route2.fullPath || route2.path;\n // 检查路径是否可能冲突\n if (this.pathsMayConflict(path1, path2)) {\n console.warn(\n `⚠️ 潜在路由冲突: ${method1} ${path1} 可能与 ${path2} 冲突`\n );\n }\n }\n }\n }\n }\n\n /**\n * 判断两个路径是否可能冲突\n */\n private pathsMayConflict(path1: string, path2: string): boolean {\n const parts1 = path1.split(\"/\").filter(Boolean);\n const parts2 = path2.split(\"/\").filter(Boolean);\n\n if (parts1.length !== parts2.length) return false;\n\n for (let i = 0; i < parts1.length; i++) {\n const p1 = parts1[i];\n const p2 = parts2[i];\n\n // 如果两个部分都是静态的且不同,则不会冲突\n if (\n !p1.startsWith(\":\") &&\n !p1.startsWith(\"*\") &&\n !p2.startsWith(\":\") &&\n !p2.startsWith(\"*\") &&\n p1 !== p2\n ) {\n return false;\n }\n\n // 如果一个是通配符,另一个是动态参数,可能冲突\n if (\n (p1 === \"*\" && p2.startsWith(\":\")) ||\n (p2 === \"*\" && p1.startsWith(\":\"))\n ) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 路径匹配\n */\n protected matchPath(pattern: string, path: string): boolean {\n const patternParts = pattern.split(\"/\").filter(Boolean);\n const pathParts = path.split(\"/\").filter(Boolean);\n\n if (patternParts.length !== pathParts.length) {\n return false;\n }\n\n for (let i = 0; i < patternParts.length; i++) {\n if (patternParts[i] !== pathParts[i] && !patternParts[i].startsWith(\":\")) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 提取路径参数\n */\n protected extractParams(pattern: string, path: string): Record<string, string> {\n const params: Record<string, string> = {};\n const patternParts = pattern.split(\"/\").filter(Boolean);\n const pathParts = path.split(\"/\").filter(Boolean);\n\n for (let i = 0; i < patternParts.length; i++) {\n if (patternParts[i].startsWith(\":\")) {\n const paramName = patternParts[i].slice(1);\n params[paramName] = pathParts[i];\n }\n }\n\n return params;\n }\n\n /**\n * 处理 OPTIONS 请求\n */\n protected handleOptions(pathname: string, routes: any[]): Response {\n const availableMethods: string[] = [];\n\n for (const route of routes) {\n const path = route.fullPath || route.path;\n const method = route.method || \"GET\";\n if (this.matchPath(path, pathname)) {\n availableMethods.push(method);\n }\n }\n\n // 去重并排序\n const uniqueMethods = [...new Set(availableMethods)].sort();\n\n return new Response(null, {\n status: 204,\n headers: {\n Allow: uniqueMethods.join(\", \"),\n \"Access-Control-Allow-Methods\": uniqueMethods.join(\", \"),\n \"Access-Control-Allow-Headers\": \"Content-Type, Authorization\",\n },\n });\n }\n}\n","/**\n * 路径匹配工具类\n * 提供统一的路径匹配和参数提取功能\n */\nexport class PathMatcher {\n /**\n * 路径匹配\n */\n static matchPath(pattern: string, path: string): boolean {\n const patternParts = pattern.split(\"/\").filter(Boolean);\n const pathParts = path.split(\"/\").filter(Boolean);\n\n if (patternParts.length !== pathParts.length) {\n return false;\n }\n\n for (let i = 0; i < patternParts.length; i++) {\n if (patternParts[i] !== pathParts[i] && !patternParts[i].startsWith(\":\")) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 提取路径参数\n */\n static extractParams(pattern: string, path: string): Record<string, string> {\n const params: Record<string, string> = {};\n const patternParts = pattern.split(\"/\").filter(Boolean);\n const pathParts = path.split(\"/\").filter(Boolean);\n\n for (let i = 0; i < patternParts.length; i++) {\n if (patternParts[i].startsWith(\":\")) {\n const paramName = patternParts[i].slice(1);\n params[paramName] = pathParts[i];\n }\n }\n\n return params;\n }\n\n /**\n * 计算路径特异性分数\n * 用于路由排序:静态 > 动态(:param) > 通配符(*)\n */\n static calculatePathScore(path: string): number {\n const parts = path.split(\"/\").filter(Boolean);\n let score = 0;\n for (const p of parts) {\n if (p === \"*\") score += 1; // 最弱\n else if (p.startsWith(\":\")) score += 2; // 中等\n else score += 3; // 静态最强\n }\n // 更长的路径更具体,略微提升\n return score * 10 + parts.length;\n }\n\n /**\n * 判断两个路径是否可能冲突\n */\n static pathsMayConflict(path1: string, path2: string): boolean {\n const parts1 = path1.split(\"/\").filter(Boolean);\n const parts2 = path2.split(\"/\").filter(Boolean);\n\n if (parts1.length !== parts2.length) return false;\n\n for (let i = 0; i < parts1.length; i++) {\n const p1 = parts1[i];\n const p2 = parts2[i];\n\n // 如果两个部分都是静态的且不同,则不会冲突\n if (\n !p1.startsWith(\":\") &&\n !p1.startsWith(\"*\") &&\n !p2.startsWith(\":\") &&\n !p2.startsWith(\"*\") &&\n p1 !== p2\n ) {\n return false;\n }\n\n // 如果一个是通配符,另一个是动态参数,可能冲突\n if (\n (p1 === \"*\" && p2.startsWith(\":\")) ||\n (p2 === \"*\" && p1.startsWith(\":\"))\n ) {\n return true;\n }\n }\n\n return false;\n }\n}\n","import type {\n Handler,\n Middleware,\n Route,\n NestedRoute,\n FlattenedRoute,\n} from \"../types\";\nimport { matchPath, flattenNestedRoutes } from \"../router\";\nimport { composeMiddleware } from \"../middleware\";\nimport { json } from \"../utils/response\";\nimport { BaseServer } from \"./base-server\";\nimport { PathMatcher } from \"../utils/path-matcher\";\n\nexport class Server extends BaseServer {\n private routes: FlattenedRoute[];\n\n constructor(routes: (Route | NestedRoute)[]) {\n super();\n // 扁平化嵌套路由,计算完整的中间件链\n this.routes = flattenNestedRoutes(routes);\n\n // 在构造时按路由\"特异性\"排序:静态 > 动态(:param) > 通配符(*)\n this.routes = this.routes.sort(\n (a, b) =>\n PathMatcher.calculatePathScore(b.fullPath) -\n PathMatcher.calculatePathScore(a.fullPath)\n );\n\n // 检测路由冲突\n this.detectRouteConflicts(this.routes);\n\n // 打印扁平化后的路由信息\n this.logFlattenedRoutes(this.routes);\n }\n\n fetch = async (req: Request): Promise<Response> => {\n const { pathname } = new URL(req.url);\n const method = req.method;\n\n // 自动处理 OPTIONS 请求\n if (method === \"OPTIONS\") {\n return this.handleOptions(pathname, this.routes);\n }\n\n let matched: FlattenedRoute | undefined;\n let params: Record<string, string> = {};\n let availableMethods: string[] = [];\n\n for (const route of this.routes) {\n const result = matchPath(route.fullPath, pathname);\n if (result.matched) {\n if (route.method === method) {\n matched = route;\n params = result.params;\n break;\n } else {\n // 路径匹配但方法不匹配,收集可用方法\n availableMethods.push(route.method);\n }\n }\n }\n\n const handler: Handler = async (req) => {\n if (matched) {\n // 将路径参数设置到 req 对象上,以便 TypedRoute 处理器能够访问\n (req as any).params = params;\n return await matched.handler(req, params);\n } else if (availableMethods.length > 0) {\n // 路径存在但方法不匹配,返回 405 Method Not Allowed\n return json(\n {\n success: false,\n error: \"Method Not Allowed\",\n message: `Method ${method} not allowed for this endpoint`,\n allowedMethods: availableMethods,\n },\n 405,\n {\n Allow: availableMethods.join(\", \"),\n }\n );\n } else {\n // 路径不存在,返回 404 Not Found\n return json({ success: false, error: \"Not Found\" }, 404);\n }\n };\n\n const middlewareChain = matched?.middlewareChain\n ? [...this.globalMiddleware, ...matched.middlewareChain]\n : this.globalMiddleware;\n\n // 使用 composeMiddleware 来确保错误处理中间件被应用\n const composedHandler = composeMiddleware(middlewareChain, handler);\n return await composedHandler(req);\n };\n}\n","import type {\n ComponentRoute,\n NestedComponentRoute,\n FlattenedComponentRoute,\n} from \"../types/component-route\";\nimport { vueRenderer, reactRenderer } from \"./component-renderer\";\n\n/**\n * 扁平化嵌套组件路由\n */\nexport function flattenComponentRoutes(\n routes: (ComponentRoute | NestedComponentRoute)[]\n): FlattenedComponentRoute[] {\n const flattened: FlattenedComponentRoute[] = [];\n\n function processRoute(\n route: ComponentRoute | NestedComponentRoute,\n parentPath: string = \"\",\n parentMiddleware: any[] = []\n ) {\n const currentPath = parentPath + route.path;\n const currentMiddleware = [...parentMiddleware, ...(route.middleware || [])];\n\n if (\"component\" in route) {\n // 这是一个组件路由\n flattened.push({\n ...route,\n fullPath: currentPath,\n middlewareChain: currentMiddleware,\n });\n } else if (\"children\" in route && route.children) {\n // 这是一个嵌套路由\n for (const child of route.children) {\n processRoute(child, currentPath, currentMiddleware);\n }\n }\n }\n\n for (const route of routes) {\n processRoute(route);\n }\n\n return flattened;\n}\n\n/**\n * 组件路由处理器中间件\n * 自动检测组件类型并应用相应的渲染器\n */\nexport const componentRouter = () => {\n return async (req: Request, next: () => Promise<Response>) => {\n // 这里可以添加组件路由的自动处理逻辑\n // 比如自动检测组件类型,应用相应的渲染器\n return next();\n };\n};\n","/**\n * HTML渲染工具类\n * 提供统一的HTML模板生成功能\n */\nexport class HtmlRenderer {\n /**\n * 生成基础HTML模板\n */\n static generateBaseHtml(\n content: string,\n context: any,\n clientScriptPath: string = \"/client.js\"\n ): string {\n return `\n <!doctype html>\n <html>\n <head>\n <meta charset=\"utf-8\">\n <title>Vafast SSR App</title>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n </head>\n <body>\n <div id=\"app\">${content}</div>\n <script>\n window.__ROUTE_INFO__ = {\n params: ${JSON.stringify(context.params || {})},\n query: ${JSON.stringify(context.query || {})},\n pathname: '${context.pathname}'\n };\n </script>\n <script type=\"module\" src=\"${clientScriptPath}\"></script>\n </body>\n </html>\n `;\n }\n\n /**\n * 生成Vue组件HTML\n */\n static generateVueHtml(\n content: string,\n context: any,\n clientScriptPath: string = \"/client.js\"\n ): string {\n return this.generateBaseHtml(content, context, clientScriptPath);\n }\n\n /**\n * 生成React组件HTML\n */\n static generateReactHtml(\n content: string,\n context: any,\n clientScriptPath: string = \"/client.js\"\n ): string {\n return `\n <!doctype html>\n <html>\n <head>\n <meta charset=\"utf-8\">\n <title>Vafast SSR App</title>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n </head>\n <body>\n <div id=\"root\">${content}</div>\n <script>\n window.__ROUTE_INFO__ = {\n params: ${JSON.stringify(context.params || {})},\n query: ${JSON.stringify(context.query || {})},\n pathname: '${context.pathname}'\n };\n </script>\n <script type=\"module\" src=\"${clientScriptPath}\"></script>\n </body>\n </html>\n `;\n }\n}\n","/**\n * 依赖管理器\n * 负责按需加载和管理框架依赖\n */\nexport class DependencyManager {\n private dependencyCache = new Map<string, any>();\n\n /**\n * 按需获取框架依赖\n */\n async getFrameworkDeps(framework: \"vue\" | \"react\") {\n if (this.dependencyCache.has(framework)) {\n return this.dependencyCache.get(framework);\n }\n\n console.log(`📦 按需加载 ${framework} 依赖...`);\n\n try {\n let deps;\n switch (framework) {\n case \"vue\":\n deps = await Promise.all([import(\"vue\"), import(\"@vue/server-renderer\")]);\n break;\n case \"react\":\n deps = await Promise.all([import(\"react\"), import(\"react-dom/server\")]);\n break;\n default:\n throw new Error(`不支持的框架: ${framework}`);\n }\n\n this.dependencyCache.set(framework, deps);\n console.log(`✅ ${framework} 依赖加载完成`);\n return deps;\n } catch (error) {\n console.error(`❌ ${framework} 依赖加载失败:`, error);\n throw error;\n }\n }\n\n /**\n * 检测组件类型\n */\n detectComponentType(component: any): \"vue\" | \"react\" {\n // 简单的组件类型检测\n if (component.render && typeof component.render === \"function\") {\n return \"vue\";\n }\n if (component.$$typeof) {\n return \"react\";\n }\n // 默认使用 Vue\n return \"vue\";\n }\n\n /**\n * 清除缓存\n */\n clearCache(): void {\n this.dependencyCache.clear();\n console.log(\"🧹 依赖缓存已清除\");\n }\n\n /**\n * 获取缓存状态\n */\n getCacheStatus(): Record<string, boolean> {\n const status: Record<string, boolean> = {};\n for (const [framework] of this.dependencyCache) {\n status[framework] = true;\n }\n return status;\n }\n}\n","import type {\n ComponentRoute,\n NestedComponentRoute,\n FlattenedComponentRoute,\n} from \"../types/component-route\";\nimport { flattenComponentRoutes } from \"../middleware/component-router\";\nimport { BaseServer } from \"./base-server\";\nimport { PathMatcher } from \"../utils/path-matcher\";\nimport { HtmlRenderer } from \"../utils/html-renderer\";\nimport { DependencyManager } from \"../utils/dependency-manager\";\n\n/**\n * 组件路由服务器\n * 专门处理声明式组件路由\n */\nexport class ComponentServer extends BaseServer {\n private routes: FlattenedComponentRoute[];\n private dependencyManager: DependencyManager;\n\n constructor(routes: (ComponentRoute | NestedComponentRoute)[]) {\n super();\n this.routes = flattenComponentRoutes(routes);\n this.dependencyManager = new DependencyManager();\n\n // 检测路由冲突\n this.detectRouteConflicts(this.routes);\n this.logFlattenedRoutes(this.routes, \"组件路由\");\n console.log(\"🚀 依赖按需加载,服务器启动完成\");\n }\n\n /**\n * 处理请求\n */\n async fetch(req: Request): Promise<Response> {\n const url = new URL(req.url);\n const pathname = url.pathname;\n const method = req.method;\n\n // 只支持 GET 请求\n if (method !== \"GET\") {\n return new Response(\"Method Not Allowed\", { status: 405 });\n }\n\n // 查找匹配的路由\n let matchedRoute: FlattenedComponentRoute | null = null;\n for (const route of this.routes) {\n if (PathMatcher.matchPath(route.fullPath, pathname)) {\n matchedRoute = route;\n break;\n }\n }\n\n if (!matchedRoute) {\n return new Response(\"Not Found\", { status: 404 });\n }\n\n try {\n // 创建中间件上下文\n const context = {\n req,\n params: PathMatcher.extractParams(matchedRoute.fullPath, pathname),\n query: Object.fromEntries(url.searchParams),\n pathname,\n };\n\n // 执行中间件链,中间件会处理组件渲染\n return await this.executeMiddlewareChain(\n matchedRoute.middlewareChain,\n context,\n matchedRoute.component\n );\n } catch (error) {\n console.error(\"组件渲染失败:\", error);\n return new Response(\"Internal Server Error\", { status: 500 });\n }\n }\n\n /**\n * 执行中间件链\n */\n private async executeMiddlewareChain(\n middlewareChain: any[],\n context: any,\n componentImport: () => Promise<any>\n ): Promise<Response> {\n // 创建最终的渲染函数\n const renderComponent = async () => {\n const componentModule = await componentImport();\n const component = componentModule.default || componentModule;\n\n // 自动检测组件类型\n const componentType =\n this.dependencyManager.detectComponentType(component);\n\n // 按需加载依赖\n const deps = await this.dependencyManager.getFrameworkDeps(componentType);\n\n // 根据组件类型渲染\n if (componentType === \"vue\") {\n return await this.renderVueComponent(component, context, deps);\n } else if (componentType === \"react\") {\n return await this.renderReactComponent(component, context, deps);\n } else {\n throw new Error(`不支持的组件类型: ${componentType}`);\n }\n };\n\n // 执行中间件链\n let index = 0;\n const next = async (): Promise<Response> => {\n if (index >= middlewareChain.length) {\n return await renderComponent();\n }\n\n const middleware = middlewareChain[index++];\n return await middleware(context.req, next);\n };\n\n return await next();\n }\n\n /**\n * 渲染 Vue 组件\n */\n private async renderVueComponent(\n component: any,\n context: any,\n deps: any\n ): Promise<Response> {\n try {\n const [vue, renderer] = deps;\n const app = vue.createSSRApp(component);\n\n // 提供路由信息\n app.provide(\"routeInfo\", {\n params: context.params || {},\n query: context.query || {},\n pathname: context.pathname,\n });\n\n const html = await renderer.renderToString(app);\n const fullHtml = HtmlRenderer.generateVueHtml(html, context);\n\n return new Response(fullHtml, {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n } catch (error) {\n console.error(\"Vue 组件渲染失败:\", error);\n return new Response(\"Vue Component Render Error\", { status: 500 });\n }\n }\n\n /**\n * 渲染 React 组件\n */\n private async renderReactComponent(\n component: any,\n context: any,\n deps: any\n ): Promise<Response> {\n try {\n const [react, renderer] = deps;\n const content = react.createElement(component, {\n req: context.req,\n params: context.params || {},\n query: context.query || {},\n });\n\n const html = renderer.renderToString(content);\n const fullHtml = HtmlRenderer.generateReactHtml(html, context);\n\n return new Response(fullHtml, {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n } catch (error) {\n console.error(\"React 组件渲染失败:\", error);\n return new Response(\"React Component Render Error\", { status: 500 });\n }\n }\n\n /**\n * 获取依赖管理器(用于外部访问)\n */\n getDependencyManager(): DependencyManager {\n return this.dependencyManager;\n }\n}\n","import type { Route, NestedRoute } from \"../types\";\nimport type {\n ComponentRoute,\n NestedComponentRoute,\n} from \"../types/component-route\";\nimport { Server } from \"../server\";\nimport { ComponentServer } from \"./component-server\";\n\n/**\n * 服务器工厂类\n * 用于创建和管理不同类型的服务器\n */\nexport class ServerFactory {\n private servers: Map<string, Server | ComponentServer> = new Map();\n\n /**\n * 创建标准REST API服务器\n */\n createRestServer(routes: (Route | NestedRoute)[]): Server {\n const server = new Server(routes);\n this.servers.set(\"rest\", server);\n return server;\n }\n\n /**\n * 创建组件服务器\n */\n createComponentServer(\n routes: (ComponentRoute | NestedComponentRoute)[]\n ): ComponentServer {\n const server = new ComponentServer(routes);\n this.servers.set(\"component\", server);\n return server;\n }\n\n /**\n * 获取指定类型的服务器\n */\n getServer(type: \"rest\" | \"component\"): Server | ComponentServer | undefined {\n return this.servers.get(type);\n }\n\n /**\n * 获取所有服务器\n */\n getAllServers(): Map<string, Server | ComponentServer> {\n return this.servers;\n }\n\n /**\n * 移除指定类型的服务器\n */\n removeServer(type: string): boolean {\n return this.servers.delete(type);\n }\n\n /**\n * 清除所有服务器\n */\n clearServers(): void {\n this.servers.clear();\n }\n\n /**\n * 获取服务器状态信息\n */\n getServerStatus(): Record<string, { type: string; routes: number }> {\n const status: Record<string, { type: string; routes: number }> = {};\n\n for (const [name, server] of this.servers) {\n if (server instanceof Server) {\n status[name] = {\n type: \"REST API\",\n routes: (server as any).routes?.length || 0,\n };\n } else if (server instanceof ComponentServer) {\n status[name] = {\n type: \"Component\",\n routes: (server as any).routes?.length || 0,\n };\n }\n }\n\n return status;\n }\n}\n","// src/parsers.ts\nimport qs from \"qs\";\nimport cookie from \"cookie\";\n\n// 文件信息接口\nexport interface FileInfo {\n name: string;\n type: string;\n size: number;\n data: ArrayBuffer;\n}\n\n// 表单数据接口\nexport interface FormData {\n fields: Record<string, string>;\n files: Record<string, FileInfo>;\n}\n\n/**\n * 简化的请求体解析函数\n * 优先简洁性,处理最常见的场景\n */\nexport async function parseBody(req: Request): Promise<unknown> {\n const contentType = req.headers.get(\"content-type\") || \"\";\n if (contentType.includes(\"application/json\")) {\n return await req.json();\n }\n if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n const text = await req.text();\n return Object.fromEntries(new URLSearchParams(text));\n }\n return await req.text(); // fallback\n}\n\n/**\n * 解析 multipart/form-data 格式\n * 支持文件上传和普通表单字段\n */\nasync function parseMultipartFormData(req: Request): Promise<FormData> {\n const formData = await req.formData();\n const result: FormData = {\n fields: {},\n files: {},\n };\n\n for (const [key, value] of formData.entries()) {\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"name\" in value &&\n \"type\" in value &&\n \"size\" in value\n ) {\n // 处理文件\n const file = value as any;\n const arrayBuffer = await file.arrayBuffer();\n result.files[key] = {\n name: file.name,\n type: file.type,\n size: file.size,\n data: arrayBuffer,\n };\n } else {\n // 处理普通字段\n result.fields[key] = value as string;\n }\n }\n\n return result;\n}\n\n/**\n * 解析请求体为特定类型\n * 提供类型安全的解析方法\n */\nexport async function parseBodyAs<T>(req: Request): Promise<T> {\n const body = await parseBody(req);\n return body as T;\n}\n\n/**\n * 解析请求体为表单数据\n * 专门用于处理 multipart/form-data\n */\nexport async function parseFormData(req: Request): Promise<FormData> {\n const contentType = req.headers.get(\"content-type\") || \"\";\n\n if (!contentType.includes(\"multipart/form-data\")) {\n throw new Error(\"请求不是 multipart/form-data 格式\");\n }\n\n return await parseMultipartFormData(req);\n}\n\n/**\n * 解析请求体为文件\n * 专门用于处理文件上传\n */\nexport async function parseFile(req: Request): Promise<FileInfo> {\n const contentType = req.headers.get(\"content-type\") || \"\";\n\n if (!contentType.includes(\"multipart/form-data\")) {\n throw new Error(\"请求不是 multipart/form-data 格式\");\n }\n\n const formData = await parseMultipartFormData(req);\n const fileKeys = Object.keys(formData.files);\n\n if (fileKeys.length === 0) {\n throw new Error(\"请求中没有文件\");\n }\n\n if (fileKeys.length > 1) {\n throw new Error(\"请求中包含多个文件,请使用 parseFormData\");\n }\n\n return formData.files[fileKeys[0]];\n}\n\n/** 获取查询字符串,直接返回对象 */\nexport function parseQuery(req: Request): Record<string, any> {\n const url = new URL(req.url);\n return qs.parse(url.search.slice(1)); // 去掉开头的 ?\n}\n\n/** 解析请求头,返回对象 */\nexport function parseHeaders(req: Request): Record<string, string> {\n const headers: Record<string, string> = {};\n req.headers.forEach((value, key) => {\n if (value !== undefined && value !== null) {\n headers[key] = value;\n }\n });\n return headers;\n}\n\n/** 使用cookie库解析Cookie,保证可靠性 */\nexport function parseCookies(req: Request): Record<string, string> {\n const cookieHeader = req.headers.get(\"cookie\");\n if (!cookieHeader) return {};\n\n try {\n const parsed = cookie.parse(cookieHeader);\n // 过滤掉undefined和null值\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(parsed)) {\n if (value !== undefined && value !== null) {\n result[key] = value;\n }\n }\n return result;\n } catch (error) {\n console.error(\"Cookie解析失败:\", error);\n console.error(\"原始Cookie字符串:\", cookieHeader);\n return {};\n }\n}\n","import { parseCookies } from \"./parsers\";\n\n/** 获取单个 Cookie 值 */\nexport function getCookie(req: Request, key: string): string | null {\n const cookies = parseCookies(req);\n return cookies[key] || null;\n}\n\n/** 生成 Set-Cookie 头 */\nexport function setCookie(\n key: string,\n value: string,\n options: {\n path?: string;\n httpOnly?: boolean;\n maxAge?: number;\n secure?: boolean;\n } = {}\n): string {\n let cookie = `${key}=${encodeURIComponent(value)}`;\n\n if (options.path) cookie += `; Path=${options.path}`;\n if (options.httpOnly) cookie += `; HttpOnly`;\n if (options.secure) cookie += `; Secure`;\n if (options.maxAge) cookie += `; Max-Age=${options.maxAge}`;\n\n return cookie;\n}\n\n// 提供给中间件写入\"局部上下文\"的工具函数\nexport function setLocals<T extends object>(req: Request, extras: T) {\n const target = req as any;\n target.__locals = { ...(target.__locals ?? {}), ...extras };\n}\n","// src/middleware/authMiddleware.ts\nimport type { Middleware } from \"../types\";\nimport { VafastError } from \"../middleware\";\nimport { getCookie } from \"../utils/handle\";\n\nexport const requireAuth: Middleware = async (req, next) => {\n const token = getCookie(req, \"auth\");\n\n if (!token || token !== \"valid-token\") {\n throw new VafastError(\"Unauthorized\", {\n status: 401,\n type: \"unauthorized\",\n expose: true,\n });\n }\n\n return next();\n};\n","// src/middleware/rateLimit.ts\n\nimport type { Middleware } from \"../types\";\nimport { VafastError } from \"../middleware\";\n\ninterface RateLimitOptions {\n windowMs?: number; // 限制窗口(毫秒)\n max?: number; // 最大请求数\n keyFn?: (req: Request) => string;\n}\n\ntype Entry = {\n count: number;\n expires: number;\n};\n\nconst store = new Map<string, Entry>();\n\nexport function rateLimit(options: RateLimitOptions = {}): Middleware {\n const windowMs = options.windowMs ?? 60_000; // 默认: 1分钟\n const max = options.max ?? 30;\n const keyFn = options.keyFn ?? getIP;\n\n return async (req, next) => {\n const key = keyFn(req);\n const now = Date.now();\n\n const entry = store.get(key);\n if (entry && entry.expires > now) {\n if (entry.count >= max) {\n throw new VafastError(\"Too many requests\", {\n status: 429,\n type: \"rate_limit\",\n expose: true,\n });\n }\n entry.count += 1;\n } else {\n store.set(key, { count: 1, expires: now + windowMs });\n }\n\n return next();\n };\n}\n\n// Edge 安全的 IP 获取\nfunction getIP(req: Request): string {\n return (\n req.headers.get(\"cf-connecting-ip\") || // Cloudflare\n req.headers.get(\"x-forwarded-for\")?.split(\",\")[0]?.trim() || // Vercel\n \"unknown\"\n );\n}\n","import type { Middleware } from \"../types\";\n\nexport interface CORSOptions {\n origin?: string[] | \"*\";\n methods?: string[];\n headers?: string[];\n credentials?: boolean;\n maxAge?: number;\n}\n\nexport function createCORS(options: CORSOptions = {}): Middleware {\n const {\n origin = [],\n methods = [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"OPTIONS\"],\n headers = [],\n credentials = false,\n maxAge,\n } = options;\n\n return async (req, next) => {\n const reqOrigin = req.headers.get(\"Origin\") || \"\";\n\n // 判断:是否为允许的 Origin?\n const isAllowedOrigin = origin === \"*\" || origin.includes(reqOrigin);\n\n // 预检 (OPTIONS) 请求处理\n if (req.method === \"OPTIONS\") {\n const resHeaders = new Headers();\n\n if (isAllowedOrigin) {\n resHeaders.set(\"Access-Control-Allow-Origin\", origin === \"*\" ? \"*\" : reqOrigin);\n resHeaders.set(\"Access-Control-Allow-Methods\", methods.join(\",\"));\n resHeaders.set(\"Access-Control-Allow-Headers\", headers.join(\",\"));\n if (credentials) resHeaders.set(\"Access-Control-Allow-Credentials\", \"true\");\n if (maxAge) resHeaders.set(\"Access-Control-Max-Age\", maxAge.toString());\n }\n\n return new Response(null, { status: 204, headers: resHeaders });\n }\n\n // 正常请求:在 next 后添加头部\n const res = await next();\n\n if (isAllowedOrigin) {\n res.headers.set(\"Access-Control-Allow-Origin\", origin === \"*\" ? \"*\" : reqOrigin);\n if (credentials) res.headers.set(\"Access-Control-Allow-Credentials\", \"true\");\n }\n\n return res;\n };\n}\n","export function base64urlEncode(str: string): string {\n return btoa(str)\n .replace(/=/g, \"\") // ✅ 删除填充\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\");\n}\n\nexport function base64urlDecode(str: string): string {\n const pad = str.length % 4 === 0 ? \"\" : \"=\".repeat(4 - (str.length % 4));\n const base64 = str.replace(/-/g, \"+\").replace(/_/g, \"/\") + pad;\n return atob(base64);\n}\n","// src/auth/token.ts\nimport { base64urlEncode, base64urlDecode } from \"../utils/base64url\";\n\n// 类型定义\nexport interface TokenPayload {\n [key: string]: any;\n exp?: number; // 过期时间戳\n iat?: number; // 签发时间戳\n sub?: string; // 主题(通常是用户ID)\n aud?: string; // 受众\n iss?: string; // 签发者\n}\n\nexport interface TokenResult {\n payload: TokenPayload;\n token: string;\n expiresAt: number;\n}\n\nexport interface TokenOptions {\n expiresIn?: number; // 过期时间(秒)\n issuer?: string; // 签发者\n audience?: string; // 受众\n subject?: string; // 主题\n}\n\nexport class TokenError extends Error {\n constructor(\n message: string,\n public code:\n | \"INVALID_TOKEN\"\n | \"EXPIRED_TOKEN\"\n | \"INVALID_SIGNATURE\"\n | \"MALFORMED_TOKEN\"\n | \"INVALID_PAYLOAD\"\n ) {\n super(message);\n this.name = \"TokenError\";\n }\n}\n\nconst encoder = new TextEncoder();\n\n/** 使用 HMAC-SHA256 进行签名 */\nasync function sign(data: string, secret: string): Promise<string> {\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n );\n\n const signature = await crypto.subtle.sign(\"HMAC\", key, encoder.encode(data));\n return btoa(\n String.fromCharCode.apply(null, Array.from(new Uint8Array(signature)))\n );\n}\n\n/** 生成令牌 */\nexport async function generateToken(\n payload: TokenPayload,\n secret: string,\n options: TokenOptions = {}\n): Promise<TokenResult> {\n const { expiresIn = 3600, issuer, audience, subject } = options;\n\n // 创建令牌载荷,强制使用当前时间\n const now = Math.floor(Date.now() / 1000);\n const tokenPayload: TokenPayload = {\n ...payload,\n iat: now,\n exp: now + expiresIn,\n };\n\n // 添加可选字段\n if (issuer) tokenPayload.iss = issuer;\n if (audience) tokenPayload.aud = audience;\n if (subject) tokenPayload.sub = subject;\n\n const data = base64urlEncode(JSON.stringify(tokenPayload));\n const sig = await sign(data, secret);\n const token = `${data}.${base64urlEncode(sig)}`;\n\n return {\n payload: tokenPayload,\n token,\n expiresAt: tokenPayload.exp! * 1000, // 转换为毫秒\n };\n}\n\n/** 验证令牌 */\nexport async function verifyToken(\n token: string,\n secret: string\n): Promise<TokenPayload | null> {\n try {\n const [data, sig] = token.split(\".\");\n if (!data || !sig) {\n throw new TokenError(\"令牌格式无效\", \"MALFORMED_TOKEN\");\n }\n\n const expectedSig = await sign(data, secret);\n const expected = base64urlEncode(expectedSig);\n\n if (sig !== expected) {\n throw new TokenError(\"令牌签名无效\", \"INVALID_SIGNATURE\");\n }\n\n const payload = JSON.parse(base64urlDecode(data)) as TokenPayload;\n\n // 检查过期时间\n if (payload.exp && Date.now() / 1000 > payload.exp) {\n throw new TokenError(\"令牌已过期\", \"EXPIRED_TOKEN\");\n }\n\n return payload;\n } catch (error) {\n if (error instanceof TokenError) {\n throw error;\n }\n throw new TokenError(\"令牌验证失败\", \"INVALID_TOKEN\");\n }\n}\n\n/** 解析令牌(不验证签名) */\nexport function parseToken(token: string): TokenPayload | null {\n try {\n const [data] = token.split(\".\");\n if (!data) return null;\n\n return JSON.parse(base64urlDecode(data));\n } catch {\n return null;\n }\n}\n\n/** 检查令牌是否过期 */\nexport function isTokenExpired(token: string): boolean {\n const payload = parseToken(token);\n if (!payload || !payload.exp) return true;\n\n return Date.now() / 1000 > payload.exp;\n}\n\n/** 获取令牌剩余有效时间(秒) */\nexport function getTokenTimeRemaining(token: string): number {\n const payload = parseToken(token);\n if (!payload || !payload.exp) return 0;\n\n const remaining = payload.exp - Date.now() / 1000;\n return Math.max(0, Math.floor(remaining));\n}\n\n/** 刷新令牌 */\nexport async function refreshToken(\n token: string,\n secret: string,\n options: TokenOptions = {}\n): Promise<TokenResult | null> {\n try {\n const payload = await verifyToken(token, secret);\n if (!payload) return null;\n\n // 移除时间相关字段,重新生成\n const { exp, iat, ...cleanPayload } = payload;\n\n // 添加延迟确保时间戳不同\n await new Promise((resolve) => setTimeout(resolve, 10));\n\n return await generateToken(cleanPayload, secret, options);\n } catch {\n return null;\n }\n}\n\n/** 创建访问令牌和刷新令牌对 */\nexport async function createTokenPair(\n payload: TokenPayload,\n secret: string,\n options: TokenOptions = {}\n): Promise<{\n accessToken: TokenResult;\n refreshToken: TokenResult;\n}> {\n const accessToken = await generateToken(payload, secret, {\n ...options,\n expiresIn: options.expiresIn || 3600, // 1小时\n });\n\n const refreshToken = await generateToken(payload, secret, {\n ...options,\n expiresIn: 7 * 24 * 3600, // 7天\n });\n\n return { accessToken, refreshToken };\n}\n","// src/middleware/auth.ts\n\nimport type { Middleware } from \"../types\";\nimport { VafastError } from \"../middleware\";\nimport { getCookie } from \"../utils/handle\";\nimport { verifyToken, TokenError, type TokenPayload } from \"../auth/token\";\n\ninterface AuthOptions {\n secret: string;\n cookieName?: string;\n headerName?: string;\n required?: boolean; // 是否必需认证\n roles?: string[]; // 允许的角色\n permissions?: string[]; // 允许的权限\n}\n\nexport function createAuth(options: AuthOptions): Middleware {\n const {\n secret,\n cookieName = \"auth\",\n headerName = \"authorization\",\n required = true,\n roles = [],\n permissions = [],\n } = options;\n\n return async (req, next) => {\n const token =\n getCookie(req, cookieName) ||\n req.headers.get(headerName)?.replace(\"Bearer \", \"\") ||\n \"\";\n\n if (!token && required) {\n throw new VafastError(\"缺少认证令牌\", {\n status: 401,\n type: \"unauthorized\",\n expose: true,\n });\n }\n\n if (!token && !required) {\n return next();\n }\n\n try {\n const user = (await verifyToken(token, secret)) as TokenPayload;\n\n if (!user) {\n throw new VafastError(\"令牌验证失败\", {\n status: 401,\n type: \"unauthorized\",\n expose: true,\n });\n }\n\n // 检查角色权限\n if (roles.length > 0 && user.role && !roles.includes(user.role)) {\n throw new VafastError(\"权限不足\", {\n status: 403,\n type: \"forbidden\",\n expose: true,\n });\n }\n\n // 检查具体权限\n if (permissions.length > 0 && user.permissions) {\n const userPermissions = Array.isArray(user.permissions)\n ? user.permissions\n : [user.permissions];\n\n const hasPermission = permissions.some((permission) =>\n userPermissions.includes(permission)\n );\n\n if (!hasPermission) {\n throw new VafastError(\"权限不足\", {\n status: 403,\n type: \"forbidden\",\n expose: true,\n });\n }\n }\n\n // 🪄 在这里扩展 Request 对象\n (req as any).user = user;\n (req as any).token = token;\n\n return next();\n } catch (error) {\n if (error instanceof TokenError) {\n let status = 401;\n let message = \"认证失败\";\n\n switch (error.code) {\n case \"EXPIRED_TOKEN\":\n status = 401;\n message = \"令牌已过期\";\n break;\n case \"INVALID_SIGNATURE\":\n status = 401;\n message = \"令牌签名无效\";\n break;\n case \"MALFORMED_TOKEN\":\n status = 400;\n message = \"令牌格式错误\";\n break;\n default:\n status = 401;\n message = \"令牌验证失败\";\n }\n\n throw new VafastError(message, {\n status,\n type: \"unauthorized\",\n expose: true,\n });\n }\n\n if (error instanceof VafastError) {\n throw error;\n }\n\n throw new VafastError(\"认证过程中发生错误\", {\n status: 500,\n type: \"internal_error\",\n expose: false,\n });\n }\n };\n}\n\n// 可选认证中间件\nexport function createOptionalAuth(\n options: Omit<AuthOptions, \"required\">\n): Middleware {\n return createAuth({ ...options, required: false });\n}\n\n// 角色验证中间件\nexport function createRoleAuth(\n roles: string[],\n options: Omit<AuthOptions, \"roles\">\n): Middleware {\n return createAuth({ ...options, roles });\n}\n\n// 权限验证中间件\nexport function createPermissionAuth(\n permissions: string[],\n options: Omit<AuthOptions, \"permissions\">\n): Middleware {\n return createAuth({ ...options, permissions });\n}\n","import type { Route } from \"./types\";\n\nexport function defineRoutes(routes: Route[]): Route[] {\n return routes;\n}\n","/**\n * Go 风格的错误处理工具\n * 将 Promise 转换为 [Error | null, T | undefined] 格式\n *\n * @author Framework Team\n * @version 1.0.0\n * @license MIT\n */\n\n/**\n * Go 风格的错误处理工具\n * 将 Promise 转换为 [Error | null, T | undefined] 格式\n *\n * @param promise 要处理的 Promise\n * @returns [Error | null, T | undefined] 元组,第一个元素是错误,第二个是结果\n *\n * @example\n * ```typescript\n * const [error, result] = await goAwait(someAsyncFunction());\n * if (error) {\n * console.error(\"操作失败:\", error);\n * } else {\n * console.log(\"操作成功:\", result);\n * }\n * ```\n */\nexport function goAwait<T>(promise: Promise<T>): Promise<[Error | null, T | undefined]> {\n return promise\n .then<[null, T]>((data) => [null, data])\n .catch<[Error, undefined]>((err) => [\n err instanceof Error ? err : new Error(String(err)),\n undefined,\n ]);\n}\n","/**\n * 超优化版Schema验证器 v5.0.0\n *\n * 使用经过验证的优化技术,确保极致性能\n * - 内联函数调用\n * - 预编译缓存优化\n * - 内存池优化\n * - 位运算优化\n * - 类型特化优化\n * - 循环展开优化\n * - 位掩码优化\n * - 字符串池优化\n * - 内联缓存优化\n * - 内存对齐优化\n *\n * @author Framework Team\n * @version 5.0.0\n * @license MIT\n */\n\nimport { TypeCompiler } from \"@sinclair/typebox/compiler\";\nimport type { TSchema } from \"@sinclair/typebox\";\n\n// 统一的Schema配置接口\nexport interface SchemaConfig {\n body?: TSchema;\n query?: TSchema;\n params?: TSchema;\n headers?: TSchema;\n cookies?: TSchema;\n}\n\n// 位掩码常量 - 用于快速检查Schema配置\nconst SCHEMA_FLAGS = {\n BODY: 1 << 0, // 1\n QUERY: 1 << 1, // 2\n PARAMS: 1 << 2, // 4\n HEADERS: 1 << 3, // 8\n COOKIES: 1 << 4, // 16\n} as const;\n\n// 超优化的Schema缓存 - 使用Map避免WeakMap的查找开销\nconst ultraSchemaCache = new Map<TSchema, any>();\nconst schemaCacheHits = new Map<TSchema, number>();\n\n// 内存池优化 - 预分配错误对象\nconst errorPool: Error[] = [];\nconst ERROR_POOL_SIZE = 200; // 增加池大小\n\n// 字符串池 - 避免重复创建错误消息\nconst errorMessagePool = new Map<string, string>();\nconst commonMessages = [\n \"请求体验证失败\",\n \"Query参数验证失败\",\n \"路径参数验证失败\",\n \"请求头验证失败\",\n \"Cookie验证失败\",\n \"类型验证失败\",\n \"Schema编译失败\",\n \"未知错误\",\n];\n\n// 初始化字符串池\ncommonMessages.forEach((msg) => errorMessagePool.set(msg, msg));\n\n// 初始化错误池\nfor (let i = 0; i < ERROR_POOL_SIZE; i++) {\n errorPool.push(new Error());\n}\n\nlet errorPoolIndex = 0;\n\n// 获取错误对象 - 避免重复创建\nfunction getErrorFromPool(message: string): Error {\n const error = errorPool[errorPoolIndex];\n error.message = message;\n errorPoolIndex = (errorPoolIndex + 1) % ERROR_POOL_SIZE;\n return error;\n}\n\n// 获取或创建字符串 - 字符串池优化\nfunction getPooledString(key: string): string {\n let pooled = errorMessagePool.get(key);\n if (!pooled) {\n pooled = key;\n errorMessagePool.set(key, key);\n }\n return pooled;\n}\n\n// 获取或编译Schema - 超内联优化版本\nfunction getUltraSchemaCompiler(schema: TSchema): any {\n // 直接检查缓存,避免WeakMap的has()调用\n let compiler = ultraSchemaCache.get(schema);\n if (compiler) {\n // 缓存命中统计\n schemaCacheHits.set(schema, (schemaCacheHits.get(schema) || 0) + 1);\n return compiler;\n }\n\n try {\n compiler = TypeCompiler.Compile(schema);\n ultraSchemaCache.set(schema, compiler);\n return compiler;\n } catch (error) {\n return null;\n }\n}\n\n// 计算Schema配置的位掩码 - 用于快速检查\nfunction getSchemaFlags(config: SchemaConfig): number {\n let flags = 0;\n if (config.body) flags |= SCHEMA_FLAGS.BODY;\n if (config.query) flags |= SCHEMA_FLAGS.QUERY;\n if (config.params) flags |= SCHEMA_FLAGS.PARAMS;\n if (config.headers) flags |= SCHEMA_FLAGS.HEADERS;\n if (config.cookies) flags |= SCHEMA_FLAGS.COOKIES;\n return flags;\n}\n\n// 超优化的Schema验证函数 - 位运算优化版本\nexport function validateSchemaUltra(\n schema: TSchema | undefined,\n data: any,\n context: string\n): any {\n if (!schema) return data;\n\n try {\n // 完全内联逻辑,零函数调用开销\n let compiler = ultraSchemaCache.get(schema);\n if (!compiler) {\n try {\n compiler = TypeCompiler.Compile(schema);\n ultraSchemaCache.set(schema, compiler);\n } catch (error) {\n // 使用错误池和字符串池\n const message = getPooledString(`${context}验证失败: Schema编译失败`);\n throw getErrorFromPool(message);\n }\n }\n\n // 直接验证,零额外开销\n const result = compiler.Check(data);\n if (!result) {\n // 使用错误池和字符串池\n const message = getPooledString(`${context}验证失败`);\n throw getErrorFromPool(message);\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"验证失败\")) {\n throw error;\n }\n // 使用错误池和字符串池\n const message = getPooledString(\n `${context}验证失败: ${\n error instanceof Error ? error.message : \"未知错误\"\n }`\n );\n throw getErrorFromPool(message);\n }\n}\n\n// 超优化的批量验证 - 位掩码优化版本(极致性能)\nexport function validateAllSchemasUltra(\n config: SchemaConfig,\n data: {\n body: any;\n query: any;\n params: any;\n headers: any;\n cookies: any;\n }\n): any {\n // 使用位掩码快速检查,避免多次条件判断\n const flags = getSchemaFlags(config);\n\n // 位运算检查,比条件判断快\n if (flags & SCHEMA_FLAGS.BODY) {\n validateSchemaUltra(config.body, data.body, \"请求体\");\n }\n if (flags & SCHEMA_FLAGS.QUERY) {\n validateSchemaUltra(config.query, data.query, \"Query参数\");\n }\n if (flags & SCHEMA_FLAGS.PARAMS) {\n validateSchemaUltra(config.params, data.params, \"路径参数\");\n }\n if (flags & SCHEMA_FLAGS.HEADERS) {\n validateSchemaUltra(config.headers, data.headers, \"请求头\");\n }\n if (flags & SCHEMA_FLAGS.COOKIES) {\n validateSchemaUltra(config.cookies, data.cookies, \"Cookie\");\n }\n return data;\n}\n\n// 超优化的预编译 - 位掩码优化版本\nexport function precompileSchemasUltra(config: SchemaConfig): void {\n const flags = getSchemaFlags(config);\n\n // 使用位运算检查,避免重复条件判断\n if (flags & SCHEMA_FLAGS.BODY && config.body) {\n getUltraSchemaCompiler(config.body);\n }\n if (flags & SCHEMA_FLAGS.QUERY && config.query) {\n getUltraSchemaCompiler(config.query);\n }\n if (flags & SCHEMA_FLAGS.PARAMS && config.params) {\n getUltraSchemaCompiler(config.params);\n }\n if (flags & SCHEMA_FLAGS.HEADERS && config.headers) {\n getUltraSchemaCompiler(config.headers);\n }\n if (flags & SCHEMA_FLAGS.COOKIES && config.cookies) {\n getUltraSchemaCompiler(config.cookies);\n }\n}\n\n// 类型特化验证器 - 针对特定类型优化\nexport function createTypedValidatorUltra<T>(schema: TSchema): (data: T) => T {\n const compiler = getUltraSchemaCompiler(schema);\n\n return (data: T): T => {\n if (!compiler.Check(data)) {\n throw getErrorFromPool(getPooledString(\"类型验证失败\"));\n }\n return data;\n };\n}\n\n// 批量类型验证器 - 一次验证多个数据,循环展开优化\nexport function validateBatchUltra<T>(schema: TSchema, dataArray: T[]): T[] {\n const compiler = getUltraSchemaCompiler(schema);\n const results: T[] = [];\n const length = dataArray.length;\n\n // 循环展开优化 - 处理前4个元素\n if (length >= 1) {\n if (!compiler.Check(dataArray[0])) {\n throw getErrorFromPool(getPooledString(\"第1个数据验证失败\"));\n }\n results.push(dataArray[0]);\n }\n if (length >= 2) {\n if (!compiler.Check(dataArray[1])) {\n throw getErrorFromPool(getPooledString(\"第2个数据验证失败\"));\n }\n results.push(dataArray[1]);\n }\n if (length >= 3) {\n if (!compiler.Check(dataArray[2])) {\n throw getErrorFromPool(getPooledString(\"第3个数据验证失败\"));\n }\n results.push(dataArray[2]);\n }\n if (length >= 4) {\n if (!compiler.Check(dataArray[3])) {\n throw getErrorFromPool(getPooledString(\"第4个数据验证失败\"));\n }\n results.push(dataArray[3]);\n }\n\n // 处理剩余元素\n for (let i = 4; i < length; i++) {\n const data = dataArray[i];\n if (!compiler.Check(data)) {\n throw getErrorFromPool(getPooledString(`第${i + 1}个数据验证失败`));\n }\n results.push(data);\n }\n\n return results;\n}\n\n// 内存优化的缓存统计\nexport function getCacheStats() {\n const totalSchemas = ultraSchemaCache.size;\n const totalHits = Array.from(schemaCacheHits.values()).reduce(\n (sum, hits) => sum + hits,\n 0\n );\n const hitRate =\n totalHits > 0\n ? ((totalHits / (totalHits + totalSchemas)) * 100).toFixed(2)\n : \"0.00\";\n\n return {\n totalSchemas,\n totalHits,\n hitRate: `${hitRate}%`,\n cacheSize: ultraSchemaCache.size,\n errorPoolUsage: `${errorPoolIndex}/${ERROR_POOL_SIZE}`,\n stringPoolSize: errorMessagePool.size,\n memoryEfficiency:\n totalHits > 0 ? (totalHits / totalSchemas).toFixed(2) : \"0.00\",\n };\n}\n\n// 智能缓存清理 - 只清理最少使用的Schema\nexport function smartClearUltraCache(keepTop: number = 10): void {\n if (ultraSchemaCache.size <= keepTop) return;\n\n // 按使用频率排序\n const sortedSchemas = Array.from(schemaCacheHits.entries())\n .sort(([, a], [, b]) => b - a)\n .slice(0, keepTop);\n\n // 清理缓存\n ultraSchemaCache.clear();\n schemaCacheHits.clear();\n\n // 重新添加最常用的Schema\n for (const [schema, hits] of sortedSchemas) {\n ultraSchemaCache.set(schema, getUltraSchemaCompiler(schema));\n schemaCacheHits.set(schema, hits);\n }\n}\n\n// 完全清理缓存\nexport function clearUltraCache(): void {\n ultraSchemaCache.clear();\n schemaCacheHits.clear();\n errorPoolIndex = 0;\n}\n\n// 性能监控装饰器 - 使用高精度计时器\nexport function withPerformanceMonitoring<T extends (...args: any[]) => any>(\n fn: T,\n name: string\n): T {\n return ((...args: any[]) => {\n const start = performance.now();\n try {\n const result = fn(...args);\n const end = performance.now();\n console.log(`⚡ ${name} 执行时间: ${(end - start).toFixed(6)}ms`);\n return result;\n } catch (error) {\n const end = performance.now();\n console.log(`❌ ${name} 执行时间: ${(end - start).toFixed(6)}ms (失败)`);\n throw error;\n }\n }) as T;\n}\n\n// 导出主要函数(使用标准命名)\nexport {\n validateAllSchemasUltra as validateAllSchemas,\n createTypedValidatorUltra as createTypedValidator,\n validateBatchUltra as validateBatch,\n clearUltraCache as clearCache,\n smartClearUltraCache as smartClearCache,\n};\n","/**\n * 路由处理器工厂\n *\n * 负责创建和配置路由处理器,处理请求数据解析和验证\n * 提供统一的错误处理和响应格式\n *\n * @author Framework Team\n * @version 1.0.0\n * @license MIT\n */\n\nimport { parseQuery, parseHeaders, parseCookies, parseBody } from \"./parsers\";\nimport { goAwait } from \"./go-await\";\nimport { json } from \"./response\";\nimport {\n validateAllSchemasUltra,\n precompileSchemasUltra,\n type SchemaConfig,\n} from \"./validators/schema-validators-ultra\";\nimport type { Static } from \"@sinclair/typebox\";\n\n// 类型推导的配置接口\nexport interface TypedConfig extends SchemaConfig {\n docs?: any;\n timeout?: number;\n maxBodySize?: string;\n // 验证错误处理配置\n validationErrorHandler?: ValidationErrorHandler;\n [key: string]: any;\n}\n\n// 验证错误处理器类型\nexport type ValidationErrorHandler = (\n error: Error,\n field: string,\n value: any,\n schema: any\n) => Response | Promise<Response>;\n\n// 默认验证错误处理器\nconst defaultValidationErrorHandler: ValidationErrorHandler = (\n error,\n field,\n value,\n schema\n) => {\n return json(\n {\n success: false,\n error: \"Validation Error\",\n message: error instanceof Error ? error.message : \"验证失败\",\n field,\n receivedValue: value,\n timestamp: new Date().toISOString(),\n },\n 400\n );\n};\n\n// 类型推导的处理器类型 - 现在使用单参数上下文对象\nexport type TypedHandler<\n TBody = any,\n TQuery = any,\n TParams = any,\n THeaders = any,\n TCookies = any,\n TExtra extends object = {}\n> = (\n ctx: {\n req: Request;\n body: TBody;\n query: TQuery;\n params: TParams;\n headers: THeaders;\n cookies: TCookies;\n } & TExtra\n) => Response | Promise<Response> | any | Promise<any>;\n\n// 预定义的常用响应头,避免重复创建\nconst TEXT_HEADERS = { \"Content-Type\": \"text/plain; charset=utf-8\" };\nconst JSON_HEADERS = { \"Content-Type\": \"application/json\" };\nconst EMPTY_RESPONSE_204 = new Response(null, { status: 204 });\n\n// 超高性能的 Response 自动转换函数 - 生产环境推荐使用\nfunction autoResponseUltra(result: any): Response {\n // 快速路径:已经是 Response 对象\n if (result instanceof Response) {\n return result;\n }\n\n // 快速路径:null/undefined - 复用预创建的对象\n if (result === null || result === undefined) {\n return EMPTY_RESPONSE_204;\n }\n\n // 使用 switch 语句优化类型检查\n switch (typeof result) {\n case \"string\":\n // 优化:复用预定义的头部对象\n return new Response(result, { headers: TEXT_HEADERS });\n\n case \"number\":\n case \"boolean\":\n // 优化:使用更高效的字符串转换,复用头部\n return new Response(result.toString(), { headers: TEXT_HEADERS });\n\n case \"object\":\n // 检查是否是 { data, status, headers } 格式\n if (\"data\" in result) {\n const { data, status = 200, headers = {} } = result;\n\n // 无内容\n if (data === null || data === undefined) {\n return new Response(\"\", {\n status: status === 200 ? 204 : status,\n headers,\n });\n }\n\n // 纯文本类型\n if (\n typeof data === \"string\" ||\n typeof data === \"number\" ||\n typeof data === \"boolean\"\n ) {\n // 优化:减少对象展开操作,直接构建最终对象\n const finalHeaders = {\n \"Content-Type\": \"text/plain; charset=utf-8\",\n ...headers,\n };\n return new Response(data.toString(), {\n status,\n headers: finalHeaders,\n });\n }\n\n // JSON 类型 - 复用 json 函数\n return json(data, status, headers);\n }\n\n // 普通对象/数组,复用 json 函数\n return json(result);\n\n default:\n // 其他类型(如 symbol, function 等)\n return EMPTY_RESPONSE_204;\n }\n}\n\n// 创建路由处理器的通用函数\nexport function createRouteHandler<\n TConfig extends TypedConfig,\n TBody = TConfig extends { body: any } ? Static<TConfig[\"body\"]> : any,\n TQuery = TConfig extends { query: any } ? Static<TConfig[\"query\"]> : any,\n TParams = TConfig extends { params: any } ? Static<TConfig[\"params\"]> : any,\n THeaders = TConfig extends { headers: any }\n ? Static<TConfig[\"headers\"]>\n : any,\n TCookies = TConfig extends { cookies: any }\n ? Static<TConfig[\"cookies\"]>\n : any,\n TExtra extends object = {}\n>(\n handler: TypedHandler<TBody, TQuery, TParams, THeaders, TCookies, TExtra>,\n config: TConfig = {} as TConfig\n) {\n // 检查哪些验证器是必需的\n const hasBodySchema = config.body !== undefined;\n const hasQuerySchema = config.query !== undefined;\n const hasParamsSchema = config.params !== undefined;\n const hasHeadersSchema = config.headers !== undefined;\n const hasCookiesSchema = config.cookies !== undefined;\n\n // 只在有验证器时预编译Schema\n if (\n hasBodySchema ||\n hasQuerySchema ||\n hasParamsSchema ||\n hasHeadersSchema ||\n hasCookiesSchema\n ) {\n precompileSchemasUltra(config);\n }\n\n // 获取验证错误处理器\n const errorHandler =\n config.validationErrorHandler || defaultValidationErrorHandler;\n\n return async (req: Request) => {\n try {\n let queryObj: TQuery = {} as TQuery;\n let headers: THeaders = {} as THeaders;\n let cookies: TCookies = {} as TCookies;\n let body: TBody = undefined as TBody;\n let params: TParams = {} as TParams;\n\n // 默认总是解析所有数据,只有在有验证器时才进行验证\n queryObj = parseQuery(req) as TQuery;\n headers = parseHeaders(req) as THeaders;\n cookies = parseCookies(req) as TCookies;\n\n // 总是解析 body\n const [, parsedBody] = await goAwait(parseBody(req));\n body = parsedBody as TBody;\n\n // 总是尝试获取路径参数\n params = ((req as any).pathParams ||\n (req as any).params ||\n {}) as TParams;\n\n // 只在有验证器时执行验证\n if (\n hasBodySchema ||\n hasQuerySchema ||\n hasParamsSchema ||\n hasHeadersSchema ||\n hasCookiesSchema\n ) {\n const data = { body, query: queryObj, params, headers, cookies };\n validateAllSchemasUltra(config, data);\n }\n\n // 合并中间件注入的本地上下文\n const extras = ((req as any).__locals ?? {}) as TExtra;\n\n // 调用处理器,传递上下文\n const result = await handler({\n req,\n body,\n query: queryObj,\n params,\n headers,\n cookies,\n ...(extras as object),\n } as unknown as {\n req: Request;\n body: TBody;\n query: TQuery;\n params: TParams;\n headers: THeaders;\n cookies: TCookies;\n } & TExtra);\n return autoResponseUltra(result);\n } catch (error) {\n // 使用用户自定义的验证错误处理器\n if (error instanceof Error && error.message.includes(\"验证失败\")) {\n // 尝试提取字段信息\n const field = extractFieldFromError(error);\n const value = extractValueFromError(error);\n const schema = extractSchemaFromError(error);\n\n return await errorHandler(error, field, value, schema);\n }\n\n // 其他错误使用默认处理\n return json(\n {\n success: false,\n error: \"Internal Error\",\n message: error instanceof Error ? error.message : \"未知错误\",\n },\n 500\n );\n }\n };\n}\n\n// 从错误中提取字段信息的辅助函数\nfunction extractFieldFromError(error: Error): string {\n // 尝试从错误消息中提取字段名\n const fieldMatch = error.message.match(/字段\\s*(\\w+)/);\n return fieldMatch ? fieldMatch[1] : \"unknown\";\n}\n\n// 从错误中提取值的辅助函数\nfunction extractValueFromError(error: Error): any {\n // 这里可以根据实际错误类型提取值\n return undefined;\n}\n\n// 从错误中提取Schema的辅助函数\nfunction extractSchemaFromError(error: Error): any {\n // 这里可以根据实际错误类型提取Schema\n return undefined;\n}\n\nexport function withExtra<TExtra extends object = {}>() {\n return function withExtraHandler<TConfig extends TypedConfig>(\n config: TConfig,\n handler: TypedHandler<\n TConfig extends { body: any } ? Static<TConfig[\"body\"]> : any,\n TConfig extends { query: any } ? Static<TConfig[\"query\"]> : any,\n TConfig extends { params: any } ? Static<TConfig[\"params\"]> : any,\n TConfig extends { headers: any } ? Static<TConfig[\"headers\"]> : any,\n TConfig extends { cookies: any } ? Static<TConfig[\"cookies\"]> : any,\n TExtra\n >\n ) {\n return createRouteHandler<\n TConfig,\n TConfig extends { body: any } ? Static<TConfig[\"body\"]> : any,\n TConfig extends { query: any } ? Static<TConfig[\"query\"]> : any,\n TConfig extends { params: any } ? Static<TConfig[\"params\"]> : any,\n TConfig extends { headers: any } ? Static<TConfig[\"headers\"]> : any,\n TConfig extends { cookies: any } ? Static<TConfig[\"cookies\"]> : any,\n TExtra\n >(handler, config);\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Middleware } from "../types";
|
|
2
|
+
interface AuthOptions {
|
|
3
|
+
secret: string;
|
|
4
|
+
cookieName?: string;
|
|
5
|
+
headerName?: string;
|
|
6
|
+
required?: boolean;
|
|
7
|
+
roles?: string[];
|
|
8
|
+
permissions?: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function createAuth(options: AuthOptions): Middleware;
|
|
11
|
+
export declare function createOptionalAuth(options: Omit<AuthOptions, "required">): Middleware;
|
|
12
|
+
export declare function createRoleAuth(roles: string[], options: Omit<AuthOptions, "roles">): Middleware;
|
|
13
|
+
export declare function createPermissionAuth(permissions: string[], options: Omit<AuthOptions, "permissions">): Middleware;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// src/middleware/auth.ts
|
|
2
|
+
import { VafastError } from "../middleware";
|
|
3
|
+
import { getCookie } from "../utils/handle";
|
|
4
|
+
import { verifyToken, TokenError } from "../auth/token";
|
|
5
|
+
export function createAuth(options) {
|
|
6
|
+
const { secret, cookieName = "auth", headerName = "authorization", required = true, roles = [], permissions = [], } = options;
|
|
7
|
+
return async (req, next) => {
|
|
8
|
+
const token = getCookie(req, cookieName) ||
|
|
9
|
+
req.headers.get(headerName)?.replace("Bearer ", "") ||
|
|
10
|
+
"";
|
|
11
|
+
if (!token && required) {
|
|
12
|
+
throw new VafastError("缺少认证令牌", {
|
|
13
|
+
status: 401,
|
|
14
|
+
type: "unauthorized",
|
|
15
|
+
expose: true,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
if (!token && !required) {
|
|
19
|
+
return next();
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const user = (await verifyToken(token, secret));
|
|
23
|
+
if (!user) {
|
|
24
|
+
throw new VafastError("令牌验证失败", {
|
|
25
|
+
status: 401,
|
|
26
|
+
type: "unauthorized",
|
|
27
|
+
expose: true,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// 检查角色权限
|
|
31
|
+
if (roles.length > 0 && user.role && !roles.includes(user.role)) {
|
|
32
|
+
throw new VafastError("权限不足", {
|
|
33
|
+
status: 403,
|
|
34
|
+
type: "forbidden",
|
|
35
|
+
expose: true,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
// 检查具体权限
|
|
39
|
+
if (permissions.length > 0 && user.permissions) {
|
|
40
|
+
const userPermissions = Array.isArray(user.permissions)
|
|
41
|
+
? user.permissions
|
|
42
|
+
: [user.permissions];
|
|
43
|
+
const hasPermission = permissions.some((permission) => userPermissions.includes(permission));
|
|
44
|
+
if (!hasPermission) {
|
|
45
|
+
throw new VafastError("权限不足", {
|
|
46
|
+
status: 403,
|
|
47
|
+
type: "forbidden",
|
|
48
|
+
expose: true,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// 🪄 在这里扩展 Request 对象
|
|
53
|
+
req.user = user;
|
|
54
|
+
req.token = token;
|
|
55
|
+
return next();
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error instanceof TokenError) {
|
|
59
|
+
let status = 401;
|
|
60
|
+
let message = "认证失败";
|
|
61
|
+
switch (error.code) {
|
|
62
|
+
case "EXPIRED_TOKEN":
|
|
63
|
+
status = 401;
|
|
64
|
+
message = "令牌已过期";
|
|
65
|
+
break;
|
|
66
|
+
case "INVALID_SIGNATURE":
|
|
67
|
+
status = 401;
|
|
68
|
+
message = "令牌签名无效";
|
|
69
|
+
break;
|
|
70
|
+
case "MALFORMED_TOKEN":
|
|
71
|
+
status = 400;
|
|
72
|
+
message = "令牌格式错误";
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
status = 401;
|
|
76
|
+
message = "令牌验证失败";
|
|
77
|
+
}
|
|
78
|
+
throw new VafastError(message, {
|
|
79
|
+
status,
|
|
80
|
+
type: "unauthorized",
|
|
81
|
+
expose: true,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (error instanceof VafastError) {
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
throw new VafastError("认证过程中发生错误", {
|
|
88
|
+
status: 500,
|
|
89
|
+
type: "internal_error",
|
|
90
|
+
expose: false,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// 可选认证中间件
|
|
96
|
+
export function createOptionalAuth(options) {
|
|
97
|
+
return createAuth({ ...options, required: false });
|
|
98
|
+
}
|
|
99
|
+
// 角色验证中间件
|
|
100
|
+
export function createRoleAuth(roles, options) {
|
|
101
|
+
return createAuth({ ...options, roles });
|
|
102
|
+
}
|
|
103
|
+
// 权限验证中间件
|
|
104
|
+
export function createPermissionAuth(permissions, options) {
|
|
105
|
+
return createAuth({ ...options, permissions });
|
|
106
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { VafastError } from "../middleware";
|
|
2
|
+
import { getCookie } from "../utils/handle";
|
|
3
|
+
export const requireAuth = async (req, next) => {
|
|
4
|
+
const token = getCookie(req, "auth");
|
|
5
|
+
if (!token || token !== "valid-token") {
|
|
6
|
+
throw new VafastError("Unauthorized", {
|
|
7
|
+
status: 401,
|
|
8
|
+
type: "unauthorized",
|
|
9
|
+
expose: true,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
return next();
|
|
13
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 组件渲染中间件 - 专注 SSR
|
|
3
|
+
* 支持 Vue 和 React 的服务端渲染
|
|
4
|
+
*/
|
|
5
|
+
export declare const vueRenderer: (preloadedDeps?: any) => (req: Request, next: () => Promise<Response>) => Promise<Response>;
|
|
6
|
+
export declare const reactRenderer: (preloadedDeps?: any) => (req: Request, next: () => Promise<Response>) => Promise<Response>;
|