vafast 0.5.5 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,21 +8,24 @@
8
8
 
9
9
  > Vafast 不只是框架,更是一种 **结构、清晰、可控** 的开发哲学。
10
10
 
11
- ```typescript
12
- import { Server, createHandler } from 'vafast';
13
-
14
- const server = new Server([
15
- { method: 'GET', path: '/', handler: createHandler(() => 'Hello Vafast!') }
16
- ]);
11
+ ## 🚀 快速开始
17
12
 
18
- export default { port: 3000, fetch: server.fetch };
13
+ ```bash
14
+ npx create-vafast-app
19
15
  ```
20
16
 
17
+ 按照提示输入项目名称,然后运行:
18
+
21
19
  ```bash
22
- # 启动服务器
23
- npx tsx index.ts
20
+ cd my-vafast-app
21
+ npm install
22
+ npm run dev
24
23
  ```
25
24
 
25
+ 访问 [http://localhost:3000](http://localhost:3000) 即可看到 "Hello Vafast!"。
26
+
27
+ > 💡 想要手动配置?查看 [安装](#-安装) 部分。
28
+
26
29
  ## ⚡ 性能
27
30
 
28
31
  | 框架 | RPS | 相对性能 |
@@ -37,10 +40,47 @@ npx tsx index.ts
37
40
 
38
41
  ## 📦 安装
39
42
 
43
+ ### 方式一:使用脚手架(推荐)
44
+
45
+ 使用官方脚手架快速创建项目:
46
+
47
+ ```bash
48
+ npx create-vafast-app
49
+ ```
50
+
51
+ ### 方式二:手动安装
52
+
53
+ 在现有项目中安装:
54
+
40
55
  ```bash
41
56
  npm install vafast
42
57
  ```
43
58
 
59
+ 然后创建 `index.ts`:
60
+
61
+ ```typescript
62
+ import { Server, defineRoute, defineRoutes, serve } from 'vafast';
63
+
64
+ const routes = defineRoutes([
65
+ defineRoute({
66
+ method: 'GET',
67
+ path: '/',
68
+ handler: () => 'Hello Vafast!'
69
+ })
70
+ ]);
71
+
72
+ const server = new Server(routes);
73
+ serve({ fetch: server.fetch, port: 3000 }, (info) => {
74
+ console.log(`🚀 Server running at http://localhost:${info.port}`);
75
+ });
76
+ ```
77
+
78
+ 运行:
79
+
80
+ ```bash
81
+ npx tsx index.ts
82
+ ```
83
+
44
84
  ## 💡 设计哲学
45
85
 
46
86
  ### 结构即真相 — 无装饰器,无链式魔法
@@ -72,14 +112,25 @@ export default app;
72
112
 
73
113
  **Vafast 完整示例:**
74
114
  ```typescript
75
- import { Server, createHandler } from 'vafast';
76
- import type { Route } from 'vafast';
115
+ import { Server, defineRoute, defineRoutes } from 'vafast';
77
116
 
78
- const routes: Route[] = [
79
- { method: 'GET', path: '/users', handler: createHandler(() => 'list users') },
80
- { method: 'POST', path: '/users', handler: createHandler(({ body }) => body) },
81
- { method: 'GET', path: '/users/:id', handler: createHandler(({ params }) => `User ${params.id}`) },
82
- ];
117
+ const routes = defineRoutes([
118
+ defineRoute({
119
+ method: 'GET',
120
+ path: '/users',
121
+ handler: () => 'list users'
122
+ }),
123
+ defineRoute({
124
+ method: 'POST',
125
+ path: '/users',
126
+ handler: ({ body }) => body
127
+ }),
128
+ defineRoute({
129
+ method: 'GET',
130
+ path: '/users/:id',
131
+ handler: ({ params }) => `User ${params.id}`
132
+ }),
133
+ ]);
83
134
 
84
135
  const server = new Server(routes);
85
136
  export default { fetch: server.fetch };
@@ -110,22 +161,21 @@ export default app;
110
161
 
111
162
  **Vafast 完整示例:**
112
163
  ```typescript
113
- import { Server, createHandler, err } from 'vafast';
114
- import type { Route } from 'vafast';
164
+ import { Server, defineRoute, defineRoutes, err } from 'vafast';
115
165
 
116
- const routes: Route[] = [
117
- {
166
+ const routes = defineRoutes([
167
+ defineRoute({
118
168
  method: 'GET',
119
169
  path: '/user',
120
- handler: createHandler((ctx) => {
121
- const name = ctx.query.name;
170
+ handler: ({ query }) => {
171
+ const name = query.name;
122
172
  if (!name) {
123
173
  throw err.badRequest('Missing name'); // ✨ 简洁!
124
174
  }
125
175
  return `Hello, ${name}`;
126
- }),
127
- },
128
- ];
176
+ },
177
+ }),
178
+ ]);
129
179
 
130
180
  const server = new Server(routes);
131
181
  export default { fetch: server.fetch };
@@ -155,21 +205,29 @@ export default app;
155
205
 
156
206
  **Vafast 完整示例:**
157
207
  ```typescript
158
- import { Server, createHandler } from 'vafast';
159
- import type { Route, Middleware } from 'vafast';
208
+ import { Server, defineRoute, defineRoutes, defineMiddleware } from 'vafast';
160
209
 
161
- const authMiddleware: Middleware = async (req, next) => {
210
+ const authMiddleware = defineMiddleware(async (req, next) => {
162
211
  const token = req.headers.get('Authorization');
163
212
  if (!token) return new Response('Unauthorized', { status: 401 });
164
213
  return next();
165
- };
214
+ });
166
215
 
167
- const routes: Route[] = [
216
+ const routes = defineRoutes([
168
217
  // 无中间件
169
- { method: 'GET', path: '/public', handler: createHandler(() => 'public') },
218
+ defineRoute({
219
+ method: 'GET',
220
+ path: '/public',
221
+ handler: () => 'public'
222
+ }),
170
223
  // 仅 auth
171
- { method: 'GET', path: '/api/users', middleware: [authMiddleware], handler: createHandler(() => 'users') },
172
- ];
224
+ defineRoute({
225
+ method: 'GET',
226
+ path: '/api/users',
227
+ middleware: [authMiddleware],
228
+ handler: () => 'users'
229
+ }),
230
+ ]);
173
231
 
174
232
  const server = new Server(routes);
175
233
  export default { fetch: server.fetch };
@@ -177,6 +235,69 @@ export default { fetch: server.fetch };
177
235
 
178
236
  **对比:Vafast 的中间件直接声明在路由上,一目了然。**
179
237
 
238
+ ### 扩展字段 — 声明式元数据,赋能业务逻辑
239
+
240
+ **其他框架的问题:**
241
+ - 路由定义和元数据分离,难以统一管理
242
+ - 需要额外的配置文件或装饰器来存储 webhook、权限、计费等信息
243
+ - 元数据查询需要遍历路由或维护独立映射表
244
+
245
+ **Vafast 完整示例:**
246
+ ```typescript
247
+ import { Server, defineRoute, defineRoutes, getRouteRegistry, defineMiddleware } from 'vafast';
248
+
249
+ // 计费中间件(基于路由元数据)
250
+ const billingMiddleware = defineMiddleware(async (req, next) => {
251
+ const route = getRouteRegistry().get(req.method, new URL(req.url).pathname);
252
+
253
+ // 从路由元数据读取计费配置
254
+ if (route?.billing) {
255
+ const { price, currency } = route.billing;
256
+ // 执行计费逻辑
257
+ await chargeUser(req, price, currency);
258
+ }
259
+
260
+ return next();
261
+ });
262
+
263
+ const routes = defineRoutes([
264
+ defineRoute({
265
+ method: 'POST',
266
+ path: '/ai/generate',
267
+ name: 'AI 生成',
268
+ description: '生成 AI 内容',
269
+ // ✨ 扩展字段:计费配置
270
+ billing: { price: 0.01, currency: 'USD' },
271
+ // ✨ 扩展字段:Webhook 事件
272
+ webhook: { eventKey: 'ai.generate', enabled: true },
273
+ // ✨ 扩展字段:权限要求
274
+ permission: 'ai.generate',
275
+ middleware: [billingMiddleware],
276
+ handler: async ({ body }) => {
277
+ const result = await generateAI(body.prompt);
278
+ return { result };
279
+ }
280
+ }),
281
+ defineRoute({
282
+ method: 'GET',
283
+ path: '/users',
284
+ // 免费 API,无需计费
285
+ handler: () => ({ users: [] })
286
+ }),
287
+ ]);
288
+
289
+ const server = new Server(routes);
290
+
291
+ // 查询所有需要计费的 API
292
+ const paidRoutes = getRouteRegistry().filter('billing');
293
+ // 查询所有 Webhook 事件
294
+ const webhookRoutes = getRouteRegistry().filter('webhook');
295
+ // 按权限筛选
296
+ const aiRoutes = getRouteRegistry().filterBy(r => r.permission?.startsWith('ai.'));
297
+ ```
298
+
299
+ **对比:Vafast 的扩展字段让路由定义成为单一数据源,元数据查询、中间件配置、业务逻辑都基于声明式配置。**
300
+
180
301
  ### 类型注入 — 跨文件不丢失
181
302
 
182
303
  **Hono 跨文件类型问题:**
@@ -205,33 +326,37 @@ export function setupRoutes(app: Hono) {
205
326
  export type AuthContext = { user: { id: string; role: string } };
206
327
 
207
328
  // -------- file: middleware/auth.ts --------
208
- import type { Middleware } from 'vafast';
329
+ import { defineMiddleware } from 'vafast';
330
+ import type { AuthContext } from '../types';
209
331
 
210
- export const authMiddleware: Middleware = async (req, next) => {
332
+ // 使用 defineMiddleware 定义带类型的中间件
333
+ export const authMiddleware = defineMiddleware<AuthContext>(async (req, next) => {
211
334
  const user = await verifyToken(req.headers.get('Authorization'));
212
- (req as any).__locals = { user };
213
- return next();
214
- };
335
+ return next({ user }); // 通过 next 传递上下文
336
+ });
215
337
 
216
338
  // -------- file: handlers/profile.ts --------
217
- import { createHandlerWithExtra } from 'vafast';
218
- import type { AuthContext } from '../types';
339
+ import { defineRoute } from 'vafast';
340
+ import { authMiddleware } from '../middleware/auth';
219
341
 
220
- // 类型在 Handler 级别定义,任意文件都能用!
221
- export const getProfile = createHandlerWithExtra<AuthContext>((ctx) => {
222
- const user = ctx.user; // ✅ 类型完整: { id: string; role: string }
223
- return { profile: user, isAdmin: user.role === 'admin' };
342
+ // 类型在路由级别定义,任意文件都能用!
343
+ export const getProfileRoute = defineRoute({
344
+ method: 'GET',
345
+ path: '/profile',
346
+ middleware: [authMiddleware],
347
+ handler: ({ user }) => {
348
+ // ✅ user 自动有类型: { id: string; role: string }
349
+ return { profile: user, isAdmin: user.role === 'admin' };
350
+ }
224
351
  });
225
352
 
226
353
  // -------- file: routes.ts --------
227
- import { Server } from 'vafast';
228
- import type { Route } from 'vafast';
229
- import { authMiddleware } from './middleware/auth';
230
- import { getProfile } from './handlers/profile';
354
+ import { Server, defineRoutes } from 'vafast';
355
+ import { getProfileRoute } from './handlers/profile';
231
356
 
232
- const routes: Route[] = [
233
- { method: 'GET', path: '/profile', middleware: [authMiddleware], handler: getProfile },
234
- ];
357
+ const routes = defineRoutes([
358
+ getProfileRoute,
359
+ ]);
235
360
 
236
361
  const server = new Server(routes);
237
362
  export default { fetch: server.fetch };
@@ -243,34 +368,49 @@ export default { fetch: server.fetch };
243
368
 
244
369
  **Bun 环境完整示例:**
245
370
  ```typescript
246
- import { Server, createHandler } from 'vafast';
371
+ import { Server, defineRoute, defineRoutes } from 'vafast';
247
372
 
248
- const server = new Server([
249
- { method: 'GET', path: '/', handler: createHandler(() => 'Hello Bun!') }
373
+ const routes = defineRoutes([
374
+ defineRoute({
375
+ method: 'GET',
376
+ path: '/',
377
+ handler: () => 'Hello Bun!'
378
+ })
250
379
  ]);
251
380
 
381
+ const server = new Server(routes);
252
382
  export default { port: 3000, fetch: server.fetch };
253
383
  ```
254
384
 
255
385
  **Cloudflare Workers 完整示例:**
256
386
  ```typescript
257
- import { Server, createHandler } from 'vafast';
387
+ import { Server, defineRoute, defineRoutes } from 'vafast';
258
388
 
259
- const server = new Server([
260
- { method: 'GET', path: '/', handler: createHandler(() => 'Hello Workers!') }
389
+ const routes = defineRoutes([
390
+ defineRoute({
391
+ method: 'GET',
392
+ path: '/',
393
+ handler: () => 'Hello Workers!'
394
+ })
261
395
  ]);
262
396
 
397
+ const server = new Server(routes);
263
398
  export default { fetch: server.fetch };
264
399
  ```
265
400
 
266
401
  **Node.js 完整示例:**
267
402
  ```typescript
268
- import { Server, createHandler, serve } from 'vafast';
403
+ import { Server, defineRoute, defineRoutes, serve } from 'vafast';
269
404
 
270
- const server = new Server([
271
- { method: 'GET', path: '/', handler: createHandler(() => 'Hello Node!') }
405
+ const routes = defineRoutes([
406
+ defineRoute({
407
+ method: 'GET',
408
+ path: '/',
409
+ handler: () => 'Hello Node!'
410
+ })
272
411
  ]);
273
412
 
413
+ const server = new Server(routes);
274
414
  serve({ fetch: server.fetch, port: 3000 }, () => {
275
415
  console.log('Server running on http://localhost:3000');
276
416
  });
@@ -287,9 +427,13 @@ nest new my-app # 生成 20+ 文件
287
427
  # ❌ Express - 需要配置和样板代码
288
428
  npm init && npm install express && mkdir routes controllers...
289
429
 
290
- # ✅ Vafast - 一个文件搞定
291
- echo "import { Server } from 'vafast';
292
- const server = new Server([{ method: 'GET', path: '/', handler: () => 'Hi' }]);
430
+ # ✅ Vafast - 使用脚手架一键创建
431
+ npx create-vafast-app
432
+
433
+ # ✅ 或手动创建 - 一个文件搞定
434
+ echo "import { Server, defineRoute, defineRoutes } from 'vafast';
435
+ const routes = defineRoutes([defineRoute({ method: 'GET', path: '/', handler: () => 'Hi' })]);
436
+ const server = new Server(routes);
293
437
  export default { fetch: server.fetch };" > index.ts && bun index.ts
294
438
  ```
295
439
 
@@ -304,6 +448,9 @@ export default { fetch: server.fetch };" > index.ts && bun index.ts
304
448
  | **类型推断** | 优秀 | 良好 | **优秀 (TypeBox)** |
305
449
  | **跨文件类型** | ⚠️ 链断裂丢失 | ❌ 实例绑定丢失 | **✅ Handler 级独立** |
306
450
  | **类型定义位置** | 链式调用上下文 | App 实例泛型 | **Handler 泛型参数** |
451
+ | **扩展字段** | ❌ 不支持 | ❌ 不支持 | **✅ 任意扩展字段** |
452
+ | **元数据查询** | ❌ 需遍历 | ❌ 需遍历 | **✅ RouteRegistry API** |
453
+ | **业务集成** | ⚠️ 需额外配置 | ⚠️ 需额外配置 | **✅ 声明式集成** |
307
454
  | **性能 (RPS)** | ~118K | ~56K | **~101K** |
308
455
  | **学习曲线** | 中等 | 简单 | **简单** |
309
456
  | **API 风格** | 函数式链 | Express-like | **配置式** |
@@ -317,8 +464,11 @@ export default { fetch: server.fetch };" > index.ts && bun index.ts
317
464
  | **需要路由一览表** | **✅ Vafast** |
318
465
  | **需要精确中间件控制** | **✅ Vafast** |
319
466
  | **需要结构化错误** | **✅ Vafast** |
467
+ | **需要扩展字段(webhook、计费、权限)** | **✅ Vafast** |
468
+ | **需要元数据查询和筛选** | **✅ Vafast (RouteRegistry)** |
320
469
  | **大型项目多文件拆分** | **✅ Vafast (类型不丢失)** |
321
470
  | **团队协作类型安全** | **✅ Vafast** |
471
+ | **API 网关/微服务场景** | **✅ Vafast (声明式配置)** |
322
472
  | 从 Express 迁移 | Hono (API 相似) |
323
473
 
324
474
  ## 🎯 核心功能
@@ -335,25 +485,31 @@ export default { fetch: server.fetch };" > index.ts && bun index.ts
335
485
  Vafast 提供简洁、对称的响应 API:
336
486
 
337
487
  ```typescript
338
- import { createHandler, json, err } from 'vafast';
339
-
340
- // ==================== 成功响应 ====================
341
- return user // 200 + JSON(自动转换)
342
- return json(user, 201) // 201 Created
343
- return json(user, 200, { // 自定义头部
344
- 'X-Request-Id': 'abc123'
488
+ import { defineRoute, json, err } from 'vafast';
489
+
490
+ defineRoute({
491
+ method: 'POST',
492
+ path: '/users',
493
+ handler: ({ body }) => {
494
+ // ==================== 成功响应 ====================
495
+ return body // 200 + JSON(自动转换)
496
+ return json(body, 201) // 201 Created
497
+ return json(body, 200, { // 自定义头部
498
+ 'X-Request-Id': 'abc123'
499
+ })
500
+ return 'Hello' // 200 + text/plain
501
+ return new Response(...) // 完全控制
502
+
503
+ // ==================== 错误响应 ====================
504
+ throw err.badRequest('参数错误') // 400
505
+ throw err.unauthorized('请先登录') // 401
506
+ throw err.forbidden('无权限') // 403
507
+ throw err.notFound('用户不存在') // 404
508
+ throw err.conflict('用户名已存在') // 409
509
+ throw err.internal('服务器错误') // 500
510
+ throw err('自定义错误', 422, 'CUSTOM_TYPE') // 自定义
511
+ }
345
512
  })
346
- return 'Hello' // 200 + text/plain
347
- return new Response(...) // 完全控制
348
-
349
- // ==================== 错误响应 ====================
350
- throw err.badRequest('参数错误') // 400
351
- throw err.unauthorized('请先登录') // 401
352
- throw err.forbidden('无权限') // 403
353
- throw err.notFound('用户不存在') // 404
354
- throw err.conflict('用户名已存在') // 409
355
- throw err.internal('服务器错误') // 500
356
- throw err('自定义错误', 422, 'CUSTOM_TYPE') // 自定义
357
513
  ```
358
514
 
359
515
  **API 速查表:**
@@ -372,20 +528,20 @@ throw err('自定义错误', 422, 'CUSTOM_TYPE') // 自定义
372
528
  ### 类型安全的路由
373
529
 
374
530
  ```typescript
375
- import { Server, defineRoutes, createHandler, Type } from 'vafast';
531
+ import { Server, defineRoute, defineRoutes, Type } from 'vafast';
376
532
 
377
533
  const routes = defineRoutes([
378
- {
534
+ defineRoute({
379
535
  method: 'POST',
380
536
  path: '/users',
381
- handler: createHandler(
382
- { body: Type.Object({ name: Type.String(), email: Type.String() }) },
383
- ({ body }) => {
384
- // body.name body.email 自动类型推断
385
- return { success: true, user: body };
386
- }
387
- )
388
- }
537
+ schema: {
538
+ body: Type.Object({ name: Type.String(), email: Type.String() })
539
+ },
540
+ handler: ({ body }) => {
541
+ // body.name body.email 自动类型推断
542
+ return { success: true, user: body };
543
+ }
544
+ })
389
545
  ]);
390
546
 
391
547
  const server = new Server(routes);
@@ -395,32 +551,34 @@ export default { port: 3000, fetch: server.fetch };
395
551
  ### 路径参数
396
552
 
397
553
  ```typescript
398
- {
554
+ defineRoute({
399
555
  method: 'GET',
400
556
  path: '/users/:id',
401
- handler: createHandler(
402
- { params: Type.Object({ id: Type.String() }) },
403
- ({ params }) => ({ userId: params.id })
404
- )
405
- }
557
+ schema: {
558
+ params: Type.Object({ id: Type.String() })
559
+ },
560
+ handler: ({ params }) => ({ userId: params.id })
561
+ })
406
562
  ```
407
563
 
408
564
  ### 中间件
409
565
 
410
566
  ```typescript
411
- const authMiddleware = async (req, next) => {
567
+ import { defineMiddleware } from 'vafast';
568
+
569
+ const authMiddleware = defineMiddleware(async (req, next) => {
412
570
  const token = req.headers.get('Authorization');
413
571
  if (!token) return new Response('Unauthorized', { status: 401 });
414
- return next(req);
415
- };
572
+ return next();
573
+ });
416
574
 
417
575
  const routes = defineRoutes([
418
- {
576
+ defineRoute({
419
577
  method: 'GET',
420
578
  path: '/protected',
421
579
  middleware: [authMiddleware],
422
- handler: createHandler(() => ({ secret: 'data' }))
423
- }
580
+ handler: () => ({ secret: 'data' })
581
+ })
424
582
  ]);
425
583
  ```
426
584
 
@@ -428,22 +586,42 @@ const routes = defineRoutes([
428
586
 
429
587
  ```typescript
430
588
  const routes = defineRoutes([
431
- {
589
+ defineRoute({
432
590
  path: '/api',
433
591
  middleware: [apiMiddleware],
434
592
  children: [
435
- { method: 'GET', path: '/users', handler: getUsers },
436
- { method: 'POST', path: '/users', handler: createUser },
437
- {
593
+ defineRoute({
594
+ method: 'GET',
595
+ path: '/users',
596
+ handler: getUsers
597
+ }),
598
+ defineRoute({
599
+ method: 'POST',
600
+ path: '/users',
601
+ handler: createUser
602
+ }),
603
+ defineRoute({
438
604
  path: '/users/:id',
439
605
  children: [
440
- { method: 'GET', path: '/', handler: getUser },
441
- { method: 'PUT', path: '/', handler: updateUser },
442
- { method: 'DELETE', path: '/', handler: deleteUser },
606
+ defineRoute({
607
+ method: 'GET',
608
+ path: '/',
609
+ handler: getUser
610
+ }),
611
+ defineRoute({
612
+ method: 'PUT',
613
+ path: '/',
614
+ handler: updateUser
615
+ }),
616
+ defineRoute({
617
+ method: 'DELETE',
618
+ path: '/',
619
+ handler: deleteUser
620
+ }),
443
621
  ]
444
- }
622
+ })
445
623
  ]
446
- }
624
+ })
447
625
  ]);
448
626
  ```
449
627
 
@@ -509,7 +687,7 @@ precompileSchemas([UserSchema, PostSchema, CommentSchema]);
509
687
  Vafast 内置 30+ 常用 format 验证器,**导入框架时自动注册**,对标 Zod 的内置验证:
510
688
 
511
689
  ```typescript
512
- import { Type, createHandler } from 'vafast';
690
+ import { defineRoute, defineRoutes, Type } from 'vafast';
513
691
 
514
692
  // 直接使用内置 format,无需手动注册
515
693
  const UserSchema = Type.Object({
@@ -520,9 +698,16 @@ const UserSchema = Type.Object({
520
698
  createdAt: Type.String({ format: 'date-time' }),
521
699
  });
522
700
 
523
- const handler = createHandler({ body: UserSchema }, ({ body }) => {
524
- return { success: true, user: body };
525
- });
701
+ const routes = defineRoutes([
702
+ defineRoute({
703
+ method: 'POST',
704
+ path: '/users',
705
+ schema: { body: UserSchema },
706
+ handler: ({ body }) => {
707
+ return { success: true, user: body };
708
+ }
709
+ })
710
+ ]);
526
711
  ```
527
712
 
528
713
  **支持的 Format 列表:**
@@ -551,52 +736,113 @@ registerFormat('order-id', (v) => /^ORD-\d{8}$/.test(v));
551
736
  const isEmail = Patterns.EMAIL.test('test@example.com');
552
737
  ```
553
738
 
554
- ### 路由注册表 (RouteRegistry)
739
+ ### 路由注册表 (RouteRegistry) — 声明式元数据,赋能业务逻辑
555
740
 
556
- Vafast 提供 `RouteRegistry` 用于路由元信息的收集和查询,适用于 API 文档生成、Webhook 事件注册、权限检查等场景:
741
+ Vafast 的声明式路由支持**任意扩展字段**,让路由定义成为业务逻辑的单一数据源。适用于 API 文档生成、Webhook 事件注册、权限检查、**按 API 计费**等场景:
557
742
 
558
743
  ```typescript
559
- import { Server, createRouteRegistry } from 'vafast';
560
- import type { Route } from 'vafast';
744
+ import { Server, defineRoute, defineRoutes, getRouteRegistry, defineMiddleware } from 'vafast';
745
+
746
+ // 计费中间件:基于路由元数据自动计费
747
+ const billingMiddleware = defineMiddleware(async (req, next) => {
748
+ const registry = getRouteRegistry();
749
+ const url = new URL(req.url);
750
+ const route = registry.get(req.method, url.pathname);
751
+
752
+ if (route?.billing) {
753
+ const { price, currency, unit } = route.billing;
754
+ const userId = getUserId(req);
755
+
756
+ // 执行计费逻辑
757
+ await chargeUser(userId, {
758
+ api: `${req.method} ${url.pathname}`,
759
+ price,
760
+ currency,
761
+ unit, // 'request' | 'token' | 'minute'
762
+ });
763
+ }
764
+
765
+ return next();
766
+ });
561
767
 
562
768
  // 定义带扩展字段的路由
563
- const routes: Route[] = [
564
- {
769
+ const routes = defineRoutes([
770
+ defineRoute({
565
771
  method: 'POST',
566
772
  path: '/auth/signIn',
773
+ name: '用户登录',
774
+ description: '用户通过邮箱密码登录',
567
775
  handler: signInHandler,
568
- name: '用户登录', // 扩展字段
569
- description: '用户通过邮箱密码登录', // 扩展字段
570
- webhook: { eventKey: 'auth.signIn' }, // 自定义扩展
571
- },
572
- {
776
+ // ✨ 扩展字段:Webhook 事件
777
+ webhook: { eventKey: 'auth.signIn', enabled: true },
778
+ }),
779
+ defineRoute({
780
+ method: 'POST',
781
+ path: '/ai/generate',
782
+ name: 'AI 生成',
783
+ description: '生成 AI 内容',
784
+ // ✨ 扩展字段:按请求计费
785
+ billing: { price: 0.01, currency: 'USD', unit: 'request' },
786
+ // ✨ 扩展字段:权限要求
787
+ permission: 'ai.generate',
788
+ middleware: [billingMiddleware],
789
+ handler: async ({ body }) => {
790
+ return await generateAI(body.prompt);
791
+ }
792
+ }),
793
+ defineRoute({
794
+ method: 'POST',
795
+ path: '/ai/chat',
796
+ name: 'AI 对话',
797
+ // ✨ 扩展字段:按 token 计费
798
+ billing: { price: 0.0001, currency: 'USD', unit: 'token' },
799
+ permission: 'ai.chat',
800
+ middleware: [billingMiddleware],
801
+ handler: async ({ body }) => {
802
+ return await chatAI(body.message);
803
+ }
804
+ }),
805
+ defineRoute({
573
806
  method: 'GET',
574
807
  path: '/users',
575
808
  handler: getUsersHandler,
576
- permission: 'users.read', // 自定义扩展
577
- },
578
- ];
809
+ permission: 'users.read',
810
+ // 免费 API,无需计费配置
811
+ }),
812
+ ]);
579
813
 
580
814
  const server = new Server(routes);
581
815
 
582
- // 创建路由注册表
583
- const registry = createRouteRegistry(server.getRoutesWithMeta());
816
+ // Server 创建时自动设置全局注册表,直接使用即可
817
+ const registry = getRouteRegistry();
584
818
 
585
- // 查询路由
586
- const route = registry.get('POST', '/auth/signIn');
587
- console.log(route?.name); // '用户登录'
819
+ // 查询路由元信息
820
+ const route = registry.get('POST', '/ai/generate');
821
+ console.log(route?.name); // 'AI 生成'
822
+ console.log(route?.billing); // { price: 0.01, currency: 'USD', unit: 'request' }
823
+ console.log(route?.permission); // 'ai.generate'
824
+
825
+ // 筛选有特定字段的路由
826
+ const webhookRoutes = registry.filter('webhook'); // 所有 Webhook 事件
827
+ const paidRoutes = registry.filter('billing'); // 所有付费 API
828
+ const aiRoutes = registry.filterBy(r => r.permission?.startsWith('ai.')); // AI 相关 API
588
829
 
589
830
  // 按分类获取
590
831
  const authRoutes = registry.getByCategory('auth');
591
-
592
- // 筛选有特定字段的路由
593
- const webhookRoutes = registry.filter('webhook');
594
- const permissionRoutes = registry.filter('permission');
832
+ const aiCategoryRoutes = registry.getByCategory('ai');
595
833
 
596
834
  // 获取所有分类
597
- const categories = registry.getCategories(); // ['auth', 'users']
835
+ const categories = registry.getCategories(); // ['auth', 'ai', 'users']
598
836
  ```
599
837
 
838
+ **扩展字段的优势:**
839
+
840
+ 1. **单一数据源**:路由定义包含所有元数据,无需额外配置文件
841
+ 2. **类型安全**:扩展字段在 TypeScript 中完全类型化
842
+ 3. **运行时查询**:通过 `RouteRegistry` API 动态查询和筛选
843
+ 4. **业务集成**:中间件可直接读取路由元数据,实现计费、权限、审计等功能
844
+ 5. **API 网关友好**:声明式配置完美适配网关场景
845
+
600
846
  **Registry 实例方法:**
601
847
 
602
848
  | 方法 | 说明 |
@@ -612,52 +858,61 @@ const categories = registry.getCategories(); // ['auth', 'users']
612
858
  | `map(callback)` | 映射所有路由 |
613
859
  | `size` | 路由数量 |
614
860
 
615
- **全局便捷函数:**
861
+ **全局便捷函数(Server 创建后自动可用):**
616
862
 
617
863
  ```typescript
618
864
  import {
619
- getRoute,
620
- getAllRoutes,
621
- filterRoutes,
622
- getRoutesByMethod,
865
+ getRouteRegistry, // 获取全局注册表实例
866
+ getRoute, // 快速查询单个路由
867
+ getAllRoutes, // 获取所有路由
868
+ filterRoutes, // 按字段筛选
869
+ getRoutesByMethod, // 按 HTTP 方法获取
623
870
  } from 'vafast'
624
871
 
625
- // 获取单个路由
626
- const route = getRoute('POST', '/users')
872
+ // 方式一:使用全局注册表实例
873
+ const registry = getRouteRegistry()
874
+ const route = registry.get('POST', '/users')
627
875
 
628
- // 获取所有路由
876
+ // 方式二:使用便捷函数(推荐,更简洁)
877
+ const route = getRoute('POST', '/users')
629
878
  const allRoutes = getAllRoutes()
630
-
631
- // 按字段筛选
632
879
  const webhookRoutes = filterRoutes('webhook')
633
-
634
- // 按 HTTP 方法获取
635
880
  const getRoutes = getRoutesByMethod('GET')
636
881
  const postRoutes = getRoutesByMethod('POST')
637
882
 
638
- // 按路径前缀筛选(自己 filter)
883
+ // 按路径前缀筛选
639
884
  const authRoutes = getAllRoutes().filter(r => r.path.startsWith('/auth'))
640
885
  ```
641
886
 
887
+ > 💡 **提示**:Server 创建时会自动设置全局 RouteRegistry,无需手动创建。在任意文件中导入 `getRouteRegistry()` 即可访问。
888
+
642
889
  ### API Spec 生成
643
890
 
644
891
  Vafast 提供 `getApiSpec` 用于生成 API 规范,支持跨仓库类型同步和 AI 工具函数生成:
645
892
 
646
893
  ```typescript
647
- import { Server, defineRoutes, getApiSpec } from 'vafast';
894
+ import { Server, defineRoute, defineRoutes, getApiSpec } from 'vafast';
648
895
 
649
896
  const routes = defineRoutes([
650
- { method: 'GET', path: '/users', handler: getUsers },
651
- { method: 'POST', path: '/users', handler: createUser },
897
+ defineRoute({
898
+ method: 'GET',
899
+ path: '/users',
900
+ handler: getUsers
901
+ }),
902
+ defineRoute({
903
+ method: 'POST',
904
+ path: '/users',
905
+ handler: createUser
906
+ }),
907
+ // 添加 API Spec 接口
908
+ defineRoute({
909
+ method: 'GET',
910
+ path: '/api-spec',
911
+ handler: getApiSpec // 直接作为 handler
912
+ }),
652
913
  ]);
653
914
 
654
- // 添加 API Spec 接口
655
- const allRoutes = [
656
- ...routes,
657
- { method: 'GET', path: '/api-spec', handler: getApiSpec } // 直接作为 handler
658
- ];
659
-
660
- const server = new Server(allRoutes);
915
+ const server = new Server(routes);
661
916
  ```
662
917
 
663
918
  **三种使用方式:**
@@ -186,10 +186,27 @@ declare function withContext<TContext extends object>(): <const TSchema$1 extend
186
186
  responses?: Record<string, unknown>;
187
187
  };
188
188
  }) => LeafRouteConfig<TMethod, TPath, TSchema$1, TReturn, TMiddleware>;
189
+ /** 带原始类型信息的路由数组 */
190
+ type RoutesWithSource<T extends readonly RouteConfigResult[]> = ProcessedRoute[] & {
191
+ __source: T;
192
+ };
189
193
  /**
190
194
  * 定义路由数组,支持嵌套路由
195
+ *
196
+ * 使用 `const T` 泛型自动保留字面量类型,无需手动添加 `as const`
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * const routes = defineRoutes([
201
+ * defineRoute({ method: 'GET', path: '/users', handler: ... }),
202
+ * defineRoute({ method: 'POST', path: '/users', handler: ... }),
203
+ * ])
204
+ *
205
+ * // 类型推断自动工作,无需 as const
206
+ * type Api = InferEden<typeof routes>
207
+ * ```
191
208
  */
192
- declare function defineRoutes(routes: ReadonlyArray<RouteConfigResult>): ProcessedRoute[];
209
+ declare function defineRoutes<const T extends readonly RouteConfigResult[]>(routes: T): RoutesWithSource<T>;
193
210
  /** 可推断的路由类型(供 vafast-api-client 使用) */
194
211
  type InferableRoute<TMethod extends string = string, TPath extends string = string, TReturn = unknown, TSchema$1 extends RouteSchema = RouteSchema> = {
195
212
  readonly method: TMethod;
@@ -204,5 +221,5 @@ type InferableRoute<TMethod extends string = string, TPath extends string = stri
204
221
  readonly middleware?: ReadonlyArray<AnyMiddleware>;
205
222
  };
206
223
  //#endregion
207
- export { RouteSchema as a, defineRoute as c, ProcessedRoute as i, defineRoutes as l, InferableRoute as n, TypedMiddleware as o, LeafRouteConfig as r, defineMiddleware as s, HandlerContext as t, withContext as u };
208
- //# sourceMappingURL=defineRoute-BNqVD0_t.d.mts.map
224
+ export { RouteSchema as a, defineMiddleware as c, withContext as d, ProcessedRoute as i, defineRoute as l, InferableRoute as n, RoutesWithSource as o, LeafRouteConfig as r, TypedMiddleware as s, HandlerContext as t, defineRoutes as u };
225
+ //# sourceMappingURL=defineRoute-FhAN4ivP.d.mts.map
@@ -1,2 +1,2 @@
1
- import { a as RouteSchema, c as defineRoute, i as ProcessedRoute, l as defineRoutes, n as InferableRoute, o as TypedMiddleware, r as LeafRouteConfig, s as defineMiddleware, t as HandlerContext, u as withContext } from "./defineRoute-BNqVD0_t.mjs";
2
- export { HandlerContext, InferableRoute, LeafRouteConfig, ProcessedRoute, RouteSchema, TypedMiddleware, defineMiddleware, defineRoute, defineRoutes, withContext };
1
+ import { a as RouteSchema, c as defineMiddleware, d as withContext, i as ProcessedRoute, l as defineRoute, n as InferableRoute, o as RoutesWithSource, r as LeafRouteConfig, s as TypedMiddleware, t as HandlerContext, u as defineRoutes } from "./defineRoute-FhAN4ivP.mjs";
2
+ export { HandlerContext, InferableRoute, LeafRouteConfig, ProcessedRoute, RouteSchema, RoutesWithSource, TypedMiddleware, defineMiddleware, defineRoute, defineRoutes, withContext };
@@ -164,9 +164,23 @@ function flattenRoutes(routes, parentPath = "", parentMiddleware = []) {
164
164
  }
165
165
  /**
166
166
  * 定义路由数组,支持嵌套路由
167
+ *
168
+ * 使用 `const T` 泛型自动保留字面量类型,无需手动添加 `as const`
169
+ *
170
+ * @example
171
+ * ```typescript
172
+ * const routes = defineRoutes([
173
+ * defineRoute({ method: 'GET', path: '/users', handler: ... }),
174
+ * defineRoute({ method: 'POST', path: '/users', handler: ... }),
175
+ * ])
176
+ *
177
+ * // 类型推断自动工作,无需 as const
178
+ * type Api = InferEden<typeof routes>
179
+ * ```
167
180
  */
168
181
  function defineRoutes(routes) {
169
- return flattenRoutes(routes);
182
+ const processed = flattenRoutes(routes);
183
+ return Object.assign(processed, { __source: routes });
170
184
  }
171
185
 
172
186
  //#endregion
@@ -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// ============= Schema 类型 =============\n\n/** 路由 Schema 配置 */\nexport interface RouteSchema {\n body?: TSchema;\n query?: TSchema;\n params?: TSchema;\n headers?: TSchema;\n cookies?: 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/** 叶子路由配置(有 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 readonly handler: (\n ctx: HandlerContextWithExtra<TSchema, MergeMiddlewareContexts<TMiddleware>>\n ) => TReturn | Promise<TReturn>;\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) */\ninterface 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 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// ============= 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/** 创建包装后的 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 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 const result = await userHandler({\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 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({ success: false, error: \"Validation Error\", message: error.message }, 400);\n }\n return json({ success: false, error: \"Internal Error\", 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 /** 显式声明上下文类型(用于父级中间件注入的场景) */\n readonly context?: TContext;\n readonly handler: (\n ctx: HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>\n ) => TReturn | Promise<TReturn>;\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 context?: object;\n readonly handler?: (ctx: HandlerContext<RouteSchema>) => unknown | Promise<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 */\nexport function withContext<TContext extends object>() {\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 readonly handler: (\n ctx: HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>\n ) => TReturn | Promise<TReturn>;\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 return config as LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware>;\n };\n}\n\n// ============= 扁平化嵌套路由 =============\n\n/**\n * 递归扁平化路由,合并路径和中间件\n */\nfunction flattenRoutes(\n routes: ReadonlyArray<RouteConfigResult>,\n parentPath: string = \"\",\n parentMiddleware: readonly AnyMiddleware[] = []\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 result.push({\n method: route.method,\n path: fullPath,\n name: route.name,\n description: route.description,\n schema: route.schema,\n handler: wrapHandler(route.schema, route.handler as (ctx: HandlerContext<RouteSchema>) => unknown),\n middleware: mergedMiddleware.length > 0 ? mergedMiddleware : undefined,\n docs: route.docs,\n });\n } else if (isNestedRoute(route)) {\n result.push(...flattenRoutes(route.children, fullPath, mergedMiddleware));\n }\n }\n\n return result;\n}\n\n// ============= defineRoutes 函数 =============\n\n/**\n * 定义路由数组,支持嵌套路由\n */\nexport function defineRoutes(routes: ReadonlyArray<RouteConfigResult>): ProcessedRoute[] {\n return flattenRoutes(routes);\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// ============= Schema 类型 =============\n\n/** 路由 Schema 配置 */\nexport interface RouteSchema {\n body?: TSchema;\n query?: TSchema;\n params?: TSchema;\n headers?: TSchema;\n cookies?: 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/** 叶子路由配置(有 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 readonly handler: (\n ctx: HandlerContextWithExtra<TSchema, MergeMiddlewareContexts<TMiddleware>>\n ) => TReturn | Promise<TReturn>;\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) */\ninterface 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 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// ============= 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/** 创建包装后的 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 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 const result = await userHandler({\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 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({ success: false, error: \"Validation Error\", message: error.message }, 400);\n }\n return json({ success: false, error: \"Internal Error\", 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 /** 显式声明上下文类型(用于父级中间件注入的场景) */\n readonly context?: TContext;\n readonly handler: (\n ctx: HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>\n ) => TReturn | Promise<TReturn>;\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 context?: object;\n readonly handler?: (ctx: HandlerContext<RouteSchema>) => unknown | Promise<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 */\nexport function withContext<TContext extends object>() {\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 readonly handler: (\n ctx: HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>\n ) => TReturn | Promise<TReturn>;\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 return config as LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware>;\n };\n}\n\n// ============= 扁平化嵌套路由 =============\n\n/**\n * 递归扁平化路由,合并路径和中间件\n */\nfunction flattenRoutes(\n routes: ReadonlyArray<RouteConfigResult>,\n parentPath: string = \"\",\n parentMiddleware: readonly AnyMiddleware[] = []\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 result.push({\n method: route.method,\n path: fullPath,\n name: route.name,\n description: route.description,\n schema: route.schema,\n handler: wrapHandler(route.schema, route.handler as (ctx: HandlerContext<RouteSchema>) => unknown),\n middleware: mergedMiddleware.length > 0 ? mergedMiddleware : undefined,\n docs: route.docs,\n });\n } else if (isNestedRoute(route)) {\n result.push(...flattenRoutes(route.children, fullPath, mergedMiddleware));\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 { i as ProcessedRoute } from "./defineRoute-BNqVD0_t.mjs";
1
+ import { i as ProcessedRoute } from "./defineRoute-FhAN4ivP.mjs";
2
2
  import { r as NestedComponentRoute, t as ComponentRoute } from "./component-route-Di7R40-2.mjs";
3
- import { t as Server } from "./server-Bicf_7Hx.mjs";
3
+ import { t as Server } from "./server-8X5Hgu7h.mjs";
4
4
  import { t as ComponentServer } from "./component-server-fR4UV6Jq.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-DCJOWsRE.d.mts.map
48
+ //# sourceMappingURL=index-XcXGKQqt.d.mts.map
package/dist/index.d.mts CHANGED
@@ -1,11 +1,11 @@
1
- import { a as RouteSchema, c as defineRoute, i as ProcessedRoute, l as defineRoutes, n as InferableRoute, o as TypedMiddleware, r as LeafRouteConfig, s as defineMiddleware, t as HandlerContext, u as withContext } from "./defineRoute-BNqVD0_t.mjs";
1
+ import { a as RouteSchema, c as defineMiddleware, d as withContext, i as ProcessedRoute, l as defineRoute, n as InferableRoute, o as RoutesWithSource, r as LeafRouteConfig, s as TypedMiddleware, t as HandlerContext, u as defineRoutes } from "./defineRoute-FhAN4ivP.mjs";
2
2
  import { i as ResponseBody, n as Method, r as Middleware, t as Handler } from "./types-B8Z3cMtZ.mjs";
3
3
  import { n as FlattenedComponentRoute, r as NestedComponentRoute, t as ComponentRoute } from "./component-route-Di7R40-2.mjs";
4
4
  import { t as BaseServer } from "./base-server-Contwrlf.mjs";
5
- import { t as Server } from "./server-Bicf_7Hx.mjs";
5
+ import { t as Server } from "./server-8X5Hgu7h.mjs";
6
6
  import { t as DependencyManager } from "./dependency-manager-DIN9X0Gj.mjs";
7
7
  import { t as ComponentServer } from "./component-server-fR4UV6Jq.mjs";
8
- import { t as ServerFactory } from "./index-DCJOWsRE.mjs";
8
+ import { t as ServerFactory } from "./index-XcXGKQqt.mjs";
9
9
  import { n as composeMiddleware, t as VafastError } from "./middleware-BR-R4p0M.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-8hIAx0OV.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-BNLzz4Tq.mjs";
@@ -14,12 +14,12 @@ import { n as base64urlEncode, t as base64urlDecode } from "./base64url-DNUGwekK
14
14
  import { t as HtmlRenderer } from "./html-renderer-DhQxRuyi.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-BFC6S_fr.mjs";
16
16
  import { i as registerFormats, n as hasFormat, r as registerFormat, t as Patterns } from "./formats-DDDSFWP0.mjs";
17
- import { a as createSSEHandler, i as SSEMarker, r as SSEHandler, t as SSEEvent } from "./sse-DYuFPif9.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-DZv4vAjT.mjs";
17
+ import { a as createSSEHandler, i as SSEMarker, r as SSEHandler, t as SSEEvent } from "./sse-DyI21Jqk.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-YIco7opr.mjs";
19
19
  import { n as getApiSpec, t as generateAITools } from "./contract-BL3JflJ7.mjs";
20
20
  import "./utils/index.mjs";
21
21
  import { normalizePath } from "./router.mjs";
22
22
  import { i as ServeResult, o as serve, r as ServeOptions, t as FetchHandler } from "./serve-DlzxgOhz.mjs";
23
23
  import "./serve.mjs";
24
24
  import { FormatRegistry, Type } from "@sinclair/typebox";
25
- export { BaseServer, ComponentRoute, ComponentServer, DependencyManager, type FetchHandler, FlattenedComponentRoute, FormatRegistry, Handler, HandlerContext, HtmlRenderer, InferableRoute, LeafRouteConfig, Method, Middleware, NestedComponentRoute, Patterns, ProcessedRoute, ResponseBody, RouteMeta, RouteRegistry, RouteSchema, SSEEvent, SSEHandler, SSEMarker, SchemaConfig, type ServeOptions, type ServeResult, Server, ServerFactory, Type, TypedMiddleware, VafastError, ValidationError, ValidationResult, base64urlDecode, base64urlEncode, composeMiddleware, createRouteRegistry, createSSEHandler, createValidator, defineMiddleware, defineRoute, defineRoutes, empty, err, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, json, normalizePath, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, serve, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow, withContext };
25
+ export { BaseServer, ComponentRoute, ComponentServer, DependencyManager, type FetchHandler, FlattenedComponentRoute, FormatRegistry, Handler, HandlerContext, HtmlRenderer, InferableRoute, LeafRouteConfig, Method, Middleware, NestedComponentRoute, Patterns, ProcessedRoute, ResponseBody, RouteMeta, RouteRegistry, RouteSchema, RoutesWithSource, SSEEvent, SSEHandler, SSEMarker, SchemaConfig, type ServeOptions, type ServeResult, Server, ServerFactory, Type, TypedMiddleware, VafastError, ValidationError, ValidationResult, base64urlDecode, base64urlEncode, composeMiddleware, createRouteRegistry, createSSEHandler, createValidator, defineMiddleware, defineRoute, defineRoutes, empty, err, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, json, normalizePath, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, serve, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow, withContext };
@@ -1,5 +1,5 @@
1
- import "../defineRoute-BNqVD0_t.mjs";
2
- import "../server-Bicf_7Hx.mjs";
3
- import "../index-DCJOWsRE.mjs";
1
+ import "../defineRoute-FhAN4ivP.mjs";
2
+ import "../server-8X5Hgu7h.mjs";
3
+ import "../index-XcXGKQqt.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-BNqVD0_t.mjs";
2
- import { t as Server } from "../server-Bicf_7Hx.mjs";
3
- import "../index-DCJOWsRE.mjs";
1
+ import "../defineRoute-FhAN4ivP.mjs";
2
+ import { t as Server } from "../server-8X5Hgu7h.mjs";
3
+ import "../index-XcXGKQqt.mjs";
4
4
 
5
5
  //#region src/monitoring/native-monitor.d.ts
6
6
 
@@ -1,4 +1,4 @@
1
- import { a as RouteSchema, i as ProcessedRoute } from "./defineRoute-BNqVD0_t.mjs";
1
+ import { a as RouteSchema, i as ProcessedRoute } from "./defineRoute-FhAN4ivP.mjs";
2
2
  import { n as Method } from "./types-B8Z3cMtZ.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-DZv4vAjT.d.mts.map
190
+ //# sourceMappingURL=route-registry-YIco7opr.d.mts.map
@@ -1,6 +1,6 @@
1
- import "../defineRoute-BNqVD0_t.mjs";
1
+ import "../defineRoute-FhAN4ivP.mjs";
2
2
  import { t as BaseServer } from "../base-server-Contwrlf.mjs";
3
- import { t as Server } from "../server-Bicf_7Hx.mjs";
3
+ import { t as Server } from "../server-8X5Hgu7h.mjs";
4
4
  import { t as ComponentServer } from "../component-server-fR4UV6Jq.mjs";
5
- import { t as ServerFactory } from "../index-DCJOWsRE.mjs";
5
+ import { t as ServerFactory } from "../index-XcXGKQqt.mjs";
6
6
  export { BaseServer, ComponentServer, Server, ServerFactory };
@@ -1,4 +1,4 @@
1
- import "../defineRoute-BNqVD0_t.mjs";
2
- import "../server-Bicf_7Hx.mjs";
3
- import { t as ServerFactory } from "../index-DCJOWsRE.mjs";
1
+ import "../defineRoute-FhAN4ivP.mjs";
2
+ import "../server-8X5Hgu7h.mjs";
3
+ import { t as ServerFactory } from "../index-XcXGKQqt.mjs";
4
4
  export { ServerFactory };
@@ -1,3 +1,3 @@
1
- import "../defineRoute-BNqVD0_t.mjs";
2
- import { t as Server } from "../server-Bicf_7Hx.mjs";
1
+ import "../defineRoute-FhAN4ivP.mjs";
2
+ import { t as Server } from "../server-8X5Hgu7h.mjs";
3
3
  export { Server };
@@ -1,4 +1,4 @@
1
- import { i as ProcessedRoute } from "./defineRoute-BNqVD0_t.mjs";
1
+ import { i as ProcessedRoute } from "./defineRoute-FhAN4ivP.mjs";
2
2
  import { n as Method } from "./types-B8Z3cMtZ.mjs";
3
3
  import { t as BaseServer } from "./base-server-Contwrlf.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-Bicf_7Hx.d.mts.map
48
+ //# sourceMappingURL=server-8X5Hgu7h.d.mts.map
@@ -1,4 +1,4 @@
1
- import { a as RouteSchema, t as HandlerContext } from "./defineRoute-BNqVD0_t.mjs";
1
+ import { a as RouteSchema, t as HandlerContext } from "./defineRoute-FhAN4ivP.mjs";
2
2
 
3
3
  //#region src/utils/sse.d.ts
4
4
 
@@ -60,4 +60,4 @@ declare function createSSEHandler<const T extends RouteSchema>(schema: T, genera
60
60
  declare function createSSEHandler(generator: SSEGenerator<RouteSchema>): SSEHandler<RouteSchema>;
61
61
  //#endregion
62
62
  export { createSSEHandler as a, SSEMarker as i, SSEGenerator as n, SSEHandler as r, SSEEvent as t };
63
- //# sourceMappingURL=sse-DYuFPif9.d.mts.map
63
+ //# sourceMappingURL=sse-DyI21Jqk.d.mts.map
@@ -1,4 +1,4 @@
1
- import "../defineRoute-BNqVD0_t.mjs";
1
+ import "../defineRoute-FhAN4ivP.mjs";
2
2
  import { t as DependencyManager } from "../dependency-manager-DIN9X0Gj.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-8hIAx0OV.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-BNLzz4Tq.mjs";
@@ -7,7 +7,7 @@ import { n as base64urlEncode, t as base64urlDecode } from "../base64url-DNUGwek
7
7
  import { t as HtmlRenderer } from "../html-renderer-DhQxRuyi.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-BFC6S_fr.mjs";
9
9
  import { i as registerFormats, n as hasFormat, r as registerFormat, t as Patterns } from "../formats-DDDSFWP0.mjs";
10
- import { a as createSSEHandler, i as SSEMarker, r as SSEHandler, t as SSEEvent } from "../sse-DYuFPif9.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-DZv4vAjT.mjs";
10
+ import { a as createSSEHandler, i as SSEMarker, r as SSEHandler, t as SSEEvent } from "../sse-DyI21Jqk.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-YIco7opr.mjs";
12
12
  import { n as getApiSpec, t as generateAITools } from "../contract-BL3JflJ7.mjs";
13
13
  export { DependencyManager, HtmlRenderer, Patterns, type RouteMeta, RouteRegistry, type SSEEvent, type SSEHandler, type SSEMarker, type SchemaConfig, type ValidationError, type ValidationResult, base64urlDecode, base64urlEncode, createRouteRegistry, createSSEHandler, 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-BNqVD0_t.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-DZv4vAjT.mjs";
1
+ import "../defineRoute-FhAN4ivP.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-YIco7opr.mjs";
3
3
  export { RouteMeta, RouteRegistry, createRouteRegistry, filterRoutes, getAllRoutes, getRoute, getRouteRegistry, getRoutesByMethod, setGlobalRegistry };
@@ -1,3 +1,3 @@
1
- import "../defineRoute-BNqVD0_t.mjs";
2
- import { a as createSSEHandler, i as SSEMarker, n as SSEGenerator, r as SSEHandler, t as SSEEvent } from "../sse-DYuFPif9.mjs";
1
+ import "../defineRoute-FhAN4ivP.mjs";
2
+ import { a as createSSEHandler, i as SSEMarker, n as SSEGenerator, r as SSEHandler, t as SSEEvent } from "../sse-DyI21Jqk.mjs";
3
3
  export { SSEEvent, SSEGenerator, SSEHandler, SSEMarker, createSSEHandler };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vafast",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
4
  "description": "极简结构化Web框架,支持 Bun 和 Node.js。Go风格,函数优先。",
5
5
  "type": "module",
6
6
  "repository": {