vafast 0.3.2 → 0.3.4
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 +13 -11
- package/dist/auth/token.js +118 -111
- package/dist/auth/token.js.map +1 -0
- package/dist/defineRoute.d.ts +5 -2
- package/dist/defineRoute.js +7 -2
- package/dist/defineRoute.js.map +1 -0
- package/dist/index.d.ts +30 -14
- package/dist/index.js +2247 -15
- package/dist/index.js.map +1 -0
- package/dist/middleware/auth.d.ts +8 -6
- package/dist/middleware/auth.js +198 -99
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/authMiddleware.d.ts +5 -2
- package/dist/middleware/authMiddleware.js +55 -11
- package/dist/middleware/authMiddleware.js.map +1 -0
- package/dist/middleware/component-renderer.d.ts +4 -2
- package/dist/middleware/component-renderer.js +87 -80
- package/dist/middleware/component-renderer.js.map +1 -0
- package/dist/middleware/component-router.d.ts +8 -3
- package/dist/middleware/component-router.js +33 -39
- package/dist/middleware/component-router.js.map +1 -0
- package/dist/middleware/cors.d.ts +6 -3
- package/dist/middleware/cors.js +42 -29
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/rateLimit.d.ts +5 -3
- package/dist/middleware/rateLimit.js +45 -29
- package/dist/middleware/rateLimit.js.map +1 -0
- package/dist/middleware.d.ts +6 -3
- package/dist/middleware.js +97 -51
- package/dist/middleware.js.map +1 -0
- package/dist/monitoring/index.d.ts +11 -4
- package/dist/monitoring/index.js +1299 -17
- package/dist/monitoring/index.js.map +1 -0
- package/dist/monitoring/native-monitor.d.ts +12 -6
- package/dist/monitoring/native-monitor.js +1258 -161
- package/dist/monitoring/native-monitor.js.map +1 -0
- package/dist/monitoring/types.d.ts +8 -6
- package/dist/monitoring/types.js +1 -1
- package/dist/monitoring/types.js.map +1 -0
- package/dist/node-server/index.d.ts +4 -22
- package/dist/node-server/index.js +254 -21
- package/dist/node-server/index.js.map +1 -0
- package/dist/node-server/request.d.ts +6 -2
- package/dist/node-server/request.js +102 -134
- package/dist/node-server/request.js.map +1 -0
- package/dist/node-server/response.d.ts +7 -3
- package/dist/node-server/response.js +67 -89
- package/dist/node-server/response.js.map +1 -0
- package/dist/node-server/serve.d.ts +11 -7
- package/dist/node-server/serve.js +231 -82
- package/dist/node-server/serve.js.map +1 -0
- package/dist/router/index.d.ts +3 -5
- package/dist/router/index.js +228 -7
- package/dist/router/index.js.map +1 -0
- package/dist/router/radix-tree.d.ts +7 -4
- package/dist/router/radix-tree.js +186 -218
- package/dist/router/radix-tree.js.map +1 -0
- package/dist/router.d.ts +7 -3
- package/dist/router.js +37 -83
- package/dist/router.js.map +1 -0
- package/dist/serve.d.ts +2 -12
- package/dist/serve.js +237 -11
- package/dist/serve.js.map +1 -0
- package/dist/server/base-server.d.ts +5 -2
- package/dist/server/base-server.js +124 -135
- package/dist/server/base-server.js.map +1 -0
- package/dist/server/component-server.d.ts +9 -4
- package/dist/server/component-server.js +481 -139
- package/dist/server/component-server.js.map +1 -0
- package/dist/server/index.d.ts +8 -7
- package/dist/server/index.js +985 -11
- package/dist/server/index.js.map +1 -0
- package/dist/server/server-factory.d.ts +11 -5
- package/dist/server/server-factory.js +979 -67
- package/dist/server/server-factory.js.map +1 -0
- package/dist/server/server.d.ts +7 -3
- package/dist/server/server.js +553 -112
- package/dist/server/server.js.map +1 -0
- package/dist/types/component-route.d.ts +8 -4
- package/dist/types/component-route.js +1 -1
- package/dist/types/component-route.js.map +1 -0
- package/dist/types/index.d.ts +5 -5
- package/dist/types/index.js +21 -4
- package/dist/types/index.js.map +1 -0
- package/dist/types/route.d.ts +13 -10
- package/dist/types/route.js +10 -9
- package/dist/types/route.js.map +1 -0
- package/dist/types/schema.d.ts +11 -7
- package/dist/types/schema.js +1 -1
- package/dist/types/schema.js.map +1 -0
- package/dist/types/types.d.ts +11 -9
- package/dist/types/types.js +1 -1
- package/dist/types/types.js.map +1 -0
- package/dist/utils/base64url.d.ts +4 -2
- package/dist/utils/base64url.js +12 -9
- package/dist/utils/base64url.js.map +1 -0
- package/dist/utils/create-handler.d.ts +11 -7
- package/dist/utils/create-handler.js +393 -217
- package/dist/utils/create-handler.js.map +1 -0
- package/dist/utils/dependency-manager.d.ts +3 -1
- package/dist/utils/dependency-manager.js +67 -69
- package/dist/utils/dependency-manager.js.map +1 -0
- package/dist/utils/go-await.d.ts +3 -1
- package/dist/utils/go-await.js +8 -22
- package/dist/utils/go-await.js.map +1 -0
- package/dist/utils/handle.d.ts +6 -4
- package/dist/utils/handle.js +44 -25
- package/dist/utils/handle.js.map +1 -0
- package/dist/utils/html-renderer.d.ts +3 -1
- package/dist/utils/html-renderer.js +25 -24
- package/dist/utils/html-renderer.js.map +1 -0
- package/dist/utils/index.d.ts +13 -13
- package/dist/utils/index.js +832 -21
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/parsers.d.ts +15 -13
- package/dist/utils/parsers.js +138 -188
- package/dist/utils/parsers.js.map +1 -0
- package/dist/utils/path-matcher.d.ts +3 -1
- package/dist/utils/path-matcher.js +68 -78
- package/dist/utils/path-matcher.js.map +1 -0
- package/dist/utils/request-validator.d.ts +13 -10
- package/dist/utils/request-validator.js +234 -84
- package/dist/utils/request-validator.js.map +1 -0
- package/dist/utils/response.d.ts +9 -7
- package/dist/utils/response.js +93 -102
- package/dist/utils/response.js.map +1 -0
- package/dist/utils/validators/schema-validator.d.ts +13 -9
- package/dist/utils/validators/schema-validator.js +228 -209
- package/dist/utils/validators/schema-validator.js.map +1 -0
- package/dist/utils/validators/schema-validators-ultra.d.ts +15 -12
- package/dist/utils/validators/schema-validators-ultra.js +233 -256
- package/dist/utils/validators/schema-validators-ultra.js.map +1 -0
- package/dist/utils/validators/validators.d.ts +15 -12
- package/dist/utils/validators/validators.js +81 -122
- package/dist/utils/validators/validators.js.map +1 -0
- package/package.json +5 -4
package/dist/server/server.js
CHANGED
|
@@ -1,122 +1,563 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
1
|
+
// src/router.ts
|
|
2
|
+
function flattenNestedRoutes(routes) {
|
|
3
|
+
const flattened = [];
|
|
4
|
+
function processRoute(route, parentPath = "", parentMiddleware = []) {
|
|
5
|
+
const currentPath = normalizePath(parentPath + route.path);
|
|
6
|
+
const currentMiddleware = [
|
|
7
|
+
...parentMiddleware,
|
|
8
|
+
...route.middleware || []
|
|
9
|
+
];
|
|
10
|
+
if ("method" in route && "handler" in route) {
|
|
11
|
+
flattened.push({
|
|
12
|
+
...route,
|
|
13
|
+
fullPath: currentPath,
|
|
14
|
+
middlewareChain: currentMiddleware
|
|
15
|
+
});
|
|
16
|
+
} else if ("children" in route && route.children) {
|
|
17
|
+
for (const child of route.children) {
|
|
18
|
+
processRoute(child, currentPath, currentMiddleware);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (const route of routes) {
|
|
23
|
+
processRoute(route);
|
|
24
|
+
}
|
|
25
|
+
return flattened;
|
|
26
|
+
}
|
|
27
|
+
function normalizePath(path) {
|
|
28
|
+
let normalized = decodeURIComponent(path);
|
|
29
|
+
normalized = normalized.replace(/\/+/g, "/");
|
|
30
|
+
if (normalized === "") return "/";
|
|
31
|
+
if (normalized !== "/" && normalized.endsWith("/")) {
|
|
32
|
+
normalized = normalized.slice(0, -1);
|
|
33
|
+
}
|
|
34
|
+
return normalized;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/utils/response.ts
|
|
38
|
+
function json(data, status = 200, headers = {}) {
|
|
39
|
+
const body = JSON.stringify(data);
|
|
40
|
+
if (Object.keys(headers).length === 0) {
|
|
41
|
+
return new Response(body, {
|
|
42
|
+
status,
|
|
43
|
+
headers: { "Content-Type": "application/json" }
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const h = new Headers({
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
...headers
|
|
49
|
+
});
|
|
50
|
+
return new Response(body, {
|
|
51
|
+
status,
|
|
52
|
+
headers: h
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
var JSON_HEADERS = { "Content-Type": "application/json" };
|
|
56
|
+
var TEXT_HEADERS = { "Content-Type": "text/plain" };
|
|
57
|
+
function mapResponse(response) {
|
|
58
|
+
if (response instanceof Response) return response;
|
|
59
|
+
switch (response?.constructor?.name) {
|
|
60
|
+
case "String":
|
|
61
|
+
return new Response(response, { headers: TEXT_HEADERS });
|
|
62
|
+
case "Object":
|
|
63
|
+
case "Array":
|
|
64
|
+
return new Response(JSON.stringify(response), { headers: JSON_HEADERS });
|
|
65
|
+
case "Number":
|
|
66
|
+
case "Boolean":
|
|
67
|
+
return new Response(String(response), { headers: TEXT_HEADERS });
|
|
68
|
+
case void 0:
|
|
69
|
+
return new Response(null, { status: 204 });
|
|
70
|
+
case "ReadableStream":
|
|
71
|
+
return new Response(response);
|
|
72
|
+
case "Blob":
|
|
73
|
+
return new Response(response);
|
|
74
|
+
case "ArrayBuffer":
|
|
75
|
+
return new Response(response);
|
|
76
|
+
case "Uint8Array":
|
|
77
|
+
return new Response(response);
|
|
78
|
+
default:
|
|
79
|
+
if (response instanceof Promise) {
|
|
80
|
+
return response.then(mapResponse);
|
|
81
|
+
}
|
|
82
|
+
return new Response(JSON.stringify(response), { headers: JSON_HEADERS });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/middleware.ts
|
|
87
|
+
var VafastError = class extends Error {
|
|
88
|
+
status;
|
|
89
|
+
type;
|
|
90
|
+
expose;
|
|
91
|
+
constructor(message, options = {}) {
|
|
92
|
+
super(message);
|
|
93
|
+
this.name = "VafastError";
|
|
94
|
+
this.status = options.status ?? 500;
|
|
95
|
+
this.type = options.type ?? "internal_error";
|
|
96
|
+
this.expose = options.expose ?? false;
|
|
97
|
+
if (options.cause) this.cause = options.cause;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
function composeMiddleware(middleware, finalHandler) {
|
|
101
|
+
const all = [errorHandler, ...middleware];
|
|
102
|
+
return function composedHandler(req) {
|
|
103
|
+
let i = -1;
|
|
104
|
+
const dispatch = (index) => {
|
|
105
|
+
if (index <= i)
|
|
106
|
+
return Promise.reject(new Error("next() called multiple times"));
|
|
107
|
+
i = index;
|
|
108
|
+
if (index < all.length) {
|
|
109
|
+
const mw = all[index];
|
|
110
|
+
return Promise.resolve(mw(req, () => dispatch(index + 1)));
|
|
111
|
+
}
|
|
112
|
+
return Promise.resolve(finalHandler(req)).then(mapResponse);
|
|
113
|
+
};
|
|
114
|
+
return dispatch(0);
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
var errorHandler = async (req, next) => {
|
|
118
|
+
try {
|
|
119
|
+
return await next();
|
|
120
|
+
} catch (err) {
|
|
121
|
+
console.error("\u672A\u5904\u7406\u7684\u9519\u8BEF:", err);
|
|
122
|
+
if (err instanceof VafastError) {
|
|
123
|
+
return json(
|
|
124
|
+
{
|
|
125
|
+
error: err.type,
|
|
126
|
+
message: err.expose ? err.message : "\u53D1\u751F\u4E86\u4E00\u4E2A\u9519\u8BEF"
|
|
127
|
+
},
|
|
128
|
+
err.status
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
return json({ error: "internal_error", message: "\u51FA\u73B0\u4E86\u4E00\u4E9B\u95EE\u9898" }, 500);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/server/base-server.ts
|
|
136
|
+
var BaseServer = class {
|
|
137
|
+
globalMiddleware = [];
|
|
138
|
+
use(mw) {
|
|
139
|
+
this.globalMiddleware.push(mw);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 打印扁平化后的路由信息,用于调试
|
|
143
|
+
*/
|
|
144
|
+
logFlattenedRoutes(routes, type = "\u8DEF\u7531") {
|
|
145
|
+
console.log(`\u{1F680} \u6241\u5E73\u5316\u540E\u7684${type}:`);
|
|
146
|
+
for (const route of routes) {
|
|
147
|
+
const method = route.method || "GET";
|
|
148
|
+
const path = route.fullPath || route.path;
|
|
149
|
+
console.log(` ${method} ${path}`);
|
|
150
|
+
if (route.middlewareChain && route.middlewareChain.length > 0) {
|
|
151
|
+
console.log(` \u4E2D\u95F4\u4EF6\u94FE: ${route.middlewareChain.length} \u4E2A`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
console.log("");
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 检测路由冲突
|
|
158
|
+
* 检查是否有路径相同但方法不同的路由,以及潜在的路径冲突
|
|
159
|
+
*/
|
|
160
|
+
detectRouteConflicts(routes) {
|
|
161
|
+
const pathGroups = /* @__PURE__ */ new Map();
|
|
162
|
+
for (const route of routes) {
|
|
163
|
+
const path = route.fullPath || route.path;
|
|
164
|
+
const method = route.method || "GET";
|
|
165
|
+
if (!pathGroups.has(path)) {
|
|
166
|
+
pathGroups.set(path, []);
|
|
167
|
+
}
|
|
168
|
+
pathGroups.get(path).push({ ...route, method });
|
|
39
169
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
for (const route of flattened) {
|
|
54
|
-
this.router.register(route.method, route.fullPath, route.handler, route.middlewareChain || []);
|
|
170
|
+
for (const [path, routeList] of pathGroups) {
|
|
171
|
+
if (routeList.length > 1) {
|
|
172
|
+
const methods = routeList.map((r) => r.method);
|
|
173
|
+
const uniqueMethods = [...new Set(methods)];
|
|
174
|
+
if (uniqueMethods.length === 1) {
|
|
175
|
+
console.warn(
|
|
176
|
+
`\u26A0\uFE0F \u8DEF\u7531\u51B2\u7A81: ${uniqueMethods[0]} ${path} \u5B9A\u4E49\u4E86 ${routeList.length} \u6B21`
|
|
177
|
+
);
|
|
178
|
+
routeList.forEach((route, index) => {
|
|
179
|
+
console.warn(` ${index + 1}. ${route.method} ${path}`);
|
|
180
|
+
});
|
|
181
|
+
} else {
|
|
182
|
+
console.log(`\u2139\uFE0F \u8DEF\u5F84 ${path} \u652F\u6301\u65B9\u6CD5: ${uniqueMethods.join(", ")}`);
|
|
55
183
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
this.detectDynamicRouteConflicts(routes);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* 检测动态路由的潜在冲突
|
|
190
|
+
*/
|
|
191
|
+
detectDynamicRouteConflicts(routes) {
|
|
192
|
+
const dynamicRoutes = routes.filter((r) => {
|
|
193
|
+
const path = r.fullPath || r.path;
|
|
194
|
+
return path.includes(":") || path.includes("*");
|
|
195
|
+
});
|
|
196
|
+
for (let i = 0; i < dynamicRoutes.length; i++) {
|
|
197
|
+
for (let j = i + 1; j < dynamicRoutes.length; j++) {
|
|
198
|
+
const route1 = dynamicRoutes[i];
|
|
199
|
+
const route2 = dynamicRoutes[j];
|
|
200
|
+
const method1 = route1.method || "GET";
|
|
201
|
+
const method2 = route2.method || "GET";
|
|
202
|
+
if (method1 === method2) {
|
|
203
|
+
const path1 = route1.fullPath || route1.path;
|
|
204
|
+
const path2 = route2.fullPath || route2.path;
|
|
205
|
+
if (this.pathsMayConflict(path1, path2)) {
|
|
206
|
+
console.warn(
|
|
207
|
+
`\u26A0\uFE0F \u6F5C\u5728\u8DEF\u7531\u51B2\u7A81: ${method1} ${path1} \u53EF\u80FD\u4E0E ${path2} \u51B2\u7A81`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
61
210
|
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* 判断两个路径是否可能冲突
|
|
216
|
+
*/
|
|
217
|
+
pathsMayConflict(path1, path2) {
|
|
218
|
+
const parts1 = path1.split("/").filter(Boolean);
|
|
219
|
+
const parts2 = path2.split("/").filter(Boolean);
|
|
220
|
+
if (parts1.length !== parts2.length) return false;
|
|
221
|
+
for (let i = 0; i < parts1.length; i++) {
|
|
222
|
+
const p1 = parts1[i];
|
|
223
|
+
const p2 = parts2[i];
|
|
224
|
+
if (!p1.startsWith(":") && !p1.startsWith("*") && !p2.startsWith(":") && !p2.startsWith("*") && p1 !== p2) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
if (p1 === "*" && p2.startsWith(":") || p2 === "*" && p1.startsWith(":")) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* 路径匹配
|
|
235
|
+
*/
|
|
236
|
+
matchPath(pattern, path) {
|
|
237
|
+
const patternParts = pattern.split("/").filter(Boolean);
|
|
238
|
+
const pathParts = path.split("/").filter(Boolean);
|
|
239
|
+
if (patternParts.length !== pathParts.length) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
243
|
+
if (patternParts[i] !== pathParts[i] && !patternParts[i].startsWith(":")) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* 提取路径参数
|
|
251
|
+
*/
|
|
252
|
+
extractParams(pattern, path) {
|
|
253
|
+
const params = {};
|
|
254
|
+
const patternParts = pattern.split("/").filter(Boolean);
|
|
255
|
+
const pathParts = path.split("/").filter(Boolean);
|
|
256
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
257
|
+
if (patternParts[i].startsWith(":")) {
|
|
258
|
+
const paramName = patternParts[i].slice(1);
|
|
259
|
+
params[paramName] = pathParts[i];
|
|
260
|
+
}
|
|
62
261
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
262
|
+
return params;
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// src/router/radix-tree.ts
|
|
267
|
+
var RadixRouter = class {
|
|
268
|
+
root;
|
|
269
|
+
constructor() {
|
|
270
|
+
this.root = this.createNode("");
|
|
271
|
+
}
|
|
272
|
+
createNode(path) {
|
|
273
|
+
return {
|
|
274
|
+
path,
|
|
275
|
+
children: /* @__PURE__ */ Object.create(null),
|
|
276
|
+
handlers: /* @__PURE__ */ Object.create(null)
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
/** 分割路径 */
|
|
280
|
+
splitPath(path) {
|
|
281
|
+
return path.split("/").filter(Boolean);
|
|
282
|
+
}
|
|
283
|
+
/** 编译器函数 - 用于预编译中间件链 */
|
|
284
|
+
compiler;
|
|
285
|
+
/** 设置中间件编译器 */
|
|
286
|
+
setCompiler(compiler) {
|
|
287
|
+
this.compiler = compiler;
|
|
288
|
+
}
|
|
289
|
+
/** 注册路由 */
|
|
290
|
+
register(method, pattern, handler, middleware = []) {
|
|
291
|
+
const segments = this.splitPath(pattern);
|
|
292
|
+
let node = this.root;
|
|
293
|
+
for (const segment of segments) {
|
|
294
|
+
const firstChar = segment[0];
|
|
295
|
+
if (firstChar === ":") {
|
|
296
|
+
if (!node.paramChild) {
|
|
297
|
+
node.paramChild = this.createNode(segment);
|
|
298
|
+
node.paramChild.paramName = segment.substring(1);
|
|
299
|
+
}
|
|
300
|
+
node = node.paramChild;
|
|
301
|
+
} else if (firstChar === "*") {
|
|
302
|
+
if (!node.wildcardChild) {
|
|
303
|
+
node.wildcardChild = this.createNode(segment);
|
|
304
|
+
node.wildcardChild.paramName = segment.length > 1 ? segment.substring(1) : "*";
|
|
93
305
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
error: "Method Not Allowed",
|
|
100
|
-
message: `Method ${method} not allowed for this endpoint`,
|
|
101
|
-
allowedMethods,
|
|
102
|
-
}, 405, { Allow: allowedMethods.join(", ") });
|
|
306
|
+
node = node.wildcardChild;
|
|
307
|
+
break;
|
|
308
|
+
} else {
|
|
309
|
+
if (!node.children[segment]) {
|
|
310
|
+
node.children[segment] = this.createNode(segment);
|
|
103
311
|
}
|
|
104
|
-
|
|
105
|
-
|
|
312
|
+
node = node.children[segment];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const routeHandler = { handler, middleware };
|
|
316
|
+
if (this.compiler && middleware.length === 0) {
|
|
317
|
+
routeHandler.compiled = this.compiler([], handler);
|
|
318
|
+
}
|
|
319
|
+
node.handlers[method] = routeHandler;
|
|
320
|
+
}
|
|
321
|
+
/** 预编译所有路由(在添加全局中间件后调用) */
|
|
322
|
+
precompileAll(globalMiddleware) {
|
|
323
|
+
if (!this.compiler) return;
|
|
324
|
+
this.precompileNode(this.root, globalMiddleware);
|
|
325
|
+
}
|
|
326
|
+
precompileNode(node, globalMiddleware) {
|
|
327
|
+
for (const method in node.handlers) {
|
|
328
|
+
const routeHandler = node.handlers[method];
|
|
329
|
+
if (routeHandler) {
|
|
330
|
+
const allMiddleware = [...globalMiddleware, ...routeHandler.middleware];
|
|
331
|
+
routeHandler.compiled = this.compiler(
|
|
332
|
+
allMiddleware,
|
|
333
|
+
routeHandler.handler
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
for (const key in node.children) {
|
|
338
|
+
this.precompileNode(node.children[key], globalMiddleware);
|
|
339
|
+
}
|
|
340
|
+
if (node.paramChild) {
|
|
341
|
+
this.precompileNode(node.paramChild, globalMiddleware);
|
|
342
|
+
}
|
|
343
|
+
if (node.wildcardChild) {
|
|
344
|
+
this.precompileNode(node.wildcardChild, globalMiddleware);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
/** 匹配路由 */
|
|
348
|
+
match(method, path) {
|
|
349
|
+
const segments = this.splitPath(path);
|
|
350
|
+
const params = /* @__PURE__ */ Object.create(null);
|
|
351
|
+
const node = this.matchNode(this.root, segments, 0, params);
|
|
352
|
+
if (!node) return null;
|
|
353
|
+
const routeHandler = node.handlers[method];
|
|
354
|
+
if (!routeHandler) return null;
|
|
355
|
+
return {
|
|
356
|
+
handler: routeHandler.handler,
|
|
357
|
+
middleware: routeHandler.middleware,
|
|
358
|
+
params,
|
|
359
|
+
compiled: routeHandler.compiled
|
|
106
360
|
};
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
361
|
+
}
|
|
362
|
+
/** 递归匹配节点 (优先级: 静态 > 动态参数 > 通配符) */
|
|
363
|
+
matchNode(node, segments, index, params) {
|
|
364
|
+
if (index === segments.length) {
|
|
365
|
+
for (const method in node.handlers) {
|
|
366
|
+
if (node.handlers[method]) return node;
|
|
367
|
+
}
|
|
368
|
+
return null;
|
|
115
369
|
}
|
|
116
|
-
|
|
117
|
-
|
|
370
|
+
const segment = segments[index];
|
|
371
|
+
const staticChild = node.children[segment];
|
|
372
|
+
if (staticChild) {
|
|
373
|
+
const result = this.matchNode(staticChild, segments, index + 1, params);
|
|
374
|
+
if (result) return result;
|
|
118
375
|
}
|
|
119
|
-
|
|
120
|
-
|
|
376
|
+
if (node.paramChild) {
|
|
377
|
+
const paramName = node.paramChild.paramName;
|
|
378
|
+
const oldValue = params[paramName];
|
|
379
|
+
params[paramName] = segment;
|
|
380
|
+
const result = this.matchNode(
|
|
381
|
+
node.paramChild,
|
|
382
|
+
segments,
|
|
383
|
+
index + 1,
|
|
384
|
+
params
|
|
385
|
+
);
|
|
386
|
+
if (result) return result;
|
|
387
|
+
if (oldValue === void 0) {
|
|
388
|
+
delete params[paramName];
|
|
389
|
+
} else {
|
|
390
|
+
params[paramName] = oldValue;
|
|
391
|
+
}
|
|
121
392
|
}
|
|
122
|
-
|
|
393
|
+
if (node.wildcardChild) {
|
|
394
|
+
params[node.wildcardChild.paramName || "*"] = segments.slice(index).join("/");
|
|
395
|
+
return node.wildcardChild;
|
|
396
|
+
}
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
/** 获取路径允许的 HTTP 方法 */
|
|
400
|
+
getAllowedMethods(path) {
|
|
401
|
+
const segments = this.splitPath(path);
|
|
402
|
+
const node = this.findNode(segments);
|
|
403
|
+
if (!node) return [];
|
|
404
|
+
const methods = [];
|
|
405
|
+
for (const method in node.handlers) {
|
|
406
|
+
if (node.handlers[method]) {
|
|
407
|
+
methods.push(method);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return methods;
|
|
411
|
+
}
|
|
412
|
+
/** 查找节点(不提取参数) */
|
|
413
|
+
findNode(segments) {
|
|
414
|
+
let node = this.root;
|
|
415
|
+
for (const segment of segments) {
|
|
416
|
+
if (node.children[segment]) {
|
|
417
|
+
node = node.children[segment];
|
|
418
|
+
} else if (node.paramChild) {
|
|
419
|
+
node = node.paramChild;
|
|
420
|
+
} else if (node.wildcardChild) {
|
|
421
|
+
return node.wildcardChild;
|
|
422
|
+
} else {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return node;
|
|
427
|
+
}
|
|
428
|
+
/** 获取所有已注册的路由 */
|
|
429
|
+
getRoutes() {
|
|
430
|
+
const routes = [];
|
|
431
|
+
this.collectRoutes(this.root, "", routes);
|
|
432
|
+
return routes;
|
|
433
|
+
}
|
|
434
|
+
collectRoutes(node, prefix, routes) {
|
|
435
|
+
const currentPath = prefix + (node.path ? "/" + node.path : "");
|
|
436
|
+
for (const method in node.handlers) {
|
|
437
|
+
if (node.handlers[method]) {
|
|
438
|
+
routes.push({ method, path: currentPath || "/" });
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
for (const key in node.children) {
|
|
442
|
+
this.collectRoutes(node.children[key], currentPath, routes);
|
|
443
|
+
}
|
|
444
|
+
if (node.paramChild) {
|
|
445
|
+
this.collectRoutes(node.paramChild, currentPath, routes);
|
|
446
|
+
}
|
|
447
|
+
if (node.wildcardChild) {
|
|
448
|
+
this.collectRoutes(node.wildcardChild, currentPath, routes);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
// src/server/server.ts
|
|
454
|
+
var Server = class extends BaseServer {
|
|
455
|
+
router;
|
|
456
|
+
routes;
|
|
457
|
+
/** 是否已预编译 */
|
|
458
|
+
isCompiled = false;
|
|
459
|
+
/** 预编译时的全局中间件数量 */
|
|
460
|
+
compiledWithMiddlewareCount = 0;
|
|
461
|
+
constructor(routes = []) {
|
|
462
|
+
super();
|
|
463
|
+
this.router = new RadixRouter();
|
|
464
|
+
this.routes = [];
|
|
465
|
+
this.router.setCompiler(
|
|
466
|
+
(middleware, handler) => composeMiddleware(middleware, handler)
|
|
467
|
+
);
|
|
468
|
+
if (routes.length > 0) {
|
|
469
|
+
this.registerRoutes(routes);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* 预编译所有路由处理链
|
|
474
|
+
* 在添加所有路由和全局中间件后调用,可提升运行时性能
|
|
475
|
+
*/
|
|
476
|
+
compile() {
|
|
477
|
+
this.router.precompileAll(this.globalMiddleware);
|
|
478
|
+
this.isCompiled = true;
|
|
479
|
+
this.compiledWithMiddlewareCount = this.globalMiddleware.length;
|
|
480
|
+
return this;
|
|
481
|
+
}
|
|
482
|
+
registerRoutes(routes) {
|
|
483
|
+
const flattened = flattenNestedRoutes(routes);
|
|
484
|
+
this.routes.push(...flattened);
|
|
485
|
+
for (const route of flattened) {
|
|
486
|
+
this.router.register(
|
|
487
|
+
route.method,
|
|
488
|
+
route.fullPath,
|
|
489
|
+
route.handler,
|
|
490
|
+
route.middlewareChain || []
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
this.detectRouteConflicts(flattened);
|
|
494
|
+
this.logFlattenedRoutes(flattened);
|
|
495
|
+
if (this.globalMiddleware.length === 0 && !this.isCompiled) {
|
|
496
|
+
this.compile();
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
/** 快速提取 pathname */
|
|
500
|
+
extractPathname(url) {
|
|
501
|
+
let start = url.indexOf("://");
|
|
502
|
+
start = start === -1 ? 0 : start + 3;
|
|
503
|
+
const pathStart = url.indexOf("/", start);
|
|
504
|
+
if (pathStart === -1) return "/";
|
|
505
|
+
let end = url.indexOf("?", pathStart);
|
|
506
|
+
if (end === -1) end = url.indexOf("#", pathStart);
|
|
507
|
+
if (end === -1) end = url.length;
|
|
508
|
+
return url.substring(pathStart, end) || "/";
|
|
509
|
+
}
|
|
510
|
+
/** 处理请求 */
|
|
511
|
+
fetch = async (req) => {
|
|
512
|
+
const pathname = this.extractPathname(req.url);
|
|
513
|
+
const method = req.method;
|
|
514
|
+
const match = this.router.match(method, pathname);
|
|
515
|
+
if (match) {
|
|
516
|
+
req.params = match.params;
|
|
517
|
+
if (match.compiled && this.globalMiddleware.length === this.compiledWithMiddlewareCount) {
|
|
518
|
+
return match.compiled(req);
|
|
519
|
+
}
|
|
520
|
+
const allMiddleware = [...this.globalMiddleware, ...match.middleware];
|
|
521
|
+
const handler = composeMiddleware(allMiddleware, match.handler);
|
|
522
|
+
return handler(req);
|
|
523
|
+
}
|
|
524
|
+
const allowedMethods = this.router.getAllowedMethods(pathname);
|
|
525
|
+
if (allowedMethods.length > 0) {
|
|
526
|
+
return json(
|
|
527
|
+
{
|
|
528
|
+
success: false,
|
|
529
|
+
error: "Method Not Allowed",
|
|
530
|
+
message: `Method ${method} not allowed for this endpoint`,
|
|
531
|
+
allowedMethods
|
|
532
|
+
},
|
|
533
|
+
405,
|
|
534
|
+
{ Allow: allowedMethods.join(", ") }
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
return json({ success: false, error: "Not Found" }, 404);
|
|
538
|
+
};
|
|
539
|
+
addRoute(route) {
|
|
540
|
+
const flattenedRoute = {
|
|
541
|
+
...route,
|
|
542
|
+
fullPath: route.path,
|
|
543
|
+
middlewareChain: route.middleware || []
|
|
544
|
+
};
|
|
545
|
+
this.routes.push(flattenedRoute);
|
|
546
|
+
this.router.register(
|
|
547
|
+
route.method,
|
|
548
|
+
route.path,
|
|
549
|
+
route.handler,
|
|
550
|
+
route.middleware || []
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
addRoutes(routes) {
|
|
554
|
+
this.registerRoutes(routes);
|
|
555
|
+
}
|
|
556
|
+
getRoutes() {
|
|
557
|
+
return this.router.getRoutes();
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
export {
|
|
561
|
+
Server
|
|
562
|
+
};
|
|
563
|
+
//# sourceMappingURL=server.js.map
|