vafast 0.1.13 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/middleware/component-renderer.js +10 -14
- package/dist/middleware/component-router.js +4 -1
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.js +8 -3
- package/dist/monitoring/types.d.ts +1 -1
- package/dist/router/index.d.ts +5 -0
- package/dist/router/index.js +7 -0
- package/dist/router/radix-tree.d.ts +51 -0
- package/dist/router/radix-tree.js +186 -0
- package/dist/router.d.ts +38 -10
- package/dist/router.js +55 -43
- package/dist/server/base-server.d.ts +0 -4
- package/dist/server/base-server.js +2 -24
- package/dist/server/index.d.ts +4 -4
- package/dist/server/index.js +8 -6
- package/dist/server/server.d.ts +30 -2
- package/dist/server/server.js +84 -60
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.js +3 -2
- package/dist/types/route.d.ts +2 -2
- package/dist/types/schema.d.ts +75 -0
- package/dist/types/schema.js +10 -0
- package/dist/types/types.d.ts +6 -2
- package/dist/utils/create-handler.d.ts +74 -0
- package/dist/utils/create-handler.js +234 -0
- package/dist/utils/dependency-manager.js +8 -2
- package/dist/utils/go-await.js +1 -4
- package/dist/utils/handle.d.ts +1 -0
- package/dist/utils/handle.js +5 -0
- package/dist/utils/index.d.ts +12 -10
- package/dist/utils/index.js +21 -11
- package/dist/utils/path-matcher.js +2 -1
- package/dist/utils/response.d.ts +5 -0
- package/dist/utils/response.js +41 -0
- package/package.json +30 -27
- package/dist/index.js.map +0 -1
- package/dist/types.d.ts +0 -18
- package/dist/types.js +0 -1
- package/dist/utils/route-handler-factory.d.ts +0 -50
- package/dist/utils/route-handler-factory.js +0 -182
|
@@ -6,13 +6,11 @@
|
|
|
6
6
|
const renderVueSSR = async (componentImport, req, preloadedDeps) => {
|
|
7
7
|
try {
|
|
8
8
|
// 使用预加载的依赖或动态导入
|
|
9
|
-
const { createSSRApp, renderToString } = preloadedDeps ||
|
|
10
|
-
import("vue"),
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
renderToString: renderer.renderToString
|
|
15
|
-
}));
|
|
9
|
+
const { createSSRApp, renderToString } = preloadedDeps ||
|
|
10
|
+
(await Promise.all([import("vue"), import("@vue/server-renderer")]).then(([vue, renderer]) => ({
|
|
11
|
+
createSSRApp: vue.createSSRApp,
|
|
12
|
+
renderToString: renderer.renderToString,
|
|
13
|
+
})));
|
|
16
14
|
const componentModule = await componentImport();
|
|
17
15
|
const component = componentModule.default || componentModule;
|
|
18
16
|
const app = createSSRApp(component);
|
|
@@ -64,13 +62,11 @@ const renderVueSSR = async (componentImport, req, preloadedDeps) => {
|
|
|
64
62
|
const renderReactSSR = async (componentImport, req, preloadedDeps) => {
|
|
65
63
|
try {
|
|
66
64
|
// 使用预加载的依赖或动态导入
|
|
67
|
-
const { createElement, renderToString } = preloadedDeps ||
|
|
68
|
-
import("react"),
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
renderToString: renderer.renderToString
|
|
73
|
-
}));
|
|
65
|
+
const { createElement, renderToString } = preloadedDeps ||
|
|
66
|
+
(await Promise.all([import("react"), import("react-dom/server")]).then(([react, renderer]) => ({
|
|
67
|
+
createElement: react.createElement,
|
|
68
|
+
renderToString: renderer.renderToString,
|
|
69
|
+
})));
|
|
74
70
|
const componentModule = await componentImport();
|
|
75
71
|
const Component = componentModule.default || componentModule;
|
|
76
72
|
const content = createElement(Component, {
|
|
@@ -5,7 +5,10 @@ export function flattenComponentRoutes(routes) {
|
|
|
5
5
|
const flattened = [];
|
|
6
6
|
function processRoute(route, parentPath = "", parentMiddleware = []) {
|
|
7
7
|
const currentPath = parentPath + route.path;
|
|
8
|
-
const currentMiddleware = [
|
|
8
|
+
const currentMiddleware = [
|
|
9
|
+
...parentMiddleware,
|
|
10
|
+
...(route.middleware || []),
|
|
11
|
+
];
|
|
9
12
|
if ("component" in route) {
|
|
10
13
|
// 这是一个组件路由
|
|
11
14
|
flattened.push({
|
package/dist/middleware.d.ts
CHANGED
|
@@ -15,4 +15,4 @@ export declare class VafastError extends Error {
|
|
|
15
15
|
/**
|
|
16
16
|
* 组合类型: 自动注入错误处理器进行中间件组合
|
|
17
17
|
*/
|
|
18
|
-
export declare function composeMiddleware(middleware: Middleware[], finalHandler: Handler):
|
|
18
|
+
export declare function composeMiddleware(middleware: Middleware[], finalHandler: Handler): (req: Request) => Promise<Response>;
|
package/dist/middleware.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/middleware.ts
|
|
2
|
-
import { json } from "./utils/response";
|
|
2
|
+
import { json, mapResponse } from "./utils/response";
|
|
3
3
|
/** 中间件类型:使用 next() 传递给下一个处理 */
|
|
4
4
|
/** Vafast 自定义错误类型 */
|
|
5
5
|
export class VafastError extends Error {
|
|
@@ -27,8 +27,13 @@ export function composeMiddleware(middleware, finalHandler) {
|
|
|
27
27
|
if (index <= i)
|
|
28
28
|
return Promise.reject(new Error("next() called multiple times"));
|
|
29
29
|
i = index;
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
// 中间件阶段
|
|
31
|
+
if (index < all.length) {
|
|
32
|
+
const mw = all[index];
|
|
33
|
+
return Promise.resolve(mw(req, () => dispatch(index + 1)));
|
|
34
|
+
}
|
|
35
|
+
// 最终 handler - 使用 mapResponse 转换返回值
|
|
36
|
+
return Promise.resolve(finalHandler(req)).then(mapResponse);
|
|
32
37
|
};
|
|
33
38
|
return dispatch(0);
|
|
34
39
|
};
|
|
@@ -107,7 +107,7 @@ export interface MonitoringConfig {
|
|
|
107
107
|
};
|
|
108
108
|
}
|
|
109
109
|
export interface MonitoringEvent {
|
|
110
|
-
type:
|
|
110
|
+
type: "request_start" | "request_end" | "validation_start" | "validation_end" | "error";
|
|
111
111
|
timestamp: number;
|
|
112
112
|
requestId: string;
|
|
113
113
|
data: any;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Radix Tree 路由匹配器
|
|
3
|
+
*
|
|
4
|
+
* 高性能路由匹配实现,时间复杂度 O(k),k 为路径段数
|
|
5
|
+
*
|
|
6
|
+
* 支持的路由模式:
|
|
7
|
+
* - 静态路径: /users, /api/v1/health
|
|
8
|
+
* - 动态参数: /users/:id, /posts/:postId/comments/:commentId
|
|
9
|
+
* - 通配符: /files/*, /static/*filepath
|
|
10
|
+
*/
|
|
11
|
+
import type { Handler, Middleware, Method } from "../types";
|
|
12
|
+
/** 路由匹配结果 */
|
|
13
|
+
export interface MatchResult {
|
|
14
|
+
handler: Handler;
|
|
15
|
+
middleware: Middleware[];
|
|
16
|
+
params: Record<string, string>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Radix Tree 路由器
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const router = new RadixRouter();
|
|
24
|
+
* router.register("GET", "/users/:id", handler);
|
|
25
|
+
* const result = router.match("GET", "/users/123");
|
|
26
|
+
* // result.params = { id: "123" }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class RadixRouter {
|
|
30
|
+
private root;
|
|
31
|
+
constructor();
|
|
32
|
+
private createNode;
|
|
33
|
+
/** 分割路径 */
|
|
34
|
+
private splitPath;
|
|
35
|
+
/** 注册路由 */
|
|
36
|
+
register(method: Method, pattern: string, handler: Handler, middleware?: Middleware[]): void;
|
|
37
|
+
/** 匹配路由 */
|
|
38
|
+
match(method: Method, path: string): MatchResult | null;
|
|
39
|
+
/** 递归匹配节点 (优先级: 静态 > 动态参数 > 通配符) */
|
|
40
|
+
private matchNode;
|
|
41
|
+
/** 获取路径允许的 HTTP 方法 */
|
|
42
|
+
getAllowedMethods(path: string): Method[];
|
|
43
|
+
/** 查找节点(不提取参数) */
|
|
44
|
+
private findNode;
|
|
45
|
+
/** 获取所有已注册的路由 */
|
|
46
|
+
getRoutes(): Array<{
|
|
47
|
+
method: Method;
|
|
48
|
+
path: string;
|
|
49
|
+
}>;
|
|
50
|
+
private collectRoutes;
|
|
51
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Radix Tree 路由匹配器
|
|
3
|
+
*
|
|
4
|
+
* 高性能路由匹配实现,时间复杂度 O(k),k 为路径段数
|
|
5
|
+
*
|
|
6
|
+
* 支持的路由模式:
|
|
7
|
+
* - 静态路径: /users, /api/v1/health
|
|
8
|
+
* - 动态参数: /users/:id, /posts/:postId/comments/:commentId
|
|
9
|
+
* - 通配符: /files/*, /static/*filepath
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Radix Tree 路由器
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const router = new RadixRouter();
|
|
17
|
+
* router.register("GET", "/users/:id", handler);
|
|
18
|
+
* const result = router.match("GET", "/users/123");
|
|
19
|
+
* // result.params = { id: "123" }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class RadixRouter {
|
|
23
|
+
root;
|
|
24
|
+
constructor() {
|
|
25
|
+
this.root = this.createNode("");
|
|
26
|
+
}
|
|
27
|
+
createNode(path) {
|
|
28
|
+
return {
|
|
29
|
+
path,
|
|
30
|
+
children: Object.create(null),
|
|
31
|
+
handlers: Object.create(null),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** 分割路径 */
|
|
35
|
+
splitPath(path) {
|
|
36
|
+
return path.split("/").filter(Boolean);
|
|
37
|
+
}
|
|
38
|
+
/** 注册路由 */
|
|
39
|
+
register(method, pattern, handler, middleware = []) {
|
|
40
|
+
const segments = this.splitPath(pattern);
|
|
41
|
+
let node = this.root;
|
|
42
|
+
for (const segment of segments) {
|
|
43
|
+
const firstChar = segment[0];
|
|
44
|
+
if (firstChar === ":") {
|
|
45
|
+
// 动态参数节点
|
|
46
|
+
if (!node.paramChild) {
|
|
47
|
+
node.paramChild = this.createNode(segment);
|
|
48
|
+
node.paramChild.paramName = segment.substring(1);
|
|
49
|
+
}
|
|
50
|
+
node = node.paramChild;
|
|
51
|
+
}
|
|
52
|
+
else if (firstChar === "*") {
|
|
53
|
+
// 通配符节点
|
|
54
|
+
if (!node.wildcardChild) {
|
|
55
|
+
node.wildcardChild = this.createNode(segment);
|
|
56
|
+
node.wildcardChild.paramName =
|
|
57
|
+
segment.length > 1 ? segment.substring(1) : "*";
|
|
58
|
+
}
|
|
59
|
+
node = node.wildcardChild;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// 静态路径节点
|
|
64
|
+
if (!node.children[segment]) {
|
|
65
|
+
node.children[segment] = this.createNode(segment);
|
|
66
|
+
}
|
|
67
|
+
node = node.children[segment];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
node.handlers[method] = { handler, middleware };
|
|
71
|
+
}
|
|
72
|
+
/** 匹配路由 */
|
|
73
|
+
match(method, path) {
|
|
74
|
+
const segments = this.splitPath(path);
|
|
75
|
+
const params = Object.create(null);
|
|
76
|
+
const node = this.matchNode(this.root, segments, 0, params);
|
|
77
|
+
if (!node)
|
|
78
|
+
return null;
|
|
79
|
+
const routeHandler = node.handlers[method];
|
|
80
|
+
if (!routeHandler)
|
|
81
|
+
return null;
|
|
82
|
+
return {
|
|
83
|
+
handler: routeHandler.handler,
|
|
84
|
+
middleware: routeHandler.middleware,
|
|
85
|
+
params,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** 递归匹配节点 (优先级: 静态 > 动态参数 > 通配符) */
|
|
89
|
+
matchNode(node, segments, index, params) {
|
|
90
|
+
if (index === segments.length) {
|
|
91
|
+
for (const method in node.handlers) {
|
|
92
|
+
if (node.handlers[method])
|
|
93
|
+
return node;
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const segment = segments[index];
|
|
98
|
+
// 1. 静态路径
|
|
99
|
+
const staticChild = node.children[segment];
|
|
100
|
+
if (staticChild) {
|
|
101
|
+
const result = this.matchNode(staticChild, segments, index + 1, params);
|
|
102
|
+
if (result)
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
// 2. 动态参数
|
|
106
|
+
if (node.paramChild) {
|
|
107
|
+
const paramName = node.paramChild.paramName;
|
|
108
|
+
const oldValue = params[paramName];
|
|
109
|
+
params[paramName] = segment;
|
|
110
|
+
const result = this.matchNode(node.paramChild, segments, index + 1, params);
|
|
111
|
+
if (result)
|
|
112
|
+
return result;
|
|
113
|
+
// 回溯
|
|
114
|
+
if (oldValue === undefined) {
|
|
115
|
+
delete params[paramName];
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
params[paramName] = oldValue;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// 3. 通配符
|
|
122
|
+
if (node.wildcardChild) {
|
|
123
|
+
params[node.wildcardChild.paramName || "*"] = segments
|
|
124
|
+
.slice(index)
|
|
125
|
+
.join("/");
|
|
126
|
+
return node.wildcardChild;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
/** 获取路径允许的 HTTP 方法 */
|
|
131
|
+
getAllowedMethods(path) {
|
|
132
|
+
const segments = this.splitPath(path);
|
|
133
|
+
const node = this.findNode(segments);
|
|
134
|
+
if (!node)
|
|
135
|
+
return [];
|
|
136
|
+
const methods = [];
|
|
137
|
+
for (const method in node.handlers) {
|
|
138
|
+
if (node.handlers[method]) {
|
|
139
|
+
methods.push(method);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return methods;
|
|
143
|
+
}
|
|
144
|
+
/** 查找节点(不提取参数) */
|
|
145
|
+
findNode(segments) {
|
|
146
|
+
let node = this.root;
|
|
147
|
+
for (const segment of segments) {
|
|
148
|
+
if (node.children[segment]) {
|
|
149
|
+
node = node.children[segment];
|
|
150
|
+
}
|
|
151
|
+
else if (node.paramChild) {
|
|
152
|
+
node = node.paramChild;
|
|
153
|
+
}
|
|
154
|
+
else if (node.wildcardChild) {
|
|
155
|
+
return node.wildcardChild;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return node;
|
|
162
|
+
}
|
|
163
|
+
/** 获取所有已注册的路由 */
|
|
164
|
+
getRoutes() {
|
|
165
|
+
const routes = [];
|
|
166
|
+
this.collectRoutes(this.root, "", routes);
|
|
167
|
+
return routes;
|
|
168
|
+
}
|
|
169
|
+
collectRoutes(node, prefix, routes) {
|
|
170
|
+
const currentPath = prefix + (node.path ? "/" + node.path : "");
|
|
171
|
+
for (const method in node.handlers) {
|
|
172
|
+
if (node.handlers[method]) {
|
|
173
|
+
routes.push({ method: method, path: currentPath || "/" });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
for (const key in node.children) {
|
|
177
|
+
this.collectRoutes(node.children[key], currentPath, routes);
|
|
178
|
+
}
|
|
179
|
+
if (node.paramChild) {
|
|
180
|
+
this.collectRoutes(node.paramChild, currentPath, routes);
|
|
181
|
+
}
|
|
182
|
+
if (node.wildcardChild) {
|
|
183
|
+
this.collectRoutes(node.wildcardChild, currentPath, routes);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
package/dist/router.d.ts
CHANGED
|
@@ -1,17 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 路由工具函数
|
|
3
|
+
*
|
|
4
|
+
* 提供路由处理的基础工具
|
|
5
|
+
*/
|
|
1
6
|
import type { Route, NestedRoute, FlattenedRoute } from "./types";
|
|
2
|
-
export interface MatchResult {
|
|
3
|
-
matched: boolean;
|
|
4
|
-
params: Record<string, string>;
|
|
5
|
-
}
|
|
6
7
|
/**
|
|
7
|
-
*
|
|
8
|
+
* 扁平化嵌套路由
|
|
9
|
+
*
|
|
10
|
+
* 将嵌套路由结构转换为扁平数组,计算完整路径和中间件链
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const routes = flattenNestedRoutes([
|
|
15
|
+
* {
|
|
16
|
+
* path: "/api",
|
|
17
|
+
* middleware: [authMiddleware],
|
|
18
|
+
* children: [
|
|
19
|
+
* { path: "/users", method: "GET", handler: getUsers },
|
|
20
|
+
* { path: "/users/:id", method: "GET", handler: getUser },
|
|
21
|
+
* ],
|
|
22
|
+
* },
|
|
23
|
+
* ]);
|
|
24
|
+
* // 结果:
|
|
25
|
+
* // [
|
|
26
|
+
* // { fullPath: "/api/users", method: "GET", ... },
|
|
27
|
+
* // { fullPath: "/api/users/:id", method: "GET", ... },
|
|
28
|
+
* // ]
|
|
29
|
+
* ```
|
|
8
30
|
*/
|
|
9
31
|
export declare function flattenNestedRoutes(routes: (Route | NestedRoute)[]): FlattenedRoute[];
|
|
10
32
|
/**
|
|
11
|
-
*
|
|
33
|
+
* 标准化路径
|
|
34
|
+
*
|
|
35
|
+
* - 解码 URL 编码字符
|
|
36
|
+
* - 去除重复斜杠
|
|
37
|
+
* - 处理结尾斜杠
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* normalizePath("//api//users/") // "/api/users"
|
|
42
|
+
* normalizePath("/api/%20test") // "/api/ test"
|
|
43
|
+
* ```
|
|
12
44
|
*/
|
|
13
45
|
export declare function normalizePath(path: string): string;
|
|
14
|
-
/**
|
|
15
|
-
* 匹配函数:支持动态路由和路径标准化
|
|
16
|
-
*/
|
|
17
|
-
export declare function matchPath(pattern: string, path: string): MatchResult;
|
package/dist/router.js
CHANGED
|
@@ -1,21 +1,52 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 路由工具函数
|
|
3
|
+
*
|
|
4
|
+
* 提供路由处理的基础工具
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 扁平化嵌套路由
|
|
8
|
+
*
|
|
9
|
+
* 将嵌套路由结构转换为扁平数组,计算完整路径和中间件链
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const routes = flattenNestedRoutes([
|
|
14
|
+
* {
|
|
15
|
+
* path: "/api",
|
|
16
|
+
* middleware: [authMiddleware],
|
|
17
|
+
* children: [
|
|
18
|
+
* { path: "/users", method: "GET", handler: getUsers },
|
|
19
|
+
* { path: "/users/:id", method: "GET", handler: getUser },
|
|
20
|
+
* ],
|
|
21
|
+
* },
|
|
22
|
+
* ]);
|
|
23
|
+
* // 结果:
|
|
24
|
+
* // [
|
|
25
|
+
* // { fullPath: "/api/users", method: "GET", ... },
|
|
26
|
+
* // { fullPath: "/api/users/:id", method: "GET", ... },
|
|
27
|
+
* // ]
|
|
28
|
+
* ```
|
|
3
29
|
*/
|
|
4
30
|
export function flattenNestedRoutes(routes) {
|
|
5
31
|
const flattened = [];
|
|
6
32
|
function processRoute(route, parentPath = "", parentMiddleware = []) {
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
33
|
+
// 计算当前完整路径
|
|
34
|
+
const currentPath = normalizePath(parentPath + route.path);
|
|
35
|
+
// 合并中间件链
|
|
36
|
+
const currentMiddleware = [
|
|
37
|
+
...parentMiddleware,
|
|
38
|
+
...(route.middleware || []),
|
|
39
|
+
];
|
|
40
|
+
if ("method" in route && "handler" in route) {
|
|
41
|
+
// 叶子路由(有处理函数)
|
|
11
42
|
flattened.push({
|
|
12
43
|
...route,
|
|
13
44
|
fullPath: currentPath,
|
|
14
|
-
middlewareChain: currentMiddleware
|
|
45
|
+
middlewareChain: currentMiddleware,
|
|
15
46
|
});
|
|
16
47
|
}
|
|
17
|
-
else if (
|
|
18
|
-
//
|
|
48
|
+
else if ("children" in route && route.children) {
|
|
49
|
+
// 分组路由,递归处理子路由
|
|
19
50
|
for (const child of route.children) {
|
|
20
51
|
processRoute(child, currentPath, currentMiddleware);
|
|
21
52
|
}
|
|
@@ -27,48 +58,29 @@ export function flattenNestedRoutes(routes) {
|
|
|
27
58
|
return flattened;
|
|
28
59
|
}
|
|
29
60
|
/**
|
|
30
|
-
*
|
|
61
|
+
* 标准化路径
|
|
62
|
+
*
|
|
63
|
+
* - 解码 URL 编码字符
|
|
64
|
+
* - 去除重复斜杠
|
|
65
|
+
* - 处理结尾斜杠
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* normalizePath("//api//users/") // "/api/users"
|
|
70
|
+
* normalizePath("/api/%20test") // "/api/ test"
|
|
71
|
+
* ```
|
|
31
72
|
*/
|
|
32
73
|
export function normalizePath(path) {
|
|
33
|
-
// 解码 URL
|
|
74
|
+
// 解码 URL 编码
|
|
34
75
|
let normalized = decodeURIComponent(path);
|
|
35
|
-
//
|
|
76
|
+
// 去除重复斜杠
|
|
36
77
|
normalized = normalized.replace(/\/+/g, "/");
|
|
37
|
-
//
|
|
78
|
+
// 空路径转为根路径
|
|
38
79
|
if (normalized === "")
|
|
39
|
-
|
|
40
|
-
//
|
|
80
|
+
return "/";
|
|
81
|
+
// 去除结尾斜杠(根路径除外)
|
|
41
82
|
if (normalized !== "/" && normalized.endsWith("/")) {
|
|
42
83
|
normalized = normalized.slice(0, -1);
|
|
43
84
|
}
|
|
44
85
|
return normalized;
|
|
45
86
|
}
|
|
46
|
-
/**
|
|
47
|
-
* 匹配函数:支持动态路由和路径标准化
|
|
48
|
-
*/
|
|
49
|
-
export function matchPath(pattern, path) {
|
|
50
|
-
// 标准化输入路径
|
|
51
|
-
const normalizedPath = normalizePath(path);
|
|
52
|
-
const patternParts = pattern.split("/").filter(Boolean);
|
|
53
|
-
const pathParts = normalizedPath.split("/").filter(Boolean);
|
|
54
|
-
const params = {};
|
|
55
|
-
for (let i = 0; i < patternParts.length; i++) {
|
|
56
|
-
const pat = patternParts[i];
|
|
57
|
-
const part = pathParts[i];
|
|
58
|
-
if (pat === "*") {
|
|
59
|
-
params["*"] = pathParts.slice(i).join("/");
|
|
60
|
-
return { matched: true, params };
|
|
61
|
-
}
|
|
62
|
-
if (pat.startsWith(":")) {
|
|
63
|
-
if (!part)
|
|
64
|
-
return { matched: false, params: {} };
|
|
65
|
-
params[pat.slice(1)] = part;
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (pat !== part)
|
|
69
|
-
return { matched: false, params: {} };
|
|
70
|
-
}
|
|
71
|
-
if (patternParts.length !== pathParts.length)
|
|
72
|
-
return { matched: false, params: {} };
|
|
73
|
-
return { matched: true, params };
|
|
74
|
-
}
|
|
@@ -120,7 +120,8 @@ export class BaseServer {
|
|
|
120
120
|
return false;
|
|
121
121
|
}
|
|
122
122
|
for (let i = 0; i < patternParts.length; i++) {
|
|
123
|
-
if (patternParts[i] !== pathParts[i] &&
|
|
123
|
+
if (patternParts[i] !== pathParts[i] &&
|
|
124
|
+
!patternParts[i].startsWith(":")) {
|
|
124
125
|
return false;
|
|
125
126
|
}
|
|
126
127
|
}
|
|
@@ -141,27 +142,4 @@ export class BaseServer {
|
|
|
141
142
|
}
|
|
142
143
|
return params;
|
|
143
144
|
}
|
|
144
|
-
/**
|
|
145
|
-
* 处理 OPTIONS 请求
|
|
146
|
-
*/
|
|
147
|
-
handleOptions(pathname, routes) {
|
|
148
|
-
const availableMethods = [];
|
|
149
|
-
for (const route of routes) {
|
|
150
|
-
const path = route.fullPath || route.path;
|
|
151
|
-
const method = route.method || "GET";
|
|
152
|
-
if (this.matchPath(path, pathname)) {
|
|
153
|
-
availableMethods.push(method);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// 去重并排序
|
|
157
|
-
const uniqueMethods = [...new Set(availableMethods)].sort();
|
|
158
|
-
return new Response(null, {
|
|
159
|
-
status: 204,
|
|
160
|
-
headers: {
|
|
161
|
-
Allow: uniqueMethods.join(", "),
|
|
162
|
-
"Access-Control-Allow-Methods": uniqueMethods.join(", "),
|
|
163
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
164
|
-
},
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
145
|
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 服务器模块导出
|
|
3
|
+
*/
|
|
1
4
|
export { Server } from "./server";
|
|
2
5
|
export { ComponentServer } from "./component-server";
|
|
3
|
-
export { BaseServer } from "./base-server";
|
|
4
6
|
export { ServerFactory } from "./server-factory";
|
|
5
|
-
export {
|
|
6
|
-
export { HtmlRenderer } from "../utils/html-renderer";
|
|
7
|
-
export { DependencyManager } from "../utils/dependency-manager";
|
|
7
|
+
export { BaseServer } from "./base-server";
|
package/dist/server/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 服务器模块导出
|
|
3
|
+
*/
|
|
4
|
+
// 主服务器类
|
|
2
5
|
export { Server } from "./server";
|
|
6
|
+
// 组件服务器 (SSR)
|
|
3
7
|
export { ComponentServer } from "./component-server";
|
|
4
|
-
|
|
8
|
+
// 服务器工厂
|
|
5
9
|
export { ServerFactory } from "./server-factory";
|
|
6
|
-
//
|
|
7
|
-
export {
|
|
8
|
-
export { HtmlRenderer } from "../utils/html-renderer";
|
|
9
|
-
export { DependencyManager } from "../utils/dependency-manager";
|
|
10
|
+
// 基类 (仅用于扩展)
|
|
11
|
+
export { BaseServer } from "./base-server";
|
package/dist/server/server.d.ts
CHANGED
|
@@ -1,7 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Vafast 核心服务器
|
|
3
|
+
*
|
|
4
|
+
* 基于 Radix Tree 的高性能路由匹配
|
|
5
|
+
* 时间复杂度: O(k),k 为路径段数
|
|
6
|
+
*/
|
|
7
|
+
import type { Route, NestedRoute, Method } from "../types";
|
|
2
8
|
import { BaseServer } from "./base-server";
|
|
9
|
+
/**
|
|
10
|
+
* Vafast 服务器
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const server = new Server([
|
|
15
|
+
* { method: "GET", path: "/", handler: () => new Response("Hello") },
|
|
16
|
+
* ]);
|
|
17
|
+
* export default { fetch: server.fetch };
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
3
20
|
export declare class Server extends BaseServer {
|
|
21
|
+
private router;
|
|
4
22
|
private routes;
|
|
5
|
-
constructor(routes
|
|
23
|
+
constructor(routes?: (Route | NestedRoute)[]);
|
|
24
|
+
private registerRoutes;
|
|
25
|
+
/** 快速提取 pathname */
|
|
26
|
+
private extractPathname;
|
|
27
|
+
/** 处理请求 */
|
|
6
28
|
fetch: (req: Request) => Promise<Response>;
|
|
29
|
+
addRoute(route: Route): void;
|
|
30
|
+
addRoutes(routes: (Route | NestedRoute)[]): void;
|
|
31
|
+
getRoutes(): Array<{
|
|
32
|
+
method: Method;
|
|
33
|
+
path: string;
|
|
34
|
+
}>;
|
|
7
35
|
}
|