@faapi/faapi 6.1.0 → 6.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 +1272 -520
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +116 -3
- package/dist/index.js +946 -255
- package/dist/index.js.map +1 -1
- package/dist/{routeTypes-Bm--uTbm.d.ts → routeTypes-CCveqSnY.d.ts} +214 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +48 -2
- package/dist/testing.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1120,8 +1120,10 @@ var init_resolveInjection = __esm({
|
|
|
1120
1120
|
fields: "fields",
|
|
1121
1121
|
agent: "agent",
|
|
1122
1122
|
// Phase 2.3
|
|
1123
|
-
agents: "agents"
|
|
1123
|
+
agents: "agents",
|
|
1124
1124
|
// Phase 2.3
|
|
1125
|
+
tasks: "tasks"
|
|
1126
|
+
// 任务子系统:TaskClient(入队/查询)
|
|
1125
1127
|
};
|
|
1126
1128
|
injectionCache = /* @__PURE__ */ new WeakMap();
|
|
1127
1129
|
}
|
|
@@ -1231,13 +1233,13 @@ var init_collectRouteSchemaSources = __esm({
|
|
|
1231
1233
|
});
|
|
1232
1234
|
|
|
1233
1235
|
// src/utils/atomicWrite.ts
|
|
1234
|
-
import
|
|
1235
|
-
import
|
|
1236
|
+
import path9 from "path";
|
|
1237
|
+
import fs7 from "fs";
|
|
1236
1238
|
async function atomicWriteFile(outputPath, content) {
|
|
1237
|
-
await
|
|
1239
|
+
await fs7.promises.mkdir(path9.dirname(outputPath), { recursive: true });
|
|
1238
1240
|
const tmp = `${outputPath}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
1239
|
-
await
|
|
1240
|
-
await
|
|
1241
|
+
await fs7.promises.writeFile(tmp, content, "utf-8");
|
|
1242
|
+
await fs7.promises.rename(tmp, outputPath);
|
|
1241
1243
|
}
|
|
1242
1244
|
var init_atomicWrite = __esm({
|
|
1243
1245
|
"src/utils/atomicWrite.ts"() {
|
|
@@ -1584,7 +1586,7 @@ __export(generateSchemaFiles_exports, {
|
|
|
1584
1586
|
getRuntimeSchemaPath: () => getRuntimeSchemaPath,
|
|
1585
1587
|
getSchemaOutputPath: () => getSchemaOutputPath
|
|
1586
1588
|
});
|
|
1587
|
-
import
|
|
1589
|
+
import path10 from "path";
|
|
1588
1590
|
function getSchemaOutputPath(sourceFile, dist, rootDir) {
|
|
1589
1591
|
let rel = sourceFile.replace(/\\/g, "/");
|
|
1590
1592
|
if (rel.startsWith("src/")) {
|
|
@@ -1592,7 +1594,7 @@ function getSchemaOutputPath(sourceFile, dist, rootDir) {
|
|
|
1592
1594
|
}
|
|
1593
1595
|
const idx = rel.lastIndexOf("/");
|
|
1594
1596
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
1595
|
-
return
|
|
1597
|
+
return path10.resolve(rootDir, dist, relDir, "zod.js");
|
|
1596
1598
|
}
|
|
1597
1599
|
function getRuntimeSchemaPath(filePath, dist, rootDir) {
|
|
1598
1600
|
let rel = filePath.replace(/\\/g, "/");
|
|
@@ -1603,7 +1605,7 @@ function getRuntimeSchemaPath(filePath, dist, rootDir) {
|
|
|
1603
1605
|
}
|
|
1604
1606
|
const idx = rel.lastIndexOf("/");
|
|
1605
1607
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
1606
|
-
return
|
|
1608
|
+
return path10.resolve(rootDir, dist, relDir, "zod.js");
|
|
1607
1609
|
}
|
|
1608
1610
|
function getHelpersImportPath(relDir) {
|
|
1609
1611
|
if (!relDir) return `./${HELPERS_FILENAME}`;
|
|
@@ -1662,7 +1664,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
1662
1664
|
}
|
|
1663
1665
|
const fileEntries = [];
|
|
1664
1666
|
for (const [filePath, fileSources] of sourcesByFile) {
|
|
1665
|
-
const relFile =
|
|
1667
|
+
const relFile = path10.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
1666
1668
|
const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
|
|
1667
1669
|
let relForDir = relFile;
|
|
1668
1670
|
if (relForDir.startsWith("src/")) {
|
|
@@ -1681,7 +1683,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
1681
1683
|
}
|
|
1682
1684
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
1683
1685
|
if (usesCoerceHelpers(allSourceCode)) {
|
|
1684
|
-
const helpersPath =
|
|
1686
|
+
const helpersPath = path10.resolve(rootDir, dist, HELPERS_FILENAME);
|
|
1685
1687
|
await writeSchemaFile(helpersPath, generateHelpersFileSource());
|
|
1686
1688
|
}
|
|
1687
1689
|
await Promise.all(
|
|
@@ -1707,6 +1709,29 @@ init_resolveTypeNode();
|
|
|
1707
1709
|
init_inputType();
|
|
1708
1710
|
init_collectRouteSchemaSources();
|
|
1709
1711
|
|
|
1712
|
+
// src/task/taskRegistry.ts
|
|
1713
|
+
function createTaskRegistry() {
|
|
1714
|
+
let registry = /* @__PURE__ */ new Map();
|
|
1715
|
+
return {
|
|
1716
|
+
hydrate(tasks) {
|
|
1717
|
+
const next = /* @__PURE__ */ new Map();
|
|
1718
|
+
for (const task of tasks) {
|
|
1719
|
+
next.set(task.name, task);
|
|
1720
|
+
}
|
|
1721
|
+
registry = next;
|
|
1722
|
+
},
|
|
1723
|
+
get(name) {
|
|
1724
|
+
return registry.get(name);
|
|
1725
|
+
},
|
|
1726
|
+
list() {
|
|
1727
|
+
return Array.from(registry.values());
|
|
1728
|
+
},
|
|
1729
|
+
clear() {
|
|
1730
|
+
registry = /* @__PURE__ */ new Map();
|
|
1731
|
+
}
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1710
1735
|
// src/injection/registries.ts
|
|
1711
1736
|
function createToolRegistry() {
|
|
1712
1737
|
let registry = /* @__PURE__ */ new Map();
|
|
@@ -1829,15 +1854,483 @@ function createAgentHandleStore() {
|
|
|
1829
1854
|
}
|
|
1830
1855
|
};
|
|
1831
1856
|
}
|
|
1857
|
+
function createTaskHandleStore() {
|
|
1858
|
+
let currentFactory = null;
|
|
1859
|
+
return {
|
|
1860
|
+
register(factory) {
|
|
1861
|
+
currentFactory = factory;
|
|
1862
|
+
},
|
|
1863
|
+
get(ctx) {
|
|
1864
|
+
if (currentFactory === null) return void 0;
|
|
1865
|
+
return currentFactory(ctx);
|
|
1866
|
+
},
|
|
1867
|
+
clear() {
|
|
1868
|
+
currentFactory = null;
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1832
1872
|
function createAppRegistries() {
|
|
1833
1873
|
const tool = createToolRegistry();
|
|
1834
1874
|
const agent = createAgentRegistry(tool);
|
|
1835
1875
|
const skill = createSkillRegistry();
|
|
1876
|
+
const task = createTaskRegistry();
|
|
1836
1877
|
const agentHandle = createAgentHandleStore();
|
|
1837
|
-
|
|
1878
|
+
const taskHandle = createTaskHandleStore();
|
|
1879
|
+
return { tool, agent, skill, task, agentHandle, taskHandle };
|
|
1838
1880
|
}
|
|
1839
1881
|
var defaultRegistries = createAppRegistries();
|
|
1840
1882
|
|
|
1883
|
+
// src/task/taskQueue.ts
|
|
1884
|
+
import path3 from "path";
|
|
1885
|
+
|
|
1886
|
+
// src/errors/FaapiError.ts
|
|
1887
|
+
var FaapiError = class extends Error {
|
|
1888
|
+
constructor(code, message, statusCode) {
|
|
1889
|
+
super(message);
|
|
1890
|
+
this.code = code;
|
|
1891
|
+
this.statusCode = statusCode;
|
|
1892
|
+
this.name = "FaapiError";
|
|
1893
|
+
}
|
|
1894
|
+
code;
|
|
1895
|
+
statusCode;
|
|
1896
|
+
};
|
|
1897
|
+
|
|
1898
|
+
// src/errors/httpErrors.ts
|
|
1899
|
+
function deriveStatusCode(issues) {
|
|
1900
|
+
const has400 = issues.some((i) => i.code === "INVALID_FORMAT" || i.code === "MISSING_FIELD");
|
|
1901
|
+
return has400 ? 400 : 422;
|
|
1902
|
+
}
|
|
1903
|
+
var ValidationError = class extends FaapiError {
|
|
1904
|
+
constructor(message, issues) {
|
|
1905
|
+
super("VALIDATION_ERROR", message, deriveStatusCode(issues));
|
|
1906
|
+
this.issues = issues;
|
|
1907
|
+
this.name = "ValidationError";
|
|
1908
|
+
}
|
|
1909
|
+
issues;
|
|
1910
|
+
};
|
|
1911
|
+
var RouteNotFoundError = class extends FaapiError {
|
|
1912
|
+
constructor(path28) {
|
|
1913
|
+
super("ROUTE_NOT_FOUND", `Route not found: ${path28}`, 404);
|
|
1914
|
+
this.name = "RouteNotFoundError";
|
|
1915
|
+
}
|
|
1916
|
+
};
|
|
1917
|
+
var MethodNotAllowedError = class extends FaapiError {
|
|
1918
|
+
constructor(method, path28, allowedMethods) {
|
|
1919
|
+
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path28}`, 405);
|
|
1920
|
+
this.allowedMethods = allowedMethods;
|
|
1921
|
+
this.name = "MethodNotAllowedError";
|
|
1922
|
+
}
|
|
1923
|
+
allowedMethods;
|
|
1924
|
+
};
|
|
1925
|
+
var InternalError = class extends FaapiError {
|
|
1926
|
+
constructor(message) {
|
|
1927
|
+
super("INTERNAL_ERROR", message, 500);
|
|
1928
|
+
this.name = "InternalError";
|
|
1929
|
+
}
|
|
1930
|
+
};
|
|
1931
|
+
var ModuleLoadError = class extends FaapiError {
|
|
1932
|
+
constructor(filePath, reason) {
|
|
1933
|
+
super("MODULE_LOAD_ERROR", `Failed to load module ${filePath}: ${reason}`, 500);
|
|
1934
|
+
this.name = "ModuleLoadError";
|
|
1935
|
+
}
|
|
1936
|
+
};
|
|
1937
|
+
var PayloadTooLargeError = class extends FaapiError {
|
|
1938
|
+
constructor(maxSize) {
|
|
1939
|
+
super("PAYLOAD_TOO_LARGE", `Request body exceeds size limit of ${maxSize} bytes`, 413);
|
|
1940
|
+
this.name = "PayloadTooLargeError";
|
|
1941
|
+
}
|
|
1942
|
+
};
|
|
1943
|
+
|
|
1944
|
+
// src/task/memoryDriver.ts
|
|
1945
|
+
import { randomUUID } from "crypto";
|
|
1946
|
+
var RETRY_BASE_DELAY_MS = 500;
|
|
1947
|
+
var RETRY_MAX_DELAY_MS = 3e4;
|
|
1948
|
+
function createMemoryDriver() {
|
|
1949
|
+
const jobs = /* @__PURE__ */ new Map();
|
|
1950
|
+
const pendingByTask = /* @__PURE__ */ new Map();
|
|
1951
|
+
const runningCount = /* @__PURE__ */ new Map();
|
|
1952
|
+
const workers = /* @__PURE__ */ new Map();
|
|
1953
|
+
let stopped = false;
|
|
1954
|
+
function pump() {
|
|
1955
|
+
if (stopped) return;
|
|
1956
|
+
for (const [name, worker] of workers) {
|
|
1957
|
+
const queue = pendingByTask.get(name);
|
|
1958
|
+
if (!queue || queue.length === 0) continue;
|
|
1959
|
+
let running = runningCount.get(name) ?? 0;
|
|
1960
|
+
while (running < worker.concurrency && queue.length > 0) {
|
|
1961
|
+
const head = jobs.get(queue[0]);
|
|
1962
|
+
if (!head) {
|
|
1963
|
+
queue.shift();
|
|
1964
|
+
continue;
|
|
1965
|
+
}
|
|
1966
|
+
if (head.runAt > Date.now()) break;
|
|
1967
|
+
queue.shift();
|
|
1968
|
+
running += 1;
|
|
1969
|
+
runningCount.set(name, running);
|
|
1970
|
+
void dispatch(name, worker, head);
|
|
1971
|
+
}
|
|
1972
|
+
if (running === 0) runningCount.delete(name);
|
|
1973
|
+
else runningCount.set(name, running);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
async function dispatch(name, worker, job) {
|
|
1977
|
+
job.attempts += 1;
|
|
1978
|
+
const driverJob = {
|
|
1979
|
+
id: job.id,
|
|
1980
|
+
name,
|
|
1981
|
+
payload: job.payload,
|
|
1982
|
+
attempt: job.attempts,
|
|
1983
|
+
signal: job.controller.signal
|
|
1984
|
+
};
|
|
1985
|
+
try {
|
|
1986
|
+
await worker.process(driverJob);
|
|
1987
|
+
} catch (err) {
|
|
1988
|
+
if (job.attempts <= job.retries) {
|
|
1989
|
+
const delay = Math.min(RETRY_BASE_DELAY_MS * 2 ** (job.attempts - 1), RETRY_MAX_DELAY_MS);
|
|
1990
|
+
job.runAt = Date.now() + delay;
|
|
1991
|
+
job.timer = setTimeout(() => {
|
|
1992
|
+
job.timer = void 0;
|
|
1993
|
+
pendingByTask.get(name)?.push(job.id);
|
|
1994
|
+
pump();
|
|
1995
|
+
}, delay);
|
|
1996
|
+
}
|
|
1997
|
+
void err;
|
|
1998
|
+
} finally {
|
|
1999
|
+
const running = (runningCount.get(name) ?? 1) - 1;
|
|
2000
|
+
if (running <= 0) runningCount.delete(name);
|
|
2001
|
+
else runningCount.set(name, running);
|
|
2002
|
+
pump();
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
return {
|
|
2006
|
+
async enqueue(name, payload, opts) {
|
|
2007
|
+
if (stopped) {
|
|
2008
|
+
throw new Error("[faapi] Task queue is stopped and no longer accepts jobs");
|
|
2009
|
+
}
|
|
2010
|
+
const id = randomUUID();
|
|
2011
|
+
const job = {
|
|
2012
|
+
id,
|
|
2013
|
+
payload,
|
|
2014
|
+
retries: opts?.retries ?? 0,
|
|
2015
|
+
runAt: opts?.delayMs ? Date.now() + opts.delayMs : Date.now(),
|
|
2016
|
+
attempts: 0,
|
|
2017
|
+
controller: new AbortController()
|
|
2018
|
+
};
|
|
2019
|
+
jobs.set(id, job);
|
|
2020
|
+
if (job.runAt > Date.now()) {
|
|
2021
|
+
job.timer = setTimeout(() => {
|
|
2022
|
+
job.timer = void 0;
|
|
2023
|
+
pendingByTask.get(name)?.push(id);
|
|
2024
|
+
pump();
|
|
2025
|
+
}, job.runAt - Date.now());
|
|
2026
|
+
} else {
|
|
2027
|
+
let q = pendingByTask.get(name);
|
|
2028
|
+
if (!q) {
|
|
2029
|
+
q = [];
|
|
2030
|
+
pendingByTask.set(name, q);
|
|
2031
|
+
}
|
|
2032
|
+
q.push(id);
|
|
2033
|
+
pump();
|
|
2034
|
+
}
|
|
2035
|
+
return id;
|
|
2036
|
+
},
|
|
2037
|
+
startWorker(name, opts) {
|
|
2038
|
+
workers.set(name, opts);
|
|
2039
|
+
pump();
|
|
2040
|
+
},
|
|
2041
|
+
async stop(timeoutMs = 1e4) {
|
|
2042
|
+
stopped = true;
|
|
2043
|
+
for (const job of jobs.values()) {
|
|
2044
|
+
if (job.timer) {
|
|
2045
|
+
clearTimeout(job.timer);
|
|
2046
|
+
job.timer = void 0;
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
const start = Date.now();
|
|
2050
|
+
while (Date.now() - start < timeoutMs) {
|
|
2051
|
+
const total = Array.from(runningCount.values()).reduce((sum, n) => sum + n, 0);
|
|
2052
|
+
if (total === 0) return;
|
|
2053
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
2054
|
+
}
|
|
2055
|
+
for (const job of jobs.values()) {
|
|
2056
|
+
job.controller.abort();
|
|
2057
|
+
}
|
|
2058
|
+
},
|
|
2059
|
+
async stopWorkers() {
|
|
2060
|
+
workers.clear();
|
|
2061
|
+
}
|
|
2062
|
+
};
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
// src/task/taskQueue.ts
|
|
2066
|
+
function createTaskQueue(deps) {
|
|
2067
|
+
const { registry, rootDir } = deps;
|
|
2068
|
+
const driver = deps.driver ?? createMemoryDriver();
|
|
2069
|
+
const records = /* @__PURE__ */ new Map();
|
|
2070
|
+
const moduleCache2 = /* @__PURE__ */ new Map();
|
|
2071
|
+
const schemaCache = /* @__PURE__ */ new Map();
|
|
2072
|
+
let started = false;
|
|
2073
|
+
let stopped = false;
|
|
2074
|
+
const loadTaskModule = deps.loadTaskModule ?? (async (filePath) => await import(filePath));
|
|
2075
|
+
const loadPayloadSchema = deps.loadPayloadSchema ?? (async (filePath) => {
|
|
2076
|
+
const zodPath = path3.join(path3.dirname(filePath), "zod.js");
|
|
2077
|
+
try {
|
|
2078
|
+
const mod = await import(zodPath);
|
|
2079
|
+
const schemaKey = Object.keys(mod).find((k) => k.endsWith("Schema"));
|
|
2080
|
+
return schemaKey ? mod[schemaKey] : void 0;
|
|
2081
|
+
} catch {
|
|
2082
|
+
return void 0;
|
|
2083
|
+
}
|
|
2084
|
+
});
|
|
2085
|
+
function assertKnownTask(name) {
|
|
2086
|
+
const meta = registry.get(name);
|
|
2087
|
+
if (!meta) {
|
|
2088
|
+
const known = registry.list().map((t) => t.name).join(", ") || "(none)";
|
|
2089
|
+
throw new Error(`[faapi] Unknown task "${name}". Registered tasks: ${known}`);
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
async function validatePayload(name, payload) {
|
|
2093
|
+
if (!schemaCache.has(name)) {
|
|
2094
|
+
const meta = registry.get(name);
|
|
2095
|
+
schemaCache.set(
|
|
2096
|
+
name,
|
|
2097
|
+
await loadPayloadSchema(path3.resolve(rootDir, meta.filePath)).catch(() => void 0)
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2100
|
+
const schema = schemaCache.get(name);
|
|
2101
|
+
if (!schema || typeof schema.safeParse !== "function") {
|
|
2102
|
+
return payload;
|
|
2103
|
+
}
|
|
2104
|
+
const result = schema.safeParse(payload);
|
|
2105
|
+
if (!result.success) {
|
|
2106
|
+
throw new ValidationError(
|
|
2107
|
+
`Task payload validation failed for "${name}": ${JSON.stringify(result.error)}`,
|
|
2108
|
+
[]
|
|
2109
|
+
);
|
|
2110
|
+
}
|
|
2111
|
+
return result.data;
|
|
2112
|
+
}
|
|
2113
|
+
async function runJob(job) {
|
|
2114
|
+
const meta = registry.get(job.name);
|
|
2115
|
+
if (!meta) throw new Error(`[faapi] Unknown task "${job.name}" at worker dispatch`);
|
|
2116
|
+
const record = records.get(job.id) ?? {
|
|
2117
|
+
id: job.id,
|
|
2118
|
+
name: job.name,
|
|
2119
|
+
payload: job.payload,
|
|
2120
|
+
status: "pending",
|
|
2121
|
+
attempts: 0,
|
|
2122
|
+
createdAt: Date.now()
|
|
2123
|
+
};
|
|
2124
|
+
record.attempts = job.attempt;
|
|
2125
|
+
record.status = "running";
|
|
2126
|
+
record.error = void 0;
|
|
2127
|
+
records.set(job.id, record);
|
|
2128
|
+
try {
|
|
2129
|
+
let mod = moduleCache2.get(job.name);
|
|
2130
|
+
if (!mod) {
|
|
2131
|
+
mod = await loadTaskModule(path3.resolve(rootDir, meta.filePath));
|
|
2132
|
+
moduleCache2.set(job.name, mod);
|
|
2133
|
+
}
|
|
2134
|
+
if (typeof mod.run !== "function") {
|
|
2135
|
+
throw new Error(`Task "${job.name}" module has no run export`);
|
|
2136
|
+
}
|
|
2137
|
+
const taskCtx = {
|
|
2138
|
+
signal: job.signal,
|
|
2139
|
+
config: deps.config,
|
|
2140
|
+
job: { id: job.id, name: job.name, attempt: job.attempt }
|
|
2141
|
+
};
|
|
2142
|
+
const result = await mod.run(job.payload, taskCtx);
|
|
2143
|
+
record.status = "done";
|
|
2144
|
+
record.result = result;
|
|
2145
|
+
return result;
|
|
2146
|
+
} catch (err) {
|
|
2147
|
+
record.status = "failed";
|
|
2148
|
+
record.error = err instanceof Error ? err.message : String(err);
|
|
2149
|
+
throw err;
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
async function startWorkers() {
|
|
2153
|
+
for (const meta of registry.list()) {
|
|
2154
|
+
await driver.startWorker(meta.name, {
|
|
2155
|
+
concurrency: meta.concurrency ?? 1,
|
|
2156
|
+
process: runJob
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
const queue = {
|
|
2161
|
+
async enqueue(name, payload = {}, opts) {
|
|
2162
|
+
if (stopped) {
|
|
2163
|
+
throw new Error("[faapi] Task queue is stopped and no longer accepts jobs");
|
|
2164
|
+
}
|
|
2165
|
+
assertKnownTask(name);
|
|
2166
|
+
const data = await validatePayload(name, payload);
|
|
2167
|
+
const meta = registry.get(name);
|
|
2168
|
+
const id = await driver.enqueue(name, data, {
|
|
2169
|
+
delayMs: opts?.delayMs,
|
|
2170
|
+
retries: meta.retries ?? 0
|
|
2171
|
+
});
|
|
2172
|
+
if (!records.has(id)) {
|
|
2173
|
+
records.set(id, {
|
|
2174
|
+
id,
|
|
2175
|
+
name,
|
|
2176
|
+
payload: data,
|
|
2177
|
+
status: "pending",
|
|
2178
|
+
attempts: 0,
|
|
2179
|
+
createdAt: Date.now(),
|
|
2180
|
+
...opts?.delayMs ? { runAt: Date.now() + opts.delayMs } : {}
|
|
2181
|
+
});
|
|
2182
|
+
}
|
|
2183
|
+
return { id };
|
|
2184
|
+
},
|
|
2185
|
+
list(name) {
|
|
2186
|
+
const snapshot = [];
|
|
2187
|
+
for (const job of records.values()) {
|
|
2188
|
+
if (name !== void 0 && job.name !== name) continue;
|
|
2189
|
+
snapshot.push({ ...job });
|
|
2190
|
+
}
|
|
2191
|
+
return snapshot;
|
|
2192
|
+
},
|
|
2193
|
+
async start() {
|
|
2194
|
+
if (stopped) {
|
|
2195
|
+
throw new Error("[faapi] Task queue is stopped and cannot be restarted");
|
|
2196
|
+
}
|
|
2197
|
+
if (started) return;
|
|
2198
|
+
started = true;
|
|
2199
|
+
await startWorkers();
|
|
2200
|
+
},
|
|
2201
|
+
async stop(timeoutMs = 1e4) {
|
|
2202
|
+
stopped = true;
|
|
2203
|
+
await driver.stop(timeoutMs);
|
|
2204
|
+
},
|
|
2205
|
+
async reload() {
|
|
2206
|
+
await driver.stopWorkers?.();
|
|
2207
|
+
await startWorkers();
|
|
2208
|
+
},
|
|
2209
|
+
invalidateModules() {
|
|
2210
|
+
moduleCache2.clear();
|
|
2211
|
+
},
|
|
2212
|
+
invalidateSchemas() {
|
|
2213
|
+
schemaCache.clear();
|
|
2214
|
+
}
|
|
2215
|
+
};
|
|
2216
|
+
return queue;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
// src/task/loadTaskDriver.ts
|
|
2220
|
+
async function loadTaskDriver(driver, driverOptions) {
|
|
2221
|
+
if (driver === void 0 || driver === "memory") {
|
|
2222
|
+
return createMemoryDriver();
|
|
2223
|
+
}
|
|
2224
|
+
if (typeof driver === "object") {
|
|
2225
|
+
return driver;
|
|
2226
|
+
}
|
|
2227
|
+
if (driver !== "pgboss" && driver !== "bullmq") {
|
|
2228
|
+
throw new Error(
|
|
2229
|
+
`[faapi] Unknown task driver "${driver}". Supported: 'memory' (default), 'pgboss', 'bullmq', or a TaskDriver instance.`
|
|
2230
|
+
);
|
|
2231
|
+
}
|
|
2232
|
+
const specifier = `@faapi/task-${driver}`;
|
|
2233
|
+
let mod;
|
|
2234
|
+
try {
|
|
2235
|
+
mod = await import(
|
|
2236
|
+
/* @vite-ignore */
|
|
2237
|
+
specifier
|
|
2238
|
+
);
|
|
2239
|
+
} catch {
|
|
2240
|
+
throw new Error(
|
|
2241
|
+
`[faapi] Task driver "${driver}" requires package "${specifier}" to be installed in your project.`
|
|
2242
|
+
);
|
|
2243
|
+
}
|
|
2244
|
+
const factoryName = driver === "pgboss" ? "createPgBossDriver" : "createBullMQDriver";
|
|
2245
|
+
const factory = mod[factoryName];
|
|
2246
|
+
if (typeof factory !== "function") {
|
|
2247
|
+
throw new Error(
|
|
2248
|
+
`[faapi] Package "${specifier}" does not export ${factoryName}() \u2014 check the package version.`
|
|
2249
|
+
);
|
|
2250
|
+
}
|
|
2251
|
+
return factory(driverOptions);
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
// src/task/cronScheduler.ts
|
|
2255
|
+
import { Cron } from "croner";
|
|
2256
|
+
function createCronScheduler(registry, enqueue) {
|
|
2257
|
+
let schedules = [];
|
|
2258
|
+
return {
|
|
2259
|
+
start() {
|
|
2260
|
+
this.stop();
|
|
2261
|
+
for (const task of registry.list()) {
|
|
2262
|
+
if (!task.cron) continue;
|
|
2263
|
+
schedules.push(
|
|
2264
|
+
new Cron(task.cron, () => {
|
|
2265
|
+
void Promise.resolve().then(() => enqueue(task.name)).catch((err) => {
|
|
2266
|
+
console.error(`[faapi] Cron enqueue failed for task "${task.name}":`, err);
|
|
2267
|
+
});
|
|
2268
|
+
})
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
},
|
|
2272
|
+
stop() {
|
|
2273
|
+
for (const schedule of schedules) {
|
|
2274
|
+
schedule.stop();
|
|
2275
|
+
}
|
|
2276
|
+
schedules = [];
|
|
2277
|
+
}
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
// src/task/scanTasks.ts
|
|
2282
|
+
import fg from "fast-glob";
|
|
2283
|
+
import path4 from "path";
|
|
2284
|
+
import fs2 from "fs";
|
|
2285
|
+
var TASK_PATTERNS = ["src/tasks/**/task.ts"];
|
|
2286
|
+
var TASK_FILENAME = "task.ts";
|
|
2287
|
+
var CRON_RE = /(?:^|\n)\s*cron:\s*['"`]([^'"`\n]+)['"`]/;
|
|
2288
|
+
var CONCURRENCY_RE = /(?:^|\n)\s*concurrency:\s*(\d+)/;
|
|
2289
|
+
var RETRIES_RE = /(?:^|\n)\s*retries:\s*(\d+)/;
|
|
2290
|
+
function filePathToTaskName(filePath) {
|
|
2291
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
2292
|
+
const match = normalized.match(/(?:^|\/)tasks\/(.+)\/task\.ts$/);
|
|
2293
|
+
if (!match) {
|
|
2294
|
+
throw new Error(`[faapi] Invalid task file path: ${filePath}`);
|
|
2295
|
+
}
|
|
2296
|
+
return match[1].split("/").join(".");
|
|
2297
|
+
}
|
|
2298
|
+
async function scanTasks(rootDir, patterns) {
|
|
2299
|
+
const files = await fg(patterns, {
|
|
2300
|
+
cwd: rootDir,
|
|
2301
|
+
onlyFiles: true,
|
|
2302
|
+
absolute: false
|
|
2303
|
+
});
|
|
2304
|
+
const tasks = [];
|
|
2305
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2306
|
+
for (const file of files) {
|
|
2307
|
+
const normalizedFile = file.replace(/\\/g, "/");
|
|
2308
|
+
const fileName = path4.posix.basename(normalizedFile);
|
|
2309
|
+
if (fileName !== TASK_FILENAME) {
|
|
2310
|
+
continue;
|
|
2311
|
+
}
|
|
2312
|
+
const absPath = path4.resolve(rootDir, normalizedFile);
|
|
2313
|
+
const source = await fs2.promises.readFile(absPath, "utf8").catch(() => "");
|
|
2314
|
+
const name = filePathToTaskName(normalizedFile);
|
|
2315
|
+
const prevFile = seen.get(name);
|
|
2316
|
+
if (prevFile) {
|
|
2317
|
+
throw new Error(
|
|
2318
|
+
`Task conflict: "${name}" declared in both ${prevFile} and ${normalizedFile}`
|
|
2319
|
+
);
|
|
2320
|
+
}
|
|
2321
|
+
seen.set(name, normalizedFile);
|
|
2322
|
+
const manifest = { name, filePath: normalizedFile };
|
|
2323
|
+
const cron = CRON_RE.exec(source)?.[1];
|
|
2324
|
+
const concurrency = CONCURRENCY_RE.exec(source)?.[1];
|
|
2325
|
+
const retries = RETRIES_RE.exec(source)?.[1];
|
|
2326
|
+
if (cron !== void 0) manifest.cron = cron;
|
|
2327
|
+
if (concurrency !== void 0) manifest.concurrency = Number(concurrency);
|
|
2328
|
+
if (retries !== void 0) manifest.retries = Number(retries);
|
|
2329
|
+
tasks.push(manifest);
|
|
2330
|
+
}
|
|
2331
|
+
return tasks;
|
|
2332
|
+
}
|
|
2333
|
+
|
|
1841
2334
|
// src/injection/agentRegistry.ts
|
|
1842
2335
|
function getAgent(name) {
|
|
1843
2336
|
return defaultRegistries.agent.getAgent(name);
|
|
@@ -1878,7 +2371,7 @@ function listSkills() {
|
|
|
1878
2371
|
}
|
|
1879
2372
|
|
|
1880
2373
|
// src/loader/loadAgentModule.ts
|
|
1881
|
-
import
|
|
2374
|
+
import fs10 from "fs";
|
|
1882
2375
|
|
|
1883
2376
|
// src/loader/resolveExports.ts
|
|
1884
2377
|
function resolveExport(module, exportName) {
|
|
@@ -1924,18 +2417,18 @@ async function importWithCacheBust(filePath, bustViteCache = false) {
|
|
|
1924
2417
|
}
|
|
1925
2418
|
|
|
1926
2419
|
// src/cli/compileOnDemand.ts
|
|
1927
|
-
import
|
|
1928
|
-
import
|
|
2420
|
+
import path12 from "path";
|
|
2421
|
+
import fs9 from "fs";
|
|
1929
2422
|
|
|
1930
2423
|
// src/cli/compileSourceFiles.ts
|
|
1931
|
-
import
|
|
1932
|
-
import
|
|
1933
|
-
import
|
|
2424
|
+
import path8 from "path";
|
|
2425
|
+
import fs6 from "fs";
|
|
2426
|
+
import fg2 from "fast-glob";
|
|
1934
2427
|
|
|
1935
2428
|
// src/cli/aliasPlugin.ts
|
|
1936
2429
|
import ts7 from "typescript";
|
|
1937
|
-
import
|
|
1938
|
-
import
|
|
2430
|
+
import path7 from "path";
|
|
2431
|
+
import fs5 from "fs";
|
|
1939
2432
|
|
|
1940
2433
|
// src/utils/resolveAlias.ts
|
|
1941
2434
|
function resolveAlias(specifier, config) {
|
|
@@ -1961,8 +2454,8 @@ function resolveAlias(specifier, config) {
|
|
|
1961
2454
|
}
|
|
1962
2455
|
|
|
1963
2456
|
// src/utils/prodPaths.ts
|
|
1964
|
-
import
|
|
1965
|
-
import
|
|
2457
|
+
import path5 from "path";
|
|
2458
|
+
import fs3 from "fs";
|
|
1966
2459
|
var APP_DIR = "src";
|
|
1967
2460
|
var ROUTE_PATTERNS = ["src/api/**/*.ts"];
|
|
1968
2461
|
function toProdFilePath(filePath, dist) {
|
|
@@ -1981,27 +2474,27 @@ function toProdExtension(filePath) {
|
|
|
1981
2474
|
}
|
|
1982
2475
|
function toRealPath(p) {
|
|
1983
2476
|
try {
|
|
1984
|
-
return
|
|
2477
|
+
return fs3.realpathSync(p);
|
|
1985
2478
|
} catch {
|
|
1986
2479
|
return p;
|
|
1987
2480
|
}
|
|
1988
2481
|
}
|
|
1989
2482
|
function isInsideDir(filePath, dir) {
|
|
1990
|
-
const rel =
|
|
1991
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
2483
|
+
const rel = path5.relative(dir, filePath);
|
|
2484
|
+
return rel !== "" && !rel.startsWith("..") && !path5.isAbsolute(rel);
|
|
1992
2485
|
}
|
|
1993
2486
|
|
|
1994
2487
|
// src/utils/readTsconfig.ts
|
|
1995
2488
|
import ts6 from "typescript";
|
|
1996
|
-
import
|
|
1997
|
-
import
|
|
2489
|
+
import path6 from "path";
|
|
2490
|
+
import fs4 from "fs";
|
|
1998
2491
|
var tsconfigCache = /* @__PURE__ */ new Map();
|
|
1999
2492
|
function readTsconfig(rootDir) {
|
|
2000
|
-
const tsconfigPath =
|
|
2001
|
-
if (!
|
|
2493
|
+
const tsconfigPath = path6.resolve(rootDir, "tsconfig.json");
|
|
2494
|
+
if (!fs4.existsSync(tsconfigPath)) return null;
|
|
2002
2495
|
let mtimeMs;
|
|
2003
2496
|
try {
|
|
2004
|
-
mtimeMs =
|
|
2497
|
+
mtimeMs = fs4.statSync(tsconfigPath).mtimeMs;
|
|
2005
2498
|
} catch {
|
|
2006
2499
|
return null;
|
|
2007
2500
|
}
|
|
@@ -2017,7 +2510,7 @@ function readTsconfig(rootDir) {
|
|
|
2017
2510
|
const config = rawPaths ? (() => {
|
|
2018
2511
|
const paths = {};
|
|
2019
2512
|
for (const [pattern, targets] of Object.entries(rawPaths)) {
|
|
2020
|
-
paths[pattern] = targets.map((t) =>
|
|
2513
|
+
paths[pattern] = targets.map((t) => path6.resolve(baseUrl, t));
|
|
2021
2514
|
}
|
|
2022
2515
|
return { baseUrl, paths };
|
|
2023
2516
|
})() : null;
|
|
@@ -2027,26 +2520,26 @@ function readTsconfig(rootDir) {
|
|
|
2027
2520
|
|
|
2028
2521
|
// src/cli/aliasPlugin.ts
|
|
2029
2522
|
function toProdImportPath(sourceFile, importer) {
|
|
2030
|
-
const importerDir =
|
|
2031
|
-
let rel =
|
|
2032
|
-
rel = rel.split(
|
|
2523
|
+
const importerDir = path7.dirname(importer);
|
|
2524
|
+
let rel = path7.relative(importerDir, sourceFile);
|
|
2525
|
+
rel = rel.split(path7.sep).join("/");
|
|
2033
2526
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
2034
2527
|
return toProdExtension(rel);
|
|
2035
2528
|
}
|
|
2036
2529
|
function toStrippedProdImportPath(sourceFile, rootDir) {
|
|
2037
|
-
const appDirAbs = toRealPath(
|
|
2530
|
+
const appDirAbs = toRealPath(path7.resolve(rootDir, APP_DIR));
|
|
2038
2531
|
const sourceReal = toRealPath(sourceFile);
|
|
2039
|
-
let rel =
|
|
2040
|
-
rel = rel.split(
|
|
2532
|
+
let rel = path7.relative(appDirAbs, sourceReal);
|
|
2533
|
+
rel = rel.split(path7.sep).join("/");
|
|
2041
2534
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
2042
2535
|
return toProdExtension(rel);
|
|
2043
2536
|
}
|
|
2044
2537
|
function toProdImportFromImporter(importer, rootDir, relFromDist) {
|
|
2045
|
-
const importerRel =
|
|
2046
|
-
const importerProdDir =
|
|
2538
|
+
const importerRel = path7.relative(toRealPath(path7.resolve(rootDir)), toRealPath(importer)).split(path7.sep).join("/");
|
|
2539
|
+
const importerProdDir = path7.posix.dirname(toProdExtension(importerRel));
|
|
2047
2540
|
if (importerProdDir === ".") return relFromDist;
|
|
2048
2541
|
const target = relFromDist.replace(/^\.\//, "");
|
|
2049
|
-
let rel =
|
|
2542
|
+
let rel = path7.posix.relative(importerProdDir, target);
|
|
2050
2543
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
2051
2544
|
return rel;
|
|
2052
2545
|
}
|
|
@@ -2061,41 +2554,41 @@ var INDEX_EXTS = [
|
|
|
2061
2554
|
"/index.cjs"
|
|
2062
2555
|
];
|
|
2063
2556
|
function resolveRelativeSpecifier(importer, specifier) {
|
|
2064
|
-
const importerDir =
|
|
2065
|
-
const base =
|
|
2557
|
+
const importerDir = path7.dirname(importer);
|
|
2558
|
+
const base = path7.resolve(importerDir, specifier);
|
|
2066
2559
|
if (PROD_EXTS.some((ext) => specifier.endsWith(ext))) {
|
|
2067
|
-
if (
|
|
2560
|
+
if (fs5.existsSync(base)) return base;
|
|
2068
2561
|
if (base.endsWith(".js")) {
|
|
2069
2562
|
for (const ext of [".ts", ".tsx", ".jsx"]) {
|
|
2070
2563
|
const file = base.slice(0, -3) + ext;
|
|
2071
|
-
if (
|
|
2564
|
+
if (fs5.existsSync(file)) return file;
|
|
2072
2565
|
}
|
|
2073
2566
|
}
|
|
2074
2567
|
return null;
|
|
2075
2568
|
}
|
|
2076
2569
|
if (/\.(ts|tsx|jsx)$/.test(specifier)) {
|
|
2077
|
-
return
|
|
2570
|
+
return fs5.existsSync(base) ? base : null;
|
|
2078
2571
|
}
|
|
2079
2572
|
for (const ext of SOURCE_EXTS) {
|
|
2080
2573
|
const file = base + ext;
|
|
2081
|
-
if (
|
|
2574
|
+
if (fs5.existsSync(file)) return file;
|
|
2082
2575
|
}
|
|
2083
2576
|
for (const indexExt of INDEX_EXTS) {
|
|
2084
2577
|
const file = base + indexExt;
|
|
2085
|
-
if (
|
|
2578
|
+
if (fs5.existsSync(file)) return file;
|
|
2086
2579
|
}
|
|
2087
2580
|
return null;
|
|
2088
2581
|
}
|
|
2089
2582
|
function createAliasPlugin(config, options) {
|
|
2090
|
-
const appDirAbs = options?.rootDir ? toRealPath(
|
|
2583
|
+
const appDirAbs = options?.rootDir ? toRealPath(path7.resolve(options.rootDir, APP_DIR)) : null;
|
|
2091
2584
|
const probeCandidateFile = (candidate) => {
|
|
2092
2585
|
for (const ext of SOURCE_EXTS) {
|
|
2093
2586
|
const file = candidate + ext;
|
|
2094
|
-
if (
|
|
2587
|
+
if (fs5.existsSync(file)) return file;
|
|
2095
2588
|
}
|
|
2096
2589
|
for (const indexExt of INDEX_EXTS) {
|
|
2097
2590
|
const file = candidate + indexExt;
|
|
2098
|
-
if (
|
|
2591
|
+
if (fs5.existsSync(file)) return file;
|
|
2099
2592
|
}
|
|
2100
2593
|
return null;
|
|
2101
2594
|
};
|
|
@@ -2105,7 +2598,7 @@ function createAliasPlugin(config, options) {
|
|
|
2105
2598
|
build.onLoad({ filter: /\.(ts|tsx|js|jsx|mjs|cjs)$/ }, (args) => {
|
|
2106
2599
|
let source;
|
|
2107
2600
|
try {
|
|
2108
|
-
source =
|
|
2601
|
+
source = fs5.readFileSync(args.path, "utf8");
|
|
2109
2602
|
} catch {
|
|
2110
2603
|
return void 0;
|
|
2111
2604
|
}
|
|
@@ -2221,7 +2714,7 @@ function buildAliasPlugins(rootDir) {
|
|
|
2221
2714
|
// src/cli/compileSourceFiles.ts
|
|
2222
2715
|
async function compileSourceFiles(options) {
|
|
2223
2716
|
const { rootDir, dist, files, logLevel = "silent", production, atomicWrite } = options;
|
|
2224
|
-
const entryPoints = files ?? await
|
|
2717
|
+
const entryPoints = files ?? await fg2([`${APP_DIR}/**/*.ts`], {
|
|
2225
2718
|
cwd: rootDir,
|
|
2226
2719
|
onlyFiles: true,
|
|
2227
2720
|
absolute: true,
|
|
@@ -2230,11 +2723,11 @@ async function compileSourceFiles(options) {
|
|
|
2230
2723
|
if (entryPoints.length === 0) {
|
|
2231
2724
|
return { compiledFiles: [] };
|
|
2232
2725
|
}
|
|
2233
|
-
const absDist =
|
|
2234
|
-
await
|
|
2726
|
+
const absDist = path8.resolve(rootDir, dist);
|
|
2727
|
+
await fs6.promises.mkdir(absDist, { recursive: true });
|
|
2235
2728
|
const plugins = buildAliasPlugins(rootDir);
|
|
2236
2729
|
const esbuild = await import("esbuild");
|
|
2237
|
-
const outbase =
|
|
2730
|
+
const outbase = path8.resolve(rootDir, APP_DIR);
|
|
2238
2731
|
const result = await esbuild.build({
|
|
2239
2732
|
entryPoints,
|
|
2240
2733
|
outdir: absDist,
|
|
@@ -2254,10 +2747,10 @@ async function compileSourceFiles(options) {
|
|
|
2254
2747
|
if (atomicWrite && result.outputFiles) {
|
|
2255
2748
|
await Promise.all(
|
|
2256
2749
|
result.outputFiles.map(async (file) => {
|
|
2257
|
-
await
|
|
2750
|
+
await fs6.promises.mkdir(path8.dirname(file.path), { recursive: true });
|
|
2258
2751
|
const tmp = `${file.path}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
2259
|
-
await
|
|
2260
|
-
await
|
|
2752
|
+
await fs6.promises.writeFile(tmp, file.contents);
|
|
2753
|
+
await fs6.promises.rename(tmp, file.path);
|
|
2261
2754
|
})
|
|
2262
2755
|
);
|
|
2263
2756
|
}
|
|
@@ -2274,8 +2767,8 @@ init_generateSchemaFiles();
|
|
|
2274
2767
|
init_generateSchemaFiles();
|
|
2275
2768
|
|
|
2276
2769
|
// src/cli/collectImports.ts
|
|
2277
|
-
import
|
|
2278
|
-
import
|
|
2770
|
+
import path11 from "path";
|
|
2771
|
+
import fs8 from "fs";
|
|
2279
2772
|
var SPEC_RE = /(\bfrom\s*|import\s*\(\s*)(['"])([^'"]+)\2/g;
|
|
2280
2773
|
function extractImportSpecifiers(source) {
|
|
2281
2774
|
const specifiers = [];
|
|
@@ -2287,10 +2780,10 @@ function extractImportSpecifiers(source) {
|
|
|
2287
2780
|
return specifiers;
|
|
2288
2781
|
}
|
|
2289
2782
|
function resolveSpecifierFromDir(dir, specifier) {
|
|
2290
|
-
return resolveRelativeSpecifier(
|
|
2783
|
+
return resolveRelativeSpecifier(path11.join(dir, "__faapi_probe__.ts"), specifier);
|
|
2291
2784
|
}
|
|
2292
2785
|
async function collectRelativeImports(entryFiles, rootDir) {
|
|
2293
|
-
const appDirAbs = toRealPath(
|
|
2786
|
+
const appDirAbs = toRealPath(path11.resolve(rootDir, "src"));
|
|
2294
2787
|
const tsconfig = readTsconfig(rootDir);
|
|
2295
2788
|
const visited = /* @__PURE__ */ new Set();
|
|
2296
2789
|
const insideFiles = /* @__PURE__ */ new Set();
|
|
@@ -2300,7 +2793,7 @@ async function collectRelativeImports(entryFiles, rootDir) {
|
|
|
2300
2793
|
visited.add(filePath);
|
|
2301
2794
|
let source;
|
|
2302
2795
|
try {
|
|
2303
|
-
source = await
|
|
2796
|
+
source = await fs8.promises.readFile(filePath, "utf8");
|
|
2304
2797
|
} catch {
|
|
2305
2798
|
return;
|
|
2306
2799
|
}
|
|
@@ -2322,7 +2815,7 @@ async function collectRelativeImports(entryFiles, rootDir) {
|
|
|
2322
2815
|
resolved = null;
|
|
2323
2816
|
}
|
|
2324
2817
|
if (!resolved) continue;
|
|
2325
|
-
if (!isInsideDir(toRealPath(resolved), toRealPath(
|
|
2818
|
+
if (!isInsideDir(toRealPath(resolved), toRealPath(path11.resolve(rootDir)))) continue;
|
|
2326
2819
|
if (isInsideDir(toRealPath(resolved), appDirAbs)) {
|
|
2327
2820
|
insideFiles.add(resolved);
|
|
2328
2821
|
} else {
|
|
@@ -2343,8 +2836,8 @@ async function collectRelativeImports(entryFiles, rootDir) {
|
|
|
2343
2836
|
// src/cli/compileOnDemand.ts
|
|
2344
2837
|
function isProductFresh(sourceAbsPath, productAbsPath) {
|
|
2345
2838
|
try {
|
|
2346
|
-
const srcStat =
|
|
2347
|
-
const prodStat =
|
|
2839
|
+
const srcStat = fs9.statSync(sourceAbsPath);
|
|
2840
|
+
const prodStat = fs9.statSync(productAbsPath);
|
|
2348
2841
|
return prodStat.mtimeMs >= srcStat.mtimeMs;
|
|
2349
2842
|
} catch {
|
|
2350
2843
|
return false;
|
|
@@ -2376,7 +2869,7 @@ async function ensureCompiled(sourceAbsPath, rootDir, dist) {
|
|
|
2376
2869
|
if (state.compiledFiles.has(sourceAbsPath)) {
|
|
2377
2870
|
return false;
|
|
2378
2871
|
}
|
|
2379
|
-
if (!
|
|
2872
|
+
if (!fs9.existsSync(sourceAbsPath)) {
|
|
2380
2873
|
return false;
|
|
2381
2874
|
}
|
|
2382
2875
|
const productPath = prodSourcePathToProductPath(sourceAbsPath, rootDir, dist);
|
|
@@ -2426,11 +2919,11 @@ async function ensureMiddlewaresCompiled(middlewarePaths, rootDir) {
|
|
|
2426
2919
|
}
|
|
2427
2920
|
}
|
|
2428
2921
|
function prodSourcePathToProductPath(sourceAbsPath, rootDir, dist) {
|
|
2429
|
-
const rel =
|
|
2922
|
+
const rel = path12.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
|
|
2430
2923
|
if (!rel.startsWith("src/")) return null;
|
|
2431
2924
|
const relWithoutSrc = rel.slice(4);
|
|
2432
2925
|
const jsRel = relWithoutSrc.replace(/\.ts$/, ".js");
|
|
2433
|
-
return
|
|
2926
|
+
return path12.resolve(rootDir, dist, jsRel);
|
|
2434
2927
|
}
|
|
2435
2928
|
function clearGeneratedSchemas() {
|
|
2436
2929
|
state.generatedSchemas.clear();
|
|
@@ -2446,9 +2939,9 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
|
|
|
2446
2939
|
if (state.generatedSchemas.has(schemaPath)) {
|
|
2447
2940
|
return false;
|
|
2448
2941
|
}
|
|
2449
|
-
const prodAbsPath =
|
|
2942
|
+
const prodAbsPath = path12.resolve(rootDir, routeFilePath);
|
|
2450
2943
|
const sourceAbsPath = prodPathToSourcePath(prodAbsPath, rootDir, dist);
|
|
2451
|
-
if (!
|
|
2944
|
+
if (!fs9.existsSync(sourceAbsPath)) {
|
|
2452
2945
|
return false;
|
|
2453
2946
|
}
|
|
2454
2947
|
if (isProductFresh(sourceAbsPath, schemaPath)) {
|
|
@@ -2459,7 +2952,7 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
|
|
|
2459
2952
|
if (fileRoutes.length === 0) {
|
|
2460
2953
|
return false;
|
|
2461
2954
|
}
|
|
2462
|
-
const sourceRelPath =
|
|
2955
|
+
const sourceRelPath = path12.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
|
|
2463
2956
|
const sourceRoutes = fileRoutes.map((r) => ({ ...r, filePath: sourceRelPath }));
|
|
2464
2957
|
const generatePromise = (async () => {
|
|
2465
2958
|
await generateSchemaFiles(sourceRoutes, rootDir, dist);
|
|
@@ -2480,7 +2973,7 @@ async function deleteSchemaFiles(routes, rootDir, dist) {
|
|
|
2480
2973
|
if (deleted.has(schemaPath)) continue;
|
|
2481
2974
|
deleted.add(schemaPath);
|
|
2482
2975
|
try {
|
|
2483
|
-
await
|
|
2976
|
+
await fs9.promises.unlink(schemaPath);
|
|
2484
2977
|
} catch {
|
|
2485
2978
|
}
|
|
2486
2979
|
}
|
|
@@ -2489,19 +2982,19 @@ var sourcePathCache = /* @__PURE__ */ new Map();
|
|
|
2489
2982
|
function prodPathToSourcePath(prodAbsPath, rootDir, dist) {
|
|
2490
2983
|
const cached = sourcePathCache.get(prodAbsPath);
|
|
2491
2984
|
if (cached) return cached;
|
|
2492
|
-
const rel =
|
|
2985
|
+
const rel = path12.relative(rootDir, prodAbsPath).replace(/\\/g, "/");
|
|
2493
2986
|
let relWithoutDist = rel;
|
|
2494
2987
|
if (relWithoutDist.startsWith(`${dist}/`)) {
|
|
2495
2988
|
relWithoutDist = relWithoutDist.slice(dist.length + 1);
|
|
2496
2989
|
}
|
|
2497
2990
|
const srcRel = `src/${relWithoutDist}`;
|
|
2498
2991
|
const tsRel = srcRel.replace(/\.js$/, ".ts");
|
|
2499
|
-
const tsAbs =
|
|
2992
|
+
const tsAbs = path12.resolve(rootDir, tsRel);
|
|
2500
2993
|
let result;
|
|
2501
|
-
if (
|
|
2994
|
+
if (fs9.existsSync(tsAbs)) {
|
|
2502
2995
|
result = tsAbs;
|
|
2503
2996
|
} else {
|
|
2504
|
-
result =
|
|
2997
|
+
result = path12.resolve(rootDir, srcRel);
|
|
2505
2998
|
}
|
|
2506
2999
|
sourcePathCache.set(prodAbsPath, result);
|
|
2507
3000
|
return result;
|
|
@@ -2519,7 +3012,7 @@ async function loadAgentModule(filePath, hasRun, rootDir) {
|
|
|
2519
3012
|
const dist = getDevDist();
|
|
2520
3013
|
if (dist) {
|
|
2521
3014
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
2522
|
-
if (sourcePath &&
|
|
3015
|
+
if (sourcePath && fs10.existsSync(sourcePath)) {
|
|
2523
3016
|
try {
|
|
2524
3017
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
2525
3018
|
} catch (compileErr) {
|
|
@@ -2552,13 +3045,13 @@ async function loadAgentModule(filePath, hasRun, rootDir) {
|
|
|
2552
3045
|
}
|
|
2553
3046
|
|
|
2554
3047
|
// src/loader/loadToolModule.ts
|
|
2555
|
-
import
|
|
3048
|
+
import fs11 from "fs";
|
|
2556
3049
|
async function loadToolModule(filePath, functionName, rootDir) {
|
|
2557
3050
|
if (isDevOnDemandEnabled() && rootDir) {
|
|
2558
3051
|
const dist = getDevDist();
|
|
2559
3052
|
if (dist) {
|
|
2560
3053
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
2561
|
-
if (sourcePath &&
|
|
3054
|
+
if (sourcePath && fs11.existsSync(sourcePath)) {
|
|
2562
3055
|
try {
|
|
2563
3056
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
2564
3057
|
} catch (compileErr) {
|
|
@@ -2590,7 +3083,7 @@ async function loadToolModule(filePath, functionName, rootDir) {
|
|
|
2590
3083
|
import { existsSync as existsSync2 } from "fs";
|
|
2591
3084
|
|
|
2592
3085
|
// src/cli/generateToolArtifacts.ts
|
|
2593
|
-
import
|
|
3086
|
+
import path13 from "path";
|
|
2594
3087
|
import { existsSync } from "fs";
|
|
2595
3088
|
|
|
2596
3089
|
// src/ast/extractToolMetadata.ts
|
|
@@ -2714,7 +3207,7 @@ function collectToolSchemaSources(tools, rootDir) {
|
|
|
2714
3207
|
const toolsByFile = /* @__PURE__ */ new Map();
|
|
2715
3208
|
for (const tool of tools) {
|
|
2716
3209
|
if (!tool.inputTypeName) continue;
|
|
2717
|
-
const absPath =
|
|
3210
|
+
const absPath = path13.resolve(rootDir, tool.filePath);
|
|
2718
3211
|
let list = toolsByFile.get(absPath);
|
|
2719
3212
|
if (!list) {
|
|
2720
3213
|
list = [];
|
|
@@ -2774,15 +3267,15 @@ function generateToolSchemaFileSource(sources, resolveType, helpersImportPath) {
|
|
|
2774
3267
|
}
|
|
2775
3268
|
async function maybeGenerateHelpers(allSourceCode, distDir) {
|
|
2776
3269
|
if (!usesCoerceHelpers(allSourceCode)) return;
|
|
2777
|
-
const helpersPath =
|
|
3270
|
+
const helpersPath = path13.resolve(distDir, HELPERS_FILENAME);
|
|
2778
3271
|
if (existsSync(helpersPath)) return;
|
|
2779
3272
|
await atomicWriteFile(helpersPath, generateHelpersFileSource());
|
|
2780
3273
|
}
|
|
2781
3274
|
async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
2782
3275
|
const metadata = [];
|
|
2783
|
-
const programByFile = createPrograms(tools.map((m) =>
|
|
3276
|
+
const programByFile = createPrograms(tools.map((m) => path13.resolve(rootDir, m.filePath)));
|
|
2784
3277
|
for (const manifest of tools) {
|
|
2785
|
-
const absPath =
|
|
3278
|
+
const absPath = path13.resolve(rootDir, manifest.filePath);
|
|
2786
3279
|
const program = programByFile.get(absPath);
|
|
2787
3280
|
const result = extractToolMetadata(program, absPath, manifest.functionName, {
|
|
2788
3281
|
name: manifest.name,
|
|
@@ -2793,7 +3286,7 @@ async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
|
2793
3286
|
}
|
|
2794
3287
|
}
|
|
2795
3288
|
const serialized = serializeTools(metadata, dist);
|
|
2796
|
-
const toolsPath =
|
|
3289
|
+
const toolsPath = path13.resolve(rootDir, dist, TOOLS_FILE);
|
|
2797
3290
|
await writeToolsModule(serialized, toolsPath);
|
|
2798
3291
|
if (options?.skipSchema) {
|
|
2799
3292
|
return metadata;
|
|
@@ -2816,7 +3309,7 @@ async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
|
2816
3309
|
}
|
|
2817
3310
|
const fileEntries = [];
|
|
2818
3311
|
for (const [filePath, fileSources] of sourcesByFile) {
|
|
2819
|
-
const relFile =
|
|
3312
|
+
const relFile = path13.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
2820
3313
|
const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
|
|
2821
3314
|
const resolver = resolversByFile.get(filePath);
|
|
2822
3315
|
let relForDir = relFile;
|
|
@@ -2834,7 +3327,7 @@ async function generateToolArtifacts(tools, rootDir, dist, options) {
|
|
|
2834
3327
|
fileEntries.push({ outputPath, source });
|
|
2835
3328
|
}
|
|
2836
3329
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
2837
|
-
const distDir =
|
|
3330
|
+
const distDir = path13.resolve(rootDir, dist);
|
|
2838
3331
|
await maybeGenerateHelpers(allSourceCode, distDir);
|
|
2839
3332
|
await Promise.all(
|
|
2840
3333
|
fileEntries.map(({ outputPath, source }) => writeToolSchemaFile(outputPath, source))
|
|
@@ -3043,16 +3536,16 @@ function helmet(options = {}) {
|
|
|
3043
3536
|
}
|
|
3044
3537
|
|
|
3045
3538
|
// src/config/loadConfig.ts
|
|
3046
|
-
import
|
|
3047
|
-
import
|
|
3539
|
+
import path14 from "path";
|
|
3540
|
+
import fs12 from "fs";
|
|
3048
3541
|
var CONFIG_PRODUCT_FILE = "faapi-config.js";
|
|
3049
3542
|
async function loadConfig(rootDir, dist) {
|
|
3050
|
-
const configProductPath =
|
|
3051
|
-
if (
|
|
3543
|
+
const configProductPath = path14.resolve(rootDir, dist, CONFIG_PRODUCT_FILE);
|
|
3544
|
+
if (fs12.existsSync(configProductPath)) {
|
|
3052
3545
|
const module = await importWithCacheBust(configProductPath);
|
|
3053
3546
|
return module.default ?? {};
|
|
3054
3547
|
}
|
|
3055
|
-
const hasSourceConfig =
|
|
3548
|
+
const hasSourceConfig = fs12.existsSync(path14.join(rootDir, "faapi.config.ts")) || fs12.existsSync(path14.join(rootDir, "faapi.config.js"));
|
|
3056
3549
|
if (hasSourceConfig) {
|
|
3057
3550
|
throw new Error(
|
|
3058
3551
|
`[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`
|
|
@@ -3062,8 +3555,8 @@ async function loadConfig(rootDir, dist) {
|
|
|
3062
3555
|
}
|
|
3063
3556
|
|
|
3064
3557
|
// src/cli/loadEnv.ts
|
|
3065
|
-
import
|
|
3066
|
-
import
|
|
3558
|
+
import fs13 from "fs";
|
|
3559
|
+
import path15 from "path";
|
|
3067
3560
|
function resolveEnv() {
|
|
3068
3561
|
return process.env.NODE_ENV || "development";
|
|
3069
3562
|
}
|
|
@@ -3130,9 +3623,9 @@ function loadEnv(rootDir) {
|
|
|
3130
3623
|
const files = getEnvFiles(env);
|
|
3131
3624
|
const merged = {};
|
|
3132
3625
|
for (const file of files) {
|
|
3133
|
-
const filePath =
|
|
3134
|
-
if (!
|
|
3135
|
-
const content =
|
|
3626
|
+
const filePath = path15.join(rootDir, file);
|
|
3627
|
+
if (!fs13.existsSync(filePath)) continue;
|
|
3628
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
3136
3629
|
const parsed = parseEnvFile(content, merged);
|
|
3137
3630
|
Object.assign(merged, parsed);
|
|
3138
3631
|
}
|
|
@@ -3143,67 +3636,9 @@ function loadEnv(rootDir) {
|
|
|
3143
3636
|
}
|
|
3144
3637
|
}
|
|
3145
3638
|
|
|
3146
|
-
// src/errors/FaapiError.ts
|
|
3147
|
-
var FaapiError = class extends Error {
|
|
3148
|
-
constructor(code, message, statusCode) {
|
|
3149
|
-
super(message);
|
|
3150
|
-
this.code = code;
|
|
3151
|
-
this.statusCode = statusCode;
|
|
3152
|
-
this.name = "FaapiError";
|
|
3153
|
-
}
|
|
3154
|
-
code;
|
|
3155
|
-
statusCode;
|
|
3156
|
-
};
|
|
3157
|
-
|
|
3158
|
-
// src/errors/httpErrors.ts
|
|
3159
|
-
function deriveStatusCode(issues) {
|
|
3160
|
-
const has400 = issues.some((i) => i.code === "INVALID_FORMAT" || i.code === "MISSING_FIELD");
|
|
3161
|
-
return has400 ? 400 : 422;
|
|
3162
|
-
}
|
|
3163
|
-
var ValidationError = class extends FaapiError {
|
|
3164
|
-
constructor(message, issues) {
|
|
3165
|
-
super("VALIDATION_ERROR", message, deriveStatusCode(issues));
|
|
3166
|
-
this.issues = issues;
|
|
3167
|
-
this.name = "ValidationError";
|
|
3168
|
-
}
|
|
3169
|
-
issues;
|
|
3170
|
-
};
|
|
3171
|
-
var RouteNotFoundError = class extends FaapiError {
|
|
3172
|
-
constructor(path24) {
|
|
3173
|
-
super("ROUTE_NOT_FOUND", `Route not found: ${path24}`, 404);
|
|
3174
|
-
this.name = "RouteNotFoundError";
|
|
3175
|
-
}
|
|
3176
|
-
};
|
|
3177
|
-
var MethodNotAllowedError = class extends FaapiError {
|
|
3178
|
-
constructor(method, path24, allowedMethods) {
|
|
3179
|
-
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path24}`, 405);
|
|
3180
|
-
this.allowedMethods = allowedMethods;
|
|
3181
|
-
this.name = "MethodNotAllowedError";
|
|
3182
|
-
}
|
|
3183
|
-
allowedMethods;
|
|
3184
|
-
};
|
|
3185
|
-
var InternalError = class extends FaapiError {
|
|
3186
|
-
constructor(message) {
|
|
3187
|
-
super("INTERNAL_ERROR", message, 500);
|
|
3188
|
-
this.name = "InternalError";
|
|
3189
|
-
}
|
|
3190
|
-
};
|
|
3191
|
-
var ModuleLoadError = class extends FaapiError {
|
|
3192
|
-
constructor(filePath, reason) {
|
|
3193
|
-
super("MODULE_LOAD_ERROR", `Failed to load module ${filePath}: ${reason}`, 500);
|
|
3194
|
-
this.name = "ModuleLoadError";
|
|
3195
|
-
}
|
|
3196
|
-
};
|
|
3197
|
-
var PayloadTooLargeError = class extends FaapiError {
|
|
3198
|
-
constructor(maxSize) {
|
|
3199
|
-
super("PAYLOAD_TOO_LARGE", `Request body exceeds size limit of ${maxSize} bytes`, 413);
|
|
3200
|
-
this.name = "PayloadTooLargeError";
|
|
3201
|
-
}
|
|
3202
|
-
};
|
|
3203
|
-
|
|
3204
3639
|
// src/cli/createAppCore.ts
|
|
3205
|
-
import
|
|
3206
|
-
import
|
|
3640
|
+
import fs18 from "fs";
|
|
3641
|
+
import path23 from "path";
|
|
3207
3642
|
import { PassThrough, Readable as Readable3 } from "stream";
|
|
3208
3643
|
|
|
3209
3644
|
// src/router/sortRoutes.ts
|
|
@@ -3256,7 +3691,7 @@ import {
|
|
|
3256
3691
|
import { createSecureServer as createHttp2SecureServer } from "http2";
|
|
3257
3692
|
import { readFileSync } from "fs";
|
|
3258
3693
|
import { Readable as Readable2 } from "stream";
|
|
3259
|
-
import
|
|
3694
|
+
import path17 from "path";
|
|
3260
3695
|
|
|
3261
3696
|
// src/router/matchRoute.ts
|
|
3262
3697
|
var httpIndexCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -3298,18 +3733,18 @@ function getWsIndex(routes) {
|
|
|
3298
3733
|
wsIndexCache.set(routes, index);
|
|
3299
3734
|
return index;
|
|
3300
3735
|
}
|
|
3301
|
-
function matchRoute(routes, method,
|
|
3736
|
+
function matchRoute(routes, method, path28) {
|
|
3302
3737
|
const index = getHttpIndex(routes);
|
|
3303
3738
|
const upper = method.toUpperCase();
|
|
3304
|
-
const hit = matchByMethod(index, upper,
|
|
3739
|
+
const hit = matchByMethod(index, upper, path28);
|
|
3305
3740
|
if (hit) return hit;
|
|
3306
3741
|
if (upper === "HEAD") {
|
|
3307
|
-
return matchByMethod(index, "GET",
|
|
3742
|
+
return matchByMethod(index, "GET", path28);
|
|
3308
3743
|
}
|
|
3309
3744
|
return null;
|
|
3310
3745
|
}
|
|
3311
|
-
function matchByMethod(index, method,
|
|
3312
|
-
const staticHit = index.static.get(`${method}|${
|
|
3746
|
+
function matchByMethod(index, method, path28) {
|
|
3747
|
+
const staticHit = index.static.get(`${method}|${path28}`);
|
|
3313
3748
|
if (staticHit) {
|
|
3314
3749
|
return { route: staticHit, params: {} };
|
|
3315
3750
|
}
|
|
@@ -3318,31 +3753,31 @@ function matchByMethod(index, method, path24) {
|
|
|
3318
3753
|
if (route.method !== method) {
|
|
3319
3754
|
continue;
|
|
3320
3755
|
}
|
|
3321
|
-
const params = matchSegments(entry.segments,
|
|
3756
|
+
const params = matchSegments(entry.segments, path28, route.paramNames, route.isCatchAll);
|
|
3322
3757
|
if (params !== null) {
|
|
3323
3758
|
return { route, params };
|
|
3324
3759
|
}
|
|
3325
3760
|
}
|
|
3326
3761
|
return null;
|
|
3327
3762
|
}
|
|
3328
|
-
function matchWsRoute(wsRoutes,
|
|
3763
|
+
function matchWsRoute(wsRoutes, path28) {
|
|
3329
3764
|
const index = getWsIndex(wsRoutes);
|
|
3330
|
-
const staticHit = index.static.get(
|
|
3765
|
+
const staticHit = index.static.get(path28);
|
|
3331
3766
|
if (staticHit) {
|
|
3332
3767
|
return { route: staticHit, params: {} };
|
|
3333
3768
|
}
|
|
3334
3769
|
for (const route of index.dynamics) {
|
|
3335
|
-
const params = matchDynamicPath(route.urlPath,
|
|
3770
|
+
const params = matchDynamicPath(route.urlPath, path28, route.paramNames, route.isCatchAll);
|
|
3336
3771
|
if (params !== null) {
|
|
3337
3772
|
return { route, params };
|
|
3338
3773
|
}
|
|
3339
3774
|
}
|
|
3340
3775
|
return null;
|
|
3341
3776
|
}
|
|
3342
|
-
function findAllowedMethods(routes,
|
|
3777
|
+
function findAllowedMethods(routes, path28) {
|
|
3343
3778
|
const index = getHttpIndex(routes);
|
|
3344
3779
|
const methods = /* @__PURE__ */ new Set();
|
|
3345
|
-
const staticMethods = index.methodsByStaticPath.get(
|
|
3780
|
+
const staticMethods = index.methodsByStaticPath.get(path28);
|
|
3346
3781
|
if (staticMethods) {
|
|
3347
3782
|
for (const method of staticMethods) {
|
|
3348
3783
|
methods.add(method);
|
|
@@ -3351,7 +3786,7 @@ function findAllowedMethods(routes, path24) {
|
|
|
3351
3786
|
for (const entry of index.dynamics) {
|
|
3352
3787
|
const params = matchSegments(
|
|
3353
3788
|
entry.segments,
|
|
3354
|
-
|
|
3789
|
+
path28,
|
|
3355
3790
|
entry.route.paramNames,
|
|
3356
3791
|
entry.route.isCatchAll
|
|
3357
3792
|
);
|
|
@@ -3364,11 +3799,11 @@ function findAllowedMethods(routes, path24) {
|
|
|
3364
3799
|
}
|
|
3365
3800
|
return Array.from(methods);
|
|
3366
3801
|
}
|
|
3367
|
-
function matchDynamicPath(pattern,
|
|
3368
|
-
return matchSegments(pattern.split("/").filter(Boolean),
|
|
3802
|
+
function matchDynamicPath(pattern, path28, paramNames, isCatchAll) {
|
|
3803
|
+
return matchSegments(pattern.split("/").filter(Boolean), path28, paramNames, isCatchAll);
|
|
3369
3804
|
}
|
|
3370
|
-
function matchSegments(patternSegments,
|
|
3371
|
-
const pathSegments =
|
|
3805
|
+
function matchSegments(patternSegments, path28, paramNames, isCatchAll) {
|
|
3806
|
+
const pathSegments = path28.split("/").filter(Boolean);
|
|
3372
3807
|
if (isCatchAll) {
|
|
3373
3808
|
const nonCatchAllCount = patternSegments.length - 1;
|
|
3374
3809
|
if (pathSegments.length <= nonCatchAllCount) {
|
|
@@ -3773,6 +4208,7 @@ function createContextFromUrl(request, url, params, config = {}, ip = "", regist
|
|
|
3773
4208
|
};
|
|
3774
4209
|
if (registries) {
|
|
3775
4210
|
ctx.registries = registries;
|
|
4211
|
+
ctx.tasks = registries.taskHandle.get(ctx);
|
|
3776
4212
|
}
|
|
3777
4213
|
const extend = config?.extendContext;
|
|
3778
4214
|
if (typeof extend === "function") {
|
|
@@ -4062,6 +4498,9 @@ function getBuiltinInjectionValue(type, ctx, body) {
|
|
|
4062
4498
|
// Phase 3.5:调 @faapi/agent 插件注册的工厂获取 AgentHandle
|
|
4063
4499
|
case "agent":
|
|
4064
4500
|
return ctx.registries ? ctx.registries.agentHandle.get(ctx) : getAgentHandle(ctx);
|
|
4501
|
+
// 任务子系统:注入 TaskClient(入队/查询);未注册工厂(无 app 编排)时 undefined
|
|
4502
|
+
case "tasks":
|
|
4503
|
+
return ctx.registries ? ctx.registries.taskHandle.get(ctx) : void 0;
|
|
4065
4504
|
default:
|
|
4066
4505
|
return void 0;
|
|
4067
4506
|
}
|
|
@@ -4256,9 +4695,9 @@ async function validateInput(schemaPath, method, inputType, input) {
|
|
|
4256
4695
|
function mapZodIssues(error) {
|
|
4257
4696
|
return error.issues.map((issue) => {
|
|
4258
4697
|
const code = mapZodCode(issue);
|
|
4259
|
-
const
|
|
4698
|
+
const path28 = issue.path.map(String).join(".") || "";
|
|
4260
4699
|
return {
|
|
4261
|
-
path:
|
|
4700
|
+
path: path28,
|
|
4262
4701
|
code,
|
|
4263
4702
|
expected: issue.expected ?? mapExpectedFromMessage(issue.message),
|
|
4264
4703
|
received: issue.received ?? mapReceivedFromMessage(issue.message),
|
|
@@ -4490,9 +4929,9 @@ function etag(options = {}) {
|
|
|
4490
4929
|
}
|
|
4491
4930
|
|
|
4492
4931
|
// src/server/handleWsUpgrade.ts
|
|
4493
|
-
import
|
|
4932
|
+
import fs14 from "fs";
|
|
4494
4933
|
import { WebSocketServer, WebSocket } from "ws";
|
|
4495
|
-
import
|
|
4934
|
+
import path16 from "path";
|
|
4496
4935
|
|
|
4497
4936
|
// src/server/serverUtils.ts
|
|
4498
4937
|
function nodeHttpToWebHeaders(req) {
|
|
@@ -4627,7 +5066,7 @@ async function loadWsHandler(filePath, ctx, rootDir) {
|
|
|
4627
5066
|
const dist = getDevDist();
|
|
4628
5067
|
if (dist) {
|
|
4629
5068
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
4630
|
-
if (sourcePath &&
|
|
5069
|
+
if (sourcePath && fs14.existsSync(sourcePath)) {
|
|
4631
5070
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
4632
5071
|
}
|
|
4633
5072
|
}
|
|
@@ -4741,7 +5180,7 @@ function attachWebSocket(options) {
|
|
|
4741
5180
|
const finalHandler = async () => {
|
|
4742
5181
|
let handlers;
|
|
4743
5182
|
try {
|
|
4744
|
-
const absoluteFilePath =
|
|
5183
|
+
const absoluteFilePath = path16.resolve(rootDir, route.filePath);
|
|
4745
5184
|
handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
|
|
4746
5185
|
} catch (err) {
|
|
4747
5186
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -4994,7 +5433,7 @@ function getRoutePaths(route, rootDir, dist) {
|
|
|
4994
5433
|
let cached = routePathCache.get(route);
|
|
4995
5434
|
if (!cached) {
|
|
4996
5435
|
cached = {
|
|
4997
|
-
absFilePath:
|
|
5436
|
+
absFilePath: path17.resolve(rootDir, route.filePath),
|
|
4998
5437
|
schemaPath: getRuntimeSchemaPath(route.filePath, dist, rootDir)
|
|
4999
5438
|
};
|
|
5000
5439
|
routePathCache.set(route, cached);
|
|
@@ -5116,8 +5555,8 @@ function applyPluginWrappers(server, handlerWrappers, upgradeWrappers) {
|
|
|
5116
5555
|
}
|
|
5117
5556
|
|
|
5118
5557
|
// src/cli/generateRoutes.ts
|
|
5119
|
-
import
|
|
5120
|
-
import
|
|
5558
|
+
import fs15 from "fs";
|
|
5559
|
+
import path18 from "path";
|
|
5121
5560
|
async function hydrateRoutes(manifest) {
|
|
5122
5561
|
const hydrateRoute = (serialized) => ({
|
|
5123
5562
|
method: serialized.method,
|
|
@@ -5142,7 +5581,7 @@ async function hydrateRoutes(manifest) {
|
|
|
5142
5581
|
}
|
|
5143
5582
|
|
|
5144
5583
|
// src/cli/generateAgentArtifacts.ts
|
|
5145
|
-
import
|
|
5584
|
+
import path19 from "path";
|
|
5146
5585
|
|
|
5147
5586
|
// src/ast/extractAgentMetadata.ts
|
|
5148
5587
|
import ts10 from "typescript";
|
|
@@ -5415,9 +5854,9 @@ function validateAgentList(metadata) {
|
|
|
5415
5854
|
}
|
|
5416
5855
|
async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
5417
5856
|
const metadata = [];
|
|
5418
|
-
const programByFile = createPrograms(agents.map((m) =>
|
|
5857
|
+
const programByFile = createPrograms(agents.map((m) => path19.resolve(rootDir, m.filePath)));
|
|
5419
5858
|
for (const manifest of agents) {
|
|
5420
|
-
const absPath =
|
|
5859
|
+
const absPath = path19.resolve(rootDir, manifest.filePath);
|
|
5421
5860
|
const program = programByFile.get(absPath);
|
|
5422
5861
|
const result = extractAgentMetadata(program, absPath, {
|
|
5423
5862
|
name: manifest.name,
|
|
@@ -5433,24 +5872,181 @@ async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
|
5433
5872
|
}
|
|
5434
5873
|
validateAgentList(metadata);
|
|
5435
5874
|
const serialized = serializeAgents(metadata, dist);
|
|
5436
|
-
const agentsPath =
|
|
5875
|
+
const agentsPath = path19.resolve(rootDir, dist, AGENTS_FILE);
|
|
5437
5876
|
await writeAgentsModule(serialized, agentsPath);
|
|
5438
5877
|
return metadata;
|
|
5439
5878
|
}
|
|
5440
5879
|
|
|
5880
|
+
// src/cli/generateTaskArtifacts.ts
|
|
5881
|
+
import path20 from "path";
|
|
5882
|
+
init_createProgram();
|
|
5883
|
+
init_atomicWrite();
|
|
5884
|
+
init_generateSchemaFiles();
|
|
5885
|
+
init_extractHandlerTypes();
|
|
5886
|
+
init_generateZodSchema();
|
|
5887
|
+
var TASKS_FILE = "faapi-tasks.js";
|
|
5888
|
+
function serializeTasks(tasks, dist = "dist") {
|
|
5889
|
+
return tasks.map((t) => ({
|
|
5890
|
+
name: t.name,
|
|
5891
|
+
filePath: toProdFilePath(t.filePath, dist),
|
|
5892
|
+
...t.cron !== void 0 ? { cron: t.cron } : {},
|
|
5893
|
+
...t.concurrency !== void 0 ? { concurrency: t.concurrency } : {},
|
|
5894
|
+
...t.retries !== void 0 ? { retries: t.retries } : {}
|
|
5895
|
+
}));
|
|
5896
|
+
}
|
|
5897
|
+
async function writeTasksModule(manifest, outputPath) {
|
|
5898
|
+
const content = `// \u81EA\u52A8\u751F\u6210,\u8BF7\u52FF\u624B\u52A8\u7F16\u8F91(faapi build/dev \u4EA7\u7269)
|
|
5899
|
+
export const tasks = ${JSON.stringify(manifest, null, 2)};
|
|
5900
|
+
`;
|
|
5901
|
+
await atomicWriteFile(outputPath, content);
|
|
5902
|
+
}
|
|
5903
|
+
function hydrateTasks(manifest) {
|
|
5904
|
+
return manifest.map((t) => ({
|
|
5905
|
+
name: t.name,
|
|
5906
|
+
filePath: t.filePath,
|
|
5907
|
+
cron: t.cron ?? void 0,
|
|
5908
|
+
concurrency: t.concurrency ?? void 0,
|
|
5909
|
+
retries: t.retries ?? void 0
|
|
5910
|
+
}));
|
|
5911
|
+
}
|
|
5912
|
+
function collectTaskSchemaSources(tasks, rootDir) {
|
|
5913
|
+
const tasksByFile = /* @__PURE__ */ new Map();
|
|
5914
|
+
for (const task of tasks) {
|
|
5915
|
+
if (!task.inputTypeName) continue;
|
|
5916
|
+
const absPath = path20.resolve(rootDir, task.filePath);
|
|
5917
|
+
let list = tasksByFile.get(absPath);
|
|
5918
|
+
if (!list) {
|
|
5919
|
+
list = [];
|
|
5920
|
+
tasksByFile.set(absPath, list);
|
|
5921
|
+
}
|
|
5922
|
+
list.push(task);
|
|
5923
|
+
}
|
|
5924
|
+
const programByFile = createPrograms([...tasksByFile.keys()]);
|
|
5925
|
+
const resolversByFile = /* @__PURE__ */ new Map();
|
|
5926
|
+
for (const filePath of tasksByFile.keys()) {
|
|
5927
|
+
resolversByFile.set(filePath, createLazyTypeResolver(programByFile.get(filePath), filePath));
|
|
5928
|
+
}
|
|
5929
|
+
const sources = [];
|
|
5930
|
+
for (const [filePath, fileTasks] of tasksByFile) {
|
|
5931
|
+
const program = programByFile.get(filePath);
|
|
5932
|
+
for (const task of fileTasks) {
|
|
5933
|
+
const typeInfo = extractTypeInfo(program, filePath, task.inputTypeName);
|
|
5934
|
+
sources.push({
|
|
5935
|
+
name: task.taskName,
|
|
5936
|
+
filePath,
|
|
5937
|
+
schemaName: task.inputTypeName,
|
|
5938
|
+
typeInfo
|
|
5939
|
+
});
|
|
5940
|
+
}
|
|
5941
|
+
}
|
|
5942
|
+
return { sources, resolversByFile };
|
|
5943
|
+
}
|
|
5944
|
+
function generateTaskSchemaFileSource(sources, resolveType, helpersImportPath) {
|
|
5945
|
+
const lines = ["import { z } from 'zod';"];
|
|
5946
|
+
const schemaBlocks = [];
|
|
5947
|
+
for (const source of sources) {
|
|
5948
|
+
if (!source.typeInfo) continue;
|
|
5949
|
+
const block = [`// task ${source.name} \u2192 ${source.schemaName}`];
|
|
5950
|
+
const schemaCode = generateZodSchemaSource(
|
|
5951
|
+
source.typeInfo,
|
|
5952
|
+
resolveType,
|
|
5953
|
+
source.schemaName,
|
|
5954
|
+
false
|
|
5955
|
+
).replace(/^import \{ z \} from 'zod';\s*\n\s*\n/, "");
|
|
5956
|
+
block.push(schemaCode);
|
|
5957
|
+
block.push("");
|
|
5958
|
+
schemaBlocks.push(block.join("\n"));
|
|
5959
|
+
}
|
|
5960
|
+
const allSchemaCode = schemaBlocks.join("\n");
|
|
5961
|
+
if (helpersImportPath && usesCoerceHelpers(allSchemaCode)) {
|
|
5962
|
+
lines.push(
|
|
5963
|
+
`import { coerceNumber, coerceBoolean, coerceMap, coerceSet } from '${helpersImportPath}';`
|
|
5964
|
+
);
|
|
5965
|
+
}
|
|
5966
|
+
lines.push("");
|
|
5967
|
+
lines.push(...schemaBlocks);
|
|
5968
|
+
return lines.join("\n").replace(/\n+$/, "\n");
|
|
5969
|
+
}
|
|
5970
|
+
async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
5971
|
+
const metadata = [];
|
|
5972
|
+
if (manifests.length > 0) {
|
|
5973
|
+
const programByFile = createPrograms(manifests.map((m) => path20.resolve(rootDir, m.filePath)));
|
|
5974
|
+
for (const manifest of manifests) {
|
|
5975
|
+
const absPath = path20.resolve(rootDir, manifest.filePath);
|
|
5976
|
+
const result = extractToolMetadata(programByFile.get(absPath), absPath, "run", {
|
|
5977
|
+
name: manifest.name,
|
|
5978
|
+
filePath: manifest.filePath
|
|
5979
|
+
});
|
|
5980
|
+
if (result) {
|
|
5981
|
+
metadata.push({ ...result, taskName: manifest.name });
|
|
5982
|
+
}
|
|
5983
|
+
}
|
|
5984
|
+
}
|
|
5985
|
+
const serialized = serializeTasks(manifests, dist);
|
|
5986
|
+
const tasksPath = path20.resolve(rootDir, dist, TASKS_FILE);
|
|
5987
|
+
await writeTasksModule(serialized, tasksPath);
|
|
5988
|
+
if (metadata.length === 0) {
|
|
5989
|
+
return hydrateTasks(serialized);
|
|
5990
|
+
}
|
|
5991
|
+
const { sources, resolversByFile } = collectTaskSchemaSources(metadata, rootDir);
|
|
5992
|
+
if (sources.length === 0) {
|
|
5993
|
+
return hydrateTasks(serialized);
|
|
5994
|
+
}
|
|
5995
|
+
const sourcesByFile = /* @__PURE__ */ new Map();
|
|
5996
|
+
for (const source of sources) {
|
|
5997
|
+
let list = sourcesByFile.get(source.filePath);
|
|
5998
|
+
if (!list) {
|
|
5999
|
+
list = [];
|
|
6000
|
+
sourcesByFile.set(source.filePath, list);
|
|
6001
|
+
}
|
|
6002
|
+
list.push(source);
|
|
6003
|
+
}
|
|
6004
|
+
const fileEntries = [];
|
|
6005
|
+
for (const [filePath, fileSources] of sourcesByFile) {
|
|
6006
|
+
const relFile = path20.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
6007
|
+
const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
|
|
6008
|
+
const resolver = resolversByFile.get(filePath);
|
|
6009
|
+
let relForDir = relFile;
|
|
6010
|
+
if (relForDir.startsWith("src/")) {
|
|
6011
|
+
relForDir = relForDir.slice(4);
|
|
6012
|
+
}
|
|
6013
|
+
const dirIdx = relForDir.lastIndexOf("/");
|
|
6014
|
+
const zodRelDir = dirIdx >= 0 ? relForDir.slice(0, dirIdx) : "";
|
|
6015
|
+
const helpersImportPath = getHelpersImportPath(zodRelDir);
|
|
6016
|
+
const source = generateTaskSchemaFileSource(
|
|
6017
|
+
fileSources,
|
|
6018
|
+
(name) => resolver?.resolve(name)?.runtimeType,
|
|
6019
|
+
helpersImportPath
|
|
6020
|
+
);
|
|
6021
|
+
fileEntries.push({ outputPath, source });
|
|
6022
|
+
}
|
|
6023
|
+
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
6024
|
+
if (usesCoerceHelpers(allSourceCode)) {
|
|
6025
|
+
const helpersPath = path20.resolve(rootDir, dist, HELPERS_FILENAME);
|
|
6026
|
+
const { existsSync: existsSync3 } = await import("fs");
|
|
6027
|
+
if (!existsSync3(helpersPath)) {
|
|
6028
|
+
await atomicWriteFile(helpersPath, generateHelpersFileSource());
|
|
6029
|
+
}
|
|
6030
|
+
}
|
|
6031
|
+
await Promise.all(
|
|
6032
|
+
fileEntries.map(({ outputPath, source }) => atomicWriteFile(outputPath, source))
|
|
6033
|
+
);
|
|
6034
|
+
return hydrateTasks(serialized);
|
|
6035
|
+
}
|
|
6036
|
+
|
|
5441
6037
|
// src/cli/loadPlugins.ts
|
|
5442
|
-
import
|
|
5443
|
-
import
|
|
6038
|
+
import path22 from "path";
|
|
6039
|
+
import fs17 from "fs";
|
|
5444
6040
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
5445
6041
|
|
|
5446
6042
|
// src/cli/compileConfig.ts
|
|
5447
|
-
import
|
|
5448
|
-
import
|
|
6043
|
+
import path21 from "path";
|
|
6044
|
+
import fs16 from "fs";
|
|
5449
6045
|
async function compileProjectModules(entryPoints, rootDir, dist) {
|
|
5450
6046
|
const { insideFiles, outsideFiles } = await collectRelativeImports(entryPoints, rootDir);
|
|
5451
6047
|
const esbuild = await import("esbuild");
|
|
5452
6048
|
const aliasPlugins = buildAliasPlugins(rootDir);
|
|
5453
|
-
const absDist =
|
|
6049
|
+
const absDist = path21.resolve(rootDir, dist);
|
|
5454
6050
|
await esbuild.build({
|
|
5455
6051
|
entryPoints: [...entryPoints, ...outsideFiles],
|
|
5456
6052
|
outdir: absDist,
|
|
@@ -5464,7 +6060,7 @@ async function compileProjectModules(entryPoints, rootDir, dist) {
|
|
|
5464
6060
|
logLevel: "silent"
|
|
5465
6061
|
});
|
|
5466
6062
|
if (insideFiles.length > 0) {
|
|
5467
|
-
const appOutbase =
|
|
6063
|
+
const appOutbase = path21.resolve(rootDir, "src");
|
|
5468
6064
|
await esbuild.build({
|
|
5469
6065
|
entryPoints: insideFiles,
|
|
5470
6066
|
outdir: absDist,
|
|
@@ -5545,37 +6141,37 @@ async function loadPlugins(declarations, ctx, rootDir, dist) {
|
|
|
5545
6141
|
var TS_EXTS = /\.(ts|tsx|mts|cts)$/;
|
|
5546
6142
|
var JS_EXTS = /\.(js|mjs|cjs|jsx)$/;
|
|
5547
6143
|
function resolveLocalPluginSource(specifier, baseDir) {
|
|
5548
|
-
const base =
|
|
5549
|
-
if ((TS_EXTS.test(base) || JS_EXTS.test(base)) &&
|
|
6144
|
+
const base = path22.isAbsolute(specifier) ? specifier : path22.resolve(baseDir, specifier);
|
|
6145
|
+
if ((TS_EXTS.test(base) || JS_EXTS.test(base)) && fs17.existsSync(base)) return base;
|
|
5550
6146
|
for (const ext of [".ts", ".js"]) {
|
|
5551
|
-
if (
|
|
6147
|
+
if (fs17.existsSync(base + ext)) return base + ext;
|
|
5552
6148
|
}
|
|
5553
6149
|
for (const indexExt of ["/index.ts", "/index.js"]) {
|
|
5554
|
-
if (
|
|
6150
|
+
if (fs17.existsSync(base + indexExt)) return base + indexExt;
|
|
5555
6151
|
}
|
|
5556
6152
|
return null;
|
|
5557
6153
|
}
|
|
5558
6154
|
function mirrorProductPath(sourcePath, baseDir, distDir) {
|
|
5559
|
-
let rel =
|
|
6155
|
+
let rel = path22.relative(baseDir, sourcePath).replace(/\\/g, "/");
|
|
5560
6156
|
if (rel.startsWith("src/")) rel = rel.slice(4);
|
|
5561
|
-
return
|
|
6157
|
+
return path22.resolve(distDir, rel.replace(TS_EXTS, ".js"));
|
|
5562
6158
|
}
|
|
5563
6159
|
function isSourceNewer(sourcePath, productPath) {
|
|
5564
6160
|
try {
|
|
5565
|
-
return
|
|
6161
|
+
return fs17.statSync(sourcePath).mtimeMs > fs17.statSync(productPath).mtimeMs;
|
|
5566
6162
|
} catch {
|
|
5567
6163
|
return true;
|
|
5568
6164
|
}
|
|
5569
6165
|
}
|
|
5570
6166
|
async function importPluginModule(specifier, baseDir, dist) {
|
|
5571
6167
|
const isRelative = specifier.startsWith("./") || specifier.startsWith("../");
|
|
5572
|
-
if (!isRelative && !
|
|
6168
|
+
if (!isRelative && !path22.isAbsolute(specifier)) {
|
|
5573
6169
|
return import(specifier);
|
|
5574
6170
|
}
|
|
5575
|
-
const distDir = dist ?
|
|
6171
|
+
const distDir = dist ? path22.resolve(baseDir, dist) : null;
|
|
5576
6172
|
const sourcePath = resolveLocalPluginSource(specifier, baseDir);
|
|
5577
6173
|
const productPath = sourcePath && distDir ? mirrorProductPath(sourcePath, baseDir, distDir) : null;
|
|
5578
|
-
if (productPath !== null &&
|
|
6174
|
+
if (productPath !== null && fs17.existsSync(productPath) && (sourcePath === null || !isSourceNewer(sourcePath, productPath))) {
|
|
5579
6175
|
return import(pathToFileURL2(productPath).href);
|
|
5580
6176
|
}
|
|
5581
6177
|
if (sourcePath && TS_EXTS.test(sourcePath)) {
|
|
@@ -5584,13 +6180,13 @@ async function importPluginModule(specifier, baseDir, dist) {
|
|
|
5584
6180
|
`Local plugin "${specifier}" has no up-to-date build artifact (dist is stale or missing). Run "faapi build" first, or use "faapi dev" for on-demand compilation.`
|
|
5585
6181
|
);
|
|
5586
6182
|
}
|
|
5587
|
-
const relFromRoot =
|
|
6183
|
+
const relFromRoot = path22.relative(baseDir, sourcePath).replace(/\\/g, "/");
|
|
5588
6184
|
if (relFromRoot.startsWith("src/")) {
|
|
5589
6185
|
await ensureCompiled(sourcePath, baseDir, dist);
|
|
5590
6186
|
} else {
|
|
5591
6187
|
await compileProjectModules([sourcePath], baseDir, dist);
|
|
5592
6188
|
}
|
|
5593
|
-
if (productPath &&
|
|
6189
|
+
if (productPath && fs17.existsSync(productPath)) {
|
|
5594
6190
|
return import(pathToFileURL2(productPath).href);
|
|
5595
6191
|
}
|
|
5596
6192
|
}
|
|
@@ -5602,7 +6198,7 @@ async function importPluginModule(specifier, baseDir, dist) {
|
|
|
5602
6198
|
`${specifier}/index.ts`,
|
|
5603
6199
|
`${specifier}.js`,
|
|
5604
6200
|
`${specifier}/index.js`
|
|
5605
|
-
].map((c) =>
|
|
6201
|
+
].map((c) => path22.isAbsolute(c) ? c : path22.join(baseDir, c));
|
|
5606
6202
|
throw new Error(
|
|
5607
6203
|
`Cannot find local plugin "${specifier}" (resolved from ${baseDir}). Expected one of:
|
|
5608
6204
|
${candidates.join("\n ")}
|
|
@@ -5633,8 +6229,8 @@ var ROUTES_FILE = "faapi-routes.js";
|
|
|
5633
6229
|
var TOOLS_FILE2 = "faapi-tools.js";
|
|
5634
6230
|
var AGENTS_FILE2 = "faapi-agents.js";
|
|
5635
6231
|
async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries) {
|
|
5636
|
-
const toolsPath =
|
|
5637
|
-
if (!
|
|
6232
|
+
const toolsPath = path23.resolve(rootDir, dist, TOOLS_FILE2);
|
|
6233
|
+
if (!fs18.existsSync(toolsPath)) {
|
|
5638
6234
|
return [];
|
|
5639
6235
|
}
|
|
5640
6236
|
const serialized = await importWithCacheBust(toolsPath);
|
|
@@ -5643,8 +6239,8 @@ async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries
|
|
|
5643
6239
|
return hydrated;
|
|
5644
6240
|
}
|
|
5645
6241
|
async function loadAndHydrateAgents(rootDir, dist, registries = defaultRegistries) {
|
|
5646
|
-
const agentsPath =
|
|
5647
|
-
if (!
|
|
6242
|
+
const agentsPath = path23.resolve(rootDir, dist, AGENTS_FILE2);
|
|
6243
|
+
if (!fs18.existsSync(agentsPath)) {
|
|
5648
6244
|
return [];
|
|
5649
6245
|
}
|
|
5650
6246
|
const serialized = await importWithCacheBust(agentsPath);
|
|
@@ -5652,6 +6248,24 @@ async function loadAndHydrateAgents(rootDir, dist, registries = defaultRegistrie
|
|
|
5652
6248
|
registries.agent.hydrate(hydrated);
|
|
5653
6249
|
return hydrated;
|
|
5654
6250
|
}
|
|
6251
|
+
function getTaskDriverOptions(config) {
|
|
6252
|
+
if (!config?.task) return void 0;
|
|
6253
|
+
const taskConfig = config.task;
|
|
6254
|
+
const driver = taskConfig.driver;
|
|
6255
|
+
if (driver === "pgboss") return taskConfig.pgboss;
|
|
6256
|
+
if (driver === "bullmq") return taskConfig.bullmq;
|
|
6257
|
+
return void 0;
|
|
6258
|
+
}
|
|
6259
|
+
async function loadAndHydrateTasks(rootDir, dist, registries = defaultRegistries) {
|
|
6260
|
+
const tasksPath = path23.resolve(rootDir, dist, TASKS_FILE);
|
|
6261
|
+
if (!fs18.existsSync(tasksPath)) {
|
|
6262
|
+
return [];
|
|
6263
|
+
}
|
|
6264
|
+
const serialized = await importWithCacheBust(tasksPath);
|
|
6265
|
+
const hydrated = hydrateTasks(serialized.tasks ?? []);
|
|
6266
|
+
registries.task.hydrate(hydrated);
|
|
6267
|
+
return hydrated;
|
|
6268
|
+
}
|
|
5655
6269
|
var APP_INSTANCE_KEY = /* @__PURE__ */ Symbol.for("faapi.app.instance");
|
|
5656
6270
|
function getCurrentApp() {
|
|
5657
6271
|
return globalThis[APP_INSTANCE_KEY] ?? null;
|
|
@@ -5703,7 +6317,8 @@ var FAAPI_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
5703
6317
|
"logger",
|
|
5704
6318
|
"http2",
|
|
5705
6319
|
"trustedProxy",
|
|
5706
|
-
"response"
|
|
6320
|
+
"response",
|
|
6321
|
+
"task"
|
|
5707
6322
|
]);
|
|
5708
6323
|
function isFaapiConfigKey(key) {
|
|
5709
6324
|
return FAAPI_CONFIG_KEYS.has(key);
|
|
@@ -5711,8 +6326,8 @@ function isFaapiConfigKey(key) {
|
|
|
5711
6326
|
async function createAppBase(options) {
|
|
5712
6327
|
const rootDir = options?.rootDir ?? process.cwd();
|
|
5713
6328
|
const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
|
|
5714
|
-
const routesPath =
|
|
5715
|
-
if (!
|
|
6329
|
+
const routesPath = path23.resolve(rootDir, dist, ROUTES_FILE);
|
|
6330
|
+
if (!fs18.existsSync(routesPath)) {
|
|
5716
6331
|
throw new Error(
|
|
5717
6332
|
`[faapi] ${dist}/${ROUTES_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
|
|
5718
6333
|
);
|
|
@@ -5734,6 +6349,28 @@ async function createAppBase(options) {
|
|
|
5734
6349
|
const registries = createAppRegistries();
|
|
5735
6350
|
const tools = await loadAndHydrateTools(rootDir, dist, registries);
|
|
5736
6351
|
const agents = await loadAndHydrateAgents(rootDir, dist, registries);
|
|
6352
|
+
const taskMetas = await loadAndHydrateTasks(rootDir, dist, registries);
|
|
6353
|
+
const taskDriver = await loadTaskDriver(config?.task?.driver, getTaskDriverOptions(config));
|
|
6354
|
+
const taskQueue = createTaskQueue({
|
|
6355
|
+
registry: registries.task,
|
|
6356
|
+
rootDir,
|
|
6357
|
+
config,
|
|
6358
|
+
driver: taskDriver
|
|
6359
|
+
});
|
|
6360
|
+
const cronScheduler = createCronScheduler(
|
|
6361
|
+
registries.task,
|
|
6362
|
+
(name) => taskQueue.enqueue(name)
|
|
6363
|
+
);
|
|
6364
|
+
const taskEnabled = process.env.FAAPI_TASKS_DISABLED === "1" ? false : config?.task?.enabled ?? true;
|
|
6365
|
+
const stopTaskRuntime = async () => {
|
|
6366
|
+
cronScheduler.stop();
|
|
6367
|
+
await taskQueue.stop(config?.task?.shutdownTimeoutMs ?? 1e4);
|
|
6368
|
+
};
|
|
6369
|
+
if (taskEnabled) {
|
|
6370
|
+
taskQueue.start();
|
|
6371
|
+
cronScheduler.start();
|
|
6372
|
+
}
|
|
6373
|
+
registries.taskHandle.register(() => taskQueue);
|
|
5737
6374
|
const pluginConfig = config ? Object.fromEntries(Object.entries(config).filter(([k]) => !isFaapiConfigKey(k))) : {};
|
|
5738
6375
|
const { server, routesRef } = createServer({
|
|
5739
6376
|
routes: sorted,
|
|
@@ -5775,14 +6412,22 @@ async function createAppBase(options) {
|
|
|
5775
6412
|
routes: sorted,
|
|
5776
6413
|
wsRoutes,
|
|
5777
6414
|
rootDir,
|
|
6415
|
+
tasks: taskQueue,
|
|
5778
6416
|
async listen(listenPort) {
|
|
5779
6417
|
const envPort = process.env.PORT ? Number(process.env.PORT) : void 0;
|
|
5780
6418
|
const actualPort = listenPort ?? options?.port ?? envPort ?? DEFAULT_PORT;
|
|
5781
6419
|
if (config?.lifecycle?.onBoot) {
|
|
5782
6420
|
try {
|
|
5783
|
-
await config.lifecycle.onBoot({
|
|
6421
|
+
await config.lifecycle.onBoot({
|
|
6422
|
+
rootDir,
|
|
6423
|
+
routes: sorted,
|
|
6424
|
+
server,
|
|
6425
|
+
registries,
|
|
6426
|
+
tasks: taskQueue
|
|
6427
|
+
});
|
|
5784
6428
|
console.log("- onBoot hook executed");
|
|
5785
6429
|
} catch (err) {
|
|
6430
|
+
await stopTaskRuntime();
|
|
5786
6431
|
const message = err instanceof Error ? err.message : String(err);
|
|
5787
6432
|
console.error(`[faapi] onBoot hook failed: ${message}`);
|
|
5788
6433
|
throw err;
|
|
@@ -5830,9 +6475,22 @@ async function createAppBase(options) {
|
|
|
5830
6475
|
console.log(` ${agent.name} [${exports}] ${agent.filePath}`);
|
|
5831
6476
|
}
|
|
5832
6477
|
}
|
|
6478
|
+
if (taskMetas.length > 0) {
|
|
6479
|
+
console.log(`- Loaded ${taskMetas.length} task(s):`);
|
|
6480
|
+
for (const taskMeta of taskMetas) {
|
|
6481
|
+
const schedule = taskMeta.cron ? ` cron=${taskMeta.cron}` : "";
|
|
6482
|
+
console.log(` ${taskMeta.name}${schedule} ${taskMeta.filePath}`);
|
|
6483
|
+
}
|
|
6484
|
+
}
|
|
5833
6485
|
registerDefaultShutdownHandlers();
|
|
5834
6486
|
if (config?.lifecycle?.onReady) {
|
|
5835
|
-
await config.lifecycle.onReady({
|
|
6487
|
+
await config.lifecycle.onReady({
|
|
6488
|
+
rootDir,
|
|
6489
|
+
routes: sorted,
|
|
6490
|
+
server,
|
|
6491
|
+
registries,
|
|
6492
|
+
tasks: taskQueue
|
|
6493
|
+
});
|
|
5836
6494
|
console.log("- onReady hook executed");
|
|
5837
6495
|
}
|
|
5838
6496
|
app.server = server;
|
|
@@ -5925,13 +6583,22 @@ async function createAppBase(options) {
|
|
|
5925
6583
|
closed = true;
|
|
5926
6584
|
const s = server;
|
|
5927
6585
|
s.closeIdleConnections?.();
|
|
6586
|
+
await stopTaskRuntime();
|
|
5928
6587
|
if (config?.lifecycle?.onClose) {
|
|
5929
|
-
await config.lifecycle.onClose({
|
|
6588
|
+
await config.lifecycle.onClose({
|
|
6589
|
+
rootDir,
|
|
6590
|
+
routes: sorted,
|
|
6591
|
+
server,
|
|
6592
|
+
registries,
|
|
6593
|
+
tasks: taskQueue
|
|
6594
|
+
});
|
|
5930
6595
|
}
|
|
5931
6596
|
registries.tool.clear();
|
|
5932
6597
|
registries.agent.clear();
|
|
5933
6598
|
registries.skill.clear();
|
|
6599
|
+
registries.task.clear();
|
|
5934
6600
|
registries.agentHandle.clear();
|
|
6601
|
+
registries.taskHandle.clear();
|
|
5935
6602
|
if (!server.listening) {
|
|
5936
6603
|
app.server = null;
|
|
5937
6604
|
if (getCurrentApp() === app) setCurrentApp(null);
|
|
@@ -5968,6 +6635,7 @@ async function createAppBase(options) {
|
|
|
5968
6635
|
registries,
|
|
5969
6636
|
dist,
|
|
5970
6637
|
patterns: ROUTE_PATTERNS,
|
|
6638
|
+
taskQueue,
|
|
5971
6639
|
server,
|
|
5972
6640
|
routesRef,
|
|
5973
6641
|
config,
|
|
@@ -5983,19 +6651,22 @@ async function createAppBase(options) {
|
|
|
5983
6651
|
return { app, ctx };
|
|
5984
6652
|
}
|
|
5985
6653
|
|
|
6654
|
+
// src/cli/createDevApp.ts
|
|
6655
|
+
import path27 from "path";
|
|
6656
|
+
|
|
5986
6657
|
// src/router/scanRoutes.ts
|
|
5987
|
-
import
|
|
5988
|
-
import
|
|
5989
|
-
import
|
|
6658
|
+
import fg3 from "fast-glob";
|
|
6659
|
+
import path24 from "path";
|
|
6660
|
+
import fs19 from "fs";
|
|
5990
6661
|
|
|
5991
6662
|
// src/router/constants.ts
|
|
5992
6663
|
var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
5993
6664
|
var HTTP_METHOD_SET = new Set(HTTP_METHODS);
|
|
5994
6665
|
|
|
5995
6666
|
// src/utils/normalizePath.ts
|
|
5996
|
-
function normalizePath(
|
|
5997
|
-
if (!
|
|
5998
|
-
let result =
|
|
6667
|
+
function normalizePath(path28) {
|
|
6668
|
+
if (!path28) return "";
|
|
6669
|
+
let result = path28.replace(/\\/g, "/");
|
|
5999
6670
|
result = result.replace(/\/+/g, "/");
|
|
6000
6671
|
result = result.replace(/\/+$/, "");
|
|
6001
6672
|
if (result && !result.startsWith("/")) {
|
|
@@ -6056,34 +6727,34 @@ function extractExportsFromSource(source) {
|
|
|
6056
6727
|
return names;
|
|
6057
6728
|
}
|
|
6058
6729
|
function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
|
|
6059
|
-
const routeDir =
|
|
6060
|
-
const resolvedRoot =
|
|
6730
|
+
const routeDir = path24.dirname(routeFilePath);
|
|
6731
|
+
const resolvedRoot = path24.resolve(rootDir);
|
|
6061
6732
|
const paths = [];
|
|
6062
|
-
let currentDir =
|
|
6733
|
+
let currentDir = path24.resolve(rootDir, routeDir);
|
|
6063
6734
|
while (true) {
|
|
6064
6735
|
if (dist) {
|
|
6065
|
-
const mwTsPath =
|
|
6066
|
-
const mwJsPath =
|
|
6067
|
-
const absTsPath =
|
|
6068
|
-
const absJsPath =
|
|
6069
|
-
const absMwPath =
|
|
6736
|
+
const mwTsPath = path24.join(currentDir, "middlewares.ts");
|
|
6737
|
+
const mwJsPath = path24.join(currentDir, "middlewares.js");
|
|
6738
|
+
const absTsPath = path24.resolve(rootDir, mwTsPath);
|
|
6739
|
+
const absJsPath = path24.resolve(rootDir, mwJsPath);
|
|
6740
|
+
const absMwPath = fs19.existsSync(absTsPath) ? absTsPath : fs19.existsSync(absJsPath) ? absJsPath : null;
|
|
6070
6741
|
if (absMwPath) {
|
|
6071
|
-
const relMwPath =
|
|
6072
|
-
const prodAbsPath =
|
|
6742
|
+
const relMwPath = path24.relative(rootDir, absMwPath);
|
|
6743
|
+
const prodAbsPath = path24.resolve(rootDir, toProdFilePath(relMwPath, dist));
|
|
6073
6744
|
paths.push(prodAbsPath);
|
|
6074
6745
|
}
|
|
6075
6746
|
} else {
|
|
6076
6747
|
for (const ext of [".ts", ".js"]) {
|
|
6077
|
-
const mwPath =
|
|
6078
|
-
const absMwPath =
|
|
6079
|
-
if (
|
|
6748
|
+
const mwPath = path24.join(currentDir, `middlewares${ext}`);
|
|
6749
|
+
const absMwPath = path24.resolve(rootDir, mwPath);
|
|
6750
|
+
if (fs19.existsSync(absMwPath)) {
|
|
6080
6751
|
paths.push(absMwPath);
|
|
6081
6752
|
break;
|
|
6082
6753
|
}
|
|
6083
6754
|
}
|
|
6084
6755
|
}
|
|
6085
6756
|
if (currentDir === resolvedRoot) break;
|
|
6086
|
-
const parentDir =
|
|
6757
|
+
const parentDir = path24.dirname(currentDir);
|
|
6087
6758
|
if (parentDir === currentDir) break;
|
|
6088
6759
|
currentDir = parentDir;
|
|
6089
6760
|
}
|
|
@@ -6091,7 +6762,7 @@ function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
|
|
|
6091
6762
|
return paths;
|
|
6092
6763
|
}
|
|
6093
6764
|
async function scanRoutes(rootDir, patterns, dist) {
|
|
6094
|
-
const files = await
|
|
6765
|
+
const files = await fg3(patterns, {
|
|
6095
6766
|
cwd: rootDir,
|
|
6096
6767
|
onlyFiles: true,
|
|
6097
6768
|
absolute: false
|
|
@@ -6102,7 +6773,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
6102
6773
|
const normalizedFile = file.replace(/\\/g, "/");
|
|
6103
6774
|
const fileName = normalizedFile.split("/").pop();
|
|
6104
6775
|
if (fileName === "handler.ts" || fileName === "handler.js") {
|
|
6105
|
-
const absPath =
|
|
6776
|
+
const absPath = path24.resolve(rootDir, normalizedFile);
|
|
6106
6777
|
const urlPath = filePathToUrlPath(normalizedFile);
|
|
6107
6778
|
const paramNames = extractParamNames(urlPath);
|
|
6108
6779
|
const isDynamic = paramNames.length > 0;
|
|
@@ -6115,7 +6786,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
6115
6786
|
const mwPaths = collectMiddlewarePaths(normalizedFile, rootDir);
|
|
6116
6787
|
middlewareBundle = await loadMergedMiddlewares(mwPaths);
|
|
6117
6788
|
}
|
|
6118
|
-
const source = await
|
|
6789
|
+
const source = await fs19.promises.readFile(absPath, "utf8").catch(() => "");
|
|
6119
6790
|
const exportNames = extractExportsFromSource(source);
|
|
6120
6791
|
const methods = HTTP_METHODS.filter((m) => exportNames.has(m));
|
|
6121
6792
|
for (const method of methods) {
|
|
@@ -6150,9 +6821,9 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
6150
6821
|
}
|
|
6151
6822
|
|
|
6152
6823
|
// src/tools/scanTools.ts
|
|
6153
|
-
import
|
|
6154
|
-
import
|
|
6155
|
-
import
|
|
6824
|
+
import fg4 from "fast-glob";
|
|
6825
|
+
import path25 from "path";
|
|
6826
|
+
import fs20 from "fs";
|
|
6156
6827
|
var TOOL_PATTERNS = ["src/tools/**/*.ts"];
|
|
6157
6828
|
var TOOL_EXPORT_RE = new RegExp(
|
|
6158
6829
|
String.raw`export\s+(?:async\s+)?(?:function\s+|const\s+)([A-Za-z_$][\w$]*)\s*(?:\(|=)`,
|
|
@@ -6189,7 +6860,7 @@ function buildToolName(namespace, functionName) {
|
|
|
6189
6860
|
return namespace ? `${namespace}.${functionName}` : functionName;
|
|
6190
6861
|
}
|
|
6191
6862
|
async function scanTools(rootDir, patterns) {
|
|
6192
|
-
const files = await
|
|
6863
|
+
const files = await fg4(patterns, {
|
|
6193
6864
|
cwd: rootDir,
|
|
6194
6865
|
onlyFiles: true,
|
|
6195
6866
|
absolute: false
|
|
@@ -6202,8 +6873,8 @@ async function scanTools(rootDir, patterns) {
|
|
|
6202
6873
|
if (fileName !== "handler.ts" && fileName !== "handler.js") {
|
|
6203
6874
|
continue;
|
|
6204
6875
|
}
|
|
6205
|
-
const absPath =
|
|
6206
|
-
const source = await
|
|
6876
|
+
const absPath = path25.resolve(rootDir, normalizedFile);
|
|
6877
|
+
const source = await fs20.promises.readFile(absPath, "utf8").catch(() => "");
|
|
6207
6878
|
const exportNames = extractToolExportsFromSource(source);
|
|
6208
6879
|
const namespace = filePathToToolNamespace(normalizedFile);
|
|
6209
6880
|
for (const fnName of exportNames) {
|
|
@@ -6226,20 +6897,20 @@ async function scanTools(rootDir, patterns) {
|
|
|
6226
6897
|
}
|
|
6227
6898
|
|
|
6228
6899
|
// src/agents/scanAgents.ts
|
|
6229
|
-
import
|
|
6230
|
-
import
|
|
6231
|
-
import
|
|
6232
|
-
var DEFAULT_AGENT_PATTERNS = ["src/agents
|
|
6900
|
+
import fg5 from "fast-glob";
|
|
6901
|
+
import path26 from "path";
|
|
6902
|
+
import fs21 from "fs";
|
|
6903
|
+
var DEFAULT_AGENT_PATTERNS = ["src/agents/**/handler.ts"];
|
|
6233
6904
|
var RUN_EXPORT_RE = /export\s+(?:async\s+)?(?:function\s+|const\s+)run\b/;
|
|
6234
6905
|
function extractAgentNameFromPath(filePath) {
|
|
6235
6906
|
const normalized = filePath.replace(/\\/g, "/");
|
|
6236
|
-
const match = normalized.match(/(?:^|\/)agents\/(
|
|
6907
|
+
const match = normalized.match(/(?:^|\/)agents\/(.+)\/handler\.ts$/);
|
|
6237
6908
|
if (!match) {
|
|
6238
6909
|
throw new Error(
|
|
6239
6910
|
`Not an agent path: "${filePath}". Expected pattern: src/agents/<name>/handler.ts`
|
|
6240
6911
|
);
|
|
6241
6912
|
}
|
|
6242
|
-
return match[1];
|
|
6913
|
+
return match[1].replace(/\//g, ".");
|
|
6243
6914
|
}
|
|
6244
6915
|
function detectAgentExports(source) {
|
|
6245
6916
|
return {
|
|
@@ -6247,7 +6918,7 @@ function detectAgentExports(source) {
|
|
|
6247
6918
|
};
|
|
6248
6919
|
}
|
|
6249
6920
|
async function scanAgents(rootDir, patterns) {
|
|
6250
|
-
const files = await
|
|
6921
|
+
const files = await fg5(patterns, {
|
|
6251
6922
|
cwd: rootDir,
|
|
6252
6923
|
onlyFiles: true,
|
|
6253
6924
|
absolute: false
|
|
@@ -6260,8 +6931,8 @@ async function scanAgents(rootDir, patterns) {
|
|
|
6260
6931
|
if (fileName !== "handler.ts" && fileName !== "handler.js") {
|
|
6261
6932
|
continue;
|
|
6262
6933
|
}
|
|
6263
|
-
const absPath =
|
|
6264
|
-
const source = await
|
|
6934
|
+
const absPath = path26.resolve(rootDir, normalizedFile);
|
|
6935
|
+
const source = await fs21.promises.readFile(absPath, "utf8").catch(() => "");
|
|
6265
6936
|
const { hasRun } = detectAgentExports(source);
|
|
6266
6937
|
const name = extractAgentNameFromPath(normalizedFile);
|
|
6267
6938
|
const prevFile = seen.get(name);
|
|
@@ -6326,6 +6997,19 @@ async function createDevApp(options) {
|
|
|
6326
6997
|
await generateAgentArtifacts(agents, ctx.rootDir, ctx.dist);
|
|
6327
6998
|
await loadAndHydrateAgents(ctx.rootDir, ctx.dist, ctx.registries);
|
|
6328
6999
|
};
|
|
7000
|
+
devApp.reloadTasks = async () => {
|
|
7001
|
+
setLoadTimestamp(Date.now());
|
|
7002
|
+
invalidateProgramCache();
|
|
7003
|
+
const tasks = await scanTasks(ctx.rootDir, TASK_PATTERNS);
|
|
7004
|
+
for (const task of tasks) {
|
|
7005
|
+
await ensureCompiled(path27.resolve(ctx.rootDir, task.filePath), ctx.rootDir, ctx.dist);
|
|
7006
|
+
}
|
|
7007
|
+
await generateTaskArtifacts(tasks, ctx.rootDir, ctx.dist);
|
|
7008
|
+
ctx.taskQueue.invalidateModules();
|
|
7009
|
+
ctx.taskQueue.invalidateSchemas();
|
|
7010
|
+
await ctx.taskQueue.reload();
|
|
7011
|
+
await loadAndHydrateTasks(ctx.rootDir, ctx.dist, ctx.registries);
|
|
7012
|
+
};
|
|
6329
7013
|
return devApp;
|
|
6330
7014
|
}
|
|
6331
7015
|
|
|
@@ -6341,16 +7025,21 @@ export {
|
|
|
6341
7025
|
ModuleLoadError,
|
|
6342
7026
|
RouteNotFoundError,
|
|
6343
7027
|
SchemaExtractionError,
|
|
7028
|
+
TASK_PATTERNS,
|
|
6344
7029
|
ValidationError,
|
|
6345
7030
|
clearAgentHandleFactory,
|
|
6346
7031
|
collectRouteSchemaSources,
|
|
6347
7032
|
cors,
|
|
6348
7033
|
createProdApp as createApp,
|
|
6349
7034
|
createAppRegistries,
|
|
7035
|
+
createCronScheduler,
|
|
6350
7036
|
createDevApp,
|
|
7037
|
+
createMemoryDriver,
|
|
6351
7038
|
createProdApp,
|
|
6352
7039
|
createProgram,
|
|
6353
7040
|
createPrograms,
|
|
7041
|
+
createTaskQueue,
|
|
7042
|
+
createTaskRegistry,
|
|
6354
7043
|
extractTypeInfo,
|
|
6355
7044
|
getAgent,
|
|
6356
7045
|
getAgentEntry,
|
|
@@ -6366,6 +7055,7 @@ export {
|
|
|
6366
7055
|
loadAgentModule,
|
|
6367
7056
|
loadConfig,
|
|
6368
7057
|
loadEnv,
|
|
7058
|
+
loadTaskDriver,
|
|
6369
7059
|
loadToolModule,
|
|
6370
7060
|
loadToolSchema,
|
|
6371
7061
|
logger,
|
|
@@ -6374,6 +7064,7 @@ export {
|
|
|
6374
7064
|
resolveAgentTools,
|
|
6375
7065
|
resolveSubAgents,
|
|
6376
7066
|
resolveTypeNode,
|
|
7067
|
+
scanTasks,
|
|
6377
7068
|
upsertSkill
|
|
6378
7069
|
};
|
|
6379
7070
|
//# sourceMappingURL=index.js.map
|