@faapi/faapi 3.2.0 → 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 +657 -413
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +63 -6
- package/dist/index.js +549 -303
- package/dist/index.js.map +1 -1
- package/dist/testing.js +473 -239
- package/dist/testing.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -10,35 +10,143 @@ var __export = (target, all) => {
|
|
|
10
10
|
|
|
11
11
|
// src/ast/createProgram.ts
|
|
12
12
|
import ts from "typescript";
|
|
13
|
+
import fs from "fs";
|
|
14
|
+
import path from "path";
|
|
13
15
|
function invalidateProgramCache() {
|
|
14
16
|
programCache.clear();
|
|
17
|
+
tsConfigCache.clear();
|
|
18
|
+
}
|
|
19
|
+
function findTsConfig(filePath) {
|
|
20
|
+
let dir = path.dirname(filePath);
|
|
21
|
+
const root = path.parse(dir).root;
|
|
22
|
+
while (true) {
|
|
23
|
+
const candidate = path.join(dir, "tsconfig.json");
|
|
24
|
+
if (fs.existsSync(candidate)) {
|
|
25
|
+
return candidate;
|
|
26
|
+
}
|
|
27
|
+
if (dir === root) return null;
|
|
28
|
+
const parent = path.dirname(dir);
|
|
29
|
+
if (parent === dir) return null;
|
|
30
|
+
dir = parent;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function parseTsConfig(tsconfigPath) {
|
|
34
|
+
const cached = tsConfigCache.get(tsconfigPath);
|
|
35
|
+
if (cached) return cached;
|
|
36
|
+
const result = { fileNames: [] };
|
|
37
|
+
try {
|
|
38
|
+
const configFile = ts.readConfigFile(tsconfigPath, (p) => fs.readFileSync(p, "utf-8"));
|
|
39
|
+
if (configFile.error) {
|
|
40
|
+
tsConfigCache.set(tsconfigPath, result);
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
const config = configFile.config ?? {};
|
|
44
|
+
const basePath = path.dirname(tsconfigPath);
|
|
45
|
+
const parsed = ts.parseJsonConfigFileContent(
|
|
46
|
+
config,
|
|
47
|
+
ts.sys,
|
|
48
|
+
basePath,
|
|
49
|
+
/* existingOptions */
|
|
50
|
+
void 0,
|
|
51
|
+
tsconfigPath
|
|
52
|
+
);
|
|
53
|
+
result.fileNames = parsed.fileNames;
|
|
54
|
+
if (parsed.options.module !== void 0) {
|
|
55
|
+
result.module = parsed.options.module;
|
|
56
|
+
}
|
|
57
|
+
if (parsed.options.moduleResolution !== void 0) {
|
|
58
|
+
result.moduleResolution = parsed.options.moduleResolution;
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
tsConfigCache.set(tsconfigPath, result);
|
|
63
|
+
return result;
|
|
15
64
|
}
|
|
16
65
|
function createProgram(filePath) {
|
|
17
66
|
const cached = programCache.get(filePath);
|
|
18
67
|
if (cached) {
|
|
19
68
|
return cached;
|
|
20
69
|
}
|
|
21
|
-
const program =
|
|
70
|
+
const program = buildProgram([filePath], findTsConfig(filePath));
|
|
71
|
+
programCache.set(filePath, program);
|
|
72
|
+
return program;
|
|
73
|
+
}
|
|
74
|
+
function createPrograms(filePaths) {
|
|
75
|
+
const unique = [...new Set(filePaths)];
|
|
76
|
+
const result = /* @__PURE__ */ new Map();
|
|
77
|
+
const groups = /* @__PURE__ */ new Map();
|
|
78
|
+
const noTsconfigFiles = [];
|
|
79
|
+
for (const filePath of unique) {
|
|
80
|
+
const tsconfigPath = findTsConfig(filePath);
|
|
81
|
+
if (!tsconfigPath) {
|
|
82
|
+
noTsconfigFiles.push(filePath);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const group = groups.get(tsconfigPath);
|
|
86
|
+
if (group) {
|
|
87
|
+
group.files.push(filePath);
|
|
88
|
+
} else {
|
|
89
|
+
groups.set(tsconfigPath, { tsconfigPath, files: [filePath] });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const { tsconfigPath, files } of groups.values()) {
|
|
93
|
+
const cacheKey = `shared::${tsconfigPath}::${[...files].sort().join("|")}`;
|
|
94
|
+
let program = programCache.get(cacheKey);
|
|
95
|
+
if (!program) {
|
|
96
|
+
program = buildProgram(files, tsconfigPath);
|
|
97
|
+
programCache.set(cacheKey, program);
|
|
98
|
+
}
|
|
99
|
+
for (const filePath of files) {
|
|
100
|
+
result.set(filePath, program);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const filePath of noTsconfigFiles) {
|
|
104
|
+
result.set(filePath, createProgram(filePath));
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
function buildProgram(entryFiles, tsconfigPath) {
|
|
109
|
+
const options = {
|
|
22
110
|
strict: true,
|
|
23
111
|
target: ts.ScriptTarget.ES2022,
|
|
24
112
|
module: ts.ModuleKind.NodeNext,
|
|
25
113
|
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
26
114
|
skipLibCheck: true,
|
|
27
115
|
noEmit: true
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
116
|
+
};
|
|
117
|
+
const rootNames = [...entryFiles];
|
|
118
|
+
if (tsconfigPath) {
|
|
119
|
+
const tsOptions = parseTsConfig(tsconfigPath);
|
|
120
|
+
if (tsOptions.module !== void 0) {
|
|
121
|
+
options.module = tsOptions.module;
|
|
122
|
+
}
|
|
123
|
+
if (tsOptions.moduleResolution !== void 0) {
|
|
124
|
+
options.moduleResolution = tsOptions.moduleResolution;
|
|
125
|
+
}
|
|
126
|
+
if (tsOptions.fileNames.length > 0) {
|
|
127
|
+
for (const fileName of tsOptions.fileNames) {
|
|
128
|
+
if (!rootNames.includes(fileName)) {
|
|
129
|
+
rootNames.push(fileName);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return ts.createProgram(rootNames, options);
|
|
31
135
|
}
|
|
32
|
-
var programCache;
|
|
136
|
+
var programCache, tsConfigCache;
|
|
33
137
|
var init_createProgram = __esm({
|
|
34
138
|
"src/ast/createProgram.ts"() {
|
|
35
139
|
"use strict";
|
|
36
140
|
programCache = /* @__PURE__ */ new Map();
|
|
141
|
+
tsConfigCache = /* @__PURE__ */ new Map();
|
|
37
142
|
}
|
|
38
143
|
});
|
|
39
144
|
|
|
40
145
|
// src/ast/resolveTypeNode.ts
|
|
41
146
|
import ts2 from "typescript";
|
|
147
|
+
function setProgramContext(program) {
|
|
148
|
+
currentProgram = program;
|
|
149
|
+
}
|
|
42
150
|
function resolveTypeNode(typeNode, checker, visited = /* @__PURE__ */ new Set()) {
|
|
43
151
|
const kind = typeNode.kind;
|
|
44
152
|
switch (kind) {
|
|
@@ -351,11 +459,69 @@ function resolveTypeReference(typeNode, checker, visited = /* @__PURE__ */ new S
|
|
|
351
459
|
if (ts2.isEnumDeclaration(declaration)) {
|
|
352
460
|
return resolveEnumDeclaration(declaration);
|
|
353
461
|
}
|
|
462
|
+
if (ts2.isImportSpecifier(declaration) || ts2.isImportClause(declaration)) {
|
|
463
|
+
const resolved = resolveImportAlias(typeNode, symbol, checker, visited);
|
|
464
|
+
if (resolved) return resolved;
|
|
465
|
+
}
|
|
354
466
|
}
|
|
355
467
|
}
|
|
356
468
|
}
|
|
357
469
|
throw new SchemaExtractionError(typeNode.getText(), `\u65E0\u6CD5\u89E3\u6790\u7684\u5F15\u7528\u7C7B\u578B "${typeName}"`);
|
|
358
470
|
}
|
|
471
|
+
function resolveImportAlias(typeNode, symbol, checker, visited) {
|
|
472
|
+
const typeName = typeNode.typeName.getText();
|
|
473
|
+
try {
|
|
474
|
+
const aliased = checker.getAliasedSymbol(symbol);
|
|
475
|
+
if (aliased && aliased.declarations && aliased.declarations.length > 0) {
|
|
476
|
+
const decl = aliased.declarations[0];
|
|
477
|
+
if (ts2.isInterfaceDeclaration(decl)) {
|
|
478
|
+
return resolveInterfaceDeclaration(decl, checker, visited);
|
|
479
|
+
}
|
|
480
|
+
if (ts2.isTypeAliasDeclaration(decl)) {
|
|
481
|
+
return resolveTypeNode(decl.type, checker, visited);
|
|
482
|
+
}
|
|
483
|
+
if (ts2.isEnumDeclaration(decl)) {
|
|
484
|
+
return resolveEnumDeclaration(decl);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
} catch {
|
|
488
|
+
}
|
|
489
|
+
const program = currentProgram;
|
|
490
|
+
if (!program) return null;
|
|
491
|
+
const allSFs = program.getSourceFiles();
|
|
492
|
+
for (const sourceFile of allSFs) {
|
|
493
|
+
if (sourceFile.fileName.includes("/node_modules/") || sourceFile.fileName.includes("typescript/lib/")) {
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
const found = findTopLevelDecl(sourceFile, typeName);
|
|
497
|
+
if (found) {
|
|
498
|
+
if (found.kind === "interface") {
|
|
499
|
+
return resolveInterfaceDeclaration(found.node, checker, visited);
|
|
500
|
+
}
|
|
501
|
+
if (found.kind === "typeAlias") {
|
|
502
|
+
return resolveTypeNode(found.node.type, checker, visited);
|
|
503
|
+
}
|
|
504
|
+
if (found.kind === "enum") {
|
|
505
|
+
return resolveEnumDeclaration(found.node);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
function findTopLevelDecl(sourceFile, typeName) {
|
|
512
|
+
let found = null;
|
|
513
|
+
ts2.forEachChild(sourceFile, (node) => {
|
|
514
|
+
if (found) return;
|
|
515
|
+
if (ts2.isInterfaceDeclaration(node) && node.name.text === typeName) {
|
|
516
|
+
found = { kind: "interface", node };
|
|
517
|
+
} else if (ts2.isTypeAliasDeclaration(node) && node.name.text === typeName) {
|
|
518
|
+
found = { kind: "typeAlias", node };
|
|
519
|
+
} else if (ts2.isEnumDeclaration(node) && node.name.text === typeName) {
|
|
520
|
+
found = { kind: "enum", node };
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
return found;
|
|
524
|
+
}
|
|
359
525
|
function resolveEnumDeclaration(node) {
|
|
360
526
|
const members = [];
|
|
361
527
|
let nextNumericValue = 0;
|
|
@@ -534,10 +700,11 @@ function validateConstraints(constraints, type, fieldName) {
|
|
|
534
700
|
}
|
|
535
701
|
}
|
|
536
702
|
}
|
|
537
|
-
var SchemaExtractionError, NUMBER_CONSTRAINT_KINDS, LENGTH_CONSTRAINT_KINDS, STRING_FORMAT_CONSTRAINT_KINDS;
|
|
703
|
+
var currentProgram, SchemaExtractionError, NUMBER_CONSTRAINT_KINDS, LENGTH_CONSTRAINT_KINDS, STRING_FORMAT_CONSTRAINT_KINDS;
|
|
538
704
|
var init_resolveTypeNode = __esm({
|
|
539
705
|
"src/ast/resolveTypeNode.ts"() {
|
|
540
706
|
"use strict";
|
|
707
|
+
currentProgram = null;
|
|
541
708
|
SchemaExtractionError = class extends Error {
|
|
542
709
|
constructor(typeText, reason, options) {
|
|
543
710
|
super(`\u65E0\u6CD5\u89E3\u6790\u7C7B\u578B "${typeText}": ${reason}`, options);
|
|
@@ -577,80 +744,90 @@ function extractTypeInfo(program, filePath, typeName) {
|
|
|
577
744
|
const sourceFile = program.getSourceFile(filePath);
|
|
578
745
|
if (!sourceFile) return null;
|
|
579
746
|
const checker = program.getTypeChecker();
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
747
|
+
setProgramContext(program);
|
|
748
|
+
try {
|
|
749
|
+
let result = null;
|
|
750
|
+
ts3.forEachChild(sourceFile, (node) => {
|
|
751
|
+
if (result) return;
|
|
752
|
+
if (ts3.isInterfaceDeclaration(node) && node.name.text === typeName) {
|
|
753
|
+
const visited = /* @__PURE__ */ new Set();
|
|
754
|
+
visited.add(typeName);
|
|
755
|
+
const runtimeType = withFileContext(
|
|
756
|
+
filePath,
|
|
757
|
+
typeName,
|
|
758
|
+
() => resolveInterfaceDeclaration(node, checker, visited)
|
|
759
|
+
);
|
|
760
|
+
result = {
|
|
761
|
+
name: typeName,
|
|
762
|
+
properties: runtimeType.kind === "object" ? runtimeType.properties : [],
|
|
763
|
+
runtimeType
|
|
764
|
+
};
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
if (ts3.isTypeAliasDeclaration(node) && node.name.text === typeName) {
|
|
768
|
+
const visited = /* @__PURE__ */ new Set();
|
|
769
|
+
visited.add(typeName);
|
|
770
|
+
const runtimeType = withFileContext(
|
|
771
|
+
filePath,
|
|
772
|
+
typeName,
|
|
773
|
+
() => resolveTypeNode(node.type, checker, visited)
|
|
774
|
+
);
|
|
775
|
+
result = {
|
|
776
|
+
name: typeName,
|
|
777
|
+
properties: runtimeType.kind === "object" ? runtimeType.properties : [],
|
|
778
|
+
runtimeType
|
|
779
|
+
};
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
return result;
|
|
784
|
+
} finally {
|
|
785
|
+
setProgramContext(null);
|
|
786
|
+
}
|
|
615
787
|
}
|
|
616
788
|
function extractAllTypes(program, filePath) {
|
|
617
789
|
const sourceFile = program.getSourceFile(filePath);
|
|
618
790
|
if (!sourceFile) return /* @__PURE__ */ new Map();
|
|
619
791
|
const checker = program.getTypeChecker();
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
792
|
+
setProgramContext(program);
|
|
793
|
+
try {
|
|
794
|
+
const result = /* @__PURE__ */ new Map();
|
|
795
|
+
ts3.forEachChild(sourceFile, (node) => {
|
|
796
|
+
if (ts3.isInterfaceDeclaration(node)) {
|
|
797
|
+
const visited = /* @__PURE__ */ new Set();
|
|
798
|
+
visited.add(node.name.text);
|
|
799
|
+
const runtimeType = withFileContext(
|
|
800
|
+
filePath,
|
|
801
|
+
node.name.text,
|
|
802
|
+
() => resolveInterfaceDeclaration(node, checker, visited)
|
|
803
|
+
);
|
|
804
|
+
result.set(node.name.text, {
|
|
805
|
+
name: node.name.text,
|
|
806
|
+
properties: runtimeType.kind === "object" ? runtimeType.properties : [],
|
|
807
|
+
runtimeType
|
|
808
|
+
});
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
if (ts3.isTypeAliasDeclaration(node)) {
|
|
812
|
+
const visited = /* @__PURE__ */ new Set();
|
|
813
|
+
visited.add(node.name.text);
|
|
814
|
+
const runtimeType = withFileContext(
|
|
815
|
+
filePath,
|
|
816
|
+
node.name.text,
|
|
817
|
+
() => resolveTypeNode(node.type, checker, visited)
|
|
818
|
+
);
|
|
819
|
+
result.set(node.name.text, {
|
|
820
|
+
name: node.name.text,
|
|
821
|
+
properties: runtimeType.kind === "object" ? runtimeType.properties : [],
|
|
822
|
+
runtimeType
|
|
823
|
+
});
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
return result;
|
|
828
|
+
} finally {
|
|
829
|
+
setProgramContext(null);
|
|
830
|
+
}
|
|
654
831
|
}
|
|
655
832
|
function withFileContext(filePath, typeName, fn) {
|
|
656
833
|
try {
|
|
@@ -851,11 +1028,11 @@ var init_analyzeInjection = __esm({
|
|
|
851
1028
|
});
|
|
852
1029
|
|
|
853
1030
|
// src/cli/collectRouteSchemaSources.ts
|
|
854
|
-
import
|
|
1031
|
+
import path2 from "path";
|
|
855
1032
|
function collectRouteSchemaSources(routes, rootDir) {
|
|
856
1033
|
const methodsByFile = /* @__PURE__ */ new Map();
|
|
857
1034
|
for (const route of routes) {
|
|
858
|
-
const filePath = rootDir ?
|
|
1035
|
+
const filePath = rootDir ? path2.resolve(rootDir, route.filePath) : route.filePath;
|
|
859
1036
|
let entry = methodsByFile.get(filePath);
|
|
860
1037
|
if (!entry) {
|
|
861
1038
|
entry = { urlPath: route.urlPath, methods: /* @__PURE__ */ new Set() };
|
|
@@ -863,12 +1040,11 @@ function collectRouteSchemaSources(routes, rootDir) {
|
|
|
863
1040
|
}
|
|
864
1041
|
entry.methods.add(route.method);
|
|
865
1042
|
}
|
|
866
|
-
const programByFile =
|
|
1043
|
+
const programByFile = createPrograms([...methodsByFile.keys()]);
|
|
867
1044
|
const allTypesByFile = /* @__PURE__ */ new Map();
|
|
868
1045
|
const mergedAllTypes = /* @__PURE__ */ new Map();
|
|
869
1046
|
for (const filePath of methodsByFile.keys()) {
|
|
870
|
-
const program =
|
|
871
|
-
programByFile.set(filePath, program);
|
|
1047
|
+
const program = programByFile.get(filePath);
|
|
872
1048
|
const allTypes = extractAllTypes(program, filePath);
|
|
873
1049
|
allTypesByFile.set(filePath, allTypes);
|
|
874
1050
|
for (const [name, info] of allTypes) {
|
|
@@ -1223,8 +1399,8 @@ __export(generateSchemaFiles_exports, {
|
|
|
1223
1399
|
getRuntimeSchemaPath: () => getRuntimeSchemaPath,
|
|
1224
1400
|
getSchemaOutputPath: () => getSchemaOutputPath
|
|
1225
1401
|
});
|
|
1226
|
-
import
|
|
1227
|
-
import
|
|
1402
|
+
import path6 from "path";
|
|
1403
|
+
import fs5 from "fs/promises";
|
|
1228
1404
|
function getSchemaOutputPath(sourceFile, dist, rootDir) {
|
|
1229
1405
|
let rel = sourceFile.replace(/\\/g, "/");
|
|
1230
1406
|
if (rel.startsWith("src/")) {
|
|
@@ -1232,7 +1408,7 @@ function getSchemaOutputPath(sourceFile, dist, rootDir) {
|
|
|
1232
1408
|
}
|
|
1233
1409
|
const idx = rel.lastIndexOf("/");
|
|
1234
1410
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
1235
|
-
return
|
|
1411
|
+
return path6.resolve(rootDir, dist, relDir, "zod.js");
|
|
1236
1412
|
}
|
|
1237
1413
|
function getRuntimeSchemaPath(filePath, dist, rootDir) {
|
|
1238
1414
|
let rel = filePath.replace(/\\/g, "/");
|
|
@@ -1243,7 +1419,7 @@ function getRuntimeSchemaPath(filePath, dist, rootDir) {
|
|
|
1243
1419
|
}
|
|
1244
1420
|
const idx = rel.lastIndexOf("/");
|
|
1245
1421
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
1246
|
-
return
|
|
1422
|
+
return path6.resolve(rootDir, dist, relDir, "zod.js");
|
|
1247
1423
|
}
|
|
1248
1424
|
function getHelpersImportPath(relDir) {
|
|
1249
1425
|
if (!relDir) return `./${HELPERS_FILENAME}`;
|
|
@@ -1293,7 +1469,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
1293
1469
|
}
|
|
1294
1470
|
const fileEntries = [];
|
|
1295
1471
|
for (const [filePath, fileSources] of sourcesByFile) {
|
|
1296
|
-
const relFile =
|
|
1472
|
+
const relFile = path6.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
1297
1473
|
const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
|
|
1298
1474
|
const allTypes = allTypesByFile.get(filePath) ?? /* @__PURE__ */ new Map();
|
|
1299
1475
|
let relForDir = relFile;
|
|
@@ -1308,7 +1484,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
1308
1484
|
}
|
|
1309
1485
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
1310
1486
|
if (usesCoerceHelpers(allSourceCode)) {
|
|
1311
|
-
const helpersPath =
|
|
1487
|
+
const helpersPath = path6.resolve(rootDir, dist, HELPERS_FILENAME);
|
|
1312
1488
|
await writeSchemaFile(helpersPath, generateHelpersFileSource());
|
|
1313
1489
|
}
|
|
1314
1490
|
await Promise.all(
|
|
@@ -1316,8 +1492,8 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
1316
1492
|
);
|
|
1317
1493
|
}
|
|
1318
1494
|
async function writeSchemaFile(outputPath, source) {
|
|
1319
|
-
await
|
|
1320
|
-
await
|
|
1495
|
+
await fs5.mkdir(path6.dirname(outputPath), { recursive: true });
|
|
1496
|
+
await fs5.writeFile(outputPath, source, "utf-8");
|
|
1321
1497
|
}
|
|
1322
1498
|
var init_generateSchemaFiles = __esm({
|
|
1323
1499
|
"src/cli/generateSchemaFiles.ts"() {
|
|
@@ -1422,7 +1598,7 @@ function listSkills() {
|
|
|
1422
1598
|
}
|
|
1423
1599
|
|
|
1424
1600
|
// src/loader/loadAgentModule.ts
|
|
1425
|
-
import
|
|
1601
|
+
import fs7 from "fs";
|
|
1426
1602
|
|
|
1427
1603
|
// src/loader/resolveExports.ts
|
|
1428
1604
|
function resolveExport(module, exportName) {
|
|
@@ -1468,17 +1644,17 @@ async function importWithCacheBust(filePath, bustViteCache = false) {
|
|
|
1468
1644
|
}
|
|
1469
1645
|
|
|
1470
1646
|
// src/cli/compileOnDemand.ts
|
|
1471
|
-
import
|
|
1472
|
-
import
|
|
1647
|
+
import path7 from "path";
|
|
1648
|
+
import fs6 from "fs";
|
|
1473
1649
|
|
|
1474
1650
|
// src/cli/compileDevRoutes.ts
|
|
1475
|
-
import
|
|
1476
|
-
import
|
|
1651
|
+
import path5 from "path";
|
|
1652
|
+
import fs4 from "fs";
|
|
1477
1653
|
import fg from "fast-glob";
|
|
1478
1654
|
|
|
1479
1655
|
// src/cli/aliasPlugin.ts
|
|
1480
|
-
import
|
|
1481
|
-
import
|
|
1656
|
+
import path4 from "path";
|
|
1657
|
+
import fs3 from "fs";
|
|
1482
1658
|
|
|
1483
1659
|
// src/utils/resolveAlias.ts
|
|
1484
1660
|
function resolveAlias(specifier, config) {
|
|
@@ -1505,11 +1681,11 @@ function resolveAlias(specifier, config) {
|
|
|
1505
1681
|
|
|
1506
1682
|
// src/utils/readTsconfig.ts
|
|
1507
1683
|
import ts6 from "typescript";
|
|
1508
|
-
import
|
|
1509
|
-
import
|
|
1684
|
+
import path3 from "path";
|
|
1685
|
+
import fs2 from "fs";
|
|
1510
1686
|
function readTsconfig(rootDir) {
|
|
1511
|
-
const tsconfigPath =
|
|
1512
|
-
if (!
|
|
1687
|
+
const tsconfigPath = path3.resolve(rootDir, "tsconfig.json");
|
|
1688
|
+
if (!fs2.existsSync(tsconfigPath)) return null;
|
|
1513
1689
|
const configFile = ts6.readConfigFile(tsconfigPath, ts6.sys.readFile);
|
|
1514
1690
|
if (configFile.error || !configFile.config) return null;
|
|
1515
1691
|
const parsed = ts6.parseJsonConfigFileContent(configFile.config, ts6.sys, rootDir);
|
|
@@ -1518,7 +1694,7 @@ function readTsconfig(rootDir) {
|
|
|
1518
1694
|
if (!rawPaths) return null;
|
|
1519
1695
|
const paths = {};
|
|
1520
1696
|
for (const [pattern, targets] of Object.entries(rawPaths)) {
|
|
1521
|
-
paths[pattern] = targets.map((t) =>
|
|
1697
|
+
paths[pattern] = targets.map((t) => path3.resolve(baseUrl, t));
|
|
1522
1698
|
}
|
|
1523
1699
|
return { baseUrl, paths };
|
|
1524
1700
|
}
|
|
@@ -1531,29 +1707,29 @@ function toProdExtension(filePath) {
|
|
|
1531
1707
|
return filePath;
|
|
1532
1708
|
}
|
|
1533
1709
|
function toProdImportPath(sourceFile, importer) {
|
|
1534
|
-
const importerDir =
|
|
1535
|
-
let rel =
|
|
1536
|
-
rel = rel.split(
|
|
1710
|
+
const importerDir = path4.dirname(importer);
|
|
1711
|
+
let rel = path4.relative(importerDir, sourceFile);
|
|
1712
|
+
rel = rel.split(path4.sep).join("/");
|
|
1537
1713
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
1538
1714
|
return toProdExtension(rel);
|
|
1539
1715
|
}
|
|
1540
1716
|
function toRealPath(p) {
|
|
1541
1717
|
try {
|
|
1542
|
-
return
|
|
1718
|
+
return fs3.realpathSync(p);
|
|
1543
1719
|
} catch {
|
|
1544
1720
|
return p;
|
|
1545
1721
|
}
|
|
1546
1722
|
}
|
|
1547
1723
|
function isInsideDir(filePath, dir) {
|
|
1548
|
-
const rel =
|
|
1549
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
1724
|
+
const rel = path4.relative(dir, filePath);
|
|
1725
|
+
return rel !== "" && !rel.startsWith("..") && !path4.isAbsolute(rel);
|
|
1550
1726
|
}
|
|
1551
1727
|
var APP_DIR = "src";
|
|
1552
1728
|
function toStrippedProdImportPath(sourceFile, rootDir) {
|
|
1553
|
-
const appDirAbs = toRealPath(
|
|
1729
|
+
const appDirAbs = toRealPath(path4.resolve(rootDir, APP_DIR));
|
|
1554
1730
|
const sourceReal = toRealPath(sourceFile);
|
|
1555
|
-
let rel =
|
|
1556
|
-
rel = rel.split(
|
|
1731
|
+
let rel = path4.relative(appDirAbs, sourceReal);
|
|
1732
|
+
rel = rel.split(path4.sep).join("/");
|
|
1557
1733
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
1558
1734
|
return toProdExtension(rel);
|
|
1559
1735
|
}
|
|
@@ -1568,34 +1744,34 @@ var INDEX_EXTS = [
|
|
|
1568
1744
|
"/index.cjs"
|
|
1569
1745
|
];
|
|
1570
1746
|
function resolveRelativeSpecifier(importer, specifier) {
|
|
1571
|
-
const importerDir =
|
|
1572
|
-
const base =
|
|
1747
|
+
const importerDir = path4.dirname(importer);
|
|
1748
|
+
const base = path4.resolve(importerDir, specifier);
|
|
1573
1749
|
if (PROD_EXTS.some((ext) => specifier.endsWith(ext))) {
|
|
1574
|
-
return
|
|
1750
|
+
return fs3.existsSync(base) ? base : null;
|
|
1575
1751
|
}
|
|
1576
1752
|
if (/\.(ts|tsx|jsx)$/.test(specifier)) {
|
|
1577
|
-
return
|
|
1753
|
+
return fs3.existsSync(base) ? base : null;
|
|
1578
1754
|
}
|
|
1579
1755
|
for (const ext of SOURCE_EXTS) {
|
|
1580
1756
|
const file = base + ext;
|
|
1581
|
-
if (
|
|
1757
|
+
if (fs3.existsSync(file)) return file;
|
|
1582
1758
|
}
|
|
1583
1759
|
for (const indexExt of INDEX_EXTS) {
|
|
1584
1760
|
const file = base + indexExt;
|
|
1585
|
-
if (
|
|
1761
|
+
if (fs3.existsSync(file)) return file;
|
|
1586
1762
|
}
|
|
1587
1763
|
return null;
|
|
1588
1764
|
}
|
|
1589
1765
|
function createAliasPlugin(config, options) {
|
|
1590
1766
|
const SPEC_RE = /(\bfrom\s*|import\s*\(\s*)(['"])([^'"]+)\2/g;
|
|
1591
|
-
const appDirAbs = options?.rootDir ? toRealPath(
|
|
1767
|
+
const appDirAbs = options?.rootDir ? toRealPath(path4.resolve(options.rootDir, APP_DIR)) : null;
|
|
1592
1768
|
return {
|
|
1593
1769
|
name: "faapi-alias",
|
|
1594
1770
|
setup(build) {
|
|
1595
1771
|
build.onLoad({ filter: /\.(ts|tsx|js|jsx|mjs|cjs)$/ }, (args) => {
|
|
1596
1772
|
let source;
|
|
1597
1773
|
try {
|
|
1598
|
-
source =
|
|
1774
|
+
source = fs3.readFileSync(args.path, "utf8");
|
|
1599
1775
|
} catch {
|
|
1600
1776
|
return void 0;
|
|
1601
1777
|
}
|
|
@@ -1628,7 +1804,7 @@ function createAliasPlugin(config, options) {
|
|
|
1628
1804
|
for (const candidate of candidates) {
|
|
1629
1805
|
for (const ext of SOURCE_EXTS) {
|
|
1630
1806
|
const file = candidate + ext;
|
|
1631
|
-
if (
|
|
1807
|
+
if (fs3.existsSync(file)) {
|
|
1632
1808
|
modified = true;
|
|
1633
1809
|
if (appDirAbs && importerOutsideAppDir && isInsideDir(file, appDirAbs)) {
|
|
1634
1810
|
return `${prefix}${quote}${toStrippedProdImportPath(
|
|
@@ -1641,7 +1817,7 @@ function createAliasPlugin(config, options) {
|
|
|
1641
1817
|
}
|
|
1642
1818
|
for (const indexExt of INDEX_EXTS) {
|
|
1643
1819
|
const file = candidate + indexExt;
|
|
1644
|
-
if (
|
|
1820
|
+
if (fs3.existsSync(file)) {
|
|
1645
1821
|
modified = true;
|
|
1646
1822
|
if (appDirAbs && importerOutsideAppDir && isInsideDir(file, appDirAbs)) {
|
|
1647
1823
|
return `${prefix}${quote}${toStrippedProdImportPath(
|
|
@@ -1679,11 +1855,11 @@ async function compileDevRoutes(options) {
|
|
|
1679
1855
|
if (entryPoints.length === 0) {
|
|
1680
1856
|
return { compiledFiles: [] };
|
|
1681
1857
|
}
|
|
1682
|
-
const absDist =
|
|
1683
|
-
await
|
|
1858
|
+
const absDist = path5.resolve(rootDir, dist);
|
|
1859
|
+
await fs4.promises.mkdir(absDist, { recursive: true });
|
|
1684
1860
|
const plugins = buildAliasPlugins(rootDir);
|
|
1685
1861
|
const esbuild = await import("esbuild");
|
|
1686
|
-
const outbase =
|
|
1862
|
+
const outbase = path5.resolve(rootDir, APP_DIR2);
|
|
1687
1863
|
const result = await esbuild.build({
|
|
1688
1864
|
entryPoints,
|
|
1689
1865
|
outdir: absDist,
|
|
@@ -1700,10 +1876,10 @@ async function compileDevRoutes(options) {
|
|
|
1700
1876
|
if (result.outputFiles) {
|
|
1701
1877
|
await Promise.all(
|
|
1702
1878
|
result.outputFiles.map(async (file) => {
|
|
1703
|
-
await
|
|
1879
|
+
await fs4.promises.mkdir(path5.dirname(file.path), { recursive: true });
|
|
1704
1880
|
const tmp = `${file.path}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
1705
|
-
await
|
|
1706
|
-
await
|
|
1881
|
+
await fs4.promises.writeFile(tmp, file.contents);
|
|
1882
|
+
await fs4.promises.rename(tmp, file.path);
|
|
1707
1883
|
})
|
|
1708
1884
|
);
|
|
1709
1885
|
}
|
|
@@ -1715,8 +1891,8 @@ init_generateSchemaFiles();
|
|
|
1715
1891
|
init_generateSchemaFiles();
|
|
1716
1892
|
function isProductFresh(sourceAbsPath, productAbsPath) {
|
|
1717
1893
|
try {
|
|
1718
|
-
const srcStat =
|
|
1719
|
-
const prodStat =
|
|
1894
|
+
const srcStat = fs6.statSync(sourceAbsPath);
|
|
1895
|
+
const prodStat = fs6.statSync(productAbsPath);
|
|
1720
1896
|
return prodStat.mtimeMs >= srcStat.mtimeMs;
|
|
1721
1897
|
} catch {
|
|
1722
1898
|
return false;
|
|
@@ -1736,6 +1912,7 @@ var state = createDevOnDemandState();
|
|
|
1736
1912
|
function clearCompiledFiles() {
|
|
1737
1913
|
state.compiledFiles.clear();
|
|
1738
1914
|
state.inFlightCompilations.clear();
|
|
1915
|
+
sourcePathCache.clear();
|
|
1739
1916
|
}
|
|
1740
1917
|
async function ensureCompiled(sourceAbsPath, rootDir, dist) {
|
|
1741
1918
|
const inFlight = state.inFlightCompilations.get(sourceAbsPath);
|
|
@@ -1747,7 +1924,7 @@ async function ensureCompiled(sourceAbsPath, rootDir, dist) {
|
|
|
1747
1924
|
if (state.compiledFiles.has(sourceAbsPath)) {
|
|
1748
1925
|
return false;
|
|
1749
1926
|
}
|
|
1750
|
-
if (!
|
|
1927
|
+
if (!fs6.existsSync(sourceAbsPath)) {
|
|
1751
1928
|
return false;
|
|
1752
1929
|
}
|
|
1753
1930
|
const productPath = prodSourcePathToProductPath(sourceAbsPath, rootDir, dist);
|
|
@@ -1773,11 +1950,11 @@ async function ensureCompiled(sourceAbsPath, rootDir, dist) {
|
|
|
1773
1950
|
}
|
|
1774
1951
|
}
|
|
1775
1952
|
function prodSourcePathToProductPath(sourceAbsPath, rootDir, dist) {
|
|
1776
|
-
const rel =
|
|
1953
|
+
const rel = path7.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
|
|
1777
1954
|
if (!rel.startsWith("src/")) return null;
|
|
1778
1955
|
const relWithoutSrc = rel.slice(4);
|
|
1779
1956
|
const jsRel = relWithoutSrc.replace(/\.ts$/, ".js");
|
|
1780
|
-
return
|
|
1957
|
+
return path7.resolve(rootDir, dist, jsRel);
|
|
1781
1958
|
}
|
|
1782
1959
|
function clearGeneratedSchemas() {
|
|
1783
1960
|
state.generatedSchemas.clear();
|
|
@@ -1793,9 +1970,9 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
|
|
|
1793
1970
|
if (state.generatedSchemas.has(schemaPath)) {
|
|
1794
1971
|
return false;
|
|
1795
1972
|
}
|
|
1796
|
-
const prodAbsPath =
|
|
1973
|
+
const prodAbsPath = path7.resolve(rootDir, routeFilePath);
|
|
1797
1974
|
const sourceAbsPath = prodPathToSourcePath(prodAbsPath, rootDir, dist);
|
|
1798
|
-
if (!
|
|
1975
|
+
if (!fs6.existsSync(sourceAbsPath)) {
|
|
1799
1976
|
return false;
|
|
1800
1977
|
}
|
|
1801
1978
|
if (isProductFresh(sourceAbsPath, schemaPath)) {
|
|
@@ -1806,7 +1983,7 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
|
|
|
1806
1983
|
if (fileRoutes.length === 0) {
|
|
1807
1984
|
return false;
|
|
1808
1985
|
}
|
|
1809
|
-
const sourceRelPath =
|
|
1986
|
+
const sourceRelPath = path7.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
|
|
1810
1987
|
const sourceRoutes = fileRoutes.map((r) => ({ ...r, filePath: sourceRelPath }));
|
|
1811
1988
|
const generatePromise = (async () => {
|
|
1812
1989
|
await generateSchemaFiles(sourceRoutes, rootDir, dist);
|
|
@@ -1827,22 +2004,31 @@ async function deleteSchemaFiles(routes, rootDir, dist) {
|
|
|
1827
2004
|
if (deleted.has(schemaPath)) continue;
|
|
1828
2005
|
deleted.add(schemaPath);
|
|
1829
2006
|
try {
|
|
1830
|
-
await
|
|
2007
|
+
await fs6.promises.unlink(schemaPath);
|
|
1831
2008
|
} catch {
|
|
1832
2009
|
}
|
|
1833
2010
|
}
|
|
1834
2011
|
}
|
|
2012
|
+
var sourcePathCache = /* @__PURE__ */ new Map();
|
|
1835
2013
|
function prodPathToSourcePath(prodAbsPath, rootDir, dist) {
|
|
1836
|
-
const
|
|
2014
|
+
const cached = sourcePathCache.get(prodAbsPath);
|
|
2015
|
+
if (cached) return cached;
|
|
2016
|
+
const rel = path7.relative(rootDir, prodAbsPath).replace(/\\/g, "/");
|
|
1837
2017
|
let relWithoutDist = rel;
|
|
1838
2018
|
if (relWithoutDist.startsWith(`${dist}/`)) {
|
|
1839
2019
|
relWithoutDist = relWithoutDist.slice(dist.length + 1);
|
|
1840
2020
|
}
|
|
1841
2021
|
const srcRel = `src/${relWithoutDist}`;
|
|
1842
2022
|
const tsRel = srcRel.replace(/\.js$/, ".ts");
|
|
1843
|
-
const tsAbs =
|
|
1844
|
-
|
|
1845
|
-
|
|
2023
|
+
const tsAbs = path7.resolve(rootDir, tsRel);
|
|
2024
|
+
let result;
|
|
2025
|
+
if (fs6.existsSync(tsAbs)) {
|
|
2026
|
+
result = tsAbs;
|
|
2027
|
+
} else {
|
|
2028
|
+
result = path7.resolve(rootDir, srcRel);
|
|
2029
|
+
}
|
|
2030
|
+
sourcePathCache.set(prodAbsPath, result);
|
|
2031
|
+
return result;
|
|
1846
2032
|
}
|
|
1847
2033
|
function isDevOnDemandEnabled() {
|
|
1848
2034
|
return state.enabled;
|
|
@@ -1857,7 +2043,7 @@ async function loadAgentModule(filePath, hasRun, rootDir) {
|
|
|
1857
2043
|
const dist = getDevDist();
|
|
1858
2044
|
if (dist) {
|
|
1859
2045
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
1860
|
-
if (sourcePath &&
|
|
2046
|
+
if (sourcePath && fs7.existsSync(sourcePath)) {
|
|
1861
2047
|
try {
|
|
1862
2048
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
1863
2049
|
} catch (compileErr) {
|
|
@@ -1890,13 +2076,13 @@ async function loadAgentModule(filePath, hasRun, rootDir) {
|
|
|
1890
2076
|
}
|
|
1891
2077
|
|
|
1892
2078
|
// src/loader/loadToolModule.ts
|
|
1893
|
-
import
|
|
2079
|
+
import fs8 from "fs";
|
|
1894
2080
|
async function loadToolModule(filePath, functionName, rootDir) {
|
|
1895
2081
|
if (isDevOnDemandEnabled() && rootDir) {
|
|
1896
2082
|
const dist = getDevDist();
|
|
1897
2083
|
if (dist) {
|
|
1898
2084
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
1899
|
-
if (sourcePath &&
|
|
2085
|
+
if (sourcePath && fs8.existsSync(sourcePath)) {
|
|
1900
2086
|
try {
|
|
1901
2087
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
1902
2088
|
} catch (compileErr) {
|
|
@@ -1928,8 +2114,8 @@ async function loadToolModule(filePath, functionName, rootDir) {
|
|
|
1928
2114
|
import { existsSync as existsSync2 } from "fs";
|
|
1929
2115
|
|
|
1930
2116
|
// src/cli/generateToolArtifacts.ts
|
|
1931
|
-
import
|
|
1932
|
-
import
|
|
2117
|
+
import path8 from "path";
|
|
2118
|
+
import fs9 from "fs/promises";
|
|
1933
2119
|
import { existsSync } from "fs";
|
|
1934
2120
|
|
|
1935
2121
|
// src/ast/extractToolMetadata.ts
|
|
@@ -2024,7 +2210,7 @@ function getToolSchemaOutputPath(sourceFile, dist, rootDir) {
|
|
|
2024
2210
|
}
|
|
2025
2211
|
const idx = rel.lastIndexOf("/");
|
|
2026
2212
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
2027
|
-
return
|
|
2213
|
+
return path8.resolve(rootDir, dist, relDir, "zod.js");
|
|
2028
2214
|
}
|
|
2029
2215
|
function getRuntimeToolSchemaPath(filePath, dist, rootDir) {
|
|
2030
2216
|
let rel = filePath.replace(/\\/g, "/");
|
|
@@ -2035,7 +2221,7 @@ function getRuntimeToolSchemaPath(filePath, dist, rootDir) {
|
|
|
2035
2221
|
}
|
|
2036
2222
|
const idx = rel.lastIndexOf("/");
|
|
2037
2223
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
2038
|
-
return
|
|
2224
|
+
return path8.resolve(rootDir, dist, relDir, "zod.js");
|
|
2039
2225
|
}
|
|
2040
2226
|
function toProdFilePath(filePath, dist) {
|
|
2041
2227
|
let rel = filePath.replace(/\\/g, "/");
|
|
@@ -2055,12 +2241,12 @@ function serializeTools(tools, dist = "dist") {
|
|
|
2055
2241
|
}));
|
|
2056
2242
|
}
|
|
2057
2243
|
async function writeToolsModule(manifest, outputPath) {
|
|
2058
|
-
const dir =
|
|
2059
|
-
await
|
|
2244
|
+
const dir = path8.dirname(outputPath);
|
|
2245
|
+
await fs9.mkdir(dir, { recursive: true });
|
|
2060
2246
|
const content = `// \u81EA\u52A8\u751F\u6210,\u8BF7\u52FF\u624B\u52A8\u7F16\u8F91(faapi build/dev \u4EA7\u7269)
|
|
2061
2247
|
export const tools = ${JSON.stringify(manifest, null, 2)};
|
|
2062
2248
|
`;
|
|
2063
|
-
await
|
|
2249
|
+
await fs9.writeFile(outputPath, content, "utf-8");
|
|
2064
2250
|
}
|
|
2065
2251
|
function hydrateTools(manifest) {
|
|
2066
2252
|
return manifest.map((t) => ({
|
|
@@ -2075,7 +2261,7 @@ function collectToolSchemaSources(tools, rootDir) {
|
|
|
2075
2261
|
const toolsByFile = /* @__PURE__ */ new Map();
|
|
2076
2262
|
for (const tool of tools) {
|
|
2077
2263
|
if (!tool.inputTypeName) continue;
|
|
2078
|
-
const absPath =
|
|
2264
|
+
const absPath = path8.resolve(rootDir, tool.filePath);
|
|
2079
2265
|
let list = toolsByFile.get(absPath);
|
|
2080
2266
|
if (!list) {
|
|
2081
2267
|
list = [];
|
|
@@ -2083,15 +2269,16 @@ function collectToolSchemaSources(tools, rootDir) {
|
|
|
2083
2269
|
}
|
|
2084
2270
|
list.push(tool);
|
|
2085
2271
|
}
|
|
2272
|
+
const programByFile = createPrograms([...toolsByFile.keys()]);
|
|
2086
2273
|
const allTypesByFile = /* @__PURE__ */ new Map();
|
|
2087
2274
|
for (const filePath of toolsByFile.keys()) {
|
|
2088
|
-
const program =
|
|
2275
|
+
const program = programByFile.get(filePath);
|
|
2089
2276
|
const allTypes = extractAllTypes(program, filePath);
|
|
2090
2277
|
allTypesByFile.set(filePath, allTypes);
|
|
2091
2278
|
}
|
|
2092
2279
|
const sources = [];
|
|
2093
2280
|
for (const [filePath, fileTools] of toolsByFile) {
|
|
2094
|
-
const program =
|
|
2281
|
+
const program = programByFile.get(filePath);
|
|
2095
2282
|
for (const tool of fileTools) {
|
|
2096
2283
|
const inputTypeName = tool.inputTypeName;
|
|
2097
2284
|
const typeInfo = extractTypeInfo(program, filePath, inputTypeName);
|
|
@@ -2137,16 +2324,17 @@ function generateToolSchemaFileSource(sources, allTypes, helpersImportPath) {
|
|
|
2137
2324
|
}
|
|
2138
2325
|
async function maybeGenerateHelpers(allSourceCode, distDir) {
|
|
2139
2326
|
if (!usesCoerceHelpers(allSourceCode)) return;
|
|
2140
|
-
const helpersPath =
|
|
2327
|
+
const helpersPath = path8.resolve(distDir, HELPERS_FILENAME);
|
|
2141
2328
|
if (existsSync(helpersPath)) return;
|
|
2142
|
-
await
|
|
2143
|
-
await
|
|
2329
|
+
await fs9.mkdir(path8.dirname(helpersPath), { recursive: true });
|
|
2330
|
+
await fs9.writeFile(helpersPath, generateHelpersFileSource(), "utf-8");
|
|
2144
2331
|
}
|
|
2145
2332
|
async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
2146
2333
|
const metadata = [];
|
|
2334
|
+
const programByFile = createPrograms(tools.map((m) => path8.resolve(rootDir, m.filePath)));
|
|
2147
2335
|
for (const manifest of tools) {
|
|
2148
|
-
const absPath =
|
|
2149
|
-
const program =
|
|
2336
|
+
const absPath = path8.resolve(rootDir, manifest.filePath);
|
|
2337
|
+
const program = programByFile.get(absPath);
|
|
2150
2338
|
const result = extractToolMetadata(program, absPath, manifest.functionName, {
|
|
2151
2339
|
name: manifest.name,
|
|
2152
2340
|
filePath: manifest.filePath
|
|
@@ -2156,7 +2344,7 @@ async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
|
2156
2344
|
}
|
|
2157
2345
|
}
|
|
2158
2346
|
const serialized = serializeTools(metadata, dist);
|
|
2159
|
-
const toolsPath =
|
|
2347
|
+
const toolsPath = path8.resolve(rootDir, dist, TOOLS_FILE);
|
|
2160
2348
|
await writeToolsModule(serialized, toolsPath);
|
|
2161
2349
|
if (options?.skipSchema) {
|
|
2162
2350
|
return metadata;
|
|
@@ -2179,7 +2367,7 @@ async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
|
2179
2367
|
}
|
|
2180
2368
|
const fileEntries = [];
|
|
2181
2369
|
for (const [filePath, fileSources] of sourcesByFile) {
|
|
2182
|
-
const relFile =
|
|
2370
|
+
const relFile = path8.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
2183
2371
|
const outputPath = getToolSchemaOutputPath(relFile, dist, rootDir);
|
|
2184
2372
|
const allTypes = allTypesByFile.get(filePath) ?? /* @__PURE__ */ new Map();
|
|
2185
2373
|
let relForDir = relFile;
|
|
@@ -2193,7 +2381,7 @@ async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
|
2193
2381
|
fileEntries.push({ outputPath, source });
|
|
2194
2382
|
}
|
|
2195
2383
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
2196
|
-
const distDir =
|
|
2384
|
+
const distDir = path8.resolve(rootDir, dist);
|
|
2197
2385
|
await maybeGenerateHelpers(allSourceCode, distDir);
|
|
2198
2386
|
await Promise.all(
|
|
2199
2387
|
fileEntries.map(({ outputPath, source }) => writeToolSchemaFile(outputPath, source))
|
|
@@ -2201,8 +2389,8 @@ async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
|
2201
2389
|
return metadata;
|
|
2202
2390
|
}
|
|
2203
2391
|
async function writeToolSchemaFile(outputPath, source) {
|
|
2204
|
-
await
|
|
2205
|
-
await
|
|
2392
|
+
await fs9.mkdir(path8.dirname(outputPath), { recursive: true });
|
|
2393
|
+
await fs9.writeFile(outputPath, source, "utf-8");
|
|
2206
2394
|
}
|
|
2207
2395
|
|
|
2208
2396
|
// src/loader/loadToolSchema.ts
|
|
@@ -2212,11 +2400,14 @@ function getDist() {
|
|
|
2212
2400
|
}
|
|
2213
2401
|
return process.env.FAAPI_DIST ?? "dist";
|
|
2214
2402
|
}
|
|
2403
|
+
function getToolSchemaPath(tool, rootDir) {
|
|
2404
|
+
const dist = getDist();
|
|
2405
|
+
return getRuntimeToolSchemaPath(tool.filePath, dist, rootDir ?? process.cwd());
|
|
2406
|
+
}
|
|
2215
2407
|
async function loadToolSchema(tool, rootDir) {
|
|
2216
2408
|
if (!tool.inputTypeName) return void 0;
|
|
2217
2409
|
const schemaName = `${tool.inputTypeName}Schema`;
|
|
2218
|
-
const
|
|
2219
|
-
const zodPath = getRuntimeToolSchemaPath(tool.filePath, dist, rootDir ?? process.cwd());
|
|
2410
|
+
const zodPath = getToolSchemaPath(tool, rootDir);
|
|
2220
2411
|
if (!existsSync2(zodPath)) return void 0;
|
|
2221
2412
|
try {
|
|
2222
2413
|
const mod = await importWithCacheBust(zodPath, isDevOnDemandEnabled());
|
|
@@ -2402,16 +2593,16 @@ function helmet(options = {}) {
|
|
|
2402
2593
|
}
|
|
2403
2594
|
|
|
2404
2595
|
// src/config/loadConfig.ts
|
|
2405
|
-
import
|
|
2406
|
-
import
|
|
2596
|
+
import path9 from "path";
|
|
2597
|
+
import fs10 from "fs";
|
|
2407
2598
|
var CONFIG_PRODUCT_FILE = "faapi-config.js";
|
|
2408
2599
|
async function loadConfig(rootDir, dist) {
|
|
2409
|
-
const configProductPath =
|
|
2410
|
-
if (
|
|
2600
|
+
const configProductPath = path9.resolve(rootDir, dist, CONFIG_PRODUCT_FILE);
|
|
2601
|
+
if (fs10.existsSync(configProductPath)) {
|
|
2411
2602
|
const module = await importWithCacheBust(configProductPath);
|
|
2412
2603
|
return module.default ?? {};
|
|
2413
2604
|
}
|
|
2414
|
-
const hasSourceConfig =
|
|
2605
|
+
const hasSourceConfig = fs10.existsSync(path9.join(rootDir, "faapi.config.ts")) || fs10.existsSync(path9.join(rootDir, "faapi.config.js"));
|
|
2415
2606
|
if (hasSourceConfig) {
|
|
2416
2607
|
throw new Error(
|
|
2417
2608
|
`[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`
|
|
@@ -2421,8 +2612,8 @@ async function loadConfig(rootDir, dist) {
|
|
|
2421
2612
|
}
|
|
2422
2613
|
|
|
2423
2614
|
// src/cli/loadEnv.ts
|
|
2424
|
-
import
|
|
2425
|
-
import
|
|
2615
|
+
import fs11 from "fs";
|
|
2616
|
+
import path10 from "path";
|
|
2426
2617
|
function resolveEnv() {
|
|
2427
2618
|
return process.env.NODE_ENV || "development";
|
|
2428
2619
|
}
|
|
@@ -2488,9 +2679,9 @@ function loadEnv(rootDir) {
|
|
|
2488
2679
|
const files = getEnvFiles(env);
|
|
2489
2680
|
const merged = {};
|
|
2490
2681
|
for (const file of files) {
|
|
2491
|
-
const filePath =
|
|
2492
|
-
if (!
|
|
2493
|
-
const content =
|
|
2682
|
+
const filePath = path10.join(rootDir, file);
|
|
2683
|
+
if (!fs11.existsSync(filePath)) continue;
|
|
2684
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
2494
2685
|
const parsed = parseEnvFile(content, merged);
|
|
2495
2686
|
Object.assign(merged, parsed);
|
|
2496
2687
|
}
|
|
@@ -2527,14 +2718,14 @@ var ValidationError = class extends FaapiError {
|
|
|
2527
2718
|
issues;
|
|
2528
2719
|
};
|
|
2529
2720
|
var RouteNotFoundError = class extends FaapiError {
|
|
2530
|
-
constructor(
|
|
2531
|
-
super("ROUTE_NOT_FOUND", `Route not found: ${
|
|
2721
|
+
constructor(path19) {
|
|
2722
|
+
super("ROUTE_NOT_FOUND", `Route not found: ${path19}`, 404);
|
|
2532
2723
|
this.name = "RouteNotFoundError";
|
|
2533
2724
|
}
|
|
2534
2725
|
};
|
|
2535
2726
|
var MethodNotAllowedError = class extends FaapiError {
|
|
2536
|
-
constructor(method,
|
|
2537
|
-
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${
|
|
2727
|
+
constructor(method, path19, allowedMethods) {
|
|
2728
|
+
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path19}`, 405);
|
|
2538
2729
|
this.allowedMethods = allowedMethods;
|
|
2539
2730
|
this.name = "MethodNotAllowedError";
|
|
2540
2731
|
}
|
|
@@ -2561,7 +2752,7 @@ var PayloadTooLargeError = class extends FaapiError {
|
|
|
2561
2752
|
|
|
2562
2753
|
// src/cli/createAppCore.ts
|
|
2563
2754
|
import fs15 from "fs";
|
|
2564
|
-
import
|
|
2755
|
+
import path15 from "path";
|
|
2565
2756
|
import { PassThrough, Readable as Readable3 } from "stream";
|
|
2566
2757
|
|
|
2567
2758
|
// src/router/sortRoutes.ts
|
|
@@ -2614,45 +2805,96 @@ import {
|
|
|
2614
2805
|
import { createSecureServer as createHttp2SecureServer } from "http2";
|
|
2615
2806
|
import { readFileSync } from "fs";
|
|
2616
2807
|
import { Readable as Readable2 } from "stream";
|
|
2617
|
-
import
|
|
2808
|
+
import path12 from "path";
|
|
2618
2809
|
|
|
2619
2810
|
// src/router/matchRoute.ts
|
|
2620
|
-
|
|
2811
|
+
var httpIndexCache = /* @__PURE__ */ new WeakMap();
|
|
2812
|
+
var wsIndexCache = /* @__PURE__ */ new WeakMap();
|
|
2813
|
+
function getHttpIndex(routes) {
|
|
2814
|
+
let index = httpIndexCache.get(routes);
|
|
2815
|
+
if (index) return index;
|
|
2816
|
+
index = { static: /* @__PURE__ */ new Map(), methodsByStaticPath: /* @__PURE__ */ new Map(), dynamics: [] };
|
|
2621
2817
|
for (const route of routes) {
|
|
2622
|
-
if (route.
|
|
2623
|
-
|
|
2624
|
-
}
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2818
|
+
if (route.isDynamic) {
|
|
2819
|
+
index.dynamics.push(route);
|
|
2820
|
+
} else {
|
|
2821
|
+
index.static.set(`${route.method}|${route.urlPath}`, route);
|
|
2822
|
+
let methods = index.methodsByStaticPath.get(route.urlPath);
|
|
2823
|
+
if (!methods) {
|
|
2824
|
+
methods = /* @__PURE__ */ new Set();
|
|
2825
|
+
index.methodsByStaticPath.set(route.urlPath, methods);
|
|
2628
2826
|
}
|
|
2827
|
+
methods.add(route.method);
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
httpIndexCache.set(routes, index);
|
|
2831
|
+
return index;
|
|
2832
|
+
}
|
|
2833
|
+
function getWsIndex(routes) {
|
|
2834
|
+
let index = wsIndexCache.get(routes);
|
|
2835
|
+
if (index) return index;
|
|
2836
|
+
index = { static: /* @__PURE__ */ new Map(), dynamics: [] };
|
|
2837
|
+
for (const route of routes) {
|
|
2838
|
+
if (route.isDynamic) {
|
|
2839
|
+
index.dynamics.push(route);
|
|
2840
|
+
} else {
|
|
2841
|
+
index.static.set(route.urlPath, route);
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
wsIndexCache.set(routes, index);
|
|
2845
|
+
return index;
|
|
2846
|
+
}
|
|
2847
|
+
function matchRoute(routes, method, path19) {
|
|
2848
|
+
const index = getHttpIndex(routes);
|
|
2849
|
+
const staticHit = index.static.get(`${method}|${path19}`);
|
|
2850
|
+
if (staticHit) {
|
|
2851
|
+
return { route: staticHit, params: {} };
|
|
2852
|
+
}
|
|
2853
|
+
for (const route of index.dynamics) {
|
|
2854
|
+
if (route.method !== method) {
|
|
2629
2855
|
continue;
|
|
2630
2856
|
}
|
|
2631
|
-
const params = matchDynamicPath(route.urlPath,
|
|
2857
|
+
const params = matchDynamicPath(route.urlPath, path19, route.paramNames, route.isCatchAll);
|
|
2632
2858
|
if (params !== null) {
|
|
2633
2859
|
return { route, params };
|
|
2634
2860
|
}
|
|
2635
2861
|
}
|
|
2636
2862
|
return null;
|
|
2637
2863
|
}
|
|
2638
|
-
function matchWsRoute(wsRoutes,
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
const params = matchDynamicPath(route.urlPath, path18, route.paramNames, route.isCatchAll);
|
|
2864
|
+
function matchWsRoute(wsRoutes, path19) {
|
|
2865
|
+
const index = getWsIndex(wsRoutes);
|
|
2866
|
+
const staticHit = index.static.get(path19);
|
|
2867
|
+
if (staticHit) {
|
|
2868
|
+
return { route: staticHit, params: {} };
|
|
2869
|
+
}
|
|
2870
|
+
for (const route of index.dynamics) {
|
|
2871
|
+
const params = matchDynamicPath(route.urlPath, path19, route.paramNames, route.isCatchAll);
|
|
2647
2872
|
if (params !== null) {
|
|
2648
2873
|
return { route, params };
|
|
2649
2874
|
}
|
|
2650
2875
|
}
|
|
2651
2876
|
return null;
|
|
2652
2877
|
}
|
|
2653
|
-
function
|
|
2878
|
+
function findAllowedMethods(routes, path19) {
|
|
2879
|
+
const index = getHttpIndex(routes);
|
|
2880
|
+
const methods = /* @__PURE__ */ new Set();
|
|
2881
|
+
const staticMethods = index.methodsByStaticPath.get(path19);
|
|
2882
|
+
if (staticMethods) {
|
|
2883
|
+
for (const method of staticMethods) {
|
|
2884
|
+
methods.add(method);
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
for (const route of index.dynamics) {
|
|
2888
|
+
const params = matchDynamicPath(route.urlPath, path19, route.paramNames, route.isCatchAll);
|
|
2889
|
+
if (params !== null) {
|
|
2890
|
+
methods.add(route.method);
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
return Array.from(methods);
|
|
2894
|
+
}
|
|
2895
|
+
function matchDynamicPath(pattern, path19, paramNames, isCatchAll) {
|
|
2654
2896
|
const patternSegments = pattern.split("/").filter(Boolean);
|
|
2655
|
-
const pathSegments =
|
|
2897
|
+
const pathSegments = path19.split("/").filter(Boolean);
|
|
2656
2898
|
if (isCatchAll) {
|
|
2657
2899
|
const nonCatchAllCount = patternSegments.length - 1;
|
|
2658
2900
|
if (pathSegments.length <= nonCatchAllCount) {
|
|
@@ -2697,9 +2939,6 @@ function matchDynamicPath(pattern, path18, paramNames, isCatchAll) {
|
|
|
2697
2939
|
return params;
|
|
2698
2940
|
}
|
|
2699
2941
|
|
|
2700
|
-
// src/loader/loadRouteModule.ts
|
|
2701
|
-
import fs11 from "fs";
|
|
2702
|
-
|
|
2703
2942
|
// src/loader/validateRouteModule.ts
|
|
2704
2943
|
function validateRouteModule(value, method, filePath) {
|
|
2705
2944
|
if (typeof value !== "function") {
|
|
@@ -2715,7 +2954,7 @@ async function loadRouteModule(filePath, method, rootDir) {
|
|
|
2715
2954
|
const dist = getDevDist();
|
|
2716
2955
|
if (dist) {
|
|
2717
2956
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
2718
|
-
if (sourcePath
|
|
2957
|
+
if (sourcePath) {
|
|
2719
2958
|
try {
|
|
2720
2959
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
2721
2960
|
} catch (compileErr) {
|
|
@@ -2955,7 +3194,9 @@ function formatSetCookie(name, value, options) {
|
|
|
2955
3194
|
return cookie;
|
|
2956
3195
|
}
|
|
2957
3196
|
function createContext(request, params, config = {}, ip = "") {
|
|
2958
|
-
|
|
3197
|
+
return createContextFromUrl(request, new URL(request.url), params, config, ip);
|
|
3198
|
+
}
|
|
3199
|
+
function createContextFromUrl(request, url, params, config = {}, ip = "") {
|
|
2959
3200
|
const meta = { headers: {}, setCookies: [] };
|
|
2960
3201
|
const parsedCookies = parseCookies(request.headers.get("cookie") ?? "");
|
|
2961
3202
|
const cookiesObj = {};
|
|
@@ -3110,7 +3351,7 @@ async function parseMultipart(request) {
|
|
|
3110
3351
|
|
|
3111
3352
|
// src/runtime/resolveInput.ts
|
|
3112
3353
|
init_inputType();
|
|
3113
|
-
async function
|
|
3354
|
+
async function resolveInputFromUrl(method, request, url) {
|
|
3114
3355
|
const inputType = getInputTypeForMethod(method);
|
|
3115
3356
|
if (inputType === "body") {
|
|
3116
3357
|
const contentType = request.headers.get("content-type") ?? "";
|
|
@@ -3145,7 +3386,6 @@ async function resolveInput(method, request) {
|
|
|
3145
3386
|
}
|
|
3146
3387
|
return result.data;
|
|
3147
3388
|
}
|
|
3148
|
-
const url = new URL(request.url);
|
|
3149
3389
|
return queryToObject(url.searchParams);
|
|
3150
3390
|
}
|
|
3151
3391
|
|
|
@@ -3470,9 +3710,9 @@ async function validateInput(schemaPath, method, inputType, input) {
|
|
|
3470
3710
|
function mapZodIssues(error) {
|
|
3471
3711
|
return error.issues.map((issue) => {
|
|
3472
3712
|
const code = mapZodCode(issue.code, issue.message);
|
|
3473
|
-
const
|
|
3713
|
+
const path19 = issue.path.map(String).join(".") || "";
|
|
3474
3714
|
return {
|
|
3475
|
-
path:
|
|
3715
|
+
path: path19,
|
|
3476
3716
|
code,
|
|
3477
3717
|
expected: issue.expected ?? mapExpectedFromMessage(issue.message),
|
|
3478
3718
|
received: issue.received ?? mapReceivedFromMessage(issue.message),
|
|
@@ -3517,11 +3757,13 @@ function mapReceivedFromMessage(message) {
|
|
|
3517
3757
|
init_inputType();
|
|
3518
3758
|
|
|
3519
3759
|
// src/utils/getClientIp.ts
|
|
3520
|
-
function getClientIp(req) {
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3760
|
+
function getClientIp(req, trustedProxy = false) {
|
|
3761
|
+
if (trustedProxy) {
|
|
3762
|
+
const xff = req.headers["x-forwarded-for"];
|
|
3763
|
+
if (typeof xff === "string" && xff.length > 0) {
|
|
3764
|
+
const first = xff.split(",")[0]?.trim();
|
|
3765
|
+
if (first) return first;
|
|
3766
|
+
}
|
|
3525
3767
|
}
|
|
3526
3768
|
const remote = req.socket?.remoteAddress;
|
|
3527
3769
|
if (remote) {
|
|
@@ -3536,7 +3778,7 @@ function getClientIp(req) {
|
|
|
3536
3778
|
// src/server/handleWsUpgrade.ts
|
|
3537
3779
|
import fs12 from "fs";
|
|
3538
3780
|
import { WebSocketServer, WebSocket } from "ws";
|
|
3539
|
-
import
|
|
3781
|
+
import path11 from "path";
|
|
3540
3782
|
|
|
3541
3783
|
// src/server/serverUtils.ts
|
|
3542
3784
|
function nodeHttpToWebHeaders(req) {
|
|
@@ -3720,7 +3962,7 @@ async function sendResponseToSocket(socket, response) {
|
|
|
3720
3962
|
socket.destroy();
|
|
3721
3963
|
}
|
|
3722
3964
|
function attachWebSocket(options) {
|
|
3723
|
-
const { server, routesRef, rootDir, config, globalMiddlewares } = options;
|
|
3965
|
+
const { server, routesRef, rootDir, config, globalMiddlewares, trustedProxy = false } = options;
|
|
3724
3966
|
const wss = new WebSocketServer({ noServer: true });
|
|
3725
3967
|
server.on("upgrade", async (req, socket, head) => {
|
|
3726
3968
|
const currentWsRoutes = routesRef.wsCurrent;
|
|
@@ -3736,13 +3978,13 @@ function attachWebSocket(options) {
|
|
|
3736
3978
|
const host = req.headers.host ?? "localhost";
|
|
3737
3979
|
const url = `http://${host}${req.url ?? "/"}`;
|
|
3738
3980
|
const request = new Request(url, { method: "GET", headers });
|
|
3739
|
-
const ctx = createContext(request, params, config, getClientIp(req));
|
|
3981
|
+
const ctx = createContext(request, params, config, getClientIp(req, trustedProxy));
|
|
3740
3982
|
const meta = ctx.meta;
|
|
3741
3983
|
let upgraded = false;
|
|
3742
3984
|
const finalHandler = async () => {
|
|
3743
3985
|
let handlers;
|
|
3744
3986
|
try {
|
|
3745
|
-
const absoluteFilePath =
|
|
3987
|
+
const absoluteFilePath = path11.resolve(rootDir, route.filePath);
|
|
3746
3988
|
handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
|
|
3747
3989
|
} catch (err) {
|
|
3748
3990
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -3806,16 +4048,26 @@ function toWebRequest(req, bodyLimit = DEFAULT_BODY_LIMIT) {
|
|
|
3806
4048
|
const headers = nodeHttpToWebHeaders(req);
|
|
3807
4049
|
const method = req.method ?? "GET";
|
|
3808
4050
|
if (method === "GET" || method === "HEAD") {
|
|
3809
|
-
return new Request(url.toString(), { method, headers });
|
|
4051
|
+
return { request: new Request(url.toString(), { method, headers }), url };
|
|
4052
|
+
}
|
|
4053
|
+
const contentLength = req.headers["content-length"];
|
|
4054
|
+
if (contentLength !== void 0) {
|
|
4055
|
+
const declared = Number(Array.isArray(contentLength) ? contentLength[0] : contentLength);
|
|
4056
|
+
if (Number.isFinite(declared) && declared > bodyLimit) {
|
|
4057
|
+
throw new PayloadTooLargeError(bodyLimit);
|
|
4058
|
+
}
|
|
3810
4059
|
}
|
|
3811
4060
|
const stream = Readable2.toWeb(req);
|
|
3812
4061
|
const limitedStream = limitStreamSize(stream, bodyLimit);
|
|
3813
|
-
return
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
4062
|
+
return {
|
|
4063
|
+
request: new Request(url.toString(), {
|
|
4064
|
+
method,
|
|
4065
|
+
headers,
|
|
4066
|
+
body: limitedStream,
|
|
4067
|
+
duplex: "half"
|
|
4068
|
+
}),
|
|
4069
|
+
url
|
|
4070
|
+
};
|
|
3819
4071
|
}
|
|
3820
4072
|
function limitStreamSize(stream, maxSize) {
|
|
3821
4073
|
let totalSize = 0;
|
|
@@ -3867,22 +4119,6 @@ function limitStreamSize(stream, maxSize) {
|
|
|
3867
4119
|
}
|
|
3868
4120
|
});
|
|
3869
4121
|
}
|
|
3870
|
-
function findAllowedMethods(routes, path18) {
|
|
3871
|
-
const methods = /* @__PURE__ */ new Set();
|
|
3872
|
-
for (const route of routes) {
|
|
3873
|
-
if (route.urlPath === path18) {
|
|
3874
|
-
methods.add(route.method);
|
|
3875
|
-
continue;
|
|
3876
|
-
}
|
|
3877
|
-
if (route.isDynamic) {
|
|
3878
|
-
const params = matchDynamicPath(route.urlPath, path18, route.paramNames, route.isCatchAll);
|
|
3879
|
-
if (params !== null) {
|
|
3880
|
-
methods.add(route.method);
|
|
3881
|
-
}
|
|
3882
|
-
}
|
|
3883
|
-
}
|
|
3884
|
-
return Array.from(methods);
|
|
3885
|
-
}
|
|
3886
4122
|
function createServer(options) {
|
|
3887
4123
|
const {
|
|
3888
4124
|
routes,
|
|
@@ -3897,7 +4133,8 @@ function createServer(options) {
|
|
|
3897
4133
|
helmet: helmetOption,
|
|
3898
4134
|
logger: loggerOption,
|
|
3899
4135
|
bodyLimit = DEFAULT_BODY_LIMIT,
|
|
3900
|
-
http2: http2Option
|
|
4136
|
+
http2: http2Option,
|
|
4137
|
+
trustedProxy = false
|
|
3901
4138
|
} = options;
|
|
3902
4139
|
const routesRef = { current: routes, wsCurrent: wsRoutes ?? [] };
|
|
3903
4140
|
const configMiddlewares = [];
|
|
@@ -3909,6 +4146,10 @@ function createServer(options) {
|
|
|
3909
4146
|
}
|
|
3910
4147
|
const loggerMiddlewareInst = loggerOption === false ? null : loggerOption === true || loggerOption === void 0 ? logger() : logger(loggerOption);
|
|
3911
4148
|
if (loggerMiddlewareInst) configMiddlewares.push(loggerMiddlewareInst);
|
|
4149
|
+
const outerMiddlewares = [...configMiddlewares];
|
|
4150
|
+
if (globalMiddlewares && globalMiddlewares.length > 0) {
|
|
4151
|
+
outerMiddlewares.push(...globalMiddlewares);
|
|
4152
|
+
}
|
|
3912
4153
|
const server = (() => {
|
|
3913
4154
|
if (http2Option) {
|
|
3914
4155
|
const h2Opts = typeof http2Option === "object" ? http2Option : {};
|
|
@@ -3928,29 +4169,29 @@ function createServer(options) {
|
|
|
3928
4169
|
dist,
|
|
3929
4170
|
req,
|
|
3930
4171
|
res,
|
|
3931
|
-
|
|
4172
|
+
outerMiddlewares,
|
|
3932
4173
|
onError,
|
|
3933
4174
|
config,
|
|
3934
|
-
globalMiddlewares,
|
|
3935
4175
|
globalInjectors,
|
|
3936
|
-
bodyLimit
|
|
4176
|
+
bodyLimit,
|
|
4177
|
+
trustedProxy
|
|
3937
4178
|
).catch(() => {
|
|
3938
4179
|
res.statusCode = 500;
|
|
3939
4180
|
res.end();
|
|
3940
4181
|
});
|
|
3941
4182
|
});
|
|
3942
4183
|
if (routesRef.wsCurrent.length > 0) {
|
|
3943
|
-
attachWebSocket({ server, routesRef, rootDir, config, globalMiddlewares });
|
|
4184
|
+
attachWebSocket({ server, routesRef, rootDir, config, globalMiddlewares, trustedProxy });
|
|
3944
4185
|
}
|
|
3945
4186
|
return { server, routesRef };
|
|
3946
4187
|
}
|
|
3947
|
-
function prepareRequest(req, config, bodyLimit) {
|
|
3948
|
-
const request = toWebRequest(req, bodyLimit);
|
|
4188
|
+
function prepareRequest(req, config, bodyLimit, trustedProxy) {
|
|
4189
|
+
const { request, url } = toWebRequest(req, bodyLimit);
|
|
3949
4190
|
const method = request.method.toUpperCase();
|
|
3950
|
-
const urlPath =
|
|
3951
|
-
const ctx =
|
|
4191
|
+
const urlPath = url.pathname;
|
|
4192
|
+
const ctx = createContextFromUrl(request, url, {}, config, getClientIp(req, trustedProxy));
|
|
3952
4193
|
const meta = ctx.meta;
|
|
3953
|
-
return { request, ctx, meta, method, urlPath };
|
|
4194
|
+
return { request, url, ctx, meta, method, urlPath };
|
|
3954
4195
|
}
|
|
3955
4196
|
function resolveRouteOrThrow(routes, method, urlPath) {
|
|
3956
4197
|
const match = matchRoute(routes, method, urlPath);
|
|
@@ -3962,14 +4203,14 @@ function resolveRouteOrThrow(routes, method, urlPath) {
|
|
|
3962
4203
|
throw new RouteNotFoundError(urlPath);
|
|
3963
4204
|
}
|
|
3964
4205
|
function createRoutePipeline(opts) {
|
|
3965
|
-
const { routes, method, urlPath, ctx, request, rootDir, dist, globalInjectors } = opts;
|
|
4206
|
+
const { routes, method, urlPath, url, ctx, request, rootDir, dist, globalInjectors } = opts;
|
|
3966
4207
|
return async () => {
|
|
3967
4208
|
const match = resolveRouteOrThrow(routes, method, urlPath);
|
|
3968
4209
|
ctx.params = match.params;
|
|
3969
4210
|
const { route } = match;
|
|
3970
|
-
const absoluteFilePath =
|
|
4211
|
+
const absoluteFilePath = path12.resolve(rootDir, route.filePath);
|
|
3971
4212
|
const routeModule = await loadRouteModule(absoluteFilePath, route.method, rootDir);
|
|
3972
|
-
const input = await
|
|
4213
|
+
const input = await resolveInputFromUrl(route.method, request, url);
|
|
3973
4214
|
const inputType = getInputTypeForMethod(route.method);
|
|
3974
4215
|
const schemaPath = getRuntimeSchemaPath(route.filePath, dist, rootDir);
|
|
3975
4216
|
if (isDevOnDemandEnabled()) {
|
|
@@ -4001,33 +4242,33 @@ async function sendSuccessResponse(response, res) {
|
|
|
4001
4242
|
await sendNodeResponse(response, res);
|
|
4002
4243
|
}
|
|
4003
4244
|
async function sendErrorResponse(err, meta, res, onError, ctx) {
|
|
4004
|
-
await sendNodeResponse(mergeMeta(buildErrorResponse(err, ctx
|
|
4005
|
-
if (onError) {
|
|
4245
|
+
await sendNodeResponse(mergeMeta(buildErrorResponse(err, ctx?.config), meta), res);
|
|
4246
|
+
if (onError && ctx) {
|
|
4006
4247
|
try {
|
|
4007
4248
|
await onError(err, ctx);
|
|
4008
4249
|
} catch {
|
|
4009
4250
|
}
|
|
4010
4251
|
}
|
|
4011
4252
|
}
|
|
4012
|
-
async function handleRequest(routes, rootDir, dist, req, res,
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
routes,
|
|
4016
|
-
method,
|
|
4017
|
-
urlPath,
|
|
4018
|
-
ctx,
|
|
4019
|
-
request,
|
|
4020
|
-
rootDir,
|
|
4021
|
-
dist,
|
|
4022
|
-
globalMiddlewares,
|
|
4023
|
-
globalInjectors
|
|
4024
|
-
});
|
|
4025
|
-
const outerMiddlewares = [];
|
|
4026
|
-
if (configMiddlewares.length > 0) outerMiddlewares.push(...configMiddlewares);
|
|
4027
|
-
if (globalMiddlewares && globalMiddlewares.length > 0) {
|
|
4028
|
-
outerMiddlewares.push(...globalMiddlewares);
|
|
4029
|
-
}
|
|
4253
|
+
async function handleRequest(routes, rootDir, dist, req, res, outerMiddlewares, onError, config, globalInjectors, bodyLimit, trustedProxy) {
|
|
4254
|
+
let meta = { headers: {}, setCookies: [] };
|
|
4255
|
+
let ctx;
|
|
4030
4256
|
try {
|
|
4257
|
+
const prepared = prepareRequest(req, config, bodyLimit, trustedProxy);
|
|
4258
|
+
ctx = prepared.ctx;
|
|
4259
|
+
meta = prepared.meta;
|
|
4260
|
+
const { request, url, method, urlPath } = prepared;
|
|
4261
|
+
const routePipeline = createRoutePipeline({
|
|
4262
|
+
routes,
|
|
4263
|
+
method,
|
|
4264
|
+
urlPath,
|
|
4265
|
+
url,
|
|
4266
|
+
ctx,
|
|
4267
|
+
request,
|
|
4268
|
+
rootDir,
|
|
4269
|
+
dist,
|
|
4270
|
+
globalInjectors
|
|
4271
|
+
});
|
|
4031
4272
|
const response = outerMiddlewares.length > 0 ? await compose(outerMiddlewares, ctx, routePipeline) : await routePipeline();
|
|
4032
4273
|
await sendSuccessResponse(response, res);
|
|
4033
4274
|
} catch (err) {
|
|
@@ -4065,7 +4306,7 @@ function applyPluginWrappers(server, handlerWrappers, upgradeWrappers) {
|
|
|
4065
4306
|
|
|
4066
4307
|
// src/cli/generateRoutes.ts
|
|
4067
4308
|
import fs13 from "fs";
|
|
4068
|
-
import
|
|
4309
|
+
import path13 from "path";
|
|
4069
4310
|
async function hydrateRoutes(manifest) {
|
|
4070
4311
|
const hydrateRoute = (serialized) => ({
|
|
4071
4312
|
method: serialized.method,
|
|
@@ -4090,7 +4331,7 @@ async function hydrateRoutes(manifest) {
|
|
|
4090
4331
|
}
|
|
4091
4332
|
|
|
4092
4333
|
// src/cli/generateAgentArtifacts.ts
|
|
4093
|
-
import
|
|
4334
|
+
import path14 from "path";
|
|
4094
4335
|
import fs14 from "fs/promises";
|
|
4095
4336
|
|
|
4096
4337
|
// src/ast/extractAgentMetadata.ts
|
|
@@ -4305,7 +4546,7 @@ function serializeAgents(agents, dist = "dist") {
|
|
|
4305
4546
|
}));
|
|
4306
4547
|
}
|
|
4307
4548
|
async function writeAgentsModule(manifest, outputPath) {
|
|
4308
|
-
const dir =
|
|
4549
|
+
const dir = path14.dirname(outputPath);
|
|
4309
4550
|
await fs14.mkdir(dir, { recursive: true });
|
|
4310
4551
|
const content = `// \u81EA\u52A8\u751F\u6210,\u8BF7\u52FF\u624B\u52A8\u7F16\u8F91(faapi build/dev \u4EA7\u7269)
|
|
4311
4552
|
export const agents = ${JSON.stringify(manifest, null, 2)};
|
|
@@ -4327,9 +4568,10 @@ function hydrateAgents(manifest) {
|
|
|
4327
4568
|
}
|
|
4328
4569
|
async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
4329
4570
|
const metadata = [];
|
|
4571
|
+
const programByFile = createPrograms(agents.map((m) => path14.resolve(rootDir, m.filePath)));
|
|
4330
4572
|
for (const manifest of agents) {
|
|
4331
|
-
const absPath =
|
|
4332
|
-
const program =
|
|
4573
|
+
const absPath = path14.resolve(rootDir, manifest.filePath);
|
|
4574
|
+
const program = programByFile.get(absPath);
|
|
4333
4575
|
const result = extractAgentMetadata(program, absPath, {
|
|
4334
4576
|
name: manifest.name,
|
|
4335
4577
|
filePath: manifest.filePath,
|
|
@@ -4340,7 +4582,7 @@ async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
|
4340
4582
|
}
|
|
4341
4583
|
}
|
|
4342
4584
|
const serialized = serializeAgents(metadata, dist);
|
|
4343
|
-
const agentsPath =
|
|
4585
|
+
const agentsPath = path14.resolve(rootDir, dist, AGENTS_FILE);
|
|
4344
4586
|
await writeAgentsModule(serialized, agentsPath);
|
|
4345
4587
|
return metadata;
|
|
4346
4588
|
}
|
|
@@ -4412,7 +4654,7 @@ var TOOLS_FILE2 = "faapi-tools.js";
|
|
|
4412
4654
|
var AGENTS_FILE2 = "faapi-agents.js";
|
|
4413
4655
|
var PATTERNS = ["src/api/**/*.ts"];
|
|
4414
4656
|
async function loadAndHydrateTools(rootDir, dist) {
|
|
4415
|
-
const toolsPath =
|
|
4657
|
+
const toolsPath = path15.resolve(rootDir, dist, TOOLS_FILE2);
|
|
4416
4658
|
if (!fs15.existsSync(toolsPath)) {
|
|
4417
4659
|
return [];
|
|
4418
4660
|
}
|
|
@@ -4422,7 +4664,7 @@ async function loadAndHydrateTools(rootDir, dist) {
|
|
|
4422
4664
|
return hydrated;
|
|
4423
4665
|
}
|
|
4424
4666
|
async function loadAndHydrateAgents(rootDir, dist) {
|
|
4425
|
-
const agentsPath =
|
|
4667
|
+
const agentsPath = path15.resolve(rootDir, dist, AGENTS_FILE2);
|
|
4426
4668
|
if (!fs15.existsSync(agentsPath)) {
|
|
4427
4669
|
return [];
|
|
4428
4670
|
}
|
|
@@ -4462,6 +4704,7 @@ var FAAPI_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
4462
4704
|
"bodyLimit",
|
|
4463
4705
|
"logger",
|
|
4464
4706
|
"http2",
|
|
4707
|
+
"trustedProxy",
|
|
4465
4708
|
"response"
|
|
4466
4709
|
]);
|
|
4467
4710
|
function isFaapiConfigKey(key) {
|
|
@@ -4470,7 +4713,7 @@ function isFaapiConfigKey(key) {
|
|
|
4470
4713
|
async function createAppBase(options) {
|
|
4471
4714
|
const rootDir = options?.rootDir ?? process.cwd();
|
|
4472
4715
|
const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
|
|
4473
|
-
const routesPath =
|
|
4716
|
+
const routesPath = path15.resolve(rootDir, dist, ROUTES_FILE);
|
|
4474
4717
|
if (!fs15.existsSync(routesPath)) {
|
|
4475
4718
|
throw new Error(
|
|
4476
4719
|
`[faapi] ${dist}/${ROUTES_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
|
|
@@ -4506,7 +4749,8 @@ async function createAppBase(options) {
|
|
|
4506
4749
|
helmet: config?.helmet,
|
|
4507
4750
|
logger: config?.logger,
|
|
4508
4751
|
bodyLimit: config?.bodyLimit,
|
|
4509
|
-
http2: config?.http2
|
|
4752
|
+
http2: config?.http2,
|
|
4753
|
+
trustedProxy: config?.trustedProxy
|
|
4510
4754
|
});
|
|
4511
4755
|
const { handlerWrappers, upgradeWrappers } = await loadPlugins(config?.plugins, {
|
|
4512
4756
|
rootDir,
|
|
@@ -4692,7 +4936,7 @@ async function createAppBase(options) {
|
|
|
4692
4936
|
|
|
4693
4937
|
// src/router/scanRoutes.ts
|
|
4694
4938
|
import fg2 from "fast-glob";
|
|
4695
|
-
import
|
|
4939
|
+
import path16 from "path";
|
|
4696
4940
|
import fs16 from "fs";
|
|
4697
4941
|
|
|
4698
4942
|
// src/router/constants.ts
|
|
@@ -4700,9 +4944,9 @@ var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
|
4700
4944
|
var HTTP_METHOD_SET = new Set(HTTP_METHODS);
|
|
4701
4945
|
|
|
4702
4946
|
// src/utils/normalizePath.ts
|
|
4703
|
-
function normalizePath(
|
|
4704
|
-
if (!
|
|
4705
|
-
let result =
|
|
4947
|
+
function normalizePath(path19) {
|
|
4948
|
+
if (!path19) return "";
|
|
4949
|
+
let result = path19.replace(/\\/g, "/");
|
|
4706
4950
|
result = result.replace(/\/+/g, "/");
|
|
4707
4951
|
result = result.replace(/\/+$/, "");
|
|
4708
4952
|
if (result && !result.startsWith("/")) {
|
|
@@ -4763,26 +5007,26 @@ function extractExportsFromSource(source) {
|
|
|
4763
5007
|
return names;
|
|
4764
5008
|
}
|
|
4765
5009
|
function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
|
|
4766
|
-
const routeDir =
|
|
4767
|
-
const resolvedRoot =
|
|
5010
|
+
const routeDir = path16.dirname(routeFilePath);
|
|
5011
|
+
const resolvedRoot = path16.resolve(rootDir);
|
|
4768
5012
|
const paths = [];
|
|
4769
|
-
let currentDir =
|
|
5013
|
+
let currentDir = path16.resolve(rootDir, routeDir);
|
|
4770
5014
|
while (true) {
|
|
4771
5015
|
if (dist) {
|
|
4772
|
-
const mwTsPath =
|
|
4773
|
-
const mwJsPath =
|
|
4774
|
-
const absTsPath =
|
|
4775
|
-
const absJsPath =
|
|
5016
|
+
const mwTsPath = path16.join(currentDir, "middlewares.ts");
|
|
5017
|
+
const mwJsPath = path16.join(currentDir, "middlewares.js");
|
|
5018
|
+
const absTsPath = path16.resolve(rootDir, mwTsPath);
|
|
5019
|
+
const absJsPath = path16.resolve(rootDir, mwJsPath);
|
|
4776
5020
|
const absMwPath = fs16.existsSync(absTsPath) ? absTsPath : fs16.existsSync(absJsPath) ? absJsPath : null;
|
|
4777
5021
|
if (absMwPath) {
|
|
4778
|
-
const relMwPath =
|
|
4779
|
-
const prodAbsPath =
|
|
5022
|
+
const relMwPath = path16.relative(rootDir, absMwPath);
|
|
5023
|
+
const prodAbsPath = path16.resolve(rootDir, toProdFilePath3(relMwPath, dist));
|
|
4780
5024
|
paths.push(prodAbsPath);
|
|
4781
5025
|
}
|
|
4782
5026
|
} else {
|
|
4783
5027
|
for (const ext of [".ts", ".js"]) {
|
|
4784
|
-
const mwPath =
|
|
4785
|
-
const absMwPath =
|
|
5028
|
+
const mwPath = path16.join(currentDir, `middlewares${ext}`);
|
|
5029
|
+
const absMwPath = path16.resolve(rootDir, mwPath);
|
|
4786
5030
|
if (fs16.existsSync(absMwPath)) {
|
|
4787
5031
|
paths.push(absMwPath);
|
|
4788
5032
|
break;
|
|
@@ -4790,7 +5034,7 @@ function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
|
|
|
4790
5034
|
}
|
|
4791
5035
|
}
|
|
4792
5036
|
if (currentDir === resolvedRoot) break;
|
|
4793
|
-
const parentDir =
|
|
5037
|
+
const parentDir = path16.dirname(currentDir);
|
|
4794
5038
|
if (parentDir === currentDir) break;
|
|
4795
5039
|
currentDir = parentDir;
|
|
4796
5040
|
}
|
|
@@ -4817,7 +5061,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
4817
5061
|
const normalizedFile = file.replace(/\\/g, "/");
|
|
4818
5062
|
const fileName = normalizedFile.split("/").pop();
|
|
4819
5063
|
if (fileName === "handler.ts" || fileName === "handler.js") {
|
|
4820
|
-
const absPath =
|
|
5064
|
+
const absPath = path16.resolve(rootDir, normalizedFile);
|
|
4821
5065
|
const urlPath = filePathToUrlPath(normalizedFile);
|
|
4822
5066
|
const paramNames = extractParamNames(urlPath);
|
|
4823
5067
|
const isDynamic = paramNames.length > 0;
|
|
@@ -4866,7 +5110,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
4866
5110
|
|
|
4867
5111
|
// src/tools/scanTools.ts
|
|
4868
5112
|
import fg3 from "fast-glob";
|
|
4869
|
-
import
|
|
5113
|
+
import path17 from "path";
|
|
4870
5114
|
import fs17 from "fs";
|
|
4871
5115
|
var TOOL_PATTERNS = ["src/tools/**/*.ts"];
|
|
4872
5116
|
var TOOL_EXPORT_RE = new RegExp(
|
|
@@ -4917,7 +5161,7 @@ async function scanTools(rootDir, patterns) {
|
|
|
4917
5161
|
if (fileName !== "handler.ts" && fileName !== "handler.js") {
|
|
4918
5162
|
continue;
|
|
4919
5163
|
}
|
|
4920
|
-
const absPath =
|
|
5164
|
+
const absPath = path17.resolve(rootDir, normalizedFile);
|
|
4921
5165
|
const source = await fs17.promises.readFile(absPath, "utf8").catch(() => "");
|
|
4922
5166
|
const exportNames = extractToolExportsFromSource(source);
|
|
4923
5167
|
const namespace = filePathToToolNamespace(normalizedFile);
|
|
@@ -4942,7 +5186,7 @@ async function scanTools(rootDir, patterns) {
|
|
|
4942
5186
|
|
|
4943
5187
|
// src/agents/scanAgents.ts
|
|
4944
5188
|
import fg4 from "fast-glob";
|
|
4945
|
-
import
|
|
5189
|
+
import path18 from "path";
|
|
4946
5190
|
import fs18 from "fs";
|
|
4947
5191
|
var DEFAULT_AGENT_PATTERNS = ["src/agents/*/handler.ts"];
|
|
4948
5192
|
var RUN_EXPORT_RE = /export\s+(?:async\s+)?(?:function\s+|const\s+)run\b/;
|
|
@@ -4975,7 +5219,7 @@ async function scanAgents(rootDir, patterns) {
|
|
|
4975
5219
|
if (fileName !== "handler.ts" && fileName !== "handler.js") {
|
|
4976
5220
|
continue;
|
|
4977
5221
|
}
|
|
4978
|
-
const absPath =
|
|
5222
|
+
const absPath = path18.resolve(rootDir, normalizedFile);
|
|
4979
5223
|
const source = await fs18.promises.readFile(absPath, "utf8").catch(() => "");
|
|
4980
5224
|
const { hasRun } = detectAgentExports(source);
|
|
4981
5225
|
const name = extractAgentNameFromPath(normalizedFile);
|
|
@@ -5056,6 +5300,7 @@ export {
|
|
|
5056
5300
|
createDevApp,
|
|
5057
5301
|
createProdApp,
|
|
5058
5302
|
createProgram,
|
|
5303
|
+
createPrograms,
|
|
5059
5304
|
extractTypeInfo,
|
|
5060
5305
|
getAgent,
|
|
5061
5306
|
getAgentEntry,
|
|
@@ -5063,6 +5308,7 @@ export {
|
|
|
5063
5308
|
getInputTypeForMethod,
|
|
5064
5309
|
getSkill,
|
|
5065
5310
|
getTool,
|
|
5311
|
+
getToolSchemaPath,
|
|
5066
5312
|
helmet,
|
|
5067
5313
|
hydrateSkillRegistry,
|
|
5068
5314
|
invalidateProgramCache,
|