vafast 0.4.3 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{base-server-Gakrozqk.d.mts → base-server-CtA1bZSg.d.mts} +2 -2
- package/dist/{base-server-Bq4_lJWK.mjs → base-server-DMhpmq5v.mjs} +2 -2
- package/dist/{base-server-Bq4_lJWK.mjs.map → base-server-DMhpmq5v.mjs.map} +1 -1
- package/dist/{base64url-BY-HBSpL.d.mts → base64url-0N9uQPjZ.d.mts} +1 -1
- package/dist/{base64url-DLDOeXsk.mjs → base64url-DUtluDF0.mjs} +1 -1
- package/dist/{base64url-DLDOeXsk.mjs.map → base64url-DUtluDF0.mjs.map} +1 -1
- package/dist/{component-route-BYV_X1rA.d.mts → component-route-DF5feXJI.d.mts} +2 -2
- package/dist/{component-router-DXUXLp1R.mjs → component-router-uSylkByf.mjs} +2 -2
- package/dist/{component-router-DXUXLp1R.mjs.map → component-router-uSylkByf.mjs.map} +1 -1
- package/dist/{component-server-ARXvZJUQ.mjs → component-server-DIgykV0F.mjs} +7 -7
- package/dist/{component-server-ARXvZJUQ.mjs.map → component-server-DIgykV0F.mjs.map} +1 -1
- package/dist/{component-server-BOz4Q-Qt.d.mts → component-server-DvcPVnL4.d.mts} +4 -4
- package/dist/{create-handler-Dtt0xv6g.d.mts → create-handler-DRcJRkx9.d.mts} +2 -2
- package/dist/{create-handler-CbSoroA1.mjs → create-handler-IzOE24L5.mjs} +5 -5
- package/dist/{create-handler-CbSoroA1.mjs.map → create-handler-IzOE24L5.mjs.map} +1 -1
- package/dist/defineRoute.d.mts +3 -3
- package/dist/{dependency-manager-CPkwMI7J.mjs → dependency-manager-BpN2YufZ.mjs} +2 -2
- package/dist/{dependency-manager-CPkwMI7J.mjs.map → dependency-manager-BpN2YufZ.mjs.map} +1 -1
- package/dist/{dependency-manager-Dbug5INp.d.mts → dependency-manager-C_qZvkaw.d.mts} +1 -1
- package/dist/{formats-BSqJWCsG.d.mts → formats-CYLwo9GJ.d.mts} +1 -1
- package/dist/{go-await-B-KP-K8x.mjs → go-await-2Pzj4snS.mjs} +1 -1
- package/dist/{go-await-B-KP-K8x.mjs.map → go-await-2Pzj4snS.mjs.map} +1 -1
- package/dist/{go-await-CqPx9dVQ.d.mts → go-await-DRItVwwh.d.mts} +1 -1
- package/dist/{handle-DOidKTI-.d.mts → handle-D0TFoOiX.d.mts} +1 -1
- package/dist/{handle-BhpqNgGf.mjs → handle-s4V-E2RE.mjs} +2 -2
- package/dist/{handle-BhpqNgGf.mjs.map → handle-s4V-E2RE.mjs.map} +1 -1
- package/dist/{html-renderer-C3LKTLme.d.mts → html-renderer-CMGKJoIy.d.mts} +1 -1
- package/dist/{html-renderer-CJ3B2Hft.mjs → html-renderer-CuakkPIt.mjs} +2 -2
- package/dist/{html-renderer-CJ3B2Hft.mjs.map → html-renderer-CuakkPIt.mjs.map} +1 -1
- package/dist/{index-DFsQyT61.d.mts → index-CdOYxwDQ.d.mts} +5 -5
- package/dist/index.d.mts +25 -30
- package/dist/index.mjs +21 -27
- 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-5PjaxPMA.d.mts +23 -0
- package/dist/middleware-CV5o-4wk.mjs +189 -0
- package/dist/middleware-CV5o-4wk.mjs.map +1 -0
- package/dist/middleware.d.mts +4 -25
- package/dist/middleware.mjs +1 -1
- package/dist/monitoring/index.d.mts +6 -6
- package/dist/monitoring/index.mjs +5 -3
- package/dist/monitoring/index.mjs.map +1 -1
- package/dist/monitoring/native-monitor.d.mts +6 -6
- package/dist/monitoring/native-monitor.mjs +6 -4
- package/dist/monitoring/native-monitor.mjs.map +1 -1
- 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-CodQFP1Z.d.mts → parsers-7lvt3Oss.d.mts} +1 -1
- package/dist/{parsers-ROIZWSGI.mjs → parsers-BQ63b0YE.mjs} +1 -1
- package/dist/{parsers-ROIZWSGI.mjs.map → parsers-BQ63b0YE.mjs.map} +1 -1
- package/dist/{path-matcher-CXMJ-IrG.mjs → path-matcher-BNaaJgI3.mjs} +2 -2
- package/dist/{path-matcher-CXMJ-IrG.mjs.map → path-matcher-BNaaJgI3.mjs.map} +1 -1
- package/dist/{radix-tree-BWmhTLhT.mjs → radix-tree-Qxr-QpCx.mjs} +2 -2
- package/dist/{radix-tree-BWmhTLhT.mjs.map → radix-tree-Qxr-QpCx.mjs.map} +1 -1
- package/dist/{request-B2BkUecT.mjs → request-B886yCvG.mjs} +1 -1
- package/dist/{request-B2BkUecT.mjs.map → request-B886yCvG.mjs.map} +1 -1
- package/dist/{request-validator-u2Ccj3_x.d.mts → request-validator-42lY21gn.d.mts} +2 -2
- package/dist/{request-validator-Dyqng-H_.mjs → request-validator-DLFtm4uV.mjs} +3 -3
- package/dist/{request-validator-Dyqng-H_.mjs.map → request-validator-DLFtm4uV.mjs.map} +1 -1
- package/dist/{response-BhFKEphr.mjs → response-30WnzABq.mjs} +1 -1
- package/dist/{response-BhFKEphr.mjs.map → response-30WnzABq.mjs.map} +1 -1
- package/dist/response-CxYf6Ep3.d.mts +48 -0
- package/dist/{route-BRR15b-p.mjs → route-B3ONOzxQ.mjs} +1 -1
- package/dist/{route-BRR15b-p.mjs.map → route-B3ONOzxQ.mjs.map} +1 -1
- package/dist/{route-BqmWCG4e.d.mts → route-CUbNpSwz.d.mts} +2 -2
- package/dist/{route-registry-AlkDgbcE.mjs → route-registry-BVvbghgH.mjs} +2 -2
- package/dist/{route-registry-AlkDgbcE.mjs.map → route-registry-BVvbghgH.mjs.map} +1 -1
- package/dist/{route-registry-ykzRmaHB.d.mts → route-registry-CYD7m6QP.d.mts} +2 -2
- package/dist/router/index.d.mts +2 -2
- package/dist/router/index.mjs +2 -2
- package/dist/router/radix-tree.d.mts +3 -3
- package/dist/router/radix-tree.mjs +1 -1
- package/dist/{router-BOeVQrjz.mjs → router-B9HUUCkR.mjs} +2 -2
- package/dist/{router-BOeVQrjz.mjs.map → router-B9HUUCkR.mjs.map} +1 -1
- package/dist/router.d.mts +3 -3
- package/dist/router.mjs +1 -1
- package/dist/{schema-CVuttFSw.d.mts → schema-DOKg31ZX.d.mts} +1 -1
- package/dist/{serve-BQQ2JzIH.d.mts → serve-B5WmhK6m.d.mts} +1 -1
- package/dist/{serve-MRGGK7-q.mjs → serve-DgWBnexE.mjs} +3 -3
- package/dist/{serve-MRGGK7-q.mjs.map → serve-DgWBnexE.mjs.map} +1 -1
- package/dist/serve.d.mts +1 -1
- package/dist/serve.mjs +2 -2
- package/dist/server/base-server.d.mts +3 -3
- package/dist/server/base-server.mjs +1 -1
- package/dist/server/component-server.d.mts +4 -4
- package/dist/server/component-server.mjs +2 -2
- package/dist/server/index.d.mts +6 -6
- package/dist/server/index.mjs +6 -5
- package/dist/server/server-factory.d.mts +6 -6
- package/dist/server/server-factory.mjs +5 -3
- package/dist/server/server.d.mts +4 -4
- package/dist/server/server.mjs +2 -1
- package/dist/{server-B0nzGCG5.mjs → server-BttM6Ssc.mjs} +5 -5
- package/dist/{server-B0nzGCG5.mjs.map → server-BttM6Ssc.mjs.map} +1 -1
- package/dist/{server-C8WCshmG.mjs → server-C3yoZXNs.mjs} +7 -8
- package/dist/{server-C8WCshmG.mjs.map → server-C3yoZXNs.mjs.map} +1 -1
- package/dist/{server-Drc2kSxp.d.mts → server-CWIZP6nb.d.mts} +3 -3
- package/dist/{sse-BOd2pvUK.d.mts → sse-BDIptC85.d.mts} +2 -2
- package/dist/{sse-US5D9mgE.mjs → sse-CCVfFW6s.mjs} +3 -3
- package/dist/{sse-US5D9mgE.mjs.map → sse-CCVfFW6s.mjs.map} +1 -1
- package/dist/types/component-route.d.mts +1 -1
- package/dist/types/index.d.mts +5 -5
- package/dist/types/index.mjs +1 -1
- package/dist/types/route.d.mts +1 -1
- package/dist/types/route.mjs +1 -1
- package/dist/types/schema.d.mts +1 -1
- package/dist/types/types.d.mts +1 -1
- package/dist/{types-Cb7_2VSt.d.mts → types-mpeSaHdI.d.mts} +1 -1
- package/dist/utils/base64url.d.mts +1 -1
- package/dist/utils/base64url.mjs +1 -1
- package/dist/utils/create-handler.d.mts +2 -2
- package/dist/utils/create-handler.mjs +4 -3
- 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.d.mts +1 -1
- package/dist/utils/handle.mjs +2 -2
- package/dist/utils/html-renderer.d.mts +1 -1
- package/dist/utils/html-renderer.mjs +1 -1
- package/dist/utils/index.d.mts +17 -16
- package/dist/utils/index.mjs +13 -13
- package/dist/utils/index.mjs.map +1 -1
- 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/request-validator.d.mts +2 -2
- package/dist/utils/request-validator.mjs +3 -3
- package/dist/utils/response.d.mts +5 -2
- package/dist/utils/response.mjs +2 -2
- package/dist/utils/route-registry.d.mts +3 -3
- package/dist/utils/route-registry.mjs +1 -1
- package/dist/utils/sse.d.mts +2 -2
- package/dist/utils/sse.mjs +3 -3
- package/dist/utils/validators/validators.d.mts +1 -1
- package/dist/utils/validators/validators.mjs +1 -1
- package/dist/{validators-C0eZyxPh.d.mts → validators-CPmnj_y9.d.mts} +1 -1
- package/dist/{validators-CbCLj0Rc.mjs → validators-WXQ49LcR.mjs} +1 -1
- package/dist/{validators-CbCLj0Rc.mjs.map → validators-WXQ49LcR.mjs.map} +1 -1
- package/package.json +1 -1
- package/dist/auth/token.d.mts +0 -44
- package/dist/auth/token.mjs +0 -105
- package/dist/auth/token.mjs.map +0 -1
- package/dist/middleware/auth.d.mts +0 -20
- package/dist/middleware/auth.mjs +0 -98
- package/dist/middleware/auth.mjs.map +0 -1
- package/dist/middleware/authMiddleware.d.mts +0 -9
- package/dist/middleware/authMiddleware.mjs +0 -19
- package/dist/middleware/authMiddleware.mjs.map +0 -1
- package/dist/middleware/cors.d.mts +0 -16
- package/dist/middleware/cors.mjs +0 -38
- package/dist/middleware/cors.mjs.map +0 -1
- package/dist/middleware/rateLimit.d.mts +0 -14
- package/dist/middleware/rateLimit.mjs +0 -34
- package/dist/middleware/rateLimit.mjs.map +0 -1
- package/dist/middleware-3ShRJyd1.mjs +0 -59
- package/dist/middleware-3ShRJyd1.mjs.map +0 -1
- package/dist/response-CSKW5hsS.mjs +0 -97
- package/dist/response-CSKW5hsS.mjs.map +0 -1
- package/dist/response-CUyV5FIm.d.mts +0 -21
- /package/dist/{chunk-67U6L5Jh.mjs → chunk-DW4-Jl94.mjs} +0 -0
- /package/dist/{component-route-Do2yyYTi.mjs → component-route-BKUFoJ5P.mjs} +0 -0
- /package/dist/{index-DXJd7-2Z.d.mts → index-CTHojwxd.d.mts} +0 -0
- /package/dist/{schema-CbAaktsZ.mjs → schema-CflsMJuG.mjs} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-matcher-
|
|
1
|
+
{"version":3,"file":"path-matcher-BNaaJgI3.mjs","names":[],"sources":["../src/utils/path-matcher.ts"],"sourcesContent":["/**\n * 路径匹配工具类\n * 提供统一的路径匹配和参数提取功能\n */\nexport class PathMatcher {\n /**\n * 路径匹配\n */\n static matchPath(pattern: string, path: string): boolean {\n const patternParts = pattern.split(\"/\").filter(Boolean);\n const pathParts = path.split(\"/\").filter(Boolean);\n\n if (patternParts.length !== pathParts.length) {\n return false;\n }\n\n for (let i = 0; i < patternParts.length; i++) {\n if (\n patternParts[i] !== pathParts[i] &&\n !patternParts[i].startsWith(\":\")\n ) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 提取路径参数\n */\n static extractParams(pattern: string, path: string): Record<string, string> {\n const params: Record<string, string> = {};\n const patternParts = pattern.split(\"/\").filter(Boolean);\n const pathParts = path.split(\"/\").filter(Boolean);\n\n for (let i = 0; i < patternParts.length; i++) {\n if (patternParts[i].startsWith(\":\")) {\n const paramName = patternParts[i].slice(1);\n params[paramName] = pathParts[i];\n }\n }\n\n return params;\n }\n\n /**\n * 计算路径特异性分数\n * 用于路由排序:静态 > 动态(:param) > 通配符(*)\n */\n static calculatePathScore(path: string): number {\n const parts = path.split(\"/\").filter(Boolean);\n let score = 0;\n for (const p of parts) {\n if (p === \"*\")\n score += 1; // 最弱\n else if (p.startsWith(\":\"))\n score += 2; // 中等\n else score += 3; // 静态最强\n }\n // 更长的路径更具体,略微提升\n return score * 10 + parts.length;\n }\n\n /**\n * 判断两个路径是否可能冲突\n */\n static pathsMayConflict(path1: string, path2: string): boolean {\n const parts1 = path1.split(\"/\").filter(Boolean);\n const parts2 = path2.split(\"/\").filter(Boolean);\n\n if (parts1.length !== parts2.length) return false;\n\n for (let i = 0; i < parts1.length; i++) {\n const p1 = parts1[i];\n const p2 = parts2[i];\n\n // 如果两个部分都是静态的且不同,则不会冲突\n if (\n !p1.startsWith(\":\") &&\n !p1.startsWith(\"*\") &&\n !p2.startsWith(\":\") &&\n !p2.startsWith(\"*\") &&\n p1 !== p2\n ) {\n return false;\n }\n\n // 如果一个是通配符,另一个是动态参数,可能冲突\n if (\n (p1 === \"*\" && p2.startsWith(\":\")) ||\n (p2 === \"*\" && p1.startsWith(\":\"))\n ) {\n return true;\n }\n }\n\n return false;\n }\n}\n"],"mappings":";;;;;CAIa,cAAb,MAAyB;;;;EAIvB,OAAO,UAAU,SAAiB,MAAuB;GACvD,MAAM,eAAe,QAAQ,MAAM,IAAI,CAAC,OAAO,QAAQ;GACvD,MAAM,YAAY,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ;AAEjD,OAAI,aAAa,WAAW,UAAU,OACpC,QAAO;AAGT,QAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,IACvC,KACE,aAAa,OAAO,UAAU,MAC9B,CAAC,aAAa,GAAG,WAAW,IAAI,CAEhC,QAAO;AAIX,UAAO;;;;;EAMT,OAAO,cAAc,SAAiB,MAAsC;GAC1E,MAAM,SAAiC,EAAE;GACzC,MAAM,eAAe,QAAQ,MAAM,IAAI,CAAC,OAAO,QAAQ;GACvD,MAAM,YAAY,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ;AAEjD,QAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,IACvC,KAAI,aAAa,GAAG,WAAW,IAAI,EAAE;IACnC,MAAM,YAAY,aAAa,GAAG,MAAM,EAAE;AAC1C,WAAO,aAAa,UAAU;;AAIlC,UAAO;;;;;;EAOT,OAAO,mBAAmB,MAAsB;GAC9C,MAAM,QAAQ,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ;GAC7C,IAAI,QAAQ;AACZ,QAAK,MAAM,KAAK,MACd,KAAI,MAAM,IACR,UAAS;YACF,EAAE,WAAW,IAAI,CACxB,UAAS;OACN,UAAS;AAGhB,UAAO,QAAQ,KAAK,MAAM;;;;;EAM5B,OAAO,iBAAiB,OAAe,OAAwB;GAC7D,MAAM,SAAS,MAAM,MAAM,IAAI,CAAC,OAAO,QAAQ;GAC/C,MAAM,SAAS,MAAM,MAAM,IAAI,CAAC,OAAO,QAAQ;AAE/C,OAAI,OAAO,WAAW,OAAO,OAAQ,QAAO;AAE5C,QAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;IACtC,MAAM,KAAK,OAAO;IAClB,MAAM,KAAK,OAAO;AAGlB,QACE,CAAC,GAAG,WAAW,IAAI,IACnB,CAAC,GAAG,WAAW,IAAI,IACnB,CAAC,GAAG,WAAW,IAAI,IACnB,CAAC,GAAG,WAAW,IAAI,IACnB,OAAO,GAEP,QAAO;AAIT,QACG,OAAO,OAAO,GAAG,WAAW,IAAI,IAChC,OAAO,OAAO,GAAG,WAAW,IAAI,CAEjC,QAAO;;AAIX,UAAO"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as __esmMin } from "./chunk-
|
|
1
|
+
import { t as __esmMin } from "./chunk-DW4-Jl94.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/router/radix-tree.ts
|
|
4
4
|
var RadixRouter;
|
|
@@ -154,4 +154,4 @@ var init_radix_tree = __esmMin((() => {
|
|
|
154
154
|
|
|
155
155
|
//#endregion
|
|
156
156
|
export { init_radix_tree as n, RadixRouter as t };
|
|
157
|
-
//# sourceMappingURL=radix-tree-
|
|
157
|
+
//# sourceMappingURL=radix-tree-Qxr-QpCx.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radix-tree-BWmhTLhT.mjs","names":[],"sources":["../src/router/radix-tree.ts"],"sourcesContent":["/**\n * Radix Tree 路由匹配器\n *\n * 高性能路由匹配实现,时间复杂度 O(k),k 为路径段数\n *\n * 支持的路由模式:\n * - 静态路径: /users, /api/v1/health\n * - 动态参数: /users/:id, /posts/:postId/comments/:commentId\n * - 通配符: /files/*, /static/*filepath\n */\n\nimport type { Handler, Middleware, Method } from \"../types\";\n\n/** 预编译的处理器类型 */\ntype CompiledHandler = (req: Request) => Promise<Response>;\n\n/** 路由处理信息 */\ninterface RouteHandler {\n handler: Handler;\n middleware: Middleware[];\n /** 预编译后的完整处理链(包含中间件) */\n compiled?: CompiledHandler;\n}\n\n/** Radix Tree 节点 */\ninterface RadixNode {\n path: string;\n children: Record<string, RadixNode>;\n paramChild?: RadixNode;\n wildcardChild?: RadixNode;\n paramName?: string;\n handlers: Record<Method, RouteHandler | undefined>;\n}\n\n/** 路由匹配结果 */\nexport interface MatchResult {\n handler: Handler;\n middleware: Middleware[];\n params: Record<string, string>;\n /** 预编译后的完整处理链 */\n compiled?: CompiledHandler;\n}\n\n/**\n * Radix Tree 路由器\n *\n * @example\n * ```typescript\n * const router = new RadixRouter();\n * router.register(\"GET\", \"/users/:id\", handler);\n * const result = router.match(\"GET\", \"/users/123\");\n * // result.params = { id: \"123\" }\n * ```\n */\nexport class RadixRouter {\n private root: RadixNode;\n\n constructor() {\n this.root = this.createNode(\"\");\n }\n\n private createNode(path: string): RadixNode {\n return {\n path,\n children: Object.create(null),\n handlers: Object.create(null),\n };\n }\n\n /** 分割路径 */\n private splitPath(path: string): string[] {\n return path.split(\"/\").filter(Boolean);\n }\n\n /** 编译器函数 - 用于预编译中间件链 */\n private compiler?: (\n middleware: Middleware[],\n handler: Handler,\n ) => CompiledHandler;\n\n /** 设置中间件编译器 */\n setCompiler(\n compiler: (middleware: Middleware[], handler: Handler) => CompiledHandler,\n ): void {\n this.compiler = compiler;\n }\n\n /** 注册路由 */\n register(\n method: Method,\n pattern: string,\n handler: Handler,\n middleware: Middleware[] = [],\n ): void {\n const segments = this.splitPath(pattern);\n let node = this.root;\n\n for (const segment of segments) {\n const firstChar = segment[0];\n\n if (firstChar === \":\") {\n // 动态参数节点\n if (!node.paramChild) {\n node.paramChild = this.createNode(segment);\n node.paramChild.paramName = segment.substring(1);\n }\n node = node.paramChild;\n } else if (firstChar === \"*\") {\n // 通配符节点\n if (!node.wildcardChild) {\n node.wildcardChild = this.createNode(segment);\n node.wildcardChild.paramName =\n segment.length > 1 ? segment.substring(1) : \"*\";\n }\n node = node.wildcardChild;\n break;\n } else {\n // 静态路径节点\n if (!node.children[segment]) {\n node.children[segment] = this.createNode(segment);\n }\n node = node.children[segment];\n }\n }\n\n const routeHandler: RouteHandler = { handler, middleware };\n\n // 如果没有全局中间件且设置了编译器,预编译处理链\n if (this.compiler && middleware.length === 0) {\n routeHandler.compiled = this.compiler([], handler);\n }\n\n node.handlers[method] = routeHandler;\n }\n\n /** 预编译所有路由(在添加全局中间件后调用) */\n precompileAll(globalMiddleware: Middleware[]): void {\n if (!this.compiler) return;\n this.precompileNode(this.root, globalMiddleware);\n }\n\n private precompileNode(\n node: RadixNode,\n globalMiddleware: Middleware[],\n ): void {\n for (const method in node.handlers) {\n const routeHandler = node.handlers[method as Method];\n if (routeHandler) {\n const allMiddleware = [...globalMiddleware, ...routeHandler.middleware];\n routeHandler.compiled = this.compiler!(\n allMiddleware,\n routeHandler.handler,\n );\n }\n }\n\n for (const key in node.children) {\n this.precompileNode(node.children[key], globalMiddleware);\n }\n\n if (node.paramChild) {\n this.precompileNode(node.paramChild, globalMiddleware);\n }\n\n if (node.wildcardChild) {\n this.precompileNode(node.wildcardChild, globalMiddleware);\n }\n }\n\n /** 匹配路由 */\n match(method: Method, path: string): MatchResult | null {\n const segments = this.splitPath(path);\n const params: Record<string, string> = Object.create(null);\n\n const node = this.matchNode(this.root, segments, 0, params);\n if (!node) return null;\n\n const routeHandler = node.handlers[method];\n if (!routeHandler) return null;\n\n return {\n handler: routeHandler.handler,\n middleware: routeHandler.middleware,\n params,\n compiled: routeHandler.compiled,\n };\n }\n\n /** 递归匹配节点 (优先级: 静态 > 动态参数 > 通配符) */\n private matchNode(\n node: RadixNode,\n segments: string[],\n index: number,\n params: Record<string, string>,\n ): RadixNode | null {\n if (index === segments.length) {\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) return node;\n }\n return null;\n }\n\n const segment = segments[index];\n\n // 1. 静态路径\n const staticChild = node.children[segment];\n if (staticChild) {\n const result = this.matchNode(staticChild, segments, index + 1, params);\n if (result) return result;\n }\n\n // 2. 动态参数\n if (node.paramChild) {\n const paramName = node.paramChild.paramName!;\n const oldValue = params[paramName];\n\n params[paramName] = segment;\n const result = this.matchNode(\n node.paramChild,\n segments,\n index + 1,\n params,\n );\n\n if (result) return result;\n\n // 回溯\n if (oldValue === undefined) {\n delete params[paramName];\n } else {\n params[paramName] = oldValue;\n }\n }\n\n // 3. 通配符\n if (node.wildcardChild) {\n params[node.wildcardChild.paramName || \"*\"] = segments\n .slice(index)\n .join(\"/\");\n return node.wildcardChild;\n }\n\n return null;\n }\n\n /** 获取路径允许的 HTTP 方法 */\n getAllowedMethods(path: string): Method[] {\n const segments = this.splitPath(path);\n const node = this.findNode(segments);\n if (!node) return [];\n\n const methods: Method[] = [];\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) {\n methods.push(method as Method);\n }\n }\n return methods;\n }\n\n /** 查找节点(不提取参数) */\n private findNode(segments: string[]): RadixNode | null {\n let node = this.root;\n\n for (const segment of segments) {\n if (node.children[segment]) {\n node = node.children[segment];\n } else if (node.paramChild) {\n node = node.paramChild;\n } else if (node.wildcardChild) {\n return node.wildcardChild;\n } else {\n return null;\n }\n }\n\n return node;\n }\n\n /** 获取所有已注册的路由 */\n getRoutes(): Array<{ method: Method; path: string }> {\n const routes: Array<{ method: Method; path: string }> = [];\n this.collectRoutes(this.root, \"\", routes);\n return routes;\n }\n\n private collectRoutes(\n node: RadixNode,\n prefix: string,\n routes: Array<{ method: Method; path: string }>,\n ): void {\n const currentPath = prefix + (node.path ? \"/\" + node.path : \"\");\n\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) {\n routes.push({ method: method as Method, path: currentPath || \"/\" });\n }\n }\n\n for (const key in node.children) {\n this.collectRoutes(node.children[key], currentPath, routes);\n }\n\n if (node.paramChild) {\n this.collectRoutes(node.paramChild, currentPath, routes);\n }\n\n if (node.wildcardChild) {\n this.collectRoutes(node.wildcardChild, currentPath, routes);\n }\n }\n}\n"],"mappings":";;;;;CAsDa,cAAb,MAAyB;EACvB,AAAQ;EAER,cAAc;AACZ,QAAK,OAAO,KAAK,WAAW,GAAG;;EAGjC,AAAQ,WAAW,MAAyB;AAC1C,UAAO;IACL;IACA,UAAU,OAAO,OAAO,KAAK;IAC7B,UAAU,OAAO,OAAO,KAAK;IAC9B;;;EAIH,AAAQ,UAAU,MAAwB;AACxC,UAAO,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ;;;EAIxC,AAAQ;;EAMR,YACE,UACM;AACN,QAAK,WAAW;;;EAIlB,SACE,QACA,SACA,SACA,aAA2B,EAAE,EACvB;GACN,MAAM,WAAW,KAAK,UAAU,QAAQ;GACxC,IAAI,OAAO,KAAK;AAEhB,QAAK,MAAM,WAAW,UAAU;IAC9B,MAAM,YAAY,QAAQ;AAE1B,QAAI,cAAc,KAAK;AAErB,SAAI,CAAC,KAAK,YAAY;AACpB,WAAK,aAAa,KAAK,WAAW,QAAQ;AAC1C,WAAK,WAAW,YAAY,QAAQ,UAAU,EAAE;;AAElD,YAAO,KAAK;eACH,cAAc,KAAK;AAE5B,SAAI,CAAC,KAAK,eAAe;AACvB,WAAK,gBAAgB,KAAK,WAAW,QAAQ;AAC7C,WAAK,cAAc,YACjB,QAAQ,SAAS,IAAI,QAAQ,UAAU,EAAE,GAAG;;AAEhD,YAAO,KAAK;AACZ;WACK;AAEL,SAAI,CAAC,KAAK,SAAS,SACjB,MAAK,SAAS,WAAW,KAAK,WAAW,QAAQ;AAEnD,YAAO,KAAK,SAAS;;;GAIzB,MAAM,eAA6B;IAAE;IAAS;IAAY;AAG1D,OAAI,KAAK,YAAY,WAAW,WAAW,EACzC,cAAa,WAAW,KAAK,SAAS,EAAE,EAAE,QAAQ;AAGpD,QAAK,SAAS,UAAU;;;EAI1B,cAAc,kBAAsC;AAClD,OAAI,CAAC,KAAK,SAAU;AACpB,QAAK,eAAe,KAAK,MAAM,iBAAiB;;EAGlD,AAAQ,eACN,MACA,kBACM;AACN,QAAK,MAAM,UAAU,KAAK,UAAU;IAClC,MAAM,eAAe,KAAK,SAAS;AACnC,QAAI,cAAc;KAChB,MAAM,gBAAgB,CAAC,GAAG,kBAAkB,GAAG,aAAa,WAAW;AACvE,kBAAa,WAAW,KAAK,SAC3B,eACA,aAAa,QACd;;;AAIL,QAAK,MAAM,OAAO,KAAK,SACrB,MAAK,eAAe,KAAK,SAAS,MAAM,iBAAiB;AAG3D,OAAI,KAAK,WACP,MAAK,eAAe,KAAK,YAAY,iBAAiB;AAGxD,OAAI,KAAK,cACP,MAAK,eAAe,KAAK,eAAe,iBAAiB;;;EAK7D,MAAM,QAAgB,MAAkC;GACtD,MAAM,WAAW,KAAK,UAAU,KAAK;GACrC,MAAM,SAAiC,OAAO,OAAO,KAAK;GAE1D,MAAM,OAAO,KAAK,UAAU,KAAK,MAAM,UAAU,GAAG,OAAO;AAC3D,OAAI,CAAC,KAAM,QAAO;GAElB,MAAM,eAAe,KAAK,SAAS;AACnC,OAAI,CAAC,aAAc,QAAO;AAE1B,UAAO;IACL,SAAS,aAAa;IACtB,YAAY,aAAa;IACzB;IACA,UAAU,aAAa;IACxB;;;EAIH,AAAQ,UACN,MACA,UACA,OACA,QACkB;AAClB,OAAI,UAAU,SAAS,QAAQ;AAC7B,SAAK,MAAM,UAAU,KAAK,SACxB,KAAI,KAAK,SAAS,QAAmB,QAAO;AAE9C,WAAO;;GAGT,MAAM,UAAU,SAAS;GAGzB,MAAM,cAAc,KAAK,SAAS;AAClC,OAAI,aAAa;IACf,MAAM,SAAS,KAAK,UAAU,aAAa,UAAU,QAAQ,GAAG,OAAO;AACvE,QAAI,OAAQ,QAAO;;AAIrB,OAAI,KAAK,YAAY;IACnB,MAAM,YAAY,KAAK,WAAW;IAClC,MAAM,WAAW,OAAO;AAExB,WAAO,aAAa;IACpB,MAAM,SAAS,KAAK,UAClB,KAAK,YACL,UACA,QAAQ,GACR,OACD;AAED,QAAI,OAAQ,QAAO;AAGnB,QAAI,aAAa,OACf,QAAO,OAAO;QAEd,QAAO,aAAa;;AAKxB,OAAI,KAAK,eAAe;AACtB,WAAO,KAAK,cAAc,aAAa,OAAO,SAC3C,MAAM,MAAM,CACZ,KAAK,IAAI;AACZ,WAAO,KAAK;;AAGd,UAAO;;;EAIT,kBAAkB,MAAwB;GACxC,MAAM,WAAW,KAAK,UAAU,KAAK;GACrC,MAAM,OAAO,KAAK,SAAS,SAAS;AACpC,OAAI,CAAC,KAAM,QAAO,EAAE;GAEpB,MAAM,UAAoB,EAAE;AAC5B,QAAK,MAAM,UAAU,KAAK,SACxB,KAAI,KAAK,SAAS,QAChB,SAAQ,KAAK,OAAiB;AAGlC,UAAO;;;EAIT,AAAQ,SAAS,UAAsC;GACrD,IAAI,OAAO,KAAK;AAEhB,QAAK,MAAM,WAAW,SACpB,KAAI,KAAK,SAAS,SAChB,QAAO,KAAK,SAAS;YACZ,KAAK,WACd,QAAO,KAAK;YACH,KAAK,cACd,QAAO,KAAK;OAEZ,QAAO;AAIX,UAAO;;;EAIT,YAAqD;GACnD,MAAM,SAAkD,EAAE;AAC1D,QAAK,cAAc,KAAK,MAAM,IAAI,OAAO;AACzC,UAAO;;EAGT,AAAQ,cACN,MACA,QACA,QACM;GACN,MAAM,cAAc,UAAU,KAAK,OAAO,MAAM,KAAK,OAAO;AAE5D,QAAK,MAAM,UAAU,KAAK,SACxB,KAAI,KAAK,SAAS,QAChB,QAAO,KAAK;IAAU;IAAkB,MAAM,eAAe;IAAK,CAAC;AAIvE,QAAK,MAAM,OAAO,KAAK,SACrB,MAAK,cAAc,KAAK,SAAS,MAAM,aAAa,OAAO;AAG7D,OAAI,KAAK,WACP,MAAK,cAAc,KAAK,YAAY,aAAa,OAAO;AAG1D,OAAI,KAAK,cACP,MAAK,cAAc,KAAK,eAAe,aAAa,OAAO"}
|
|
1
|
+
{"version":3,"file":"radix-tree-Qxr-QpCx.mjs","names":[],"sources":["../src/router/radix-tree.ts"],"sourcesContent":["/**\n * Radix Tree 路由匹配器\n *\n * 高性能路由匹配实现,时间复杂度 O(k),k 为路径段数\n *\n * 支持的路由模式:\n * - 静态路径: /users, /api/v1/health\n * - 动态参数: /users/:id, /posts/:postId/comments/:commentId\n * - 通配符: /files/*, /static/*filepath\n */\n\nimport type { Handler, Middleware, Method } from \"../types\";\n\n/** 预编译的处理器类型 */\ntype CompiledHandler = (req: Request) => Promise<Response>;\n\n/** 路由处理信息 */\ninterface RouteHandler {\n handler: Handler;\n middleware: Middleware[];\n /** 预编译后的完整处理链(包含中间件) */\n compiled?: CompiledHandler;\n}\n\n/** Radix Tree 节点 */\ninterface RadixNode {\n path: string;\n children: Record<string, RadixNode>;\n paramChild?: RadixNode;\n wildcardChild?: RadixNode;\n paramName?: string;\n handlers: Record<Method, RouteHandler | undefined>;\n}\n\n/** 路由匹配结果 */\nexport interface MatchResult {\n handler: Handler;\n middleware: Middleware[];\n params: Record<string, string>;\n /** 预编译后的完整处理链 */\n compiled?: CompiledHandler;\n}\n\n/**\n * Radix Tree 路由器\n *\n * @example\n * ```typescript\n * const router = new RadixRouter();\n * router.register(\"GET\", \"/users/:id\", handler);\n * const result = router.match(\"GET\", \"/users/123\");\n * // result.params = { id: \"123\" }\n * ```\n */\nexport class RadixRouter {\n private root: RadixNode;\n\n constructor() {\n this.root = this.createNode(\"\");\n }\n\n private createNode(path: string): RadixNode {\n return {\n path,\n children: Object.create(null),\n handlers: Object.create(null),\n };\n }\n\n /** 分割路径 */\n private splitPath(path: string): string[] {\n return path.split(\"/\").filter(Boolean);\n }\n\n /** 编译器函数 - 用于预编译中间件链 */\n private compiler?: (\n middleware: Middleware[],\n handler: Handler,\n ) => CompiledHandler;\n\n /** 设置中间件编译器 */\n setCompiler(\n compiler: (middleware: Middleware[], handler: Handler) => CompiledHandler,\n ): void {\n this.compiler = compiler;\n }\n\n /** 注册路由 */\n register(\n method: Method,\n pattern: string,\n handler: Handler,\n middleware: Middleware[] = [],\n ): void {\n const segments = this.splitPath(pattern);\n let node = this.root;\n\n for (const segment of segments) {\n const firstChar = segment[0];\n\n if (firstChar === \":\") {\n // 动态参数节点\n if (!node.paramChild) {\n node.paramChild = this.createNode(segment);\n node.paramChild.paramName = segment.substring(1);\n }\n node = node.paramChild;\n } else if (firstChar === \"*\") {\n // 通配符节点\n if (!node.wildcardChild) {\n node.wildcardChild = this.createNode(segment);\n node.wildcardChild.paramName =\n segment.length > 1 ? segment.substring(1) : \"*\";\n }\n node = node.wildcardChild;\n break;\n } else {\n // 静态路径节点\n if (!node.children[segment]) {\n node.children[segment] = this.createNode(segment);\n }\n node = node.children[segment];\n }\n }\n\n const routeHandler: RouteHandler = { handler, middleware };\n\n // 如果没有全局中间件且设置了编译器,预编译处理链\n if (this.compiler && middleware.length === 0) {\n routeHandler.compiled = this.compiler([], handler);\n }\n\n node.handlers[method] = routeHandler;\n }\n\n /** 预编译所有路由(在添加全局中间件后调用) */\n precompileAll(globalMiddleware: Middleware[]): void {\n if (!this.compiler) return;\n this.precompileNode(this.root, globalMiddleware);\n }\n\n private precompileNode(\n node: RadixNode,\n globalMiddleware: Middleware[],\n ): void {\n for (const method in node.handlers) {\n const routeHandler = node.handlers[method as Method];\n if (routeHandler) {\n const allMiddleware = [...globalMiddleware, ...routeHandler.middleware];\n routeHandler.compiled = this.compiler!(\n allMiddleware,\n routeHandler.handler,\n );\n }\n }\n\n for (const key in node.children) {\n this.precompileNode(node.children[key], globalMiddleware);\n }\n\n if (node.paramChild) {\n this.precompileNode(node.paramChild, globalMiddleware);\n }\n\n if (node.wildcardChild) {\n this.precompileNode(node.wildcardChild, globalMiddleware);\n }\n }\n\n /** 匹配路由 */\n match(method: Method, path: string): MatchResult | null {\n const segments = this.splitPath(path);\n const params: Record<string, string> = Object.create(null);\n\n const node = this.matchNode(this.root, segments, 0, params);\n if (!node) return null;\n\n const routeHandler = node.handlers[method];\n if (!routeHandler) return null;\n\n return {\n handler: routeHandler.handler,\n middleware: routeHandler.middleware,\n params,\n compiled: routeHandler.compiled,\n };\n }\n\n /** 递归匹配节点 (优先级: 静态 > 动态参数 > 通配符) */\n private matchNode(\n node: RadixNode,\n segments: string[],\n index: number,\n params: Record<string, string>,\n ): RadixNode | null {\n if (index === segments.length) {\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) return node;\n }\n return null;\n }\n\n const segment = segments[index];\n\n // 1. 静态路径\n const staticChild = node.children[segment];\n if (staticChild) {\n const result = this.matchNode(staticChild, segments, index + 1, params);\n if (result) return result;\n }\n\n // 2. 动态参数\n if (node.paramChild) {\n const paramName = node.paramChild.paramName!;\n const oldValue = params[paramName];\n\n params[paramName] = segment;\n const result = this.matchNode(\n node.paramChild,\n segments,\n index + 1,\n params,\n );\n\n if (result) return result;\n\n // 回溯\n if (oldValue === undefined) {\n delete params[paramName];\n } else {\n params[paramName] = oldValue;\n }\n }\n\n // 3. 通配符\n if (node.wildcardChild) {\n params[node.wildcardChild.paramName || \"*\"] = segments\n .slice(index)\n .join(\"/\");\n return node.wildcardChild;\n }\n\n return null;\n }\n\n /** 获取路径允许的 HTTP 方法 */\n getAllowedMethods(path: string): Method[] {\n const segments = this.splitPath(path);\n const node = this.findNode(segments);\n if (!node) return [];\n\n const methods: Method[] = [];\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) {\n methods.push(method as Method);\n }\n }\n return methods;\n }\n\n /** 查找节点(不提取参数) */\n private findNode(segments: string[]): RadixNode | null {\n let node = this.root;\n\n for (const segment of segments) {\n if (node.children[segment]) {\n node = node.children[segment];\n } else if (node.paramChild) {\n node = node.paramChild;\n } else if (node.wildcardChild) {\n return node.wildcardChild;\n } else {\n return null;\n }\n }\n\n return node;\n }\n\n /** 获取所有已注册的路由 */\n getRoutes(): Array<{ method: Method; path: string }> {\n const routes: Array<{ method: Method; path: string }> = [];\n this.collectRoutes(this.root, \"\", routes);\n return routes;\n }\n\n private collectRoutes(\n node: RadixNode,\n prefix: string,\n routes: Array<{ method: Method; path: string }>,\n ): void {\n const currentPath = prefix + (node.path ? \"/\" + node.path : \"\");\n\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) {\n routes.push({ method: method as Method, path: currentPath || \"/\" });\n }\n }\n\n for (const key in node.children) {\n this.collectRoutes(node.children[key], currentPath, routes);\n }\n\n if (node.paramChild) {\n this.collectRoutes(node.paramChild, currentPath, routes);\n }\n\n if (node.wildcardChild) {\n this.collectRoutes(node.wildcardChild, currentPath, routes);\n }\n }\n}\n"],"mappings":";;;;;CAsDa,cAAb,MAAyB;EACvB,AAAQ;EAER,cAAc;AACZ,QAAK,OAAO,KAAK,WAAW,GAAG;;EAGjC,AAAQ,WAAW,MAAyB;AAC1C,UAAO;IACL;IACA,UAAU,OAAO,OAAO,KAAK;IAC7B,UAAU,OAAO,OAAO,KAAK;IAC9B;;;EAIH,AAAQ,UAAU,MAAwB;AACxC,UAAO,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ;;;EAIxC,AAAQ;;EAMR,YACE,UACM;AACN,QAAK,WAAW;;;EAIlB,SACE,QACA,SACA,SACA,aAA2B,EAAE,EACvB;GACN,MAAM,WAAW,KAAK,UAAU,QAAQ;GACxC,IAAI,OAAO,KAAK;AAEhB,QAAK,MAAM,WAAW,UAAU;IAC9B,MAAM,YAAY,QAAQ;AAE1B,QAAI,cAAc,KAAK;AAErB,SAAI,CAAC,KAAK,YAAY;AACpB,WAAK,aAAa,KAAK,WAAW,QAAQ;AAC1C,WAAK,WAAW,YAAY,QAAQ,UAAU,EAAE;;AAElD,YAAO,KAAK;eACH,cAAc,KAAK;AAE5B,SAAI,CAAC,KAAK,eAAe;AACvB,WAAK,gBAAgB,KAAK,WAAW,QAAQ;AAC7C,WAAK,cAAc,YACjB,QAAQ,SAAS,IAAI,QAAQ,UAAU,EAAE,GAAG;;AAEhD,YAAO,KAAK;AACZ;WACK;AAEL,SAAI,CAAC,KAAK,SAAS,SACjB,MAAK,SAAS,WAAW,KAAK,WAAW,QAAQ;AAEnD,YAAO,KAAK,SAAS;;;GAIzB,MAAM,eAA6B;IAAE;IAAS;IAAY;AAG1D,OAAI,KAAK,YAAY,WAAW,WAAW,EACzC,cAAa,WAAW,KAAK,SAAS,EAAE,EAAE,QAAQ;AAGpD,QAAK,SAAS,UAAU;;;EAI1B,cAAc,kBAAsC;AAClD,OAAI,CAAC,KAAK,SAAU;AACpB,QAAK,eAAe,KAAK,MAAM,iBAAiB;;EAGlD,AAAQ,eACN,MACA,kBACM;AACN,QAAK,MAAM,UAAU,KAAK,UAAU;IAClC,MAAM,eAAe,KAAK,SAAS;AACnC,QAAI,cAAc;KAChB,MAAM,gBAAgB,CAAC,GAAG,kBAAkB,GAAG,aAAa,WAAW;AACvE,kBAAa,WAAW,KAAK,SAC3B,eACA,aAAa,QACd;;;AAIL,QAAK,MAAM,OAAO,KAAK,SACrB,MAAK,eAAe,KAAK,SAAS,MAAM,iBAAiB;AAG3D,OAAI,KAAK,WACP,MAAK,eAAe,KAAK,YAAY,iBAAiB;AAGxD,OAAI,KAAK,cACP,MAAK,eAAe,KAAK,eAAe,iBAAiB;;;EAK7D,MAAM,QAAgB,MAAkC;GACtD,MAAM,WAAW,KAAK,UAAU,KAAK;GACrC,MAAM,SAAiC,OAAO,OAAO,KAAK;GAE1D,MAAM,OAAO,KAAK,UAAU,KAAK,MAAM,UAAU,GAAG,OAAO;AAC3D,OAAI,CAAC,KAAM,QAAO;GAElB,MAAM,eAAe,KAAK,SAAS;AACnC,OAAI,CAAC,aAAc,QAAO;AAE1B,UAAO;IACL,SAAS,aAAa;IACtB,YAAY,aAAa;IACzB;IACA,UAAU,aAAa;IACxB;;;EAIH,AAAQ,UACN,MACA,UACA,OACA,QACkB;AAClB,OAAI,UAAU,SAAS,QAAQ;AAC7B,SAAK,MAAM,UAAU,KAAK,SACxB,KAAI,KAAK,SAAS,QAAmB,QAAO;AAE9C,WAAO;;GAGT,MAAM,UAAU,SAAS;GAGzB,MAAM,cAAc,KAAK,SAAS;AAClC,OAAI,aAAa;IACf,MAAM,SAAS,KAAK,UAAU,aAAa,UAAU,QAAQ,GAAG,OAAO;AACvE,QAAI,OAAQ,QAAO;;AAIrB,OAAI,KAAK,YAAY;IACnB,MAAM,YAAY,KAAK,WAAW;IAClC,MAAM,WAAW,OAAO;AAExB,WAAO,aAAa;IACpB,MAAM,SAAS,KAAK,UAClB,KAAK,YACL,UACA,QAAQ,GACR,OACD;AAED,QAAI,OAAQ,QAAO;AAGnB,QAAI,aAAa,OACf,QAAO,OAAO;QAEd,QAAO,aAAa;;AAKxB,OAAI,KAAK,eAAe;AACtB,WAAO,KAAK,cAAc,aAAa,OAAO,SAC3C,MAAM,MAAM,CACZ,KAAK,IAAI;AACZ,WAAO,KAAK;;AAGd,UAAO;;;EAIT,kBAAkB,MAAwB;GACxC,MAAM,WAAW,KAAK,UAAU,KAAK;GACrC,MAAM,OAAO,KAAK,SAAS,SAAS;AACpC,OAAI,CAAC,KAAM,QAAO,EAAE;GAEpB,MAAM,UAAoB,EAAE;AAC5B,QAAK,MAAM,UAAU,KAAK,SACxB,KAAI,KAAK,SAAS,QAChB,SAAQ,KAAK,OAAiB;AAGlC,UAAO;;;EAIT,AAAQ,SAAS,UAAsC;GACrD,IAAI,OAAO,KAAK;AAEhB,QAAK,MAAM,WAAW,SACpB,KAAI,KAAK,SAAS,SAChB,QAAO,KAAK,SAAS;YACZ,KAAK,WACd,QAAO,KAAK;YACH,KAAK,cACd,QAAO,KAAK;OAEZ,QAAO;AAIX,UAAO;;;EAIT,YAAqD;GACnD,MAAM,SAAkD,EAAE;AAC1D,QAAK,cAAc,KAAK,MAAM,IAAI,OAAO;AACzC,UAAO;;EAGT,AAAQ,cACN,MACA,QACA,QACM;GACN,MAAM,cAAc,UAAU,KAAK,OAAO,MAAM,KAAK,OAAO;AAE5D,QAAK,MAAM,UAAU,KAAK,SACxB,KAAI,KAAK,SAAS,QAChB,QAAO,KAAK;IAAU;IAAkB,MAAM,eAAe;IAAK,CAAC;AAIvE,QAAK,MAAM,OAAO,KAAK,SACrB,MAAK,cAAc,KAAK,SAAS,MAAM,aAAa,OAAO;AAG7D,OAAI,KAAK,WACP,MAAK,cAAc,KAAK,YAAY,aAAa,OAAO;AAG1D,OAAI,KAAK,cACP,MAAK,cAAc,KAAK,eAAe,aAAa,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-
|
|
1
|
+
{"version":3,"file":"request-B886yCvG.mjs","names":[],"sources":["../src/node-server/request.ts"],"sourcesContent":["/**\n * 优化的 Request 代理\n * 延迟创建真实 Request,减少不必要的对象分配\n */\n\nimport { Readable } from \"node:stream\";\nimport type { ReadableStream as NodeReadableStream } from \"node:stream/web\";\nimport type { IncomingMessage } from \"node:http\";\n\n// 内部 Symbol\nconst requestCache = Symbol(\"requestCache\");\nconst incomingKey = Symbol(\"incoming\");\nconst urlKey = Symbol(\"url\");\nconst headersKey = Symbol(\"headers\");\n\n/**\n * 从 rawHeaders 高效解析 Headers\n */\nfunction parseHeaders(rawHeaders: string[]): Headers {\n const headers = new Headers();\n for (let i = 0; i < rawHeaders.length; i += 2) {\n const key = rawHeaders[i];\n const value = rawHeaders[i + 1];\n // 跳过 HTTP/2 伪头 (以 : 开头)\n if (key.charCodeAt(0) !== 58) {\n headers.append(key, value);\n }\n }\n return headers;\n}\n\n/**\n * 将 Node.js ReadableStream 转换为 Web 标准 ReadableStream\n * Node.js 和 Web 标准的 ReadableStream 在运行时兼容,但 TypeScript 类型不同\n */\nfunction toWebStream(\n nodeStream: NodeReadableStream<Uint8Array>,\n): ReadableStream<Uint8Array> {\n // Node.js ReadableStream 和 Web ReadableStream 在运行时是兼容的\n // 这里使用类型断言是安全的,因为 Node.js >= 18 的 stream/web 完全实现了 WHATWG Streams 标准\n return nodeStream as unknown as ReadableStream<Uint8Array>;\n}\n\n/** 代理 Request 内部接口 */\ninterface ProxyRequestInternal {\n [requestCache]?: Request;\n [incomingKey]: IncomingMessage;\n [urlKey]: string;\n [headersKey]?: Headers;\n _getRequest(): Request;\n}\n\n/**\n * 创建真实的 Request 对象\n */\nfunction createRealRequest(proxy: ProxyRequestInternal): Request {\n const incoming = proxy[incomingKey];\n const method = incoming.method || \"GET\";\n const init: RequestInit & { duplex?: string } = {\n method,\n headers: proxy[headersKey] || parseHeaders(incoming.rawHeaders),\n };\n\n // 只有非 GET/HEAD 请求才有 body\n if (method !== \"GET\" && method !== \"HEAD\") {\n // 使用 Node.js 原生流转换,避免收集 chunks\n const nodeWebStream = Readable.toWeb(\n incoming,\n ) as NodeReadableStream<Uint8Array>;\n init.body = toWebStream(nodeWebStream);\n init.duplex = \"half\";\n }\n\n return new Request(proxy[urlKey], init);\n}\n\n/**\n * Request 代理原型\n * 使用 Object.defineProperty 定义属性以支持 this 绑定\n */\nconst requestPrototype: object = {};\n\n// 定义 method 属性\nObject.defineProperty(requestPrototype, \"method\", {\n get() {\n const self = this as ProxyRequestInternal;\n return self[incomingKey].method || \"GET\";\n },\n enumerable: true,\n});\n\n// 定义 url 属性\nObject.defineProperty(requestPrototype, \"url\", {\n get() {\n const self = this as ProxyRequestInternal;\n return self[urlKey];\n },\n enumerable: true,\n});\n\n// 定义 headers 属性(延迟解析)\nObject.defineProperty(requestPrototype, \"headers\", {\n get() {\n const self = this as ProxyRequestInternal;\n if (!self[headersKey]) {\n self[headersKey] = parseHeaders(self[incomingKey].rawHeaders);\n }\n return self[headersKey];\n },\n enumerable: true,\n});\n\n// 定义 _getRequest 方法(获取或创建真实 Request)\nObject.defineProperty(requestPrototype, \"_getRequest\", {\n value: function () {\n const self = this as ProxyRequestInternal;\n if (!self[requestCache]) {\n self[requestCache] = createRealRequest(self);\n }\n return self[requestCache]!;\n },\n enumerable: false,\n});\n\n// 代理需要访问真实 Request 的属性\nconst proxyGetters = [\n \"body\",\n \"bodyUsed\",\n \"signal\",\n \"cache\",\n \"credentials\",\n \"destination\",\n \"integrity\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"keepalive\",\n];\n\nproxyGetters.forEach((key) => {\n Object.defineProperty(requestPrototype, key, {\n get() {\n const self = this as ProxyRequestInternal;\n return self._getRequest()[key as keyof Request];\n },\n enumerable: true,\n });\n});\n\n// 代理需要调用真实 Request 的方法\nconst proxyMethods = [\n \"arrayBuffer\",\n \"blob\",\n \"clone\",\n \"formData\",\n \"json\",\n \"text\",\n];\n\nproxyMethods.forEach((key) => {\n Object.defineProperty(requestPrototype, key, {\n value: function () {\n const self = this as ProxyRequestInternal;\n const req = self._getRequest();\n return (req[key as keyof Request] as () => Promise<unknown>).call(req);\n },\n enumerable: true,\n });\n});\n\n// 设置原型链\nObject.setPrototypeOf(requestPrototype, Request.prototype);\n\n/**\n * 创建代理 Request\n * @param incoming Node.js IncomingMessage\n * @param defaultHost 默认主机名\n */\nexport function createProxyRequest(\n incoming: IncomingMessage,\n defaultHost: string,\n): Request {\n const req = Object.create(requestPrototype) as ProxyRequestInternal;\n req[incomingKey] = incoming;\n\n // 构建 URL\n const host = incoming.headers.host || defaultHost;\n const protocol = (incoming.socket as { encrypted?: boolean }).encrypted\n ? \"https\"\n : \"http\";\n req[urlKey] = `${protocol}://${host}${incoming.url || \"/\"}`;\n\n return req as unknown as Request;\n}\n"],"mappings":";;;;;;;AAUA,MAAM,eAAe,OAAO,eAAe;AAC3C,MAAM,cAAc,OAAO,WAAW;AACtC,MAAM,SAAS,OAAO,MAAM;AAC5B,MAAM,aAAa,OAAO,UAAU;;;;AAKpC,SAAS,aAAa,YAA+B;CACnD,MAAM,UAAU,IAAI,SAAS;AAC7B,MAAK,IAAI,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,GAAG;EAC7C,MAAM,MAAM,WAAW;EACvB,MAAM,QAAQ,WAAW,IAAI;AAE7B,MAAI,IAAI,WAAW,EAAE,KAAK,GACxB,SAAQ,OAAO,KAAK,MAAM;;AAG9B,QAAO;;;;;;AAOT,SAAS,YACP,YAC4B;AAG5B,QAAO;;;;;AAeT,SAAS,kBAAkB,OAAsC;CAC/D,MAAM,WAAW,MAAM;CACvB,MAAM,SAAS,SAAS,UAAU;CAClC,MAAM,OAA0C;EAC9C;EACA,SAAS,MAAM,eAAe,aAAa,SAAS,WAAW;EAChE;AAGD,KAAI,WAAW,SAAS,WAAW,QAAQ;AAKzC,OAAK,OAAO,YAHU,SAAS,MAC7B,SACD,CACqC;AACtC,OAAK,SAAS;;AAGhB,QAAO,IAAI,QAAQ,MAAM,SAAS,KAAK;;;;;;AAOzC,MAAM,mBAA2B,EAAE;AAGnC,OAAO,eAAe,kBAAkB,UAAU;CAChD,MAAM;AAEJ,SADa,KACD,aAAa,UAAU;;CAErC,YAAY;CACb,CAAC;AAGF,OAAO,eAAe,kBAAkB,OAAO;CAC7C,MAAM;AAEJ,SADa,KACD;;CAEd,YAAY;CACb,CAAC;AAGF,OAAO,eAAe,kBAAkB,WAAW;CACjD,MAAM;EACJ,MAAM,OAAO;AACb,MAAI,CAAC,KAAK,YACR,MAAK,cAAc,aAAa,KAAK,aAAa,WAAW;AAE/D,SAAO,KAAK;;CAEd,YAAY;CACb,CAAC;AAGF,OAAO,eAAe,kBAAkB,eAAe;CACrD,OAAO,WAAY;EACjB,MAAM,OAAO;AACb,MAAI,CAAC,KAAK,cACR,MAAK,gBAAgB,kBAAkB,KAAK;AAE9C,SAAO,KAAK;;CAEd,YAAY;CACb,CAAC;AAGmB;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAEY,SAAS,QAAQ;AAC5B,QAAO,eAAe,kBAAkB,KAAK;EAC3C,MAAM;AAEJ,UADa,KACD,aAAa,CAAC;;EAE5B,YAAY;EACb,CAAC;EACF;AAGmB;CACnB;CACA;CACA;CACA;CACA;CACA;CACD,CAEY,SAAS,QAAQ;AAC5B,QAAO,eAAe,kBAAkB,KAAK;EAC3C,OAAO,WAAY;GAEjB,MAAM,MADO,KACI,aAAa;AAC9B,UAAQ,IAAI,KAAiD,KAAK,IAAI;;EAExE,YAAY;EACb,CAAC;EACF;AAGF,OAAO,eAAe,kBAAkB,QAAQ,UAAU;;;;;;AAO1D,SAAgB,mBACd,UACA,aACS;CACT,MAAM,MAAM,OAAO,OAAO,iBAAiB;AAC3C,KAAI,eAAe;CAGnB,MAAM,OAAO,SAAS,QAAQ,QAAQ;AAItC,KAAI,UAAU,GAHI,SAAS,OAAmC,YAC1D,UACA,OACsB,KAAK,OAAO,SAAS,OAAO;AAEtD,QAAO"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as SchemaConfig } from "./validators-
|
|
1
|
+
import { t as SchemaConfig } from "./validators-CPmnj_y9.mjs";
|
|
2
2
|
import { Static, TSchema } from "@sinclair/typebox";
|
|
3
3
|
|
|
4
4
|
//#region src/utils/request-validator.d.ts
|
|
@@ -64,4 +64,4 @@ declare function parseAndValidateRequest<T extends SchemaConfig>(request: Reques
|
|
|
64
64
|
declare function createRequestValidator<T extends SchemaConfig>(config: T): (request: Request, params?: Record<string, string>) => Promise<ValidationResult<T>>;
|
|
65
65
|
//#endregion
|
|
66
66
|
export { parseAndValidateRequest as a, createRequestValidator as i, ValidatedRequestData as n, parseRequest as o, ValidationResult as r, validateRequest as s, RequestData as t };
|
|
67
|
-
//# sourceMappingURL=request-validator-
|
|
67
|
+
//# sourceMappingURL=request-validator-42lY21gn.d.mts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as parseCookies, l as parseHeaders, r as parseBody, u as parseQuery } from "./parsers-
|
|
2
|
-
import { a as validateAllSchemas } from "./validators-
|
|
1
|
+
import { a as parseCookies, l as parseHeaders, r as parseBody, u as parseQuery } from "./parsers-BQ63b0YE.mjs";
|
|
2
|
+
import { a as validateAllSchemas } from "./validators-WXQ49LcR.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/utils/request-validator.ts
|
|
5
5
|
/**
|
|
@@ -74,4 +74,4 @@ function createRequestValidator(config) {
|
|
|
74
74
|
|
|
75
75
|
//#endregion
|
|
76
76
|
export { validateRequest as i, parseAndValidateRequest as n, parseRequest as r, createRequestValidator as t };
|
|
77
|
-
//# sourceMappingURL=request-validator-
|
|
77
|
+
//# sourceMappingURL=request-validator-DLFtm4uV.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-validator-
|
|
1
|
+
{"version":3,"file":"request-validator-DLFtm4uV.mjs","names":[],"sources":["../src/utils/request-validator.ts"],"sourcesContent":["/**\n * 请求解析和验证器\n *\n * 解析handler的req参数,使用Ultra验证器进行验证,\n * 并类型安全地返回解析出来的值\n *\n * @author Framework Team\n * @version 1.0.0\n * @license MIT\n */\n\nimport type { TSchema } from \"@sinclair/typebox\";\nimport type { Static } from \"@sinclair/typebox\";\nimport {\n validateAllSchemas,\n type SchemaConfig,\n} from \"./validators/validators\";\nimport { parseBody, parseQuery, parseHeaders, parseCookies } from \"./parsers\";\n\n// 请求数据结构\nexport interface RequestData {\n body: unknown;\n query: unknown;\n params: Record<string, string>;\n headers: Record<string, string>;\n cookies: Record<string, string>;\n}\n\n// 验证后的请求数据类型\nexport interface ValidatedRequestData<T extends SchemaConfig> {\n body: T[\"body\"] extends TSchema ? Static<T[\"body\"]> : unknown;\n query: T[\"query\"] extends TSchema ? Static<T[\"query\"]> : unknown;\n params: T[\"params\"] extends TSchema\n ? Static<T[\"params\"]>\n : Record<string, string>;\n headers: T[\"headers\"] extends TSchema\n ? Static<T[\"headers\"]>\n : Record<string, string>;\n cookies: T[\"cookies\"] extends TSchema\n ? Static<T[\"cookies\"]>\n : Record<string, string>;\n}\n\n// 验证结果\nexport interface ValidationResult<T extends SchemaConfig> {\n success: boolean;\n data?: ValidatedRequestData<T>;\n errors?: Array<{ field: keyof SchemaConfig; message: string }>;\n}\n\n/**\n * 解析Request对象,提取所有相关数据\n * @param request Request对象\n * @param params 路径参数(可选)\n * @returns 解析后的请求数据\n */\nexport async function parseRequest(\n request: Request,\n params?: Record<string, string>,\n): Promise<RequestData> {\n const requestData: RequestData = {\n body: undefined,\n query: parseQuery(request),\n params: params || {},\n headers: parseHeaders(request),\n cookies: parseCookies(request),\n };\n\n // 对于非GET请求,尝试解析请求体\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n requestData.body = await parseBody(request);\n }\n\n return requestData;\n}\n\n/**\n * 验证请求数据\n * @param config Schema配置\n * @param requestData 请求数据\n * @returns 验证结果\n */\nexport function validateRequest<T extends SchemaConfig>(\n config: T,\n requestData: RequestData,\n): ValidationResult<T> {\n try {\n const validatedData = validateAllSchemas(config, requestData);\n\n return {\n success: true,\n data: validatedData as ValidatedRequestData<T>,\n };\n } catch (error) {\n return {\n success: false,\n errors: [\n {\n field: \"unknown\" as keyof SchemaConfig,\n message: error instanceof Error ? error.message : \"验证失败\",\n },\n ],\n };\n }\n}\n\n/**\n * 完整的请求解析和验证流程\n * @param request Request对象\n * @param config Schema配置\n * @param params 路径参数(可选)\n * @returns 验证结果\n */\nexport async function parseAndValidateRequest<T extends SchemaConfig>(\n request: Request,\n config: T,\n params?: Record<string, string>,\n): Promise<ValidationResult<T>> {\n try {\n // 1. 解析请求\n const requestData = await parseRequest(request, params);\n\n // 2. 验证数据\n return validateRequest(config, requestData);\n } catch (error) {\n return {\n success: false,\n errors: [\n {\n field: \"unknown\" as keyof SchemaConfig,\n message: error instanceof Error ? error.message : \"请求解析失败\",\n },\n ],\n };\n }\n}\n\n/**\n * 创建类型安全的请求验证器工厂\n * @param config Schema配置\n * @returns 验证器函数\n */\nexport function createRequestValidator<T extends SchemaConfig>(config: T) {\n return async (request: Request, params?: Record<string, string>) => {\n return parseAndValidateRequest(request, config, params);\n };\n}\n"],"mappings":";;;;;;;;;;AAwDA,eAAsB,aACpB,SACA,QACsB;CACtB,MAAM,cAA2B;EAC/B,MAAM;EACN,OAAO,WAAW,QAAQ;EAC1B,QAAQ,UAAU,EAAE;EACpB,SAAS,aAAa,QAAQ;EAC9B,SAAS,aAAa,QAAQ;EAC/B;AAGD,KAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,OACjD,aAAY,OAAO,MAAM,UAAU,QAAQ;AAG7C,QAAO;;;;;;;;AAST,SAAgB,gBACd,QACA,aACqB;AACrB,KAAI;AAGF,SAAO;GACL,SAAS;GACT,MAJoB,mBAAmB,QAAQ,YAAY;GAK5D;UACM,OAAO;AACd,SAAO;GACL,SAAS;GACT,QAAQ,CACN;IACE,OAAO;IACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU;IACnD,CACF;GACF;;;;;;;;;;AAWL,eAAsB,wBACpB,SACA,QACA,QAC8B;AAC9B,KAAI;AAKF,SAAO,gBAAgB,QAHH,MAAM,aAAa,SAAS,OAAO,CAGZ;UACpC,OAAO;AACd,SAAO;GACL,SAAS;GACT,QAAQ,CACN;IACE,OAAO;IACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU;IACnD,CACF;GACF;;;;;;;;AASL,SAAgB,uBAA+C,QAAW;AACxE,QAAO,OAAO,SAAkB,WAAoC;AAClE,SAAO,wBAAwB,SAAS,QAAQ,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-
|
|
1
|
+
{"version":3,"file":"response-30WnzABq.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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { t as VafastError } from "./middleware-5PjaxPMA.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/response.d.ts
|
|
4
|
+
/** 生成 JSON 响应 */
|
|
5
|
+
declare function json(data: unknown, status?: number, headers?: HeadersInit): Response;
|
|
6
|
+
/**
|
|
7
|
+
* 类型特化的响应映射
|
|
8
|
+
* 根据返回值类型直接生成 Response,避免不必要的检查
|
|
9
|
+
*/
|
|
10
|
+
declare function mapResponse(response: unknown): Response;
|
|
11
|
+
/** 生成重定向响应 */
|
|
12
|
+
declare function redirect(location: string, status?: 301 | 302): Response;
|
|
13
|
+
/** 生成纯文本响应 */
|
|
14
|
+
declare function text(content: string, status?: number, headers?: HeadersInit): Response;
|
|
15
|
+
/** 生成HTML响应 */
|
|
16
|
+
declare function html(content: string, status?: number, headers?: HeadersInit): Response;
|
|
17
|
+
/** 生成空响应(204 No Content) */
|
|
18
|
+
declare function empty(status?: number, headers?: HeadersInit): Response;
|
|
19
|
+
/** 生成流式响应 */
|
|
20
|
+
declare function stream(stream: ReadableStream, status?: number, headers?: HeadersInit): Response;
|
|
21
|
+
/**
|
|
22
|
+
* 创建错误响应
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // 自定义错误
|
|
27
|
+
* throw err('用户不存在', 404, 'NOT_FOUND')
|
|
28
|
+
*
|
|
29
|
+
* // 预定义错误
|
|
30
|
+
* throw err.notFound('用户不存在')
|
|
31
|
+
* throw err.badRequest('参数错误')
|
|
32
|
+
* throw err.unauthorized('请先登录')
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
declare function err(message: string, status?: number, type?: string): VafastError;
|
|
36
|
+
declare namespace err {
|
|
37
|
+
var badRequest: (message?: string) => VafastError;
|
|
38
|
+
var unauthorized: (message?: string) => VafastError;
|
|
39
|
+
var forbidden: (message?: string) => VafastError;
|
|
40
|
+
var notFound: (message?: string) => VafastError;
|
|
41
|
+
var conflict: (message?: string) => VafastError;
|
|
42
|
+
var unprocessable: (message?: string) => VafastError;
|
|
43
|
+
var tooMany: (message?: string) => VafastError;
|
|
44
|
+
var internal: (message?: string) => VafastError;
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
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 };
|
|
48
|
+
//# sourceMappingURL=response-CxYf6Ep3.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-
|
|
1
|
+
{"version":3,"file":"route-B3ONOzxQ.mjs","names":[],"sources":["../src/types/route.ts"],"sourcesContent":["import { Route, ResponseBody } from \"./types\";\n\n// 定义中间件类型\nexport interface Middleware {\n (req: Request, next: () => Promise<Response>): Promise<Response>;\n}\n\n// 基础路由配置\nexport interface BaseRouteConfig {\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"OPTIONS\" | \"HEAD\";\n path: string;\n handler: (req: Request) => ResponseBody | Promise<ResponseBody>;\n}\n\n// 扩展的路由配置 - 只保留Schema验证和中间件\nexport interface ExtendedRouteConfig extends BaseRouteConfig {\n // Tirne 中间件系统\n middleware?: Middleware[];\n\n // Schema验证配置\n body?: any;\n query?: any;\n params?: any;\n headers?: any;\n cookies?: any;\n\n // 其他配置\n docs?: {\n description?: string;\n tags?: string[];\n security?: any[];\n responses?: Record<string, any>;\n };\n timeout?: number;\n maxBodySize?: string;\n\n // 允许任意扩展\n [key: string]: any;\n}\n\n// 嵌套路由配置\nexport interface NestedRouteConfig {\n path: string;\n middleware?: Middleware[];\n children?: (NestedRouteConfig | ExtendedRouteConfig)[];\n}\n\n// 类型安全的路由\nexport type TypedRoute = ExtendedRouteConfig;\n\n// 兼容类型:可以接受Route或TypedRoute\nexport type CompatibleRoute = Route | TypedRoute;\n\n// 扁平化后的路由,包含完整的中间件链\nexport interface FlattenedRoute extends ExtendedRouteConfig {\n fullPath: string;\n middlewareChain: Middleware[];\n}\n\n// 导出一些实际的函数,确保 JavaScript 代码生成\nexport function createTypedRoute(\n config: ExtendedRouteConfig,\n): ExtendedRouteConfig {\n return config;\n}\n\nexport function isTypedRoute(route: any): route is TypedRoute {\n return (\n route &&\n typeof route === \"object\" &&\n \"method\" in route &&\n \"path\" in route &&\n \"handler\" in route\n );\n}\n"],"mappings":";AA4DA,SAAgB,iBACd,QACqB;AACrB,QAAO;;AAGT,SAAgB,aAAa,OAAiC;AAC5D,QACE,SACA,OAAO,UAAU,YACjB,YAAY,SACZ,UAAU,SACV,aAAa"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as ResponseBody, l as Route } from "./types-
|
|
1
|
+
import { c as ResponseBody, l as Route } from "./types-mpeSaHdI.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/types/route.d.ts
|
|
4
4
|
interface Middleware {
|
|
@@ -41,4 +41,4 @@ declare function createTypedRoute(config: ExtendedRouteConfig): ExtendedRouteCon
|
|
|
41
41
|
declare function isTypedRoute(route: any): route is TypedRoute;
|
|
42
42
|
//#endregion
|
|
43
43
|
export { Middleware as a, createTypedRoute as c, FlattenedRoute as i, isTypedRoute as l, CompatibleRoute as n, NestedRouteConfig as o, ExtendedRouteConfig as r, TypedRoute as s, BaseRouteConfig as t };
|
|
44
|
-
//# sourceMappingURL=route-
|
|
44
|
+
//# sourceMappingURL=route-CUbNpSwz.d.mts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as __esmMin } from "./chunk-
|
|
1
|
+
import { t as __esmMin } from "./chunk-DW4-Jl94.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/utils/route-registry.ts
|
|
4
4
|
/**
|
|
@@ -222,4 +222,4 @@ var init_route_registry = __esmMin((() => {
|
|
|
222
222
|
|
|
223
223
|
//#endregion
|
|
224
224
|
export { getRoute as a, setGlobalRegistry as c, getAllRoutes as i, createRouteRegistry as n, getRouteRegistry as o, filterRoutes as r, init_route_registry as s, RouteRegistry as t };
|
|
225
|
-
//# sourceMappingURL=route-registry-
|
|
225
|
+
//# sourceMappingURL=route-registry-BVvbghgH.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-registry-
|
|
1
|
+
{"version":3,"file":"route-registry-BVvbghgH.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 { FlattenedRoute, Method } from '../types'\n\n/**\n * 路由元信息(不含 handler 和 middleware)\n */\nexport interface RouteMeta {\n method: Method\n path: string\n fullPath: string\n name?: string\n description?: string\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:fullPath -> RouteMeta */\n private routeMap = new Map<string, RouteMeta>()\n\n /** 分类映射表:category -> RouteMeta[] */\n private categoryMap = new Map<string, RouteMeta[]>()\n\n constructor(routes: FlattenedRoute[]) {\n this.buildRegistry(routes)\n }\n\n /**\n * 构建注册表\n */\n private buildRegistry(routes: FlattenedRoute[]): void {\n for (const route of routes) {\n // 提取元信息(排除 handler 和 middleware)\n const meta: RouteMeta = {\n method: route.method,\n path: route.path,\n fullPath: route.fullPath,\n name: route.name,\n description: route.description,\n }\n\n // 复制扩展字段\n for (const key of Object.keys(route)) {\n if (!['method', 'path', 'fullPath', 'name', 'description', 'handler', 'middleware', 'middlewareChain'].includes(key)) {\n meta[key] = route[key as keyof FlattenedRoute]\n }\n }\n\n this.routes.push(meta)\n this.routeMap.set(`${route.method}:${route.fullPath}`, meta)\n\n // 按分类索引\n const category = this.extractCategory(route.fullPath)\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: FlattenedRoute[]\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6MA,SAAgB,oBACd,QACkB;AAClB,QAAO,IAAI,cAAiB,OAAO;;;;;;AAcrC,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;;;;CA/P5B,gBAAb,MAAwF;;EAEtF,AAAQ,SAAsB,EAAE;;EAGhC,AAAQ,2BAAW,IAAI,KAAwB;;EAG/C,AAAQ,8BAAc,IAAI,KAA0B;EAEpD,YAAY,QAA0B;AACpC,QAAK,cAAc,OAAO;;;;;EAM5B,AAAQ,cAAc,QAAgC;AACpD,QAAK,MAAM,SAAS,QAAQ;IAE1B,MAAM,OAAkB;KACtB,QAAQ,MAAM;KACd,MAAM,MAAM;KACZ,UAAU,MAAM;KAChB,MAAM,MAAM;KACZ,aAAa,MAAM;KACpB;AAGD,SAAK,MAAM,OAAO,OAAO,KAAK,MAAM,CAClC,KAAI,CAAC;KAAC;KAAU;KAAQ;KAAY;KAAQ;KAAe;KAAW;KAAc;KAAkB,CAAC,SAAS,IAAI,CAClH,MAAK,OAAO,MAAM;AAItB,SAAK,OAAO,KAAK,KAAK;AACtB,SAAK,SAAS,IAAI,GAAG,MAAM,OAAO,GAAG,MAAM,YAAY,KAAK;IAG5D,MAAM,WAAW,KAAK,gBAAgB,MAAM,SAAS;AACrD,QAAI,CAAC,KAAK,YAAY,IAAI,SAAS,CACjC,MAAK,YAAY,IAAI,UAAU,EAAE,CAAC;AAEpC,SAAK,YAAY,IAAI,SAAS,CAAE,KAAK,KAAK;;;;;;EAO9C,AAAQ,gBAAgB,MAAsB;AAE5C,UADiB,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ,CAChC,MAAM;;;;;EAUxB,SAAsB;AACpB,UAAO,CAAC,GAAG,KAAK,OAAO;;;;;EAMzB,IAAI,QAAgB,MAA2C;AAC7D,UAAO,KAAK,SAAS,IAAI,GAAG,OAAO,GAAG,OAAO;;;;;EAM/C,IAAI,QAAgB,MAAuB;AACzC,UAAO,KAAK,SAAS,IAAI,GAAG,OAAO,GAAG,OAAO;;;;;EAM/C,cAAc,UAA+B;AAC3C,UAAO,KAAK,YAAY,IAAI,SAAS,IAAI,EAAE;;;;;EAM7C,gBAA0B;AACxB,UAAO,MAAM,KAAK,KAAK,YAAY,MAAM,CAAC,CAAC,MAAM;;;;;;;;;;;EAYnD,OAAyB,OAA8C;AACrE,UAAO,KAAK,OAAO,QAAQ,MAAM,SAAS,KAAK,EAAE,WAAW,OAAU;;;;;;;;;;;EAYxE,SAAS,WAAuD;AAC9D,UAAO,KAAK,OAAO,OAAO,UAAU;;;;;EAMtC,IAAI,OAAe;AACjB,UAAO,KAAK,OAAO;;;;;EAMrB,QAAQ,UAA2D;AACjE,QAAK,OAAO,QAAQ,SAAS;;;;;EAM/B,IAAO,UAAuD;AAC5D,UAAO,KAAK,OAAO,IAAI,SAAS;;;CAoChC,iBAAuC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as Method, n as FlattenedRoute } from "./types-
|
|
1
|
+
import { a as Method, n as FlattenedRoute } from "./types-mpeSaHdI.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/utils/route-registry.d.ts
|
|
4
4
|
|
|
@@ -173,4 +173,4 @@ declare function getAllRoutes(): RouteMeta[];
|
|
|
173
173
|
declare function filterRoutes<K extends string>(field: K): (RouteMeta & Record<K, unknown>)[];
|
|
174
174
|
//#endregion
|
|
175
175
|
export { getAllRoutes as a, setGlobalRegistry as c, filterRoutes as i, RouteRegistry as n, getRoute as o, createRouteRegistry as r, getRouteRegistry as s, RouteMeta as t };
|
|
176
|
-
//# sourceMappingURL=route-registry-
|
|
176
|
+
//# sourceMappingURL=route-registry-CYD7m6QP.d.mts.map
|
package/dist/router/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "../schema-
|
|
2
|
-
import "../index-
|
|
1
|
+
import "../schema-DOKg31ZX.mjs";
|
|
2
|
+
import "../index-CTHojwxd.mjs";
|
|
3
3
|
import { flattenNestedRoutes, normalizePath } from "../router.mjs";
|
|
4
4
|
import { RadixRouter } from "./radix-tree.mjs";
|
|
5
5
|
export { RadixRouter, flattenNestedRoutes, normalizePath };
|
package/dist/router/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as init_router, r as normalizePath, t as flattenNestedRoutes } from "../router-
|
|
2
|
-
import { n as init_radix_tree, t as RadixRouter } from "../radix-tree-
|
|
1
|
+
import { n as init_router, r as normalizePath, t as flattenNestedRoutes } from "../router-B9HUUCkR.mjs";
|
|
2
|
+
import { n as init_radix_tree, t as RadixRouter } from "../radix-tree-Qxr-QpCx.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/router/index.ts
|
|
5
5
|
init_radix_tree();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as Method, o as Middleware, r as Handler } from "../types-
|
|
2
|
-
import "../schema-
|
|
3
|
-
import "../index-
|
|
1
|
+
import { a as Method, o as Middleware, r as Handler } from "../types-mpeSaHdI.mjs";
|
|
2
|
+
import "../schema-DOKg31ZX.mjs";
|
|
3
|
+
import "../index-CTHojwxd.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/router/radix-tree.d.ts
|
|
6
6
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as __esmMin } from "./chunk-
|
|
1
|
+
import { t as __esmMin } from "./chunk-DW4-Jl94.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/router.ts
|
|
4
4
|
/**
|
|
@@ -68,4 +68,4 @@ var init_router = __esmMin((() => {}));
|
|
|
68
68
|
|
|
69
69
|
//#endregion
|
|
70
70
|
export { init_router as n, normalizePath as r, flattenNestedRoutes as t };
|
|
71
|
-
//# sourceMappingURL=router-
|
|
71
|
+
//# sourceMappingURL=router-B9HUUCkR.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router-
|
|
1
|
+
{"version":3,"file":"router-B9HUUCkR.mjs","names":[],"sources":["../src/router.ts"],"sourcesContent":["/**\n * 路由工具函数\n *\n * 提供路由处理的基础工具\n */\n\nimport type { Route, NestedRoute, FlattenedRoute, Middleware } from \"./types\";\n\n/**\n * 扁平化嵌套路由\n *\n * 将嵌套路由结构转换为扁平数组,计算完整路径和中间件链\n *\n * @example\n * ```typescript\n * const routes = flattenNestedRoutes([\n * {\n * path: \"/api\",\n * middleware: [authMiddleware],\n * children: [\n * { path: \"/users\", method: \"GET\", handler: getUsers },\n * { path: \"/users/:id\", method: \"GET\", handler: getUser },\n * ],\n * },\n * ]);\n * // 结果:\n * // [\n * // { fullPath: \"/api/users\", method: \"GET\", ... },\n * // { fullPath: \"/api/users/:id\", method: \"GET\", ... },\n * // ]\n * ```\n */\nexport function flattenNestedRoutes(\n routes: (Route | NestedRoute)[],\n): FlattenedRoute[] {\n const flattened: FlattenedRoute[] = [];\n\n function processRoute(\n route: Route | NestedRoute,\n parentPath = \"\",\n parentMiddleware: Middleware[] = [],\n parentName?: string,\n ): void {\n // 计算当前完整路径\n const currentPath = normalizePath(parentPath + route.path);\n // 合并中间件链\n const currentMiddleware = [\n ...parentMiddleware,\n ...(route.middleware || []),\n ];\n // 当前路由的 name(用于传递给子路由)\n const currentName = route.name || parentName;\n\n if (\"method\" in route && \"handler\" in route) {\n // 叶子路由(有处理函数)\n const leafRoute = route as Route;\n flattened.push({\n ...leafRoute,\n fullPath: currentPath,\n middlewareChain: currentMiddleware,\n parentName: parentName, // 保存父级名称\n });\n } else if (\"children\" in route && route.children) {\n // 分组路由,递归处理子路由\n for (const child of route.children) {\n processRoute(child, currentPath, currentMiddleware, currentName);\n }\n }\n }\n\n for (const route of routes) {\n processRoute(route);\n }\n\n return flattened;\n}\n\n/**\n * 标准化路径\n *\n * - 解码 URL 编码字符\n * - 去除重复斜杠\n * - 处理结尾斜杠\n *\n * @example\n * ```typescript\n * normalizePath(\"//api//users/\") // \"/api/users\"\n * normalizePath(\"/api/%20test\") // \"/api/ test\"\n * ```\n */\nexport function normalizePath(path: string): string {\n // 解码 URL 编码\n let normalized = decodeURIComponent(path);\n\n // 去除重复斜杠\n normalized = normalized.replace(/\\/+/g, \"/\");\n\n // 空路径转为根路径\n if (normalized === \"\") return \"/\";\n\n // 去除结尾斜杠(根路径除外)\n if (normalized !== \"/\" && normalized.endsWith(\"/\")) {\n normalized = normalized.slice(0, -1);\n }\n\n return normalized;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,oBACd,QACkB;CAClB,MAAM,YAA8B,EAAE;CAEtC,SAAS,aACP,OACA,aAAa,IACb,mBAAiC,EAAE,EACnC,YACM;EAEN,MAAM,cAAc,cAAc,aAAa,MAAM,KAAK;EAE1D,MAAM,oBAAoB,CACxB,GAAG,kBACH,GAAI,MAAM,cAAc,EAAE,CAC3B;EAED,MAAM,cAAc,MAAM,QAAQ;AAElC,MAAI,YAAY,SAAS,aAAa,OAAO;GAE3C,MAAM,YAAY;AAClB,aAAU,KAAK;IACb,GAAG;IACH,UAAU;IACV,iBAAiB;IACL;IACb,CAAC;aACO,cAAc,SAAS,MAAM,SAEtC,MAAK,MAAM,SAAS,MAAM,SACxB,cAAa,OAAO,aAAa,mBAAmB,YAAY;;AAKtE,MAAK,MAAM,SAAS,OAClB,cAAa,MAAM;AAGrB,QAAO;;;;;;;;;;;;;;;AAgBT,SAAgB,cAAc,MAAsB;CAElD,IAAI,aAAa,mBAAmB,KAAK;AAGzC,cAAa,WAAW,QAAQ,QAAQ,IAAI;AAG5C,KAAI,eAAe,GAAI,QAAO;AAG9B,KAAI,eAAe,OAAO,WAAW,SAAS,IAAI,CAChD,cAAa,WAAW,MAAM,GAAG,GAAG;AAGtC,QAAO"}
|
package/dist/router.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { l as Route, n as FlattenedRoute, s as NestedRoute } from "./types-
|
|
2
|
-
import "./schema-
|
|
3
|
-
import "./index-
|
|
1
|
+
import { l as Route, n as FlattenedRoute, s as NestedRoute } from "./types-mpeSaHdI.mjs";
|
|
2
|
+
import "./schema-DOKg31ZX.mjs";
|
|
3
|
+
import "./index-CTHojwxd.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/router.d.ts
|
|
6
6
|
|
package/dist/router.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as init_router, r as normalizePath, t as flattenNestedRoutes } from "./router-
|
|
1
|
+
import { n as init_router, r as normalizePath, t as flattenNestedRoutes } from "./router-B9HUUCkR.mjs";
|
|
2
2
|
|
|
3
3
|
init_router();
|
|
4
4
|
export { flattenNestedRoutes, normalizePath };
|
|
@@ -78,4 +78,4 @@ interface TypedRouteConfig<T extends RouteSchema = RouteSchema> {
|
|
|
78
78
|
}
|
|
79
79
|
//#endregion
|
|
80
80
|
export { TypedHandler as a, RouteSchema as i, HandlerContextWithExtra as n, TypedRouteConfig as o, InferSchema as r, HandlerContext as t };
|
|
81
|
-
//# sourceMappingURL=schema-
|
|
81
|
+
//# sourceMappingURL=schema-DOKg31ZX.d.mts.map
|
|
@@ -66,4 +66,4 @@ declare function serve(options: ServeOptions, callback?: () => void): ServeResul
|
|
|
66
66
|
declare function createAdaptorServer(fetch: FetchHandler, onError?: (error: Error) => Response | Promise<Response>): Server;
|
|
67
67
|
//#endregion
|
|
68
68
|
export { createAdaptorServer as a, ServeResult as i, GracefulShutdownOptions as n, serve as o, ServeOptions as r, FetchHandler as t };
|
|
69
|
-
//# sourceMappingURL=serve-
|
|
69
|
+
//# sourceMappingURL=serve-B5WmhK6m.d.mts.map
|
|
@@ -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-B886yCvG.mjs";
|
|
2
|
+
import { t as writeResponse } from "./response-30WnzABq.mjs";
|
|
3
3
|
import { createServer } from "node:http";
|
|
4
4
|
|
|
5
5
|
//#region src/node-server/serve.ts
|
|
@@ -104,4 +104,4 @@ function createAdaptorServer(fetch, onError) {
|
|
|
104
104
|
|
|
105
105
|
//#endregion
|
|
106
106
|
export { serve as n, createAdaptorServer as t };
|
|
107
|
-
//# sourceMappingURL=serve-
|
|
107
|
+
//# sourceMappingURL=serve-DgWBnexE.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve-
|
|
1
|
+
{"version":3,"file":"serve-DgWBnexE.mjs","names":[],"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/** 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\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/**\n * 创建请求处理函数\n */\nfunction createRequestHandler(\n fetch: FetchHandler,\n defaultHost: string,\n onError?: (error: Error) => Response | Promise<Response>,\n) {\n return async (incoming: IncomingMessage, outgoing: ServerResponse) => {\n try {\n // 创建代理 Request(延迟创建真实 Request)\n const request = createProxyRequest(incoming, defaultHost);\n\n // 调用 fetch handler\n const response = await fetch(request);\n\n // 流式写入 Response\n await writeResponse(response, outgoing);\n } catch (error) {\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 } = options;\n\n const defaultHost = `${hostname === \"0.0.0.0\" ? \"localhost\" : hostname}:${port}`;\n const handler = createRequestHandler(fetch, defaultHost, onError);\n\n const server = createServer(handler);\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): HttpServer {\n const handler = createRequestHandler(fetch, \"localhost\", onError);\n return createServer(handler);\n}\n"],"mappings":";;;;;;;;;;;;AA4DA,SAAS,qBACP,OACA,aACA,SACA;AACA,QAAO,OAAO,UAA2B,aAA6B;AACpE,MAAI;AAQF,SAAM,cAHW,MAAM,MAHP,mBAAmB,UAAU,YAAY,CAGpB,EAGP,SAAS;WAChC,OAAO;GAEd,MAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;AAErE,OAAI,QACF,KAAI;AAEF,UAAM,cADgB,MAAM,QAAQ,IAAI,EACL,SAAS;AAC5C;WACM;AAMV,OAAI,CAAC,SAAS,aAAa;AACzB,aAAS,aAAa;AACtB,aAAS,UAAU,gBAAgB,aAAa;AAChD,aAAS,IAAI,wBAAwB;;;;;;;;;;;;;;;;;;;;;;AAuB7C,SAAgB,MACd,SACA,UACa;CACb,MAAM,EAAE,OAAO,OAAO,KAAM,WAAW,WAAW,SAAS,qBAAqB;CAKhF,MAAM,SAAS,aAFC,qBAAqB,OADjB,GAAG,aAAa,YAAY,cAAc,SAAS,GAAG,QACjB,QAAQ,CAE7B;CAGpC,MAAM,8BAAc,IAAI,KAAgC;AAExD,QAAO,GAAG,eAAe,WAAW;AAClC,cAAY,IAAI,OAAO;AACvB,SAAO,GAAG,eAAe,YAAY,OAAO,OAAO,CAAC;GACpD;CAGF,IAAI,iBAAiB;CAErB,MAAM,WAAW,YAA2B;AAC1C,MAAI,eAAgB;AACpB,mBAAiB;EAEjB,MAAM,kBACJ,OAAO,qBAAqB,WAAW,mBAAmB,EAAE;EAE9D,MAAM,UAAU,gBAAgB,WAAW;AAG3C,MAAI,gBAAgB,WAClB,OAAM,gBAAgB,YAAY;AAGpC,SAAO,IAAI,SAAe,YAAY;GAEpC,MAAM,kBAAkB,iBAAiB;AAEvC,SAAK,MAAM,UAAU,YACnB,QAAO,SAAS;AAElB,gBAAY,OAAO;AACnB,aAAS;MACR,QAAQ;AAGX,UAAO,YAAY;AACjB,iBAAa,gBAAgB;AAC7B,oBAAgB,sBAAsB;AACtC,aAAS;KACT;AAGF,QAAK,MAAM,UAAU,YAEnB,KAAI,CAAC,OAAO,eACV,QAAO,KAAK;IAGhB;;AAIJ,KAAI,kBAAkB;EAIpB,MAAM,WAFJ,OAAO,qBAAqB,WAAW,mBAAmB,EAAE,EAE9B,WAAW,CAAC,UAAU,UAAU;AAEhE,OAAK,MAAM,UAAU,QACnB,SAAQ,GAAG,cAAc;AACvB,aAAU,CAAC,WAAW,QAAQ,KAAK,EAAE,CAAC;IACtC;;AAKN,QAAO,OAAO,MAAM,UAAU,SAAS;AAEvC,QAAO;EACL;EACA;EACA;EACA,YACE,IAAI,SAAe,SAAS,WAAW;AACrC,UAAO,OAAO,QAAQ;AACpB,QAAI,IAAK,QAAO,IAAI;QACf,UAAS;KACd;IACF;EACJ;EACD;;;;;;AAOH,SAAgB,oBACd,OACA,SACY;AAEZ,QAAO,aADS,qBAAqB,OAAO,aAAa,QAAQ,CACrC"}
|
package/dist/serve.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as createAdaptorServer, i as ServeResult, o as serve, r as ServeOptions, t as FetchHandler } from "./serve-
|
|
1
|
+
import { a as createAdaptorServer, i as ServeResult, o as serve, r as ServeOptions, t as FetchHandler } from "./serve-B5WmhK6m.mjs";
|
|
2
2
|
export { type FetchHandler, type ServeOptions, type ServeResult, createAdaptorServer, serve };
|
package/dist/serve.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "../schema-
|
|
2
|
-
import "../index-
|
|
3
|
-
import { t as BaseServer } from "../base-server-
|
|
1
|
+
import "../schema-DOKg31ZX.mjs";
|
|
2
|
+
import "../index-CTHojwxd.mjs";
|
|
3
|
+
import { t as BaseServer } from "../base-server-CtA1bZSg.mjs";
|
|
4
4
|
export { BaseServer };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "../schema-
|
|
2
|
-
import "../index-
|
|
3
|
-
import "../base-server-
|
|
4
|
-
import { t as ComponentServer } from "../component-server-
|
|
1
|
+
import "../schema-DOKg31ZX.mjs";
|
|
2
|
+
import "../index-CTHojwxd.mjs";
|
|
3
|
+
import "../base-server-CtA1bZSg.mjs";
|
|
4
|
+
import { t as ComponentServer } from "../component-server-DvcPVnL4.mjs";
|
|
5
5
|
export { ComponentServer };
|