vafast 0.1.10 → 0.1.12
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 +14 -459
- package/dist/index.js +14 -1400
- 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/route.d.ts +37 -0
- package/dist/types/route.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/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 +181 -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
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 依赖管理器
|
|
3
|
+
* 负责按需加载和管理框架依赖
|
|
4
|
+
*/
|
|
5
|
+
export declare class DependencyManager {
|
|
6
|
+
private dependencyCache;
|
|
7
|
+
/**
|
|
8
|
+
* 按需获取框架依赖
|
|
9
|
+
*/
|
|
10
|
+
getFrameworkDeps(framework: "vue" | "react"): Promise<any>;
|
|
11
|
+
/**
|
|
12
|
+
* 检测组件类型
|
|
13
|
+
*/
|
|
14
|
+
detectComponentType(component: any): "vue" | "react";
|
|
15
|
+
/**
|
|
16
|
+
* 清除缓存
|
|
17
|
+
*/
|
|
18
|
+
clearCache(): void;
|
|
19
|
+
/**
|
|
20
|
+
* 获取缓存状态
|
|
21
|
+
*/
|
|
22
|
+
getCacheStatus(): Record<string, boolean>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 依赖管理器
|
|
3
|
+
* 负责按需加载和管理框架依赖
|
|
4
|
+
*/
|
|
5
|
+
export class DependencyManager {
|
|
6
|
+
dependencyCache = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* 按需获取框架依赖
|
|
9
|
+
*/
|
|
10
|
+
async getFrameworkDeps(framework) {
|
|
11
|
+
if (this.dependencyCache.has(framework)) {
|
|
12
|
+
return this.dependencyCache.get(framework);
|
|
13
|
+
}
|
|
14
|
+
console.log(`📦 按需加载 ${framework} 依赖...`);
|
|
15
|
+
try {
|
|
16
|
+
let deps;
|
|
17
|
+
switch (framework) {
|
|
18
|
+
case "vue":
|
|
19
|
+
deps = await Promise.all([import("vue"), import("@vue/server-renderer")]);
|
|
20
|
+
break;
|
|
21
|
+
case "react":
|
|
22
|
+
deps = await Promise.all([import("react"), import("react-dom/server")]);
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
throw new Error(`不支持的框架: ${framework}`);
|
|
26
|
+
}
|
|
27
|
+
this.dependencyCache.set(framework, deps);
|
|
28
|
+
console.log(`✅ ${framework} 依赖加载完成`);
|
|
29
|
+
return deps;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error(`❌ ${framework} 依赖加载失败:`, error);
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 检测组件类型
|
|
38
|
+
*/
|
|
39
|
+
detectComponentType(component) {
|
|
40
|
+
// 简单的组件类型检测
|
|
41
|
+
if (component.render && typeof component.render === "function") {
|
|
42
|
+
return "vue";
|
|
43
|
+
}
|
|
44
|
+
if (component.$$typeof) {
|
|
45
|
+
return "react";
|
|
46
|
+
}
|
|
47
|
+
// 默认使用 Vue
|
|
48
|
+
return "vue";
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 清除缓存
|
|
52
|
+
*/
|
|
53
|
+
clearCache() {
|
|
54
|
+
this.dependencyCache.clear();
|
|
55
|
+
console.log("🧹 依赖缓存已清除");
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 获取缓存状态
|
|
59
|
+
*/
|
|
60
|
+
getCacheStatus() {
|
|
61
|
+
const status = {};
|
|
62
|
+
for (const [framework] of this.dependencyCache) {
|
|
63
|
+
status[framework] = true;
|
|
64
|
+
}
|
|
65
|
+
return status;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Go 风格的错误处理工具
|
|
3
|
+
* 将 Promise 转换为 [Error | null, T | undefined] 格式
|
|
4
|
+
*
|
|
5
|
+
* @author Framework Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
* @license MIT
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Go 风格的错误处理工具
|
|
11
|
+
* 将 Promise 转换为 [Error | null, T | undefined] 格式
|
|
12
|
+
*
|
|
13
|
+
* @param promise 要处理的 Promise
|
|
14
|
+
* @returns [Error | null, T | undefined] 元组,第一个元素是错误,第二个是结果
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const [error, result] = await goAwait(someAsyncFunction());
|
|
19
|
+
* if (error) {
|
|
20
|
+
* console.error("操作失败:", error);
|
|
21
|
+
* } else {
|
|
22
|
+
* console.log("操作成功:", result);
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function goAwait<T>(promise: Promise<T>): Promise<[Error | null, T | undefined]>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Go 风格的错误处理工具
|
|
3
|
+
* 将 Promise 转换为 [Error | null, T | undefined] 格式
|
|
4
|
+
*
|
|
5
|
+
* @author Framework Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
* @license MIT
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Go 风格的错误处理工具
|
|
11
|
+
* 将 Promise 转换为 [Error | null, T | undefined] 格式
|
|
12
|
+
*
|
|
13
|
+
* @param promise 要处理的 Promise
|
|
14
|
+
* @returns [Error | null, T | undefined] 元组,第一个元素是错误,第二个是结果
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const [error, result] = await goAwait(someAsyncFunction());
|
|
19
|
+
* if (error) {
|
|
20
|
+
* console.error("操作失败:", error);
|
|
21
|
+
* } else {
|
|
22
|
+
* console.log("操作成功:", result);
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function goAwait(promise) {
|
|
27
|
+
return promise
|
|
28
|
+
.then((data) => [null, data])
|
|
29
|
+
.catch((err) => [
|
|
30
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
31
|
+
undefined,
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** 获取单个 Cookie 值 */
|
|
2
|
+
export declare function getCookie(req: Request, key: string): string | null;
|
|
3
|
+
/** 生成 Set-Cookie 头 */
|
|
4
|
+
export declare function setCookie(key: string, value: string, options?: {
|
|
5
|
+
path?: string;
|
|
6
|
+
httpOnly?: boolean;
|
|
7
|
+
maxAge?: number;
|
|
8
|
+
secure?: boolean;
|
|
9
|
+
}): string;
|
|
10
|
+
export declare function setLocals<T extends object>(req: Request, extras: T): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { parseCookies } from "./parsers";
|
|
2
|
+
/** 获取单个 Cookie 值 */
|
|
3
|
+
export function getCookie(req, key) {
|
|
4
|
+
const cookies = parseCookies(req);
|
|
5
|
+
return cookies[key] || null;
|
|
6
|
+
}
|
|
7
|
+
/** 生成 Set-Cookie 头 */
|
|
8
|
+
export function setCookie(key, value, options = {}) {
|
|
9
|
+
let cookie = `${key}=${encodeURIComponent(value)}`;
|
|
10
|
+
if (options.path)
|
|
11
|
+
cookie += `; Path=${options.path}`;
|
|
12
|
+
if (options.httpOnly)
|
|
13
|
+
cookie += `; HttpOnly`;
|
|
14
|
+
if (options.secure)
|
|
15
|
+
cookie += `; Secure`;
|
|
16
|
+
if (options.maxAge)
|
|
17
|
+
cookie += `; Max-Age=${options.maxAge}`;
|
|
18
|
+
return cookie;
|
|
19
|
+
}
|
|
20
|
+
// 提供给中间件写入"局部上下文"的工具函数
|
|
21
|
+
export function setLocals(req, extras) {
|
|
22
|
+
const target = req;
|
|
23
|
+
target.__locals = { ...(target.__locals ?? {}), ...extras };
|
|
24
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML渲染工具类
|
|
3
|
+
* 提供统一的HTML模板生成功能
|
|
4
|
+
*/
|
|
5
|
+
export declare class HtmlRenderer {
|
|
6
|
+
/**
|
|
7
|
+
* 生成基础HTML模板
|
|
8
|
+
*/
|
|
9
|
+
static generateBaseHtml(content: string, context: any, clientScriptPath?: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* 生成Vue组件HTML
|
|
12
|
+
*/
|
|
13
|
+
static generateVueHtml(content: string, context: any, clientScriptPath?: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* 生成React组件HTML
|
|
16
|
+
*/
|
|
17
|
+
static generateReactHtml(content: string, context: any, clientScriptPath?: string): string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML渲染工具类
|
|
3
|
+
* 提供统一的HTML模板生成功能
|
|
4
|
+
*/
|
|
5
|
+
export class HtmlRenderer {
|
|
6
|
+
/**
|
|
7
|
+
* 生成基础HTML模板
|
|
8
|
+
*/
|
|
9
|
+
static generateBaseHtml(content, context, clientScriptPath = "/client.js") {
|
|
10
|
+
return `
|
|
11
|
+
<!doctype html>
|
|
12
|
+
<html>
|
|
13
|
+
<head>
|
|
14
|
+
<meta charset="utf-8">
|
|
15
|
+
<title>Vafast SSR App</title>
|
|
16
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<div id="app">${content}</div>
|
|
20
|
+
<script>
|
|
21
|
+
window.__ROUTE_INFO__ = {
|
|
22
|
+
params: ${JSON.stringify(context.params || {})},
|
|
23
|
+
query: ${JSON.stringify(context.query || {})},
|
|
24
|
+
pathname: '${context.pathname}'
|
|
25
|
+
};
|
|
26
|
+
</script>
|
|
27
|
+
<script type="module" src="${clientScriptPath}"></script>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
30
|
+
`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 生成Vue组件HTML
|
|
34
|
+
*/
|
|
35
|
+
static generateVueHtml(content, context, clientScriptPath = "/client.js") {
|
|
36
|
+
return this.generateBaseHtml(content, context, clientScriptPath);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 生成React组件HTML
|
|
40
|
+
*/
|
|
41
|
+
static generateReactHtml(content, context, clientScriptPath = "/client.js") {
|
|
42
|
+
return `
|
|
43
|
+
<!doctype html>
|
|
44
|
+
<html>
|
|
45
|
+
<head>
|
|
46
|
+
<meta charset="utf-8">
|
|
47
|
+
<title>Vafast SSR App</title>
|
|
48
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
49
|
+
</head>
|
|
50
|
+
<body>
|
|
51
|
+
<div id="root">${content}</div>
|
|
52
|
+
<script>
|
|
53
|
+
window.__ROUTE_INFO__ = {
|
|
54
|
+
params: ${JSON.stringify(context.params || {})},
|
|
55
|
+
query: ${JSON.stringify(context.query || {})},
|
|
56
|
+
pathname: '${context.pathname}'
|
|
57
|
+
};
|
|
58
|
+
</script>
|
|
59
|
+
<script type="module" src="${clientScriptPath}"></script>
|
|
60
|
+
</body>
|
|
61
|
+
</html>
|
|
62
|
+
`;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface FileInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string;
|
|
4
|
+
size: number;
|
|
5
|
+
data: ArrayBuffer;
|
|
6
|
+
}
|
|
7
|
+
export interface FormData {
|
|
8
|
+
fields: Record<string, string>;
|
|
9
|
+
files: Record<string, FileInfo>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 简化的请求体解析函数
|
|
13
|
+
* 优先简洁性,处理最常见的场景
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseBody(req: Request): Promise<unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* 解析请求体为特定类型
|
|
18
|
+
* 提供类型安全的解析方法
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseBodyAs<T>(req: Request): Promise<T>;
|
|
21
|
+
/**
|
|
22
|
+
* 解析请求体为表单数据
|
|
23
|
+
* 专门用于处理 multipart/form-data
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseFormData(req: Request): Promise<FormData>;
|
|
26
|
+
/**
|
|
27
|
+
* 解析请求体为文件
|
|
28
|
+
* 专门用于处理文件上传
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseFile(req: Request): Promise<FileInfo>;
|
|
31
|
+
/** 获取查询字符串,直接返回对象 */
|
|
32
|
+
export declare function parseQuery(req: Request): Record<string, any>;
|
|
33
|
+
/** 解析请求头,返回对象 */
|
|
34
|
+
export declare function parseHeaders(req: Request): Record<string, string>;
|
|
35
|
+
/** 使用cookie库解析Cookie,保证可靠性 */
|
|
36
|
+
export declare function parseCookies(req: Request): Record<string, string>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// src/parsers.ts
|
|
2
|
+
import qs from "qs";
|
|
3
|
+
import cookie from "cookie";
|
|
4
|
+
/**
|
|
5
|
+
* 简化的请求体解析函数
|
|
6
|
+
* 优先简洁性,处理最常见的场景
|
|
7
|
+
*/
|
|
8
|
+
export async function parseBody(req) {
|
|
9
|
+
const contentType = req.headers.get("content-type") || "";
|
|
10
|
+
if (contentType.includes("application/json")) {
|
|
11
|
+
return await req.json();
|
|
12
|
+
}
|
|
13
|
+
if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
14
|
+
const text = await req.text();
|
|
15
|
+
return Object.fromEntries(new URLSearchParams(text));
|
|
16
|
+
}
|
|
17
|
+
return await req.text(); // fallback
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 解析 multipart/form-data 格式
|
|
21
|
+
* 支持文件上传和普通表单字段
|
|
22
|
+
*/
|
|
23
|
+
async function parseMultipartFormData(req) {
|
|
24
|
+
const formData = await req.formData();
|
|
25
|
+
const result = {
|
|
26
|
+
fields: {},
|
|
27
|
+
files: {},
|
|
28
|
+
};
|
|
29
|
+
for (const [key, value] of formData.entries()) {
|
|
30
|
+
if (typeof value === "object" &&
|
|
31
|
+
value !== null &&
|
|
32
|
+
"name" in value &&
|
|
33
|
+
"type" in value &&
|
|
34
|
+
"size" in value) {
|
|
35
|
+
// 处理文件
|
|
36
|
+
const file = value;
|
|
37
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
38
|
+
result.files[key] = {
|
|
39
|
+
name: file.name,
|
|
40
|
+
type: file.type,
|
|
41
|
+
size: file.size,
|
|
42
|
+
data: arrayBuffer,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// 处理普通字段
|
|
47
|
+
result.fields[key] = value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 解析请求体为特定类型
|
|
54
|
+
* 提供类型安全的解析方法
|
|
55
|
+
*/
|
|
56
|
+
export async function parseBodyAs(req) {
|
|
57
|
+
const body = await parseBody(req);
|
|
58
|
+
return body;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 解析请求体为表单数据
|
|
62
|
+
* 专门用于处理 multipart/form-data
|
|
63
|
+
*/
|
|
64
|
+
export async function parseFormData(req) {
|
|
65
|
+
const contentType = req.headers.get("content-type") || "";
|
|
66
|
+
if (!contentType.includes("multipart/form-data")) {
|
|
67
|
+
throw new Error("请求不是 multipart/form-data 格式");
|
|
68
|
+
}
|
|
69
|
+
return await parseMultipartFormData(req);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 解析请求体为文件
|
|
73
|
+
* 专门用于处理文件上传
|
|
74
|
+
*/
|
|
75
|
+
export async function parseFile(req) {
|
|
76
|
+
const contentType = req.headers.get("content-type") || "";
|
|
77
|
+
if (!contentType.includes("multipart/form-data")) {
|
|
78
|
+
throw new Error("请求不是 multipart/form-data 格式");
|
|
79
|
+
}
|
|
80
|
+
const formData = await parseMultipartFormData(req);
|
|
81
|
+
const fileKeys = Object.keys(formData.files);
|
|
82
|
+
if (fileKeys.length === 0) {
|
|
83
|
+
throw new Error("请求中没有文件");
|
|
84
|
+
}
|
|
85
|
+
if (fileKeys.length > 1) {
|
|
86
|
+
throw new Error("请求中包含多个文件,请使用 parseFormData");
|
|
87
|
+
}
|
|
88
|
+
return formData.files[fileKeys[0]];
|
|
89
|
+
}
|
|
90
|
+
/** 获取查询字符串,直接返回对象 */
|
|
91
|
+
export function parseQuery(req) {
|
|
92
|
+
const url = new URL(req.url);
|
|
93
|
+
return qs.parse(url.search.slice(1)); // 去掉开头的 ?
|
|
94
|
+
}
|
|
95
|
+
/** 解析请求头,返回对象 */
|
|
96
|
+
export function parseHeaders(req) {
|
|
97
|
+
const headers = {};
|
|
98
|
+
req.headers.forEach((value, key) => {
|
|
99
|
+
if (value !== undefined && value !== null) {
|
|
100
|
+
headers[key] = value;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return headers;
|
|
104
|
+
}
|
|
105
|
+
/** 使用cookie库解析Cookie,保证可靠性 */
|
|
106
|
+
export function parseCookies(req) {
|
|
107
|
+
const cookieHeader = req.headers.get("cookie");
|
|
108
|
+
if (!cookieHeader)
|
|
109
|
+
return {};
|
|
110
|
+
try {
|
|
111
|
+
const parsed = cookie.parse(cookieHeader);
|
|
112
|
+
// 过滤掉undefined和null值
|
|
113
|
+
const result = {};
|
|
114
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
115
|
+
if (value !== undefined && value !== null) {
|
|
116
|
+
result[key] = value;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error("Cookie解析失败:", error);
|
|
123
|
+
console.error("原始Cookie字符串:", cookieHeader);
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 路径匹配工具类
|
|
3
|
+
* 提供统一的路径匹配和参数提取功能
|
|
4
|
+
*/
|
|
5
|
+
export declare class PathMatcher {
|
|
6
|
+
/**
|
|
7
|
+
* 路径匹配
|
|
8
|
+
*/
|
|
9
|
+
static matchPath(pattern: string, path: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* 提取路径参数
|
|
12
|
+
*/
|
|
13
|
+
static extractParams(pattern: string, path: string): Record<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
* 计算路径特异性分数
|
|
16
|
+
* 用于路由排序:静态 > 动态(:param) > 通配符(*)
|
|
17
|
+
*/
|
|
18
|
+
static calculatePathScore(path: string): number;
|
|
19
|
+
/**
|
|
20
|
+
* 判断两个路径是否可能冲突
|
|
21
|
+
*/
|
|
22
|
+
static pathsMayConflict(path1: string, path2: string): boolean;
|
|
23
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 路径匹配工具类
|
|
3
|
+
* 提供统一的路径匹配和参数提取功能
|
|
4
|
+
*/
|
|
5
|
+
export class PathMatcher {
|
|
6
|
+
/**
|
|
7
|
+
* 路径匹配
|
|
8
|
+
*/
|
|
9
|
+
static matchPath(pattern, path) {
|
|
10
|
+
const patternParts = pattern.split("/").filter(Boolean);
|
|
11
|
+
const pathParts = path.split("/").filter(Boolean);
|
|
12
|
+
if (patternParts.length !== pathParts.length) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
16
|
+
if (patternParts[i] !== pathParts[i] && !patternParts[i].startsWith(":")) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 提取路径参数
|
|
24
|
+
*/
|
|
25
|
+
static extractParams(pattern, path) {
|
|
26
|
+
const params = {};
|
|
27
|
+
const patternParts = pattern.split("/").filter(Boolean);
|
|
28
|
+
const pathParts = path.split("/").filter(Boolean);
|
|
29
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
30
|
+
if (patternParts[i].startsWith(":")) {
|
|
31
|
+
const paramName = patternParts[i].slice(1);
|
|
32
|
+
params[paramName] = pathParts[i];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return params;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 计算路径特异性分数
|
|
39
|
+
* 用于路由排序:静态 > 动态(:param) > 通配符(*)
|
|
40
|
+
*/
|
|
41
|
+
static calculatePathScore(path) {
|
|
42
|
+
const parts = path.split("/").filter(Boolean);
|
|
43
|
+
let score = 0;
|
|
44
|
+
for (const p of parts) {
|
|
45
|
+
if (p === "*")
|
|
46
|
+
score += 1; // 最弱
|
|
47
|
+
else if (p.startsWith(":"))
|
|
48
|
+
score += 2; // 中等
|
|
49
|
+
else
|
|
50
|
+
score += 3; // 静态最强
|
|
51
|
+
}
|
|
52
|
+
// 更长的路径更具体,略微提升
|
|
53
|
+
return score * 10 + parts.length;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 判断两个路径是否可能冲突
|
|
57
|
+
*/
|
|
58
|
+
static pathsMayConflict(path1, path2) {
|
|
59
|
+
const parts1 = path1.split("/").filter(Boolean);
|
|
60
|
+
const parts2 = path2.split("/").filter(Boolean);
|
|
61
|
+
if (parts1.length !== parts2.length)
|
|
62
|
+
return false;
|
|
63
|
+
for (let i = 0; i < parts1.length; i++) {
|
|
64
|
+
const p1 = parts1[i];
|
|
65
|
+
const p2 = parts2[i];
|
|
66
|
+
// 如果两个部分都是静态的且不同,则不会冲突
|
|
67
|
+
if (!p1.startsWith(":") &&
|
|
68
|
+
!p1.startsWith("*") &&
|
|
69
|
+
!p2.startsWith(":") &&
|
|
70
|
+
!p2.startsWith("*") &&
|
|
71
|
+
p1 !== p2) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
// 如果一个是通配符,另一个是动态参数,可能冲突
|
|
75
|
+
if ((p1 === "*" && p2.startsWith(":")) ||
|
|
76
|
+
(p2 === "*" && p1.startsWith(":"))) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 请求解析和验证器
|
|
3
|
+
*
|
|
4
|
+
* 解析handler的req参数,使用Ultra验证器进行验证,
|
|
5
|
+
* 并类型安全地返回解析出来的值
|
|
6
|
+
*
|
|
7
|
+
* @author Framework Team
|
|
8
|
+
* @version 1.0.0
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
12
|
+
import type { Static } from "@sinclair/typebox";
|
|
13
|
+
import { type SchemaConfig } from "./validators/schema-validators-ultra";
|
|
14
|
+
export interface RequestData {
|
|
15
|
+
body: unknown;
|
|
16
|
+
query: unknown;
|
|
17
|
+
params: Record<string, string>;
|
|
18
|
+
headers: Record<string, string>;
|
|
19
|
+
cookies: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
export interface ValidatedRequestData<T extends SchemaConfig> {
|
|
22
|
+
body: T["body"] extends TSchema ? Static<T["body"]> : unknown;
|
|
23
|
+
query: T["query"] extends TSchema ? Static<T["query"]> : unknown;
|
|
24
|
+
params: T["params"] extends TSchema ? Static<T["params"]> : Record<string, string>;
|
|
25
|
+
headers: T["headers"] extends TSchema ? Static<T["headers"]> : Record<string, string>;
|
|
26
|
+
cookies: T["cookies"] extends TSchema ? Static<T["cookies"]> : Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
export interface ValidationResult<T extends SchemaConfig> {
|
|
29
|
+
success: boolean;
|
|
30
|
+
data?: ValidatedRequestData<T>;
|
|
31
|
+
errors?: Array<{
|
|
32
|
+
field: keyof SchemaConfig;
|
|
33
|
+
message: string;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 解析Request对象,提取所有相关数据
|
|
38
|
+
* @param request Request对象
|
|
39
|
+
* @param params 路径参数(可选)
|
|
40
|
+
* @returns 解析后的请求数据
|
|
41
|
+
*/
|
|
42
|
+
export declare function parseRequest(request: Request, params?: Record<string, string>): Promise<RequestData>;
|
|
43
|
+
/**
|
|
44
|
+
* 验证请求数据
|
|
45
|
+
* @param config Schema配置
|
|
46
|
+
* @param requestData 请求数据
|
|
47
|
+
* @returns 验证结果
|
|
48
|
+
*/
|
|
49
|
+
export declare function validateRequest<T extends SchemaConfig>(config: T, requestData: RequestData): ValidationResult<T>;
|
|
50
|
+
/**
|
|
51
|
+
* 完整的请求解析和验证流程
|
|
52
|
+
* @param request Request对象
|
|
53
|
+
* @param config Schema配置
|
|
54
|
+
* @param params 路径参数(可选)
|
|
55
|
+
* @returns 验证结果
|
|
56
|
+
*/
|
|
57
|
+
export declare function parseAndValidateRequest<T extends SchemaConfig>(request: Request, config: T, params?: Record<string, string>): Promise<ValidationResult<T>>;
|
|
58
|
+
/**
|
|
59
|
+
* 创建类型安全的请求验证器工厂
|
|
60
|
+
* @param config Schema配置
|
|
61
|
+
* @returns 验证器函数
|
|
62
|
+
*/
|
|
63
|
+
export declare function createRequestValidator<T extends SchemaConfig>(config: T): (request: Request, params?: Record<string, string>) => Promise<ValidationResult<T>>;
|