vafast 0.3.11 → 0.4.0

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
@@ -507,6 +507,67 @@ server.compile(); // 预编译所有路由的处理链
507
507
 
508
508
  **性能效果:1000 次请求仅需 ~4ms,平均每次 0.004ms**
509
509
 
510
+ ### 路由注册表 (RouteRegistry)
511
+
512
+ Vafast 提供 `RouteRegistry` 用于路由元信息的收集和查询,适用于 API 文档生成、Webhook 事件注册、权限检查等场景:
513
+
514
+ ```typescript
515
+ import { Server, createRouteRegistry } from 'vafast';
516
+ import type { Route } from 'vafast';
517
+
518
+ // 定义带扩展字段的路由
519
+ const routes: Route[] = [
520
+ {
521
+ method: 'POST',
522
+ path: '/auth/signIn',
523
+ handler: signInHandler,
524
+ name: '用户登录', // 扩展字段
525
+ description: '用户通过邮箱密码登录', // 扩展字段
526
+ webhook: { eventKey: 'auth.signIn' }, // 自定义扩展
527
+ },
528
+ {
529
+ method: 'GET',
530
+ path: '/users',
531
+ handler: getUsersHandler,
532
+ permission: 'users.read', // 自定义扩展
533
+ },
534
+ ];
535
+
536
+ const server = new Server(routes);
537
+
538
+ // 创建路由注册表
539
+ const registry = createRouteRegistry(server.getRoutesWithMeta());
540
+
541
+ // 查询路由
542
+ const route = registry.get('POST', '/auth/signIn');
543
+ console.log(route?.name); // '用户登录'
544
+
545
+ // 按分类获取
546
+ const authRoutes = registry.getByCategory('auth');
547
+
548
+ // 筛选有特定字段的路由
549
+ const webhookRoutes = registry.filter('webhook');
550
+ const permissionRoutes = registry.filter('permission');
551
+
552
+ // 获取所有分类
553
+ const categories = registry.getCategories(); // ['auth', 'users']
554
+ ```
555
+
556
+ **完整 API:**
557
+
558
+ | 方法 | 说明 |
559
+ |------|------|
560
+ | `getAll()` | 获取所有路由元信息 |
561
+ | `get(method, path)` | 按 method+path 查询 |
562
+ | `has(method, path)` | 检查路由是否存在 |
563
+ | `getByCategory(category)` | 按分类获取路由 |
564
+ | `getCategories()` | 获取所有分类 |
565
+ | `filter(field)` | 筛选有特定字段的路由 |
566
+ | `filterBy(predicate)` | 自定义条件筛选 |
567
+ | `forEach(callback)` | 遍历所有路由 |
568
+ | `map(callback)` | 映射所有路由 |
569
+ | `size` | 路由数量 |
570
+
510
571
  ## 🔧 运行时支持
511
572
 
512
573
  ### Bun
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ export { DependencyManager } from './utils/dependency-manager.js';
15
15
  export { SchemaConfig, ValidationError, ValidationResult, createValidator, getValidatorCacheStats, precompileSchemas, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow } from './utils/validators/validators.js';
16
16
  export { Patterns, hasFormat, registerFormat, registerFormats } from './utils/formats.js';
17
17
  export { SSEEvent, SSEHandler, SSEMarker, createSSEHandler } from './utils/sse.js';
18
+ export { RouteMeta, RouteRegistry, createRouteRegistry } from './utils/route-registry.js';
18
19
  export { flattenNestedRoutes, normalizePath } from './router.js';
19
20
  export { requireAuth } from './middleware/authMiddleware.js';
20
21
  export { rateLimit } from './middleware/rateLimit.js';
package/dist/index.js CHANGED
@@ -8,8 +8,9 @@ function flattenNestedRoutes(routes) {
8
8
  ...route2.middleware || []
9
9
  ];
10
10
  if ("method" in route2 && "handler" in route2) {
11
+ const leafRoute = route2;
11
12
  flattened.push({
12
- ...route2,
13
+ ...leafRoute,
13
14
  fullPath: currentPath,
14
15
  middlewareChain: currentMiddleware
15
16
  });
@@ -628,6 +629,22 @@ var Server = class extends BaseServer {
628
629
  getRoutes() {
629
630
  return this.router.getRoutes();
630
631
  }
632
+ /**
633
+ * 获取完整的路由元信息(不含 handler 和 middleware)
634
+ *
635
+ * 用于 API 文档生成、Webhook 事件注册、权限检查等场景
636
+ *
637
+ * @example
638
+ * ```typescript
639
+ * const routes = server.getRoutesWithMeta()
640
+ * for (const route of routes) {
641
+ * console.log(route.fullPath, route.name, route.description)
642
+ * }
643
+ * ```
644
+ */
645
+ getRoutesWithMeta() {
646
+ return this.routes;
647
+ }
631
648
  };
632
649
 
633
650
  // src/middleware/component-router.ts
@@ -1683,6 +1700,130 @@ function createSSEHandler(schemaOrGenerator, maybeGenerator) {
1683
1700
  return handler;
1684
1701
  }
1685
1702
 
1703
+ // src/utils/route-registry.ts
1704
+ var RouteRegistry = class {
1705
+ /** 所有路由元信息 */
1706
+ routes = [];
1707
+ /** 路由映射表:METHOD:fullPath -> RouteMeta */
1708
+ routeMap = /* @__PURE__ */ new Map();
1709
+ /** 分类映射表:category -> RouteMeta[] */
1710
+ categoryMap = /* @__PURE__ */ new Map();
1711
+ constructor(routes) {
1712
+ this.buildRegistry(routes);
1713
+ }
1714
+ /**
1715
+ * 构建注册表
1716
+ */
1717
+ buildRegistry(routes) {
1718
+ for (const route2 of routes) {
1719
+ const meta = {
1720
+ method: route2.method,
1721
+ path: route2.path,
1722
+ fullPath: route2.fullPath,
1723
+ name: route2.name,
1724
+ description: route2.description
1725
+ };
1726
+ for (const key of Object.keys(route2)) {
1727
+ if (!["method", "path", "fullPath", "name", "description", "handler", "middleware", "middlewareChain"].includes(key)) {
1728
+ meta[key] = route2[key];
1729
+ }
1730
+ }
1731
+ this.routes.push(meta);
1732
+ this.routeMap.set(`${route2.method}:${route2.fullPath}`, meta);
1733
+ const category = this.extractCategory(route2.fullPath);
1734
+ if (!this.categoryMap.has(category)) {
1735
+ this.categoryMap.set(category, []);
1736
+ }
1737
+ this.categoryMap.get(category).push(meta);
1738
+ }
1739
+ }
1740
+ /**
1741
+ * 提取分类(第一段路径)
1742
+ */
1743
+ extractCategory(path) {
1744
+ const segments = path.split("/").filter(Boolean);
1745
+ return segments[0] || "root";
1746
+ }
1747
+ // ============================================
1748
+ // 查询接口
1749
+ // ============================================
1750
+ /**
1751
+ * 获取所有路由元信息
1752
+ */
1753
+ getAll() {
1754
+ return [...this.routes];
1755
+ }
1756
+ /**
1757
+ * 按 method + path 查询路由
1758
+ */
1759
+ get(method, path) {
1760
+ return this.routeMap.get(`${method}:${path}`);
1761
+ }
1762
+ /**
1763
+ * 检查路由是否存在
1764
+ */
1765
+ has(method, path) {
1766
+ return this.routeMap.has(`${method}:${path}`);
1767
+ }
1768
+ /**
1769
+ * 按分类获取路由
1770
+ */
1771
+ getByCategory(category) {
1772
+ return this.categoryMap.get(category) || [];
1773
+ }
1774
+ /**
1775
+ * 获取所有分类
1776
+ */
1777
+ getCategories() {
1778
+ return Array.from(this.categoryMap.keys()).sort();
1779
+ }
1780
+ /**
1781
+ * 筛选有特定字段的路由
1782
+ *
1783
+ * @example
1784
+ * ```typescript
1785
+ * // 获取所有配置了 webhook 的路由
1786
+ * const webhookRoutes = registry.filter('webhook')
1787
+ * ```
1788
+ */
1789
+ filter(field) {
1790
+ return this.routes.filter((r) => field in r && r[field] !== void 0);
1791
+ }
1792
+ /**
1793
+ * 按条件筛选路由
1794
+ *
1795
+ * @example
1796
+ * ```typescript
1797
+ * // 获取所有 POST 请求
1798
+ * const postRoutes = registry.filterBy(r => r.method === 'POST')
1799
+ * ```
1800
+ */
1801
+ filterBy(predicate) {
1802
+ return this.routes.filter(predicate);
1803
+ }
1804
+ /**
1805
+ * 获取路由数量
1806
+ */
1807
+ get size() {
1808
+ return this.routes.length;
1809
+ }
1810
+ /**
1811
+ * 遍历所有路由
1812
+ */
1813
+ forEach(callback) {
1814
+ this.routes.forEach(callback);
1815
+ }
1816
+ /**
1817
+ * 映射所有路由
1818
+ */
1819
+ map(callback) {
1820
+ return this.routes.map(callback);
1821
+ }
1822
+ };
1823
+ function createRouteRegistry(routes) {
1824
+ return new RouteRegistry(routes);
1825
+ }
1826
+
1686
1827
  // src/middleware/authMiddleware.ts
1687
1828
  var requireAuth = async (req, next) => {
1688
1829
  const token = getCookie2(req, "auth");
@@ -2299,6 +2440,7 @@ export {
2299
2440
  FormatRegistry2 as FormatRegistry,
2300
2441
  HtmlRenderer,
2301
2442
  Patterns,
2443
+ RouteRegistry,
2302
2444
  Server,
2303
2445
  ServerFactory,
2304
2446
  TokenError,
@@ -2315,6 +2457,7 @@ export {
2315
2457
  createPermissionAuth,
2316
2458
  createRequestValidator,
2317
2459
  createRoleAuth,
2460
+ createRouteRegistry,
2318
2461
  createSSEHandler,
2319
2462
  createTokenPair,
2320
2463
  createTypedRoute,