vafast 0.3.10 → 0.3.11

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.
@@ -1,5 +1,103 @@
1
- import { Route } from './types/types.js';
1
+ import { RouteSchema } from './types/schema.js';
2
+ import { InferableHandler } from './utils/create-handler.js';
3
+ import '@sinclair/typebox';
2
4
 
3
- declare function defineRoutes(routes: Route[]): Route[];
5
+ /**
6
+ * 可推断的路由类型(用于类型推断)
7
+ * 供 vafast-api-client 使用,保留完整的类型信息
8
+ */
9
+ type InferableRoute<TMethod extends string = string, TPath extends string = string, TReturn = unknown, TSchema extends RouteSchema = RouteSchema> = {
10
+ readonly method: TMethod;
11
+ readonly path: TPath;
12
+ readonly handler: InferableHandler<TReturn, TSchema>;
13
+ readonly middleware?: ReadonlyArray<(req: Request, next: () => Promise<Response>) => Promise<Response>>;
14
+ };
15
+ /**
16
+ * 中间件类型
17
+ */
18
+ type Middleware = (req: Request, next: () => Promise<Response>) => Promise<Response>;
19
+ /**
20
+ * 路由定义类型(保留完整 handler 类型)
21
+ */
22
+ type RouteDefinition<TMethod extends string = string, TPath extends string = string, THandler = unknown> = {
23
+ readonly method: TMethod;
24
+ readonly path: TPath;
25
+ readonly handler: THandler;
26
+ readonly middleware?: ReadonlyArray<Middleware>;
27
+ };
28
+ /**
29
+ * 创建单个路由定义(自动保留字面量类型,无需 as const)
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * import { route, defineRoutes, createHandler, Type } from 'vafast'
34
+ *
35
+ * const routes = defineRoutes([
36
+ * route('GET', '/users', createHandler(
37
+ * { query: Type.Object({ page: Type.Number() }) },
38
+ * async ({ query }) => ({ users: [], total: 0 })
39
+ * )),
40
+ * route('POST', '/users', createHandler(
41
+ * { body: Type.Object({ name: Type.String() }) },
42
+ * async ({ body }) => ({ id: '1', name: body.name })
43
+ * )),
44
+ * route('GET', '/users/:id', createHandler(
45
+ * { params: Type.Object({ id: Type.String() }) },
46
+ * async ({ params }) => ({ id: params.id, name: 'User' })
47
+ * ))
48
+ * ])
49
+ *
50
+ * // 无需 as const!类型自动推断
51
+ * type Api = InferEden<typeof routes>
52
+ * ```
53
+ */
54
+ declare function route<TMethod extends string, TPath extends string, THandler>(method: TMethod, path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<TMethod, TPath, THandler>;
55
+ /**
56
+ * GET 路由快捷方法
57
+ */
58
+ declare function get<TPath extends string, THandler>(path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<'GET', TPath, THandler>;
59
+ /**
60
+ * POST 路由快捷方法
61
+ */
62
+ declare function post<TPath extends string, THandler>(path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<'POST', TPath, THandler>;
63
+ /**
64
+ * PUT 路由快捷方法
65
+ */
66
+ declare function put<TPath extends string, THandler>(path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<'PUT', TPath, THandler>;
67
+ /**
68
+ * DELETE 路由快捷方法
69
+ */
70
+ declare function del<TPath extends string, THandler>(path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<'DELETE', TPath, THandler>;
71
+ /**
72
+ * PATCH 路由快捷方法
73
+ */
74
+ declare function patch<TPath extends string, THandler>(path: TPath, handler: THandler, middleware?: Middleware[]): RouteDefinition<'PATCH', TPath, THandler>;
75
+ /**
76
+ * 定义路由数组(保留完整类型信息)
77
+ *
78
+ * 推荐配合 route() 函数使用,无需 as const
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * import { defineRoutes, route, createHandler, Type } from 'vafast'
83
+ *
84
+ * // ✨ 新方式:使用 route() 函数,无需 as const
85
+ * const routes = defineRoutes([
86
+ * route('GET', '/users', createHandler(...)),
87
+ * route('POST', '/users', createHandler(...))
88
+ * ])
89
+ *
90
+ * // 🔙 旧方式:需要 as const(仍然支持)
91
+ * const routes = defineRoutes([
92
+ * { method: 'GET', path: '/users', handler: createHandler(...) }
93
+ * ] as const)
94
+ * ```
95
+ */
96
+ declare function defineRoutes<const T extends readonly {
97
+ readonly method: string;
98
+ readonly path: string;
99
+ readonly handler: unknown;
100
+ readonly middleware?: ReadonlyArray<Middleware>;
101
+ }[]>(routes: T): T;
4
102
 
5
- export { defineRoutes };
103
+ export { type InferableRoute, type RouteDefinition, defineRoutes, del, get, patch, post, put, route };
@@ -1,8 +1,37 @@
1
1
  // src/defineRoute.ts
2
+ function route(method, path, handler, middleware) {
3
+ return {
4
+ method,
5
+ path,
6
+ handler,
7
+ middleware
8
+ };
9
+ }
10
+ function get(path, handler, middleware) {
11
+ return route("GET", path, handler, middleware);
12
+ }
13
+ function post(path, handler, middleware) {
14
+ return route("POST", path, handler, middleware);
15
+ }
16
+ function put(path, handler, middleware) {
17
+ return route("PUT", path, handler, middleware);
18
+ }
19
+ function del(path, handler, middleware) {
20
+ return route("DELETE", path, handler, middleware);
21
+ }
22
+ function patch(path, handler, middleware) {
23
+ return route("PATCH", path, handler, middleware);
24
+ }
2
25
  function defineRoutes(routes) {
3
26
  return routes;
4
27
  }
5
28
  export {
6
- defineRoutes
29
+ defineRoutes,
30
+ del,
31
+ get,
32
+ patch,
33
+ post,
34
+ put,
35
+ route
7
36
  };
8
37
  //# sourceMappingURL=defineRoute.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/defineRoute.ts"],"sourcesContent":["import type { Route } from \"./types\";\n\nexport function defineRoutes(routes: Route[]): Route[] {\n return routes;\n}\n"],"mappings":";AAEO,SAAS,aAAa,QAA0B;AACrD,SAAO;AACT;","names":[]}
1
+ {"version":3,"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":";AAgEO,SAAS,MAKd,QACA,MACA,SACA,YAC2C;AAC3C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAKO,SAAS,IACd,MACA,SACA,YACyC;AACzC,SAAO,MAAM,OAAO,MAAM,SAAS,UAAU;AAC/C;AAKO,SAAS,KACd,MACA,SACA,YAC0C;AAC1C,SAAO,MAAM,QAAQ,MAAM,SAAS,UAAU;AAChD;AAKO,SAAS,IACd,MACA,SACA,YACyC;AACzC,SAAO,MAAM,OAAO,MAAM,SAAS,UAAU;AAC/C;AAKO,SAAS,IACd,MACA,SACA,YAC4C;AAC5C,SAAO,MAAM,UAAU,MAAM,SAAS,UAAU;AAClD;AAKO,SAAS,MACd,MACA,SACA,YAC2C;AAC3C,SAAO,MAAM,SAAS,MAAM,SAAS,UAAU;AACjD;AAuBO,SAAS,aAOd,QAAc;AACd,SAAO;AACT;","names":[]}
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export { ComponentServer } from './server/component-server.js';
3
3
  export { ServerFactory } from './server/server-factory.js';
4
4
  export { BaseServer } from './server/base-server.js';
5
5
  export { VafastError, composeMiddleware } from './middleware.js';
6
- export { createHandler, createHandlerWithExtra, simpleHandler } from './utils/create-handler.js';
6
+ export { InferableHandler, createHandler, createHandlerWithExtra, simpleHandler } from './utils/create-handler.js';
7
7
  export { getCookie, getHeader, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast } from './utils/parsers.js';
8
8
  export { empty, html, json, redirect, stream, text } from './utils/response.js';
9
9
  export { goAwait } from './utils/go-await.js';
@@ -14,13 +14,14 @@ export { HtmlRenderer } from './utils/html-renderer.js';
14
14
  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
+ export { SSEEvent, SSEHandler, SSEMarker, createSSEHandler } from './utils/sse.js';
17
18
  export { flattenNestedRoutes, normalizePath } from './router.js';
18
19
  export { requireAuth } from './middleware/authMiddleware.js';
19
20
  export { rateLimit } from './middleware/rateLimit.js';
20
21
  export { CORSOptions, createCORS } from './middleware/cors.js';
21
22
  export { TokenError, TokenOptions, TokenPayload, TokenResult, createTokenPair, generateToken, getTokenTimeRemaining, isTokenExpired, parseToken, refreshToken, verifyToken } from './auth/token.js';
22
23
  export { createAuth, createOptionalAuth, createPermissionAuth, createRoleAuth } from './middleware/auth.js';
23
- export { defineRoutes } from './defineRoute.js';
24
+ export { InferableRoute, RouteDefinition, defineRoutes, del, get, patch, post, put, route } from './defineRoute.js';
24
25
  export { FlattenedRoute, Handler, Method, Middleware, NestedRoute, ResponseBody, Route } from './types/types.js';
25
26
  export { BaseRouteConfig, CompatibleRoute, ExtendedRouteConfig, NestedRouteConfig, TypedRoute, createTypedRoute, isTypedRoute } from './types/route.js';
26
27
  export { ComponentRoute, FlattenedComponentRoute, NestedComponentRoute } from './types/component-route.js';
package/dist/index.js CHANGED
@@ -1,26 +1,26 @@
1
1
  // src/router.ts
2
2
  function flattenNestedRoutes(routes) {
3
3
  const flattened = [];
4
- function processRoute(route, parentPath = "", parentMiddleware = []) {
5
- const currentPath = normalizePath(parentPath + route.path);
4
+ function processRoute(route2, parentPath = "", parentMiddleware = []) {
5
+ const currentPath = normalizePath(parentPath + route2.path);
6
6
  const currentMiddleware = [
7
7
  ...parentMiddleware,
8
- ...route.middleware || []
8
+ ...route2.middleware || []
9
9
  ];
10
- if ("method" in route && "handler" in route) {
10
+ if ("method" in route2 && "handler" in route2) {
11
11
  flattened.push({
12
- ...route,
12
+ ...route2,
13
13
  fullPath: currentPath,
14
14
  middlewareChain: currentMiddleware
15
15
  });
16
- } else if ("children" in route && route.children) {
17
- for (const child of route.children) {
16
+ } else if ("children" in route2 && route2.children) {
17
+ for (const child of route2.children) {
18
18
  processRoute(child, currentPath, currentMiddleware);
19
19
  }
20
20
  }
21
21
  }
22
- for (const route of routes) {
23
- processRoute(route);
22
+ for (const route2 of routes) {
23
+ processRoute(route2);
24
24
  }
25
25
  return flattened;
26
26
  }
@@ -187,12 +187,12 @@ var BaseServer = class {
187
187
  */
188
188
  logFlattenedRoutes(routes, type = "\u8DEF\u7531") {
189
189
  console.log(`\u{1F680} \u6241\u5E73\u5316\u540E\u7684${type}:`);
190
- for (const route of routes) {
191
- const method = route.method || "GET";
192
- const path = route.fullPath || route.path;
190
+ for (const route2 of routes) {
191
+ const method = route2.method || "GET";
192
+ const path = route2.fullPath || route2.path;
193
193
  console.log(` ${method} ${path}`);
194
- if (route.middlewareChain && route.middlewareChain.length > 0) {
195
- console.log(` \u4E2D\u95F4\u4EF6\u94FE: ${route.middlewareChain.length} \u4E2A`);
194
+ if (route2.middlewareChain && route2.middlewareChain.length > 0) {
195
+ console.log(` \u4E2D\u95F4\u4EF6\u94FE: ${route2.middlewareChain.length} \u4E2A`);
196
196
  }
197
197
  }
198
198
  console.log("");
@@ -203,13 +203,13 @@ var BaseServer = class {
203
203
  */
204
204
  detectRouteConflicts(routes) {
205
205
  const pathGroups = /* @__PURE__ */ new Map();
206
- for (const route of routes) {
207
- const path = route.fullPath || route.path;
208
- const method = route.method || "GET";
206
+ for (const route2 of routes) {
207
+ const path = route2.fullPath || route2.path;
208
+ const method = route2.method || "GET";
209
209
  if (!pathGroups.has(path)) {
210
210
  pathGroups.set(path, []);
211
211
  }
212
- pathGroups.get(path).push({ ...route, method });
212
+ pathGroups.get(path).push({ ...route2, method });
213
213
  }
214
214
  for (const [path, routeList] of pathGroups) {
215
215
  if (routeList.length > 1) {
@@ -219,8 +219,8 @@ var BaseServer = class {
219
219
  console.warn(
220
220
  `\u26A0\uFE0F \u8DEF\u7531\u51B2\u7A81: ${uniqueMethods[0]} ${path} \u5B9A\u4E49\u4E86 ${routeList.length} \u6B21`
221
221
  );
222
- routeList.forEach((route, index) => {
223
- console.warn(` ${index + 1}. ${route.method} ${path}`);
222
+ routeList.forEach((route2, index) => {
223
+ console.warn(` ${index + 1}. ${route2.method} ${path}`);
224
224
  });
225
225
  } else {
226
226
  console.log(`\u2139\uFE0F \u8DEF\u5F84 ${path} \u652F\u6301\u65B9\u6CD5: ${uniqueMethods.join(", ")}`);
@@ -526,12 +526,12 @@ var Server = class extends BaseServer {
526
526
  registerRoutes(routes) {
527
527
  const flattened = flattenNestedRoutes(routes);
528
528
  this.routes.push(...flattened);
529
- for (const route of flattened) {
529
+ for (const route2 of flattened) {
530
530
  this.router.register(
531
- route.method,
532
- route.fullPath,
533
- route.handler,
534
- route.middlewareChain || []
531
+ route2.method,
532
+ route2.fullPath,
533
+ route2.handler,
534
+ route2.middlewareChain || []
535
535
  );
536
536
  }
537
537
  this.detectRouteConflicts(flattened);
@@ -608,18 +608,18 @@ var Server = class extends BaseServer {
608
608
  }
609
609
  return this.createErrorResponse(method, pathname);
610
610
  };
611
- addRoute(route) {
611
+ addRoute(route2) {
612
612
  const flattenedRoute = {
613
- ...route,
614
- fullPath: route.path,
615
- middlewareChain: route.middleware || []
613
+ ...route2,
614
+ fullPath: route2.path,
615
+ middlewareChain: route2.middleware || []
616
616
  };
617
617
  this.routes.push(flattenedRoute);
618
618
  this.router.register(
619
- route.method,
620
- route.path,
621
- route.handler,
622
- route.middleware || []
619
+ route2.method,
620
+ route2.path,
621
+ route2.handler,
622
+ route2.middleware || []
623
623
  );
624
624
  }
625
625
  addRoutes(routes) {
@@ -633,26 +633,26 @@ var Server = class extends BaseServer {
633
633
  // src/middleware/component-router.ts
634
634
  function flattenComponentRoutes(routes) {
635
635
  const flattened = [];
636
- function processRoute(route, parentPath = "", parentMiddleware = []) {
637
- const currentPath = parentPath + route.path;
636
+ function processRoute(route2, parentPath = "", parentMiddleware = []) {
637
+ const currentPath = parentPath + route2.path;
638
638
  const currentMiddleware = [
639
639
  ...parentMiddleware,
640
- ...route.middleware || []
640
+ ...route2.middleware || []
641
641
  ];
642
- if ("component" in route) {
642
+ if ("component" in route2) {
643
643
  flattened.push({
644
- ...route,
644
+ ...route2,
645
645
  fullPath: currentPath,
646
646
  middlewareChain: currentMiddleware
647
647
  });
648
- } else if ("children" in route && route.children) {
649
- for (const child of route.children) {
648
+ } else if ("children" in route2 && route2.children) {
649
+ for (const child of route2.children) {
650
650
  processRoute(child, currentPath, currentMiddleware);
651
651
  }
652
652
  }
653
653
  }
654
- for (const route of routes) {
655
- processRoute(route);
654
+ for (const route2 of routes) {
655
+ processRoute(route2);
656
656
  }
657
657
  return flattened;
658
658
  }
@@ -880,9 +880,9 @@ var ComponentServer = class extends BaseServer {
880
880
  return new Response("Method Not Allowed", { status: 405 });
881
881
  }
882
882
  let matchedRoute = null;
883
- for (const route of this.routes) {
884
- if (PathMatcher.matchPath(route.fullPath, pathname)) {
885
- matchedRoute = route;
883
+ for (const route2 of this.routes) {
884
+ if (PathMatcher.matchPath(route2.fullPath, pathname)) {
885
+ matchedRoute = route2;
886
886
  break;
887
887
  }
888
888
  }
@@ -1314,7 +1314,7 @@ function createHandler(schemaOrHandler, maybeHandler) {
1314
1314
  if (schema.body || schema.query || schema.params || schema.headers || schema.cookies) {
1315
1315
  precompileSchemas(schema);
1316
1316
  }
1317
- return async (req) => {
1317
+ const handlerFn = async (req) => {
1318
1318
  try {
1319
1319
  const query = parseQuery(req);
1320
1320
  const headers = parseHeaders(req);
@@ -1345,6 +1345,7 @@ function createHandler(schemaOrHandler, maybeHandler) {
1345
1345
  return handleInternalError(error);
1346
1346
  }
1347
1347
  };
1348
+ return handlerFn;
1348
1349
  }
1349
1350
  function createHandlerWithExtra(schemaOrHandler, maybeHandler) {
1350
1351
  const hasSchema = !isHandler(schemaOrHandler);
@@ -1587,6 +1588,101 @@ var Patterns = {
1587
1588
  JWT: JWT_REGEX
1588
1589
  };
1589
1590
 
1591
+ // src/utils/sse.ts
1592
+ function formatSSEEvent(event) {
1593
+ const lines = [];
1594
+ if (event.id !== void 0) {
1595
+ lines.push(`id: ${event.id}`);
1596
+ }
1597
+ if (event.event !== void 0) {
1598
+ lines.push(`event: ${event.event}`);
1599
+ }
1600
+ if (event.retry !== void 0) {
1601
+ lines.push(`retry: ${event.retry}`);
1602
+ }
1603
+ const dataStr = typeof event.data === "string" ? event.data : JSON.stringify(event.data);
1604
+ const dataLines = dataStr.split("\n");
1605
+ for (const line of dataLines) {
1606
+ lines.push(`data: ${line}`);
1607
+ }
1608
+ return lines.join("\n") + "\n\n";
1609
+ }
1610
+ function createSSEHandler(schemaOrGenerator, maybeGenerator) {
1611
+ const hasSchema = typeof schemaOrGenerator !== "function";
1612
+ const schema = hasSchema ? schemaOrGenerator : {};
1613
+ const generator = hasSchema ? maybeGenerator : schemaOrGenerator;
1614
+ if (schema.body || schema.query || schema.params || schema.headers || schema.cookies) {
1615
+ precompileSchemas(schema);
1616
+ }
1617
+ const handlerFn = async (req) => {
1618
+ try {
1619
+ const query = parseQuery(req);
1620
+ const headers = parseHeaders(req);
1621
+ const cookies = parseCookies(req);
1622
+ const params = req.params || {};
1623
+ const data = { body: void 0, query, params, headers, cookies };
1624
+ if (schema.body || schema.query || schema.params || schema.headers || schema.cookies) {
1625
+ validateAllSchemas(schema, data);
1626
+ }
1627
+ const stream2 = new ReadableStream({
1628
+ async start(controller) {
1629
+ const encoder2 = new TextEncoder();
1630
+ try {
1631
+ const gen = generator({
1632
+ req,
1633
+ body: void 0,
1634
+ query,
1635
+ params,
1636
+ headers,
1637
+ cookies
1638
+ });
1639
+ for await (const event of gen) {
1640
+ const formatted = formatSSEEvent(event);
1641
+ controller.enqueue(encoder2.encode(formatted));
1642
+ }
1643
+ } catch (error) {
1644
+ const errorEvent = formatSSEEvent({
1645
+ event: "error",
1646
+ data: {
1647
+ message: error instanceof Error ? error.message : "Unknown error"
1648
+ }
1649
+ });
1650
+ controller.enqueue(encoder2.encode(errorEvent));
1651
+ } finally {
1652
+ controller.close();
1653
+ }
1654
+ }
1655
+ });
1656
+ return new Response(stream2, {
1657
+ headers: {
1658
+ "Content-Type": "text/event-stream",
1659
+ "Cache-Control": "no-cache",
1660
+ "Connection": "keep-alive",
1661
+ "X-Accel-Buffering": "no"
1662
+ // Nginx 禁用缓冲
1663
+ }
1664
+ });
1665
+ } catch (error) {
1666
+ return new Response(
1667
+ JSON.stringify({
1668
+ success: false,
1669
+ error: "Validation Error",
1670
+ message: error instanceof Error ? error.message : "Unknown error"
1671
+ }),
1672
+ {
1673
+ status: 400,
1674
+ headers: { "Content-Type": "application/json" }
1675
+ }
1676
+ );
1677
+ }
1678
+ };
1679
+ const handler = handlerFn;
1680
+ handler.__sse = { __brand: "SSE" };
1681
+ handler.__schema = schema;
1682
+ handler.__returnType = void 0;
1683
+ return handler;
1684
+ }
1685
+
1590
1686
  // src/middleware/authMiddleware.ts
1591
1687
  var requireAuth = async (req, next) => {
1592
1688
  const token = getCookie2(req, "auth");
@@ -1885,6 +1981,29 @@ function createPermissionAuth(permissions, options) {
1885
1981
  }
1886
1982
 
1887
1983
  // src/defineRoute.ts
1984
+ function route(method, path, handler, middleware) {
1985
+ return {
1986
+ method,
1987
+ path,
1988
+ handler,
1989
+ middleware
1990
+ };
1991
+ }
1992
+ function get(path, handler, middleware) {
1993
+ return route("GET", path, handler, middleware);
1994
+ }
1995
+ function post(path, handler, middleware) {
1996
+ return route("POST", path, handler, middleware);
1997
+ }
1998
+ function put(path, handler, middleware) {
1999
+ return route("PUT", path, handler, middleware);
2000
+ }
2001
+ function del(path, handler, middleware) {
2002
+ return route("DELETE", path, handler, middleware);
2003
+ }
2004
+ function patch(path, handler, middleware) {
2005
+ return route("PATCH", path, handler, middleware);
2006
+ }
1888
2007
  function defineRoutes(routes) {
1889
2008
  return routes;
1890
2009
  }
@@ -1893,8 +2012,8 @@ function defineRoutes(routes) {
1893
2012
  function createTypedRoute(config) {
1894
2013
  return config;
1895
2014
  }
1896
- function isTypedRoute(route) {
1897
- return route && typeof route === "object" && "method" in route && "path" in route && "handler" in route;
2015
+ function isTypedRoute(route2) {
2016
+ return route2 && typeof route2 === "object" && "method" in route2 && "path" in route2 && "handler" in route2;
1898
2017
  }
1899
2018
 
1900
2019
  // src/node-server/serve.ts
@@ -2108,10 +2227,53 @@ function createRequestHandler(fetch, defaultHost, onError) {
2108
2227
  };
2109
2228
  }
2110
2229
  function serve(options, callback) {
2111
- const { fetch, port = 3e3, hostname = "0.0.0.0", onError } = options;
2230
+ const { fetch, port = 3e3, hostname = "0.0.0.0", onError, gracefulShutdown } = options;
2112
2231
  const defaultHost = `${hostname === "0.0.0.0" ? "localhost" : hostname}:${port}`;
2113
2232
  const handler = createRequestHandler(fetch, defaultHost, onError);
2114
2233
  const server = createServer(handler);
2234
+ const connections = /* @__PURE__ */ new Set();
2235
+ server.on("connection", (socket) => {
2236
+ connections.add(socket);
2237
+ socket.on("close", () => connections.delete(socket));
2238
+ });
2239
+ let isShuttingDown = false;
2240
+ const shutdown = async () => {
2241
+ if (isShuttingDown) return;
2242
+ isShuttingDown = true;
2243
+ const shutdownOptions = typeof gracefulShutdown === "object" ? gracefulShutdown : {};
2244
+ const timeout = shutdownOptions.timeout ?? 3e4;
2245
+ if (shutdownOptions.onShutdown) {
2246
+ await shutdownOptions.onShutdown();
2247
+ }
2248
+ return new Promise((resolve) => {
2249
+ const forceCloseTimer = setTimeout(() => {
2250
+ for (const socket of connections) {
2251
+ socket.destroy();
2252
+ }
2253
+ connections.clear();
2254
+ resolve();
2255
+ }, timeout);
2256
+ server.close(() => {
2257
+ clearTimeout(forceCloseTimer);
2258
+ shutdownOptions.onShutdownComplete?.();
2259
+ resolve();
2260
+ });
2261
+ for (const socket of connections) {
2262
+ if (!socket.writableLength) {
2263
+ socket.end();
2264
+ }
2265
+ }
2266
+ });
2267
+ };
2268
+ if (gracefulShutdown) {
2269
+ const shutdownOptions = typeof gracefulShutdown === "object" ? gracefulShutdown : {};
2270
+ const signals = shutdownOptions.signals ?? ["SIGINT", "SIGTERM"];
2271
+ for (const signal of signals) {
2272
+ process.on(signal, () => {
2273
+ shutdown().then(() => process.exit(0));
2274
+ });
2275
+ }
2276
+ }
2115
2277
  server.listen(port, hostname, callback);
2116
2278
  return {
2117
2279
  server,
@@ -2122,7 +2284,8 @@ function serve(options, callback) {
2122
2284
  if (err) reject(err);
2123
2285
  else resolve();
2124
2286
  });
2125
- })
2287
+ }),
2288
+ shutdown
2126
2289
  };
2127
2290
  }
2128
2291
 
@@ -2152,13 +2315,16 @@ export {
2152
2315
  createPermissionAuth,
2153
2316
  createRequestValidator,
2154
2317
  createRoleAuth,
2318
+ createSSEHandler,
2155
2319
  createTokenPair,
2156
2320
  createTypedRoute,
2157
2321
  createValidator,
2158
2322
  defineRoutes,
2323
+ del,
2159
2324
  empty,
2160
2325
  flattenNestedRoutes,
2161
2326
  generateToken,
2327
+ get,
2162
2328
  getCookie,
2163
2329
  getHeader,
2164
2330
  getLocals,
@@ -2180,13 +2346,17 @@ export {
2180
2346
  parseQueryFast,
2181
2347
  parseRequest,
2182
2348
  parseToken,
2349
+ patch,
2350
+ post,
2183
2351
  precompileSchemas,
2352
+ put,
2184
2353
  rateLimit,
2185
2354
  redirect,
2186
2355
  refreshToken,
2187
2356
  registerFormat,
2188
2357
  registerFormats,
2189
2358
  requireAuth,
2359
+ route,
2190
2360
  serve,
2191
2361
  setLocals,
2192
2362
  simpleHandler,