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,33 @@
|
|
|
1
|
+
// src/middleware/rateLimit.ts
|
|
2
|
+
import { VafastError } from "../middleware";
|
|
3
|
+
const store = new Map();
|
|
4
|
+
export function rateLimit(options = {}) {
|
|
5
|
+
const windowMs = options.windowMs ?? 60_000; // 默认: 1分钟
|
|
6
|
+
const max = options.max ?? 30;
|
|
7
|
+
const keyFn = options.keyFn ?? getIP;
|
|
8
|
+
return async (req, next) => {
|
|
9
|
+
const key = keyFn(req);
|
|
10
|
+
const now = Date.now();
|
|
11
|
+
const entry = store.get(key);
|
|
12
|
+
if (entry && entry.expires > now) {
|
|
13
|
+
if (entry.count >= max) {
|
|
14
|
+
throw new VafastError("Too many requests", {
|
|
15
|
+
status: 429,
|
|
16
|
+
type: "rate_limit",
|
|
17
|
+
expose: true,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
entry.count += 1;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
store.set(key, { count: 1, expires: now + windowMs });
|
|
24
|
+
}
|
|
25
|
+
return next();
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
// Edge 安全的 IP 获取
|
|
29
|
+
function getIP(req) {
|
|
30
|
+
return (req.headers.get("cf-connecting-ip") || // Cloudflare
|
|
31
|
+
req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || // Vercel
|
|
32
|
+
"unknown");
|
|
33
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Handler, Middleware } from "./types";
|
|
2
|
+
/** 中间件类型:使用 next() 传递给下一个处理 */
|
|
3
|
+
/** Vafast 自定义错误类型 */
|
|
4
|
+
export declare class VafastError extends Error {
|
|
5
|
+
status: number;
|
|
6
|
+
type: string;
|
|
7
|
+
expose: boolean;
|
|
8
|
+
constructor(message: string, options?: {
|
|
9
|
+
status?: number;
|
|
10
|
+
type?: string;
|
|
11
|
+
expose?: boolean;
|
|
12
|
+
cause?: unknown;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 组合类型: 自动注入错误处理器进行中间件组合
|
|
17
|
+
*/
|
|
18
|
+
export declare function composeMiddleware(middleware: Middleware[], finalHandler: Handler): Handler;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/middleware.ts
|
|
2
|
+
import { json } from "./utils/response";
|
|
3
|
+
/** 中间件类型:使用 next() 传递给下一个处理 */
|
|
4
|
+
/** Vafast 自定义错误类型 */
|
|
5
|
+
export class VafastError extends Error {
|
|
6
|
+
status;
|
|
7
|
+
type;
|
|
8
|
+
expose;
|
|
9
|
+
constructor(message, options = {}) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "VafastError";
|
|
12
|
+
this.status = options.status ?? 500;
|
|
13
|
+
this.type = options.type ?? "internal_error";
|
|
14
|
+
this.expose = options.expose ?? false;
|
|
15
|
+
if (options.cause)
|
|
16
|
+
this.cause = options.cause;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 组合类型: 自动注入错误处理器进行中间件组合
|
|
21
|
+
*/
|
|
22
|
+
export function composeMiddleware(middleware, finalHandler) {
|
|
23
|
+
const all = [errorHandler, ...middleware];
|
|
24
|
+
return function composedHandler(req) {
|
|
25
|
+
let i = -1;
|
|
26
|
+
const dispatch = (index) => {
|
|
27
|
+
if (index <= i)
|
|
28
|
+
return Promise.reject(new Error("next() called multiple times"));
|
|
29
|
+
i = index;
|
|
30
|
+
const fn = index < all.length ? all[index] : finalHandler;
|
|
31
|
+
return Promise.resolve(fn(req, (() => dispatch(index + 1))));
|
|
32
|
+
};
|
|
33
|
+
return dispatch(0);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** 默认包含的全局错误处理器 */
|
|
37
|
+
const errorHandler = async (req, next) => {
|
|
38
|
+
try {
|
|
39
|
+
return await next();
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
console.error("未处理的错误:", err);
|
|
43
|
+
if (err instanceof VafastError) {
|
|
44
|
+
return json({
|
|
45
|
+
error: err.type,
|
|
46
|
+
message: err.expose ? err.message : "发生了一个错误",
|
|
47
|
+
}, err.status);
|
|
48
|
+
}
|
|
49
|
+
return json({ error: "internal_error", message: "出现了一些问题" }, 500);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 原生监控系统入口
|
|
3
|
+
*
|
|
4
|
+
* @author Framework Team
|
|
5
|
+
* @version 2.0.0
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
export * from "./types";
|
|
9
|
+
export * from "./native-monitor";
|
|
10
|
+
export declare const defaultMonitoringConfig: {
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
console: boolean;
|
|
13
|
+
slowThreshold: number;
|
|
14
|
+
errorThreshold: number;
|
|
15
|
+
tags: {
|
|
16
|
+
framework: string;
|
|
17
|
+
version: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export declare function createMonitoringConfig(config?: Partial<typeof defaultMonitoringConfig>): {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
console: boolean;
|
|
23
|
+
slowThreshold: number;
|
|
24
|
+
errorThreshold: number;
|
|
25
|
+
tags: {
|
|
26
|
+
framework: string;
|
|
27
|
+
version: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 原生监控系统入口
|
|
3
|
+
*
|
|
4
|
+
* @author Framework Team
|
|
5
|
+
* @version 2.0.0
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
export * from "./types";
|
|
9
|
+
export * from "./native-monitor";
|
|
10
|
+
// 默认监控配置
|
|
11
|
+
export const defaultMonitoringConfig = {
|
|
12
|
+
enabled: true,
|
|
13
|
+
console: true,
|
|
14
|
+
slowThreshold: 1000, // 1秒
|
|
15
|
+
errorThreshold: 0.05, // 5%
|
|
16
|
+
tags: {
|
|
17
|
+
framework: "vafast",
|
|
18
|
+
version: "2.0.0",
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
// 创建监控配置
|
|
22
|
+
export function createMonitoringConfig(config = {}) {
|
|
23
|
+
return { ...defaultMonitoringConfig, ...config };
|
|
24
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 原生监控装饰器
|
|
3
|
+
*
|
|
4
|
+
* 通过装饰器模式为 Server 添加监控能力,完全不入侵原类
|
|
5
|
+
*
|
|
6
|
+
* @author Framework Team
|
|
7
|
+
* @version 2.0.0
|
|
8
|
+
* @license MIT
|
|
9
|
+
*/
|
|
10
|
+
import type { Server } from "../server";
|
|
11
|
+
export interface NativeMonitoringConfig {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
console?: boolean;
|
|
14
|
+
slowThreshold?: number;
|
|
15
|
+
errorThreshold?: number;
|
|
16
|
+
tags?: Record<string, string>;
|
|
17
|
+
}
|
|
18
|
+
export interface NativeMonitoringMetrics {
|
|
19
|
+
requestId: string;
|
|
20
|
+
method: string;
|
|
21
|
+
path: string;
|
|
22
|
+
statusCode: number;
|
|
23
|
+
totalTime: number;
|
|
24
|
+
timestamp: number;
|
|
25
|
+
memoryUsage: {
|
|
26
|
+
heapUsed: number;
|
|
27
|
+
heapTotal: number;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export interface MonitoredServer extends Server {
|
|
31
|
+
getMonitoringStatus(): any;
|
|
32
|
+
getMonitoringMetrics(): NativeMonitoringMetrics[];
|
|
33
|
+
resetMonitoring(): void;
|
|
34
|
+
fetch: (req: Request) => Promise<Response>;
|
|
35
|
+
use: (mw: any) => void;
|
|
36
|
+
}
|
|
37
|
+
export declare function withMonitoring(server: Server, config?: NativeMonitoringConfig): MonitoredServer;
|
|
38
|
+
export declare function createMonitoredServer(routes: any[], config?: NativeMonitoringConfig): MonitoredServer;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 原生监控装饰器
|
|
3
|
+
*
|
|
4
|
+
* 通过装饰器模式为 Server 添加监控能力,完全不入侵原类
|
|
5
|
+
*
|
|
6
|
+
* @author Framework Team
|
|
7
|
+
* @version 2.0.0
|
|
8
|
+
* @license MIT
|
|
9
|
+
*/
|
|
10
|
+
// 原生监控器
|
|
11
|
+
class NativeMonitor {
|
|
12
|
+
config;
|
|
13
|
+
metrics = [];
|
|
14
|
+
isEnabled = false;
|
|
15
|
+
constructor(config = {}) {
|
|
16
|
+
this.config = {
|
|
17
|
+
enabled: true,
|
|
18
|
+
console: true,
|
|
19
|
+
slowThreshold: 1000,
|
|
20
|
+
errorThreshold: 0.05,
|
|
21
|
+
tags: { framework: "vafast" },
|
|
22
|
+
...config,
|
|
23
|
+
};
|
|
24
|
+
this.isEnabled = this.config.enabled ?? true;
|
|
25
|
+
if (this.isEnabled && this.config.console) {
|
|
26
|
+
console.log("✅ 原生监控已启用");
|
|
27
|
+
console.log(`📊 监控配置:`, {
|
|
28
|
+
慢请求阈值: `${this.config.slowThreshold}ms`,
|
|
29
|
+
错误率阈值: `${(this.config.errorThreshold * 100).toFixed(1)}%`,
|
|
30
|
+
标签: this.config.tags,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// 记录监控指标
|
|
35
|
+
recordMetrics(metrics) {
|
|
36
|
+
if (!this.isEnabled)
|
|
37
|
+
return;
|
|
38
|
+
this.metrics.push(metrics);
|
|
39
|
+
// 保持最近1000条记录
|
|
40
|
+
if (this.metrics.length > 1000) {
|
|
41
|
+
this.metrics = this.metrics.slice(-1000);
|
|
42
|
+
}
|
|
43
|
+
// 控制台输出
|
|
44
|
+
if (this.config.console) {
|
|
45
|
+
const status = metrics.statusCode < 400 ? "✅" : "❌";
|
|
46
|
+
const timeColor = metrics.totalTime > this.config.slowThreshold ? "🐌" : "⚡";
|
|
47
|
+
console.log(`${status} ${metrics.method} ${metrics.path} - ${metrics.statusCode} (${timeColor} ${metrics.totalTime.toFixed(2)}ms)`);
|
|
48
|
+
// 慢请求警告
|
|
49
|
+
if (metrics.totalTime > this.config.slowThreshold) {
|
|
50
|
+
console.warn(`🐌 慢请求警告: ${metrics.path} 耗时 ${metrics.totalTime.toFixed(2)}ms`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// 获取监控状态
|
|
55
|
+
getStatus() {
|
|
56
|
+
if (!this.isEnabled) {
|
|
57
|
+
return { enabled: false, message: "监控未启用" };
|
|
58
|
+
}
|
|
59
|
+
const totalRequests = this.metrics.length;
|
|
60
|
+
const successfulRequests = this.metrics.filter((m) => m.statusCode < 400).length;
|
|
61
|
+
const failedRequests = totalRequests - successfulRequests;
|
|
62
|
+
const avgResponseTime = totalRequests > 0
|
|
63
|
+
? this.metrics.reduce((sum, m) => sum + m.totalTime, 0) / totalRequests
|
|
64
|
+
: 0;
|
|
65
|
+
return {
|
|
66
|
+
enabled: true,
|
|
67
|
+
totalRequests,
|
|
68
|
+
successfulRequests,
|
|
69
|
+
failedRequests,
|
|
70
|
+
errorRate: totalRequests > 0 ? failedRequests / totalRequests : 0,
|
|
71
|
+
avgResponseTime: avgResponseTime.toFixed(2) + "ms",
|
|
72
|
+
memoryUsage: this.getMemoryUsage(),
|
|
73
|
+
recentRequests: this.metrics.slice(-5),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// 获取监控指标
|
|
77
|
+
getMetrics() {
|
|
78
|
+
return this.metrics;
|
|
79
|
+
}
|
|
80
|
+
// 重置监控数据
|
|
81
|
+
reset() {
|
|
82
|
+
this.metrics = [];
|
|
83
|
+
console.log("🔄 监控数据已重置");
|
|
84
|
+
}
|
|
85
|
+
// 获取内存使用情况
|
|
86
|
+
getMemoryUsage() {
|
|
87
|
+
if (typeof process !== "undefined" && process.memoryUsage) {
|
|
88
|
+
const mem = process.memoryUsage();
|
|
89
|
+
return {
|
|
90
|
+
heapUsed: (mem.heapUsed / 1024 / 1024).toFixed(2) + "MB",
|
|
91
|
+
heapTotal: (mem.heapTotal / 1024 / 1024).toFixed(2) + "MB",
|
|
92
|
+
external: (mem.external / 1024 / 1024).toFixed(2) + "MB",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return { message: "内存信息不可用" };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// 纯函数:为 Server 添加监控能力
|
|
99
|
+
export function withMonitoring(server, config = {}) {
|
|
100
|
+
const monitor = new NativeMonitor(config);
|
|
101
|
+
// 保存原始的 fetch 方法
|
|
102
|
+
const originalFetch = server.fetch.bind(server);
|
|
103
|
+
// 创建带监控的 fetch 方法
|
|
104
|
+
const monitoredFetch = async (req) => {
|
|
105
|
+
const startTime = performance.now();
|
|
106
|
+
const requestId = `req_${Date.now()}_${Math.random()
|
|
107
|
+
.toString(36)
|
|
108
|
+
.substr(2, 9)}`;
|
|
109
|
+
const { pathname } = new URL(req.url);
|
|
110
|
+
const method = req.method;
|
|
111
|
+
try {
|
|
112
|
+
// 调用原始 fetch
|
|
113
|
+
const response = await originalFetch(req);
|
|
114
|
+
// 记录监控指标
|
|
115
|
+
const totalTime = performance.now() - startTime;
|
|
116
|
+
monitor.recordMetrics({
|
|
117
|
+
requestId,
|
|
118
|
+
method,
|
|
119
|
+
path: pathname,
|
|
120
|
+
statusCode: response.status,
|
|
121
|
+
totalTime,
|
|
122
|
+
timestamp: Date.now(),
|
|
123
|
+
memoryUsage: (() => {
|
|
124
|
+
if (typeof process !== "undefined" && process.memoryUsage) {
|
|
125
|
+
const mem = process.memoryUsage();
|
|
126
|
+
return {
|
|
127
|
+
heapUsed: mem.heapUsed,
|
|
128
|
+
heapTotal: mem.heapTotal,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return { heapUsed: 0, heapTotal: 0 };
|
|
132
|
+
})(),
|
|
133
|
+
});
|
|
134
|
+
return response;
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
// 记录错误监控指标
|
|
138
|
+
const totalTime = performance.now() - startTime;
|
|
139
|
+
monitor.recordMetrics({
|
|
140
|
+
requestId,
|
|
141
|
+
method,
|
|
142
|
+
path: pathname,
|
|
143
|
+
statusCode: 500,
|
|
144
|
+
totalTime,
|
|
145
|
+
timestamp: Date.now(),
|
|
146
|
+
memoryUsage: (() => {
|
|
147
|
+
if (typeof process !== "undefined" && process.memoryUsage) {
|
|
148
|
+
const mem = process.memoryUsage();
|
|
149
|
+
return {
|
|
150
|
+
heapUsed: mem.heapUsed,
|
|
151
|
+
heapTotal: mem.heapTotal,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return { heapUsed: 0, heapTotal: 0 };
|
|
155
|
+
})(),
|
|
156
|
+
});
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
// 创建带监控的 Server 对象
|
|
161
|
+
const monitoredServer = {
|
|
162
|
+
...server,
|
|
163
|
+
fetch: monitoredFetch,
|
|
164
|
+
// 监控方法
|
|
165
|
+
getMonitoringStatus: () => monitor.getStatus(),
|
|
166
|
+
getMonitoringMetrics: () => monitor.getMetrics(),
|
|
167
|
+
resetMonitoring: () => monitor.reset(),
|
|
168
|
+
};
|
|
169
|
+
return monitoredServer;
|
|
170
|
+
}
|
|
171
|
+
// 便捷函数:创建带监控的 Server
|
|
172
|
+
export function createMonitoredServer(routes, config) {
|
|
173
|
+
const { Server } = require("../server");
|
|
174
|
+
const server = new Server(routes);
|
|
175
|
+
return withMonitoring(server, config);
|
|
176
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 性能监控系统类型定义
|
|
3
|
+
*
|
|
4
|
+
* @author Framework Team
|
|
5
|
+
* @version 1.0.0
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
export interface BaseMetrics {
|
|
9
|
+
timestamp: number;
|
|
10
|
+
requestId: string;
|
|
11
|
+
method: string;
|
|
12
|
+
path: string;
|
|
13
|
+
statusCode: number;
|
|
14
|
+
userAgent?: string;
|
|
15
|
+
ip?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface PerformanceMetrics extends BaseMetrics {
|
|
18
|
+
totalTime: number;
|
|
19
|
+
routeMatchTime: number;
|
|
20
|
+
validationTime: number;
|
|
21
|
+
handlerTime: number;
|
|
22
|
+
responseTime: number;
|
|
23
|
+
memoryUsage: {
|
|
24
|
+
heapUsed: number;
|
|
25
|
+
heapTotal: number;
|
|
26
|
+
external: number;
|
|
27
|
+
rss: number;
|
|
28
|
+
};
|
|
29
|
+
validation: {
|
|
30
|
+
bodyValidated: boolean;
|
|
31
|
+
queryValidated: boolean;
|
|
32
|
+
paramsValidated: boolean;
|
|
33
|
+
headersValidated: boolean;
|
|
34
|
+
cookiesValidated: boolean;
|
|
35
|
+
validationErrors: number;
|
|
36
|
+
};
|
|
37
|
+
routing: {
|
|
38
|
+
routeFound: boolean;
|
|
39
|
+
middlewareCount: number;
|
|
40
|
+
dynamicParams: number;
|
|
41
|
+
};
|
|
42
|
+
error?: {
|
|
43
|
+
type: string;
|
|
44
|
+
message: string;
|
|
45
|
+
stack?: string;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export interface AggregatedMetrics {
|
|
49
|
+
timeRange: {
|
|
50
|
+
start: number;
|
|
51
|
+
end: number;
|
|
52
|
+
};
|
|
53
|
+
requests: {
|
|
54
|
+
total: number;
|
|
55
|
+
successful: number;
|
|
56
|
+
failed: number;
|
|
57
|
+
byMethod: Record<string, number>;
|
|
58
|
+
byPath: Record<string, number>;
|
|
59
|
+
byStatusCode: Record<number, number>;
|
|
60
|
+
};
|
|
61
|
+
performance: {
|
|
62
|
+
avgTotalTime: number;
|
|
63
|
+
avgRouteMatchTime: number;
|
|
64
|
+
avgValidationTime: number;
|
|
65
|
+
avgHandlerTime: number;
|
|
66
|
+
avgResponseTime: number;
|
|
67
|
+
p50TotalTime: number;
|
|
68
|
+
p90TotalTime: number;
|
|
69
|
+
p95TotalTime: number;
|
|
70
|
+
p99TotalTime: number;
|
|
71
|
+
minTotalTime: number;
|
|
72
|
+
maxTotalTime: number;
|
|
73
|
+
};
|
|
74
|
+
memory: {
|
|
75
|
+
avgHeapUsed: number;
|
|
76
|
+
avgHeapTotal: number;
|
|
77
|
+
maxHeapUsed: number;
|
|
78
|
+
maxHeapTotal: number;
|
|
79
|
+
};
|
|
80
|
+
validation: {
|
|
81
|
+
totalValidations: number;
|
|
82
|
+
validationErrors: number;
|
|
83
|
+
validationSuccessRate: number;
|
|
84
|
+
};
|
|
85
|
+
routing: {
|
|
86
|
+
totalRoutes: number;
|
|
87
|
+
routesWithMiddleware: number;
|
|
88
|
+
dynamicRoutes: number;
|
|
89
|
+
routeHitCount: Record<string, number>;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export interface MonitoringConfig {
|
|
93
|
+
enabled: boolean;
|
|
94
|
+
retention: {
|
|
95
|
+
maxRecords: number;
|
|
96
|
+
maxAge: number;
|
|
97
|
+
cleanupInterval: number;
|
|
98
|
+
};
|
|
99
|
+
samplingRate: number;
|
|
100
|
+
recordErrors: boolean;
|
|
101
|
+
recordBodySize: boolean;
|
|
102
|
+
recordResponseSize: boolean;
|
|
103
|
+
thresholds: {
|
|
104
|
+
slowRequest: number;
|
|
105
|
+
highMemoryUsage: number;
|
|
106
|
+
errorRate: number;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export interface MonitoringEvent {
|
|
110
|
+
type: 'request_start' | 'request_end' | 'validation_start' | 'validation_end' | 'error';
|
|
111
|
+
timestamp: number;
|
|
112
|
+
requestId: string;
|
|
113
|
+
data: any;
|
|
114
|
+
}
|
|
115
|
+
export interface PerformanceReport {
|
|
116
|
+
id: string;
|
|
117
|
+
timestamp: number;
|
|
118
|
+
timeRange: {
|
|
119
|
+
start: number;
|
|
120
|
+
end: number;
|
|
121
|
+
};
|
|
122
|
+
summary: {
|
|
123
|
+
totalRequests: number;
|
|
124
|
+
avgResponseTime: number;
|
|
125
|
+
errorRate: number;
|
|
126
|
+
memoryUsage: number;
|
|
127
|
+
};
|
|
128
|
+
details: {
|
|
129
|
+
topSlowestRoutes: Array<{
|
|
130
|
+
path: string;
|
|
131
|
+
avgTime: number;
|
|
132
|
+
count: number;
|
|
133
|
+
}>;
|
|
134
|
+
topErrorRoutes: Array<{
|
|
135
|
+
path: string;
|
|
136
|
+
errorCount: number;
|
|
137
|
+
errorRate: number;
|
|
138
|
+
}>;
|
|
139
|
+
memoryTrend: Array<{
|
|
140
|
+
timestamp: number;
|
|
141
|
+
heapUsed: number;
|
|
142
|
+
}>;
|
|
143
|
+
responseTimeDistribution: Record<string, number>;
|
|
144
|
+
};
|
|
145
|
+
recommendations: string[];
|
|
146
|
+
}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Route, NestedRoute, FlattenedRoute } from "./types";
|
|
2
|
+
export interface MatchResult {
|
|
3
|
+
matched: boolean;
|
|
4
|
+
params: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* 扁平化嵌套路由,计算完整路径和中间件链
|
|
8
|
+
*/
|
|
9
|
+
export declare function flattenNestedRoutes(routes: (Route | NestedRoute)[]): FlattenedRoute[];
|
|
10
|
+
/**
|
|
11
|
+
* 标准化路径:去重斜杠、解码URL、处理结尾斜杠
|
|
12
|
+
*/
|
|
13
|
+
export declare function normalizePath(path: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* 匹配函数:支持动态路由和路径标准化
|
|
16
|
+
*/
|
|
17
|
+
export declare function matchPath(pattern: string, path: string): MatchResult;
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 扁平化嵌套路由,计算完整路径和中间件链
|
|
3
|
+
*/
|
|
4
|
+
export function flattenNestedRoutes(routes) {
|
|
5
|
+
const flattened = [];
|
|
6
|
+
function processRoute(route, parentPath = "", parentMiddleware = []) {
|
|
7
|
+
const currentPath = parentPath + route.path;
|
|
8
|
+
const currentMiddleware = [...parentMiddleware, ...(route.middleware || [])];
|
|
9
|
+
if ('method' in route && 'handler' in route) {
|
|
10
|
+
// 这是一个叶子路由(有处理函数)
|
|
11
|
+
flattened.push({
|
|
12
|
+
...route,
|
|
13
|
+
fullPath: currentPath,
|
|
14
|
+
middlewareChain: currentMiddleware
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
else if ('children' in route && route.children) {
|
|
18
|
+
// 这是一个分组路由,处理子路由
|
|
19
|
+
for (const child of route.children) {
|
|
20
|
+
processRoute(child, currentPath, currentMiddleware);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
for (const route of routes) {
|
|
25
|
+
processRoute(route);
|
|
26
|
+
}
|
|
27
|
+
return flattened;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 标准化路径:去重斜杠、解码URL、处理结尾斜杠
|
|
31
|
+
*/
|
|
32
|
+
export function normalizePath(path) {
|
|
33
|
+
// 解码 URL 编码的字符
|
|
34
|
+
let normalized = decodeURIComponent(path);
|
|
35
|
+
// 去重连续的斜杠
|
|
36
|
+
normalized = normalized.replace(/\/+/g, "/");
|
|
37
|
+
// 处理根路径
|
|
38
|
+
if (normalized === "")
|
|
39
|
+
normalized = "/";
|
|
40
|
+
// 去掉结尾斜杠(除非是根路径)
|
|
41
|
+
if (normalized !== "/" && normalized.endsWith("/")) {
|
|
42
|
+
normalized = normalized.slice(0, -1);
|
|
43
|
+
}
|
|
44
|
+
return normalized;
|
|
45
|
+
}
|
|
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
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Middleware } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* 服务器基类
|
|
4
|
+
* 包含所有服务器类型的公共逻辑
|
|
5
|
+
*/
|
|
6
|
+
export declare abstract class BaseServer {
|
|
7
|
+
protected globalMiddleware: Middleware[];
|
|
8
|
+
use(mw: Middleware): void;
|
|
9
|
+
/**
|
|
10
|
+
* 打印扁平化后的路由信息,用于调试
|
|
11
|
+
*/
|
|
12
|
+
protected logFlattenedRoutes(routes: any[], type?: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* 检测路由冲突
|
|
15
|
+
* 检查是否有路径相同但方法不同的路由,以及潜在的路径冲突
|
|
16
|
+
*/
|
|
17
|
+
protected detectRouteConflicts(routes: any[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* 检测动态路由的潜在冲突
|
|
20
|
+
*/
|
|
21
|
+
private detectDynamicRouteConflicts;
|
|
22
|
+
/**
|
|
23
|
+
* 判断两个路径是否可能冲突
|
|
24
|
+
*/
|
|
25
|
+
private pathsMayConflict;
|
|
26
|
+
/**
|
|
27
|
+
* 路径匹配
|
|
28
|
+
*/
|
|
29
|
+
protected matchPath(pattern: string, path: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 提取路径参数
|
|
32
|
+
*/
|
|
33
|
+
protected extractParams(pattern: string, path: string): Record<string, string>;
|
|
34
|
+
/**
|
|
35
|
+
* 处理 OPTIONS 请求
|
|
36
|
+
*/
|
|
37
|
+
protected handleOptions(pathname: string, routes: any[]): Response;
|
|
38
|
+
}
|