@faapi/faapi 0.0.0-canary.f08a14e → 1.0.0-canary.3a00f3e
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 +297 -255
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +29 -6
- package/dist/index.js +135 -53
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -561,17 +561,19 @@ interface LifecycleContext {
|
|
|
561
561
|
* } satisfies FaapiConfig;
|
|
562
562
|
* ```
|
|
563
563
|
*
|
|
564
|
-
*
|
|
564
|
+
* 自定义业务配置(任意 key):
|
|
565
565
|
* ```ts
|
|
566
566
|
* import type { FaapiConfig } from '@faapi/faapi';
|
|
567
567
|
* export default {
|
|
568
568
|
* cors: { origin: '*' },
|
|
569
|
-
* //
|
|
570
|
-
* db: { host: 'localhost', port: 5432 },
|
|
569
|
+
* // 通过 process.env.XXX 读取 .env 文件加载的环境变量
|
|
570
|
+
* db: { host: process.env.DB_HOST ?? 'localhost', port: 5432 },
|
|
571
571
|
* } satisfies FaapiConfig;
|
|
572
572
|
* ```
|
|
573
573
|
*
|
|
574
|
-
*
|
|
574
|
+
* 多环境差异通过 `.env` 系列文件实现(见 `loadEnv`):
|
|
575
|
+
* - `.env` / `.env.local` / `.env.{env}` / `.env.{env}.local`
|
|
576
|
+
* - 环境由 `NODE_ENV > 'development'` 决定
|
|
575
577
|
*
|
|
576
578
|
* 框架元信息通过环境变量配置(不放在 config 内):
|
|
577
579
|
* - `PORT`:服务端口,默认 3000
|
|
@@ -1009,7 +1011,8 @@ declare function collectRouteSchemaSources(routes: RouteManifest, rootDir?: stri
|
|
|
1009
1011
|
* - dev 模式:`faapi dev` 启动时由 `compileConfig` 生成 `.faapi/faapi-config.js`
|
|
1010
1012
|
* - prod 模式:`faapi build` 时由 `compileConfig` 生成 `dist/faapi-config.js`
|
|
1011
1013
|
*
|
|
1012
|
-
* 产物由 `compileConfig`
|
|
1014
|
+
* 产物由 `compileConfig` 在构建阶段编译,运行时不读源码、不现场编译。
|
|
1015
|
+
* 环境变量由 `loadEnv` 从 `.env` 系列文件加载到 `process.env`,配置文件中通过 `process.env.XXX` 读取。
|
|
1013
1016
|
*
|
|
1014
1017
|
* - 产物存在 → import 并返回 default
|
|
1015
1018
|
* - 产物不存在但源码有配置文件 → 抛错(强制 rebuild)
|
|
@@ -1021,6 +1024,26 @@ declare function collectRouteSchemaSources(routes: RouteManifest, rootDir?: stri
|
|
|
1021
1024
|
*/
|
|
1022
1025
|
declare function loadConfig(rootDir: string, dist: string): Promise<Partial<FaapiConfig> | null>;
|
|
1023
1026
|
|
|
1027
|
+
/**
|
|
1028
|
+
* 加载 `.env` 系列文件到 `process.env`
|
|
1029
|
+
*
|
|
1030
|
+
* 按 Next.js 约定加载四级文件(从低到高):
|
|
1031
|
+
* 1. `.env` — 所有环境共享
|
|
1032
|
+
* 2. `.env.local` — 本地覆盖
|
|
1033
|
+
* 3. `.env.{env}` — 按环境覆盖
|
|
1034
|
+
* 4. `.env.{env}.local` — 按环境本地覆盖
|
|
1035
|
+
*
|
|
1036
|
+
* env 由 `NODE_ENV || 'development'` 决定。调用方应在调 loadEnv 之前自行兜底 NODE_ENV
|
|
1037
|
+
* (dev 设 'development',prod 设 'production')。
|
|
1038
|
+
*
|
|
1039
|
+
* 合并规则:
|
|
1040
|
+
* - 后加载的文件覆盖先加载的同名变量
|
|
1041
|
+
* - **shell 已设置的变量不被覆盖**(`process.env` 已有的值优先)
|
|
1042
|
+
*
|
|
1043
|
+
* @param rootDir 项目根目录(`.env` 文件所在目录)
|
|
1044
|
+
*/
|
|
1045
|
+
declare function loadEnv(rootDir: string): void;
|
|
1046
|
+
|
|
1024
1047
|
declare const VALIDATION_ERROR = "VALIDATION_ERROR";
|
|
1025
1048
|
declare const ROUTE_NOT_FOUND = "ROUTE_NOT_FOUND";
|
|
1026
1049
|
declare const METHOD_NOT_ALLOWED = "METHOD_NOT_ALLOWED";
|
|
@@ -1192,4 +1215,4 @@ type ProdApp = AppBase;
|
|
|
1192
1215
|
*/
|
|
1193
1216
|
declare function createProdApp(options?: CreateAppOptions): Promise<ProdApp>;
|
|
1194
1217
|
|
|
1195
|
-
export { type ProdApp as App, type CorsOptions, type CreateAppOptions, type DevApp, type FaapiConfig, type FaapiContext, type FaapiContextConfig, FaapiError, type FaapiMiddleware, type FaapiPlugin, type HandlerTypeInfo, type HelmetOptions, type InjectOptions, type InjectResponse, type Injector, type InjectorMap, InternalError, type LifecycleContext, type LifecycleHooks, type LoggerOptions, MethodNotAllowedError, ModuleLoadError, type PluginContext, type PluginDeclaration, type ProdApp, type PropertyType, type RequestHandler, type RouteInfo, type RouteInputSchema, type RouteManifest, RouteNotFoundError, type RouteOutputSchema, type RouteParamSchema, type RouteSchemaSource, type RuntimeType, SchemaExtractionError, type SseEvent, type SseWriter, type TypeConstraint, type UpgradeHandler, ValidationError, type ValidationErrorCode, type ValidationIssue, type WsContext, type WsEventHandlers, type WsHandler, type WsSocket, collectRouteSchemaSources, cors, createProdApp as createApp, createContext, createDevApp, createProdApp, createProgram, extractTypeInfo, getInputTypeForMethod, helmet, invalidateProgramCache, invokeHandler, loadConfig, logger, resolveTypeNode };
|
|
1218
|
+
export { type ProdApp as App, type CorsOptions, type CreateAppOptions, type DevApp, type FaapiConfig, type FaapiContext, type FaapiContextConfig, FaapiError, type FaapiMiddleware, type FaapiPlugin, type HandlerTypeInfo, type HelmetOptions, type InjectOptions, type InjectResponse, type Injector, type InjectorMap, InternalError, type LifecycleContext, type LifecycleHooks, type LoggerOptions, MethodNotAllowedError, ModuleLoadError, type PluginContext, type PluginDeclaration, type ProdApp, type PropertyType, type RequestHandler, type RouteInfo, type RouteInputSchema, type RouteManifest, RouteNotFoundError, type RouteOutputSchema, type RouteParamSchema, type RouteSchemaSource, type RuntimeType, SchemaExtractionError, type SseEvent, type SseWriter, type TypeConstraint, type UpgradeHandler, ValidationError, type ValidationErrorCode, type ValidationIssue, type WsContext, type WsEventHandlers, type WsHandler, type WsSocket, collectRouteSchemaSources, cors, createProdApp as createApp, createContext, createDevApp, createProdApp, createProgram, extractTypeInfo, getInputTypeForMethod, helmet, invalidateProgramCache, invokeHandler, loadConfig, loadEnv, logger, resolveTypeNode };
|
package/dist/index.js
CHANGED
|
@@ -1043,6 +1043,87 @@ async function loadConfig(rootDir, dist) {
|
|
|
1043
1043
|
return null;
|
|
1044
1044
|
}
|
|
1045
1045
|
|
|
1046
|
+
// src/cli/loadEnv.ts
|
|
1047
|
+
import fs2 from "fs";
|
|
1048
|
+
import path3 from "path";
|
|
1049
|
+
function resolveEnv() {
|
|
1050
|
+
return process.env.NODE_ENV || "development";
|
|
1051
|
+
}
|
|
1052
|
+
function getEnvFiles(env) {
|
|
1053
|
+
return [".env", ".env.local", `.env.${env}`, `.env.${env}.local`];
|
|
1054
|
+
}
|
|
1055
|
+
function parseEnvFile(content, fileVars) {
|
|
1056
|
+
const result = {};
|
|
1057
|
+
const lines = content.replace(/\r\n/g, "\n").split("\n");
|
|
1058
|
+
for (const line of lines) {
|
|
1059
|
+
const trimmed = line.trim();
|
|
1060
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
1061
|
+
const match = /^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(trimmed);
|
|
1062
|
+
if (!match) continue;
|
|
1063
|
+
const [, key, rawValue] = match;
|
|
1064
|
+
const value = parseValue(rawValue, { ...fileVars, ...result });
|
|
1065
|
+
result[key] = value;
|
|
1066
|
+
}
|
|
1067
|
+
return result;
|
|
1068
|
+
}
|
|
1069
|
+
function parseValue(raw, env) {
|
|
1070
|
+
if (raw === "") return "";
|
|
1071
|
+
if (raw[0] === "'") {
|
|
1072
|
+
const end = raw.indexOf("'", 1);
|
|
1073
|
+
return end === -1 ? raw.slice(1) : raw.slice(1, end);
|
|
1074
|
+
}
|
|
1075
|
+
if (raw[0] === '"') {
|
|
1076
|
+
const match = /^"((?:\\.|[^"\\])*)"/.exec(raw);
|
|
1077
|
+
const inner = match ? match[1] : raw.slice(1);
|
|
1078
|
+
return expandEscapesAndVars(inner, env);
|
|
1079
|
+
}
|
|
1080
|
+
const commentMatch = /^(.*?)(\s+#.*)$/.exec(raw);
|
|
1081
|
+
const value = commentMatch ? commentMatch[1] : raw;
|
|
1082
|
+
return value.trim();
|
|
1083
|
+
}
|
|
1084
|
+
function expandEscapesAndVars(str, env) {
|
|
1085
|
+
const escaped = str.replace(/\\(.)/g, (_, ch) => {
|
|
1086
|
+
switch (ch) {
|
|
1087
|
+
case "n":
|
|
1088
|
+
return "\n";
|
|
1089
|
+
case "r":
|
|
1090
|
+
return "\r";
|
|
1091
|
+
case "t":
|
|
1092
|
+
return " ";
|
|
1093
|
+
case "\\":
|
|
1094
|
+
return "\\";
|
|
1095
|
+
case '"':
|
|
1096
|
+
return '"';
|
|
1097
|
+
default:
|
|
1098
|
+
return ch;
|
|
1099
|
+
}
|
|
1100
|
+
});
|
|
1101
|
+
return escaped.replace(
|
|
1102
|
+
/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g,
|
|
1103
|
+
(_, braced, plain) => {
|
|
1104
|
+
const varName = braced || plain;
|
|
1105
|
+
return env[varName] ?? process.env[varName] ?? "";
|
|
1106
|
+
}
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
function loadEnv(rootDir) {
|
|
1110
|
+
const env = resolveEnv();
|
|
1111
|
+
const files = getEnvFiles(env);
|
|
1112
|
+
const merged = {};
|
|
1113
|
+
for (const file of files) {
|
|
1114
|
+
const filePath = path3.join(rootDir, file);
|
|
1115
|
+
if (!fs2.existsSync(filePath)) continue;
|
|
1116
|
+
const content = fs2.readFileSync(filePath, "utf-8");
|
|
1117
|
+
const parsed = parseEnvFile(content, merged);
|
|
1118
|
+
Object.assign(merged, parsed);
|
|
1119
|
+
}
|
|
1120
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
1121
|
+
if (process.env[key] === void 0) {
|
|
1122
|
+
process.env[key] = value;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1046
1127
|
// src/errors/FaapiError.ts
|
|
1047
1128
|
var FaapiError = class extends Error {
|
|
1048
1129
|
constructor(code, message, statusCode) {
|
|
@@ -1069,14 +1150,14 @@ var ValidationError = class extends FaapiError {
|
|
|
1069
1150
|
issues;
|
|
1070
1151
|
};
|
|
1071
1152
|
var RouteNotFoundError = class extends FaapiError {
|
|
1072
|
-
constructor(
|
|
1073
|
-
super("ROUTE_NOT_FOUND", `Route not found: ${
|
|
1153
|
+
constructor(path10) {
|
|
1154
|
+
super("ROUTE_NOT_FOUND", `Route not found: ${path10}`, 404);
|
|
1074
1155
|
this.name = "RouteNotFoundError";
|
|
1075
1156
|
}
|
|
1076
1157
|
};
|
|
1077
1158
|
var MethodNotAllowedError = class extends FaapiError {
|
|
1078
|
-
constructor(method,
|
|
1079
|
-
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${
|
|
1159
|
+
constructor(method, path10, allowedMethods) {
|
|
1160
|
+
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path10}`, 405);
|
|
1080
1161
|
this.allowedMethods = allowedMethods;
|
|
1081
1162
|
this.name = "MethodNotAllowedError";
|
|
1082
1163
|
}
|
|
@@ -1554,8 +1635,8 @@ async function invokeHandler(handler, ctx, body, middlewares, injectors) {
|
|
|
1554
1635
|
}
|
|
1555
1636
|
|
|
1556
1637
|
// src/cli/createAppCore.ts
|
|
1557
|
-
import
|
|
1558
|
-
import
|
|
1638
|
+
import fs5 from "fs";
|
|
1639
|
+
import path8 from "path";
|
|
1559
1640
|
import { PassThrough } from "stream";
|
|
1560
1641
|
|
|
1561
1642
|
// src/router/sortRoutes.ts
|
|
@@ -1608,45 +1689,45 @@ import {
|
|
|
1608
1689
|
import { createSecureServer as createHttp2SecureServer } from "http2";
|
|
1609
1690
|
import { readFileSync } from "fs";
|
|
1610
1691
|
import { Readable as Readable2 } from "stream";
|
|
1611
|
-
import
|
|
1692
|
+
import path6 from "path";
|
|
1612
1693
|
|
|
1613
1694
|
// src/router/matchRoute.ts
|
|
1614
|
-
function matchRoute(routes, method,
|
|
1695
|
+
function matchRoute(routes, method, path10) {
|
|
1615
1696
|
for (const route of routes) {
|
|
1616
1697
|
if (route.method !== method) {
|
|
1617
1698
|
continue;
|
|
1618
1699
|
}
|
|
1619
1700
|
if (!route.isDynamic) {
|
|
1620
|
-
if (route.urlPath ===
|
|
1701
|
+
if (route.urlPath === path10) {
|
|
1621
1702
|
return { route, params: {} };
|
|
1622
1703
|
}
|
|
1623
1704
|
continue;
|
|
1624
1705
|
}
|
|
1625
|
-
const params = matchDynamicPath(route.urlPath,
|
|
1706
|
+
const params = matchDynamicPath(route.urlPath, path10, route.paramNames, route.isCatchAll);
|
|
1626
1707
|
if (params !== null) {
|
|
1627
1708
|
return { route, params };
|
|
1628
1709
|
}
|
|
1629
1710
|
}
|
|
1630
1711
|
return null;
|
|
1631
1712
|
}
|
|
1632
|
-
function matchWsRoute(wsRoutes,
|
|
1713
|
+
function matchWsRoute(wsRoutes, path10) {
|
|
1633
1714
|
for (const route of wsRoutes) {
|
|
1634
1715
|
if (!route.isDynamic) {
|
|
1635
|
-
if (route.urlPath ===
|
|
1716
|
+
if (route.urlPath === path10) {
|
|
1636
1717
|
return { route, params: {} };
|
|
1637
1718
|
}
|
|
1638
1719
|
continue;
|
|
1639
1720
|
}
|
|
1640
|
-
const params = matchDynamicPath(route.urlPath,
|
|
1721
|
+
const params = matchDynamicPath(route.urlPath, path10, route.paramNames, route.isCatchAll);
|
|
1641
1722
|
if (params !== null) {
|
|
1642
1723
|
return { route, params };
|
|
1643
1724
|
}
|
|
1644
1725
|
}
|
|
1645
1726
|
return null;
|
|
1646
1727
|
}
|
|
1647
|
-
function matchDynamicPath(pattern,
|
|
1728
|
+
function matchDynamicPath(pattern, path10, paramNames, isCatchAll) {
|
|
1648
1729
|
const patternSegments = pattern.split("/").filter(Boolean);
|
|
1649
|
-
const pathSegments =
|
|
1730
|
+
const pathSegments = path10.split("/").filter(Boolean);
|
|
1650
1731
|
if (isCatchAll) {
|
|
1651
1732
|
const nonCatchAllCount = patternSegments.length - 1;
|
|
1652
1733
|
if (pathSegments.length <= nonCatchAllCount) {
|
|
@@ -1877,9 +1958,9 @@ async function validateInput(schemaPath, method, inputType, input) {
|
|
|
1877
1958
|
function mapZodIssues(error) {
|
|
1878
1959
|
return error.issues.map((issue) => {
|
|
1879
1960
|
const code = mapZodCode(issue.code, issue.message);
|
|
1880
|
-
const
|
|
1961
|
+
const path10 = issue.path.map(String).join(".") || "";
|
|
1881
1962
|
return {
|
|
1882
|
-
path:
|
|
1963
|
+
path: path10,
|
|
1883
1964
|
code,
|
|
1884
1965
|
expected: issue.expected ?? mapExpectedFromMessage(issue.message),
|
|
1885
1966
|
received: issue.received ?? mapReceivedFromMessage(issue.message),
|
|
@@ -1939,7 +2020,7 @@ function getClientIp(req) {
|
|
|
1939
2020
|
|
|
1940
2021
|
// src/server/handleWsUpgrade.ts
|
|
1941
2022
|
import { WebSocketServer, WebSocket } from "ws";
|
|
1942
|
-
import
|
|
2023
|
+
import path4 from "path";
|
|
1943
2024
|
|
|
1944
2025
|
// src/errors/formatErrorResponse.ts
|
|
1945
2026
|
function formatErrorResponse(error) {
|
|
@@ -2112,7 +2193,7 @@ function attachWebSocket(options) {
|
|
|
2112
2193
|
const finalHandler = async () => {
|
|
2113
2194
|
let handlers;
|
|
2114
2195
|
try {
|
|
2115
|
-
const absoluteFilePath =
|
|
2196
|
+
const absoluteFilePath = path4.resolve(rootDir, route.filePath);
|
|
2116
2197
|
handlers = await loadWsHandler(absoluteFilePath, ctx);
|
|
2117
2198
|
} catch (err) {
|
|
2118
2199
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -2158,8 +2239,8 @@ function attachWebSocket(options) {
|
|
|
2158
2239
|
}
|
|
2159
2240
|
|
|
2160
2241
|
// src/cli/generateSchemaFiles.ts
|
|
2161
|
-
import
|
|
2162
|
-
import
|
|
2242
|
+
import path5 from "path";
|
|
2243
|
+
import fs3 from "fs/promises";
|
|
2163
2244
|
|
|
2164
2245
|
// src/ast/generateZodSchema.ts
|
|
2165
2246
|
var CodeGenContext = class {
|
|
@@ -2468,7 +2549,7 @@ function getSchemaOutputPath(sourceFile, dist, rootDir) {
|
|
|
2468
2549
|
}
|
|
2469
2550
|
const idx = rel.lastIndexOf("/");
|
|
2470
2551
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
2471
|
-
return
|
|
2552
|
+
return path5.resolve(rootDir, dist, relDir, "zod.js");
|
|
2472
2553
|
}
|
|
2473
2554
|
function getRuntimeSchemaPath(filePath, dist, rootDir) {
|
|
2474
2555
|
let rel = filePath.replace(/\\/g, "/");
|
|
@@ -2479,7 +2560,7 @@ function getRuntimeSchemaPath(filePath, dist, rootDir) {
|
|
|
2479
2560
|
}
|
|
2480
2561
|
const idx = rel.lastIndexOf("/");
|
|
2481
2562
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
2482
|
-
return
|
|
2563
|
+
return path5.resolve(rootDir, dist, relDir, "zod.js");
|
|
2483
2564
|
}
|
|
2484
2565
|
function getHelpersImportPath(relDir) {
|
|
2485
2566
|
if (!relDir) return `./${HELPERS_FILENAME}`;
|
|
@@ -2529,7 +2610,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
2529
2610
|
}
|
|
2530
2611
|
const fileEntries = [];
|
|
2531
2612
|
for (const [filePath, fileSources] of sourcesByFile) {
|
|
2532
|
-
const relFile =
|
|
2613
|
+
const relFile = path5.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
2533
2614
|
const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
|
|
2534
2615
|
const allTypes = allTypesByFile.get(filePath) ?? /* @__PURE__ */ new Map();
|
|
2535
2616
|
let relForDir = relFile;
|
|
@@ -2544,7 +2625,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
2544
2625
|
}
|
|
2545
2626
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
2546
2627
|
if (usesCoerceHelpers(allSourceCode)) {
|
|
2547
|
-
const helpersPath =
|
|
2628
|
+
const helpersPath = path5.resolve(rootDir, dist, HELPERS_FILENAME);
|
|
2548
2629
|
await writeSchemaFile(helpersPath, generateHelpersFileSource());
|
|
2549
2630
|
}
|
|
2550
2631
|
await Promise.all(
|
|
@@ -2552,8 +2633,8 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
2552
2633
|
);
|
|
2553
2634
|
}
|
|
2554
2635
|
async function writeSchemaFile(outputPath, source) {
|
|
2555
|
-
await
|
|
2556
|
-
await
|
|
2636
|
+
await fs3.mkdir(path5.dirname(outputPath), { recursive: true });
|
|
2637
|
+
await fs3.writeFile(outputPath, source, "utf-8");
|
|
2557
2638
|
}
|
|
2558
2639
|
|
|
2559
2640
|
// src/server/createServer.ts
|
|
@@ -2601,15 +2682,15 @@ function limitStreamSize(stream, maxSize) {
|
|
|
2601
2682
|
}
|
|
2602
2683
|
});
|
|
2603
2684
|
}
|
|
2604
|
-
function findAllowedMethods(routes,
|
|
2685
|
+
function findAllowedMethods(routes, path10) {
|
|
2605
2686
|
const methods = /* @__PURE__ */ new Set();
|
|
2606
2687
|
for (const route of routes) {
|
|
2607
|
-
if (route.urlPath ===
|
|
2688
|
+
if (route.urlPath === path10) {
|
|
2608
2689
|
methods.add(route.method);
|
|
2609
2690
|
continue;
|
|
2610
2691
|
}
|
|
2611
2692
|
if (route.isDynamic) {
|
|
2612
|
-
const params = matchDynamicPath(route.urlPath,
|
|
2693
|
+
const params = matchDynamicPath(route.urlPath, path10, route.paramNames, route.isCatchAll);
|
|
2613
2694
|
if (params !== null) {
|
|
2614
2695
|
methods.add(route.method);
|
|
2615
2696
|
}
|
|
@@ -2695,7 +2776,7 @@ async function handleRequest(routes, rootDir, dist, req, res, configMiddlewares,
|
|
|
2695
2776
|
}
|
|
2696
2777
|
ctx.params = match.params;
|
|
2697
2778
|
const { route } = match;
|
|
2698
|
-
const absoluteFilePath =
|
|
2779
|
+
const absoluteFilePath = path6.resolve(rootDir, route.filePath);
|
|
2699
2780
|
const routeModule = await loadRouteModule(absoluteFilePath, route.method);
|
|
2700
2781
|
const input = await resolveInput(route.method, request);
|
|
2701
2782
|
const inputType = getInputTypeForMethod(route.method);
|
|
@@ -2769,8 +2850,8 @@ function applyPluginWrappers(server, handlerWrappers, upgradeWrappers) {
|
|
|
2769
2850
|
}
|
|
2770
2851
|
|
|
2771
2852
|
// src/cli/generateRoutes.ts
|
|
2772
|
-
import
|
|
2773
|
-
import
|
|
2853
|
+
import fs4 from "fs";
|
|
2854
|
+
import path7 from "path";
|
|
2774
2855
|
|
|
2775
2856
|
// src/middleware/loadMiddlewares.ts
|
|
2776
2857
|
var middlewareCache = /* @__PURE__ */ new Map();
|
|
@@ -2948,8 +3029,8 @@ function isFaapiConfigKey(key) {
|
|
|
2948
3029
|
async function createAppBase(options) {
|
|
2949
3030
|
const rootDir = options?.rootDir ?? process.cwd();
|
|
2950
3031
|
const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
|
|
2951
|
-
const routesPath =
|
|
2952
|
-
if (!
|
|
3032
|
+
const routesPath = path8.resolve(rootDir, dist, ROUTES_FILE);
|
|
3033
|
+
if (!fs5.existsSync(routesPath)) {
|
|
2953
3034
|
throw new Error(
|
|
2954
3035
|
`[faapi] ${dist}/${ROUTES_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
|
|
2955
3036
|
);
|
|
@@ -3152,8 +3233,8 @@ async function createAppBase(options) {
|
|
|
3152
3233
|
|
|
3153
3234
|
// src/router/scanRoutes.ts
|
|
3154
3235
|
import fg from "fast-glob";
|
|
3155
|
-
import
|
|
3156
|
-
import
|
|
3236
|
+
import path9 from "path";
|
|
3237
|
+
import fs6 from "fs";
|
|
3157
3238
|
|
|
3158
3239
|
// src/router/constants.ts
|
|
3159
3240
|
var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
@@ -3163,9 +3244,9 @@ function isHttpMethod(value) {
|
|
|
3163
3244
|
}
|
|
3164
3245
|
|
|
3165
3246
|
// src/utils/normalizePath.ts
|
|
3166
|
-
function normalizePath(
|
|
3167
|
-
if (!
|
|
3168
|
-
let result =
|
|
3247
|
+
function normalizePath(path10) {
|
|
3248
|
+
if (!path10) return "";
|
|
3249
|
+
let result = path10.replace(/\\/g, "/");
|
|
3169
3250
|
result = result.replace(/\/+/g, "/");
|
|
3170
3251
|
result = result.replace(/\/+$/, "");
|
|
3171
3252
|
if (result && !result.startsWith("/")) {
|
|
@@ -3214,38 +3295,38 @@ function filePathToUrlPath(filePath) {
|
|
|
3214
3295
|
// src/router/scanRoutes.ts
|
|
3215
3296
|
var APP_DIR = "src";
|
|
3216
3297
|
function toProdAbsPath(sourceAbsPath, rootDir, dist) {
|
|
3217
|
-
let rel =
|
|
3298
|
+
let rel = path9.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
|
|
3218
3299
|
if (rel.startsWith(`${APP_DIR}/`)) {
|
|
3219
3300
|
rel = rel.slice(APP_DIR.length + 1);
|
|
3220
3301
|
}
|
|
3221
3302
|
const prodRel = `${dist}/${rel.replace(/\.ts$/, ".js")}`;
|
|
3222
|
-
return
|
|
3303
|
+
return path9.resolve(rootDir, prodRel);
|
|
3223
3304
|
}
|
|
3224
3305
|
async function findMergedMiddlewares(routeFilePath, rootDir, dist) {
|
|
3225
|
-
const routeDir =
|
|
3226
|
-
const resolvedRoot =
|
|
3306
|
+
const routeDir = path9.dirname(routeFilePath);
|
|
3307
|
+
const resolvedRoot = path9.resolve(rootDir);
|
|
3227
3308
|
const mwPaths = [];
|
|
3228
|
-
let currentDir =
|
|
3309
|
+
let currentDir = path9.resolve(rootDir, routeDir);
|
|
3229
3310
|
while (true) {
|
|
3230
3311
|
if (dist) {
|
|
3231
|
-
const mwPath =
|
|
3232
|
-
const absMwPath =
|
|
3312
|
+
const mwPath = path9.join(currentDir, "middlewares.js");
|
|
3313
|
+
const absMwPath = path9.resolve(rootDir, mwPath);
|
|
3233
3314
|
const prodAbsMwPath = toProdAbsPath(absMwPath, rootDir, dist);
|
|
3234
|
-
if (
|
|
3315
|
+
if (fs6.existsSync(prodAbsMwPath)) {
|
|
3235
3316
|
mwPaths.push(prodAbsMwPath);
|
|
3236
3317
|
}
|
|
3237
3318
|
} else {
|
|
3238
3319
|
for (const ext of [".ts", ".js"]) {
|
|
3239
|
-
const mwPath =
|
|
3240
|
-
const absMwPath =
|
|
3241
|
-
if (
|
|
3320
|
+
const mwPath = path9.join(currentDir, `middlewares${ext}`);
|
|
3321
|
+
const absMwPath = path9.resolve(rootDir, mwPath);
|
|
3322
|
+
if (fs6.existsSync(absMwPath)) {
|
|
3242
3323
|
mwPaths.push(absMwPath);
|
|
3243
3324
|
break;
|
|
3244
3325
|
}
|
|
3245
3326
|
}
|
|
3246
3327
|
}
|
|
3247
3328
|
if (currentDir === resolvedRoot) break;
|
|
3248
|
-
const parentDir =
|
|
3329
|
+
const parentDir = path9.dirname(currentDir);
|
|
3249
3330
|
if (parentDir === currentDir) break;
|
|
3250
3331
|
currentDir = parentDir;
|
|
3251
3332
|
}
|
|
@@ -3307,7 +3388,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
3307
3388
|
const normalizedFile = file.replace(/\\/g, "/");
|
|
3308
3389
|
const fileName = normalizedFile.split("/").pop();
|
|
3309
3390
|
if (fileName === "handler.ts" || fileName === "handler.js") {
|
|
3310
|
-
const absPath =
|
|
3391
|
+
const absPath = path9.resolve(rootDir, normalizedFile);
|
|
3311
3392
|
const importPath = dist ? toProdAbsPath(absPath, rootDir, dist) : absPath;
|
|
3312
3393
|
const urlPath = filePathToUrlPath(normalizedFile);
|
|
3313
3394
|
const paramNames = extractParamNames(urlPath);
|
|
@@ -3388,6 +3469,7 @@ export {
|
|
|
3388
3469
|
invalidateProgramCache,
|
|
3389
3470
|
invokeHandler,
|
|
3390
3471
|
loadConfig,
|
|
3472
|
+
loadEnv,
|
|
3391
3473
|
logger,
|
|
3392
3474
|
resolveTypeNode
|
|
3393
3475
|
};
|