vafast 0.4.21 → 0.4.23

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
@@ -20,7 +20,6 @@ export default { port: 3000, fetch: server.fetch };
20
20
 
21
21
  ```bash
22
22
  # 启动服务器
23
- bun run index.ts # 或
24
23
  npx tsx index.ts
25
24
  ```
26
25
 
@@ -39,11 +38,7 @@ npx tsx index.ts
39
38
  ## 📦 安装
40
39
 
41
40
  ```bash
42
- # npm
43
41
  npm install vafast
44
-
45
- # bun
46
- bun add vafast
47
42
  ```
48
43
 
49
44
  ## 💡 设计哲学
@@ -504,7 +499,7 @@ const handler = createHandler({ body: UserSchema }, ({ body }) => {
504
499
 
505
500
  | 分类 | Format | 说明 |
506
501
  |------|--------|------|
507
- | **标识符** | `email`, `uuid`, `cuid`, `cuid2`, `ulid`, `nanoid`, `objectid`, `slug` | 各种 ID 格式 |
502
+ | **标识符** | `email`, `uuid`, `uuid-any`, `cuid`, `cuid2`, `ulid`, `nanoid`, `objectid`, `slug` | 各种 ID 格式 |
508
503
  | **网络** | `url`, `uri`, `ipv4`, `ipv6`, `ip`, `cidr`, `hostname` | 网络地址 |
509
504
  | **日期时间** | `date`, `time`, `date-time`, `datetime`, `duration` | ISO 8601 格式 |
510
505
  | **手机号** | `phone` (中国), `phone-cn`, `phone-e164` (国际) | 电话号码 |
@@ -512,6 +507,8 @@ const handler = createHandler({ body: UserSchema }, ({ body }) => {
512
507
  | **颜色** | `hex-color`, `rgb-color`, `color` | 颜色值 |
513
508
  | **其他** | `emoji`, `semver`, `credit-card` | 特殊格式 |
514
509
 
510
+ > **源码位置:** `src/utils/formats.ts` - 框架启动时自动注册所有 format 验证器
511
+
515
512
  **自定义 Format:**
516
513
 
517
514
  ```typescript
@@ -666,8 +663,8 @@ export default { port: 3000, fetch: server.fetch };
666
663
  ```bash
667
664
  git clone https://github.com/vafast/vafast.git
668
665
  cd vafast
669
- npm install # 或 bun install
670
- npm test # 或 bun test
666
+ npm install
667
+ npm test
671
668
  ```
672
669
 
673
670
  ## 🚀 发布流程
@@ -19,82 +19,36 @@ type InferableRoute<TMethod extends string = string, TPath extends string = stri
19
19
  */
20
20
  type Middleware = (req: Request, next: () => Promise<Response>) => Promise<Response>;
21
21
  /**
22
- * 路由定义类型(保留完整 handler 类型)
23
- */
24
- type RouteDefinition<TMethod extends string = string, TPath extends string = string, THandler = unknown> = {
25
- readonly method: TMethod;
26
- readonly path: TPath;
27
- readonly handler: THandler;
28
- readonly middleware?: ReadonlyArray<Middleware>;
29
- };
30
- /**
31
- * 创建单个路由定义(自动保留字面量类型,无需 as const)
22
+ * 定义路由数组(自动保留字面量类型,支持端到端类型推断)
32
23
  *
33
24
  * @example
34
25
  * ```typescript
35
- * import { route, defineRoutes, createHandler, Type } from 'vafast'
26
+ * import { defineRoutes, createHandler, Type } from 'vafast'
27
+ * import type { InferEden } from 'vafast-api-client'
36
28
  *
37
29
  * const routes = defineRoutes([
38
- * route('GET', '/users', createHandler(
39
- * { query: Type.Object({ page: Type.Number() }) },
40
- * async ({ query }) => ({ users: [], total: 0 })
41
- * )),
42
- * route('POST', '/users', createHandler(
43
- * { body: Type.Object({ name: Type.String() }) },
44
- * async ({ body }) => ({ id: '1', name: body.name })
45
- * )),
46
- * route('GET', '/users/:id', createHandler(
47
- * { params: Type.Object({ id: Type.String() }) },
48
- * async ({ params }) => ({ id: params.id, name: 'User' })
49
- * ))
30
+ * {
31
+ * method: 'GET',
32
+ * path: '/users',
33
+ * handler: createHandler(
34
+ * { query: Type.Object({ page: Type.Number() }) },
35
+ * async ({ query }) => ({ users: [], total: 0 })
36
+ * )
37
+ * },
38
+ * {
39
+ * method: 'POST',
40
+ * path: '/users',
41
+ * handler: createHandler(
42
+ * { body: Type.Object({ name: Type.String() }) },
43
+ * async ({ body }) => ({ id: '1', name: body.name })
44
+ * )
45
+ * }
50
46
  * ])
51
47
  *
52
- * // 无需 as const!类型自动推断
48
+ * // 自动推断字面量类型,支持端到端类型推断
53
49
  * type Api = InferEden<typeof routes>
54
50
  * ```
55
51
  */
56
- declare function route<TMethod extends string, TPath extends string, THandler>(method: TMethod, path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<TMethod, TPath, THandler>;
57
- /**
58
- * GET 路由快捷方法
59
- */
60
- declare function get<TPath extends string, THandler>(path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<'GET', TPath, THandler>;
61
- /**
62
- * POST 路由快捷方法
63
- */
64
- declare function post<TPath extends string, THandler>(path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<'POST', TPath, THandler>;
65
- /**
66
- * PUT 路由快捷方法
67
- */
68
- declare function put<TPath extends string, THandler>(path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<'PUT', TPath, THandler>;
69
- /**
70
- * DELETE 路由快捷方法
71
- */
72
- declare function del<TPath extends string, THandler>(path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<'DELETE', TPath, THandler>;
73
- /**
74
- * PATCH 路由快捷方法
75
- */
76
- declare function patch<TPath extends string, THandler>(path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<'PATCH', TPath, THandler>;
77
- /**
78
- * 定义路由数组(保留完整类型信息)
79
- *
80
- * 推荐配合 route() 函数使用,无需 as const
81
- *
82
- * @example
83
- * ```typescript
84
- * import { defineRoutes, route, createHandler, Type } from 'vafast'
85
- *
86
- * // ✨ 新方式:使用 route() 函数,无需 as const
87
- * const routes = defineRoutes([
88
- * route('GET', '/users', createHandler(...)),
89
- * route('POST', '/users', createHandler(...))
90
- * ])
91
- *
92
- * // 🔙 旧方式:需要 as const(仍然支持)
93
- * const routes = defineRoutes([
94
- * { method: 'GET', path: '/users', handler: createHandler(...) }
95
- * ] as const)
96
- * ```
97
- */
98
52
  declare function defineRoutes<const T extends readonly {
99
53
  readonly method: string;
100
54
  readonly path: string;
@@ -102,5 +56,5 @@ declare function defineRoutes<const T extends readonly {
102
56
  readonly middleware?: ReadonlyArray<Middleware>;
103
57
  }[]>(routes: T): T;
104
58
  //#endregion
105
- export { InferableRoute, RouteDefinition, defineRoutes, del, get, patch, post, put, route };
59
+ export { InferableRoute, defineRoutes };
106
60
  //# sourceMappingURL=defineRoute.d.mts.map
@@ -1,93 +1,39 @@
1
1
  //#region src/defineRoute.ts
2
2
  /**
3
- * 创建单个路由定义(自动保留字面量类型,无需 as const)
4
- *
3
+ * 定义路由数组(自动保留字面量类型,支持端到端类型推断)
4
+ *
5
5
  * @example
6
6
  * ```typescript
7
- * import { route, defineRoutes, createHandler, Type } from 'vafast'
8
- *
7
+ * import { defineRoutes, createHandler, Type } from 'vafast'
8
+ * import type { InferEden } from 'vafast-api-client'
9
+ *
9
10
  * const routes = defineRoutes([
10
- * route('GET', '/users', createHandler(
11
- * { query: Type.Object({ page: Type.Number() }) },
12
- * async ({ query }) => ({ users: [], total: 0 })
13
- * )),
14
- * route('POST', '/users', createHandler(
15
- * { body: Type.Object({ name: Type.String() }) },
16
- * async ({ body }) => ({ id: '1', name: body.name })
17
- * )),
18
- * route('GET', '/users/:id', createHandler(
19
- * { params: Type.Object({ id: Type.String() }) },
20
- * async ({ params }) => ({ id: params.id, name: 'User' })
21
- * ))
11
+ * {
12
+ * method: 'GET',
13
+ * path: '/users',
14
+ * handler: createHandler(
15
+ * { query: Type.Object({ page: Type.Number() }) },
16
+ * async ({ query }) => ({ users: [], total: 0 })
17
+ * )
18
+ * },
19
+ * {
20
+ * method: 'POST',
21
+ * path: '/users',
22
+ * handler: createHandler(
23
+ * { body: Type.Object({ name: Type.String() }) },
24
+ * async ({ body }) => ({ id: '1', name: body.name })
25
+ * )
26
+ * }
22
27
  * ])
23
- *
24
- * // 无需 as const!类型自动推断
28
+ *
29
+ * // 自动推断字面量类型,支持端到端类型推断
25
30
  * type Api = InferEden<typeof routes>
26
31
  * ```
27
32
  */
28
- function route(method, path, handler, middleware) {
29
- return {
30
- method,
31
- path,
32
- handler,
33
- middleware
34
- };
35
- }
36
- /**
37
- * GET 路由快捷方法
38
- */
39
- function get(path, handler, middleware) {
40
- return route("GET", path, handler, middleware);
41
- }
42
- /**
43
- * POST 路由快捷方法
44
- */
45
- function post(path, handler, middleware) {
46
- return route("POST", path, handler, middleware);
47
- }
48
- /**
49
- * PUT 路由快捷方法
50
- */
51
- function put(path, handler, middleware) {
52
- return route("PUT", path, handler, middleware);
53
- }
54
- /**
55
- * DELETE 路由快捷方法
56
- */
57
- function del(path, handler, middleware) {
58
- return route("DELETE", path, handler, middleware);
59
- }
60
- /**
61
- * PATCH 路由快捷方法
62
- */
63
- function patch(path, handler, middleware) {
64
- return route("PATCH", path, handler, middleware);
65
- }
66
- /**
67
- * 定义路由数组(保留完整类型信息)
68
- *
69
- * 推荐配合 route() 函数使用,无需 as const
70
- *
71
- * @example
72
- * ```typescript
73
- * import { defineRoutes, route, createHandler, Type } from 'vafast'
74
- *
75
- * // ✨ 新方式:使用 route() 函数,无需 as const
76
- * const routes = defineRoutes([
77
- * route('GET', '/users', createHandler(...)),
78
- * route('POST', '/users', createHandler(...))
79
- * ])
80
- *
81
- * // 🔙 旧方式:需要 as const(仍然支持)
82
- * const routes = defineRoutes([
83
- * { method: 'GET', path: '/users', handler: createHandler(...) }
84
- * ] as const)
85
- * ```
86
- */
87
33
  function defineRoutes(routes) {
88
34
  return routes;
89
35
  }
90
36
 
91
37
  //#endregion
92
- export { defineRoutes, del, get, patch, post, put, route };
38
+ export { defineRoutes };
93
39
  //# sourceMappingURL=defineRoute.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"defineRoute.mjs","names":[],"sources":["../src/defineRoute.ts"],"sourcesContent":["import type { RouteSchema } from \"./types\";\nimport type { InferableHandler } from \"./utils/create-handler\";\n\n/**\n * 可推断的路由类型(用于类型推断)\n * 供 vafast-api-client 使用,保留完整的类型信息\n */\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 handler: InferableHandler<TReturn, TSchema>;\n readonly middleware?: ReadonlyArray<(req: Request, next: () => Promise<Response>) => Promise<Response>>;\n}\n\n/**\n * 中间件类型\n */\ntype Middleware = (req: Request, next: () => Promise<Response>) => Promise<Response>;\n\n/**\n * 路由定义类型(保留完整 handler 类型)\n */\nexport type RouteDefinition<\n TMethod extends string = string,\n TPath extends string = string,\n THandler = unknown\n> = {\n readonly method: TMethod;\n readonly path: TPath;\n readonly handler: THandler;\n readonly middleware?: ReadonlyArray<Middleware>;\n}\n\n/**\n * 创建单个路由定义(自动保留字面量类型,无需 as const)\n * \n * @example\n * ```typescript\n * import { route, defineRoutes, createHandler, Type } from 'vafast'\n * \n * const routes = defineRoutes([\n * route('GET', '/users', createHandler(\n * { query: Type.Object({ page: Type.Number() }) },\n * async ({ query }) => ({ users: [], total: 0 })\n * )),\n * route('POST', '/users', createHandler(\n * { body: Type.Object({ name: Type.String() }) },\n * async ({ body }) => ({ id: '1', name: body.name })\n * )),\n * route('GET', '/users/:id', createHandler(\n * { params: Type.Object({ id: Type.String() }) },\n * async ({ params }) => ({ id: params.id, name: 'User' })\n * ))\n * ])\n * \n * // 无需 as const!类型自动推断\n * type Api = InferEden<typeof routes>\n * ```\n */\nexport function route<\n TMethod extends string,\n TPath extends string,\n THandler\n>(\n method: TMethod,\n path: TPath,\n handler: THandler,\n middleware?: Middleware[]\n): RouteDefinition<TMethod, TPath, THandler> {\n return {\n method,\n path,\n handler,\n middleware\n };\n}\n\n/**\n * GET 路由快捷方法\n */\nexport function get<TPath extends string, THandler>(\n path: TPath,\n handler: THandler,\n middleware?: Middleware[]\n): RouteDefinition<'GET', TPath, THandler> {\n return route('GET', path, handler, middleware);\n}\n\n/**\n * POST 路由快捷方法\n */\nexport function post<TPath extends string, THandler>(\n path: TPath,\n handler: THandler,\n middleware?: Middleware[]\n): RouteDefinition<'POST', TPath, THandler> {\n return route('POST', path, handler, middleware);\n}\n\n/**\n * PUT 路由快捷方法\n */\nexport function put<TPath extends string, THandler>(\n path: TPath,\n handler: THandler,\n middleware?: Middleware[]\n): RouteDefinition<'PUT', TPath, THandler> {\n return route('PUT', path, handler, middleware);\n}\n\n/**\n * DELETE 路由快捷方法\n */\nexport function del<TPath extends string, THandler>(\n path: TPath,\n handler: THandler,\n middleware?: Middleware[]\n): RouteDefinition<'DELETE', TPath, THandler> {\n return route('DELETE', path, handler, middleware);\n}\n\n/**\n * PATCH 路由快捷方法\n */\nexport function patch<TPath extends string, THandler>(\n path: TPath,\n handler: THandler,\n middleware?: Middleware[]\n): RouteDefinition<'PATCH', TPath, THandler> {\n return route('PATCH', path, handler, middleware);\n}\n\n/**\n * 定义路由数组(保留完整类型信息)\n * \n * 推荐配合 route() 函数使用,无需 as const\n * \n * @example\n * ```typescript\n * import { defineRoutes, route, createHandler, Type } from 'vafast'\n * \n * // ✨ 新方式:使用 route() 函数,无需 as const\n * const routes = defineRoutes([\n * route('GET', '/users', createHandler(...)),\n * route('POST', '/users', createHandler(...))\n * ])\n * \n * // 🔙 旧方式:需要 as const(仍然支持)\n * const routes = defineRoutes([\n * { method: 'GET', path: '/users', handler: createHandler(...) }\n * ] as const)\n * ```\n */\nexport function defineRoutes<\n const T extends readonly {\n readonly method: string\n readonly path: string\n readonly handler: unknown\n readonly middleware?: ReadonlyArray<Middleware>\n }[]\n>(routes: T): T {\n return routes;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,SAAgB,MAKd,QACA,MACA,SACA,YAC2C;AAC3C,QAAO;EACL;EACA;EACA;EACA;EACD;;;;;AAMH,SAAgB,IACd,MACA,SACA,YACyC;AACzC,QAAO,MAAM,OAAO,MAAM,SAAS,WAAW;;;;;AAMhD,SAAgB,KACd,MACA,SACA,YAC0C;AAC1C,QAAO,MAAM,QAAQ,MAAM,SAAS,WAAW;;;;;AAMjD,SAAgB,IACd,MACA,SACA,YACyC;AACzC,QAAO,MAAM,OAAO,MAAM,SAAS,WAAW;;;;;AAMhD,SAAgB,IACd,MACA,SACA,YAC4C;AAC5C,QAAO,MAAM,UAAU,MAAM,SAAS,WAAW;;;;;AAMnD,SAAgB,MACd,MACA,SACA,YAC2C;AAC3C,QAAO,MAAM,SAAS,MAAM,SAAS,WAAW;;;;;;;;;;;;;;;;;;;;;;;AAwBlD,SAAgB,aAOd,QAAc;AACd,QAAO"}
1
+ {"version":3,"file":"defineRoute.mjs","names":[],"sources":["../src/defineRoute.ts"],"sourcesContent":["import type { RouteSchema } from \"./types\";\nimport type { InferableHandler } from \"./utils/create-handler\";\n\n/**\n * 可推断的路由类型(用于类型推断)\n * 供 vafast-api-client 使用,保留完整的类型信息\n */\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 handler: InferableHandler<TReturn, TSchema>;\n readonly middleware?: ReadonlyArray<(req: Request, next: () => Promise<Response>) => Promise<Response>>;\n}\n\n/**\n * 中间件类型\n */\ntype Middleware = (req: Request, next: () => Promise<Response>) => Promise<Response>;\n\n/**\n * 定义路由数组(自动保留字面量类型,支持端到端类型推断)\n *\n * @example\n * ```typescript\n * import { defineRoutes, createHandler, Type } from 'vafast'\n * import type { InferEden } from 'vafast-api-client'\n *\n * const routes = defineRoutes([\n * {\n * method: 'GET',\n * path: '/users',\n * handler: createHandler(\n * { query: Type.Object({ page: Type.Number() }) },\n * async ({ query }) => ({ users: [], total: 0 })\n * )\n * },\n * {\n * method: 'POST',\n * path: '/users',\n * handler: createHandler(\n * { body: Type.Object({ name: Type.String() }) },\n * async ({ body }) => ({ id: '1', name: body.name })\n * )\n * }\n * ])\n *\n * // 自动推断字面量类型,支持端到端类型推断\n * type Api = InferEden<typeof routes>\n * ```\n */\nexport function defineRoutes<\n const T extends readonly {\n readonly method: string\n readonly path: string\n readonly handler: unknown\n readonly middleware?: ReadonlyArray<Middleware>\n }[]\n>(routes: T): T {\n return routes;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,SAAgB,aAOd,QAAc;AACd,QAAO"}
@@ -1,6 +1,6 @@
1
1
  import { l as Route, s as NestedRoute } from "./types-D1PUFkda.mjs";
2
2
  import { r as NestedComponentRoute, t as ComponentRoute } from "./component-route-nrrO0iSI.mjs";
3
- import { t as Server } from "./server-DGA3dd5s.mjs";
3
+ import { t as Server } from "./server-C2RPKSvC.mjs";
4
4
  import { t as ComponentServer } from "./component-server-JqpDC7wy.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-CEfOqqvd.d.mts.map
48
+ //# sourceMappingURL=index-Bj3SWrMU.d.mts.map
package/dist/index.d.mts CHANGED
@@ -4,12 +4,12 @@ import { n as FlattenedComponentRoute, r as NestedComponentRoute, t as Component
4
4
  import { a as TypedHandler, i as RouteSchema, n as HandlerContextWithExtra, o as TypedRouteConfig, r as InferSchema, t as HandlerContext } from "./schema-B6DFN5c2.mjs";
5
5
  import "./index-CREkvfw9.mjs";
6
6
  import { i as simpleHandler, n as createHandler, r as createHandlerWithExtra, t as InferableHandler } from "./create-handler-DKw-sQOV.mjs";
7
- import { InferableRoute, RouteDefinition, defineRoutes, del, get, patch, post, put, route } from "./defineRoute.mjs";
7
+ import { InferableRoute, defineRoutes } from "./defineRoute.mjs";
8
8
  import { t as BaseServer } from "./base-server-DLxtulAO.mjs";
9
- import { t as Server } from "./server-DGA3dd5s.mjs";
9
+ import { t as Server } from "./server-C2RPKSvC.mjs";
10
10
  import { t as DependencyManager } from "./dependency-manager-C3_7ic4h.mjs";
11
11
  import { t as ComponentServer } from "./component-server-JqpDC7wy.mjs";
12
- import { t as ServerFactory } from "./index-CEfOqqvd.mjs";
12
+ import { t as ServerFactory } from "./index-Bj3SWrMU.mjs";
13
13
  import { n as composeMiddleware, t as VafastError } from "./middleware-KXEoefLX.mjs";
14
14
  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-BerGr2_q.mjs";
15
15
  import { c as text, i as json, n as err, o as redirect, r as html, s as stream, t as empty } from "./response-BMfdEcTm.mjs";
@@ -27,4 +27,4 @@ import { flattenNestedRoutes, normalizePath } from "./router.mjs";
27
27
  import { i as ServeResult, o as serve, r as ServeOptions, t as FetchHandler } from "./serve-AG80VaIr.mjs";
28
28
  import "./serve.mjs";
29
29
  import { FormatRegistry, Type } from "@sinclair/typebox";
30
- export { BaseRouteConfig, BaseServer, CompatibleRoute, ComponentRoute, ComponentServer, DependencyManager, ExtendedRouteConfig, type FetchHandler, FlattenedComponentRoute, FlattenedRoute, FormatRegistry, Handler, HandlerContext, HandlerContextWithExtra, HtmlRenderer, InferSchema, InferableHandler, InferableRoute, Method, Middleware, NestedComponentRoute, NestedRoute, NestedRouteConfig, Patterns, ResponseBody, Route, RouteDefinition, RouteMeta, RouteRegistry, RouteSchema, SSEEvent, SSEHandler, SSEMarker, SchemaConfig, type ServeOptions, type ServeResult, Server, ServerFactory, Type, TypedHandler, TypedRoute, TypedRouteConfig, VafastError, ValidationError, ValidationResult, base64urlDecode, base64urlEncode, composeMiddleware, createHandler, createHandlerWithExtra, createRequestValidator, createRouteRegistry, createSSEHandler, createTypedRoute, createValidator, defineRoutes, del, empty, err, filterRoutes, flattenNestedRoutes, get, getAllRoutes, getCookie, getHeader, getLocals, getRoute, getRouteRegistry, getValidatorCacheStats, goAwait, hasFormat, html, isTypedRoute, json, normalizePath, parseAndValidateRequest, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, parseRequest, patch, post, precompileSchemas, put, redirect, registerFormat, registerFormats, route, serve, setLocals, simpleHandler, stream, text, validateAllSchemas, validateFast, validateRequest, validateSchema, validateSchemaOrThrow };
30
+ export { BaseRouteConfig, BaseServer, CompatibleRoute, ComponentRoute, ComponentServer, DependencyManager, ExtendedRouteConfig, type FetchHandler, FlattenedComponentRoute, FlattenedRoute, FormatRegistry, Handler, HandlerContext, HandlerContextWithExtra, HtmlRenderer, InferSchema, InferableHandler, InferableRoute, Method, Middleware, NestedComponentRoute, NestedRoute, NestedRouteConfig, Patterns, ResponseBody, Route, RouteMeta, RouteRegistry, RouteSchema, SSEEvent, SSEHandler, SSEMarker, SchemaConfig, type ServeOptions, type ServeResult, Server, ServerFactory, Type, TypedHandler, TypedRoute, TypedRouteConfig, VafastError, ValidationError, ValidationResult, base64urlDecode, base64urlEncode, composeMiddleware, createHandler, createHandlerWithExtra, createRequestValidator, createRouteRegistry, createSSEHandler, createTypedRoute, createValidator, defineRoutes, empty, err, filterRoutes, flattenNestedRoutes, getAllRoutes, getCookie, getHeader, getLocals, getRoute, getRouteRegistry, getValidatorCacheStats, goAwait, hasFormat, html, isTypedRoute, json, normalizePath, parseAndValidateRequest, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, parseRequest, precompileSchemas, redirect, registerFormat, registerFormats, serve, setLocals, simpleHandler, stream, text, validateAllSchemas, validateFast, validateRequest, validateSchema, validateSchemaOrThrow };
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
- import { defineRoutes, del, get, patch, post, put, route } from "./defineRoute.mjs";
1
+ import { defineRoutes } from "./defineRoute.mjs";
2
2
  import { n as normalizePath, t as flattenNestedRoutes } from "./router-xWzwz_1a.mjs";
3
3
  import { a as html, c as redirect, i as err, l as stream, n as composeMiddleware, o as json, r as empty, t as VafastError, u as text } from "./middleware-CewKbtb4.mjs";
4
4
  import { t as BaseServer } from "./base-server-B7MYJNsl.mjs";
5
5
  import { a as getRoute, i as getAllRoutes, n as createRouteRegistry, o as getRouteRegistry, r as filterRoutes, t as RouteRegistry } from "./route-registry-emTmRrWQ.mjs";
6
- import { t as Server } from "./server-L_FNwdap.mjs";
6
+ import { t as Server } from "./server-DdIIf4co.mjs";
7
7
  import { t as HtmlRenderer } from "./html-renderer-DTtJ_Yic.mjs";
8
8
  import { t as DependencyManager } from "./dependency-manager-DCmh7xFc.mjs";
9
9
  import { t as ComponentServer } from "./component-server-DomPJ_7S.mjs";
10
- import { t as ServerFactory } from "./server-C75o1b-a.mjs";
10
+ import { t as ServerFactory } from "./server-CezB-92R.mjs";
11
11
  import { a as parseCookies, d as parseQueryFast, l as parseHeaders, n as getHeader, o as parseCookiesFast, r as parseBody, t as getCookie, u as parseQuery } from "./parsers-DpH_mD0H.mjs";
12
12
  import { t as goAwait } from "./go-await-C4ZdEUwY.mjs";
13
13
  import { a as validateAllSchemas, c as validateSchemaOrThrow, i as precompileSchemas, n as createValidator, o as validateFast, r as getValidatorCacheStats, s as validateSchema } from "./validators-DBkyw6BG.mjs";
@@ -29,5 +29,5 @@ import { FormatRegistry, Type } from "@sinclair/typebox";
29
29
  registerFormats();
30
30
 
31
31
  //#endregion
32
- export { BaseServer, ComponentServer, DependencyManager, FormatRegistry, HtmlRenderer, Patterns, RouteRegistry, Server, ServerFactory, Type, VafastError, base64urlDecode, base64urlEncode, composeMiddleware, createHandler, createHandlerWithExtra, createRequestValidator, createRouteRegistry, createSSEHandler, createTypedRoute, createValidator, defineRoutes, del, empty, err, filterRoutes, flattenNestedRoutes, get, getAllRoutes, getCookie, getHeader, getLocals, getRoute, getRouteRegistry, getValidatorCacheStats, goAwait, hasFormat, html, isTypedRoute, json, normalizePath, parseAndValidateRequest, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, parseRequest, patch, post, precompileSchemas, put, redirect, registerFormat, registerFormats, route, serve, setLocals, simpleHandler, stream, text, validateAllSchemas, validateFast, validateRequest, validateSchema, validateSchemaOrThrow };
32
+ export { BaseServer, ComponentServer, DependencyManager, FormatRegistry, HtmlRenderer, Patterns, RouteRegistry, Server, ServerFactory, Type, VafastError, base64urlDecode, base64urlEncode, composeMiddleware, createHandler, createHandlerWithExtra, createRequestValidator, createRouteRegistry, createSSEHandler, createTypedRoute, createValidator, defineRoutes, empty, err, filterRoutes, flattenNestedRoutes, getAllRoutes, getCookie, getHeader, getLocals, getRoute, getRouteRegistry, getValidatorCacheStats, goAwait, hasFormat, html, isTypedRoute, json, normalizePath, parseAndValidateRequest, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, parseRequest, precompileSchemas, redirect, registerFormat, registerFormats, serve, setLocals, simpleHandler, stream, text, validateAllSchemas, validateFast, validateRequest, validateSchema, validateSchemaOrThrow };
33
33
  //# sourceMappingURL=index.mjs.map
@@ -1,8 +1,8 @@
1
1
  import "../schema-B6DFN5c2.mjs";
2
2
  import "../index-CREkvfw9.mjs";
3
3
  import "../base-server-DLxtulAO.mjs";
4
- import "../server-DGA3dd5s.mjs";
4
+ import "../server-C2RPKSvC.mjs";
5
5
  import "../component-server-JqpDC7wy.mjs";
6
- import "../index-CEfOqqvd.mjs";
6
+ import "../index-Bj3SWrMU.mjs";
7
7
  import { MemoryInfo, MonitoredServer, MonitoringConfig, MonitoringMetrics, MonitoringStatus, PathStats, StatusCodeDistribution, TimeWindowStats, createMonitoredServer, withMonitoring } from "./native-monitor.mjs";
8
8
  export { type MemoryInfo, type MonitoredServer, type MonitoringConfig, type MonitoringMetrics, type MonitoringStatus, type PathStats, type StatusCodeDistribution, type TimeWindowStats, createMonitoredServer, withMonitoring };
@@ -1,9 +1,9 @@
1
1
  import "../schema-B6DFN5c2.mjs";
2
2
  import "../index-CREkvfw9.mjs";
3
3
  import "../base-server-DLxtulAO.mjs";
4
- import { t as Server } from "../server-DGA3dd5s.mjs";
4
+ import { t as Server } from "../server-C2RPKSvC.mjs";
5
5
  import "../component-server-JqpDC7wy.mjs";
6
- import "../index-CEfOqqvd.mjs";
6
+ import "../index-Bj3SWrMU.mjs";
7
7
 
8
8
  //#region src/monitoring/native-monitor.d.ts
9
9
 
@@ -1 +1 @@
1
- {"version":3,"file":"native-monitor.mjs","names":[],"sources":["../../src/monitoring/native-monitor.ts"],"sourcesContent":["/**\n * 原生监控模块(零外部依赖)\n *\n * 特性:\n * - P50/P95/P99 百分位数统计\n * - 按路径分组统计\n * - 时间窗口统计(1分钟/5分钟/1小时)\n * - RPS 计算(每秒请求数)\n * - 状态码分布\n * - 环形缓冲区(内存友好)\n * - 采样率控制\n * - 路径排除\n * - 自定义回调\n */\n\nimport type { Server } from \"../server\";\n\n// ========== 类型定义 ==========\n\n/** 监控配置 */\nexport interface MonitoringConfig {\n /** 是否启用监控,默认 true */\n enabled?: boolean;\n /** 是否输出到控制台,默认 true */\n console?: boolean;\n /** 慢请求阈值(毫秒),默认 1000 */\n slowThreshold?: number;\n /** 最大记录数,默认 1000 */\n maxRecords?: number;\n /** 采样率 0-1,默认 1(全部记录) */\n samplingRate?: number;\n /** 排除的路径(不记录) */\n excludePaths?: string[];\n /** 自定义标签 */\n tags?: Record<string, string>;\n /** 请求完成回调 */\n onRequest?: (metrics: MonitoringMetrics) => void;\n /** 慢请求回调 */\n onSlowRequest?: (metrics: MonitoringMetrics) => void;\n}\n\n/** 监控指标 */\nexport interface MonitoringMetrics {\n requestId: string;\n method: string;\n path: string;\n statusCode: number;\n totalTime: number;\n timestamp: number;\n memoryUsage: MemoryInfo;\n}\n\n/** 内存信息 */\nexport interface MemoryInfo {\n heapUsed: number;\n heapTotal: number;\n}\n\n/** 路径统计 */\nexport interface PathStats {\n count: number;\n totalTime: number;\n avgTime: number;\n minTime: number;\n maxTime: number;\n errorCount: number;\n}\n\n/** 时间窗口统计 */\nexport interface TimeWindowStats {\n /** 请求数 */\n requests: number;\n /** 成功数 */\n successful: number;\n /** 失败数 */\n failed: number;\n /** 错误率 */\n errorRate: number;\n /** 平均响应时间 */\n avgTime: number;\n /** RPS(每秒请求数) */\n rps: number;\n}\n\n/** 状态码分布 */\nexport interface StatusCodeDistribution {\n /** 2xx 成功 */\n \"2xx\": number;\n /** 3xx 重定向 */\n \"3xx\": number;\n /** 4xx 客户端错误 */\n \"4xx\": number;\n /** 5xx 服务器错误 */\n \"5xx\": number;\n /** 详细分布 */\n detail: Record<number, number>;\n}\n\n/** 监控状态 */\nexport interface MonitoringStatus {\n enabled: boolean;\n /** 服务运行时间(毫秒) */\n uptime: number;\n totalRequests: number;\n successfulRequests: number;\n failedRequests: number;\n errorRate: number;\n /** 平均响应时间(毫秒) */\n avgResponseTime: number;\n /** P50 响应时间(毫秒) */\n p50: number;\n /** P95 响应时间(毫秒) */\n p95: number;\n /** P99 响应时间(毫秒) */\n p99: number;\n /** 最小响应时间 */\n minTime: number;\n /** 最大响应时间 */\n maxTime: number;\n /** 当前 RPS */\n rps: number;\n /** 状态码分布 */\n statusCodes: StatusCodeDistribution;\n /** 时间窗口统计 */\n timeWindows: {\n /** 最近 1 分钟 */\n last1min: TimeWindowStats;\n /** 最近 5 分钟 */\n last5min: TimeWindowStats;\n /** 最近 1 小时 */\n last1hour: TimeWindowStats;\n };\n /** 按路径统计 */\n byPath: Record<string, PathStats>;\n /** 内存使用 */\n memoryUsage: {\n heapUsed: string;\n heapTotal: string;\n };\n /** 最近请求 */\n recentRequests: MonitoringMetrics[];\n}\n\n/** 带监控的 Server */\nexport interface MonitoredServer extends Server {\n getMonitoringStatus(): MonitoringStatus;\n getMonitoringMetrics(): MonitoringMetrics[];\n getPathStats(path: string): PathStats | undefined;\n getTimeWindowStats(windowMs: number): TimeWindowStats;\n getRPS(): number;\n getStatusCodeDistribution(): StatusCodeDistribution;\n resetMonitoring(): void;\n}\n\n// ========== 常量 ==========\n\nconst ONE_MINUTE = 60 * 1000;\nconst FIVE_MINUTES = 5 * 60 * 1000;\nconst ONE_HOUR = 60 * 60 * 1000;\n\n// ========== 环形缓冲区 ==========\n\nfunction createRingBuffer<T>(capacity: number) {\n const buffer: T[] = new Array(capacity);\n let head = 0;\n let size = 0;\n\n return {\n push(item: T) {\n buffer[head % capacity] = item;\n head++;\n if (size < capacity) size++;\n },\n\n toArray(): T[] {\n if (size === 0) return [];\n if (size < capacity) {\n return buffer.slice(0, size);\n }\n const start = head % capacity;\n return [...buffer.slice(start), ...buffer.slice(0, start)];\n },\n\n getSize: () => size,\n\n clear() {\n head = 0;\n size = 0;\n },\n\n recent(n: number): T[] {\n const arr = this.toArray();\n return arr.slice(-n);\n },\n };\n}\n\n// ========== 工具函数 ==========\n\nfunction generateRequestId(): string {\n return `req_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;\n}\n\nfunction getMemoryInfo(): MemoryInfo {\n if (typeof process !== \"undefined\" && process.memoryUsage) {\n const mem = process.memoryUsage();\n return { heapUsed: mem.heapUsed, heapTotal: mem.heapTotal };\n }\n return { heapUsed: 0, heapTotal: 0 };\n}\n\nfunction formatMemory(bytes: number): string {\n return (bytes / 1024 / 1024).toFixed(2) + \"MB\";\n}\n\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const index = Math.ceil((p / 100) * sorted.length) - 1;\n return sorted[Math.max(0, index)];\n}\n\nfunction shouldExclude(path: string, excludePaths: string[]): boolean {\n return excludePaths.some(\n (p) =>\n path === p ||\n path.startsWith(p + \"/\") ||\n (p.endsWith(\"*\") && path.startsWith(p.slice(0, -1)))\n );\n}\n\nfunction getStatusCodeCategory(code: number): \"2xx\" | \"3xx\" | \"4xx\" | \"5xx\" {\n if (code >= 200 && code < 300) return \"2xx\";\n if (code >= 300 && code < 400) return \"3xx\";\n if (code >= 400 && code < 500) return \"4xx\";\n return \"5xx\";\n}\n\n// ========== 监控状态管理 ==========\n\nfunction createMonitorState(config: Required<MonitoringConfig>) {\n const buffer = createRingBuffer<MonitoringMetrics>(config.maxRecords);\n const pathStats = new Map<string, PathStats>();\n const startTime = Date.now();\n\n /** 获取时间窗口内的指标 */\n function getMetricsInWindow(windowMs: number): MonitoringMetrics[] {\n const now = Date.now();\n const cutoff = now - windowMs;\n return buffer.toArray().filter((m) => m.timestamp >= cutoff);\n }\n\n /** 计算时间窗口统计 */\n function calcTimeWindowStats(windowMs: number): TimeWindowStats {\n const metrics = getMetricsInWindow(windowMs);\n const count = metrics.length;\n\n if (count === 0) {\n return {\n requests: 0,\n successful: 0,\n failed: 0,\n errorRate: 0,\n avgTime: 0,\n rps: 0,\n };\n }\n\n const successful = metrics.filter((m) => m.statusCode < 400).length;\n const failed = count - successful;\n const avgTime = metrics.reduce((sum, m) => sum + m.totalTime, 0) / count;\n\n // 计算实际时间跨度(用于 RPS)\n const timestamps = metrics.map((m) => m.timestamp);\n const actualWindow = Math.max(...timestamps) - Math.min(...timestamps);\n const effectiveWindow = Math.max(actualWindow, 1000); // 至少 1 秒\n const rps = (count / effectiveWindow) * 1000;\n\n return {\n requests: count,\n successful,\n failed,\n errorRate: failed / count,\n avgTime: Number(avgTime.toFixed(2)),\n rps: Number(rps.toFixed(2)),\n };\n }\n\n /** 计算状态码分布 */\n function calcStatusCodeDistribution(): StatusCodeDistribution {\n const metrics = buffer.toArray();\n const dist: StatusCodeDistribution = {\n \"2xx\": 0,\n \"3xx\": 0,\n \"4xx\": 0,\n \"5xx\": 0,\n detail: {},\n };\n\n for (const m of metrics) {\n const category = getStatusCodeCategory(m.statusCode);\n dist[category]++;\n dist.detail[m.statusCode] = (dist.detail[m.statusCode] || 0) + 1;\n }\n\n return dist;\n }\n\n /** 计算当前 RPS(基于最近 10 秒) */\n function calcCurrentRPS(): number {\n const metrics = getMetricsInWindow(10000); // 最近 10 秒\n if (metrics.length === 0) return 0;\n return Number((metrics.length / 10).toFixed(2));\n }\n\n return {\n addMetrics(m: MonitoringMetrics) {\n buffer.push(m);\n\n // 更新路径统计\n const stats = pathStats.get(m.path) || {\n count: 0,\n totalTime: 0,\n avgTime: 0,\n minTime: Infinity,\n maxTime: 0,\n errorCount: 0,\n };\n\n stats.count++;\n stats.totalTime += m.totalTime;\n stats.avgTime = stats.totalTime / stats.count;\n stats.minTime = Math.min(stats.minTime, m.totalTime);\n stats.maxTime = Math.max(stats.maxTime, m.totalTime);\n if (m.statusCode >= 400) stats.errorCount++;\n\n pathStats.set(m.path, stats);\n },\n\n getMetrics: () => buffer.toArray(),\n\n getPathStats: (path: string) => pathStats.get(path),\n\n getTimeWindowStats: calcTimeWindowStats,\n\n getRPS: calcCurrentRPS,\n\n getStatusCodeDistribution: calcStatusCodeDistribution,\n\n reset() {\n buffer.clear();\n pathStats.clear();\n },\n\n getStatus(): MonitoringStatus {\n const metrics = buffer.toArray();\n const total = metrics.length;\n\n if (total === 0) {\n return {\n enabled: config.enabled,\n uptime: Date.now() - startTime,\n totalRequests: 0,\n successfulRequests: 0,\n failedRequests: 0,\n errorRate: 0,\n avgResponseTime: 0,\n p50: 0,\n p95: 0,\n p99: 0,\n minTime: 0,\n maxTime: 0,\n rps: 0,\n statusCodes: { \"2xx\": 0, \"3xx\": 0, \"4xx\": 0, \"5xx\": 0, detail: {} },\n timeWindows: {\n last1min: { requests: 0, successful: 0, failed: 0, errorRate: 0, avgTime: 0, rps: 0 },\n last5min: { requests: 0, successful: 0, failed: 0, errorRate: 0, avgTime: 0, rps: 0 },\n last1hour: { requests: 0, successful: 0, failed: 0, errorRate: 0, avgTime: 0, rps: 0 },\n },\n byPath: {},\n memoryUsage: { heapUsed: formatMemory(0), heapTotal: formatMemory(0) },\n recentRequests: [],\n };\n }\n\n const successful = metrics.filter((m) => m.statusCode < 400).length;\n const failed = total - successful;\n\n const times = metrics.map((m) => m.totalTime);\n const sortedTimes = [...times].sort((a, b) => a - b);\n const avgTime = times.reduce((a, b) => a + b, 0) / total;\n\n const mem = getMemoryInfo();\n\n const byPath: Record<string, PathStats> = {};\n pathStats.forEach((stats, path) => {\n byPath[path] = { ...stats, minTime: stats.minTime === Infinity ? 0 : stats.minTime };\n });\n\n return {\n enabled: config.enabled,\n uptime: Date.now() - startTime,\n totalRequests: total,\n successfulRequests: successful,\n failedRequests: failed,\n errorRate: Number((failed / total).toFixed(4)),\n avgResponseTime: Number(avgTime.toFixed(2)),\n p50: Number(percentile(sortedTimes, 50).toFixed(2)),\n p95: Number(percentile(sortedTimes, 95).toFixed(2)),\n p99: Number(percentile(sortedTimes, 99).toFixed(2)),\n minTime: Number(sortedTimes[0].toFixed(2)),\n maxTime: Number(sortedTimes[sortedTimes.length - 1].toFixed(2)),\n rps: calcCurrentRPS(),\n statusCodes: calcStatusCodeDistribution(),\n timeWindows: {\n last1min: calcTimeWindowStats(ONE_MINUTE),\n last5min: calcTimeWindowStats(FIVE_MINUTES),\n last1hour: calcTimeWindowStats(ONE_HOUR),\n },\n byPath,\n memoryUsage: {\n heapUsed: formatMemory(mem.heapUsed),\n heapTotal: formatMemory(mem.heapTotal),\n },\n recentRequests: buffer.recent(5),\n };\n },\n };\n}\n\n// ========== 日志输出 ==========\n\nfunction logRequest(\n metrics: MonitoringMetrics,\n slowThreshold: number,\n enabled: boolean\n) {\n if (!enabled) return;\n\n const status = metrics.statusCode < 400 ? \"✅\" : \"❌\";\n const speed = metrics.totalTime > slowThreshold ? \"🐌\" : \"⚡\";\n\n console.log(\n `${status} ${metrics.method} ${metrics.path} - ${metrics.statusCode} (${speed} ${metrics.totalTime.toFixed(2)}ms)`\n );\n}\n\n// ========== 主函数 ==========\n\nconst defaultConfig: Required<MonitoringConfig> = {\n enabled: true,\n console: true,\n slowThreshold: 1000,\n maxRecords: 1000,\n samplingRate: 1,\n excludePaths: [],\n tags: { framework: \"vafast\" },\n onRequest: () => {},\n onSlowRequest: () => {},\n};\n\n/**\n * 为 Server 添加监控能力\n *\n * @example\n * ```ts\n * const server = new Server(routes)\n * const monitored = withMonitoring(server, {\n * slowThreshold: 500,\n * excludePaths: ['/health'],\n * onSlowRequest: (m) => console.warn('Slow!', m.path)\n * })\n *\n * // 获取完整状态\n * const status = monitored.getMonitoringStatus()\n * console.log(`P99: ${status.p99}ms`)\n * console.log(`RPS: ${status.rps}`)\n * console.log(`Last 1min errors: ${status.timeWindows.last1min.errorRate}`)\n *\n * // 单独获取 RPS\n * console.log(`Current RPS: ${monitored.getRPS()}`)\n *\n * // 自定义时间窗口\n * const last30sec = monitored.getTimeWindowStats(30000)\n * ```\n */\nexport function withMonitoring(\n server: Server,\n config: MonitoringConfig = {}\n): MonitoredServer {\n const finalConfig = { ...defaultConfig, ...config };\n const state = createMonitorState(finalConfig);\n const originalFetch = server.fetch.bind(server);\n\n if (finalConfig.enabled && finalConfig.console) {\n console.log(\"✅ Monitoring enabled\");\n console.log(`📊 Config:`, {\n slowThreshold: `${finalConfig.slowThreshold}ms`,\n maxRecords: finalConfig.maxRecords,\n samplingRate: finalConfig.samplingRate,\n excludePaths: finalConfig.excludePaths,\n });\n }\n\n const monitoredFetch = async (req: Request): Promise<Response> => {\n if (!finalConfig.enabled) {\n return originalFetch(req);\n }\n\n const { pathname } = new URL(req.url);\n\n if (shouldExclude(pathname, finalConfig.excludePaths)) {\n return originalFetch(req);\n }\n\n if (finalConfig.samplingRate < 1 && Math.random() > finalConfig.samplingRate) {\n return originalFetch(req);\n }\n\n const startTime = performance.now();\n const requestId = generateRequestId();\n const method = req.method;\n\n let statusCode = 500;\n try {\n const response = await originalFetch(req);\n statusCode = response.status;\n return response;\n } finally {\n const totalTime = performance.now() - startTime;\n const metrics: MonitoringMetrics = {\n requestId,\n method,\n path: pathname,\n statusCode,\n totalTime,\n timestamp: Date.now(),\n memoryUsage: getMemoryInfo(),\n };\n\n state.addMetrics(metrics);\n logRequest(metrics, finalConfig.slowThreshold, finalConfig.console);\n\n finalConfig.onRequest(metrics);\n if (totalTime > finalConfig.slowThreshold) {\n finalConfig.onSlowRequest(metrics);\n }\n }\n };\n\n return {\n ...server,\n fetch: monitoredFetch,\n getMonitoringStatus: state.getStatus,\n getMonitoringMetrics: state.getMetrics,\n getPathStats: state.getPathStats,\n getTimeWindowStats: state.getTimeWindowStats,\n getRPS: state.getRPS,\n getStatusCodeDistribution: state.getStatusCodeDistribution,\n resetMonitoring: state.reset,\n } as MonitoredServer;\n}\n\n/**\n * 创建带监控的 Server(便捷函数)\n */\nexport function createMonitoredServer(\n ServerClass: typeof Server,\n routes: ConstructorParameters<typeof Server>[0],\n config?: MonitoringConfig\n): MonitoredServer {\n const server = new ServerClass(routes);\n return withMonitoring(server, config);\n}\n"],"mappings":";AA4JA,MAAM,aAAa,KAAK;AACxB,MAAM,eAAe,MAAS;AAC9B,MAAM,WAAW,OAAU;AAI3B,SAAS,iBAAoB,UAAkB;CAC7C,MAAM,SAAc,IAAI,MAAM,SAAS;CACvC,IAAI,OAAO;CACX,IAAI,OAAO;AAEX,QAAO;EACL,KAAK,MAAS;AACZ,UAAO,OAAO,YAAY;AAC1B;AACA,OAAI,OAAO,SAAU;;EAGvB,UAAe;AACb,OAAI,SAAS,EAAG,QAAO,EAAE;AACzB,OAAI,OAAO,SACT,QAAO,OAAO,MAAM,GAAG,KAAK;GAE9B,MAAM,QAAQ,OAAO;AACrB,UAAO,CAAC,GAAG,OAAO,MAAM,MAAM,EAAE,GAAG,OAAO,MAAM,GAAG,MAAM,CAAC;;EAG5D,eAAe;EAEf,QAAQ;AACN,UAAO;AACP,UAAO;;EAGT,OAAO,GAAgB;AAErB,UADY,KAAK,SAAS,CACf,MAAM,CAAC,EAAE;;EAEvB;;AAKH,SAAS,oBAA4B;AACnC,QAAO,OAAO,KAAK,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,GAAG,GAAG;;AAGrE,SAAS,gBAA4B;AACnC,KAAI,OAAO,YAAY,eAAe,QAAQ,aAAa;EACzD,MAAM,MAAM,QAAQ,aAAa;AACjC,SAAO;GAAE,UAAU,IAAI;GAAU,WAAW,IAAI;GAAW;;AAE7D,QAAO;EAAE,UAAU;EAAG,WAAW;EAAG;;AAGtC,SAAS,aAAa,OAAuB;AAC3C,SAAQ,QAAQ,OAAO,MAAM,QAAQ,EAAE,GAAG;;AAG5C,SAAS,WAAW,QAAkB,GAAmB;AACvD,KAAI,OAAO,WAAW,EAAG,QAAO;CAChC,MAAM,QAAQ,KAAK,KAAM,IAAI,MAAO,OAAO,OAAO,GAAG;AACrD,QAAO,OAAO,KAAK,IAAI,GAAG,MAAM;;AAGlC,SAAS,cAAc,MAAc,cAAiC;AACpE,QAAO,aAAa,MACjB,MACC,SAAS,KACT,KAAK,WAAW,IAAI,IAAI,IACvB,EAAE,SAAS,IAAI,IAAI,KAAK,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,CACtD;;AAGH,SAAS,sBAAsB,MAA6C;AAC1E,KAAI,QAAQ,OAAO,OAAO,IAAK,QAAO;AACtC,KAAI,QAAQ,OAAO,OAAO,IAAK,QAAO;AACtC,KAAI,QAAQ,OAAO,OAAO,IAAK,QAAO;AACtC,QAAO;;AAKT,SAAS,mBAAmB,QAAoC;CAC9D,MAAM,SAAS,iBAAoC,OAAO,WAAW;CACrE,MAAM,4BAAY,IAAI,KAAwB;CAC9C,MAAM,YAAY,KAAK,KAAK;;CAG5B,SAAS,mBAAmB,UAAuC;EAEjE,MAAM,SADM,KAAK,KAAK,GACD;AACrB,SAAO,OAAO,SAAS,CAAC,QAAQ,MAAM,EAAE,aAAa,OAAO;;;CAI9D,SAAS,oBAAoB,UAAmC;EAC9D,MAAM,UAAU,mBAAmB,SAAS;EAC5C,MAAM,QAAQ,QAAQ;AAEtB,MAAI,UAAU,EACZ,QAAO;GACL,UAAU;GACV,YAAY;GACZ,QAAQ;GACR,WAAW;GACX,SAAS;GACT,KAAK;GACN;EAGH,MAAM,aAAa,QAAQ,QAAQ,MAAM,EAAE,aAAa,IAAI,CAAC;EAC7D,MAAM,SAAS,QAAQ;EACvB,MAAM,UAAU,QAAQ,QAAQ,KAAK,MAAM,MAAM,EAAE,WAAW,EAAE,GAAG;EAGnE,MAAM,aAAa,QAAQ,KAAK,MAAM,EAAE,UAAU;EAClD,MAAM,eAAe,KAAK,IAAI,GAAG,WAAW,GAAG,KAAK,IAAI,GAAG,WAAW;EAEtE,MAAM,MAAO,QADW,KAAK,IAAI,cAAc,IAAK,GACZ;AAExC,SAAO;GACL,UAAU;GACV;GACA;GACA,WAAW,SAAS;GACpB,SAAS,OAAO,QAAQ,QAAQ,EAAE,CAAC;GACnC,KAAK,OAAO,IAAI,QAAQ,EAAE,CAAC;GAC5B;;;CAIH,SAAS,6BAAqD;EAC5D,MAAM,UAAU,OAAO,SAAS;EAChC,MAAM,OAA+B;GACnC,OAAO;GACP,OAAO;GACP,OAAO;GACP,OAAO;GACP,QAAQ,EAAE;GACX;AAED,OAAK,MAAM,KAAK,SAAS;GACvB,MAAM,WAAW,sBAAsB,EAAE,WAAW;AACpD,QAAK;AACL,QAAK,OAAO,EAAE,eAAe,KAAK,OAAO,EAAE,eAAe,KAAK;;AAGjE,SAAO;;;CAIT,SAAS,iBAAyB;EAChC,MAAM,UAAU,mBAAmB,IAAM;AACzC,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SAAO,QAAQ,QAAQ,SAAS,IAAI,QAAQ,EAAE,CAAC;;AAGjD,QAAO;EACL,WAAW,GAAsB;AAC/B,UAAO,KAAK,EAAE;GAGd,MAAM,QAAQ,UAAU,IAAI,EAAE,KAAK,IAAI;IACrC,OAAO;IACP,WAAW;IACX,SAAS;IACT,SAAS;IACT,SAAS;IACT,YAAY;IACb;AAED,SAAM;AACN,SAAM,aAAa,EAAE;AACrB,SAAM,UAAU,MAAM,YAAY,MAAM;AACxC,SAAM,UAAU,KAAK,IAAI,MAAM,SAAS,EAAE,UAAU;AACpD,SAAM,UAAU,KAAK,IAAI,MAAM,SAAS,EAAE,UAAU;AACpD,OAAI,EAAE,cAAc,IAAK,OAAM;AAE/B,aAAU,IAAI,EAAE,MAAM,MAAM;;EAG9B,kBAAkB,OAAO,SAAS;EAElC,eAAe,SAAiB,UAAU,IAAI,KAAK;EAEnD,oBAAoB;EAEpB,QAAQ;EAER,2BAA2B;EAE3B,QAAQ;AACN,UAAO,OAAO;AACd,aAAU,OAAO;;EAGnB,YAA8B;GAC5B,MAAM,UAAU,OAAO,SAAS;GAChC,MAAM,QAAQ,QAAQ;AAEtB,OAAI,UAAU,EACZ,QAAO;IACL,SAAS,OAAO;IAChB,QAAQ,KAAK,KAAK,GAAG;IACrB,eAAe;IACf,oBAAoB;IACpB,gBAAgB;IAChB,WAAW;IACX,iBAAiB;IACjB,KAAK;IACL,KAAK;IACL,KAAK;IACL,SAAS;IACT,SAAS;IACT,KAAK;IACL,aAAa;KAAE,OAAO;KAAG,OAAO;KAAG,OAAO;KAAG,OAAO;KAAG,QAAQ,EAAE;KAAE;IACnE,aAAa;KACX,UAAU;MAAE,UAAU;MAAG,YAAY;MAAG,QAAQ;MAAG,WAAW;MAAG,SAAS;MAAG,KAAK;MAAG;KACrF,UAAU;MAAE,UAAU;MAAG,YAAY;MAAG,QAAQ;MAAG,WAAW;MAAG,SAAS;MAAG,KAAK;MAAG;KACrF,WAAW;MAAE,UAAU;MAAG,YAAY;MAAG,QAAQ;MAAG,WAAW;MAAG,SAAS;MAAG,KAAK;MAAG;KACvF;IACD,QAAQ,EAAE;IACV,aAAa;KAAE,UAAU,aAAa,EAAE;KAAE,WAAW,aAAa,EAAE;KAAE;IACtE,gBAAgB,EAAE;IACnB;GAGH,MAAM,aAAa,QAAQ,QAAQ,MAAM,EAAE,aAAa,IAAI,CAAC;GAC7D,MAAM,SAAS,QAAQ;GAEvB,MAAM,QAAQ,QAAQ,KAAK,MAAM,EAAE,UAAU;GAC7C,MAAM,cAAc,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE;GACpD,MAAM,UAAU,MAAM,QAAQ,GAAG,MAAM,IAAI,GAAG,EAAE,GAAG;GAEnD,MAAM,MAAM,eAAe;GAE3B,MAAM,SAAoC,EAAE;AAC5C,aAAU,SAAS,OAAO,SAAS;AACjC,WAAO,QAAQ;KAAE,GAAG;KAAO,SAAS,MAAM,YAAY,WAAW,IAAI,MAAM;KAAS;KACpF;AAEF,UAAO;IACL,SAAS,OAAO;IAChB,QAAQ,KAAK,KAAK,GAAG;IACrB,eAAe;IACf,oBAAoB;IACpB,gBAAgB;IAChB,WAAW,QAAQ,SAAS,OAAO,QAAQ,EAAE,CAAC;IAC9C,iBAAiB,OAAO,QAAQ,QAAQ,EAAE,CAAC;IAC3C,KAAK,OAAO,WAAW,aAAa,GAAG,CAAC,QAAQ,EAAE,CAAC;IACnD,KAAK,OAAO,WAAW,aAAa,GAAG,CAAC,QAAQ,EAAE,CAAC;IACnD,KAAK,OAAO,WAAW,aAAa,GAAG,CAAC,QAAQ,EAAE,CAAC;IACnD,SAAS,OAAO,YAAY,GAAG,QAAQ,EAAE,CAAC;IAC1C,SAAS,OAAO,YAAY,YAAY,SAAS,GAAG,QAAQ,EAAE,CAAC;IAC/D,KAAK,gBAAgB;IACrB,aAAa,4BAA4B;IACzC,aAAa;KACX,UAAU,oBAAoB,WAAW;KACzC,UAAU,oBAAoB,aAAa;KAC3C,WAAW,oBAAoB,SAAS;KACzC;IACD;IACA,aAAa;KACX,UAAU,aAAa,IAAI,SAAS;KACpC,WAAW,aAAa,IAAI,UAAU;KACvC;IACD,gBAAgB,OAAO,OAAO,EAAE;IACjC;;EAEJ;;AAKH,SAAS,WACP,SACA,eACA,SACA;AACA,KAAI,CAAC,QAAS;CAEd,MAAM,SAAS,QAAQ,aAAa,MAAM,MAAM;CAChD,MAAM,QAAQ,QAAQ,YAAY,gBAAgB,OAAO;AAEzD,SAAQ,IACN,GAAG,OAAO,GAAG,QAAQ,OAAO,GAAG,QAAQ,KAAK,KAAK,QAAQ,WAAW,IAAI,MAAM,GAAG,QAAQ,UAAU,QAAQ,EAAE,CAAC,KAC/G;;AAKH,MAAM,gBAA4C;CAChD,SAAS;CACT,SAAS;CACT,eAAe;CACf,YAAY;CACZ,cAAc;CACd,cAAc,EAAE;CAChB,MAAM,EAAE,WAAW,UAAU;CAC7B,iBAAiB;CACjB,qBAAqB;CACtB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BD,SAAgB,eACd,QACA,SAA2B,EAAE,EACZ;CACjB,MAAM,cAAc;EAAE,GAAG;EAAe,GAAG;EAAQ;CACnD,MAAM,QAAQ,mBAAmB,YAAY;CAC7C,MAAM,gBAAgB,OAAO,MAAM,KAAK,OAAO;AAE/C,KAAI,YAAY,WAAW,YAAY,SAAS;AAC9C,UAAQ,IAAI,uBAAuB;AACnC,UAAQ,IAAI,cAAc;GACxB,eAAe,GAAG,YAAY,cAAc;GAC5C,YAAY,YAAY;GACxB,cAAc,YAAY;GAC1B,cAAc,YAAY;GAC3B,CAAC;;CAGJ,MAAM,iBAAiB,OAAO,QAAoC;AAChE,MAAI,CAAC,YAAY,QACf,QAAO,cAAc,IAAI;EAG3B,MAAM,EAAE,aAAa,IAAI,IAAI,IAAI,IAAI;AAErC,MAAI,cAAc,UAAU,YAAY,aAAa,CACnD,QAAO,cAAc,IAAI;AAG3B,MAAI,YAAY,eAAe,KAAK,KAAK,QAAQ,GAAG,YAAY,aAC9D,QAAO,cAAc,IAAI;EAG3B,MAAM,YAAY,YAAY,KAAK;EACnC,MAAM,YAAY,mBAAmB;EACrC,MAAM,SAAS,IAAI;EAEnB,IAAI,aAAa;AACjB,MAAI;GACF,MAAM,WAAW,MAAM,cAAc,IAAI;AACzC,gBAAa,SAAS;AACtB,UAAO;YACC;GACR,MAAM,YAAY,YAAY,KAAK,GAAG;GACtC,MAAM,UAA6B;IACjC;IACA;IACA,MAAM;IACN;IACA;IACA,WAAW,KAAK,KAAK;IACrB,aAAa,eAAe;IAC7B;AAED,SAAM,WAAW,QAAQ;AACzB,cAAW,SAAS,YAAY,eAAe,YAAY,QAAQ;AAEnE,eAAY,UAAU,QAAQ;AAC9B,OAAI,YAAY,YAAY,cAC1B,aAAY,cAAc,QAAQ;;;AAKxC,QAAO;EACL,GAAG;EACH,OAAO;EACP,qBAAqB,MAAM;EAC3B,sBAAsB,MAAM;EAC5B,cAAc,MAAM;EACpB,oBAAoB,MAAM;EAC1B,QAAQ,MAAM;EACd,2BAA2B,MAAM;EACjC,iBAAiB,MAAM;EACxB;;;;;AAMH,SAAgB,sBACd,aACA,QACA,QACiB;AAEjB,QAAO,eADQ,IAAI,YAAY,OAAO,EACR,OAAO"}
1
+ {"version":3,"file":"native-monitor.mjs","names":[],"sources":["../../src/monitoring/native-monitor.ts"],"sourcesContent":["/**\n * 原生监控模块(零外部依赖)\n *\n * 特性:\n * - P50/P95/P99 百分位数统计\n * - 按路径分组统计\n * - 时间窗口统计(1分钟/5分钟/1小时)\n * - RPS 计算(每秒请求数)\n * - 状态码分布\n * - 环形缓冲区(内存友好)\n * - 采样率控制\n * - 路径排除\n * - 自定义回调\n */\n\nimport type { Server } from \"../server\";\n\n// ========== 类型定义 ==========\n\n/** 监控配置 */\nexport interface MonitoringConfig {\n /** 是否启用监控,默认 true */\n enabled?: boolean;\n /** 是否输出到控制台,默认 true */\n console?: boolean;\n /** 慢请求阈值(毫秒),默认 1000 */\n slowThreshold?: number;\n /** 最大记录数,默认 1000 */\n maxRecords?: number;\n /** 采样率 0-1,默认 1(全部记录) */\n samplingRate?: number;\n /** 排除的路径(不记录) */\n excludePaths?: string[];\n /** 自定义标签 */\n tags?: Record<string, string>;\n /** 请求完成回调 */\n onRequest?: (metrics: MonitoringMetrics) => void;\n /** 慢请求回调 */\n onSlowRequest?: (metrics: MonitoringMetrics) => void;\n}\n\n/** 监控指标 */\nexport interface MonitoringMetrics {\n requestId: string;\n method: string;\n path: string;\n statusCode: number;\n totalTime: number;\n timestamp: number;\n memoryUsage: MemoryInfo;\n}\n\n/** 内存信息 */\nexport interface MemoryInfo {\n heapUsed: number;\n heapTotal: number;\n}\n\n/** 路径统计 */\nexport interface PathStats {\n count: number;\n totalTime: number;\n avgTime: number;\n minTime: number;\n maxTime: number;\n errorCount: number;\n}\n\n/** 时间窗口统计 */\nexport interface TimeWindowStats {\n /** 请求数 */\n requests: number;\n /** 成功数 */\n successful: number;\n /** 失败数 */\n failed: number;\n /** 错误率 */\n errorRate: number;\n /** 平均响应时间 */\n avgTime: number;\n /** RPS(每秒请求数) */\n rps: number;\n}\n\n/** 状态码分布 */\nexport interface StatusCodeDistribution {\n /** 2xx 成功 */\n \"2xx\": number;\n /** 3xx 重定向 */\n \"3xx\": number;\n /** 4xx 客户端错误 */\n \"4xx\": number;\n /** 5xx 服务器错误 */\n \"5xx\": number;\n /** 详细分布 */\n detail: Record<number, number>;\n}\n\n/** 监控状态 */\nexport interface MonitoringStatus {\n enabled: boolean;\n /** 服务运行时间(毫秒) */\n uptime: number;\n totalRequests: number;\n successfulRequests: number;\n failedRequests: number;\n errorRate: number;\n /** 平均响应时间(毫秒) */\n avgResponseTime: number;\n /** P50 响应时间(毫秒) */\n p50: number;\n /** P95 响应时间(毫秒) */\n p95: number;\n /** P99 响应时间(毫秒) */\n p99: number;\n /** 最小响应时间 */\n minTime: number;\n /** 最大响应时间 */\n maxTime: number;\n /** 当前 RPS */\n rps: number;\n /** 状态码分布 */\n statusCodes: StatusCodeDistribution;\n /** 时间窗口统计 */\n timeWindows: {\n /** 最近 1 分钟 */\n last1min: TimeWindowStats;\n /** 最近 5 分钟 */\n last5min: TimeWindowStats;\n /** 最近 1 小时 */\n last1hour: TimeWindowStats;\n };\n /** 按路径统计 */\n byPath: Record<string, PathStats>;\n /** 内存使用 */\n memoryUsage: {\n heapUsed: string;\n heapTotal: string;\n };\n /** 最近请求 */\n recentRequests: MonitoringMetrics[];\n}\n\n/** 带监控的 Server */\nexport interface MonitoredServer extends Server {\n getMonitoringStatus(): MonitoringStatus;\n getMonitoringMetrics(): MonitoringMetrics[];\n getPathStats(path: string): PathStats | undefined;\n getTimeWindowStats(windowMs: number): TimeWindowStats;\n getRPS(): number;\n getStatusCodeDistribution(): StatusCodeDistribution;\n resetMonitoring(): void;\n}\n\n// ========== 常量 ==========\n\nconst ONE_MINUTE = 60 * 1000;\nconst FIVE_MINUTES = 5 * 60 * 1000;\nconst ONE_HOUR = 60 * 60 * 1000;\n\n// ========== 环形缓冲区 ==========\n\nfunction createRingBuffer<T>(capacity: number) {\n const buffer: T[] = new Array(capacity);\n let head = 0;\n let size = 0;\n\n return {\n push(item: T) {\n buffer[head % capacity] = item;\n head++;\n if (size < capacity) size++;\n },\n\n toArray(): T[] {\n if (size === 0) return [];\n if (size < capacity) {\n return buffer.slice(0, size);\n }\n const start = head % capacity;\n return [...buffer.slice(start), ...buffer.slice(0, start)];\n },\n\n getSize: () => size,\n\n clear() {\n head = 0;\n size = 0;\n },\n\n recent(n: number): T[] {\n const arr = this.toArray();\n return arr.slice(-n);\n },\n };\n}\n\n// ========== 工具函数 ==========\n\nfunction generateRequestId(): string {\n return `req_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;\n}\n\nfunction getMemoryInfo(): MemoryInfo {\n if (typeof process !== \"undefined\" && process.memoryUsage) {\n const mem = process.memoryUsage();\n return { heapUsed: mem.heapUsed, heapTotal: mem.heapTotal };\n }\n return { heapUsed: 0, heapTotal: 0 };\n}\n\nfunction formatMemory(bytes: number): string {\n return (bytes / 1024 / 1024).toFixed(2) + \"MB\";\n }\n\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const index = Math.ceil((p / 100) * sorted.length) - 1;\n return sorted[Math.max(0, index)];\n}\n\nfunction shouldExclude(path: string, excludePaths: string[]): boolean {\n return excludePaths.some(\n (p) =>\n path === p ||\n path.startsWith(p + \"/\") ||\n (p.endsWith(\"*\") && path.startsWith(p.slice(0, -1)))\n );\n }\n\nfunction getStatusCodeCategory(code: number): \"2xx\" | \"3xx\" | \"4xx\" | \"5xx\" {\n if (code >= 200 && code < 300) return \"2xx\";\n if (code >= 300 && code < 400) return \"3xx\";\n if (code >= 400 && code < 500) return \"4xx\";\n return \"5xx\";\n}\n\n// ========== 监控状态管理 ==========\n\nfunction createMonitorState(config: Required<MonitoringConfig>) {\n const buffer = createRingBuffer<MonitoringMetrics>(config.maxRecords);\n const pathStats = new Map<string, PathStats>();\n const startTime = Date.now();\n\n /** 获取时间窗口内的指标 */\n function getMetricsInWindow(windowMs: number): MonitoringMetrics[] {\n const now = Date.now();\n const cutoff = now - windowMs;\n return buffer.toArray().filter((m) => m.timestamp >= cutoff);\n }\n\n /** 计算时间窗口统计 */\n function calcTimeWindowStats(windowMs: number): TimeWindowStats {\n const metrics = getMetricsInWindow(windowMs);\n const count = metrics.length;\n\n if (count === 0) {\n return {\n requests: 0,\n successful: 0,\n failed: 0,\n errorRate: 0,\n avgTime: 0,\n rps: 0,\n };\n }\n\n const successful = metrics.filter((m) => m.statusCode < 400).length;\n const failed = count - successful;\n const avgTime = metrics.reduce((sum, m) => sum + m.totalTime, 0) / count;\n\n // 计算实际时间跨度(用于 RPS)\n const timestamps = metrics.map((m) => m.timestamp);\n const actualWindow = Math.max(...timestamps) - Math.min(...timestamps);\n const effectiveWindow = Math.max(actualWindow, 1000); // 至少 1 秒\n const rps = (count / effectiveWindow) * 1000;\n\n return {\n requests: count,\n successful,\n failed,\n errorRate: failed / count,\n avgTime: Number(avgTime.toFixed(2)),\n rps: Number(rps.toFixed(2)),\n };\n }\n\n /** 计算状态码分布 */\n function calcStatusCodeDistribution(): StatusCodeDistribution {\n const metrics = buffer.toArray();\n const dist: StatusCodeDistribution = {\n \"2xx\": 0,\n \"3xx\": 0,\n \"4xx\": 0,\n \"5xx\": 0,\n detail: {},\n };\n\n for (const m of metrics) {\n const category = getStatusCodeCategory(m.statusCode);\n dist[category]++;\n dist.detail[m.statusCode] = (dist.detail[m.statusCode] || 0) + 1;\n }\n\n return dist;\n }\n\n /** 计算当前 RPS(基于最近 10 秒) */\n function calcCurrentRPS(): number {\n const metrics = getMetricsInWindow(10000); // 最近 10 秒\n if (metrics.length === 0) return 0;\n return Number((metrics.length / 10).toFixed(2));\n }\n\n return {\n addMetrics(m: MonitoringMetrics) {\n buffer.push(m);\n\n // 更新路径统计\n const stats = pathStats.get(m.path) || {\n count: 0,\n totalTime: 0,\n avgTime: 0,\n minTime: Infinity,\n maxTime: 0,\n errorCount: 0,\n };\n\n stats.count++;\n stats.totalTime += m.totalTime;\n stats.avgTime = stats.totalTime / stats.count;\n stats.minTime = Math.min(stats.minTime, m.totalTime);\n stats.maxTime = Math.max(stats.maxTime, m.totalTime);\n if (m.statusCode >= 400) stats.errorCount++;\n\n pathStats.set(m.path, stats);\n },\n\n getMetrics: () => buffer.toArray(),\n\n getPathStats: (path: string) => pathStats.get(path),\n\n getTimeWindowStats: calcTimeWindowStats,\n\n getRPS: calcCurrentRPS,\n\n getStatusCodeDistribution: calcStatusCodeDistribution,\n\n reset() {\n buffer.clear();\n pathStats.clear();\n },\n\n getStatus(): MonitoringStatus {\n const metrics = buffer.toArray();\n const total = metrics.length;\n\n if (total === 0) {\n return {\n enabled: config.enabled,\n uptime: Date.now() - startTime,\n totalRequests: 0,\n successfulRequests: 0,\n failedRequests: 0,\n errorRate: 0,\n avgResponseTime: 0,\n p50: 0,\n p95: 0,\n p99: 0,\n minTime: 0,\n maxTime: 0,\n rps: 0,\n statusCodes: { \"2xx\": 0, \"3xx\": 0, \"4xx\": 0, \"5xx\": 0, detail: {} },\n timeWindows: {\n last1min: { requests: 0, successful: 0, failed: 0, errorRate: 0, avgTime: 0, rps: 0 },\n last5min: { requests: 0, successful: 0, failed: 0, errorRate: 0, avgTime: 0, rps: 0 },\n last1hour: { requests: 0, successful: 0, failed: 0, errorRate: 0, avgTime: 0, rps: 0 },\n },\n byPath: {},\n memoryUsage: { heapUsed: formatMemory(0), heapTotal: formatMemory(0) },\n recentRequests: [],\n };\n }\n\n const successful = metrics.filter((m) => m.statusCode < 400).length;\n const failed = total - successful;\n\n const times = metrics.map((m) => m.totalTime);\n const sortedTimes = [...times].sort((a, b) => a - b);\n const avgTime = times.reduce((a, b) => a + b, 0) / total;\n\n const mem = getMemoryInfo();\n\n const byPath: Record<string, PathStats> = {};\n pathStats.forEach((stats, path) => {\n byPath[path] = { ...stats, minTime: stats.minTime === Infinity ? 0 : stats.minTime };\n });\n\n return {\n enabled: config.enabled,\n uptime: Date.now() - startTime,\n totalRequests: total,\n successfulRequests: successful,\n failedRequests: failed,\n errorRate: Number((failed / total).toFixed(4)),\n avgResponseTime: Number(avgTime.toFixed(2)),\n p50: Number(percentile(sortedTimes, 50).toFixed(2)),\n p95: Number(percentile(sortedTimes, 95).toFixed(2)),\n p99: Number(percentile(sortedTimes, 99).toFixed(2)),\n minTime: Number(sortedTimes[0].toFixed(2)),\n maxTime: Number(sortedTimes[sortedTimes.length - 1].toFixed(2)),\n rps: calcCurrentRPS(),\n statusCodes: calcStatusCodeDistribution(),\n timeWindows: {\n last1min: calcTimeWindowStats(ONE_MINUTE),\n last5min: calcTimeWindowStats(FIVE_MINUTES),\n last1hour: calcTimeWindowStats(ONE_HOUR),\n },\n byPath,\n memoryUsage: {\n heapUsed: formatMemory(mem.heapUsed),\n heapTotal: formatMemory(mem.heapTotal),\n },\n recentRequests: buffer.recent(5),\n };\n },\n };\n}\n\n// ========== 日志输出 ==========\n\nfunction logRequest(\n metrics: MonitoringMetrics,\n slowThreshold: number,\n enabled: boolean\n) {\n if (!enabled) return;\n\n const status = metrics.statusCode < 400 ? \"✅\" : \"❌\";\n const speed = metrics.totalTime > slowThreshold ? \"🐌\" : \"⚡\";\n\n console.log(\n `${status} ${metrics.method} ${metrics.path} - ${metrics.statusCode} (${speed} ${metrics.totalTime.toFixed(2)}ms)`\n );\n }\n\n// ========== 主函数 ==========\n\nconst defaultConfig: Required<MonitoringConfig> = {\n enabled: true,\n console: true,\n slowThreshold: 1000,\n maxRecords: 1000,\n samplingRate: 1,\n excludePaths: [],\n tags: { framework: \"vafast\" },\n onRequest: () => {},\n onSlowRequest: () => {},\n};\n\n/**\n * 为 Server 添加监控能力\n *\n * @example\n * ```ts\n * const server = new Server(routes)\n * const monitored = withMonitoring(server, {\n * slowThreshold: 500,\n * excludePaths: ['/health'],\n * onSlowRequest: (m) => console.warn('Slow!', m.path)\n * })\n *\n * // 获取完整状态\n * const status = monitored.getMonitoringStatus()\n * console.log(`P99: ${status.p99}ms`)\n * console.log(`RPS: ${status.rps}`)\n * console.log(`Last 1min errors: ${status.timeWindows.last1min.errorRate}`)\n *\n * // 单独获取 RPS\n * console.log(`Current RPS: ${monitored.getRPS()}`)\n *\n * // 自定义时间窗口\n * const last30sec = monitored.getTimeWindowStats(30000)\n * ```\n */\nexport function withMonitoring(\n server: Server,\n config: MonitoringConfig = {}\n): MonitoredServer {\n const finalConfig = { ...defaultConfig, ...config };\n const state = createMonitorState(finalConfig);\n const originalFetch = server.fetch.bind(server);\n\n if (finalConfig.enabled && finalConfig.console) {\n console.log(\"✅ Monitoring enabled\");\n console.log(`📊 Config:`, {\n slowThreshold: `${finalConfig.slowThreshold}ms`,\n maxRecords: finalConfig.maxRecords,\n samplingRate: finalConfig.samplingRate,\n excludePaths: finalConfig.excludePaths,\n });\n }\n\n const monitoredFetch = async (req: Request): Promise<Response> => {\n if (!finalConfig.enabled) {\n return originalFetch(req);\n }\n\n const { pathname } = new URL(req.url);\n\n if (shouldExclude(pathname, finalConfig.excludePaths)) {\n return originalFetch(req);\n }\n\n if (finalConfig.samplingRate < 1 && Math.random() > finalConfig.samplingRate) {\n return originalFetch(req);\n }\n\n const startTime = performance.now();\n const requestId = generateRequestId();\n const method = req.method;\n\n let statusCode = 500;\n try {\n const response = await originalFetch(req);\n statusCode = response.status;\n return response;\n } finally {\n const totalTime = performance.now() - startTime;\n const metrics: MonitoringMetrics = {\n requestId,\n method,\n path: pathname,\n statusCode,\n totalTime,\n timestamp: Date.now(),\n memoryUsage: getMemoryInfo(),\n };\n\n state.addMetrics(metrics);\n logRequest(metrics, finalConfig.slowThreshold, finalConfig.console);\n\n finalConfig.onRequest(metrics);\n if (totalTime > finalConfig.slowThreshold) {\n finalConfig.onSlowRequest(metrics);\n }\n }\n };\n\n return {\n ...server,\n fetch: monitoredFetch,\n getMonitoringStatus: state.getStatus,\n getMonitoringMetrics: state.getMetrics,\n getPathStats: state.getPathStats,\n getTimeWindowStats: state.getTimeWindowStats,\n getRPS: state.getRPS,\n getStatusCodeDistribution: state.getStatusCodeDistribution,\n resetMonitoring: state.reset,\n } as MonitoredServer;\n}\n\n/**\n * 创建带监控的 Server(便捷函数)\n */\nexport function createMonitoredServer(\n ServerClass: typeof Server,\n routes: ConstructorParameters<typeof Server>[0],\n config?: MonitoringConfig\n): MonitoredServer {\n const server = new ServerClass(routes);\n return withMonitoring(server, config);\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import "../schema-B6DFN5c2.mjs";
2
2
  import "../index-CREkvfw9.mjs";
3
3
  import { t as BaseServer } from "../base-server-DLxtulAO.mjs";
4
- import { t as Server } from "../server-DGA3dd5s.mjs";
4
+ import { t as Server } from "../server-C2RPKSvC.mjs";
5
5
  import { t as ComponentServer } from "../component-server-JqpDC7wy.mjs";
6
- import { t as ServerFactory } from "../index-CEfOqqvd.mjs";
6
+ import { t as ServerFactory } from "../index-Bj3SWrMU.mjs";
7
7
  export { BaseServer, ComponentServer, Server, ServerFactory };
@@ -1,8 +1,8 @@
1
1
  import "../middleware-CewKbtb4.mjs";
2
2
  import { t as BaseServer } from "../base-server-B7MYJNsl.mjs";
3
- import { t as Server } from "../server-L_FNwdap.mjs";
3
+ import { t as Server } from "../server-DdIIf4co.mjs";
4
4
  import "../dependency-manager-DCmh7xFc.mjs";
5
5
  import { t as ComponentServer } from "../component-server-DomPJ_7S.mjs";
6
- import { t as ServerFactory } from "../server-C75o1b-a.mjs";
6
+ import { t as ServerFactory } from "../server-CezB-92R.mjs";
7
7
 
8
8
  export { BaseServer, ComponentServer, Server, ServerFactory };
@@ -1,7 +1,7 @@
1
1
  import "../schema-B6DFN5c2.mjs";
2
2
  import "../index-CREkvfw9.mjs";
3
3
  import "../base-server-DLxtulAO.mjs";
4
- import "../server-DGA3dd5s.mjs";
4
+ import "../server-C2RPKSvC.mjs";
5
5
  import "../component-server-JqpDC7wy.mjs";
6
- import { t as ServerFactory } from "../index-CEfOqqvd.mjs";
6
+ import { t as ServerFactory } from "../index-Bj3SWrMU.mjs";
7
7
  export { ServerFactory };
@@ -1,7 +1,7 @@
1
1
  import "../middleware-CewKbtb4.mjs";
2
- import "../server-L_FNwdap.mjs";
2
+ import "../server-DdIIf4co.mjs";
3
3
  import "../dependency-manager-DCmh7xFc.mjs";
4
4
  import "../component-server-DomPJ_7S.mjs";
5
- import { t as ServerFactory } from "../server-C75o1b-a.mjs";
5
+ import { t as ServerFactory } from "../server-CezB-92R.mjs";
6
6
 
7
7
  export { ServerFactory };
@@ -1,5 +1,5 @@
1
1
  import "../schema-B6DFN5c2.mjs";
2
2
  import "../index-CREkvfw9.mjs";
3
3
  import "../base-server-DLxtulAO.mjs";
4
- import { t as Server } from "../server-DGA3dd5s.mjs";
4
+ import { t as Server } from "../server-C2RPKSvC.mjs";
5
5
  export { Server };
@@ -1,4 +1,4 @@
1
1
  import "../middleware-CewKbtb4.mjs";
2
- import { t as Server } from "../server-L_FNwdap.mjs";
2
+ import { t as Server } from "../server-DdIIf4co.mjs";
3
3
 
4
4
  export { Server };
@@ -17,16 +17,7 @@ import { t as BaseServer } from "./base-server-DLxtulAO.mjs";
17
17
  declare class Server extends BaseServer {
18
18
  private router;
19
19
  private routes;
20
- /** 是否已预编译 */
21
- private isCompiled;
22
- /** 预编译时的全局中间件数量 */
23
- private compiledWithMiddlewareCount;
24
20
  constructor(routes?: readonly (Route | NestedRoute)[]);
25
- /**
26
- * 预编译所有路由处理链
27
- * 在添加所有路由和全局中间件后调用,可提升运行时性能
28
- */
29
- compile(): this;
30
21
  private registerRoutes;
31
22
  /** 快速提取 pathname */
32
23
  private extractPathname;
@@ -57,4 +48,4 @@ declare class Server extends BaseServer {
57
48
  }
58
49
  //#endregion
59
50
  export { Server as t };
60
- //# sourceMappingURL=server-DGA3dd5s.d.mts.map
51
+ //# sourceMappingURL=server-C2RPKSvC.d.mts.map
@@ -1,4 +1,4 @@
1
- import { t as Server } from "./server-L_FNwdap.mjs";
1
+ import { t as Server } from "./server-DdIIf4co.mjs";
2
2
  import { t as ComponentServer } from "./component-server-DomPJ_7S.mjs";
3
3
 
4
4
  //#region src/server/server-factory.ts
@@ -67,4 +67,4 @@ var ServerFactory = class {
67
67
 
68
68
  //#endregion
69
69
  export { ServerFactory as t };
70
- //# sourceMappingURL=server-C75o1b-a.mjs.map
70
+ //# sourceMappingURL=server-CezB-92R.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-C75o1b-a.mjs","names":[],"sources":["../src/server/server-factory.ts"],"sourcesContent":["import type { Route, NestedRoute } from \"../types\";\nimport type {\n ComponentRoute,\n NestedComponentRoute,\n} from \"../types/component-route\";\nimport { Server } from \"../server\";\nimport { ComponentServer } from \"./component-server\";\n\n/**\n * 服务器工厂类\n * 用于创建和管理不同类型的服务器\n */\nexport class ServerFactory {\n private servers: Map<string, Server | ComponentServer> = new Map();\n\n /**\n * 创建标准REST API服务器\n */\n createRestServer(routes: (Route | NestedRoute)[]): Server {\n const server = new Server(routes);\n this.servers.set(\"rest\", server);\n return server;\n }\n\n /**\n * 创建组件服务器\n */\n createComponentServer(\n routes: (ComponentRoute | NestedComponentRoute)[],\n ): ComponentServer {\n const server = new ComponentServer(routes);\n this.servers.set(\"component\", server);\n return server;\n }\n\n /**\n * 获取指定类型的服务器\n */\n getServer(type: \"rest\" | \"component\"): Server | ComponentServer | undefined {\n return this.servers.get(type);\n }\n\n /**\n * 获取所有服务器\n */\n getAllServers(): Map<string, Server | ComponentServer> {\n return this.servers;\n }\n\n /**\n * 移除指定类型的服务器\n */\n removeServer(type: string): boolean {\n return this.servers.delete(type);\n }\n\n /**\n * 清除所有服务器\n */\n clearServers(): void {\n this.servers.clear();\n }\n\n /**\n * 获取服务器状态信息\n */\n getServerStatus(): Record<string, { type: string; routes: number }> {\n const status: Record<string, { type: string; routes: number }> = {};\n\n for (const [name, server] of this.servers) {\n if (server instanceof Server) {\n status[name] = {\n type: \"REST API\",\n routes: (server as any).routes?.length || 0,\n };\n } else if (server instanceof ComponentServer) {\n status[name] = {\n type: \"Component\",\n routes: (server as any).routes?.length || 0,\n };\n }\n }\n\n return status;\n }\n}\n"],"mappings":";;;;;;;;AAYA,IAAa,gBAAb,MAA2B;CACzB,AAAQ,0BAAiD,IAAI,KAAK;;;;CAKlE,iBAAiB,QAAyC;EACxD,MAAM,SAAS,IAAI,OAAO,OAAO;AACjC,OAAK,QAAQ,IAAI,QAAQ,OAAO;AAChC,SAAO;;;;;CAMT,sBACE,QACiB;EACjB,MAAM,SAAS,IAAI,gBAAgB,OAAO;AAC1C,OAAK,QAAQ,IAAI,aAAa,OAAO;AACrC,SAAO;;;;;CAMT,UAAU,MAAkE;AAC1E,SAAO,KAAK,QAAQ,IAAI,KAAK;;;;;CAM/B,gBAAuD;AACrD,SAAO,KAAK;;;;;CAMd,aAAa,MAAuB;AAClC,SAAO,KAAK,QAAQ,OAAO,KAAK;;;;;CAMlC,eAAqB;AACnB,OAAK,QAAQ,OAAO;;;;;CAMtB,kBAAoE;EAClE,MAAM,SAA2D,EAAE;AAEnE,OAAK,MAAM,CAAC,MAAM,WAAW,KAAK,QAChC,KAAI,kBAAkB,OACpB,QAAO,QAAQ;GACb,MAAM;GACN,QAAS,OAAe,QAAQ,UAAU;GAC3C;WACQ,kBAAkB,gBAC3B,QAAO,QAAQ;GACb,MAAM;GACN,QAAS,OAAe,QAAQ,UAAU;GAC3C;AAIL,SAAO"}
1
+ {"version":3,"file":"server-CezB-92R.mjs","names":[],"sources":["../src/server/server-factory.ts"],"sourcesContent":["import type { Route, NestedRoute } from \"../types\";\nimport type {\n ComponentRoute,\n NestedComponentRoute,\n} from \"../types/component-route\";\nimport { Server } from \"../server\";\nimport { ComponentServer } from \"./component-server\";\n\n/**\n * 服务器工厂类\n * 用于创建和管理不同类型的服务器\n */\nexport class ServerFactory {\n private servers: Map<string, Server | ComponentServer> = new Map();\n\n /**\n * 创建标准REST API服务器\n */\n createRestServer(routes: (Route | NestedRoute)[]): Server {\n const server = new Server(routes);\n this.servers.set(\"rest\", server);\n return server;\n }\n\n /**\n * 创建组件服务器\n */\n createComponentServer(\n routes: (ComponentRoute | NestedComponentRoute)[],\n ): ComponentServer {\n const server = new ComponentServer(routes);\n this.servers.set(\"component\", server);\n return server;\n }\n\n /**\n * 获取指定类型的服务器\n */\n getServer(type: \"rest\" | \"component\"): Server | ComponentServer | undefined {\n return this.servers.get(type);\n }\n\n /**\n * 获取所有服务器\n */\n getAllServers(): Map<string, Server | ComponentServer> {\n return this.servers;\n }\n\n /**\n * 移除指定类型的服务器\n */\n removeServer(type: string): boolean {\n return this.servers.delete(type);\n }\n\n /**\n * 清除所有服务器\n */\n clearServers(): void {\n this.servers.clear();\n }\n\n /**\n * 获取服务器状态信息\n */\n getServerStatus(): Record<string, { type: string; routes: number }> {\n const status: Record<string, { type: string; routes: number }> = {};\n\n for (const [name, server] of this.servers) {\n if (server instanceof Server) {\n status[name] = {\n type: \"REST API\",\n routes: (server as any).routes?.length || 0,\n };\n } else if (server instanceof ComponentServer) {\n status[name] = {\n type: \"Component\",\n routes: (server as any).routes?.length || 0,\n };\n }\n }\n\n return status;\n }\n}\n"],"mappings":";;;;;;;;AAYA,IAAa,gBAAb,MAA2B;CACzB,AAAQ,0BAAiD,IAAI,KAAK;;;;CAKlE,iBAAiB,QAAyC;EACxD,MAAM,SAAS,IAAI,OAAO,OAAO;AACjC,OAAK,QAAQ,IAAI,QAAQ,OAAO;AAChC,SAAO;;;;;CAMT,sBACE,QACiB;EACjB,MAAM,SAAS,IAAI,gBAAgB,OAAO;AAC1C,OAAK,QAAQ,IAAI,aAAa,OAAO;AACrC,SAAO;;;;;CAMT,UAAU,MAAkE;AAC1E,SAAO,KAAK,QAAQ,IAAI,KAAK;;;;;CAM/B,gBAAuD;AACrD,SAAO,KAAK;;;;;CAMd,aAAa,MAAuB;AAClC,SAAO,KAAK,QAAQ,OAAO,KAAK;;;;;CAMlC,eAAqB;AACnB,OAAK,QAAQ,OAAO;;;;;CAMtB,kBAAoE;EAClE,MAAM,SAA2D,EAAE;AAEnE,OAAK,MAAM,CAAC,MAAM,WAAW,KAAK,QAChC,KAAI,kBAAkB,OACpB,QAAO,QAAQ;GACb,MAAM;GACN,QAAS,OAAe,QAAQ,UAAU;GAC3C;WACQ,kBAAkB,gBAC3B,QAAO,QAAQ;GACb,MAAM;GACN,QAAS,OAAe,QAAQ,UAAU;GAC3C;AAIL,SAAO"}
@@ -19,34 +19,18 @@ import { s as setGlobalRegistry, t as RouteRegistry } from "./route-registry-emT
19
19
  var Server = class extends BaseServer {
20
20
  router;
21
21
  routes;
22
- /** 是否已预编译 */
23
- isCompiled = false;
24
- /** 预编译时的全局中间件数量 */
25
- compiledWithMiddlewareCount = 0;
26
22
  constructor(routes = []) {
27
23
  super();
28
24
  this.router = new RadixRouter();
29
25
  this.routes = [];
30
- this.router.setCompiler((middleware, handler) => composeMiddleware(middleware, handler));
31
26
  if (routes.length > 0) this.registerRoutes([...routes]);
32
27
  }
33
- /**
34
- * 预编译所有路由处理链
35
- * 在添加所有路由和全局中间件后调用,可提升运行时性能
36
- */
37
- compile() {
38
- this.router.precompileAll(this.globalMiddleware);
39
- this.isCompiled = true;
40
- this.compiledWithMiddlewareCount = this.globalMiddleware.length;
41
- return this;
42
- }
43
28
  registerRoutes(routes) {
44
29
  const flattened = flattenNestedRoutes(routes);
45
30
  this.routes.push(...flattened);
46
31
  for (const route of flattened) this.router.register(route.method, route.fullPath, route.handler, route.middlewareChain || []);
47
32
  this.detectRouteConflicts(flattened);
48
33
  this.logFlattenedRoutes(flattened);
49
- if (this.globalMiddleware.length === 0 && !this.isCompiled) this.compile();
50
34
  setGlobalRegistry(new RouteRegistry(this.routes));
51
35
  }
52
36
  /** 快速提取 pathname */
@@ -81,7 +65,6 @@ var Server = class extends BaseServer {
81
65
  const match = this.router.match(method, pathname);
82
66
  if (match) {
83
67
  req.params = match.params;
84
- if (match.compiled && this.globalMiddleware.length === this.compiledWithMiddlewareCount) return match.compiled(req);
85
68
  return composeMiddleware([...this.globalMiddleware, ...match.middleware], match.handler)(req);
86
69
  }
87
70
  if (method === "OPTIONS") {
@@ -134,4 +117,4 @@ var Server = class extends BaseServer {
134
117
 
135
118
  //#endregion
136
119
  export { Server as t };
137
- //# sourceMappingURL=server-L_FNwdap.mjs.map
120
+ //# sourceMappingURL=server-DdIIf4co.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-DdIIf4co.mjs","names":[],"sources":["../src/server/server.ts"],"sourcesContent":["/**\n * Vafast 核心服务器\n *\n * 基于 Radix Tree 的高性能路由匹配\n * 时间复杂度: O(k),k 为路径段数\n */\n\nimport type { Route, NestedRoute, FlattenedRoute, Method } from \"../types\";\nimport { flattenNestedRoutes } from \"../router\";\nimport { composeMiddleware } from \"../middleware\";\nimport { json } from \"../utils/response\";\nimport { BaseServer } from \"./base-server\";\nimport { RadixRouter } from \"../router/radix-tree\";\nimport { RouteRegistry, setGlobalRegistry } from \"../utils/route-registry\";\n\n/**\n * Vafast 服务器\n *\n * @example\n * ```typescript\n * const server = new Server([\n * { method: \"GET\", path: \"/\", handler: () => new Response(\"Hello\") },\n * ]);\n * export default { fetch: server.fetch };\n * ```\n */\nexport class Server extends BaseServer {\n private router: RadixRouter;\n private routes: FlattenedRoute[];\n\n constructor(routes: readonly (Route | NestedRoute)[] = []) {\n super();\n this.router = new RadixRouter();\n this.routes = [];\n\n if (routes.length > 0) {\n this.registerRoutes([...routes]);\n }\n }\n\n private registerRoutes(routes: (Route | NestedRoute)[]): void {\n const flattened = flattenNestedRoutes(routes);\n this.routes.push(...flattened);\n\n for (const route of flattened) {\n this.router.register(\n route.method as Method,\n route.fullPath,\n route.handler,\n route.middlewareChain || [],\n );\n }\n\n this.detectRouteConflicts(flattened);\n this.logFlattenedRoutes(flattened);\n\n // 自动设置全局 RouteRegistry(支持在任意位置通过 getRouteRegistry() 访问)\n setGlobalRegistry(new RouteRegistry(this.routes));\n }\n\n /** 快速提取 pathname */\n private extractPathname(url: string): string {\n let start = url.indexOf(\"://\");\n start = start === -1 ? 0 : start + 3;\n\n const pathStart = url.indexOf(\"/\", start);\n if (pathStart === -1) return \"/\";\n\n let end = url.indexOf(\"?\", pathStart);\n if (end === -1) end = url.indexOf(\"#\", pathStart);\n if (end === -1) end = url.length;\n\n return url.substring(pathStart, end) || \"/\";\n }\n\n /** 生成 404/405 响应 */\n private createErrorResponse(method: string, pathname: string): Response {\n const allowedMethods = this.router.getAllowedMethods(pathname);\n if (allowedMethods.length > 0) {\n return json(\n {\n success: false,\n error: \"Method Not Allowed\",\n message: `Method ${method} not allowed for this endpoint`,\n allowedMethods,\n },\n 405,\n { Allow: allowedMethods.join(\", \") },\n );\n }\n return json({ success: false, error: \"Not Found\" }, 404);\n }\n\n /** 处理请求 */\n fetch = async (req: Request): Promise<Response> => {\n const pathname = this.extractPathname(req.url);\n const method = req.method as Method;\n\n const match = this.router.match(method, pathname);\n\n if (match) {\n (req as unknown as Record<string, unknown>).params = match.params;\n\n // 运行时组合中间件\n const allMiddleware = [...this.globalMiddleware, ...match.middleware];\n const handler = composeMiddleware(allMiddleware, match.handler);\n\n return handler(req);\n }\n\n // OPTIONS 预检请求特殊处理:查找同路径其他方法的路由,使用其中间件\n // 这允许路由级 CORS 中间件正常工作\n if (method === \"OPTIONS\") {\n const allowedMethods = this.router.getAllowedMethods(pathname);\n if (allowedMethods.length > 0) {\n // 尝试获取该路径任意方法的路由中间件\n const anyMatch = this.router.match(\n allowedMethods[0] as Method,\n pathname,\n );\n const routeMiddleware = anyMatch?.middleware || [];\n const allMiddleware = [...this.globalMiddleware, ...routeMiddleware];\n\n // OPTIONS 请求默认返回 204(中间件如 CORS 可能会提前响应)\n const optionsHandler = () =>\n new Response(null, {\n status: 204,\n headers: { Allow: allowedMethods.join(\", \") },\n });\n\n const handler = composeMiddleware(allMiddleware, optionsHandler);\n return handler(req);\n }\n }\n\n // 未匹配路由时,仍执行全局中间件(如 CORS 处理 OPTIONS 预检)\n if (this.globalMiddleware.length > 0) {\n const handler = composeMiddleware(this.globalMiddleware, () =>\n this.createErrorResponse(method, pathname),\n );\n return handler(req);\n }\n\n return this.createErrorResponse(method, pathname);\n };\n\n addRoute(route: Route): void {\n const flattenedRoute: FlattenedRoute = {\n ...route,\n fullPath: route.path,\n middlewareChain: route.middleware || [],\n };\n\n this.routes.push(flattenedRoute);\n this.router.register(\n route.method as Method,\n route.path,\n route.handler,\n route.middleware || [],\n );\n }\n\n addRoutes(routes: readonly (Route | NestedRoute)[]): void {\n this.registerRoutes([...routes]);\n }\n\n getRoutes(): Array<{ method: Method; path: string }> {\n return this.router.getRoutes();\n }\n\n /**\n * 获取完整的路由元信息(不含 handler 和 middleware)\n *\n * 用于 API 文档生成、Webhook 事件注册、权限检查等场景\n *\n * @example\n * ```typescript\n * const routes = server.getRoutesWithMeta()\n * for (const route of routes) {\n * console.log(route.fullPath, route.name, route.description)\n * }\n * ```\n */\n getRoutesWithMeta(): FlattenedRoute[] {\n return this.routes;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA0BA,IAAa,SAAb,cAA4B,WAAW;CACrC,AAAQ;CACR,AAAQ;CAER,YAAY,SAA2C,EAAE,EAAE;AACzD,SAAO;AACP,OAAK,SAAS,IAAI,aAAa;AAC/B,OAAK,SAAS,EAAE;AAEhB,MAAI,OAAO,SAAS,EAClB,MAAK,eAAe,CAAC,GAAG,OAAO,CAAC;;CAIpC,AAAQ,eAAe,QAAuC;EAC5D,MAAM,YAAY,oBAAoB,OAAO;AAC7C,OAAK,OAAO,KAAK,GAAG,UAAU;AAE9B,OAAK,MAAM,SAAS,UAClB,MAAK,OAAO,SACV,MAAM,QACN,MAAM,UACN,MAAM,SACN,MAAM,mBAAmB,EAAE,CAC5B;AAGH,OAAK,qBAAqB,UAAU;AACpC,OAAK,mBAAmB,UAAU;AAGlC,oBAAkB,IAAI,cAAc,KAAK,OAAO,CAAC;;;CAInD,AAAQ,gBAAgB,KAAqB;EAC3C,IAAI,QAAQ,IAAI,QAAQ,MAAM;AAC9B,UAAQ,UAAU,KAAK,IAAI,QAAQ;EAEnC,MAAM,YAAY,IAAI,QAAQ,KAAK,MAAM;AACzC,MAAI,cAAc,GAAI,QAAO;EAE7B,IAAI,MAAM,IAAI,QAAQ,KAAK,UAAU;AACrC,MAAI,QAAQ,GAAI,OAAM,IAAI,QAAQ,KAAK,UAAU;AACjD,MAAI,QAAQ,GAAI,OAAM,IAAI;AAE1B,SAAO,IAAI,UAAU,WAAW,IAAI,IAAI;;;CAI1C,AAAQ,oBAAoB,QAAgB,UAA4B;EACtE,MAAM,iBAAiB,KAAK,OAAO,kBAAkB,SAAS;AAC9D,MAAI,eAAe,SAAS,EAC1B,QAAO,KACL;GACE,SAAS;GACT,OAAO;GACP,SAAS,UAAU,OAAO;GAC1B;GACD,EACD,KACA,EAAE,OAAO,eAAe,KAAK,KAAK,EAAE,CACrC;AAEH,SAAO,KAAK;GAAE,SAAS;GAAO,OAAO;GAAa,EAAE,IAAI;;;CAI1D,QAAQ,OAAO,QAAoC;EACjD,MAAM,WAAW,KAAK,gBAAgB,IAAI,IAAI;EAC9C,MAAM,SAAS,IAAI;EAEnB,MAAM,QAAQ,KAAK,OAAO,MAAM,QAAQ,SAAS;AAEjD,MAAI,OAAO;AACT,GAAC,IAA2C,SAAS,MAAM;AAM3D,UAFgB,kBADM,CAAC,GAAG,KAAK,kBAAkB,GAAG,MAAM,WAAW,EACpB,MAAM,QAAQ,CAEhD,IAAI;;AAKrB,MAAI,WAAW,WAAW;GACxB,MAAM,iBAAiB,KAAK,OAAO,kBAAkB,SAAS;AAC9D,OAAI,eAAe,SAAS,GAAG;IAM7B,MAAM,kBAJW,KAAK,OAAO,MAC3B,eAAe,IACf,SACD,EACiC,cAAc,EAAE;IAClD,MAAM,gBAAgB,CAAC,GAAG,KAAK,kBAAkB,GAAG,gBAAgB;IAGpE,MAAM,uBACJ,IAAI,SAAS,MAAM;KACjB,QAAQ;KACR,SAAS,EAAE,OAAO,eAAe,KAAK,KAAK,EAAE;KAC9C,CAAC;AAGJ,WADgB,kBAAkB,eAAe,eAAe,CACjD,IAAI;;;AAKvB,MAAI,KAAK,iBAAiB,SAAS,EAIjC,QAHgB,kBAAkB,KAAK,wBACrC,KAAK,oBAAoB,QAAQ,SAAS,CAC3C,CACc,IAAI;AAGrB,SAAO,KAAK,oBAAoB,QAAQ,SAAS;;CAGnD,SAAS,OAAoB;EAC3B,MAAM,iBAAiC;GACrC,GAAG;GACH,UAAU,MAAM;GAChB,iBAAiB,MAAM,cAAc,EAAE;GACxC;AAED,OAAK,OAAO,KAAK,eAAe;AAChC,OAAK,OAAO,SACV,MAAM,QACN,MAAM,MACN,MAAM,SACN,MAAM,cAAc,EAAE,CACvB;;CAGH,UAAU,QAAgD;AACxD,OAAK,eAAe,CAAC,GAAG,OAAO,CAAC;;CAGlC,YAAqD;AACnD,SAAO,KAAK,OAAO,WAAW;;;;;;;;;;;;;;;CAgBhC,oBAAsC;AACpC,SAAO,KAAK"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vafast",
3
- "version": "0.4.21",
3
+ "version": "0.4.23",
4
4
  "description": "极简结构化Web框架,支持 Bun 和 Node.js。Go风格,函数优先。",
5
5
  "type": "module",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-L_FNwdap.mjs","names":[],"sources":["../src/server/server.ts"],"sourcesContent":["/**\n * Vafast 核心服务器\n *\n * 基于 Radix Tree 的高性能路由匹配\n * 时间复杂度: O(k),k 为路径段数\n */\n\nimport type { Route, NestedRoute, FlattenedRoute, Method } from \"../types\";\nimport { flattenNestedRoutes } from \"../router\";\nimport { composeMiddleware } from \"../middleware\";\nimport { json } from \"../utils/response\";\nimport { BaseServer } from \"./base-server\";\nimport { RadixRouter } from \"../router/radix-tree\";\nimport { RouteRegistry, setGlobalRegistry } from \"../utils/route-registry\";\n\n/**\n * Vafast 服务器\n *\n * @example\n * ```typescript\n * const server = new Server([\n * { method: \"GET\", path: \"/\", handler: () => new Response(\"Hello\") },\n * ]);\n * export default { fetch: server.fetch };\n * ```\n */\nexport class Server extends BaseServer {\n private router: RadixRouter;\n private routes: FlattenedRoute[];\n /** 是否已预编译 */\n private isCompiled = false;\n /** 预编译时的全局中间件数量 */\n private compiledWithMiddlewareCount = 0;\n\n constructor(routes: readonly (Route | NestedRoute)[] = []) {\n super();\n this.router = new RadixRouter();\n this.routes = [];\n\n // 设置中间件编译器\n this.router.setCompiler((middleware, handler) =>\n composeMiddleware(middleware, handler),\n );\n\n if (routes.length > 0) {\n this.registerRoutes([...routes]);\n }\n }\n\n /**\n * 预编译所有路由处理链\n * 在添加所有路由和全局中间件后调用,可提升运行时性能\n */\n compile(): this {\n this.router.precompileAll(this.globalMiddleware);\n this.isCompiled = true;\n this.compiledWithMiddlewareCount = this.globalMiddleware.length;\n return this;\n }\n\n private registerRoutes(routes: (Route | NestedRoute)[]): void {\n const flattened = flattenNestedRoutes(routes);\n this.routes.push(...flattened);\n\n for (const route of flattened) {\n this.router.register(\n route.method as Method,\n route.fullPath,\n route.handler,\n route.middlewareChain || [],\n );\n }\n\n this.detectRouteConflicts(flattened);\n this.logFlattenedRoutes(flattened);\n\n // 自动预编译(如果没有全局中间件)\n if (this.globalMiddleware.length === 0 && !this.isCompiled) {\n this.compile();\n }\n\n // 自动设置全局 RouteRegistry(支持在任意位置通过 getRouteRegistry() 访问)\n setGlobalRegistry(new RouteRegistry(this.routes));\n }\n\n /** 快速提取 pathname */\n private extractPathname(url: string): string {\n let start = url.indexOf(\"://\");\n start = start === -1 ? 0 : start + 3;\n\n const pathStart = url.indexOf(\"/\", start);\n if (pathStart === -1) return \"/\";\n\n let end = url.indexOf(\"?\", pathStart);\n if (end === -1) end = url.indexOf(\"#\", pathStart);\n if (end === -1) end = url.length;\n\n return url.substring(pathStart, end) || \"/\";\n }\n\n /** 生成 404/405 响应 */\n private createErrorResponse(method: string, pathname: string): Response {\n const allowedMethods = this.router.getAllowedMethods(pathname);\n if (allowedMethods.length > 0) {\n return json(\n {\n success: false,\n error: \"Method Not Allowed\",\n message: `Method ${method} not allowed for this endpoint`,\n allowedMethods,\n },\n 405,\n { Allow: allowedMethods.join(\", \") },\n );\n }\n return json({ success: false, error: \"Not Found\" }, 404);\n }\n\n /** 处理请求 */\n fetch = async (req: Request): Promise<Response> => {\n const pathname = this.extractPathname(req.url);\n const method = req.method as Method;\n\n const match = this.router.match(method, pathname);\n\n if (match) {\n (req as unknown as Record<string, unknown>).params = match.params;\n\n // 优先使用预编译的处理链(仅当全局中间件未变化时)\n if (\n match.compiled &&\n this.globalMiddleware.length === this.compiledWithMiddlewareCount\n ) {\n return match.compiled(req);\n }\n\n // 回退:运行时组合中间件\n const allMiddleware = [...this.globalMiddleware, ...match.middleware];\n const handler = composeMiddleware(allMiddleware, match.handler);\n\n return handler(req);\n }\n\n // OPTIONS 预检请求特殊处理:查找同路径其他方法的路由,使用其中间件\n // 这允许路由级 CORS 中间件正常工作\n if (method === \"OPTIONS\") {\n const allowedMethods = this.router.getAllowedMethods(pathname);\n if (allowedMethods.length > 0) {\n // 尝试获取该路径任意方法的路由中间件\n const anyMatch = this.router.match(\n allowedMethods[0] as Method,\n pathname,\n );\n const routeMiddleware = anyMatch?.middleware || [];\n const allMiddleware = [...this.globalMiddleware, ...routeMiddleware];\n\n // OPTIONS 请求默认返回 204(中间件如 CORS 可能会提前响应)\n const optionsHandler = () =>\n new Response(null, {\n status: 204,\n headers: { Allow: allowedMethods.join(\", \") },\n });\n\n const handler = composeMiddleware(allMiddleware, optionsHandler);\n return handler(req);\n }\n }\n\n // 未匹配路由时,仍执行全局中间件(如 CORS 处理 OPTIONS 预检)\n if (this.globalMiddleware.length > 0) {\n const handler = composeMiddleware(this.globalMiddleware, () =>\n this.createErrorResponse(method, pathname),\n );\n return handler(req);\n }\n\n return this.createErrorResponse(method, pathname);\n };\n\n addRoute(route: Route): void {\n const flattenedRoute: FlattenedRoute = {\n ...route,\n fullPath: route.path,\n middlewareChain: route.middleware || [],\n };\n\n this.routes.push(flattenedRoute);\n this.router.register(\n route.method as Method,\n route.path,\n route.handler,\n route.middleware || [],\n );\n }\n\n addRoutes(routes: readonly (Route | NestedRoute)[]): void {\n this.registerRoutes([...routes]);\n }\n\n getRoutes(): Array<{ method: Method; path: string }> {\n return this.router.getRoutes();\n }\n\n /**\n * 获取完整的路由元信息(不含 handler 和 middleware)\n *\n * 用于 API 文档生成、Webhook 事件注册、权限检查等场景\n *\n * @example\n * ```typescript\n * const routes = server.getRoutesWithMeta()\n * for (const route of routes) {\n * console.log(route.fullPath, route.name, route.description)\n * }\n * ```\n */\n getRoutesWithMeta(): FlattenedRoute[] {\n return this.routes;\n }\n}\n"],"mappings":"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"}