vafast 0.7.1 → 0.7.2
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 +35 -12
- package/dist/{defineRoute-B9VdaoQA.d.mts → defineRoute-DKVyYELW.d.mts} +36 -2
- package/dist/defineRoute.d.mts +2 -2
- package/dist/defineRoute.mjs +43 -8
- package/dist/defineRoute.mjs.map +1 -1
- package/dist/{index-CRU-u6NT.d.mts → index-BPXVOE-X.d.mts} +3 -3
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +2 -2
- package/dist/monitoring/index.d.mts +3 -3
- package/dist/monitoring/native-monitor.d.mts +3 -3
- package/dist/{route-registry-C6h13Mks.d.mts → route-registry-C2a27CuM.d.mts} +2 -2
- package/dist/server/index.d.mts +3 -3
- package/dist/server/server-factory.d.mts +3 -3
- package/dist/server/server.d.mts +2 -2
- package/dist/{server-CQ-_WgQN.d.mts → server-D3IERUlj.d.mts} +2 -2
- package/dist/sse-BqvrwmK6.d.mts +76 -0
- package/dist/utils/index.d.mts +3 -3
- package/dist/utils/route-registry.d.mts +2 -2
- package/dist/utils/sse.d.mts +2 -2
- package/package.json +1 -1
- package/dist/sse-D77CKcsH.d.mts +0 -45
package/README.md
CHANGED
|
@@ -589,37 +589,60 @@ defineRoute({
|
|
|
589
589
|
|
|
590
590
|
### SSE 流式响应
|
|
591
591
|
|
|
592
|
-
通过 `sse: true` 显式声明 SSE 端点,适用于 AI
|
|
592
|
+
通过 `sse: true` 显式声明 SSE 端点,适用于 AI 聊天、进度更新等场景。
|
|
593
|
+
|
|
594
|
+
**简单模式(推荐)** - 直接 yield 任意数据:
|
|
593
595
|
|
|
594
596
|
```typescript
|
|
595
597
|
import { defineRoute, defineRoutes, Type } from 'vafast'
|
|
596
598
|
|
|
597
599
|
const routes = defineRoutes([
|
|
600
|
+
// AI 聊天场景
|
|
601
|
+
defineRoute({
|
|
602
|
+
method: 'POST',
|
|
603
|
+
path: '/chat/stream',
|
|
604
|
+
sse: true,
|
|
605
|
+
schema: { body: Type.Object({ message: Type.String() }) },
|
|
606
|
+
handler: async function* ({ body }) {
|
|
607
|
+
// 直接 yield 数据,框架自动包装为 SSE data 字段
|
|
608
|
+
yield { type: 'start', input: body.message }
|
|
609
|
+
|
|
610
|
+
for await (const chunk of aiStream(body.message)) {
|
|
611
|
+
yield { type: 'text_delta', content: chunk }
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
yield { type: 'done', usage: { tokens: 100 } }
|
|
615
|
+
},
|
|
616
|
+
}),
|
|
617
|
+
|
|
618
|
+
// 进度更新场景
|
|
598
619
|
defineRoute({
|
|
599
620
|
method: 'GET',
|
|
600
621
|
path: '/tasks/:taskId/progress',
|
|
601
|
-
sse: true,
|
|
622
|
+
sse: true,
|
|
602
623
|
schema: { params: Type.Object({ taskId: Type.String() }) },
|
|
603
624
|
handler: async function* ({ params }) {
|
|
604
|
-
yield { event: 'start', data: { taskId: params.taskId } }
|
|
605
|
-
|
|
606
625
|
for (let i = 0; i <= 100; i += 10) {
|
|
607
|
-
yield {
|
|
626
|
+
yield { progress: i, taskId: params.taskId }
|
|
608
627
|
await new Promise(r => setTimeout(r, 100))
|
|
609
628
|
}
|
|
610
|
-
|
|
611
|
-
yield { event: 'complete', data: { message: 'Done!' } }
|
|
612
629
|
},
|
|
613
630
|
}),
|
|
614
631
|
])
|
|
615
632
|
```
|
|
616
633
|
|
|
617
|
-
|
|
634
|
+
**高级模式** - 需要设置 SSE event/id/retry 时使用 `sse()` 函数:
|
|
618
635
|
|
|
619
|
-
```
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
636
|
+
```typescript
|
|
637
|
+
import { sse } from 'vafast'
|
|
638
|
+
|
|
639
|
+
handler: async function* () {
|
|
640
|
+
// 带事件名称
|
|
641
|
+
yield sse({ event: 'status' }, { ready: true })
|
|
642
|
+
|
|
643
|
+
// 带事件 ID 和重试间隔
|
|
644
|
+
yield sse({ event: 'update', id: '42', retry: 5000 }, { value: 1 })
|
|
645
|
+
}
|
|
623
646
|
```
|
|
624
647
|
|
|
625
648
|
> 📖 详细文档见 [docs/sse.md](./docs/sse.md)
|
|
@@ -139,6 +139,40 @@ type Route = ProcessedRoute;
|
|
|
139
139
|
* ```
|
|
140
140
|
*/
|
|
141
141
|
declare function defineMiddleware<TContext extends object = object>(handler: (req: Request, next: (ctx?: TContext) => Promise<Response>) => Promise<Response>): TypedMiddleware<TContext>;
|
|
142
|
+
/**
|
|
143
|
+
* SSE 元数据接口(用于高级场景)
|
|
144
|
+
*/
|
|
145
|
+
interface SSEMeta {
|
|
146
|
+
/** SSE 事件名称 */
|
|
147
|
+
event?: string;
|
|
148
|
+
/** SSE 事件 ID */
|
|
149
|
+
id?: string;
|
|
150
|
+
/** SSE 重试间隔(毫秒) */
|
|
151
|
+
retry?: number;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 带元数据的 SSE 事件(高级用法)
|
|
155
|
+
*/
|
|
156
|
+
interface SSEEventWithMeta<T = unknown> {
|
|
157
|
+
/** SSE 元数据标记 */
|
|
158
|
+
__sse__: SSEMeta;
|
|
159
|
+
/** 事件数据 */
|
|
160
|
+
data: T;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 创建带元数据的 SSE 事件
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* // 设置事件名称
|
|
167
|
+
* yield sse({ event: 'status' }, { ready: true })
|
|
168
|
+
*
|
|
169
|
+
* // 设置 ID(支持断线重连)
|
|
170
|
+
* yield sse({ event: 'update', id: '42' }, { value: 1 })
|
|
171
|
+
*
|
|
172
|
+
* // 设置重试间隔
|
|
173
|
+
* yield sse({ retry: 5000 }, 'reconnect hint')
|
|
174
|
+
*/
|
|
175
|
+
declare function sse<T>(meta: SSEMeta, data: T): SSEEventWithMeta<T>;
|
|
142
176
|
/**
|
|
143
177
|
* 定义叶子路由(有 method 和 handler),支持中间件类型推断和显式上下文类型
|
|
144
178
|
*
|
|
@@ -292,5 +326,5 @@ type InferableRoute<TMethod extends string = string, TPath extends string = stri
|
|
|
292
326
|
readonly middleware?: ReadonlyArray<AnyMiddleware>;
|
|
293
327
|
};
|
|
294
328
|
//#endregion
|
|
295
|
-
export { ProcessedRoute as a, RoutesWithSource as c,
|
|
296
|
-
//# sourceMappingURL=defineRoute-
|
|
329
|
+
export { sse as _, ProcessedRoute as a, RoutesWithSource as c, SSEGeneratorType as d, SSEMeta as f, defineRoutes as g, defineRoute as h, NestedRouteConfig as i, SSEEventType as l, defineMiddleware as m, InferableRoute as n, Route as o, TypedMiddleware as p, LeafRouteConfig as r, RouteSchema as s, HandlerContext as t, SSEEventWithMeta as u, withContext as v };
|
|
330
|
+
//# sourceMappingURL=defineRoute-DKVyYELW.d.mts.map
|
package/dist/defineRoute.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ProcessedRoute, c as RoutesWithSource, d as
|
|
2
|
-
export { HandlerContext, InferableRoute, LeafRouteConfig, NestedRouteConfig, ProcessedRoute, Route, RouteSchema, RoutesWithSource, SSEEventType, SSEGeneratorType, TypedMiddleware, defineMiddleware, defineRoute, defineRoutes, withContext };
|
|
1
|
+
import { _ as sse, a as ProcessedRoute, c as RoutesWithSource, d as SSEGeneratorType, f as SSEMeta, g as defineRoutes, h as defineRoute, i as NestedRouteConfig, l as SSEEventType, m as defineMiddleware, n as InferableRoute, o as Route, p as TypedMiddleware, r as LeafRouteConfig, s as RouteSchema, t as HandlerContext, u as SSEEventWithMeta, v as withContext } from "./defineRoute-DKVyYELW.mjs";
|
|
2
|
+
export { HandlerContext, InferableRoute, LeafRouteConfig, NestedRouteConfig, ProcessedRoute, Route, RouteSchema, RoutesWithSource, SSEEventType, SSEEventWithMeta, SSEGeneratorType, SSEMeta, TypedMiddleware, defineMiddleware, defineRoute, defineRoutes, sse, withContext };
|
package/dist/defineRoute.mjs
CHANGED
|
@@ -105,21 +105,56 @@ function wrapHandler(schema, userHandler) {
|
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
|
-
*
|
|
108
|
+
* 创建带元数据的 SSE 事件
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* // 设置事件名称
|
|
112
|
+
* yield sse({ event: 'status' }, { ready: true })
|
|
113
|
+
*
|
|
114
|
+
* // 设置 ID(支持断线重连)
|
|
115
|
+
* yield sse({ event: 'update', id: '42' }, { value: 1 })
|
|
116
|
+
*
|
|
117
|
+
* // 设置重试间隔
|
|
118
|
+
* yield sse({ retry: 5000 }, 'reconnect hint')
|
|
119
|
+
*/
|
|
120
|
+
function sse(meta, data) {
|
|
121
|
+
return {
|
|
122
|
+
__sse__: meta,
|
|
123
|
+
data
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 检查是否是带元数据的 SSE 事件
|
|
128
|
+
*/
|
|
129
|
+
function isSSEEventWithMeta(event) {
|
|
130
|
+
return event !== null && typeof event === "object" && "__sse__" in event && "data" in event;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 格式化 SSE 事件为字符串
|
|
134
|
+
*
|
|
135
|
+
* 支持两种用法:
|
|
136
|
+
* 1. 简单模式(推荐):yield anyData → 自动包装为 data
|
|
137
|
+
* 2. 高级模式:yield { __sse__: { event, id, retry }, data } → 完整 SSE 控制
|
|
109
138
|
*/
|
|
110
139
|
function formatSSEEvent(event) {
|
|
111
140
|
const lines = [];
|
|
112
|
-
|
|
113
|
-
if (event
|
|
114
|
-
|
|
115
|
-
|
|
141
|
+
let data;
|
|
142
|
+
if (isSSEEventWithMeta(event)) {
|
|
143
|
+
const meta = event.__sse__;
|
|
144
|
+
if (meta.id !== void 0) lines.push(`id: ${meta.id}`);
|
|
145
|
+
if (meta.event !== void 0) lines.push(`event: ${meta.event}`);
|
|
146
|
+
if (meta.retry !== void 0) lines.push(`retry: ${meta.retry}`);
|
|
147
|
+
data = event.data;
|
|
148
|
+
} else data = event;
|
|
149
|
+
const dataStr = typeof data === "string" ? data : JSON.stringify(data);
|
|
116
150
|
for (const line of dataStr.split("\n")) lines.push(`data: ${line}`);
|
|
117
151
|
return lines.join("\n") + "\n\n";
|
|
118
152
|
}
|
|
119
153
|
/**
|
|
120
154
|
* 将 AsyncGenerator 包装为 SSE Handler
|
|
121
155
|
*
|
|
122
|
-
* 支持用户直接写 `async function* (ctx) { yield
|
|
156
|
+
* 支持用户直接写 `async function* (ctx) { yield anyData }`
|
|
157
|
+
* 数据会自动包装为 SSE data 字段发送
|
|
123
158
|
*/
|
|
124
159
|
function wrapGeneratorToSSEHandler(generator) {
|
|
125
160
|
return async (ctx) => {
|
|
@@ -129,7 +164,7 @@ function wrapGeneratorToSSEHandler(generator) {
|
|
|
129
164
|
for await (const event of generator(ctx)) controller.enqueue(encoder.encode(formatSSEEvent(event)));
|
|
130
165
|
} catch (error) {
|
|
131
166
|
const errorEvent = formatSSEEvent({
|
|
132
|
-
event: "error",
|
|
167
|
+
__sse__: { event: "error" },
|
|
133
168
|
data: { error: error instanceof Error ? error.message : "未知错误" }
|
|
134
169
|
});
|
|
135
170
|
controller.enqueue(encoder.encode(errorEvent));
|
|
@@ -261,5 +296,5 @@ function defineRoutes(routes) {
|
|
|
261
296
|
}
|
|
262
297
|
|
|
263
298
|
//#endregion
|
|
264
|
-
export { defineMiddleware, defineRoute, defineRoutes, withContext };
|
|
299
|
+
export { defineMiddleware, defineRoute, defineRoutes, sse, withContext };
|
|
265
300
|
//# sourceMappingURL=defineRoute.mjs.map
|
package/dist/defineRoute.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defineRoute.mjs","names":[],"sources":["../src/defineRoute.ts"],"sourcesContent":["/**\n * 路由定义 - Schema 在路由级别定义,支持嵌套路由和中间件类型推断\n *\n * @example\n * ```typescript\n * // 定义带类型的中间件(函数式风格,通过 next 传递上下文)\n * const authMiddleware = defineMiddleware<{ user: User }>((req, next) => {\n * const user = getUser(req)\n * return next({ user }) // 通过 next 参数传递上下文\n * })\n *\n * // 路由自动推断中间件注入的类型\n * const routes = defineRoutes([\n * defineRoute({\n * path: '/api',\n * middleware: [authMiddleware],\n * children: [\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * handler: ({ user }) => ({ name: user.name }) // ✅ user 有类型\n * })\n * ]\n * })\n * ])\n * ```\n */\n\nimport type { TSchema, Static } from \"@sinclair/typebox\";\nimport { parseBody, parseQuery, parseHeaders, parseCookies } from \"./utils/parsers\";\nimport { validateAllSchemas, precompileSchemas } from \"./utils/validators/validators\";\nimport { json } from \"./utils/response\";\nimport { VafastError } from \"./middleware\";\n\n// ============= SSE 事件类型(内联定义,避免循环依赖) =============\n\n/** SSE 事件 */\nexport interface SSEEventType<T = unknown> {\n event?: string;\n data: T;\n id?: string;\n retry?: number;\n}\n\n/** SSE Generator 类型 */\nexport type SSEGeneratorType<TSchema extends RouteSchema = RouteSchema> = (\n ctx: HandlerContext<TSchema>\n) => AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n\n// ============= Schema 类型 =============\n\n/** 路由 Schema 配置 */\nexport interface RouteSchema {\n body?: TSchema;\n query?: TSchema;\n params?: TSchema;\n headers?: TSchema;\n cookies?: TSchema;\n /** 响应类型 schema(用于类型同步,运行时不做校验) */\n response?: TSchema;\n}\n\n/** 从 Schema 推断类型 */\ntype InferSchemaType<T extends RouteSchema> = {\n body: T[\"body\"] extends TSchema ? Static<T[\"body\"]> : unknown;\n query: T[\"query\"] extends TSchema ? Static<T[\"query\"]> : Record<string, string>;\n params: T[\"params\"] extends TSchema ? Static<T[\"params\"]> : Record<string, string>;\n headers: T[\"headers\"] extends TSchema ? Static<T[\"headers\"]> : Record<string, string>;\n cookies: T[\"cookies\"] extends TSchema ? Static<T[\"cookies\"]> : Record<string, string>;\n};\n\n// ============= 中间件类型系统 =============\n\n/** 带类型标记的中间件 */\nexport interface TypedMiddleware<TContext extends object = object> {\n (req: Request, next: (ctx?: TContext) => Promise<Response>): Response | Promise<Response>;\n /** 类型标记(仅编译时使用) */\n __context?: TContext;\n}\n\n/** 普通中间件(无类型注入) */\ntype PlainMiddleware = (req: Request, next: () => Promise<Response>) => Response | Promise<Response>;\n\n/** 任意中间件类型 */\ntype AnyMiddleware = TypedMiddleware<object> | PlainMiddleware;\n\n/** 从中间件提取上下文类型 */\ntype ExtractMiddlewareContext<T> = T extends TypedMiddleware<infer C> ? C : object;\n\n/** 合并中间件数组的上下文类型 */\ntype MergeMiddlewareContexts<T extends readonly unknown[]> =\n T extends readonly [infer First, ...infer Rest]\n ? ExtractMiddlewareContext<First> & MergeMiddlewareContexts<Rest>\n : object;\n\n// ============= Handler 上下文 =============\n\n/** Handler 上下文(包含 schema 推断) */\nexport interface HandlerContext<TSchema extends RouteSchema = RouteSchema> {\n req: Request;\n body: InferSchemaType<TSchema>[\"body\"];\n query: InferSchemaType<TSchema>[\"query\"];\n params: InferSchemaType<TSchema>[\"params\"];\n headers: InferSchemaType<TSchema>[\"headers\"];\n cookies: InferSchemaType<TSchema>[\"cookies\"];\n}\n\n/** Handler 上下文(带中间件注入的额外类型) */\ntype HandlerContextWithExtra<TSchema extends RouteSchema, TExtra> =\n HandlerContext<TSchema> & TExtra;\n\n// ============= 路由配置类型 =============\n\n/** HTTP 方法 */\ntype HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"OPTIONS\" | \"HEAD\";\n\n/** Handler 上下文类型(带中间件扩展) */\ntype HandlerCtx<TSchema extends RouteSchema, TMiddleware extends readonly AnyMiddleware[]> =\n HandlerContextWithExtra<TSchema, MergeMiddlewareContexts<TMiddleware>>;\n\n/** 普通 Handler 类型 */\ntype NormalHandler<TSchema extends RouteSchema, TReturn, TMiddleware extends readonly AnyMiddleware[]> = (\n ctx: HandlerCtx<TSchema, TMiddleware>\n) => TReturn | Promise<TReturn>;\n\n/** SSE Generator Handler 类型(直接写 async function*,无需 createSSEHandler 包装) */\ntype SSEHandler<TSchema extends RouteSchema, TMiddleware extends readonly AnyMiddleware[]> = (\n ctx: HandlerCtx<TSchema, TMiddleware>\n) => AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n\n/** 叶子路由配置(有 method 和 handler) */\nexport interface LeafRouteConfig<\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string,\n TSchema extends RouteSchema = RouteSchema,\n TReturn = unknown,\n TMiddleware extends readonly AnyMiddleware[] = readonly AnyMiddleware[]\n> {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** \n * 是否为 SSE 端点(显式声明,推荐)\n * \n * 设置为 true 时,handler 应返回 AsyncGenerator:\n * ```typescript\n * sse: true,\n * handler: async function* (ctx) { yield { data: ... } }\n * ```\n */\n readonly sse?: boolean;\n /** \n * Handler 支持两种写法:\n * 1. 普通函数: `async (ctx) => { return result }`\n * 2. SSE Generator(需配合 sse: true): `async function* (ctx) { yield { data: ... } }`\n */\n readonly handler: NormalHandler<TSchema, TReturn, TMiddleware> | SSEHandler<TSchema, TMiddleware>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}\n\n/** 嵌套路由配置(有 children,无 method 和 handler) */\nexport interface NestedRouteConfig<\n TPath extends string = string,\n TMiddleware extends readonly AnyMiddleware[] = readonly AnyMiddleware[]\n> {\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly middleware?: TMiddleware;\n readonly children: ReadonlyArray<RouteConfigResult>;\n}\n\n/** defineRoute 返回的类型 */\ntype RouteConfigResult =\n | LeafRouteConfig<HTTPMethod, string, RouteSchema, unknown, readonly AnyMiddleware[]>\n | NestedRouteConfig<string, readonly AnyMiddleware[]>;\n\n/** 处理后的扁平路由 */\nexport interface ProcessedRoute {\n method: HTTPMethod;\n path: string;\n name?: string;\n description?: string;\n schema?: RouteSchema;\n /** 是否为 SSE 端点 */\n sse?: boolean;\n handler: (req: Request) => Promise<Response>;\n middleware?: readonly AnyMiddleware[];\n docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n /** 允许任意扩展(兼容 Route 类型) */\n [key: string]: unknown;\n}\n\n/** Route 类型别名(便于用户使用) */\nexport type Route = ProcessedRoute;\n\n// ============= defineMiddleware =============\n\n/**\n * 定义带类型的中间件(函数式风格)\n *\n * 通过 next() 参数传递上下文,更符合函数式编程风格\n *\n * @example\n * ```typescript\n * type AuthContext = { user: { id: string; name: string } }\n *\n * const authMiddleware = defineMiddleware<AuthContext>((req, next) => {\n * const user = getUserFromToken(req)\n * return next({ user }) // 通过 next 传递上下文\n * })\n * ```\n */\nexport function defineMiddleware<TContext extends object = object>(\n handler: (\n req: Request,\n next: (ctx?: TContext) => Promise<Response>\n ) => Promise<Response>\n): TypedMiddleware<TContext> {\n // 包装成标准中间件签名\n const middleware = ((req: Request, originalNext: () => Promise<Response>) => {\n // 包装 next,接收上下文参数并存储到 req.__locals\n const nextWithContext = (ctx?: TContext): Promise<Response> => {\n if (ctx) {\n const target = req as unknown as { __locals?: object };\n target.__locals = { ...(target.__locals || {}), ...ctx };\n }\n return originalNext();\n };\n return handler(req, nextWithContext);\n }) as TypedMiddleware<TContext>;\n\n return middleware;\n}\n\n// ============= 响应处理 =============\n\n/** 自动转换返回值为 Response */\nfunction autoResponse(result: unknown): Response {\n if (result instanceof Response) return result;\n if (result === null || result === undefined) return new Response(null, { status: 204 });\n if (typeof result === \"string\") {\n return new Response(result, { headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } });\n }\n if (typeof result === \"number\" || typeof result === \"boolean\") {\n return new Response(String(result), { headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } });\n }\n if (typeof result === \"object\") {\n const obj = result as Record<string, unknown>;\n if (\"data\" in obj && (\"status\" in obj || \"headers\" in obj)) {\n const { data, status = 200, headers = {} } = obj;\n if (data === null || data === undefined) {\n return new Response(null, { status: status === 200 ? 204 : (status as number), headers: headers as HeadersInit });\n }\n return json(data, status as number, headers as Record<string, string>);\n }\n return json(result);\n }\n return new Response(null, { status: 204 });\n}\n\n/**\n * 构建 HandlerContext(公共逻辑,供普通 handler 和 SSE handler 复用)\n */\nasync function buildHandlerContext<TSchema extends RouteSchema>(\n req: Request,\n schema: TSchema | undefined\n): Promise<HandlerContext<TSchema>> {\n const query = parseQuery(req);\n const headers = parseHeaders(req);\n const cookies = parseCookies(req);\n const params = ((req as unknown as Record<string, unknown>).params as Record<string, string>) || {};\n\n let body: unknown = undefined;\n if (req.method !== \"GET\" && req.method !== \"HEAD\") {\n try {\n body = await parseBody(req);\n } catch {\n // 忽略解析错误\n }\n }\n\n const data = { body, query, params, headers, cookies };\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n validateAllSchemas(schema, data);\n }\n\n // 获取中间件注入的上下文\n const extraCtx = (req as unknown as { __locals?: unknown }).__locals || {};\n\n return {\n req,\n body: body as HandlerContext<TSchema>[\"body\"],\n query: query as HandlerContext<TSchema>[\"query\"],\n params: params as HandlerContext<TSchema>[\"params\"],\n headers: headers as HandlerContext<TSchema>[\"headers\"],\n cookies: cookies as HandlerContext<TSchema>[\"cookies\"],\n ...extraCtx,\n } as HandlerContext<TSchema>;\n}\n\n/** 创建包装后的 handler(普通路由) */\nfunction wrapHandler<TSchema extends RouteSchema>(\n schema: TSchema | undefined,\n userHandler: (ctx: HandlerContext<TSchema>) => unknown | Promise<unknown>\n): (req: Request) => Promise<Response> {\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n precompileSchemas(schema);\n }\n\n return async (req: Request): Promise<Response> => {\n try {\n const ctx = await buildHandlerContext(req, schema);\n const result = await userHandler(ctx);\n return autoResponse(result);\n } catch (error) {\n // 如果是 VafastError,重新抛出让错误处理中间件处理\n if (error instanceof VafastError) {\n throw error;\n }\n if (error instanceof Error && error.message.includes(\"验证失败\")) {\n return json({ code: 400, message: error.message }, 400);\n }\n return json({ code: 500, message: error instanceof Error ? error.message : \"未知错误\" }, 500);\n }\n };\n}\n\n/**\n * SSE Handler 函数类型\n * \n * SSE handler 与普通 handler 使用统一的上下文模型,接收完整的 HandlerContext。\n * 框架自动完成:body 解析、schema 验证、中间件上下文注入。\n * SSE handler 只需关注流式响应逻辑,返回 SSE Stream Response。\n */\ntype SSEHandlerFn<TSchema extends RouteSchema = RouteSchema> = \n (ctx: HandlerContext<TSchema>) => Promise<Response>;\n\n/**\n * 格式化 SSE 事件为字符串(内联,避免循环依赖)\n */\nfunction formatSSEEvent(event: SSEEventType): string {\n const lines: string[] = [];\n if (event.id !== undefined) lines.push(`id: ${event.id}`);\n if (event.event !== undefined) lines.push(`event: ${event.event}`);\n if (event.retry !== undefined) lines.push(`retry: ${event.retry}`);\n \n const dataStr = typeof event.data === 'string' ? event.data : JSON.stringify(event.data);\n for (const line of dataStr.split('\\n')) {\n lines.push(`data: ${line}`);\n }\n return lines.join('\\n') + '\\n\\n';\n}\n\n/**\n * 将 AsyncGenerator 包装为 SSE Handler\n * \n * 支持用户直接写 `async function* (ctx) { yield ... }` 而无需 createSSEHandler\n */\nfunction wrapGeneratorToSSEHandler<TSchema extends RouteSchema>(\n generator: (ctx: HandlerContext<TSchema>) => AsyncGenerator<SSEEventType<unknown>, void, unknown>\n): SSEHandlerFn<TSchema> {\n return async (ctx: HandlerContext<TSchema>): Promise<Response> => {\n const stream = new ReadableStream({\n async start(controller) {\n const encoder = new TextEncoder();\n try {\n for await (const event of generator(ctx)) {\n controller.enqueue(encoder.encode(formatSSEEvent(event)));\n }\n } catch (error) {\n const errorEvent = formatSSEEvent({\n event: 'error',\n data: { error: error instanceof Error ? error.message : '未知错误' }\n });\n controller.enqueue(encoder.encode(errorEvent));\n } finally {\n controller.close();\n }\n }\n });\n\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'X-Accel-Buffering': 'no',\n }\n });\n };\n}\n\n/**\n * 创建 SSE handler 的请求包装器\n * \n * SSE handler 与普通 handler 使用相同的上下文构建流程(buildHandlerContext),\n * 确保:\n * - body/query/params 解析一致\n * - schema 验证统一\n * - 中间件注入的上下文(如 userInfo)自动可用\n * - 错误处理统一\n * \n * 唯一区别:SSE handler 返回的是 SSE Stream Response,而非普通 JSON Response\n */\nfunction wrapSSEHandler<TSchema extends RouteSchema>(\n schema: TSchema | undefined,\n sseHandler: SSEHandlerFn<TSchema>\n): (req: Request) => Promise<Response> {\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n precompileSchemas(schema);\n }\n\n return async (req: Request): Promise<Response> => {\n try {\n // 与普通 handler 使用相同的上下文构建逻辑\n const ctx = await buildHandlerContext(req, schema);\n // SSE handler 返回 SSE Stream Response\n return await sseHandler(ctx);\n } catch (error) {\n // 如果是 VafastError,重新抛出让错误处理中间件处理\n if (error instanceof VafastError) {\n throw error;\n }\n if (error instanceof Error && error.message.includes(\"验证失败\")) {\n return json({ code: 400, message: error.message }, 400);\n }\n return json({ code: 500, message: error instanceof Error ? error.message : \"未知错误\" }, 500);\n }\n };\n}\n\n// ============= 判断路由类型 =============\n\n/** 判断是否为叶子路由 */\nfunction isLeafRoute(route: RouteConfigResult): route is LeafRouteConfig {\n return \"method\" in route && \"handler\" in route;\n}\n\n/** 判断是否为嵌套路由 */\nfunction isNestedRoute(route: RouteConfigResult): route is NestedRouteConfig {\n return \"children\" in route;\n}\n\n// ============= defineRoute 函数(支持重载) =============\n\n/**\n * 定义叶子路由(有 method 和 handler),支持中间件类型推断和显式上下文类型\n *\n * @example\n * ```typescript\n * // 方式1:通过中间件自动推断上下文\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * middleware: [authMiddleware],\n * handler: ({ user }) => { ... } // user 来自 authMiddleware\n * })\n *\n * // 方式2:显式声明上下文类型(用于父级中间件注入的场景)\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * context: {} as { userInfo: UserInfo },\n * handler: ({ userInfo }) => { ... } // userInfo 有类型\n * })\n * ```\n */\nexport function defineRoute<\n const TSchema extends RouteSchema,\n TReturn,\n const TMiddleware extends readonly AnyMiddleware[],\n TContext extends object = object,\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string\n>(config: {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** 是否为 SSE 端点,设置为 true 时 handler 应返回 AsyncGenerator */\n readonly sse?: boolean;\n /** 显式声明上下文类型(用于父级中间件注入的场景) */\n readonly context?: TContext;\n readonly handler: (\n ctx: HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>\n ) => TReturn | Promise<TReturn> | AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}): LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware>;\n\n/**\n * 定义嵌套路由(有 children),支持中间件类型推断\n */\nexport function defineRoute<\n const TMiddleware extends readonly AnyMiddleware[],\n TPath extends string = string\n>(config: {\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly middleware?: TMiddleware;\n readonly children: ReadonlyArray<RouteConfigResult>;\n}): NestedRouteConfig<TPath, TMiddleware>;\n\n/**\n * defineRoute 实现\n */\nexport function defineRoute(config: {\n readonly method?: HTTPMethod;\n readonly path: string;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: RouteSchema;\n readonly sse?: boolean;\n readonly context?: object;\n readonly handler?: (ctx: HandlerContext<RouteSchema>) => unknown | Promise<unknown> | AsyncGenerator<unknown, void, unknown>;\n readonly middleware?: readonly AnyMiddleware[];\n readonly children?: ReadonlyArray<RouteConfigResult>;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}): RouteConfigResult {\n return config as RouteConfigResult;\n}\n\n// ============= withContext 工厂函数 =============\n\n/**\n * 创建带预设上下文类型的路由定义器\n *\n * 用于父级中间件注入上下文的场景,定义一次,多处复用\n *\n * @example\n * ```typescript\n * // 1. 在 middleware/index.ts 中定义\n * export const defineAuthRoute = withContext<{ userInfo: UserInfo }>()\n *\n * // 2. 在路由文件中使用\n * defineAuthRoute({\n * method: 'GET',\n * path: '/profile',\n * handler: ({ userInfo }) => {\n * // userInfo 自动有类型!\n * return { id: userInfo.id }\n * }\n * })\n * ```\n */\n/**\n * 带扩展类型的路由定义器\n *\n * @typeParam TContext - Handler 上下文类型(如 { userInfo: UserInfo })\n * @typeParam TExtensions - 路由扩展字段类型(如 { webhook?: boolean })\n *\n * @example\n * ```typescript\n * // 定义扩展类型\n * interface WebhookExtension {\n * webhook?: boolean | { eventKey?: string }\n * }\n *\n * // 使用扩展\n * const defineRoute = withContext<MyContext, WebhookExtension>()\n * defineRoute({\n * method: 'POST',\n * path: '/create',\n * webhook: true, // TypeScript 严格检查\n * handler: ...\n * })\n * ```\n */\n/** withContext Handler 上下文类型 */\ntype WithContextHandlerCtx<TSchema extends RouteSchema, TContext extends object, TMiddleware extends readonly AnyMiddleware[]> =\n HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>;\n\n/** withContext 支持的 Handler 类型(普通函数 + SSE Generator) */\ntype WithContextHandler<TSchema extends RouteSchema, TContext extends object, TMiddleware extends readonly AnyMiddleware[], TReturn> =\n | ((ctx: WithContextHandlerCtx<TSchema, TContext, TMiddleware>) => TReturn | Promise<TReturn>)\n | ((ctx: WithContextHandlerCtx<TSchema, TContext, TMiddleware>) => AsyncGenerator<SSEEventType<unknown>, void, unknown>);\n\nexport function withContext<\n TContext extends object,\n TExtensions extends object = object\n>() {\n return <\n const TSchema extends RouteSchema,\n TReturn,\n const TMiddleware extends readonly AnyMiddleware[],\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string\n >(config: {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** \n * 是否为 SSE 端点\n * 设置为 true 时,handler 应返回 AsyncGenerator\n */\n readonly sse?: boolean;\n /** Handler 支持两种写法:普通函数 或 SSE Generator(需配合 sse: true) */\n readonly handler: WithContextHandler<TSchema, TContext, TMiddleware, TReturn>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n } & TExtensions): LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware> => {\n return config as unknown as LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware>;\n };\n}\n\n// ============= 扁平化嵌套路由 =============\n\n/** 父级路由信息 */\ninterface ParentRouteInfo {\n /** 父级路由路径 */\n path: string;\n /** 父级路由名称 */\n name?: string;\n /** 父级路由描述 */\n description?: string;\n}\n\n/**\n * 递归扁平化路由,合并路径和中间件\n */\nfunction flattenRoutes(\n routes: ReadonlyArray<RouteConfigResult>,\n parentPath: string = \"\",\n parentMiddleware: readonly AnyMiddleware[] = [],\n parent?: ParentRouteInfo\n): ProcessedRoute[] {\n const result: ProcessedRoute[] = [];\n\n for (const route of routes) {\n const fullPath = parentPath + route.path;\n const mergedMiddleware = [...parentMiddleware, ...(route.middleware || [])];\n\n if (isLeafRoute(route)) {\n // SSE 检测:只通过显式 sse: true 声明\n const routeWithSSE = route as typeof route & { sse?: boolean };\n const isSSE = routeWithSSE.sse === true;\n \n // 基础属性\n const processed: ProcessedRoute = {\n method: route.method,\n path: fullPath,\n name: route.name,\n description: route.description,\n schema: route.schema,\n sse: isSSE || undefined, // SSE 标记\n handler: isSSE \n ? wrapSSEHandler(route.schema, wrapGeneratorToSSEHandler(route.handler as (ctx: HandlerContext<RouteSchema>) => AsyncGenerator<SSEEventType<unknown>, void, unknown>))\n : wrapHandler(route.schema, route.handler as (ctx: HandlerContext<RouteSchema>) => unknown),\n middleware: mergedMiddleware.length > 0 ? mergedMiddleware : undefined,\n docs: route.docs,\n };\n \n // 添加父级路由信息\n if (parent) {\n processed.parent = parent;\n }\n // 复制扩展属性(如 webhook, permission 等)\n const knownKeys = ['method', 'path', 'name', 'description', 'schema', 'handler', 'middleware', 'docs'];\n for (const key of Object.keys(route)) {\n if (!knownKeys.includes(key)) {\n processed[key] = (route as unknown as Record<string, unknown>)[key];\n }\n }\n result.push(processed);\n } else if (isNestedRoute(route)) {\n // 传递当前路由信息作为子路由的 parent\n const currentParent: ParentRouteInfo = {\n path: fullPath,\n name: route.name,\n description: route.description,\n };\n result.push(...flattenRoutes(route.children, fullPath, mergedMiddleware, currentParent));\n }\n }\n\n return result;\n}\n\n// ============= defineRoutes 函数 =============\n\n/** 带原始类型信息的路由数组 */\nexport type RoutesWithSource<T extends readonly RouteConfigResult[]> = ProcessedRoute[] & { __source: T };\n\n/**\n * 定义路由数组,支持嵌套路由\n *\n * 使用 `const T` 泛型自动保留字面量类型,无需手动添加 `as const`\n *\n * @example\n * ```typescript\n * const routes = defineRoutes([\n * defineRoute({ method: 'GET', path: '/users', handler: ... }),\n * defineRoute({ method: 'POST', path: '/users', handler: ... }),\n * ])\n *\n * // 类型推断自动工作,无需 as const\n * type Api = InferEden<typeof routes>\n * ```\n */\nexport function defineRoutes<const T extends readonly RouteConfigResult[]>(\n routes: T\n): RoutesWithSource<T> {\n const processed = flattenRoutes(routes);\n // 附加原始类型信息(仅用于类型推断,运行时不使用)\n return Object.assign(processed, { __source: routes }) as RoutesWithSource<T>;\n}\n\n// ============= 用于 API Client 的类型推断 =============\n\n/** 可推断的路由类型(供 vafast-api-client 使用) */\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 name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n readonly handler: {\n __returnType: TReturn;\n __schema: TSchema;\n };\n readonly middleware?: ReadonlyArray<AnyMiddleware>;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"defineRoute.mjs","names":[],"sources":["../src/defineRoute.ts"],"sourcesContent":["/**\n * 路由定义 - Schema 在路由级别定义,支持嵌套路由和中间件类型推断\n *\n * @example\n * ```typescript\n * // 定义带类型的中间件(函数式风格,通过 next 传递上下文)\n * const authMiddleware = defineMiddleware<{ user: User }>((req, next) => {\n * const user = getUser(req)\n * return next({ user }) // 通过 next 参数传递上下文\n * })\n *\n * // 路由自动推断中间件注入的类型\n * const routes = defineRoutes([\n * defineRoute({\n * path: '/api',\n * middleware: [authMiddleware],\n * children: [\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * handler: ({ user }) => ({ name: user.name }) // ✅ user 有类型\n * })\n * ]\n * })\n * ])\n * ```\n */\n\nimport type { TSchema, Static } from \"@sinclair/typebox\";\nimport { parseBody, parseQuery, parseHeaders, parseCookies } from \"./utils/parsers\";\nimport { validateAllSchemas, precompileSchemas } from \"./utils/validators/validators\";\nimport { json } from \"./utils/response\";\nimport { VafastError } from \"./middleware\";\n\n// ============= SSE 事件类型(内联定义,避免循环依赖) =============\n\n/** SSE 事件 */\nexport interface SSEEventType<T = unknown> {\n event?: string;\n data: T;\n id?: string;\n retry?: number;\n}\n\n/** SSE Generator 类型 */\nexport type SSEGeneratorType<TSchema extends RouteSchema = RouteSchema> = (\n ctx: HandlerContext<TSchema>\n) => AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n\n// ============= Schema 类型 =============\n\n/** 路由 Schema 配置 */\nexport interface RouteSchema {\n body?: TSchema;\n query?: TSchema;\n params?: TSchema;\n headers?: TSchema;\n cookies?: TSchema;\n /** 响应类型 schema(用于类型同步,运行时不做校验) */\n response?: TSchema;\n}\n\n/** 从 Schema 推断类型 */\ntype InferSchemaType<T extends RouteSchema> = {\n body: T[\"body\"] extends TSchema ? Static<T[\"body\"]> : unknown;\n query: T[\"query\"] extends TSchema ? Static<T[\"query\"]> : Record<string, string>;\n params: T[\"params\"] extends TSchema ? Static<T[\"params\"]> : Record<string, string>;\n headers: T[\"headers\"] extends TSchema ? Static<T[\"headers\"]> : Record<string, string>;\n cookies: T[\"cookies\"] extends TSchema ? Static<T[\"cookies\"]> : Record<string, string>;\n};\n\n// ============= 中间件类型系统 =============\n\n/** 带类型标记的中间件 */\nexport interface TypedMiddleware<TContext extends object = object> {\n (req: Request, next: (ctx?: TContext) => Promise<Response>): Response | Promise<Response>;\n /** 类型标记(仅编译时使用) */\n __context?: TContext;\n}\n\n/** 普通中间件(无类型注入) */\ntype PlainMiddleware = (req: Request, next: () => Promise<Response>) => Response | Promise<Response>;\n\n/** 任意中间件类型 */\ntype AnyMiddleware = TypedMiddleware<object> | PlainMiddleware;\n\n/** 从中间件提取上下文类型 */\ntype ExtractMiddlewareContext<T> = T extends TypedMiddleware<infer C> ? C : object;\n\n/** 合并中间件数组的上下文类型 */\ntype MergeMiddlewareContexts<T extends readonly unknown[]> =\n T extends readonly [infer First, ...infer Rest]\n ? ExtractMiddlewareContext<First> & MergeMiddlewareContexts<Rest>\n : object;\n\n// ============= Handler 上下文 =============\n\n/** Handler 上下文(包含 schema 推断) */\nexport interface HandlerContext<TSchema extends RouteSchema = RouteSchema> {\n req: Request;\n body: InferSchemaType<TSchema>[\"body\"];\n query: InferSchemaType<TSchema>[\"query\"];\n params: InferSchemaType<TSchema>[\"params\"];\n headers: InferSchemaType<TSchema>[\"headers\"];\n cookies: InferSchemaType<TSchema>[\"cookies\"];\n}\n\n/** Handler 上下文(带中间件注入的额外类型) */\ntype HandlerContextWithExtra<TSchema extends RouteSchema, TExtra> =\n HandlerContext<TSchema> & TExtra;\n\n// ============= 路由配置类型 =============\n\n/** HTTP 方法 */\ntype HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"OPTIONS\" | \"HEAD\";\n\n/** Handler 上下文类型(带中间件扩展) */\ntype HandlerCtx<TSchema extends RouteSchema, TMiddleware extends readonly AnyMiddleware[]> =\n HandlerContextWithExtra<TSchema, MergeMiddlewareContexts<TMiddleware>>;\n\n/** 普通 Handler 类型 */\ntype NormalHandler<TSchema extends RouteSchema, TReturn, TMiddleware extends readonly AnyMiddleware[]> = (\n ctx: HandlerCtx<TSchema, TMiddleware>\n) => TReturn | Promise<TReturn>;\n\n/** SSE Generator Handler 类型(直接写 async function*,无需 createSSEHandler 包装) */\ntype SSEHandler<TSchema extends RouteSchema, TMiddleware extends readonly AnyMiddleware[]> = (\n ctx: HandlerCtx<TSchema, TMiddleware>\n) => AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n\n/** 叶子路由配置(有 method 和 handler) */\nexport interface LeafRouteConfig<\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string,\n TSchema extends RouteSchema = RouteSchema,\n TReturn = unknown,\n TMiddleware extends readonly AnyMiddleware[] = readonly AnyMiddleware[]\n> {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** \n * 是否为 SSE 端点(显式声明,推荐)\n * \n * 设置为 true 时,handler 应返回 AsyncGenerator:\n * ```typescript\n * sse: true,\n * handler: async function* (ctx) { yield { data: ... } }\n * ```\n */\n readonly sse?: boolean;\n /** \n * Handler 支持两种写法:\n * 1. 普通函数: `async (ctx) => { return result }`\n * 2. SSE Generator(需配合 sse: true): `async function* (ctx) { yield { data: ... } }`\n */\n readonly handler: NormalHandler<TSchema, TReturn, TMiddleware> | SSEHandler<TSchema, TMiddleware>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}\n\n/** 嵌套路由配置(有 children,无 method 和 handler) */\nexport interface NestedRouteConfig<\n TPath extends string = string,\n TMiddleware extends readonly AnyMiddleware[] = readonly AnyMiddleware[]\n> {\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly middleware?: TMiddleware;\n readonly children: ReadonlyArray<RouteConfigResult>;\n}\n\n/** defineRoute 返回的类型 */\ntype RouteConfigResult =\n | LeafRouteConfig<HTTPMethod, string, RouteSchema, unknown, readonly AnyMiddleware[]>\n | NestedRouteConfig<string, readonly AnyMiddleware[]>;\n\n/** 处理后的扁平路由 */\nexport interface ProcessedRoute {\n method: HTTPMethod;\n path: string;\n name?: string;\n description?: string;\n schema?: RouteSchema;\n /** 是否为 SSE 端点 */\n sse?: boolean;\n handler: (req: Request) => Promise<Response>;\n middleware?: readonly AnyMiddleware[];\n docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n /** 允许任意扩展(兼容 Route 类型) */\n [key: string]: unknown;\n}\n\n/** Route 类型别名(便于用户使用) */\nexport type Route = ProcessedRoute;\n\n// ============= defineMiddleware =============\n\n/**\n * 定义带类型的中间件(函数式风格)\n *\n * 通过 next() 参数传递上下文,更符合函数式编程风格\n *\n * @example\n * ```typescript\n * type AuthContext = { user: { id: string; name: string } }\n *\n * const authMiddleware = defineMiddleware<AuthContext>((req, next) => {\n * const user = getUserFromToken(req)\n * return next({ user }) // 通过 next 传递上下文\n * })\n * ```\n */\nexport function defineMiddleware<TContext extends object = object>(\n handler: (\n req: Request,\n next: (ctx?: TContext) => Promise<Response>\n ) => Promise<Response>\n): TypedMiddleware<TContext> {\n // 包装成标准中间件签名\n const middleware = ((req: Request, originalNext: () => Promise<Response>) => {\n // 包装 next,接收上下文参数并存储到 req.__locals\n const nextWithContext = (ctx?: TContext): Promise<Response> => {\n if (ctx) {\n const target = req as unknown as { __locals?: object };\n target.__locals = { ...(target.__locals || {}), ...ctx };\n }\n return originalNext();\n };\n return handler(req, nextWithContext);\n }) as TypedMiddleware<TContext>;\n\n return middleware;\n}\n\n// ============= 响应处理 =============\n\n/** 自动转换返回值为 Response */\nfunction autoResponse(result: unknown): Response {\n if (result instanceof Response) return result;\n if (result === null || result === undefined) return new Response(null, { status: 204 });\n if (typeof result === \"string\") {\n return new Response(result, { headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } });\n }\n if (typeof result === \"number\" || typeof result === \"boolean\") {\n return new Response(String(result), { headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } });\n }\n if (typeof result === \"object\") {\n const obj = result as Record<string, unknown>;\n if (\"data\" in obj && (\"status\" in obj || \"headers\" in obj)) {\n const { data, status = 200, headers = {} } = obj;\n if (data === null || data === undefined) {\n return new Response(null, { status: status === 200 ? 204 : (status as number), headers: headers as HeadersInit });\n }\n return json(data, status as number, headers as Record<string, string>);\n }\n return json(result);\n }\n return new Response(null, { status: 204 });\n}\n\n/**\n * 构建 HandlerContext(公共逻辑,供普通 handler 和 SSE handler 复用)\n */\nasync function buildHandlerContext<TSchema extends RouteSchema>(\n req: Request,\n schema: TSchema | undefined\n): Promise<HandlerContext<TSchema>> {\n const query = parseQuery(req);\n const headers = parseHeaders(req);\n const cookies = parseCookies(req);\n const params = ((req as unknown as Record<string, unknown>).params as Record<string, string>) || {};\n\n let body: unknown = undefined;\n if (req.method !== \"GET\" && req.method !== \"HEAD\") {\n try {\n body = await parseBody(req);\n } catch {\n // 忽略解析错误\n }\n }\n\n const data = { body, query, params, headers, cookies };\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n validateAllSchemas(schema, data);\n }\n\n // 获取中间件注入的上下文\n const extraCtx = (req as unknown as { __locals?: unknown }).__locals || {};\n\n return {\n req,\n body: body as HandlerContext<TSchema>[\"body\"],\n query: query as HandlerContext<TSchema>[\"query\"],\n params: params as HandlerContext<TSchema>[\"params\"],\n headers: headers as HandlerContext<TSchema>[\"headers\"],\n cookies: cookies as HandlerContext<TSchema>[\"cookies\"],\n ...extraCtx,\n } as HandlerContext<TSchema>;\n}\n\n/** 创建包装后的 handler(普通路由) */\nfunction wrapHandler<TSchema extends RouteSchema>(\n schema: TSchema | undefined,\n userHandler: (ctx: HandlerContext<TSchema>) => unknown | Promise<unknown>\n): (req: Request) => Promise<Response> {\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n precompileSchemas(schema);\n }\n\n return async (req: Request): Promise<Response> => {\n try {\n const ctx = await buildHandlerContext(req, schema);\n const result = await userHandler(ctx);\n return autoResponse(result);\n } catch (error) {\n // 如果是 VafastError,重新抛出让错误处理中间件处理\n if (error instanceof VafastError) {\n throw error;\n }\n if (error instanceof Error && error.message.includes(\"验证失败\")) {\n return json({ code: 400, message: error.message }, 400);\n }\n return json({ code: 500, message: error instanceof Error ? error.message : \"未知错误\" }, 500);\n }\n };\n}\n\n/**\n * SSE Handler 函数类型\n * \n * SSE handler 与普通 handler 使用统一的上下文模型,接收完整的 HandlerContext。\n * 框架自动完成:body 解析、schema 验证、中间件上下文注入。\n * SSE handler 只需关注流式响应逻辑,返回 SSE Stream Response。\n */\ntype SSEHandlerFn<TSchema extends RouteSchema = RouteSchema> = \n (ctx: HandlerContext<TSchema>) => Promise<Response>;\n\n/**\n * SSE 元数据接口(用于高级场景)\n */\nexport interface SSEMeta {\n /** SSE 事件名称 */\n event?: string;\n /** SSE 事件 ID */\n id?: string;\n /** SSE 重试间隔(毫秒) */\n retry?: number;\n}\n\n/**\n * 带元数据的 SSE 事件(高级用法)\n */\nexport interface SSEEventWithMeta<T = unknown> {\n /** SSE 元数据标记 */\n __sse__: SSEMeta;\n /** 事件数据 */\n data: T;\n}\n\n/**\n * 创建带元数据的 SSE 事件\n * \n * @example\n * // 设置事件名称\n * yield sse({ event: 'status' }, { ready: true })\n * \n * // 设置 ID(支持断线重连)\n * yield sse({ event: 'update', id: '42' }, { value: 1 })\n * \n * // 设置重试间隔\n * yield sse({ retry: 5000 }, 'reconnect hint')\n */\nexport function sse<T>(meta: SSEMeta, data: T): SSEEventWithMeta<T> {\n return { __sse__: meta, data };\n}\n\n/**\n * 检查是否是带元数据的 SSE 事件\n */\nfunction isSSEEventWithMeta(event: unknown): event is SSEEventWithMeta {\n return (\n event !== null &&\n typeof event === 'object' &&\n '__sse__' in event &&\n 'data' in event\n );\n}\n\n/**\n * 格式化 SSE 事件为字符串\n * \n * 支持两种用法:\n * 1. 简单模式(推荐):yield anyData → 自动包装为 data\n * 2. 高级模式:yield { __sse__: { event, id, retry }, data } → 完整 SSE 控制\n */\nfunction formatSSEEvent(event: unknown): string {\n const lines: string[] = [];\n let data: unknown;\n\n if (isSSEEventWithMeta(event)) {\n // 高级模式:用户提供了 SSE 元数据\n const meta = event.__sse__;\n if (meta.id !== undefined) lines.push(`id: ${meta.id}`);\n if (meta.event !== undefined) lines.push(`event: ${meta.event}`);\n if (meta.retry !== undefined) lines.push(`retry: ${meta.retry}`);\n data = event.data;\n } else {\n // 简单模式:直接把 event 作为 data\n data = event;\n }\n \n const dataStr = typeof data === 'string' ? data : JSON.stringify(data);\n for (const line of dataStr.split('\\n')) {\n lines.push(`data: ${line}`);\n }\n return lines.join('\\n') + '\\n\\n';\n}\n\n/**\n * 将 AsyncGenerator 包装为 SSE Handler\n * \n * 支持用户直接写 `async function* (ctx) { yield anyData }` \n * 数据会自动包装为 SSE data 字段发送\n */\nfunction wrapGeneratorToSSEHandler<TSchema extends RouteSchema>(\n generator: (ctx: HandlerContext<TSchema>) => AsyncGenerator<unknown, void, unknown>\n): SSEHandlerFn<TSchema> {\n return async (ctx: HandlerContext<TSchema>): Promise<Response> => {\n const stream = new ReadableStream({\n async start(controller) {\n const encoder = new TextEncoder();\n try {\n for await (const event of generator(ctx)) {\n controller.enqueue(encoder.encode(formatSSEEvent(event)));\n }\n } catch (error) {\n // 使用高级模式发送错误事件\n const errorEvent = formatSSEEvent({\n __sse__: { event: 'error' },\n data: { error: error instanceof Error ? error.message : '未知错误' }\n });\n controller.enqueue(encoder.encode(errorEvent));\n } finally {\n controller.close();\n }\n }\n });\n\n return new Response(stream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'X-Accel-Buffering': 'no',\n }\n });\n };\n}\n\n/**\n * 创建 SSE handler 的请求包装器\n * \n * SSE handler 与普通 handler 使用相同的上下文构建流程(buildHandlerContext),\n * 确保:\n * - body/query/params 解析一致\n * - schema 验证统一\n * - 中间件注入的上下文(如 userInfo)自动可用\n * - 错误处理统一\n * \n * 唯一区别:SSE handler 返回的是 SSE Stream Response,而非普通 JSON Response\n */\nfunction wrapSSEHandler<TSchema extends RouteSchema>(\n schema: TSchema | undefined,\n sseHandler: SSEHandlerFn<TSchema>\n): (req: Request) => Promise<Response> {\n if (schema && (schema.body || schema.query || schema.params || schema.headers || schema.cookies)) {\n precompileSchemas(schema);\n }\n\n return async (req: Request): Promise<Response> => {\n try {\n // 与普通 handler 使用相同的上下文构建逻辑\n const ctx = await buildHandlerContext(req, schema);\n // SSE handler 返回 SSE Stream Response\n return await sseHandler(ctx);\n } catch (error) {\n // 如果是 VafastError,重新抛出让错误处理中间件处理\n if (error instanceof VafastError) {\n throw error;\n }\n if (error instanceof Error && error.message.includes(\"验证失败\")) {\n return json({ code: 400, message: error.message }, 400);\n }\n return json({ code: 500, message: error instanceof Error ? error.message : \"未知错误\" }, 500);\n }\n };\n}\n\n// ============= 判断路由类型 =============\n\n/** 判断是否为叶子路由 */\nfunction isLeafRoute(route: RouteConfigResult): route is LeafRouteConfig {\n return \"method\" in route && \"handler\" in route;\n}\n\n/** 判断是否为嵌套路由 */\nfunction isNestedRoute(route: RouteConfigResult): route is NestedRouteConfig {\n return \"children\" in route;\n}\n\n// ============= defineRoute 函数(支持重载) =============\n\n/**\n * 定义叶子路由(有 method 和 handler),支持中间件类型推断和显式上下文类型\n *\n * @example\n * ```typescript\n * // 方式1:通过中间件自动推断上下文\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * middleware: [authMiddleware],\n * handler: ({ user }) => { ... } // user 来自 authMiddleware\n * })\n *\n * // 方式2:显式声明上下文类型(用于父级中间件注入的场景)\n * defineRoute({\n * method: 'GET',\n * path: '/profile',\n * context: {} as { userInfo: UserInfo },\n * handler: ({ userInfo }) => { ... } // userInfo 有类型\n * })\n * ```\n */\nexport function defineRoute<\n const TSchema extends RouteSchema,\n TReturn,\n const TMiddleware extends readonly AnyMiddleware[],\n TContext extends object = object,\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string\n>(config: {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** 是否为 SSE 端点,设置为 true 时 handler 应返回 AsyncGenerator */\n readonly sse?: boolean;\n /** 显式声明上下文类型(用于父级中间件注入的场景) */\n readonly context?: TContext;\n readonly handler: (\n ctx: HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>\n ) => TReturn | Promise<TReturn> | AsyncGenerator<SSEEventType<unknown>, void, unknown>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}): LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware>;\n\n/**\n * 定义嵌套路由(有 children),支持中间件类型推断\n */\nexport function defineRoute<\n const TMiddleware extends readonly AnyMiddleware[],\n TPath extends string = string\n>(config: {\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly middleware?: TMiddleware;\n readonly children: ReadonlyArray<RouteConfigResult>;\n}): NestedRouteConfig<TPath, TMiddleware>;\n\n/**\n * defineRoute 实现\n */\nexport function defineRoute(config: {\n readonly method?: HTTPMethod;\n readonly path: string;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: RouteSchema;\n readonly sse?: boolean;\n readonly context?: object;\n readonly handler?: (ctx: HandlerContext<RouteSchema>) => unknown | Promise<unknown> | AsyncGenerator<unknown, void, unknown>;\n readonly middleware?: readonly AnyMiddleware[];\n readonly children?: ReadonlyArray<RouteConfigResult>;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n}): RouteConfigResult {\n return config as RouteConfigResult;\n}\n\n// ============= withContext 工厂函数 =============\n\n/**\n * 创建带预设上下文类型的路由定义器\n *\n * 用于父级中间件注入上下文的场景,定义一次,多处复用\n *\n * @example\n * ```typescript\n * // 1. 在 middleware/index.ts 中定义\n * export const defineAuthRoute = withContext<{ userInfo: UserInfo }>()\n *\n * // 2. 在路由文件中使用\n * defineAuthRoute({\n * method: 'GET',\n * path: '/profile',\n * handler: ({ userInfo }) => {\n * // userInfo 自动有类型!\n * return { id: userInfo.id }\n * }\n * })\n * ```\n */\n/**\n * 带扩展类型的路由定义器\n *\n * @typeParam TContext - Handler 上下文类型(如 { userInfo: UserInfo })\n * @typeParam TExtensions - 路由扩展字段类型(如 { webhook?: boolean })\n *\n * @example\n * ```typescript\n * // 定义扩展类型\n * interface WebhookExtension {\n * webhook?: boolean | { eventKey?: string }\n * }\n *\n * // 使用扩展\n * const defineRoute = withContext<MyContext, WebhookExtension>()\n * defineRoute({\n * method: 'POST',\n * path: '/create',\n * webhook: true, // TypeScript 严格检查\n * handler: ...\n * })\n * ```\n */\n/** withContext Handler 上下文类型 */\ntype WithContextHandlerCtx<TSchema extends RouteSchema, TContext extends object, TMiddleware extends readonly AnyMiddleware[]> =\n HandlerContextWithExtra<TSchema, TContext & MergeMiddlewareContexts<TMiddleware>>;\n\n/** withContext 支持的 Handler 类型(普通函数 + SSE Generator) */\ntype WithContextHandler<TSchema extends RouteSchema, TContext extends object, TMiddleware extends readonly AnyMiddleware[], TReturn> =\n | ((ctx: WithContextHandlerCtx<TSchema, TContext, TMiddleware>) => TReturn | Promise<TReturn>)\n | ((ctx: WithContextHandlerCtx<TSchema, TContext, TMiddleware>) => AsyncGenerator<SSEEventType<unknown>, void, unknown>);\n\nexport function withContext<\n TContext extends object,\n TExtensions extends object = object\n>() {\n return <\n const TSchema extends RouteSchema,\n TReturn,\n const TMiddleware extends readonly AnyMiddleware[],\n TMethod extends HTTPMethod = HTTPMethod,\n TPath extends string = string\n >(config: {\n readonly method: TMethod;\n readonly path: TPath;\n readonly name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n /** \n * 是否为 SSE 端点\n * 设置为 true 时,handler 应返回 AsyncGenerator\n */\n readonly sse?: boolean;\n /** Handler 支持两种写法:普通函数 或 SSE Generator(需配合 sse: true) */\n readonly handler: WithContextHandler<TSchema, TContext, TMiddleware, TReturn>;\n readonly middleware?: TMiddleware;\n readonly docs?: {\n tags?: string[];\n security?: unknown[];\n responses?: Record<string, unknown>;\n };\n } & TExtensions): LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware> => {\n return config as unknown as LeafRouteConfig<TMethod, TPath, TSchema, TReturn, TMiddleware>;\n };\n}\n\n// ============= 扁平化嵌套路由 =============\n\n/** 父级路由信息 */\ninterface ParentRouteInfo {\n /** 父级路由路径 */\n path: string;\n /** 父级路由名称 */\n name?: string;\n /** 父级路由描述 */\n description?: string;\n}\n\n/**\n * 递归扁平化路由,合并路径和中间件\n */\nfunction flattenRoutes(\n routes: ReadonlyArray<RouteConfigResult>,\n parentPath: string = \"\",\n parentMiddleware: readonly AnyMiddleware[] = [],\n parent?: ParentRouteInfo\n): ProcessedRoute[] {\n const result: ProcessedRoute[] = [];\n\n for (const route of routes) {\n const fullPath = parentPath + route.path;\n const mergedMiddleware = [...parentMiddleware, ...(route.middleware || [])];\n\n if (isLeafRoute(route)) {\n // SSE 检测:只通过显式 sse: true 声明\n const routeWithSSE = route as typeof route & { sse?: boolean };\n const isSSE = routeWithSSE.sse === true;\n \n // 基础属性\n const processed: ProcessedRoute = {\n method: route.method,\n path: fullPath,\n name: route.name,\n description: route.description,\n schema: route.schema,\n sse: isSSE || undefined, // SSE 标记\n handler: isSSE \n ? wrapSSEHandler(route.schema, wrapGeneratorToSSEHandler(route.handler as (ctx: HandlerContext<RouteSchema>) => AsyncGenerator<SSEEventType<unknown>, void, unknown>))\n : wrapHandler(route.schema, route.handler as (ctx: HandlerContext<RouteSchema>) => unknown),\n middleware: mergedMiddleware.length > 0 ? mergedMiddleware : undefined,\n docs: route.docs,\n };\n \n // 添加父级路由信息\n if (parent) {\n processed.parent = parent;\n }\n // 复制扩展属性(如 webhook, permission 等)\n const knownKeys = ['method', 'path', 'name', 'description', 'schema', 'handler', 'middleware', 'docs'];\n for (const key of Object.keys(route)) {\n if (!knownKeys.includes(key)) {\n processed[key] = (route as unknown as Record<string, unknown>)[key];\n }\n }\n result.push(processed);\n } else if (isNestedRoute(route)) {\n // 传递当前路由信息作为子路由的 parent\n const currentParent: ParentRouteInfo = {\n path: fullPath,\n name: route.name,\n description: route.description,\n };\n result.push(...flattenRoutes(route.children, fullPath, mergedMiddleware, currentParent));\n }\n }\n\n return result;\n}\n\n// ============= defineRoutes 函数 =============\n\n/** 带原始类型信息的路由数组 */\nexport type RoutesWithSource<T extends readonly RouteConfigResult[]> = ProcessedRoute[] & { __source: T };\n\n/**\n * 定义路由数组,支持嵌套路由\n *\n * 使用 `const T` 泛型自动保留字面量类型,无需手动添加 `as const`\n *\n * @example\n * ```typescript\n * const routes = defineRoutes([\n * defineRoute({ method: 'GET', path: '/users', handler: ... }),\n * defineRoute({ method: 'POST', path: '/users', handler: ... }),\n * ])\n *\n * // 类型推断自动工作,无需 as const\n * type Api = InferEden<typeof routes>\n * ```\n */\nexport function defineRoutes<const T extends readonly RouteConfigResult[]>(\n routes: T\n): RoutesWithSource<T> {\n const processed = flattenRoutes(routes);\n // 附加原始类型信息(仅用于类型推断,运行时不使用)\n return Object.assign(processed, { __source: routes }) as RoutesWithSource<T>;\n}\n\n// ============= 用于 API Client 的类型推断 =============\n\n/** 可推断的路由类型(供 vafast-api-client 使用) */\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 name?: string;\n readonly description?: string;\n readonly schema?: TSchema;\n readonly handler: {\n __returnType: TReturn;\n __schema: TSchema;\n };\n readonly middleware?: ReadonlyArray<AnyMiddleware>;\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as ProcessedRoute } from "./defineRoute-
|
|
1
|
+
import { a as ProcessedRoute } from "./defineRoute-DKVyYELW.mjs";
|
|
2
2
|
import { r as NestedComponentRoute, t as ComponentRoute } from "./component-route-CGbmQm5P.mjs";
|
|
3
|
-
import { t as Server } from "./server-
|
|
3
|
+
import { t as Server } from "./server-D3IERUlj.mjs";
|
|
4
4
|
import { t as ComponentServer } from "./component-server-CKcXIvMg.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-
|
|
48
|
+
//# sourceMappingURL=index-BPXVOE-X.d.mts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { a as ProcessedRoute, c as RoutesWithSource, d as
|
|
1
|
+
import { _ as sse, a as ProcessedRoute, c as RoutesWithSource, d as SSEGeneratorType, f as SSEMeta, g as defineRoutes, h as defineRoute, i as NestedRouteConfig, l as SSEEventType, m as defineMiddleware, n as InferableRoute, o as Route, p as TypedMiddleware, r as LeafRouteConfig, s as RouteSchema, t as HandlerContext, u as SSEEventWithMeta, v as withContext } from "./defineRoute-DKVyYELW.mjs";
|
|
2
2
|
import { a as VafastRequest, i as ResponseBody, n as Method, r as Middleware, t as Handler } from "./types-aczawQFE.mjs";
|
|
3
3
|
import { n as FlattenedComponentRoute, r as NestedComponentRoute, t as ComponentRoute } from "./component-route-CGbmQm5P.mjs";
|
|
4
4
|
import { t as BaseServer } from "./base-server-CeJ8LTBk.mjs";
|
|
5
|
-
import { t as Server } from "./server-
|
|
5
|
+
import { t as Server } from "./server-D3IERUlj.mjs";
|
|
6
6
|
import { t as DependencyManager } from "./dependency-manager-mqzLAocb.mjs";
|
|
7
7
|
import { t as ComponentServer } from "./component-server-CKcXIvMg.mjs";
|
|
8
|
-
import { t as ServerFactory } from "./index-
|
|
8
|
+
import { t as ServerFactory } from "./index-BPXVOE-X.mjs";
|
|
9
9
|
import { a as isVafastError, i as errorHandler, n as VafastError, r as composeMiddleware, t as VAFAST_ERROR_SYMBOL } from "./middleware-BTg4GbjC.mjs";
|
|
10
10
|
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-BAQtDA1q.mjs";
|
|
11
11
|
import { c as text, i as json, n as err, o as redirect, r as html, s as stream, t as empty } from "./response-lI0YZoia.mjs";
|
|
@@ -14,12 +14,12 @@ import { n as base64urlEncode, t as base64urlDecode } from "./base64url-CAmasWF0
|
|
|
14
14
|
import { t as HtmlRenderer } from "./html-renderer-Up52eIS6.mjs";
|
|
15
15
|
import { a as ValidationError, c as getValidatorCacheStats, d as validateFast, f as validateSchema, l as precompileSchemas, o as ValidationResult, p as validateSchemaOrThrow, s as createValidator, t as SchemaConfig, u as validateAllSchemas } from "./validators-D5KJCSZr.mjs";
|
|
16
16
|
import { i as registerFormats, n as hasFormat, r as registerFormat, t as Patterns } from "./formats-Ca7ASaYH.mjs";
|
|
17
|
-
import { t as SSEEvent } from "./sse-
|
|
18
|
-
import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "./route-registry-
|
|
17
|
+
import { t as SSEEvent } from "./sse-BqvrwmK6.mjs";
|
|
18
|
+
import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "./route-registry-C2a27CuM.mjs";
|
|
19
19
|
import { n as generateAITools, r as getApiSpec, t as ApiSpec } from "./contract-C-xQoZ6r.mjs";
|
|
20
20
|
import "./utils/index.mjs";
|
|
21
21
|
import { normalizePath } from "./router.mjs";
|
|
22
22
|
import { a as ServeResult, c as serve, i as ServeOptions, n as GracefulShutdownOptions, o as TrustProxyOption, r as RequestTimeoutOptions, t as FetchHandler } from "./serve-Dw-GHkc3.mjs";
|
|
23
23
|
import "./serve.mjs";
|
|
24
24
|
import { FormatRegistry, Type } from "@sinclair/typebox";
|
|
25
|
-
export { ApiSpec, BaseServer, ComponentRoute, ComponentServer, DependencyManager, type FetchHandler, FlattenedComponentRoute, FormatRegistry, type GracefulShutdownOptions, Handler, HandlerContext, HtmlRenderer, InferableRoute, LeafRouteConfig, Method, Middleware, NestedComponentRoute, NestedRouteConfig, Patterns, ProcessedRoute, type RequestTimeoutOptions, ResponseBody, Route, RouteMeta, RouteRegistry, RouteSchema, RoutesWithSource, SSEEvent, SSEEventType, SSEGeneratorType, SchemaConfig, type ServeOptions, type ServeResult, Server, ServerFactory, type TrustProxyOption, Type, TypedMiddleware, VAFAST_ERROR_SYMBOL, VafastError, VafastRequest, ValidationError, ValidationResult, base64urlDecode, base64urlEncode, composeMiddleware, createRouteRegistry, createValidator, defineMiddleware, defineRoute, defineRoutes, empty, err, errorHandler, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, isVafastError, json, normalizePath, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, serve, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow, withContext };
|
|
25
|
+
export { ApiSpec, BaseServer, ComponentRoute, ComponentServer, DependencyManager, type FetchHandler, FlattenedComponentRoute, FormatRegistry, type GracefulShutdownOptions, Handler, HandlerContext, HtmlRenderer, InferableRoute, LeafRouteConfig, Method, Middleware, NestedComponentRoute, NestedRouteConfig, Patterns, ProcessedRoute, type RequestTimeoutOptions, ResponseBody, Route, RouteMeta, RouteRegistry, RouteSchema, RoutesWithSource, SSEEvent, SSEEventType, SSEEventWithMeta, SSEGeneratorType, SSEMeta, SchemaConfig, type ServeOptions, type ServeResult, Server, ServerFactory, type TrustProxyOption, Type, TypedMiddleware, VAFAST_ERROR_SYMBOL, VafastError, VafastRequest, ValidationError, ValidationResult, base64urlDecode, base64urlEncode, composeMiddleware, createRouteRegistry, createValidator, defineMiddleware, defineRoute, defineRoutes, empty, err, errorHandler, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, isVafastError, json, normalizePath, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, serve, sse, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow, withContext };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
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-BrG_mRLq.mjs";
|
|
2
2
|
import { a as validateAllSchemas, c as validateSchemaOrThrow, i as precompileSchemas, n as createValidator, o as validateFast, r as getValidatorCacheStats, s as validateSchema } from "./validators-CkfvNBbK.mjs";
|
|
3
3
|
import { c as text, d as composeMiddleware, f as errorHandler, i as json, l as VAFAST_ERROR_SYMBOL, n as err, o as redirect, p as isVafastError, r as html, s as stream, t as empty, u as VafastError } from "./response-Bs9GhJz-.mjs";
|
|
4
|
-
import { defineMiddleware, defineRoute, defineRoutes, withContext } from "./defineRoute.mjs";
|
|
4
|
+
import { defineMiddleware, defineRoute, defineRoutes, sse, withContext } from "./defineRoute.mjs";
|
|
5
5
|
import { t as BaseServer } from "./base-server-CE0mfqPY.mjs";
|
|
6
6
|
import { a as getRoute, i as getAllRoutes, n as createRouteRegistry, o as getRouteRegistry, r as filterRoutes, s as getRoutesByMethod, t as RouteRegistry } from "./route-registry-DsPslV2b.mjs";
|
|
7
7
|
import { t as Server } from "./server-B4YDcNJy.mjs";
|
|
@@ -25,5 +25,5 @@ import { FormatRegistry, Type } from "@sinclair/typebox";
|
|
|
25
25
|
registerFormats();
|
|
26
26
|
|
|
27
27
|
//#endregion
|
|
28
|
-
export { BaseServer, ComponentServer, DependencyManager, FormatRegistry, HtmlRenderer, Patterns, RouteRegistry, Server, ServerFactory, Type, VAFAST_ERROR_SYMBOL, VafastError, base64urlDecode, base64urlEncode, composeMiddleware, createRouteRegistry, createValidator, defineMiddleware, defineRoute, defineRoutes, empty, err, errorHandler, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, isVafastError, json, normalizePath, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, serve, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow, withContext };
|
|
28
|
+
export { BaseServer, ComponentServer, DependencyManager, FormatRegistry, HtmlRenderer, Patterns, RouteRegistry, Server, ServerFactory, Type, VAFAST_ERROR_SYMBOL, VafastError, base64urlDecode, base64urlEncode, composeMiddleware, createRouteRegistry, createValidator, defineMiddleware, defineRoute, defineRoutes, empty, err, errorHandler, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, isVafastError, json, normalizePath, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, serve, sse, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow, withContext };
|
|
29
29
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "../defineRoute-
|
|
2
|
-
import "../server-
|
|
3
|
-
import "../index-
|
|
1
|
+
import "../defineRoute-DKVyYELW.mjs";
|
|
2
|
+
import "../server-D3IERUlj.mjs";
|
|
3
|
+
import "../index-BPXVOE-X.mjs";
|
|
4
4
|
import { MemoryInfo, MonitoredServer, MonitoringConfig, MonitoringMetrics, MonitoringStatus, PathStats, StatusCodeDistribution, TimeWindowStats, createMonitoredServer, withMonitoring } from "./native-monitor.mjs";
|
|
5
5
|
export { type MemoryInfo, type MonitoredServer, type MonitoringConfig, type MonitoringMetrics, type MonitoringStatus, type PathStats, type StatusCodeDistribution, type TimeWindowStats, createMonitoredServer, withMonitoring };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import "../defineRoute-
|
|
2
|
-
import { t as Server } from "../server-
|
|
3
|
-
import "../index-
|
|
1
|
+
import "../defineRoute-DKVyYELW.mjs";
|
|
2
|
+
import { t as Server } from "../server-D3IERUlj.mjs";
|
|
3
|
+
import "../index-BPXVOE-X.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/monitoring/native-monitor.d.ts
|
|
6
6
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ProcessedRoute, s as RouteSchema } from "./defineRoute-
|
|
1
|
+
import { a as ProcessedRoute, s as RouteSchema } from "./defineRoute-DKVyYELW.mjs";
|
|
2
2
|
import { n as Method } from "./types-aczawQFE.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/utils/route-registry.d.ts
|
|
@@ -187,4 +187,4 @@ declare function filterRoutes<K extends string>(field: K): (RouteMeta & Record<K
|
|
|
187
187
|
declare function getRoutesByMethod(method: string): RouteMeta[];
|
|
188
188
|
//#endregion
|
|
189
189
|
export { getAllRoutes as a, getRoutesByMethod as c, filterRoutes as i, setGlobalRegistry as l, RouteRegistry as n, getRoute as o, createRouteRegistry as r, getRouteRegistry as s, RouteMeta as t };
|
|
190
|
-
//# sourceMappingURL=route-registry-
|
|
190
|
+
//# sourceMappingURL=route-registry-C2a27CuM.d.mts.map
|
package/dist/server/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import "../defineRoute-
|
|
1
|
+
import "../defineRoute-DKVyYELW.mjs";
|
|
2
2
|
import { t as BaseServer } from "../base-server-CeJ8LTBk.mjs";
|
|
3
|
-
import { t as Server } from "../server-
|
|
3
|
+
import { t as Server } from "../server-D3IERUlj.mjs";
|
|
4
4
|
import { t as ComponentServer } from "../component-server-CKcXIvMg.mjs";
|
|
5
|
-
import { t as ServerFactory } from "../index-
|
|
5
|
+
import { t as ServerFactory } from "../index-BPXVOE-X.mjs";
|
|
6
6
|
export { BaseServer, ComponentServer, Server, ServerFactory };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "../defineRoute-
|
|
2
|
-
import "../server-
|
|
3
|
-
import { t as ServerFactory } from "../index-
|
|
1
|
+
import "../defineRoute-DKVyYELW.mjs";
|
|
2
|
+
import "../server-D3IERUlj.mjs";
|
|
3
|
+
import { t as ServerFactory } from "../index-BPXVOE-X.mjs";
|
|
4
4
|
export { ServerFactory };
|
package/dist/server/server.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "../defineRoute-
|
|
2
|
-
import { t as Server } from "../server-
|
|
1
|
+
import "../defineRoute-DKVyYELW.mjs";
|
|
2
|
+
import { t as Server } from "../server-D3IERUlj.mjs";
|
|
3
3
|
export { Server };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ProcessedRoute } from "./defineRoute-
|
|
1
|
+
import { a as ProcessedRoute } from "./defineRoute-DKVyYELW.mjs";
|
|
2
2
|
import { n as Method } from "./types-aczawQFE.mjs";
|
|
3
3
|
import { t as BaseServer } from "./base-server-CeJ8LTBk.mjs";
|
|
4
4
|
|
|
@@ -45,4 +45,4 @@ declare class Server extends BaseServer {
|
|
|
45
45
|
}
|
|
46
46
|
//#endregion
|
|
47
47
|
export { Server as t };
|
|
48
|
-
//# sourceMappingURL=server-
|
|
48
|
+
//# sourceMappingURL=server-D3IERUlj.d.mts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//#region src/utils/sse.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Server-Sent Events (SSE) 类型定义
|
|
4
|
+
*
|
|
5
|
+
* SSE 端点通过 `sse: true` 显式声明,handler 使用 async generator 语法
|
|
6
|
+
*
|
|
7
|
+
* ## 简单模式(推荐)
|
|
8
|
+
*
|
|
9
|
+
* 直接 yield 任意数据,框架自动包装为 SSE data 字段:
|
|
10
|
+
*
|
|
11
|
+
* ```typescript
|
|
12
|
+
* defineRoute({
|
|
13
|
+
* method: 'POST',
|
|
14
|
+
* path: '/chat/stream',
|
|
15
|
+
* sse: true,
|
|
16
|
+
* handler: async function* ({ body }) {
|
|
17
|
+
* // 直接 yield 数据,框架自动处理
|
|
18
|
+
* yield { type: 'start', message: 'Starting...' }
|
|
19
|
+
*
|
|
20
|
+
* for await (const chunk of aiStream(body.prompt)) {
|
|
21
|
+
* yield chunk // 任意对象都可以
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* yield { type: 'done', message: 'Complete!' }
|
|
25
|
+
* }
|
|
26
|
+
* })
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* ## 高级模式
|
|
30
|
+
*
|
|
31
|
+
* 如果需要设置 SSE event/id/retry,使用 `__sse__` 标记:
|
|
32
|
+
*
|
|
33
|
+
* ```typescript
|
|
34
|
+
* yield {
|
|
35
|
+
* __sse__: { event: 'status', id: '123', retry: 5000 },
|
|
36
|
+
* data: { progress: 50 }
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* SSE 元数据(高级模式)
|
|
42
|
+
*/
|
|
43
|
+
interface SSEMeta {
|
|
44
|
+
/** SSE 事件名称 */
|
|
45
|
+
event?: string;
|
|
46
|
+
/** SSE 事件 ID */
|
|
47
|
+
id?: string;
|
|
48
|
+
/** SSE 重试间隔(毫秒) */
|
|
49
|
+
retry?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 带元数据的 SSE 事件(高级模式)
|
|
53
|
+
*/
|
|
54
|
+
interface SSEEventWithMeta<T = unknown> {
|
|
55
|
+
/** SSE 元数据标记 */
|
|
56
|
+
__sse__: SSEMeta;
|
|
57
|
+
/** 事件数据 */
|
|
58
|
+
data: T;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* SSE 事件类型(兼容旧版,不推荐使用)
|
|
62
|
+
* @deprecated 直接 yield 数据即可,无需包装
|
|
63
|
+
*/
|
|
64
|
+
interface SSEEvent<T = unknown> {
|
|
65
|
+
/** 事件名称(可选,默认为 message) */
|
|
66
|
+
event?: string;
|
|
67
|
+
/** 事件数据 */
|
|
68
|
+
data: T;
|
|
69
|
+
/** 事件 ID(可选) */
|
|
70
|
+
id?: string;
|
|
71
|
+
/** 重试间隔(毫秒,可选) */
|
|
72
|
+
retry?: number;
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
export { SSEEventWithMeta as n, SSEMeta as r, SSEEvent as t };
|
|
76
|
+
//# sourceMappingURL=sse-BqvrwmK6.d.mts.map
|
package/dist/utils/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "../defineRoute-
|
|
1
|
+
import "../defineRoute-DKVyYELW.mjs";
|
|
2
2
|
import { t as DependencyManager } from "../dependency-manager-mqzLAocb.mjs";
|
|
3
3
|
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-BAQtDA1q.mjs";
|
|
4
4
|
import { c as text, i as json, n as err, o as redirect, r as html, s as stream, t as empty } from "../response-lI0YZoia.mjs";
|
|
@@ -7,7 +7,7 @@ import { n as base64urlEncode, t as base64urlDecode } from "../base64url-CAmasWF
|
|
|
7
7
|
import { t as HtmlRenderer } from "../html-renderer-Up52eIS6.mjs";
|
|
8
8
|
import { a as ValidationError, c as getValidatorCacheStats, d as validateFast, f as validateSchema, l as precompileSchemas, o as ValidationResult, p as validateSchemaOrThrow, s as createValidator, t as SchemaConfig, u as validateAllSchemas } from "../validators-D5KJCSZr.mjs";
|
|
9
9
|
import { i as registerFormats, n as hasFormat, r as registerFormat, t as Patterns } from "../formats-Ca7ASaYH.mjs";
|
|
10
|
-
import { t as SSEEvent } from "../sse-
|
|
11
|
-
import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "../route-registry-
|
|
10
|
+
import { t as SSEEvent } from "../sse-BqvrwmK6.mjs";
|
|
11
|
+
import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "../route-registry-C2a27CuM.mjs";
|
|
12
12
|
import { n as generateAITools, r as getApiSpec, t as ApiSpec } from "../contract-C-xQoZ6r.mjs";
|
|
13
13
|
export { type ApiSpec, DependencyManager, HtmlRenderer, Patterns, type RouteMeta, RouteRegistry, type SSEEvent, type SchemaConfig, type ValidationError, type ValidationResult, base64urlDecode, base64urlEncode, createRouteRegistry, createValidator, empty, err, filterRoutes, generateAITools, getAllRoutes, getApiSpec, getCookie, getHeader, getRoute, getRouteRegistry, getRoutesByMethod, getValidatorCacheStats, goAwait, hasFormat, html, json, parseBody, parseCookies, parseCookiesFast, parseHeaders, parseQuery, parseQueryFast, precompileSchemas, redirect, registerFormat, registerFormats, stream, text, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "../defineRoute-
|
|
2
|
-
import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, l as setGlobalRegistry, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "../route-registry-
|
|
1
|
+
import "../defineRoute-DKVyYELW.mjs";
|
|
2
|
+
import { a as getAllRoutes, c as getRoutesByMethod, i as filterRoutes, l as setGlobalRegistry, n as RouteRegistry, o as getRoute, r as createRouteRegistry, s as getRouteRegistry, t as RouteMeta } from "../route-registry-C2a27CuM.mjs";
|
|
3
3
|
export { RouteMeta, RouteRegistry, createRouteRegistry, filterRoutes, getAllRoutes, getRoute, getRouteRegistry, getRoutesByMethod, setGlobalRegistry };
|
package/dist/utils/sse.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as SSEEvent } from "../sse-
|
|
2
|
-
export { SSEEvent };
|
|
1
|
+
import { n as SSEEventWithMeta, r as SSEMeta, t as SSEEvent } from "../sse-BqvrwmK6.mjs";
|
|
2
|
+
export { SSEEvent, SSEEventWithMeta, SSEMeta };
|
package/package.json
CHANGED
package/dist/sse-D77CKcsH.d.mts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
//#region src/utils/sse.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Server-Sent Events (SSE) 类型定义
|
|
4
|
-
*
|
|
5
|
-
* SSE 端点通过 `sse: true` 显式声明,handler 使用 async generator 语法
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* import { defineRoute, Type } from 'vafast'
|
|
10
|
-
*
|
|
11
|
-
* defineRoute({
|
|
12
|
-
* method: 'POST',
|
|
13
|
-
* path: '/chat/stream',
|
|
14
|
-
* sse: true, // 显式声明 SSE 端点
|
|
15
|
-
* schema: {
|
|
16
|
-
* body: Type.Object({ prompt: Type.String() })
|
|
17
|
-
* },
|
|
18
|
-
* handler: async function* ({ body }) {
|
|
19
|
-
* yield { event: 'start', data: { message: 'Starting...' } }
|
|
20
|
-
*
|
|
21
|
-
* for await (const chunk of aiStream(body.prompt)) {
|
|
22
|
-
* yield { data: chunk }
|
|
23
|
-
* }
|
|
24
|
-
*
|
|
25
|
-
* yield { event: 'end', data: { message: 'Done!' } }
|
|
26
|
-
* }
|
|
27
|
-
* })
|
|
28
|
-
* ```
|
|
29
|
-
*/
|
|
30
|
-
/**
|
|
31
|
-
* SSE 事件类型
|
|
32
|
-
*/
|
|
33
|
-
interface SSEEvent<T = unknown> {
|
|
34
|
-
/** 事件名称(可选,默认为 message) */
|
|
35
|
-
event?: string;
|
|
36
|
-
/** 事件数据 */
|
|
37
|
-
data: T;
|
|
38
|
-
/** 事件 ID(可选) */
|
|
39
|
-
id?: string;
|
|
40
|
-
/** 重试间隔(毫秒,可选) */
|
|
41
|
-
retry?: number;
|
|
42
|
-
}
|
|
43
|
-
//#endregion
|
|
44
|
-
export { SSEEvent as t };
|
|
45
|
-
//# sourceMappingURL=sse-D77CKcsH.d.mts.map
|