@faapi/faapi 6.9.1 → 6.10.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.
@@ -306,24 +306,27 @@ interface CreateLoggerOptions {
306
306
  /**
307
307
  * `config.log` 的对象形状(config 侧另接受 boolean:false 全静默、true 默认)
308
308
  *
309
- * level 解析顺序:显式值 > `LOG_LEVEL` 环境变量 > 模式默认(`dir` 文件模式不过滤,
310
- * 其余模式 `'info'`;非法值启动报错)。`sink` 与 `dir` 互斥,同时配置启动报错。
309
+ * 参考 egg.js 的单管道模型:一条日志管道、两个输出出口(文件/sink 与 console),
310
+ * 各有独立阈值——`level` 管管道出口(不配不过滤),`consoleLevel` 管 console 出口
311
+ * (不配 `'info'`)。非法级别值启动报错。`sink` 与 `dir` 互斥,同时配置启动报错。
311
312
  */
312
313
  interface LogConfig {
313
- /** 实例级级别(覆盖全局 level) */
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 语义);请求日志自动并入(`accessLog` 缺省 true)
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
- /** 请求日志是否并入统一管道;缺省 = `dir` 配置时 true(见 middleware/logger.md) */
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 ToolPathMeta as $, type AppRegistries as A, type RouteInputSchema as B, type CorsOptions as C, type RouteOutputSchema as D, type RouteParamSchema as E, type FaapiContext as F, type SseEvent as G, type HelmetOptions as H, type InjectorMap as I, type SseWriter as J, type TaskContext as K, type LoggerOptions as L, type TaskDriverJob as M, type TaskDriverProcess as N, type TaskDriverRecord as O, type TaskFailedInfo as P, type TaskJob as Q, type RouteManifest as R, type SkillRegistry as S, type TaskClient as T, type TaskJobStatus as U, type TaskMetadata as V, type WsRouteManifest as W, type TaskModule as X, type TaskRegistriesSnapshot as Y, type TaskRegistriesView as Z, type ToolCore as _, type LogConfig as a, type ToolRegistry as a0, cors as a1, createAppRegistries as a2, createTaskRegistriesView as a3, createTaskRegistry as a4, helmet as a5, logger as a6, type FaapiMiddleware as b, type TaskFailedHandler as c, type TaskQueueDeps as d, type TaskQueue as e, type TaskDriver as f, type TaskRegistry as g, type TaskManifest as h, type ToolMetadata as i, type AgentCore as j, type AgentMetadata as k, type CreateLoggerOptions as l, type Logger as m, type AgentHandleFactory as n, type AgentHandleStore as o, type AgentPathMeta as p, type AgentRegistry as q, type AgentToolDescriptor as r, type FaapiContextConfig as s, type FaapiTaskMeta as t, type FailOptions as u, type Injector as v, type LogEntry as w, type LogLevel as x, type LogSink as y, type RouteInfo as z };
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 { F as FaapiContext, b as FaapiMiddleware, I as InjectorMap, R as RouteManifest, W as WsRouteManifest, C as CorsOptions, H as HelmetOptions, L as LoggerOptions } from './routeTypes-CuGMDCGB.js';
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/Logger,避免污染断言)
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,60 @@ 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 globalState = { level: null, sink: null, fileSink: null, stdout: true, accessLog: false, disabled: false };
275
- function globalThreshold() {
276
- if (globalState.level) return globalState.level;
277
- if (globalState.fileSink) return void 0;
278
- return "info";
274
+ var globalState = {
275
+ level: null,
276
+ consoleLevel: null,
277
+ sink: null,
278
+ fileSink: null,
279
+ stdout: true,
280
+ accessLog: true,
281
+ disabled: false
282
+ };
283
+ function pipelineThreshold() {
284
+ return globalState.level ?? void 0;
285
+ }
286
+ function consoleThreshold() {
287
+ return globalState.consoleLevel ?? "info";
279
288
  }
280
289
  function belowThreshold(level, threshold) {
281
290
  return threshold !== void 0 && LEVEL_RANK[level] < LEVEL_RANK[threshold];
282
291
  }
283
- var consoleSink = (entry) => {
284
- console[CONSOLE_METHOD[entry.level]](formatEntry(entry));
285
- };
286
292
  var CONSOLE_METHOD = {
287
293
  debug: "debug",
288
294
  info: "info",
289
295
  warn: "warn",
290
296
  error: "error"
291
297
  };
298
+ function consoleDispatch(entry) {
299
+ const threshold = consoleThreshold();
300
+ if (threshold === false || belowThreshold(entry.level, threshold)) return;
301
+ console[CONSOLE_METHOD[entry.level]](formatEntry(entry));
302
+ }
292
303
  function globalDispatch(entry) {
293
304
  if (globalState.disabled) return;
305
+ const pipeThreshold = pipelineThreshold();
294
306
  if (globalState.sink) {
295
- globalState.sink(entry);
307
+ if (!belowThreshold(entry.level, pipeThreshold)) globalState.sink(entry);
296
308
  return;
297
309
  }
298
310
  if (globalState.fileSink) {
299
- globalState.fileSink.write(entry);
300
- if (globalState.stdout) consoleSink(entry);
311
+ if (!belowThreshold(entry.level, pipeThreshold)) globalState.fileSink.write(entry);
312
+ if (globalState.stdout) consoleDispatch(entry);
301
313
  return;
302
314
  }
303
- consoleSink(entry);
315
+ consoleDispatch(entry);
304
316
  }
305
317
  function writeLogEntry(entry) {
306
- if (belowThreshold(entry.level, globalThreshold())) return;
307
318
  globalDispatch(entry);
308
319
  }
309
- function isAccessLogPiped() {
320
+ function isAccessLogEnabled() {
310
321
  return !globalState.disabled && globalState.accessLog;
311
322
  }
312
323
  function createLogger(scope, options) {
313
324
  const baseScope = scope;
314
325
  const baseFields = options?.fields;
315
326
  const write = (level, message, callFields, scopeSuffix) => {
316
- const threshold = options?.level ?? globalThreshold();
317
- if (belowThreshold(level, threshold)) return;
327
+ if (belowThreshold(level, options?.level)) return;
318
328
  const entry = {
319
329
  level,
320
330
  message,
@@ -4212,18 +4222,14 @@ function levelForStatus(status) {
4212
4222
  return "info";
4213
4223
  }
4214
4224
  function defaultLog(entry, text) {
4215
- if (isAccessLogPiped()) {
4216
- const logEntry = {
4217
- level: levelForStatus(entry.status),
4218
- message: text,
4219
- time: (/* @__PURE__ */ new Date()).toISOString(),
4220
- scope: "access",
4221
- fields: entry
4222
- };
4223
- writeLogEntry(logEntry);
4224
- return;
4225
- }
4226
- console.log(entry);
4225
+ if (!isAccessLogEnabled()) return;
4226
+ writeLogEntry({
4227
+ level: levelForStatus(entry.status),
4228
+ message: text,
4229
+ time: (/* @__PURE__ */ new Date()).toISOString(),
4230
+ scope: "access",
4231
+ fields: entry
4232
+ });
4227
4233
  }
4228
4234
  function logger(options = {}) {
4229
4235
  return async (ctx, next) => {
@@ -4586,7 +4592,6 @@ function createServer(options) {
4586
4592
  compression: compressionOption,
4587
4593
  etag: etagOption,
4588
4594
  registries,
4589
- logger: loggerOption,
4590
4595
  bodyLimit = DEFAULT_BODY_LIMIT,
4591
4596
  http2: http2Option,
4592
4597
  trustedProxy = false
@@ -4603,8 +4608,7 @@ function createServer(options) {
4603
4608
  const helmOpts = typeof helmetOption === "object" ? helmetOption : {};
4604
4609
  configMiddlewares.push(helmet(helmOpts));
4605
4610
  }
4606
- const loggerMiddlewareInst = loggerOption === false ? null : loggerOption === true || loggerOption === void 0 ? logger() : logger(loggerOption);
4607
- if (loggerMiddlewareInst) configMiddlewares.push(loggerMiddlewareInst);
4611
+ configMiddlewares.push(logger());
4608
4612
  if (etagOption) {
4609
4613
  const etagOpts = typeof etagOption === "object" ? etagOption : {};
4610
4614
  configMiddlewares.push(etag(etagOpts));
@@ -4787,7 +4791,6 @@ async function createTestServer(options) {
4787
4791
  dist,
4788
4792
  cors: cors2 = false,
4789
4793
  helmet: helmet2 = false,
4790
- logger: logger2 = false,
4791
4794
  middlewares,
4792
4795
  injectors,
4793
4796
  onError,
@@ -4804,7 +4807,6 @@ async function createTestServer(options) {
4804
4807
  dist: schemaDist,
4805
4808
  cors: cors2,
4806
4809
  helmet: helmet2,
4807
- logger: logger2,
4808
4810
  middlewares,
4809
4811
  injectors,
4810
4812
  onError,