vafast 0.8.0 → 0.8.2
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 +54 -2
- package/dist/{base-server-CE0mfqPY.mjs → base-server-CbnxNoNf.mjs} +1 -1
- package/dist/{base-server-CE0mfqPY.mjs.map → base-server-CbnxNoNf.mjs.map} +1 -1
- package/dist/{base-server-CeJ8LTBk.d.mts → base-server-DDNu97SA.d.mts} +2 -2
- package/dist/{base64url-Cc77f1ms.mjs → base64url-Cc25EVjw.mjs} +1 -1
- package/dist/{base64url-Cc77f1ms.mjs.map → base64url-Cc25EVjw.mjs.map} +1 -1
- package/dist/{base64url-CAmasWF0.d.mts → base64url-wYuxnrb0.d.mts} +1 -1
- package/dist/{component-route-CGbmQm5P.d.mts → component-route-BAaJKp8X.d.mts} +2 -2
- package/dist/{component-router-B6M5XDnp.mjs → component-router-wQc8auz9.mjs} +1 -1
- package/dist/{component-router-B6M5XDnp.mjs.map → component-router-wQc8auz9.mjs.map} +1 -1
- package/dist/{component-server-CKcXIvMg.d.mts → component-server-CVhgbxOe.d.mts} +4 -4
- package/dist/{component-server-Cya46YN3.mjs → component-server-llGj--XB.mjs} +6 -6
- package/dist/{component-server-Cya46YN3.mjs.map → component-server-llGj--XB.mjs.map} +1 -1
- package/dist/{contract-vSyKiRwz.mjs → contract-BIqqOwPd.mjs} +2 -2
- package/dist/{contract-vSyKiRwz.mjs.map → contract-BIqqOwPd.mjs.map} +1 -1
- package/dist/{contract-C-xQoZ6r.d.mts → contract-ChZaybx9.d.mts} +1 -1
- package/dist/{defineRoute-Rod-Vi6-.d.mts → defineRoute-DUYeO8TR.d.mts} +1 -1
- package/dist/defineRoute.d.mts +1 -1
- package/dist/defineRoute.mjs +6 -13
- package/dist/defineRoute.mjs.map +1 -1
- package/dist/{dependency-manager-mqzLAocb.d.mts → dependency-manager-BIjSc7j3.d.mts} +1 -1
- package/dist/{dependency-manager-CGMZJTer.mjs → dependency-manager-DaDThGEc.mjs} +3 -2
- package/dist/dependency-manager-DaDThGEc.mjs.map +1 -0
- package/dist/{formats-Ca7ASaYH.d.mts → formats-B1vlpb1f.d.mts} +1 -1
- package/dist/{go-await-B1U27PgB.mjs → go-await-C4ZdEUwY.mjs} +1 -1
- package/dist/{go-await-B1U27PgB.mjs.map → go-await-C4ZdEUwY.mjs.map} +1 -1
- package/dist/{go-await-Dz1CRSTT.d.mts → go-await-KQIMkGZy.d.mts} +1 -1
- package/dist/{html-renderer-D1zzDVQM.mjs → html-renderer-DgYwJP_a.mjs} +1 -1
- package/dist/{html-renderer-D1zzDVQM.mjs.map → html-renderer-DgYwJP_a.mjs.map} +1 -1
- package/dist/{html-renderer-Up52eIS6.d.mts → html-renderer-ZY_sfcpi.d.mts} +1 -1
- package/dist/{index-CqwSjhXb.d.mts → index-DgIsC7ua.d.mts} +5 -5
- package/dist/index.d.mts +22 -21
- package/dist/index.mjs +17 -16
- package/dist/index.mjs.map +1 -1
- package/dist/middleware/component-router.d.mts +1 -1
- package/dist/middleware/component-router.mjs +1 -1
- package/dist/{middleware-BTg4GbjC.d.mts → middleware-B_fMMYr3.d.mts} +2 -2
- package/dist/middleware.d.mts +1 -1
- package/dist/middleware.mjs +2 -1
- package/dist/monitoring/index.d.mts +3 -3
- package/dist/monitoring/native-monitor.d.mts +3 -3
- package/dist/node-server/index.d.mts +1 -1
- package/dist/node-server/index.mjs +3 -3
- package/dist/node-server/request.mjs +1 -1
- package/dist/node-server/response.mjs +1 -1
- package/dist/node-server/serve.d.mts +1 -1
- package/dist/node-server/serve.mjs +2 -2
- package/dist/{parsers-CEkO18PZ.d.mts → parsers-B1dewjiN.d.mts} +1 -1
- package/dist/{parsers-BPBVKby-.mjs → parsers-DPKyyUv3.mjs} +1 -1
- package/dist/{parsers-BPBVKby-.mjs.map → parsers-DPKyyUv3.mjs.map} +1 -1
- package/dist/{path-matcher-Dp-DRUV9.mjs → path-matcher-BwpVrcVG.mjs} +1 -1
- package/dist/{path-matcher-Dp-DRUV9.mjs.map → path-matcher-BwpVrcVG.mjs.map} +1 -1
- package/dist/{radix-tree-dyn3qDFX.mjs → radix-tree-DPcGUi6x.mjs} +1 -1
- package/dist/{radix-tree-dyn3qDFX.mjs.map → radix-tree-DPcGUi6x.mjs.map} +1 -1
- package/dist/{request-D5oMj6sH.mjs → request-COqaDa-c.mjs} +1 -1
- package/dist/{request-D5oMj6sH.mjs.map → request-COqaDa-c.mjs.map} +1 -1
- package/dist/{response-BlHLmKys.mjs → response-BK2pYq43.mjs} +1 -1
- package/dist/{response-BlHLmKys.mjs.map → response-BK2pYq43.mjs.map} +1 -1
- package/dist/{response-Bs9GhJz-.mjs → response-BlkS--Fb.mjs} +9 -2
- package/dist/response-BlkS--Fb.mjs.map +1 -0
- package/dist/{response-lI0YZoia.d.mts → response-DsH8MnBO.d.mts} +2 -2
- package/dist/{route-registry-DmbGzvgn.d.mts → route-registry-B0q_pJDC.d.mts} +3 -3
- package/dist/{route-registry-DsPslV2b.mjs → route-registry-ClmI5VwE.mjs} +1 -1
- package/dist/{route-registry-DsPslV2b.mjs.map → route-registry-ClmI5VwE.mjs.map} +1 -1
- package/dist/router/index.mjs +1 -1
- package/dist/router/radix-tree.d.mts +1 -1
- package/dist/router/radix-tree.mjs +1 -1
- package/dist/{serve-Cj0bYhav.mjs → serve-CozN9Tlz.mjs} +3 -3
- package/dist/{serve-Cj0bYhav.mjs.map → serve-CozN9Tlz.mjs.map} +1 -1
- package/dist/{serve-Dw-GHkc3.d.mts → serve-Dh6Ux5Pg.d.mts} +1 -1
- package/dist/serve.d.mts +1 -1
- package/dist/serve.mjs +2 -2
- package/dist/server/base-server.d.mts +1 -1
- package/dist/server/base-server.mjs +1 -1
- package/dist/server/component-server.d.mts +1 -1
- package/dist/server/component-server.mjs +2 -2
- package/dist/server/index.d.mts +5 -5
- package/dist/server/index.mjs +7 -6
- package/dist/server/server-factory.d.mts +3 -3
- package/dist/server/server-factory.mjs +6 -5
- package/dist/server/server.d.mts +2 -2
- package/dist/server/server.mjs +3 -2
- package/dist/{server-BNpY3NH6.mjs → server-D-jaEU-V.mjs} +3 -3
- package/dist/{server-BNpY3NH6.mjs.map → server-D-jaEU-V.mjs.map} +1 -1
- package/dist/{server-B-X9ANNh.d.mts → server-Dr_qEIqu.d.mts} +4 -4
- package/dist/{server-B4YDcNJy.mjs → server-Dtk8M7eI.mjs} +5 -5
- package/dist/{server-B4YDcNJy.mjs.map → server-Dtk8M7eI.mjs.map} +1 -1
- package/dist/{sse-BqvrwmK6.d.mts → sse-CZnFOi2K.d.mts} +1 -1
- package/dist/types/component-route.d.mts +1 -1
- package/dist/types/index.d.mts +2 -2
- package/dist/types/types.d.mts +1 -1
- package/dist/{types-aczawQFE.d.mts → types-BaIZETLg.d.mts} +1 -1
- package/dist/utils/base64url.d.mts +1 -1
- package/dist/utils/base64url.mjs +1 -1
- package/dist/utils/contract.d.mts +1 -1
- package/dist/utils/contract.mjs +1 -1
- package/dist/utils/dependency-manager.d.mts +1 -1
- package/dist/utils/dependency-manager.mjs +1 -1
- package/dist/utils/formats.d.mts +1 -1
- package/dist/utils/go-await.d.mts +1 -1
- package/dist/utils/go-await.mjs +1 -1
- package/dist/utils/handle.mjs +1 -1
- package/dist/utils/html-renderer.d.mts +1 -1
- package/dist/utils/html-renderer.mjs +1 -1
- package/dist/utils/index.d.mts +14 -13
- package/dist/utils/index.mjs +11 -10
- package/dist/utils/parsers.d.mts +1 -1
- package/dist/utils/parsers.mjs +1 -1
- package/dist/utils/path-matcher.mjs +1 -1
- package/dist/utils/response.d.mts +1 -1
- package/dist/utils/response.mjs +2 -1
- package/dist/utils/route-registry.d.mts +2 -2
- package/dist/utils/route-registry.mjs +1 -1
- package/dist/utils/sse.d.mts +1 -1
- package/dist/utils/validators/validation-errors.d.mts +2 -0
- package/dist/utils/validators/validation-errors.mjs +3 -0
- package/dist/utils/validators/validators.d.mts +1 -1
- package/dist/utils/validators/validators.mjs +2 -1
- package/dist/validation-errors-BXOr6Rf2.d.mts +36 -0
- package/dist/validation-errors-j7DAULlG.mjs +38 -0
- package/dist/validation-errors-j7DAULlG.mjs.map +1 -0
- package/dist/{validators-CkfvNBbK.mjs → validators-DdEfUzCC.mjs} +60 -21
- package/dist/validators-DdEfUzCC.mjs.map +1 -0
- package/dist/{validators-D5KJCSZr.d.mts → validators-jkeNFN8V.d.mts} +7 -5
- package/package.json +1 -1
- package/dist/dependency-manager-CGMZJTer.mjs.map +0 -1
- package/dist/response-Bs9GhJz-.mjs.map +0 -1
- package/dist/validators-CkfvNBbK.mjs.map +0 -1
- /package/dist/{component-route-DdKFowzp.mjs → component-route-B6jaTxLT.mjs} +0 -0
- /package/dist/{index-D4DUvwPf.d.mts → index-1-AkepUA.d.mts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-
|
|
1
|
+
{"version":3,"file":"response-BK2pYq43.mjs","names":[],"sources":["../src/node-server/response.ts"],"sourcesContent":["/**\n * 优化的 Response 写入\n * 流式写入,避免内存拷贝\n */\n\nimport type { ServerResponse } from \"node:http\";\n\n/**\n * 构建 Node.js 响应头\n * 处理 set-cookie 多值情况\n */\nfunction buildOutgoingHeaders(\n headers: Headers,\n): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n const cookies: string[] = [];\n\n headers.forEach((value, key) => {\n if (key === \"set-cookie\") {\n cookies.push(value);\n } else {\n result[key] = value;\n }\n });\n\n if (cookies.length > 0) {\n result[\"set-cookie\"] = cookies;\n }\n\n return result;\n}\n\n/**\n * 流式写入 Response body 到 ServerResponse\n * 支持背压处理,避免内存溢出\n */\nasync function writeBodyStream(\n body: ReadableStream<Uint8Array>,\n outgoing: ServerResponse,\n): Promise<void> {\n const reader = body.getReader();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n break;\n }\n\n // 背压处理:如果写入返回 false,等待 drain 事件\n const canContinue = outgoing.write(value);\n if (!canContinue) {\n await new Promise<void>((resolve) => {\n outgoing.once(\"drain\", resolve);\n });\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * 将 Web Response 写入 Node.js ServerResponse\n * 流式写入,零拷贝\n */\nexport async function writeResponse(\n response: Response,\n outgoing: ServerResponse,\n): Promise<void> {\n // 设置状态码\n outgoing.statusCode = response.status;\n\n // 设置响应头\n const headers = buildOutgoingHeaders(response.headers);\n for (const [key, value] of Object.entries(headers)) {\n outgoing.setHeader(key, value);\n }\n\n const body = response.body;\n\n // 无 body 的情况\n if (!body) {\n outgoing.end();\n return;\n }\n\n // 流式写入 body\n try {\n await writeBodyStream(body, outgoing);\n outgoing.end();\n } catch (error) {\n // 处理客户端提前断开等情况\n if (!outgoing.destroyed) {\n outgoing.destroy(\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n}\n\n/**\n * 简化版写入(用于已知小体积响应)\n * 直接 arrayBuffer 转换,适用于确定的小响应\n */\nexport async function writeResponseSimple(\n response: Response,\n outgoing: ServerResponse,\n): Promise<void> {\n outgoing.statusCode = response.status;\n\n const headers = buildOutgoingHeaders(response.headers);\n for (const [key, value] of Object.entries(headers)) {\n outgoing.setHeader(key, value);\n }\n\n const body = response.body;\n if (!body) {\n outgoing.end();\n return;\n }\n\n // 对于小响应,直接读取全部内容\n const buffer = await response.arrayBuffer();\n outgoing.end(Buffer.from(buffer));\n}\n"],"mappings":";;;;;AAWA,SAAS,qBACP,SACmC;CACnC,MAAM,SAA4C,EAAE;CACpD,MAAM,UAAoB,EAAE;AAE5B,SAAQ,SAAS,OAAO,QAAQ;AAC9B,MAAI,QAAQ,aACV,SAAQ,KAAK,MAAM;MAEnB,QAAO,OAAO;GAEhB;AAEF,KAAI,QAAQ,SAAS,EACnB,QAAO,gBAAgB;AAGzB,QAAO;;;;;;AAOT,eAAe,gBACb,MACA,UACe;CACf,MAAM,SAAS,KAAK,WAAW;AAE/B,KAAI;AACF,SAAO,MAAM;GACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAE3C,OAAI,KACF;AAKF,OAAI,CADgB,SAAS,MAAM,MAAM,CAEvC,OAAM,IAAI,SAAe,YAAY;AACnC,aAAS,KAAK,SAAS,QAAQ;KAC/B;;WAGE;AACR,SAAO,aAAa;;;;;;;AAQxB,eAAsB,cACpB,UACA,UACe;AAEf,UAAS,aAAa,SAAS;CAG/B,MAAM,UAAU,qBAAqB,SAAS,QAAQ;AACtD,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAChD,UAAS,UAAU,KAAK,MAAM;CAGhC,MAAM,OAAO,SAAS;AAGtB,KAAI,CAAC,MAAM;AACT,WAAS,KAAK;AACd;;AAIF,KAAI;AACF,QAAM,gBAAgB,MAAM,SAAS;AACrC,WAAS,KAAK;UACP,OAAO;AAEd,MAAI,CAAC,SAAS,UACZ,UAAS,QACP,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,CAC1D;;;;;;;AASP,eAAsB,oBACpB,UACA,UACe;AACf,UAAS,aAAa,SAAS;CAE/B,MAAM,UAAU,qBAAqB,SAAS,QAAQ;AACtD,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAChD,UAAS,UAAU,KAAK,MAAM;AAIhC,KAAI,CADS,SAAS,MACX;AACT,WAAS,KAAK;AACd;;CAIF,MAAM,SAAS,MAAM,SAAS,aAAa;AAC3C,UAAS,IAAI,OAAO,KAAK,OAAO,CAAC"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { i as isValidationFailedError } from "./validation-errors-j7DAULlG.mjs";
|
|
2
|
+
|
|
1
3
|
//#region src/middleware.ts
|
|
2
4
|
/**
|
|
3
5
|
* 全局 Symbol 标识 VafastError
|
|
@@ -64,7 +66,12 @@ const errorHandler = async (req, next) => {
|
|
|
64
66
|
try {
|
|
65
67
|
return await next();
|
|
66
68
|
} catch (err$1) {
|
|
67
|
-
console.error("未处理的错误:", err$1);
|
|
69
|
+
if (!isValidationFailedError(err$1)) console.error("未处理的错误:", err$1);
|
|
70
|
+
if (isValidationFailedError(err$1)) return json({
|
|
71
|
+
code: err$1.code,
|
|
72
|
+
message: err$1.message,
|
|
73
|
+
details: err$1.details
|
|
74
|
+
}, err$1.status);
|
|
68
75
|
if (isVafastError(err$1)) return json({
|
|
69
76
|
code: err$1.code,
|
|
70
77
|
message: err$1.expose ? err$1.message : "发生了一个错误"
|
|
@@ -215,4 +222,4 @@ err.internal = (message = "服务器内部错误", code) => err(message, 500, co
|
|
|
215
222
|
|
|
216
223
|
//#endregion
|
|
217
224
|
export { mapResponse as a, text as c, composeMiddleware as d, errorHandler as f, json as i, VAFAST_ERROR_SYMBOL as l, err as n, redirect as o, isVafastError as p, html as r, stream as s, empty as t, VafastError as u };
|
|
218
|
-
//# sourceMappingURL=response-
|
|
225
|
+
//# sourceMappingURL=response-BlkS--Fb.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-BlkS--Fb.mjs","names":["err","stream"],"sources":["../src/middleware.ts","../src/utils/response.ts"],"sourcesContent":["// src/middleware.ts\n\nimport { json, mapResponse } from \"./utils/response\";\n\nimport type { Handler, Middleware } from \"./types\";\nimport {\n isValidationFailedError,\n} from \"./utils/validators/validation-errors\";\n\n/**\n * 全局 Symbol 标识 VafastError\n *\n * 使用 Symbol.for() 确保跨包共享同一个 Symbol 引用,\n * 彻底解决多包实例 instanceof 失效的问题。\n */\nexport const VAFAST_ERROR_SYMBOL = Symbol.for(\"vafast.error\");\n\n/** Vafast 自定义错误类型 */\nexport class VafastError extends Error {\n /** 全局标识,用于跨包识别 */\n readonly [VAFAST_ERROR_SYMBOL] = true;\n\n status: number;\n code: number;\n expose: boolean;\n\n constructor(\n message: string,\n options: {\n status?: number;\n code?: number;\n expose?: boolean;\n cause?: unknown;\n } = {},\n ) {\n super(message);\n this.name = \"VafastError\";\n this.status = options.status ?? 500;\n this.code = options.code ?? options.status ?? 500;\n this.expose = options.expose ?? false;\n if (options.cause) (this as any).cause = options.cause;\n }\n}\n\n/** 检查是否是 VafastError(跨包安全) */\nexport function isVafastError(err: unknown): err is VafastError {\n return (\n err instanceof VafastError ||\n (typeof err === \"object\" &&\n err !== null &&\n (err as any)[VAFAST_ERROR_SYMBOL] === true)\n );\n}\n\n/**\n * 组合中间件链\n *\n * 纯粹的中间件组合,不自动注入任何中间件。\n * 错误处理器由 Server 在适当位置注入,确保洋葱模型正确:\n *\n * ```\n * CORS.before → errorHandler.try → auth → handler\n * ↓ (error)\n * errorHandler.catch → return errorResponse\n * CORS.after (添加 CORS 头) ← errorResponse\n * ```\n */\nexport function composeMiddleware(\n middleware: Middleware[],\n finalHandler: Handler,\n): (req: Request) => Promise<Response> {\n return function composedHandler(req: Request): Promise<Response> {\n let i = -1;\n\n const dispatch = (index: number): Promise<Response> => {\n if (index <= i)\n return Promise.reject(new Error(\"next() called multiple times\"));\n i = index;\n\n // 中间件阶段\n if (index < middleware.length) {\n const mw = middleware[index];\n return Promise.resolve(mw(req, () => dispatch(index + 1)));\n }\n\n // 最终 handler - 使用 mapResponse 转换返回值\n return Promise.resolve(finalHandler(req)).then(mapResponse);\n };\n\n return dispatch(0);\n };\n}\n\n/**\n * 全局错误处理中间件\n *\n * 捕获后续中间件和 handler 抛出的所有错误,转换为标准 JSON 响应。\n * 由 Server 自动注入到全局中间件之后、路由中间件之前。\n */\nexport const errorHandler: Middleware = async (req, next) => {\n try {\n return await next();\n } catch (err) {\n if (!isValidationFailedError(err)) {\n console.error(\"未处理的错误:\", err);\n }\n\n if (isValidationFailedError(err)) {\n return json(\n {\n code: err.code,\n message: err.message,\n details: err.details,\n },\n err.status,\n );\n }\n\n // 使用 Symbol.for() 跨包安全识别 VafastError\n if (isVafastError(err)) {\n return json(\n {\n code: err.code,\n message: err.expose ? err.message : \"发生了一个错误\",\n },\n err.status,\n );\n }\n\n return json({ code: 500, message: \"出现了一些问题\" }, 500);\n }\n};\n","// src/response.ts\n\nimport { VafastError } from \"../middleware\";\n\n/** 生成 JSON 响应 */\nexport function json(\n data: unknown,\n status = 200,\n headers: HeadersInit = {},\n): Response {\n const body = JSON.stringify(data);\n\n // 优化:只在有自定义 headers 时才创建 Headers 对象\n if (Object.keys(headers).length === 0) {\n return new Response(body, {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n // 有自定义 headers 时才创建 Headers 对象\n const h = new Headers({\n \"Content-Type\": \"application/json\",\n ...headers,\n });\n\n return new Response(body, {\n status,\n headers: h,\n });\n}\n\n// JSON 响应的预创建 headers(避免每次创建)\nconst JSON_HEADERS = { \"Content-Type\": \"application/json\" };\nconst TEXT_HEADERS = { \"Content-Type\": \"text/plain\" };\n\n/**\n * 类型特化的响应映射\n * 根据返回值类型直接生成 Response,避免不必要的检查\n */\nexport function mapResponse(response: unknown): Response {\n // 快速路径:已经是 Response\n if (response instanceof Response) return response;\n\n // 使用 constructor.name 进行类型判断(比 instanceof 更快)\n switch (response?.constructor?.name) {\n case \"String\":\n return new Response(response as string, { headers: TEXT_HEADERS });\n\n case \"Object\":\n case \"Array\":\n return new Response(JSON.stringify(response), { headers: JSON_HEADERS });\n\n case \"Number\":\n case \"Boolean\":\n return new Response(String(response), { headers: TEXT_HEADERS });\n\n case undefined:\n // null 或 undefined\n return new Response(null, { status: 204 });\n\n case \"ReadableStream\":\n return new Response(response as ReadableStream);\n\n case \"Blob\":\n return new Response(response as Blob);\n\n case \"ArrayBuffer\":\n return new Response(response as ArrayBuffer);\n\n case \"Uint8Array\":\n return new Response(response as unknown as BodyInit);\n\n default:\n // Promise 处理\n if (response instanceof Promise) {\n return response.then(mapResponse) as unknown as Response;\n }\n // 其他情况使用 JSON 序列化\n return new Response(JSON.stringify(response), { headers: JSON_HEADERS });\n }\n}\n\n/** 生成重定向响应 */\nexport function redirect(location: string, status: 301 | 302 = 302): Response {\n return new Response(null, {\n status,\n headers: {\n Location: location,\n },\n });\n}\n\n/** 生成纯文本响应 */\nexport function text(\n content: string,\n status = 200,\n headers: HeadersInit = {},\n): Response {\n const h = new Headers({\n \"Content-Type\": \"text/plain; charset=utf-8\",\n ...headers,\n });\n\n return new Response(content, {\n status,\n headers: h,\n });\n}\n\n/** 生成HTML响应 */\nexport function html(\n content: string,\n status = 200,\n headers: HeadersInit = {},\n): Response {\n const h = new Headers({\n \"Content-Type\": \"text/html; charset=utf-8\",\n ...headers,\n });\n\n return new Response(content, {\n status,\n headers: h,\n });\n}\n\n/** 生成空响应(204 No Content) */\nexport function empty(status = 204, headers: HeadersInit = {}): Response {\n return new Response(null, {\n status,\n headers,\n });\n}\n\n/** 生成流式响应 */\nexport function stream(\n stream: ReadableStream,\n status = 200,\n headers: HeadersInit = {},\n): Response {\n const h = new Headers({\n \"Content-Type\": \"application/octet-stream\",\n ...headers,\n });\n\n return new Response(stream, {\n status,\n headers: h,\n });\n}\n\n// ==================== 错误响应工具 ====================\n\n/**\n * 创建错误响应\n *\n * @param message - 错误信息\n * @param status - HTTP 状态码,默认 500\n * @param code - 业务错误码,默认等于 status\n *\n * @example\n * ```typescript\n * // 使用默认 code(等于 HTTP status)\n * throw err('用户不存在', 404)\n * // 响应: HTTP 404, { code: 404, message: \"用户不存在\" }\n *\n * // 使用自定义业务 code\n * throw err('用户不存在', 404, 10001)\n * // 响应: HTTP 404, { code: 10001, message: \"用户不存在\" }\n *\n * // 预定义错误\n * throw err.notFound('用户不存在')\n * throw err.notFound('用户不存在', 10001) // 带业务码\n * throw err.badRequest('参数错误')\n * throw err.unauthorized('请先登录')\n * ```\n */\nexport function err(message: string, status = 500, code?: number) {\n return new VafastError(message, { status, code: code ?? status, expose: true });\n}\n\n/** 400 Bad Request */\nerr.badRequest = (message = \"请求参数错误\", code?: number) =>\n err(message, 400, code);\n\n/** 401 Unauthorized */\nerr.unauthorized = (message = \"未授权\", code?: number) =>\n err(message, 401, code);\n\n/** 403 Forbidden */\nerr.forbidden = (message = \"禁止访问\", code?: number) =>\n err(message, 403, code);\n\n/** 404 Not Found */\nerr.notFound = (message = \"资源不存在\", code?: number) =>\n err(message, 404, code);\n\n/** 409 Conflict */\nerr.conflict = (message = \"资源冲突\", code?: number) =>\n err(message, 409, code);\n\n/** 422 Unprocessable Entity */\nerr.unprocessable = (message = \"无法处理的实体\", code?: number) =>\n err(message, 422, code);\n\n/** 429 Too Many Requests */\nerr.tooMany = (message = \"请求过于频繁\", code?: number) =>\n err(message, 429, code);\n\n/** 500 Internal Server Error */\nerr.internal = (message = \"服务器内部错误\", code?: number) =>\n err(message, 500, code);\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as VafastError } from "./middleware-
|
|
1
|
+
import { n as VafastError } from "./middleware-B_fMMYr3.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/utils/response.d.ts
|
|
4
4
|
/** 生成 JSON 响应 */
|
|
@@ -55,4 +55,4 @@ declare namespace err {
|
|
|
55
55
|
}
|
|
56
56
|
//#endregion
|
|
57
57
|
export { mapResponse as a, text as c, json as i, err as n, redirect as o, html as r, stream as s, empty as t };
|
|
58
|
-
//# sourceMappingURL=response-
|
|
58
|
+
//# sourceMappingURL=response-DsH8MnBO.d.mts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as ProcessedRoute, s as RouteSchema } from "./defineRoute-
|
|
2
|
-
import { n as Method } from "./types-
|
|
1
|
+
import { a as ProcessedRoute, s as RouteSchema } from "./defineRoute-DUYeO8TR.mjs";
|
|
2
|
+
import { n as Method } from "./types-BaIZETLg.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/utils/route-registry.d.ts
|
|
5
5
|
|
|
@@ -187,4 +187,4 @@ declare function filterRoutes<K extends string>(field: K): (RouteMeta & Record<K
|
|
|
187
187
|
declare function getRoutesByMethod(method: string): RouteMeta[];
|
|
188
188
|
//#endregion
|
|
189
189
|
export { getAllRoutes as a, getRoutesByMethod as c, filterRoutes as i, setGlobalRegistry as l, RouteRegistry as n, getRoute as o, createRouteRegistry as r, getRouteRegistry as s, RouteMeta as t };
|
|
190
|
-
//# sourceMappingURL=route-registry-
|
|
190
|
+
//# sourceMappingURL=route-registry-B0q_pJDC.d.mts.map
|
|
@@ -238,4 +238,4 @@ function getRoutesByMethod(method) {
|
|
|
238
238
|
|
|
239
239
|
//#endregion
|
|
240
240
|
export { getRoute as a, setGlobalRegistry as c, getAllRoutes as i, createRouteRegistry as n, getRouteRegistry as o, filterRoutes as r, getRoutesByMethod as s, RouteRegistry as t };
|
|
241
|
-
//# sourceMappingURL=route-registry-
|
|
241
|
+
//# sourceMappingURL=route-registry-ClmI5VwE.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-registry-
|
|
1
|
+
{"version":3,"file":"route-registry-ClmI5VwE.mjs","names":[],"sources":["../src/utils/route-registry.ts"],"sourcesContent":["/**\n * 路由注册表\n *\n * 提供路由元信息的收集和查询能力\n * 可用于:API 文档生成、Webhook 事件注册、权限检查、审计日志等\n *\n * @example\n * ```typescript\n * // 创建注册表\n * const registry = createRouteRegistry(server.getRoutes())\n *\n * // 查询路由\n * const route = registry.get('POST', '/auth/signIn')\n *\n * // 筛选有 webhook 配置的路由\n * const webhookRoutes = registry.filter('webhook')\n *\n * // 按分类获取\n * const authRoutes = registry.getByCategory('auth')\n * ```\n */\n\nimport type { Method } from '../types'\nimport type { ProcessedRoute, RouteSchema } from '../defineRoute'\n\n/**\n * 路由元信息(不含 handler 和 middleware)\n */\nexport interface RouteMeta {\n method: Method\n path: string\n name?: string\n description?: string\n /** Schema 定义(用于契约生成) */\n schema?: RouteSchema\n /** 扩展字段 */\n [key: string]: unknown\n}\n\n/**\n * 路由注册表\n *\n * 泛型 T 用于定义扩展字段的类型\n */\nexport class RouteRegistry<T extends Record<string, unknown> = Record<string, unknown>> {\n /** 所有路由元信息 */\n private routes: RouteMeta[] = []\n\n /** 路由映射表:METHOD:path -> RouteMeta */\n private routeMap = new Map<string, RouteMeta>()\n\n /** 分类映射表:category -> RouteMeta[] */\n private categoryMap = new Map<string, RouteMeta[]>()\n\n constructor(routes: ProcessedRoute[]) {\n this.buildRegistry(routes)\n }\n\n /**\n * 构建注册表\n */\n private buildRegistry(routes: ProcessedRoute[]): void {\n for (const route of routes) {\n // 提取元信息(排除 handler 和 middleware)\n const meta: RouteMeta = {\n method: route.method as Method,\n path: route.path,\n name: route.name,\n description: route.description,\n schema: route.schema, // 保留 schema 用于契约生成\n }\n\n // 检测 SSE handler 并添加标记\n const handler = route.handler as unknown as { __sse?: { readonly __brand: 'SSE' } }\n if (handler?.__sse?.__brand === 'SSE') {\n meta.sse = true\n }\n\n // 复制扩展字段\n for (const key of Object.keys(route)) {\n if (!['method', 'path', 'name', 'description', 'handler', 'middleware', 'schema', 'docs'].includes(key)) {\n meta[key] = route[key]\n }\n }\n\n this.routes.push(meta)\n this.routeMap.set(`${route.method}:${route.path}`, meta)\n\n // 按分类索引\n const category = this.extractCategory(route.path)\n if (!this.categoryMap.has(category)) {\n this.categoryMap.set(category, [])\n }\n this.categoryMap.get(category)!.push(meta)\n }\n }\n\n /**\n * 提取分类(第一段路径)\n */\n private extractCategory(path: string): string {\n const segments = path.split('/').filter(Boolean)\n return segments[0] || 'root'\n }\n\n // ============================================\n // 查询接口\n // ============================================\n\n /**\n * 获取所有路由元信息\n */\n getAll(): RouteMeta[] {\n return [...this.routes]\n }\n\n /**\n * 按 method + path 查询路由\n */\n get(method: string, path: string): (RouteMeta & T) | undefined {\n return this.routeMap.get(`${method}:${path}`) as (RouteMeta & T) | undefined\n }\n\n /**\n * 检查路由是否存在\n */\n has(method: string, path: string): boolean {\n return this.routeMap.has(`${method}:${path}`)\n }\n\n /**\n * 按分类获取路由\n */\n getByCategory(category: string): RouteMeta[] {\n return this.categoryMap.get(category) || []\n }\n\n /**\n * 获取所有分类\n */\n getCategories(): string[] {\n return Array.from(this.categoryMap.keys()).sort()\n }\n\n /**\n * 筛选有特定字段的路由\n *\n * @example\n * ```typescript\n * // 获取所有配置了 webhook 的路由\n * const webhookRoutes = registry.filter('webhook')\n * ```\n */\n filter<K extends string>(field: K): (RouteMeta & Record<K, unknown>)[] {\n return this.routes.filter((r) => field in r && r[field] !== undefined) as (RouteMeta & Record<K, unknown>)[]\n }\n\n /**\n * 按条件筛选路由\n *\n * @example\n * ```typescript\n * // 获取所有 POST 请求\n * const postRoutes = registry.filterBy(r => r.method === 'POST')\n * ```\n */\n filterBy(predicate: (route: RouteMeta) => boolean): RouteMeta[] {\n return this.routes.filter(predicate)\n }\n\n /**\n * 获取路由数量\n */\n get size(): number {\n return this.routes.length\n }\n\n /**\n * 遍历所有路由\n */\n forEach(callback: (route: RouteMeta, index: number) => void): void {\n this.routes.forEach(callback)\n }\n\n /**\n * 映射所有路由\n */\n map<R>(callback: (route: RouteMeta, index: number) => R): R[] {\n return this.routes.map(callback)\n }\n}\n\n/**\n * 创建路由注册表\n *\n * @example\n * ```typescript\n * // 定义扩展字段类型\n * interface MyRouteMeta {\n * webhook?: { eventKey: string }\n * permission?: string\n * }\n *\n * // 创建带类型的注册表\n * const registry = createRouteRegistry<MyRouteMeta>(server.getRoutes())\n *\n * // 类型安全的查询\n * const route = registry.get('POST', '/auth/signIn')\n * if (route?.webhook) {\n * console.log(route.webhook.eventKey)\n * }\n * ```\n */\nexport function createRouteRegistry<T extends Record<string, unknown> = Record<string, unknown>>(\n routes: ProcessedRoute[]\n): RouteRegistry<T> {\n return new RouteRegistry<T>(routes)\n}\n\n// ============================================\n// 全局 Registry(单例模式)\n// ============================================\n\n/** 全局 registry 实例 */\nlet globalRegistry: RouteRegistry | null = null\n\n/**\n * 设置全局 registry(框架内部使用)\n * @internal\n */\nexport function setGlobalRegistry(registry: RouteRegistry): void {\n globalRegistry = registry\n}\n\n/**\n * 获取全局路由注册表\n *\n * @example\n * ```typescript\n * // 在任意文件中\n * import { getRouteRegistry } from 'vafast'\n *\n * const registry = getRouteRegistry()\n * const webhookRoutes = registry.filter('webhook')\n * ```\n *\n * @throws 如果 Server 尚未创建\n */\nexport function getRouteRegistry<T extends Record<string, unknown> = Record<string, unknown>>(): RouteRegistry<T> {\n if (!globalRegistry) {\n throw new Error('RouteRegistry not initialized. Make sure Server is created first.')\n }\n return globalRegistry as RouteRegistry<T>\n}\n\n/**\n * 按 method + path 获取单个路由\n *\n * 便捷函数,无需先获取 registry\n *\n * @example\n * ```typescript\n * // 在中间件或接口中\n * import { getRoute } from 'vafast'\n *\n * const route = getRoute('POST', '/auth/signIn')\n * if (route?.webhook) {\n * console.log('This route has webhook:', route.webhook)\n * }\n * ```\n */\nexport function getRoute<T extends Record<string, unknown> = Record<string, unknown>>(\n method: string,\n path: string\n): (RouteMeta & T) | undefined {\n return getRouteRegistry<T>().get(method, path)\n}\n\n/**\n * 获取所有路由\n *\n * @example\n * ```typescript\n * import { getAllRoutes } from 'vafast'\n *\n * const routes = getAllRoutes()\n * console.log(`Total ${routes.length} routes`)\n * ```\n */\nexport function getAllRoutes(): RouteMeta[] {\n return getRouteRegistry().getAll()\n}\n\n/**\n * 筛选有特定字段的路由\n *\n * @example\n * ```typescript\n * import { filterRoutes } from 'vafast'\n *\n * // 获取所有配置了 webhook 的路由\n * const webhookRoutes = filterRoutes('webhook')\n * ```\n */\nexport function filterRoutes<K extends string>(field: K): (RouteMeta & Record<K, unknown>)[] {\n return getRouteRegistry().filter(field)\n}\n\n/**\n * 按 HTTP 方法获取路由\n *\n * @example\n * ```typescript\n * import { getRoutesByMethod } from 'vafast'\n *\n * const getRoutes = getRoutesByMethod('GET')\n * const postRoutes = getRoutesByMethod('POST')\n * ```\n */\nexport function getRoutesByMethod(method: string): RouteMeta[] {\n return getRouteRegistry().filterBy(r => r.method === method)\n}\n\n"],"mappings":";;;;;;AA4CA,IAAa,gBAAb,MAAwF;;CAEtF,AAAQ,SAAsB,EAAE;;CAGhC,AAAQ,2BAAW,IAAI,KAAwB;;CAG/C,AAAQ,8BAAc,IAAI,KAA0B;CAEpD,YAAY,QAA0B;AACpC,OAAK,cAAc,OAAO;;;;;CAM5B,AAAQ,cAAc,QAAgC;AACpD,OAAK,MAAM,SAAS,QAAQ;GAE1B,MAAM,OAAkB;IACtB,QAAQ,MAAM;IACd,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,aAAa,MAAM;IACnB,QAAQ,MAAM;IACf;AAID,OADgB,MAAM,SACT,OAAO,YAAY,MAC9B,MAAK,MAAM;AAIb,QAAK,MAAM,OAAO,OAAO,KAAK,MAAM,CAClC,KAAI,CAAC;IAAC;IAAU;IAAQ;IAAQ;IAAe;IAAW;IAAc;IAAU;IAAO,CAAC,SAAS,IAAI,CACrG,MAAK,OAAO,MAAM;AAItB,QAAK,OAAO,KAAK,KAAK;AACtB,QAAK,SAAS,IAAI,GAAG,MAAM,OAAO,GAAG,MAAM,QAAQ,KAAK;GAGxD,MAAM,WAAW,KAAK,gBAAgB,MAAM,KAAK;AACjD,OAAI,CAAC,KAAK,YAAY,IAAI,SAAS,CACjC,MAAK,YAAY,IAAI,UAAU,EAAE,CAAC;AAEpC,QAAK,YAAY,IAAI,SAAS,CAAE,KAAK,KAAK;;;;;;CAO9C,AAAQ,gBAAgB,MAAsB;AAE5C,SADiB,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ,CAChC,MAAM;;;;;CAUxB,SAAsB;AACpB,SAAO,CAAC,GAAG,KAAK,OAAO;;;;;CAMzB,IAAI,QAAgB,MAA2C;AAC7D,SAAO,KAAK,SAAS,IAAI,GAAG,OAAO,GAAG,OAAO;;;;;CAM/C,IAAI,QAAgB,MAAuB;AACzC,SAAO,KAAK,SAAS,IAAI,GAAG,OAAO,GAAG,OAAO;;;;;CAM/C,cAAc,UAA+B;AAC3C,SAAO,KAAK,YAAY,IAAI,SAAS,IAAI,EAAE;;;;;CAM7C,gBAA0B;AACxB,SAAO,MAAM,KAAK,KAAK,YAAY,MAAM,CAAC,CAAC,MAAM;;;;;;;;;;;CAYnD,OAAyB,OAA8C;AACrE,SAAO,KAAK,OAAO,QAAQ,MAAM,SAAS,KAAK,EAAE,WAAW,OAAU;;;;;;;;;;;CAYxE,SAAS,WAAuD;AAC9D,SAAO,KAAK,OAAO,OAAO,UAAU;;;;;CAMtC,IAAI,OAAe;AACjB,SAAO,KAAK,OAAO;;;;;CAMrB,QAAQ,UAA2D;AACjE,OAAK,OAAO,QAAQ,SAAS;;;;;CAM/B,IAAO,UAAuD;AAC5D,SAAO,KAAK,OAAO,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;AAyBpC,SAAgB,oBACd,QACkB;AAClB,QAAO,IAAI,cAAiB,OAAO;;;AAQrC,IAAI,iBAAuC;;;;;AAM3C,SAAgB,kBAAkB,UAA+B;AAC/D,kBAAiB;;;;;;;;;;;;;;;;AAiBnB,SAAgB,mBAAkG;AAChH,KAAI,CAAC,eACH,OAAM,IAAI,MAAM,oEAAoE;AAEtF,QAAO;;;;;;;;;;;;;;;;;;AAmBT,SAAgB,SACd,QACA,MAC6B;AAC7B,QAAO,kBAAqB,CAAC,IAAI,QAAQ,KAAK;;;;;;;;;;;;;AAchD,SAAgB,eAA4B;AAC1C,QAAO,kBAAkB,CAAC,QAAQ;;;;;;;;;;;;;AAcpC,SAAgB,aAA+B,OAA8C;AAC3F,QAAO,kBAAkB,CAAC,OAAO,MAAM;;;;;;;;;;;;;AAczC,SAAgB,kBAAkB,QAA6B;AAC7D,QAAO,kBAAkB,CAAC,UAAS,MAAK,EAAE,WAAW,OAAO"}
|
package/dist/router/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as createProxyRequest } from "./request-
|
|
2
|
-
import { t as writeResponse } from "./response-
|
|
1
|
+
import { t as createProxyRequest } from "./request-COqaDa-c.mjs";
|
|
2
|
+
import { t as writeResponse } from "./response-BK2pYq43.mjs";
|
|
3
3
|
import { createServer } from "node:http";
|
|
4
4
|
|
|
5
5
|
//#region src/node-server/serve.ts
|
|
@@ -144,4 +144,4 @@ function createAdaptorServer(fetch, onError, timeout, bodyLimit, trustProxy) {
|
|
|
144
144
|
|
|
145
145
|
//#endregion
|
|
146
146
|
export { serve as n, createAdaptorServer as t };
|
|
147
|
-
//# sourceMappingURL=serve-
|
|
147
|
+
//# sourceMappingURL=serve-CozN9Tlz.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve-Cj0bYhav.mjs","names":["timeout"],"sources":["../src/node-server/serve.ts"],"sourcesContent":["/**\n * Node.js 服务器适配器\n * 提供类似 Bun.serve 的 API\n */\n\nimport {\n createServer,\n type Server as HttpServer,\n type IncomingMessage,\n type ServerResponse,\n} from \"node:http\";\nimport { createProxyRequest } from \"./request\";\nimport { writeResponse } from \"./response\";\n\n/** fetch 函数类型 */\nexport type FetchHandler = (request: Request) => Response | Promise<Response>;\n\n/** 优雅关闭配置 */\nexport interface GracefulShutdownOptions {\n /** 关闭超时时间(毫秒),默认 30000 */\n timeout?: number;\n /** 关闭前回调 */\n onShutdown?: () => void | Promise<void>;\n /** 关闭完成回调 */\n onShutdownComplete?: () => void;\n /** 监听的信号,默认 ['SIGINT', 'SIGTERM'] */\n signals?: NodeJS.Signals[];\n}\n\n/**\n * 请求超时配置\n *\n * 默认行为与 Fastify 和 Node.js 一致:\n * - requestTimeout: 0(无限制,需显式设置以防 DoS 攻击)\n * - headersTimeout: 使用 Node.js 默认值 60000ms\n * - keepAliveTimeout: 使用 Node.js 默认值 5000ms\n *\n * @see https://fastify.dev/docs/latest/Reference/Server/#requesttimeout\n */\nexport interface RequestTimeoutOptions {\n /**\n * 单个请求的最大处理时间(毫秒)\n * - 默认: 0(无限制)\n * - 建议: 如果没有反向代理,设置为 30000-120000 以防 DoS\n */\n requestTimeout?: number;\n /**\n * 接收完整请求头的超时时间(毫秒)\n * - 不设置则使用 Node.js 默认值(60000ms)\n */\n headersTimeout?: number;\n /**\n * Keep-Alive 连接空闲超时时间(毫秒)\n * - 不设置则使用 Node.js 默认值(5000ms)\n */\n keepAliveTimeout?: number;\n /**\n * 超时时返回的 JSON 响应\n * - 默认: { code: 504, message: \"Request timeout\" }\n */\n timeoutResponse?: { code: number; message: string };\n}\n\n/**\n * 信任代理配置\n * - true: 信任所有代理,从 X-Forwarded-For 等头获取真实 IP\n * - false: 不信任代理,使用 socket IP(默认)\n * - string: 信任特定 IP 或 CIDR(如 \"127.0.0.1\" 或 \"10.0.0.0/8\")\n * - string[]: 信任多个 IP 或 CIDR\n */\nexport type TrustProxyOption = boolean | string | string[];\n\n/** serve 配置选项 */\nexport interface ServeOptions {\n /** fetch 处理函数 */\n fetch: FetchHandler;\n /** 端口号,默认 3000 */\n port?: number;\n /** 主机名,默认 0.0.0.0 */\n hostname?: string;\n /** 错误处理函数 */\n onError?: (error: Error) => Response | Promise<Response>;\n /** 优雅关闭配置,设置为 true 使用默认配置 */\n gracefulShutdown?: boolean | GracefulShutdownOptions;\n /** 请求超时配置 */\n timeout?: RequestTimeoutOptions;\n /**\n * 请求体大小限制(字节)\n * - 默认: 1048576 (1MB)\n * - 设置为 0 表示不限制\n * - 超过限制返回 413 Payload Too Large\n */\n bodyLimit?: number;\n /**\n * 信任代理配置\n * - true: 信任所有代理,从 X-Forwarded-For 等头获取真实 IP\n * - false: 不信任代理,使用 socket IP(默认)\n * - string/string[]: 信任特定 IP 或 CIDR\n * \n * 启用后,request 对象会附加 ip 和 ips 属性\n */\n trustProxy?: TrustProxyOption;\n}\n\n/** serve 返回的服务器信息 */\nexport interface ServeResult {\n /** Node.js HTTP Server 实例 */\n server: HttpServer;\n /** 服务器端口 */\n port: number;\n /** 服务器主机名 */\n hostname: string;\n /** 关闭服务器 */\n stop: () => Promise<void>;\n /** 优雅关闭(等待现有请求完成) */\n shutdown: () => Promise<void>;\n}\n\n/** 默认请求体大小限制:1MB */\nconst DEFAULT_BODY_LIMIT = 1048576;\n\n/**\n * 创建请求处理函数\n */\nfunction createRequestHandler(\n fetch: FetchHandler,\n defaultHost: string,\n onError?: (error: Error) => Response | Promise<Response>,\n timeoutOptions?: RequestTimeoutOptions,\n bodyLimit?: number,\n trustProxy?: TrustProxyOption,\n) {\n const requestTimeout = timeoutOptions?.requestTimeout ?? 0;\n const timeoutResponse = timeoutOptions?.timeoutResponse ?? {\n code: 504,\n message: \"Request timeout\",\n };\n // bodyLimit: undefined 使用默认值,0 表示不限制\n const maxBodySize = bodyLimit === undefined ? DEFAULT_BODY_LIMIT : bodyLimit;\n\n return async (incoming: IncomingMessage, outgoing: ServerResponse) => {\n // 检查请求体大小限制\n if (maxBodySize > 0) {\n const contentLength = incoming.headers[\"content-length\"];\n if (contentLength && parseInt(contentLength, 10) > maxBodySize) {\n outgoing.statusCode = 413;\n outgoing.setHeader(\"Content-Type\", \"application/json\");\n outgoing.end(JSON.stringify({\n code: 413,\n message: \"Payload Too Large\",\n limit: maxBodySize,\n }));\n return;\n }\n }\n\n // 请求级别超时处理\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let isTimedOut = false;\n\n if (requestTimeout > 0) {\n timeoutId = setTimeout(() => {\n isTimedOut = true;\n if (!outgoing.headersSent) {\n outgoing.statusCode = 504;\n outgoing.setHeader(\"Content-Type\", \"application/json\");\n outgoing.end(JSON.stringify(timeoutResponse));\n }\n }, requestTimeout);\n }\n\n try {\n // 创建代理 Request(延迟创建真实 Request)\n const request = createProxyRequest(incoming, defaultHost, { trustProxy });\n\n // 调用 fetch handler\n const response = await fetch(request);\n\n // 清除超时定时器\n if (timeoutId) clearTimeout(timeoutId);\n\n // 如果已超时,不再写入响应\n if (isTimedOut) return;\n\n // 流式写入 Response\n await writeResponse(response, outgoing);\n } catch (error) {\n // 清除超时定时器\n if (timeoutId) clearTimeout(timeoutId);\n\n // 如果已超时,不再处理错误\n if (isTimedOut) return;\n\n // 错误处理\n const err = error instanceof Error ? error : new Error(String(error));\n\n if (onError) {\n try {\n const errorResponse = await onError(err);\n await writeResponse(errorResponse, outgoing);\n return;\n } catch {\n // onError 也失败了,返回 500\n }\n }\n\n // 默认错误响应\n if (!outgoing.headersSent) {\n outgoing.statusCode = 500;\n outgoing.setHeader(\"Content-Type\", \"text/plain\");\n outgoing.end(\"Internal Server Error\");\n }\n }\n };\n}\n\n/**\n * 启动 HTTP 服务器\n *\n * @example\n * ```ts\n * import { serve } from \"@vafast/node-server\";\n * import { Server } from \"vafast\";\n *\n * const app = new Server([\n * { method: \"GET\", path: \"/\", handler: () => \"Hello World\" },\n * ]);\n *\n * serve({ fetch: app.fetch, port: 3000 }, () => {\n * console.log(\"Server running on http://localhost:3000\");\n * });\n * ```\n */\nexport function serve(\n options: ServeOptions,\n callback?: () => void,\n): ServeResult {\n const { fetch, port = 3000, hostname = \"0.0.0.0\", onError, gracefulShutdown, timeout, bodyLimit, trustProxy } = options;\n\n const defaultHost = `${hostname === \"0.0.0.0\" ? \"localhost\" : hostname}:${port}`;\n const handler = createRequestHandler(fetch, defaultHost, onError, timeout, bodyLimit, trustProxy);\n\n const server = createServer(handler);\n\n // 设置服务器级别超时(Node.js 原生能力)\n if (timeout) {\n // headersTimeout: 接收完整请求头的超时时间\n if (timeout.headersTimeout !== undefined) {\n server.headersTimeout = timeout.headersTimeout;\n }\n // keepAliveTimeout: Keep-Alive 连接空闲超时时间\n if (timeout.keepAliveTimeout !== undefined) {\n server.keepAliveTimeout = timeout.keepAliveTimeout;\n }\n }\n\n // 追踪活跃连接\n const connections = new Set<import(\"node:net\").Socket>();\n\n server.on(\"connection\", (socket) => {\n connections.add(socket);\n socket.on(\"close\", () => connections.delete(socket));\n });\n\n // 优雅关闭函数\n let isShuttingDown = false;\n\n const shutdown = async (): Promise<void> => {\n if (isShuttingDown) return;\n isShuttingDown = true;\n\n const shutdownOptions: GracefulShutdownOptions =\n typeof gracefulShutdown === \"object\" ? gracefulShutdown : {};\n\n const timeout = shutdownOptions.timeout ?? 30000;\n\n // 执行关闭前回调\n if (shutdownOptions.onShutdown) {\n await shutdownOptions.onShutdown();\n }\n\n return new Promise<void>((resolve) => {\n // 设置超时强制关闭\n const forceCloseTimer = setTimeout(() => {\n // 强制关闭所有连接\n for (const socket of connections) {\n socket.destroy();\n }\n connections.clear();\n resolve();\n }, timeout);\n\n // 停止接受新连接\n server.close(() => {\n clearTimeout(forceCloseTimer);\n shutdownOptions.onShutdownComplete?.();\n resolve();\n });\n\n // 关闭空闲连接\n for (const socket of connections) {\n // 如果连接空闲,立即关闭\n if (!socket.writableLength) {\n socket.end();\n }\n }\n });\n };\n\n // 注册信号处理\n if (gracefulShutdown) {\n const shutdownOptions: GracefulShutdownOptions =\n typeof gracefulShutdown === \"object\" ? gracefulShutdown : {};\n\n const signals = shutdownOptions.signals ?? [\"SIGINT\", \"SIGTERM\"];\n\n for (const signal of signals) {\n process.on(signal, () => {\n shutdown().then(() => process.exit(0));\n });\n }\n }\n\n // 启动服务器\n server.listen(port, hostname, callback);\n\n return {\n server,\n port,\n hostname,\n stop: () =>\n new Promise<void>((resolve, reject) => {\n server.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n }),\n shutdown,\n };\n}\n\n/**\n * 创建适配器服务器(不自动启动)\n * 用于需要更多控制的场景\n */\nexport function createAdaptorServer(\n fetch: FetchHandler,\n onError?: (error: Error) => Response | Promise<Response>,\n timeout?: RequestTimeoutOptions,\n bodyLimit?: number,\n trustProxy?: TrustProxyOption,\n): HttpServer {\n const handler = createRequestHandler(fetch, \"localhost\", onError, timeout, bodyLimit, trustProxy);\n return createServer(handler);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"serve-CozN9Tlz.mjs","names":["timeout"],"sources":["../src/node-server/serve.ts"],"sourcesContent":["/**\n * Node.js 服务器适配器\n * 提供类似 Bun.serve 的 API\n */\n\nimport {\n createServer,\n type Server as HttpServer,\n type IncomingMessage,\n type ServerResponse,\n} from \"node:http\";\nimport { createProxyRequest } from \"./request\";\nimport { writeResponse } from \"./response\";\n\n/** fetch 函数类型 */\nexport type FetchHandler = (request: Request) => Response | Promise<Response>;\n\n/** 优雅关闭配置 */\nexport interface GracefulShutdownOptions {\n /** 关闭超时时间(毫秒),默认 30000 */\n timeout?: number;\n /** 关闭前回调 */\n onShutdown?: () => void | Promise<void>;\n /** 关闭完成回调 */\n onShutdownComplete?: () => void;\n /** 监听的信号,默认 ['SIGINT', 'SIGTERM'] */\n signals?: NodeJS.Signals[];\n}\n\n/**\n * 请求超时配置\n *\n * 默认行为与 Fastify 和 Node.js 一致:\n * - requestTimeout: 0(无限制,需显式设置以防 DoS 攻击)\n * - headersTimeout: 使用 Node.js 默认值 60000ms\n * - keepAliveTimeout: 使用 Node.js 默认值 5000ms\n *\n * @see https://fastify.dev/docs/latest/Reference/Server/#requesttimeout\n */\nexport interface RequestTimeoutOptions {\n /**\n * 单个请求的最大处理时间(毫秒)\n * - 默认: 0(无限制)\n * - 建议: 如果没有反向代理,设置为 30000-120000 以防 DoS\n */\n requestTimeout?: number;\n /**\n * 接收完整请求头的超时时间(毫秒)\n * - 不设置则使用 Node.js 默认值(60000ms)\n */\n headersTimeout?: number;\n /**\n * Keep-Alive 连接空闲超时时间(毫秒)\n * - 不设置则使用 Node.js 默认值(5000ms)\n */\n keepAliveTimeout?: number;\n /**\n * 超时时返回的 JSON 响应\n * - 默认: { code: 504, message: \"Request timeout\" }\n */\n timeoutResponse?: { code: number; message: string };\n}\n\n/**\n * 信任代理配置\n * - true: 信任所有代理,从 X-Forwarded-For 等头获取真实 IP\n * - false: 不信任代理,使用 socket IP(默认)\n * - string: 信任特定 IP 或 CIDR(如 \"127.0.0.1\" 或 \"10.0.0.0/8\")\n * - string[]: 信任多个 IP 或 CIDR\n */\nexport type TrustProxyOption = boolean | string | string[];\n\n/** serve 配置选项 */\nexport interface ServeOptions {\n /** fetch 处理函数 */\n fetch: FetchHandler;\n /** 端口号,默认 3000 */\n port?: number;\n /** 主机名,默认 0.0.0.0 */\n hostname?: string;\n /** 错误处理函数 */\n onError?: (error: Error) => Response | Promise<Response>;\n /** 优雅关闭配置,设置为 true 使用默认配置 */\n gracefulShutdown?: boolean | GracefulShutdownOptions;\n /** 请求超时配置 */\n timeout?: RequestTimeoutOptions;\n /**\n * 请求体大小限制(字节)\n * - 默认: 1048576 (1MB)\n * - 设置为 0 表示不限制\n * - 超过限制返回 413 Payload Too Large\n */\n bodyLimit?: number;\n /**\n * 信任代理配置\n * - true: 信任所有代理,从 X-Forwarded-For 等头获取真实 IP\n * - false: 不信任代理,使用 socket IP(默认)\n * - string/string[]: 信任特定 IP 或 CIDR\n * \n * 启用后,request 对象会附加 ip 和 ips 属性\n */\n trustProxy?: TrustProxyOption;\n}\n\n/** serve 返回的服务器信息 */\nexport interface ServeResult {\n /** Node.js HTTP Server 实例 */\n server: HttpServer;\n /** 服务器端口 */\n port: number;\n /** 服务器主机名 */\n hostname: string;\n /** 关闭服务器 */\n stop: () => Promise<void>;\n /** 优雅关闭(等待现有请求完成) */\n shutdown: () => Promise<void>;\n}\n\n/** 默认请求体大小限制:1MB */\nconst DEFAULT_BODY_LIMIT = 1048576;\n\n/**\n * 创建请求处理函数\n */\nfunction createRequestHandler(\n fetch: FetchHandler,\n defaultHost: string,\n onError?: (error: Error) => Response | Promise<Response>,\n timeoutOptions?: RequestTimeoutOptions,\n bodyLimit?: number,\n trustProxy?: TrustProxyOption,\n) {\n const requestTimeout = timeoutOptions?.requestTimeout ?? 0;\n const timeoutResponse = timeoutOptions?.timeoutResponse ?? {\n code: 504,\n message: \"Request timeout\",\n };\n // bodyLimit: undefined 使用默认值,0 表示不限制\n const maxBodySize = bodyLimit === undefined ? DEFAULT_BODY_LIMIT : bodyLimit;\n\n return async (incoming: IncomingMessage, outgoing: ServerResponse) => {\n // 检查请求体大小限制\n if (maxBodySize > 0) {\n const contentLength = incoming.headers[\"content-length\"];\n if (contentLength && parseInt(contentLength, 10) > maxBodySize) {\n outgoing.statusCode = 413;\n outgoing.setHeader(\"Content-Type\", \"application/json\");\n outgoing.end(JSON.stringify({\n code: 413,\n message: \"Payload Too Large\",\n limit: maxBodySize,\n }));\n return;\n }\n }\n\n // 请求级别超时处理\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let isTimedOut = false;\n\n if (requestTimeout > 0) {\n timeoutId = setTimeout(() => {\n isTimedOut = true;\n if (!outgoing.headersSent) {\n outgoing.statusCode = 504;\n outgoing.setHeader(\"Content-Type\", \"application/json\");\n outgoing.end(JSON.stringify(timeoutResponse));\n }\n }, requestTimeout);\n }\n\n try {\n // 创建代理 Request(延迟创建真实 Request)\n const request = createProxyRequest(incoming, defaultHost, { trustProxy });\n\n // 调用 fetch handler\n const response = await fetch(request);\n\n // 清除超时定时器\n if (timeoutId) clearTimeout(timeoutId);\n\n // 如果已超时,不再写入响应\n if (isTimedOut) return;\n\n // 流式写入 Response\n await writeResponse(response, outgoing);\n } catch (error) {\n // 清除超时定时器\n if (timeoutId) clearTimeout(timeoutId);\n\n // 如果已超时,不再处理错误\n if (isTimedOut) return;\n\n // 错误处理\n const err = error instanceof Error ? error : new Error(String(error));\n\n if (onError) {\n try {\n const errorResponse = await onError(err);\n await writeResponse(errorResponse, outgoing);\n return;\n } catch {\n // onError 也失败了,返回 500\n }\n }\n\n // 默认错误响应\n if (!outgoing.headersSent) {\n outgoing.statusCode = 500;\n outgoing.setHeader(\"Content-Type\", \"text/plain\");\n outgoing.end(\"Internal Server Error\");\n }\n }\n };\n}\n\n/**\n * 启动 HTTP 服务器\n *\n * @example\n * ```ts\n * import { serve } from \"@vafast/node-server\";\n * import { Server } from \"vafast\";\n *\n * const app = new Server([\n * { method: \"GET\", path: \"/\", handler: () => \"Hello World\" },\n * ]);\n *\n * serve({ fetch: app.fetch, port: 3000 }, () => {\n * console.log(\"Server running on http://localhost:3000\");\n * });\n * ```\n */\nexport function serve(\n options: ServeOptions,\n callback?: () => void,\n): ServeResult {\n const { fetch, port = 3000, hostname = \"0.0.0.0\", onError, gracefulShutdown, timeout, bodyLimit, trustProxy } = options;\n\n const defaultHost = `${hostname === \"0.0.0.0\" ? \"localhost\" : hostname}:${port}`;\n const handler = createRequestHandler(fetch, defaultHost, onError, timeout, bodyLimit, trustProxy);\n\n const server = createServer(handler);\n\n // 设置服务器级别超时(Node.js 原生能力)\n if (timeout) {\n // headersTimeout: 接收完整请求头的超时时间\n if (timeout.headersTimeout !== undefined) {\n server.headersTimeout = timeout.headersTimeout;\n }\n // keepAliveTimeout: Keep-Alive 连接空闲超时时间\n if (timeout.keepAliveTimeout !== undefined) {\n server.keepAliveTimeout = timeout.keepAliveTimeout;\n }\n }\n\n // 追踪活跃连接\n const connections = new Set<import(\"node:net\").Socket>();\n\n server.on(\"connection\", (socket) => {\n connections.add(socket);\n socket.on(\"close\", () => connections.delete(socket));\n });\n\n // 优雅关闭函数\n let isShuttingDown = false;\n\n const shutdown = async (): Promise<void> => {\n if (isShuttingDown) return;\n isShuttingDown = true;\n\n const shutdownOptions: GracefulShutdownOptions =\n typeof gracefulShutdown === \"object\" ? gracefulShutdown : {};\n\n const timeout = shutdownOptions.timeout ?? 30000;\n\n // 执行关闭前回调\n if (shutdownOptions.onShutdown) {\n await shutdownOptions.onShutdown();\n }\n\n return new Promise<void>((resolve) => {\n // 设置超时强制关闭\n const forceCloseTimer = setTimeout(() => {\n // 强制关闭所有连接\n for (const socket of connections) {\n socket.destroy();\n }\n connections.clear();\n resolve();\n }, timeout);\n\n // 停止接受新连接\n server.close(() => {\n clearTimeout(forceCloseTimer);\n shutdownOptions.onShutdownComplete?.();\n resolve();\n });\n\n // 关闭空闲连接\n for (const socket of connections) {\n // 如果连接空闲,立即关闭\n if (!socket.writableLength) {\n socket.end();\n }\n }\n });\n };\n\n // 注册信号处理\n if (gracefulShutdown) {\n const shutdownOptions: GracefulShutdownOptions =\n typeof gracefulShutdown === \"object\" ? gracefulShutdown : {};\n\n const signals = shutdownOptions.signals ?? [\"SIGINT\", \"SIGTERM\"];\n\n for (const signal of signals) {\n process.on(signal, () => {\n shutdown().then(() => process.exit(0));\n });\n }\n }\n\n // 启动服务器\n server.listen(port, hostname, callback);\n\n return {\n server,\n port,\n hostname,\n stop: () =>\n new Promise<void>((resolve, reject) => {\n server.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n }),\n shutdown,\n };\n}\n\n/**\n * 创建适配器服务器(不自动启动)\n * 用于需要更多控制的场景\n */\nexport function createAdaptorServer(\n fetch: FetchHandler,\n onError?: (error: Error) => Response | Promise<Response>,\n timeout?: RequestTimeoutOptions,\n bodyLimit?: number,\n trustProxy?: TrustProxyOption,\n): HttpServer {\n const handler = createRequestHandler(fetch, \"localhost\", onError, timeout, bodyLimit, trustProxy);\n return createServer(handler);\n}\n"],"mappings":"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"}
|
|
@@ -128,4 +128,4 @@ declare function serve(options: ServeOptions, callback?: () => void): ServeResul
|
|
|
128
128
|
declare function createAdaptorServer(fetch: FetchHandler, onError?: (error: Error) => Response | Promise<Response>, timeout?: RequestTimeoutOptions, bodyLimit?: number, trustProxy?: TrustProxyOption): Server;
|
|
129
129
|
//#endregion
|
|
130
130
|
export { ServeResult as a, serve as c, ServeOptions as i, GracefulShutdownOptions as n, TrustProxyOption as o, RequestTimeoutOptions as r, createAdaptorServer as s, FetchHandler as t };
|
|
131
|
-
//# sourceMappingURL=serve-
|
|
131
|
+
//# sourceMappingURL=serve-Dh6Ux5Pg.d.mts.map
|
package/dist/serve.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ServeResult, c as serve, i as ServeOptions, n as GracefulShutdownOptions, o as TrustProxyOption, r as RequestTimeoutOptions, s as createAdaptorServer, t as FetchHandler } from "./serve-
|
|
1
|
+
import { a as ServeResult, c as serve, i as ServeOptions, n as GracefulShutdownOptions, o as TrustProxyOption, r as RequestTimeoutOptions, s as createAdaptorServer, t as FetchHandler } from "./serve-Dh6Ux5Pg.mjs";
|
|
2
2
|
export { type FetchHandler, type GracefulShutdownOptions, type RequestTimeoutOptions, type ServeOptions, type ServeResult, type TrustProxyOption, createAdaptorServer, serve };
|
package/dist/serve.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as BaseServer } from "../base-server-
|
|
1
|
+
import { t as BaseServer } from "../base-server-DDNu97SA.mjs";
|
|
2
2
|
export { BaseServer };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as ComponentServer } from "../component-server-
|
|
1
|
+
import { t as ComponentServer } from "../component-server-CVhgbxOe.mjs";
|
|
2
2
|
export { ComponentServer };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "../dependency-manager-
|
|
2
|
-
import { t as ComponentServer } from "../component-server-
|
|
1
|
+
import "../dependency-manager-DaDThGEc.mjs";
|
|
2
|
+
import { t as ComponentServer } from "../component-server-llGj--XB.mjs";
|
|
3
3
|
|
|
4
4
|
export { ComponentServer };
|
package/dist/server/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import "../defineRoute-
|
|
2
|
-
import { t as BaseServer } from "../base-server-
|
|
3
|
-
import { t as Server } from "../server-
|
|
4
|
-
import { t as ComponentServer } from "../component-server-
|
|
5
|
-
import { t as ServerFactory } from "../index-
|
|
1
|
+
import "../defineRoute-DUYeO8TR.mjs";
|
|
2
|
+
import { t as BaseServer } from "../base-server-DDNu97SA.mjs";
|
|
3
|
+
import { t as Server } from "../server-Dr_qEIqu.mjs";
|
|
4
|
+
import { t as ComponentServer } from "../component-server-CVhgbxOe.mjs";
|
|
5
|
+
import { t as ServerFactory } from "../index-DgIsC7ua.mjs";
|
|
6
6
|
export { BaseServer, ComponentServer, Server, ServerFactory };
|
package/dist/server/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import
|
|
3
|
-
import { t as
|
|
4
|
-
import "../
|
|
5
|
-
import
|
|
6
|
-
import { t as
|
|
1
|
+
import "../validation-errors-j7DAULlG.mjs";
|
|
2
|
+
import "../response-BlkS--Fb.mjs";
|
|
3
|
+
import { t as BaseServer } from "../base-server-CbnxNoNf.mjs";
|
|
4
|
+
import { t as Server } from "../server-Dtk8M7eI.mjs";
|
|
5
|
+
import "../dependency-manager-DaDThGEc.mjs";
|
|
6
|
+
import { t as ComponentServer } from "../component-server-llGj--XB.mjs";
|
|
7
|
+
import { t as ServerFactory } from "../server-D-jaEU-V.mjs";
|
|
7
8
|
|
|
8
9
|
export { BaseServer, ComponentServer, Server, ServerFactory };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "../defineRoute-
|
|
2
|
-
import "../server-
|
|
3
|
-
import { t as ServerFactory } from "../index-
|
|
1
|
+
import "../defineRoute-DUYeO8TR.mjs";
|
|
2
|
+
import "../server-Dr_qEIqu.mjs";
|
|
3
|
+
import { t as ServerFactory } from "../index-DgIsC7ua.mjs";
|
|
4
4
|
export { ServerFactory };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import "../
|
|
3
|
-
import "../
|
|
4
|
-
import "../
|
|
5
|
-
import
|
|
1
|
+
import "../validation-errors-j7DAULlG.mjs";
|
|
2
|
+
import "../response-BlkS--Fb.mjs";
|
|
3
|
+
import "../server-Dtk8M7eI.mjs";
|
|
4
|
+
import "../dependency-manager-DaDThGEc.mjs";
|
|
5
|
+
import "../component-server-llGj--XB.mjs";
|
|
6
|
+
import { t as ServerFactory } from "../server-D-jaEU-V.mjs";
|
|
6
7
|
|
|
7
8
|
export { ServerFactory };
|
package/dist/server/server.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "../defineRoute-
|
|
2
|
-
import { t as Server } from "../server-
|
|
1
|
+
import "../defineRoute-DUYeO8TR.mjs";
|
|
2
|
+
import { t as Server } from "../server-Dr_qEIqu.mjs";
|
|
3
3
|
export { Server };
|
package/dist/server/server.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as Server } from "./server-
|
|
2
|
-
import { t as ComponentServer } from "./component-server-
|
|
1
|
+
import { t as Server } from "./server-Dtk8M7eI.mjs";
|
|
2
|
+
import { t as ComponentServer } from "./component-server-llGj--XB.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/server/server-factory.ts
|
|
5
5
|
/**
|
|
@@ -67,4 +67,4 @@ var ServerFactory = class {
|
|
|
67
67
|
|
|
68
68
|
//#endregion
|
|
69
69
|
export { ServerFactory as t };
|
|
70
|
-
//# sourceMappingURL=server-
|
|
70
|
+
//# sourceMappingURL=server-D-jaEU-V.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-
|
|
1
|
+
{"version":3,"file":"server-D-jaEU-V.mjs","names":[],"sources":["../src/server/server-factory.ts"],"sourcesContent":["import type { ProcessedRoute } from \"../defineRoute\";\nimport type {\n ComponentRoute,\n NestedComponentRoute,\n} from \"../types/component-route\";\nimport { Server } from \"../server\";\nimport { ComponentServer } from \"./component-server\";\n\n/**\n * 服务器工厂类\n * 用于创建和管理不同类型的服务器\n */\nexport class ServerFactory {\n private servers: Map<string, Server | ComponentServer> = new Map();\n\n /**\n * 创建标准REST API服务器\n */\n createRestServer(routes: ProcessedRoute[]): Server {\n const server = new Server(routes);\n this.servers.set(\"rest\", server);\n return server;\n }\n\n /**\n * 创建组件服务器\n */\n createComponentServer(\n routes: (ComponentRoute | NestedComponentRoute)[],\n ): ComponentServer {\n const server = new ComponentServer(routes);\n this.servers.set(\"component\", server);\n return server;\n }\n\n /**\n * 获取指定类型的服务器\n */\n getServer(type: \"rest\" | \"component\"): Server | ComponentServer | undefined {\n return this.servers.get(type);\n }\n\n /**\n * 获取所有服务器\n */\n getAllServers(): Map<string, Server | ComponentServer> {\n return this.servers;\n }\n\n /**\n * 移除指定类型的服务器\n */\n removeServer(type: string): boolean {\n return this.servers.delete(type);\n }\n\n /**\n * 清除所有服务器\n */\n clearServers(): void {\n this.servers.clear();\n }\n\n /**\n * 获取服务器状态信息\n */\n getServerStatus(): Record<string, { type: string; routes: number }> {\n const status: Record<string, { type: string; routes: number }> = {};\n\n for (const [name, server] of this.servers) {\n if (server instanceof Server) {\n status[name] = {\n type: \"REST API\",\n routes: (server as any).routes?.length || 0,\n };\n } else if (server instanceof ComponentServer) {\n status[name] = {\n type: \"Component\",\n routes: (server as any).routes?.length || 0,\n };\n }\n }\n\n return status;\n }\n}\n"],"mappings":";;;;;;;;AAYA,IAAa,gBAAb,MAA2B;CACzB,AAAQ,0BAAiD,IAAI,KAAK;;;;CAKlE,iBAAiB,QAAkC;EACjD,MAAM,SAAS,IAAI,OAAO,OAAO;AACjC,OAAK,QAAQ,IAAI,QAAQ,OAAO;AAChC,SAAO;;;;;CAMT,sBACE,QACiB;EACjB,MAAM,SAAS,IAAI,gBAAgB,OAAO;AAC1C,OAAK,QAAQ,IAAI,aAAa,OAAO;AACrC,SAAO;;;;;CAMT,UAAU,MAAkE;AAC1E,SAAO,KAAK,QAAQ,IAAI,KAAK;;;;;CAM/B,gBAAuD;AACrD,SAAO,KAAK;;;;;CAMd,aAAa,MAAuB;AAClC,SAAO,KAAK,QAAQ,OAAO,KAAK;;;;;CAMlC,eAAqB;AACnB,OAAK,QAAQ,OAAO;;;;;CAMtB,kBAAoE;EAClE,MAAM,SAA2D,EAAE;AAEnE,OAAK,MAAM,CAAC,MAAM,WAAW,KAAK,QAChC,KAAI,kBAAkB,OACpB,QAAO,QAAQ;GACb,MAAM;GACN,QAAS,OAAe,QAAQ,UAAU;GAC3C;WACQ,kBAAkB,gBAC3B,QAAO,QAAQ;GACb,MAAM;GACN,QAAS,OAAe,QAAQ,UAAU;GAC3C;AAIL,SAAO"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as ProcessedRoute } from "./defineRoute-
|
|
2
|
-
import { n as Method } from "./types-
|
|
3
|
-
import { t as BaseServer } from "./base-server-
|
|
1
|
+
import { a as ProcessedRoute } from "./defineRoute-DUYeO8TR.mjs";
|
|
2
|
+
import { n as Method } from "./types-BaIZETLg.mjs";
|
|
3
|
+
import { t as BaseServer } from "./base-server-DDNu97SA.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/server/server.d.ts
|
|
6
6
|
|
|
@@ -45,4 +45,4 @@ declare class Server extends BaseServer {
|
|
|
45
45
|
}
|
|
46
46
|
//#endregion
|
|
47
47
|
export { Server as t };
|
|
48
|
-
//# sourceMappingURL=server-
|
|
48
|
+
//# sourceMappingURL=server-Dr_qEIqu.d.mts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { d as composeMiddleware, f as errorHandler, i as json } from "./response-
|
|
2
|
-
import { t as BaseServer } from "./base-server-
|
|
3
|
-
import { t as RadixRouter } from "./radix-tree-
|
|
4
|
-
import { c as setGlobalRegistry, t as RouteRegistry } from "./route-registry-
|
|
1
|
+
import { d as composeMiddleware, f as errorHandler, i as json } from "./response-BlkS--Fb.mjs";
|
|
2
|
+
import { t as BaseServer } from "./base-server-CbnxNoNf.mjs";
|
|
3
|
+
import { t as RadixRouter } from "./radix-tree-DPcGUi6x.mjs";
|
|
4
|
+
import { c as setGlobalRegistry, t as RouteRegistry } from "./route-registry-ClmI5VwE.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/server/server.ts
|
|
7
7
|
/**
|
|
@@ -113,4 +113,4 @@ var Server = class extends BaseServer {
|
|
|
113
113
|
|
|
114
114
|
//#endregion
|
|
115
115
|
export { Server as t };
|
|
116
|
-
//# sourceMappingURL=server-
|
|
116
|
+
//# sourceMappingURL=server-Dtk8M7eI.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-
|
|
1
|
+
{"version":3,"file":"server-Dtk8M7eI.mjs","names":[],"sources":["../src/server/server.ts"],"sourcesContent":["/**\n * Vafast 核心服务器\n *\n * 基于 Radix Tree 的高性能路由匹配\n * 时间复杂度: O(k),k 为路径段数\n */\n\nimport type { Method, Middleware } from \"../types\";\nimport type { ProcessedRoute } from \"../defineRoute\";\nimport { composeMiddleware, errorHandler } from \"../middleware\";\nimport { json } from \"../utils/response\";\nimport { BaseServer } from \"./base-server\";\nimport { RadixRouter } from \"../router/radix-tree\";\nimport { RouteRegistry, setGlobalRegistry } from \"../utils/route-registry\";\n\n/**\n * Vafast 服务器\n *\n * @example\n * ```typescript\n * const routes = defineRoutes([\n * defineRoute({ method: \"GET\", path: \"/\", handler: () => \"Hello\" }),\n * ])\n * const server = new Server(routes)\n * export default { fetch: server.fetch }\n * ```\n */\nexport class Server extends BaseServer {\n private router: RadixRouter;\n private routes: ProcessedRoute[];\n\n constructor(routes: readonly ProcessedRoute[] = []) {\n super();\n this.router = new RadixRouter();\n this.routes = [];\n\n if (routes.length > 0) {\n this.registerRoutes([...routes]);\n }\n }\n\n private registerRoutes(routes: ProcessedRoute[]): void {\n this.routes.push(...routes);\n\n for (const route of routes) {\n this.router.register(\n route.method as Method,\n route.path,\n route.handler,\n (route.middleware || []) as Middleware[],\n );\n }\n\n this.detectRouteConflicts(routes);\n this.logRoutes(routes);\n\n // 自动设置全局 RouteRegistry\n setGlobalRegistry(new RouteRegistry(this.routes));\n }\n\n /** 快速提取 pathname */\n private extractPathname(url: string): string {\n let start = url.indexOf(\"://\");\n start = start === -1 ? 0 : start + 3;\n\n const pathStart = url.indexOf(\"/\", start);\n if (pathStart === -1) return \"/\";\n\n let end = url.indexOf(\"?\", pathStart);\n if (end === -1) end = url.indexOf(\"#\", pathStart);\n if (end === -1) end = url.length;\n\n return url.substring(pathStart, end) || \"/\";\n }\n\n /** 生成 404/405 响应 */\n private createErrorResponse(method: string, pathname: string): Response {\n const allowedMethods = this.router.getAllowedMethods(pathname);\n if (allowedMethods.length > 0) {\n return json(\n {\n code: 405,\n message: `Method ${method} not allowed for this endpoint`,\n allowedMethods,\n },\n 405,\n { Allow: allowedMethods.join(\", \") },\n );\n }\n return json({ code: 404, message: \"Not Found\" }, 404);\n }\n\n /** 处理请求 */\n fetch = async (req: Request): Promise<Response> => {\n const pathname = this.extractPathname(req.url);\n const method = req.method as Method;\n\n const match = this.router.match(method, pathname);\n\n if (match) {\n (req as unknown as Record<string, unknown>).params = match.params;\n\n // 运行时组合中间件\n // 洋葱模型:globalMiddleware → errorHandler → routeMiddleware → handler\n // 这样 errorHandler 返回的错误响应也会经过 globalMiddleware(如 CORS)的后处理\n const allMiddleware = [\n ...this.globalMiddleware,\n errorHandler,\n ...match.middleware,\n ];\n const handler = composeMiddleware(allMiddleware, match.handler);\n\n return handler(req);\n }\n\n // OPTIONS 预检请求特殊处理:查找同路径其他方法的路由,使用其中间件\n // 这允许路由级 CORS 中间件正常工作\n if (method === \"OPTIONS\") {\n const allowedMethods = this.router.getAllowedMethods(pathname);\n if (allowedMethods.length > 0) {\n // 尝试获取该路径任意方法的路由中间件\n const anyMatch = this.router.match(\n allowedMethods[0] as Method,\n pathname,\n );\n const routeMiddleware = anyMatch?.middleware || [];\n const allMiddleware = [\n ...this.globalMiddleware,\n errorHandler,\n ...routeMiddleware,\n ];\n\n // OPTIONS 请求默认返回 204(中间件如 CORS 可能会提前响应)\n const optionsHandler = () =>\n new Response(null, {\n status: 204,\n headers: { Allow: allowedMethods.join(\", \") },\n });\n\n const handler = composeMiddleware(allMiddleware, optionsHandler);\n return handler(req);\n }\n }\n\n // 未匹配路由时,仍执行全局中间件(如 CORS 处理 OPTIONS 预检)\n if (this.globalMiddleware.length > 0) {\n const allMiddleware = [...this.globalMiddleware, errorHandler];\n const handler = composeMiddleware(allMiddleware, () =>\n this.createErrorResponse(method, pathname),\n );\n return handler(req);\n }\n\n return this.createErrorResponse(method, pathname);\n };\n\n /** 动态添加单个路由 */\n addRoute(route: ProcessedRoute): void {\n this.routes.push(route);\n this.router.register(\n route.method as Method,\n route.path,\n route.handler,\n (route.middleware || []) as Middleware[],\n );\n }\n\n /** 动态添加多个路由 */\n addRoutes(routes: readonly ProcessedRoute[]): void {\n this.registerRoutes([...routes]);\n }\n\n /** 获取路由列表 */\n getRoutes(): Array<{ method: Method; path: string }> {\n return this.router.getRoutes();\n }\n\n /**\n * 获取完整的路由元信息\n *\n * 用于 API 文档生成、Webhook 事件注册、权限检查等场景\n */\n getRoutesWithMeta(): ProcessedRoute[] {\n return this.routes;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA2BA,IAAa,SAAb,cAA4B,WAAW;CACrC,AAAQ;CACR,AAAQ;CAER,YAAY,SAAoC,EAAE,EAAE;AAClD,SAAO;AACP,OAAK,SAAS,IAAI,aAAa;AAC/B,OAAK,SAAS,EAAE;AAEhB,MAAI,OAAO,SAAS,EAClB,MAAK,eAAe,CAAC,GAAG,OAAO,CAAC;;CAIpC,AAAQ,eAAe,QAAgC;AACrD,OAAK,OAAO,KAAK,GAAG,OAAO;AAE3B,OAAK,MAAM,SAAS,OAClB,MAAK,OAAO,SACV,MAAM,QACN,MAAM,MACN,MAAM,SACL,MAAM,cAAc,EAAE,CACxB;AAGH,OAAK,qBAAqB,OAAO;AACjC,OAAK,UAAU,OAAO;AAGtB,oBAAkB,IAAI,cAAc,KAAK,OAAO,CAAC;;;CAInD,AAAQ,gBAAgB,KAAqB;EAC3C,IAAI,QAAQ,IAAI,QAAQ,MAAM;AAC9B,UAAQ,UAAU,KAAK,IAAI,QAAQ;EAEnC,MAAM,YAAY,IAAI,QAAQ,KAAK,MAAM;AACzC,MAAI,cAAc,GAAI,QAAO;EAE7B,IAAI,MAAM,IAAI,QAAQ,KAAK,UAAU;AACrC,MAAI,QAAQ,GAAI,OAAM,IAAI,QAAQ,KAAK,UAAU;AACjD,MAAI,QAAQ,GAAI,OAAM,IAAI;AAE1B,SAAO,IAAI,UAAU,WAAW,IAAI,IAAI;;;CAI1C,AAAQ,oBAAoB,QAAgB,UAA4B;EACtE,MAAM,iBAAiB,KAAK,OAAO,kBAAkB,SAAS;AAC9D,MAAI,eAAe,SAAS,EAC1B,QAAO,KACL;GACE,MAAM;GACN,SAAS,UAAU,OAAO;GAC1B;GACD,EACD,KACA,EAAE,OAAO,eAAe,KAAK,KAAK,EAAE,CACrC;AAEH,SAAO,KAAK;GAAE,MAAM;GAAK,SAAS;GAAa,EAAE,IAAI;;;CAIvD,QAAQ,OAAO,QAAoC;EACjD,MAAM,WAAW,KAAK,gBAAgB,IAAI,IAAI;EAC9C,MAAM,SAAS,IAAI;EAEnB,MAAM,QAAQ,KAAK,OAAO,MAAM,QAAQ,SAAS;AAEjD,MAAI,OAAO;AACT,GAAC,IAA2C,SAAS,MAAM;AAY3D,UAFgB,kBALM;IACpB,GAAG,KAAK;IACR;IACA,GAAG,MAAM;IACV,EACgD,MAAM,QAAQ,CAEhD,IAAI;;AAKrB,MAAI,WAAW,WAAW;GACxB,MAAM,iBAAiB,KAAK,OAAO,kBAAkB,SAAS;AAC9D,OAAI,eAAe,SAAS,GAAG;IAM7B,MAAM,kBAJW,KAAK,OAAO,MAC3B,eAAe,IACf,SACD,EACiC,cAAc,EAAE;IAClD,MAAM,gBAAgB;KACpB,GAAG,KAAK;KACR;KACA,GAAG;KACJ;IAGD,MAAM,uBACJ,IAAI,SAAS,MAAM;KACjB,QAAQ;KACR,SAAS,EAAE,OAAO,eAAe,KAAK,KAAK,EAAE;KAC9C,CAAC;AAGJ,WADgB,kBAAkB,eAAe,eAAe,CACjD,IAAI;;;AAKvB,MAAI,KAAK,iBAAiB,SAAS,EAKjC,QAHgB,kBADM,CAAC,GAAG,KAAK,kBAAkB,aAAa,QAE5D,KAAK,oBAAoB,QAAQ,SAAS,CAC3C,CACc,IAAI;AAGrB,SAAO,KAAK,oBAAoB,QAAQ,SAAS;;;CAInD,SAAS,OAA6B;AACpC,OAAK,OAAO,KAAK,MAAM;AACvB,OAAK,OAAO,SACV,MAAM,QACN,MAAM,MACN,MAAM,SACL,MAAM,cAAc,EAAE,CACxB;;;CAIH,UAAU,QAAyC;AACjD,OAAK,eAAe,CAAC,GAAG,OAAO,CAAC;;;CAIlC,YAAqD;AACnD,SAAO,KAAK,OAAO,WAAW;;;;;;;CAQhC,oBAAsC;AACpC,SAAO,KAAK"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as FlattenedComponentRoute, r as NestedComponentRoute, t as ComponentRoute } from "../component-route-
|
|
1
|
+
import { n as FlattenedComponentRoute, r as NestedComponentRoute, t as ComponentRoute } from "../component-route-BAaJKp8X.mjs";
|
|
2
2
|
export { ComponentRoute, FlattenedComponentRoute, NestedComponentRoute };
|
package/dist/types/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as VafastRequest, i as ResponseBody, n as Method, r as Middleware, t as Handler } from "../types-
|
|
2
|
-
import { n as FlattenedComponentRoute, r as NestedComponentRoute, t as ComponentRoute } from "../component-route-
|
|
1
|
+
import { a as VafastRequest, i as ResponseBody, n as Method, r as Middleware, t as Handler } from "../types-BaIZETLg.mjs";
|
|
2
|
+
import { n as FlattenedComponentRoute, r as NestedComponentRoute, t as ComponentRoute } from "../component-route-BAaJKp8X.mjs";
|
|
3
3
|
export { ComponentRoute, FlattenedComponentRoute, Handler, Method, Middleware, NestedComponentRoute, ResponseBody, VafastRequest };
|
package/dist/types/types.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as VafastRequest, i as ResponseBody, n as Method, r as Middleware, t as Handler } from "../types-
|
|
1
|
+
import { a as VafastRequest, i as ResponseBody, n as Method, r as Middleware, t as Handler } from "../types-BaIZETLg.mjs";
|
|
2
2
|
export { Handler, Method, Middleware, ResponseBody, VafastRequest };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as base64urlEncode, t as base64urlDecode } from "../base64url-
|
|
1
|
+
import { n as base64urlEncode, t as base64urlDecode } from "../base64url-wYuxnrb0.mjs";
|
|
2
2
|
export { base64urlDecode, base64urlEncode };
|
package/dist/utils/base64url.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as generateAITools, r as getApiSpec, t as ApiSpec } from "../contract-
|
|
1
|
+
import { n as generateAITools, r as getApiSpec, t as ApiSpec } from "../contract-ChZaybx9.mjs";
|
|
2
2
|
export { ApiSpec, generateAITools, getApiSpec };
|
package/dist/utils/contract.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as DependencyManager } from "../dependency-manager-
|
|
1
|
+
import { t as DependencyManager } from "../dependency-manager-BIjSc7j3.mjs";
|
|
2
2
|
export { DependencyManager };
|
package/dist/utils/formats.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as registerFormats, n as hasFormat, r as registerFormat, t as Patterns } from "../formats-
|
|
1
|
+
import { i as registerFormats, n as hasFormat, r as registerFormat, t as Patterns } from "../formats-B1vlpb1f.mjs";
|
|
2
2
|
export { Patterns, hasFormat, registerFormat, registerFormats };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as goAwait } from "../go-await-
|
|
1
|
+
import { t as goAwait } from "../go-await-KQIMkGZy.mjs";
|
|
2
2
|
export { goAwait };
|
package/dist/utils/go-await.mjs
CHANGED