vafast 0.7.0 → 0.7.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 (34) hide show
  1. package/README.md +97 -13
  2. package/dist/{defineRoute-B9VdaoQA.d.mts → defineRoute-DKVyYELW.d.mts} +36 -2
  3. package/dist/defineRoute.d.mts +2 -2
  4. package/dist/defineRoute.mjs +43 -8
  5. package/dist/defineRoute.mjs.map +1 -1
  6. package/dist/{index-CRU-u6NT.d.mts → index-BPXVOE-X.d.mts} +3 -3
  7. package/dist/index.d.mts +6 -6
  8. package/dist/index.mjs +4 -4
  9. package/dist/monitoring/index.d.mts +3 -3
  10. package/dist/monitoring/native-monitor.d.mts +3 -3
  11. package/dist/{radix-tree-CccjvyTP.mjs → radix-tree-dyn3qDFX.mjs} +35 -15
  12. package/dist/radix-tree-dyn3qDFX.mjs.map +1 -0
  13. package/dist/{route-registry-C6h13Mks.d.mts → route-registry-C2a27CuM.d.mts} +2 -2
  14. package/dist/router/index.mjs +1 -1
  15. package/dist/router/radix-tree.d.mts +11 -0
  16. package/dist/router/radix-tree.mjs +1 -1
  17. package/dist/server/index.d.mts +3 -3
  18. package/dist/server/index.mjs +2 -2
  19. package/dist/server/server-factory.d.mts +3 -3
  20. package/dist/server/server-factory.mjs +2 -2
  21. package/dist/server/server.d.mts +2 -2
  22. package/dist/server/server.mjs +1 -1
  23. package/dist/{server-DWndB63Z.mjs → server-B4YDcNJy.mjs} +2 -2
  24. package/dist/{server-DWndB63Z.mjs.map → server-B4YDcNJy.mjs.map} +1 -1
  25. package/dist/{server-CAhwnEPW.mjs → server-BNpY3NH6.mjs} +2 -2
  26. package/dist/{server-CAhwnEPW.mjs.map → server-BNpY3NH6.mjs.map} +1 -1
  27. package/dist/{server-CQ-_WgQN.d.mts → server-D3IERUlj.d.mts} +2 -2
  28. package/dist/sse-BqvrwmK6.d.mts +76 -0
  29. package/dist/utils/index.d.mts +3 -3
  30. package/dist/utils/route-registry.d.mts +2 -2
  31. package/dist/utils/sse.d.mts +2 -2
  32. package/package.json +1 -1
  33. package/dist/radix-tree-CccjvyTP.mjs.map +0 -1
  34. package/dist/sse-D77CKcsH.d.mts +0 -45
package/README.md CHANGED
@@ -474,13 +474,74 @@ export default { fetch: server.fetch };" > index.ts && bun index.ts
474
474
  ## 🎯 核心功能
475
475
 
476
476
  - ⚡ **JIT 编译验证器** - Schema 验证器编译缓存,避免重复编译
477
- - 🌲 **Radix Tree 路由** - O(k) 时间复杂度的高效路由匹配
477
+ - 🌲 **Radix Tree 路由** - O(k) 时间复杂度的高效路由匹配(详见[路由规则](#路由匹配规则))
478
478
  - 🎯 **快速请求解析** - 优化的 Query/Cookie 解析,比标准方法快 2x
479
479
  - 🔒 **端到端类型安全** - 完整的 TypeScript 类型推断
480
480
  - 🧩 **灵活中间件系统** - 可组合的中间件架构
481
481
  - 📡 **SSE 流式响应** - 内置 Server-Sent Events 支持,适用于 AI 聊天、进度更新等场景
482
482
  - 📦 **零配置** - 开箱即用,无需复杂配置
483
483
 
484
+ ### 路由匹配规则
485
+
486
+ Vafast 使用 Radix Tree 实现高效路由匹配,支持以下特性:
487
+
488
+ **1. 路由类型**
489
+
490
+ ```typescript
491
+ // 静态路由
492
+ '/users'
493
+ '/api/v1/health'
494
+
495
+ // 动态参数 (:param)
496
+ '/users/:id'
497
+ '/posts/:postId/comments/:commentId'
498
+
499
+ // 通配符 (* 或 *name)
500
+ '/files/*' // 匿名通配符,params['*']
501
+ '/static/*filepath' // 命名通配符,params['filepath']
502
+ ```
503
+
504
+ **2. 优先级规则(与 Hono/Fastify 一致)**
505
+
506
+ ```
507
+ 静态路由 > 动态参数 > 通配符
508
+ ```
509
+
510
+ ```typescript
511
+ // 注册顺序不影响优先级
512
+ router.register('GET', '/users/:id', dynamicHandler);
513
+ router.register('GET', '/users/admin', staticHandler); // 后注册
514
+
515
+ // 匹配结果
516
+ GET /users/admin → staticHandler ✅ 静态优先
517
+ GET /users/123 → dynamicHandler
518
+ ```
519
+
520
+ **3. 同一位置支持不同参数名**
521
+
522
+ 不同路由在同一位置可以使用不同的参数名,每个路由独立返回其定义的参数名:
523
+
524
+ ```typescript
525
+ // 同一位置(/sessions/ 后)使用不同参数名
526
+ router.register('PUT', '/sessions/:id', updateHandler);
527
+ router.register('GET', '/sessions/:sessionId/messages', messagesHandler);
528
+
529
+ // 每个路由返回各自定义的参数名
530
+ PUT /sessions/123 → params = { id: '123' }
531
+ GET /sessions/456/messages → params = { sessionId: '456' }
532
+
533
+ // CRUD 场景完全支持
534
+ router.register('GET', '/users/:userId', getHandler);
535
+ router.register('PUT', '/users/:id', updateHandler);
536
+ router.register('DELETE', '/users/:uid', deleteHandler);
537
+
538
+ GET /users/1 → { userId: '1' }
539
+ PUT /users/2 → { id: '2' }
540
+ DELETE /users/3 → { uid: '3' }
541
+ ```
542
+
543
+ > 💡 参数名冲突时会输出警告(建议保持一致),但不影响功能。
544
+
484
545
  ### 返回值与错误处理
485
546
 
486
547
  Vafast 提供简洁、对称的响应 API:
@@ -528,37 +589,60 @@ defineRoute({
528
589
 
529
590
  ### SSE 流式响应
530
591
 
531
- 通过 `sse: true` 显式声明 SSE 端点,适用于 AI 聊天、进度更新等场景:
592
+ 通过 `sse: true` 显式声明 SSE 端点,适用于 AI 聊天、进度更新等场景。
593
+
594
+ **简单模式(推荐)** - 直接 yield 任意数据:
532
595
 
533
596
  ```typescript
534
597
  import { defineRoute, defineRoutes, Type } from 'vafast'
535
598
 
536
599
  const routes = defineRoutes([
600
+ // AI 聊天场景
601
+ defineRoute({
602
+ method: 'POST',
603
+ path: '/chat/stream',
604
+ sse: true,
605
+ schema: { body: Type.Object({ message: Type.String() }) },
606
+ handler: async function* ({ body }) {
607
+ // 直接 yield 数据,框架自动包装为 SSE data 字段
608
+ yield { type: 'start', input: body.message }
609
+
610
+ for await (const chunk of aiStream(body.message)) {
611
+ yield { type: 'text_delta', content: chunk }
612
+ }
613
+
614
+ yield { type: 'done', usage: { tokens: 100 } }
615
+ },
616
+ }),
617
+
618
+ // 进度更新场景
537
619
  defineRoute({
538
620
  method: 'GET',
539
621
  path: '/tasks/:taskId/progress',
540
- sse: true, // 显式声明 SSE 端点
622
+ sse: true,
541
623
  schema: { params: Type.Object({ taskId: Type.String() }) },
542
624
  handler: async function* ({ params }) {
543
- yield { event: 'start', data: { taskId: params.taskId } }
544
-
545
625
  for (let i = 0; i <= 100; i += 10) {
546
- yield { data: { progress: i } }
626
+ yield { progress: i, taskId: params.taskId }
547
627
  await new Promise(r => setTimeout(r, 100))
548
628
  }
549
-
550
- yield { event: 'complete', data: { message: 'Done!' } }
551
629
  },
552
630
  }),
553
631
  ])
554
632
  ```
555
633
 
556
- 客户端使用:
634
+ **高级模式** - 需要设置 SSE event/id/retry 时使用 `sse()` 函数:
557
635
 
558
- ```javascript
559
- const eventSource = new EventSource('/tasks/123/progress')
560
- eventSource.onmessage = (e) => console.log(JSON.parse(e.data))
561
- eventSource.addEventListener('complete', () => eventSource.close())
636
+ ```typescript
637
+ import { sse } from 'vafast'
638
+
639
+ handler: async function* () {
640
+ // 带事件名称
641
+ yield sse({ event: 'status' }, { ready: true })
642
+
643
+ // 带事件 ID 和重试间隔
644
+ yield sse({ event: 'update', id: '42', retry: 5000 }, { value: 1 })
645
+ }
562
646
  ```
563
647
 
564
648
  > 📖 详细文档见 [docs/sse.md](./docs/sse.md)
@@ -139,6 +139,40 @@ type Route = ProcessedRoute;
139
139
  * ```
140
140
  */
141
141
  declare function defineMiddleware<TContext extends object = object>(handler: (req: Request, next: (ctx?: TContext) => Promise<Response>) => Promise<Response>): TypedMiddleware<TContext>;
142
+ /**
143
+ * SSE 元数据接口(用于高级场景)
144
+ */
145
+ interface SSEMeta {
146
+ /** SSE 事件名称 */
147
+ event?: string;
148
+ /** SSE 事件 ID */
149
+ id?: string;
150
+ /** SSE 重试间隔(毫秒) */
151
+ retry?: number;
152
+ }
153
+ /**
154
+ * 带元数据的 SSE 事件(高级用法)
155
+ */
156
+ interface SSEEventWithMeta<T = unknown> {
157
+ /** SSE 元数据标记 */
158
+ __sse__: SSEMeta;
159
+ /** 事件数据 */
160
+ data: T;
161
+ }
162
+ /**
163
+ * 创建带元数据的 SSE 事件
164
+ *
165
+ * @example
166
+ * // 设置事件名称
167
+ * yield sse({ event: 'status' }, { ready: true })
168
+ *
169
+ * // 设置 ID(支持断线重连)
170
+ * yield sse({ event: 'update', id: '42' }, { value: 1 })
171
+ *
172
+ * // 设置重试间隔
173
+ * yield sse({ retry: 5000 }, 'reconnect hint')
174
+ */
175
+ declare function sse<T>(meta: SSEMeta, data: T): SSEEventWithMeta<T>;
142
176
  /**
143
177
  * 定义叶子路由(有 method 和 handler),支持中间件类型推断和显式上下文类型
144
178
  *
@@ -292,5 +326,5 @@ type InferableRoute<TMethod extends string = string, TPath extends string = stri
292
326
  readonly middleware?: ReadonlyArray<AnyMiddleware>;
293
327
  };
294
328
  //#endregion
295
- export { ProcessedRoute as a, RoutesWithSource as c, TypedMiddleware as d, defineMiddleware as f, withContext as h, NestedRouteConfig as i, SSEEventType as l, defineRoutes as m, InferableRoute as n, Route as o, defineRoute as p, LeafRouteConfig as r, RouteSchema as s, HandlerContext as t, SSEGeneratorType as u };
296
- //# sourceMappingURL=defineRoute-B9VdaoQA.d.mts.map
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-DKVyYELW.d.mts.map
@@ -1,2 +1,2 @@
1
- import { a as ProcessedRoute, c as RoutesWithSource, d as TypedMiddleware, f as defineMiddleware, h as withContext, i as NestedRouteConfig, l as SSEEventType, m as defineRoutes, n as InferableRoute, o as Route, p as defineRoute, r as LeafRouteConfig, s as RouteSchema, t as HandlerContext, u as SSEGeneratorType } from "./defineRoute-B9VdaoQA.mjs";
2
- export { HandlerContext, InferableRoute, LeafRouteConfig, NestedRouteConfig, ProcessedRoute, Route, RouteSchema, RoutesWithSource, SSEEventType, SSEGeneratorType, TypedMiddleware, defineMiddleware, defineRoute, defineRoutes, withContext };
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-DKVyYELW.mjs";
2
+ export { HandlerContext, InferableRoute, LeafRouteConfig, NestedRouteConfig, ProcessedRoute, Route, RouteSchema, RoutesWithSource, SSEEventType, SSEEventWithMeta, SSEGeneratorType, SSEMeta, TypedMiddleware, defineMiddleware, defineRoute, defineRoutes, sse, withContext };
@@ -105,21 +105,56 @@ function wrapHandler(schema, userHandler) {
105
105
  };
106
106
  }
107
107
  /**
108
- * 格式化 SSE 事件为字符串(内联,避免循环依赖)
108
+ * 创建带元数据的 SSE 事件
109
+ *
110
+ * @example
111
+ * // 设置事件名称
112
+ * yield sse({ event: 'status' }, { ready: true })
113
+ *
114
+ * // 设置 ID(支持断线重连)
115
+ * yield sse({ event: 'update', id: '42' }, { value: 1 })
116
+ *
117
+ * // 设置重试间隔
118
+ * yield sse({ retry: 5000 }, 'reconnect hint')
119
+ */
120
+ function sse(meta, data) {
121
+ return {
122
+ __sse__: meta,
123
+ data
124
+ };
125
+ }
126
+ /**
127
+ * 检查是否是带元数据的 SSE 事件
128
+ */
129
+ function isSSEEventWithMeta(event) {
130
+ return event !== null && typeof event === "object" && "__sse__" in event && "data" in event;
131
+ }
132
+ /**
133
+ * 格式化 SSE 事件为字符串
134
+ *
135
+ * 支持两种用法:
136
+ * 1. 简单模式(推荐):yield anyData → 自动包装为 data
137
+ * 2. 高级模式:yield { __sse__: { event, id, retry }, data } → 完整 SSE 控制
109
138
  */
110
139
  function formatSSEEvent(event) {
111
140
  const lines = [];
112
- if (event.id !== void 0) lines.push(`id: ${event.id}`);
113
- if (event.event !== void 0) lines.push(`event: ${event.event}`);
114
- if (event.retry !== void 0) lines.push(`retry: ${event.retry}`);
115
- const dataStr = typeof event.data === "string" ? event.data : JSON.stringify(event.data);
141
+ let data;
142
+ if (isSSEEventWithMeta(event)) {
143
+ const meta = event.__sse__;
144
+ if (meta.id !== void 0) lines.push(`id: ${meta.id}`);
145
+ if (meta.event !== void 0) lines.push(`event: ${meta.event}`);
146
+ if (meta.retry !== void 0) lines.push(`retry: ${meta.retry}`);
147
+ data = event.data;
148
+ } else data = event;
149
+ const dataStr = typeof data === "string" ? data : JSON.stringify(data);
116
150
  for (const line of dataStr.split("\n")) lines.push(`data: ${line}`);
117
151
  return lines.join("\n") + "\n\n";
118
152
  }
119
153
  /**
120
154
  * 将 AsyncGenerator 包装为 SSE Handler
121
155
  *
122
- * 支持用户直接写 `async function* (ctx) { yield ... }` 而无需 createSSEHandler
156
+ * 支持用户直接写 `async function* (ctx) { yield anyData }`
157
+ * 数据会自动包装为 SSE data 字段发送
123
158
  */
124
159
  function wrapGeneratorToSSEHandler(generator) {
125
160
  return async (ctx) => {
@@ -129,7 +164,7 @@ function wrapGeneratorToSSEHandler(generator) {
129
164
  for await (const event of generator(ctx)) controller.enqueue(encoder.encode(formatSSEEvent(event)));
130
165
  } catch (error) {
131
166
  const errorEvent = formatSSEEvent({
132
- event: "error",
167
+ __sse__: { event: "error" },
133
168
  data: { error: error instanceof Error ? error.message : "未知错误" }
134
169
  });
135
170
  controller.enqueue(encoder.encode(errorEvent));
@@ -261,5 +296,5 @@ function defineRoutes(routes) {
261
296
  }
262
297
 
263
298
  //#endregion
264
- export { defineMiddleware, defineRoute, defineRoutes, withContext };
299
+ export { defineMiddleware, defineRoute, defineRoutes, sse, withContext };
265
300
  //# sourceMappingURL=defineRoute.mjs.map
@@ -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 类型(直接写 async function*,无需 createSSEHandler 包装) */\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 */\nfunction formatSSEEvent(event: SSEEventType): string {\n const lines: string[] = [];\n if (event.id !== undefined) lines.push(`id: ${event.id}`);\n if (event.event !== undefined) lines.push(`event: ${event.event}`);\n if (event.retry !== undefined) lines.push(`retry: ${event.retry}`);\n \n const dataStr = typeof event.data === 'string' ? event.data : JSON.stringify(event.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 ... }` 而无需 createSSEHandler\n */\nfunction wrapGeneratorToSSEHandler<TSchema extends RouteSchema>(\n generator: (ctx: HandlerContext<TSchema>) => AsyncGenerator<SSEEventType<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 const errorEvent = formatSSEEvent({\n 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>) => TReturn | Promise<TReturn>)\n | ((ctx: WithContextHandlerCtx<TSchema, TContext, TMiddleware>) => 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\";\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 类型(直接写 async function*,无需 createSSEHandler 包装) */\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>) => TReturn | Promise<TReturn>)\n | ((ctx: WithContextHandlerCtx<TSchema, TContext, TMiddleware>) => 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,6 +1,6 @@
1
- import { a as ProcessedRoute } from "./defineRoute-B9VdaoQA.mjs";
1
+ import { a as ProcessedRoute } from "./defineRoute-DKVyYELW.mjs";
2
2
  import { r as NestedComponentRoute, t as ComponentRoute } from "./component-route-CGbmQm5P.mjs";
3
- import { t as Server } from "./server-CQ-_WgQN.mjs";
3
+ import { t as Server } from "./server-D3IERUlj.mjs";
4
4
  import { t as ComponentServer } from "./component-server-CKcXIvMg.mjs";
5
5
 
6
6
  //#region src/server/server-factory.d.ts
@@ -45,4 +45,4 @@ declare class ServerFactory {
45
45
  }
46
46
  //#endregion
47
47
  export { ServerFactory as t };
48
- //# sourceMappingURL=index-CRU-u6NT.d.mts.map
48
+ //# sourceMappingURL=index-BPXVOE-X.d.mts.map
package/dist/index.d.mts CHANGED
@@ -1,11 +1,11 @@
1
- import { a as ProcessedRoute, c as RoutesWithSource, d as TypedMiddleware, f as defineMiddleware, h as withContext, i as NestedRouteConfig, l as SSEEventType, m as defineRoutes, n as InferableRoute, o as Route, p as defineRoute, r as LeafRouteConfig, s as RouteSchema, t as HandlerContext, u as SSEGeneratorType } from "./defineRoute-B9VdaoQA.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-DKVyYELW.mjs";
2
2
  import { a as VafastRequest, i as ResponseBody, n as Method, r as Middleware, t as Handler } from "./types-aczawQFE.mjs";
3
3
  import { n as FlattenedComponentRoute, r as NestedComponentRoute, t as ComponentRoute } from "./component-route-CGbmQm5P.mjs";
4
4
  import { t as BaseServer } from "./base-server-CeJ8LTBk.mjs";
5
- import { t as Server } from "./server-CQ-_WgQN.mjs";
5
+ import { t as Server } from "./server-D3IERUlj.mjs";
6
6
  import { t as DependencyManager } from "./dependency-manager-mqzLAocb.mjs";
7
7
  import { t as ComponentServer } from "./component-server-CKcXIvMg.mjs";
8
- import { t as ServerFactory } from "./index-CRU-u6NT.mjs";
8
+ import { t as ServerFactory } from "./index-BPXVOE-X.mjs";
9
9
  import { a as isVafastError, i as errorHandler, n as VafastError, r as composeMiddleware, t as VAFAST_ERROR_SYMBOL } from "./middleware-BTg4GbjC.mjs";
10
10
  import { a as parseBody, c as parseCookiesFast, d as parseHeaders, f as parseQuery, i as getHeader, p as parseQueryFast, r as getCookie, s as parseCookies } from "./parsers-BAQtDA1q.mjs";
11
11
  import { c as text, i as json, n as err, o as redirect, r as html, s as stream, t as empty } from "./response-lI0YZoia.mjs";
@@ -14,12 +14,12 @@ import { n as base64urlEncode, t as base64urlDecode } from "./base64url-CAmasWF0
14
14
  import { t as HtmlRenderer } from "./html-renderer-Up52eIS6.mjs";
15
15
  import { a as ValidationError, c as getValidatorCacheStats, d as validateFast, f as validateSchema, l as precompileSchemas, o as ValidationResult, p as validateSchemaOrThrow, s as createValidator, t as SchemaConfig, u as validateAllSchemas } from "./validators-D5KJCSZr.mjs";
16
16
  import { i as registerFormats, n as hasFormat, r as registerFormat, t as Patterns } from "./formats-Ca7ASaYH.mjs";
17
- import { t as SSEEvent } from "./sse-D77CKcsH.mjs";
18
- import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "./route-registry-C6h13Mks.mjs";
17
+ import { t as SSEEvent } from "./sse-BqvrwmK6.mjs";
18
+ import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "./route-registry-C2a27CuM.mjs";
19
19
  import { n as generateAITools, r as getApiSpec, t as ApiSpec } from "./contract-C-xQoZ6r.mjs";
20
20
  import "./utils/index.mjs";
21
21
  import { normalizePath } from "./router.mjs";
22
22
  import { a as ServeResult, c as serve, i as ServeOptions, n as GracefulShutdownOptions, o as TrustProxyOption, r as RequestTimeoutOptions, t as FetchHandler } from "./serve-Dw-GHkc3.mjs";
23
23
  import "./serve.mjs";
24
24
  import { FormatRegistry, Type } from "@sinclair/typebox";
25
- export { ApiSpec, BaseServer, ComponentRoute, ComponentServer, DependencyManager, type FetchHandler, FlattenedComponentRoute, FormatRegistry, type GracefulShutdownOptions, Handler, HandlerContext, HtmlRenderer, InferableRoute, LeafRouteConfig, Method, Middleware, NestedComponentRoute, NestedRouteConfig, Patterns, ProcessedRoute, type RequestTimeoutOptions, ResponseBody, Route, RouteMeta, RouteRegistry, RouteSchema, RoutesWithSource, SSEEvent, SSEEventType, SSEGeneratorType, SchemaConfig, type ServeOptions, type ServeResult, Server, ServerFactory, type TrustProxyOption, Type, TypedMiddleware, VAFAST_ERROR_SYMBOL, VafastError, VafastRequest, ValidationError, ValidationResult, base64urlDecode, base64urlEncode, composeMiddleware, createRouteRegistry, createValidator, defineMiddleware, defineRoute, defineRoutes, empty, err, errorHandler, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, isVafastError, json, normalizePath, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, serve, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow, withContext };
25
+ export { ApiSpec, BaseServer, ComponentRoute, ComponentServer, DependencyManager, type FetchHandler, FlattenedComponentRoute, FormatRegistry, type GracefulShutdownOptions, Handler, HandlerContext, HtmlRenderer, InferableRoute, LeafRouteConfig, Method, Middleware, NestedComponentRoute, NestedRouteConfig, Patterns, ProcessedRoute, type RequestTimeoutOptions, ResponseBody, Route, RouteMeta, RouteRegistry, RouteSchema, RoutesWithSource, SSEEvent, SSEEventType, SSEEventWithMeta, SSEGeneratorType, SSEMeta, SchemaConfig, type ServeOptions, type ServeResult, Server, ServerFactory, type TrustProxyOption, Type, TypedMiddleware, VAFAST_ERROR_SYMBOL, VafastError, VafastRequest, ValidationError, ValidationResult, base64urlDecode, base64urlEncode, composeMiddleware, createRouteRegistry, createValidator, defineMiddleware, defineRoute, defineRoutes, empty, err, errorHandler, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, isVafastError, json, normalizePath, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, serve, sse, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow, withContext };
package/dist/index.mjs CHANGED
@@ -1,14 +1,14 @@
1
1
  import { a as parseCookies, d as parseQueryFast, l as parseHeaders, n as getHeader, o as parseCookiesFast, r as parseBody, t as getCookie, u as parseQuery } from "./parsers-BrG_mRLq.mjs";
2
2
  import { a as validateAllSchemas, c as validateSchemaOrThrow, i as precompileSchemas, n as createValidator, o as validateFast, r as getValidatorCacheStats, s as validateSchema } from "./validators-CkfvNBbK.mjs";
3
3
  import { c as text, d as composeMiddleware, f as errorHandler, i as json, l as VAFAST_ERROR_SYMBOL, n as err, o as redirect, p as isVafastError, r as html, s as stream, t as empty, u as VafastError } from "./response-Bs9GhJz-.mjs";
4
- import { defineMiddleware, defineRoute, defineRoutes, withContext } from "./defineRoute.mjs";
4
+ import { defineMiddleware, defineRoute, defineRoutes, sse, withContext } from "./defineRoute.mjs";
5
5
  import { t as BaseServer } from "./base-server-CE0mfqPY.mjs";
6
6
  import { a as getRoute, i as getAllRoutes, n as createRouteRegistry, o as getRouteRegistry, r as filterRoutes, s as getRoutesByMethod, t as RouteRegistry } from "./route-registry-DsPslV2b.mjs";
7
- import { t as Server } from "./server-DWndB63Z.mjs";
7
+ import { t as Server } from "./server-B4YDcNJy.mjs";
8
8
  import { t as HtmlRenderer } from "./html-renderer-D1zzDVQM.mjs";
9
9
  import { t as DependencyManager } from "./dependency-manager-CGMZJTer.mjs";
10
10
  import { t as ComponentServer } from "./component-server-Cya46YN3.mjs";
11
- import { t as ServerFactory } from "./server-CAhwnEPW.mjs";
11
+ import { t as ServerFactory } from "./server-BNpY3NH6.mjs";
12
12
  import { t as goAwait } from "./go-await-B1U27PgB.mjs";
13
13
  import { n as base64urlEncode, t as base64urlDecode } from "./base64url-Cc77f1ms.mjs";
14
14
  import { Patterns, hasFormat, registerFormat, registerFormats } from "./utils/formats.mjs";
@@ -25,5 +25,5 @@ import { FormatRegistry, Type } from "@sinclair/typebox";
25
25
  registerFormats();
26
26
 
27
27
  //#endregion
28
- export { BaseServer, ComponentServer, DependencyManager, FormatRegistry, HtmlRenderer, Patterns, RouteRegistry, Server, ServerFactory, Type, VAFAST_ERROR_SYMBOL, VafastError, base64urlDecode, base64urlEncode, composeMiddleware, createRouteRegistry, createValidator, defineMiddleware, defineRoute, defineRoutes, empty, err, errorHandler, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, isVafastError, json, normalizePath, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, serve, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow, withContext };
28
+ export { BaseServer, ComponentServer, DependencyManager, FormatRegistry, HtmlRenderer, Patterns, RouteRegistry, Server, ServerFactory, Type, VAFAST_ERROR_SYMBOL, VafastError, base64urlDecode, base64urlEncode, composeMiddleware, createRouteRegistry, createValidator, defineMiddleware, defineRoute, defineRoutes, empty, err, errorHandler, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, isVafastError, json, normalizePath, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, serve, sse, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow, withContext };
29
29
  //# sourceMappingURL=index.mjs.map
@@ -1,5 +1,5 @@
1
- import "../defineRoute-B9VdaoQA.mjs";
2
- import "../server-CQ-_WgQN.mjs";
3
- import "../index-CRU-u6NT.mjs";
1
+ import "../defineRoute-DKVyYELW.mjs";
2
+ import "../server-D3IERUlj.mjs";
3
+ import "../index-BPXVOE-X.mjs";
4
4
  import { MemoryInfo, MonitoredServer, MonitoringConfig, MonitoringMetrics, MonitoringStatus, PathStats, StatusCodeDistribution, TimeWindowStats, createMonitoredServer, withMonitoring } from "./native-monitor.mjs";
5
5
  export { type MemoryInfo, type MonitoredServer, type MonitoringConfig, type MonitoringMetrics, type MonitoringStatus, type PathStats, type StatusCodeDistribution, type TimeWindowStats, createMonitoredServer, withMonitoring };
@@ -1,6 +1,6 @@
1
- import "../defineRoute-B9VdaoQA.mjs";
2
- import { t as Server } from "../server-CQ-_WgQN.mjs";
3
- import "../index-CRU-u6NT.mjs";
1
+ import "../defineRoute-DKVyYELW.mjs";
2
+ import { t as Server } from "../server-D3IERUlj.mjs";
3
+ import "../index-BPXVOE-X.mjs";
4
4
 
5
5
  //#region src/monitoring/native-monitor.d.ts
6
6
 
@@ -8,6 +8,12 @@
8
8
  * router.register("GET", "/users/:id", handler);
9
9
  * const result = router.match("GET", "/users/123");
10
10
  * // result.params = { id: "123" }
11
+ *
12
+ * // 支持同一位置使用不同参数名
13
+ * router.register("PUT", "/sessions/:id", updateHandler);
14
+ * router.register("GET", "/sessions/:sessionId/messages", messagesHandler);
15
+ * // PUT /sessions/123 → params = { id: "123" }
16
+ * // GET /sessions/123/messages → params = { sessionId: "123" }
11
17
  * ```
12
18
  */
13
19
  var RadixRouter = class {
@@ -32,17 +38,30 @@ var RadixRouter = class {
32
38
  setCompiler(compiler) {
33
39
  this.compiler = compiler;
34
40
  }
41
+ /**
42
+ * 从路由模式中提取参数名列表
43
+ * @example "/users/:id/posts/:postId" → ["id", "postId"]
44
+ */
45
+ extractParamNames(pattern) {
46
+ const paramNames = [];
47
+ const segments = this.splitPath(pattern);
48
+ for (const segment of segments) if (segment[0] === ":") paramNames.push(segment.substring(1));
49
+ else if (segment[0] === "*") paramNames.push(segment.length > 1 ? segment.substring(1) : "*");
50
+ return paramNames;
51
+ }
35
52
  /** 注册路由 */
36
53
  register(method, pattern, handler, middleware = []) {
37
54
  const segments = this.splitPath(pattern);
55
+ const paramNames = this.extractParamNames(pattern);
38
56
  let node = this.root;
39
57
  for (const segment of segments) {
40
58
  const firstChar = segment[0];
41
59
  if (firstChar === ":") {
60
+ const paramName = segment.substring(1);
42
61
  if (!node.paramChild) {
43
62
  node.paramChild = this.createNode(segment);
44
- node.paramChild.paramName = segment.substring(1);
45
- }
63
+ node.paramChild.paramName = paramName;
64
+ } else if (node.paramChild.paramName !== paramName) console.warn(`⚠️ 路由参数名冲突: 位置 "${node.path || "/"}" 下已有参数 ":${node.paramChild.paramName}",新路由使用 ":${paramName}"。建议使用一致的参数名。`);
46
65
  node = node.paramChild;
47
66
  } else if (firstChar === "*") {
48
67
  if (!node.wildcardChild) {
@@ -58,7 +77,8 @@ var RadixRouter = class {
58
77
  }
59
78
  const routeHandler = {
60
79
  handler,
61
- middleware
80
+ middleware,
81
+ paramNames
62
82
  };
63
83
  if (this.compiler && middleware.length === 0) routeHandler.compiled = this.compiler([], handler);
64
84
  node.handlers[method] = routeHandler;
@@ -83,11 +103,13 @@ var RadixRouter = class {
83
103
  /** 匹配路由 */
84
104
  match(method, path) {
85
105
  const segments = this.splitPath(path);
86
- const params = Object.create(null);
87
- const node = this.matchNode(this.root, segments, 0, params);
106
+ const paramValues = [];
107
+ const node = this.matchNode(this.root, segments, 0, paramValues);
88
108
  if (!node) return null;
89
109
  const routeHandler = node.handlers[method];
90
110
  if (!routeHandler) return null;
111
+ const params = Object.create(null);
112
+ for (let i = 0; i < routeHandler.paramNames.length; i++) params[routeHandler.paramNames[i]] = paramValues[i];
91
113
  return {
92
114
  handler: routeHandler.handler,
93
115
  middleware: routeHandler.middleware,
@@ -96,7 +118,7 @@ var RadixRouter = class {
96
118
  };
97
119
  }
98
120
  /** 递归匹配节点 (优先级: 静态 > 动态参数 > 通配符) */
99
- matchNode(node, segments, index, params) {
121
+ matchNode(node, segments, index, paramValues) {
100
122
  if (index === segments.length) {
101
123
  for (const method in node.handlers) if (node.handlers[method]) return node;
102
124
  return null;
@@ -104,20 +126,18 @@ var RadixRouter = class {
104
126
  const segment = segments[index];
105
127
  const staticChild = node.children[segment];
106
128
  if (staticChild) {
107
- const result = this.matchNode(staticChild, segments, index + 1, params);
129
+ const result = this.matchNode(staticChild, segments, index + 1, paramValues);
108
130
  if (result) return result;
109
131
  }
110
132
  if (node.paramChild) {
111
- const paramName = node.paramChild.paramName;
112
- const oldValue = params[paramName];
113
- params[paramName] = segment;
114
- const result = this.matchNode(node.paramChild, segments, index + 1, params);
133
+ const valueIndex = paramValues.length;
134
+ paramValues.push(segment);
135
+ const result = this.matchNode(node.paramChild, segments, index + 1, paramValues);
115
136
  if (result) return result;
116
- if (oldValue === void 0) delete params[paramName];
117
- else params[paramName] = oldValue;
137
+ paramValues.length = valueIndex;
118
138
  }
119
139
  if (node.wildcardChild) {
120
- params[node.wildcardChild.paramName || "*"] = segments.slice(index).join("/");
140
+ paramValues.push(segments.slice(index).join("/"));
121
141
  return node.wildcardChild;
122
142
  }
123
143
  return null;
@@ -160,4 +180,4 @@ var RadixRouter = class {
160
180
 
161
181
  //#endregion
162
182
  export { RadixRouter as t };
163
- //# sourceMappingURL=radix-tree-CccjvyTP.mjs.map
183
+ //# sourceMappingURL=radix-tree-dyn3qDFX.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radix-tree-dyn3qDFX.mjs","names":[],"sources":["../src/router/radix-tree.ts"],"sourcesContent":["/**\n * Radix Tree 路由匹配器\n *\n * 高性能路由匹配实现,时间复杂度 O(k),k 为路径段数\n *\n * 支持的路由模式:\n * - 静态路径: /users, /api/v1/health\n * - 动态参数: /users/:id, /posts/:postId/comments/:commentId\n * - 通配符: /files/*, /static/*filepath\n * \n * 特性:\n * - 同一位置支持不同参数名(如 /sessions/:id 和 /sessions/:sessionId/messages)\n * - 参数名冲突时会发出警告,但不影响功能\n */\n\nimport type { Handler, Middleware, Method } from \"../types\";\n\n/** 预编译的处理器类型 */\ntype CompiledHandler = (req: Request) => Promise<Response>;\n\n/** 路由处理信息 */\ninterface RouteHandler {\n handler: Handler;\n middleware: Middleware[];\n /** 预编译后的完整处理链(包含中间件) */\n compiled?: CompiledHandler;\n /** 该路由的参数名列表(按顺序) */\n paramNames: string[];\n}\n\n/** Radix Tree 节点 */\ninterface RadixNode {\n path: string;\n children: Record<string, RadixNode>;\n paramChild?: RadixNode;\n wildcardChild?: RadixNode;\n /** 该位置的参数名(仅用于调试和警告) */\n paramName?: string;\n handlers: Record<Method, RouteHandler | undefined>;\n}\n\n/** 路由匹配结果 */\nexport interface MatchResult {\n handler: Handler;\n middleware: Middleware[];\n params: Record<string, string>;\n /** 预编译后的完整处理链 */\n compiled?: CompiledHandler;\n}\n\n/**\n * Radix Tree 路由器\n *\n * @example\n * ```typescript\n * const router = new RadixRouter();\n * router.register(\"GET\", \"/users/:id\", handler);\n * const result = router.match(\"GET\", \"/users/123\");\n * // result.params = { id: \"123\" }\n * \n * // 支持同一位置使用不同参数名\n * router.register(\"PUT\", \"/sessions/:id\", updateHandler);\n * router.register(\"GET\", \"/sessions/:sessionId/messages\", messagesHandler);\n * // PUT /sessions/123 → params = { id: \"123\" }\n * // GET /sessions/123/messages → params = { sessionId: \"123\" }\n * ```\n */\nexport class RadixRouter {\n private root: RadixNode;\n\n constructor() {\n this.root = this.createNode(\"\");\n }\n\n private createNode(path: string): RadixNode {\n return {\n path,\n children: Object.create(null),\n handlers: Object.create(null),\n };\n }\n\n /** 分割路径 */\n private splitPath(path: string): string[] {\n return path.split(\"/\").filter(Boolean);\n }\n\n /** 编译器函数 - 用于预编译中间件链 */\n private compiler?: (\n middleware: Middleware[],\n handler: Handler,\n ) => CompiledHandler;\n\n /** 设置中间件编译器 */\n setCompiler(\n compiler: (middleware: Middleware[], handler: Handler) => CompiledHandler,\n ): void {\n this.compiler = compiler;\n }\n\n /**\n * 从路由模式中提取参数名列表\n * @example \"/users/:id/posts/:postId\" → [\"id\", \"postId\"]\n */\n private extractParamNames(pattern: string): string[] {\n const paramNames: string[] = [];\n const segments = this.splitPath(pattern);\n \n for (const segment of segments) {\n if (segment[0] === \":\") {\n paramNames.push(segment.substring(1));\n } else if (segment[0] === \"*\") {\n paramNames.push(segment.length > 1 ? segment.substring(1) : \"*\");\n }\n }\n \n return paramNames;\n }\n\n /** 注册路由 */\n register(\n method: Method,\n pattern: string,\n handler: Handler,\n middleware: Middleware[] = [],\n ): void {\n const segments = this.splitPath(pattern);\n const paramNames = this.extractParamNames(pattern);\n let node = this.root;\n\n for (const segment of segments) {\n const firstChar = segment[0];\n\n if (firstChar === \":\") {\n // 动态参数节点\n const paramName = segment.substring(1);\n if (!node.paramChild) {\n node.paramChild = this.createNode(segment);\n node.paramChild.paramName = paramName;\n } else if (node.paramChild.paramName !== paramName) {\n // 参数名冲突警告(但不影响功能)\n console.warn(\n `⚠️ 路由参数名冲突: 位置 \"${node.path || '/'}\" 下已有参数 \":${node.paramChild.paramName}\",` +\n `新路由使用 \":${paramName}\"。建议使用一致的参数名。`\n );\n }\n node = node.paramChild;\n } else if (firstChar === \"*\") {\n // 通配符节点\n if (!node.wildcardChild) {\n node.wildcardChild = this.createNode(segment);\n node.wildcardChild.paramName =\n segment.length > 1 ? segment.substring(1) : \"*\";\n }\n node = node.wildcardChild;\n break;\n } else {\n // 静态路径节点\n if (!node.children[segment]) {\n node.children[segment] = this.createNode(segment);\n }\n node = node.children[segment];\n }\n }\n\n const routeHandler: RouteHandler = { handler, middleware, paramNames };\n\n // 如果没有全局中间件且设置了编译器,预编译处理链\n if (this.compiler && middleware.length === 0) {\n routeHandler.compiled = this.compiler([], handler);\n }\n\n node.handlers[method] = routeHandler;\n }\n\n /** 预编译所有路由(在添加全局中间件后调用) */\n precompileAll(globalMiddleware: Middleware[]): void {\n if (!this.compiler) return;\n this.precompileNode(this.root, globalMiddleware);\n }\n\n private precompileNode(\n node: RadixNode,\n globalMiddleware: Middleware[],\n ): void {\n for (const method in node.handlers) {\n const routeHandler = node.handlers[method as Method];\n if (routeHandler) {\n const allMiddleware = [...globalMiddleware, ...routeHandler.middleware];\n routeHandler.compiled = this.compiler!(\n allMiddleware,\n routeHandler.handler,\n );\n }\n }\n\n for (const key in node.children) {\n this.precompileNode(node.children[key], globalMiddleware);\n }\n\n if (node.paramChild) {\n this.precompileNode(node.paramChild, globalMiddleware);\n }\n\n if (node.wildcardChild) {\n this.precompileNode(node.wildcardChild, globalMiddleware);\n }\n }\n\n /** 匹配路由 */\n match(method: Method, path: string): MatchResult | null {\n const segments = this.splitPath(path);\n // 使用数组按位置收集参数值\n const paramValues: string[] = [];\n\n const node = this.matchNode(this.root, segments, 0, paramValues);\n if (!node) return null;\n\n const routeHandler = node.handlers[method];\n if (!routeHandler) return null;\n\n // 根据路由自己的 paramNames 构建 params 对象\n const params: Record<string, string> = Object.create(null);\n for (let i = 0; i < routeHandler.paramNames.length; i++) {\n params[routeHandler.paramNames[i]] = paramValues[i];\n }\n\n return {\n handler: routeHandler.handler,\n middleware: routeHandler.middleware,\n params,\n compiled: routeHandler.compiled,\n };\n }\n\n /** 递归匹配节点 (优先级: 静态 > 动态参数 > 通配符) */\n private matchNode(\n node: RadixNode,\n segments: string[],\n index: number,\n paramValues: string[],\n ): RadixNode | null {\n if (index === segments.length) {\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) return node;\n }\n return null;\n }\n\n const segment = segments[index];\n\n // 1. 静态路径\n const staticChild = node.children[segment];\n if (staticChild) {\n const result = this.matchNode(staticChild, segments, index + 1, paramValues);\n if (result) return result;\n }\n\n // 2. 动态参数\n if (node.paramChild) {\n const valueIndex = paramValues.length;\n paramValues.push(segment);\n \n const result = this.matchNode(\n node.paramChild,\n segments,\n index + 1,\n paramValues,\n );\n\n if (result) return result;\n\n // 回溯:移除添加的参数值\n paramValues.length = valueIndex;\n }\n\n // 3. 通配符\n if (node.wildcardChild) {\n paramValues.push(segments.slice(index).join(\"/\"));\n return node.wildcardChild;\n }\n\n return null;\n }\n\n /** 获取路径允许的 HTTP 方法 */\n getAllowedMethods(path: string): Method[] {\n const segments = this.splitPath(path);\n const node = this.findNode(segments);\n if (!node) return [];\n\n const methods: Method[] = [];\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) {\n methods.push(method as Method);\n }\n }\n return methods;\n }\n\n /** 查找节点(不提取参数) */\n private findNode(segments: string[]): RadixNode | null {\n let node = this.root;\n\n for (const segment of segments) {\n if (node.children[segment]) {\n node = node.children[segment];\n } else if (node.paramChild) {\n node = node.paramChild;\n } else if (node.wildcardChild) {\n return node.wildcardChild;\n } else {\n return null;\n }\n }\n\n return node;\n }\n\n /** 获取所有已注册的路由 */\n getRoutes(): Array<{ method: Method; path: string }> {\n const routes: Array<{ method: Method; path: string }> = [];\n this.collectRoutes(this.root, \"\", routes);\n return routes;\n }\n\n private collectRoutes(\n node: RadixNode,\n prefix: string,\n routes: Array<{ method: Method; path: string }>,\n ): void {\n const currentPath = prefix + (node.path ? \"/\" + node.path : \"\");\n\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) {\n routes.push({ method: method as Method, path: currentPath || \"/\" });\n }\n }\n\n for (const key in node.children) {\n this.collectRoutes(node.children[key], currentPath, routes);\n }\n\n if (node.paramChild) {\n this.collectRoutes(node.paramChild, currentPath, routes);\n }\n\n if (node.wildcardChild) {\n this.collectRoutes(node.wildcardChild, currentPath, routes);\n }\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { a as ProcessedRoute, s as RouteSchema } from "./defineRoute-B9VdaoQA.mjs";
1
+ import { a as ProcessedRoute, s as RouteSchema } from "./defineRoute-DKVyYELW.mjs";
2
2
  import { n as Method } from "./types-aczawQFE.mjs";
3
3
 
4
4
  //#region src/utils/route-registry.d.ts
@@ -187,4 +187,4 @@ declare function filterRoutes<K extends string>(field: K): (RouteMeta & Record<K
187
187
  declare function getRoutesByMethod(method: string): RouteMeta[];
188
188
  //#endregion
189
189
  export { getAllRoutes as a, getRoutesByMethod as c, filterRoutes as i, setGlobalRegistry as l, RouteRegistry as n, getRoute as o, createRouteRegistry as r, getRouteRegistry as s, RouteMeta as t };
190
- //# sourceMappingURL=route-registry-C6h13Mks.d.mts.map
190
+ //# sourceMappingURL=route-registry-C2a27CuM.d.mts.map
@@ -1,4 +1,4 @@
1
- import { t as RadixRouter } from "../radix-tree-CccjvyTP.mjs";
1
+ import { t as RadixRouter } from "../radix-tree-dyn3qDFX.mjs";
2
2
  import { normalizePath } from "../router.mjs";
3
3
 
4
4
  export { RadixRouter, normalizePath };
@@ -21,6 +21,12 @@ interface MatchResult {
21
21
  * router.register("GET", "/users/:id", handler);
22
22
  * const result = router.match("GET", "/users/123");
23
23
  * // result.params = { id: "123" }
24
+ *
25
+ * // 支持同一位置使用不同参数名
26
+ * router.register("PUT", "/sessions/:id", updateHandler);
27
+ * router.register("GET", "/sessions/:sessionId/messages", messagesHandler);
28
+ * // PUT /sessions/123 → params = { id: "123" }
29
+ * // GET /sessions/123/messages → params = { sessionId: "123" }
24
30
  * ```
25
31
  */
26
32
  declare class RadixRouter {
@@ -33,6 +39,11 @@ declare class RadixRouter {
33
39
  private compiler?;
34
40
  /** 设置中间件编译器 */
35
41
  setCompiler(compiler: (middleware: Middleware[], handler: Handler) => CompiledHandler): void;
42
+ /**
43
+ * 从路由模式中提取参数名列表
44
+ * @example "/users/:id/posts/:postId" → ["id", "postId"]
45
+ */
46
+ private extractParamNames;
36
47
  /** 注册路由 */
37
48
  register(method: Method, pattern: string, handler: Handler, middleware?: Middleware[]): void;
38
49
  /** 预编译所有路由(在添加全局中间件后调用) */
@@ -1,3 +1,3 @@
1
- import { t as RadixRouter } from "../radix-tree-CccjvyTP.mjs";
1
+ import { t as RadixRouter } from "../radix-tree-dyn3qDFX.mjs";
2
2
 
3
3
  export { RadixRouter };
@@ -1,6 +1,6 @@
1
- import "../defineRoute-B9VdaoQA.mjs";
1
+ import "../defineRoute-DKVyYELW.mjs";
2
2
  import { t as BaseServer } from "../base-server-CeJ8LTBk.mjs";
3
- import { t as Server } from "../server-CQ-_WgQN.mjs";
3
+ import { t as Server } from "../server-D3IERUlj.mjs";
4
4
  import { t as ComponentServer } from "../component-server-CKcXIvMg.mjs";
5
- import { t as ServerFactory } from "../index-CRU-u6NT.mjs";
5
+ import { t as ServerFactory } from "../index-BPXVOE-X.mjs";
6
6
  export { BaseServer, ComponentServer, Server, ServerFactory };
@@ -1,8 +1,8 @@
1
1
  import "../response-Bs9GhJz-.mjs";
2
2
  import { t as BaseServer } from "../base-server-CE0mfqPY.mjs";
3
- import { t as Server } from "../server-DWndB63Z.mjs";
3
+ import { t as Server } from "../server-B4YDcNJy.mjs";
4
4
  import "../dependency-manager-CGMZJTer.mjs";
5
5
  import { t as ComponentServer } from "../component-server-Cya46YN3.mjs";
6
- import { t as ServerFactory } from "../server-CAhwnEPW.mjs";
6
+ import { t as ServerFactory } from "../server-BNpY3NH6.mjs";
7
7
 
8
8
  export { BaseServer, ComponentServer, Server, ServerFactory };
@@ -1,4 +1,4 @@
1
- import "../defineRoute-B9VdaoQA.mjs";
2
- import "../server-CQ-_WgQN.mjs";
3
- import { t as ServerFactory } from "../index-CRU-u6NT.mjs";
1
+ import "../defineRoute-DKVyYELW.mjs";
2
+ import "../server-D3IERUlj.mjs";
3
+ import { t as ServerFactory } from "../index-BPXVOE-X.mjs";
4
4
  export { ServerFactory };
@@ -1,7 +1,7 @@
1
1
  import "../response-Bs9GhJz-.mjs";
2
- import "../server-DWndB63Z.mjs";
2
+ import "../server-B4YDcNJy.mjs";
3
3
  import "../dependency-manager-CGMZJTer.mjs";
4
4
  import "../component-server-Cya46YN3.mjs";
5
- import { t as ServerFactory } from "../server-CAhwnEPW.mjs";
5
+ import { t as ServerFactory } from "../server-BNpY3NH6.mjs";
6
6
 
7
7
  export { ServerFactory };
@@ -1,3 +1,3 @@
1
- import "../defineRoute-B9VdaoQA.mjs";
2
- import { t as Server } from "../server-CQ-_WgQN.mjs";
1
+ import "../defineRoute-DKVyYELW.mjs";
2
+ import { t as Server } from "../server-D3IERUlj.mjs";
3
3
  export { Server };
@@ -1,4 +1,4 @@
1
1
  import "../response-Bs9GhJz-.mjs";
2
- import { t as Server } from "../server-DWndB63Z.mjs";
2
+ import { t as Server } from "../server-B4YDcNJy.mjs";
3
3
 
4
4
  export { Server };
@@ -1,6 +1,6 @@
1
1
  import { d as composeMiddleware, f as errorHandler, i as json } from "./response-Bs9GhJz-.mjs";
2
2
  import { t as BaseServer } from "./base-server-CE0mfqPY.mjs";
3
- import { t as RadixRouter } from "./radix-tree-CccjvyTP.mjs";
3
+ import { t as RadixRouter } from "./radix-tree-dyn3qDFX.mjs";
4
4
  import { c as setGlobalRegistry, t as RouteRegistry } from "./route-registry-DsPslV2b.mjs";
5
5
 
6
6
  //#region src/server/server.ts
@@ -113,4 +113,4 @@ var Server = class extends BaseServer {
113
113
 
114
114
  //#endregion
115
115
  export { Server as t };
116
- //# sourceMappingURL=server-DWndB63Z.mjs.map
116
+ //# sourceMappingURL=server-B4YDcNJy.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-DWndB63Z.mjs","names":[],"sources":["../src/server/server.ts"],"sourcesContent":["/**\n * Vafast 核心服务器\n *\n * 基于 Radix Tree 的高性能路由匹配\n * 时间复杂度: O(k),k 为路径段数\n */\n\nimport type { Method, Middleware } from \"../types\";\nimport type { ProcessedRoute } from \"../defineRoute\";\nimport { composeMiddleware, errorHandler } from \"../middleware\";\nimport { json } from \"../utils/response\";\nimport { BaseServer } from \"./base-server\";\nimport { RadixRouter } from \"../router/radix-tree\";\nimport { RouteRegistry, setGlobalRegistry } from \"../utils/route-registry\";\n\n/**\n * Vafast 服务器\n *\n * @example\n * ```typescript\n * const routes = defineRoutes([\n * defineRoute({ method: \"GET\", path: \"/\", handler: () => \"Hello\" }),\n * ])\n * const server = new Server(routes)\n * export default { fetch: server.fetch }\n * ```\n */\nexport class Server extends BaseServer {\n private router: RadixRouter;\n private routes: ProcessedRoute[];\n\n constructor(routes: readonly ProcessedRoute[] = []) {\n super();\n this.router = new RadixRouter();\n this.routes = [];\n\n if (routes.length > 0) {\n this.registerRoutes([...routes]);\n }\n }\n\n private registerRoutes(routes: ProcessedRoute[]): void {\n this.routes.push(...routes);\n\n for (const route of routes) {\n this.router.register(\n route.method as Method,\n route.path,\n route.handler,\n (route.middleware || []) as Middleware[],\n );\n }\n\n this.detectRouteConflicts(routes);\n this.logRoutes(routes);\n\n // 自动设置全局 RouteRegistry\n setGlobalRegistry(new RouteRegistry(this.routes));\n }\n\n /** 快速提取 pathname */\n private extractPathname(url: string): string {\n let start = url.indexOf(\"://\");\n start = start === -1 ? 0 : start + 3;\n\n const pathStart = url.indexOf(\"/\", start);\n if (pathStart === -1) return \"/\";\n\n let end = url.indexOf(\"?\", pathStart);\n if (end === -1) end = url.indexOf(\"#\", pathStart);\n if (end === -1) end = url.length;\n\n return url.substring(pathStart, end) || \"/\";\n }\n\n /** 生成 404/405 响应 */\n private createErrorResponse(method: string, pathname: string): Response {\n const allowedMethods = this.router.getAllowedMethods(pathname);\n if (allowedMethods.length > 0) {\n return json(\n {\n code: 405,\n message: `Method ${method} not allowed for this endpoint`,\n allowedMethods,\n },\n 405,\n { Allow: allowedMethods.join(\", \") },\n );\n }\n return json({ code: 404, message: \"Not Found\" }, 404);\n }\n\n /** 处理请求 */\n fetch = async (req: Request): Promise<Response> => {\n const pathname = this.extractPathname(req.url);\n const method = req.method as Method;\n\n const match = this.router.match(method, pathname);\n\n if (match) {\n (req as unknown as Record<string, unknown>).params = match.params;\n\n // 运行时组合中间件\n // 洋葱模型:globalMiddleware → errorHandler → routeMiddleware → handler\n // 这样 errorHandler 返回的错误响应也会经过 globalMiddleware(如 CORS)的后处理\n const allMiddleware = [\n ...this.globalMiddleware,\n errorHandler,\n ...match.middleware,\n ];\n const handler = composeMiddleware(allMiddleware, match.handler);\n\n return handler(req);\n }\n\n // OPTIONS 预检请求特殊处理:查找同路径其他方法的路由,使用其中间件\n // 这允许路由级 CORS 中间件正常工作\n if (method === \"OPTIONS\") {\n const allowedMethods = this.router.getAllowedMethods(pathname);\n if (allowedMethods.length > 0) {\n // 尝试获取该路径任意方法的路由中间件\n const anyMatch = this.router.match(\n allowedMethods[0] as Method,\n pathname,\n );\n const routeMiddleware = anyMatch?.middleware || [];\n const allMiddleware = [\n ...this.globalMiddleware,\n errorHandler,\n ...routeMiddleware,\n ];\n\n // OPTIONS 请求默认返回 204(中间件如 CORS 可能会提前响应)\n const optionsHandler = () =>\n new Response(null, {\n status: 204,\n headers: { Allow: allowedMethods.join(\", \") },\n });\n\n const handler = composeMiddleware(allMiddleware, optionsHandler);\n return handler(req);\n }\n }\n\n // 未匹配路由时,仍执行全局中间件(如 CORS 处理 OPTIONS 预检)\n if (this.globalMiddleware.length > 0) {\n const allMiddleware = [...this.globalMiddleware, errorHandler];\n const handler = composeMiddleware(allMiddleware, () =>\n this.createErrorResponse(method, pathname),\n );\n return handler(req);\n }\n\n return this.createErrorResponse(method, pathname);\n };\n\n /** 动态添加单个路由 */\n addRoute(route: ProcessedRoute): void {\n this.routes.push(route);\n this.router.register(\n route.method as Method,\n route.path,\n route.handler,\n (route.middleware || []) as Middleware[],\n );\n }\n\n /** 动态添加多个路由 */\n addRoutes(routes: readonly ProcessedRoute[]): void {\n this.registerRoutes([...routes]);\n }\n\n /** 获取路由列表 */\n getRoutes(): Array<{ method: Method; path: string }> {\n return this.router.getRoutes();\n }\n\n /**\n * 获取完整的路由元信息\n *\n * 用于 API 文档生成、Webhook 事件注册、权限检查等场景\n */\n getRoutesWithMeta(): ProcessedRoute[] {\n return this.routes;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA2BA,IAAa,SAAb,cAA4B,WAAW;CACrC,AAAQ;CACR,AAAQ;CAER,YAAY,SAAoC,EAAE,EAAE;AAClD,SAAO;AACP,OAAK,SAAS,IAAI,aAAa;AAC/B,OAAK,SAAS,EAAE;AAEhB,MAAI,OAAO,SAAS,EAClB,MAAK,eAAe,CAAC,GAAG,OAAO,CAAC;;CAIpC,AAAQ,eAAe,QAAgC;AACrD,OAAK,OAAO,KAAK,GAAG,OAAO;AAE3B,OAAK,MAAM,SAAS,OAClB,MAAK,OAAO,SACV,MAAM,QACN,MAAM,MACN,MAAM,SACL,MAAM,cAAc,EAAE,CACxB;AAGH,OAAK,qBAAqB,OAAO;AACjC,OAAK,UAAU,OAAO;AAGtB,oBAAkB,IAAI,cAAc,KAAK,OAAO,CAAC;;;CAInD,AAAQ,gBAAgB,KAAqB;EAC3C,IAAI,QAAQ,IAAI,QAAQ,MAAM;AAC9B,UAAQ,UAAU,KAAK,IAAI,QAAQ;EAEnC,MAAM,YAAY,IAAI,QAAQ,KAAK,MAAM;AACzC,MAAI,cAAc,GAAI,QAAO;EAE7B,IAAI,MAAM,IAAI,QAAQ,KAAK,UAAU;AACrC,MAAI,QAAQ,GAAI,OAAM,IAAI,QAAQ,KAAK,UAAU;AACjD,MAAI,QAAQ,GAAI,OAAM,IAAI;AAE1B,SAAO,IAAI,UAAU,WAAW,IAAI,IAAI;;;CAI1C,AAAQ,oBAAoB,QAAgB,UAA4B;EACtE,MAAM,iBAAiB,KAAK,OAAO,kBAAkB,SAAS;AAC9D,MAAI,eAAe,SAAS,EAC1B,QAAO,KACL;GACE,MAAM;GACN,SAAS,UAAU,OAAO;GAC1B;GACD,EACD,KACA,EAAE,OAAO,eAAe,KAAK,KAAK,EAAE,CACrC;AAEH,SAAO,KAAK;GAAE,MAAM;GAAK,SAAS;GAAa,EAAE,IAAI;;;CAIvD,QAAQ,OAAO,QAAoC;EACjD,MAAM,WAAW,KAAK,gBAAgB,IAAI,IAAI;EAC9C,MAAM,SAAS,IAAI;EAEnB,MAAM,QAAQ,KAAK,OAAO,MAAM,QAAQ,SAAS;AAEjD,MAAI,OAAO;AACT,GAAC,IAA2C,SAAS,MAAM;AAY3D,UAFgB,kBALM;IACpB,GAAG,KAAK;IACR;IACA,GAAG,MAAM;IACV,EACgD,MAAM,QAAQ,CAEhD,IAAI;;AAKrB,MAAI,WAAW,WAAW;GACxB,MAAM,iBAAiB,KAAK,OAAO,kBAAkB,SAAS;AAC9D,OAAI,eAAe,SAAS,GAAG;IAM7B,MAAM,kBAJW,KAAK,OAAO,MAC3B,eAAe,IACf,SACD,EACiC,cAAc,EAAE;IAClD,MAAM,gBAAgB;KACpB,GAAG,KAAK;KACR;KACA,GAAG;KACJ;IAGD,MAAM,uBACJ,IAAI,SAAS,MAAM;KACjB,QAAQ;KACR,SAAS,EAAE,OAAO,eAAe,KAAK,KAAK,EAAE;KAC9C,CAAC;AAGJ,WADgB,kBAAkB,eAAe,eAAe,CACjD,IAAI;;;AAKvB,MAAI,KAAK,iBAAiB,SAAS,EAKjC,QAHgB,kBADM,CAAC,GAAG,KAAK,kBAAkB,aAAa,QAE5D,KAAK,oBAAoB,QAAQ,SAAS,CAC3C,CACc,IAAI;AAGrB,SAAO,KAAK,oBAAoB,QAAQ,SAAS;;;CAInD,SAAS,OAA6B;AACpC,OAAK,OAAO,KAAK,MAAM;AACvB,OAAK,OAAO,SACV,MAAM,QACN,MAAM,MACN,MAAM,SACL,MAAM,cAAc,EAAE,CACxB;;;CAIH,UAAU,QAAyC;AACjD,OAAK,eAAe,CAAC,GAAG,OAAO,CAAC;;;CAIlC,YAAqD;AACnD,SAAO,KAAK,OAAO,WAAW;;;;;;;CAQhC,oBAAsC;AACpC,SAAO,KAAK"}
1
+ {"version":3,"file":"server-B4YDcNJy.mjs","names":[],"sources":["../src/server/server.ts"],"sourcesContent":["/**\n * Vafast 核心服务器\n *\n * 基于 Radix Tree 的高性能路由匹配\n * 时间复杂度: O(k),k 为路径段数\n */\n\nimport type { Method, Middleware } from \"../types\";\nimport type { ProcessedRoute } from \"../defineRoute\";\nimport { composeMiddleware, errorHandler } from \"../middleware\";\nimport { json } from \"../utils/response\";\nimport { BaseServer } from \"./base-server\";\nimport { RadixRouter } from \"../router/radix-tree\";\nimport { RouteRegistry, setGlobalRegistry } from \"../utils/route-registry\";\n\n/**\n * Vafast 服务器\n *\n * @example\n * ```typescript\n * const routes = defineRoutes([\n * defineRoute({ method: \"GET\", path: \"/\", handler: () => \"Hello\" }),\n * ])\n * const server = new Server(routes)\n * export default { fetch: server.fetch }\n * ```\n */\nexport class Server extends BaseServer {\n private router: RadixRouter;\n private routes: ProcessedRoute[];\n\n constructor(routes: readonly ProcessedRoute[] = []) {\n super();\n this.router = new RadixRouter();\n this.routes = [];\n\n if (routes.length > 0) {\n this.registerRoutes([...routes]);\n }\n }\n\n private registerRoutes(routes: ProcessedRoute[]): void {\n this.routes.push(...routes);\n\n for (const route of routes) {\n this.router.register(\n route.method as Method,\n route.path,\n route.handler,\n (route.middleware || []) as Middleware[],\n );\n }\n\n this.detectRouteConflicts(routes);\n this.logRoutes(routes);\n\n // 自动设置全局 RouteRegistry\n setGlobalRegistry(new RouteRegistry(this.routes));\n }\n\n /** 快速提取 pathname */\n private extractPathname(url: string): string {\n let start = url.indexOf(\"://\");\n start = start === -1 ? 0 : start + 3;\n\n const pathStart = url.indexOf(\"/\", start);\n if (pathStart === -1) return \"/\";\n\n let end = url.indexOf(\"?\", pathStart);\n if (end === -1) end = url.indexOf(\"#\", pathStart);\n if (end === -1) end = url.length;\n\n return url.substring(pathStart, end) || \"/\";\n }\n\n /** 生成 404/405 响应 */\n private createErrorResponse(method: string, pathname: string): Response {\n const allowedMethods = this.router.getAllowedMethods(pathname);\n if (allowedMethods.length > 0) {\n return json(\n {\n code: 405,\n message: `Method ${method} not allowed for this endpoint`,\n allowedMethods,\n },\n 405,\n { Allow: allowedMethods.join(\", \") },\n );\n }\n return json({ code: 404, message: \"Not Found\" }, 404);\n }\n\n /** 处理请求 */\n fetch = async (req: Request): Promise<Response> => {\n const pathname = this.extractPathname(req.url);\n const method = req.method as Method;\n\n const match = this.router.match(method, pathname);\n\n if (match) {\n (req as unknown as Record<string, unknown>).params = match.params;\n\n // 运行时组合中间件\n // 洋葱模型:globalMiddleware → errorHandler → routeMiddleware → handler\n // 这样 errorHandler 返回的错误响应也会经过 globalMiddleware(如 CORS)的后处理\n const allMiddleware = [\n ...this.globalMiddleware,\n errorHandler,\n ...match.middleware,\n ];\n const handler = composeMiddleware(allMiddleware, match.handler);\n\n return handler(req);\n }\n\n // OPTIONS 预检请求特殊处理:查找同路径其他方法的路由,使用其中间件\n // 这允许路由级 CORS 中间件正常工作\n if (method === \"OPTIONS\") {\n const allowedMethods = this.router.getAllowedMethods(pathname);\n if (allowedMethods.length > 0) {\n // 尝试获取该路径任意方法的路由中间件\n const anyMatch = this.router.match(\n allowedMethods[0] as Method,\n pathname,\n );\n const routeMiddleware = anyMatch?.middleware || [];\n const allMiddleware = [\n ...this.globalMiddleware,\n errorHandler,\n ...routeMiddleware,\n ];\n\n // OPTIONS 请求默认返回 204(中间件如 CORS 可能会提前响应)\n const optionsHandler = () =>\n new Response(null, {\n status: 204,\n headers: { Allow: allowedMethods.join(\", \") },\n });\n\n const handler = composeMiddleware(allMiddleware, optionsHandler);\n return handler(req);\n }\n }\n\n // 未匹配路由时,仍执行全局中间件(如 CORS 处理 OPTIONS 预检)\n if (this.globalMiddleware.length > 0) {\n const allMiddleware = [...this.globalMiddleware, errorHandler];\n const handler = composeMiddleware(allMiddleware, () =>\n this.createErrorResponse(method, pathname),\n );\n return handler(req);\n }\n\n return this.createErrorResponse(method, pathname);\n };\n\n /** 动态添加单个路由 */\n addRoute(route: ProcessedRoute): void {\n this.routes.push(route);\n this.router.register(\n route.method as Method,\n route.path,\n route.handler,\n (route.middleware || []) as Middleware[],\n );\n }\n\n /** 动态添加多个路由 */\n addRoutes(routes: readonly ProcessedRoute[]): void {\n this.registerRoutes([...routes]);\n }\n\n /** 获取路由列表 */\n getRoutes(): Array<{ method: Method; path: string }> {\n return this.router.getRoutes();\n }\n\n /**\n * 获取完整的路由元信息\n *\n * 用于 API 文档生成、Webhook 事件注册、权限检查等场景\n */\n getRoutesWithMeta(): ProcessedRoute[] {\n return this.routes;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA2BA,IAAa,SAAb,cAA4B,WAAW;CACrC,AAAQ;CACR,AAAQ;CAER,YAAY,SAAoC,EAAE,EAAE;AAClD,SAAO;AACP,OAAK,SAAS,IAAI,aAAa;AAC/B,OAAK,SAAS,EAAE;AAEhB,MAAI,OAAO,SAAS,EAClB,MAAK,eAAe,CAAC,GAAG,OAAO,CAAC;;CAIpC,AAAQ,eAAe,QAAgC;AACrD,OAAK,OAAO,KAAK,GAAG,OAAO;AAE3B,OAAK,MAAM,SAAS,OAClB,MAAK,OAAO,SACV,MAAM,QACN,MAAM,MACN,MAAM,SACL,MAAM,cAAc,EAAE,CACxB;AAGH,OAAK,qBAAqB,OAAO;AACjC,OAAK,UAAU,OAAO;AAGtB,oBAAkB,IAAI,cAAc,KAAK,OAAO,CAAC;;;CAInD,AAAQ,gBAAgB,KAAqB;EAC3C,IAAI,QAAQ,IAAI,QAAQ,MAAM;AAC9B,UAAQ,UAAU,KAAK,IAAI,QAAQ;EAEnC,MAAM,YAAY,IAAI,QAAQ,KAAK,MAAM;AACzC,MAAI,cAAc,GAAI,QAAO;EAE7B,IAAI,MAAM,IAAI,QAAQ,KAAK,UAAU;AACrC,MAAI,QAAQ,GAAI,OAAM,IAAI,QAAQ,KAAK,UAAU;AACjD,MAAI,QAAQ,GAAI,OAAM,IAAI;AAE1B,SAAO,IAAI,UAAU,WAAW,IAAI,IAAI;;;CAI1C,AAAQ,oBAAoB,QAAgB,UAA4B;EACtE,MAAM,iBAAiB,KAAK,OAAO,kBAAkB,SAAS;AAC9D,MAAI,eAAe,SAAS,EAC1B,QAAO,KACL;GACE,MAAM;GACN,SAAS,UAAU,OAAO;GAC1B;GACD,EACD,KACA,EAAE,OAAO,eAAe,KAAK,KAAK,EAAE,CACrC;AAEH,SAAO,KAAK;GAAE,MAAM;GAAK,SAAS;GAAa,EAAE,IAAI;;;CAIvD,QAAQ,OAAO,QAAoC;EACjD,MAAM,WAAW,KAAK,gBAAgB,IAAI,IAAI;EAC9C,MAAM,SAAS,IAAI;EAEnB,MAAM,QAAQ,KAAK,OAAO,MAAM,QAAQ,SAAS;AAEjD,MAAI,OAAO;AACT,GAAC,IAA2C,SAAS,MAAM;AAY3D,UAFgB,kBALM;IACpB,GAAG,KAAK;IACR;IACA,GAAG,MAAM;IACV,EACgD,MAAM,QAAQ,CAEhD,IAAI;;AAKrB,MAAI,WAAW,WAAW;GACxB,MAAM,iBAAiB,KAAK,OAAO,kBAAkB,SAAS;AAC9D,OAAI,eAAe,SAAS,GAAG;IAM7B,MAAM,kBAJW,KAAK,OAAO,MAC3B,eAAe,IACf,SACD,EACiC,cAAc,EAAE;IAClD,MAAM,gBAAgB;KACpB,GAAG,KAAK;KACR;KACA,GAAG;KACJ;IAGD,MAAM,uBACJ,IAAI,SAAS,MAAM;KACjB,QAAQ;KACR,SAAS,EAAE,OAAO,eAAe,KAAK,KAAK,EAAE;KAC9C,CAAC;AAGJ,WADgB,kBAAkB,eAAe,eAAe,CACjD,IAAI;;;AAKvB,MAAI,KAAK,iBAAiB,SAAS,EAKjC,QAHgB,kBADM,CAAC,GAAG,KAAK,kBAAkB,aAAa,QAE5D,KAAK,oBAAoB,QAAQ,SAAS,CAC3C,CACc,IAAI;AAGrB,SAAO,KAAK,oBAAoB,QAAQ,SAAS;;;CAInD,SAAS,OAA6B;AACpC,OAAK,OAAO,KAAK,MAAM;AACvB,OAAK,OAAO,SACV,MAAM,QACN,MAAM,MACN,MAAM,SACL,MAAM,cAAc,EAAE,CACxB;;;CAIH,UAAU,QAAyC;AACjD,OAAK,eAAe,CAAC,GAAG,OAAO,CAAC;;;CAIlC,YAAqD;AACnD,SAAO,KAAK,OAAO,WAAW;;;;;;;CAQhC,oBAAsC;AACpC,SAAO,KAAK"}
@@ -1,4 +1,4 @@
1
- import { t as Server } from "./server-DWndB63Z.mjs";
1
+ import { t as Server } from "./server-B4YDcNJy.mjs";
2
2
  import { t as ComponentServer } from "./component-server-Cya46YN3.mjs";
3
3
 
4
4
  //#region src/server/server-factory.ts
@@ -67,4 +67,4 @@ var ServerFactory = class {
67
67
 
68
68
  //#endregion
69
69
  export { ServerFactory as t };
70
- //# sourceMappingURL=server-CAhwnEPW.mjs.map
70
+ //# sourceMappingURL=server-BNpY3NH6.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-CAhwnEPW.mjs","names":[],"sources":["../src/server/server-factory.ts"],"sourcesContent":["import type { ProcessedRoute } from \"../defineRoute\";\nimport type {\n ComponentRoute,\n NestedComponentRoute,\n} from \"../types/component-route\";\nimport { Server } from \"../server\";\nimport { ComponentServer } from \"./component-server\";\n\n/**\n * 服务器工厂类\n * 用于创建和管理不同类型的服务器\n */\nexport class ServerFactory {\n private servers: Map<string, Server | ComponentServer> = new Map();\n\n /**\n * 创建标准REST API服务器\n */\n createRestServer(routes: ProcessedRoute[]): Server {\n const server = new Server(routes);\n this.servers.set(\"rest\", server);\n return server;\n }\n\n /**\n * 创建组件服务器\n */\n createComponentServer(\n routes: (ComponentRoute | NestedComponentRoute)[],\n ): ComponentServer {\n const server = new ComponentServer(routes);\n this.servers.set(\"component\", server);\n return server;\n }\n\n /**\n * 获取指定类型的服务器\n */\n getServer(type: \"rest\" | \"component\"): Server | ComponentServer | undefined {\n return this.servers.get(type);\n }\n\n /**\n * 获取所有服务器\n */\n getAllServers(): Map<string, Server | ComponentServer> {\n return this.servers;\n }\n\n /**\n * 移除指定类型的服务器\n */\n removeServer(type: string): boolean {\n return this.servers.delete(type);\n }\n\n /**\n * 清除所有服务器\n */\n clearServers(): void {\n this.servers.clear();\n }\n\n /**\n * 获取服务器状态信息\n */\n getServerStatus(): Record<string, { type: string; routes: number }> {\n const status: Record<string, { type: string; routes: number }> = {};\n\n for (const [name, server] of this.servers) {\n if (server instanceof Server) {\n status[name] = {\n type: \"REST API\",\n routes: (server as any).routes?.length || 0,\n };\n } else if (server instanceof ComponentServer) {\n status[name] = {\n type: \"Component\",\n routes: (server as any).routes?.length || 0,\n };\n }\n }\n\n return status;\n }\n}\n"],"mappings":";;;;;;;;AAYA,IAAa,gBAAb,MAA2B;CACzB,AAAQ,0BAAiD,IAAI,KAAK;;;;CAKlE,iBAAiB,QAAkC;EACjD,MAAM,SAAS,IAAI,OAAO,OAAO;AACjC,OAAK,QAAQ,IAAI,QAAQ,OAAO;AAChC,SAAO;;;;;CAMT,sBACE,QACiB;EACjB,MAAM,SAAS,IAAI,gBAAgB,OAAO;AAC1C,OAAK,QAAQ,IAAI,aAAa,OAAO;AACrC,SAAO;;;;;CAMT,UAAU,MAAkE;AAC1E,SAAO,KAAK,QAAQ,IAAI,KAAK;;;;;CAM/B,gBAAuD;AACrD,SAAO,KAAK;;;;;CAMd,aAAa,MAAuB;AAClC,SAAO,KAAK,QAAQ,OAAO,KAAK;;;;;CAMlC,eAAqB;AACnB,OAAK,QAAQ,OAAO;;;;;CAMtB,kBAAoE;EAClE,MAAM,SAA2D,EAAE;AAEnE,OAAK,MAAM,CAAC,MAAM,WAAW,KAAK,QAChC,KAAI,kBAAkB,OACpB,QAAO,QAAQ;GACb,MAAM;GACN,QAAS,OAAe,QAAQ,UAAU;GAC3C;WACQ,kBAAkB,gBAC3B,QAAO,QAAQ;GACb,MAAM;GACN,QAAS,OAAe,QAAQ,UAAU;GAC3C;AAIL,SAAO"}
1
+ {"version":3,"file":"server-BNpY3NH6.mjs","names":[],"sources":["../src/server/server-factory.ts"],"sourcesContent":["import type { ProcessedRoute } from \"../defineRoute\";\nimport type {\n ComponentRoute,\n NestedComponentRoute,\n} from \"../types/component-route\";\nimport { Server } from \"../server\";\nimport { ComponentServer } from \"./component-server\";\n\n/**\n * 服务器工厂类\n * 用于创建和管理不同类型的服务器\n */\nexport class ServerFactory {\n private servers: Map<string, Server | ComponentServer> = new Map();\n\n /**\n * 创建标准REST API服务器\n */\n createRestServer(routes: ProcessedRoute[]): Server {\n const server = new Server(routes);\n this.servers.set(\"rest\", server);\n return server;\n }\n\n /**\n * 创建组件服务器\n */\n createComponentServer(\n routes: (ComponentRoute | NestedComponentRoute)[],\n ): ComponentServer {\n const server = new ComponentServer(routes);\n this.servers.set(\"component\", server);\n return server;\n }\n\n /**\n * 获取指定类型的服务器\n */\n getServer(type: \"rest\" | \"component\"): Server | ComponentServer | undefined {\n return this.servers.get(type);\n }\n\n /**\n * 获取所有服务器\n */\n getAllServers(): Map<string, Server | ComponentServer> {\n return this.servers;\n }\n\n /**\n * 移除指定类型的服务器\n */\n removeServer(type: string): boolean {\n return this.servers.delete(type);\n }\n\n /**\n * 清除所有服务器\n */\n clearServers(): void {\n this.servers.clear();\n }\n\n /**\n * 获取服务器状态信息\n */\n getServerStatus(): Record<string, { type: string; routes: number }> {\n const status: Record<string, { type: string; routes: number }> = {};\n\n for (const [name, server] of this.servers) {\n if (server instanceof Server) {\n status[name] = {\n type: \"REST API\",\n routes: (server as any).routes?.length || 0,\n };\n } else if (server instanceof ComponentServer) {\n status[name] = {\n type: \"Component\",\n routes: (server as any).routes?.length || 0,\n };\n }\n }\n\n return status;\n }\n}\n"],"mappings":";;;;;;;;AAYA,IAAa,gBAAb,MAA2B;CACzB,AAAQ,0BAAiD,IAAI,KAAK;;;;CAKlE,iBAAiB,QAAkC;EACjD,MAAM,SAAS,IAAI,OAAO,OAAO;AACjC,OAAK,QAAQ,IAAI,QAAQ,OAAO;AAChC,SAAO;;;;;CAMT,sBACE,QACiB;EACjB,MAAM,SAAS,IAAI,gBAAgB,OAAO;AAC1C,OAAK,QAAQ,IAAI,aAAa,OAAO;AACrC,SAAO;;;;;CAMT,UAAU,MAAkE;AAC1E,SAAO,KAAK,QAAQ,IAAI,KAAK;;;;;CAM/B,gBAAuD;AACrD,SAAO,KAAK;;;;;CAMd,aAAa,MAAuB;AAClC,SAAO,KAAK,QAAQ,OAAO,KAAK;;;;;CAMlC,eAAqB;AACnB,OAAK,QAAQ,OAAO;;;;;CAMtB,kBAAoE;EAClE,MAAM,SAA2D,EAAE;AAEnE,OAAK,MAAM,CAAC,MAAM,WAAW,KAAK,QAChC,KAAI,kBAAkB,OACpB,QAAO,QAAQ;GACb,MAAM;GACN,QAAS,OAAe,QAAQ,UAAU;GAC3C;WACQ,kBAAkB,gBAC3B,QAAO,QAAQ;GACb,MAAM;GACN,QAAS,OAAe,QAAQ,UAAU;GAC3C;AAIL,SAAO"}
@@ -1,4 +1,4 @@
1
- import { a as ProcessedRoute } from "./defineRoute-B9VdaoQA.mjs";
1
+ import { a as ProcessedRoute } from "./defineRoute-DKVyYELW.mjs";
2
2
  import { n as Method } from "./types-aczawQFE.mjs";
3
3
  import { t as BaseServer } from "./base-server-CeJ8LTBk.mjs";
4
4
 
@@ -45,4 +45,4 @@ declare class Server extends BaseServer {
45
45
  }
46
46
  //#endregion
47
47
  export { Server as t };
48
- //# sourceMappingURL=server-CQ-_WgQN.d.mts.map
48
+ //# sourceMappingURL=server-D3IERUlj.d.mts.map
@@ -0,0 +1,76 @@
1
+ //#region src/utils/sse.d.ts
2
+ /**
3
+ * Server-Sent Events (SSE) 类型定义
4
+ *
5
+ * SSE 端点通过 `sse: true` 显式声明,handler 使用 async generator 语法
6
+ *
7
+ * ## 简单模式(推荐)
8
+ *
9
+ * 直接 yield 任意数据,框架自动包装为 SSE data 字段:
10
+ *
11
+ * ```typescript
12
+ * defineRoute({
13
+ * method: 'POST',
14
+ * path: '/chat/stream',
15
+ * sse: true,
16
+ * handler: async function* ({ body }) {
17
+ * // 直接 yield 数据,框架自动处理
18
+ * yield { type: 'start', message: 'Starting...' }
19
+ *
20
+ * for await (const chunk of aiStream(body.prompt)) {
21
+ * yield chunk // 任意对象都可以
22
+ * }
23
+ *
24
+ * yield { type: 'done', message: 'Complete!' }
25
+ * }
26
+ * })
27
+ * ```
28
+ *
29
+ * ## 高级模式
30
+ *
31
+ * 如果需要设置 SSE event/id/retry,使用 `__sse__` 标记:
32
+ *
33
+ * ```typescript
34
+ * yield {
35
+ * __sse__: { event: 'status', id: '123', retry: 5000 },
36
+ * data: { progress: 50 }
37
+ * }
38
+ * ```
39
+ */
40
+ /**
41
+ * SSE 元数据(高级模式)
42
+ */
43
+ interface SSEMeta {
44
+ /** SSE 事件名称 */
45
+ event?: string;
46
+ /** SSE 事件 ID */
47
+ id?: string;
48
+ /** SSE 重试间隔(毫秒) */
49
+ retry?: number;
50
+ }
51
+ /**
52
+ * 带元数据的 SSE 事件(高级模式)
53
+ */
54
+ interface SSEEventWithMeta<T = unknown> {
55
+ /** SSE 元数据标记 */
56
+ __sse__: SSEMeta;
57
+ /** 事件数据 */
58
+ data: T;
59
+ }
60
+ /**
61
+ * SSE 事件类型(兼容旧版,不推荐使用)
62
+ * @deprecated 直接 yield 数据即可,无需包装
63
+ */
64
+ interface SSEEvent<T = unknown> {
65
+ /** 事件名称(可选,默认为 message) */
66
+ event?: string;
67
+ /** 事件数据 */
68
+ data: T;
69
+ /** 事件 ID(可选) */
70
+ id?: string;
71
+ /** 重试间隔(毫秒,可选) */
72
+ retry?: number;
73
+ }
74
+ //#endregion
75
+ export { SSEEventWithMeta as n, SSEMeta as r, SSEEvent as t };
76
+ //# sourceMappingURL=sse-BqvrwmK6.d.mts.map
@@ -1,4 +1,4 @@
1
- import "../defineRoute-B9VdaoQA.mjs";
1
+ import "../defineRoute-DKVyYELW.mjs";
2
2
  import { t as DependencyManager } from "../dependency-manager-mqzLAocb.mjs";
3
3
  import { a as parseBody, c as parseCookiesFast, d as parseHeaders, f as parseQuery, i as getHeader, p as parseQueryFast, r as getCookie, s as parseCookies } from "../parsers-BAQtDA1q.mjs";
4
4
  import { c as text, i as json, n as err, o as redirect, r as html, s as stream, t as empty } from "../response-lI0YZoia.mjs";
@@ -7,7 +7,7 @@ import { n as base64urlEncode, t as base64urlDecode } from "../base64url-CAmasWF
7
7
  import { t as HtmlRenderer } from "../html-renderer-Up52eIS6.mjs";
8
8
  import { a as ValidationError, c as getValidatorCacheStats, d as validateFast, f as validateSchema, l as precompileSchemas, o as ValidationResult, p as validateSchemaOrThrow, s as createValidator, t as SchemaConfig, u as validateAllSchemas } from "../validators-D5KJCSZr.mjs";
9
9
  import { i as registerFormats, n as hasFormat, r as registerFormat, t as Patterns } from "../formats-Ca7ASaYH.mjs";
10
- import { t as SSEEvent } from "../sse-D77CKcsH.mjs";
11
- import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "../route-registry-C6h13Mks.mjs";
10
+ import { t as SSEEvent } from "../sse-BqvrwmK6.mjs";
11
+ import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "../route-registry-C2a27CuM.mjs";
12
12
  import { n as generateAITools, r as getApiSpec, t as ApiSpec } from "../contract-C-xQoZ6r.mjs";
13
13
  export { type ApiSpec, DependencyManager, HtmlRenderer, Patterns, type RouteMeta, RouteRegistry, type SSEEvent, type SchemaConfig, type ValidationError, type ValidationResult, base64urlDecode, base64urlEncode, createRouteRegistry, createValidator, empty, err, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, json, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow };
@@ -1,3 +1,3 @@
1
- import "../defineRoute-B9VdaoQA.mjs";
2
- import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, l as setGlobalRegistry, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "../route-registry-C6h13Mks.mjs";
1
+ import "../defineRoute-DKVyYELW.mjs";
2
+ import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, l as setGlobalRegistry, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "../route-registry-C2a27CuM.mjs";
3
3
  export { RouteMeta, RouteRegistry, createRouteRegistry, filterRoutes, getAllRoutes, getRoute, getRouteRegistry, getRoutesByMethod, setGlobalRegistry };
@@ -1,2 +1,2 @@
1
- import { t as SSEEvent } from "../sse-D77CKcsH.mjs";
2
- export { SSEEvent };
1
+ import { n as SSEEventWithMeta, r as SSEMeta, t as SSEEvent } from "../sse-BqvrwmK6.mjs";
2
+ export { SSEEvent, SSEEventWithMeta, SSEMeta };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vafast",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "极简结构化Web框架,支持 Bun 和 Node.js。Go风格,函数优先。",
5
5
  "type": "module",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"radix-tree-CccjvyTP.mjs","names":[],"sources":["../src/router/radix-tree.ts"],"sourcesContent":["/**\n * Radix Tree 路由匹配器\n *\n * 高性能路由匹配实现,时间复杂度 O(k),k 为路径段数\n *\n * 支持的路由模式:\n * - 静态路径: /users, /api/v1/health\n * - 动态参数: /users/:id, /posts/:postId/comments/:commentId\n * - 通配符: /files/*, /static/*filepath\n */\n\nimport type { Handler, Middleware, Method } from \"../types\";\n\n/** 预编译的处理器类型 */\ntype CompiledHandler = (req: Request) => Promise<Response>;\n\n/** 路由处理信息 */\ninterface RouteHandler {\n handler: Handler;\n middleware: Middleware[];\n /** 预编译后的完整处理链(包含中间件) */\n compiled?: CompiledHandler;\n}\n\n/** Radix Tree 节点 */\ninterface RadixNode {\n path: string;\n children: Record<string, RadixNode>;\n paramChild?: RadixNode;\n wildcardChild?: RadixNode;\n paramName?: string;\n handlers: Record<Method, RouteHandler | undefined>;\n}\n\n/** 路由匹配结果 */\nexport interface MatchResult {\n handler: Handler;\n middleware: Middleware[];\n params: Record<string, string>;\n /** 预编译后的完整处理链 */\n compiled?: CompiledHandler;\n}\n\n/**\n * Radix Tree 路由器\n *\n * @example\n * ```typescript\n * const router = new RadixRouter();\n * router.register(\"GET\", \"/users/:id\", handler);\n * const result = router.match(\"GET\", \"/users/123\");\n * // result.params = { id: \"123\" }\n * ```\n */\nexport class RadixRouter {\n private root: RadixNode;\n\n constructor() {\n this.root = this.createNode(\"\");\n }\n\n private createNode(path: string): RadixNode {\n return {\n path,\n children: Object.create(null),\n handlers: Object.create(null),\n };\n }\n\n /** 分割路径 */\n private splitPath(path: string): string[] {\n return path.split(\"/\").filter(Boolean);\n }\n\n /** 编译器函数 - 用于预编译中间件链 */\n private compiler?: (\n middleware: Middleware[],\n handler: Handler,\n ) => CompiledHandler;\n\n /** 设置中间件编译器 */\n setCompiler(\n compiler: (middleware: Middleware[], handler: Handler) => CompiledHandler,\n ): void {\n this.compiler = compiler;\n }\n\n /** 注册路由 */\n register(\n method: Method,\n pattern: string,\n handler: Handler,\n middleware: Middleware[] = [],\n ): void {\n const segments = this.splitPath(pattern);\n let node = this.root;\n\n for (const segment of segments) {\n const firstChar = segment[0];\n\n if (firstChar === \":\") {\n // 动态参数节点\n if (!node.paramChild) {\n node.paramChild = this.createNode(segment);\n node.paramChild.paramName = segment.substring(1);\n }\n node = node.paramChild;\n } else if (firstChar === \"*\") {\n // 通配符节点\n if (!node.wildcardChild) {\n node.wildcardChild = this.createNode(segment);\n node.wildcardChild.paramName =\n segment.length > 1 ? segment.substring(1) : \"*\";\n }\n node = node.wildcardChild;\n break;\n } else {\n // 静态路径节点\n if (!node.children[segment]) {\n node.children[segment] = this.createNode(segment);\n }\n node = node.children[segment];\n }\n }\n\n const routeHandler: RouteHandler = { handler, middleware };\n\n // 如果没有全局中间件且设置了编译器,预编译处理链\n if (this.compiler && middleware.length === 0) {\n routeHandler.compiled = this.compiler([], handler);\n }\n\n node.handlers[method] = routeHandler;\n }\n\n /** 预编译所有路由(在添加全局中间件后调用) */\n precompileAll(globalMiddleware: Middleware[]): void {\n if (!this.compiler) return;\n this.precompileNode(this.root, globalMiddleware);\n }\n\n private precompileNode(\n node: RadixNode,\n globalMiddleware: Middleware[],\n ): void {\n for (const method in node.handlers) {\n const routeHandler = node.handlers[method as Method];\n if (routeHandler) {\n const allMiddleware = [...globalMiddleware, ...routeHandler.middleware];\n routeHandler.compiled = this.compiler!(\n allMiddleware,\n routeHandler.handler,\n );\n }\n }\n\n for (const key in node.children) {\n this.precompileNode(node.children[key], globalMiddleware);\n }\n\n if (node.paramChild) {\n this.precompileNode(node.paramChild, globalMiddleware);\n }\n\n if (node.wildcardChild) {\n this.precompileNode(node.wildcardChild, globalMiddleware);\n }\n }\n\n /** 匹配路由 */\n match(method: Method, path: string): MatchResult | null {\n const segments = this.splitPath(path);\n const params: Record<string, string> = Object.create(null);\n\n const node = this.matchNode(this.root, segments, 0, params);\n if (!node) return null;\n\n const routeHandler = node.handlers[method];\n if (!routeHandler) return null;\n\n return {\n handler: routeHandler.handler,\n middleware: routeHandler.middleware,\n params,\n compiled: routeHandler.compiled,\n };\n }\n\n /** 递归匹配节点 (优先级: 静态 > 动态参数 > 通配符) */\n private matchNode(\n node: RadixNode,\n segments: string[],\n index: number,\n params: Record<string, string>,\n ): RadixNode | null {\n if (index === segments.length) {\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) return node;\n }\n return null;\n }\n\n const segment = segments[index];\n\n // 1. 静态路径\n const staticChild = node.children[segment];\n if (staticChild) {\n const result = this.matchNode(staticChild, segments, index + 1, params);\n if (result) return result;\n }\n\n // 2. 动态参数\n if (node.paramChild) {\n const paramName = node.paramChild.paramName!;\n const oldValue = params[paramName];\n\n params[paramName] = segment;\n const result = this.matchNode(\n node.paramChild,\n segments,\n index + 1,\n params,\n );\n\n if (result) return result;\n\n // 回溯\n if (oldValue === undefined) {\n delete params[paramName];\n } else {\n params[paramName] = oldValue;\n }\n }\n\n // 3. 通配符\n if (node.wildcardChild) {\n params[node.wildcardChild.paramName || \"*\"] = segments\n .slice(index)\n .join(\"/\");\n return node.wildcardChild;\n }\n\n return null;\n }\n\n /** 获取路径允许的 HTTP 方法 */\n getAllowedMethods(path: string): Method[] {\n const segments = this.splitPath(path);\n const node = this.findNode(segments);\n if (!node) return [];\n\n const methods: Method[] = [];\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) {\n methods.push(method as Method);\n }\n }\n return methods;\n }\n\n /** 查找节点(不提取参数) */\n private findNode(segments: string[]): RadixNode | null {\n let node = this.root;\n\n for (const segment of segments) {\n if (node.children[segment]) {\n node = node.children[segment];\n } else if (node.paramChild) {\n node = node.paramChild;\n } else if (node.wildcardChild) {\n return node.wildcardChild;\n } else {\n return null;\n }\n }\n\n return node;\n }\n\n /** 获取所有已注册的路由 */\n getRoutes(): Array<{ method: Method; path: string }> {\n const routes: Array<{ method: Method; path: string }> = [];\n this.collectRoutes(this.root, \"\", routes);\n return routes;\n }\n\n private collectRoutes(\n node: RadixNode,\n prefix: string,\n routes: Array<{ method: Method; path: string }>,\n ): void {\n const currentPath = prefix + (node.path ? \"/\" + node.path : \"\");\n\n for (const method in node.handlers) {\n if (node.handlers[method as Method]) {\n routes.push({ method: method as Method, path: currentPath || \"/\" });\n }\n }\n\n for (const key in node.children) {\n this.collectRoutes(node.children[key], currentPath, routes);\n }\n\n if (node.paramChild) {\n this.collectRoutes(node.paramChild, currentPath, routes);\n }\n\n if (node.wildcardChild) {\n this.collectRoutes(node.wildcardChild, currentPath, routes);\n }\n }\n}\n"],"mappings":"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"}
@@ -1,45 +0,0 @@
1
- //#region src/utils/sse.d.ts
2
- /**
3
- * Server-Sent Events (SSE) 类型定义
4
- *
5
- * SSE 端点通过 `sse: true` 显式声明,handler 使用 async generator 语法
6
- *
7
- * @example
8
- * ```typescript
9
- * import { defineRoute, Type } from 'vafast'
10
- *
11
- * defineRoute({
12
- * method: 'POST',
13
- * path: '/chat/stream',
14
- * sse: true, // 显式声明 SSE 端点
15
- * schema: {
16
- * body: Type.Object({ prompt: Type.String() })
17
- * },
18
- * handler: async function* ({ body }) {
19
- * yield { event: 'start', data: { message: 'Starting...' } }
20
- *
21
- * for await (const chunk of aiStream(body.prompt)) {
22
- * yield { data: chunk }
23
- * }
24
- *
25
- * yield { event: 'end', data: { message: 'Done!' } }
26
- * }
27
- * })
28
- * ```
29
- */
30
- /**
31
- * SSE 事件类型
32
- */
33
- interface SSEEvent<T = unknown> {
34
- /** 事件名称(可选,默认为 message) */
35
- event?: string;
36
- /** 事件数据 */
37
- data: T;
38
- /** 事件 ID(可选) */
39
- id?: string;
40
- /** 重试间隔(毫秒,可选) */
41
- retry?: number;
42
- }
43
- //#endregion
44
- export { SSEEvent as t };
45
- //# sourceMappingURL=sse-D77CKcsH.d.mts.map