@faapi/faapi 6.8.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 +384 -267
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +18 -11
- package/dist/index.js +349 -247
- package/dist/index.js.map +1 -1
- package/dist/{routeTypes-J5pPbjwR.d.ts → routeTypes-CuGMDCGB.d.ts} +20 -4
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +54 -16
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1235,13 +1235,13 @@ var init_collectRouteSchemaSources = __esm({
|
|
|
1235
1235
|
});
|
|
1236
1236
|
|
|
1237
1237
|
// src/utils/atomicWrite.ts
|
|
1238
|
-
import
|
|
1239
|
-
import
|
|
1238
|
+
import path10 from "path";
|
|
1239
|
+
import fs8 from "fs";
|
|
1240
1240
|
async function atomicWriteFile(outputPath, content) {
|
|
1241
|
-
await
|
|
1241
|
+
await fs8.promises.mkdir(path10.dirname(outputPath), { recursive: true });
|
|
1242
1242
|
const tmp = `${outputPath}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
1243
|
-
await
|
|
1244
|
-
await
|
|
1243
|
+
await fs8.promises.writeFile(tmp, content, "utf-8");
|
|
1244
|
+
await fs8.promises.rename(tmp, outputPath);
|
|
1245
1245
|
}
|
|
1246
1246
|
var init_atomicWrite = __esm({
|
|
1247
1247
|
"src/utils/atomicWrite.ts"() {
|
|
@@ -1588,7 +1588,7 @@ __export(generateSchemaFiles_exports, {
|
|
|
1588
1588
|
getRuntimeSchemaPath: () => getRuntimeSchemaPath,
|
|
1589
1589
|
getSchemaOutputPath: () => getSchemaOutputPath
|
|
1590
1590
|
});
|
|
1591
|
-
import
|
|
1591
|
+
import path11 from "path";
|
|
1592
1592
|
function getSchemaOutputPath(sourceFile, dist, rootDir) {
|
|
1593
1593
|
let rel = sourceFile.replace(/\\/g, "/");
|
|
1594
1594
|
if (rel.startsWith("src/")) {
|
|
@@ -1596,7 +1596,7 @@ function getSchemaOutputPath(sourceFile, dist, rootDir) {
|
|
|
1596
1596
|
}
|
|
1597
1597
|
const idx = rel.lastIndexOf("/");
|
|
1598
1598
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
1599
|
-
return
|
|
1599
|
+
return path11.resolve(rootDir, dist, relDir, "zod.js");
|
|
1600
1600
|
}
|
|
1601
1601
|
function getRuntimeSchemaPath(filePath, dist, rootDir) {
|
|
1602
1602
|
let rel = filePath.replace(/\\/g, "/");
|
|
@@ -1607,7 +1607,7 @@ function getRuntimeSchemaPath(filePath, dist, rootDir) {
|
|
|
1607
1607
|
}
|
|
1608
1608
|
const idx = rel.lastIndexOf("/");
|
|
1609
1609
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
1610
|
-
return
|
|
1610
|
+
return path11.resolve(rootDir, dist, relDir, "zod.js");
|
|
1611
1611
|
}
|
|
1612
1612
|
function getHelpersImportPath(relDir) {
|
|
1613
1613
|
if (!relDir) return `./${HELPERS_FILENAME}`;
|
|
@@ -1666,7 +1666,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
1666
1666
|
}
|
|
1667
1667
|
const fileEntries = [];
|
|
1668
1668
|
for (const [filePath, fileSources] of sourcesByFile) {
|
|
1669
|
-
const relFile =
|
|
1669
|
+
const relFile = path11.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
1670
1670
|
const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
|
|
1671
1671
|
let relForDir = relFile;
|
|
1672
1672
|
if (relForDir.startsWith("src/")) {
|
|
@@ -1685,7 +1685,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
1685
1685
|
}
|
|
1686
1686
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
1687
1687
|
if (usesCoerceHelpers(allSourceCode)) {
|
|
1688
|
-
const helpersPath =
|
|
1688
|
+
const helpersPath = path11.resolve(rootDir, dist, HELPERS_FILENAME);
|
|
1689
1689
|
await writeSchemaFile(helpersPath, generateHelpersFileSource());
|
|
1690
1690
|
}
|
|
1691
1691
|
await Promise.all(
|
|
@@ -1917,7 +1917,7 @@ function createAppRegistries() {
|
|
|
1917
1917
|
var defaultRegistries = createAppRegistries();
|
|
1918
1918
|
|
|
1919
1919
|
// src/task/taskQueue.ts
|
|
1920
|
-
import
|
|
1920
|
+
import path4 from "path";
|
|
1921
1921
|
|
|
1922
1922
|
// src/errors/FaapiError.ts
|
|
1923
1923
|
var FaapiError = class extends Error {
|
|
@@ -1945,14 +1945,14 @@ var ValidationError = class extends FaapiError {
|
|
|
1945
1945
|
issues;
|
|
1946
1946
|
};
|
|
1947
1947
|
var RouteNotFoundError = class extends FaapiError {
|
|
1948
|
-
constructor(
|
|
1949
|
-
super("ROUTE_NOT_FOUND", `Route not found: ${
|
|
1948
|
+
constructor(path29) {
|
|
1949
|
+
super("ROUTE_NOT_FOUND", `Route not found: ${path29}`, 404);
|
|
1950
1950
|
this.name = "RouteNotFoundError";
|
|
1951
1951
|
}
|
|
1952
1952
|
};
|
|
1953
1953
|
var MethodNotAllowedError = class extends FaapiError {
|
|
1954
|
-
constructor(method,
|
|
1955
|
-
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${
|
|
1954
|
+
constructor(method, path29, allowedMethods) {
|
|
1955
|
+
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path29}`, 405);
|
|
1956
1956
|
this.allowedMethods = allowedMethods;
|
|
1957
1957
|
this.name = "MethodNotAllowedError";
|
|
1958
1958
|
}
|
|
@@ -2073,7 +2073,7 @@ var LOG_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
|
2073
2073
|
function createTaskLogger(level, scope, fields) {
|
|
2074
2074
|
function make(suffix) {
|
|
2075
2075
|
function write(lvl, message, callFields) {
|
|
2076
|
-
if (LOG_RANK[lvl] < LOG_RANK[level]) return;
|
|
2076
|
+
if (level !== undefined && LOG_RANK[lvl] < LOG_RANK[level]) return;
|
|
2077
2077
|
var entry = { level: lvl, message: message, time: new Date().toISOString() };
|
|
2078
2078
|
var fullScope = suffix === undefined ? scope : scope === undefined ? suffix : scope + ':' + suffix;
|
|
2079
2079
|
if (fullScope !== undefined) entry.scope = fullScope;
|
|
@@ -2275,6 +2275,95 @@ async function runTaskInWorker(options) {
|
|
|
2275
2275
|
});
|
|
2276
2276
|
}
|
|
2277
2277
|
|
|
2278
|
+
// src/logger/formatEntry.ts
|
|
2279
|
+
function serializeFieldValue(value) {
|
|
2280
|
+
if (value instanceof Error) {
|
|
2281
|
+
return { name: value.name, message: value.message, stack: value.stack };
|
|
2282
|
+
}
|
|
2283
|
+
return value;
|
|
2284
|
+
}
|
|
2285
|
+
function formatEntry(entry) {
|
|
2286
|
+
let line = `[${entry.time}] ${entry.level.toUpperCase()} `;
|
|
2287
|
+
if (entry.scope) line += `[${entry.scope}] `;
|
|
2288
|
+
line += entry.message;
|
|
2289
|
+
if (entry.fields !== void 0) {
|
|
2290
|
+
const plain = Object.fromEntries(
|
|
2291
|
+
Object.entries(entry.fields).map(([k, v]) => [k, serializeFieldValue(v)])
|
|
2292
|
+
);
|
|
2293
|
+
try {
|
|
2294
|
+
line += ` ${JSON.stringify(plain)}`;
|
|
2295
|
+
} catch (err) {
|
|
2296
|
+
line += ` [unserializable fields: ${err instanceof Error ? err.message : String(err)}]`;
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
return line;
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
// src/logger/fileSink.ts
|
|
2303
|
+
import fs2 from "fs";
|
|
2304
|
+
import path3 from "path";
|
|
2305
|
+
var LEVEL_FILES = ["debug", "info", "warn", "error"];
|
|
2306
|
+
function createFileLogSink(options) {
|
|
2307
|
+
fs2.mkdirSync(options.dir, { recursive: true });
|
|
2308
|
+
const streams = /* @__PURE__ */ new Map();
|
|
2309
|
+
const getStream = (name) => {
|
|
2310
|
+
if (streams.has(name)) return streams.get(name);
|
|
2311
|
+
return void 0;
|
|
2312
|
+
};
|
|
2313
|
+
const openStream = (name) => {
|
|
2314
|
+
const stream = fs2.createWriteStream(path3.join(options.dir, `${name}.log`), { flags: "a" });
|
|
2315
|
+
stream.on("error", () => {
|
|
2316
|
+
});
|
|
2317
|
+
streams.set(name, stream);
|
|
2318
|
+
};
|
|
2319
|
+
const fileNames = options.splitByLevel ? [...LEVEL_FILES] : ["app", "error"];
|
|
2320
|
+
for (const name of fileNames) openStream(name);
|
|
2321
|
+
let pendingCount = 0;
|
|
2322
|
+
let drainWaiters = [];
|
|
2323
|
+
const onWriteDone = () => {
|
|
2324
|
+
pendingCount--;
|
|
2325
|
+
if (pendingCount === 0 && drainWaiters.length > 0) {
|
|
2326
|
+
const waiters = drainWaiters;
|
|
2327
|
+
drainWaiters = [];
|
|
2328
|
+
for (const waiter of waiters) waiter();
|
|
2329
|
+
}
|
|
2330
|
+
};
|
|
2331
|
+
const write = (entry) => {
|
|
2332
|
+
const line = `${formatEntry(entry)}
|
|
2333
|
+
`;
|
|
2334
|
+
const target = options.splitByLevel ? entry.level : "app";
|
|
2335
|
+
const main = getStream(target);
|
|
2336
|
+
if (main) {
|
|
2337
|
+
pendingCount++;
|
|
2338
|
+
main.write(line, onWriteDone);
|
|
2339
|
+
}
|
|
2340
|
+
if (!options.splitByLevel && entry.level === "error") {
|
|
2341
|
+
const dup = getStream("error");
|
|
2342
|
+
if (dup) {
|
|
2343
|
+
pendingCount++;
|
|
2344
|
+
dup.write(line, onWriteDone);
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
};
|
|
2348
|
+
const flush = () => new Promise((resolve) => {
|
|
2349
|
+
if (pendingCount === 0) {
|
|
2350
|
+
resolve();
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
drainWaiters.push(resolve);
|
|
2354
|
+
});
|
|
2355
|
+
const close = () => Promise.all(
|
|
2356
|
+
[...streams.values()].map(
|
|
2357
|
+
(stream) => new Promise((resolve) => {
|
|
2358
|
+
stream.end(() => resolve());
|
|
2359
|
+
})
|
|
2360
|
+
)
|
|
2361
|
+
).then(() => {
|
|
2362
|
+
streams.clear();
|
|
2363
|
+
});
|
|
2364
|
+
return { write, flush, close };
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2278
2367
|
// src/logger/logger.ts
|
|
2279
2368
|
var LEVEL_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
2280
2369
|
var VALID_LEVELS = ["debug", "info", "warn", "error"];
|
|
@@ -2285,21 +2374,20 @@ function assertLogLevel(value, source) {
|
|
|
2285
2374
|
);
|
|
2286
2375
|
}
|
|
2287
2376
|
}
|
|
2288
|
-
var globalState = {
|
|
2289
|
-
level: null,
|
|
2290
|
-
sink: null,
|
|
2291
|
-
disabled: false
|
|
2292
|
-
};
|
|
2377
|
+
var globalState = { level: null, sink: null, fileSink: null, stdout: true, accessLog: false, disabled: false };
|
|
2293
2378
|
function configureLogging(config) {
|
|
2294
|
-
if (config === void 0) {
|
|
2295
|
-
globalState.level = null;
|
|
2296
|
-
globalState.sink = null;
|
|
2297
|
-
globalState.disabled = false;
|
|
2298
|
-
return;
|
|
2299
|
-
}
|
|
2300
2379
|
const objectConfig = typeof config === "object" ? config : {};
|
|
2380
|
+
if (objectConfig.sink && objectConfig.dir) {
|
|
2381
|
+
throw new Error(
|
|
2382
|
+
"[faapi] config.log.sink and config.log.dir are mutually exclusive: pick one output pipeline (custom sink OR built-in file logs)."
|
|
2383
|
+
);
|
|
2384
|
+
}
|
|
2385
|
+
void globalState.fileSink?.close();
|
|
2301
2386
|
globalState.disabled = config === false;
|
|
2302
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;
|
|
2303
2391
|
if (objectConfig.level !== void 0) {
|
|
2304
2392
|
assertLogLevel(objectConfig.level, "config.log.level");
|
|
2305
2393
|
globalState.level = objectConfig.level;
|
|
@@ -2311,56 +2399,51 @@ function configureLogging(config) {
|
|
|
2311
2399
|
}
|
|
2312
2400
|
}
|
|
2313
2401
|
function globalThreshold() {
|
|
2314
|
-
|
|
2402
|
+
if (globalState.level) return globalState.level;
|
|
2403
|
+
if (globalState.fileSink) return void 0;
|
|
2404
|
+
return "info";
|
|
2405
|
+
}
|
|
2406
|
+
function belowThreshold(level, threshold) {
|
|
2407
|
+
return threshold !== void 0 && LEVEL_RANK[level] < LEVEL_RANK[threshold];
|
|
2315
2408
|
}
|
|
2316
2409
|
function getEffectiveLogLevel() {
|
|
2317
2410
|
return globalThreshold();
|
|
2318
2411
|
}
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
}
|
|
2323
|
-
return value;
|
|
2324
|
-
}
|
|
2325
|
-
function formatEntry(entry) {
|
|
2326
|
-
let line = `[${entry.time}] ${entry.level.toUpperCase()} `;
|
|
2327
|
-
if (entry.scope) line += `[${entry.scope}] `;
|
|
2328
|
-
line += entry.message;
|
|
2329
|
-
if (entry.fields !== void 0) {
|
|
2330
|
-
const plain = Object.fromEntries(
|
|
2331
|
-
Object.entries(entry.fields).map(([k, v]) => [k, serializeFieldValue(v)])
|
|
2332
|
-
);
|
|
2333
|
-
try {
|
|
2334
|
-
line += ` ${JSON.stringify(plain)}`;
|
|
2335
|
-
} catch (err) {
|
|
2336
|
-
line += ` [unserializable fields: ${err instanceof Error ? err.message : String(err)}]`;
|
|
2337
|
-
}
|
|
2338
|
-
}
|
|
2339
|
-
return line;
|
|
2340
|
-
}
|
|
2412
|
+
var consoleSink = (entry) => {
|
|
2413
|
+
console[CONSOLE_METHOD[entry.level]](formatEntry(entry));
|
|
2414
|
+
};
|
|
2341
2415
|
var CONSOLE_METHOD = {
|
|
2342
2416
|
debug: "debug",
|
|
2343
2417
|
info: "info",
|
|
2344
2418
|
warn: "warn",
|
|
2345
2419
|
error: "error"
|
|
2346
2420
|
};
|
|
2347
|
-
var consoleSink = (entry) => {
|
|
2348
|
-
console[CONSOLE_METHOD[entry.level]](formatEntry(entry));
|
|
2349
|
-
};
|
|
2350
2421
|
function globalDispatch(entry) {
|
|
2351
2422
|
if (globalState.disabled) return;
|
|
2352
|
-
(globalState.sink
|
|
2423
|
+
if (globalState.sink) {
|
|
2424
|
+
globalState.sink(entry);
|
|
2425
|
+
return;
|
|
2426
|
+
}
|
|
2427
|
+
if (globalState.fileSink) {
|
|
2428
|
+
globalState.fileSink.write(entry);
|
|
2429
|
+
if (globalState.stdout) consoleSink(entry);
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
consoleSink(entry);
|
|
2353
2433
|
}
|
|
2354
2434
|
function writeLogEntry(entry) {
|
|
2355
|
-
if (
|
|
2435
|
+
if (belowThreshold(entry.level, globalThreshold())) return;
|
|
2356
2436
|
globalDispatch(entry);
|
|
2357
2437
|
}
|
|
2438
|
+
function isAccessLogPiped() {
|
|
2439
|
+
return !globalState.disabled && globalState.accessLog;
|
|
2440
|
+
}
|
|
2358
2441
|
function createLogger(scope, options) {
|
|
2359
2442
|
const baseScope = scope;
|
|
2360
2443
|
const baseFields = options?.fields;
|
|
2361
2444
|
const write = (level, message, callFields, scopeSuffix) => {
|
|
2362
2445
|
const threshold = options?.level ?? globalThreshold();
|
|
2363
|
-
if (
|
|
2446
|
+
if (belowThreshold(level, threshold)) return;
|
|
2364
2447
|
const entry = {
|
|
2365
2448
|
level,
|
|
2366
2449
|
message,
|
|
@@ -2419,7 +2502,7 @@ function createTaskQueue(deps) {
|
|
|
2419
2502
|
}
|
|
2420
2503
|
const loadTaskModule = deps.loadTaskModule ?? (async (filePath) => await import(filePath));
|
|
2421
2504
|
const loadPayloadSchema = deps.loadPayloadSchema ?? (async (filePath) => {
|
|
2422
|
-
const zodPath =
|
|
2505
|
+
const zodPath = path4.join(path4.dirname(filePath), "zod.js");
|
|
2423
2506
|
try {
|
|
2424
2507
|
const mod = await import(zodPath);
|
|
2425
2508
|
const schemaKey = Object.keys(mod).find((k) => k.endsWith("Schema"));
|
|
@@ -2447,7 +2530,7 @@ function createTaskQueue(deps) {
|
|
|
2447
2530
|
const meta = registry.get(name);
|
|
2448
2531
|
schemaCache.set(
|
|
2449
2532
|
name,
|
|
2450
|
-
await loadPayloadSchema(
|
|
2533
|
+
await loadPayloadSchema(path4.resolve(rootDir, meta.filePath)).catch(() => void 0)
|
|
2451
2534
|
);
|
|
2452
2535
|
}
|
|
2453
2536
|
const schema = schemaCache.get(name);
|
|
@@ -2483,7 +2566,7 @@ function createTaskQueue(deps) {
|
|
|
2483
2566
|
let result;
|
|
2484
2567
|
if (meta.timeoutMs !== void 0 && meta.timeoutMs > 0) {
|
|
2485
2568
|
result = await (deps.runIsolated ?? runTaskInWorker)({
|
|
2486
|
-
taskModulePath:
|
|
2569
|
+
taskModulePath: path4.resolve(rootDir, meta.filePath),
|
|
2487
2570
|
payload: job.payload,
|
|
2488
2571
|
taskCtx: {
|
|
2489
2572
|
config: deps.config,
|
|
@@ -2508,7 +2591,7 @@ function createTaskQueue(deps) {
|
|
|
2508
2591
|
} else {
|
|
2509
2592
|
let mod = moduleCache2.get(job.name);
|
|
2510
2593
|
if (!mod) {
|
|
2511
|
-
mod = await loadTaskModule(
|
|
2594
|
+
mod = await loadTaskModule(path4.resolve(rootDir, meta.filePath));
|
|
2512
2595
|
moduleCache2.set(job.name, mod);
|
|
2513
2596
|
}
|
|
2514
2597
|
if (typeof mod.run !== "function") {
|
|
@@ -2745,8 +2828,8 @@ function createCronScheduler(registry, enqueue) {
|
|
|
2745
2828
|
|
|
2746
2829
|
// src/task/scanTasks.ts
|
|
2747
2830
|
import fg from "fast-glob";
|
|
2748
|
-
import
|
|
2749
|
-
import
|
|
2831
|
+
import path5 from "path";
|
|
2832
|
+
import fs3 from "fs";
|
|
2750
2833
|
var TASK_PATTERNS = ["src/tasks/**/task.ts"];
|
|
2751
2834
|
var TASK_FILENAME = "task.ts";
|
|
2752
2835
|
var CRON_RE = /(?:^|\n)\s*cron:\s*['"`]([^'"`\n]+)['"`]/;
|
|
@@ -2777,12 +2860,12 @@ async function scanTasks(rootDir, patterns) {
|
|
|
2777
2860
|
const seen = /* @__PURE__ */ new Map();
|
|
2778
2861
|
for (const file of files) {
|
|
2779
2862
|
const normalizedFile = file.replace(/\\/g, "/");
|
|
2780
|
-
const fileName =
|
|
2863
|
+
const fileName = path5.posix.basename(normalizedFile);
|
|
2781
2864
|
if (fileName !== TASK_FILENAME) {
|
|
2782
2865
|
continue;
|
|
2783
2866
|
}
|
|
2784
|
-
const absPath =
|
|
2785
|
-
const source = await
|
|
2867
|
+
const absPath = path5.resolve(rootDir, normalizedFile);
|
|
2868
|
+
const source = await fs3.promises.readFile(absPath, "utf8").catch(() => "");
|
|
2786
2869
|
const name = filePathToTaskName(normalizedFile);
|
|
2787
2870
|
const prevFile = seen.get(name);
|
|
2788
2871
|
if (prevFile) {
|
|
@@ -2855,7 +2938,7 @@ function listSkills() {
|
|
|
2855
2938
|
}
|
|
2856
2939
|
|
|
2857
2940
|
// src/loader/loadAgentModule.ts
|
|
2858
|
-
import
|
|
2941
|
+
import fs11 from "fs";
|
|
2859
2942
|
|
|
2860
2943
|
// src/loader/resolveExports.ts
|
|
2861
2944
|
function resolveExport(module, exportName) {
|
|
@@ -2901,18 +2984,18 @@ async function importWithCacheBust(filePath, bustViteCache = false) {
|
|
|
2901
2984
|
}
|
|
2902
2985
|
|
|
2903
2986
|
// src/cli/compileOnDemand.ts
|
|
2904
|
-
import
|
|
2905
|
-
import
|
|
2987
|
+
import path13 from "path";
|
|
2988
|
+
import fs10 from "fs";
|
|
2906
2989
|
|
|
2907
2990
|
// src/cli/compileSourceFiles.ts
|
|
2908
|
-
import
|
|
2909
|
-
import
|
|
2991
|
+
import path9 from "path";
|
|
2992
|
+
import fs7 from "fs";
|
|
2910
2993
|
import fg2 from "fast-glob";
|
|
2911
2994
|
|
|
2912
2995
|
// src/cli/aliasPlugin.ts
|
|
2913
2996
|
import ts7 from "typescript";
|
|
2914
|
-
import
|
|
2915
|
-
import
|
|
2997
|
+
import path8 from "path";
|
|
2998
|
+
import fs6 from "fs";
|
|
2916
2999
|
|
|
2917
3000
|
// src/utils/resolveAlias.ts
|
|
2918
3001
|
function resolveAlias(specifier, config) {
|
|
@@ -2938,8 +3021,8 @@ function resolveAlias(specifier, config) {
|
|
|
2938
3021
|
}
|
|
2939
3022
|
|
|
2940
3023
|
// src/utils/prodPaths.ts
|
|
2941
|
-
import
|
|
2942
|
-
import
|
|
3024
|
+
import path6 from "path";
|
|
3025
|
+
import fs4 from "fs";
|
|
2943
3026
|
var APP_DIR = "src";
|
|
2944
3027
|
var ROUTE_PATTERNS = ["src/api/**/*.ts"];
|
|
2945
3028
|
function toProdFilePath(filePath, dist) {
|
|
@@ -2958,27 +3041,27 @@ function toProdExtension(filePath) {
|
|
|
2958
3041
|
}
|
|
2959
3042
|
function toRealPath(p) {
|
|
2960
3043
|
try {
|
|
2961
|
-
return
|
|
3044
|
+
return fs4.realpathSync(p);
|
|
2962
3045
|
} catch {
|
|
2963
3046
|
return p;
|
|
2964
3047
|
}
|
|
2965
3048
|
}
|
|
2966
3049
|
function isInsideDir(filePath, dir) {
|
|
2967
|
-
const rel =
|
|
2968
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
3050
|
+
const rel = path6.relative(dir, filePath);
|
|
3051
|
+
return rel !== "" && !rel.startsWith("..") && !path6.isAbsolute(rel);
|
|
2969
3052
|
}
|
|
2970
3053
|
|
|
2971
3054
|
// src/utils/readTsconfig.ts
|
|
2972
3055
|
import ts6 from "typescript";
|
|
2973
|
-
import
|
|
2974
|
-
import
|
|
3056
|
+
import path7 from "path";
|
|
3057
|
+
import fs5 from "fs";
|
|
2975
3058
|
var tsconfigCache = /* @__PURE__ */ new Map();
|
|
2976
3059
|
function readTsconfig(rootDir) {
|
|
2977
|
-
const tsconfigPath =
|
|
2978
|
-
if (!
|
|
3060
|
+
const tsconfigPath = path7.resolve(rootDir, "tsconfig.json");
|
|
3061
|
+
if (!fs5.existsSync(tsconfigPath)) return null;
|
|
2979
3062
|
let mtimeMs;
|
|
2980
3063
|
try {
|
|
2981
|
-
mtimeMs =
|
|
3064
|
+
mtimeMs = fs5.statSync(tsconfigPath).mtimeMs;
|
|
2982
3065
|
} catch {
|
|
2983
3066
|
return null;
|
|
2984
3067
|
}
|
|
@@ -2994,7 +3077,7 @@ function readTsconfig(rootDir) {
|
|
|
2994
3077
|
const config = rawPaths ? (() => {
|
|
2995
3078
|
const paths = {};
|
|
2996
3079
|
for (const [pattern, targets] of Object.entries(rawPaths)) {
|
|
2997
|
-
paths[pattern] = targets.map((t) =>
|
|
3080
|
+
paths[pattern] = targets.map((t) => path7.resolve(baseUrl, t));
|
|
2998
3081
|
}
|
|
2999
3082
|
return { baseUrl, paths };
|
|
3000
3083
|
})() : null;
|
|
@@ -3004,26 +3087,26 @@ function readTsconfig(rootDir) {
|
|
|
3004
3087
|
|
|
3005
3088
|
// src/cli/aliasPlugin.ts
|
|
3006
3089
|
function toProdImportPath(sourceFile, importer) {
|
|
3007
|
-
const importerDir =
|
|
3008
|
-
let rel =
|
|
3009
|
-
rel = rel.split(
|
|
3090
|
+
const importerDir = path8.dirname(importer);
|
|
3091
|
+
let rel = path8.relative(importerDir, sourceFile);
|
|
3092
|
+
rel = rel.split(path8.sep).join("/");
|
|
3010
3093
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
3011
3094
|
return toProdExtension(rel);
|
|
3012
3095
|
}
|
|
3013
3096
|
function toStrippedProdImportPath(sourceFile, rootDir) {
|
|
3014
|
-
const appDirAbs = toRealPath(
|
|
3097
|
+
const appDirAbs = toRealPath(path8.resolve(rootDir, APP_DIR));
|
|
3015
3098
|
const sourceReal = toRealPath(sourceFile);
|
|
3016
|
-
let rel =
|
|
3017
|
-
rel = rel.split(
|
|
3099
|
+
let rel = path8.relative(appDirAbs, sourceReal);
|
|
3100
|
+
rel = rel.split(path8.sep).join("/");
|
|
3018
3101
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
3019
3102
|
return toProdExtension(rel);
|
|
3020
3103
|
}
|
|
3021
3104
|
function toProdImportFromImporter(importer, rootDir, relFromDist) {
|
|
3022
|
-
const importerRel =
|
|
3023
|
-
const importerProdDir =
|
|
3105
|
+
const importerRel = path8.relative(toRealPath(path8.resolve(rootDir)), toRealPath(importer)).split(path8.sep).join("/");
|
|
3106
|
+
const importerProdDir = path8.posix.dirname(toProdExtension(importerRel));
|
|
3024
3107
|
if (importerProdDir === ".") return relFromDist;
|
|
3025
3108
|
const target = relFromDist.replace(/^\.\//, "");
|
|
3026
|
-
let rel =
|
|
3109
|
+
let rel = path8.posix.relative(importerProdDir, target);
|
|
3027
3110
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
3028
3111
|
return rel;
|
|
3029
3112
|
}
|
|
@@ -3038,41 +3121,41 @@ var INDEX_EXTS = [
|
|
|
3038
3121
|
"/index.cjs"
|
|
3039
3122
|
];
|
|
3040
3123
|
function resolveRelativeSpecifier(importer, specifier) {
|
|
3041
|
-
const importerDir =
|
|
3042
|
-
const base =
|
|
3124
|
+
const importerDir = path8.dirname(importer);
|
|
3125
|
+
const base = path8.resolve(importerDir, specifier);
|
|
3043
3126
|
if (PROD_EXTS.some((ext) => specifier.endsWith(ext))) {
|
|
3044
|
-
if (
|
|
3127
|
+
if (fs6.existsSync(base)) return base;
|
|
3045
3128
|
if (base.endsWith(".js")) {
|
|
3046
3129
|
for (const ext of [".ts", ".tsx", ".jsx"]) {
|
|
3047
3130
|
const file = base.slice(0, -3) + ext;
|
|
3048
|
-
if (
|
|
3131
|
+
if (fs6.existsSync(file)) return file;
|
|
3049
3132
|
}
|
|
3050
3133
|
}
|
|
3051
3134
|
return null;
|
|
3052
3135
|
}
|
|
3053
3136
|
if (/\.(ts|tsx|jsx)$/.test(specifier)) {
|
|
3054
|
-
return
|
|
3137
|
+
return fs6.existsSync(base) ? base : null;
|
|
3055
3138
|
}
|
|
3056
3139
|
for (const ext of SOURCE_EXTS) {
|
|
3057
3140
|
const file = base + ext;
|
|
3058
|
-
if (
|
|
3141
|
+
if (fs6.existsSync(file)) return file;
|
|
3059
3142
|
}
|
|
3060
3143
|
for (const indexExt of INDEX_EXTS) {
|
|
3061
3144
|
const file = base + indexExt;
|
|
3062
|
-
if (
|
|
3145
|
+
if (fs6.existsSync(file)) return file;
|
|
3063
3146
|
}
|
|
3064
3147
|
return null;
|
|
3065
3148
|
}
|
|
3066
3149
|
function createAliasPlugin(config, options) {
|
|
3067
|
-
const appDirAbs = options?.rootDir ? toRealPath(
|
|
3150
|
+
const appDirAbs = options?.rootDir ? toRealPath(path8.resolve(options.rootDir, APP_DIR)) : null;
|
|
3068
3151
|
const probeCandidateFile = (candidate) => {
|
|
3069
3152
|
for (const ext of SOURCE_EXTS) {
|
|
3070
3153
|
const file = candidate + ext;
|
|
3071
|
-
if (
|
|
3154
|
+
if (fs6.existsSync(file)) return file;
|
|
3072
3155
|
}
|
|
3073
3156
|
for (const indexExt of INDEX_EXTS) {
|
|
3074
3157
|
const file = candidate + indexExt;
|
|
3075
|
-
if (
|
|
3158
|
+
if (fs6.existsSync(file)) return file;
|
|
3076
3159
|
}
|
|
3077
3160
|
return null;
|
|
3078
3161
|
};
|
|
@@ -3082,7 +3165,7 @@ function createAliasPlugin(config, options) {
|
|
|
3082
3165
|
build.onLoad({ filter: /\.(ts|tsx|js|jsx|mjs|cjs)$/ }, (args) => {
|
|
3083
3166
|
let source;
|
|
3084
3167
|
try {
|
|
3085
|
-
source =
|
|
3168
|
+
source = fs6.readFileSync(args.path, "utf8");
|
|
3086
3169
|
} catch {
|
|
3087
3170
|
return void 0;
|
|
3088
3171
|
}
|
|
@@ -3207,11 +3290,11 @@ async function compileSourceFiles(options) {
|
|
|
3207
3290
|
if (entryPoints.length === 0) {
|
|
3208
3291
|
return { compiledFiles: [] };
|
|
3209
3292
|
}
|
|
3210
|
-
const absDist =
|
|
3211
|
-
await
|
|
3293
|
+
const absDist = path9.resolve(rootDir, dist);
|
|
3294
|
+
await fs7.promises.mkdir(absDist, { recursive: true });
|
|
3212
3295
|
const plugins = buildAliasPlugins(rootDir);
|
|
3213
3296
|
const esbuild = await import("esbuild");
|
|
3214
|
-
const outbase =
|
|
3297
|
+
const outbase = path9.resolve(rootDir, APP_DIR);
|
|
3215
3298
|
const result = await esbuild.build({
|
|
3216
3299
|
entryPoints,
|
|
3217
3300
|
outdir: absDist,
|
|
@@ -3231,10 +3314,10 @@ async function compileSourceFiles(options) {
|
|
|
3231
3314
|
if (atomicWrite && result.outputFiles) {
|
|
3232
3315
|
await Promise.all(
|
|
3233
3316
|
result.outputFiles.map(async (file) => {
|
|
3234
|
-
await
|
|
3317
|
+
await fs7.promises.mkdir(path9.dirname(file.path), { recursive: true });
|
|
3235
3318
|
const tmp = `${file.path}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
3236
|
-
await
|
|
3237
|
-
await
|
|
3319
|
+
await fs7.promises.writeFile(tmp, file.contents);
|
|
3320
|
+
await fs7.promises.rename(tmp, file.path);
|
|
3238
3321
|
})
|
|
3239
3322
|
);
|
|
3240
3323
|
}
|
|
@@ -3251,8 +3334,8 @@ init_generateSchemaFiles();
|
|
|
3251
3334
|
init_generateSchemaFiles();
|
|
3252
3335
|
|
|
3253
3336
|
// src/cli/collectImports.ts
|
|
3254
|
-
import
|
|
3255
|
-
import
|
|
3337
|
+
import path12 from "path";
|
|
3338
|
+
import fs9 from "fs";
|
|
3256
3339
|
var SPEC_RE = /(\bfrom\s*|import\s*\(\s*)(['"])([^'"]+)\2/g;
|
|
3257
3340
|
function extractImportSpecifiers(source) {
|
|
3258
3341
|
const specifiers = [];
|
|
@@ -3264,10 +3347,10 @@ function extractImportSpecifiers(source) {
|
|
|
3264
3347
|
return specifiers;
|
|
3265
3348
|
}
|
|
3266
3349
|
function resolveSpecifierFromDir(dir, specifier) {
|
|
3267
|
-
return resolveRelativeSpecifier(
|
|
3350
|
+
return resolveRelativeSpecifier(path12.join(dir, "__faapi_probe__.ts"), specifier);
|
|
3268
3351
|
}
|
|
3269
3352
|
async function collectRelativeImports(entryFiles, rootDir) {
|
|
3270
|
-
const appDirAbs = toRealPath(
|
|
3353
|
+
const appDirAbs = toRealPath(path12.resolve(rootDir, "src"));
|
|
3271
3354
|
const tsconfig = readTsconfig(rootDir);
|
|
3272
3355
|
const visited = /* @__PURE__ */ new Set();
|
|
3273
3356
|
const insideFiles = /* @__PURE__ */ new Set();
|
|
@@ -3277,7 +3360,7 @@ async function collectRelativeImports(entryFiles, rootDir) {
|
|
|
3277
3360
|
visited.add(filePath);
|
|
3278
3361
|
let source;
|
|
3279
3362
|
try {
|
|
3280
|
-
source = await
|
|
3363
|
+
source = await fs9.promises.readFile(filePath, "utf8");
|
|
3281
3364
|
} catch {
|
|
3282
3365
|
return;
|
|
3283
3366
|
}
|
|
@@ -3299,7 +3382,7 @@ async function collectRelativeImports(entryFiles, rootDir) {
|
|
|
3299
3382
|
resolved = null;
|
|
3300
3383
|
}
|
|
3301
3384
|
if (!resolved) continue;
|
|
3302
|
-
if (!isInsideDir(toRealPath(resolved), toRealPath(
|
|
3385
|
+
if (!isInsideDir(toRealPath(resolved), toRealPath(path12.resolve(rootDir)))) continue;
|
|
3303
3386
|
if (isInsideDir(toRealPath(resolved), appDirAbs)) {
|
|
3304
3387
|
insideFiles.add(resolved);
|
|
3305
3388
|
} else {
|
|
@@ -3320,8 +3403,8 @@ async function collectRelativeImports(entryFiles, rootDir) {
|
|
|
3320
3403
|
// src/cli/compileOnDemand.ts
|
|
3321
3404
|
function isProductFresh(sourceAbsPath, productAbsPath) {
|
|
3322
3405
|
try {
|
|
3323
|
-
const srcStat =
|
|
3324
|
-
const prodStat =
|
|
3406
|
+
const srcStat = fs10.statSync(sourceAbsPath);
|
|
3407
|
+
const prodStat = fs10.statSync(productAbsPath);
|
|
3325
3408
|
return prodStat.mtimeMs >= srcStat.mtimeMs;
|
|
3326
3409
|
} catch {
|
|
3327
3410
|
return false;
|
|
@@ -3353,7 +3436,7 @@ async function ensureCompiled(sourceAbsPath, rootDir, dist) {
|
|
|
3353
3436
|
if (state.compiledFiles.has(sourceAbsPath)) {
|
|
3354
3437
|
return false;
|
|
3355
3438
|
}
|
|
3356
|
-
if (!
|
|
3439
|
+
if (!fs10.existsSync(sourceAbsPath)) {
|
|
3357
3440
|
return false;
|
|
3358
3441
|
}
|
|
3359
3442
|
const productPath = prodSourcePathToProductPath(sourceAbsPath, rootDir, dist);
|
|
@@ -3403,11 +3486,11 @@ async function ensureMiddlewaresCompiled(middlewarePaths, rootDir) {
|
|
|
3403
3486
|
}
|
|
3404
3487
|
}
|
|
3405
3488
|
function prodSourcePathToProductPath(sourceAbsPath, rootDir, dist) {
|
|
3406
|
-
const rel =
|
|
3489
|
+
const rel = path13.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
|
|
3407
3490
|
if (!rel.startsWith("src/")) return null;
|
|
3408
3491
|
const relWithoutSrc = rel.slice(4);
|
|
3409
3492
|
const jsRel = relWithoutSrc.replace(/\.ts$/, ".js");
|
|
3410
|
-
return
|
|
3493
|
+
return path13.resolve(rootDir, dist, jsRel);
|
|
3411
3494
|
}
|
|
3412
3495
|
function clearGeneratedSchemas() {
|
|
3413
3496
|
state.generatedSchemas.clear();
|
|
@@ -3423,9 +3506,9 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
|
|
|
3423
3506
|
if (state.generatedSchemas.has(schemaPath)) {
|
|
3424
3507
|
return false;
|
|
3425
3508
|
}
|
|
3426
|
-
const prodAbsPath =
|
|
3509
|
+
const prodAbsPath = path13.resolve(rootDir, routeFilePath);
|
|
3427
3510
|
const sourceAbsPath = prodPathToSourcePath(prodAbsPath, rootDir, dist);
|
|
3428
|
-
if (!
|
|
3511
|
+
if (!fs10.existsSync(sourceAbsPath)) {
|
|
3429
3512
|
return false;
|
|
3430
3513
|
}
|
|
3431
3514
|
if (isProductFresh(sourceAbsPath, schemaPath)) {
|
|
@@ -3436,7 +3519,7 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
|
|
|
3436
3519
|
if (fileRoutes.length === 0) {
|
|
3437
3520
|
return false;
|
|
3438
3521
|
}
|
|
3439
|
-
const sourceRelPath =
|
|
3522
|
+
const sourceRelPath = path13.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
|
|
3440
3523
|
const sourceRoutes = fileRoutes.map((r) => ({ ...r, filePath: sourceRelPath }));
|
|
3441
3524
|
const generatePromise = (async () => {
|
|
3442
3525
|
await generateSchemaFiles(sourceRoutes, rootDir, dist);
|
|
@@ -3457,7 +3540,7 @@ async function deleteSchemaFiles(routes, rootDir, dist) {
|
|
|
3457
3540
|
if (deleted.has(schemaPath)) continue;
|
|
3458
3541
|
deleted.add(schemaPath);
|
|
3459
3542
|
try {
|
|
3460
|
-
await
|
|
3543
|
+
await fs10.promises.unlink(schemaPath);
|
|
3461
3544
|
} catch {
|
|
3462
3545
|
}
|
|
3463
3546
|
}
|
|
@@ -3466,19 +3549,19 @@ var sourcePathCache = /* @__PURE__ */ new Map();
|
|
|
3466
3549
|
function prodPathToSourcePath(prodAbsPath, rootDir, dist) {
|
|
3467
3550
|
const cached = sourcePathCache.get(prodAbsPath);
|
|
3468
3551
|
if (cached) return cached;
|
|
3469
|
-
const rel =
|
|
3552
|
+
const rel = path13.relative(rootDir, prodAbsPath).replace(/\\/g, "/");
|
|
3470
3553
|
let relWithoutDist = rel;
|
|
3471
3554
|
if (relWithoutDist.startsWith(`${dist}/`)) {
|
|
3472
3555
|
relWithoutDist = relWithoutDist.slice(dist.length + 1);
|
|
3473
3556
|
}
|
|
3474
3557
|
const srcRel = `src/${relWithoutDist}`;
|
|
3475
3558
|
const tsRel = srcRel.replace(/\.js$/, ".ts");
|
|
3476
|
-
const tsAbs =
|
|
3559
|
+
const tsAbs = path13.resolve(rootDir, tsRel);
|
|
3477
3560
|
let result;
|
|
3478
|
-
if (
|
|
3561
|
+
if (fs10.existsSync(tsAbs)) {
|
|
3479
3562
|
result = tsAbs;
|
|
3480
3563
|
} else {
|
|
3481
|
-
result =
|
|
3564
|
+
result = path13.resolve(rootDir, srcRel);
|
|
3482
3565
|
}
|
|
3483
3566
|
sourcePathCache.set(prodAbsPath, result);
|
|
3484
3567
|
return result;
|
|
@@ -3496,7 +3579,7 @@ async function loadAgentModule(filePath, hasRun, rootDir) {
|
|
|
3496
3579
|
const dist = getDevDist();
|
|
3497
3580
|
if (dist) {
|
|
3498
3581
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
3499
|
-
if (sourcePath &&
|
|
3582
|
+
if (sourcePath && fs11.existsSync(sourcePath)) {
|
|
3500
3583
|
try {
|
|
3501
3584
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
3502
3585
|
} catch (compileErr) {
|
|
@@ -3529,13 +3612,13 @@ async function loadAgentModule(filePath, hasRun, rootDir) {
|
|
|
3529
3612
|
}
|
|
3530
3613
|
|
|
3531
3614
|
// src/loader/loadToolModule.ts
|
|
3532
|
-
import
|
|
3615
|
+
import fs12 from "fs";
|
|
3533
3616
|
async function loadToolModule(filePath, functionName, rootDir) {
|
|
3534
3617
|
if (isDevOnDemandEnabled() && rootDir) {
|
|
3535
3618
|
const dist = getDevDist();
|
|
3536
3619
|
if (dist) {
|
|
3537
3620
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
3538
|
-
if (sourcePath &&
|
|
3621
|
+
if (sourcePath && fs12.existsSync(sourcePath)) {
|
|
3539
3622
|
try {
|
|
3540
3623
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
3541
3624
|
} catch (compileErr) {
|
|
@@ -3567,7 +3650,7 @@ async function loadToolModule(filePath, functionName, rootDir) {
|
|
|
3567
3650
|
import { existsSync as existsSync2 } from "fs";
|
|
3568
3651
|
|
|
3569
3652
|
// src/cli/generateToolArtifacts.ts
|
|
3570
|
-
import
|
|
3653
|
+
import path14 from "path";
|
|
3571
3654
|
import { existsSync } from "fs";
|
|
3572
3655
|
|
|
3573
3656
|
// src/ast/extractToolMetadata.ts
|
|
@@ -3691,7 +3774,7 @@ function collectToolSchemaSources(tools, rootDir) {
|
|
|
3691
3774
|
const toolsByFile = /* @__PURE__ */ new Map();
|
|
3692
3775
|
for (const tool of tools) {
|
|
3693
3776
|
if (!tool.inputTypeName) continue;
|
|
3694
|
-
const absPath =
|
|
3777
|
+
const absPath = path14.resolve(rootDir, tool.filePath);
|
|
3695
3778
|
let list = toolsByFile.get(absPath);
|
|
3696
3779
|
if (!list) {
|
|
3697
3780
|
list = [];
|
|
@@ -3751,15 +3834,15 @@ function generateToolSchemaFileSource(sources, resolveType, helpersImportPath) {
|
|
|
3751
3834
|
}
|
|
3752
3835
|
async function maybeGenerateHelpers(allSourceCode, distDir) {
|
|
3753
3836
|
if (!usesCoerceHelpers(allSourceCode)) return;
|
|
3754
|
-
const helpersPath =
|
|
3837
|
+
const helpersPath = path14.resolve(distDir, HELPERS_FILENAME);
|
|
3755
3838
|
if (existsSync(helpersPath)) return;
|
|
3756
3839
|
await atomicWriteFile(helpersPath, generateHelpersFileSource());
|
|
3757
3840
|
}
|
|
3758
3841
|
async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
3759
3842
|
const metadata = [];
|
|
3760
|
-
const programByFile = createPrograms(tools.map((m) =>
|
|
3843
|
+
const programByFile = createPrograms(tools.map((m) => path14.resolve(rootDir, m.filePath)));
|
|
3761
3844
|
for (const manifest of tools) {
|
|
3762
|
-
const absPath =
|
|
3845
|
+
const absPath = path14.resolve(rootDir, manifest.filePath);
|
|
3763
3846
|
const program = programByFile.get(absPath);
|
|
3764
3847
|
const result = extractToolMetadata(program, absPath, manifest.functionName, {
|
|
3765
3848
|
name: manifest.name,
|
|
@@ -3770,7 +3853,7 @@ async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
|
3770
3853
|
}
|
|
3771
3854
|
}
|
|
3772
3855
|
const serialized = serializeTools(metadata, dist);
|
|
3773
|
-
const toolsPath =
|
|
3856
|
+
const toolsPath = path14.resolve(rootDir, dist, TOOLS_FILE);
|
|
3774
3857
|
await writeToolsModule(serialized, toolsPath);
|
|
3775
3858
|
if (options?.skipSchema) {
|
|
3776
3859
|
return metadata;
|
|
@@ -3793,7 +3876,7 @@ async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
|
3793
3876
|
}
|
|
3794
3877
|
const fileEntries = [];
|
|
3795
3878
|
for (const [filePath, fileSources] of sourcesByFile) {
|
|
3796
|
-
const relFile =
|
|
3879
|
+
const relFile = path14.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
3797
3880
|
const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
|
|
3798
3881
|
const resolver = resolversByFile.get(filePath);
|
|
3799
3882
|
let relForDir = relFile;
|
|
@@ -3811,7 +3894,7 @@ async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
|
3811
3894
|
fileEntries.push({ outputPath, source });
|
|
3812
3895
|
}
|
|
3813
3896
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
3814
|
-
const distDir =
|
|
3897
|
+
const distDir = path14.resolve(rootDir, dist);
|
|
3815
3898
|
await maybeGenerateHelpers(allSourceCode, distDir);
|
|
3816
3899
|
await Promise.all(
|
|
3817
3900
|
fileEntries.map(({ outputPath, source }) => writeToolSchemaFile(outputPath, source))
|
|
@@ -3925,9 +4008,28 @@ function cors(options = {}) {
|
|
|
3925
4008
|
}
|
|
3926
4009
|
|
|
3927
4010
|
// src/middleware/logger.ts
|
|
4011
|
+
function levelForStatus(status) {
|
|
4012
|
+
if (status >= 500) return "error";
|
|
4013
|
+
if (status >= 400) return "warn";
|
|
4014
|
+
return "info";
|
|
4015
|
+
}
|
|
4016
|
+
function defaultLog(entry, text) {
|
|
4017
|
+
if (isAccessLogPiped()) {
|
|
4018
|
+
const logEntry = {
|
|
4019
|
+
level: levelForStatus(entry.status),
|
|
4020
|
+
message: text,
|
|
4021
|
+
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4022
|
+
scope: "access",
|
|
4023
|
+
fields: entry
|
|
4024
|
+
};
|
|
4025
|
+
writeLogEntry(logEntry);
|
|
4026
|
+
return;
|
|
4027
|
+
}
|
|
4028
|
+
console.log(entry);
|
|
4029
|
+
}
|
|
3928
4030
|
function logger(options = {}) {
|
|
3929
4031
|
return async (ctx, next) => {
|
|
3930
|
-
const log = options.log ??
|
|
4032
|
+
const log = options.log ?? defaultLog;
|
|
3931
4033
|
const start = Date.now();
|
|
3932
4034
|
try {
|
|
3933
4035
|
const response = await next();
|
|
@@ -4022,16 +4124,16 @@ function helmet(options = {}) {
|
|
|
4022
4124
|
}
|
|
4023
4125
|
|
|
4024
4126
|
// src/config/loadConfig.ts
|
|
4025
|
-
import
|
|
4026
|
-
import
|
|
4127
|
+
import path15 from "path";
|
|
4128
|
+
import fs13 from "fs";
|
|
4027
4129
|
var CONFIG_PRODUCT_FILE = "faapi-config.js";
|
|
4028
4130
|
async function loadConfig(rootDir, dist) {
|
|
4029
|
-
const configProductPath =
|
|
4030
|
-
if (
|
|
4131
|
+
const configProductPath = path15.resolve(rootDir, dist, CONFIG_PRODUCT_FILE);
|
|
4132
|
+
if (fs13.existsSync(configProductPath)) {
|
|
4031
4133
|
const module = await importWithCacheBust(configProductPath);
|
|
4032
4134
|
return module.default ?? {};
|
|
4033
4135
|
}
|
|
4034
|
-
const hasSourceConfig =
|
|
4136
|
+
const hasSourceConfig = fs13.existsSync(path15.join(rootDir, "faapi.config.ts")) || fs13.existsSync(path15.join(rootDir, "faapi.config.js"));
|
|
4035
4137
|
if (hasSourceConfig) {
|
|
4036
4138
|
throw new Error(
|
|
4037
4139
|
`[faapi] ${dist}/${CONFIG_PRODUCT_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
|
|
@@ -4041,8 +4143,8 @@ async function loadConfig(rootDir, dist) {
|
|
|
4041
4143
|
}
|
|
4042
4144
|
|
|
4043
4145
|
// src/cli/loadEnv.ts
|
|
4044
|
-
import
|
|
4045
|
-
import
|
|
4146
|
+
import fs14 from "fs";
|
|
4147
|
+
import path16 from "path";
|
|
4046
4148
|
function resolveEnv() {
|
|
4047
4149
|
return process.env.NODE_ENV || "development";
|
|
4048
4150
|
}
|
|
@@ -4109,9 +4211,9 @@ function loadEnv(rootDir) {
|
|
|
4109
4211
|
const files = getEnvFiles(env);
|
|
4110
4212
|
const merged = {};
|
|
4111
4213
|
for (const file of files) {
|
|
4112
|
-
const filePath =
|
|
4113
|
-
if (!
|
|
4114
|
-
const content =
|
|
4214
|
+
const filePath = path16.join(rootDir, file);
|
|
4215
|
+
if (!fs14.existsSync(filePath)) continue;
|
|
4216
|
+
const content = fs14.readFileSync(filePath, "utf-8");
|
|
4115
4217
|
const parsed = parseEnvFile(content, merged);
|
|
4116
4218
|
Object.assign(merged, parsed);
|
|
4117
4219
|
}
|
|
@@ -4123,8 +4225,8 @@ function loadEnv(rootDir) {
|
|
|
4123
4225
|
}
|
|
4124
4226
|
|
|
4125
4227
|
// src/cli/createAppCore.ts
|
|
4126
|
-
import
|
|
4127
|
-
import
|
|
4228
|
+
import fs19 from "fs";
|
|
4229
|
+
import path24 from "path";
|
|
4128
4230
|
import { PassThrough, Readable as Readable3 } from "stream";
|
|
4129
4231
|
|
|
4130
4232
|
// src/router/sortRoutes.ts
|
|
@@ -4177,7 +4279,7 @@ import {
|
|
|
4177
4279
|
import { createSecureServer as createHttp2SecureServer } from "http2";
|
|
4178
4280
|
import { readFileSync } from "fs";
|
|
4179
4281
|
import { Readable as Readable2 } from "stream";
|
|
4180
|
-
import
|
|
4282
|
+
import path18 from "path";
|
|
4181
4283
|
|
|
4182
4284
|
// src/router/matchRoute.ts
|
|
4183
4285
|
var httpIndexCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -4219,18 +4321,18 @@ function getWsIndex(routes) {
|
|
|
4219
4321
|
wsIndexCache.set(routes, index);
|
|
4220
4322
|
return index;
|
|
4221
4323
|
}
|
|
4222
|
-
function matchRoute(routes, method,
|
|
4324
|
+
function matchRoute(routes, method, path29) {
|
|
4223
4325
|
const index = getHttpIndex(routes);
|
|
4224
4326
|
const upper = method.toUpperCase();
|
|
4225
|
-
const hit = matchByMethod(index, upper,
|
|
4327
|
+
const hit = matchByMethod(index, upper, path29);
|
|
4226
4328
|
if (hit) return hit;
|
|
4227
4329
|
if (upper === "HEAD") {
|
|
4228
|
-
return matchByMethod(index, "GET",
|
|
4330
|
+
return matchByMethod(index, "GET", path29);
|
|
4229
4331
|
}
|
|
4230
4332
|
return null;
|
|
4231
4333
|
}
|
|
4232
|
-
function matchByMethod(index, method,
|
|
4233
|
-
const staticHit = index.static.get(`${method}|${
|
|
4334
|
+
function matchByMethod(index, method, path29) {
|
|
4335
|
+
const staticHit = index.static.get(`${method}|${path29}`);
|
|
4234
4336
|
if (staticHit) {
|
|
4235
4337
|
return { route: staticHit, params: {} };
|
|
4236
4338
|
}
|
|
@@ -4239,31 +4341,31 @@ function matchByMethod(index, method, path28) {
|
|
|
4239
4341
|
if (route.method !== method) {
|
|
4240
4342
|
continue;
|
|
4241
4343
|
}
|
|
4242
|
-
const params = matchSegments(entry.segments,
|
|
4344
|
+
const params = matchSegments(entry.segments, path29, route.paramNames, route.isCatchAll);
|
|
4243
4345
|
if (params !== null) {
|
|
4244
4346
|
return { route, params };
|
|
4245
4347
|
}
|
|
4246
4348
|
}
|
|
4247
4349
|
return null;
|
|
4248
4350
|
}
|
|
4249
|
-
function matchWsRoute(wsRoutes,
|
|
4351
|
+
function matchWsRoute(wsRoutes, path29) {
|
|
4250
4352
|
const index = getWsIndex(wsRoutes);
|
|
4251
|
-
const staticHit = index.static.get(
|
|
4353
|
+
const staticHit = index.static.get(path29);
|
|
4252
4354
|
if (staticHit) {
|
|
4253
4355
|
return { route: staticHit, params: {} };
|
|
4254
4356
|
}
|
|
4255
4357
|
for (const route of index.dynamics) {
|
|
4256
|
-
const params = matchDynamicPath(route.urlPath,
|
|
4358
|
+
const params = matchDynamicPath(route.urlPath, path29, route.paramNames, route.isCatchAll);
|
|
4257
4359
|
if (params !== null) {
|
|
4258
4360
|
return { route, params };
|
|
4259
4361
|
}
|
|
4260
4362
|
}
|
|
4261
4363
|
return null;
|
|
4262
4364
|
}
|
|
4263
|
-
function findAllowedMethods(routes,
|
|
4365
|
+
function findAllowedMethods(routes, path29) {
|
|
4264
4366
|
const index = getHttpIndex(routes);
|
|
4265
4367
|
const methods = /* @__PURE__ */ new Set();
|
|
4266
|
-
const staticMethods = index.methodsByStaticPath.get(
|
|
4368
|
+
const staticMethods = index.methodsByStaticPath.get(path29);
|
|
4267
4369
|
if (staticMethods) {
|
|
4268
4370
|
for (const method of staticMethods) {
|
|
4269
4371
|
methods.add(method);
|
|
@@ -4272,7 +4374,7 @@ function findAllowedMethods(routes, path28) {
|
|
|
4272
4374
|
for (const entry of index.dynamics) {
|
|
4273
4375
|
const params = matchSegments(
|
|
4274
4376
|
entry.segments,
|
|
4275
|
-
|
|
4377
|
+
path29,
|
|
4276
4378
|
entry.route.paramNames,
|
|
4277
4379
|
entry.route.isCatchAll
|
|
4278
4380
|
);
|
|
@@ -4285,11 +4387,11 @@ function findAllowedMethods(routes, path28) {
|
|
|
4285
4387
|
}
|
|
4286
4388
|
return Array.from(methods);
|
|
4287
4389
|
}
|
|
4288
|
-
function matchDynamicPath(pattern,
|
|
4289
|
-
return matchSegments(pattern.split("/").filter(Boolean),
|
|
4390
|
+
function matchDynamicPath(pattern, path29, paramNames, isCatchAll) {
|
|
4391
|
+
return matchSegments(pattern.split("/").filter(Boolean), path29, paramNames, isCatchAll);
|
|
4290
4392
|
}
|
|
4291
|
-
function matchSegments(patternSegments,
|
|
4292
|
-
const pathSegments =
|
|
4393
|
+
function matchSegments(patternSegments, path29, paramNames, isCatchAll) {
|
|
4394
|
+
const pathSegments = path29.split("/").filter(Boolean);
|
|
4293
4395
|
if (isCatchAll) {
|
|
4294
4396
|
const nonCatchAllCount = patternSegments.length - 1;
|
|
4295
4397
|
if (pathSegments.length <= nonCatchAllCount) {
|
|
@@ -5196,9 +5298,9 @@ async function validateInput(schemaPath, method, inputType, input) {
|
|
|
5196
5298
|
function mapZodIssues(error) {
|
|
5197
5299
|
return error.issues.map((issue) => {
|
|
5198
5300
|
const code = mapZodCode(issue);
|
|
5199
|
-
const
|
|
5301
|
+
const path29 = issue.path.map(String).join(".") || "";
|
|
5200
5302
|
return {
|
|
5201
|
-
path:
|
|
5303
|
+
path: path29,
|
|
5202
5304
|
code,
|
|
5203
5305
|
expected: issue.expected ?? mapExpectedFromMessage(issue.message),
|
|
5204
5306
|
received: issue.received ?? mapReceivedFromMessage(issue.message),
|
|
@@ -5430,9 +5532,9 @@ function etag(options = {}) {
|
|
|
5430
5532
|
}
|
|
5431
5533
|
|
|
5432
5534
|
// src/server/handleWsUpgrade.ts
|
|
5433
|
-
import
|
|
5535
|
+
import fs15 from "fs";
|
|
5434
5536
|
import { WebSocketServer, WebSocket } from "ws";
|
|
5435
|
-
import
|
|
5537
|
+
import path17 from "path";
|
|
5436
5538
|
|
|
5437
5539
|
// src/server/serverUtils.ts
|
|
5438
5540
|
function nodeHttpToWebHeaders(req) {
|
|
@@ -5567,7 +5669,7 @@ async function loadWsHandler(filePath, ctx, rootDir) {
|
|
|
5567
5669
|
const dist = getDevDist();
|
|
5568
5670
|
if (dist) {
|
|
5569
5671
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
5570
|
-
if (sourcePath &&
|
|
5672
|
+
if (sourcePath && fs15.existsSync(sourcePath)) {
|
|
5571
5673
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
5572
5674
|
}
|
|
5573
5675
|
}
|
|
@@ -5681,7 +5783,7 @@ function attachWebSocket(options) {
|
|
|
5681
5783
|
const finalHandler = async () => {
|
|
5682
5784
|
let handlers;
|
|
5683
5785
|
try {
|
|
5684
|
-
const absoluteFilePath =
|
|
5786
|
+
const absoluteFilePath = path17.resolve(rootDir, route.filePath);
|
|
5685
5787
|
handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
|
|
5686
5788
|
} catch (err) {
|
|
5687
5789
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -5934,7 +6036,7 @@ function getRoutePaths(route, rootDir, dist) {
|
|
|
5934
6036
|
let cached = routePathCache.get(route);
|
|
5935
6037
|
if (!cached) {
|
|
5936
6038
|
cached = {
|
|
5937
|
-
absFilePath:
|
|
6039
|
+
absFilePath: path18.resolve(rootDir, route.filePath),
|
|
5938
6040
|
schemaPath: getRuntimeSchemaPath(route.filePath, dist, rootDir)
|
|
5939
6041
|
};
|
|
5940
6042
|
routePathCache.set(route, cached);
|
|
@@ -6056,8 +6158,8 @@ function applyPluginWrappers(server, handlerWrappers, upgradeWrappers) {
|
|
|
6056
6158
|
}
|
|
6057
6159
|
|
|
6058
6160
|
// src/cli/generateRoutes.ts
|
|
6059
|
-
import
|
|
6060
|
-
import
|
|
6161
|
+
import fs16 from "fs";
|
|
6162
|
+
import path19 from "path";
|
|
6061
6163
|
async function hydrateRoutes(manifest) {
|
|
6062
6164
|
const hydrateRoute = (serialized) => ({
|
|
6063
6165
|
method: serialized.method,
|
|
@@ -6082,7 +6184,7 @@ async function hydrateRoutes(manifest) {
|
|
|
6082
6184
|
}
|
|
6083
6185
|
|
|
6084
6186
|
// src/cli/generateAgentArtifacts.ts
|
|
6085
|
-
import
|
|
6187
|
+
import path20 from "path";
|
|
6086
6188
|
|
|
6087
6189
|
// src/ast/extractAgentMetadata.ts
|
|
6088
6190
|
import ts10 from "typescript";
|
|
@@ -6355,9 +6457,9 @@ function validateAgentList(metadata) {
|
|
|
6355
6457
|
}
|
|
6356
6458
|
async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
6357
6459
|
const metadata = [];
|
|
6358
|
-
const programByFile = createPrograms(agents.map((m) =>
|
|
6460
|
+
const programByFile = createPrograms(agents.map((m) => path20.resolve(rootDir, m.filePath)));
|
|
6359
6461
|
for (const manifest of agents) {
|
|
6360
|
-
const absPath =
|
|
6462
|
+
const absPath = path20.resolve(rootDir, manifest.filePath);
|
|
6361
6463
|
const program = programByFile.get(absPath);
|
|
6362
6464
|
const result = extractAgentMetadata(program, absPath, {
|
|
6363
6465
|
name: manifest.name,
|
|
@@ -6373,13 +6475,13 @@ async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
|
6373
6475
|
}
|
|
6374
6476
|
validateAgentList(metadata);
|
|
6375
6477
|
const serialized = serializeAgents(metadata, dist);
|
|
6376
|
-
const agentsPath =
|
|
6478
|
+
const agentsPath = path20.resolve(rootDir, dist, AGENTS_FILE);
|
|
6377
6479
|
await writeAgentsModule(serialized, agentsPath);
|
|
6378
6480
|
return metadata;
|
|
6379
6481
|
}
|
|
6380
6482
|
|
|
6381
6483
|
// src/cli/generateTaskArtifacts.ts
|
|
6382
|
-
import
|
|
6484
|
+
import path21 from "path";
|
|
6383
6485
|
init_createProgram();
|
|
6384
6486
|
init_atomicWrite();
|
|
6385
6487
|
init_generateSchemaFiles();
|
|
@@ -6418,7 +6520,7 @@ function collectTaskSchemaSources(tasks, rootDir) {
|
|
|
6418
6520
|
const tasksByFile = /* @__PURE__ */ new Map();
|
|
6419
6521
|
for (const task of tasks) {
|
|
6420
6522
|
if (!task.inputTypeName) continue;
|
|
6421
|
-
const absPath =
|
|
6523
|
+
const absPath = path21.resolve(rootDir, task.filePath);
|
|
6422
6524
|
let list = tasksByFile.get(absPath);
|
|
6423
6525
|
if (!list) {
|
|
6424
6526
|
list = [];
|
|
@@ -6475,9 +6577,9 @@ function generateTaskSchemaFileSource(sources, resolveType, helpersImportPath) {
|
|
|
6475
6577
|
async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
6476
6578
|
const metadata = [];
|
|
6477
6579
|
if (manifests.length > 0) {
|
|
6478
|
-
const programByFile = createPrograms(manifests.map((m) =>
|
|
6580
|
+
const programByFile = createPrograms(manifests.map((m) => path21.resolve(rootDir, m.filePath)));
|
|
6479
6581
|
for (const manifest of manifests) {
|
|
6480
|
-
const absPath =
|
|
6582
|
+
const absPath = path21.resolve(rootDir, manifest.filePath);
|
|
6481
6583
|
const result = extractToolMetadata(programByFile.get(absPath), absPath, "run", {
|
|
6482
6584
|
name: manifest.name,
|
|
6483
6585
|
filePath: manifest.filePath
|
|
@@ -6488,7 +6590,7 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
|
6488
6590
|
}
|
|
6489
6591
|
}
|
|
6490
6592
|
const serialized = serializeTasks(manifests, dist);
|
|
6491
|
-
const tasksPath =
|
|
6593
|
+
const tasksPath = path21.resolve(rootDir, dist, TASKS_FILE);
|
|
6492
6594
|
await writeTasksModule(serialized, tasksPath);
|
|
6493
6595
|
if (metadata.length === 0) {
|
|
6494
6596
|
return hydrateTasks(serialized);
|
|
@@ -6508,7 +6610,7 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
|
6508
6610
|
}
|
|
6509
6611
|
const fileEntries = [];
|
|
6510
6612
|
for (const [filePath, fileSources] of sourcesByFile) {
|
|
6511
|
-
const relFile =
|
|
6613
|
+
const relFile = path21.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
6512
6614
|
const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
|
|
6513
6615
|
const resolver = resolversByFile.get(filePath);
|
|
6514
6616
|
let relForDir = relFile;
|
|
@@ -6527,7 +6629,7 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
|
6527
6629
|
}
|
|
6528
6630
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
6529
6631
|
if (usesCoerceHelpers(allSourceCode)) {
|
|
6530
|
-
const helpersPath =
|
|
6632
|
+
const helpersPath = path21.resolve(rootDir, dist, HELPERS_FILENAME);
|
|
6531
6633
|
const { existsSync: existsSync3 } = await import("fs");
|
|
6532
6634
|
if (!existsSync3(helpersPath)) {
|
|
6533
6635
|
await atomicWriteFile(helpersPath, generateHelpersFileSource());
|
|
@@ -6559,18 +6661,18 @@ function createIdleTaskDriver() {
|
|
|
6559
6661
|
}
|
|
6560
6662
|
|
|
6561
6663
|
// src/cli/loadPlugins.ts
|
|
6562
|
-
import
|
|
6563
|
-
import
|
|
6664
|
+
import path23 from "path";
|
|
6665
|
+
import fs18 from "fs";
|
|
6564
6666
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
6565
6667
|
|
|
6566
6668
|
// src/cli/compileConfig.ts
|
|
6567
|
-
import
|
|
6568
|
-
import
|
|
6669
|
+
import path22 from "path";
|
|
6670
|
+
import fs17 from "fs";
|
|
6569
6671
|
async function compileProjectModules(entryPoints, rootDir, dist) {
|
|
6570
6672
|
const { insideFiles, outsideFiles } = await collectRelativeImports(entryPoints, rootDir);
|
|
6571
6673
|
const esbuild = await import("esbuild");
|
|
6572
6674
|
const aliasPlugins = buildAliasPlugins(rootDir);
|
|
6573
|
-
const absDist =
|
|
6675
|
+
const absDist = path22.resolve(rootDir, dist);
|
|
6574
6676
|
await esbuild.build({
|
|
6575
6677
|
entryPoints: [...entryPoints, ...outsideFiles],
|
|
6576
6678
|
outdir: absDist,
|
|
@@ -6584,7 +6686,7 @@ async function compileProjectModules(entryPoints, rootDir, dist) {
|
|
|
6584
6686
|
logLevel: "silent"
|
|
6585
6687
|
});
|
|
6586
6688
|
if (insideFiles.length > 0) {
|
|
6587
|
-
const appOutbase =
|
|
6689
|
+
const appOutbase = path22.resolve(rootDir, "src");
|
|
6588
6690
|
await esbuild.build({
|
|
6589
6691
|
entryPoints: insideFiles,
|
|
6590
6692
|
outdir: absDist,
|
|
@@ -6665,37 +6767,37 @@ async function loadPlugins(declarations, ctx, rootDir, dist) {
|
|
|
6665
6767
|
var TS_EXTS = /\.(ts|tsx|mts|cts)$/;
|
|
6666
6768
|
var JS_EXTS = /\.(js|mjs|cjs|jsx)$/;
|
|
6667
6769
|
function resolveLocalPluginSource(specifier, baseDir) {
|
|
6668
|
-
const base =
|
|
6669
|
-
if ((TS_EXTS.test(base) || JS_EXTS.test(base)) &&
|
|
6770
|
+
const base = path23.isAbsolute(specifier) ? specifier : path23.resolve(baseDir, specifier);
|
|
6771
|
+
if ((TS_EXTS.test(base) || JS_EXTS.test(base)) && fs18.existsSync(base)) return base;
|
|
6670
6772
|
for (const ext of [".ts", ".js"]) {
|
|
6671
|
-
if (
|
|
6773
|
+
if (fs18.existsSync(base + ext)) return base + ext;
|
|
6672
6774
|
}
|
|
6673
6775
|
for (const indexExt of ["/index.ts", "/index.js"]) {
|
|
6674
|
-
if (
|
|
6776
|
+
if (fs18.existsSync(base + indexExt)) return base + indexExt;
|
|
6675
6777
|
}
|
|
6676
6778
|
return null;
|
|
6677
6779
|
}
|
|
6678
6780
|
function mirrorProductPath(sourcePath, baseDir, distDir) {
|
|
6679
|
-
let rel =
|
|
6781
|
+
let rel = path23.relative(baseDir, sourcePath).replace(/\\/g, "/");
|
|
6680
6782
|
if (rel.startsWith("src/")) rel = rel.slice(4);
|
|
6681
|
-
return
|
|
6783
|
+
return path23.resolve(distDir, rel.replace(TS_EXTS, ".js"));
|
|
6682
6784
|
}
|
|
6683
6785
|
function isSourceNewer(sourcePath, productPath) {
|
|
6684
6786
|
try {
|
|
6685
|
-
return
|
|
6787
|
+
return fs18.statSync(sourcePath).mtimeMs > fs18.statSync(productPath).mtimeMs;
|
|
6686
6788
|
} catch {
|
|
6687
6789
|
return true;
|
|
6688
6790
|
}
|
|
6689
6791
|
}
|
|
6690
6792
|
async function importPluginModule(specifier, baseDir, dist) {
|
|
6691
6793
|
const isRelative = specifier.startsWith("./") || specifier.startsWith("../");
|
|
6692
|
-
if (!isRelative && !
|
|
6794
|
+
if (!isRelative && !path23.isAbsolute(specifier)) {
|
|
6693
6795
|
return import(specifier);
|
|
6694
6796
|
}
|
|
6695
|
-
const distDir = dist ?
|
|
6797
|
+
const distDir = dist ? path23.resolve(baseDir, dist) : null;
|
|
6696
6798
|
const sourcePath = resolveLocalPluginSource(specifier, baseDir);
|
|
6697
6799
|
const productPath = sourcePath && distDir ? mirrorProductPath(sourcePath, baseDir, distDir) : null;
|
|
6698
|
-
if (productPath !== null &&
|
|
6800
|
+
if (productPath !== null && fs18.existsSync(productPath) && (sourcePath === null || !isSourceNewer(sourcePath, productPath))) {
|
|
6699
6801
|
return import(pathToFileURL3(productPath).href);
|
|
6700
6802
|
}
|
|
6701
6803
|
if (sourcePath && TS_EXTS.test(sourcePath)) {
|
|
@@ -6704,13 +6806,13 @@ async function importPluginModule(specifier, baseDir, dist) {
|
|
|
6704
6806
|
`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.`
|
|
6705
6807
|
);
|
|
6706
6808
|
}
|
|
6707
|
-
const relFromRoot =
|
|
6809
|
+
const relFromRoot = path23.relative(baseDir, sourcePath).replace(/\\/g, "/");
|
|
6708
6810
|
if (relFromRoot.startsWith("src/")) {
|
|
6709
6811
|
await ensureCompiled(sourcePath, baseDir, dist);
|
|
6710
6812
|
} else {
|
|
6711
6813
|
await compileProjectModules([sourcePath], baseDir, dist);
|
|
6712
6814
|
}
|
|
6713
|
-
if (productPath &&
|
|
6815
|
+
if (productPath && fs18.existsSync(productPath)) {
|
|
6714
6816
|
return import(pathToFileURL3(productPath).href);
|
|
6715
6817
|
}
|
|
6716
6818
|
}
|
|
@@ -6722,7 +6824,7 @@ async function importPluginModule(specifier, baseDir, dist) {
|
|
|
6722
6824
|
`${specifier}/index.ts`,
|
|
6723
6825
|
`${specifier}.js`,
|
|
6724
6826
|
`${specifier}/index.js`
|
|
6725
|
-
].map((c) =>
|
|
6827
|
+
].map((c) => path23.isAbsolute(c) ? c : path23.join(baseDir, c));
|
|
6726
6828
|
throw new Error(
|
|
6727
6829
|
`Cannot find local plugin "${specifier}" (resolved from ${baseDir}). Expected one of:
|
|
6728
6830
|
${candidates.join("\n ")}
|
|
@@ -6753,8 +6855,8 @@ var ROUTES_FILE = "faapi-routes.js";
|
|
|
6753
6855
|
var TOOLS_FILE2 = "faapi-tools.js";
|
|
6754
6856
|
var AGENTS_FILE2 = "faapi-agents.js";
|
|
6755
6857
|
async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries) {
|
|
6756
|
-
const toolsPath =
|
|
6757
|
-
if (!
|
|
6858
|
+
const toolsPath = path24.resolve(rootDir, dist, TOOLS_FILE2);
|
|
6859
|
+
if (!fs19.existsSync(toolsPath)) {
|
|
6758
6860
|
return [];
|
|
6759
6861
|
}
|
|
6760
6862
|
const serialized = await importWithCacheBust(toolsPath);
|
|
@@ -6763,8 +6865,8 @@ async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries
|
|
|
6763
6865
|
return hydrated;
|
|
6764
6866
|
}
|
|
6765
6867
|
async function loadAndHydrateAgents(rootDir, dist, registries = defaultRegistries) {
|
|
6766
|
-
const agentsPath =
|
|
6767
|
-
if (!
|
|
6868
|
+
const agentsPath = path24.resolve(rootDir, dist, AGENTS_FILE2);
|
|
6869
|
+
if (!fs19.existsSync(agentsPath)) {
|
|
6768
6870
|
return [];
|
|
6769
6871
|
}
|
|
6770
6872
|
const serialized = await importWithCacheBust(agentsPath);
|
|
@@ -6779,8 +6881,8 @@ function getTaskDriverOptions(config) {
|
|
|
6779
6881
|
return void 0;
|
|
6780
6882
|
}
|
|
6781
6883
|
async function loadAndHydrateTasks(rootDir, dist, registries = defaultRegistries) {
|
|
6782
|
-
const tasksPath =
|
|
6783
|
-
if (!
|
|
6884
|
+
const tasksPath = path24.resolve(rootDir, dist, TASKS_FILE);
|
|
6885
|
+
if (!fs19.existsSync(tasksPath)) {
|
|
6784
6886
|
return [];
|
|
6785
6887
|
}
|
|
6786
6888
|
const serialized = await importWithCacheBust(tasksPath);
|
|
@@ -6849,8 +6951,8 @@ function isFaapiConfigKey(key) {
|
|
|
6849
6951
|
async function createAppBase(options) {
|
|
6850
6952
|
const rootDir = options?.rootDir ?? process.cwd();
|
|
6851
6953
|
const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
|
|
6852
|
-
const routesPath =
|
|
6853
|
-
if (!
|
|
6954
|
+
const routesPath = path24.resolve(rootDir, dist, ROUTES_FILE);
|
|
6955
|
+
if (!fs19.existsSync(routesPath)) {
|
|
6854
6956
|
throw new Error(
|
|
6855
6957
|
`[faapi] ${dist}/${ROUTES_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
|
|
6856
6958
|
);
|
|
@@ -7178,21 +7280,21 @@ async function createAppBase(options) {
|
|
|
7178
7280
|
}
|
|
7179
7281
|
|
|
7180
7282
|
// src/cli/createDevApp.ts
|
|
7181
|
-
import
|
|
7283
|
+
import path28 from "path";
|
|
7182
7284
|
|
|
7183
7285
|
// src/router/scanRoutes.ts
|
|
7184
7286
|
import fg3 from "fast-glob";
|
|
7185
|
-
import
|
|
7186
|
-
import
|
|
7287
|
+
import path25 from "path";
|
|
7288
|
+
import fs20 from "fs";
|
|
7187
7289
|
|
|
7188
7290
|
// src/router/constants.ts
|
|
7189
7291
|
var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
7190
7292
|
var HTTP_METHOD_SET = new Set(HTTP_METHODS);
|
|
7191
7293
|
|
|
7192
7294
|
// src/utils/normalizePath.ts
|
|
7193
|
-
function normalizePath(
|
|
7194
|
-
if (!
|
|
7195
|
-
let result =
|
|
7295
|
+
function normalizePath(path29) {
|
|
7296
|
+
if (!path29) return "";
|
|
7297
|
+
let result = path29.replace(/\\/g, "/");
|
|
7196
7298
|
result = result.replace(/\/+/g, "/");
|
|
7197
7299
|
result = result.replace(/\/+$/, "");
|
|
7198
7300
|
if (result && !result.startsWith("/")) {
|
|
@@ -7253,34 +7355,34 @@ function extractExportsFromSource(source) {
|
|
|
7253
7355
|
return names;
|
|
7254
7356
|
}
|
|
7255
7357
|
function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
|
|
7256
|
-
const routeDir =
|
|
7257
|
-
const resolvedRoot =
|
|
7358
|
+
const routeDir = path25.dirname(routeFilePath);
|
|
7359
|
+
const resolvedRoot = path25.resolve(rootDir);
|
|
7258
7360
|
const paths = [];
|
|
7259
|
-
let currentDir =
|
|
7361
|
+
let currentDir = path25.resolve(rootDir, routeDir);
|
|
7260
7362
|
while (true) {
|
|
7261
7363
|
if (dist) {
|
|
7262
|
-
const mwTsPath =
|
|
7263
|
-
const mwJsPath =
|
|
7264
|
-
const absTsPath =
|
|
7265
|
-
const absJsPath =
|
|
7266
|
-
const absMwPath =
|
|
7364
|
+
const mwTsPath = path25.join(currentDir, "middlewares.ts");
|
|
7365
|
+
const mwJsPath = path25.join(currentDir, "middlewares.js");
|
|
7366
|
+
const absTsPath = path25.resolve(rootDir, mwTsPath);
|
|
7367
|
+
const absJsPath = path25.resolve(rootDir, mwJsPath);
|
|
7368
|
+
const absMwPath = fs20.existsSync(absTsPath) ? absTsPath : fs20.existsSync(absJsPath) ? absJsPath : null;
|
|
7267
7369
|
if (absMwPath) {
|
|
7268
|
-
const relMwPath =
|
|
7269
|
-
const prodAbsPath =
|
|
7370
|
+
const relMwPath = path25.relative(rootDir, absMwPath);
|
|
7371
|
+
const prodAbsPath = path25.resolve(rootDir, toProdFilePath(relMwPath, dist));
|
|
7270
7372
|
paths.push(prodAbsPath);
|
|
7271
7373
|
}
|
|
7272
7374
|
} else {
|
|
7273
7375
|
for (const ext of [".ts", ".js"]) {
|
|
7274
|
-
const mwPath =
|
|
7275
|
-
const absMwPath =
|
|
7276
|
-
if (
|
|
7376
|
+
const mwPath = path25.join(currentDir, `middlewares${ext}`);
|
|
7377
|
+
const absMwPath = path25.resolve(rootDir, mwPath);
|
|
7378
|
+
if (fs20.existsSync(absMwPath)) {
|
|
7277
7379
|
paths.push(absMwPath);
|
|
7278
7380
|
break;
|
|
7279
7381
|
}
|
|
7280
7382
|
}
|
|
7281
7383
|
}
|
|
7282
7384
|
if (currentDir === resolvedRoot) break;
|
|
7283
|
-
const parentDir =
|
|
7385
|
+
const parentDir = path25.dirname(currentDir);
|
|
7284
7386
|
if (parentDir === currentDir) break;
|
|
7285
7387
|
currentDir = parentDir;
|
|
7286
7388
|
}
|
|
@@ -7299,7 +7401,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
7299
7401
|
const normalizedFile = file.replace(/\\/g, "/");
|
|
7300
7402
|
const fileName = normalizedFile.split("/").pop();
|
|
7301
7403
|
if (fileName === "handler.ts" || fileName === "handler.js") {
|
|
7302
|
-
const absPath =
|
|
7404
|
+
const absPath = path25.resolve(rootDir, normalizedFile);
|
|
7303
7405
|
const urlPath = filePathToUrlPath(normalizedFile);
|
|
7304
7406
|
const paramNames = extractParamNames(urlPath);
|
|
7305
7407
|
const isDynamic = paramNames.length > 0;
|
|
@@ -7312,7 +7414,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
7312
7414
|
const mwPaths = collectMiddlewarePaths(normalizedFile, rootDir);
|
|
7313
7415
|
middlewareBundle = await loadMergedMiddlewares(mwPaths);
|
|
7314
7416
|
}
|
|
7315
|
-
const source = await
|
|
7417
|
+
const source = await fs20.promises.readFile(absPath, "utf8").catch(() => "");
|
|
7316
7418
|
const exportNames = extractExportsFromSource(source);
|
|
7317
7419
|
const methods = HTTP_METHODS.filter((m) => exportNames.has(m));
|
|
7318
7420
|
for (const method of methods) {
|
|
@@ -7348,8 +7450,8 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
7348
7450
|
|
|
7349
7451
|
// src/tools/scanTools.ts
|
|
7350
7452
|
import fg4 from "fast-glob";
|
|
7351
|
-
import
|
|
7352
|
-
import
|
|
7453
|
+
import path26 from "path";
|
|
7454
|
+
import fs21 from "fs";
|
|
7353
7455
|
var TOOL_PATTERNS = ["src/tools/**/*.ts"];
|
|
7354
7456
|
var TOOL_EXPORT_RE = new RegExp(
|
|
7355
7457
|
String.raw`export\s+(?:async\s+)?(?:function\s+|const\s+)([A-Za-z_$][\w$]*)\s*(?:\(|=)`,
|
|
@@ -7399,8 +7501,8 @@ async function scanTools(rootDir, patterns) {
|
|
|
7399
7501
|
if (fileName !== "handler.ts" && fileName !== "handler.js") {
|
|
7400
7502
|
continue;
|
|
7401
7503
|
}
|
|
7402
|
-
const absPath =
|
|
7403
|
-
const source = await
|
|
7504
|
+
const absPath = path26.resolve(rootDir, normalizedFile);
|
|
7505
|
+
const source = await fs21.promises.readFile(absPath, "utf8").catch(() => "");
|
|
7404
7506
|
const exportNames = extractToolExportsFromSource(source);
|
|
7405
7507
|
const namespace = filePathToToolNamespace(normalizedFile);
|
|
7406
7508
|
for (const fnName of exportNames) {
|
|
@@ -7424,8 +7526,8 @@ async function scanTools(rootDir, patterns) {
|
|
|
7424
7526
|
|
|
7425
7527
|
// src/agents/scanAgents.ts
|
|
7426
7528
|
import fg5 from "fast-glob";
|
|
7427
|
-
import
|
|
7428
|
-
import
|
|
7529
|
+
import path27 from "path";
|
|
7530
|
+
import fs22 from "fs";
|
|
7429
7531
|
var DEFAULT_AGENT_PATTERNS = ["src/agents/**/handler.ts"];
|
|
7430
7532
|
var RUN_EXPORT_RE = /export\s+(?:async\s+)?(?:function\s+|const\s+)run\b/;
|
|
7431
7533
|
function extractAgentNameFromPath(filePath) {
|
|
@@ -7457,8 +7559,8 @@ async function scanAgents(rootDir, patterns) {
|
|
|
7457
7559
|
if (fileName !== "handler.ts" && fileName !== "handler.js") {
|
|
7458
7560
|
continue;
|
|
7459
7561
|
}
|
|
7460
|
-
const absPath =
|
|
7461
|
-
const source = await
|
|
7562
|
+
const absPath = path27.resolve(rootDir, normalizedFile);
|
|
7563
|
+
const source = await fs22.promises.readFile(absPath, "utf8").catch(() => "");
|
|
7462
7564
|
const { hasRun } = detectAgentExports(source);
|
|
7463
7565
|
const name = extractAgentNameFromPath(normalizedFile);
|
|
7464
7566
|
const prevFile = seen.get(name);
|
|
@@ -7528,7 +7630,7 @@ async function createDevApp(options) {
|
|
|
7528
7630
|
invalidateProgramCache();
|
|
7529
7631
|
const tasks = await scanTasks(ctx.rootDir, TASK_PATTERNS);
|
|
7530
7632
|
for (const task of tasks) {
|
|
7531
|
-
await ensureCompiled(
|
|
7633
|
+
await ensureCompiled(path28.resolve(ctx.rootDir, task.filePath), ctx.rootDir, ctx.dist);
|
|
7532
7634
|
}
|
|
7533
7635
|
await generateTaskArtifacts(tasks, ctx.rootDir, ctx.dist);
|
|
7534
7636
|
ctx.taskQueue.invalidateModules();
|