@faapi/faapi 1.5.0 → 2.0.1-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +15 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +6 -694
- package/dist/index.js +1366 -1566
- package/dist/index.js.map +1 -1
- package/dist/routeTypes-FtbRkpVF.d.ts +491 -0
- package/dist/testing.d.ts +232 -0
- package/dist/testing.js +3578 -0
- package/dist/testing.js.map +1 -0
- package/package.json +5 -1
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE(Server-Sent Events)支持
|
|
3
|
+
*
|
|
4
|
+
* 让 handler 能向客户端推送流式事件,用于 LLM token 流、进度通知等场景。
|
|
5
|
+
*
|
|
6
|
+
* 核心导出:
|
|
7
|
+
* - `encodeSseEvent(event)`:把 SSE 事件对象编码为符合 HTML5 SSE 规范的字符串
|
|
8
|
+
* - `createSseWriter()`:创建一个 SseWriter,封装 ReadableStream + Response,提供 send/close/sendError API
|
|
9
|
+
* - `SseWriter`:writer 类型,ctx.sse() 返回此类型
|
|
10
|
+
*
|
|
11
|
+
* 设计要点:
|
|
12
|
+
* - writer 内部用 ReadableStream + TextEncoder,send 时 enqueue,close 时 close controller
|
|
13
|
+
* - response 预设 text/event-stream、no-cache、keep-alive 头,状态码默认 200
|
|
14
|
+
* - close 后再 send 静默忽略,避免 handler 异步流程中误写已关闭的流
|
|
15
|
+
* - sendError 向流写入 event: error 后关闭,用于流式输出中报错的优雅终止
|
|
16
|
+
*
|
|
17
|
+
* 与 ctx 的集成:
|
|
18
|
+
* - ctx.sse() 调用 createSseWriter(),并把 response 缓存到 ctx 内部字段
|
|
19
|
+
* - invokeHandler 在 handler 返回后检查 ctx 是否持有 SSE response,有则优先使用
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* SSE 事件字段
|
|
23
|
+
*
|
|
24
|
+
* 遵循 HTML5 SSE 规范:
|
|
25
|
+
* - `data`:消息数据,多行时每行加 `data: ` 前缀;对象自动 JSON.stringify
|
|
26
|
+
* - `event`:事件类型,客户端可用 addEventListener(event) 监听
|
|
27
|
+
* - `id`:事件 ID,客户端断线重连时通过 Last-Event-ID 头发送
|
|
28
|
+
* - `retry`:重连等待时间(毫秒)
|
|
29
|
+
* - `comment`:注释行(以 `:` 开头),用于 keep-alive 心跳,不传递给客户端消息
|
|
30
|
+
*/
|
|
31
|
+
interface SseEvent {
|
|
32
|
+
/** 消息数据。字符串原样输出;对象自动 JSON.stringify;多行时每行加 data: 前缀 */
|
|
33
|
+
data?: unknown;
|
|
34
|
+
/** 事件类型,客户端可用 addEventListener 监听 */
|
|
35
|
+
event?: string;
|
|
36
|
+
/** 事件 ID,客户端断线重连时通过 Last-Event-ID 头发送 */
|
|
37
|
+
id?: string | number;
|
|
38
|
+
/** 重连等待时间(毫秒) */
|
|
39
|
+
retry?: number;
|
|
40
|
+
/** 注释行(以 : 开头),用于 keep-alive 心跳 */
|
|
41
|
+
comment?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* SSE writer:封装流式推送 API
|
|
45
|
+
*
|
|
46
|
+
* 通过 `ctx.sse()` 创建,handler 调用 `send` 推送事件,`close` 关闭流。
|
|
47
|
+
* 框架在 handler 返回后,自动使用 writer.response 作为 HTTP 响应。
|
|
48
|
+
*/
|
|
49
|
+
interface SseWriter {
|
|
50
|
+
/** 推送一个 SSE 事件 */
|
|
51
|
+
send(event: SseEvent): void;
|
|
52
|
+
/**
|
|
53
|
+
* 直接写入原始字节/字符串,不做任何 SSE 序列化
|
|
54
|
+
*
|
|
55
|
+
* 用于透传上游已有的 SSE 原文(如 LLM 中转平台逐 chunk 转发 OpenAI 响应)。
|
|
56
|
+
* 调用方负责保证内容符合 HTML5 SSE 规范;`send` 会再次加 `data: ` 前缀,
|
|
57
|
+
* 不适用于原文透传场景。
|
|
58
|
+
*
|
|
59
|
+
* 接受 string 或 Uint8Array(Buffer 是 Uint8Array 子类,自然兼容)。
|
|
60
|
+
* 与 `send` 一致:close/aborted 后静默忽略,不抛错。
|
|
61
|
+
*/
|
|
62
|
+
sendRaw(chunk: string | Uint8Array): void;
|
|
63
|
+
/** 推送一个 error 事件并关闭流(用于流式输出中报错的优雅终止) */
|
|
64
|
+
sendError(error: unknown): void;
|
|
65
|
+
/** 关闭流(多次调用安全) */
|
|
66
|
+
close(): void;
|
|
67
|
+
/** 流是否已关闭(handler 主动 close 或框架自动 close) */
|
|
68
|
+
readonly closed: boolean;
|
|
69
|
+
/** 客户端是否已断开(ReadableStream 被 cancel) */
|
|
70
|
+
readonly aborted: boolean;
|
|
71
|
+
/** 对应的 HTTP Response(由框架使用,用户一般不需要直接访问) */
|
|
72
|
+
readonly response: Response;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface CookieOptions {
|
|
76
|
+
domain?: string;
|
|
77
|
+
path?: string;
|
|
78
|
+
maxAge?: number;
|
|
79
|
+
expires?: Date;
|
|
80
|
+
httpOnly?: boolean;
|
|
81
|
+
secure?: boolean;
|
|
82
|
+
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* ctx.fail() 的参数类型(对象形式,status 和 code 均可省略)
|
|
86
|
+
*
|
|
87
|
+
* - status: HTTP 状态码(可选,省略时默认 500)
|
|
88
|
+
* - code: 业务错误码(可选,省略时响应 body 里不含 code 字段)
|
|
89
|
+
* - message: 人类可读错误描述(必填)
|
|
90
|
+
*
|
|
91
|
+
* status 和 code 是两个独立维度,无关联:
|
|
92
|
+
* - status 控制 HTTP 状态码
|
|
93
|
+
* - code 是 body 里的业务错误码字段
|
|
94
|
+
*
|
|
95
|
+
* ```ts
|
|
96
|
+
* ctx.fail({ message: '出错' }) // HTTP 500, { error: { message: '出错' } }
|
|
97
|
+
* ctx.fail({ status: 404, message: '用户不存在' }) // HTTP 404, { error: { message: '用户不存在' } }
|
|
98
|
+
* ctx.fail({ status: 404, code: 'USER_NOT_FOUND', message: '用户不存在' }) // HTTP 404, { error: { code: 'USER_NOT_FOUND', message: '用户不存在' } }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
interface FailOptions {
|
|
102
|
+
/** HTTP 状态码(可选,省略时默认 500) */
|
|
103
|
+
status?: number;
|
|
104
|
+
/** 业务错误码(可选,省略时响应 body 里不含 code 字段) */
|
|
105
|
+
code?: string;
|
|
106
|
+
/** 人类可读错误描述 */
|
|
107
|
+
message: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* ctx.config 的类型:用户自定义业务配置
|
|
111
|
+
*
|
|
112
|
+
* 默认是 Record<string, unknown>(宽松)。用户可通过 `declare module '@faapi/faapi'` 增强:
|
|
113
|
+
*
|
|
114
|
+
* ```ts
|
|
115
|
+
* declare module '@faapi/faapi' {
|
|
116
|
+
* interface FaapiContextConfig {
|
|
117
|
+
* db: { host: string; port: number };
|
|
118
|
+
* }
|
|
119
|
+
* }
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* 增强后 `ctx.config.db.host` 即有类型提示。
|
|
123
|
+
*/
|
|
124
|
+
interface FaapiContextConfig extends Record<string, unknown> {
|
|
125
|
+
}
|
|
126
|
+
interface FaapiContext {
|
|
127
|
+
request: Request;
|
|
128
|
+
params: Record<string, string>;
|
|
129
|
+
query: URLSearchParams;
|
|
130
|
+
headers: Headers;
|
|
131
|
+
method: string;
|
|
132
|
+
path: string;
|
|
133
|
+
/**
|
|
134
|
+
* 客户端 IP
|
|
135
|
+
*
|
|
136
|
+
* 优先 `x-forwarded-for` 第一个 IP(反向代理场景),回退到 socket.remoteAddress。
|
|
137
|
+
* IPv6 形式 `::ffff:1.2.3.4` 会被规整为 IPv4 形式 `1.2.3.4`。
|
|
138
|
+
* 无法获取时为空字符串。
|
|
139
|
+
*/
|
|
140
|
+
ip: string;
|
|
141
|
+
/**
|
|
142
|
+
* 客户端 User-Agent(请求头 `user-agent` 原值)
|
|
143
|
+
*
|
|
144
|
+
* 在 createContext 内部从 request.headers 读取(与 ip 不同,无需调用方传入)。
|
|
145
|
+
* 不做解析/规整,仅原样透传;无该请求头时为空字符串。
|
|
146
|
+
*/
|
|
147
|
+
ua: string;
|
|
148
|
+
/** 解析后的所有 cookie 键值对 */
|
|
149
|
+
cookies: Record<string, string>;
|
|
150
|
+
/** 配置文件中的自定义业务配置(类型可通过 declare module '@faapi/faapi' 增强 FaapiContextConfig) */
|
|
151
|
+
config: FaapiContextConfig;
|
|
152
|
+
/**
|
|
153
|
+
* 设置响应状态码
|
|
154
|
+
*/
|
|
155
|
+
setStatus(status: number): void;
|
|
156
|
+
/**
|
|
157
|
+
* 设置响应头
|
|
158
|
+
*/
|
|
159
|
+
setHeader(key: string, value: string): void;
|
|
160
|
+
/**
|
|
161
|
+
* 设置 ETag 响应头
|
|
162
|
+
*
|
|
163
|
+
* handler 中基于业务数据(如 updatedAt / version / contentHash)设置 ETag:
|
|
164
|
+
* ```ts
|
|
165
|
+
* export function GET(ctx) {
|
|
166
|
+
* const data = await fetchData();
|
|
167
|
+
* ctx.setETag(`"${data.version}-${data.updatedAt}"`);
|
|
168
|
+
* return data;
|
|
169
|
+
* }
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
setETag(value: string): void;
|
|
173
|
+
/**
|
|
174
|
+
* 返回 JSON 响应(handler 直接 return)
|
|
175
|
+
*
|
|
176
|
+
* ```ts
|
|
177
|
+
* return ctx.json({ error: 'Not found' }, 404);
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
json(data: unknown, status?: number): Response;
|
|
181
|
+
/**
|
|
182
|
+
* 返回 HTML 响应(handler 直接 return)
|
|
183
|
+
*
|
|
184
|
+
* ```ts
|
|
185
|
+
* return ctx.html('<h1>Hello</h1>');
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
html(html: string, status?: number): Response;
|
|
189
|
+
/**
|
|
190
|
+
* 返回重定向响应(handler 直接 return)
|
|
191
|
+
*
|
|
192
|
+
* ```ts
|
|
193
|
+
* return ctx.redirect('/login');
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
redirect(url: string, status?: number): Response;
|
|
197
|
+
/**
|
|
198
|
+
* 创建 SSE writer,用于流式推送事件(LLM token 流、进度通知等)
|
|
199
|
+
*
|
|
200
|
+
* handler 调用此方法后,通过返回的 writer 推送事件,框架自动把 writer.response
|
|
201
|
+
* 作为 HTTP 响应(Content-Type: text/event-stream)。与 ctx.json / ctx.html 互斥。
|
|
202
|
+
*
|
|
203
|
+
* ```ts
|
|
204
|
+
* export async function POST(ctx) {
|
|
205
|
+
* const sse = ctx.sse();
|
|
206
|
+
* for await (const chunk of stream) {
|
|
207
|
+
* sse.send({ data: chunk.text });
|
|
208
|
+
* }
|
|
209
|
+
* sse.close();
|
|
210
|
+
* }
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
sse(): SseWriter;
|
|
214
|
+
/**
|
|
215
|
+
* 显式包装成功响应(返回 Response 对象)
|
|
216
|
+
*
|
|
217
|
+
* 用 config.response.ok 包裹 data 并返回 Response。
|
|
218
|
+
* 等价于 handler 直接 `return data`(框架自动包裹),但显式调用语义更清晰。
|
|
219
|
+
*
|
|
220
|
+
* 返回 Response 对象,不会被框架自动包裹再次包装(避免双重包裹)。
|
|
221
|
+
*
|
|
222
|
+
* ```ts
|
|
223
|
+
* // 以下两种写法等价(假设配置了 response.ok = (data) => ({ data })):
|
|
224
|
+
* export function GET() {
|
|
225
|
+
* return { id: 1 }; // 自动包裹 → { data: { id: 1 } }
|
|
226
|
+
* }
|
|
227
|
+
* export function GET2(ctx) {
|
|
228
|
+
* return ctx.ok({ id: 1 }); // 显式包裹 → { data: { id: 1 } }
|
|
229
|
+
* }
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
ok(data: unknown): Response;
|
|
233
|
+
/**
|
|
234
|
+
* 返回错误响应(对象形式参数,status 和 code 均可省略)
|
|
235
|
+
*
|
|
236
|
+
* @param options.status HTTP 状态码(可选,省略时默认 500)
|
|
237
|
+
* @param options.code 业务错误码(可选,省略时响应 body 里不含 code 字段)
|
|
238
|
+
* @param options.message 人类可读错误描述(必填)
|
|
239
|
+
*
|
|
240
|
+
* status 和 code 独立无关联:status 控制 HTTP 状态码,code 是 body 里的业务错误码字段。
|
|
241
|
+
*
|
|
242
|
+
* ```ts
|
|
243
|
+
* return ctx.fail({ message: '出错' }); // HTTP 500, { error: { message: '出错' } }
|
|
244
|
+
* return ctx.fail({ status: 404, message: '用户不存在' }); // HTTP 404, { error: { message: '用户不存在' } }
|
|
245
|
+
* return ctx.fail({ status: 404, code: 'USER_NOT_FOUND', message: '用户不存在' }); // HTTP 404, { error: { code: 'USER_NOT_FOUND', message: '用户不存在' } }
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
fail(options: FailOptions): Response;
|
|
249
|
+
/**
|
|
250
|
+
* 读取 cookie 值
|
|
251
|
+
*/
|
|
252
|
+
getCookie(name: string): string | undefined;
|
|
253
|
+
/**
|
|
254
|
+
* 设置 cookie
|
|
255
|
+
*/
|
|
256
|
+
setCookie(name: string, value: string, options?: CookieOptions): void;
|
|
257
|
+
/**
|
|
258
|
+
* 删除 cookie(设置过期)
|
|
259
|
+
*/
|
|
260
|
+
deleteCookie(name: string): void;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* faapi 中间件(洋葱模型)
|
|
265
|
+
*
|
|
266
|
+
* 单一 async 函数,通过 `await next()` 衔接前置/后置逻辑:
|
|
267
|
+
* - `await next()` 之前的代码:前置处理(鉴权、日志开始计时等)
|
|
268
|
+
* - `await next()` 之后的代码:后置处理(日志输出、响应修改等)
|
|
269
|
+
* - 不调用 `next()` 即拦截请求(如鉴权失败直接返回 Response)
|
|
270
|
+
* - `next()` 返回内层 Response,中间件可选择使用或替换
|
|
271
|
+
* - 返回 `Response`:作为响应返回(可用于拦截或错误处理)
|
|
272
|
+
* - 返回 `void`:使用 `await next()` 返回的内层响应
|
|
273
|
+
*
|
|
274
|
+
* 错误处理用 try/catch 包裹 `await next()`,而非独立的 error 钩子。
|
|
275
|
+
*
|
|
276
|
+
* 执行顺序(洋葱模型):
|
|
277
|
+
* ```
|
|
278
|
+
* mw1.before → mw2.before → handler → mw2.after → mw1.after
|
|
279
|
+
* ```
|
|
280
|
+
*
|
|
281
|
+
* 示例 middlewares.ts:
|
|
282
|
+
* ```ts
|
|
283
|
+
* import type { FaapiMiddleware } from '@faapi/faapi';
|
|
284
|
+
*
|
|
285
|
+
* export default [
|
|
286
|
+
* // 鉴权:不调 next() 即拦截
|
|
287
|
+
* async (ctx, next) => {
|
|
288
|
+
* const token = ctx.headers.get('authorization');
|
|
289
|
+
* if (!token) return new Response('Unauthorized', { status: 401 });
|
|
290
|
+
* ctx.user = await verifyToken(token);
|
|
291
|
+
* await next();
|
|
292
|
+
* },
|
|
293
|
+
* // 日志:before/after 一体,闭包共享状态
|
|
294
|
+
* async (ctx, next) => {
|
|
295
|
+
* const start = Date.now();
|
|
296
|
+
* await next();
|
|
297
|
+
* console.log(`${ctx.method} ${ctx.path} ${Date.now() - start}ms`);
|
|
298
|
+
* },
|
|
299
|
+
* // 错误处理:try/catch 语义
|
|
300
|
+
* async (ctx, next) => {
|
|
301
|
+
* try {
|
|
302
|
+
* await next();
|
|
303
|
+
* } catch (err) {
|
|
304
|
+
* return new Response(JSON.stringify({ error: String(err) }), { status: 500 });
|
|
305
|
+
* }
|
|
306
|
+
* },
|
|
307
|
+
* ] satisfies FaapiMiddleware[];
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
type FaapiMiddleware = (ctx: FaapiContext, next: () => Promise<Response>) => Promise<void | Response>;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* 注入器:按参数名匹配,提供 handler 所需的依赖
|
|
314
|
+
*
|
|
315
|
+
* 注入器是 faapi 的依赖注入扩展点,与中间件解耦:
|
|
316
|
+
* - 中间件只管请求流程(鉴权、日志、错误处理)
|
|
317
|
+
* - 注入器只管提供依赖(数据库连接、用户对象等)
|
|
318
|
+
*
|
|
319
|
+
* 注入器可以读取中间件塞进 ctx 的值(如鉴权中间件塞的 ctx.user),
|
|
320
|
+
* 也可以独立提供依赖(如数据库连接池)。
|
|
321
|
+
*
|
|
322
|
+
* 注入器按需执行:只对 handler 声明的参数执行对应的注入器,避免无谓计算。
|
|
323
|
+
*
|
|
324
|
+
* 在 middlewares.ts 中通过命名导出 `injectors` 注册:
|
|
325
|
+
* ```ts
|
|
326
|
+
* import type { InjectorMap } from '@faapi/faapi';
|
|
327
|
+
*
|
|
328
|
+
* export const injectors: InjectorMap = {
|
|
329
|
+
* db: () => getDbConnection(),
|
|
330
|
+
* user: (ctx) => ctx.user, // 取中间件塞的值
|
|
331
|
+
* };
|
|
332
|
+
* ```
|
|
333
|
+
*/
|
|
334
|
+
type Injector = (ctx: FaapiContext) => unknown | Promise<unknown>;
|
|
335
|
+
/**
|
|
336
|
+
* 注入器映射表:参数名 → 注入器函数
|
|
337
|
+
*
|
|
338
|
+
* key 必须与 handler 参数名一致,运行时按参数名匹配执行。
|
|
339
|
+
*/
|
|
340
|
+
type InjectorMap = Record<string, Injector>;
|
|
341
|
+
|
|
342
|
+
interface CorsOptions {
|
|
343
|
+
origin?: string | string[] | true;
|
|
344
|
+
methods?: string[];
|
|
345
|
+
allowedHeaders?: string[];
|
|
346
|
+
exposeHeaders?: string[];
|
|
347
|
+
credentials?: boolean;
|
|
348
|
+
maxAge?: number;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* 创建 CORS 中间件(洋葱模型)
|
|
352
|
+
*
|
|
353
|
+
* - origin=true: 允许所有来源(反射请求的 Origin)
|
|
354
|
+
* - origin=string: 允许指定来源
|
|
355
|
+
* - origin=string[]: 允许多个来源
|
|
356
|
+
*
|
|
357
|
+
* OPTIONS 预检请求直接返回 204,不调用 next()。
|
|
358
|
+
*/
|
|
359
|
+
declare function cors(options?: CorsOptions): FaapiMiddleware;
|
|
360
|
+
|
|
361
|
+
type LoggerFn = (messageOrObj: string | Record<string, unknown>, message?: string) => void;
|
|
362
|
+
interface LoggerOptions {
|
|
363
|
+
/**
|
|
364
|
+
* 自定义日志函数
|
|
365
|
+
*
|
|
366
|
+
* - 传入 `console.log`(默认):纯文本格式 `GET /api/users 200 12ms`
|
|
367
|
+
* - 传入 pino logger:结构化日志 `logger.info({ method, path, status, durationMs }, 'request completed')`
|
|
368
|
+
* - 传入 winston logger:`logger.info('GET /api/users 200 12ms', { method, path })`
|
|
369
|
+
*/
|
|
370
|
+
log?: LoggerFn;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* 创建请求日志中间件(洋葱模型)
|
|
374
|
+
*
|
|
375
|
+
* 日志格式(文本模式):GET /api/users 200 12ms
|
|
376
|
+
* 错误格式(文本模式):POST /api/users 400 45ms - Error: ...
|
|
377
|
+
*
|
|
378
|
+
* 结构化模式:传入 pino/winston 等 logger 实例时,会自动传递结构化字段。
|
|
379
|
+
*
|
|
380
|
+
* before/after 一体,闭包变量共享开始时间,无需污染 ctx。
|
|
381
|
+
* 错误用 try/catch 捕获,记录后重新抛出(让上层处理)。
|
|
382
|
+
* 成功时从 next() 返回的 Response 读取状态码。
|
|
383
|
+
*
|
|
384
|
+
* log 函数每次请求时读取(options.log ?? console.log),运行时替换 console.log 会生效。
|
|
385
|
+
*/
|
|
386
|
+
declare function logger(options?: LoggerOptions): FaapiMiddleware;
|
|
387
|
+
|
|
388
|
+
interface HelmetOptions {
|
|
389
|
+
contentSecurityPolicy?: string | false;
|
|
390
|
+
xFrameOptions?: 'DENY' | 'SAMEORIGIN' | false;
|
|
391
|
+
xContentTypeOptions?: boolean;
|
|
392
|
+
referrerPolicy?: string | false;
|
|
393
|
+
strictTransportSecurity?: string | false;
|
|
394
|
+
xDnsPrefetchControl?: boolean;
|
|
395
|
+
xDownloadOptions?: boolean;
|
|
396
|
+
xPermittedCrossDomainPolicies?: string | false;
|
|
397
|
+
crossOriginOpenerPolicy?: string | false;
|
|
398
|
+
crossOriginResourcePolicy?: string | false;
|
|
399
|
+
crossOriginEmbedderPolicy?: string | false;
|
|
400
|
+
originAgentCluster?: boolean;
|
|
401
|
+
xPoweredBy?: boolean;
|
|
402
|
+
}
|
|
403
|
+
declare function helmet(options?: HelmetOptions): FaapiMiddleware;
|
|
404
|
+
|
|
405
|
+
declare const HTTP_METHODS: readonly ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
406
|
+
type HttpMethod = (typeof HTTP_METHODS)[number];
|
|
407
|
+
|
|
408
|
+
interface RouteRecord {
|
|
409
|
+
method: HttpMethod;
|
|
410
|
+
urlPath: string;
|
|
411
|
+
filePath: string;
|
|
412
|
+
paramNames: string[];
|
|
413
|
+
isDynamic: boolean;
|
|
414
|
+
/** 是否为 catch-all 路由([...slug]) */
|
|
415
|
+
isCatchAll?: boolean;
|
|
416
|
+
/** 中间件文件绝对路径列表(根在前,路由目录在后;按需加载用) */
|
|
417
|
+
middlewarePaths?: string[];
|
|
418
|
+
/** 路由对应的中间件集合(从根到路由目录合并,按需加载后缓存) */
|
|
419
|
+
middlewares?: FaapiMiddleware[];
|
|
420
|
+
/** 路由对应的注入器映射表(从根到路由目录合并,按需加载后缓存) */
|
|
421
|
+
injectors?: InjectorMap;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* WebSocket 路由记录
|
|
425
|
+
*
|
|
426
|
+
* 与 HTTP RouteRecord 类似,但不绑定 HTTP 方法(WS 是协议升级,不区分 GET/POST)。
|
|
427
|
+
* 一个 handler.ts 中导出 WS 即生成一条 WS 路由记录。
|
|
428
|
+
*/
|
|
429
|
+
interface WsRouteRecord {
|
|
430
|
+
urlPath: string;
|
|
431
|
+
filePath: string;
|
|
432
|
+
paramNames: string[];
|
|
433
|
+
isDynamic: boolean;
|
|
434
|
+
/** 是否为 catch-all 路由([...slug]) */
|
|
435
|
+
isCatchAll?: boolean;
|
|
436
|
+
/** 中间件文件绝对路径列表(根在前,路由目录在后;按需加载用) */
|
|
437
|
+
middlewarePaths?: string[];
|
|
438
|
+
/** 路由对应的中间件集合(握手阶段执行,复用鉴权/CORS/日志;按需加载后缓存) */
|
|
439
|
+
middlewares?: FaapiMiddleware[];
|
|
440
|
+
/** 路由对应的注入器映射表 */
|
|
441
|
+
injectors?: InjectorMap;
|
|
442
|
+
}
|
|
443
|
+
type RouteManifest = RouteRecord[];
|
|
444
|
+
type WsRouteManifest = WsRouteRecord[];
|
|
445
|
+
/**
|
|
446
|
+
* 路由单个参数的 schema 描述
|
|
447
|
+
*
|
|
448
|
+
* 供 @faapi/schema 扩展包消费,通过 MCP 暴露给 LLM。
|
|
449
|
+
*/
|
|
450
|
+
interface RouteParamSchema {
|
|
451
|
+
name: string;
|
|
452
|
+
type: string;
|
|
453
|
+
required: boolean;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* 路由单个输入源的 schema 描述
|
|
457
|
+
*/
|
|
458
|
+
interface RouteInputSchema {
|
|
459
|
+
source: 'query' | 'body' | 'params';
|
|
460
|
+
schemaName: string | null;
|
|
461
|
+
properties: RouteParamSchema[];
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* 路由响应类型的 schema 描述
|
|
465
|
+
*
|
|
466
|
+
* 由 @faapi/schema 扩展包的 buildRouteSchemas 生成。
|
|
467
|
+
* output 为 null 表示无显式返回类型注解、void/Promise<void>、或解析失败降级。
|
|
468
|
+
*/
|
|
469
|
+
interface RouteOutputSchema {
|
|
470
|
+
/** 命名类型名(如 'UserResponse'),内联类型为 null */
|
|
471
|
+
schemaName: string | null;
|
|
472
|
+
/** 顶层属性列表 */
|
|
473
|
+
properties: RouteParamSchema[];
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* 路由的完整 schema 描述
|
|
477
|
+
*
|
|
478
|
+
* 由 @faapi/schema 扩展包的 buildRouteSchemas 生成。
|
|
479
|
+
* 主包只定义类型契约,逻辑实现在扩展包。
|
|
480
|
+
*/
|
|
481
|
+
interface RouteInfo {
|
|
482
|
+
method: string;
|
|
483
|
+
path: string;
|
|
484
|
+
filePath: string;
|
|
485
|
+
isDynamic: boolean;
|
|
486
|
+
inputs: RouteInputSchema[];
|
|
487
|
+
/** 响应类型描述(null 表示无返回类型注解/void/解析失败) */
|
|
488
|
+
output: RouteOutputSchema | null;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export { type CorsOptions as C, type FaapiContext as F, type HelmetOptions as H, type InjectorMap as I, type LoggerOptions as L, type RouteManifest as R, type SseEvent as S, type WsRouteManifest as W, type FaapiMiddleware as a, type FaapiContextConfig as b, type FailOptions as c, type Injector as d, type RouteInfo as e, type RouteInputSchema as f, type RouteOutputSchema as g, type RouteParamSchema as h, type SseWriter as i, cors as j, helmet as k, logger as l };
|