vafast 0.3.9 → 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.
- package/dist/defineRoute.d.ts +101 -3
- package/dist/defineRoute.js +30 -1
- package/dist/defineRoute.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +220 -50
- package/dist/index.js.map +1 -1
- package/dist/node-server/index.js +46 -2
- package/dist/node-server/index.js.map +1 -1
- package/dist/node-server/serve.d.ts +16 -1
- package/dist/node-server/serve.js +46 -2
- package/dist/node-server/serve.js.map +1 -1
- package/dist/serve.js +46 -2
- package/dist/serve.js.map +1 -1
- package/dist/utils/create-handler.d.ts +12 -3
- package/dist/utils/create-handler.js +2 -1
- package/dist/utils/create-handler.js.map +1 -1
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +98 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/sse.d.ts +87 -0
- package/dist/utils/sse.js +181 -0
- package/dist/utils/sse.js.map +1 -0
- package/package.json +3 -21
package/dist/defineRoute.d.ts
CHANGED
|
@@ -1,5 +1,103 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RouteSchema } from './types/schema.js';
|
|
2
|
+
import { InferableHandler } from './utils/create-handler.js';
|
|
3
|
+
import '@sinclair/typebox';
|
|
2
4
|
|
|
3
|
-
|
|
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 };
|
package/dist/defineRoute.js
CHANGED
|
@@ -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
|
package/dist/defineRoute.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/defineRoute.ts"],"sourcesContent":["import type {
|
|
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(
|
|
5
|
-
const currentPath = normalizePath(parentPath +
|
|
4
|
+
function processRoute(route2, parentPath = "", parentMiddleware = []) {
|
|
5
|
+
const currentPath = normalizePath(parentPath + route2.path);
|
|
6
6
|
const currentMiddleware = [
|
|
7
7
|
...parentMiddleware,
|
|
8
|
-
...
|
|
8
|
+
...route2.middleware || []
|
|
9
9
|
];
|
|
10
|
-
if ("method" in
|
|
10
|
+
if ("method" in route2 && "handler" in route2) {
|
|
11
11
|
flattened.push({
|
|
12
|
-
...
|
|
12
|
+
...route2,
|
|
13
13
|
fullPath: currentPath,
|
|
14
14
|
middlewareChain: currentMiddleware
|
|
15
15
|
});
|
|
16
|
-
} else if ("children" in
|
|
17
|
-
for (const child of
|
|
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
|
|
23
|
-
processRoute(
|
|
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
|
|
191
|
-
const method =
|
|
192
|
-
const 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 (
|
|
195
|
-
console.log(` \u4E2D\u95F4\u4EF6\u94FE: ${
|
|
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
|
|
207
|
-
const path =
|
|
208
|
-
const method =
|
|
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({ ...
|
|
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((
|
|
223
|
-
console.warn(` ${index + 1}. ${
|
|
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
|
|
529
|
+
for (const route2 of flattened) {
|
|
530
530
|
this.router.register(
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
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(
|
|
611
|
+
addRoute(route2) {
|
|
612
612
|
const flattenedRoute = {
|
|
613
|
-
...
|
|
614
|
-
fullPath:
|
|
615
|
-
middlewareChain:
|
|
613
|
+
...route2,
|
|
614
|
+
fullPath: route2.path,
|
|
615
|
+
middlewareChain: route2.middleware || []
|
|
616
616
|
};
|
|
617
617
|
this.routes.push(flattenedRoute);
|
|
618
618
|
this.router.register(
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
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(
|
|
637
|
-
const currentPath = parentPath +
|
|
636
|
+
function processRoute(route2, parentPath = "", parentMiddleware = []) {
|
|
637
|
+
const currentPath = parentPath + route2.path;
|
|
638
638
|
const currentMiddleware = [
|
|
639
639
|
...parentMiddleware,
|
|
640
|
-
...
|
|
640
|
+
...route2.middleware || []
|
|
641
641
|
];
|
|
642
|
-
if ("component" in
|
|
642
|
+
if ("component" in route2) {
|
|
643
643
|
flattened.push({
|
|
644
|
-
...
|
|
644
|
+
...route2,
|
|
645
645
|
fullPath: currentPath,
|
|
646
646
|
middlewareChain: currentMiddleware
|
|
647
647
|
});
|
|
648
|
-
} else if ("children" in
|
|
649
|
-
for (const child of
|
|
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
|
|
655
|
-
processRoute(
|
|
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
|
|
884
|
-
if (PathMatcher.matchPath(
|
|
885
|
-
matchedRoute =
|
|
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
|
-
|
|
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(
|
|
1897
|
-
return
|
|
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,
|