@faapi/faapi 6.7.0 → 6.8.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 +196 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +43 -3
- package/dist/index.js +186 -4
- package/dist/index.js.map +1 -1
- package/dist/{routeTypes-CsL7xtqu.d.ts → routeTypes-J5pPbjwR.d.ts} +104 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +97 -1
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -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
|
}
|
|
@@ -6386,7 +6388,131 @@ var init_responseFormatter = __esm({
|
|
|
6386
6388
|
}
|
|
6387
6389
|
});
|
|
6388
6390
|
|
|
6391
|
+
// src/logger/logger.ts
|
|
6392
|
+
function assertLogLevel(value, source) {
|
|
6393
|
+
if (typeof value !== "string" || !VALID_LEVELS.includes(value)) {
|
|
6394
|
+
throw new Error(
|
|
6395
|
+
`[faapi] Invalid log level from ${source}: ${String(value)}. Expected one of: ${VALID_LEVELS.join(", ")}.`
|
|
6396
|
+
);
|
|
6397
|
+
}
|
|
6398
|
+
}
|
|
6399
|
+
function configureLogging(config) {
|
|
6400
|
+
if (config === void 0) {
|
|
6401
|
+
globalState.level = null;
|
|
6402
|
+
globalState.sink = null;
|
|
6403
|
+
globalState.disabled = false;
|
|
6404
|
+
return;
|
|
6405
|
+
}
|
|
6406
|
+
const objectConfig = typeof config === "object" ? config : {};
|
|
6407
|
+
globalState.disabled = config === false;
|
|
6408
|
+
globalState.sink = objectConfig.sink ?? null;
|
|
6409
|
+
if (objectConfig.level !== void 0) {
|
|
6410
|
+
assertLogLevel(objectConfig.level, "config.log.level");
|
|
6411
|
+
globalState.level = objectConfig.level;
|
|
6412
|
+
} else if (process.env.LOG_LEVEL !== void 0) {
|
|
6413
|
+
assertLogLevel(process.env.LOG_LEVEL, "LOG_LEVEL env");
|
|
6414
|
+
globalState.level = process.env.LOG_LEVEL;
|
|
6415
|
+
} else {
|
|
6416
|
+
globalState.level = null;
|
|
6417
|
+
}
|
|
6418
|
+
}
|
|
6419
|
+
function globalThreshold() {
|
|
6420
|
+
return globalState.level ?? "info";
|
|
6421
|
+
}
|
|
6422
|
+
function getEffectiveLogLevel() {
|
|
6423
|
+
return globalThreshold();
|
|
6424
|
+
}
|
|
6425
|
+
function serializeFieldValue(value) {
|
|
6426
|
+
if (value instanceof Error) {
|
|
6427
|
+
return { name: value.name, message: value.message, stack: value.stack };
|
|
6428
|
+
}
|
|
6429
|
+
return value;
|
|
6430
|
+
}
|
|
6431
|
+
function formatEntry(entry) {
|
|
6432
|
+
let line = `[${entry.time}] ${entry.level.toUpperCase()} `;
|
|
6433
|
+
if (entry.scope) line += `[${entry.scope}] `;
|
|
6434
|
+
line += entry.message;
|
|
6435
|
+
if (entry.fields !== void 0) {
|
|
6436
|
+
const plain = Object.fromEntries(
|
|
6437
|
+
Object.entries(entry.fields).map(([k, v]) => [k, serializeFieldValue(v)])
|
|
6438
|
+
);
|
|
6439
|
+
try {
|
|
6440
|
+
line += ` ${JSON.stringify(plain)}`;
|
|
6441
|
+
} catch (err) {
|
|
6442
|
+
line += ` [unserializable fields: ${err instanceof Error ? err.message : String(err)}]`;
|
|
6443
|
+
}
|
|
6444
|
+
}
|
|
6445
|
+
return line;
|
|
6446
|
+
}
|
|
6447
|
+
function globalDispatch(entry) {
|
|
6448
|
+
if (globalState.disabled) return;
|
|
6449
|
+
(globalState.sink ?? consoleSink)(entry);
|
|
6450
|
+
}
|
|
6451
|
+
function writeLogEntry(entry) {
|
|
6452
|
+
if (LEVEL_RANK[entry.level] < LEVEL_RANK[globalThreshold()]) return;
|
|
6453
|
+
globalDispatch(entry);
|
|
6454
|
+
}
|
|
6455
|
+
function createLogger(scope, options) {
|
|
6456
|
+
const baseScope = scope;
|
|
6457
|
+
const baseFields = options?.fields;
|
|
6458
|
+
const write = (level, message, callFields, scopeSuffix) => {
|
|
6459
|
+
const threshold = options?.level ?? globalThreshold();
|
|
6460
|
+
if (LEVEL_RANK[level] < LEVEL_RANK[threshold]) return;
|
|
6461
|
+
const entry = {
|
|
6462
|
+
level,
|
|
6463
|
+
message,
|
|
6464
|
+
time: (/* @__PURE__ */ new Date()).toISOString()
|
|
6465
|
+
};
|
|
6466
|
+
const fullScope = scopeSuffix === void 0 ? baseScope : baseScope === void 0 ? scopeSuffix : `${baseScope}:${scopeSuffix}`;
|
|
6467
|
+
if (fullScope !== void 0) entry.scope = fullScope;
|
|
6468
|
+
if (baseFields !== void 0 || callFields !== void 0) {
|
|
6469
|
+
entry.fields = { ...baseFields, ...callFields };
|
|
6470
|
+
}
|
|
6471
|
+
if (options?.sink) {
|
|
6472
|
+
options.sink(entry);
|
|
6473
|
+
} else {
|
|
6474
|
+
globalDispatch(entry);
|
|
6475
|
+
}
|
|
6476
|
+
};
|
|
6477
|
+
const makeLogger = (scopeSuffix) => ({
|
|
6478
|
+
debug: (message, fields) => write("debug", message, fields, scopeSuffix),
|
|
6479
|
+
info: (message, fields) => write("info", message, fields, scopeSuffix),
|
|
6480
|
+
warn: (message, fields) => write("warn", message, fields, scopeSuffix),
|
|
6481
|
+
error: (message, fields) => write("error", message, fields, scopeSuffix),
|
|
6482
|
+
child: (childScope) => makeLogger(scopeSuffix === void 0 ? childScope : `${scopeSuffix}:${childScope}`)
|
|
6483
|
+
});
|
|
6484
|
+
return makeLogger(void 0);
|
|
6485
|
+
}
|
|
6486
|
+
var LEVEL_RANK, VALID_LEVELS, globalState, CONSOLE_METHOD, consoleSink;
|
|
6487
|
+
var init_logger = __esm({
|
|
6488
|
+
"src/logger/logger.ts"() {
|
|
6489
|
+
"use strict";
|
|
6490
|
+
LEVEL_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
6491
|
+
VALID_LEVELS = ["debug", "info", "warn", "error"];
|
|
6492
|
+
globalState = {
|
|
6493
|
+
level: null,
|
|
6494
|
+
sink: null,
|
|
6495
|
+
disabled: false
|
|
6496
|
+
};
|
|
6497
|
+
CONSOLE_METHOD = {
|
|
6498
|
+
debug: "debug",
|
|
6499
|
+
info: "info",
|
|
6500
|
+
warn: "warn",
|
|
6501
|
+
error: "error"
|
|
6502
|
+
};
|
|
6503
|
+
consoleSink = (entry) => {
|
|
6504
|
+
console[CONSOLE_METHOD[entry.level]](formatEntry(entry));
|
|
6505
|
+
};
|
|
6506
|
+
}
|
|
6507
|
+
});
|
|
6508
|
+
|
|
6389
6509
|
// src/runtime/createContext.ts
|
|
6510
|
+
function resolveRequestId(request) {
|
|
6511
|
+
const header = request.headers.get("x-request-id");
|
|
6512
|
+
const first = header?.split(",")[0]?.trim();
|
|
6513
|
+
if (first) return first;
|
|
6514
|
+
return crypto.randomUUID();
|
|
6515
|
+
}
|
|
6390
6516
|
function parseCookies(cookieHeader) {
|
|
6391
6517
|
const cookies = /* @__PURE__ */ new Map();
|
|
6392
6518
|
if (!cookieHeader) return cookies;
|
|
@@ -6420,7 +6546,13 @@ function createContextFromUrl(request, url, params, config = {}, ip = "", regist
|
|
|
6420
6546
|
for (const [key, val] of parsedCookies) {
|
|
6421
6547
|
cookiesObj[key] = val;
|
|
6422
6548
|
}
|
|
6549
|
+
const requestId = resolveRequestId(request);
|
|
6550
|
+
const log = createLogger("http", {
|
|
6551
|
+
fields: { requestId, method: request.method, path: url.pathname }
|
|
6552
|
+
});
|
|
6423
6553
|
const ctx = {
|
|
6554
|
+
requestId,
|
|
6555
|
+
log,
|
|
6424
6556
|
request,
|
|
6425
6557
|
params,
|
|
6426
6558
|
query: url.searchParams,
|
|
@@ -6525,6 +6657,7 @@ var init_createContext = __esm({
|
|
|
6525
6657
|
"use strict";
|
|
6526
6658
|
init_sse();
|
|
6527
6659
|
init_responseFormatter();
|
|
6660
|
+
init_logger();
|
|
6528
6661
|
}
|
|
6529
6662
|
});
|
|
6530
6663
|
|
|
@@ -7092,6 +7225,9 @@ function getBuiltinInjectionValue(type, ctx, body) {
|
|
|
7092
7225
|
// 任务子系统:注入 TaskClient(入队/查询);未注册工厂(无 app 编排)时 undefined
|
|
7093
7226
|
case "tasks":
|
|
7094
7227
|
return ctx.registries ? ctx.registries.taskHandle.get(ctx) : void 0;
|
|
7228
|
+
// 请求级日志器:与 ctx.log 同一实例(scope http,自动带 requestId/method/path 字段)
|
|
7229
|
+
case "log":
|
|
7230
|
+
return ctx.log;
|
|
7095
7231
|
default:
|
|
7096
7232
|
return void 0;
|
|
7097
7233
|
}
|
|
@@ -7716,6 +7852,7 @@ function logger(options = {}) {
|
|
|
7716
7852
|
const response = await next();
|
|
7717
7853
|
const duration = Date.now() - start;
|
|
7718
7854
|
const entry = {
|
|
7855
|
+
requestId: ctx.requestId,
|
|
7719
7856
|
method: ctx.method,
|
|
7720
7857
|
path: ctx.path,
|
|
7721
7858
|
status: response.status,
|
|
@@ -7728,6 +7865,7 @@ function logger(options = {}) {
|
|
|
7728
7865
|
const message = err instanceof Error ? err.message : String(err);
|
|
7729
7866
|
const status = err?.statusCode ?? 500;
|
|
7730
7867
|
const entry = {
|
|
7868
|
+
requestId: ctx.requestId,
|
|
7731
7869
|
method: ctx.method,
|
|
7732
7870
|
path: ctx.path,
|
|
7733
7871
|
status,
|
|
@@ -7739,7 +7877,7 @@ function logger(options = {}) {
|
|
|
7739
7877
|
}
|
|
7740
7878
|
};
|
|
7741
7879
|
}
|
|
7742
|
-
var
|
|
7880
|
+
var init_logger2 = __esm({
|
|
7743
7881
|
"src/middleware/logger.ts"() {
|
|
7744
7882
|
"use strict";
|
|
7745
7883
|
}
|
|
@@ -8317,7 +8455,7 @@ var init_createServer = __esm({
|
|
|
8317
8455
|
init_helmet();
|
|
8318
8456
|
init_compression();
|
|
8319
8457
|
init_etag();
|
|
8320
|
-
|
|
8458
|
+
init_logger2();
|
|
8321
8459
|
init_handleWsUpgrade();
|
|
8322
8460
|
init_serverUtils();
|
|
8323
8461
|
init_generateSchemaFiles();
|
|
@@ -8386,6 +8524,8 @@ ${BUILD_VIEW_SOURCE}
|
|
|
8386
8524
|
|
|
8387
8525
|
${SERIALIZE_ERROR_SOURCE}
|
|
8388
8526
|
|
|
8527
|
+
${BUILD_LOGGER_SOURCE}
|
|
8528
|
+
|
|
8389
8529
|
const run = mod.run;
|
|
8390
8530
|
if (typeof run !== 'function') {
|
|
8391
8531
|
parentPort.postMessage({
|
|
@@ -8405,7 +8545,8 @@ if (typeof run !== 'function') {
|
|
|
8405
8545
|
try {
|
|
8406
8546
|
const registries = buildRegistriesView(msg.registries);
|
|
8407
8547
|
const progress = (value) => parentPort.postMessage({ type: 'progress', value });
|
|
8408
|
-
const
|
|
8548
|
+
const taskLog = msg.log ? createTaskLogger(msg.log.level, msg.log.scope, msg.log.fields) : undefined;
|
|
8549
|
+
const result = await run(payload, { ...taskCtx, signal: controller.signal, registries, progress, log: taskLog });
|
|
8409
8550
|
parentPort.postMessage({ type: 'done', result });
|
|
8410
8551
|
} catch (err) {
|
|
8411
8552
|
const serialized = serializeError(err);
|
|
@@ -8513,6 +8654,8 @@ async function runTaskInWorker(options) {
|
|
|
8513
8654
|
finish(() => reject(reviveError(msg.error)));
|
|
8514
8655
|
} else if (msg?.type === "progress") {
|
|
8515
8656
|
options.onProgress?.(msg.value);
|
|
8657
|
+
} else if (msg?.type === "log") {
|
|
8658
|
+
options.onLog?.(msg.entry);
|
|
8516
8659
|
}
|
|
8517
8660
|
}
|
|
8518
8661
|
);
|
|
@@ -8536,7 +8679,8 @@ async function runTaskInWorker(options) {
|
|
|
8536
8679
|
type: "run",
|
|
8537
8680
|
payload,
|
|
8538
8681
|
taskCtx: { config: safeConfig(taskCtx.config), job: taskCtx.job },
|
|
8539
|
-
registries: options.registries
|
|
8682
|
+
registries: options.registries,
|
|
8683
|
+
log: options.log
|
|
8540
8684
|
});
|
|
8541
8685
|
} catch (err) {
|
|
8542
8686
|
finish(
|
|
@@ -8547,7 +8691,7 @@ async function runTaskInWorker(options) {
|
|
|
8547
8691
|
}
|
|
8548
8692
|
});
|
|
8549
8693
|
}
|
|
8550
|
-
var KILL_GRACE_MS, TaskCancelledError, BUILD_VIEW_SOURCE, SERIALIZE_ERROR_SOURCE;
|
|
8694
|
+
var KILL_GRACE_MS, TaskCancelledError, BUILD_VIEW_SOURCE, SERIALIZE_ERROR_SOURCE, BUILD_LOGGER_SOURCE;
|
|
8551
8695
|
var init_taskWorker = __esm({
|
|
8552
8696
|
"src/task/taskWorker.ts"() {
|
|
8553
8697
|
"use strict";
|
|
@@ -8625,6 +8769,36 @@ function serializeError(err) {
|
|
|
8625
8769
|
}
|
|
8626
8770
|
return { name: 'Error', message: String(err), stack: undefined, props: {} };
|
|
8627
8771
|
}
|
|
8772
|
+
`;
|
|
8773
|
+
BUILD_LOGGER_SOURCE = `
|
|
8774
|
+
var LOG_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
8775
|
+
function createTaskLogger(level, scope, fields) {
|
|
8776
|
+
function make(suffix) {
|
|
8777
|
+
function write(lvl, message, callFields) {
|
|
8778
|
+
if (LOG_RANK[lvl] < LOG_RANK[level]) return;
|
|
8779
|
+
var entry = { level: lvl, message: message, time: new Date().toISOString() };
|
|
8780
|
+
var fullScope = suffix === undefined ? scope : scope === undefined ? suffix : scope + ':' + suffix;
|
|
8781
|
+
if (fullScope !== undefined) entry.scope = fullScope;
|
|
8782
|
+
if (fields !== undefined || callFields !== undefined) {
|
|
8783
|
+
entry.fields = Object.assign({}, fields, callFields);
|
|
8784
|
+
}
|
|
8785
|
+
try {
|
|
8786
|
+
parentPort.postMessage({ type: 'log', entry: entry });
|
|
8787
|
+
} catch (_) {
|
|
8788
|
+
entry.fields = { warning: 'log fields not cloneable across worker boundary, dropped' };
|
|
8789
|
+
parentPort.postMessage({ type: 'log', entry: entry });
|
|
8790
|
+
}
|
|
8791
|
+
}
|
|
8792
|
+
return {
|
|
8793
|
+
debug: function (m, f) { write('debug', m, f); },
|
|
8794
|
+
info: function (m, f) { write('info', m, f); },
|
|
8795
|
+
warn: function (m, f) { write('warn', m, f); },
|
|
8796
|
+
error: function (m, f) { write('error', m, f); },
|
|
8797
|
+
child: function (cs) { return make(suffix === undefined ? cs : suffix + ':' + cs); },
|
|
8798
|
+
};
|
|
8799
|
+
}
|
|
8800
|
+
return make(undefined);
|
|
8801
|
+
}
|
|
8628
8802
|
`;
|
|
8629
8803
|
}
|
|
8630
8804
|
});
|
|
@@ -8731,12 +8905,20 @@ function createTaskQueue(deps) {
|
|
|
8731
8905
|
job: { id: job.id, name: job.name, attempt: job.attempt }
|
|
8732
8906
|
},
|
|
8733
8907
|
registries: snapshotRegistries(),
|
|
8908
|
+
// 日志配置随 workerData 下发(纯数据),worker 内联重建 taskCtx.log,
|
|
8909
|
+
// 条目回传宿主走统一管道(scope/fields 与进程内路径一致)
|
|
8910
|
+
log: {
|
|
8911
|
+
level: getEffectiveLogLevel(),
|
|
8912
|
+
scope: `task:${job.name}`,
|
|
8913
|
+
fields: { jobId: job.id, task: job.name, attempt: job.attempt }
|
|
8914
|
+
},
|
|
8734
8915
|
timeoutMs: meta.timeoutMs,
|
|
8735
8916
|
graceMs: meta.graceMs,
|
|
8736
8917
|
externalSignal: job.signal,
|
|
8737
8918
|
onProgress: (value) => {
|
|
8738
8919
|
if (record.status === "running") record.progress = value;
|
|
8739
|
-
}
|
|
8920
|
+
},
|
|
8921
|
+
onLog: writeLogEntry
|
|
8740
8922
|
});
|
|
8741
8923
|
} else {
|
|
8742
8924
|
let mod = moduleCache2.get(job.name);
|
|
@@ -8752,6 +8934,9 @@ function createTaskQueue(deps) {
|
|
|
8752
8934
|
config: deps.config,
|
|
8753
8935
|
job: { id: job.id, name: job.name, attempt: job.attempt },
|
|
8754
8936
|
registries: registriesView,
|
|
8937
|
+
log: createLogger(`task:${job.name}`, {
|
|
8938
|
+
fields: { jobId: job.id, task: job.name, attempt: job.attempt }
|
|
8939
|
+
}),
|
|
8755
8940
|
progress: (value) => {
|
|
8756
8941
|
if (record.status === "running") record.progress = value;
|
|
8757
8942
|
}
|
|
@@ -8906,6 +9091,7 @@ var init_taskQueue = __esm({
|
|
|
8906
9091
|
init_httpErrors();
|
|
8907
9092
|
init_taskWorker();
|
|
8908
9093
|
init_registries();
|
|
9094
|
+
init_logger();
|
|
8909
9095
|
TERMINAL_STATUSES = /* @__PURE__ */ new Set(["done", "failed", "cancelled"]);
|
|
8910
9096
|
MAX_FINISHED_RECORDS = 1e3;
|
|
8911
9097
|
}
|
|
@@ -9253,6 +9439,7 @@ async function createAppBase(options) {
|
|
|
9253
9439
|
);
|
|
9254
9440
|
}
|
|
9255
9441
|
const config = await loadConfig(rootDir, dist);
|
|
9442
|
+
configureLogging(config?.log);
|
|
9256
9443
|
const serialized = await importWithCacheBust(routesPath);
|
|
9257
9444
|
const hydrated = await hydrateRoutes(serialized);
|
|
9258
9445
|
let sorted = sortRoutes(hydrated.routes);
|
|
@@ -9589,6 +9776,7 @@ var init_createAppCore = __esm({
|
|
|
9589
9776
|
init_loadTaskDriver();
|
|
9590
9777
|
init_idleTaskDriver();
|
|
9591
9778
|
init_cronScheduler();
|
|
9779
|
+
init_logger();
|
|
9592
9780
|
init_loadPlugins();
|
|
9593
9781
|
init_importWithCacheBust();
|
|
9594
9782
|
init_registries();
|
|
@@ -9612,6 +9800,7 @@ var init_createAppCore = __esm({
|
|
|
9612
9800
|
"etag",
|
|
9613
9801
|
"bodyLimit",
|
|
9614
9802
|
"logger",
|
|
9803
|
+
"log",
|
|
9615
9804
|
"http2",
|
|
9616
9805
|
"trustedProxy",
|
|
9617
9806
|
"response",
|