@faapi/faapi 6.9.1 → 6.10.1
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 +73 -48
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +47 -21
- package/dist/index.js +74 -48
- package/dist/index.js.map +1 -1
- package/dist/{routeTypes-CuGMDCGB.d.ts → routeTypes-m9wZHWyo.d.ts} +9 -34
- package/dist/testing.d.ts +2 -4
- package/dist/testing.js +53 -37
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
|
@@ -306,24 +306,27 @@ interface CreateLoggerOptions {
|
|
|
306
306
|
/**
|
|
307
307
|
* `config.log` 的对象形状(config 侧另接受 boolean:false 全静默、true 默认)
|
|
308
308
|
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
309
|
+
* 参考 egg.js 的单管道模型:一条日志管道、两个输出出口(文件/sink 与 console),
|
|
310
|
+
* 各有独立阈值——`level` 管管道出口(不配不过滤),`consoleLevel` 管 console 出口
|
|
311
|
+
* (不配 `'info'`)。非法级别值启动报错。`sink` 与 `dir` 互斥,同时配置启动报错。
|
|
311
312
|
*/
|
|
312
313
|
interface LogConfig {
|
|
313
|
-
/**
|
|
314
|
+
/** 管道阈值(文件/sink 收到的条目;不配不过滤,LOG_LEVEL env 同源) */
|
|
314
315
|
level?: LogLevel;
|
|
316
|
+
/** console 出口阈值(不配 `'info'`;`false` 关闭 console 输出) */
|
|
317
|
+
consoleLevel?: LogLevel | false;
|
|
315
318
|
/** 自定义输出管道(整体接管,与 `dir` 互斥) */
|
|
316
319
|
sink?: LogSink;
|
|
317
320
|
/**
|
|
318
321
|
* 文件日志目录(egg 风格):配置即启用内置文件管道——默认 `app.log` 全量 +
|
|
319
|
-
* `error.log` 仅 error(dup
|
|
322
|
+
* `error.log` 仅 error(dup 语义);请求日志自动并入
|
|
320
323
|
*/
|
|
321
324
|
dir?: string;
|
|
322
325
|
/** true 时按级别四文件 `debug.log`/`info.log`/`warn.log`/`error.log`(各只含对应级别) */
|
|
323
326
|
splitByLevel?: boolean;
|
|
324
327
|
/** 文件模式下是否保留 console 双写(默认 true;false 纯文件) */
|
|
325
328
|
stdout?: boolean;
|
|
326
|
-
/**
|
|
329
|
+
/** 请求日志是否并入管道(默认 true;false 关闭请求日志,不输出) */
|
|
327
330
|
accessLog?: boolean;
|
|
328
331
|
}
|
|
329
332
|
|
|
@@ -1125,34 +1128,6 @@ interface CorsOptions {
|
|
|
1125
1128
|
*/
|
|
1126
1129
|
declare function cors(options?: CorsOptions): FaapiMiddleware;
|
|
1127
1130
|
|
|
1128
|
-
type LoggerFn = (messageOrObj: string | Record<string, unknown>, message?: string) => void;
|
|
1129
|
-
interface LoggerOptions {
|
|
1130
|
-
/**
|
|
1131
|
-
* 自定义日志函数
|
|
1132
|
-
*
|
|
1133
|
-
* - 传入 `console.log`(默认):纯文本格式 `GET /api/users 200 12ms`
|
|
1134
|
-
* - 传入 pino logger:结构化日志 `logger.info({ method, path, status, durationMs }, 'request completed')`
|
|
1135
|
-
* - 传入 winston logger:`logger.info('GET /api/users 200 12ms', { method, path })`
|
|
1136
|
-
*/
|
|
1137
|
-
log?: LoggerFn;
|
|
1138
|
-
}
|
|
1139
|
-
/**
|
|
1140
|
-
* 创建请求日志中间件(洋葱模型)
|
|
1141
|
-
*
|
|
1142
|
-
* 日志格式(文本模式):GET /api/users 200 12ms
|
|
1143
|
-
* 错误格式(文本模式):POST /api/users 400 45ms - Error: ...
|
|
1144
|
-
*
|
|
1145
|
-
* 结构化模式:传入 pino/winston 等 logger 实例时,会自动传递结构化字段。
|
|
1146
|
-
*
|
|
1147
|
-
* before/after 一体,闭包变量共享开始时间,无需污染 ctx。
|
|
1148
|
-
* 错误用 try/catch 捕获,记录后重新抛出(让上层处理)。
|
|
1149
|
-
* 成功时从 next() 返回的 Response 读取状态码。
|
|
1150
|
-
*
|
|
1151
|
-
* log 函数每次请求时读取(options.log ?? defaultLog),运行时替换 console.log 或
|
|
1152
|
-
* 切换全局日志配置均会生效。
|
|
1153
|
-
*/
|
|
1154
|
-
declare function logger(options?: LoggerOptions): FaapiMiddleware;
|
|
1155
|
-
|
|
1156
1131
|
interface HelmetOptions {
|
|
1157
1132
|
contentSecurityPolicy?: string | false;
|
|
1158
1133
|
xFrameOptions?: 'DENY' | 'SAMEORIGIN' | false;
|
|
@@ -1256,4 +1231,4 @@ interface RouteInfo {
|
|
|
1256
1231
|
output: RouteOutputSchema | null;
|
|
1257
1232
|
}
|
|
1258
1233
|
|
|
1259
|
-
export { type
|
|
1234
|
+
export { type ToolRegistry as $, type AppRegistries as A, type RouteOutputSchema as B, type CorsOptions as C, type RouteParamSchema as D, type SseEvent as E, type FaapiMiddleware as F, type SseWriter as G, type HelmetOptions as H, type InjectorMap as I, type TaskContext as J, type TaskDriverJob as K, type LogConfig as L, type TaskDriverProcess as M, type TaskDriverRecord as N, type TaskFailedInfo as O, type TaskJob as P, type TaskJobStatus as Q, type RouteManifest as R, type SkillRegistry as S, type TaskClient as T, type TaskMetadata as U, type TaskModule as V, type WsRouteManifest as W, type TaskRegistriesSnapshot as X, type TaskRegistriesView as Y, type ToolCore as Z, type ToolPathMeta as _, type FaapiContext as a, cors as a0, createAppRegistries as a1, createTaskRegistriesView as a2, createTaskRegistry as a3, helmet as a4, type TaskFailedHandler as b, type TaskQueueDeps as c, type TaskQueue as d, type TaskDriver as e, type TaskRegistry as f, type TaskManifest as g, type ToolMetadata as h, type AgentCore as i, type AgentMetadata as j, type CreateLoggerOptions as k, type Logger as l, type AgentHandleFactory as m, type AgentHandleStore as n, type AgentPathMeta as o, type AgentRegistry as p, type AgentToolDescriptor as q, type FaapiContextConfig as r, type FaapiTaskMeta as s, type FailOptions as t, type Injector as u, type LogEntry as v, type LogLevel as w, type LogSink as x, type RouteInfo as y, type RouteInputSchema as z };
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as FaapiContext, F as FaapiMiddleware, I as InjectorMap, R as RouteManifest, W as WsRouteManifest, C as CorsOptions, H as HelmetOptions } from './routeTypes-m9wZHWyo.js';
|
|
2
2
|
import { Server } from 'node:http';
|
|
3
3
|
import { WebSocket } from 'ws';
|
|
4
4
|
|
|
@@ -76,8 +76,6 @@ interface TestServerOptions {
|
|
|
76
76
|
cors?: CorsOptions | boolean;
|
|
77
77
|
/** 安全头配置,默认 false */
|
|
78
78
|
helmet?: HelmetOptions | boolean;
|
|
79
|
-
/** 请求日志配置,默认 false(避免污染测试输出) */
|
|
80
|
-
logger?: LoggerOptions | boolean;
|
|
81
79
|
/** 全局中间件(外层洋葱) */
|
|
82
80
|
middlewares?: FaapiMiddleware[];
|
|
83
81
|
/** 全局注入器 */
|
|
@@ -126,7 +124,7 @@ interface TestServer {
|
|
|
126
124
|
* 2. sortRoutes 排序
|
|
127
125
|
* 3. mkdtemp 创建临时 schema 目录(或用传入的 dist)
|
|
128
126
|
* 4. generateSchemaFiles 生成 zod.js
|
|
129
|
-
* 5. createServer 创建 server(默认禁用 CORS/Helmet
|
|
127
|
+
* 5. createServer 创建 server(默认禁用 CORS/Helmet,避免污染断言)
|
|
130
128
|
* 6. server.listen(0) 随机端口
|
|
131
129
|
* 7. 返回 TestServer
|
|
132
130
|
*
|
package/dist/testing.js
CHANGED
|
@@ -271,50 +271,74 @@ function formatEntry(entry) {
|
|
|
271
271
|
|
|
272
272
|
// src/logger/logger.ts
|
|
273
273
|
var LEVEL_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
274
|
-
var
|
|
275
|
-
function
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
274
|
+
var LOGGING_STATE_KEY = /* @__PURE__ */ Symbol.for("faapi.logger.state");
|
|
275
|
+
function createDefaultLoggingState() {
|
|
276
|
+
return {
|
|
277
|
+
level: null,
|
|
278
|
+
consoleLevel: null,
|
|
279
|
+
sink: null,
|
|
280
|
+
fileSink: null,
|
|
281
|
+
stdout: true,
|
|
282
|
+
accessLog: true,
|
|
283
|
+
disabled: false
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function getLoggingState() {
|
|
287
|
+
const g = globalThis;
|
|
288
|
+
let state2 = g[LOGGING_STATE_KEY];
|
|
289
|
+
if (!state2) {
|
|
290
|
+
state2 = createDefaultLoggingState();
|
|
291
|
+
g[LOGGING_STATE_KEY] = state2;
|
|
292
|
+
}
|
|
293
|
+
return state2;
|
|
294
|
+
}
|
|
295
|
+
function pipelineThreshold() {
|
|
296
|
+
return getLoggingState().level ?? void 0;
|
|
297
|
+
}
|
|
298
|
+
function consoleThreshold() {
|
|
299
|
+
return getLoggingState().consoleLevel ?? "info";
|
|
279
300
|
}
|
|
280
301
|
function belowThreshold(level, threshold) {
|
|
281
302
|
return threshold !== void 0 && LEVEL_RANK[level] < LEVEL_RANK[threshold];
|
|
282
303
|
}
|
|
283
|
-
var consoleSink = (entry) => {
|
|
284
|
-
console[CONSOLE_METHOD[entry.level]](formatEntry(entry));
|
|
285
|
-
};
|
|
286
304
|
var CONSOLE_METHOD = {
|
|
287
305
|
debug: "debug",
|
|
288
306
|
info: "info",
|
|
289
307
|
warn: "warn",
|
|
290
308
|
error: "error"
|
|
291
309
|
};
|
|
310
|
+
function consoleDispatch(entry) {
|
|
311
|
+
const threshold = consoleThreshold();
|
|
312
|
+
if (threshold === false || belowThreshold(entry.level, threshold)) return;
|
|
313
|
+
console[CONSOLE_METHOD[entry.level]](formatEntry(entry));
|
|
314
|
+
}
|
|
292
315
|
function globalDispatch(entry) {
|
|
293
|
-
|
|
294
|
-
if (
|
|
295
|
-
|
|
316
|
+
const state2 = getLoggingState();
|
|
317
|
+
if (state2.disabled) return;
|
|
318
|
+
const pipeThreshold = pipelineThreshold();
|
|
319
|
+
if (state2.sink) {
|
|
320
|
+
if (!belowThreshold(entry.level, pipeThreshold)) state2.sink(entry);
|
|
296
321
|
return;
|
|
297
322
|
}
|
|
298
|
-
if (
|
|
299
|
-
|
|
300
|
-
if (
|
|
323
|
+
if (state2.fileSink) {
|
|
324
|
+
if (!belowThreshold(entry.level, pipeThreshold)) state2.fileSink.write(entry);
|
|
325
|
+
if (state2.stdout) consoleDispatch(entry);
|
|
301
326
|
return;
|
|
302
327
|
}
|
|
303
|
-
|
|
328
|
+
consoleDispatch(entry);
|
|
304
329
|
}
|
|
305
330
|
function writeLogEntry(entry) {
|
|
306
|
-
if (belowThreshold(entry.level, globalThreshold())) return;
|
|
307
331
|
globalDispatch(entry);
|
|
308
332
|
}
|
|
309
|
-
function
|
|
310
|
-
|
|
333
|
+
function isAccessLogEnabled() {
|
|
334
|
+
const state2 = getLoggingState();
|
|
335
|
+
return !state2.disabled && state2.accessLog;
|
|
311
336
|
}
|
|
312
337
|
function createLogger(scope, options) {
|
|
313
338
|
const baseScope = scope;
|
|
314
339
|
const baseFields = options?.fields;
|
|
315
340
|
const write = (level, message, callFields, scopeSuffix) => {
|
|
316
|
-
|
|
317
|
-
if (belowThreshold(level, threshold)) return;
|
|
341
|
+
if (belowThreshold(level, options?.level)) return;
|
|
318
342
|
const entry = {
|
|
319
343
|
level,
|
|
320
344
|
message,
|
|
@@ -4212,18 +4236,14 @@ function levelForStatus(status) {
|
|
|
4212
4236
|
return "info";
|
|
4213
4237
|
}
|
|
4214
4238
|
function defaultLog(entry, text) {
|
|
4215
|
-
if (
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
writeLogEntry(logEntry);
|
|
4224
|
-
return;
|
|
4225
|
-
}
|
|
4226
|
-
console.log(entry);
|
|
4239
|
+
if (!isAccessLogEnabled()) return;
|
|
4240
|
+
writeLogEntry({
|
|
4241
|
+
level: levelForStatus(entry.status),
|
|
4242
|
+
message: text,
|
|
4243
|
+
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4244
|
+
scope: "access",
|
|
4245
|
+
fields: entry
|
|
4246
|
+
});
|
|
4227
4247
|
}
|
|
4228
4248
|
function logger(options = {}) {
|
|
4229
4249
|
return async (ctx, next) => {
|
|
@@ -4586,7 +4606,6 @@ function createServer(options) {
|
|
|
4586
4606
|
compression: compressionOption,
|
|
4587
4607
|
etag: etagOption,
|
|
4588
4608
|
registries,
|
|
4589
|
-
logger: loggerOption,
|
|
4590
4609
|
bodyLimit = DEFAULT_BODY_LIMIT,
|
|
4591
4610
|
http2: http2Option,
|
|
4592
4611
|
trustedProxy = false
|
|
@@ -4603,8 +4622,7 @@ function createServer(options) {
|
|
|
4603
4622
|
const helmOpts = typeof helmetOption === "object" ? helmetOption : {};
|
|
4604
4623
|
configMiddlewares.push(helmet(helmOpts));
|
|
4605
4624
|
}
|
|
4606
|
-
|
|
4607
|
-
if (loggerMiddlewareInst) configMiddlewares.push(loggerMiddlewareInst);
|
|
4625
|
+
configMiddlewares.push(logger());
|
|
4608
4626
|
if (etagOption) {
|
|
4609
4627
|
const etagOpts = typeof etagOption === "object" ? etagOption : {};
|
|
4610
4628
|
configMiddlewares.push(etag(etagOpts));
|
|
@@ -4787,7 +4805,6 @@ async function createTestServer(options) {
|
|
|
4787
4805
|
dist,
|
|
4788
4806
|
cors: cors2 = false,
|
|
4789
4807
|
helmet: helmet2 = false,
|
|
4790
|
-
logger: logger2 = false,
|
|
4791
4808
|
middlewares,
|
|
4792
4809
|
injectors,
|
|
4793
4810
|
onError,
|
|
@@ -4804,7 +4821,6 @@ async function createTestServer(options) {
|
|
|
4804
4821
|
dist: schemaDist,
|
|
4805
4822
|
cors: cors2,
|
|
4806
4823
|
helmet: helmet2,
|
|
4807
|
-
logger: logger2,
|
|
4808
4824
|
middlewares,
|
|
4809
4825
|
injectors,
|
|
4810
4826
|
onError,
|