@faapi/faapi 6.24.0 → 6.26.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 +272 -381
- package/dist/cli/index.js.map +1 -1
- package/dist/{routeTypes-D1swYDVC.d.ts → contextTypes-gYf84EXF.d.ts} +9 -205
- package/dist/index.d.ts +16 -3
- package/dist/index.js +172 -254
- package/dist/index.js.map +1 -1
- package/dist/routeTypes-DlD6nnbT.d.ts +204 -0
- package/dist/testing.d.ts +8 -2
- package/dist/testing.js +185 -168
- package/dist/testing.js.map +1 -1
- package/dist/workerEntry.d.ts +90 -0
- package/dist/workerEntry.js +166 -0
- package/dist/workerEntry.js.map +1 -0
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1662,7 +1662,7 @@ var init_atomicWrite = __esm({
|
|
|
1662
1662
|
|
|
1663
1663
|
// src/cli/generateZodArtifacts.ts
|
|
1664
1664
|
import path11 from "path";
|
|
1665
|
-
import { existsSync } from "fs";
|
|
1665
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1666
1666
|
async function generateZodArtifacts(sources, options) {
|
|
1667
1667
|
const { generateFileSource, resolversByFile, rootDir, dist } = options;
|
|
1668
1668
|
if (sources.length === 0) return;
|
|
@@ -1696,7 +1696,7 @@ async function generateZodArtifacts(sources, options) {
|
|
|
1696
1696
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
1697
1697
|
if (usesCoerceHelpers(allSourceCode)) {
|
|
1698
1698
|
const helpersPath = path11.resolve(rootDir, dist, HELPERS_FILENAME);
|
|
1699
|
-
if (!
|
|
1699
|
+
if (!existsSync2(helpersPath)) {
|
|
1700
1700
|
await atomicWriteFile(helpersPath, generateHelpersFileSource());
|
|
1701
1701
|
}
|
|
1702
1702
|
}
|
|
@@ -2046,14 +2046,14 @@ var ValidationError = class extends FaapiError {
|
|
|
2046
2046
|
issues;
|
|
2047
2047
|
};
|
|
2048
2048
|
var RouteNotFoundError = class extends FaapiError {
|
|
2049
|
-
constructor(
|
|
2050
|
-
super("ROUTE_NOT_FOUND", `Route not found: ${
|
|
2049
|
+
constructor(path32) {
|
|
2050
|
+
super("ROUTE_NOT_FOUND", `Route not found: ${path32}`, 404);
|
|
2051
2051
|
this.name = "RouteNotFoundError";
|
|
2052
2052
|
}
|
|
2053
2053
|
};
|
|
2054
2054
|
var MethodNotAllowedError = class extends FaapiError {
|
|
2055
|
-
constructor(method,
|
|
2056
|
-
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${
|
|
2055
|
+
constructor(method, path32, allowedMethods) {
|
|
2056
|
+
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path32}`, 405);
|
|
2057
2057
|
this.allowedMethods = allowedMethods;
|
|
2058
2058
|
this.name = "MethodNotAllowedError";
|
|
2059
2059
|
}
|
|
@@ -2079,8 +2079,16 @@ var PayloadTooLargeError = class extends FaapiError {
|
|
|
2079
2079
|
};
|
|
2080
2080
|
|
|
2081
2081
|
// src/task/taskWorker.ts
|
|
2082
|
+
import { existsSync } from "fs";
|
|
2082
2083
|
import { Worker } from "worker_threads";
|
|
2083
|
-
import { pathToFileURL } from "url";
|
|
2084
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
2085
|
+
var workerEntryUrl;
|
|
2086
|
+
function resolveWorkerEntryUrl() {
|
|
2087
|
+
if (workerEntryUrl) return workerEntryUrl;
|
|
2088
|
+
const js = new URL("./workerEntry.js", import.meta.url);
|
|
2089
|
+
workerEntryUrl = existsSync(fileURLToPath(js)) ? js : new URL("./workerEntry.ts", import.meta.url);
|
|
2090
|
+
return workerEntryUrl;
|
|
2091
|
+
}
|
|
2084
2092
|
var KILL_GRACE_MS = 5e3;
|
|
2085
2093
|
var TaskCancelledError = class extends Error {
|
|
2086
2094
|
constructor(message) {
|
|
@@ -2101,153 +2109,6 @@ function safeConfig(config) {
|
|
|
2101
2109
|
return void 0;
|
|
2102
2110
|
}
|
|
2103
2111
|
}
|
|
2104
|
-
var BUILD_VIEW_SOURCE = `
|
|
2105
|
-
function buildRegistriesView(snapshot) {
|
|
2106
|
-
var agents = new Map(((snapshot && snapshot.agents) || []).map(function (a) { return [a.name, a]; }));
|
|
2107
|
-
var tools = new Map(((snapshot && snapshot.tools) || []).map(function (t) { return [t.name, t]; }));
|
|
2108
|
-
var skills = new Map(((snapshot && snapshot.skills) || []).map(function (s) { return [s.name, s]; }));
|
|
2109
|
-
return {
|
|
2110
|
-
agent: {
|
|
2111
|
-
getAgent: function (name) { return agents.get(name); },
|
|
2112
|
-
getAgentEntry: function (name) { return agents.get(name); },
|
|
2113
|
-
listAgents: function () { return Array.from(agents.values()); },
|
|
2114
|
-
asTool: function (name) {
|
|
2115
|
-
var agent = agents.get(name);
|
|
2116
|
-
if (!agent) return undefined;
|
|
2117
|
-
return {
|
|
2118
|
-
kind: 'agent',
|
|
2119
|
-
name: 'agent.' + agent.name,
|
|
2120
|
-
agentName: agent.name,
|
|
2121
|
-
description: agent.description,
|
|
2122
|
-
metadata: agent,
|
|
2123
|
-
};
|
|
2124
|
-
},
|
|
2125
|
-
resolveAgentTools: function (name) {
|
|
2126
|
-
var agent = agents.get(name);
|
|
2127
|
-
var result = new Map();
|
|
2128
|
-
if (agent && agent.tools) {
|
|
2129
|
-
agent.tools.forEach(function (toolName) {
|
|
2130
|
-
var resolved = tools.get(toolName);
|
|
2131
|
-
if (resolved) result.set(resolved.name, resolved);
|
|
2132
|
-
});
|
|
2133
|
-
}
|
|
2134
|
-
return Array.from(result.values());
|
|
2135
|
-
},
|
|
2136
|
-
resolveSubAgents: function (name) {
|
|
2137
|
-
var agent = agents.get(name);
|
|
2138
|
-
var result = [];
|
|
2139
|
-
if (agent && agent.agents) {
|
|
2140
|
-
agent.agents.forEach(function (subName) {
|
|
2141
|
-
var sub = agents.get(subName);
|
|
2142
|
-
if (sub) result.push(sub);
|
|
2143
|
-
});
|
|
2144
|
-
}
|
|
2145
|
-
return result;
|
|
2146
|
-
},
|
|
2147
|
-
},
|
|
2148
|
-
tool: {
|
|
2149
|
-
get: function (name) { return tools.get(name); },
|
|
2150
|
-
list: function () { return Array.from(tools.values()); },
|
|
2151
|
-
},
|
|
2152
|
-
skill: {
|
|
2153
|
-
get: function (name) { return skills.get(name); },
|
|
2154
|
-
list: function () { return Array.from(skills.values()); },
|
|
2155
|
-
},
|
|
2156
|
-
};
|
|
2157
|
-
}
|
|
2158
|
-
`;
|
|
2159
|
-
var SERIALIZE_ERROR_SOURCE = `
|
|
2160
|
-
function serializeError(err) {
|
|
2161
|
-
if (err instanceof Error) {
|
|
2162
|
-
var props = {};
|
|
2163
|
-
var keys = Object.keys(err);
|
|
2164
|
-
for (var i = 0; i < keys.length; i++) {
|
|
2165
|
-
props[keys[i]] = err[keys[i]];
|
|
2166
|
-
}
|
|
2167
|
-
return { name: err.name, message: err.message, stack: err.stack, props: props };
|
|
2168
|
-
}
|
|
2169
|
-
return { name: 'Error', message: String(err), stack: undefined, props: {} };
|
|
2170
|
-
}
|
|
2171
|
-
`;
|
|
2172
|
-
var BUILD_LOGGER_SOURCE = `
|
|
2173
|
-
var LOG_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
2174
|
-
function createTaskLogger(level, scope, fields) {
|
|
2175
|
-
function make(suffix) {
|
|
2176
|
-
function write(lvl, message, callFields) {
|
|
2177
|
-
if (level !== undefined && LOG_RANK[lvl] < LOG_RANK[level]) return;
|
|
2178
|
-
var entry = { level: lvl, message: message, time: new Date().toISOString() };
|
|
2179
|
-
var fullScope = suffix === undefined ? scope : scope === undefined ? suffix : scope + ':' + suffix;
|
|
2180
|
-
if (fullScope !== undefined) entry.scope = fullScope;
|
|
2181
|
-
if (fields !== undefined || callFields !== undefined) {
|
|
2182
|
-
entry.fields = Object.assign({}, fields, callFields);
|
|
2183
|
-
}
|
|
2184
|
-
try {
|
|
2185
|
-
parentPort.postMessage({ type: 'log', entry: entry });
|
|
2186
|
-
} catch (_) {
|
|
2187
|
-
entry.fields = { warning: 'log fields not cloneable across worker boundary, dropped' };
|
|
2188
|
-
parentPort.postMessage({ type: 'log', entry: entry });
|
|
2189
|
-
}
|
|
2190
|
-
}
|
|
2191
|
-
return {
|
|
2192
|
-
debug: function (m, f) { write('debug', m, f); },
|
|
2193
|
-
info: function (m, f) { write('info', m, f); },
|
|
2194
|
-
warn: function (m, f) { write('warn', m, f); },
|
|
2195
|
-
error: function (m, f) { write('error', m, f); },
|
|
2196
|
-
child: function (cs) { return make(suffix === undefined ? cs : suffix + ':' + cs); },
|
|
2197
|
-
};
|
|
2198
|
-
}
|
|
2199
|
-
return make(undefined);
|
|
2200
|
-
}
|
|
2201
|
-
`;
|
|
2202
|
-
function buildWrapperSource(moduleUrl) {
|
|
2203
|
-
return `
|
|
2204
|
-
import { parentPort } from 'node:worker_threads';
|
|
2205
|
-
import * as mod from '${moduleUrl}';
|
|
2206
|
-
|
|
2207
|
-
${BUILD_VIEW_SOURCE}
|
|
2208
|
-
|
|
2209
|
-
${SERIALIZE_ERROR_SOURCE}
|
|
2210
|
-
|
|
2211
|
-
${BUILD_LOGGER_SOURCE}
|
|
2212
|
-
|
|
2213
|
-
const run = mod.run;
|
|
2214
|
-
if (typeof run !== 'function') {
|
|
2215
|
-
parentPort.postMessage({
|
|
2216
|
-
type: 'error',
|
|
2217
|
-
error: { name: 'Error', message: 'Task module has no run export', stack: undefined, props: {} },
|
|
2218
|
-
});
|
|
2219
|
-
} else {
|
|
2220
|
-
let controller = null;
|
|
2221
|
-
parentPort.on('message', async (msg) => {
|
|
2222
|
-
if (msg?.type === 'abort') {
|
|
2223
|
-
controller?.abort(new Error(msg.reason));
|
|
2224
|
-
return;
|
|
2225
|
-
}
|
|
2226
|
-
if (msg?.type !== 'run') return;
|
|
2227
|
-
controller = new AbortController();
|
|
2228
|
-
const { payload, taskCtx } = msg;
|
|
2229
|
-
try {
|
|
2230
|
-
const registries = buildRegistriesView(msg.registries);
|
|
2231
|
-
const progress = (value) => parentPort.postMessage({ type: 'progress', value });
|
|
2232
|
-
const taskLog = msg.log ? createTaskLogger(msg.log.level, msg.log.scope, msg.log.fields) : undefined;
|
|
2233
|
-
const result = await run(payload, { ...taskCtx, signal: controller.signal, registries, progress, log: taskLog });
|
|
2234
|
-
parentPort.postMessage({ type: 'done', result });
|
|
2235
|
-
} catch (err) {
|
|
2236
|
-
const serialized = serializeError(err);
|
|
2237
|
-
try {
|
|
2238
|
-
parentPort.postMessage({ type: 'error', error: serialized });
|
|
2239
|
-
} catch (_) {
|
|
2240
|
-
// props \u542B\u4E0D\u53EF\u514B\u9686\u503C\uFF08\u51FD\u6570\u7B49\uFF09\u65F6\u4E22\u5F03 props\uFF0C\u4FDD\u5E95 name/message/stack
|
|
2241
|
-
parentPort.postMessage({
|
|
2242
|
-
type: 'error',
|
|
2243
|
-
error: { name: serialized.name, message: serialized.message, stack: serialized.stack, props: {} },
|
|
2244
|
-
});
|
|
2245
|
-
}
|
|
2246
|
-
}
|
|
2247
|
-
});
|
|
2248
|
-
}
|
|
2249
|
-
`;
|
|
2250
|
-
}
|
|
2251
2112
|
function reviveError(payload) {
|
|
2252
2113
|
const err = new Error(payload?.message ?? "task worker error");
|
|
2253
2114
|
if (payload?.name !== void 0) err.name = payload.name;
|
|
@@ -2268,13 +2129,12 @@ async function runTaskInWorker(options) {
|
|
|
2268
2129
|
);
|
|
2269
2130
|
}
|
|
2270
2131
|
const moduleUrl = pathToFileURL(taskModulePath).href;
|
|
2271
|
-
const wrapperUrl = new URL(
|
|
2272
|
-
`data:text/javascript,${encodeURIComponent(buildWrapperSource(moduleUrl))}`
|
|
2273
|
-
);
|
|
2274
2132
|
return new Promise((resolve, reject) => {
|
|
2275
2133
|
let worker;
|
|
2276
2134
|
try {
|
|
2277
|
-
worker = new Worker(
|
|
2135
|
+
worker = new Worker(resolveWorkerEntryUrl(), {
|
|
2136
|
+
workerData: { moduleUrl, resourcesDir: taskCtx.resourcesDir }
|
|
2137
|
+
});
|
|
2278
2138
|
} catch (err) {
|
|
2279
2139
|
reject(err);
|
|
2280
2140
|
return;
|
|
@@ -2997,6 +2857,7 @@ function parseNumericLiteral(raw) {
|
|
|
2997
2857
|
return Number(raw.replace(/_/g, ""));
|
|
2998
2858
|
}
|
|
2999
2859
|
var MIN_ISOLATED_TIMEOUT_MS = 6e4;
|
|
2860
|
+
var MAX_ISOLATED_TIMEOUT_MS = 23 * 60 * 6e4;
|
|
3000
2861
|
function filePathToTaskName(filePath) {
|
|
3001
2862
|
const normalized = filePath.replace(/\\/g, "/");
|
|
3002
2863
|
const match = normalized.match(/(?:^|\/)tasks\/(.+)\/task\.ts$/);
|
|
@@ -3045,6 +2906,11 @@ async function scanTasks(rootDir, patterns) {
|
|
|
3045
2906
|
`[faapi] Task "${name}" timeoutMs ${value} is below the minimum ${MIN_ISOLATED_TIMEOUT_MS}ms (1 minute). Declaring a timeout means this is a long-running task that needs real cancellation \u2014 tasks finishing within a minute do not need one: remove timeoutMs to run in-process (implement your own deadline with Promise.race if needed), or raise it.`
|
|
3046
2907
|
);
|
|
3047
2908
|
}
|
|
2909
|
+
if (value > MAX_ISOLATED_TIMEOUT_MS) {
|
|
2910
|
+
throw new Error(
|
|
2911
|
+
`[faapi] Task "${name}" timeoutMs ${value} exceeds the maximum ${MAX_ISOLATED_TIMEOUT_MS}ms (23 hours). The pg-boss driver budgets expire_in from timeoutMs (execution budget preventing mid-run re-delivery), and pg-boss versions before 12.28 assert expire_in strictly below 24h \u2014 the 23h cap keeps every driver and pg-boss version on a single bound. Split the work into a resumable pipeline (persist progress, enqueue the next stage), or use the bullmq driver (Redis has no such cap).`
|
|
2912
|
+
);
|
|
2913
|
+
}
|
|
3048
2914
|
manifest.timeoutMs = value;
|
|
3049
2915
|
}
|
|
3050
2916
|
if (graceMs !== void 0) manifest.graceMs = parseNumericLiteral(graceMs);
|
|
@@ -3778,7 +3644,7 @@ async function loadToolModule(filePath, functionName, rootDir) {
|
|
|
3778
3644
|
}
|
|
3779
3645
|
|
|
3780
3646
|
// src/loader/loadToolSchema.ts
|
|
3781
|
-
import { existsSync as
|
|
3647
|
+
import { existsSync as existsSync3 } from "fs";
|
|
3782
3648
|
|
|
3783
3649
|
// src/cli/generateToolArtifacts.ts
|
|
3784
3650
|
init_generateZodArtifacts();
|
|
@@ -4012,7 +3878,7 @@ async function loadToolSchema(tool, rootDir) {
|
|
|
4012
3878
|
if (!tool.inputTypeName) return void 0;
|
|
4013
3879
|
const schemaName = `${tool.inputTypeName}Schema`;
|
|
4014
3880
|
const zodPath = getToolSchemaPath(tool, rootDir);
|
|
4015
|
-
if (!
|
|
3881
|
+
if (!existsSync3(zodPath)) return void 0;
|
|
4016
3882
|
try {
|
|
4017
3883
|
const mod = await importWithCacheBust(zodPath, isDevOnDemandEnabled());
|
|
4018
3884
|
const schema = mod[`${tool.inputTypeName}Schema`];
|
|
@@ -4320,9 +4186,53 @@ function loadEnv(rootDir) {
|
|
|
4320
4186
|
}
|
|
4321
4187
|
}
|
|
4322
4188
|
|
|
4189
|
+
// src/utils/readResource.ts
|
|
4190
|
+
import path18 from "path";
|
|
4191
|
+
import fs15 from "fs/promises";
|
|
4192
|
+
var ACTIVE_RESOURCES_DIR_KEY = /* @__PURE__ */ Symbol.for("faapi.resources.dir");
|
|
4193
|
+
function getActiveResourcesDir() {
|
|
4194
|
+
return globalThis[ACTIVE_RESOURCES_DIR_KEY] ?? null;
|
|
4195
|
+
}
|
|
4196
|
+
function setActiveResourcesDir(dir) {
|
|
4197
|
+
if (dir === null) {
|
|
4198
|
+
delete globalThis[ACTIVE_RESOURCES_DIR_KEY];
|
|
4199
|
+
} else {
|
|
4200
|
+
globalThis[ACTIVE_RESOURCES_DIR_KEY] = dir;
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
function resolveResourceTarget(resourcesDir, relativePath) {
|
|
4204
|
+
if (typeof relativePath !== "string" || relativePath === "") {
|
|
4205
|
+
throw new Error("[faapi] readResource: relativePath must be a non-empty string");
|
|
4206
|
+
}
|
|
4207
|
+
const root = toRealPath(path18.resolve(resourcesDir));
|
|
4208
|
+
const resolved = path18.resolve(root, relativePath);
|
|
4209
|
+
if (!isInsideDir(resolved, root)) {
|
|
4210
|
+
throw new Error(
|
|
4211
|
+
`[faapi] readResource: "${relativePath}" escapes the resources directory (absolute paths and ".." are not allowed)`
|
|
4212
|
+
);
|
|
4213
|
+
}
|
|
4214
|
+
const realTarget = toRealPath(resolved);
|
|
4215
|
+
if (!isInsideDir(realTarget, root)) {
|
|
4216
|
+
throw new Error(
|
|
4217
|
+
`[faapi] readResource: "${relativePath}" resolves outside the resources directory via a symlink`
|
|
4218
|
+
);
|
|
4219
|
+
}
|
|
4220
|
+
return realTarget;
|
|
4221
|
+
}
|
|
4222
|
+
async function readResource(relativePath, encoding) {
|
|
4223
|
+
const resourcesDir = getActiveResourcesDir();
|
|
4224
|
+
if (!resourcesDir) {
|
|
4225
|
+
throw new Error(
|
|
4226
|
+
"[faapi] readResource: no active app in this process \u2014 resources are bound at app startup (createAppBase); testing direct-call can pass `resourcesDir` to createTestContext to bind"
|
|
4227
|
+
);
|
|
4228
|
+
}
|
|
4229
|
+
const target = resolveResourceTarget(resourcesDir, relativePath);
|
|
4230
|
+
return encoding === void 0 ? fs15.readFile(target) : fs15.readFile(target, encoding);
|
|
4231
|
+
}
|
|
4232
|
+
|
|
4323
4233
|
// src/cli/createAppCore.ts
|
|
4324
|
-
import
|
|
4325
|
-
import
|
|
4234
|
+
import fs22 from "fs";
|
|
4235
|
+
import path28 from "path";
|
|
4326
4236
|
|
|
4327
4237
|
// src/router/sortRoutes.ts
|
|
4328
4238
|
function sortRoutes(routes) {
|
|
@@ -4386,7 +4296,7 @@ import {
|
|
|
4386
4296
|
import { createSecureServer as createHttp2SecureServer } from "http2";
|
|
4387
4297
|
import { readFileSync } from "fs";
|
|
4388
4298
|
import { Readable as Readable2 } from "stream";
|
|
4389
|
-
import
|
|
4299
|
+
import path21 from "path";
|
|
4390
4300
|
|
|
4391
4301
|
// src/router/matchRoute.ts
|
|
4392
4302
|
var httpIndexCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -4428,25 +4338,25 @@ function getWsIndex(routes) {
|
|
|
4428
4338
|
wsIndexCache.set(routes, index);
|
|
4429
4339
|
return index;
|
|
4430
4340
|
}
|
|
4431
|
-
function matchRoute(routes, method,
|
|
4341
|
+
function matchRoute(routes, method, path32) {
|
|
4432
4342
|
const index = getHttpIndex(routes);
|
|
4433
4343
|
const upper = method.toUpperCase();
|
|
4434
|
-
const hit = matchByMethod(index, upper,
|
|
4344
|
+
const hit = matchByMethod(index, upper, path32);
|
|
4435
4345
|
if (hit) return hit;
|
|
4436
4346
|
if (upper === "HEAD") {
|
|
4437
|
-
return matchByMethod(index, "GET",
|
|
4347
|
+
return matchByMethod(index, "GET", path32);
|
|
4438
4348
|
}
|
|
4439
4349
|
return null;
|
|
4440
4350
|
}
|
|
4441
|
-
function matchByMethod(index, method,
|
|
4442
|
-
const staticHit = index.static.get(`${method}|${
|
|
4351
|
+
function matchByMethod(index, method, path32) {
|
|
4352
|
+
const staticHit = index.static.get(`${method}|${path32}`);
|
|
4443
4353
|
if (staticHit) {
|
|
4444
4354
|
return { route: staticHit, params: {} };
|
|
4445
4355
|
}
|
|
4446
4356
|
if (index.dynamics.length === 0) {
|
|
4447
4357
|
return null;
|
|
4448
4358
|
}
|
|
4449
|
-
const pathSegments =
|
|
4359
|
+
const pathSegments = path32.split("/").filter(Boolean);
|
|
4450
4360
|
for (const entry of index.dynamics) {
|
|
4451
4361
|
const route = entry.route;
|
|
4452
4362
|
if (route.method !== method) {
|
|
@@ -4459,31 +4369,31 @@ function matchByMethod(index, method, path31) {
|
|
|
4459
4369
|
}
|
|
4460
4370
|
return null;
|
|
4461
4371
|
}
|
|
4462
|
-
function matchWsRoute(wsRoutes,
|
|
4372
|
+
function matchWsRoute(wsRoutes, path32) {
|
|
4463
4373
|
const index = getWsIndex(wsRoutes);
|
|
4464
|
-
const staticHit = index.static.get(
|
|
4374
|
+
const staticHit = index.static.get(path32);
|
|
4465
4375
|
if (staticHit) {
|
|
4466
4376
|
return { route: staticHit, params: {} };
|
|
4467
4377
|
}
|
|
4468
4378
|
for (const route of index.dynamics) {
|
|
4469
|
-
const params = matchDynamicPath(route.urlPath,
|
|
4379
|
+
const params = matchDynamicPath(route.urlPath, path32, route.paramNames, route.isCatchAll);
|
|
4470
4380
|
if (params !== null) {
|
|
4471
4381
|
return { route, params };
|
|
4472
4382
|
}
|
|
4473
4383
|
}
|
|
4474
4384
|
return null;
|
|
4475
4385
|
}
|
|
4476
|
-
function findAllowedMethods(routes,
|
|
4386
|
+
function findAllowedMethods(routes, path32) {
|
|
4477
4387
|
const index = getHttpIndex(routes);
|
|
4478
4388
|
const methods = /* @__PURE__ */ new Set();
|
|
4479
|
-
const staticMethods = index.methodsByStaticPath.get(
|
|
4389
|
+
const staticMethods = index.methodsByStaticPath.get(path32);
|
|
4480
4390
|
if (staticMethods) {
|
|
4481
4391
|
for (const method of staticMethods) {
|
|
4482
4392
|
methods.add(method);
|
|
4483
4393
|
}
|
|
4484
4394
|
}
|
|
4485
4395
|
if (index.dynamics.length > 0) {
|
|
4486
|
-
const pathSegments =
|
|
4396
|
+
const pathSegments = path32.split("/").filter(Boolean);
|
|
4487
4397
|
for (const entry of index.dynamics) {
|
|
4488
4398
|
const params = matchSegments(
|
|
4489
4399
|
entry.segments,
|
|
@@ -4501,10 +4411,10 @@ function findAllowedMethods(routes, path31) {
|
|
|
4501
4411
|
}
|
|
4502
4412
|
return Array.from(methods);
|
|
4503
4413
|
}
|
|
4504
|
-
function matchDynamicPath(pattern,
|
|
4414
|
+
function matchDynamicPath(pattern, path32, paramNames, isCatchAll) {
|
|
4505
4415
|
return matchSegments(
|
|
4506
4416
|
pattern.split("/").filter(Boolean),
|
|
4507
|
-
|
|
4417
|
+
path32.split("/").filter(Boolean),
|
|
4508
4418
|
paramNames,
|
|
4509
4419
|
isCatchAll
|
|
4510
4420
|
);
|
|
@@ -5643,9 +5553,9 @@ async function validateInput(schemaPath, method, inputType, input) {
|
|
|
5643
5553
|
function mapZodIssues(error) {
|
|
5644
5554
|
return error.issues.map((issue) => {
|
|
5645
5555
|
const code = mapZodCode(issue);
|
|
5646
|
-
const
|
|
5556
|
+
const path32 = issue.path.map(String).join(".") || "";
|
|
5647
5557
|
return {
|
|
5648
|
-
path:
|
|
5558
|
+
path: path32,
|
|
5649
5559
|
code,
|
|
5650
5560
|
expected: issue.expected ?? mapExpectedFromMessage(issue.message),
|
|
5651
5561
|
received: issue.received ?? mapReceivedFromMessage(issue.message),
|
|
@@ -5866,16 +5776,16 @@ function etag(options = {}) {
|
|
|
5866
5776
|
}
|
|
5867
5777
|
|
|
5868
5778
|
// src/server/handleWsUpgrade.ts
|
|
5869
|
-
import
|
|
5779
|
+
import fs17 from "fs";
|
|
5870
5780
|
import { WebSocketServer, WebSocket } from "ws";
|
|
5871
|
-
import
|
|
5781
|
+
import path20 from "path";
|
|
5872
5782
|
|
|
5873
5783
|
// src/cli/copyResources.ts
|
|
5874
|
-
import
|
|
5875
|
-
import
|
|
5784
|
+
import path19 from "path";
|
|
5785
|
+
import fs16 from "fs";
|
|
5876
5786
|
var RESOURCES_OUTPUT_DIR = "resources";
|
|
5877
5787
|
function resolveResourcesDir(rootDir, dist) {
|
|
5878
|
-
return
|
|
5788
|
+
return path19.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
|
|
5879
5789
|
}
|
|
5880
5790
|
|
|
5881
5791
|
// src/server/serverUtils.ts
|
|
@@ -6016,7 +5926,7 @@ async function loadWsHandler(filePath, ctx, rootDir) {
|
|
|
6016
5926
|
const dist = getDevDist();
|
|
6017
5927
|
if (dist) {
|
|
6018
5928
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
6019
|
-
if (sourcePath &&
|
|
5929
|
+
if (sourcePath && fs17.existsSync(sourcePath)) {
|
|
6020
5930
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
6021
5931
|
}
|
|
6022
5932
|
}
|
|
@@ -6158,7 +6068,7 @@ function attachWebSocket(options) {
|
|
|
6158
6068
|
let upgraded = false;
|
|
6159
6069
|
const finalHandler = async () => {
|
|
6160
6070
|
const schemaPath = getRuntimeSchemaPath(route.filePath, dist, rootDir);
|
|
6161
|
-
if (
|
|
6071
|
+
if (fs17.existsSync(schemaPath)) {
|
|
6162
6072
|
if (isDevOnDemandEnabled()) {
|
|
6163
6073
|
const devDist = getDevDist();
|
|
6164
6074
|
if (devDist) {
|
|
@@ -6197,7 +6107,7 @@ function attachWebSocket(options) {
|
|
|
6197
6107
|
}
|
|
6198
6108
|
let handlers;
|
|
6199
6109
|
try {
|
|
6200
|
-
const absoluteFilePath =
|
|
6110
|
+
const absoluteFilePath = path20.resolve(rootDir, route.filePath);
|
|
6201
6111
|
handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
|
|
6202
6112
|
} catch (err) {
|
|
6203
6113
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -6460,7 +6370,7 @@ function getRoutePaths(route, rootDir, dist) {
|
|
|
6460
6370
|
let cached = routePathCache.get(route);
|
|
6461
6371
|
if (!cached) {
|
|
6462
6372
|
cached = {
|
|
6463
|
-
absFilePath:
|
|
6373
|
+
absFilePath: path21.resolve(rootDir, route.filePath),
|
|
6464
6374
|
schemaPath: getRuntimeSchemaPath(route.filePath, dist, rootDir)
|
|
6465
6375
|
};
|
|
6466
6376
|
routePathCache.set(route, cached);
|
|
@@ -6680,8 +6590,8 @@ function applyPluginWrappers(server, handlerWrappers, upgradeWrappers) {
|
|
|
6680
6590
|
}
|
|
6681
6591
|
|
|
6682
6592
|
// src/cli/generateRoutes.ts
|
|
6683
|
-
import
|
|
6684
|
-
import
|
|
6593
|
+
import fs18 from "fs";
|
|
6594
|
+
import path22 from "path";
|
|
6685
6595
|
async function hydrateRoutes(manifest) {
|
|
6686
6596
|
const hydrateRoute = (serialized) => ({
|
|
6687
6597
|
method: serialized.method,
|
|
@@ -6725,18 +6635,18 @@ function createIdleTaskDriver() {
|
|
|
6725
6635
|
}
|
|
6726
6636
|
|
|
6727
6637
|
// src/cli/loadPlugins.ts
|
|
6728
|
-
import
|
|
6729
|
-
import
|
|
6638
|
+
import path24 from "path";
|
|
6639
|
+
import fs20 from "fs";
|
|
6730
6640
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
6731
6641
|
|
|
6732
6642
|
// src/cli/compileConfig.ts
|
|
6733
|
-
import
|
|
6734
|
-
import
|
|
6643
|
+
import path23 from "path";
|
|
6644
|
+
import fs19 from "fs";
|
|
6735
6645
|
async function compileProjectModules(entryPoints, rootDir, dist) {
|
|
6736
6646
|
const { insideFiles, outsideFiles } = await collectRelativeImports(entryPoints, rootDir);
|
|
6737
6647
|
const esbuild = await import("esbuild");
|
|
6738
6648
|
const aliasPlugins = buildAliasPlugins(rootDir);
|
|
6739
|
-
const absDist =
|
|
6649
|
+
const absDist = path23.resolve(rootDir, dist);
|
|
6740
6650
|
await esbuild.build({
|
|
6741
6651
|
entryPoints: [...entryPoints, ...outsideFiles],
|
|
6742
6652
|
outdir: absDist,
|
|
@@ -6750,7 +6660,7 @@ async function compileProjectModules(entryPoints, rootDir, dist) {
|
|
|
6750
6660
|
logLevel: "silent"
|
|
6751
6661
|
});
|
|
6752
6662
|
if (insideFiles.length > 0) {
|
|
6753
|
-
const appOutbase =
|
|
6663
|
+
const appOutbase = path23.resolve(rootDir, "src");
|
|
6754
6664
|
await esbuild.build({
|
|
6755
6665
|
entryPoints: insideFiles,
|
|
6756
6666
|
outdir: absDist,
|
|
@@ -6831,30 +6741,30 @@ async function loadPlugins(declarations, ctx, rootDir, dist) {
|
|
|
6831
6741
|
var TS_EXTS = /\.(ts|tsx|mts|cts)$/;
|
|
6832
6742
|
var JS_EXTS = /\.(js|mjs|cjs|jsx)$/;
|
|
6833
6743
|
function resolveLocalPluginSource(specifier, baseDir) {
|
|
6834
|
-
const base =
|
|
6835
|
-
if ((TS_EXTS.test(base) || JS_EXTS.test(base)) &&
|
|
6744
|
+
const base = path24.isAbsolute(specifier) ? specifier : path24.resolve(baseDir, specifier);
|
|
6745
|
+
if ((TS_EXTS.test(base) || JS_EXTS.test(base)) && fs20.existsSync(base)) return base;
|
|
6836
6746
|
for (const ext of [".ts", ".js"]) {
|
|
6837
|
-
if (
|
|
6747
|
+
if (fs20.existsSync(base + ext)) return base + ext;
|
|
6838
6748
|
}
|
|
6839
6749
|
for (const indexExt of ["/index.ts", "/index.js"]) {
|
|
6840
|
-
if (
|
|
6750
|
+
if (fs20.existsSync(base + indexExt)) return base + indexExt;
|
|
6841
6751
|
}
|
|
6842
6752
|
return null;
|
|
6843
6753
|
}
|
|
6844
6754
|
function mirrorProductPath(sourcePath, baseDir, distDir) {
|
|
6845
|
-
let rel =
|
|
6755
|
+
let rel = path24.relative(baseDir, sourcePath).replace(/\\/g, "/");
|
|
6846
6756
|
if (rel.startsWith("src/")) rel = rel.slice(4);
|
|
6847
|
-
return
|
|
6757
|
+
return path24.resolve(distDir, rel.replace(TS_EXTS, ".js"));
|
|
6848
6758
|
}
|
|
6849
6759
|
async function importPluginModule(specifier, baseDir, dist) {
|
|
6850
6760
|
const isRelative = specifier.startsWith("./") || specifier.startsWith("../");
|
|
6851
|
-
if (!isRelative && !
|
|
6761
|
+
if (!isRelative && !path24.isAbsolute(specifier)) {
|
|
6852
6762
|
return import(specifier);
|
|
6853
6763
|
}
|
|
6854
|
-
const distDir = dist ?
|
|
6764
|
+
const distDir = dist ? path24.resolve(baseDir, dist) : null;
|
|
6855
6765
|
const sourcePath = resolveLocalPluginSource(specifier, baseDir);
|
|
6856
6766
|
const productPath = sourcePath && distDir ? mirrorProductPath(sourcePath, baseDir, distDir) : null;
|
|
6857
|
-
if (productPath !== null &&
|
|
6767
|
+
if (productPath !== null && fs20.existsSync(productPath) && (sourcePath === null || isProductFresh(sourcePath, productPath))) {
|
|
6858
6768
|
return import(pathToFileURL3(productPath).href);
|
|
6859
6769
|
}
|
|
6860
6770
|
if (sourcePath && TS_EXTS.test(sourcePath)) {
|
|
@@ -6863,13 +6773,13 @@ async function importPluginModule(specifier, baseDir, dist) {
|
|
|
6863
6773
|
`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.`
|
|
6864
6774
|
);
|
|
6865
6775
|
}
|
|
6866
|
-
const relFromRoot =
|
|
6776
|
+
const relFromRoot = path24.relative(baseDir, sourcePath).replace(/\\/g, "/");
|
|
6867
6777
|
if (relFromRoot.startsWith("src/")) {
|
|
6868
6778
|
await ensureCompiled(sourcePath, baseDir, dist);
|
|
6869
6779
|
} else {
|
|
6870
6780
|
await compileProjectModules([sourcePath], baseDir, dist);
|
|
6871
6781
|
}
|
|
6872
|
-
if (productPath &&
|
|
6782
|
+
if (productPath && fs20.existsSync(productPath)) {
|
|
6873
6783
|
return import(pathToFileURL3(productPath).href);
|
|
6874
6784
|
}
|
|
6875
6785
|
}
|
|
@@ -6881,7 +6791,7 @@ async function importPluginModule(specifier, baseDir, dist) {
|
|
|
6881
6791
|
`${specifier}/index.ts`,
|
|
6882
6792
|
`${specifier}.js`,
|
|
6883
6793
|
`${specifier}/index.js`
|
|
6884
|
-
].map((c) =>
|
|
6794
|
+
].map((c) => path24.isAbsolute(c) ? c : path24.join(baseDir, c));
|
|
6885
6795
|
throw new Error(
|
|
6886
6796
|
`Cannot find local plugin "${specifier}" (resolved from ${baseDir}). Expected one of:
|
|
6887
6797
|
${candidates.join("\n ")}
|
|
@@ -6906,11 +6816,11 @@ function resolveDeclaration(decl) {
|
|
|
6906
6816
|
}
|
|
6907
6817
|
|
|
6908
6818
|
// src/cli/manifestLoader.ts
|
|
6909
|
-
import
|
|
6910
|
-
import
|
|
6819
|
+
import fs21 from "fs";
|
|
6820
|
+
import path27 from "path";
|
|
6911
6821
|
|
|
6912
6822
|
// src/cli/generateAgentArtifacts.ts
|
|
6913
|
-
import
|
|
6823
|
+
import path25 from "path";
|
|
6914
6824
|
|
|
6915
6825
|
// src/ast/extractAgentMetadata.ts
|
|
6916
6826
|
import ts11 from "typescript";
|
|
@@ -7227,9 +7137,9 @@ function validateAgentList(metadata) {
|
|
|
7227
7137
|
}
|
|
7228
7138
|
async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
7229
7139
|
const metadata = [];
|
|
7230
|
-
const programByFile = createPrograms(agents.map((m) =>
|
|
7140
|
+
const programByFile = createPrograms(agents.map((m) => path25.resolve(rootDir, m.filePath)));
|
|
7231
7141
|
for (const manifest of agents) {
|
|
7232
|
-
const absPath =
|
|
7142
|
+
const absPath = path25.resolve(rootDir, manifest.filePath);
|
|
7233
7143
|
const program = programByFile.get(absPath);
|
|
7234
7144
|
const result = extractAgentMetadata(program, absPath, {
|
|
7235
7145
|
name: manifest.name,
|
|
@@ -7244,14 +7154,14 @@ async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
|
7244
7154
|
}
|
|
7245
7155
|
validateAgentList(metadata);
|
|
7246
7156
|
const serialized = serializeAgents(metadata, dist);
|
|
7247
|
-
const agentsPath =
|
|
7157
|
+
const agentsPath = path25.resolve(rootDir, dist, AGENTS_FILE);
|
|
7248
7158
|
await writeAgentsModule(serialized, agentsPath);
|
|
7249
7159
|
return metadata;
|
|
7250
7160
|
}
|
|
7251
7161
|
|
|
7252
7162
|
// src/cli/generateTaskArtifacts.ts
|
|
7253
7163
|
init_generateZodArtifacts();
|
|
7254
|
-
import
|
|
7164
|
+
import path26 from "path";
|
|
7255
7165
|
init_createProgram();
|
|
7256
7166
|
init_atomicWrite();
|
|
7257
7167
|
init_extractHandlerTypes();
|
|
@@ -7289,7 +7199,7 @@ function collectTaskSchemaSources(tasks, rootDir) {
|
|
|
7289
7199
|
const tasksByFile = /* @__PURE__ */ new Map();
|
|
7290
7200
|
for (const task of tasks) {
|
|
7291
7201
|
if (!task.inputTypeName) continue;
|
|
7292
|
-
const absPath =
|
|
7202
|
+
const absPath = path26.resolve(rootDir, task.filePath);
|
|
7293
7203
|
let list = tasksByFile.get(absPath);
|
|
7294
7204
|
if (!list) {
|
|
7295
7205
|
list = [];
|
|
@@ -7346,9 +7256,9 @@ function generateTaskSchemaFileSource(sources, resolveType, helpersImportPath) {
|
|
|
7346
7256
|
async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
7347
7257
|
const metadata = [];
|
|
7348
7258
|
if (manifests.length > 0) {
|
|
7349
|
-
const programByFile = createPrograms(manifests.map((m) =>
|
|
7259
|
+
const programByFile = createPrograms(manifests.map((m) => path26.resolve(rootDir, m.filePath)));
|
|
7350
7260
|
for (const manifest of manifests) {
|
|
7351
|
-
const absPath =
|
|
7261
|
+
const absPath = path26.resolve(rootDir, manifest.filePath);
|
|
7352
7262
|
const result = extractToolMetadata(programByFile.get(absPath), absPath, "run", {
|
|
7353
7263
|
name: manifest.name,
|
|
7354
7264
|
filePath: manifest.filePath
|
|
@@ -7359,7 +7269,7 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
|
7359
7269
|
}
|
|
7360
7270
|
}
|
|
7361
7271
|
const serialized = serializeTasks(manifests, dist);
|
|
7362
|
-
const tasksPath =
|
|
7272
|
+
const tasksPath = path26.resolve(rootDir, dist, TASKS_FILE);
|
|
7363
7273
|
await writeTasksModule(serialized, tasksPath);
|
|
7364
7274
|
if (metadata.length === 0) {
|
|
7365
7275
|
return hydrateTasks(serialized);
|
|
@@ -7381,8 +7291,8 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
|
7381
7291
|
var TOOLS_FILE2 = "faapi-tools.js";
|
|
7382
7292
|
var AGENTS_FILE2 = "faapi-agents.js";
|
|
7383
7293
|
async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries) {
|
|
7384
|
-
const toolsPath =
|
|
7385
|
-
if (!
|
|
7294
|
+
const toolsPath = path27.resolve(rootDir, dist, TOOLS_FILE2);
|
|
7295
|
+
if (!fs21.existsSync(toolsPath)) {
|
|
7386
7296
|
return [];
|
|
7387
7297
|
}
|
|
7388
7298
|
const serialized = await importWithCacheBust(toolsPath);
|
|
@@ -7391,8 +7301,8 @@ async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries
|
|
|
7391
7301
|
return hydrated;
|
|
7392
7302
|
}
|
|
7393
7303
|
async function loadAndHydrateAgents(rootDir, dist, registries = defaultRegistries) {
|
|
7394
|
-
const agentsPath =
|
|
7395
|
-
if (!
|
|
7304
|
+
const agentsPath = path27.resolve(rootDir, dist, AGENTS_FILE2);
|
|
7305
|
+
if (!fs21.existsSync(agentsPath)) {
|
|
7396
7306
|
return [];
|
|
7397
7307
|
}
|
|
7398
7308
|
const serialized = await importWithCacheBust(agentsPath);
|
|
@@ -7407,8 +7317,8 @@ function getTaskDriverOptions(config) {
|
|
|
7407
7317
|
return void 0;
|
|
7408
7318
|
}
|
|
7409
7319
|
async function loadAndHydrateTasks(rootDir, dist, registries = defaultRegistries) {
|
|
7410
|
-
const tasksPath =
|
|
7411
|
-
if (!
|
|
7320
|
+
const tasksPath = path27.resolve(rootDir, dist, TASKS_FILE);
|
|
7321
|
+
if (!fs21.existsSync(tasksPath)) {
|
|
7412
7322
|
return [];
|
|
7413
7323
|
}
|
|
7414
7324
|
const serialized = await importWithCacheBust(tasksPath);
|
|
@@ -7597,11 +7507,17 @@ function logStartupSummary(routes, wsRoutes, tools, agents, taskMetas, p) {
|
|
|
7597
7507
|
}
|
|
7598
7508
|
}
|
|
7599
7509
|
async function createAppBase(options) {
|
|
7510
|
+
if (getCurrentApp()) {
|
|
7511
|
+
throw new Error(
|
|
7512
|
+
"[faapi] createApp: an app is already alive in this process \u2014 faapi supports a single app per process. Close it first (`await app.close()`) or run the second app in a separate process."
|
|
7513
|
+
);
|
|
7514
|
+
}
|
|
7600
7515
|
const rootDir = options?.rootDir ?? process.cwd();
|
|
7601
7516
|
const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
|
|
7602
7517
|
const resourcesDir = resolveResourcesDir(rootDir, dist);
|
|
7603
|
-
|
|
7604
|
-
|
|
7518
|
+
setActiveResourcesDir(resourcesDir);
|
|
7519
|
+
const routesPath = path28.resolve(rootDir, dist, ROUTES_FILE);
|
|
7520
|
+
if (!fs22.existsSync(routesPath)) {
|
|
7605
7521
|
throw new Error(
|
|
7606
7522
|
`[faapi] ${dist}/${ROUTES_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
|
|
7607
7523
|
);
|
|
@@ -7766,6 +7682,7 @@ async function createAppBase(options) {
|
|
|
7766
7682
|
registries.task.clear();
|
|
7767
7683
|
registries.agentHandle.clear();
|
|
7768
7684
|
registries.taskHandle.clear();
|
|
7685
|
+
setActiveResourcesDir(null);
|
|
7769
7686
|
if (!server.listening) {
|
|
7770
7687
|
app.server = null;
|
|
7771
7688
|
if (getCurrentApp() === app) setCurrentApp(null);
|
|
@@ -7819,21 +7736,21 @@ async function createAppBase(options) {
|
|
|
7819
7736
|
}
|
|
7820
7737
|
|
|
7821
7738
|
// src/cli/createDevApp.ts
|
|
7822
|
-
import
|
|
7739
|
+
import path31 from "path";
|
|
7823
7740
|
|
|
7824
7741
|
// src/router/scanRoutes.ts
|
|
7825
7742
|
import fg3 from "fast-glob";
|
|
7826
|
-
import
|
|
7827
|
-
import
|
|
7743
|
+
import path29 from "path";
|
|
7744
|
+
import fs23 from "fs";
|
|
7828
7745
|
|
|
7829
7746
|
// src/router/constants.ts
|
|
7830
7747
|
var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
7831
7748
|
var HTTP_METHOD_SET = new Set(HTTP_METHODS);
|
|
7832
7749
|
|
|
7833
7750
|
// src/utils/normalizePath.ts
|
|
7834
|
-
function normalizePath(
|
|
7835
|
-
if (!
|
|
7836
|
-
let result =
|
|
7751
|
+
function normalizePath(path32) {
|
|
7752
|
+
if (!path32) return "";
|
|
7753
|
+
let result = path32.replace(/\\/g, "/");
|
|
7837
7754
|
result = result.replace(/\/+/g, "/");
|
|
7838
7755
|
result = result.replace(/\/+$/, "");
|
|
7839
7756
|
if (result && !result.startsWith("/")) {
|
|
@@ -7894,34 +7811,34 @@ function extractExportsFromSource(source) {
|
|
|
7894
7811
|
return names;
|
|
7895
7812
|
}
|
|
7896
7813
|
function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
|
|
7897
|
-
const routeDir =
|
|
7898
|
-
const resolvedRoot =
|
|
7814
|
+
const routeDir = path29.dirname(routeFilePath);
|
|
7815
|
+
const resolvedRoot = path29.resolve(rootDir);
|
|
7899
7816
|
const paths = [];
|
|
7900
|
-
let currentDir =
|
|
7817
|
+
let currentDir = path29.resolve(rootDir, routeDir);
|
|
7901
7818
|
while (true) {
|
|
7902
7819
|
if (dist) {
|
|
7903
|
-
const mwTsPath =
|
|
7904
|
-
const mwJsPath =
|
|
7905
|
-
const absTsPath =
|
|
7906
|
-
const absJsPath =
|
|
7907
|
-
const absMwPath =
|
|
7820
|
+
const mwTsPath = path29.join(currentDir, "middlewares.ts");
|
|
7821
|
+
const mwJsPath = path29.join(currentDir, "middlewares.js");
|
|
7822
|
+
const absTsPath = path29.resolve(rootDir, mwTsPath);
|
|
7823
|
+
const absJsPath = path29.resolve(rootDir, mwJsPath);
|
|
7824
|
+
const absMwPath = fs23.existsSync(absTsPath) ? absTsPath : fs23.existsSync(absJsPath) ? absJsPath : null;
|
|
7908
7825
|
if (absMwPath) {
|
|
7909
|
-
const relMwPath =
|
|
7910
|
-
const prodAbsPath =
|
|
7826
|
+
const relMwPath = path29.relative(rootDir, absMwPath);
|
|
7827
|
+
const prodAbsPath = path29.resolve(rootDir, toProdFilePath(relMwPath, dist));
|
|
7911
7828
|
paths.push(prodAbsPath);
|
|
7912
7829
|
}
|
|
7913
7830
|
} else {
|
|
7914
7831
|
for (const ext of [".ts", ".js"]) {
|
|
7915
|
-
const mwPath =
|
|
7916
|
-
const absMwPath =
|
|
7917
|
-
if (
|
|
7832
|
+
const mwPath = path29.join(currentDir, `middlewares${ext}`);
|
|
7833
|
+
const absMwPath = path29.resolve(rootDir, mwPath);
|
|
7834
|
+
if (fs23.existsSync(absMwPath)) {
|
|
7918
7835
|
paths.push(absMwPath);
|
|
7919
7836
|
break;
|
|
7920
7837
|
}
|
|
7921
7838
|
}
|
|
7922
7839
|
}
|
|
7923
7840
|
if (currentDir === resolvedRoot) break;
|
|
7924
|
-
const parentDir =
|
|
7841
|
+
const parentDir = path29.dirname(currentDir);
|
|
7925
7842
|
if (parentDir === currentDir) break;
|
|
7926
7843
|
currentDir = parentDir;
|
|
7927
7844
|
}
|
|
@@ -7940,7 +7857,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
7940
7857
|
const normalizedFile = file.replace(/\\/g, "/");
|
|
7941
7858
|
const fileName = normalizedFile.split("/").pop();
|
|
7942
7859
|
if (fileName === "handler.ts" || fileName === "handler.js") {
|
|
7943
|
-
const absPath =
|
|
7860
|
+
const absPath = path29.resolve(rootDir, normalizedFile);
|
|
7944
7861
|
const urlPath = filePathToUrlPath(normalizedFile);
|
|
7945
7862
|
const paramNames = extractParamNames(urlPath);
|
|
7946
7863
|
const isDynamic = paramNames.length > 0;
|
|
@@ -7953,7 +7870,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
7953
7870
|
const mwPaths = collectMiddlewarePaths(normalizedFile, rootDir);
|
|
7954
7871
|
middlewareBundle = await loadMergedMiddlewares(mwPaths);
|
|
7955
7872
|
}
|
|
7956
|
-
const source = await
|
|
7873
|
+
const source = await fs23.promises.readFile(absPath, "utf8").catch(() => "");
|
|
7957
7874
|
const exportNames = extractExportsFromSource(source);
|
|
7958
7875
|
const methods = HTTP_METHODS.filter((m) => exportNames.has(m));
|
|
7959
7876
|
for (const method of methods) {
|
|
@@ -7989,8 +7906,8 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
7989
7906
|
|
|
7990
7907
|
// src/tools/scanTools.ts
|
|
7991
7908
|
import fg4 from "fast-glob";
|
|
7992
|
-
import
|
|
7993
|
-
import
|
|
7909
|
+
import path30 from "path";
|
|
7910
|
+
import fs24 from "fs";
|
|
7994
7911
|
var TOOL_PATTERNS = ["src/tools/**/*.ts"];
|
|
7995
7912
|
var TOOL_EXPORT_RE = new RegExp(
|
|
7996
7913
|
String.raw`export\s+(?:async\s+)?(?:function\s+|const\s+)([A-Za-z_$][\w$]*)\s*(?:\(|=)`,
|
|
@@ -8040,8 +7957,8 @@ async function scanTools(rootDir, patterns) {
|
|
|
8040
7957
|
if (fileName !== "handler.ts" && fileName !== "handler.js") {
|
|
8041
7958
|
continue;
|
|
8042
7959
|
}
|
|
8043
|
-
const absPath =
|
|
8044
|
-
const source = await
|
|
7960
|
+
const absPath = path30.resolve(rootDir, normalizedFile);
|
|
7961
|
+
const source = await fs24.promises.readFile(absPath, "utf8").catch(() => "");
|
|
8045
7962
|
const exportNames = extractToolExportsFromSource(source);
|
|
8046
7963
|
const namespace = filePathToToolNamespace(normalizedFile);
|
|
8047
7964
|
for (const fnName of exportNames) {
|
|
@@ -8158,7 +8075,7 @@ async function createDevApp(options) {
|
|
|
8158
8075
|
if (!suppressProgramInvalidation) invalidateProgramCache();
|
|
8159
8076
|
const tasks = await scanTasks(ctx.rootDir, TASK_PATTERNS);
|
|
8160
8077
|
for (const task of tasks) {
|
|
8161
|
-
await ensureCompiled(
|
|
8078
|
+
await ensureCompiled(path31.resolve(ctx.rootDir, task.filePath), ctx.rootDir, ctx.dist);
|
|
8162
8079
|
}
|
|
8163
8080
|
await generateTaskArtifacts(tasks, ctx.rootDir, ctx.dist);
|
|
8164
8081
|
ctx.taskQueue.invalidateModules();
|
|
@@ -8230,6 +8147,7 @@ export {
|
|
|
8230
8147
|
loadToolModule,
|
|
8231
8148
|
loadToolSchema,
|
|
8232
8149
|
logger,
|
|
8150
|
+
readResource,
|
|
8233
8151
|
registerAgentHandleFactory,
|
|
8234
8152
|
removeSkill,
|
|
8235
8153
|
resolveAgentTools,
|