@faapi/faapi 3.2.1 → 3.3.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 +214 -111
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +51 -5
- package/dist/index.js +227 -122
- package/dist/index.js.map +1 -1
- package/dist/testing.js +196 -102
- package/dist/testing.js.map +1 -1
- package/package.json +3 -3
package/dist/cli/index.js
CHANGED
|
@@ -1021,6 +1021,45 @@ function createProgram(filePath) {
|
|
|
1021
1021
|
if (cached) {
|
|
1022
1022
|
return cached;
|
|
1023
1023
|
}
|
|
1024
|
+
const program = buildProgram([filePath], findTsConfig(filePath));
|
|
1025
|
+
programCache.set(filePath, program);
|
|
1026
|
+
return program;
|
|
1027
|
+
}
|
|
1028
|
+
function createPrograms(filePaths) {
|
|
1029
|
+
const unique = [...new Set(filePaths)];
|
|
1030
|
+
const result = /* @__PURE__ */ new Map();
|
|
1031
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1032
|
+
const noTsconfigFiles = [];
|
|
1033
|
+
for (const filePath of unique) {
|
|
1034
|
+
const tsconfigPath = findTsConfig(filePath);
|
|
1035
|
+
if (!tsconfigPath) {
|
|
1036
|
+
noTsconfigFiles.push(filePath);
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
1039
|
+
const group = groups.get(tsconfigPath);
|
|
1040
|
+
if (group) {
|
|
1041
|
+
group.files.push(filePath);
|
|
1042
|
+
} else {
|
|
1043
|
+
groups.set(tsconfigPath, { tsconfigPath, files: [filePath] });
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
for (const { tsconfigPath, files } of groups.values()) {
|
|
1047
|
+
const cacheKey = `shared::${tsconfigPath}::${[...files].sort().join("|")}`;
|
|
1048
|
+
let program = programCache.get(cacheKey);
|
|
1049
|
+
if (!program) {
|
|
1050
|
+
program = buildProgram(files, tsconfigPath);
|
|
1051
|
+
programCache.set(cacheKey, program);
|
|
1052
|
+
}
|
|
1053
|
+
for (const filePath of files) {
|
|
1054
|
+
result.set(filePath, program);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
for (const filePath of noTsconfigFiles) {
|
|
1058
|
+
result.set(filePath, createProgram(filePath));
|
|
1059
|
+
}
|
|
1060
|
+
return result;
|
|
1061
|
+
}
|
|
1062
|
+
function buildProgram(entryFiles, tsconfigPath) {
|
|
1024
1063
|
const options = {
|
|
1025
1064
|
strict: true,
|
|
1026
1065
|
target: ts3.ScriptTarget.ES2022,
|
|
@@ -1029,8 +1068,7 @@ function createProgram(filePath) {
|
|
|
1029
1068
|
skipLibCheck: true,
|
|
1030
1069
|
noEmit: true
|
|
1031
1070
|
};
|
|
1032
|
-
|
|
1033
|
-
const tsconfigPath = findTsConfig(filePath);
|
|
1071
|
+
const rootNames = [...entryFiles];
|
|
1034
1072
|
if (tsconfigPath) {
|
|
1035
1073
|
const tsOptions = parseTsConfig(tsconfigPath);
|
|
1036
1074
|
if (tsOptions.module !== void 0) {
|
|
@@ -1040,16 +1078,14 @@ function createProgram(filePath) {
|
|
|
1040
1078
|
options.moduleResolution = tsOptions.moduleResolution;
|
|
1041
1079
|
}
|
|
1042
1080
|
if (tsOptions.fileNames.length > 0) {
|
|
1043
|
-
|
|
1044
|
-
rootNames
|
|
1045
|
-
|
|
1046
|
-
|
|
1081
|
+
for (const fileName of tsOptions.fileNames) {
|
|
1082
|
+
if (!rootNames.includes(fileName)) {
|
|
1083
|
+
rootNames.push(fileName);
|
|
1084
|
+
}
|
|
1047
1085
|
}
|
|
1048
1086
|
}
|
|
1049
1087
|
}
|
|
1050
|
-
|
|
1051
|
-
programCache.set(filePath, program);
|
|
1052
|
-
return program;
|
|
1088
|
+
return ts3.createProgram(rootNames, options);
|
|
1053
1089
|
}
|
|
1054
1090
|
var programCache, tsConfigCache;
|
|
1055
1091
|
var init_createProgram = __esm({
|
|
@@ -2263,12 +2299,11 @@ function collectRouteSchemaSources(routes, rootDir) {
|
|
|
2263
2299
|
}
|
|
2264
2300
|
entry.methods.add(route.method);
|
|
2265
2301
|
}
|
|
2266
|
-
const programByFile =
|
|
2302
|
+
const programByFile = createPrograms([...methodsByFile.keys()]);
|
|
2267
2303
|
const allTypesByFile = /* @__PURE__ */ new Map();
|
|
2268
2304
|
const mergedAllTypes = /* @__PURE__ */ new Map();
|
|
2269
2305
|
for (const filePath of methodsByFile.keys()) {
|
|
2270
|
-
const program =
|
|
2271
|
-
programByFile.set(filePath, program);
|
|
2306
|
+
const program = programByFile.get(filePath);
|
|
2272
2307
|
const allTypes = extractAllTypes(program, filePath);
|
|
2273
2308
|
allTypesByFile.set(filePath, allTypes);
|
|
2274
2309
|
for (const [name, info] of allTypes) {
|
|
@@ -2481,15 +2516,16 @@ function collectToolSchemaSources(tools, rootDir) {
|
|
|
2481
2516
|
}
|
|
2482
2517
|
list.push(tool);
|
|
2483
2518
|
}
|
|
2519
|
+
const programByFile = createPrograms([...toolsByFile.keys()]);
|
|
2484
2520
|
const allTypesByFile = /* @__PURE__ */ new Map();
|
|
2485
2521
|
for (const filePath of toolsByFile.keys()) {
|
|
2486
|
-
const program =
|
|
2522
|
+
const program = programByFile.get(filePath);
|
|
2487
2523
|
const allTypes = extractAllTypes(program, filePath);
|
|
2488
2524
|
allTypesByFile.set(filePath, allTypes);
|
|
2489
2525
|
}
|
|
2490
2526
|
const sources = [];
|
|
2491
2527
|
for (const [filePath, fileTools] of toolsByFile) {
|
|
2492
|
-
const program =
|
|
2528
|
+
const program = programByFile.get(filePath);
|
|
2493
2529
|
for (const tool of fileTools) {
|
|
2494
2530
|
const inputTypeName = tool.inputTypeName;
|
|
2495
2531
|
const typeInfo = extractTypeInfo(program, filePath, inputTypeName);
|
|
@@ -2542,9 +2578,10 @@ async function maybeGenerateHelpers(allSourceCode, distDir) {
|
|
|
2542
2578
|
}
|
|
2543
2579
|
async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
2544
2580
|
const metadata = [];
|
|
2581
|
+
const programByFile = createPrograms(tools.map((m) => path10.resolve(rootDir, m.filePath)));
|
|
2545
2582
|
for (const manifest of tools) {
|
|
2546
2583
|
const absPath = path10.resolve(rootDir, manifest.filePath);
|
|
2547
|
-
const program =
|
|
2584
|
+
const program = programByFile.get(absPath);
|
|
2548
2585
|
const result = extractToolMetadata(program, absPath, manifest.functionName, {
|
|
2549
2586
|
name: manifest.name,
|
|
2550
2587
|
filePath: manifest.filePath
|
|
@@ -2915,9 +2952,10 @@ function hydrateAgents(manifest) {
|
|
|
2915
2952
|
}
|
|
2916
2953
|
async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
2917
2954
|
const metadata = [];
|
|
2955
|
+
const programByFile = createPrograms(agents.map((m) => path12.resolve(rootDir, m.filePath)));
|
|
2918
2956
|
for (const manifest of agents) {
|
|
2919
2957
|
const absPath = path12.resolve(rootDir, manifest.filePath);
|
|
2920
|
-
const program =
|
|
2958
|
+
const program = programByFile.get(absPath);
|
|
2921
2959
|
const result = extractAgentMetadata(program, absPath, {
|
|
2922
2960
|
name: manifest.name,
|
|
2923
2961
|
filePath: manifest.filePath,
|
|
@@ -4929,15 +4967,48 @@ var init_detectRouteConflicts = __esm({
|
|
|
4929
4967
|
});
|
|
4930
4968
|
|
|
4931
4969
|
// src/router/matchRoute.ts
|
|
4932
|
-
function
|
|
4970
|
+
function getHttpIndex(routes) {
|
|
4971
|
+
let index = httpIndexCache.get(routes);
|
|
4972
|
+
if (index) return index;
|
|
4973
|
+
index = { static: /* @__PURE__ */ new Map(), methodsByStaticPath: /* @__PURE__ */ new Map(), dynamics: [] };
|
|
4933
4974
|
for (const route of routes) {
|
|
4934
|
-
if (route.
|
|
4935
|
-
|
|
4936
|
-
}
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4975
|
+
if (route.isDynamic) {
|
|
4976
|
+
index.dynamics.push(route);
|
|
4977
|
+
} else {
|
|
4978
|
+
index.static.set(`${route.method}|${route.urlPath}`, route);
|
|
4979
|
+
let methods = index.methodsByStaticPath.get(route.urlPath);
|
|
4980
|
+
if (!methods) {
|
|
4981
|
+
methods = /* @__PURE__ */ new Set();
|
|
4982
|
+
index.methodsByStaticPath.set(route.urlPath, methods);
|
|
4940
4983
|
}
|
|
4984
|
+
methods.add(route.method);
|
|
4985
|
+
}
|
|
4986
|
+
}
|
|
4987
|
+
httpIndexCache.set(routes, index);
|
|
4988
|
+
return index;
|
|
4989
|
+
}
|
|
4990
|
+
function getWsIndex(routes) {
|
|
4991
|
+
let index = wsIndexCache.get(routes);
|
|
4992
|
+
if (index) return index;
|
|
4993
|
+
index = { static: /* @__PURE__ */ new Map(), dynamics: [] };
|
|
4994
|
+
for (const route of routes) {
|
|
4995
|
+
if (route.isDynamic) {
|
|
4996
|
+
index.dynamics.push(route);
|
|
4997
|
+
} else {
|
|
4998
|
+
index.static.set(route.urlPath, route);
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
wsIndexCache.set(routes, index);
|
|
5002
|
+
return index;
|
|
5003
|
+
}
|
|
5004
|
+
function matchRoute(routes, method, path24) {
|
|
5005
|
+
const index = getHttpIndex(routes);
|
|
5006
|
+
const staticHit = index.static.get(`${method}|${path24}`);
|
|
5007
|
+
if (staticHit) {
|
|
5008
|
+
return { route: staticHit, params: {} };
|
|
5009
|
+
}
|
|
5010
|
+
for (const route of index.dynamics) {
|
|
5011
|
+
if (route.method !== method) {
|
|
4941
5012
|
continue;
|
|
4942
5013
|
}
|
|
4943
5014
|
const params = matchDynamicPath(route.urlPath, path24, route.paramNames, route.isCatchAll);
|
|
@@ -4948,13 +5019,12 @@ function matchRoute(routes, method, path24) {
|
|
|
4948
5019
|
return null;
|
|
4949
5020
|
}
|
|
4950
5021
|
function matchWsRoute(wsRoutes, path24) {
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
}
|
|
5022
|
+
const index = getWsIndex(wsRoutes);
|
|
5023
|
+
const staticHit = index.static.get(path24);
|
|
5024
|
+
if (staticHit) {
|
|
5025
|
+
return { route: staticHit, params: {} };
|
|
5026
|
+
}
|
|
5027
|
+
for (const route of index.dynamics) {
|
|
4958
5028
|
const params = matchDynamicPath(route.urlPath, path24, route.paramNames, route.isCatchAll);
|
|
4959
5029
|
if (params !== null) {
|
|
4960
5030
|
return { route, params };
|
|
@@ -4962,6 +5032,23 @@ function matchWsRoute(wsRoutes, path24) {
|
|
|
4962
5032
|
}
|
|
4963
5033
|
return null;
|
|
4964
5034
|
}
|
|
5035
|
+
function findAllowedMethods(routes, path24) {
|
|
5036
|
+
const index = getHttpIndex(routes);
|
|
5037
|
+
const methods = /* @__PURE__ */ new Set();
|
|
5038
|
+
const staticMethods = index.methodsByStaticPath.get(path24);
|
|
5039
|
+
if (staticMethods) {
|
|
5040
|
+
for (const method of staticMethods) {
|
|
5041
|
+
methods.add(method);
|
|
5042
|
+
}
|
|
5043
|
+
}
|
|
5044
|
+
for (const route of index.dynamics) {
|
|
5045
|
+
const params = matchDynamicPath(route.urlPath, path24, route.paramNames, route.isCatchAll);
|
|
5046
|
+
if (params !== null) {
|
|
5047
|
+
methods.add(route.method);
|
|
5048
|
+
}
|
|
5049
|
+
}
|
|
5050
|
+
return Array.from(methods);
|
|
5051
|
+
}
|
|
4965
5052
|
function matchDynamicPath(pattern, path24, paramNames, isCatchAll) {
|
|
4966
5053
|
const patternSegments = pattern.split("/").filter(Boolean);
|
|
4967
5054
|
const pathSegments = path24.split("/").filter(Boolean);
|
|
@@ -5008,9 +5095,12 @@ function matchDynamicPath(pattern, path24, paramNames, isCatchAll) {
|
|
|
5008
5095
|
}
|
|
5009
5096
|
return params;
|
|
5010
5097
|
}
|
|
5098
|
+
var httpIndexCache, wsIndexCache;
|
|
5011
5099
|
var init_matchRoute = __esm({
|
|
5012
5100
|
"src/router/matchRoute.ts"() {
|
|
5013
5101
|
"use strict";
|
|
5102
|
+
httpIndexCache = /* @__PURE__ */ new WeakMap();
|
|
5103
|
+
wsIndexCache = /* @__PURE__ */ new WeakMap();
|
|
5014
5104
|
}
|
|
5015
5105
|
});
|
|
5016
5106
|
|
|
@@ -5073,6 +5163,7 @@ function createDevOnDemandState() {
|
|
|
5073
5163
|
function clearCompiledFiles() {
|
|
5074
5164
|
state.compiledFiles.clear();
|
|
5075
5165
|
state.inFlightCompilations.clear();
|
|
5166
|
+
sourcePathCache.clear();
|
|
5076
5167
|
}
|
|
5077
5168
|
async function ensureCompiled(sourceAbsPath, rootDir, dist) {
|
|
5078
5169
|
const inFlight = state.inFlightCompilations.get(sourceAbsPath);
|
|
@@ -5170,6 +5261,8 @@ async function deleteSchemaFiles(routes, rootDir, dist) {
|
|
|
5170
5261
|
}
|
|
5171
5262
|
}
|
|
5172
5263
|
function prodPathToSourcePath(prodAbsPath, rootDir, dist) {
|
|
5264
|
+
const cached = sourcePathCache.get(prodAbsPath);
|
|
5265
|
+
if (cached) return cached;
|
|
5173
5266
|
const rel = path17.relative(rootDir, prodAbsPath).replace(/\\/g, "/");
|
|
5174
5267
|
let relWithoutDist = rel;
|
|
5175
5268
|
if (relWithoutDist.startsWith(`${dist}/`)) {
|
|
@@ -5178,8 +5271,14 @@ function prodPathToSourcePath(prodAbsPath, rootDir, dist) {
|
|
|
5178
5271
|
const srcRel = `src/${relWithoutDist}`;
|
|
5179
5272
|
const tsRel = srcRel.replace(/\.js$/, ".ts");
|
|
5180
5273
|
const tsAbs = path17.resolve(rootDir, tsRel);
|
|
5181
|
-
|
|
5182
|
-
|
|
5274
|
+
let result;
|
|
5275
|
+
if (fs15.existsSync(tsAbs)) {
|
|
5276
|
+
result = tsAbs;
|
|
5277
|
+
} else {
|
|
5278
|
+
result = path17.resolve(rootDir, srcRel);
|
|
5279
|
+
}
|
|
5280
|
+
sourcePathCache.set(prodAbsPath, result);
|
|
5281
|
+
return result;
|
|
5183
5282
|
}
|
|
5184
5283
|
function setDevOnDemandEnabled(enabled) {
|
|
5185
5284
|
state.enabled = enabled;
|
|
@@ -5193,7 +5292,7 @@ function setDevDist(dist) {
|
|
|
5193
5292
|
function getDevDist() {
|
|
5194
5293
|
return state.distDir;
|
|
5195
5294
|
}
|
|
5196
|
-
var state;
|
|
5295
|
+
var state, sourcePathCache;
|
|
5197
5296
|
var init_compileOnDemand = __esm({
|
|
5198
5297
|
"src/cli/compileOnDemand.ts"() {
|
|
5199
5298
|
"use strict";
|
|
@@ -5201,17 +5300,17 @@ var init_compileOnDemand = __esm({
|
|
|
5201
5300
|
init_generateSchemaFiles();
|
|
5202
5301
|
init_generateSchemaFiles();
|
|
5203
5302
|
state = createDevOnDemandState();
|
|
5303
|
+
sourcePathCache = /* @__PURE__ */ new Map();
|
|
5204
5304
|
}
|
|
5205
5305
|
});
|
|
5206
5306
|
|
|
5207
5307
|
// src/loader/loadRouteModule.ts
|
|
5208
|
-
import fs16 from "fs";
|
|
5209
5308
|
async function loadRouteModule(filePath, method, rootDir) {
|
|
5210
5309
|
if (isDevOnDemandEnabled() && rootDir) {
|
|
5211
5310
|
const dist = getDevDist();
|
|
5212
5311
|
if (dist) {
|
|
5213
5312
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
5214
|
-
if (sourcePath
|
|
5313
|
+
if (sourcePath) {
|
|
5215
5314
|
try {
|
|
5216
5315
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
5217
5316
|
} catch (compileErr) {
|
|
@@ -5537,7 +5636,9 @@ function formatSetCookie(name, value, options) {
|
|
|
5537
5636
|
return cookie;
|
|
5538
5637
|
}
|
|
5539
5638
|
function createContext(request, params, config = {}, ip = "") {
|
|
5540
|
-
|
|
5639
|
+
return createContextFromUrl(request, new URL(request.url), params, config, ip);
|
|
5640
|
+
}
|
|
5641
|
+
function createContextFromUrl(request, url, params, config = {}, ip = "") {
|
|
5541
5642
|
const meta = { headers: {}, setCookies: [] };
|
|
5542
5643
|
const parsedCookies = parseCookies(request.headers.get("cookie") ?? "");
|
|
5543
5644
|
const cookiesObj = {};
|
|
@@ -5713,7 +5814,7 @@ var init_parseMultipart = __esm({
|
|
|
5713
5814
|
});
|
|
5714
5815
|
|
|
5715
5816
|
// src/runtime/resolveInput.ts
|
|
5716
|
-
async function
|
|
5817
|
+
async function resolveInputFromUrl(method, request, url) {
|
|
5717
5818
|
const inputType = getInputTypeForMethod(method);
|
|
5718
5819
|
if (inputType === "body") {
|
|
5719
5820
|
const contentType = request.headers.get("content-type") ?? "";
|
|
@@ -5748,7 +5849,6 @@ async function resolveInput(method, request) {
|
|
|
5748
5849
|
}
|
|
5749
5850
|
return result.data;
|
|
5750
5851
|
}
|
|
5751
|
-
const url = new URL(request.url);
|
|
5752
5852
|
return queryToObject(url.searchParams);
|
|
5753
5853
|
}
|
|
5754
5854
|
var init_resolveInput = __esm({
|
|
@@ -6227,11 +6327,13 @@ var init_validateInput = __esm({
|
|
|
6227
6327
|
});
|
|
6228
6328
|
|
|
6229
6329
|
// src/utils/getClientIp.ts
|
|
6230
|
-
function getClientIp(req) {
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6330
|
+
function getClientIp(req, trustedProxy = false) {
|
|
6331
|
+
if (trustedProxy) {
|
|
6332
|
+
const xff = req.headers["x-forwarded-for"];
|
|
6333
|
+
if (typeof xff === "string" && xff.length > 0) {
|
|
6334
|
+
const first = xff.split(",")[0]?.trim();
|
|
6335
|
+
if (first) return first;
|
|
6336
|
+
}
|
|
6235
6337
|
}
|
|
6236
6338
|
const remote = req.socket?.remoteAddress;
|
|
6237
6339
|
if (remote) {
|
|
@@ -6488,7 +6590,7 @@ var init_wsHandler = __esm({
|
|
|
6488
6590
|
});
|
|
6489
6591
|
|
|
6490
6592
|
// src/server/handleWsUpgrade.ts
|
|
6491
|
-
import
|
|
6593
|
+
import fs16 from "fs";
|
|
6492
6594
|
import { WebSocketServer, WebSocket } from "ws";
|
|
6493
6595
|
import path18 from "path";
|
|
6494
6596
|
function getPathname(req) {
|
|
@@ -6501,7 +6603,7 @@ async function loadWsHandler(filePath, ctx, rootDir) {
|
|
|
6501
6603
|
const dist = getDevDist();
|
|
6502
6604
|
if (dist) {
|
|
6503
6605
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
6504
|
-
if (sourcePath &&
|
|
6606
|
+
if (sourcePath && fs16.existsSync(sourcePath)) {
|
|
6505
6607
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
6506
6608
|
}
|
|
6507
6609
|
}
|
|
@@ -6559,7 +6661,7 @@ async function sendResponseToSocket(socket, response) {
|
|
|
6559
6661
|
socket.destroy();
|
|
6560
6662
|
}
|
|
6561
6663
|
function attachWebSocket(options) {
|
|
6562
|
-
const { server, routesRef, rootDir, config, globalMiddlewares } = options;
|
|
6664
|
+
const { server, routesRef, rootDir, config, globalMiddlewares, trustedProxy = false } = options;
|
|
6563
6665
|
const wss = new WebSocketServer({ noServer: true });
|
|
6564
6666
|
server.on("upgrade", async (req, socket, head) => {
|
|
6565
6667
|
const currentWsRoutes = routesRef.wsCurrent;
|
|
@@ -6575,7 +6677,7 @@ function attachWebSocket(options) {
|
|
|
6575
6677
|
const host = req.headers.host ?? "localhost";
|
|
6576
6678
|
const url = `http://${host}${req.url ?? "/"}`;
|
|
6577
6679
|
const request = new Request(url, { method: "GET", headers });
|
|
6578
|
-
const ctx = createContext(request, params, config, getClientIp(req));
|
|
6680
|
+
const ctx = createContext(request, params, config, getClientIp(req, trustedProxy));
|
|
6579
6681
|
const meta = ctx.meta;
|
|
6580
6682
|
let upgraded = false;
|
|
6581
6683
|
const finalHandler = async () => {
|
|
@@ -6664,16 +6766,26 @@ function toWebRequest(req, bodyLimit = DEFAULT_BODY_LIMIT) {
|
|
|
6664
6766
|
const headers = nodeHttpToWebHeaders(req);
|
|
6665
6767
|
const method = req.method ?? "GET";
|
|
6666
6768
|
if (method === "GET" || method === "HEAD") {
|
|
6667
|
-
return new Request(url.toString(), { method, headers });
|
|
6769
|
+
return { request: new Request(url.toString(), { method, headers }), url };
|
|
6770
|
+
}
|
|
6771
|
+
const contentLength = req.headers["content-length"];
|
|
6772
|
+
if (contentLength !== void 0) {
|
|
6773
|
+
const declared = Number(Array.isArray(contentLength) ? contentLength[0] : contentLength);
|
|
6774
|
+
if (Number.isFinite(declared) && declared > bodyLimit) {
|
|
6775
|
+
throw new PayloadTooLargeError(bodyLimit);
|
|
6776
|
+
}
|
|
6668
6777
|
}
|
|
6669
6778
|
const stream = Readable3.toWeb(req);
|
|
6670
6779
|
const limitedStream = limitStreamSize(stream, bodyLimit);
|
|
6671
|
-
return
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6780
|
+
return {
|
|
6781
|
+
request: new Request(url.toString(), {
|
|
6782
|
+
method,
|
|
6783
|
+
headers,
|
|
6784
|
+
body: limitedStream,
|
|
6785
|
+
duplex: "half"
|
|
6786
|
+
}),
|
|
6787
|
+
url
|
|
6788
|
+
};
|
|
6677
6789
|
}
|
|
6678
6790
|
function limitStreamSize(stream, maxSize) {
|
|
6679
6791
|
let totalSize = 0;
|
|
@@ -6725,22 +6837,6 @@ function limitStreamSize(stream, maxSize) {
|
|
|
6725
6837
|
}
|
|
6726
6838
|
});
|
|
6727
6839
|
}
|
|
6728
|
-
function findAllowedMethods(routes, path24) {
|
|
6729
|
-
const methods = /* @__PURE__ */ new Set();
|
|
6730
|
-
for (const route of routes) {
|
|
6731
|
-
if (route.urlPath === path24) {
|
|
6732
|
-
methods.add(route.method);
|
|
6733
|
-
continue;
|
|
6734
|
-
}
|
|
6735
|
-
if (route.isDynamic) {
|
|
6736
|
-
const params = matchDynamicPath(route.urlPath, path24, route.paramNames, route.isCatchAll);
|
|
6737
|
-
if (params !== null) {
|
|
6738
|
-
methods.add(route.method);
|
|
6739
|
-
}
|
|
6740
|
-
}
|
|
6741
|
-
}
|
|
6742
|
-
return Array.from(methods);
|
|
6743
|
-
}
|
|
6744
6840
|
function createServer(options) {
|
|
6745
6841
|
const {
|
|
6746
6842
|
routes,
|
|
@@ -6755,7 +6851,8 @@ function createServer(options) {
|
|
|
6755
6851
|
helmet: helmetOption,
|
|
6756
6852
|
logger: loggerOption,
|
|
6757
6853
|
bodyLimit = DEFAULT_BODY_LIMIT,
|
|
6758
|
-
http2: http2Option
|
|
6854
|
+
http2: http2Option,
|
|
6855
|
+
trustedProxy = false
|
|
6759
6856
|
} = options;
|
|
6760
6857
|
const routesRef = { current: routes, wsCurrent: wsRoutes ?? [] };
|
|
6761
6858
|
const configMiddlewares = [];
|
|
@@ -6767,6 +6864,10 @@ function createServer(options) {
|
|
|
6767
6864
|
}
|
|
6768
6865
|
const loggerMiddlewareInst = loggerOption === false ? null : loggerOption === true || loggerOption === void 0 ? logger() : logger(loggerOption);
|
|
6769
6866
|
if (loggerMiddlewareInst) configMiddlewares.push(loggerMiddlewareInst);
|
|
6867
|
+
const outerMiddlewares = [...configMiddlewares];
|
|
6868
|
+
if (globalMiddlewares && globalMiddlewares.length > 0) {
|
|
6869
|
+
outerMiddlewares.push(...globalMiddlewares);
|
|
6870
|
+
}
|
|
6770
6871
|
const server = (() => {
|
|
6771
6872
|
if (http2Option) {
|
|
6772
6873
|
const h2Opts = typeof http2Option === "object" ? http2Option : {};
|
|
@@ -6786,29 +6887,29 @@ function createServer(options) {
|
|
|
6786
6887
|
dist,
|
|
6787
6888
|
req,
|
|
6788
6889
|
res,
|
|
6789
|
-
|
|
6890
|
+
outerMiddlewares,
|
|
6790
6891
|
onError,
|
|
6791
6892
|
config,
|
|
6792
|
-
globalMiddlewares,
|
|
6793
6893
|
globalInjectors,
|
|
6794
|
-
bodyLimit
|
|
6894
|
+
bodyLimit,
|
|
6895
|
+
trustedProxy
|
|
6795
6896
|
).catch(() => {
|
|
6796
6897
|
res.statusCode = 500;
|
|
6797
6898
|
res.end();
|
|
6798
6899
|
});
|
|
6799
6900
|
});
|
|
6800
6901
|
if (routesRef.wsCurrent.length > 0) {
|
|
6801
|
-
attachWebSocket({ server, routesRef, rootDir, config, globalMiddlewares });
|
|
6902
|
+
attachWebSocket({ server, routesRef, rootDir, config, globalMiddlewares, trustedProxy });
|
|
6802
6903
|
}
|
|
6803
6904
|
return { server, routesRef };
|
|
6804
6905
|
}
|
|
6805
|
-
function prepareRequest(req, config, bodyLimit) {
|
|
6806
|
-
const request = toWebRequest(req, bodyLimit);
|
|
6906
|
+
function prepareRequest(req, config, bodyLimit, trustedProxy) {
|
|
6907
|
+
const { request, url } = toWebRequest(req, bodyLimit);
|
|
6807
6908
|
const method = request.method.toUpperCase();
|
|
6808
|
-
const urlPath =
|
|
6809
|
-
const ctx =
|
|
6909
|
+
const urlPath = url.pathname;
|
|
6910
|
+
const ctx = createContextFromUrl(request, url, {}, config, getClientIp(req, trustedProxy));
|
|
6810
6911
|
const meta = ctx.meta;
|
|
6811
|
-
return { request, ctx, meta, method, urlPath };
|
|
6912
|
+
return { request, url, ctx, meta, method, urlPath };
|
|
6812
6913
|
}
|
|
6813
6914
|
function resolveRouteOrThrow(routes, method, urlPath) {
|
|
6814
6915
|
const match = matchRoute(routes, method, urlPath);
|
|
@@ -6820,14 +6921,14 @@ function resolveRouteOrThrow(routes, method, urlPath) {
|
|
|
6820
6921
|
throw new RouteNotFoundError(urlPath);
|
|
6821
6922
|
}
|
|
6822
6923
|
function createRoutePipeline(opts) {
|
|
6823
|
-
const { routes, method, urlPath, ctx, request, rootDir, dist, globalInjectors } = opts;
|
|
6924
|
+
const { routes, method, urlPath, url, ctx, request, rootDir, dist, globalInjectors } = opts;
|
|
6824
6925
|
return async () => {
|
|
6825
6926
|
const match = resolveRouteOrThrow(routes, method, urlPath);
|
|
6826
6927
|
ctx.params = match.params;
|
|
6827
6928
|
const { route } = match;
|
|
6828
6929
|
const absoluteFilePath = path19.resolve(rootDir, route.filePath);
|
|
6829
6930
|
const routeModule = await loadRouteModule(absoluteFilePath, route.method, rootDir);
|
|
6830
|
-
const input = await
|
|
6931
|
+
const input = await resolveInputFromUrl(route.method, request, url);
|
|
6831
6932
|
const inputType = getInputTypeForMethod(route.method);
|
|
6832
6933
|
const schemaPath = getRuntimeSchemaPath(route.filePath, dist, rootDir);
|
|
6833
6934
|
if (isDevOnDemandEnabled()) {
|
|
@@ -6859,33 +6960,33 @@ async function sendSuccessResponse(response, res) {
|
|
|
6859
6960
|
await sendNodeResponse(response, res);
|
|
6860
6961
|
}
|
|
6861
6962
|
async function sendErrorResponse(err, meta, res, onError, ctx) {
|
|
6862
|
-
await sendNodeResponse(mergeMeta(buildErrorResponse(err, ctx
|
|
6863
|
-
if (onError) {
|
|
6963
|
+
await sendNodeResponse(mergeMeta(buildErrorResponse(err, ctx?.config), meta), res);
|
|
6964
|
+
if (onError && ctx) {
|
|
6864
6965
|
try {
|
|
6865
6966
|
await onError(err, ctx);
|
|
6866
6967
|
} catch {
|
|
6867
6968
|
}
|
|
6868
6969
|
}
|
|
6869
6970
|
}
|
|
6870
|
-
async function handleRequest(routes, rootDir, dist, req, res,
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
routes,
|
|
6874
|
-
method,
|
|
6875
|
-
urlPath,
|
|
6876
|
-
ctx,
|
|
6877
|
-
request,
|
|
6878
|
-
rootDir,
|
|
6879
|
-
dist,
|
|
6880
|
-
globalMiddlewares,
|
|
6881
|
-
globalInjectors
|
|
6882
|
-
});
|
|
6883
|
-
const outerMiddlewares = [];
|
|
6884
|
-
if (configMiddlewares.length > 0) outerMiddlewares.push(...configMiddlewares);
|
|
6885
|
-
if (globalMiddlewares && globalMiddlewares.length > 0) {
|
|
6886
|
-
outerMiddlewares.push(...globalMiddlewares);
|
|
6887
|
-
}
|
|
6971
|
+
async function handleRequest(routes, rootDir, dist, req, res, outerMiddlewares, onError, config, globalInjectors, bodyLimit, trustedProxy) {
|
|
6972
|
+
let meta = { headers: {}, setCookies: [] };
|
|
6973
|
+
let ctx;
|
|
6888
6974
|
try {
|
|
6975
|
+
const prepared = prepareRequest(req, config, bodyLimit, trustedProxy);
|
|
6976
|
+
ctx = prepared.ctx;
|
|
6977
|
+
meta = prepared.meta;
|
|
6978
|
+
const { request, url, method, urlPath } = prepared;
|
|
6979
|
+
const routePipeline = createRoutePipeline({
|
|
6980
|
+
routes,
|
|
6981
|
+
method,
|
|
6982
|
+
urlPath,
|
|
6983
|
+
url,
|
|
6984
|
+
ctx,
|
|
6985
|
+
request,
|
|
6986
|
+
rootDir,
|
|
6987
|
+
dist,
|
|
6988
|
+
globalInjectors
|
|
6989
|
+
});
|
|
6889
6990
|
const response = outerMiddlewares.length > 0 ? await compose(outerMiddlewares, ctx, routePipeline) : await routePipeline();
|
|
6890
6991
|
await sendSuccessResponse(response, res);
|
|
6891
6992
|
} catch (err) {
|
|
@@ -7028,12 +7129,12 @@ var init_skillRegistry = __esm({
|
|
|
7028
7129
|
});
|
|
7029
7130
|
|
|
7030
7131
|
// src/cli/createAppCore.ts
|
|
7031
|
-
import
|
|
7132
|
+
import fs17 from "fs";
|
|
7032
7133
|
import path20 from "path";
|
|
7033
7134
|
import { PassThrough, Readable as Readable4 } from "stream";
|
|
7034
7135
|
async function loadAndHydrateTools(rootDir, dist) {
|
|
7035
7136
|
const toolsPath = path20.resolve(rootDir, dist, TOOLS_FILE2);
|
|
7036
|
-
if (!
|
|
7137
|
+
if (!fs17.existsSync(toolsPath)) {
|
|
7037
7138
|
return [];
|
|
7038
7139
|
}
|
|
7039
7140
|
const serialized = await importWithCacheBust(toolsPath);
|
|
@@ -7043,7 +7144,7 @@ async function loadAndHydrateTools(rootDir, dist) {
|
|
|
7043
7144
|
}
|
|
7044
7145
|
async function loadAndHydrateAgents(rootDir, dist) {
|
|
7045
7146
|
const agentsPath = path20.resolve(rootDir, dist, AGENTS_FILE2);
|
|
7046
|
-
if (!
|
|
7147
|
+
if (!fs17.existsSync(agentsPath)) {
|
|
7047
7148
|
return [];
|
|
7048
7149
|
}
|
|
7049
7150
|
const serialized = await importWithCacheBust(agentsPath);
|
|
@@ -7068,7 +7169,7 @@ async function createAppBase(options) {
|
|
|
7068
7169
|
const rootDir = options?.rootDir ?? process.cwd();
|
|
7069
7170
|
const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
|
|
7070
7171
|
const routesPath = path20.resolve(rootDir, dist, ROUTES_FILE);
|
|
7071
|
-
if (!
|
|
7172
|
+
if (!fs17.existsSync(routesPath)) {
|
|
7072
7173
|
throw new Error(
|
|
7073
7174
|
`[faapi] ${dist}/${ROUTES_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
|
|
7074
7175
|
);
|
|
@@ -7103,7 +7204,8 @@ async function createAppBase(options) {
|
|
|
7103
7204
|
helmet: config?.helmet,
|
|
7104
7205
|
logger: config?.logger,
|
|
7105
7206
|
bodyLimit: config?.bodyLimit,
|
|
7106
|
-
http2: config?.http2
|
|
7207
|
+
http2: config?.http2,
|
|
7208
|
+
trustedProxy: config?.trustedProxy
|
|
7107
7209
|
});
|
|
7108
7210
|
const { handlerWrappers, upgradeWrappers } = await loadPlugins(config?.plugins, {
|
|
7109
7211
|
rootDir,
|
|
@@ -7322,6 +7424,7 @@ var init_createAppCore = __esm({
|
|
|
7322
7424
|
"bodyLimit",
|
|
7323
7425
|
"logger",
|
|
7324
7426
|
"http2",
|
|
7427
|
+
"trustedProxy",
|
|
7325
7428
|
"response"
|
|
7326
7429
|
]);
|
|
7327
7430
|
}
|
|
@@ -7460,7 +7563,7 @@ var init_devCommand = __esm({
|
|
|
7460
7563
|
|
|
7461
7564
|
// src/cli/compileBuildRoutes.ts
|
|
7462
7565
|
import path22 from "path";
|
|
7463
|
-
import
|
|
7566
|
+
import fs18 from "fs";
|
|
7464
7567
|
import fg5 from "fast-glob";
|
|
7465
7568
|
async function compileBuildRoutes(options) {
|
|
7466
7569
|
const { rootDir, dist, files, logLevel = "silent" } = options;
|
|
@@ -7474,7 +7577,7 @@ async function compileBuildRoutes(options) {
|
|
|
7474
7577
|
return { compiledFiles: [] };
|
|
7475
7578
|
}
|
|
7476
7579
|
const absDist = path22.resolve(rootDir, dist);
|
|
7477
|
-
await
|
|
7580
|
+
await fs18.promises.mkdir(absDist, { recursive: true });
|
|
7478
7581
|
const plugins = buildAliasPlugins(rootDir);
|
|
7479
7582
|
const esbuild = await import("esbuild");
|
|
7480
7583
|
const outbase = path22.resolve(rootDir, APP_DIR3);
|
|
@@ -7509,7 +7612,7 @@ __export(buildCommand_exports, {
|
|
|
7509
7612
|
buildCommand: () => buildCommand
|
|
7510
7613
|
});
|
|
7511
7614
|
import path23 from "path";
|
|
7512
|
-
import
|
|
7615
|
+
import fs19 from "fs";
|
|
7513
7616
|
async function buildCommand(options) {
|
|
7514
7617
|
const rootDir = options?.rootDir ?? process.cwd();
|
|
7515
7618
|
const outdir = options?.dist ?? DEFAULT_DIST2;
|
|
@@ -7582,7 +7685,7 @@ loadEnv(process.cwd());
|
|
|
7582
7685
|
const app = await createProdApp(${createProdAppArgs});
|
|
7583
7686
|
await app.listen();
|
|
7584
7687
|
`;
|
|
7585
|
-
await
|
|
7688
|
+
await fs19.promises.writeFile(mainPath, mainContent, "utf-8");
|
|
7586
7689
|
console.log(` Written to ${mainPath}`);
|
|
7587
7690
|
console.log("\nfaapi build completed");
|
|
7588
7691
|
}
|