@faapi/faapi 6.7.0 → 6.9.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 CHANGED
@@ -649,9 +649,9 @@ var init_constants = __esm({
649
649
  });
650
650
 
651
651
  // src/utils/normalizePath.ts
652
- function normalizePath(path31) {
653
- if (!path31) return "";
654
- let result = path31.replace(/\\/g, "/");
652
+ function normalizePath(path32) {
653
+ if (!path32) return "";
654
+ let result = path32.replace(/\\/g, "/");
655
655
  result = result.replace(/\/+/g, "/");
656
656
  result = result.replace(/\/+$/, "");
657
657
  if (result && !result.startsWith("/")) {
@@ -2260,8 +2260,10 @@ var init_resolveInjection = __esm({
2260
2260
  // Phase 2.3
2261
2261
  agents: "agents",
2262
2262
  // Phase 2.3
2263
- tasks: "tasks"
2263
+ tasks: "tasks",
2264
2264
  // 任务子系统:TaskClient(入队/查询)
2265
+ log: "log"
2266
+ // 请求级日志器(ctx.log 同一实例:scope http,自动带 requestId 等字段)
2265
2267
  };
2266
2268
  injectionCache = /* @__PURE__ */ new WeakMap();
2267
2269
  }
@@ -4080,7 +4082,7 @@ var init_esm = __esm({
4080
4082
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
4081
4083
  const statMethod = opts.lstat ? lstat : stat;
4082
4084
  if (wantBigintFsStats) {
4083
- this._stat = (path31) => statMethod(path31, { bigint: true });
4085
+ this._stat = (path32) => statMethod(path32, { bigint: true });
4084
4086
  } else {
4085
4087
  this._stat = statMethod;
4086
4088
  }
@@ -4105,8 +4107,8 @@ var init_esm = __esm({
4105
4107
  const par = this.parent;
4106
4108
  const fil = par && par.files;
4107
4109
  if (fil && fil.length > 0) {
4108
- const { path: path31, depth } = par;
4109
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path31));
4110
+ const { path: path32, depth } = par;
4111
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path32));
4110
4112
  const awaited = await Promise.all(slice);
4111
4113
  for (const entry of awaited) {
4112
4114
  if (!entry)
@@ -4146,20 +4148,20 @@ var init_esm = __esm({
4146
4148
  this.reading = false;
4147
4149
  }
4148
4150
  }
4149
- async _exploreDir(path31, depth) {
4151
+ async _exploreDir(path32, depth) {
4150
4152
  let files;
4151
4153
  try {
4152
- files = await readdir(path31, this._rdOptions);
4154
+ files = await readdir(path32, this._rdOptions);
4153
4155
  } catch (error) {
4154
4156
  this._onError(error);
4155
4157
  }
4156
- return { files, depth, path: path31 };
4158
+ return { files, depth, path: path32 };
4157
4159
  }
4158
- async _formatEntry(dirent, path31) {
4160
+ async _formatEntry(dirent, path32) {
4159
4161
  let entry;
4160
4162
  const basename3 = this._isDirent ? dirent.name : dirent;
4161
4163
  try {
4162
- const fullPath = presolve(pjoin(path31, basename3));
4164
+ const fullPath = presolve(pjoin(path32, basename3));
4163
4165
  entry = { path: prelative(this._root, fullPath), fullPath, basename: basename3 };
4164
4166
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
4165
4167
  } catch (err) {
@@ -4220,16 +4222,16 @@ import { watchFile, unwatchFile, watch as fs_watch } from "fs";
4220
4222
  import { open, stat as stat2, lstat as lstat2, realpath as fsrealpath } from "fs/promises";
4221
4223
  import * as sysPath from "path";
4222
4224
  import { type as osType } from "os";
4223
- function createFsWatchInstance(path31, options, listener, errHandler, emitRaw) {
4225
+ function createFsWatchInstance(path32, options, listener, errHandler, emitRaw) {
4224
4226
  const handleEvent = (rawEvent, evPath) => {
4225
- listener(path31);
4226
- emitRaw(rawEvent, evPath, { watchedPath: path31 });
4227
- if (evPath && path31 !== evPath) {
4228
- fsWatchBroadcast(sysPath.resolve(path31, evPath), KEY_LISTENERS, sysPath.join(path31, evPath));
4227
+ listener(path32);
4228
+ emitRaw(rawEvent, evPath, { watchedPath: path32 });
4229
+ if (evPath && path32 !== evPath) {
4230
+ fsWatchBroadcast(sysPath.resolve(path32, evPath), KEY_LISTENERS, sysPath.join(path32, evPath));
4229
4231
  }
4230
4232
  };
4231
4233
  try {
4232
- return fs_watch(path31, {
4234
+ return fs_watch(path32, {
4233
4235
  persistent: options.persistent
4234
4236
  }, handleEvent);
4235
4237
  } catch (error) {
@@ -4574,12 +4576,12 @@ var init_handler = __esm({
4574
4576
  listener(val1, val2, val3);
4575
4577
  });
4576
4578
  };
4577
- setFsWatchListener = (path31, fullPath, options, handlers) => {
4579
+ setFsWatchListener = (path32, fullPath, options, handlers) => {
4578
4580
  const { listener, errHandler, rawEmitter } = handlers;
4579
4581
  let cont = FsWatchInstances.get(fullPath);
4580
4582
  let watcher;
4581
4583
  if (!options.persistent) {
4582
- watcher = createFsWatchInstance(path31, options, listener, errHandler, rawEmitter);
4584
+ watcher = createFsWatchInstance(path32, options, listener, errHandler, rawEmitter);
4583
4585
  if (!watcher)
4584
4586
  return;
4585
4587
  return watcher.close.bind(watcher);
@@ -4590,7 +4592,7 @@ var init_handler = __esm({
4590
4592
  addAndConvert(cont, KEY_RAW, rawEmitter);
4591
4593
  } else {
4592
4594
  watcher = createFsWatchInstance(
4593
- path31,
4595
+ path32,
4594
4596
  options,
4595
4597
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
4596
4598
  errHandler,
@@ -4605,7 +4607,7 @@ var init_handler = __esm({
4605
4607
  cont.watcherUnusable = true;
4606
4608
  if (isWindows && error.code === "EPERM") {
4607
4609
  try {
4608
- const fd = await open(path31, "r");
4610
+ const fd = await open(path32, "r");
4609
4611
  await fd.close();
4610
4612
  broadcastErr(error);
4611
4613
  } catch (err) {
@@ -4636,7 +4638,7 @@ var init_handler = __esm({
4636
4638
  };
4637
4639
  };
4638
4640
  FsWatchFileInstances = /* @__PURE__ */ new Map();
4639
- setFsWatchFileListener = (path31, fullPath, options, handlers) => {
4641
+ setFsWatchFileListener = (path32, fullPath, options, handlers) => {
4640
4642
  const { listener, rawEmitter } = handlers;
4641
4643
  let cont = FsWatchFileInstances.get(fullPath);
4642
4644
  const copts = cont && cont.options;
@@ -4658,7 +4660,7 @@ var init_handler = __esm({
4658
4660
  });
4659
4661
  const currmtime = curr.mtimeMs;
4660
4662
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
4661
- foreach(cont.listeners, (listener2) => listener2(path31, curr));
4663
+ foreach(cont.listeners, (listener2) => listener2(path32, curr));
4662
4664
  }
4663
4665
  })
4664
4666
  };
@@ -4686,13 +4688,13 @@ var init_handler = __esm({
4686
4688
  * @param listener on fs change
4687
4689
  * @returns closer for the watcher instance
4688
4690
  */
4689
- _watchWithNodeFs(path31, listener) {
4691
+ _watchWithNodeFs(path32, listener) {
4690
4692
  const opts = this.fsw.options;
4691
- const directory = sysPath.dirname(path31);
4692
- const basename3 = sysPath.basename(path31);
4693
+ const directory = sysPath.dirname(path32);
4694
+ const basename3 = sysPath.basename(path32);
4693
4695
  const parent = this.fsw._getWatchedDir(directory);
4694
4696
  parent.add(basename3);
4695
- const absolutePath = sysPath.resolve(path31);
4697
+ const absolutePath = sysPath.resolve(path32);
4696
4698
  const options = {
4697
4699
  persistent: opts.persistent
4698
4700
  };
@@ -4702,12 +4704,12 @@ var init_handler = __esm({
4702
4704
  if (opts.usePolling) {
4703
4705
  const enableBin = opts.interval !== opts.binaryInterval;
4704
4706
  options.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
4705
- closer = setFsWatchFileListener(path31, absolutePath, options, {
4707
+ closer = setFsWatchFileListener(path32, absolutePath, options, {
4706
4708
  listener,
4707
4709
  rawEmitter: this.fsw._emitRaw
4708
4710
  });
4709
4711
  } else {
4710
- closer = setFsWatchListener(path31, absolutePath, options, {
4712
+ closer = setFsWatchListener(path32, absolutePath, options, {
4711
4713
  listener,
4712
4714
  errHandler: this._boundHandleError,
4713
4715
  rawEmitter: this.fsw._emitRaw
@@ -4729,7 +4731,7 @@ var init_handler = __esm({
4729
4731
  let prevStats = stats;
4730
4732
  if (parent.has(basename3))
4731
4733
  return;
4732
- const listener = async (path31, newStats) => {
4734
+ const listener = async (path32, newStats) => {
4733
4735
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
4734
4736
  return;
4735
4737
  if (!newStats || newStats.mtimeMs === 0) {
@@ -4743,11 +4745,11 @@ var init_handler = __esm({
4743
4745
  this.fsw._emit(EV.CHANGE, file, newStats2);
4744
4746
  }
4745
4747
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
4746
- this.fsw._closeFile(path31);
4748
+ this.fsw._closeFile(path32);
4747
4749
  prevStats = newStats2;
4748
4750
  const closer2 = this._watchWithNodeFs(file, listener);
4749
4751
  if (closer2)
4750
- this.fsw._addPathCloser(path31, closer2);
4752
+ this.fsw._addPathCloser(path32, closer2);
4751
4753
  } else {
4752
4754
  prevStats = newStats2;
4753
4755
  }
@@ -4779,7 +4781,7 @@ var init_handler = __esm({
4779
4781
  * @param item basename of this item
4780
4782
  * @returns true if no more processing is needed for this entry.
4781
4783
  */
4782
- async _handleSymlink(entry, directory, path31, item) {
4784
+ async _handleSymlink(entry, directory, path32, item) {
4783
4785
  if (this.fsw.closed) {
4784
4786
  return;
4785
4787
  }
@@ -4789,7 +4791,7 @@ var init_handler = __esm({
4789
4791
  this.fsw._incrReadyCount();
4790
4792
  let linkPath;
4791
4793
  try {
4792
- linkPath = await fsrealpath(path31);
4794
+ linkPath = await fsrealpath(path32);
4793
4795
  } catch (e) {
4794
4796
  this.fsw._emitReady();
4795
4797
  return true;
@@ -4799,12 +4801,12 @@ var init_handler = __esm({
4799
4801
  if (dir.has(item)) {
4800
4802
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
4801
4803
  this.fsw._symlinkPaths.set(full, linkPath);
4802
- this.fsw._emit(EV.CHANGE, path31, entry.stats);
4804
+ this.fsw._emit(EV.CHANGE, path32, entry.stats);
4803
4805
  }
4804
4806
  } else {
4805
4807
  dir.add(item);
4806
4808
  this.fsw._symlinkPaths.set(full, linkPath);
4807
- this.fsw._emit(EV.ADD, path31, entry.stats);
4809
+ this.fsw._emit(EV.ADD, path32, entry.stats);
4808
4810
  }
4809
4811
  this.fsw._emitReady();
4810
4812
  return true;
@@ -4833,9 +4835,9 @@ var init_handler = __esm({
4833
4835
  return;
4834
4836
  }
4835
4837
  const item = entry.path;
4836
- let path31 = sysPath.join(directory, item);
4838
+ let path32 = sysPath.join(directory, item);
4837
4839
  current.add(item);
4838
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path31, item)) {
4840
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path32, item)) {
4839
4841
  return;
4840
4842
  }
4841
4843
  if (this.fsw.closed) {
@@ -4844,8 +4846,8 @@ var init_handler = __esm({
4844
4846
  }
4845
4847
  if (item === target || !target && !previous.has(item)) {
4846
4848
  this.fsw._incrReadyCount();
4847
- path31 = sysPath.join(dir, sysPath.relative(dir, path31));
4848
- this._addToNodeFs(path31, initialAdd, wh, depth + 1);
4849
+ path32 = sysPath.join(dir, sysPath.relative(dir, path32));
4850
+ this._addToNodeFs(path32, initialAdd, wh, depth + 1);
4849
4851
  }
4850
4852
  }).on(EV.ERROR, this._boundHandleError);
4851
4853
  return new Promise((resolve3, reject) => {
@@ -4914,13 +4916,13 @@ var init_handler = __esm({
4914
4916
  * @param depth Child path actually targeted for watch
4915
4917
  * @param target Child path actually targeted for watch
4916
4918
  */
4917
- async _addToNodeFs(path31, initialAdd, priorWh, depth, target) {
4919
+ async _addToNodeFs(path32, initialAdd, priorWh, depth, target) {
4918
4920
  const ready = this.fsw._emitReady;
4919
- if (this.fsw._isIgnored(path31) || this.fsw.closed) {
4921
+ if (this.fsw._isIgnored(path32) || this.fsw.closed) {
4920
4922
  ready();
4921
4923
  return false;
4922
4924
  }
4923
- const wh = this.fsw._getWatchHelpers(path31);
4925
+ const wh = this.fsw._getWatchHelpers(path32);
4924
4926
  if (priorWh) {
4925
4927
  wh.filterPath = (entry) => priorWh.filterPath(entry);
4926
4928
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -4936,8 +4938,8 @@ var init_handler = __esm({
4936
4938
  const follow = this.fsw.options.followSymlinks;
4937
4939
  let closer;
4938
4940
  if (stats.isDirectory()) {
4939
- const absPath = sysPath.resolve(path31);
4940
- const targetPath = follow ? await fsrealpath(path31) : path31;
4941
+ const absPath = sysPath.resolve(path32);
4942
+ const targetPath = follow ? await fsrealpath(path32) : path32;
4941
4943
  if (this.fsw.closed)
4942
4944
  return;
4943
4945
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -4947,29 +4949,29 @@ var init_handler = __esm({
4947
4949
  this.fsw._symlinkPaths.set(absPath, targetPath);
4948
4950
  }
4949
4951
  } else if (stats.isSymbolicLink()) {
4950
- const targetPath = follow ? await fsrealpath(path31) : path31;
4952
+ const targetPath = follow ? await fsrealpath(path32) : path32;
4951
4953
  if (this.fsw.closed)
4952
4954
  return;
4953
4955
  const parent = sysPath.dirname(wh.watchPath);
4954
4956
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
4955
4957
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
4956
- closer = await this._handleDir(parent, stats, initialAdd, depth, path31, wh, targetPath);
4958
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path32, wh, targetPath);
4957
4959
  if (this.fsw.closed)
4958
4960
  return;
4959
4961
  if (targetPath !== void 0) {
4960
- this.fsw._symlinkPaths.set(sysPath.resolve(path31), targetPath);
4962
+ this.fsw._symlinkPaths.set(sysPath.resolve(path32), targetPath);
4961
4963
  }
4962
4964
  } else {
4963
4965
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
4964
4966
  }
4965
4967
  ready();
4966
4968
  if (closer)
4967
- this.fsw._addPathCloser(path31, closer);
4969
+ this.fsw._addPathCloser(path32, closer);
4968
4970
  return false;
4969
4971
  } catch (error) {
4970
4972
  if (this.fsw._handleError(error)) {
4971
4973
  ready();
4972
- return path31;
4974
+ return path32;
4973
4975
  }
4974
4976
  }
4975
4977
  }
@@ -5008,26 +5010,26 @@ function createPattern(matcher) {
5008
5010
  }
5009
5011
  return () => false;
5010
5012
  }
5011
- function normalizePath2(path31) {
5012
- if (typeof path31 !== "string")
5013
+ function normalizePath2(path32) {
5014
+ if (typeof path32 !== "string")
5013
5015
  throw new Error("string expected");
5014
- path31 = sysPath2.normalize(path31);
5015
- path31 = path31.replace(/\\/g, "/");
5016
+ path32 = sysPath2.normalize(path32);
5017
+ path32 = path32.replace(/\\/g, "/");
5016
5018
  let prepend = false;
5017
- if (path31.startsWith("//"))
5019
+ if (path32.startsWith("//"))
5018
5020
  prepend = true;
5019
5021
  const DOUBLE_SLASH_RE2 = /\/\//;
5020
- while (path31.match(DOUBLE_SLASH_RE2))
5021
- path31 = path31.replace(DOUBLE_SLASH_RE2, "/");
5022
+ while (path32.match(DOUBLE_SLASH_RE2))
5023
+ path32 = path32.replace(DOUBLE_SLASH_RE2, "/");
5022
5024
  if (prepend)
5023
- path31 = "/" + path31;
5024
- return path31;
5025
+ path32 = "/" + path32;
5026
+ return path32;
5025
5027
  }
5026
5028
  function matchPatterns(patterns, testString, stats) {
5027
- const path31 = normalizePath2(testString);
5029
+ const path32 = normalizePath2(testString);
5028
5030
  for (let index = 0; index < patterns.length; index++) {
5029
5031
  const pattern = patterns[index];
5030
- if (pattern(path31, stats)) {
5032
+ if (pattern(path32, stats)) {
5031
5033
  return true;
5032
5034
  }
5033
5035
  }
@@ -5088,19 +5090,19 @@ var init_esm2 = __esm({
5088
5090
  }
5089
5091
  return str;
5090
5092
  };
5091
- normalizePathToUnix = (path31) => toUnix(sysPath2.normalize(toUnix(path31)));
5092
- normalizeIgnored = (cwd = "") => (path31) => {
5093
- if (typeof path31 === "string") {
5094
- return normalizePathToUnix(sysPath2.isAbsolute(path31) ? path31 : sysPath2.join(cwd, path31));
5093
+ normalizePathToUnix = (path32) => toUnix(sysPath2.normalize(toUnix(path32)));
5094
+ normalizeIgnored = (cwd = "") => (path32) => {
5095
+ if (typeof path32 === "string") {
5096
+ return normalizePathToUnix(sysPath2.isAbsolute(path32) ? path32 : sysPath2.join(cwd, path32));
5095
5097
  } else {
5096
- return path31;
5098
+ return path32;
5097
5099
  }
5098
5100
  };
5099
- getAbsolutePath = (path31, cwd) => {
5100
- if (sysPath2.isAbsolute(path31)) {
5101
- return path31;
5101
+ getAbsolutePath = (path32, cwd) => {
5102
+ if (sysPath2.isAbsolute(path32)) {
5103
+ return path32;
5102
5104
  }
5103
- return sysPath2.join(cwd, path31);
5105
+ return sysPath2.join(cwd, path32);
5104
5106
  };
5105
5107
  EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
5106
5108
  DirEntry = class {
@@ -5155,10 +5157,10 @@ var init_esm2 = __esm({
5155
5157
  STAT_METHOD_F = "stat";
5156
5158
  STAT_METHOD_L = "lstat";
5157
5159
  WatchHelper = class {
5158
- constructor(path31, follow, fsw) {
5160
+ constructor(path32, follow, fsw) {
5159
5161
  this.fsw = fsw;
5160
- const watchPath = path31;
5161
- this.path = path31 = path31.replace(REPLACER_RE, "");
5162
+ const watchPath = path32;
5163
+ this.path = path32 = path32.replace(REPLACER_RE, "");
5162
5164
  this.watchPath = watchPath;
5163
5165
  this.fullWatchPath = sysPath2.resolve(watchPath);
5164
5166
  this.dirParts = [];
@@ -5280,20 +5282,20 @@ var init_esm2 = __esm({
5280
5282
  this._closePromise = void 0;
5281
5283
  let paths = unifyPaths(paths_);
5282
5284
  if (cwd) {
5283
- paths = paths.map((path31) => {
5284
- const absPath = getAbsolutePath(path31, cwd);
5285
+ paths = paths.map((path32) => {
5286
+ const absPath = getAbsolutePath(path32, cwd);
5285
5287
  return absPath;
5286
5288
  });
5287
5289
  }
5288
- paths.forEach((path31) => {
5289
- this._removeIgnoredPath(path31);
5290
+ paths.forEach((path32) => {
5291
+ this._removeIgnoredPath(path32);
5290
5292
  });
5291
5293
  this._userIgnored = void 0;
5292
5294
  if (!this._readyCount)
5293
5295
  this._readyCount = 0;
5294
5296
  this._readyCount += paths.length;
5295
- Promise.all(paths.map(async (path31) => {
5296
- const res = await this._nodeFsHandler._addToNodeFs(path31, !_internal, void 0, 0, _origAdd);
5297
+ Promise.all(paths.map(async (path32) => {
5298
+ const res = await this._nodeFsHandler._addToNodeFs(path32, !_internal, void 0, 0, _origAdd);
5297
5299
  if (res)
5298
5300
  this._emitReady();
5299
5301
  return res;
@@ -5315,17 +5317,17 @@ var init_esm2 = __esm({
5315
5317
  return this;
5316
5318
  const paths = unifyPaths(paths_);
5317
5319
  const { cwd } = this.options;
5318
- paths.forEach((path31) => {
5319
- if (!sysPath2.isAbsolute(path31) && !this._closers.has(path31)) {
5320
+ paths.forEach((path32) => {
5321
+ if (!sysPath2.isAbsolute(path32) && !this._closers.has(path32)) {
5320
5322
  if (cwd)
5321
- path31 = sysPath2.join(cwd, path31);
5322
- path31 = sysPath2.resolve(path31);
5323
+ path32 = sysPath2.join(cwd, path32);
5324
+ path32 = sysPath2.resolve(path32);
5323
5325
  }
5324
- this._closePath(path31);
5325
- this._addIgnoredPath(path31);
5326
- if (this._watched.has(path31)) {
5326
+ this._closePath(path32);
5327
+ this._addIgnoredPath(path32);
5328
+ if (this._watched.has(path32)) {
5327
5329
  this._addIgnoredPath({
5328
- path: path31,
5330
+ path: path32,
5329
5331
  recursive: true
5330
5332
  });
5331
5333
  }
@@ -5389,38 +5391,38 @@ var init_esm2 = __esm({
5389
5391
  * @param stats arguments to be passed with event
5390
5392
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
5391
5393
  */
5392
- async _emit(event, path31, stats) {
5394
+ async _emit(event, path32, stats) {
5393
5395
  if (this.closed)
5394
5396
  return;
5395
5397
  const opts = this.options;
5396
5398
  if (isWindows)
5397
- path31 = sysPath2.normalize(path31);
5399
+ path32 = sysPath2.normalize(path32);
5398
5400
  if (opts.cwd)
5399
- path31 = sysPath2.relative(opts.cwd, path31);
5400
- const args = [path31];
5401
+ path32 = sysPath2.relative(opts.cwd, path32);
5402
+ const args = [path32];
5401
5403
  if (stats != null)
5402
5404
  args.push(stats);
5403
5405
  const awf = opts.awaitWriteFinish;
5404
5406
  let pw;
5405
- if (awf && (pw = this._pendingWrites.get(path31))) {
5407
+ if (awf && (pw = this._pendingWrites.get(path32))) {
5406
5408
  pw.lastChange = /* @__PURE__ */ new Date();
5407
5409
  return this;
5408
5410
  }
5409
5411
  if (opts.atomic) {
5410
5412
  if (event === EVENTS.UNLINK) {
5411
- this._pendingUnlinks.set(path31, [event, ...args]);
5413
+ this._pendingUnlinks.set(path32, [event, ...args]);
5412
5414
  setTimeout(() => {
5413
- this._pendingUnlinks.forEach((entry, path32) => {
5415
+ this._pendingUnlinks.forEach((entry, path33) => {
5414
5416
  this.emit(...entry);
5415
5417
  this.emit(EVENTS.ALL, ...entry);
5416
- this._pendingUnlinks.delete(path32);
5418
+ this._pendingUnlinks.delete(path33);
5417
5419
  });
5418
5420
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
5419
5421
  return this;
5420
5422
  }
5421
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path31)) {
5423
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path32)) {
5422
5424
  event = EVENTS.CHANGE;
5423
- this._pendingUnlinks.delete(path31);
5425
+ this._pendingUnlinks.delete(path32);
5424
5426
  }
5425
5427
  }
5426
5428
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -5438,16 +5440,16 @@ var init_esm2 = __esm({
5438
5440
  this.emitWithAll(event, args);
5439
5441
  }
5440
5442
  };
5441
- this._awaitWriteFinish(path31, awf.stabilityThreshold, event, awfEmit);
5443
+ this._awaitWriteFinish(path32, awf.stabilityThreshold, event, awfEmit);
5442
5444
  return this;
5443
5445
  }
5444
5446
  if (event === EVENTS.CHANGE) {
5445
- const isThrottled = !this._throttle(EVENTS.CHANGE, path31, 50);
5447
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path32, 50);
5446
5448
  if (isThrottled)
5447
5449
  return this;
5448
5450
  }
5449
5451
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
5450
- const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path31) : path31;
5452
+ const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path32) : path32;
5451
5453
  let stats2;
5452
5454
  try {
5453
5455
  stats2 = await stat3(fullPath);
@@ -5478,23 +5480,23 @@ var init_esm2 = __esm({
5478
5480
  * @param timeout duration of time to suppress duplicate actions
5479
5481
  * @returns tracking object or false if action should be suppressed
5480
5482
  */
5481
- _throttle(actionType, path31, timeout) {
5483
+ _throttle(actionType, path32, timeout) {
5482
5484
  if (!this._throttled.has(actionType)) {
5483
5485
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
5484
5486
  }
5485
5487
  const action = this._throttled.get(actionType);
5486
5488
  if (!action)
5487
5489
  throw new Error("invalid throttle");
5488
- const actionPath = action.get(path31);
5490
+ const actionPath = action.get(path32);
5489
5491
  if (actionPath) {
5490
5492
  actionPath.count++;
5491
5493
  return false;
5492
5494
  }
5493
5495
  let timeoutObject;
5494
5496
  const clear = () => {
5495
- const item = action.get(path31);
5497
+ const item = action.get(path32);
5496
5498
  const count = item ? item.count : 0;
5497
- action.delete(path31);
5499
+ action.delete(path32);
5498
5500
  clearTimeout(timeoutObject);
5499
5501
  if (item)
5500
5502
  clearTimeout(item.timeoutObject);
@@ -5502,7 +5504,7 @@ var init_esm2 = __esm({
5502
5504
  };
5503
5505
  timeoutObject = setTimeout(clear, timeout);
5504
5506
  const thr = { timeoutObject, clear, count: 0 };
5505
- action.set(path31, thr);
5507
+ action.set(path32, thr);
5506
5508
  return thr;
5507
5509
  }
5508
5510
  _incrReadyCount() {
@@ -5516,44 +5518,44 @@ var init_esm2 = __esm({
5516
5518
  * @param event
5517
5519
  * @param awfEmit Callback to be called when ready for event to be emitted.
5518
5520
  */
5519
- _awaitWriteFinish(path31, threshold, event, awfEmit) {
5521
+ _awaitWriteFinish(path32, threshold, event, awfEmit) {
5520
5522
  const awf = this.options.awaitWriteFinish;
5521
5523
  if (typeof awf !== "object")
5522
5524
  return;
5523
5525
  const pollInterval = awf.pollInterval;
5524
5526
  let timeoutHandler;
5525
- let fullPath = path31;
5526
- if (this.options.cwd && !sysPath2.isAbsolute(path31)) {
5527
- fullPath = sysPath2.join(this.options.cwd, path31);
5527
+ let fullPath = path32;
5528
+ if (this.options.cwd && !sysPath2.isAbsolute(path32)) {
5529
+ fullPath = sysPath2.join(this.options.cwd, path32);
5528
5530
  }
5529
5531
  const now = /* @__PURE__ */ new Date();
5530
5532
  const writes = this._pendingWrites;
5531
5533
  function awaitWriteFinishFn(prevStat) {
5532
5534
  statcb(fullPath, (err, curStat) => {
5533
- if (err || !writes.has(path31)) {
5535
+ if (err || !writes.has(path32)) {
5534
5536
  if (err && err.code !== "ENOENT")
5535
5537
  awfEmit(err);
5536
5538
  return;
5537
5539
  }
5538
5540
  const now2 = Number(/* @__PURE__ */ new Date());
5539
5541
  if (prevStat && curStat.size !== prevStat.size) {
5540
- writes.get(path31).lastChange = now2;
5542
+ writes.get(path32).lastChange = now2;
5541
5543
  }
5542
- const pw = writes.get(path31);
5544
+ const pw = writes.get(path32);
5543
5545
  const df = now2 - pw.lastChange;
5544
5546
  if (df >= threshold) {
5545
- writes.delete(path31);
5547
+ writes.delete(path32);
5546
5548
  awfEmit(void 0, curStat);
5547
5549
  } else {
5548
5550
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
5549
5551
  }
5550
5552
  });
5551
5553
  }
5552
- if (!writes.has(path31)) {
5553
- writes.set(path31, {
5554
+ if (!writes.has(path32)) {
5555
+ writes.set(path32, {
5554
5556
  lastChange: now,
5555
5557
  cancelWait: () => {
5556
- writes.delete(path31);
5558
+ writes.delete(path32);
5557
5559
  clearTimeout(timeoutHandler);
5558
5560
  return event;
5559
5561
  }
@@ -5564,8 +5566,8 @@ var init_esm2 = __esm({
5564
5566
  /**
5565
5567
  * Determines whether user has asked to ignore this path.
5566
5568
  */
5567
- _isIgnored(path31, stats) {
5568
- if (this.options.atomic && DOT_RE.test(path31))
5569
+ _isIgnored(path32, stats) {
5570
+ if (this.options.atomic && DOT_RE.test(path32))
5569
5571
  return true;
5570
5572
  if (!this._userIgnored) {
5571
5573
  const { cwd } = this.options;
@@ -5575,17 +5577,17 @@ var init_esm2 = __esm({
5575
5577
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
5576
5578
  this._userIgnored = anymatch(list, void 0);
5577
5579
  }
5578
- return this._userIgnored(path31, stats);
5580
+ return this._userIgnored(path32, stats);
5579
5581
  }
5580
- _isntIgnored(path31, stat4) {
5581
- return !this._isIgnored(path31, stat4);
5582
+ _isntIgnored(path32, stat4) {
5583
+ return !this._isIgnored(path32, stat4);
5582
5584
  }
5583
5585
  /**
5584
5586
  * Provides a set of common helpers and properties relating to symlink handling.
5585
5587
  * @param path file or directory pattern being watched
5586
5588
  */
5587
- _getWatchHelpers(path31) {
5588
- return new WatchHelper(path31, this.options.followSymlinks, this);
5589
+ _getWatchHelpers(path32) {
5590
+ return new WatchHelper(path32, this.options.followSymlinks, this);
5589
5591
  }
5590
5592
  // Directory helpers
5591
5593
  // -----------------
@@ -5617,63 +5619,63 @@ var init_esm2 = __esm({
5617
5619
  * @param item base path of item/directory
5618
5620
  */
5619
5621
  _remove(directory, item, isDirectory) {
5620
- const path31 = sysPath2.join(directory, item);
5621
- const fullPath = sysPath2.resolve(path31);
5622
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path31) || this._watched.has(fullPath);
5623
- if (!this._throttle("remove", path31, 100))
5622
+ const path32 = sysPath2.join(directory, item);
5623
+ const fullPath = sysPath2.resolve(path32);
5624
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path32) || this._watched.has(fullPath);
5625
+ if (!this._throttle("remove", path32, 100))
5624
5626
  return;
5625
5627
  if (!isDirectory && this._watched.size === 1) {
5626
5628
  this.add(directory, item, true);
5627
5629
  }
5628
- const wp = this._getWatchedDir(path31);
5630
+ const wp = this._getWatchedDir(path32);
5629
5631
  const nestedDirectoryChildren = wp.getChildren();
5630
- nestedDirectoryChildren.forEach((nested) => this._remove(path31, nested));
5632
+ nestedDirectoryChildren.forEach((nested) => this._remove(path32, nested));
5631
5633
  const parent = this._getWatchedDir(directory);
5632
5634
  const wasTracked = parent.has(item);
5633
5635
  parent.remove(item);
5634
5636
  if (this._symlinkPaths.has(fullPath)) {
5635
5637
  this._symlinkPaths.delete(fullPath);
5636
5638
  }
5637
- let relPath = path31;
5639
+ let relPath = path32;
5638
5640
  if (this.options.cwd)
5639
- relPath = sysPath2.relative(this.options.cwd, path31);
5641
+ relPath = sysPath2.relative(this.options.cwd, path32);
5640
5642
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
5641
5643
  const event = this._pendingWrites.get(relPath).cancelWait();
5642
5644
  if (event === EVENTS.ADD)
5643
5645
  return;
5644
5646
  }
5645
- this._watched.delete(path31);
5647
+ this._watched.delete(path32);
5646
5648
  this._watched.delete(fullPath);
5647
5649
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
5648
- if (wasTracked && !this._isIgnored(path31))
5649
- this._emit(eventName, path31);
5650
- this._closePath(path31);
5650
+ if (wasTracked && !this._isIgnored(path32))
5651
+ this._emit(eventName, path32);
5652
+ this._closePath(path32);
5651
5653
  }
5652
5654
  /**
5653
5655
  * Closes all watchers for a path
5654
5656
  */
5655
- _closePath(path31) {
5656
- this._closeFile(path31);
5657
- const dir = sysPath2.dirname(path31);
5658
- this._getWatchedDir(dir).remove(sysPath2.basename(path31));
5657
+ _closePath(path32) {
5658
+ this._closeFile(path32);
5659
+ const dir = sysPath2.dirname(path32);
5660
+ this._getWatchedDir(dir).remove(sysPath2.basename(path32));
5659
5661
  }
5660
5662
  /**
5661
5663
  * Closes only file-specific watchers
5662
5664
  */
5663
- _closeFile(path31) {
5664
- const closers = this._closers.get(path31);
5665
+ _closeFile(path32) {
5666
+ const closers = this._closers.get(path32);
5665
5667
  if (!closers)
5666
5668
  return;
5667
5669
  closers.forEach((closer) => closer());
5668
- this._closers.delete(path31);
5670
+ this._closers.delete(path32);
5669
5671
  }
5670
- _addPathCloser(path31, closer) {
5672
+ _addPathCloser(path32, closer) {
5671
5673
  if (!closer)
5672
5674
  return;
5673
- let list = this._closers.get(path31);
5675
+ let list = this._closers.get(path32);
5674
5676
  if (!list) {
5675
5677
  list = [];
5676
- this._closers.set(path31, list);
5678
+ this._closers.set(path32, list);
5677
5679
  }
5678
5680
  list.push(closer);
5679
5681
  }
@@ -5918,18 +5920,18 @@ function getWsIndex(routes) {
5918
5920
  wsIndexCache.set(routes, index);
5919
5921
  return index;
5920
5922
  }
5921
- function matchRoute(routes, method, path31) {
5923
+ function matchRoute(routes, method, path32) {
5922
5924
  const index = getHttpIndex(routes);
5923
5925
  const upper = method.toUpperCase();
5924
- const hit = matchByMethod(index, upper, path31);
5926
+ const hit = matchByMethod(index, upper, path32);
5925
5927
  if (hit) return hit;
5926
5928
  if (upper === "HEAD") {
5927
- return matchByMethod(index, "GET", path31);
5929
+ return matchByMethod(index, "GET", path32);
5928
5930
  }
5929
5931
  return null;
5930
5932
  }
5931
- function matchByMethod(index, method, path31) {
5932
- const staticHit = index.static.get(`${method}|${path31}`);
5933
+ function matchByMethod(index, method, path32) {
5934
+ const staticHit = index.static.get(`${method}|${path32}`);
5933
5935
  if (staticHit) {
5934
5936
  return { route: staticHit, params: {} };
5935
5937
  }
@@ -5938,31 +5940,31 @@ function matchByMethod(index, method, path31) {
5938
5940
  if (route.method !== method) {
5939
5941
  continue;
5940
5942
  }
5941
- const params = matchSegments(entry.segments, path31, route.paramNames, route.isCatchAll);
5943
+ const params = matchSegments(entry.segments, path32, route.paramNames, route.isCatchAll);
5942
5944
  if (params !== null) {
5943
5945
  return { route, params };
5944
5946
  }
5945
5947
  }
5946
5948
  return null;
5947
5949
  }
5948
- function matchWsRoute(wsRoutes, path31) {
5950
+ function matchWsRoute(wsRoutes, path32) {
5949
5951
  const index = getWsIndex(wsRoutes);
5950
- const staticHit = index.static.get(path31);
5952
+ const staticHit = index.static.get(path32);
5951
5953
  if (staticHit) {
5952
5954
  return { route: staticHit, params: {} };
5953
5955
  }
5954
5956
  for (const route of index.dynamics) {
5955
- const params = matchDynamicPath(route.urlPath, path31, route.paramNames, route.isCatchAll);
5957
+ const params = matchDynamicPath(route.urlPath, path32, route.paramNames, route.isCatchAll);
5956
5958
  if (params !== null) {
5957
5959
  return { route, params };
5958
5960
  }
5959
5961
  }
5960
5962
  return null;
5961
5963
  }
5962
- function findAllowedMethods(routes, path31) {
5964
+ function findAllowedMethods(routes, path32) {
5963
5965
  const index = getHttpIndex(routes);
5964
5966
  const methods = /* @__PURE__ */ new Set();
5965
- const staticMethods = index.methodsByStaticPath.get(path31);
5967
+ const staticMethods = index.methodsByStaticPath.get(path32);
5966
5968
  if (staticMethods) {
5967
5969
  for (const method of staticMethods) {
5968
5970
  methods.add(method);
@@ -5971,7 +5973,7 @@ function findAllowedMethods(routes, path31) {
5971
5973
  for (const entry of index.dynamics) {
5972
5974
  const params = matchSegments(
5973
5975
  entry.segments,
5974
- path31,
5976
+ path32,
5975
5977
  entry.route.paramNames,
5976
5978
  entry.route.isCatchAll
5977
5979
  );
@@ -5984,11 +5986,11 @@ function findAllowedMethods(routes, path31) {
5984
5986
  }
5985
5987
  return Array.from(methods);
5986
5988
  }
5987
- function matchDynamicPath(pattern, path31, paramNames, isCatchAll) {
5988
- return matchSegments(pattern.split("/").filter(Boolean), path31, paramNames, isCatchAll);
5989
+ function matchDynamicPath(pattern, path32, paramNames, isCatchAll) {
5990
+ return matchSegments(pattern.split("/").filter(Boolean), path32, paramNames, isCatchAll);
5989
5991
  }
5990
- function matchSegments(patternSegments, path31, paramNames, isCatchAll) {
5991
- const pathSegments = path31.split("/").filter(Boolean);
5992
+ function matchSegments(patternSegments, path32, paramNames, isCatchAll) {
5993
+ const pathSegments = path32.split("/").filter(Boolean);
5992
5994
  if (isCatchAll) {
5993
5995
  const nonCatchAllCount = patternSegments.length - 1;
5994
5996
  if (pathSegments.length <= nonCatchAllCount) {
@@ -6261,14 +6263,14 @@ var init_httpErrors = __esm({
6261
6263
  issues;
6262
6264
  };
6263
6265
  RouteNotFoundError = class extends FaapiError {
6264
- constructor(path31) {
6265
- super("ROUTE_NOT_FOUND", `Route not found: ${path31}`, 404);
6266
+ constructor(path32) {
6267
+ super("ROUTE_NOT_FOUND", `Route not found: ${path32}`, 404);
6266
6268
  this.name = "RouteNotFoundError";
6267
6269
  }
6268
6270
  };
6269
6271
  MethodNotAllowedError = class extends FaapiError {
6270
- constructor(method, path31, allowedMethods) {
6271
- super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path31}`, 405);
6272
+ constructor(method, path32, allowedMethods) {
6273
+ super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path32}`, 405);
6272
6274
  this.allowedMethods = allowedMethods;
6273
6275
  this.name = "MethodNotAllowedError";
6274
6276
  }
@@ -6386,7 +6388,228 @@ var init_responseFormatter = __esm({
6386
6388
  }
6387
6389
  });
6388
6390
 
6391
+ // src/logger/formatEntry.ts
6392
+ function serializeFieldValue(value) {
6393
+ if (value instanceof Error) {
6394
+ return { name: value.name, message: value.message, stack: value.stack };
6395
+ }
6396
+ return value;
6397
+ }
6398
+ function formatEntry(entry) {
6399
+ let line = `[${entry.time}] ${entry.level.toUpperCase()} `;
6400
+ if (entry.scope) line += `[${entry.scope}] `;
6401
+ line += entry.message;
6402
+ if (entry.fields !== void 0) {
6403
+ const plain = Object.fromEntries(
6404
+ Object.entries(entry.fields).map(([k, v]) => [k, serializeFieldValue(v)])
6405
+ );
6406
+ try {
6407
+ line += ` ${JSON.stringify(plain)}`;
6408
+ } catch (err) {
6409
+ line += ` [unserializable fields: ${err instanceof Error ? err.message : String(err)}]`;
6410
+ }
6411
+ }
6412
+ return line;
6413
+ }
6414
+ var init_formatEntry = __esm({
6415
+ "src/logger/formatEntry.ts"() {
6416
+ "use strict";
6417
+ }
6418
+ });
6419
+
6420
+ // src/logger/fileSink.ts
6421
+ import fs17 from "fs";
6422
+ import path23 from "path";
6423
+ function createFileLogSink(options) {
6424
+ fs17.mkdirSync(options.dir, { recursive: true });
6425
+ const streams = /* @__PURE__ */ new Map();
6426
+ const getStream = (name) => {
6427
+ if (streams.has(name)) return streams.get(name);
6428
+ return void 0;
6429
+ };
6430
+ const openStream = (name) => {
6431
+ const stream = fs17.createWriteStream(path23.join(options.dir, `${name}.log`), { flags: "a" });
6432
+ stream.on("error", () => {
6433
+ });
6434
+ streams.set(name, stream);
6435
+ };
6436
+ const fileNames = options.splitByLevel ? [...LEVEL_FILES] : ["app", "error"];
6437
+ for (const name of fileNames) openStream(name);
6438
+ let pendingCount = 0;
6439
+ let drainWaiters = [];
6440
+ const onWriteDone = () => {
6441
+ pendingCount--;
6442
+ if (pendingCount === 0 && drainWaiters.length > 0) {
6443
+ const waiters = drainWaiters;
6444
+ drainWaiters = [];
6445
+ for (const waiter of waiters) waiter();
6446
+ }
6447
+ };
6448
+ const write = (entry) => {
6449
+ const line = `${formatEntry(entry)}
6450
+ `;
6451
+ const target = options.splitByLevel ? entry.level : "app";
6452
+ const main = getStream(target);
6453
+ if (main) {
6454
+ pendingCount++;
6455
+ main.write(line, onWriteDone);
6456
+ }
6457
+ if (!options.splitByLevel && entry.level === "error") {
6458
+ const dup = getStream("error");
6459
+ if (dup) {
6460
+ pendingCount++;
6461
+ dup.write(line, onWriteDone);
6462
+ }
6463
+ }
6464
+ };
6465
+ const flush = () => new Promise((resolve3) => {
6466
+ if (pendingCount === 0) {
6467
+ resolve3();
6468
+ return;
6469
+ }
6470
+ drainWaiters.push(resolve3);
6471
+ });
6472
+ const close = () => Promise.all(
6473
+ [...streams.values()].map(
6474
+ (stream) => new Promise((resolve3) => {
6475
+ stream.end(() => resolve3());
6476
+ })
6477
+ )
6478
+ ).then(() => {
6479
+ streams.clear();
6480
+ });
6481
+ return { write, flush, close };
6482
+ }
6483
+ var LEVEL_FILES;
6484
+ var init_fileSink = __esm({
6485
+ "src/logger/fileSink.ts"() {
6486
+ "use strict";
6487
+ init_formatEntry();
6488
+ LEVEL_FILES = ["debug", "info", "warn", "error"];
6489
+ }
6490
+ });
6491
+
6492
+ // src/logger/logger.ts
6493
+ function assertLogLevel(value, source) {
6494
+ if (typeof value !== "string" || !VALID_LEVELS.includes(value)) {
6495
+ throw new Error(
6496
+ `[faapi] Invalid log level from ${source}: ${String(value)}. Expected one of: ${VALID_LEVELS.join(", ")}.`
6497
+ );
6498
+ }
6499
+ }
6500
+ function configureLogging(config) {
6501
+ const objectConfig = typeof config === "object" ? config : {};
6502
+ if (objectConfig.sink && objectConfig.dir) {
6503
+ throw new Error(
6504
+ "[faapi] config.log.sink and config.log.dir are mutually exclusive: pick one output pipeline (custom sink OR built-in file logs)."
6505
+ );
6506
+ }
6507
+ void globalState.fileSink?.close();
6508
+ globalState.disabled = config === false;
6509
+ globalState.sink = objectConfig.sink ?? null;
6510
+ globalState.accessLog = objectConfig.accessLog ?? objectConfig.dir !== void 0;
6511
+ globalState.stdout = objectConfig.stdout ?? true;
6512
+ globalState.fileSink = objectConfig.dir ? createFileLogSink({ dir: objectConfig.dir, splitByLevel: objectConfig.splitByLevel }) : null;
6513
+ if (objectConfig.level !== void 0) {
6514
+ assertLogLevel(objectConfig.level, "config.log.level");
6515
+ globalState.level = objectConfig.level;
6516
+ } else if (process.env.LOG_LEVEL !== void 0) {
6517
+ assertLogLevel(process.env.LOG_LEVEL, "LOG_LEVEL env");
6518
+ globalState.level = process.env.LOG_LEVEL;
6519
+ } else {
6520
+ globalState.level = null;
6521
+ }
6522
+ }
6523
+ function globalThreshold() {
6524
+ if (globalState.level) return globalState.level;
6525
+ if (globalState.fileSink) return void 0;
6526
+ return "info";
6527
+ }
6528
+ function belowThreshold(level, threshold) {
6529
+ return threshold !== void 0 && LEVEL_RANK[level] < LEVEL_RANK[threshold];
6530
+ }
6531
+ function getEffectiveLogLevel() {
6532
+ return globalThreshold();
6533
+ }
6534
+ function globalDispatch(entry) {
6535
+ if (globalState.disabled) return;
6536
+ if (globalState.sink) {
6537
+ globalState.sink(entry);
6538
+ return;
6539
+ }
6540
+ if (globalState.fileSink) {
6541
+ globalState.fileSink.write(entry);
6542
+ if (globalState.stdout) consoleSink(entry);
6543
+ return;
6544
+ }
6545
+ consoleSink(entry);
6546
+ }
6547
+ function writeLogEntry(entry) {
6548
+ if (belowThreshold(entry.level, globalThreshold())) return;
6549
+ globalDispatch(entry);
6550
+ }
6551
+ function isAccessLogPiped() {
6552
+ return !globalState.disabled && globalState.accessLog;
6553
+ }
6554
+ function createLogger(scope, options) {
6555
+ const baseScope = scope;
6556
+ const baseFields = options?.fields;
6557
+ const write = (level, message, callFields, scopeSuffix) => {
6558
+ const threshold = options?.level ?? globalThreshold();
6559
+ if (belowThreshold(level, threshold)) return;
6560
+ const entry = {
6561
+ level,
6562
+ message,
6563
+ time: (/* @__PURE__ */ new Date()).toISOString()
6564
+ };
6565
+ const fullScope = scopeSuffix === void 0 ? baseScope : baseScope === void 0 ? scopeSuffix : `${baseScope}:${scopeSuffix}`;
6566
+ if (fullScope !== void 0) entry.scope = fullScope;
6567
+ if (baseFields !== void 0 || callFields !== void 0) {
6568
+ entry.fields = { ...baseFields, ...callFields };
6569
+ }
6570
+ if (options?.sink) {
6571
+ options.sink(entry);
6572
+ } else {
6573
+ globalDispatch(entry);
6574
+ }
6575
+ };
6576
+ const makeLogger = (scopeSuffix) => ({
6577
+ debug: (message, fields) => write("debug", message, fields, scopeSuffix),
6578
+ info: (message, fields) => write("info", message, fields, scopeSuffix),
6579
+ warn: (message, fields) => write("warn", message, fields, scopeSuffix),
6580
+ error: (message, fields) => write("error", message, fields, scopeSuffix),
6581
+ child: (childScope) => makeLogger(scopeSuffix === void 0 ? childScope : `${scopeSuffix}:${childScope}`)
6582
+ });
6583
+ return makeLogger(void 0);
6584
+ }
6585
+ var LEVEL_RANK, VALID_LEVELS, globalState, consoleSink, CONSOLE_METHOD;
6586
+ var init_logger = __esm({
6587
+ "src/logger/logger.ts"() {
6588
+ "use strict";
6589
+ init_formatEntry();
6590
+ init_fileSink();
6591
+ LEVEL_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
6592
+ VALID_LEVELS = ["debug", "info", "warn", "error"];
6593
+ globalState = { level: null, sink: null, fileSink: null, stdout: true, accessLog: false, disabled: false };
6594
+ consoleSink = (entry) => {
6595
+ console[CONSOLE_METHOD[entry.level]](formatEntry(entry));
6596
+ };
6597
+ CONSOLE_METHOD = {
6598
+ debug: "debug",
6599
+ info: "info",
6600
+ warn: "warn",
6601
+ error: "error"
6602
+ };
6603
+ }
6604
+ });
6605
+
6389
6606
  // src/runtime/createContext.ts
6607
+ function resolveRequestId(request) {
6608
+ const header = request.headers.get("x-request-id");
6609
+ const first = header?.split(",")[0]?.trim();
6610
+ if (first) return first;
6611
+ return crypto.randomUUID();
6612
+ }
6390
6613
  function parseCookies(cookieHeader) {
6391
6614
  const cookies = /* @__PURE__ */ new Map();
6392
6615
  if (!cookieHeader) return cookies;
@@ -6420,7 +6643,13 @@ function createContextFromUrl(request, url, params, config = {}, ip = "", regist
6420
6643
  for (const [key, val] of parsedCookies) {
6421
6644
  cookiesObj[key] = val;
6422
6645
  }
6646
+ const requestId = resolveRequestId(request);
6647
+ const log = createLogger("http", {
6648
+ fields: { requestId, method: request.method, path: url.pathname }
6649
+ });
6423
6650
  const ctx = {
6651
+ requestId,
6652
+ log,
6424
6653
  request,
6425
6654
  params,
6426
6655
  query: url.searchParams,
@@ -6525,6 +6754,7 @@ var init_createContext = __esm({
6525
6754
  "use strict";
6526
6755
  init_sse();
6527
6756
  init_responseFormatter();
6757
+ init_logger();
6528
6758
  }
6529
6759
  });
6530
6760
 
@@ -7092,6 +7322,9 @@ function getBuiltinInjectionValue(type, ctx, body) {
7092
7322
  // 任务子系统:注入 TaskClient(入队/查询);未注册工厂(无 app 编排)时 undefined
7093
7323
  case "tasks":
7094
7324
  return ctx.registries ? ctx.registries.taskHandle.get(ctx) : void 0;
7325
+ // 请求级日志器:与 ctx.log 同一实例(scope http,自动带 requestId/method/path 字段)
7326
+ case "log":
7327
+ return ctx.log;
7095
7328
  default:
7096
7329
  return void 0;
7097
7330
  }
@@ -7308,9 +7541,9 @@ async function validateInput(schemaPath, method, inputType, input) {
7308
7541
  function mapZodIssues(error) {
7309
7542
  return error.issues.map((issue) => {
7310
7543
  const code = mapZodCode(issue);
7311
- const path31 = issue.path.map(String).join(".") || "";
7544
+ const path32 = issue.path.map(String).join(".") || "";
7312
7545
  return {
7313
- path: path31,
7546
+ path: path32,
7314
7547
  code,
7315
7548
  expected: issue.expected ?? mapExpectedFromMessage(issue.message),
7316
7549
  received: issue.received ?? mapReceivedFromMessage(issue.message),
@@ -7708,14 +7941,34 @@ var init_etag = __esm({
7708
7941
  });
7709
7942
 
7710
7943
  // src/middleware/logger.ts
7944
+ function levelForStatus(status) {
7945
+ if (status >= 500) return "error";
7946
+ if (status >= 400) return "warn";
7947
+ return "info";
7948
+ }
7949
+ function defaultLog(entry, text) {
7950
+ if (isAccessLogPiped()) {
7951
+ const logEntry = {
7952
+ level: levelForStatus(entry.status),
7953
+ message: text,
7954
+ time: (/* @__PURE__ */ new Date()).toISOString(),
7955
+ scope: "access",
7956
+ fields: entry
7957
+ };
7958
+ writeLogEntry(logEntry);
7959
+ return;
7960
+ }
7961
+ console.log(entry);
7962
+ }
7711
7963
  function logger(options = {}) {
7712
7964
  return async (ctx, next) => {
7713
- const log = options.log ?? console.log;
7965
+ const log = options.log ?? defaultLog;
7714
7966
  const start = Date.now();
7715
7967
  try {
7716
7968
  const response = await next();
7717
7969
  const duration = Date.now() - start;
7718
7970
  const entry = {
7971
+ requestId: ctx.requestId,
7719
7972
  method: ctx.method,
7720
7973
  path: ctx.path,
7721
7974
  status: response.status,
@@ -7728,6 +7981,7 @@ function logger(options = {}) {
7728
7981
  const message = err instanceof Error ? err.message : String(err);
7729
7982
  const status = err?.statusCode ?? 500;
7730
7983
  const entry = {
7984
+ requestId: ctx.requestId,
7731
7985
  method: ctx.method,
7732
7986
  path: ctx.path,
7733
7987
  status,
@@ -7739,9 +7993,10 @@ function logger(options = {}) {
7739
7993
  }
7740
7994
  };
7741
7995
  }
7742
- var init_logger = __esm({
7996
+ var init_logger2 = __esm({
7743
7997
  "src/middleware/logger.ts"() {
7744
7998
  "use strict";
7999
+ init_logger();
7745
8000
  }
7746
8001
  });
7747
8002
 
@@ -7808,9 +8063,9 @@ var init_wsHandler = __esm({
7808
8063
  });
7809
8064
 
7810
8065
  // src/server/handleWsUpgrade.ts
7811
- import fs17 from "fs";
8066
+ import fs18 from "fs";
7812
8067
  import { WebSocketServer, WebSocket } from "ws";
7813
- import path23 from "path";
8068
+ import path24 from "path";
7814
8069
  function getPathname(req) {
7815
8070
  const url = req.url ?? "/";
7816
8071
  const idx = url.indexOf("?");
@@ -7821,7 +8076,7 @@ async function loadWsHandler(filePath, ctx, rootDir) {
7821
8076
  const dist = getDevDist();
7822
8077
  if (dist) {
7823
8078
  const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
7824
- if (sourcePath && fs17.existsSync(sourcePath)) {
8079
+ if (sourcePath && fs18.existsSync(sourcePath)) {
7825
8080
  await ensureCompiled(sourcePath, rootDir, dist);
7826
8081
  }
7827
8082
  }
@@ -7935,7 +8190,7 @@ function attachWebSocket(options) {
7935
8190
  const finalHandler = async () => {
7936
8191
  let handlers;
7937
8192
  try {
7938
- const absoluteFilePath = path23.resolve(rootDir, route.filePath);
8193
+ const absoluteFilePath = path24.resolve(rootDir, route.filePath);
7939
8194
  handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
7940
8195
  } catch (err) {
7941
8196
  const reason = err instanceof Error ? err.message : String(err);
@@ -8011,7 +8266,7 @@ import {
8011
8266
  import { createSecureServer as createHttp2SecureServer } from "http2";
8012
8267
  import { readFileSync } from "fs";
8013
8268
  import { Readable as Readable3 } from "stream";
8014
- import path24 from "path";
8269
+ import path25 from "path";
8015
8270
  function toWebRequest(req, bodyLimit = DEFAULT_BODY_LIMIT, requestSignal) {
8016
8271
  const forwardedProto = req.headers["x-forwarded-proto"];
8017
8272
  const protocol = Array.isArray(forwardedProto) ? forwardedProto[0]?.split(",")[0]?.trim() ?? "http" : forwardedProto?.split(",")[0]?.trim() ?? "http";
@@ -8207,7 +8462,7 @@ function getRoutePaths(route, rootDir, dist) {
8207
8462
  let cached = routePathCache.get(route);
8208
8463
  if (!cached) {
8209
8464
  cached = {
8210
- absFilePath: path24.resolve(rootDir, route.filePath),
8465
+ absFilePath: path25.resolve(rootDir, route.filePath),
8211
8466
  schemaPath: getRuntimeSchemaPath(route.filePath, dist, rootDir)
8212
8467
  };
8213
8468
  routePathCache.set(route, cached);
@@ -8317,7 +8572,7 @@ var init_createServer = __esm({
8317
8572
  init_helmet();
8318
8573
  init_compression();
8319
8574
  init_etag();
8320
- init_logger();
8575
+ init_logger2();
8321
8576
  init_handleWsUpgrade();
8322
8577
  init_serverUtils();
8323
8578
  init_generateSchemaFiles();
@@ -8386,6 +8641,8 @@ ${BUILD_VIEW_SOURCE}
8386
8641
 
8387
8642
  ${SERIALIZE_ERROR_SOURCE}
8388
8643
 
8644
+ ${BUILD_LOGGER_SOURCE}
8645
+
8389
8646
  const run = mod.run;
8390
8647
  if (typeof run !== 'function') {
8391
8648
  parentPort.postMessage({
@@ -8405,7 +8662,8 @@ if (typeof run !== 'function') {
8405
8662
  try {
8406
8663
  const registries = buildRegistriesView(msg.registries);
8407
8664
  const progress = (value) => parentPort.postMessage({ type: 'progress', value });
8408
- const result = await run(payload, { ...taskCtx, signal: controller.signal, registries, progress });
8665
+ const taskLog = msg.log ? createTaskLogger(msg.log.level, msg.log.scope, msg.log.fields) : undefined;
8666
+ const result = await run(payload, { ...taskCtx, signal: controller.signal, registries, progress, log: taskLog });
8409
8667
  parentPort.postMessage({ type: 'done', result });
8410
8668
  } catch (err) {
8411
8669
  const serialized = serializeError(err);
@@ -8513,6 +8771,8 @@ async function runTaskInWorker(options) {
8513
8771
  finish(() => reject(reviveError(msg.error)));
8514
8772
  } else if (msg?.type === "progress") {
8515
8773
  options.onProgress?.(msg.value);
8774
+ } else if (msg?.type === "log") {
8775
+ options.onLog?.(msg.entry);
8516
8776
  }
8517
8777
  }
8518
8778
  );
@@ -8536,7 +8796,8 @@ async function runTaskInWorker(options) {
8536
8796
  type: "run",
8537
8797
  payload,
8538
8798
  taskCtx: { config: safeConfig(taskCtx.config), job: taskCtx.job },
8539
- registries: options.registries
8799
+ registries: options.registries,
8800
+ log: options.log
8540
8801
  });
8541
8802
  } catch (err) {
8542
8803
  finish(
@@ -8547,7 +8808,7 @@ async function runTaskInWorker(options) {
8547
8808
  }
8548
8809
  });
8549
8810
  }
8550
- var KILL_GRACE_MS, TaskCancelledError, BUILD_VIEW_SOURCE, SERIALIZE_ERROR_SOURCE;
8811
+ var KILL_GRACE_MS, TaskCancelledError, BUILD_VIEW_SOURCE, SERIALIZE_ERROR_SOURCE, BUILD_LOGGER_SOURCE;
8551
8812
  var init_taskWorker = __esm({
8552
8813
  "src/task/taskWorker.ts"() {
8553
8814
  "use strict";
@@ -8625,12 +8886,42 @@ function serializeError(err) {
8625
8886
  }
8626
8887
  return { name: 'Error', message: String(err), stack: undefined, props: {} };
8627
8888
  }
8889
+ `;
8890
+ BUILD_LOGGER_SOURCE = `
8891
+ var LOG_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
8892
+ function createTaskLogger(level, scope, fields) {
8893
+ function make(suffix) {
8894
+ function write(lvl, message, callFields) {
8895
+ if (level !== undefined && LOG_RANK[lvl] < LOG_RANK[level]) return;
8896
+ var entry = { level: lvl, message: message, time: new Date().toISOString() };
8897
+ var fullScope = suffix === undefined ? scope : scope === undefined ? suffix : scope + ':' + suffix;
8898
+ if (fullScope !== undefined) entry.scope = fullScope;
8899
+ if (fields !== undefined || callFields !== undefined) {
8900
+ entry.fields = Object.assign({}, fields, callFields);
8901
+ }
8902
+ try {
8903
+ parentPort.postMessage({ type: 'log', entry: entry });
8904
+ } catch (_) {
8905
+ entry.fields = { warning: 'log fields not cloneable across worker boundary, dropped' };
8906
+ parentPort.postMessage({ type: 'log', entry: entry });
8907
+ }
8908
+ }
8909
+ return {
8910
+ debug: function (m, f) { write('debug', m, f); },
8911
+ info: function (m, f) { write('info', m, f); },
8912
+ warn: function (m, f) { write('warn', m, f); },
8913
+ error: function (m, f) { write('error', m, f); },
8914
+ child: function (cs) { return make(suffix === undefined ? cs : suffix + ':' + cs); },
8915
+ };
8916
+ }
8917
+ return make(undefined);
8918
+ }
8628
8919
  `;
8629
8920
  }
8630
8921
  });
8631
8922
 
8632
8923
  // src/task/taskQueue.ts
8633
- import path25 from "path";
8924
+ import path26 from "path";
8634
8925
  function createTaskQueue(deps) {
8635
8926
  const { registry, rootDir, driver } = deps;
8636
8927
  const registriesView = deps.registries ?? createEmptyTaskRegistriesView();
@@ -8660,7 +8951,7 @@ function createTaskQueue(deps) {
8660
8951
  }
8661
8952
  const loadTaskModule = deps.loadTaskModule ?? (async (filePath) => await import(filePath));
8662
8953
  const loadPayloadSchema = deps.loadPayloadSchema ?? (async (filePath) => {
8663
- const zodPath = path25.join(path25.dirname(filePath), "zod.js");
8954
+ const zodPath = path26.join(path26.dirname(filePath), "zod.js");
8664
8955
  try {
8665
8956
  const mod = await import(zodPath);
8666
8957
  const schemaKey = Object.keys(mod).find((k) => k.endsWith("Schema"));
@@ -8688,7 +8979,7 @@ function createTaskQueue(deps) {
8688
8979
  const meta = registry.get(name);
8689
8980
  schemaCache.set(
8690
8981
  name,
8691
- await loadPayloadSchema(path25.resolve(rootDir, meta.filePath)).catch(() => void 0)
8982
+ await loadPayloadSchema(path26.resolve(rootDir, meta.filePath)).catch(() => void 0)
8692
8983
  );
8693
8984
  }
8694
8985
  const schema = schemaCache.get(name);
@@ -8724,24 +9015,32 @@ function createTaskQueue(deps) {
8724
9015
  let result;
8725
9016
  if (meta.timeoutMs !== void 0 && meta.timeoutMs > 0) {
8726
9017
  result = await (deps.runIsolated ?? runTaskInWorker)({
8727
- taskModulePath: path25.resolve(rootDir, meta.filePath),
9018
+ taskModulePath: path26.resolve(rootDir, meta.filePath),
8728
9019
  payload: job.payload,
8729
9020
  taskCtx: {
8730
9021
  config: deps.config,
8731
9022
  job: { id: job.id, name: job.name, attempt: job.attempt }
8732
9023
  },
8733
9024
  registries: snapshotRegistries(),
9025
+ // 日志配置随 workerData 下发(纯数据),worker 内联重建 taskCtx.log,
9026
+ // 条目回传宿主走统一管道(scope/fields 与进程内路径一致)
9027
+ log: {
9028
+ level: getEffectiveLogLevel(),
9029
+ scope: `task:${job.name}`,
9030
+ fields: { jobId: job.id, task: job.name, attempt: job.attempt }
9031
+ },
8734
9032
  timeoutMs: meta.timeoutMs,
8735
9033
  graceMs: meta.graceMs,
8736
9034
  externalSignal: job.signal,
8737
9035
  onProgress: (value) => {
8738
9036
  if (record.status === "running") record.progress = value;
8739
- }
9037
+ },
9038
+ onLog: writeLogEntry
8740
9039
  });
8741
9040
  } else {
8742
9041
  let mod = moduleCache2.get(job.name);
8743
9042
  if (!mod) {
8744
- mod = await loadTaskModule(path25.resolve(rootDir, meta.filePath));
9043
+ mod = await loadTaskModule(path26.resolve(rootDir, meta.filePath));
8745
9044
  moduleCache2.set(job.name, mod);
8746
9045
  }
8747
9046
  if (typeof mod.run !== "function") {
@@ -8752,6 +9051,9 @@ function createTaskQueue(deps) {
8752
9051
  config: deps.config,
8753
9052
  job: { id: job.id, name: job.name, attempt: job.attempt },
8754
9053
  registries: registriesView,
9054
+ log: createLogger(`task:${job.name}`, {
9055
+ fields: { jobId: job.id, task: job.name, attempt: job.attempt }
9056
+ }),
8755
9057
  progress: (value) => {
8756
9058
  if (record.status === "running") record.progress = value;
8757
9059
  }
@@ -8906,6 +9208,7 @@ var init_taskQueue = __esm({
8906
9208
  init_httpErrors();
8907
9209
  init_taskWorker();
8908
9210
  init_registries();
9211
+ init_logger();
8909
9212
  TERMINAL_STATUSES = /* @__PURE__ */ new Set(["done", "failed", "cancelled"]);
8910
9213
  MAX_FINISHED_RECORDS = 1e3;
8911
9214
  }
@@ -9019,8 +9322,8 @@ var init_cronScheduler = __esm({
9019
9322
  });
9020
9323
 
9021
9324
  // src/cli/loadPlugins.ts
9022
- import path26 from "path";
9023
- import fs18 from "fs";
9325
+ import path27 from "path";
9326
+ import fs19 from "fs";
9024
9327
  import { pathToFileURL as pathToFileURL3 } from "url";
9025
9328
  async function loadPlugins(declarations, ctx, rootDir, dist) {
9026
9329
  const handlerWrappers = [];
@@ -9083,37 +9386,37 @@ async function loadPlugins(declarations, ctx, rootDir, dist) {
9083
9386
  return { handlerWrappers, upgradeWrappers, failures };
9084
9387
  }
9085
9388
  function resolveLocalPluginSource(specifier, baseDir) {
9086
- const base = path26.isAbsolute(specifier) ? specifier : path26.resolve(baseDir, specifier);
9087
- if ((TS_EXTS.test(base) || JS_EXTS.test(base)) && fs18.existsSync(base)) return base;
9389
+ const base = path27.isAbsolute(specifier) ? specifier : path27.resolve(baseDir, specifier);
9390
+ if ((TS_EXTS.test(base) || JS_EXTS.test(base)) && fs19.existsSync(base)) return base;
9088
9391
  for (const ext of [".ts", ".js"]) {
9089
- if (fs18.existsSync(base + ext)) return base + ext;
9392
+ if (fs19.existsSync(base + ext)) return base + ext;
9090
9393
  }
9091
9394
  for (const indexExt of ["/index.ts", "/index.js"]) {
9092
- if (fs18.existsSync(base + indexExt)) return base + indexExt;
9395
+ if (fs19.existsSync(base + indexExt)) return base + indexExt;
9093
9396
  }
9094
9397
  return null;
9095
9398
  }
9096
9399
  function mirrorProductPath(sourcePath, baseDir, distDir) {
9097
- let rel = path26.relative(baseDir, sourcePath).replace(/\\/g, "/");
9400
+ let rel = path27.relative(baseDir, sourcePath).replace(/\\/g, "/");
9098
9401
  if (rel.startsWith("src/")) rel = rel.slice(4);
9099
- return path26.resolve(distDir, rel.replace(TS_EXTS, ".js"));
9402
+ return path27.resolve(distDir, rel.replace(TS_EXTS, ".js"));
9100
9403
  }
9101
9404
  function isSourceNewer(sourcePath, productPath) {
9102
9405
  try {
9103
- return fs18.statSync(sourcePath).mtimeMs > fs18.statSync(productPath).mtimeMs;
9406
+ return fs19.statSync(sourcePath).mtimeMs > fs19.statSync(productPath).mtimeMs;
9104
9407
  } catch {
9105
9408
  return true;
9106
9409
  }
9107
9410
  }
9108
9411
  async function importPluginModule(specifier, baseDir, dist) {
9109
9412
  const isRelative = specifier.startsWith("./") || specifier.startsWith("../");
9110
- if (!isRelative && !path26.isAbsolute(specifier)) {
9413
+ if (!isRelative && !path27.isAbsolute(specifier)) {
9111
9414
  return import(specifier);
9112
9415
  }
9113
- const distDir = dist ? path26.resolve(baseDir, dist) : null;
9416
+ const distDir = dist ? path27.resolve(baseDir, dist) : null;
9114
9417
  const sourcePath = resolveLocalPluginSource(specifier, baseDir);
9115
9418
  const productPath = sourcePath && distDir ? mirrorProductPath(sourcePath, baseDir, distDir) : null;
9116
- if (productPath !== null && fs18.existsSync(productPath) && (sourcePath === null || !isSourceNewer(sourcePath, productPath))) {
9419
+ if (productPath !== null && fs19.existsSync(productPath) && (sourcePath === null || !isSourceNewer(sourcePath, productPath))) {
9117
9420
  return import(pathToFileURL3(productPath).href);
9118
9421
  }
9119
9422
  if (sourcePath && TS_EXTS.test(sourcePath)) {
@@ -9122,13 +9425,13 @@ async function importPluginModule(specifier, baseDir, dist) {
9122
9425
  `Local plugin "${specifier}" has no up-to-date build artifact (dist is stale or missing). Run "faapi build" first, or use "faapi dev" for on-demand compilation.`
9123
9426
  );
9124
9427
  }
9125
- const relFromRoot = path26.relative(baseDir, sourcePath).replace(/\\/g, "/");
9428
+ const relFromRoot = path27.relative(baseDir, sourcePath).replace(/\\/g, "/");
9126
9429
  if (relFromRoot.startsWith("src/")) {
9127
9430
  await ensureCompiled(sourcePath, baseDir, dist);
9128
9431
  } else {
9129
9432
  await compileProjectModules([sourcePath], baseDir, dist);
9130
9433
  }
9131
- if (productPath && fs18.existsSync(productPath)) {
9434
+ if (productPath && fs19.existsSync(productPath)) {
9132
9435
  return import(pathToFileURL3(productPath).href);
9133
9436
  }
9134
9437
  }
@@ -9140,7 +9443,7 @@ async function importPluginModule(specifier, baseDir, dist) {
9140
9443
  `${specifier}/index.ts`,
9141
9444
  `${specifier}.js`,
9142
9445
  `${specifier}/index.js`
9143
- ].map((c) => path26.isAbsolute(c) ? c : path26.join(baseDir, c));
9446
+ ].map((c) => path27.isAbsolute(c) ? c : path27.join(baseDir, c));
9144
9447
  throw new Error(
9145
9448
  `Cannot find local plugin "${specifier}" (resolved from ${baseDir}). Expected one of:
9146
9449
  ${candidates.join("\n ")}
@@ -9175,12 +9478,12 @@ var init_loadPlugins = __esm({
9175
9478
  });
9176
9479
 
9177
9480
  // src/cli/createAppCore.ts
9178
- import fs19 from "fs";
9179
- import path27 from "path";
9481
+ import fs20 from "fs";
9482
+ import path28 from "path";
9180
9483
  import { PassThrough, Readable as Readable4 } from "stream";
9181
9484
  async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries) {
9182
- const toolsPath = path27.resolve(rootDir, dist, TOOLS_FILE2);
9183
- if (!fs19.existsSync(toolsPath)) {
9485
+ const toolsPath = path28.resolve(rootDir, dist, TOOLS_FILE2);
9486
+ if (!fs20.existsSync(toolsPath)) {
9184
9487
  return [];
9185
9488
  }
9186
9489
  const serialized = await importWithCacheBust(toolsPath);
@@ -9189,8 +9492,8 @@ async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries
9189
9492
  return hydrated;
9190
9493
  }
9191
9494
  async function loadAndHydrateAgents(rootDir, dist, registries = defaultRegistries) {
9192
- const agentsPath = path27.resolve(rootDir, dist, AGENTS_FILE2);
9193
- if (!fs19.existsSync(agentsPath)) {
9495
+ const agentsPath = path28.resolve(rootDir, dist, AGENTS_FILE2);
9496
+ if (!fs20.existsSync(agentsPath)) {
9194
9497
  return [];
9195
9498
  }
9196
9499
  const serialized = await importWithCacheBust(agentsPath);
@@ -9205,8 +9508,8 @@ function getTaskDriverOptions(config) {
9205
9508
  return void 0;
9206
9509
  }
9207
9510
  async function loadAndHydrateTasks(rootDir, dist, registries = defaultRegistries) {
9208
- const tasksPath = path27.resolve(rootDir, dist, TASKS_FILE);
9209
- if (!fs19.existsSync(tasksPath)) {
9511
+ const tasksPath = path28.resolve(rootDir, dist, TASKS_FILE);
9512
+ if (!fs20.existsSync(tasksPath)) {
9210
9513
  return [];
9211
9514
  }
9212
9515
  const serialized = await importWithCacheBust(tasksPath);
@@ -9246,13 +9549,14 @@ function isFaapiConfigKey(key) {
9246
9549
  async function createAppBase(options) {
9247
9550
  const rootDir = options?.rootDir ?? process.cwd();
9248
9551
  const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
9249
- const routesPath = path27.resolve(rootDir, dist, ROUTES_FILE);
9250
- if (!fs19.existsSync(routesPath)) {
9552
+ const routesPath = path28.resolve(rootDir, dist, ROUTES_FILE);
9553
+ if (!fs20.existsSync(routesPath)) {
9251
9554
  throw new Error(
9252
9555
  `[faapi] ${dist}/${ROUTES_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
9253
9556
  );
9254
9557
  }
9255
9558
  const config = await loadConfig(rootDir, dist);
9559
+ configureLogging(config?.log);
9256
9560
  const serialized = await importWithCacheBust(routesPath);
9257
9561
  const hydrated = await hydrateRoutes(serialized);
9258
9562
  let sorted = sortRoutes(hydrated.routes);
@@ -9589,6 +9893,7 @@ var init_createAppCore = __esm({
9589
9893
  init_loadTaskDriver();
9590
9894
  init_idleTaskDriver();
9591
9895
  init_cronScheduler();
9896
+ init_logger();
9592
9897
  init_loadPlugins();
9593
9898
  init_importWithCacheBust();
9594
9899
  init_registries();
@@ -9612,6 +9917,7 @@ var init_createAppCore = __esm({
9612
9917
  "etag",
9613
9918
  "bodyLimit",
9614
9919
  "logger",
9920
+ "log",
9615
9921
  "http2",
9616
9922
  "trustedProxy",
9617
9923
  "response",
@@ -9621,7 +9927,7 @@ var init_createAppCore = __esm({
9621
9927
  });
9622
9928
 
9623
9929
  // src/cli/createDevApp.ts
9624
- import path28 from "path";
9930
+ import path29 from "path";
9625
9931
  async function createDevApp(options) {
9626
9932
  const { app, ctx } = await createAppBase(options);
9627
9933
  const devApp = app;
@@ -9671,7 +9977,7 @@ async function createDevApp(options) {
9671
9977
  invalidateProgramCache();
9672
9978
  const tasks = await scanTasks(ctx.rootDir, TASK_PATTERNS);
9673
9979
  for (const task of tasks) {
9674
- await ensureCompiled(path28.resolve(ctx.rootDir, task.filePath), ctx.rootDir, ctx.dist);
9980
+ await ensureCompiled(path29.resolve(ctx.rootDir, task.filePath), ctx.rootDir, ctx.dist);
9675
9981
  }
9676
9982
  await generateTaskArtifacts(tasks, ctx.rootDir, ctx.dist);
9677
9983
  ctx.taskQueue.invalidateModules();
@@ -9713,7 +10019,7 @@ __export(devCommand_exports, {
9713
10019
  generateTaskArtifactsForDev: () => generateTaskArtifactsForDev,
9714
10020
  generateToolArtifactsForDev: () => generateToolArtifactsForDev
9715
10021
  });
9716
- import path29 from "path";
10022
+ import path30 from "path";
9717
10023
  async function devCommand(options) {
9718
10024
  const rootDir = process.cwd();
9719
10025
  if (!process.env.NODE_ENV) process.env.NODE_ENV = "development";
@@ -9742,7 +10048,7 @@ async function devCommand(options) {
9742
10048
  async function generateRouteArtifacts(rootDir, patterns, dist) {
9743
10049
  const { routes, wsRoutes } = await scanRoutes(rootDir, patterns, dist);
9744
10050
  const sorted = sortRoutes(routes);
9745
- const routesPath = path29.resolve(rootDir, dist, ROUTES_FILE2);
10051
+ const routesPath = path30.resolve(rootDir, dist, ROUTES_FILE2);
9746
10052
  const serialized = serializeRoutes(sorted, wsRoutes, rootDir, dist);
9747
10053
  await writeRoutesModule(serialized, routesPath);
9748
10054
  }
@@ -9757,7 +10063,7 @@ async function generateAgentArtifactsForDev(rootDir, dist) {
9757
10063
  async function generateTaskArtifactsForDev(rootDir, dist) {
9758
10064
  const tasks = await scanTasks(rootDir, TASK_PATTERNS);
9759
10065
  for (const task of tasks) {
9760
- await ensureCompiled(path29.resolve(rootDir, task.filePath), rootDir, dist);
10066
+ await ensureCompiled(path30.resolve(rootDir, task.filePath), rootDir, dist);
9761
10067
  }
9762
10068
  await generateTaskArtifacts(tasks, rootDir, dist);
9763
10069
  }
@@ -9805,15 +10111,15 @@ var buildCommand_exports = {};
9805
10111
  __export(buildCommand_exports, {
9806
10112
  buildCommand: () => buildCommand
9807
10113
  });
9808
- import path30 from "path";
9809
- import fs20 from "fs";
10114
+ import path31 from "path";
10115
+ import fs21 from "fs";
9810
10116
  async function buildCommand(options) {
9811
10117
  const rootDir = options?.rootDir ?? process.cwd();
9812
10118
  const outdir = options?.dist ?? DEFAULT_DIST2;
9813
- const absOut = path30.resolve(rootDir, outdir);
9814
- const realRoot = toRealPath(path30.resolve(rootDir));
10119
+ const absOut = path31.resolve(rootDir, outdir);
10120
+ const realRoot = toRealPath(path31.resolve(rootDir));
9815
10121
  if (isInsideDir(toRealPath(absOut), realRoot)) {
9816
- fs20.rmSync(absOut, { recursive: true, force: true });
10122
+ fs21.rmSync(absOut, { recursive: true, force: true });
9817
10123
  } else {
9818
10124
  console.warn(
9819
10125
  `! Output directory "${outdir}" is outside the project root, skipping clean (stale artifacts may remain)`
@@ -9821,10 +10127,10 @@ async function buildCommand(options) {
9821
10127
  }
9822
10128
  await compileConfig({ rootDir, dist: outdir });
9823
10129
  const _config = await loadConfig(rootDir, outdir);
9824
- const pkgPath = path30.resolve(rootDir, "package.json");
9825
- if (fs20.existsSync(pkgPath)) {
10130
+ const pkgPath = path31.resolve(rootDir, "package.json");
10131
+ if (fs21.existsSync(pkgPath)) {
9826
10132
  try {
9827
- const pkg = JSON.parse(fs20.readFileSync(pkgPath, "utf-8"));
10133
+ const pkg = JSON.parse(fs21.readFileSync(pkgPath, "utf-8"));
9828
10134
  if (pkg.type !== "module") {
9829
10135
  console.warn(
9830
10136
  '! package.json is missing "type": "module" \u2014 build output is ESM and `node dist/main` will fail without it'
@@ -9852,7 +10158,7 @@ async function buildCommand(options) {
9852
10158
  if (localPluginSources.length > 0) {
9853
10159
  console.log("\n[2.5/8] Compiling local plugins...");
9854
10160
  const outside = localPluginSources.filter((p) => {
9855
- const rel = path30.relative(rootDir, p).replace(/\\/g, "/");
10161
+ const rel = path31.relative(rootDir, p).replace(/\\/g, "/");
9856
10162
  return !rel.startsWith("src/");
9857
10163
  });
9858
10164
  if (outside.length > 0) {
@@ -9876,9 +10182,9 @@ async function buildCommand(options) {
9876
10182
  }
9877
10183
  console.log("\n[4/8] Generating schema...");
9878
10184
  await generateSchemaFiles(sorted, rootDir, outdir);
9879
- console.log(` Schema: zod.js files under ${path30.resolve(rootDir, outdir)}`);
10185
+ console.log(` Schema: zod.js files under ${path31.resolve(rootDir, outdir)}`);
9880
10186
  console.log("\n[5/8] Generating routes manifest...");
9881
- const routesPath = path30.resolve(rootDir, outdir, "faapi-routes.js");
10187
+ const routesPath = path31.resolve(rootDir, outdir, "faapi-routes.js");
9882
10188
  const serialized = serializeRoutes(sorted, wsRoutes, rootDir, outdir);
9883
10189
  await writeRoutesModule(serialized, routesPath);
9884
10190
  console.log(` Written to ${routesPath}`);
@@ -9886,19 +10192,19 @@ async function buildCommand(options) {
9886
10192
  const tools = await scanTools(rootDir, TOOL_PATTERNS);
9887
10193
  const toolMeta = await generateToolArtifacts(tools, rootDir, outdir);
9888
10194
  console.log(` Found ${toolMeta.length} tool(s)`);
9889
- console.log(` Tool manifest: ${path30.resolve(rootDir, outdir, "faapi-tools.js")}`);
10195
+ console.log(` Tool manifest: ${path31.resolve(rootDir, outdir, "faapi-tools.js")}`);
9890
10196
  console.log("\n[7/8] Generating agent manifest...");
9891
10197
  const agents = await scanAgents(rootDir, DEFAULT_AGENT_PATTERNS);
9892
10198
  const agentMeta = await generateAgentArtifacts(agents, rootDir, outdir);
9893
10199
  console.log(` Found ${agentMeta.length} agent(s)`);
9894
- console.log(` Agent manifest: ${path30.resolve(rootDir, outdir, "faapi-agents.js")}`);
10200
+ console.log(` Agent manifest: ${path31.resolve(rootDir, outdir, "faapi-agents.js")}`);
9895
10201
  console.log("\n[7.5/8] Generating task manifest and schema...");
9896
10202
  const tasks = await scanTasks(rootDir, TASK_PATTERNS);
9897
10203
  const taskMeta = await generateTaskArtifacts(tasks, rootDir, outdir);
9898
10204
  console.log(` Found ${taskMeta.length} task(s)`);
9899
- console.log(` Task manifest: ${path30.resolve(rootDir, outdir, "faapi-tasks.js")}`);
10205
+ console.log(` Task manifest: ${path31.resolve(rootDir, outdir, "faapi-tasks.js")}`);
9900
10206
  console.log("\n[8/8] Generating entry file...");
9901
- const mainPath = path30.resolve(rootDir, outdir, "main.js");
10207
+ const mainPath = path31.resolve(rootDir, outdir, "main.js");
9902
10208
  const createProdAppArgs = options?.dist && options.dist !== DEFAULT_DIST2 ? `{ dist: ${JSON.stringify(outdir)} }` : "";
9903
10209
  const mainContent = `// \u7531 faapi build \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u7F16\u8F91
9904
10210
  import { createProdApp, loadEnv } from '@faapi/faapi';
@@ -9910,7 +10216,7 @@ loadEnv(process.cwd());
9910
10216
  const app = await createProdApp(${createProdAppArgs});
9911
10217
  await app.listen();
9912
10218
  `;
9913
- await fs20.promises.writeFile(mainPath, mainContent, "utf-8");
10219
+ await fs21.promises.writeFile(mainPath, mainContent, "utf-8");
9914
10220
  console.log(` Written to ${mainPath}`);
9915
10221
  console.log("\nfaapi build completed");
9916
10222
  }
@@ -9924,7 +10230,7 @@ function extractLocalPluginSources(declarations, rootDir) {
9924
10230
  else if (Array.isArray(decl)) specifier = decl[0];
9925
10231
  else if ("path" in decl) specifier = decl.path;
9926
10232
  if (!specifier) continue;
9927
- if (!specifier.startsWith("./") && !specifier.startsWith("../") && !path30.isAbsolute(specifier)) {
10233
+ if (!specifier.startsWith("./") && !specifier.startsWith("../") && !path31.isAbsolute(specifier)) {
9928
10234
  continue;
9929
10235
  }
9930
10236
  const source = resolveLocalPluginSource(specifier, rootDir);