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.
Files changed (130) hide show
  1. package/README.md +54 -2
  2. package/dist/{base-server-CE0mfqPY.mjs → base-server-CbnxNoNf.mjs} +1 -1
  3. package/dist/{base-server-CE0mfqPY.mjs.map → base-server-CbnxNoNf.mjs.map} +1 -1
  4. package/dist/{base-server-CeJ8LTBk.d.mts → base-server-DDNu97SA.d.mts} +2 -2
  5. package/dist/{base64url-Cc77f1ms.mjs → base64url-Cc25EVjw.mjs} +1 -1
  6. package/dist/{base64url-Cc77f1ms.mjs.map → base64url-Cc25EVjw.mjs.map} +1 -1
  7. package/dist/{base64url-CAmasWF0.d.mts → base64url-wYuxnrb0.d.mts} +1 -1
  8. package/dist/{component-route-CGbmQm5P.d.mts → component-route-BAaJKp8X.d.mts} +2 -2
  9. package/dist/{component-router-B6M5XDnp.mjs → component-router-wQc8auz9.mjs} +1 -1
  10. package/dist/{component-router-B6M5XDnp.mjs.map → component-router-wQc8auz9.mjs.map} +1 -1
  11. package/dist/{component-server-CKcXIvMg.d.mts → component-server-CVhgbxOe.d.mts} +4 -4
  12. package/dist/{component-server-Cya46YN3.mjs → component-server-llGj--XB.mjs} +6 -6
  13. package/dist/{component-server-Cya46YN3.mjs.map → component-server-llGj--XB.mjs.map} +1 -1
  14. package/dist/{contract-vSyKiRwz.mjs → contract-BIqqOwPd.mjs} +2 -2
  15. package/dist/{contract-vSyKiRwz.mjs.map → contract-BIqqOwPd.mjs.map} +1 -1
  16. package/dist/{contract-C-xQoZ6r.d.mts → contract-ChZaybx9.d.mts} +1 -1
  17. package/dist/{defineRoute-Rod-Vi6-.d.mts → defineRoute-DUYeO8TR.d.mts} +1 -1
  18. package/dist/defineRoute.d.mts +1 -1
  19. package/dist/defineRoute.mjs +6 -13
  20. package/dist/defineRoute.mjs.map +1 -1
  21. package/dist/{dependency-manager-mqzLAocb.d.mts → dependency-manager-BIjSc7j3.d.mts} +1 -1
  22. package/dist/{dependency-manager-CGMZJTer.mjs → dependency-manager-DaDThGEc.mjs} +3 -2
  23. package/dist/dependency-manager-DaDThGEc.mjs.map +1 -0
  24. package/dist/{formats-Ca7ASaYH.d.mts → formats-B1vlpb1f.d.mts} +1 -1
  25. package/dist/{go-await-B1U27PgB.mjs → go-await-C4ZdEUwY.mjs} +1 -1
  26. package/dist/{go-await-B1U27PgB.mjs.map → go-await-C4ZdEUwY.mjs.map} +1 -1
  27. package/dist/{go-await-Dz1CRSTT.d.mts → go-await-KQIMkGZy.d.mts} +1 -1
  28. package/dist/{html-renderer-D1zzDVQM.mjs → html-renderer-DgYwJP_a.mjs} +1 -1
  29. package/dist/{html-renderer-D1zzDVQM.mjs.map → html-renderer-DgYwJP_a.mjs.map} +1 -1
  30. package/dist/{html-renderer-Up52eIS6.d.mts → html-renderer-ZY_sfcpi.d.mts} +1 -1
  31. package/dist/{index-CqwSjhXb.d.mts → index-DgIsC7ua.d.mts} +5 -5
  32. package/dist/index.d.mts +22 -21
  33. package/dist/index.mjs +17 -16
  34. package/dist/index.mjs.map +1 -1
  35. package/dist/middleware/component-router.d.mts +1 -1
  36. package/dist/middleware/component-router.mjs +1 -1
  37. package/dist/{middleware-BTg4GbjC.d.mts → middleware-B_fMMYr3.d.mts} +2 -2
  38. package/dist/middleware.d.mts +1 -1
  39. package/dist/middleware.mjs +2 -1
  40. package/dist/monitoring/index.d.mts +3 -3
  41. package/dist/monitoring/native-monitor.d.mts +3 -3
  42. package/dist/node-server/index.d.mts +1 -1
  43. package/dist/node-server/index.mjs +3 -3
  44. package/dist/node-server/request.mjs +1 -1
  45. package/dist/node-server/response.mjs +1 -1
  46. package/dist/node-server/serve.d.mts +1 -1
  47. package/dist/node-server/serve.mjs +2 -2
  48. package/dist/{parsers-CEkO18PZ.d.mts → parsers-B1dewjiN.d.mts} +1 -1
  49. package/dist/{parsers-BPBVKby-.mjs → parsers-DPKyyUv3.mjs} +1 -1
  50. package/dist/{parsers-BPBVKby-.mjs.map → parsers-DPKyyUv3.mjs.map} +1 -1
  51. package/dist/{path-matcher-Dp-DRUV9.mjs → path-matcher-BwpVrcVG.mjs} +1 -1
  52. package/dist/{path-matcher-Dp-DRUV9.mjs.map → path-matcher-BwpVrcVG.mjs.map} +1 -1
  53. package/dist/{radix-tree-dyn3qDFX.mjs → radix-tree-DPcGUi6x.mjs} +1 -1
  54. package/dist/{radix-tree-dyn3qDFX.mjs.map → radix-tree-DPcGUi6x.mjs.map} +1 -1
  55. package/dist/{request-D5oMj6sH.mjs → request-COqaDa-c.mjs} +1 -1
  56. package/dist/{request-D5oMj6sH.mjs.map → request-COqaDa-c.mjs.map} +1 -1
  57. package/dist/{response-BlHLmKys.mjs → response-BK2pYq43.mjs} +1 -1
  58. package/dist/{response-BlHLmKys.mjs.map → response-BK2pYq43.mjs.map} +1 -1
  59. package/dist/{response-Bs9GhJz-.mjs → response-BlkS--Fb.mjs} +9 -2
  60. package/dist/response-BlkS--Fb.mjs.map +1 -0
  61. package/dist/{response-lI0YZoia.d.mts → response-DsH8MnBO.d.mts} +2 -2
  62. package/dist/{route-registry-DmbGzvgn.d.mts → route-registry-B0q_pJDC.d.mts} +3 -3
  63. package/dist/{route-registry-DsPslV2b.mjs → route-registry-ClmI5VwE.mjs} +1 -1
  64. package/dist/{route-registry-DsPslV2b.mjs.map → route-registry-ClmI5VwE.mjs.map} +1 -1
  65. package/dist/router/index.mjs +1 -1
  66. package/dist/router/radix-tree.d.mts +1 -1
  67. package/dist/router/radix-tree.mjs +1 -1
  68. package/dist/{serve-Cj0bYhav.mjs → serve-CozN9Tlz.mjs} +3 -3
  69. package/dist/{serve-Cj0bYhav.mjs.map → serve-CozN9Tlz.mjs.map} +1 -1
  70. package/dist/{serve-Dw-GHkc3.d.mts → serve-Dh6Ux5Pg.d.mts} +1 -1
  71. package/dist/serve.d.mts +1 -1
  72. package/dist/serve.mjs +2 -2
  73. package/dist/server/base-server.d.mts +1 -1
  74. package/dist/server/base-server.mjs +1 -1
  75. package/dist/server/component-server.d.mts +1 -1
  76. package/dist/server/component-server.mjs +2 -2
  77. package/dist/server/index.d.mts +5 -5
  78. package/dist/server/index.mjs +7 -6
  79. package/dist/server/server-factory.d.mts +3 -3
  80. package/dist/server/server-factory.mjs +6 -5
  81. package/dist/server/server.d.mts +2 -2
  82. package/dist/server/server.mjs +3 -2
  83. package/dist/{server-BNpY3NH6.mjs → server-D-jaEU-V.mjs} +3 -3
  84. package/dist/{server-BNpY3NH6.mjs.map → server-D-jaEU-V.mjs.map} +1 -1
  85. package/dist/{server-B-X9ANNh.d.mts → server-Dr_qEIqu.d.mts} +4 -4
  86. package/dist/{server-B4YDcNJy.mjs → server-Dtk8M7eI.mjs} +5 -5
  87. package/dist/{server-B4YDcNJy.mjs.map → server-Dtk8M7eI.mjs.map} +1 -1
  88. package/dist/{sse-BqvrwmK6.d.mts → sse-CZnFOi2K.d.mts} +1 -1
  89. package/dist/types/component-route.d.mts +1 -1
  90. package/dist/types/index.d.mts +2 -2
  91. package/dist/types/types.d.mts +1 -1
  92. package/dist/{types-aczawQFE.d.mts → types-BaIZETLg.d.mts} +1 -1
  93. package/dist/utils/base64url.d.mts +1 -1
  94. package/dist/utils/base64url.mjs +1 -1
  95. package/dist/utils/contract.d.mts +1 -1
  96. package/dist/utils/contract.mjs +1 -1
  97. package/dist/utils/dependency-manager.d.mts +1 -1
  98. package/dist/utils/dependency-manager.mjs +1 -1
  99. package/dist/utils/formats.d.mts +1 -1
  100. package/dist/utils/go-await.d.mts +1 -1
  101. package/dist/utils/go-await.mjs +1 -1
  102. package/dist/utils/handle.mjs +1 -1
  103. package/dist/utils/html-renderer.d.mts +1 -1
  104. package/dist/utils/html-renderer.mjs +1 -1
  105. package/dist/utils/index.d.mts +14 -13
  106. package/dist/utils/index.mjs +11 -10
  107. package/dist/utils/parsers.d.mts +1 -1
  108. package/dist/utils/parsers.mjs +1 -1
  109. package/dist/utils/path-matcher.mjs +1 -1
  110. package/dist/utils/response.d.mts +1 -1
  111. package/dist/utils/response.mjs +2 -1
  112. package/dist/utils/route-registry.d.mts +2 -2
  113. package/dist/utils/route-registry.mjs +1 -1
  114. package/dist/utils/sse.d.mts +1 -1
  115. package/dist/utils/validators/validation-errors.d.mts +2 -0
  116. package/dist/utils/validators/validation-errors.mjs +3 -0
  117. package/dist/utils/validators/validators.d.mts +1 -1
  118. package/dist/utils/validators/validators.mjs +2 -1
  119. package/dist/validation-errors-BXOr6Rf2.d.mts +36 -0
  120. package/dist/validation-errors-j7DAULlG.mjs +38 -0
  121. package/dist/validation-errors-j7DAULlG.mjs.map +1 -0
  122. package/dist/{validators-CkfvNBbK.mjs → validators-DdEfUzCC.mjs} +60 -21
  123. package/dist/validators-DdEfUzCC.mjs.map +1 -0
  124. package/dist/{validators-D5KJCSZr.d.mts → validators-jkeNFN8V.d.mts} +7 -5
  125. package/package.json +1 -1
  126. package/dist/dependency-manager-CGMZJTer.mjs.map +0 -1
  127. package/dist/response-Bs9GhJz-.mjs.map +0 -1
  128. package/dist/validators-CkfvNBbK.mjs.map +0 -1
  129. /package/dist/{component-route-DdKFowzp.mjs → component-route-B6jaTxLT.mjs} +0 -0
  130. /package/dist/{index-D4DUvwPf.d.mts → index-1-AkepUA.d.mts} +0 -0
package/README.md CHANGED
@@ -179,7 +179,7 @@ const routes = defineRoutes([
179
179
 
180
180
  const server = new Server(routes);
181
181
  export default { fetch: server.fetch };
182
- // 错误响应: { error: 'BAD_REQUEST', message: 'Missing name' }
182
+ // 业务错误: HTTP 4xx/5xx + { code: number, message: string }
183
183
  ```
184
184
 
185
185
  **对比:Vafast 的 `err()` 函数提供语义化的错误 API,统一的响应格式。**
@@ -568,12 +568,62 @@ defineRoute({
568
568
  throw err.forbidden('无权限') // 403
569
569
  throw err.notFound('用户不存在') // 404
570
570
  throw err.conflict('用户名已存在') // 409
571
+ throw err.unprocessable('无法处理') // 422
571
572
  throw err.internal('服务器错误') // 500
572
- throw err('自定义错误', 422, 'CUSTOM_TYPE') // 自定义
573
+ throw err('业务错误', 404, 40401) // HTTP 404, code 40401
573
574
  }
574
575
  })
575
576
  ```
576
577
 
578
+ **错误响应契约:**
579
+
580
+ | 场景 | HTTP | 响应体 |
581
+ |------|------|--------|
582
+ | 成功 | 2xx | 裸 JSON 业务数据 |
583
+ | Schema 校验失败 | **422** | `{ code: 422, message, details[] }` |
584
+ | 业务/鉴权错误 | 4xx/5xx | `{ code: number, message: string }` |
585
+
586
+ `code` 始终为 **number**(HTTP 状态码或业务码如 `40101`)。
587
+
588
+ **Schema 校验失败(422)** — 路由定义 `schema` 后自动生效,`details` 透传 TypeBox 原文:
589
+
590
+ ```typescript
591
+ // POST body 校验失败示例响应
592
+ {
593
+ "code": 422,
594
+ "message": "请求参数校验失败",
595
+ "details": [
596
+ {
597
+ "location": "body",
598
+ "path": "/email",
599
+ "field": "email",
600
+ "message": "Expected string to match 'email' format",
601
+ "value": "2212"
602
+ },
603
+ {
604
+ "location": "body",
605
+ "path": "/receiver/name",
606
+ "field": "receiver.name",
607
+ "message": "Expected string length greater or equal to 1",
608
+ "value": ""
609
+ }
610
+ ]
611
+ }
612
+ ```
613
+
614
+ - `path`:TypeBox JSON Pointer(`/orderIds/0`)
615
+ - `field`:表单字段路径(`orderIds.0`)
616
+ - `message`:**TypeBox 英文原文**,框架不做翻译
617
+
618
+ ```typescript
619
+ import { ValidationFailedError, isValidationFailedError } from 'vafast';
620
+
621
+ // handler 内也可手动抛出(少见)
622
+ throw new ValidationFailedError([
623
+ { location: 'body', path: '/email', field: 'email', message: '...' },
624
+ ]);
625
+ ```
626
+
577
627
  **API 速查表:**
578
628
 
579
629
  | 场景 | 写法 | 结果 |
@@ -585,7 +635,9 @@ defineRoute({
585
635
  | 禁止访问 | `throw err.forbidden()` | 403 |
586
636
  | 未找到 | `throw err.notFound()` | 404 |
587
637
  | 资源冲突 | `throw err.conflict()` | 409 |
638
+ | 无法处理 | `throw err.unprocessable()` | 422 |
588
639
  | 服务器错误 | `throw err.internal()` | 500 |
640
+ | Schema 校验 | 自动(defineRoute.schema) | 422 + details |
589
641
 
590
642
  ### SSE 流式响应
591
643
 
@@ -97,4 +97,4 @@ var BaseServer = class {
97
97
 
98
98
  //#endregion
99
99
  export { BaseServer as t };
100
- //# sourceMappingURL=base-server-CE0mfqPY.mjs.map
100
+ //# sourceMappingURL=base-server-CbnxNoNf.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"base-server-CE0mfqPY.mjs","names":[],"sources":["../src/server/base-server.ts"],"sourcesContent":["import type { Middleware } from \"../types\";\n\n/**\n * 服务器基类\n * 包含所有服务器类型的公共逻辑\n */\nexport abstract class BaseServer {\n protected globalMiddleware: Middleware[] = [];\n\n use(mw: Middleware) {\n this.globalMiddleware.push(mw);\n }\n\n /**\n * 打印路由信息,用于调试\n */\n protected logRoutes(routes: any[], type: string = \"路由\"): void {\n console.log(`🚀 注册${type}:`);\n for (const route of routes) {\n const method = route.method || \"GET\";\n const path = route.path;\n console.log(` ${method} ${path}`);\n if (route.middleware && route.middleware.length > 0) {\n console.log(` 中间件: ${route.middleware.length} 个`);\n }\n }\n console.log(\"\");\n }\n\n /**\n * 检测路由冲突\n */\n protected detectRouteConflicts(routes: any[]): void {\n const pathGroups = new Map<string, any[]>();\n\n // 按路径分组\n for (const route of routes) {\n const path = route.path;\n const method = route.method || \"GET\";\n if (!pathGroups.has(path)) {\n pathGroups.set(path, []);\n }\n pathGroups.get(path)!.push({ ...route, method });\n }\n\n // 检查冲突\n for (const [path, routeList] of pathGroups) {\n if (routeList.length > 1) {\n const methods = routeList.map((r: { method: string }) => r.method);\n const uniqueMethods = [...new Set(methods)];\n\n if (uniqueMethods.length === 1) {\n console.warn(\n `⚠️ 路由冲突: ${uniqueMethods[0]} ${path} 定义了 ${routeList.length} 次`,\n );\n }\n }\n }\n\n // 检查动态路由冲突\n this.detectDynamicRouteConflicts(routes);\n }\n\n /**\n * 检测动态路由冲突\n */\n private detectDynamicRouteConflicts(routes: any[]): void {\n const dynamicRoutes = routes.filter((r) => {\n return r.path.includes(\":\") || r.path.includes(\"*\");\n });\n\n for (let i = 0; i < dynamicRoutes.length; i++) {\n for (let j = i + 1; j < dynamicRoutes.length; j++) {\n const route1 = dynamicRoutes[i];\n const route2 = dynamicRoutes[j];\n if (route1.method === route2.method && this.pathsMayConflict(route1.path, route2.path)) {\n console.warn(`⚠️ 潜在路由冲突: ${route1.method} ${route1.path} 与 ${route2.path}`);\n }\n }\n }\n }\n\n /**\n * 判断两个路径是否可能冲突\n */\n private 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 /**\n * 路径匹配\n */\n protected 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 protected extractParams(\n pattern: string,\n path: string,\n ): 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"],"mappings":"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"}
1
+ {"version":3,"file":"base-server-CbnxNoNf.mjs","names":[],"sources":["../src/server/base-server.ts"],"sourcesContent":["import type { Middleware } from \"../types\";\n\n/**\n * 服务器基类\n * 包含所有服务器类型的公共逻辑\n */\nexport abstract class BaseServer {\n protected globalMiddleware: Middleware[] = [];\n\n use(mw: Middleware) {\n this.globalMiddleware.push(mw);\n }\n\n /**\n * 打印路由信息,用于调试\n */\n protected logRoutes(routes: any[], type: string = \"路由\"): void {\n console.log(`🚀 注册${type}:`);\n for (const route of routes) {\n const method = route.method || \"GET\";\n const path = route.path;\n console.log(` ${method} ${path}`);\n if (route.middleware && route.middleware.length > 0) {\n console.log(` 中间件: ${route.middleware.length} 个`);\n }\n }\n console.log(\"\");\n }\n\n /**\n * 检测路由冲突\n */\n protected detectRouteConflicts(routes: any[]): void {\n const pathGroups = new Map<string, any[]>();\n\n // 按路径分组\n for (const route of routes) {\n const path = route.path;\n const method = route.method || \"GET\";\n if (!pathGroups.has(path)) {\n pathGroups.set(path, []);\n }\n pathGroups.get(path)!.push({ ...route, method });\n }\n\n // 检查冲突\n for (const [path, routeList] of pathGroups) {\n if (routeList.length > 1) {\n const methods = routeList.map((r: { method: string }) => r.method);\n const uniqueMethods = [...new Set(methods)];\n\n if (uniqueMethods.length === 1) {\n console.warn(\n `⚠️ 路由冲突: ${uniqueMethods[0]} ${path} 定义了 ${routeList.length} 次`,\n );\n }\n }\n }\n\n // 检查动态路由冲突\n this.detectDynamicRouteConflicts(routes);\n }\n\n /**\n * 检测动态路由冲突\n */\n private detectDynamicRouteConflicts(routes: any[]): void {\n const dynamicRoutes = routes.filter((r) => {\n return r.path.includes(\":\") || r.path.includes(\"*\");\n });\n\n for (let i = 0; i < dynamicRoutes.length; i++) {\n for (let j = i + 1; j < dynamicRoutes.length; j++) {\n const route1 = dynamicRoutes[i];\n const route2 = dynamicRoutes[j];\n if (route1.method === route2.method && this.pathsMayConflict(route1.path, route2.path)) {\n console.warn(`⚠️ 潜在路由冲突: ${route1.method} ${route1.path} 与 ${route2.path}`);\n }\n }\n }\n }\n\n /**\n * 判断两个路径是否可能冲突\n */\n private 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 /**\n * 路径匹配\n */\n protected 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 protected extractParams(\n pattern: string,\n path: string,\n ): 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"],"mappings":";;;;;AAMA,IAAsB,aAAtB,MAAiC;CAC/B,AAAU,mBAAiC,EAAE;CAE7C,IAAI,IAAgB;AAClB,OAAK,iBAAiB,KAAK,GAAG;;;;;CAMhC,AAAU,UAAU,QAAe,OAAe,MAAY;AAC5D,UAAQ,IAAI,QAAQ,KAAK,GAAG;AAC5B,OAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,SAAS,MAAM,UAAU;GAC/B,MAAM,OAAO,MAAM;AACnB,WAAQ,IAAI,KAAK,OAAO,GAAG,OAAO;AAClC,OAAI,MAAM,cAAc,MAAM,WAAW,SAAS,EAChD,SAAQ,IAAI,YAAY,MAAM,WAAW,OAAO,IAAI;;AAGxD,UAAQ,IAAI,GAAG;;;;;CAMjB,AAAU,qBAAqB,QAAqB;EAClD,MAAM,6BAAa,IAAI,KAAoB;AAG3C,OAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,OAAO,MAAM;GACnB,MAAM,SAAS,MAAM,UAAU;AAC/B,OAAI,CAAC,WAAW,IAAI,KAAK,CACvB,YAAW,IAAI,MAAM,EAAE,CAAC;AAE1B,cAAW,IAAI,KAAK,CAAE,KAAK;IAAE,GAAG;IAAO;IAAQ,CAAC;;AAIlD,OAAK,MAAM,CAAC,MAAM,cAAc,WAC9B,KAAI,UAAU,SAAS,GAAG;GACxB,MAAM,UAAU,UAAU,KAAK,MAA0B,EAAE,OAAO;GAClE,MAAM,gBAAgB,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC;AAE3C,OAAI,cAAc,WAAW,EAC3B,SAAQ,KACN,aAAa,cAAc,GAAG,GAAG,KAAK,OAAO,UAAU,OAAO,IAC/D;;AAMP,OAAK,4BAA4B,OAAO;;;;;CAM1C,AAAQ,4BAA4B,QAAqB;EACvD,MAAM,gBAAgB,OAAO,QAAQ,MAAM;AACzC,UAAO,EAAE,KAAK,SAAS,IAAI,IAAI,EAAE,KAAK,SAAS,IAAI;IACnD;AAEF,OAAK,IAAI,IAAI,GAAG,IAAI,cAAc,QAAQ,IACxC,MAAK,IAAI,IAAI,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;GACjD,MAAM,SAAS,cAAc;GAC7B,MAAM,SAAS,cAAc;AAC7B,OAAI,OAAO,WAAW,OAAO,UAAU,KAAK,iBAAiB,OAAO,MAAM,OAAO,KAAK,CACpF,SAAQ,KAAK,eAAe,OAAO,OAAO,GAAG,OAAO,KAAK,KAAK,OAAO,OAAO;;;;;;CASpF,AAAQ,iBAAiB,OAAe,OAAwB;EAC9D,MAAM,SAAS,MAAM,MAAM,IAAI,CAAC,OAAO,QAAQ;EAC/C,MAAM,SAAS,MAAM,MAAM,IAAI,CAAC,OAAO,QAAQ;AAE/C,MAAI,OAAO,WAAW,OAAO,OAAQ,QAAO;AAE5C,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;GACtC,MAAM,KAAK,OAAO;GAClB,MAAM,KAAK,OAAO;AAGlB,OACE,CAAC,GAAG,WAAW,IAAI,IACnB,CAAC,GAAG,WAAW,IAAI,IACnB,CAAC,GAAG,WAAW,IAAI,IACnB,CAAC,GAAG,WAAW,IAAI,IACnB,OAAO,GAEP,QAAO;AAIT,OACG,OAAO,OAAO,GAAG,WAAW,IAAI,IAChC,OAAO,OAAO,GAAG,WAAW,IAAI,CAEjC,QAAO;;AAIX,SAAO;;;;;CAMT,AAAU,UAAU,SAAiB,MAAuB;EAC1D,MAAM,eAAe,QAAQ,MAAM,IAAI,CAAC,OAAO,QAAQ;EACvD,MAAM,YAAY,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ;AAEjD,MAAI,aAAa,WAAW,UAAU,OACpC,QAAO;AAGT,OAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,IACvC,KACE,aAAa,OAAO,UAAU,MAC9B,CAAC,aAAa,GAAG,WAAW,IAAI,CAEhC,QAAO;AAIX,SAAO;;;;;CAMT,AAAU,cACR,SACA,MACwB;EACxB,MAAM,SAAiC,EAAE;EACzC,MAAM,eAAe,QAAQ,MAAM,IAAI,CAAC,OAAO,QAAQ;EACvD,MAAM,YAAY,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ;AAEjD,OAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,IACvC,KAAI,aAAa,GAAG,WAAW,IAAI,EAAE;GACnC,MAAM,YAAY,aAAa,GAAG,MAAM,EAAE;AAC1C,UAAO,aAAa,UAAU;;AAIlC,SAAO"}
@@ -1,4 +1,4 @@
1
- import { r as Middleware } from "./types-aczawQFE.mjs";
1
+ import { r as Middleware } from "./types-BaIZETLg.mjs";
2
2
 
3
3
  //#region src/server/base-server.d.ts
4
4
 
@@ -36,4 +36,4 @@ declare abstract class BaseServer {
36
36
  }
37
37
  //#endregion
38
38
  export { BaseServer as t };
39
- //# sourceMappingURL=base-server-CeJ8LTBk.d.mts.map
39
+ //# sourceMappingURL=base-server-DDNu97SA.d.mts.map
@@ -10,4 +10,4 @@ function base64urlDecode(str) {
10
10
 
11
11
  //#endregion
12
12
  export { base64urlEncode as n, base64urlDecode as t };
13
- //# sourceMappingURL=base64url-Cc77f1ms.mjs.map
13
+ //# sourceMappingURL=base64url-Cc25EVjw.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"base64url-Cc77f1ms.mjs","names":[],"sources":["../src/utils/base64url.ts"],"sourcesContent":["export function base64urlEncode(str: string): string {\n return btoa(str)\n .replace(/=/g, \"\") // ✅ 删除填充\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\");\n}\n\nexport function base64urlDecode(str: string): string {\n const pad = str.length % 4 === 0 ? \"\" : \"=\".repeat(4 - (str.length % 4));\n const base64 = str.replace(/-/g, \"+\").replace(/_/g, \"/\") + pad;\n return atob(base64);\n}\n"],"mappings":";AAAA,SAAgB,gBAAgB,KAAqB;AACnD,QAAO,KAAK,IAAI,CACb,QAAQ,MAAM,GAAG,CACjB,QAAQ,OAAO,IAAI,CACnB,QAAQ,OAAO,IAAI;;AAGxB,SAAgB,gBAAgB,KAAqB;CACnD,MAAM,MAAM,IAAI,SAAS,MAAM,IAAI,KAAK,IAAI,OAAO,IAAK,IAAI,SAAS,EAAG;CACxE,MAAM,SAAS,IAAI,QAAQ,MAAM,IAAI,CAAC,QAAQ,MAAM,IAAI,GAAG;AAC3D,QAAO,KAAK,OAAO"}
1
+ {"version":3,"file":"base64url-Cc25EVjw.mjs","names":[],"sources":["../src/utils/base64url.ts"],"sourcesContent":["export function base64urlEncode(str: string): string {\n return btoa(str)\n .replace(/=/g, \"\") // ✅ 删除填充\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\");\n}\n\nexport function base64urlDecode(str: string): string {\n const pad = str.length % 4 === 0 ? \"\" : \"=\".repeat(4 - (str.length % 4));\n const base64 = str.replace(/-/g, \"+\").replace(/_/g, \"/\") + pad;\n return atob(base64);\n}\n"],"mappings":";AAAA,SAAgB,gBAAgB,KAAqB;AACnD,QAAO,KAAK,IAAI,CACb,QAAQ,MAAM,GAAG,CACjB,QAAQ,OAAO,IAAI,CACnB,QAAQ,OAAO,IAAI;;AAGxB,SAAgB,gBAAgB,KAAqB;CACnD,MAAM,MAAM,IAAI,SAAS,MAAM,IAAI,KAAK,IAAI,OAAO,IAAK,IAAI,SAAS,EAAG;CACxE,MAAM,SAAS,IAAI,QAAQ,MAAM,IAAI,CAAC,QAAQ,MAAM,IAAI,GAAG;AAC3D,QAAO,KAAK,OAAO"}
@@ -3,4 +3,4 @@ declare function base64urlEncode(str: string): string;
3
3
  declare function base64urlDecode(str: string): string;
4
4
  //#endregion
5
5
  export { base64urlEncode as n, base64urlDecode as t };
6
- //# sourceMappingURL=base64url-CAmasWF0.d.mts.map
6
+ //# sourceMappingURL=base64url-wYuxnrb0.d.mts.map
@@ -1,4 +1,4 @@
1
- import { r as Middleware } from "./types-aczawQFE.mjs";
1
+ import { r as Middleware } from "./types-BaIZETLg.mjs";
2
2
 
3
3
  //#region src/types/component-route.d.ts
4
4
 
@@ -28,4 +28,4 @@ interface FlattenedComponentRoute extends ComponentRoute {
28
28
  }
29
29
  //#endregion
30
30
  export { FlattenedComponentRoute as n, NestedComponentRoute as r, ComponentRoute as t };
31
- //# sourceMappingURL=component-route-CGbmQm5P.d.mts.map
31
+ //# sourceMappingURL=component-route-BAaJKp8X.d.mts.map
@@ -29,4 +29,4 @@ const componentRouter = () => {
29
29
 
30
30
  //#endregion
31
31
  export { flattenComponentRoutes as n, componentRouter as t };
32
- //# sourceMappingURL=component-router-B6M5XDnp.mjs.map
32
+ //# sourceMappingURL=component-router-wQc8auz9.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"component-router-B6M5XDnp.mjs","names":[],"sources":["../src/middleware/component-router.ts"],"sourcesContent":["import type {\n ComponentRoute,\n NestedComponentRoute,\n FlattenedComponentRoute,\n} from \"../types/component-route\";\nimport { vueRenderer, reactRenderer } from \"./component-renderer\";\n\n/**\n * 扁平化嵌套组件路由\n */\nexport function flattenComponentRoutes(\n routes: (ComponentRoute | NestedComponentRoute)[],\n): FlattenedComponentRoute[] {\n const flattened: FlattenedComponentRoute[] = [];\n\n function processRoute(\n route: ComponentRoute | NestedComponentRoute,\n parentPath: string = \"\",\n parentMiddleware: any[] = [],\n ) {\n const currentPath = parentPath + route.path;\n const currentMiddleware = [\n ...parentMiddleware,\n ...(route.middleware || []),\n ];\n\n if (\"component\" in route) {\n // 这是一个组件路由\n flattened.push({\n ...route,\n fullPath: currentPath,\n middlewareChain: currentMiddleware,\n });\n } else if (\"children\" in route && route.children) {\n // 这是一个嵌套路由\n for (const child of route.children) {\n processRoute(child, currentPath, currentMiddleware);\n }\n }\n }\n\n for (const route of routes) {\n processRoute(route);\n }\n\n return flattened;\n}\n\n/**\n * 组件路由处理器中间件\n * 自动检测组件类型并应用相应的渲染器\n */\nexport const componentRouter = () => {\n return async (req: Request, next: () => Promise<Response>) => {\n // 这里可以添加组件路由的自动处理逻辑\n // 比如自动检测组件类型,应用相应的渲染器\n return next();\n };\n};\n"],"mappings":";;;;AAUA,SAAgB,uBACd,QAC2B;CAC3B,MAAM,YAAuC,EAAE;CAE/C,SAAS,aACP,OACA,aAAqB,IACrB,mBAA0B,EAAE,EAC5B;EACA,MAAM,cAAc,aAAa,MAAM;EACvC,MAAM,oBAAoB,CACxB,GAAG,kBACH,GAAI,MAAM,cAAc,EAAE,CAC3B;AAED,MAAI,eAAe,MAEjB,WAAU,KAAK;GACb,GAAG;GACH,UAAU;GACV,iBAAiB;GAClB,CAAC;WACO,cAAc,SAAS,MAAM,SAEtC,MAAK,MAAM,SAAS,MAAM,SACxB,cAAa,OAAO,aAAa,kBAAkB;;AAKzD,MAAK,MAAM,SAAS,OAClB,cAAa,MAAM;AAGrB,QAAO;;;;;;AAOT,MAAa,wBAAwB;AACnC,QAAO,OAAO,KAAc,SAAkC;AAG5D,SAAO,MAAM"}
1
+ {"version":3,"file":"component-router-wQc8auz9.mjs","names":[],"sources":["../src/middleware/component-router.ts"],"sourcesContent":["import type {\n ComponentRoute,\n NestedComponentRoute,\n FlattenedComponentRoute,\n} from \"../types/component-route\";\nimport { vueRenderer, reactRenderer } from \"./component-renderer\";\n\n/**\n * 扁平化嵌套组件路由\n */\nexport function flattenComponentRoutes(\n routes: (ComponentRoute | NestedComponentRoute)[],\n): FlattenedComponentRoute[] {\n const flattened: FlattenedComponentRoute[] = [];\n\n function processRoute(\n route: ComponentRoute | NestedComponentRoute,\n parentPath: string = \"\",\n parentMiddleware: any[] = [],\n ) {\n const currentPath = parentPath + route.path;\n const currentMiddleware = [\n ...parentMiddleware,\n ...(route.middleware || []),\n ];\n\n if (\"component\" in route) {\n // 这是一个组件路由\n flattened.push({\n ...route,\n fullPath: currentPath,\n middlewareChain: currentMiddleware,\n });\n } else if (\"children\" in route && route.children) {\n // 这是一个嵌套路由\n for (const child of route.children) {\n processRoute(child, currentPath, currentMiddleware);\n }\n }\n }\n\n for (const route of routes) {\n processRoute(route);\n }\n\n return flattened;\n}\n\n/**\n * 组件路由处理器中间件\n * 自动检测组件类型并应用相应的渲染器\n */\nexport const componentRouter = () => {\n return async (req: Request, next: () => Promise<Response>) => {\n // 这里可以添加组件路由的自动处理逻辑\n // 比如自动检测组件类型,应用相应的渲染器\n return next();\n };\n};\n"],"mappings":";;;;AAUA,SAAgB,uBACd,QAC2B;CAC3B,MAAM,YAAuC,EAAE;CAE/C,SAAS,aACP,OACA,aAAqB,IACrB,mBAA0B,EAAE,EAC5B;EACA,MAAM,cAAc,aAAa,MAAM;EACvC,MAAM,oBAAoB,CACxB,GAAG,kBACH,GAAI,MAAM,cAAc,EAAE,CAC3B;AAED,MAAI,eAAe,MAEjB,WAAU,KAAK;GACb,GAAG;GACH,UAAU;GACV,iBAAiB;GAClB,CAAC;WACO,cAAc,SAAS,MAAM,SAEtC,MAAK,MAAM,SAAS,MAAM,SACxB,cAAa,OAAO,aAAa,kBAAkB;;AAKzD,MAAK,MAAM,SAAS,OAClB,cAAa,MAAM;AAGrB,QAAO;;;;;;AAOT,MAAa,wBAAwB;AACnC,QAAO,OAAO,KAAc,SAAkC;AAG5D,SAAO,MAAM"}
@@ -1,6 +1,6 @@
1
- import { r as NestedComponentRoute, t as ComponentRoute } from "./component-route-CGbmQm5P.mjs";
2
- import { t as BaseServer } from "./base-server-CeJ8LTBk.mjs";
3
- import { t as DependencyManager } from "./dependency-manager-mqzLAocb.mjs";
1
+ import { r as NestedComponentRoute, t as ComponentRoute } from "./component-route-BAaJKp8X.mjs";
2
+ import { t as BaseServer } from "./base-server-DDNu97SA.mjs";
3
+ import { t as DependencyManager } from "./dependency-manager-BIjSc7j3.mjs";
4
4
 
5
5
  //#region src/server/component-server.d.ts
6
6
 
@@ -35,4 +35,4 @@ declare class ComponentServer extends BaseServer {
35
35
  }
36
36
  //#endregion
37
37
  export { ComponentServer as t };
38
- //# sourceMappingURL=component-server-CKcXIvMg.d.mts.map
38
+ //# sourceMappingURL=component-server-CVhgbxOe.d.mts.map
@@ -1,8 +1,8 @@
1
- import { t as BaseServer } from "./base-server-CE0mfqPY.mjs";
2
- import { n as flattenComponentRoutes } from "./component-router-B6M5XDnp.mjs";
3
- import { t as PathMatcher } from "./path-matcher-Dp-DRUV9.mjs";
4
- import { t as HtmlRenderer } from "./html-renderer-D1zzDVQM.mjs";
5
- import { t as DependencyManager } from "./dependency-manager-CGMZJTer.mjs";
1
+ import { t as BaseServer } from "./base-server-CbnxNoNf.mjs";
2
+ import { n as flattenComponentRoutes } from "./component-router-wQc8auz9.mjs";
3
+ import { t as PathMatcher } from "./path-matcher-BwpVrcVG.mjs";
4
+ import { t as HtmlRenderer } from "./html-renderer-DgYwJP_a.mjs";
5
+ import { t as DependencyManager } from "./dependency-manager-DaDThGEc.mjs";
6
6
 
7
7
  //#region src/server/component-server.ts
8
8
  /**
@@ -116,4 +116,4 @@ var ComponentServer = class extends BaseServer {
116
116
 
117
117
  //#endregion
118
118
  export { ComponentServer as t };
119
- //# sourceMappingURL=component-server-Cya46YN3.mjs.map
119
+ //# sourceMappingURL=component-server-llGj--XB.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"component-server-Cya46YN3.mjs","names":[],"sources":["../src/server/component-server.ts"],"sourcesContent":["import type {\n ComponentRoute,\n NestedComponentRoute,\n FlattenedComponentRoute,\n} from \"../types/component-route\";\nimport { flattenComponentRoutes } from \"../middleware/component-router\";\nimport { BaseServer } from \"./base-server\";\nimport { PathMatcher } from \"../utils/path-matcher\";\nimport { HtmlRenderer } from \"../utils/html-renderer\";\nimport { DependencyManager } from \"../utils/dependency-manager\";\n\n/**\n * 组件路由服务器\n * 专门处理声明式组件路由\n */\nexport class ComponentServer extends BaseServer {\n private routes: FlattenedComponentRoute[];\n private dependencyManager: DependencyManager;\n\n constructor(routes: (ComponentRoute | NestedComponentRoute)[]) {\n super();\n this.routes = flattenComponentRoutes(routes);\n this.dependencyManager = new DependencyManager();\n\n // 检测路由冲突\n this.detectRouteConflicts(this.routes);\n this.logRoutes(this.routes, \"组件路由\");\n console.log(\"🚀 依赖按需加载,服务器启动完成\");\n }\n\n /**\n * 处理请求\n */\n async fetch(req: Request): Promise<Response> {\n const url = new URL(req.url);\n const pathname = url.pathname;\n const method = req.method;\n\n // 只支持 GET 请求\n if (method !== \"GET\") {\n return new Response(\"Method Not Allowed\", { status: 405 });\n }\n\n // 查找匹配的路由\n let matchedRoute: FlattenedComponentRoute | null = null;\n for (const route of this.routes) {\n if (PathMatcher.matchPath(route.fullPath, pathname)) {\n matchedRoute = route;\n break;\n }\n }\n\n if (!matchedRoute) {\n return new Response(\"Not Found\", { status: 404 });\n }\n\n try {\n // 创建中间件上下文\n const context = {\n req,\n params: PathMatcher.extractParams(matchedRoute.fullPath, pathname),\n query: Object.fromEntries(url.searchParams),\n pathname,\n };\n\n // 执行中间件链,中间件会处理组件渲染\n return await this.executeMiddlewareChain(\n matchedRoute.middlewareChain,\n context,\n matchedRoute.component,\n );\n } catch (error) {\n console.error(\"组件渲染失败:\", error);\n return new Response(\"Internal Server Error\", { status: 500 });\n }\n }\n\n /**\n * 执行中间件链\n */\n private async executeMiddlewareChain(\n middlewareChain: any[],\n context: any,\n componentImport: () => Promise<any>,\n ): Promise<Response> {\n // 创建最终的渲染函数\n const renderComponent = async () => {\n const componentModule = await componentImport();\n const component = componentModule.default || componentModule;\n\n // 自动检测组件类型\n const componentType =\n this.dependencyManager.detectComponentType(component);\n\n // 按需加载依赖\n const deps = await this.dependencyManager.getFrameworkDeps(componentType);\n\n // 根据组件类型渲染\n if (componentType === \"vue\") {\n return await this.renderVueComponent(component, context, deps);\n } else if (componentType === \"react\") {\n return await this.renderReactComponent(component, context, deps);\n } else {\n throw new Error(`不支持的组件类型: ${componentType}`);\n }\n };\n\n // 执行中间件链\n let index = 0;\n const next = async (): Promise<Response> => {\n if (index >= middlewareChain.length) {\n return await renderComponent();\n }\n\n const middleware = middlewareChain[index++];\n return await middleware(context.req, next);\n };\n\n return await next();\n }\n\n /**\n * 渲染 Vue 组件\n */\n private async renderVueComponent(\n component: any,\n context: any,\n deps: any,\n ): Promise<Response> {\n try {\n const [vue, renderer] = deps;\n const app = vue.createSSRApp(component);\n\n // 提供路由信息\n app.provide(\"routeInfo\", {\n params: context.params || {},\n query: context.query || {},\n pathname: context.pathname,\n });\n\n const html = await renderer.renderToString(app);\n const fullHtml = HtmlRenderer.generateVueHtml(html, context);\n\n return new Response(fullHtml, {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n } catch (error) {\n console.error(\"Vue 组件渲染失败:\", error);\n return new Response(\"Vue Component Render Error\", { status: 500 });\n }\n }\n\n /**\n * 渲染 React 组件\n */\n private async renderReactComponent(\n component: any,\n context: any,\n deps: any,\n ): Promise<Response> {\n try {\n const [react, renderer] = deps;\n const content = react.createElement(component, {\n req: context.req,\n params: context.params || {},\n query: context.query || {},\n });\n\n const html = renderer.renderToString(content);\n const fullHtml = HtmlRenderer.generateReactHtml(html, context);\n\n return new Response(fullHtml, {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n } catch (error) {\n console.error(\"React 组件渲染失败:\", error);\n return new Response(\"React Component Render Error\", { status: 500 });\n }\n }\n\n /**\n * 获取依赖管理器(用于外部访问)\n */\n getDependencyManager(): DependencyManager {\n return this.dependencyManager;\n }\n}\n"],"mappings":";;;;;;;;;;;AAeA,IAAa,kBAAb,cAAqC,WAAW;CAC9C,AAAQ;CACR,AAAQ;CAER,YAAY,QAAmD;AAC7D,SAAO;AACP,OAAK,SAAS,uBAAuB,OAAO;AAC5C,OAAK,oBAAoB,IAAI,mBAAmB;AAGhD,OAAK,qBAAqB,KAAK,OAAO;AACtC,OAAK,UAAU,KAAK,QAAQ,OAAO;AACnC,UAAQ,IAAI,oBAAoB;;;;;CAMlC,MAAM,MAAM,KAAiC;EAC3C,MAAM,MAAM,IAAI,IAAI,IAAI,IAAI;EAC5B,MAAM,WAAW,IAAI;AAIrB,MAHe,IAAI,WAGJ,MACb,QAAO,IAAI,SAAS,sBAAsB,EAAE,QAAQ,KAAK,CAAC;EAI5D,IAAI,eAA+C;AACnD,OAAK,MAAM,SAAS,KAAK,OACvB,KAAI,YAAY,UAAU,MAAM,UAAU,SAAS,EAAE;AACnD,kBAAe;AACf;;AAIJ,MAAI,CAAC,aACH,QAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,KAAK,CAAC;AAGnD,MAAI;GAEF,MAAM,UAAU;IACd;IACA,QAAQ,YAAY,cAAc,aAAa,UAAU,SAAS;IAClE,OAAO,OAAO,YAAY,IAAI,aAAa;IAC3C;IACD;AAGD,UAAO,MAAM,KAAK,uBAChB,aAAa,iBACb,SACA,aAAa,UACd;WACM,OAAO;AACd,WAAQ,MAAM,WAAW,MAAM;AAC/B,UAAO,IAAI,SAAS,yBAAyB,EAAE,QAAQ,KAAK,CAAC;;;;;;CAOjE,MAAc,uBACZ,iBACA,SACA,iBACmB;EAEnB,MAAM,kBAAkB,YAAY;GAClC,MAAM,kBAAkB,MAAM,iBAAiB;GAC/C,MAAM,YAAY,gBAAgB,WAAW;GAG7C,MAAM,gBACJ,KAAK,kBAAkB,oBAAoB,UAAU;GAGvD,MAAM,OAAO,MAAM,KAAK,kBAAkB,iBAAiB,cAAc;AAGzE,OAAI,kBAAkB,MACpB,QAAO,MAAM,KAAK,mBAAmB,WAAW,SAAS,KAAK;YACrD,kBAAkB,QAC3B,QAAO,MAAM,KAAK,qBAAqB,WAAW,SAAS,KAAK;OAEhE,OAAM,IAAI,MAAM,aAAa,gBAAgB;;EAKjD,IAAI,QAAQ;EACZ,MAAM,OAAO,YAA+B;AAC1C,OAAI,SAAS,gBAAgB,OAC3B,QAAO,MAAM,iBAAiB;GAGhC,MAAM,aAAa,gBAAgB;AACnC,UAAO,MAAM,WAAW,QAAQ,KAAK,KAAK;;AAG5C,SAAO,MAAM,MAAM;;;;;CAMrB,MAAc,mBACZ,WACA,SACA,MACmB;AACnB,MAAI;GACF,MAAM,CAAC,KAAK,YAAY;GACxB,MAAM,MAAM,IAAI,aAAa,UAAU;AAGvC,OAAI,QAAQ,aAAa;IACvB,QAAQ,QAAQ,UAAU,EAAE;IAC5B,OAAO,QAAQ,SAAS,EAAE;IAC1B,UAAU,QAAQ;IACnB,CAAC;GAEF,MAAM,OAAO,MAAM,SAAS,eAAe,IAAI;GAC/C,MAAM,WAAW,aAAa,gBAAgB,MAAM,QAAQ;AAE5D,UAAO,IAAI,SAAS,UAAU,EAC5B,SAAS,EAAE,gBAAgB,4BAA4B,EACxD,CAAC;WACK,OAAO;AACd,WAAQ,MAAM,eAAe,MAAM;AACnC,UAAO,IAAI,SAAS,8BAA8B,EAAE,QAAQ,KAAK,CAAC;;;;;;CAOtE,MAAc,qBACZ,WACA,SACA,MACmB;AACnB,MAAI;GACF,MAAM,CAAC,OAAO,YAAY;GAC1B,MAAM,UAAU,MAAM,cAAc,WAAW;IAC7C,KAAK,QAAQ;IACb,QAAQ,QAAQ,UAAU,EAAE;IAC5B,OAAO,QAAQ,SAAS,EAAE;IAC3B,CAAC;GAEF,MAAM,OAAO,SAAS,eAAe,QAAQ;GAC7C,MAAM,WAAW,aAAa,kBAAkB,MAAM,QAAQ;AAE9D,UAAO,IAAI,SAAS,UAAU,EAC5B,SAAS,EAAE,gBAAgB,4BAA4B,EACxD,CAAC;WACK,OAAO;AACd,WAAQ,MAAM,iBAAiB,MAAM;AACrC,UAAO,IAAI,SAAS,gCAAgC,EAAE,QAAQ,KAAK,CAAC;;;;;;CAOxE,uBAA0C;AACxC,SAAO,KAAK"}
1
+ {"version":3,"file":"component-server-llGj--XB.mjs","names":[],"sources":["../src/server/component-server.ts"],"sourcesContent":["import type {\n ComponentRoute,\n NestedComponentRoute,\n FlattenedComponentRoute,\n} from \"../types/component-route\";\nimport { flattenComponentRoutes } from \"../middleware/component-router\";\nimport { BaseServer } from \"./base-server\";\nimport { PathMatcher } from \"../utils/path-matcher\";\nimport { HtmlRenderer } from \"../utils/html-renderer\";\nimport { DependencyManager } from \"../utils/dependency-manager\";\n\n/**\n * 组件路由服务器\n * 专门处理声明式组件路由\n */\nexport class ComponentServer extends BaseServer {\n private routes: FlattenedComponentRoute[];\n private dependencyManager: DependencyManager;\n\n constructor(routes: (ComponentRoute | NestedComponentRoute)[]) {\n super();\n this.routes = flattenComponentRoutes(routes);\n this.dependencyManager = new DependencyManager();\n\n // 检测路由冲突\n this.detectRouteConflicts(this.routes);\n this.logRoutes(this.routes, \"组件路由\");\n console.log(\"🚀 依赖按需加载,服务器启动完成\");\n }\n\n /**\n * 处理请求\n */\n async fetch(req: Request): Promise<Response> {\n const url = new URL(req.url);\n const pathname = url.pathname;\n const method = req.method;\n\n // 只支持 GET 请求\n if (method !== \"GET\") {\n return new Response(\"Method Not Allowed\", { status: 405 });\n }\n\n // 查找匹配的路由\n let matchedRoute: FlattenedComponentRoute | null = null;\n for (const route of this.routes) {\n if (PathMatcher.matchPath(route.fullPath, pathname)) {\n matchedRoute = route;\n break;\n }\n }\n\n if (!matchedRoute) {\n return new Response(\"Not Found\", { status: 404 });\n }\n\n try {\n // 创建中间件上下文\n const context = {\n req,\n params: PathMatcher.extractParams(matchedRoute.fullPath, pathname),\n query: Object.fromEntries(url.searchParams),\n pathname,\n };\n\n // 执行中间件链,中间件会处理组件渲染\n return await this.executeMiddlewareChain(\n matchedRoute.middlewareChain,\n context,\n matchedRoute.component,\n );\n } catch (error) {\n console.error(\"组件渲染失败:\", error);\n return new Response(\"Internal Server Error\", { status: 500 });\n }\n }\n\n /**\n * 执行中间件链\n */\n private async executeMiddlewareChain(\n middlewareChain: any[],\n context: any,\n componentImport: () => Promise<any>,\n ): Promise<Response> {\n // 创建最终的渲染函数\n const renderComponent = async () => {\n const componentModule = await componentImport();\n const component = componentModule.default || componentModule;\n\n // 自动检测组件类型\n const componentType =\n this.dependencyManager.detectComponentType(component);\n\n // 按需加载依赖\n const deps = await this.dependencyManager.getFrameworkDeps(componentType);\n\n // 根据组件类型渲染\n if (componentType === \"vue\") {\n return await this.renderVueComponent(component, context, deps);\n } else if (componentType === \"react\") {\n return await this.renderReactComponent(component, context, deps);\n } else {\n throw new Error(`不支持的组件类型: ${componentType}`);\n }\n };\n\n // 执行中间件链\n let index = 0;\n const next = async (): Promise<Response> => {\n if (index >= middlewareChain.length) {\n return await renderComponent();\n }\n\n const middleware = middlewareChain[index++];\n return await middleware(context.req, next);\n };\n\n return await next();\n }\n\n /**\n * 渲染 Vue 组件\n */\n private async renderVueComponent(\n component: any,\n context: any,\n deps: any,\n ): Promise<Response> {\n try {\n const [vue, renderer] = deps;\n const app = vue.createSSRApp(component);\n\n // 提供路由信息\n app.provide(\"routeInfo\", {\n params: context.params || {},\n query: context.query || {},\n pathname: context.pathname,\n });\n\n const html = await renderer.renderToString(app);\n const fullHtml = HtmlRenderer.generateVueHtml(html, context);\n\n return new Response(fullHtml, {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n } catch (error) {\n console.error(\"Vue 组件渲染失败:\", error);\n return new Response(\"Vue Component Render Error\", { status: 500 });\n }\n }\n\n /**\n * 渲染 React 组件\n */\n private async renderReactComponent(\n component: any,\n context: any,\n deps: any,\n ): Promise<Response> {\n try {\n const [react, renderer] = deps;\n const content = react.createElement(component, {\n req: context.req,\n params: context.params || {},\n query: context.query || {},\n });\n\n const html = renderer.renderToString(content);\n const fullHtml = HtmlRenderer.generateReactHtml(html, context);\n\n return new Response(fullHtml, {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n } catch (error) {\n console.error(\"React 组件渲染失败:\", error);\n return new Response(\"React Component Render Error\", { status: 500 });\n }\n }\n\n /**\n * 获取依赖管理器(用于外部访问)\n */\n getDependencyManager(): DependencyManager {\n return this.dependencyManager;\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { o as getRouteRegistry } from "./route-registry-DsPslV2b.mjs";
1
+ import { o as getRouteRegistry } from "./route-registry-ClmI5VwE.mjs";
2
2
 
3
3
  //#region src/utils/contract.ts
4
4
  /**
@@ -113,4 +113,4 @@ function getRoutesFromRegistry() {
113
113
 
114
114
  //#endregion
115
115
  export { getApiSpec as n, generateAITools as t };
116
- //# sourceMappingURL=contract-vSyKiRwz.mjs.map
116
+ //# sourceMappingURL=contract-BIqqOwPd.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract-vSyKiRwz.mjs","names":[],"sources":["../src/utils/contract.ts"],"sourcesContent":["/**\n * API Spec 生成器\n *\n * 用于生成 API 规范,支持:\n * - 跨仓库类型同步\n * - AI 工具函数生成\n * - Swagger/OpenAPI 文档生成\n *\n * @example\n * ```typescript\n * import { getApiSpec } from 'vafast'\n *\n * // 方式 1:直接作为 handler(推荐,自动从全局 Registry 获取)\n * const allRoutes = [\n * ...routes,\n * { method: 'GET', path: '/api-spec', handler: getApiSpec }\n * ]\n *\n * // 方式 2:显式传参(灵活场景,如只暴露公开 API)\n * { handler: () => getApiSpec(publicRoutes) }\n * ```\n */\n\nimport type { TSchema } from '@sinclair/typebox'\nimport type { RouteSchema } from '../defineRoute'\nimport { getRouteRegistry } from './route-registry'\n\n/** 路由规范信息 */\ninterface RouteSpec {\n method: string\n path: string\n name?: string\n description?: string\n /** 是否为 SSE 端点(Server-Sent Events) */\n sse?: boolean\n schema?: {\n body?: TSchema\n query?: TSchema\n params?: TSchema\n headers?: TSchema\n cookies?: TSchema\n response?: TSchema\n }\n}\n\n/** API 规范 */\nexport interface ApiSpec {\n version: string\n generatedAt: string\n routes: RouteSpec[]\n}\n\n/** AI 工具函数格式 */\ninterface AITool {\n name: string\n description?: string\n parameters?: TSchema\n}\n\n/**\n * 从路由数组生成 API 规范\n */\nfunction generateSpec(routes: readonly unknown[]): ApiSpec {\n const routeSpecs: RouteSpec[] = []\n\n for (const route of routes) {\n const r = route as {\n method?: string\n path?: string\n name?: string\n description?: string\n schema?: RouteSchema\n sse?: boolean\n }\n\n if (!r.method || !r.path) continue\n\n // 跳过 spec 接口本身\n if (r.path === '/api-spec' || r.path === '/__spec__') continue\n\n const spec: RouteSpec = {\n method: r.method,\n path: r.path,\n }\n\n // 直接从路由获取 name 和 description\n if (r.name) spec.name = r.name\n if (r.description) spec.description = r.description\n\n // SSE 标记\n if (r.sse === true) {\n spec.sse = true\n }\n\n // 直接从路由获取 schema\n if (r.schema) {\n const schema = r.schema\n if (schema.body || schema.query || schema.params || schema.headers || schema.cookies || schema.response) {\n spec.schema = {}\n if (schema.body) spec.schema.body = schema.body\n if (schema.query) spec.schema.query = schema.query\n if (schema.params) spec.schema.params = schema.params\n if (schema.headers) spec.schema.headers = schema.headers\n if (schema.cookies) spec.schema.cookies = schema.cookies\n if (schema.response) spec.schema.response = schema.response\n }\n }\n\n routeSpecs.push(spec)\n }\n\n return {\n version: '1.0.0',\n generatedAt: new Date().toISOString(),\n routes: routeSpecs,\n }\n}\n\n/**\n * 从路由数组生成 AI 工具函数\n *\n * 可直接用于 OpenAI Function Calling / Claude Tools\n *\n * @example\n * ```typescript\n * const tools = generateAITools(routes)\n * // [{ name: 'get_users', description: '获取用户列表', parameters: {...} }]\n * ```\n */\nexport function generateAITools(routes: readonly unknown[]): AITool[] {\n const tools: AITool[] = []\n\n for (const route of routes) {\n const r = route as {\n method?: string\n path?: string\n name?: string\n description?: string\n schema?: RouteSchema\n }\n\n if (!r.method || !r.path) continue\n if (r.path === '/api-spec' || r.path === '/__spec__') continue\n\n // 使用 name 或从 path 生成\n const name = r.name || pathToToolName(r.method, r.path)\n\n const tool: AITool = { name }\n if (r.description) tool.description = r.description\n\n // GET 用 query,其他用 body\n if (r.schema) {\n if (r.method === 'GET' && r.schema.query) {\n tool.parameters = r.schema.query\n } else if (r.schema.body) {\n tool.parameters = r.schema.body\n }\n }\n\n tools.push(tool)\n }\n\n return tools\n}\n\n/** 从路径生成工具名 */\nfunction pathToToolName(method: string, path: string): string {\n const segments = path.split('/').filter(Boolean)\n const cleanSegments = segments\n .map(s => s.startsWith(':') ? '' : s)\n .filter(Boolean)\n\n const prefix = method.toLowerCase()\n const suffix = cleanSegments.join('_')\n\n return suffix ? `${prefix}_${suffix}` : prefix\n}\n\n/**\n * 获取 API 规范\n *\n * 支持多种调用方式:\n * 1. 直接作为 handler:自动从全局 Registry 获取(推荐)\n * 2. 无参调用:同上,用于 CLI/测试\n * 3. 有参调用:显式传递路由数组(灵活场景)\n *\n * @param routesOrContext - 可选,路由数组或 handler context。不传则从全局 Registry 获取\n * @returns ApiSpec 对象\n *\n * @example\n * ```typescript\n * import { getApiSpec } from 'vafast'\n *\n * // 方式 1:直接作为 handler(推荐,最简洁)\n * { method: 'GET', path: '/api-spec', handler: getApiSpec }\n *\n * // 方式 2:显式传参(只暴露公开 API)\n * { handler: () => getApiSpec(publicRoutes) }\n *\n * // 方式 3:本地使用(CLI、测试)\n * const spec = getApiSpec()\n * ```\n */\nexport function getApiSpec(routesOrContext?: readonly unknown[] | Record<string, unknown>): ApiSpec {\n // 智能检测:是路由数组还是 handler context\n // 路由数组:Array && 第一个元素有 method 属性\n const isRoutesArray = Array.isArray(routesOrContext) &&\n routesOrContext.length > 0 &&\n typeof (routesOrContext[0] as Record<string, unknown>)?.method === 'string'\n\n const routeList = isRoutesArray\n ? routesOrContext\n : getRoutesFromRegistry()\n\n return generateSpec(routeList)\n}\n\n/**\n * 从全局 Registry 获取路由列表\n * 包含 schema 信息(Registry 存储完整路由)\n */\nfunction getRoutesFromRegistry(): readonly unknown[] {\n try {\n const registry = getRouteRegistry()\n return registry.getAll()\n } catch {\n // Registry 未初始化时返回空数组\n return []\n }\n}\n"],"mappings":";;;;;;AA8DA,SAAS,aAAa,QAAqC;CACzD,MAAM,aAA0B,EAAE;AAElC,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,IAAI;AASV,MAAI,CAAC,EAAE,UAAU,CAAC,EAAE,KAAM;AAG1B,MAAI,EAAE,SAAS,eAAe,EAAE,SAAS,YAAa;EAEtD,MAAM,OAAkB;GACtB,QAAQ,EAAE;GACV,MAAM,EAAE;GACT;AAGD,MAAI,EAAE,KAAM,MAAK,OAAO,EAAE;AAC1B,MAAI,EAAE,YAAa,MAAK,cAAc,EAAE;AAGxC,MAAI,EAAE,QAAQ,KACZ,MAAK,MAAM;AAIb,MAAI,EAAE,QAAQ;GACZ,MAAM,SAAS,EAAE;AACjB,OAAI,OAAO,QAAQ,OAAO,SAAS,OAAO,UAAU,OAAO,WAAW,OAAO,WAAW,OAAO,UAAU;AACvG,SAAK,SAAS,EAAE;AAChB,QAAI,OAAO,KAAM,MAAK,OAAO,OAAO,OAAO;AAC3C,QAAI,OAAO,MAAO,MAAK,OAAO,QAAQ,OAAO;AAC7C,QAAI,OAAO,OAAQ,MAAK,OAAO,SAAS,OAAO;AAC/C,QAAI,OAAO,QAAS,MAAK,OAAO,UAAU,OAAO;AACjD,QAAI,OAAO,QAAS,MAAK,OAAO,UAAU,OAAO;AACjD,QAAI,OAAO,SAAU,MAAK,OAAO,WAAW,OAAO;;;AAIvD,aAAW,KAAK,KAAK;;AAGvB,QAAO;EACL,SAAS;EACT,8BAAa,IAAI,MAAM,EAAC,aAAa;EACrC,QAAQ;EACT;;;;;;;;;;;;;AAcH,SAAgB,gBAAgB,QAAsC;CACpE,MAAM,QAAkB,EAAE;AAE1B,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,IAAI;AAQV,MAAI,CAAC,EAAE,UAAU,CAAC,EAAE,KAAM;AAC1B,MAAI,EAAE,SAAS,eAAe,EAAE,SAAS,YAAa;EAKtD,MAAM,OAAe,EAAE,MAFV,EAAE,QAAQ,eAAe,EAAE,QAAQ,EAAE,KAAK,EAE1B;AAC7B,MAAI,EAAE,YAAa,MAAK,cAAc,EAAE;AAGxC,MAAI,EAAE,QACJ;OAAI,EAAE,WAAW,SAAS,EAAE,OAAO,MACjC,MAAK,aAAa,EAAE,OAAO;YAClB,EAAE,OAAO,KAClB,MAAK,aAAa,EAAE,OAAO;;AAI/B,QAAM,KAAK,KAAK;;AAGlB,QAAO;;;AAIT,SAAS,eAAe,QAAgB,MAAsB;CAE5D,MAAM,gBADW,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ,CAE7C,KAAI,MAAK,EAAE,WAAW,IAAI,GAAG,KAAK,EAAE,CACpC,OAAO,QAAQ;CAElB,MAAM,SAAS,OAAO,aAAa;CACnC,MAAM,SAAS,cAAc,KAAK,IAAI;AAEtC,QAAO,SAAS,GAAG,OAAO,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4B1C,SAAgB,WAAW,iBAAyE;AAWlG,QAAO,aARe,MAAM,QAAQ,gBAAgB,IAClD,gBAAgB,SAAS,KACzB,OAAQ,gBAAgB,IAAgC,WAAW,WAGjE,kBACA,uBAAuB,CAEG;;;;;;AAOhC,SAAS,wBAA4C;AACnD,KAAI;AAEF,SADiB,kBAAkB,CACnB,QAAQ;SAClB;AAEN,SAAO,EAAE"}
1
+ {"version":3,"file":"contract-BIqqOwPd.mjs","names":[],"sources":["../src/utils/contract.ts"],"sourcesContent":["/**\n * API Spec 生成器\n *\n * 用于生成 API 规范,支持:\n * - 跨仓库类型同步\n * - AI 工具函数生成\n * - Swagger/OpenAPI 文档生成\n *\n * @example\n * ```typescript\n * import { getApiSpec } from 'vafast'\n *\n * // 方式 1:直接作为 handler(推荐,自动从全局 Registry 获取)\n * const allRoutes = [\n * ...routes,\n * { method: 'GET', path: '/api-spec', handler: getApiSpec }\n * ]\n *\n * // 方式 2:显式传参(灵活场景,如只暴露公开 API)\n * { handler: () => getApiSpec(publicRoutes) }\n * ```\n */\n\nimport type { TSchema } from '@sinclair/typebox'\nimport type { RouteSchema } from '../defineRoute'\nimport { getRouteRegistry } from './route-registry'\n\n/** 路由规范信息 */\ninterface RouteSpec {\n method: string\n path: string\n name?: string\n description?: string\n /** 是否为 SSE 端点(Server-Sent Events) */\n sse?: boolean\n schema?: {\n body?: TSchema\n query?: TSchema\n params?: TSchema\n headers?: TSchema\n cookies?: TSchema\n response?: TSchema\n }\n}\n\n/** API 规范 */\nexport interface ApiSpec {\n version: string\n generatedAt: string\n routes: RouteSpec[]\n}\n\n/** AI 工具函数格式 */\ninterface AITool {\n name: string\n description?: string\n parameters?: TSchema\n}\n\n/**\n * 从路由数组生成 API 规范\n */\nfunction generateSpec(routes: readonly unknown[]): ApiSpec {\n const routeSpecs: RouteSpec[] = []\n\n for (const route of routes) {\n const r = route as {\n method?: string\n path?: string\n name?: string\n description?: string\n schema?: RouteSchema\n sse?: boolean\n }\n\n if (!r.method || !r.path) continue\n\n // 跳过 spec 接口本身\n if (r.path === '/api-spec' || r.path === '/__spec__') continue\n\n const spec: RouteSpec = {\n method: r.method,\n path: r.path,\n }\n\n // 直接从路由获取 name 和 description\n if (r.name) spec.name = r.name\n if (r.description) spec.description = r.description\n\n // SSE 标记\n if (r.sse === true) {\n spec.sse = true\n }\n\n // 直接从路由获取 schema\n if (r.schema) {\n const schema = r.schema\n if (schema.body || schema.query || schema.params || schema.headers || schema.cookies || schema.response) {\n spec.schema = {}\n if (schema.body) spec.schema.body = schema.body\n if (schema.query) spec.schema.query = schema.query\n if (schema.params) spec.schema.params = schema.params\n if (schema.headers) spec.schema.headers = schema.headers\n if (schema.cookies) spec.schema.cookies = schema.cookies\n if (schema.response) spec.schema.response = schema.response\n }\n }\n\n routeSpecs.push(spec)\n }\n\n return {\n version: '1.0.0',\n generatedAt: new Date().toISOString(),\n routes: routeSpecs,\n }\n}\n\n/**\n * 从路由数组生成 AI 工具函数\n *\n * 可直接用于 OpenAI Function Calling / Claude Tools\n *\n * @example\n * ```typescript\n * const tools = generateAITools(routes)\n * // [{ name: 'get_users', description: '获取用户列表', parameters: {...} }]\n * ```\n */\nexport function generateAITools(routes: readonly unknown[]): AITool[] {\n const tools: AITool[] = []\n\n for (const route of routes) {\n const r = route as {\n method?: string\n path?: string\n name?: string\n description?: string\n schema?: RouteSchema\n }\n\n if (!r.method || !r.path) continue\n if (r.path === '/api-spec' || r.path === '/__spec__') continue\n\n // 使用 name 或从 path 生成\n const name = r.name || pathToToolName(r.method, r.path)\n\n const tool: AITool = { name }\n if (r.description) tool.description = r.description\n\n // GET 用 query,其他用 body\n if (r.schema) {\n if (r.method === 'GET' && r.schema.query) {\n tool.parameters = r.schema.query\n } else if (r.schema.body) {\n tool.parameters = r.schema.body\n }\n }\n\n tools.push(tool)\n }\n\n return tools\n}\n\n/** 从路径生成工具名 */\nfunction pathToToolName(method: string, path: string): string {\n const segments = path.split('/').filter(Boolean)\n const cleanSegments = segments\n .map(s => s.startsWith(':') ? '' : s)\n .filter(Boolean)\n\n const prefix = method.toLowerCase()\n const suffix = cleanSegments.join('_')\n\n return suffix ? `${prefix}_${suffix}` : prefix\n}\n\n/**\n * 获取 API 规范\n *\n * 支持多种调用方式:\n * 1. 直接作为 handler:自动从全局 Registry 获取(推荐)\n * 2. 无参调用:同上,用于 CLI/测试\n * 3. 有参调用:显式传递路由数组(灵活场景)\n *\n * @param routesOrContext - 可选,路由数组或 handler context。不传则从全局 Registry 获取\n * @returns ApiSpec 对象\n *\n * @example\n * ```typescript\n * import { getApiSpec } from 'vafast'\n *\n * // 方式 1:直接作为 handler(推荐,最简洁)\n * { method: 'GET', path: '/api-spec', handler: getApiSpec }\n *\n * // 方式 2:显式传参(只暴露公开 API)\n * { handler: () => getApiSpec(publicRoutes) }\n *\n * // 方式 3:本地使用(CLI、测试)\n * const spec = getApiSpec()\n * ```\n */\nexport function getApiSpec(routesOrContext?: readonly unknown[] | Record<string, unknown>): ApiSpec {\n // 智能检测:是路由数组还是 handler context\n // 路由数组:Array && 第一个元素有 method 属性\n const isRoutesArray = Array.isArray(routesOrContext) &&\n routesOrContext.length > 0 &&\n typeof (routesOrContext[0] as Record<string, unknown>)?.method === 'string'\n\n const routeList = isRoutesArray\n ? routesOrContext\n : getRoutesFromRegistry()\n\n return generateSpec(routeList)\n}\n\n/**\n * 从全局 Registry 获取路由列表\n * 包含 schema 信息(Registry 存储完整路由)\n */\nfunction getRoutesFromRegistry(): readonly unknown[] {\n try {\n const registry = getRouteRegistry()\n return registry.getAll()\n } catch {\n // Registry 未初始化时返回空数组\n return []\n }\n}\n"],"mappings":";;;;;;AA8DA,SAAS,aAAa,QAAqC;CACzD,MAAM,aAA0B,EAAE;AAElC,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,IAAI;AASV,MAAI,CAAC,EAAE,UAAU,CAAC,EAAE,KAAM;AAG1B,MAAI,EAAE,SAAS,eAAe,EAAE,SAAS,YAAa;EAEtD,MAAM,OAAkB;GACtB,QAAQ,EAAE;GACV,MAAM,EAAE;GACT;AAGD,MAAI,EAAE,KAAM,MAAK,OAAO,EAAE;AAC1B,MAAI,EAAE,YAAa,MAAK,cAAc,EAAE;AAGxC,MAAI,EAAE,QAAQ,KACZ,MAAK,MAAM;AAIb,MAAI,EAAE,QAAQ;GACZ,MAAM,SAAS,EAAE;AACjB,OAAI,OAAO,QAAQ,OAAO,SAAS,OAAO,UAAU,OAAO,WAAW,OAAO,WAAW,OAAO,UAAU;AACvG,SAAK,SAAS,EAAE;AAChB,QAAI,OAAO,KAAM,MAAK,OAAO,OAAO,OAAO;AAC3C,QAAI,OAAO,MAAO,MAAK,OAAO,QAAQ,OAAO;AAC7C,QAAI,OAAO,OAAQ,MAAK,OAAO,SAAS,OAAO;AAC/C,QAAI,OAAO,QAAS,MAAK,OAAO,UAAU,OAAO;AACjD,QAAI,OAAO,QAAS,MAAK,OAAO,UAAU,OAAO;AACjD,QAAI,OAAO,SAAU,MAAK,OAAO,WAAW,OAAO;;;AAIvD,aAAW,KAAK,KAAK;;AAGvB,QAAO;EACL,SAAS;EACT,8BAAa,IAAI,MAAM,EAAC,aAAa;EACrC,QAAQ;EACT;;;;;;;;;;;;;AAcH,SAAgB,gBAAgB,QAAsC;CACpE,MAAM,QAAkB,EAAE;AAE1B,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,IAAI;AAQV,MAAI,CAAC,EAAE,UAAU,CAAC,EAAE,KAAM;AAC1B,MAAI,EAAE,SAAS,eAAe,EAAE,SAAS,YAAa;EAKtD,MAAM,OAAe,EAAE,MAFV,EAAE,QAAQ,eAAe,EAAE,QAAQ,EAAE,KAAK,EAE1B;AAC7B,MAAI,EAAE,YAAa,MAAK,cAAc,EAAE;AAGxC,MAAI,EAAE,QACJ;OAAI,EAAE,WAAW,SAAS,EAAE,OAAO,MACjC,MAAK,aAAa,EAAE,OAAO;YAClB,EAAE,OAAO,KAClB,MAAK,aAAa,EAAE,OAAO;;AAI/B,QAAM,KAAK,KAAK;;AAGlB,QAAO;;;AAIT,SAAS,eAAe,QAAgB,MAAsB;CAE5D,MAAM,gBADW,KAAK,MAAM,IAAI,CAAC,OAAO,QAAQ,CAE7C,KAAI,MAAK,EAAE,WAAW,IAAI,GAAG,KAAK,EAAE,CACpC,OAAO,QAAQ;CAElB,MAAM,SAAS,OAAO,aAAa;CACnC,MAAM,SAAS,cAAc,KAAK,IAAI;AAEtC,QAAO,SAAS,GAAG,OAAO,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4B1C,SAAgB,WAAW,iBAAyE;AAWlG,QAAO,aARe,MAAM,QAAQ,gBAAgB,IAClD,gBAAgB,SAAS,KACzB,OAAQ,gBAAgB,IAAgC,WAAW,WAGjE,kBACA,uBAAuB,CAEG;;;;;;AAOhC,SAAS,wBAA4C;AACnD,KAAI;AAEF,SADiB,kBAAkB,CACnB,QAAQ;SAClB;AAEN,SAAO,EAAE"}
@@ -71,4 +71,4 @@ declare function generateAITools(routes: readonly unknown[]): AITool[];
71
71
  declare function getApiSpec(routesOrContext?: readonly unknown[] | Record<string, unknown>): ApiSpec;
72
72
  //#endregion
73
73
  export { generateAITools as n, getApiSpec as r, ApiSpec as t };
74
- //# sourceMappingURL=contract-C-xQoZ6r.d.mts.map
74
+ //# sourceMappingURL=contract-ChZaybx9.d.mts.map
@@ -327,4 +327,4 @@ type InferableRoute<TMethod extends string = string, TPath extends string = stri
327
327
  };
328
328
  //#endregion
329
329
  export { sse as _, ProcessedRoute as a, RoutesWithSource as c, SSEGeneratorType as d, SSEMeta as f, defineRoutes as g, defineRoute as h, NestedRouteConfig as i, SSEEventType as l, defineMiddleware as m, InferableRoute as n, Route as o, TypedMiddleware as p, LeafRouteConfig as r, RouteSchema as s, HandlerContext as t, SSEEventWithMeta as u, withContext as v };
330
- //# sourceMappingURL=defineRoute-Rod-Vi6-.d.mts.map
330
+ //# sourceMappingURL=defineRoute-DUYeO8TR.d.mts.map
@@ -1,2 +1,2 @@
1
- import { _ as sse, a as ProcessedRoute, c as RoutesWithSource, d as SSEGeneratorType, f as SSEMeta, g as defineRoutes, h as defineRoute, i as NestedRouteConfig, l as SSEEventType, m as defineMiddleware, n as InferableRoute, o as Route, p as TypedMiddleware, r as LeafRouteConfig, s as RouteSchema, t as HandlerContext, u as SSEEventWithMeta, v as withContext } from "./defineRoute-Rod-Vi6-.mjs";
1
+ import { _ as sse, a as ProcessedRoute, c as RoutesWithSource, d as SSEGeneratorType, f as SSEMeta, g as defineRoutes, h as defineRoute, i as NestedRouteConfig, l as SSEEventType, m as defineMiddleware, n as InferableRoute, o as Route, p as TypedMiddleware, r as LeafRouteConfig, s as RouteSchema, t as HandlerContext, u as SSEEventWithMeta, v as withContext } from "./defineRoute-DUYeO8TR.mjs";
2
2
  export { HandlerContext, InferableRoute, LeafRouteConfig, NestedRouteConfig, ProcessedRoute, Route, RouteSchema, RoutesWithSource, SSEEventType, SSEEventWithMeta, SSEGeneratorType, SSEMeta, TypedMiddleware, defineMiddleware, defineRoute, defineRoutes, sse, withContext };
@@ -1,6 +1,7 @@
1
- import { a as parseCookies, l as parseHeaders, r as parseBody, u as parseQuery } from "./parsers-BPBVKby-.mjs";
2
- import { a as validateAllSchemas, i as precompileSchemas } from "./validators-CkfvNBbK.mjs";
3
- import { i as json, u as VafastError } from "./response-Bs9GhJz-.mjs";
1
+ import { a as parseCookies, l as parseHeaders, r as parseBody, u as parseQuery } from "./parsers-DPKyyUv3.mjs";
2
+ import { i as isValidationFailedError } from "./validation-errors-j7DAULlG.mjs";
3
+ import { a as validateAllSchemas, i as precompileSchemas } from "./validators-DdEfUzCC.mjs";
4
+ import { i as json, u as VafastError } from "./response-BlkS--Fb.mjs";
4
5
 
5
6
  //#region src/defineRoute.ts
6
7
  /**
@@ -92,11 +93,7 @@ function wrapHandler(schema, userHandler) {
92
93
  try {
93
94
  return autoResponse(await userHandler(await buildHandlerContext(req, schema)));
94
95
  } catch (error) {
95
- if (error instanceof VafastError) throw error;
96
- if (error instanceof Error && error.message.includes("验证失败")) return json({
97
- code: 400,
98
- message: error.message
99
- }, 400);
96
+ if (error instanceof VafastError || isValidationFailedError(error)) throw error;
100
97
  return json({
101
98
  code: 500,
102
99
  message: error instanceof Error ? error.message : "未知错误"
@@ -198,11 +195,7 @@ function wrapSSEHandler(schema, sseHandler) {
198
195
  try {
199
196
  return await sseHandler(await buildHandlerContext(req, schema));
200
197
  } catch (error) {
201
- if (error instanceof VafastError) throw error;
202
- if (error instanceof Error && error.message.includes("验证失败")) return json({
203
- code: 400,
204
- message: error.message
205
- }, 400);
198
+ if (error instanceof VafastError || isValidationFailedError(error)) throw error;
206
199
  return json({
207
200
  code: 500,
208
201
  message: error instanceof Error ? error.message : "未知错误"
@@ -1 +1 @@
1
- {"version":3,"file":"defineRoute.mjs","names":[],"sources":["../src/defineRoute.ts"],"sourcesContent":["/**\n * 路由定义 - Schema 在路由级别定义,支持嵌套路由和中间件类型推断\n *\n * @example\n * ```typescript\n * // 定义带类型的中间件(函数式风格,通过 next 传递上下文)\n * const authMiddleware = defineMiddleware<{ user: User }>((req, next) => {\n * const user = getUser(req)\n * return next({ user }) // 通过 next 参数传递上下文\n * })\n *\n * // 路由自动推断中间件注入的类型\n * const routes = defineRoutes([\n * defineRoute({\n * path: '/api',\n * middleware: [authMiddleware],\n * children: [\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * handler: ({ user }) => ({ name: user.name }) // ✅ user 有类型\n * })\n * ]\n * })\n * ])\n * ```\n */\n\nimport type { TSchema, Static } from \"@sinclair/typebox\";\nimport { parseBody, parseQuery, parseHeaders, parseCookies } from \"./utils/parsers\";\nimport { validateAllSchemas, precompileSchemas } from \"./utils/validators/validators\";\nimport { json } from \"./utils/response\";\nimport { VafastError } from \"./middleware\";\n\n// ============= SSE 事件类型(内联定义,避免循环依赖) =============\n\n/** SSE 事件 */\nexport interface SSEEventType<T = unknown> {\n event?: string;\n data: T;\n id?: string;\n retry?: number;\n}\n\n/** SSE Generator 类型 */\nexport type SSEGeneratorType<TSchema extends RouteSchema = RouteSchema> = (\n ctx: HandlerContext<TSchema>\n) => AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n\n// ============= Schema 类型 =============\n\n/** 路由 Schema 配置 */\nexport interface RouteSchema {\n body?: TSchema;\n query?: TSchema;\n params?: TSchema;\n headers?: TSchema;\n cookies?: TSchema;\n /** 响应类型 schema(用于类型同步,运行时不做校验) */\n response?: TSchema;\n}\n\n/** 从 Schema 推断类型 */\ntype InferSchemaType<T extends RouteSchema> = {\n body: T[\"body\"] extends TSchema ? Static<T[\"body\"]> : unknown;\n query: T[\"query\"] extends TSchema ? Static<T[\"query\"]> : Record<string, string>;\n params: T[\"params\"] extends TSchema ? Static<T[\"params\"]> : Record<string, string>;\n headers: T[\"headers\"] extends TSchema ? Static<T[\"headers\"]> : Record<string, string>;\n cookies: T[\"cookies\"] extends TSchema ? Static<T[\"cookies\"]> : Record<string, string>;\n};\n\n// ============= 中间件类型系统 =============\n\n/** 带类型标记的中间件 */\nexport interface TypedMiddleware<TContext extends object = object> {\n (req: Request, next: (ctx?: TContext) => Promise<Response>): Response | Promise<Response>;\n /** 类型标记(仅编译时使用) */\n __context?: TContext;\n}\n\n/** 普通中间件(无类型注入) */\ntype PlainMiddleware = (req: Request, next: () => Promise<Response>) => Response | Promise<Response>;\n\n/** 任意中间件类型 */\ntype AnyMiddleware = TypedMiddleware<object> | PlainMiddleware;\n\n/** 从中间件提取上下文类型 */\ntype ExtractMiddlewareContext<T> = T extends TypedMiddleware<infer C> ? C : object;\n\n/** 合并中间件数组的上下文类型 */\ntype MergeMiddlewareContexts<T extends readonly unknown[]> =\n T extends readonly [infer First, ...infer Rest]\n ? ExtractMiddlewareContext<First> & MergeMiddlewareContexts<Rest>\n : object;\n\n// ============= Handler 上下文 =============\n\n/** Handler 上下文(包含 schema 推断) */\nexport interface HandlerContext<TSchema extends RouteSchema = RouteSchema> {\n req: Request;\n body: InferSchemaType<TSchema>[\"body\"];\n query: InferSchemaType<TSchema>[\"query\"];\n params: InferSchemaType<TSchema>[\"params\"];\n headers: InferSchemaType<TSchema>[\"headers\"];\n cookies: InferSchemaType<TSchema>[\"cookies\"];\n}\n\n/** Handler 上下文(带中间件注入的额外类型) */\ntype HandlerContextWithExtra<TSchema extends RouteSchema, TExtra> =\n HandlerContext<TSchema> & TExtra;\n\n// ============= 路由配置类型 =============\n\n/** HTTP 方法 */\ntype HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"OPTIONS\" | \"HEAD\";\n\n/** Handler 上下文类型(带中间件扩展) */\ntype HandlerCtx<TSchema extends RouteSchema, TMiddleware extends readonly AnyMiddleware[]> =\n HandlerContextWithExtra<TSchema, MergeMiddlewareContexts<TMiddleware>>;\n\n/** 普通 Handler 类型 */\ntype NormalHandler<TSchema extends RouteSchema, TReturn, TMiddleware extends readonly AnyMiddleware[]> = (\n ctx: HandlerCtx<TSchema, TMiddleware>\n) => TReturn | Promise<TReturn>;\n\n/** SSE Generator Handler 类型(sse: true 时直接写 async function*) */\ntype SSEHandler<TSchema extends RouteSchema, TMiddleware extends readonly AnyMiddleware[]> = (\n ctx: HandlerCtx<TSchema, TMiddleware>\n) => AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n\n/** 叶子路由配置(有 method 和 handler) */\nexport interface LeafRouteConfig<\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string,\n TSchema extends RouteSchema = RouteSchema,\n TReturn = unknown,\n TMiddleware extends readonly AnyMiddleware[] = readonly AnyMiddleware[]\n> {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** \n * 是否为 SSE 端点(显式声明,推荐)\n * \n * 设置为 true 时,handler 应返回 AsyncGenerator:\n * ```typescript\n * sse: true,\n * handler: async function* (ctx) { yield { data: ... } }\n * ```\n */\n readonly sse?: boolean;\n /** \n * Handler 支持两种写法:\n * 1. 普通函数: `async (ctx) => { return result }`\n * 2. SSE Generator(需配合 sse: true): `async function* (ctx) { yield { data: ... } }`\n */\n readonly handler: NormalHandler<TSchema, TReturn, TMiddleware> | SSEHandler<TSchema, TMiddleware>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}\n\n/** 嵌套路由配置(有 children,无 method 和 handler) */\nexport interface NestedRouteConfig<\n TPath extends string = string,\n TMiddleware extends readonly AnyMiddleware[] = readonly AnyMiddleware[]\n> {\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly middleware?: TMiddleware;\n readonly children: ReadonlyArray<RouteConfigResult>;\n}\n\n/** defineRoute 返回的类型 */\ntype RouteConfigResult =\n | LeafRouteConfig<HTTPMethod, string, RouteSchema, unknown, readonly AnyMiddleware[]>\n | NestedRouteConfig<string, readonly AnyMiddleware[]>;\n\n/** 处理后的扁平路由 */\nexport interface ProcessedRoute {\n method: HTTPMethod;\n path: string;\n name?: string;\n description?: string;\n schema?: RouteSchema;\n /** 是否为 SSE 端点 */\n sse?: boolean;\n handler: (req: Request) => Promise<Response>;\n middleware?: readonly AnyMiddleware[];\n docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n /** 允许任意扩展(兼容 Route 类型) */\n [key: string]: unknown;\n}\n\n/** Route 类型别名(便于用户使用) */\nexport type Route = ProcessedRoute;\n\n// ============= defineMiddleware =============\n\n/**\n * 定义带类型的中间件(函数式风格)\n *\n * 通过 next() 参数传递上下文,更符合函数式编程风格\n *\n * @example\n * ```typescript\n * type AuthContext = { user: { id: string; name: string } }\n *\n * const authMiddleware = defineMiddleware<AuthContext>((req, next) => {\n * const user = getUserFromToken(req)\n * return next({ user }) // 通过 next 传递上下文\n * })\n * ```\n */\nexport function defineMiddleware<TContext extends object = object>(\n handler: (\n req: Request,\n next: (ctx?: TContext) => Promise<Response>\n ) => Promise<Response>\n): TypedMiddleware<TContext> {\n // 包装成标准中间件签名\n const middleware = ((req: Request, originalNext: () => Promise<Response>) => {\n // 包装 next,接收上下文参数并存储到 req.__locals\n const nextWithContext = (ctx?: TContext): Promise<Response> => {\n if (ctx) {\n const target = req as unknown as { __locals?: object };\n target.__locals = { ...(target.__locals || {}), ...ctx };\n }\n return originalNext();\n };\n return handler(req, nextWithContext);\n }) as TypedMiddleware<TContext>;\n\n return middleware;\n}\n\n// ============= 响应处理 =============\n\n/** 自动转换返回值为 Response */\nfunction autoResponse(result: unknown): Response {\n if (result instanceof Response) return result;\n if (result === null || result === undefined) return new Response(null, { status: 204 });\n if (typeof result === \"string\") {\n return new Response(result, { headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } });\n }\n if (typeof result === \"number\" || typeof result === \"boolean\") {\n return new Response(String(result), { headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } });\n }\n if (typeof result === \"object\") {\n const obj = result as Record<string, unknown>;\n if (\"data\" in obj && (\"status\" in obj || \"headers\" in obj)) {\n const { data, status = 200, headers = {} } = obj;\n if (data === null || data === undefined) {\n return new Response(null, { status: status === 200 ? 204 : (status as number), headers: headers as HeadersInit });\n }\n return json(data, status as number, headers as Record<string, string>);\n }\n return json(result);\n }\n return new Response(null, { status: 204 });\n}\n\n/**\n * 构建 HandlerContext(公共逻辑,供普通 handler 和 SSE handler 复用)\n */\nasync function buildHandlerContext<TSchema extends RouteSchema>(\n req: Request,\n schema: TSchema | undefined\n): Promise<HandlerContext<TSchema>> {\n const query = parseQuery(req);\n const headers = parseHeaders(req);\n const cookies = parseCookies(req);\n const params = ((req as unknown as Record<string, unknown>).params as Record<string, string>) || {};\n\n let body: unknown = undefined;\n if (req.method !== \"GET\" && req.method !== \"HEAD\") {\n try {\n body = await parseBody(req);\n } catch {\n // 忽略解析错误\n }\n }\n\n const data = { body, query, params, headers, cookies };\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n validateAllSchemas(schema, data);\n }\n\n // 获取中间件注入的上下文\n const extraCtx = (req as unknown as { __locals?: unknown }).__locals || {};\n\n return {\n req,\n body: body as HandlerContext<TSchema>[\"body\"],\n query: query as HandlerContext<TSchema>[\"query\"],\n params: params as HandlerContext<TSchema>[\"params\"],\n headers: headers as HandlerContext<TSchema>[\"headers\"],\n cookies: cookies as HandlerContext<TSchema>[\"cookies\"],\n ...extraCtx,\n } as HandlerContext<TSchema>;\n}\n\n/** 创建包装后的 handler(普通路由) */\nfunction wrapHandler<TSchema extends RouteSchema>(\n schema: TSchema | undefined,\n userHandler: (ctx: HandlerContext<TSchema>) => unknown | Promise<unknown>\n): (req: Request) => Promise<Response> {\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n precompileSchemas(schema);\n }\n\n return async (req: Request): Promise<Response> => {\n try {\n const ctx = await buildHandlerContext(req, schema);\n const result = await userHandler(ctx);\n return autoResponse(result);\n } catch (error) {\n // 如果是 VafastError,重新抛出让错误处理中间件处理\n if (error instanceof VafastError) {\n throw error;\n }\n if (error instanceof Error && error.message.includes(\"验证失败\")) {\n return json({ code: 400, message: error.message }, 400);\n }\n return json({ code: 500, message: error instanceof Error ? error.message : \"未知错误\" }, 500);\n }\n };\n}\n\n/**\n * SSE Handler 函数类型\n * \n * SSE handler 与普通 handler 使用统一的上下文模型,接收完整的 HandlerContext。\n * 框架自动完成:body 解析、schema 验证、中间件上下文注入。\n * SSE handler 只需关注流式响应逻辑,返回 SSE Stream Response。\n */\ntype SSEHandlerFn<TSchema extends RouteSchema = RouteSchema> = \n (ctx: HandlerContext<TSchema>) => Promise<Response>;\n\n/**\n * SSE 元数据接口(用于高级场景)\n */\nexport interface SSEMeta {\n /** SSE 事件名称 */\n event?: string;\n /** SSE 事件 ID */\n id?: string;\n /** SSE 重试间隔(毫秒) */\n retry?: number;\n}\n\n/**\n * 带元数据的 SSE 事件(高级用法)\n */\nexport interface SSEEventWithMeta<T = unknown> {\n /** SSE 元数据标记 */\n __sse__: SSEMeta;\n /** 事件数据 */\n data: T;\n}\n\n/**\n * 创建带元数据的 SSE 事件\n * \n * @example\n * // 设置事件名称\n * yield sse({ event: 'status' }, { ready: true })\n * \n * // 设置 ID(支持断线重连)\n * yield sse({ event: 'update', id: '42' }, { value: 1 })\n * \n * // 设置重试间隔\n * yield sse({ retry: 5000 }, 'reconnect hint')\n */\nexport function sse<T>(meta: SSEMeta, data: T): SSEEventWithMeta<T> {\n return { __sse__: meta, data };\n}\n\n/**\n * 检查是否是带元数据的 SSE 事件\n */\nfunction isSSEEventWithMeta(event: unknown): event is SSEEventWithMeta {\n return (\n event !== null &&\n typeof event === 'object' &&\n '__sse__' in event &&\n 'data' in event\n );\n}\n\n/**\n * 格式化 SSE 事件为字符串\n * \n * 支持两种用法:\n * 1. 简单模式(推荐):yield anyData → 自动包装为 data\n * 2. 高级模式:yield { __sse__: { event, id, retry }, data } → 完整 SSE 控制\n */\nfunction formatSSEEvent(event: unknown): string {\n const lines: string[] = [];\n let data: unknown;\n\n if (isSSEEventWithMeta(event)) {\n // 高级模式:用户提供了 SSE 元数据\n const meta = event.__sse__;\n if (meta.id !== undefined) lines.push(`id: ${meta.id}`);\n if (meta.event !== undefined) lines.push(`event: ${meta.event}`);\n if (meta.retry !== undefined) lines.push(`retry: ${meta.retry}`);\n data = event.data;\n } else {\n // 简单模式:直接把 event 作为 data\n data = event;\n }\n \n const dataStr = typeof data === 'string' ? data : JSON.stringify(data);\n for (const line of dataStr.split('\\n')) {\n lines.push(`data: ${line}`);\n }\n return lines.join('\\n') + '\\n\\n';\n}\n\n/**\n * 将 AsyncGenerator 包装为 SSE Handler\n * \n * 支持用户直接写 `async function* (ctx) { yield anyData }` \n * 数据会自动包装为 SSE data 字段发送\n */\nfunction wrapGeneratorToSSEHandler<TSchema extends RouteSchema>(\n generator: (ctx: HandlerContext<TSchema>) => AsyncGenerator<unknown, void, unknown>\n): SSEHandlerFn<TSchema> {\n return async (ctx: HandlerContext<TSchema>): Promise<Response> => {\n const stream = new ReadableStream({\n async start(controller) {\n const encoder = new TextEncoder();\n try {\n for await (const event of generator(ctx)) {\n controller.enqueue(encoder.encode(formatSSEEvent(event)));\n }\n } catch (error) {\n // 使用高级模式发送错误事件\n const errorEvent = formatSSEEvent({\n __sse__: { event: 'error' },\n data: { error: error instanceof Error ? error.message : '未知错误' }\n });\n controller.enqueue(encoder.encode(errorEvent));\n } finally {\n controller.close();\n }\n }\n });\n\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'X-Accel-Buffering': 'no',\n }\n });\n };\n}\n\n/**\n * 创建 SSE handler 的请求包装器\n * \n * SSE handler 与普通 handler 使用相同的上下文构建流程(buildHandlerContext),\n * 确保:\n * - body/query/params 解析一致\n * - schema 验证统一\n * - 中间件注入的上下文(如 userInfo)自动可用\n * - 错误处理统一\n * \n * 唯一区别:SSE handler 返回的是 SSE Stream Response,而非普通 JSON Response\n */\nfunction wrapSSEHandler<TSchema extends RouteSchema>(\n schema: TSchema | undefined,\n sseHandler: SSEHandlerFn<TSchema>\n): (req: Request) => Promise<Response> {\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n precompileSchemas(schema);\n }\n\n return async (req: Request): Promise<Response> => {\n try {\n // 与普通 handler 使用相同的上下文构建逻辑\n const ctx = await buildHandlerContext(req, schema);\n // SSE handler 返回 SSE Stream Response\n return await sseHandler(ctx);\n } catch (error) {\n // 如果是 VafastError,重新抛出让错误处理中间件处理\n if (error instanceof VafastError) {\n throw error;\n }\n if (error instanceof Error && error.message.includes(\"验证失败\")) {\n return json({ code: 400, message: error.message }, 400);\n }\n return json({ code: 500, message: error instanceof Error ? error.message : \"未知错误\" }, 500);\n }\n };\n}\n\n// ============= 判断路由类型 =============\n\n/** 判断是否为叶子路由 */\nfunction isLeafRoute(route: RouteConfigResult): route is LeafRouteConfig {\n return \"method\" in route && \"handler\" in route;\n}\n\n/** 判断是否为嵌套路由 */\nfunction isNestedRoute(route: RouteConfigResult): route is NestedRouteConfig {\n return \"children\" in route;\n}\n\n// ============= defineRoute 函数(支持重载) =============\n\n/**\n * 定义叶子路由(有 method 和 handler),支持中间件类型推断和显式上下文类型\n *\n * @example\n * ```typescript\n * // 方式1:通过中间件自动推断上下文\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * middleware: [authMiddleware],\n * handler: ({ user }) => { ... } // user 来自 authMiddleware\n * })\n *\n * // 方式2:显式声明上下文类型(用于父级中间件注入的场景)\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * context: {} as { userInfo: UserInfo },\n * handler: ({ userInfo }) => { ... } // userInfo 有类型\n * })\n * ```\n */\nexport function defineRoute<\n const TSchema extends RouteSchema,\n TReturn,\n const TMiddleware extends readonly AnyMiddleware[],\n TContext extends object = object,\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string\n>(config: {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** 是否为 SSE 端点,设置为 true 时 handler 应返回 AsyncGenerator */\n readonly sse?: boolean;\n /** 显式声明上下文类型(用于父级中间件注入的场景) */\n readonly context?: TContext;\n readonly handler: (\n ctx: HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>\n ) => TReturn | Promise<TReturn> | AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}): LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware>;\n\n/**\n * 定义嵌套路由(有 children),支持中间件类型推断\n */\nexport function defineRoute<\n const TMiddleware extends readonly AnyMiddleware[],\n TPath extends string = string\n>(config: {\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly middleware?: TMiddleware;\n readonly children: ReadonlyArray<RouteConfigResult>;\n}): NestedRouteConfig<TPath, TMiddleware>;\n\n/**\n * defineRoute 实现\n */\nexport function defineRoute(config: {\n readonly method?: HTTPMethod;\n readonly path: string;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: RouteSchema;\n readonly sse?: boolean;\n readonly context?: object;\n readonly handler?: (ctx: HandlerContext<RouteSchema>) => unknown | Promise<unknown> | AsyncGenerator<unknown, void, unknown>;\n readonly middleware?: readonly AnyMiddleware[];\n readonly children?: ReadonlyArray<RouteConfigResult>;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}): RouteConfigResult {\n return config as RouteConfigResult;\n}\n\n// ============= withContext 工厂函数 =============\n\n/**\n * 创建带预设上下文类型的路由定义器\n *\n * 用于父级中间件注入上下文的场景,定义一次,多处复用\n *\n * @example\n * ```typescript\n * // 1. 在 middleware/index.ts 中定义\n * export const defineAuthRoute = withContext<{ userInfo: UserInfo }>()\n *\n * // 2. 在路由文件中使用\n * defineAuthRoute({\n * method: 'GET',\n * path: '/profile',\n * handler: ({ userInfo }) => {\n * // userInfo 自动有类型!\n * return { id: userInfo.id }\n * }\n * })\n * ```\n */\n/**\n * 带扩展类型的路由定义器\n *\n * @typeParam TContext - Handler 上下文类型(如 { userInfo: UserInfo })\n * @typeParam TExtensions - 路由扩展字段类型(如 { webhook?: boolean })\n *\n * @example\n * ```typescript\n * // 定义扩展类型\n * interface WebhookExtension {\n * webhook?: boolean | { eventKey?: string }\n * }\n *\n * // 使用扩展\n * const defineRoute = withContext<MyContext, WebhookExtension>()\n * defineRoute({\n * method: 'POST',\n * path: '/create',\n * webhook: true, // TypeScript 严格检查\n * handler: ...\n * })\n * ```\n */\n/** withContext Handler 上下文类型 */\ntype WithContextHandlerCtx<TSchema extends RouteSchema, TContext extends object, TMiddleware extends readonly AnyMiddleware[]> =\n HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>;\n\n/** withContext 支持的 Handler 类型(普通函数 + SSE Generator) */\ntype WithContextHandler<TSchema extends RouteSchema, TContext extends object, TMiddleware extends readonly AnyMiddleware[], TReturn> =\n (ctx: WithContextHandlerCtx<TSchema, TContext, TMiddleware>) =>\n TReturn | Promise<TReturn> | AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n\nexport function withContext<\n TContext extends object,\n TExtensions extends object = object\n>() {\n return <\n const TSchema extends RouteSchema,\n TReturn,\n const TMiddleware extends readonly AnyMiddleware[],\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string\n >(config: {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** \n * 是否为 SSE 端点\n * 设置为 true 时,handler 应返回 AsyncGenerator\n */\n readonly sse?: boolean;\n /** Handler 支持两种写法:普通函数 或 SSE Generator(需配合 sse: true) */\n readonly handler: WithContextHandler<TSchema, TContext, TMiddleware, TReturn>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n } & TExtensions): LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware> => {\n return config as unknown as LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware>;\n };\n}\n\n// ============= 扁平化嵌套路由 =============\n\n/** 父级路由信息 */\ninterface ParentRouteInfo {\n /** 父级路由路径 */\n path: string;\n /** 父级路由名称 */\n name?: string;\n /** 父级路由描述 */\n description?: string;\n}\n\n/**\n * 递归扁平化路由,合并路径和中间件\n */\nfunction flattenRoutes(\n routes: ReadonlyArray<RouteConfigResult>,\n parentPath: string = \"\",\n parentMiddleware: readonly AnyMiddleware[] = [],\n parent?: ParentRouteInfo\n): ProcessedRoute[] {\n const result: ProcessedRoute[] = [];\n\n for (const route of routes) {\n const fullPath = parentPath + route.path;\n const mergedMiddleware = [...parentMiddleware, ...(route.middleware || [])];\n\n if (isLeafRoute(route)) {\n // SSE 检测:只通过显式 sse: true 声明\n const routeWithSSE = route as typeof route & { sse?: boolean };\n const isSSE = routeWithSSE.sse === true;\n \n // 基础属性\n const processed: ProcessedRoute = {\n method: route.method,\n path: fullPath,\n name: route.name,\n description: route.description,\n schema: route.schema,\n sse: isSSE || undefined, // SSE 标记\n handler: isSSE \n ? wrapSSEHandler(route.schema, wrapGeneratorToSSEHandler(route.handler as (ctx: HandlerContext<RouteSchema>) => AsyncGenerator<SSEEventType<unknown>, void, unknown>))\n : wrapHandler(route.schema, route.handler as (ctx: HandlerContext<RouteSchema>) => unknown),\n middleware: mergedMiddleware.length > 0 ? mergedMiddleware : undefined,\n docs: route.docs,\n };\n \n // 添加父级路由信息\n if (parent) {\n processed.parent = parent;\n }\n // 复制扩展属性(如 webhook, permission 等)\n const knownKeys = ['method', 'path', 'name', 'description', 'schema', 'handler', 'middleware', 'docs'];\n for (const key of Object.keys(route)) {\n if (!knownKeys.includes(key)) {\n processed[key] = (route as unknown as Record<string, unknown>)[key];\n }\n }\n result.push(processed);\n } else if (isNestedRoute(route)) {\n // 传递当前路由信息作为子路由的 parent\n const currentParent: ParentRouteInfo = {\n path: fullPath,\n name: route.name,\n description: route.description,\n };\n result.push(...flattenRoutes(route.children, fullPath, mergedMiddleware, currentParent));\n }\n }\n\n return result;\n}\n\n// ============= defineRoutes 函数 =============\n\n/** 带原始类型信息的路由数组 */\nexport type RoutesWithSource<T extends readonly RouteConfigResult[]> = ProcessedRoute[] & { __source: T };\n\n/**\n * 定义路由数组,支持嵌套路由\n *\n * 使用 `const T` 泛型自动保留字面量类型,无需手动添加 `as const`\n *\n * @example\n * ```typescript\n * const routes = defineRoutes([\n * defineRoute({ method: 'GET', path: '/users', handler: ... }),\n * defineRoute({ method: 'POST', path: '/users', handler: ... }),\n * ])\n *\n * // 类型推断自动工作,无需 as const\n * type Api = InferEden<typeof routes>\n * ```\n */\nexport function defineRoutes<const T extends readonly RouteConfigResult[]>(\n routes: T\n): RoutesWithSource<T> {\n const processed = flattenRoutes(routes);\n // 附加原始类型信息(仅用于类型推断,运行时不使用)\n return Object.assign(processed, { __source: routes }) as RoutesWithSource<T>;\n}\n\n// ============= 用于 API Client 的类型推断 =============\n\n/** 可推断的路由类型(供 vafast-api-client 使用) */\nexport type InferableRoute<\n TMethod extends string = string,\n TPath extends string = string,\n TReturn = unknown,\n TSchema extends RouteSchema = RouteSchema\n> = {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n readonly handler: {\n __returnType: TReturn;\n __schema: TSchema;\n };\n readonly middleware?: ReadonlyArray<AnyMiddleware>;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"defineRoute.mjs","names":[],"sources":["../src/defineRoute.ts"],"sourcesContent":["/**\n * 路由定义 - Schema 在路由级别定义,支持嵌套路由和中间件类型推断\n *\n * @example\n * ```typescript\n * // 定义带类型的中间件(函数式风格,通过 next 传递上下文)\n * const authMiddleware = defineMiddleware<{ user: User }>((req, next) => {\n * const user = getUser(req)\n * return next({ user }) // 通过 next 参数传递上下文\n * })\n *\n * // 路由自动推断中间件注入的类型\n * const routes = defineRoutes([\n * defineRoute({\n * path: '/api',\n * middleware: [authMiddleware],\n * children: [\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * handler: ({ user }) => ({ name: user.name }) // ✅ user 有类型\n * })\n * ]\n * })\n * ])\n * ```\n */\n\nimport type { TSchema, Static } from \"@sinclair/typebox\";\nimport { parseBody, parseQuery, parseHeaders, parseCookies } from \"./utils/parsers\";\nimport { validateAllSchemas, precompileSchemas } from \"./utils/validators/validators\";\nimport { json } from \"./utils/response\";\nimport { VafastError } from \"./middleware\";\nimport { isValidationFailedError } from \"./utils/validators/validation-errors\";\n\n// ============= SSE 事件类型(内联定义,避免循环依赖) =============\n\n/** SSE 事件 */\nexport interface SSEEventType<T = unknown> {\n event?: string;\n data: T;\n id?: string;\n retry?: number;\n}\n\n/** SSE Generator 类型 */\nexport type SSEGeneratorType<TSchema extends RouteSchema = RouteSchema> = (\n ctx: HandlerContext<TSchema>\n) => AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n\n// ============= Schema 类型 =============\n\n/** 路由 Schema 配置 */\nexport interface RouteSchema {\n body?: TSchema;\n query?: TSchema;\n params?: TSchema;\n headers?: TSchema;\n cookies?: TSchema;\n /** 响应类型 schema(用于类型同步,运行时不做校验) */\n response?: TSchema;\n}\n\n/** 从 Schema 推断类型 */\ntype InferSchemaType<T extends RouteSchema> = {\n body: T[\"body\"] extends TSchema ? Static<T[\"body\"]> : unknown;\n query: T[\"query\"] extends TSchema ? Static<T[\"query\"]> : Record<string, string>;\n params: T[\"params\"] extends TSchema ? Static<T[\"params\"]> : Record<string, string>;\n headers: T[\"headers\"] extends TSchema ? Static<T[\"headers\"]> : Record<string, string>;\n cookies: T[\"cookies\"] extends TSchema ? Static<T[\"cookies\"]> : Record<string, string>;\n};\n\n// ============= 中间件类型系统 =============\n\n/** 带类型标记的中间件 */\nexport interface TypedMiddleware<TContext extends object = object> {\n (req: Request, next: (ctx?: TContext) => Promise<Response>): Response | Promise<Response>;\n /** 类型标记(仅编译时使用) */\n __context?: TContext;\n}\n\n/** 普通中间件(无类型注入) */\ntype PlainMiddleware = (req: Request, next: () => Promise<Response>) => Response | Promise<Response>;\n\n/** 任意中间件类型 */\ntype AnyMiddleware = TypedMiddleware<object> | PlainMiddleware;\n\n/** 从中间件提取上下文类型 */\ntype ExtractMiddlewareContext<T> = T extends TypedMiddleware<infer C> ? C : object;\n\n/** 合并中间件数组的上下文类型 */\ntype MergeMiddlewareContexts<T extends readonly unknown[]> =\n T extends readonly [infer First, ...infer Rest]\n ? ExtractMiddlewareContext<First> & MergeMiddlewareContexts<Rest>\n : object;\n\n// ============= Handler 上下文 =============\n\n/** Handler 上下文(包含 schema 推断) */\nexport interface HandlerContext<TSchema extends RouteSchema = RouteSchema> {\n req: Request;\n body: InferSchemaType<TSchema>[\"body\"];\n query: InferSchemaType<TSchema>[\"query\"];\n params: InferSchemaType<TSchema>[\"params\"];\n headers: InferSchemaType<TSchema>[\"headers\"];\n cookies: InferSchemaType<TSchema>[\"cookies\"];\n}\n\n/** Handler 上下文(带中间件注入的额外类型) */\ntype HandlerContextWithExtra<TSchema extends RouteSchema, TExtra> =\n HandlerContext<TSchema> & TExtra;\n\n// ============= 路由配置类型 =============\n\n/** HTTP 方法 */\ntype HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"OPTIONS\" | \"HEAD\";\n\n/** Handler 上下文类型(带中间件扩展) */\ntype HandlerCtx<TSchema extends RouteSchema, TMiddleware extends readonly AnyMiddleware[]> =\n HandlerContextWithExtra<TSchema, MergeMiddlewareContexts<TMiddleware>>;\n\n/** 普通 Handler 类型 */\ntype NormalHandler<TSchema extends RouteSchema, TReturn, TMiddleware extends readonly AnyMiddleware[]> = (\n ctx: HandlerCtx<TSchema, TMiddleware>\n) => TReturn | Promise<TReturn>;\n\n/** SSE Generator Handler 类型(sse: true 时直接写 async function*) */\ntype SSEHandler<TSchema extends RouteSchema, TMiddleware extends readonly AnyMiddleware[]> = (\n ctx: HandlerCtx<TSchema, TMiddleware>\n) => AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n\n/** 叶子路由配置(有 method 和 handler) */\nexport interface LeafRouteConfig<\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string,\n TSchema extends RouteSchema = RouteSchema,\n TReturn = unknown,\n TMiddleware extends readonly AnyMiddleware[] = readonly AnyMiddleware[]\n> {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** \n * 是否为 SSE 端点(显式声明,推荐)\n * \n * 设置为 true 时,handler 应返回 AsyncGenerator:\n * ```typescript\n * sse: true,\n * handler: async function* (ctx) { yield { data: ... } }\n * ```\n */\n readonly sse?: boolean;\n /** \n * Handler 支持两种写法:\n * 1. 普通函数: `async (ctx) => { return result }`\n * 2. SSE Generator(需配合 sse: true): `async function* (ctx) { yield { data: ... } }`\n */\n readonly handler: NormalHandler<TSchema, TReturn, TMiddleware> | SSEHandler<TSchema, TMiddleware>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}\n\n/** 嵌套路由配置(有 children,无 method 和 handler) */\nexport interface NestedRouteConfig<\n TPath extends string = string,\n TMiddleware extends readonly AnyMiddleware[] = readonly AnyMiddleware[]\n> {\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly middleware?: TMiddleware;\n readonly children: ReadonlyArray<RouteConfigResult>;\n}\n\n/** defineRoute 返回的类型 */\ntype RouteConfigResult =\n | LeafRouteConfig<HTTPMethod, string, RouteSchema, unknown, readonly AnyMiddleware[]>\n | NestedRouteConfig<string, readonly AnyMiddleware[]>;\n\n/** 处理后的扁平路由 */\nexport interface ProcessedRoute {\n method: HTTPMethod;\n path: string;\n name?: string;\n description?: string;\n schema?: RouteSchema;\n /** 是否为 SSE 端点 */\n sse?: boolean;\n handler: (req: Request) => Promise<Response>;\n middleware?: readonly AnyMiddleware[];\n docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n /** 允许任意扩展(兼容 Route 类型) */\n [key: string]: unknown;\n}\n\n/** Route 类型别名(便于用户使用) */\nexport type Route = ProcessedRoute;\n\n// ============= defineMiddleware =============\n\n/**\n * 定义带类型的中间件(函数式风格)\n *\n * 通过 next() 参数传递上下文,更符合函数式编程风格\n *\n * @example\n * ```typescript\n * type AuthContext = { user: { id: string; name: string } }\n *\n * const authMiddleware = defineMiddleware<AuthContext>((req, next) => {\n * const user = getUserFromToken(req)\n * return next({ user }) // 通过 next 传递上下文\n * })\n * ```\n */\nexport function defineMiddleware<TContext extends object = object>(\n handler: (\n req: Request,\n next: (ctx?: TContext) => Promise<Response>\n ) => Promise<Response>\n): TypedMiddleware<TContext> {\n // 包装成标准中间件签名\n const middleware = ((req: Request, originalNext: () => Promise<Response>) => {\n // 包装 next,接收上下文参数并存储到 req.__locals\n const nextWithContext = (ctx?: TContext): Promise<Response> => {\n if (ctx) {\n const target = req as unknown as { __locals?: object };\n target.__locals = { ...(target.__locals || {}), ...ctx };\n }\n return originalNext();\n };\n return handler(req, nextWithContext);\n }) as TypedMiddleware<TContext>;\n\n return middleware;\n}\n\n// ============= 响应处理 =============\n\n/** 自动转换返回值为 Response */\nfunction autoResponse(result: unknown): Response {\n if (result instanceof Response) return result;\n if (result === null || result === undefined) return new Response(null, { status: 204 });\n if (typeof result === \"string\") {\n return new Response(result, { headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } });\n }\n if (typeof result === \"number\" || typeof result === \"boolean\") {\n return new Response(String(result), { headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } });\n }\n if (typeof result === \"object\") {\n const obj = result as Record<string, unknown>;\n if (\"data\" in obj && (\"status\" in obj || \"headers\" in obj)) {\n const { data, status = 200, headers = {} } = obj;\n if (data === null || data === undefined) {\n return new Response(null, { status: status === 200 ? 204 : (status as number), headers: headers as HeadersInit });\n }\n return json(data, status as number, headers as Record<string, string>);\n }\n return json(result);\n }\n return new Response(null, { status: 204 });\n}\n\n/**\n * 构建 HandlerContext(公共逻辑,供普通 handler 和 SSE handler 复用)\n */\nasync function buildHandlerContext<TSchema extends RouteSchema>(\n req: Request,\n schema: TSchema | undefined\n): Promise<HandlerContext<TSchema>> {\n const query = parseQuery(req);\n const headers = parseHeaders(req);\n const cookies = parseCookies(req);\n const params = ((req as unknown as Record<string, unknown>).params as Record<string, string>) || {};\n\n let body: unknown = undefined;\n if (req.method !== \"GET\" && req.method !== \"HEAD\") {\n try {\n body = await parseBody(req);\n } catch {\n // 忽略解析错误\n }\n }\n\n const data = { body, query, params, headers, cookies };\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n validateAllSchemas(schema, data);\n }\n\n // 获取中间件注入的上下文\n const extraCtx = (req as unknown as { __locals?: unknown }).__locals || {};\n\n return {\n req,\n body: body as HandlerContext<TSchema>[\"body\"],\n query: query as HandlerContext<TSchema>[\"query\"],\n params: params as HandlerContext<TSchema>[\"params\"],\n headers: headers as HandlerContext<TSchema>[\"headers\"],\n cookies: cookies as HandlerContext<TSchema>[\"cookies\"],\n ...extraCtx,\n } as HandlerContext<TSchema>;\n}\n\n/** 创建包装后的 handler(普通路由) */\nfunction wrapHandler<TSchema extends RouteSchema>(\n schema: TSchema | undefined,\n userHandler: (ctx: HandlerContext<TSchema>) => unknown | Promise<unknown>\n): (req: Request) => Promise<Response> {\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n precompileSchemas(schema);\n }\n\n return async (req: Request): Promise<Response> => {\n try {\n const ctx = await buildHandlerContext(req, schema);\n const result = await userHandler(ctx);\n return autoResponse(result);\n } catch (error) {\n if (error instanceof VafastError || isValidationFailedError(error)) {\n throw error;\n }\n return json({ code: 500, message: error instanceof Error ? error.message : \"未知错误\" }, 500);\n }\n };\n}\n\n/**\n * SSE Handler 函数类型\n * \n * SSE handler 与普通 handler 使用统一的上下文模型,接收完整的 HandlerContext。\n * 框架自动完成:body 解析、schema 验证、中间件上下文注入。\n * SSE handler 只需关注流式响应逻辑,返回 SSE Stream Response。\n */\ntype SSEHandlerFn<TSchema extends RouteSchema = RouteSchema> = \n (ctx: HandlerContext<TSchema>) => Promise<Response>;\n\n/**\n * SSE 元数据接口(用于高级场景)\n */\nexport interface SSEMeta {\n /** SSE 事件名称 */\n event?: string;\n /** SSE 事件 ID */\n id?: string;\n /** SSE 重试间隔(毫秒) */\n retry?: number;\n}\n\n/**\n * 带元数据的 SSE 事件(高级用法)\n */\nexport interface SSEEventWithMeta<T = unknown> {\n /** SSE 元数据标记 */\n __sse__: SSEMeta;\n /** 事件数据 */\n data: T;\n}\n\n/**\n * 创建带元数据的 SSE 事件\n * \n * @example\n * // 设置事件名称\n * yield sse({ event: 'status' }, { ready: true })\n * \n * // 设置 ID(支持断线重连)\n * yield sse({ event: 'update', id: '42' }, { value: 1 })\n * \n * // 设置重试间隔\n * yield sse({ retry: 5000 }, 'reconnect hint')\n */\nexport function sse<T>(meta: SSEMeta, data: T): SSEEventWithMeta<T> {\n return { __sse__: meta, data };\n}\n\n/**\n * 检查是否是带元数据的 SSE 事件\n */\nfunction isSSEEventWithMeta(event: unknown): event is SSEEventWithMeta {\n return (\n event !== null &&\n typeof event === 'object' &&\n '__sse__' in event &&\n 'data' in event\n );\n}\n\n/**\n * 格式化 SSE 事件为字符串\n * \n * 支持两种用法:\n * 1. 简单模式(推荐):yield anyData → 自动包装为 data\n * 2. 高级模式:yield { __sse__: { event, id, retry }, data } → 完整 SSE 控制\n */\nfunction formatSSEEvent(event: unknown): string {\n const lines: string[] = [];\n let data: unknown;\n\n if (isSSEEventWithMeta(event)) {\n // 高级模式:用户提供了 SSE 元数据\n const meta = event.__sse__;\n if (meta.id !== undefined) lines.push(`id: ${meta.id}`);\n if (meta.event !== undefined) lines.push(`event: ${meta.event}`);\n if (meta.retry !== undefined) lines.push(`retry: ${meta.retry}`);\n data = event.data;\n } else {\n // 简单模式:直接把 event 作为 data\n data = event;\n }\n \n const dataStr = typeof data === 'string' ? data : JSON.stringify(data);\n for (const line of dataStr.split('\\n')) {\n lines.push(`data: ${line}`);\n }\n return lines.join('\\n') + '\\n\\n';\n}\n\n/**\n * 将 AsyncGenerator 包装为 SSE Handler\n * \n * 支持用户直接写 `async function* (ctx) { yield anyData }` \n * 数据会自动包装为 SSE data 字段发送\n */\nfunction wrapGeneratorToSSEHandler<TSchema extends RouteSchema>(\n generator: (ctx: HandlerContext<TSchema>) => AsyncGenerator<unknown, void, unknown>\n): SSEHandlerFn<TSchema> {\n return async (ctx: HandlerContext<TSchema>): Promise<Response> => {\n const stream = new ReadableStream({\n async start(controller) {\n const encoder = new TextEncoder();\n try {\n for await (const event of generator(ctx)) {\n controller.enqueue(encoder.encode(formatSSEEvent(event)));\n }\n } catch (error) {\n // 使用高级模式发送错误事件\n const errorEvent = formatSSEEvent({\n __sse__: { event: 'error' },\n data: { error: error instanceof Error ? error.message : '未知错误' }\n });\n controller.enqueue(encoder.encode(errorEvent));\n } finally {\n controller.close();\n }\n }\n });\n\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'X-Accel-Buffering': 'no',\n }\n });\n };\n}\n\n/**\n * 创建 SSE handler 的请求包装器\n * \n * SSE handler 与普通 handler 使用相同的上下文构建流程(buildHandlerContext),\n * 确保:\n * - body/query/params 解析一致\n * - schema 验证统一\n * - 中间件注入的上下文(如 userInfo)自动可用\n * - 错误处理统一\n * \n * 唯一区别:SSE handler 返回的是 SSE Stream Response,而非普通 JSON Response\n */\nfunction wrapSSEHandler<TSchema extends RouteSchema>(\n schema: TSchema | undefined,\n sseHandler: SSEHandlerFn<TSchema>\n): (req: Request) => Promise<Response> {\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n precompileSchemas(schema);\n }\n\n return async (req: Request): Promise<Response> => {\n try {\n // 与普通 handler 使用相同的上下文构建逻辑\n const ctx = await buildHandlerContext(req, schema);\n // SSE handler 返回 SSE Stream Response\n return await sseHandler(ctx);\n } catch (error) {\n if (error instanceof VafastError || isValidationFailedError(error)) {\n throw error;\n }\n return json({ code: 500, message: error instanceof Error ? error.message : \"未知错误\" }, 500);\n }\n };\n}\n\n// ============= 判断路由类型 =============\n\n/** 判断是否为叶子路由 */\nfunction isLeafRoute(route: RouteConfigResult): route is LeafRouteConfig {\n return \"method\" in route && \"handler\" in route;\n}\n\n/** 判断是否为嵌套路由 */\nfunction isNestedRoute(route: RouteConfigResult): route is NestedRouteConfig {\n return \"children\" in route;\n}\n\n// ============= defineRoute 函数(支持重载) =============\n\n/**\n * 定义叶子路由(有 method 和 handler),支持中间件类型推断和显式上下文类型\n *\n * @example\n * ```typescript\n * // 方式1:通过中间件自动推断上下文\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * middleware: [authMiddleware],\n * handler: ({ user }) => { ... } // user 来自 authMiddleware\n * })\n *\n * // 方式2:显式声明上下文类型(用于父级中间件注入的场景)\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * context: {} as { userInfo: UserInfo },\n * handler: ({ userInfo }) => { ... } // userInfo 有类型\n * })\n * ```\n */\nexport function defineRoute<\n const TSchema extends RouteSchema,\n TReturn,\n const TMiddleware extends readonly AnyMiddleware[],\n TContext extends object = object,\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string\n>(config: {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** 是否为 SSE 端点,设置为 true 时 handler 应返回 AsyncGenerator */\n readonly sse?: boolean;\n /** 显式声明上下文类型(用于父级中间件注入的场景) */\n readonly context?: TContext;\n readonly handler: (\n ctx: HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>\n ) => TReturn | Promise<TReturn> | AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}): LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware>;\n\n/**\n * 定义嵌套路由(有 children),支持中间件类型推断\n */\nexport function defineRoute<\n const TMiddleware extends readonly AnyMiddleware[],\n TPath extends string = string\n>(config: {\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly middleware?: TMiddleware;\n readonly children: ReadonlyArray<RouteConfigResult>;\n}): NestedRouteConfig<TPath, TMiddleware>;\n\n/**\n * defineRoute 实现\n */\nexport function defineRoute(config: {\n readonly method?: HTTPMethod;\n readonly path: string;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: RouteSchema;\n readonly sse?: boolean;\n readonly context?: object;\n readonly handler?: (ctx: HandlerContext<RouteSchema>) => unknown | Promise<unknown> | AsyncGenerator<unknown, void, unknown>;\n readonly middleware?: readonly AnyMiddleware[];\n readonly children?: ReadonlyArray<RouteConfigResult>;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}): RouteConfigResult {\n return config as RouteConfigResult;\n}\n\n// ============= withContext 工厂函数 =============\n\n/**\n * 创建带预设上下文类型的路由定义器\n *\n * 用于父级中间件注入上下文的场景,定义一次,多处复用\n *\n * @example\n * ```typescript\n * // 1. 在 middleware/index.ts 中定义\n * export const defineAuthRoute = withContext<{ userInfo: UserInfo }>()\n *\n * // 2. 在路由文件中使用\n * defineAuthRoute({\n * method: 'GET',\n * path: '/profile',\n * handler: ({ userInfo }) => {\n * // userInfo 自动有类型!\n * return { id: userInfo.id }\n * }\n * })\n * ```\n */\n/**\n * 带扩展类型的路由定义器\n *\n * @typeParam TContext - Handler 上下文类型(如 { userInfo: UserInfo })\n * @typeParam TExtensions - 路由扩展字段类型(如 { webhook?: boolean })\n *\n * @example\n * ```typescript\n * // 定义扩展类型\n * interface WebhookExtension {\n * webhook?: boolean | { eventKey?: string }\n * }\n *\n * // 使用扩展\n * const defineRoute = withContext<MyContext, WebhookExtension>()\n * defineRoute({\n * method: 'POST',\n * path: '/create',\n * webhook: true, // TypeScript 严格检查\n * handler: ...\n * })\n * ```\n */\n/** withContext Handler 上下文类型 */\ntype WithContextHandlerCtx<TSchema extends RouteSchema, TContext extends object, TMiddleware extends readonly AnyMiddleware[]> =\n HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>;\n\n/** withContext 支持的 Handler 类型(普通函数 + SSE Generator) */\ntype WithContextHandler<TSchema extends RouteSchema, TContext extends object, TMiddleware extends readonly AnyMiddleware[], TReturn> =\n (ctx: WithContextHandlerCtx<TSchema, TContext, TMiddleware>) =>\n TReturn | Promise<TReturn> | AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n\nexport function withContext<\n TContext extends object,\n TExtensions extends object = object\n>() {\n return <\n const TSchema extends RouteSchema,\n TReturn,\n const TMiddleware extends readonly AnyMiddleware[],\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string\n >(config: {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** \n * 是否为 SSE 端点\n * 设置为 true 时,handler 应返回 AsyncGenerator\n */\n readonly sse?: boolean;\n /** Handler 支持两种写法:普通函数 或 SSE Generator(需配合 sse: true) */\n readonly handler: WithContextHandler<TSchema, TContext, TMiddleware, TReturn>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n } & TExtensions): LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware> => {\n return config as unknown as LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware>;\n };\n}\n\n// ============= 扁平化嵌套路由 =============\n\n/** 父级路由信息 */\ninterface ParentRouteInfo {\n /** 父级路由路径 */\n path: string;\n /** 父级路由名称 */\n name?: string;\n /** 父级路由描述 */\n description?: string;\n}\n\n/**\n * 递归扁平化路由,合并路径和中间件\n */\nfunction flattenRoutes(\n routes: ReadonlyArray<RouteConfigResult>,\n parentPath: string = \"\",\n parentMiddleware: readonly AnyMiddleware[] = [],\n parent?: ParentRouteInfo\n): ProcessedRoute[] {\n const result: ProcessedRoute[] = [];\n\n for (const route of routes) {\n const fullPath = parentPath + route.path;\n const mergedMiddleware = [...parentMiddleware, ...(route.middleware || [])];\n\n if (isLeafRoute(route)) {\n // SSE 检测:只通过显式 sse: true 声明\n const routeWithSSE = route as typeof route & { sse?: boolean };\n const isSSE = routeWithSSE.sse === true;\n \n // 基础属性\n const processed: ProcessedRoute = {\n method: route.method,\n path: fullPath,\n name: route.name,\n description: route.description,\n schema: route.schema,\n sse: isSSE || undefined, // SSE 标记\n handler: isSSE \n ? wrapSSEHandler(route.schema, wrapGeneratorToSSEHandler(route.handler as (ctx: HandlerContext<RouteSchema>) => AsyncGenerator<SSEEventType<unknown>, void, unknown>))\n : wrapHandler(route.schema, route.handler as (ctx: HandlerContext<RouteSchema>) => unknown),\n middleware: mergedMiddleware.length > 0 ? mergedMiddleware : undefined,\n docs: route.docs,\n };\n \n // 添加父级路由信息\n if (parent) {\n processed.parent = parent;\n }\n // 复制扩展属性(如 webhook, permission 等)\n const knownKeys = ['method', 'path', 'name', 'description', 'schema', 'handler', 'middleware', 'docs'];\n for (const key of Object.keys(route)) {\n if (!knownKeys.includes(key)) {\n processed[key] = (route as unknown as Record<string, unknown>)[key];\n }\n }\n result.push(processed);\n } else if (isNestedRoute(route)) {\n // 传递当前路由信息作为子路由的 parent\n const currentParent: ParentRouteInfo = {\n path: fullPath,\n name: route.name,\n description: route.description,\n };\n result.push(...flattenRoutes(route.children, fullPath, mergedMiddleware, currentParent));\n }\n }\n\n return result;\n}\n\n// ============= defineRoutes 函数 =============\n\n/** 带原始类型信息的路由数组 */\nexport type RoutesWithSource<T extends readonly RouteConfigResult[]> = ProcessedRoute[] & { __source: T };\n\n/**\n * 定义路由数组,支持嵌套路由\n *\n * 使用 `const T` 泛型自动保留字面量类型,无需手动添加 `as const`\n *\n * @example\n * ```typescript\n * const routes = defineRoutes([\n * defineRoute({ method: 'GET', path: '/users', handler: ... }),\n * defineRoute({ method: 'POST', path: '/users', handler: ... }),\n * ])\n *\n * // 类型推断自动工作,无需 as const\n * type Api = InferEden<typeof routes>\n * ```\n */\nexport function defineRoutes<const T extends readonly RouteConfigResult[]>(\n routes: T\n): RoutesWithSource<T> {\n const processed = flattenRoutes(routes);\n // 附加原始类型信息(仅用于类型推断,运行时不使用)\n return Object.assign(processed, { __source: routes }) as RoutesWithSource<T>;\n}\n\n// ============= 用于 API Client 的类型推断 =============\n\n/** 可推断的路由类型(供 vafast-api-client 使用) */\nexport type InferableRoute<\n TMethod extends string = string,\n TPath extends string = string,\n TReturn = unknown,\n TSchema extends RouteSchema = RouteSchema\n> = {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n readonly handler: {\n __returnType: TReturn;\n __schema: TSchema;\n };\n readonly middleware?: ReadonlyArray<AnyMiddleware>;\n};\n"],"mappings":"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"}
@@ -24,4 +24,4 @@ declare class DependencyManager {
24
24
  }
25
25
  //#endregion
26
26
  export { DependencyManager as t };
27
- //# sourceMappingURL=dependency-manager-mqzLAocb.d.mts.map
27
+ //# sourceMappingURL=dependency-manager-BIjSc7j3.d.mts.map
@@ -26,7 +26,8 @@ var DependencyManager = class {
26
26
  console.log(`✅ ${framework} 依赖加载完成`);
27
27
  return deps;
28
28
  } catch (error) {
29
- console.error(`❌ ${framework} 依赖加载失败:`, error);
29
+ const installHint = framework === "vue" ? "npm install vue @vue/server-renderer" : "npm install react react-dom";
30
+ console.error(`❌ ${framework} 依赖加载失败,请先安装: ${installHint}`);
30
31
  throw error;
31
32
  }
32
33
  }
@@ -57,4 +58,4 @@ var DependencyManager = class {
57
58
 
58
59
  //#endregion
59
60
  export { DependencyManager as t };
60
- //# sourceMappingURL=dependency-manager-CGMZJTer.mjs.map
61
+ //# sourceMappingURL=dependency-manager-DaDThGEc.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-manager-DaDThGEc.mjs","names":[],"sources":["../src/utils/dependency-manager.ts"],"sourcesContent":["/**\n * 依赖管理器\n * 负责按需加载和管理框架依赖\n */\nexport class DependencyManager {\n private dependencyCache = new Map<string, any>();\n\n /**\n * 按需获取框架依赖\n */\n async getFrameworkDeps(framework: \"vue\" | \"react\") {\n if (this.dependencyCache.has(framework)) {\n return this.dependencyCache.get(framework);\n }\n\n console.log(`📦 按需加载 ${framework} 依赖...`);\n\n try {\n let deps;\n switch (framework) {\n case \"vue\":\n deps = await Promise.all([\n import(\"vue\"),\n import(\"@vue/server-renderer\"),\n ]);\n break;\n case \"react\":\n deps = await Promise.all([\n import(\"react\"),\n import(\"react-dom/server\"),\n ]);\n break;\n default:\n throw new Error(`不支持的框架: ${framework}`);\n }\n\n this.dependencyCache.set(framework, deps);\n console.log(`✅ ${framework} 依赖加载完成`);\n return deps;\n } catch (error) {\n const installHint = framework === 'vue'\n ? 'npm install vue @vue/server-renderer'\n : 'npm install react react-dom'\n console.error(`❌ ${framework} 依赖加载失败,请先安装: ${installHint}`)\n throw error\n }\n }\n\n /**\n * 检测组件类型\n */\n detectComponentType(component: any): \"vue\" | \"react\" {\n // 简单的组件类型检测\n if (component.render && typeof component.render === \"function\") {\n return \"vue\";\n }\n if (component.$$typeof) {\n return \"react\";\n }\n // 默认使用 Vue\n return \"vue\";\n }\n\n /**\n * 清除缓存\n */\n clearCache(): void {\n this.dependencyCache.clear();\n console.log(\"🧹 依赖缓存已清除\");\n }\n\n /**\n * 获取缓存状态\n */\n getCacheStatus(): Record<string, boolean> {\n const status: Record<string, boolean> = {};\n for (const [framework] of this.dependencyCache) {\n status[framework] = true;\n }\n return status;\n }\n}\n"],"mappings":";;;;;AAIA,IAAa,oBAAb,MAA+B;CAC7B,AAAQ,kCAAkB,IAAI,KAAkB;;;;CAKhD,MAAM,iBAAiB,WAA4B;AACjD,MAAI,KAAK,gBAAgB,IAAI,UAAU,CACrC,QAAO,KAAK,gBAAgB,IAAI,UAAU;AAG5C,UAAQ,IAAI,WAAW,UAAU,QAAQ;AAEzC,MAAI;GACF,IAAI;AACJ,WAAQ,WAAR;IACE,KAAK;AACH,YAAO,MAAM,QAAQ,IAAI,CACvB,OAAO,QACP,OAAO,wBACR,CAAC;AACF;IACF,KAAK;AACH,YAAO,MAAM,QAAQ,IAAI,CACvB,OAAO,UACP,OAAO,oBACR,CAAC;AACF;IACF,QACE,OAAM,IAAI,MAAM,WAAW,YAAY;;AAG3C,QAAK,gBAAgB,IAAI,WAAW,KAAK;AACzC,WAAQ,IAAI,KAAK,UAAU,SAAS;AACpC,UAAO;WACA,OAAO;GACd,MAAM,cAAc,cAAc,QAC9B,yCACA;AACJ,WAAQ,MAAM,KAAK,UAAU,gBAAgB,cAAc;AAC3D,SAAM;;;;;;CAOV,oBAAoB,WAAiC;AAEnD,MAAI,UAAU,UAAU,OAAO,UAAU,WAAW,WAClD,QAAO;AAET,MAAI,UAAU,SACZ,QAAO;AAGT,SAAO;;;;;CAMT,aAAmB;AACjB,OAAK,gBAAgB,OAAO;AAC5B,UAAQ,IAAI,aAAa;;;;;CAM3B,iBAA0C;EACxC,MAAM,SAAkC,EAAE;AAC1C,OAAK,MAAM,CAAC,cAAc,KAAK,gBAC7B,QAAO,aAAa;AAEtB,SAAO"}
@@ -39,4 +39,4 @@ declare const Patterns: {
39
39
  };
40
40
  //#endregion
41
41
  export { registerFormats as i, hasFormat as n, registerFormat as r, Patterns as t };
42
- //# sourceMappingURL=formats-Ca7ASaYH.d.mts.map
42
+ //# sourceMappingURL=formats-B1vlpb1f.d.mts.map
@@ -30,4 +30,4 @@ function goAwait(promise) {
30
30
 
31
31
  //#endregion
32
32
  export { goAwait as t };
33
- //# sourceMappingURL=go-await-B1U27PgB.mjs.map
33
+ //# sourceMappingURL=go-await-C4ZdEUwY.mjs.map