vafast 0.2.3 → 0.3.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/README.md +437 -143
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/node-server/index.d.ts +22 -0
- package/dist/node-server/index.js +21 -0
- package/dist/node-server/request.d.ts +11 -0
- package/dist/node-server/request.js +157 -0
- package/dist/node-server/response.d.ts +15 -0
- package/dist/node-server/response.js +98 -0
- package/dist/node-server/serve.d.ts +52 -0
- package/dist/node-server/serve.js +88 -0
- package/dist/router/radix-tree.d.ts +12 -0
- package/dist/router/radix-tree.js +37 -1
- package/dist/serve.d.ts +12 -0
- package/dist/serve.js +11 -0
- package/dist/server/server.d.ts +9 -0
- package/dist/server/server.js +26 -1
- package/dist/types/types.d.ts +6 -1
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/parsers.d.ts +19 -1
- package/dist/utils/parsers.js +93 -9
- package/dist/utils/response.js +4 -3
- package/dist/utils/validators/validators.d.ts +36 -1
- package/dist/utils/validators/validators.js +83 -3
- package/package.json +9 -2
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vafast/node-server
|
|
3
|
+
* Node.js 适配器 - 为 Vafast 提供高性能 Node.js 运行时支持
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { serve } from "@vafast/node-server";
|
|
8
|
+
* import { Server } from "vafast";
|
|
9
|
+
*
|
|
10
|
+
* const app = new Server([
|
|
11
|
+
* { method: "GET", path: "/", handler: () => "Hello World" },
|
|
12
|
+
* ]);
|
|
13
|
+
*
|
|
14
|
+
* serve({ fetch: app.fetch, port: 3000 }, () => {
|
|
15
|
+
* console.log("Server running on http://localhost:3000");
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export { serve, createAdaptorServer } from "./serve";
|
|
20
|
+
export type { ServeOptions, ServeResult, FetchHandler } from "./serve";
|
|
21
|
+
export { createProxyRequest } from "./request";
|
|
22
|
+
export { writeResponse, writeResponseSimple } from "./response";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vafast/node-server
|
|
3
|
+
* Node.js 适配器 - 为 Vafast 提供高性能 Node.js 运行时支持
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { serve } from "@vafast/node-server";
|
|
8
|
+
* import { Server } from "vafast";
|
|
9
|
+
*
|
|
10
|
+
* const app = new Server([
|
|
11
|
+
* { method: "GET", path: "/", handler: () => "Hello World" },
|
|
12
|
+
* ]);
|
|
13
|
+
*
|
|
14
|
+
* serve({ fetch: app.fetch, port: 3000 }, () => {
|
|
15
|
+
* console.log("Server running on http://localhost:3000");
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export { serve, createAdaptorServer } from "./serve";
|
|
20
|
+
export { createProxyRequest } from "./request";
|
|
21
|
+
export { writeResponse, writeResponseSimple } from "./response";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 优化的 Request 代理
|
|
3
|
+
* 延迟创建真实 Request,减少不必要的对象分配
|
|
4
|
+
*/
|
|
5
|
+
import type { IncomingMessage } from "node:http";
|
|
6
|
+
/**
|
|
7
|
+
* 创建代理 Request
|
|
8
|
+
* @param incoming Node.js IncomingMessage
|
|
9
|
+
* @param defaultHost 默认主机名
|
|
10
|
+
*/
|
|
11
|
+
export declare function createProxyRequest(incoming: IncomingMessage, defaultHost: string): Request;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 优化的 Request 代理
|
|
3
|
+
* 延迟创建真实 Request,减少不必要的对象分配
|
|
4
|
+
*/
|
|
5
|
+
import { Readable } from "node:stream";
|
|
6
|
+
// 内部 Symbol
|
|
7
|
+
const requestCache = Symbol("requestCache");
|
|
8
|
+
const incomingKey = Symbol("incoming");
|
|
9
|
+
const urlKey = Symbol("url");
|
|
10
|
+
const headersKey = Symbol("headers");
|
|
11
|
+
/**
|
|
12
|
+
* 从 rawHeaders 高效解析 Headers
|
|
13
|
+
*/
|
|
14
|
+
function parseHeaders(rawHeaders) {
|
|
15
|
+
const headers = new Headers();
|
|
16
|
+
for (let i = 0; i < rawHeaders.length; i += 2) {
|
|
17
|
+
const key = rawHeaders[i];
|
|
18
|
+
const value = rawHeaders[i + 1];
|
|
19
|
+
// 跳过 HTTP/2 伪头 (以 : 开头)
|
|
20
|
+
if (key.charCodeAt(0) !== 58) {
|
|
21
|
+
headers.append(key, value);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return headers;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 将 Node.js ReadableStream 转换为 Web 标准 ReadableStream
|
|
28
|
+
* Node.js 和 Web 标准的 ReadableStream 在运行时兼容,但 TypeScript 类型不同
|
|
29
|
+
*/
|
|
30
|
+
function toWebStream(nodeStream) {
|
|
31
|
+
// Node.js ReadableStream 和 Web ReadableStream 在运行时是兼容的
|
|
32
|
+
// 这里使用类型断言是安全的,因为 Node.js >= 18 的 stream/web 完全实现了 WHATWG Streams 标准
|
|
33
|
+
return nodeStream;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 创建真实的 Request 对象
|
|
37
|
+
*/
|
|
38
|
+
function createRealRequest(proxy) {
|
|
39
|
+
const incoming = proxy[incomingKey];
|
|
40
|
+
const method = incoming.method || "GET";
|
|
41
|
+
const init = {
|
|
42
|
+
method,
|
|
43
|
+
headers: proxy[headersKey] || parseHeaders(incoming.rawHeaders),
|
|
44
|
+
};
|
|
45
|
+
// 只有非 GET/HEAD 请求才有 body
|
|
46
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
47
|
+
// 使用 Node.js 原生流转换,避免收集 chunks
|
|
48
|
+
const nodeWebStream = Readable.toWeb(incoming);
|
|
49
|
+
init.body = toWebStream(nodeWebStream);
|
|
50
|
+
init.duplex = "half";
|
|
51
|
+
}
|
|
52
|
+
return new Request(proxy[urlKey], init);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Request 代理原型
|
|
56
|
+
* 使用 Object.defineProperty 定义属性以支持 this 绑定
|
|
57
|
+
*/
|
|
58
|
+
const requestPrototype = {};
|
|
59
|
+
// 定义 method 属性
|
|
60
|
+
Object.defineProperty(requestPrototype, "method", {
|
|
61
|
+
get() {
|
|
62
|
+
const self = this;
|
|
63
|
+
return self[incomingKey].method || "GET";
|
|
64
|
+
},
|
|
65
|
+
enumerable: true,
|
|
66
|
+
});
|
|
67
|
+
// 定义 url 属性
|
|
68
|
+
Object.defineProperty(requestPrototype, "url", {
|
|
69
|
+
get() {
|
|
70
|
+
const self = this;
|
|
71
|
+
return self[urlKey];
|
|
72
|
+
},
|
|
73
|
+
enumerable: true,
|
|
74
|
+
});
|
|
75
|
+
// 定义 headers 属性(延迟解析)
|
|
76
|
+
Object.defineProperty(requestPrototype, "headers", {
|
|
77
|
+
get() {
|
|
78
|
+
const self = this;
|
|
79
|
+
if (!self[headersKey]) {
|
|
80
|
+
self[headersKey] = parseHeaders(self[incomingKey].rawHeaders);
|
|
81
|
+
}
|
|
82
|
+
return self[headersKey];
|
|
83
|
+
},
|
|
84
|
+
enumerable: true,
|
|
85
|
+
});
|
|
86
|
+
// 定义 _getRequest 方法(获取或创建真实 Request)
|
|
87
|
+
Object.defineProperty(requestPrototype, "_getRequest", {
|
|
88
|
+
value: function () {
|
|
89
|
+
const self = this;
|
|
90
|
+
if (!self[requestCache]) {
|
|
91
|
+
self[requestCache] = createRealRequest(self);
|
|
92
|
+
}
|
|
93
|
+
return self[requestCache];
|
|
94
|
+
},
|
|
95
|
+
enumerable: false,
|
|
96
|
+
});
|
|
97
|
+
// 代理需要访问真实 Request 的属性
|
|
98
|
+
const proxyGetters = [
|
|
99
|
+
"body",
|
|
100
|
+
"bodyUsed",
|
|
101
|
+
"signal",
|
|
102
|
+
"cache",
|
|
103
|
+
"credentials",
|
|
104
|
+
"destination",
|
|
105
|
+
"integrity",
|
|
106
|
+
"mode",
|
|
107
|
+
"redirect",
|
|
108
|
+
"referrer",
|
|
109
|
+
"referrerPolicy",
|
|
110
|
+
"keepalive",
|
|
111
|
+
];
|
|
112
|
+
proxyGetters.forEach((key) => {
|
|
113
|
+
Object.defineProperty(requestPrototype, key, {
|
|
114
|
+
get() {
|
|
115
|
+
const self = this;
|
|
116
|
+
return self._getRequest()[key];
|
|
117
|
+
},
|
|
118
|
+
enumerable: true,
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
// 代理需要调用真实 Request 的方法
|
|
122
|
+
const proxyMethods = [
|
|
123
|
+
"arrayBuffer",
|
|
124
|
+
"blob",
|
|
125
|
+
"clone",
|
|
126
|
+
"formData",
|
|
127
|
+
"json",
|
|
128
|
+
"text",
|
|
129
|
+
];
|
|
130
|
+
proxyMethods.forEach((key) => {
|
|
131
|
+
Object.defineProperty(requestPrototype, key, {
|
|
132
|
+
value: function () {
|
|
133
|
+
const self = this;
|
|
134
|
+
const req = self._getRequest();
|
|
135
|
+
return req[key].call(req);
|
|
136
|
+
},
|
|
137
|
+
enumerable: true,
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
// 设置原型链
|
|
141
|
+
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
|
142
|
+
/**
|
|
143
|
+
* 创建代理 Request
|
|
144
|
+
* @param incoming Node.js IncomingMessage
|
|
145
|
+
* @param defaultHost 默认主机名
|
|
146
|
+
*/
|
|
147
|
+
export function createProxyRequest(incoming, defaultHost) {
|
|
148
|
+
const req = Object.create(requestPrototype);
|
|
149
|
+
req[incomingKey] = incoming;
|
|
150
|
+
// 构建 URL
|
|
151
|
+
const host = incoming.headers.host || defaultHost;
|
|
152
|
+
const protocol = incoming.socket.encrypted
|
|
153
|
+
? "https"
|
|
154
|
+
: "http";
|
|
155
|
+
req[urlKey] = `${protocol}://${host}${incoming.url || "/"}`;
|
|
156
|
+
return req;
|
|
157
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 优化的 Response 写入
|
|
3
|
+
* 流式写入,避免内存拷贝
|
|
4
|
+
*/
|
|
5
|
+
import type { ServerResponse } from "node:http";
|
|
6
|
+
/**
|
|
7
|
+
* 将 Web Response 写入 Node.js ServerResponse
|
|
8
|
+
* 流式写入,零拷贝
|
|
9
|
+
*/
|
|
10
|
+
export declare function writeResponse(response: Response, outgoing: ServerResponse): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* 简化版写入(用于已知小体积响应)
|
|
13
|
+
* 直接 arrayBuffer 转换,适用于确定的小响应
|
|
14
|
+
*/
|
|
15
|
+
export declare function writeResponseSimple(response: Response, outgoing: ServerResponse): Promise<void>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 优化的 Response 写入
|
|
3
|
+
* 流式写入,避免内存拷贝
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 构建 Node.js 响应头
|
|
7
|
+
* 处理 set-cookie 多值情况
|
|
8
|
+
*/
|
|
9
|
+
function buildOutgoingHeaders(headers) {
|
|
10
|
+
const result = {};
|
|
11
|
+
const cookies = [];
|
|
12
|
+
headers.forEach((value, key) => {
|
|
13
|
+
if (key === "set-cookie") {
|
|
14
|
+
cookies.push(value);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
result[key] = value;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
if (cookies.length > 0) {
|
|
21
|
+
result["set-cookie"] = cookies;
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 流式写入 Response body 到 ServerResponse
|
|
27
|
+
* 支持背压处理,避免内存溢出
|
|
28
|
+
*/
|
|
29
|
+
async function writeBodyStream(body, outgoing) {
|
|
30
|
+
const reader = body.getReader();
|
|
31
|
+
try {
|
|
32
|
+
while (true) {
|
|
33
|
+
const { done, value } = await reader.read();
|
|
34
|
+
if (done) {
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
// 背压处理:如果写入返回 false,等待 drain 事件
|
|
38
|
+
const canContinue = outgoing.write(value);
|
|
39
|
+
if (!canContinue) {
|
|
40
|
+
await new Promise((resolve) => {
|
|
41
|
+
outgoing.once("drain", resolve);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
reader.releaseLock();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 将 Web Response 写入 Node.js ServerResponse
|
|
52
|
+
* 流式写入,零拷贝
|
|
53
|
+
*/
|
|
54
|
+
export async function writeResponse(response, outgoing) {
|
|
55
|
+
// 设置状态码
|
|
56
|
+
outgoing.statusCode = response.status;
|
|
57
|
+
// 设置响应头
|
|
58
|
+
const headers = buildOutgoingHeaders(response.headers);
|
|
59
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
60
|
+
outgoing.setHeader(key, value);
|
|
61
|
+
}
|
|
62
|
+
const body = response.body;
|
|
63
|
+
// 无 body 的情况
|
|
64
|
+
if (!body) {
|
|
65
|
+
outgoing.end();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// 流式写入 body
|
|
69
|
+
try {
|
|
70
|
+
await writeBodyStream(body, outgoing);
|
|
71
|
+
outgoing.end();
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
// 处理客户端提前断开等情况
|
|
75
|
+
if (!outgoing.destroyed) {
|
|
76
|
+
outgoing.destroy(error instanceof Error ? error : new Error(String(error)));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 简化版写入(用于已知小体积响应)
|
|
82
|
+
* 直接 arrayBuffer 转换,适用于确定的小响应
|
|
83
|
+
*/
|
|
84
|
+
export async function writeResponseSimple(response, outgoing) {
|
|
85
|
+
outgoing.statusCode = response.status;
|
|
86
|
+
const headers = buildOutgoingHeaders(response.headers);
|
|
87
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
88
|
+
outgoing.setHeader(key, value);
|
|
89
|
+
}
|
|
90
|
+
const body = response.body;
|
|
91
|
+
if (!body) {
|
|
92
|
+
outgoing.end();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// 对于小响应,直接读取全部内容
|
|
96
|
+
const buffer = await response.arrayBuffer();
|
|
97
|
+
outgoing.end(Buffer.from(buffer));
|
|
98
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js 服务器适配器
|
|
3
|
+
* 提供类似 Bun.serve 的 API
|
|
4
|
+
*/
|
|
5
|
+
import { type Server as HttpServer } from "node:http";
|
|
6
|
+
/** fetch 函数类型 */
|
|
7
|
+
export type FetchHandler = (request: Request) => Response | Promise<Response>;
|
|
8
|
+
/** serve 配置选项 */
|
|
9
|
+
export interface ServeOptions {
|
|
10
|
+
/** fetch 处理函数 */
|
|
11
|
+
fetch: FetchHandler;
|
|
12
|
+
/** 端口号,默认 3000 */
|
|
13
|
+
port?: number;
|
|
14
|
+
/** 主机名,默认 0.0.0.0 */
|
|
15
|
+
hostname?: string;
|
|
16
|
+
/** 错误处理函数 */
|
|
17
|
+
onError?: (error: Error) => Response | Promise<Response>;
|
|
18
|
+
}
|
|
19
|
+
/** serve 返回的服务器信息 */
|
|
20
|
+
export interface ServeResult {
|
|
21
|
+
/** Node.js HTTP Server 实例 */
|
|
22
|
+
server: HttpServer;
|
|
23
|
+
/** 服务器端口 */
|
|
24
|
+
port: number;
|
|
25
|
+
/** 服务器主机名 */
|
|
26
|
+
hostname: string;
|
|
27
|
+
/** 关闭服务器 */
|
|
28
|
+
stop: () => Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 启动 HTTP 服务器
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { serve } from "@vafast/node-server";
|
|
36
|
+
* import { Server } from "vafast";
|
|
37
|
+
*
|
|
38
|
+
* const app = new Server([
|
|
39
|
+
* { method: "GET", path: "/", handler: () => "Hello World" },
|
|
40
|
+
* ]);
|
|
41
|
+
*
|
|
42
|
+
* serve({ fetch: app.fetch, port: 3000 }, () => {
|
|
43
|
+
* console.log("Server running on http://localhost:3000");
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function serve(options: ServeOptions, callback?: () => void): ServeResult;
|
|
48
|
+
/**
|
|
49
|
+
* 创建适配器服务器(不自动启动)
|
|
50
|
+
* 用于需要更多控制的场景
|
|
51
|
+
*/
|
|
52
|
+
export declare function createAdaptorServer(fetch: FetchHandler, onError?: (error: Error) => Response | Promise<Response>): HttpServer;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js 服务器适配器
|
|
3
|
+
* 提供类似 Bun.serve 的 API
|
|
4
|
+
*/
|
|
5
|
+
import { createServer, } from "node:http";
|
|
6
|
+
import { createProxyRequest } from "./request";
|
|
7
|
+
import { writeResponse } from "./response";
|
|
8
|
+
/**
|
|
9
|
+
* 创建请求处理函数
|
|
10
|
+
*/
|
|
11
|
+
function createRequestHandler(fetch, defaultHost, onError) {
|
|
12
|
+
return async (incoming, outgoing) => {
|
|
13
|
+
try {
|
|
14
|
+
// 创建代理 Request(延迟创建真实 Request)
|
|
15
|
+
const request = createProxyRequest(incoming, defaultHost);
|
|
16
|
+
// 调用 fetch handler
|
|
17
|
+
const response = await fetch(request);
|
|
18
|
+
// 流式写入 Response
|
|
19
|
+
await writeResponse(response, outgoing);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
// 错误处理
|
|
23
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
24
|
+
if (onError) {
|
|
25
|
+
try {
|
|
26
|
+
const errorResponse = await onError(err);
|
|
27
|
+
await writeResponse(errorResponse, outgoing);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// onError 也失败了,返回 500
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// 默认错误响应
|
|
35
|
+
if (!outgoing.headersSent) {
|
|
36
|
+
outgoing.statusCode = 500;
|
|
37
|
+
outgoing.setHeader("Content-Type", "text/plain");
|
|
38
|
+
outgoing.end("Internal Server Error");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 启动 HTTP 服务器
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { serve } from "@vafast/node-server";
|
|
49
|
+
* import { Server } from "vafast";
|
|
50
|
+
*
|
|
51
|
+
* const app = new Server([
|
|
52
|
+
* { method: "GET", path: "/", handler: () => "Hello World" },
|
|
53
|
+
* ]);
|
|
54
|
+
*
|
|
55
|
+
* serve({ fetch: app.fetch, port: 3000 }, () => {
|
|
56
|
+
* console.log("Server running on http://localhost:3000");
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function serve(options, callback) {
|
|
61
|
+
const { fetch, port = 3000, hostname = "0.0.0.0", onError } = options;
|
|
62
|
+
const defaultHost = `${hostname === "0.0.0.0" ? "localhost" : hostname}:${port}`;
|
|
63
|
+
const handler = createRequestHandler(fetch, defaultHost, onError);
|
|
64
|
+
const server = createServer(handler);
|
|
65
|
+
// 启动服务器
|
|
66
|
+
server.listen(port, hostname, callback);
|
|
67
|
+
return {
|
|
68
|
+
server,
|
|
69
|
+
port,
|
|
70
|
+
hostname,
|
|
71
|
+
stop: () => new Promise((resolve, reject) => {
|
|
72
|
+
server.close((err) => {
|
|
73
|
+
if (err)
|
|
74
|
+
reject(err);
|
|
75
|
+
else
|
|
76
|
+
resolve();
|
|
77
|
+
});
|
|
78
|
+
}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 创建适配器服务器(不自动启动)
|
|
83
|
+
* 用于需要更多控制的场景
|
|
84
|
+
*/
|
|
85
|
+
export function createAdaptorServer(fetch, onError) {
|
|
86
|
+
const handler = createRequestHandler(fetch, "localhost", onError);
|
|
87
|
+
return createServer(handler);
|
|
88
|
+
}
|
|
@@ -9,11 +9,15 @@
|
|
|
9
9
|
* - 通配符: /files/*, /static/*filepath
|
|
10
10
|
*/
|
|
11
11
|
import type { Handler, Middleware, Method } from "../types";
|
|
12
|
+
/** 预编译的处理器类型 */
|
|
13
|
+
type CompiledHandler = (req: Request) => Promise<Response>;
|
|
12
14
|
/** 路由匹配结果 */
|
|
13
15
|
export interface MatchResult {
|
|
14
16
|
handler: Handler;
|
|
15
17
|
middleware: Middleware[];
|
|
16
18
|
params: Record<string, string>;
|
|
19
|
+
/** 预编译后的完整处理链 */
|
|
20
|
+
compiled?: CompiledHandler;
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
23
|
* Radix Tree 路由器
|
|
@@ -32,8 +36,15 @@ export declare class RadixRouter {
|
|
|
32
36
|
private createNode;
|
|
33
37
|
/** 分割路径 */
|
|
34
38
|
private splitPath;
|
|
39
|
+
/** 编译器函数 - 用于预编译中间件链 */
|
|
40
|
+
private compiler?;
|
|
41
|
+
/** 设置中间件编译器 */
|
|
42
|
+
setCompiler(compiler: (middleware: Middleware[], handler: Handler) => CompiledHandler): void;
|
|
35
43
|
/** 注册路由 */
|
|
36
44
|
register(method: Method, pattern: string, handler: Handler, middleware?: Middleware[]): void;
|
|
45
|
+
/** 预编译所有路由(在添加全局中间件后调用) */
|
|
46
|
+
precompileAll(globalMiddleware: Middleware[]): void;
|
|
47
|
+
private precompileNode;
|
|
37
48
|
/** 匹配路由 */
|
|
38
49
|
match(method: Method, path: string): MatchResult | null;
|
|
39
50
|
/** 递归匹配节点 (优先级: 静态 > 动态参数 > 通配符) */
|
|
@@ -49,3 +60,4 @@ export declare class RadixRouter {
|
|
|
49
60
|
}>;
|
|
50
61
|
private collectRoutes;
|
|
51
62
|
}
|
|
63
|
+
export {};
|
|
@@ -35,6 +35,12 @@ export class RadixRouter {
|
|
|
35
35
|
splitPath(path) {
|
|
36
36
|
return path.split("/").filter(Boolean);
|
|
37
37
|
}
|
|
38
|
+
/** 编译器函数 - 用于预编译中间件链 */
|
|
39
|
+
compiler;
|
|
40
|
+
/** 设置中间件编译器 */
|
|
41
|
+
setCompiler(compiler) {
|
|
42
|
+
this.compiler = compiler;
|
|
43
|
+
}
|
|
38
44
|
/** 注册路由 */
|
|
39
45
|
register(method, pattern, handler, middleware = []) {
|
|
40
46
|
const segments = this.splitPath(pattern);
|
|
@@ -67,7 +73,36 @@ export class RadixRouter {
|
|
|
67
73
|
node = node.children[segment];
|
|
68
74
|
}
|
|
69
75
|
}
|
|
70
|
-
|
|
76
|
+
const routeHandler = { handler, middleware };
|
|
77
|
+
// 如果没有全局中间件且设置了编译器,预编译处理链
|
|
78
|
+
if (this.compiler && middleware.length === 0) {
|
|
79
|
+
routeHandler.compiled = this.compiler([], handler);
|
|
80
|
+
}
|
|
81
|
+
node.handlers[method] = routeHandler;
|
|
82
|
+
}
|
|
83
|
+
/** 预编译所有路由(在添加全局中间件后调用) */
|
|
84
|
+
precompileAll(globalMiddleware) {
|
|
85
|
+
if (!this.compiler)
|
|
86
|
+
return;
|
|
87
|
+
this.precompileNode(this.root, globalMiddleware);
|
|
88
|
+
}
|
|
89
|
+
precompileNode(node, globalMiddleware) {
|
|
90
|
+
for (const method in node.handlers) {
|
|
91
|
+
const routeHandler = node.handlers[method];
|
|
92
|
+
if (routeHandler) {
|
|
93
|
+
const allMiddleware = [...globalMiddleware, ...routeHandler.middleware];
|
|
94
|
+
routeHandler.compiled = this.compiler(allMiddleware, routeHandler.handler);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (const key in node.children) {
|
|
98
|
+
this.precompileNode(node.children[key], globalMiddleware);
|
|
99
|
+
}
|
|
100
|
+
if (node.paramChild) {
|
|
101
|
+
this.precompileNode(node.paramChild, globalMiddleware);
|
|
102
|
+
}
|
|
103
|
+
if (node.wildcardChild) {
|
|
104
|
+
this.precompileNode(node.wildcardChild, globalMiddleware);
|
|
105
|
+
}
|
|
71
106
|
}
|
|
72
107
|
/** 匹配路由 */
|
|
73
108
|
match(method, path) {
|
|
@@ -83,6 +118,7 @@ export class RadixRouter {
|
|
|
83
118
|
handler: routeHandler.handler,
|
|
84
119
|
middleware: routeHandler.middleware,
|
|
85
120
|
params,
|
|
121
|
+
compiled: routeHandler.compiled,
|
|
86
122
|
};
|
|
87
123
|
}
|
|
88
124
|
/** 递归匹配节点 (优先级: 静态 > 动态参数 > 通配符) */
|
package/dist/serve.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 统一的 serve 函数
|
|
3
|
+
* 使用 Node.js 原生 http 模块,兼容 Bun 和 Node.js
|
|
4
|
+
*
|
|
5
|
+
* 基准测试结果(Bun 环境):
|
|
6
|
+
* - Bun.serve: 35,422 req/s
|
|
7
|
+
* - node:http: 38,075 req/s
|
|
8
|
+
*
|
|
9
|
+
* node:http 在 Bun 下性能甚至更好,无需使用 Bun API
|
|
10
|
+
*/
|
|
11
|
+
export { serve, createAdaptorServer } from "./node-server/serve";
|
|
12
|
+
export type { ServeOptions, ServeResult, FetchHandler, } from "./node-server/serve";
|
package/dist/serve.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 统一的 serve 函数
|
|
3
|
+
* 使用 Node.js 原生 http 模块,兼容 Bun 和 Node.js
|
|
4
|
+
*
|
|
5
|
+
* 基准测试结果(Bun 环境):
|
|
6
|
+
* - Bun.serve: 35,422 req/s
|
|
7
|
+
* - node:http: 38,075 req/s
|
|
8
|
+
*
|
|
9
|
+
* node:http 在 Bun 下性能甚至更好,无需使用 Bun API
|
|
10
|
+
*/
|
|
11
|
+
export { serve, createAdaptorServer } from "./node-server/serve";
|
package/dist/server/server.d.ts
CHANGED
|
@@ -20,7 +20,16 @@ import { BaseServer } from "./base-server";
|
|
|
20
20
|
export declare class Server extends BaseServer {
|
|
21
21
|
private router;
|
|
22
22
|
private routes;
|
|
23
|
+
/** 是否已预编译 */
|
|
24
|
+
private isCompiled;
|
|
25
|
+
/** 预编译时的全局中间件数量 */
|
|
26
|
+
private compiledWithMiddlewareCount;
|
|
23
27
|
constructor(routes?: (Route | NestedRoute)[]);
|
|
28
|
+
/**
|
|
29
|
+
* 预编译所有路由处理链
|
|
30
|
+
* 在添加所有路由和全局中间件后调用,可提升运行时性能
|
|
31
|
+
*/
|
|
32
|
+
compile(): this;
|
|
24
33
|
private registerRoutes;
|
|
25
34
|
/** 快速提取 pathname */
|
|
26
35
|
private extractPathname;
|
package/dist/server/server.js
CHANGED
|
@@ -23,14 +23,30 @@ import { RadixRouter } from "../router/radix-tree";
|
|
|
23
23
|
export class Server extends BaseServer {
|
|
24
24
|
router;
|
|
25
25
|
routes;
|
|
26
|
+
/** 是否已预编译 */
|
|
27
|
+
isCompiled = false;
|
|
28
|
+
/** 预编译时的全局中间件数量 */
|
|
29
|
+
compiledWithMiddlewareCount = 0;
|
|
26
30
|
constructor(routes = []) {
|
|
27
31
|
super();
|
|
28
32
|
this.router = new RadixRouter();
|
|
29
33
|
this.routes = [];
|
|
34
|
+
// 设置中间件编译器
|
|
35
|
+
this.router.setCompiler((middleware, handler) => composeMiddleware(middleware, handler));
|
|
30
36
|
if (routes.length > 0) {
|
|
31
37
|
this.registerRoutes(routes);
|
|
32
38
|
}
|
|
33
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* 预编译所有路由处理链
|
|
42
|
+
* 在添加所有路由和全局中间件后调用,可提升运行时性能
|
|
43
|
+
*/
|
|
44
|
+
compile() {
|
|
45
|
+
this.router.precompileAll(this.globalMiddleware);
|
|
46
|
+
this.isCompiled = true;
|
|
47
|
+
this.compiledWithMiddlewareCount = this.globalMiddleware.length;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
34
50
|
registerRoutes(routes) {
|
|
35
51
|
const flattened = flattenNestedRoutes(routes);
|
|
36
52
|
this.routes.push(...flattened);
|
|
@@ -39,6 +55,10 @@ export class Server extends BaseServer {
|
|
|
39
55
|
}
|
|
40
56
|
this.detectRouteConflicts(flattened);
|
|
41
57
|
this.logFlattenedRoutes(flattened);
|
|
58
|
+
// 自动预编译(如果没有全局中间件)
|
|
59
|
+
if (this.globalMiddleware.length === 0 && !this.isCompiled) {
|
|
60
|
+
this.compile();
|
|
61
|
+
}
|
|
42
62
|
}
|
|
43
63
|
/** 快速提取 pathname */
|
|
44
64
|
extractPathname(url) {
|
|
@@ -61,7 +81,12 @@ export class Server extends BaseServer {
|
|
|
61
81
|
const match = this.router.match(method, pathname);
|
|
62
82
|
if (match) {
|
|
63
83
|
req.params = match.params;
|
|
64
|
-
//
|
|
84
|
+
// 优先使用预编译的处理链(仅当全局中间件未变化时)
|
|
85
|
+
if (match.compiled &&
|
|
86
|
+
this.globalMiddleware.length === this.compiledWithMiddlewareCount) {
|
|
87
|
+
return match.compiled(req);
|
|
88
|
+
}
|
|
89
|
+
// 回退:运行时组合中间件
|
|
65
90
|
const allMiddleware = [...this.globalMiddleware, ...match.middleware];
|
|
66
91
|
const handler = composeMiddleware(allMiddleware, match.handler);
|
|
67
92
|
return handler(req);
|
package/dist/types/types.d.ts
CHANGED
|
@@ -2,7 +2,12 @@ export type Method = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "
|
|
|
2
2
|
/** 支持的响应类型 - 由 mapResponse 自动转换 */
|
|
3
3
|
export type ResponseBody = Response | string | number | boolean | object | null | undefined | ReadableStream | Blob | ArrayBuffer;
|
|
4
4
|
/** Handler 返回值(支持同步/异步,任意类型) */
|
|
5
|
-
|
|
5
|
+
/** 传统 Handler 类型 */
|
|
6
|
+
export type LegacyHandler = (req: Request, params?: Record<string, string>, user?: Record<string, any>) => ResponseBody | Promise<ResponseBody>;
|
|
7
|
+
/** createHandler 返回的类型 */
|
|
8
|
+
export type FactoryHandler = (req: Request) => Promise<Response>;
|
|
9
|
+
/** Handler 联合类型(支持两种风格) */
|
|
10
|
+
export type Handler = LegacyHandler | FactoryHandler;
|
|
6
11
|
/** 中间件(返回值必须是 Response 或 Promise<Response>) */
|
|
7
12
|
export type Middleware = (req: Request, next: () => Promise<Response>) => Response | Promise<Response>;
|
|
8
13
|
export interface Route {
|