vafast 0.5.5 → 0.5.7

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 (41) hide show
  1. package/README.md +418 -163
  2. package/dist/{defineRoute-BNqVD0_t.d.mts → defineRoute-FhAN4ivP.d.mts} +20 -3
  3. package/dist/defineRoute.d.mts +2 -2
  4. package/dist/defineRoute.mjs +18 -6
  5. package/dist/defineRoute.mjs.map +1 -1
  6. package/dist/{index-DCJOWsRE.d.mts → index-XcXGKQqt.d.mts} +3 -3
  7. package/dist/index.d.mts +8 -8
  8. package/dist/index.mjs +4 -4
  9. package/dist/{middleware-BR-R4p0M.d.mts → middleware-CrD2gfzt.d.mts} +3 -3
  10. package/dist/middleware.d.mts +1 -1
  11. package/dist/middleware.mjs +1 -1
  12. package/dist/monitoring/index.d.mts +3 -3
  13. package/dist/monitoring/native-monitor.d.mts +3 -3
  14. package/dist/{response-BNLzz4Tq.d.mts → response-CJcO5s7Q.d.mts} +23 -13
  15. package/dist/{response-CQ1IgWei.mjs → response-dgNpkPIp.mjs} +27 -17
  16. package/dist/response-dgNpkPIp.mjs.map +1 -0
  17. package/dist/{route-registry-DZv4vAjT.d.mts → route-registry-YIco7opr.d.mts} +2 -2
  18. package/dist/server/index.d.mts +3 -3
  19. package/dist/server/index.mjs +3 -3
  20. package/dist/server/server-factory.d.mts +3 -3
  21. package/dist/server/server-factory.mjs +3 -3
  22. package/dist/server/server.d.mts +2 -2
  23. package/dist/server/server.mjs +2 -2
  24. package/dist/{server-Bicf_7Hx.d.mts → server-8X5Hgu7h.d.mts} +2 -2
  25. package/dist/{server-CZLmrJSk.mjs → server-AJWK-vUI.mjs} +2 -2
  26. package/dist/{server-CZLmrJSk.mjs.map → server-AJWK-vUI.mjs.map} +1 -1
  27. package/dist/{server-Bm0BGm01.mjs → server-BCjY3a63.mjs} +5 -6
  28. package/dist/server-BCjY3a63.mjs.map +1 -0
  29. package/dist/{sse-CWNz0ky7.mjs → sse-CAOZ-rXY.mjs} +2 -3
  30. package/dist/{sse-CWNz0ky7.mjs.map → sse-CAOZ-rXY.mjs.map} +1 -1
  31. package/dist/{sse-DYuFPif9.d.mts → sse-DyI21Jqk.d.mts} +2 -2
  32. package/dist/utils/index.d.mts +4 -4
  33. package/dist/utils/index.mjs +2 -2
  34. package/dist/utils/response.d.mts +1 -1
  35. package/dist/utils/response.mjs +1 -1
  36. package/dist/utils/route-registry.d.mts +2 -2
  37. package/dist/utils/sse.d.mts +2 -2
  38. package/dist/utils/sse.mjs +1 -1
  39. package/package.json +1 -1
  40. package/dist/response-CQ1IgWei.mjs.map +0 -1
  41. package/dist/server-Bm0BGm01.mjs.map +0 -1
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
  **三种使用方式:**