@faapi/faapi 0.0.0-canary.4e89b9b → 0.0.0-canary.856e11f

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/index.d.ts CHANGED
@@ -54,6 +54,17 @@ interface SseEvent {
54
54
  interface SseWriter {
55
55
  /** 推送一个 SSE 事件 */
56
56
  send(event: SseEvent): void;
57
+ /**
58
+ * 直接写入原始字节/字符串,不做任何 SSE 序列化
59
+ *
60
+ * 用于透传上游已有的 SSE 原文(如 LLM 中转平台逐 chunk 转发 OpenAI 响应)。
61
+ * 调用方负责保证内容符合 HTML5 SSE 规范;`send` 会再次加 `data: ` 前缀,
62
+ * 不适用于原文透传场景。
63
+ *
64
+ * 接受 string 或 Uint8Array(Buffer 是 Uint8Array 子类,自然兼容)。
65
+ * 与 `send` 一致:close/aborted 后静默忽略,不抛错。
66
+ */
67
+ sendRaw(chunk: string | Uint8Array): void;
57
68
  /** 推送一个 error 事件并关闭流(用于流式输出中报错的优雅终止) */
58
69
  sendError(error: unknown): void;
59
70
  /** 关闭流(多次调用安全) */
@@ -550,17 +561,19 @@ interface LifecycleContext {
550
561
  * } satisfies FaapiConfig;
551
562
  * ```
552
563
  *
553
- * 多环境配置:
564
+ * 自定义业务配置(任意 key):
554
565
  * ```ts
555
566
  * import type { FaapiConfig } from '@faapi/faapi';
556
567
  * export default {
557
568
  * cors: { origin: '*' },
558
- * // 自定义业务配置(任意 key)
559
- * db: { host: 'localhost', port: 5432 },
569
+ * // 通过 process.env.XXX 读取 .env 文件加载的环境变量
570
+ * db: { host: process.env.DB_HOST ?? 'localhost', port: 5432 },
560
571
  * } satisfies FaapiConfig;
561
572
  * ```
562
573
  *
563
- * 环境覆盖通过 faapi.config.{NODE_ENV}.ts 实现(如 faapi.config.production.ts)
574
+ * 多环境差异通过 `.env` 系列文件实现(见 `loadEnv`):
575
+ * - `.env` / `.env.local` / `.env.{env}` / `.env.{env}.local`
576
+ * - 环境由 `NODE_ENV > 'development'` 决定
564
577
  *
565
578
  * 框架元信息通过环境变量配置(不放在 config 内):
566
579
  * - `PORT`:服务端口,默认 3000
@@ -998,7 +1011,8 @@ declare function collectRouteSchemaSources(routes: RouteManifest, rootDir?: stri
998
1011
  * - dev 模式:`faapi dev` 启动时由 `compileConfig` 生成 `.faapi/faapi-config.js`
999
1012
  * - prod 模式:`faapi build` 时由 `compileConfig` 生成 `dist/faapi-config.js`
1000
1013
  *
1001
- * 产物由 `compileConfig` 在构建阶段合并 env 后固化,运行时不读源码、不现场编译、不按 env 合并。
1014
+ * 产物由 `compileConfig` 在构建阶段编译,运行时不读源码、不现场编译。
1015
+ * 环境变量由 `loadEnv` 从 `.env` 系列文件加载到 `process.env`,配置文件中通过 `process.env.XXX` 读取。
1002
1016
  *
1003
1017
  * - 产物存在 → import 并返回 default
1004
1018
  * - 产物不存在但源码有配置文件 → 抛错(强制 rebuild)
@@ -1010,6 +1024,26 @@ declare function collectRouteSchemaSources(routes: RouteManifest, rootDir?: stri
1010
1024
  */
1011
1025
  declare function loadConfig(rootDir: string, dist: string): Promise<Partial<FaapiConfig> | null>;
1012
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
+
1013
1047
  declare const VALIDATION_ERROR = "VALIDATION_ERROR";
1014
1048
  declare const ROUTE_NOT_FOUND = "ROUTE_NOT_FOUND";
1015
1049
  declare const METHOD_NOT_ALLOWED = "METHOD_NOT_ALLOWED";
@@ -1181,4 +1215,4 @@ type ProdApp = AppBase;
1181
1215
  */
1182
1216
  declare function createProdApp(options?: CreateAppOptions): Promise<ProdApp>;
1183
1217
 
1184
- 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(path9) {
1073
- super("ROUTE_NOT_FOUND", `Route not found: ${path9}`, 404);
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, path9, allowedMethods) {
1079
- super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path9}`, 405);
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
  }
@@ -1161,6 +1242,11 @@ function createSseWriter() {
1161
1242
  const text = encodeSseEvent(event);
1162
1243
  controller.enqueue(encoder.encode(text));
1163
1244
  },
1245
+ sendRaw(chunk) {
1246
+ if (closed || !controller) return;
1247
+ const bytes = typeof chunk === "string" ? encoder.encode(chunk) : chunk;
1248
+ controller.enqueue(bytes);
1249
+ },
1164
1250
  sendError(error) {
1165
1251
  if (closed || !controller) return;
1166
1252
  const message = error instanceof Error ? error.message : String(error);
@@ -1549,8 +1635,8 @@ async function invokeHandler(handler, ctx, body, middlewares, injectors) {
1549
1635
  }
1550
1636
 
1551
1637
  // src/cli/createAppCore.ts
1552
- import fs4 from "fs";
1553
- import path7 from "path";
1638
+ import fs5 from "fs";
1639
+ import path8 from "path";
1554
1640
  import { PassThrough } from "stream";
1555
1641
 
1556
1642
  // src/router/sortRoutes.ts
@@ -1603,45 +1689,45 @@ import {
1603
1689
  import { createSecureServer as createHttp2SecureServer } from "http2";
1604
1690
  import { readFileSync } from "fs";
1605
1691
  import { Readable as Readable2 } from "stream";
1606
- import path5 from "path";
1692
+ import path6 from "path";
1607
1693
 
1608
1694
  // src/router/matchRoute.ts
1609
- function matchRoute(routes, method, path9) {
1695
+ function matchRoute(routes, method, path10) {
1610
1696
  for (const route of routes) {
1611
1697
  if (route.method !== method) {
1612
1698
  continue;
1613
1699
  }
1614
1700
  if (!route.isDynamic) {
1615
- if (route.urlPath === path9) {
1701
+ if (route.urlPath === path10) {
1616
1702
  return { route, params: {} };
1617
1703
  }
1618
1704
  continue;
1619
1705
  }
1620
- const params = matchDynamicPath(route.urlPath, path9, route.paramNames, route.isCatchAll);
1706
+ const params = matchDynamicPath(route.urlPath, path10, route.paramNames, route.isCatchAll);
1621
1707
  if (params !== null) {
1622
1708
  return { route, params };
1623
1709
  }
1624
1710
  }
1625
1711
  return null;
1626
1712
  }
1627
- function matchWsRoute(wsRoutes, path9) {
1713
+ function matchWsRoute(wsRoutes, path10) {
1628
1714
  for (const route of wsRoutes) {
1629
1715
  if (!route.isDynamic) {
1630
- if (route.urlPath === path9) {
1716
+ if (route.urlPath === path10) {
1631
1717
  return { route, params: {} };
1632
1718
  }
1633
1719
  continue;
1634
1720
  }
1635
- const params = matchDynamicPath(route.urlPath, path9, route.paramNames, route.isCatchAll);
1721
+ const params = matchDynamicPath(route.urlPath, path10, route.paramNames, route.isCatchAll);
1636
1722
  if (params !== null) {
1637
1723
  return { route, params };
1638
1724
  }
1639
1725
  }
1640
1726
  return null;
1641
1727
  }
1642
- function matchDynamicPath(pattern, path9, paramNames, isCatchAll) {
1728
+ function matchDynamicPath(pattern, path10, paramNames, isCatchAll) {
1643
1729
  const patternSegments = pattern.split("/").filter(Boolean);
1644
- const pathSegments = path9.split("/").filter(Boolean);
1730
+ const pathSegments = path10.split("/").filter(Boolean);
1645
1731
  if (isCatchAll) {
1646
1732
  const nonCatchAllCount = patternSegments.length - 1;
1647
1733
  if (pathSegments.length <= nonCatchAllCount) {
@@ -1872,9 +1958,9 @@ async function validateInput(schemaPath, method, inputType, input) {
1872
1958
  function mapZodIssues(error) {
1873
1959
  return error.issues.map((issue) => {
1874
1960
  const code = mapZodCode(issue.code, issue.message);
1875
- const path9 = issue.path.map(String).join(".") || "";
1961
+ const path10 = issue.path.map(String).join(".") || "";
1876
1962
  return {
1877
- path: path9,
1963
+ path: path10,
1878
1964
  code,
1879
1965
  expected: issue.expected ?? mapExpectedFromMessage(issue.message),
1880
1966
  received: issue.received ?? mapReceivedFromMessage(issue.message),
@@ -1934,7 +2020,7 @@ function getClientIp(req) {
1934
2020
 
1935
2021
  // src/server/handleWsUpgrade.ts
1936
2022
  import { WebSocketServer, WebSocket } from "ws";
1937
- import path3 from "path";
2023
+ import path4 from "path";
1938
2024
 
1939
2025
  // src/errors/formatErrorResponse.ts
1940
2026
  function formatErrorResponse(error) {
@@ -2107,7 +2193,7 @@ function attachWebSocket(options) {
2107
2193
  const finalHandler = async () => {
2108
2194
  let handlers;
2109
2195
  try {
2110
- const absoluteFilePath = path3.resolve(rootDir, route.filePath);
2196
+ const absoluteFilePath = path4.resolve(rootDir, route.filePath);
2111
2197
  handlers = await loadWsHandler(absoluteFilePath, ctx);
2112
2198
  } catch (err) {
2113
2199
  const reason = err instanceof Error ? err.message : String(err);
@@ -2153,8 +2239,8 @@ function attachWebSocket(options) {
2153
2239
  }
2154
2240
 
2155
2241
  // src/cli/generateSchemaFiles.ts
2156
- import path4 from "path";
2157
- import fs2 from "fs/promises";
2242
+ import path5 from "path";
2243
+ import fs3 from "fs/promises";
2158
2244
 
2159
2245
  // src/ast/generateZodSchema.ts
2160
2246
  var CodeGenContext = class {
@@ -2463,7 +2549,7 @@ function getSchemaOutputPath(sourceFile, dist, rootDir) {
2463
2549
  }
2464
2550
  const idx = rel.lastIndexOf("/");
2465
2551
  const relDir = idx >= 0 ? rel.slice(0, idx) : "";
2466
- return path4.resolve(rootDir, dist, relDir, "zod.js");
2552
+ return path5.resolve(rootDir, dist, relDir, "zod.js");
2467
2553
  }
2468
2554
  function getRuntimeSchemaPath(filePath, dist, rootDir) {
2469
2555
  let rel = filePath.replace(/\\/g, "/");
@@ -2474,7 +2560,7 @@ function getRuntimeSchemaPath(filePath, dist, rootDir) {
2474
2560
  }
2475
2561
  const idx = rel.lastIndexOf("/");
2476
2562
  const relDir = idx >= 0 ? rel.slice(0, idx) : "";
2477
- return path4.resolve(rootDir, dist, relDir, "zod.js");
2563
+ return path5.resolve(rootDir, dist, relDir, "zod.js");
2478
2564
  }
2479
2565
  function getHelpersImportPath(relDir) {
2480
2566
  if (!relDir) return `./${HELPERS_FILENAME}`;
@@ -2524,7 +2610,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
2524
2610
  }
2525
2611
  const fileEntries = [];
2526
2612
  for (const [filePath, fileSources] of sourcesByFile) {
2527
- const relFile = path4.relative(rootDir, filePath).replace(/\\/g, "/");
2613
+ const relFile = path5.relative(rootDir, filePath).replace(/\\/g, "/");
2528
2614
  const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
2529
2615
  const allTypes = allTypesByFile.get(filePath) ?? /* @__PURE__ */ new Map();
2530
2616
  let relForDir = relFile;
@@ -2539,7 +2625,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
2539
2625
  }
2540
2626
  const allSourceCode = fileEntries.map((e) => e.source).join("\n");
2541
2627
  if (usesCoerceHelpers(allSourceCode)) {
2542
- const helpersPath = path4.resolve(rootDir, dist, HELPERS_FILENAME);
2628
+ const helpersPath = path5.resolve(rootDir, dist, HELPERS_FILENAME);
2543
2629
  await writeSchemaFile(helpersPath, generateHelpersFileSource());
2544
2630
  }
2545
2631
  await Promise.all(
@@ -2547,8 +2633,8 @@ async function generateSchemaFiles(routes, rootDir, dist) {
2547
2633
  );
2548
2634
  }
2549
2635
  async function writeSchemaFile(outputPath, source) {
2550
- await fs2.mkdir(path4.dirname(outputPath), { recursive: true });
2551
- await fs2.writeFile(outputPath, source, "utf-8");
2636
+ await fs3.mkdir(path5.dirname(outputPath), { recursive: true });
2637
+ await fs3.writeFile(outputPath, source, "utf-8");
2552
2638
  }
2553
2639
 
2554
2640
  // src/server/createServer.ts
@@ -2596,15 +2682,15 @@ function limitStreamSize(stream, maxSize) {
2596
2682
  }
2597
2683
  });
2598
2684
  }
2599
- function findAllowedMethods(routes, path9) {
2685
+ function findAllowedMethods(routes, path10) {
2600
2686
  const methods = /* @__PURE__ */ new Set();
2601
2687
  for (const route of routes) {
2602
- if (route.urlPath === path9) {
2688
+ if (route.urlPath === path10) {
2603
2689
  methods.add(route.method);
2604
2690
  continue;
2605
2691
  }
2606
2692
  if (route.isDynamic) {
2607
- const params = matchDynamicPath(route.urlPath, path9, route.paramNames, route.isCatchAll);
2693
+ const params = matchDynamicPath(route.urlPath, path10, route.paramNames, route.isCatchAll);
2608
2694
  if (params !== null) {
2609
2695
  methods.add(route.method);
2610
2696
  }
@@ -2690,7 +2776,7 @@ async function handleRequest(routes, rootDir, dist, req, res, configMiddlewares,
2690
2776
  }
2691
2777
  ctx.params = match.params;
2692
2778
  const { route } = match;
2693
- const absoluteFilePath = path5.resolve(rootDir, route.filePath);
2779
+ const absoluteFilePath = path6.resolve(rootDir, route.filePath);
2694
2780
  const routeModule = await loadRouteModule(absoluteFilePath, route.method);
2695
2781
  const input = await resolveInput(route.method, request);
2696
2782
  const inputType = getInputTypeForMethod(route.method);
@@ -2764,8 +2850,8 @@ function applyPluginWrappers(server, handlerWrappers, upgradeWrappers) {
2764
2850
  }
2765
2851
 
2766
2852
  // src/cli/generateRoutes.ts
2767
- import fs3 from "fs";
2768
- import path6 from "path";
2853
+ import fs4 from "fs";
2854
+ import path7 from "path";
2769
2855
 
2770
2856
  // src/middleware/loadMiddlewares.ts
2771
2857
  var middlewareCache = /* @__PURE__ */ new Map();
@@ -2943,8 +3029,8 @@ function isFaapiConfigKey(key) {
2943
3029
  async function createAppBase(options) {
2944
3030
  const rootDir = options?.rootDir ?? process.cwd();
2945
3031
  const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
2946
- const routesPath = path7.resolve(rootDir, dist, ROUTES_FILE);
2947
- if (!fs4.existsSync(routesPath)) {
3032
+ const routesPath = path8.resolve(rootDir, dist, ROUTES_FILE);
3033
+ if (!fs5.existsSync(routesPath)) {
2948
3034
  throw new Error(
2949
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`
2950
3036
  );
@@ -3147,8 +3233,8 @@ async function createAppBase(options) {
3147
3233
 
3148
3234
  // src/router/scanRoutes.ts
3149
3235
  import fg from "fast-glob";
3150
- import path8 from "path";
3151
- import fs5 from "fs";
3236
+ import path9 from "path";
3237
+ import fs6 from "fs";
3152
3238
 
3153
3239
  // src/router/constants.ts
3154
3240
  var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
@@ -3158,9 +3244,9 @@ function isHttpMethod(value) {
3158
3244
  }
3159
3245
 
3160
3246
  // src/utils/normalizePath.ts
3161
- function normalizePath(path9) {
3162
- if (!path9) return "";
3163
- let result = path9.replace(/\\/g, "/");
3247
+ function normalizePath(path10) {
3248
+ if (!path10) return "";
3249
+ let result = path10.replace(/\\/g, "/");
3164
3250
  result = result.replace(/\/+/g, "/");
3165
3251
  result = result.replace(/\/+$/, "");
3166
3252
  if (result && !result.startsWith("/")) {
@@ -3209,38 +3295,38 @@ function filePathToUrlPath(filePath) {
3209
3295
  // src/router/scanRoutes.ts
3210
3296
  var APP_DIR = "src";
3211
3297
  function toProdAbsPath(sourceAbsPath, rootDir, dist) {
3212
- let rel = path8.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
3298
+ let rel = path9.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
3213
3299
  if (rel.startsWith(`${APP_DIR}/`)) {
3214
3300
  rel = rel.slice(APP_DIR.length + 1);
3215
3301
  }
3216
3302
  const prodRel = `${dist}/${rel.replace(/\.ts$/, ".js")}`;
3217
- return path8.resolve(rootDir, prodRel);
3303
+ return path9.resolve(rootDir, prodRel);
3218
3304
  }
3219
3305
  async function findMergedMiddlewares(routeFilePath, rootDir, dist) {
3220
- const routeDir = path8.dirname(routeFilePath);
3221
- const resolvedRoot = path8.resolve(rootDir);
3306
+ const routeDir = path9.dirname(routeFilePath);
3307
+ const resolvedRoot = path9.resolve(rootDir);
3222
3308
  const mwPaths = [];
3223
- let currentDir = path8.resolve(rootDir, routeDir);
3309
+ let currentDir = path9.resolve(rootDir, routeDir);
3224
3310
  while (true) {
3225
3311
  if (dist) {
3226
- const mwPath = path8.join(currentDir, "middlewares.js");
3227
- const absMwPath = path8.resolve(rootDir, mwPath);
3312
+ const mwPath = path9.join(currentDir, "middlewares.js");
3313
+ const absMwPath = path9.resolve(rootDir, mwPath);
3228
3314
  const prodAbsMwPath = toProdAbsPath(absMwPath, rootDir, dist);
3229
- if (fs5.existsSync(prodAbsMwPath)) {
3315
+ if (fs6.existsSync(prodAbsMwPath)) {
3230
3316
  mwPaths.push(prodAbsMwPath);
3231
3317
  }
3232
3318
  } else {
3233
3319
  for (const ext of [".ts", ".js"]) {
3234
- const mwPath = path8.join(currentDir, `middlewares${ext}`);
3235
- const absMwPath = path8.resolve(rootDir, mwPath);
3236
- if (fs5.existsSync(absMwPath)) {
3320
+ const mwPath = path9.join(currentDir, `middlewares${ext}`);
3321
+ const absMwPath = path9.resolve(rootDir, mwPath);
3322
+ if (fs6.existsSync(absMwPath)) {
3237
3323
  mwPaths.push(absMwPath);
3238
3324
  break;
3239
3325
  }
3240
3326
  }
3241
3327
  }
3242
3328
  if (currentDir === resolvedRoot) break;
3243
- const parentDir = path8.dirname(currentDir);
3329
+ const parentDir = path9.dirname(currentDir);
3244
3330
  if (parentDir === currentDir) break;
3245
3331
  currentDir = parentDir;
3246
3332
  }
@@ -3302,7 +3388,7 @@ async function scanRoutes(rootDir, patterns, dist) {
3302
3388
  const normalizedFile = file.replace(/\\/g, "/");
3303
3389
  const fileName = normalizedFile.split("/").pop();
3304
3390
  if (fileName === "handler.ts" || fileName === "handler.js") {
3305
- const absPath = path8.resolve(rootDir, normalizedFile);
3391
+ const absPath = path9.resolve(rootDir, normalizedFile);
3306
3392
  const importPath = dist ? toProdAbsPath(absPath, rootDir, dist) : absPath;
3307
3393
  const urlPath = filePathToUrlPath(normalizedFile);
3308
3394
  const paramNames = extractParamNames(urlPath);
@@ -3383,6 +3469,7 @@ export {
3383
3469
  invalidateProgramCache,
3384
3470
  invokeHandler,
3385
3471
  loadConfig,
3472
+ loadEnv,
3386
3473
  logger,
3387
3474
  resolveTypeNode
3388
3475
  };