@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/index.d.ts CHANGED
@@ -1,10 +1,38 @@
1
- import { A as AppRegistries, R as RouteManifest, F as FaapiContext, C as CorsOptions, T as TaskClient, H as HelmetOptions, L as LoggerOptions, a as LogConfig, b as FaapiMiddleware, I as InjectorMap, c as TaskFailedHandler, d as TaskQueueDeps, e as TaskQueue, f as TaskDriver, g as TaskRegistry, h as TaskManifest, i as ToolMetadata, j as AgentCore, k as AgentMetadata, l as CreateLoggerOptions, m as Logger, W as WsRouteManifest } from './routeTypes-CuGMDCGB.js';
2
- export { n as AgentHandleFactory, o as AgentHandleStore, p as AgentPathMeta, q as AgentRegistry, r as AgentToolDescriptor, s as FaapiContextConfig, t as FaapiTaskMeta, u as FailOptions, v as Injector, w as LogEntry, x as LogLevel, y as LogSink, z as RouteInfo, B as RouteInputSchema, D as RouteOutputSchema, E as RouteParamSchema, S as SkillRegistry, G as SseEvent, J as SseWriter, K as TaskContext, M as TaskDriverJob, N as TaskDriverProcess, O as TaskDriverRecord, P as TaskFailedInfo, Q as TaskJob, U as TaskJobStatus, V as TaskMetadata, X as TaskModule, Y as TaskRegistriesSnapshot, Z as TaskRegistriesView, _ as ToolCore, $ as ToolPathMeta, a0 as ToolRegistry, a1 as cors, a2 as createAppRegistries, a3 as createTaskRegistriesView, a4 as createTaskRegistry, a5 as helmet, a6 as logger } from './routeTypes-CuGMDCGB.js';
1
+ import { F as FaapiMiddleware, A as AppRegistries, R as RouteManifest, a as FaapiContext, C as CorsOptions, T as TaskClient, H as HelmetOptions, L as LogConfig, I as InjectorMap, b as TaskFailedHandler, c as TaskQueueDeps, d as TaskQueue, e as TaskDriver, f as TaskRegistry, g as TaskManifest, h as ToolMetadata, i as AgentCore, j as AgentMetadata, k as CreateLoggerOptions, l as Logger, W as WsRouteManifest } from './routeTypes-m9wZHWyo.js';
2
+ export { m as AgentHandleFactory, n as AgentHandleStore, o as AgentPathMeta, p as AgentRegistry, q as AgentToolDescriptor, r as FaapiContextConfig, s as FaapiTaskMeta, t as FailOptions, u as Injector, v as LogEntry, w as LogLevel, x as LogSink, y as RouteInfo, z as RouteInputSchema, B as RouteOutputSchema, D as RouteParamSchema, S as SkillRegistry, E as SseEvent, G as SseWriter, J as TaskContext, K as TaskDriverJob, M as TaskDriverProcess, N as TaskDriverRecord, O as TaskFailedInfo, P as TaskJob, Q as TaskJobStatus, U as TaskMetadata, V as TaskModule, X as TaskRegistriesSnapshot, Y as TaskRegistriesView, Z as ToolCore, _ as ToolPathMeta, $ as ToolRegistry, a0 as cors, a1 as createAppRegistries, a2 as createTaskRegistriesView, a3 as createTaskRegistry, a4 as helmet } from './routeTypes-m9wZHWyo.js';
3
3
  import * as node_http from 'node:http';
4
4
  import { Server, IncomingMessage, ServerResponse } from 'node:http';
5
5
  import { Socket } from 'node:net';
6
6
  import ts from 'typescript';
7
7
 
8
+ type LoggerFn = (messageOrObj: string | Record<string, unknown>, message?: string) => void;
9
+ interface LoggerOptions {
10
+ /**
11
+ * 自定义日志函数(完全接管输出,不再走统一管道——高级用法,一般无需配置)
12
+ *
13
+ * - 传入 `console.log`:纯文本格式 `GET /api/users 200 12ms`
14
+ * - 传入 pino logger:结构化日志 `logger.info({ method, path, status, durationMs }, 'request completed')`
15
+ */
16
+ log?: LoggerFn;
17
+ }
18
+ /**
19
+ * 创建请求日志中间件(洋葱模型)
20
+ *
21
+ * 默认并入统一日志管道(egg 模型:访问日志与业务日志同管道,一份 config.log
22
+ * 管全部输出),`config.log.accessLog: false` 关闭。
23
+ *
24
+ * 日志格式(文本 message):GET /api/users 200 12ms
25
+ * 错误格式:POST /api/users 400 45ms - Error: ...
26
+ *
27
+ * before/after 一体,闭包变量共享开始时间,无需污染 ctx。
28
+ * 错误用 try/catch 捕获,记录后重新抛出(让上层处理)。
29
+ * 成功时从 next() 返回的 Response 读取状态码。
30
+ *
31
+ * log 函数每次请求时读取(options.log ?? defaultLog),运行时切换全局日志配置
32
+ * 同样生效。编程式自定义输出:`middlewares: [logger({ log: myFn })]`。
33
+ */
34
+ declare function logger(options?: LoggerOptions): FaapiMiddleware;
35
+
8
36
  /** HTTP 请求 handler 类型 */
9
37
  type RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;
10
38
  /** WebSocket 升级 handler 类型 */
@@ -550,21 +578,19 @@ interface FaapiConfig {
550
578
  etag?: EtagOptions | boolean;
551
579
  /** 请求体大小限制(字节),默认 10MB(10 * 1024 * 1024) */
552
580
  bodyLimit?: number;
553
- /** 日志中间件配置 */
554
- logger?: LoggerOptions | boolean;
555
581
  /**
556
- * 业务日志器全局配置(详见 logger/logger.md)
582
+ * 日志全局配置——唯一日志配置入口,业务日志与请求日志同管道(egg 模型,
583
+ * 详见 logger/logger.md;`config.logger` 独立配置已废除)
557
584
  *
558
- * - `false`:完全静默(含 error,测试降噪;不影响请求日志,关闭用 `logger: false`)
559
- * - `true` / 缺省:默认级别(显式 level > LOG_LEVEL env > 'info')+ console 文本输出
560
- * - `LogConfig`:精细配置——`sink` 自定义管道(接 pino/winston)或 `dir` egg 风格
561
- * 文件输出(app.log 全量 + error.log 仅 error,splitByLevel 按级别四文件),
562
- * 两者互斥;`dir` 模式请求日志自动并入(`accessLog` 缺省 true),未显式配置
563
- * level 时不过滤(全量落盘)
585
+ * - `false`:全部静默(含 error 与请求日志,测试降噪)
586
+ * - `true` / 缺省:console 输出(consoleLevel 默认 'info'),管道不过滤
587
+ * - `LogConfig`:`dir` egg 风格文件输出(app.log 全量 + error.log 仅 error,
588
+ * splitByLevel 按级别四文件)或 `sink` 自定义管道接管(接 pino/winston),
589
+ * 两者互斥;`level` 管道阈值(不配不过滤)、`consoleLevel` console 出口阈值
590
+ * (不配 'info',false 关 console);请求日志无条件并入(`accessLog: false` 关闭)
564
591
  *
565
- * 生效范围:`ctx.log` / 参数注入 `log` / `createLogger` / `taskCtx.log`,
566
- * `dir`/`accessLog` 模式下含请求日志中间件。
567
- * 日志全局配置是进程级资源,多 app 同进程时后启动覆盖先启动。
592
+ * 生效范围:`ctx.log` / 参数注入 `log` / `createLogger` / `taskCtx.log` /
593
+ * 请求日志中间件。日志全局配置是进程级资源,多 app 同进程时后启动覆盖先启动。
568
594
  *
569
595
  * ```ts
570
596
  * export default {
@@ -1495,14 +1521,14 @@ declare function loadEnv(rootDir: string): void;
1495
1521
  /**
1496
1522
  * 设置全局日志配置(进程级,`createAppBase` 启动时以 `config.log` 调用)
1497
1523
  *
1498
- * - `false`:完全静默(含 error,测试降噪场景)
1499
- * - `true` / `{}`:默认级别(显式 level > LOG_LEVEL env > 模式默认)+ 默认 console sink
1500
- * - `{ level, sink }`:自定义管道接管(与 dir 互斥,同时配置抛错)
1501
- * - `{ dir, splitByLevel?, stdout?, accessLog? }`:egg 风格文件输出(fileSink.md)
1524
+ * - `false`:全部静默(含 error 与请求日志,测试降噪场景)
1525
+ * - `true` / `{}`:console 出口默认 info,管道出口不过滤,无文件输出
1526
+ * - `{ level, consoleLevel, sink, dir, stdout, accessLog }`:egg 模型精细配置
1527
+ * (level 管管道出口、consoleLevel 管 console 出口;sink 与 dir 互斥)
1502
1528
  * - `undefined`:重置为默认(编程式多 app 切换全局配置用)
1503
1529
  *
1504
- * LOG_LEVEL env 仅在本函数读取——app 启动路径必经此处(env 非法在启动期报错);
1505
- * 纯编程式不调本函数时 env 不生效。
1530
+ * LOG_LEVEL env 仅作为管道 level 的环境来源(consoleLevel 无 env)——本函数是
1531
+ * env 读取点,非法值启动期报错(fail fast)。
1506
1532
  */
1507
1533
  declare function configureLogging(config?: LogConfig | boolean | undefined): void;
1508
1534
  /**
@@ -1720,4 +1746,4 @@ type ProdApp = AppBase;
1720
1746
  */
1721
1747
  declare function createProdApp(options?: CreateAppOptions): Promise<ProdApp>;
1722
1748
 
1723
- export { type AgentConfig, AgentCore, AgentMetadata, type AgentModule, type ProdApp as App, AppRegistries, CorsOptions, type CreateAppOptions, CreateLoggerOptions, type CronScheduler, type DevApp, type FaapiConfig, FaapiContext, FaapiError, FaapiMiddleware, type FaapiPlugin, type HandlerTypeInfo, HelmetOptions, type InjectOptions, type InjectResponse, InjectorMap, InternalError, type LifecycleContext, type LifecycleHooks, type LlmConfig, type LlmModelConfig, LogConfig, Logger, LoggerOptions, MethodNotAllowedError, ModuleLoadError, type PluginContext, type PluginDeclaration, type ProdApp, type PropertyType, type RequestHandler, type ResponseConfig, RouteManifest, RouteNotFoundError, type RouteSchemaSource, type RuntimeType, SchemaExtractionError, TASK_PATTERNS, type TaskBullMqOptions, TaskClient, type TaskConfig, TaskDriver, TaskFailedHandler, TaskManifest, type TaskPgBossOptions, TaskQueue, TaskRegistry, ToolMetadata, type ToolModule, type ToolSchemaModule, type TypeConstraint, type UpgradeHandler, ValidationError, type ValidationErrorCode, type ValidationIssue, type WsContext, type WsEventHandlers, type WsHandler, type WsSocket, clearAgentHandleFactory, collectRouteSchemaSources, configureLogging, createProdApp as createApp, createCronScheduler, createDevApp, createLogger, createProdApp, createProgram, createPrograms, createTaskQueue, extractTypeInfo, flushLogging, getAgent, getAgentEntry, getApp, getInputTypeForMethod, getSkill, getTool, getToolSchemaPath, hydrateSkillRegistry, invalidateProgramCache, listSkills, loadAgentModule, loadConfig, loadEnv, loadTaskDriver, loadToolModule, loadToolSchema, registerAgentHandleFactory, removeSkill, resolveAgentTools, resolveSubAgents, resolveTypeNode, scanTasks, upsertSkill };
1749
+ export { type AgentConfig, AgentCore, AgentMetadata, type AgentModule, type ProdApp as App, AppRegistries, CorsOptions, type CreateAppOptions, CreateLoggerOptions, type CronScheduler, type DevApp, type FaapiConfig, FaapiContext, FaapiError, FaapiMiddleware, type FaapiPlugin, type HandlerTypeInfo, HelmetOptions, type InjectOptions, type InjectResponse, InjectorMap, InternalError, type LifecycleContext, type LifecycleHooks, type LlmConfig, type LlmModelConfig, LogConfig, Logger, type LoggerOptions, MethodNotAllowedError, ModuleLoadError, type PluginContext, type PluginDeclaration, type ProdApp, type PropertyType, type RequestHandler, type ResponseConfig, RouteManifest, RouteNotFoundError, type RouteSchemaSource, type RuntimeType, SchemaExtractionError, TASK_PATTERNS, type TaskBullMqOptions, TaskClient, type TaskConfig, TaskDriver, TaskFailedHandler, TaskManifest, type TaskPgBossOptions, TaskQueue, TaskRegistry, ToolMetadata, type ToolModule, type ToolSchemaModule, type TypeConstraint, type UpgradeHandler, ValidationError, type ValidationErrorCode, type ValidationIssue, type WsContext, type WsEventHandlers, type WsHandler, type WsSocket, clearAgentHandleFactory, collectRouteSchemaSources, configureLogging, createProdApp as createApp, createCronScheduler, createDevApp, createLogger, createProdApp, createProgram, createPrograms, createTaskQueue, extractTypeInfo, flushLogging, getAgent, getAgentEntry, getApp, getInputTypeForMethod, getSkill, getTool, getToolSchemaPath, hydrateSkillRegistry, invalidateProgramCache, listSkills, loadAgentModule, loadConfig, loadEnv, loadTaskDriver, loadToolModule, loadToolSchema, logger, registerAgentHandleFactory, removeSkill, resolveAgentTools, resolveSubAgents, resolveTypeNode, scanTasks, upsertSkill };
package/dist/index.js CHANGED
@@ -2374,79 +2374,113 @@ function assertLogLevel(value, source) {
2374
2374
  );
2375
2375
  }
2376
2376
  }
2377
- var globalState = { level: null, sink: null, fileSink: null, stdout: true, accessLog: false, disabled: false };
2377
+ var LOGGING_STATE_KEY = /* @__PURE__ */ Symbol.for("faapi.logger.state");
2378
+ function createDefaultLoggingState() {
2379
+ return {
2380
+ level: null,
2381
+ consoleLevel: null,
2382
+ sink: null,
2383
+ fileSink: null,
2384
+ stdout: true,
2385
+ accessLog: true,
2386
+ disabled: false
2387
+ };
2388
+ }
2389
+ function getLoggingState() {
2390
+ const g = globalThis;
2391
+ let state2 = g[LOGGING_STATE_KEY];
2392
+ if (!state2) {
2393
+ state2 = createDefaultLoggingState();
2394
+ g[LOGGING_STATE_KEY] = state2;
2395
+ }
2396
+ return state2;
2397
+ }
2378
2398
  function configureLogging(config) {
2399
+ const state2 = getLoggingState();
2379
2400
  const objectConfig = typeof config === "object" ? config : {};
2380
2401
  if (objectConfig.sink && objectConfig.dir) {
2381
2402
  throw new Error(
2382
2403
  "[faapi] config.log.sink and config.log.dir are mutually exclusive: pick one output pipeline (custom sink OR built-in file logs)."
2383
2404
  );
2384
2405
  }
2385
- void globalState.fileSink?.close();
2386
- globalState.disabled = config === false;
2387
- globalState.sink = objectConfig.sink ?? null;
2388
- globalState.accessLog = objectConfig.accessLog ?? objectConfig.dir !== void 0;
2389
- globalState.stdout = objectConfig.stdout ?? true;
2390
- globalState.fileSink = objectConfig.dir ? createFileLogSink({ dir: objectConfig.dir, splitByLevel: objectConfig.splitByLevel }) : null;
2406
+ void state2.fileSink?.close();
2407
+ state2.disabled = config === false;
2408
+ state2.sink = objectConfig.sink ?? null;
2409
+ state2.accessLog = objectConfig.accessLog ?? true;
2410
+ state2.stdout = objectConfig.stdout ?? true;
2411
+ state2.fileSink = objectConfig.dir ? createFileLogSink({ dir: objectConfig.dir, splitByLevel: objectConfig.splitByLevel }) : null;
2412
+ if (objectConfig.consoleLevel !== void 0) {
2413
+ if (objectConfig.consoleLevel !== false) {
2414
+ assertLogLevel(objectConfig.consoleLevel, "config.log.consoleLevel");
2415
+ }
2416
+ state2.consoleLevel = objectConfig.consoleLevel;
2417
+ } else {
2418
+ state2.consoleLevel = null;
2419
+ }
2391
2420
  if (objectConfig.level !== void 0) {
2392
2421
  assertLogLevel(objectConfig.level, "config.log.level");
2393
- globalState.level = objectConfig.level;
2422
+ state2.level = objectConfig.level;
2394
2423
  } else if (process.env.LOG_LEVEL !== void 0) {
2395
2424
  assertLogLevel(process.env.LOG_LEVEL, "LOG_LEVEL env");
2396
- globalState.level = process.env.LOG_LEVEL;
2425
+ state2.level = process.env.LOG_LEVEL;
2397
2426
  } else {
2398
- globalState.level = null;
2427
+ state2.level = null;
2399
2428
  }
2400
2429
  }
2401
- function globalThreshold() {
2402
- if (globalState.level) return globalState.level;
2403
- if (globalState.fileSink) return void 0;
2404
- return "info";
2430
+ function pipelineThreshold() {
2431
+ return getLoggingState().level ?? void 0;
2432
+ }
2433
+ function consoleThreshold() {
2434
+ return getLoggingState().consoleLevel ?? "info";
2405
2435
  }
2406
2436
  function belowThreshold(level, threshold) {
2407
2437
  return threshold !== void 0 && LEVEL_RANK[level] < LEVEL_RANK[threshold];
2408
2438
  }
2409
2439
  function getEffectiveLogLevel() {
2410
- return globalThreshold();
2440
+ return pipelineThreshold();
2411
2441
  }
2412
- var consoleSink = (entry) => {
2413
- console[CONSOLE_METHOD[entry.level]](formatEntry(entry));
2414
- };
2415
2442
  var CONSOLE_METHOD = {
2416
2443
  debug: "debug",
2417
2444
  info: "info",
2418
2445
  warn: "warn",
2419
2446
  error: "error"
2420
2447
  };
2448
+ function consoleDispatch(entry) {
2449
+ const threshold = consoleThreshold();
2450
+ if (threshold === false || belowThreshold(entry.level, threshold)) return;
2451
+ console[CONSOLE_METHOD[entry.level]](formatEntry(entry));
2452
+ }
2421
2453
  function globalDispatch(entry) {
2422
- if (globalState.disabled) return;
2423
- if (globalState.sink) {
2424
- globalState.sink(entry);
2454
+ const state2 = getLoggingState();
2455
+ if (state2.disabled) return;
2456
+ const pipeThreshold = pipelineThreshold();
2457
+ if (state2.sink) {
2458
+ if (!belowThreshold(entry.level, pipeThreshold)) state2.sink(entry);
2425
2459
  return;
2426
2460
  }
2427
- if (globalState.fileSink) {
2428
- globalState.fileSink.write(entry);
2429
- if (globalState.stdout) consoleSink(entry);
2461
+ if (state2.fileSink) {
2462
+ if (!belowThreshold(entry.level, pipeThreshold)) state2.fileSink.write(entry);
2463
+ if (state2.stdout) consoleDispatch(entry);
2430
2464
  return;
2431
2465
  }
2432
- consoleSink(entry);
2466
+ consoleDispatch(entry);
2433
2467
  }
2434
2468
  function writeLogEntry(entry) {
2435
- if (belowThreshold(entry.level, globalThreshold())) return;
2436
2469
  globalDispatch(entry);
2437
2470
  }
2438
2471
  function flushLogging() {
2439
- return globalState.fileSink ? globalState.fileSink.flush() : Promise.resolve();
2472
+ const state2 = getLoggingState();
2473
+ return state2.fileSink ? state2.fileSink.flush() : Promise.resolve();
2440
2474
  }
2441
- function isAccessLogPiped() {
2442
- return !globalState.disabled && globalState.accessLog;
2475
+ function isAccessLogEnabled() {
2476
+ const state2 = getLoggingState();
2477
+ return !state2.disabled && state2.accessLog;
2443
2478
  }
2444
2479
  function createLogger(scope, options) {
2445
2480
  const baseScope = scope;
2446
2481
  const baseFields = options?.fields;
2447
2482
  const write = (level, message, callFields, scopeSuffix) => {
2448
- const threshold = options?.level ?? globalThreshold();
2449
- if (belowThreshold(level, threshold)) return;
2483
+ if (belowThreshold(level, options?.level)) return;
2450
2484
  const entry = {
2451
2485
  level,
2452
2486
  message,
@@ -4017,18 +4051,14 @@ function levelForStatus(status) {
4017
4051
  return "info";
4018
4052
  }
4019
4053
  function defaultLog(entry, text) {
4020
- if (isAccessLogPiped()) {
4021
- const logEntry = {
4022
- level: levelForStatus(entry.status),
4023
- message: text,
4024
- time: (/* @__PURE__ */ new Date()).toISOString(),
4025
- scope: "access",
4026
- fields: entry
4027
- };
4028
- writeLogEntry(logEntry);
4029
- return;
4030
- }
4031
- console.log(entry);
4054
+ if (!isAccessLogEnabled()) return;
4055
+ writeLogEntry({
4056
+ level: levelForStatus(entry.status),
4057
+ message: text,
4058
+ time: (/* @__PURE__ */ new Date()).toISOString(),
4059
+ scope: "access",
4060
+ fields: entry
4061
+ });
4032
4062
  }
4033
4063
  function logger(options = {}) {
4034
4064
  return async (ctx, next) => {
@@ -5941,7 +5971,6 @@ function createServer(options) {
5941
5971
  compression: compressionOption,
5942
5972
  etag: etagOption,
5943
5973
  registries,
5944
- logger: loggerOption,
5945
5974
  bodyLimit = DEFAULT_BODY_LIMIT,
5946
5975
  http2: http2Option,
5947
5976
  trustedProxy = false
@@ -5958,8 +5987,7 @@ function createServer(options) {
5958
5987
  const helmOpts = typeof helmetOption === "object" ? helmetOption : {};
5959
5988
  configMiddlewares.push(helmet(helmOpts));
5960
5989
  }
5961
- const loggerMiddlewareInst = loggerOption === false ? null : loggerOption === true || loggerOption === void 0 ? logger() : logger(loggerOption);
5962
- if (loggerMiddlewareInst) configMiddlewares.push(loggerMiddlewareInst);
5990
+ configMiddlewares.push(logger());
5963
5991
  if (etagOption) {
5964
5992
  const etagOpts = typeof etagOption === "object" ? etagOption : {};
5965
5993
  configMiddlewares.push(etag(etagOpts));
@@ -6941,7 +6969,6 @@ var FAAPI_CONFIG_KEYS = /* @__PURE__ */ new Set([
6941
6969
  "compression",
6942
6970
  "etag",
6943
6971
  "bodyLimit",
6944
- "logger",
6945
6972
  "log",
6946
6973
  "http2",
6947
6974
  "trustedProxy",
@@ -7016,7 +7043,6 @@ async function createAppBase(options) {
7016
7043
  helmet: config?.helmet,
7017
7044
  compression: config?.compression,
7018
7045
  etag: config?.etag,
7019
- logger: config?.logger,
7020
7046
  bodyLimit: config?.bodyLimit,
7021
7047
  http2: config?.http2,
7022
7048
  trustedProxy: config?.trustedProxy,