@faapi/faapi 6.24.0 → 6.26.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/testing.js CHANGED
@@ -312,14 +312,14 @@ var ValidationError = class extends FaapiError {
312
312
  issues;
313
313
  };
314
314
  var RouteNotFoundError = class extends FaapiError {
315
- constructor(path17) {
316
- super("ROUTE_NOT_FOUND", `Route not found: ${path17}`, 404);
315
+ constructor(path18) {
316
+ super("ROUTE_NOT_FOUND", `Route not found: ${path18}`, 404);
317
317
  this.name = "RouteNotFoundError";
318
318
  }
319
319
  };
320
320
  var MethodNotAllowedError = class extends FaapiError {
321
- constructor(method, path17, allowedMethods) {
322
- super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path17}`, 405);
321
+ constructor(method, path18, allowedMethods) {
322
+ super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path18}`, 405);
323
323
  this.allowedMethods = allowedMethods;
324
324
  this.name = "MethodNotAllowedError";
325
325
  }
@@ -554,6 +554,50 @@ function queryToObject(params) {
554
554
  return result;
555
555
  }
556
556
 
557
+ // src/utils/readResource.ts
558
+ import path2 from "path";
559
+ import fs2 from "fs/promises";
560
+
561
+ // src/utils/prodPaths.ts
562
+ import path from "path";
563
+ import fs from "fs";
564
+ var APP_DIR = "src";
565
+ function toProdFilePath(filePath, dist) {
566
+ let rel = filePath.replace(/\\/g, "/");
567
+ if (rel.startsWith("src/")) {
568
+ rel = rel.slice(4);
569
+ }
570
+ const jsPath = rel.replace(/\.ts$/, ".js");
571
+ return jsPath.startsWith(`${dist}/`) ? jsPath : `${dist}/${jsPath}`;
572
+ }
573
+ function toProdExtension(filePath) {
574
+ if (filePath.endsWith(".ts")) return filePath.slice(0, -3) + ".js";
575
+ if (filePath.endsWith(".tsx")) return filePath.slice(0, -4) + ".js";
576
+ if (filePath.endsWith(".jsx")) return filePath.slice(0, -4) + ".js";
577
+ return filePath;
578
+ }
579
+ function toRealPath(p) {
580
+ try {
581
+ return fs.realpathSync(p);
582
+ } catch {
583
+ return p;
584
+ }
585
+ }
586
+ function isInsideDir(filePath, dir) {
587
+ const rel = path.relative(dir, filePath);
588
+ return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel);
589
+ }
590
+
591
+ // src/utils/readResource.ts
592
+ var ACTIVE_RESOURCES_DIR_KEY = /* @__PURE__ */ Symbol.for("faapi.resources.dir");
593
+ function setActiveResourcesDir(dir) {
594
+ if (dir === null) {
595
+ delete globalThis[ACTIVE_RESOURCES_DIR_KEY];
596
+ } else {
597
+ globalThis[ACTIVE_RESOURCES_DIR_KEY] = dir;
598
+ }
599
+ }
600
+
557
601
  // src/runtime/createContext.ts
558
602
  function resolveRequestId(request) {
559
603
  const header = request.headers.get("x-request-id");
@@ -731,7 +775,7 @@ function createContextFromUrl(request, url, params, config = {}, ip = "", regist
731
775
  function createTestContext(options) {
732
776
  const {
733
777
  method = "GET",
734
- path: path17,
778
+ path: path18,
735
779
  query,
736
780
  headers,
737
781
  params = {},
@@ -740,7 +784,7 @@ function createTestContext(options) {
740
784
  registries,
741
785
  resourcesDir
742
786
  } = options;
743
- const url = new URL(`http://localhost${path17}`);
787
+ const url = new URL(`http://localhost${path18}`);
744
788
  if (query) {
745
789
  for (const [key, value] of Object.entries(query)) {
746
790
  if (Array.isArray(value)) {
@@ -756,6 +800,9 @@ function createTestContext(options) {
756
800
  method,
757
801
  headers
758
802
  });
803
+ if (resourcesDir) {
804
+ setActiveResourcesDir(resourcesDir);
805
+ }
759
806
  return createContext(request, params, config, ip, registries, resourcesDir);
760
807
  }
761
808
 
@@ -1339,23 +1386,23 @@ async function invokeHandler(handler, ctx, body, middlewares, injectors) {
1339
1386
  }
1340
1387
 
1341
1388
  // src/testServer.ts
1342
- import path16 from "path";
1389
+ import path17 from "path";
1343
1390
  import os from "os";
1344
- import fs13 from "fs/promises";
1391
+ import fs14 from "fs/promises";
1345
1392
 
1346
1393
  // src/router/scanRoutes.ts
1347
1394
  import fg from "fast-glob";
1348
- import path2 from "path";
1349
- import fs3 from "fs";
1395
+ import path3 from "path";
1396
+ import fs4 from "fs";
1350
1397
 
1351
1398
  // src/router/constants.ts
1352
1399
  var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
1353
1400
  var HTTP_METHOD_SET = new Set(HTTP_METHODS);
1354
1401
 
1355
1402
  // src/utils/normalizePath.ts
1356
- function normalizePath(path17) {
1357
- if (!path17) return "";
1358
- let result = path17.replace(/\\/g, "/");
1403
+ function normalizePath(path18) {
1404
+ if (!path18) return "";
1405
+ let result = path18.replace(/\\/g, "/");
1359
1406
  result = result.replace(/\/+/g, "/");
1360
1407
  result = result.replace(/\/+$/, "");
1361
1408
  if (result && !result.startsWith("/")) {
@@ -1402,7 +1449,7 @@ function filePathToUrlPath(filePath) {
1402
1449
  }
1403
1450
 
1404
1451
  // src/utils/importWithCacheBust.ts
1405
- import fs from "fs";
1452
+ import fs3 from "fs";
1406
1453
  import { pathToFileURL } from "url";
1407
1454
  var loadTs;
1408
1455
  function getVitestImportActual() {
@@ -1418,7 +1465,7 @@ async function importWithCacheBust(filePath, bustViteCache = false) {
1418
1465
  if (bustViteCache) {
1419
1466
  let mtimeMs = 0;
1420
1467
  try {
1421
- mtimeMs = fs.statSync(filePath).mtimeMs;
1468
+ mtimeMs = fs3.statSync(filePath).mtimeMs;
1422
1469
  } catch {
1423
1470
  }
1424
1471
  const cached = bustCache.get(filePath);
@@ -1515,36 +1562,6 @@ async function loadMergedMiddlewares(middlewarePaths) {
1515
1562
  return { middlewares: mergedMiddlewares, injectors: mergedInjectors };
1516
1563
  }
1517
1564
 
1518
- // src/utils/prodPaths.ts
1519
- import path from "path";
1520
- import fs2 from "fs";
1521
- var APP_DIR = "src";
1522
- function toProdFilePath(filePath, dist) {
1523
- let rel = filePath.replace(/\\/g, "/");
1524
- if (rel.startsWith("src/")) {
1525
- rel = rel.slice(4);
1526
- }
1527
- const jsPath = rel.replace(/\.ts$/, ".js");
1528
- return jsPath.startsWith(`${dist}/`) ? jsPath : `${dist}/${jsPath}`;
1529
- }
1530
- function toProdExtension(filePath) {
1531
- if (filePath.endsWith(".ts")) return filePath.slice(0, -3) + ".js";
1532
- if (filePath.endsWith(".tsx")) return filePath.slice(0, -4) + ".js";
1533
- if (filePath.endsWith(".jsx")) return filePath.slice(0, -4) + ".js";
1534
- return filePath;
1535
- }
1536
- function toRealPath(p) {
1537
- try {
1538
- return fs2.realpathSync(p);
1539
- } catch {
1540
- return p;
1541
- }
1542
- }
1543
- function isInsideDir(filePath, dir) {
1544
- const rel = path.relative(dir, filePath);
1545
- return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel);
1546
- }
1547
-
1548
1565
  // src/router/scanRoutes.ts
1549
1566
  var HTTP_OR_WS_EXPORT_RE = new RegExp(
1550
1567
  String.raw`export\s+(?:async\s+)?(?:function\s+|const\s+)(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS|WS)\b`,
@@ -1560,34 +1577,34 @@ function extractExportsFromSource(source) {
1560
1577
  return names;
1561
1578
  }
1562
1579
  function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
1563
- const routeDir = path2.dirname(routeFilePath);
1564
- const resolvedRoot = path2.resolve(rootDir);
1580
+ const routeDir = path3.dirname(routeFilePath);
1581
+ const resolvedRoot = path3.resolve(rootDir);
1565
1582
  const paths = [];
1566
- let currentDir = path2.resolve(rootDir, routeDir);
1583
+ let currentDir = path3.resolve(rootDir, routeDir);
1567
1584
  while (true) {
1568
1585
  if (dist) {
1569
- const mwTsPath = path2.join(currentDir, "middlewares.ts");
1570
- const mwJsPath = path2.join(currentDir, "middlewares.js");
1571
- const absTsPath = path2.resolve(rootDir, mwTsPath);
1572
- const absJsPath = path2.resolve(rootDir, mwJsPath);
1573
- const absMwPath = fs3.existsSync(absTsPath) ? absTsPath : fs3.existsSync(absJsPath) ? absJsPath : null;
1586
+ const mwTsPath = path3.join(currentDir, "middlewares.ts");
1587
+ const mwJsPath = path3.join(currentDir, "middlewares.js");
1588
+ const absTsPath = path3.resolve(rootDir, mwTsPath);
1589
+ const absJsPath = path3.resolve(rootDir, mwJsPath);
1590
+ const absMwPath = fs4.existsSync(absTsPath) ? absTsPath : fs4.existsSync(absJsPath) ? absJsPath : null;
1574
1591
  if (absMwPath) {
1575
- const relMwPath = path2.relative(rootDir, absMwPath);
1576
- const prodAbsPath = path2.resolve(rootDir, toProdFilePath(relMwPath, dist));
1592
+ const relMwPath = path3.relative(rootDir, absMwPath);
1593
+ const prodAbsPath = path3.resolve(rootDir, toProdFilePath(relMwPath, dist));
1577
1594
  paths.push(prodAbsPath);
1578
1595
  }
1579
1596
  } else {
1580
1597
  for (const ext of [".ts", ".js"]) {
1581
- const mwPath = path2.join(currentDir, `middlewares${ext}`);
1582
- const absMwPath = path2.resolve(rootDir, mwPath);
1583
- if (fs3.existsSync(absMwPath)) {
1598
+ const mwPath = path3.join(currentDir, `middlewares${ext}`);
1599
+ const absMwPath = path3.resolve(rootDir, mwPath);
1600
+ if (fs4.existsSync(absMwPath)) {
1584
1601
  paths.push(absMwPath);
1585
1602
  break;
1586
1603
  }
1587
1604
  }
1588
1605
  }
1589
1606
  if (currentDir === resolvedRoot) break;
1590
- const parentDir = path2.dirname(currentDir);
1607
+ const parentDir = path3.dirname(currentDir);
1591
1608
  if (parentDir === currentDir) break;
1592
1609
  currentDir = parentDir;
1593
1610
  }
@@ -1606,7 +1623,7 @@ async function scanRoutes(rootDir, patterns, dist) {
1606
1623
  const normalizedFile = file.replace(/\\/g, "/");
1607
1624
  const fileName = normalizedFile.split("/").pop();
1608
1625
  if (fileName === "handler.ts" || fileName === "handler.js") {
1609
- const absPath = path2.resolve(rootDir, normalizedFile);
1626
+ const absPath = path3.resolve(rootDir, normalizedFile);
1610
1627
  const urlPath = filePathToUrlPath(normalizedFile);
1611
1628
  const paramNames = extractParamNames(urlPath);
1612
1629
  const isDynamic = paramNames.length > 0;
@@ -1619,7 +1636,7 @@ async function scanRoutes(rootDir, patterns, dist) {
1619
1636
  const mwPaths = collectMiddlewarePaths(normalizedFile, rootDir);
1620
1637
  middlewareBundle = await loadMergedMiddlewares(mwPaths);
1621
1638
  }
1622
- const source = await fs3.promises.readFile(absPath, "utf8").catch(() => "");
1639
+ const source = await fs4.promises.readFile(absPath, "utf8").catch(() => "");
1623
1640
  const exportNames = extractExportsFromSource(source);
1624
1641
  const methods = HTTP_METHODS.filter((m) => exportNames.has(m));
1625
1642
  for (const method of methods) {
@@ -1672,24 +1689,24 @@ function sortRoutes(routes) {
1672
1689
  }
1673
1690
 
1674
1691
  // src/cli/generateSchemaFiles.ts
1675
- import path7 from "path";
1692
+ import path8 from "path";
1676
1693
 
1677
1694
  // src/ast/createProgram.ts
1678
1695
  import ts2 from "typescript";
1679
- import fs4 from "fs";
1680
- import path3 from "path";
1696
+ import fs5 from "fs";
1697
+ import path4 from "path";
1681
1698
  var programCache = /* @__PURE__ */ new Map();
1682
1699
  var tsConfigCache = /* @__PURE__ */ new Map();
1683
1700
  function findTsConfig(filePath) {
1684
- let dir = path3.dirname(filePath);
1685
- const root = path3.parse(dir).root;
1701
+ let dir = path4.dirname(filePath);
1702
+ const root = path4.parse(dir).root;
1686
1703
  while (true) {
1687
- const candidate = path3.join(dir, "tsconfig.json");
1688
- if (fs4.existsSync(candidate)) {
1704
+ const candidate = path4.join(dir, "tsconfig.json");
1705
+ if (fs5.existsSync(candidate)) {
1689
1706
  return candidate;
1690
1707
  }
1691
1708
  if (dir === root) return null;
1692
- const parent = path3.dirname(dir);
1709
+ const parent = path4.dirname(dir);
1693
1710
  if (parent === dir) return null;
1694
1711
  dir = parent;
1695
1712
  }
@@ -1699,13 +1716,13 @@ function parseTsConfig(tsconfigPath) {
1699
1716
  if (cached) return cached;
1700
1717
  const result = { fileNames: [] };
1701
1718
  try {
1702
- const configFile = ts2.readConfigFile(tsconfigPath, (p) => fs4.readFileSync(p, "utf-8"));
1719
+ const configFile = ts2.readConfigFile(tsconfigPath, (p) => fs5.readFileSync(p, "utf-8"));
1703
1720
  if (configFile.error) {
1704
1721
  tsConfigCache.set(tsconfigPath, result);
1705
1722
  return result;
1706
1723
  }
1707
1724
  const config = configFile.config ?? {};
1708
- const basePath = path3.dirname(tsconfigPath);
1725
+ const basePath = path4.dirname(tsconfigPath);
1709
1726
  const parsed = ts2.parseJsonConfigFileContent(
1710
1727
  config,
1711
1728
  ts2.sys,
@@ -2705,7 +2722,7 @@ function extractSchema(typeNode, sourceFile) {
2705
2722
  }
2706
2723
 
2707
2724
  // src/cli/collectRouteSchemaSources.ts
2708
- import path4 from "path";
2725
+ import path5 from "path";
2709
2726
  import ts6 from "typescript";
2710
2727
  function findExportedTypeName(sourceFile, name) {
2711
2728
  for (const statement of sourceFile.statements) {
@@ -2721,7 +2738,7 @@ function findExportedTypeName(sourceFile, name) {
2721
2738
  function collectRouteSchemaSources(routes, rootDir, wsRoutes) {
2722
2739
  const methodsByFile = /* @__PURE__ */ new Map();
2723
2740
  for (const route of routes) {
2724
- const filePath = rootDir ? path4.resolve(rootDir, route.filePath) : route.filePath;
2741
+ const filePath = rootDir ? path5.resolve(rootDir, route.filePath) : route.filePath;
2725
2742
  let entry = methodsByFile.get(filePath);
2726
2743
  if (!entry) {
2727
2744
  entry = { urlPath: route.urlPath, methods: /* @__PURE__ */ new Set() };
@@ -2732,7 +2749,7 @@ function collectRouteSchemaSources(routes, rootDir, wsRoutes) {
2732
2749
  const wsFiles = [];
2733
2750
  for (const wsRoute of wsRoutes ?? []) {
2734
2751
  wsFiles.push({
2735
- filePath: rootDir ? path4.resolve(rootDir, wsRoute.filePath) : wsRoute.filePath,
2752
+ filePath: rootDir ? path5.resolve(rootDir, wsRoute.filePath) : wsRoute.filePath,
2736
2753
  urlPath: wsRoute.urlPath
2737
2754
  });
2738
2755
  }
@@ -3127,17 +3144,17 @@ function generateZodSchemaSourceParts(typeInfo, resolveType, exportName, coerce
3127
3144
  }
3128
3145
 
3129
3146
  // src/cli/generateZodArtifacts.ts
3130
- import path6 from "path";
3147
+ import path7 from "path";
3131
3148
  import { existsSync } from "fs";
3132
3149
 
3133
3150
  // src/utils/atomicWrite.ts
3134
- import path5 from "path";
3135
- import fs5 from "fs";
3151
+ import path6 from "path";
3152
+ import fs6 from "fs";
3136
3153
  async function atomicWriteFile(outputPath, content) {
3137
- await fs5.promises.mkdir(path5.dirname(outputPath), { recursive: true });
3154
+ await fs6.promises.mkdir(path6.dirname(outputPath), { recursive: true });
3138
3155
  const tmp = `${outputPath}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
3139
- await fs5.promises.writeFile(tmp, content, "utf-8");
3140
- await fs5.promises.rename(tmp, outputPath);
3156
+ await fs6.promises.writeFile(tmp, content, "utf-8");
3157
+ await fs6.promises.rename(tmp, outputPath);
3141
3158
  }
3142
3159
 
3143
3160
  // src/cli/generateZodArtifacts.ts
@@ -3155,7 +3172,7 @@ async function generateZodArtifacts(sources, options) {
3155
3172
  }
3156
3173
  const fileEntries = [];
3157
3174
  for (const [filePath, fileSources] of sourcesByFile) {
3158
- const relFile = path6.relative(rootDir, filePath).replace(/\\/g, "/");
3175
+ const relFile = path7.relative(rootDir, filePath).replace(/\\/g, "/");
3159
3176
  const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
3160
3177
  const resolver = resolversByFile.get(filePath);
3161
3178
  let relForDir = relFile;
@@ -3173,7 +3190,7 @@ async function generateZodArtifacts(sources, options) {
3173
3190
  }
3174
3191
  const allSourceCode = fileEntries.map((e) => e.source).join("\n");
3175
3192
  if (usesCoerceHelpers(allSourceCode)) {
3176
- const helpersPath = path6.resolve(rootDir, dist, HELPERS_FILENAME);
3193
+ const helpersPath = path7.resolve(rootDir, dist, HELPERS_FILENAME);
3177
3194
  if (!existsSync(helpersPath)) {
3178
3195
  await atomicWriteFile(helpersPath, generateHelpersFileSource());
3179
3196
  }
@@ -3191,7 +3208,7 @@ function getSchemaOutputPath(sourceFile, dist, rootDir) {
3191
3208
  }
3192
3209
  const idx = rel.lastIndexOf("/");
3193
3210
  const relDir = idx >= 0 ? rel.slice(0, idx) : "";
3194
- return path7.resolve(rootDir, dist, relDir, "zod.js");
3211
+ return path8.resolve(rootDir, dist, relDir, "zod.js");
3195
3212
  }
3196
3213
  function getRuntimeSchemaPath(filePath, dist, rootDir) {
3197
3214
  let rel = filePath.replace(/\\/g, "/");
@@ -3202,7 +3219,7 @@ function getRuntimeSchemaPath(filePath, dist, rootDir) {
3202
3219
  }
3203
3220
  const idx = rel.lastIndexOf("/");
3204
3221
  const relDir = idx >= 0 ? rel.slice(0, idx) : "";
3205
- return path7.resolve(rootDir, dist, relDir, "zod.js");
3222
+ return path8.resolve(rootDir, dist, relDir, "zod.js");
3206
3223
  }
3207
3224
  function getHelpersImportPath(relDir) {
3208
3225
  if (!relDir) return `./${HELPERS_FILENAME}`;
@@ -3259,18 +3276,18 @@ async function generateSchemaFiles(routes, rootDir, dist, wsRoutes) {
3259
3276
  }
3260
3277
 
3261
3278
  // src/cli/compileOnDemand.ts
3262
- import path12 from "path";
3263
- import fs10 from "fs";
3279
+ import path13 from "path";
3280
+ import fs11 from "fs";
3264
3281
 
3265
3282
  // src/cli/compileSourceFiles.ts
3266
- import path10 from "path";
3267
- import fs8 from "fs";
3283
+ import path11 from "path";
3284
+ import fs9 from "fs";
3268
3285
  import fg2 from "fast-glob";
3269
3286
 
3270
3287
  // src/cli/aliasPlugin.ts
3271
3288
  import ts8 from "typescript";
3272
- import path9 from "path";
3273
- import fs7 from "fs";
3289
+ import path10 from "path";
3290
+ import fs8 from "fs";
3274
3291
 
3275
3292
  // src/utils/resolveAlias.ts
3276
3293
  function resolveAlias(specifier, config) {
@@ -3297,15 +3314,15 @@ function resolveAlias(specifier, config) {
3297
3314
 
3298
3315
  // src/utils/readTsconfig.ts
3299
3316
  import ts7 from "typescript";
3300
- import path8 from "path";
3301
- import fs6 from "fs";
3317
+ import path9 from "path";
3318
+ import fs7 from "fs";
3302
3319
  var tsconfigCache = /* @__PURE__ */ new Map();
3303
3320
  function readTsconfig(rootDir) {
3304
- const tsconfigPath = path8.resolve(rootDir, "tsconfig.json");
3305
- if (!fs6.existsSync(tsconfigPath)) return null;
3321
+ const tsconfigPath = path9.resolve(rootDir, "tsconfig.json");
3322
+ if (!fs7.existsSync(tsconfigPath)) return null;
3306
3323
  let mtimeMs;
3307
3324
  try {
3308
- mtimeMs = fs6.statSync(tsconfigPath).mtimeMs;
3325
+ mtimeMs = fs7.statSync(tsconfigPath).mtimeMs;
3309
3326
  } catch {
3310
3327
  return null;
3311
3328
  }
@@ -3321,7 +3338,7 @@ function readTsconfig(rootDir) {
3321
3338
  const config = rawPaths ? (() => {
3322
3339
  const paths = {};
3323
3340
  for (const [pattern, targets] of Object.entries(rawPaths)) {
3324
- paths[pattern] = targets.map((t) => path8.resolve(baseUrl, t));
3341
+ paths[pattern] = targets.map((t) => path9.resolve(baseUrl, t));
3325
3342
  }
3326
3343
  return { baseUrl, paths };
3327
3344
  })() : null;
@@ -3331,26 +3348,26 @@ function readTsconfig(rootDir) {
3331
3348
 
3332
3349
  // src/cli/aliasPlugin.ts
3333
3350
  function toProdImportPath(sourceFile, importer) {
3334
- const importerDir = path9.dirname(importer);
3335
- let rel = path9.relative(importerDir, sourceFile);
3336
- rel = rel.split(path9.sep).join("/");
3351
+ const importerDir = path10.dirname(importer);
3352
+ let rel = path10.relative(importerDir, sourceFile);
3353
+ rel = rel.split(path10.sep).join("/");
3337
3354
  if (!rel.startsWith(".")) rel = "./" + rel;
3338
3355
  return toProdExtension(rel);
3339
3356
  }
3340
3357
  function toStrippedProdImportPath(sourceFile, rootDir) {
3341
- const appDirAbs = toRealPath(path9.resolve(rootDir, APP_DIR));
3358
+ const appDirAbs = toRealPath(path10.resolve(rootDir, APP_DIR));
3342
3359
  const sourceReal = toRealPath(sourceFile);
3343
- let rel = path9.relative(appDirAbs, sourceReal);
3344
- rel = rel.split(path9.sep).join("/");
3360
+ let rel = path10.relative(appDirAbs, sourceReal);
3361
+ rel = rel.split(path10.sep).join("/");
3345
3362
  if (!rel.startsWith(".")) rel = "./" + rel;
3346
3363
  return toProdExtension(rel);
3347
3364
  }
3348
3365
  function toProdImportFromImporter(importer, rootDir, relFromDist) {
3349
- const importerRel = path9.relative(toRealPath(path9.resolve(rootDir)), toRealPath(importer)).split(path9.sep).join("/");
3350
- const importerProdDir = path9.posix.dirname(toProdExtension(importerRel));
3366
+ const importerRel = path10.relative(toRealPath(path10.resolve(rootDir)), toRealPath(importer)).split(path10.sep).join("/");
3367
+ const importerProdDir = path10.posix.dirname(toProdExtension(importerRel));
3351
3368
  if (importerProdDir === ".") return relFromDist;
3352
3369
  const target = relFromDist.replace(/^\.\//, "");
3353
- let rel = path9.posix.relative(importerProdDir, target);
3370
+ let rel = path10.posix.relative(importerProdDir, target);
3354
3371
  if (!rel.startsWith(".")) rel = "./" + rel;
3355
3372
  return rel;
3356
3373
  }
@@ -3365,41 +3382,41 @@ var INDEX_EXTS = [
3365
3382
  "/index.cjs"
3366
3383
  ];
3367
3384
  function resolveRelativeSpecifier(importer, specifier) {
3368
- const importerDir = path9.dirname(importer);
3369
- const base = path9.resolve(importerDir, specifier);
3385
+ const importerDir = path10.dirname(importer);
3386
+ const base = path10.resolve(importerDir, specifier);
3370
3387
  if (PROD_EXTS.some((ext) => specifier.endsWith(ext))) {
3371
- if (fs7.existsSync(base)) return base;
3388
+ if (fs8.existsSync(base)) return base;
3372
3389
  if (base.endsWith(".js")) {
3373
3390
  for (const ext of [".ts", ".tsx", ".jsx"]) {
3374
3391
  const file = base.slice(0, -3) + ext;
3375
- if (fs7.existsSync(file)) return file;
3392
+ if (fs8.existsSync(file)) return file;
3376
3393
  }
3377
3394
  }
3378
3395
  return null;
3379
3396
  }
3380
3397
  if (/\.(ts|tsx|jsx)$/.test(specifier)) {
3381
- return fs7.existsSync(base) ? base : null;
3398
+ return fs8.existsSync(base) ? base : null;
3382
3399
  }
3383
3400
  for (const ext of SOURCE_EXTS) {
3384
3401
  const file = base + ext;
3385
- if (fs7.existsSync(file)) return file;
3402
+ if (fs8.existsSync(file)) return file;
3386
3403
  }
3387
3404
  for (const indexExt of INDEX_EXTS) {
3388
3405
  const file = base + indexExt;
3389
- if (fs7.existsSync(file)) return file;
3406
+ if (fs8.existsSync(file)) return file;
3390
3407
  }
3391
3408
  return null;
3392
3409
  }
3393
3410
  function createAliasPlugin(config, options) {
3394
- const appDirAbs = options?.rootDir ? toRealPath(path9.resolve(options.rootDir, APP_DIR)) : null;
3411
+ const appDirAbs = options?.rootDir ? toRealPath(path10.resolve(options.rootDir, APP_DIR)) : null;
3395
3412
  const probeCandidateFile = (candidate) => {
3396
3413
  for (const ext of SOURCE_EXTS) {
3397
3414
  const file = candidate + ext;
3398
- if (fs7.existsSync(file)) return file;
3415
+ if (fs8.existsSync(file)) return file;
3399
3416
  }
3400
3417
  for (const indexExt of INDEX_EXTS) {
3401
3418
  const file = candidate + indexExt;
3402
- if (fs7.existsSync(file)) return file;
3419
+ if (fs8.existsSync(file)) return file;
3403
3420
  }
3404
3421
  return null;
3405
3422
  };
@@ -3409,7 +3426,7 @@ function createAliasPlugin(config, options) {
3409
3426
  build.onLoad({ filter: /\.(ts|tsx|js|jsx|mjs|cjs)$/ }, (args) => {
3410
3427
  let source;
3411
3428
  try {
3412
- source = fs7.readFileSync(args.path, "utf8");
3429
+ source = fs8.readFileSync(args.path, "utf8");
3413
3430
  } catch {
3414
3431
  return void 0;
3415
3432
  }
@@ -3535,11 +3552,11 @@ async function compileSourceFiles(options) {
3535
3552
  if (entryPoints.length === 0) {
3536
3553
  return { compiledFiles: [] };
3537
3554
  }
3538
- const absDist = path10.resolve(rootDir, dist);
3539
- await fs8.promises.mkdir(absDist, { recursive: true });
3555
+ const absDist = path11.resolve(rootDir, dist);
3556
+ await fs9.promises.mkdir(absDist, { recursive: true });
3540
3557
  const plugins = buildAliasPlugins(rootDir);
3541
3558
  const esbuild = await import("esbuild");
3542
- const outbase = path10.resolve(rootDir, APP_DIR);
3559
+ const outbase = path11.resolve(rootDir, APP_DIR);
3543
3560
  const result = await esbuild.build({
3544
3561
  entryPoints,
3545
3562
  outdir: absDist,
@@ -3559,10 +3576,10 @@ async function compileSourceFiles(options) {
3559
3576
  if (atomicWrite && result.outputFiles) {
3560
3577
  await Promise.all(
3561
3578
  result.outputFiles.map(async (file) => {
3562
- await fs8.promises.mkdir(path10.dirname(file.path), { recursive: true });
3579
+ await fs9.promises.mkdir(path11.dirname(file.path), { recursive: true });
3563
3580
  const tmp = `${file.path}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
3564
- await fs8.promises.writeFile(tmp, file.contents);
3565
- await fs8.promises.rename(tmp, file.path);
3581
+ await fs9.promises.writeFile(tmp, file.contents);
3582
+ await fs9.promises.rename(tmp, file.path);
3566
3583
  })
3567
3584
  );
3568
3585
  }
@@ -3575,8 +3592,8 @@ async function compileDevRoutes(options) {
3575
3592
  }
3576
3593
 
3577
3594
  // src/cli/collectImports.ts
3578
- import path11 from "path";
3579
- import fs9 from "fs";
3595
+ import path12 from "path";
3596
+ import fs10 from "fs";
3580
3597
  var SPEC_RE = /(\bfrom\s*|import\s*\(\s*)(['"])([^'"]+)\2/g;
3581
3598
  function extractImportSpecifiers(source) {
3582
3599
  const specifiers = [];
@@ -3588,10 +3605,10 @@ function extractImportSpecifiers(source) {
3588
3605
  return specifiers;
3589
3606
  }
3590
3607
  function resolveSpecifierFromDir(dir, specifier) {
3591
- return resolveRelativeSpecifier(path11.join(dir, "__faapi_probe__.ts"), specifier);
3608
+ return resolveRelativeSpecifier(path12.join(dir, "__faapi_probe__.ts"), specifier);
3592
3609
  }
3593
3610
  async function collectRelativeImports(entryFiles, rootDir) {
3594
- const appDirAbs = toRealPath(path11.resolve(rootDir, "src"));
3611
+ const appDirAbs = toRealPath(path12.resolve(rootDir, "src"));
3595
3612
  const tsconfig = readTsconfig(rootDir);
3596
3613
  const visited = /* @__PURE__ */ new Set();
3597
3614
  const insideFiles = /* @__PURE__ */ new Set();
@@ -3601,7 +3618,7 @@ async function collectRelativeImports(entryFiles, rootDir) {
3601
3618
  visited.add(filePath);
3602
3619
  let source;
3603
3620
  try {
3604
- source = await fs9.promises.readFile(filePath, "utf8");
3621
+ source = await fs10.promises.readFile(filePath, "utf8");
3605
3622
  } catch {
3606
3623
  return;
3607
3624
  }
@@ -3623,7 +3640,7 @@ async function collectRelativeImports(entryFiles, rootDir) {
3623
3640
  resolved = null;
3624
3641
  }
3625
3642
  if (!resolved) continue;
3626
- if (!isInsideDir(toRealPath(resolved), toRealPath(path11.resolve(rootDir)))) continue;
3643
+ if (!isInsideDir(toRealPath(resolved), toRealPath(path12.resolve(rootDir)))) continue;
3627
3644
  if (isInsideDir(toRealPath(resolved), appDirAbs)) {
3628
3645
  insideFiles.add(resolved);
3629
3646
  } else {
@@ -3644,8 +3661,8 @@ async function collectRelativeImports(entryFiles, rootDir) {
3644
3661
  // src/cli/compileOnDemand.ts
3645
3662
  function isProductFresh(sourceAbsPath, productAbsPath) {
3646
3663
  try {
3647
- const srcStat = fs10.statSync(sourceAbsPath);
3648
- const prodStat = fs10.statSync(productAbsPath);
3664
+ const srcStat = fs11.statSync(sourceAbsPath);
3665
+ const prodStat = fs11.statSync(productAbsPath);
3649
3666
  return prodStat.mtimeMs >= srcStat.mtimeMs;
3650
3667
  } catch {
3651
3668
  return false;
@@ -3671,7 +3688,7 @@ async function ensureCompiled(sourceAbsPath, rootDir, dist) {
3671
3688
  if (state.compiledFiles.has(sourceAbsPath)) {
3672
3689
  return false;
3673
3690
  }
3674
- if (!fs10.existsSync(sourceAbsPath)) {
3691
+ if (!fs11.existsSync(sourceAbsPath)) {
3675
3692
  return false;
3676
3693
  }
3677
3694
  const productPath = prodSourcePathToProductPath(sourceAbsPath, rootDir, dist);
@@ -3721,11 +3738,11 @@ async function ensureMiddlewaresCompiled(middlewarePaths, rootDir) {
3721
3738
  }
3722
3739
  }
3723
3740
  function prodSourcePathToProductPath(sourceAbsPath, rootDir, dist) {
3724
- const rel = path12.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
3741
+ const rel = path13.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
3725
3742
  if (!rel.startsWith("src/")) return null;
3726
3743
  const relWithoutSrc = rel.slice(4);
3727
3744
  const jsRel = relWithoutSrc.replace(/\.ts$/, ".js");
3728
- return path12.resolve(rootDir, dist, jsRel);
3745
+ return path13.resolve(rootDir, dist, jsRel);
3729
3746
  }
3730
3747
  async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir, dist, wsRoutes) {
3731
3748
  const inFlight2 = state.inFlightSchemaGenerations.get(schemaPath);
@@ -3736,9 +3753,9 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
3736
3753
  if (state.generatedSchemas.has(schemaPath)) {
3737
3754
  return false;
3738
3755
  }
3739
- const prodAbsPath = path12.resolve(rootDir, routeFilePath);
3756
+ const prodAbsPath = path13.resolve(rootDir, routeFilePath);
3740
3757
  const sourceAbsPath = prodPathToSourcePath(prodAbsPath, rootDir, dist);
3741
- if (!fs10.existsSync(sourceAbsPath)) {
3758
+ if (!fs11.existsSync(sourceAbsPath)) {
3742
3759
  return false;
3743
3760
  }
3744
3761
  if (isProductFresh(sourceAbsPath, schemaPath)) {
@@ -3750,7 +3767,7 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
3750
3767
  if (fileRoutes.length === 0 && fileWsRoutes.length === 0) {
3751
3768
  return false;
3752
3769
  }
3753
- const sourceRelPath = path12.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
3770
+ const sourceRelPath = path13.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
3754
3771
  const sourceRoutes = fileRoutes.map((r) => ({ ...r, filePath: sourceRelPath }));
3755
3772
  const sourceWsRoutes = fileWsRoutes.map((r) => ({ ...r, filePath: sourceRelPath }));
3756
3773
  const generatePromise = (async () => {
@@ -3769,19 +3786,19 @@ var sourcePathCache = /* @__PURE__ */ new Map();
3769
3786
  function prodPathToSourcePath(prodAbsPath, rootDir, dist) {
3770
3787
  const cached = sourcePathCache.get(prodAbsPath);
3771
3788
  if (cached) return cached;
3772
- const rel = path12.relative(rootDir, prodAbsPath).replace(/\\/g, "/");
3789
+ const rel = path13.relative(rootDir, prodAbsPath).replace(/\\/g, "/");
3773
3790
  let relWithoutDist = rel;
3774
3791
  if (relWithoutDist.startsWith(`${dist}/`)) {
3775
3792
  relWithoutDist = relWithoutDist.slice(dist.length + 1);
3776
3793
  }
3777
3794
  const srcRel = `src/${relWithoutDist}`;
3778
3795
  const tsRel = srcRel.replace(/\.js$/, ".ts");
3779
- const tsAbs = path12.resolve(rootDir, tsRel);
3796
+ const tsAbs = path13.resolve(rootDir, tsRel);
3780
3797
  let result;
3781
- if (fs10.existsSync(tsAbs)) {
3798
+ if (fs11.existsSync(tsAbs)) {
3782
3799
  result = tsAbs;
3783
3800
  } else {
3784
- result = path12.resolve(rootDir, srcRel);
3801
+ result = path13.resolve(rootDir, srcRel);
3785
3802
  }
3786
3803
  sourcePathCache.set(prodAbsPath, result);
3787
3804
  return result;
@@ -3834,9 +3851,9 @@ async function validateInput(schemaPath, method, inputType, input) {
3834
3851
  function mapZodIssues(error) {
3835
3852
  return error.issues.map((issue) => {
3836
3853
  const code = mapZodCode(issue);
3837
- const path17 = issue.path.map(String).join(".") || "";
3854
+ const path18 = issue.path.map(String).join(".") || "";
3838
3855
  return {
3839
- path: path17,
3856
+ path: path18,
3840
3857
  code,
3841
3858
  expected: issue.expected ?? mapExpectedFromMessage(issue.message),
3842
3859
  received: issue.received ?? mapReceivedFromMessage(issue.message),
@@ -3886,7 +3903,7 @@ import {
3886
3903
  import { createSecureServer as createHttp2SecureServer } from "http2";
3887
3904
  import { readFileSync } from "fs";
3888
3905
  import { Readable as Readable2 } from "stream";
3889
- import path15 from "path";
3906
+ import path16 from "path";
3890
3907
 
3891
3908
  // src/router/matchRoute.ts
3892
3909
  var httpIndexCache = /* @__PURE__ */ new WeakMap();
@@ -3928,25 +3945,25 @@ function getWsIndex(routes) {
3928
3945
  wsIndexCache.set(routes, index);
3929
3946
  return index;
3930
3947
  }
3931
- function matchRoute(routes, method, path17) {
3948
+ function matchRoute(routes, method, path18) {
3932
3949
  const index = getHttpIndex(routes);
3933
3950
  const upper = method.toUpperCase();
3934
- const hit = matchByMethod(index, upper, path17);
3951
+ const hit = matchByMethod(index, upper, path18);
3935
3952
  if (hit) return hit;
3936
3953
  if (upper === "HEAD") {
3937
- return matchByMethod(index, "GET", path17);
3954
+ return matchByMethod(index, "GET", path18);
3938
3955
  }
3939
3956
  return null;
3940
3957
  }
3941
- function matchByMethod(index, method, path17) {
3942
- const staticHit = index.static.get(`${method}|${path17}`);
3958
+ function matchByMethod(index, method, path18) {
3959
+ const staticHit = index.static.get(`${method}|${path18}`);
3943
3960
  if (staticHit) {
3944
3961
  return { route: staticHit, params: {} };
3945
3962
  }
3946
3963
  if (index.dynamics.length === 0) {
3947
3964
  return null;
3948
3965
  }
3949
- const pathSegments = path17.split("/").filter(Boolean);
3966
+ const pathSegments = path18.split("/").filter(Boolean);
3950
3967
  for (const entry of index.dynamics) {
3951
3968
  const route = entry.route;
3952
3969
  if (route.method !== method) {
@@ -3959,31 +3976,31 @@ function matchByMethod(index, method, path17) {
3959
3976
  }
3960
3977
  return null;
3961
3978
  }
3962
- function matchWsRoute(wsRoutes, path17) {
3979
+ function matchWsRoute(wsRoutes, path18) {
3963
3980
  const index = getWsIndex(wsRoutes);
3964
- const staticHit = index.static.get(path17);
3981
+ const staticHit = index.static.get(path18);
3965
3982
  if (staticHit) {
3966
3983
  return { route: staticHit, params: {} };
3967
3984
  }
3968
3985
  for (const route of index.dynamics) {
3969
- const params = matchDynamicPath(route.urlPath, path17, route.paramNames, route.isCatchAll);
3986
+ const params = matchDynamicPath(route.urlPath, path18, route.paramNames, route.isCatchAll);
3970
3987
  if (params !== null) {
3971
3988
  return { route, params };
3972
3989
  }
3973
3990
  }
3974
3991
  return null;
3975
3992
  }
3976
- function findAllowedMethods(routes, path17) {
3993
+ function findAllowedMethods(routes, path18) {
3977
3994
  const index = getHttpIndex(routes);
3978
3995
  const methods = /* @__PURE__ */ new Set();
3979
- const staticMethods = index.methodsByStaticPath.get(path17);
3996
+ const staticMethods = index.methodsByStaticPath.get(path18);
3980
3997
  if (staticMethods) {
3981
3998
  for (const method of staticMethods) {
3982
3999
  methods.add(method);
3983
4000
  }
3984
4001
  }
3985
4002
  if (index.dynamics.length > 0) {
3986
- const pathSegments = path17.split("/").filter(Boolean);
4003
+ const pathSegments = path18.split("/").filter(Boolean);
3987
4004
  for (const entry of index.dynamics) {
3988
4005
  const params = matchSegments(
3989
4006
  entry.segments,
@@ -4001,10 +4018,10 @@ function findAllowedMethods(routes, path17) {
4001
4018
  }
4002
4019
  return Array.from(methods);
4003
4020
  }
4004
- function matchDynamicPath(pattern, path17, paramNames, isCatchAll) {
4021
+ function matchDynamicPath(pattern, path18, paramNames, isCatchAll) {
4005
4022
  return matchSegments(
4006
4023
  pattern.split("/").filter(Boolean),
4007
- path17.split("/").filter(Boolean),
4024
+ path18.split("/").filter(Boolean),
4008
4025
  paramNames,
4009
4026
  isCatchAll
4010
4027
  );
@@ -4626,16 +4643,16 @@ function logger(options = {}) {
4626
4643
  }
4627
4644
 
4628
4645
  // src/server/handleWsUpgrade.ts
4629
- import fs12 from "fs";
4646
+ import fs13 from "fs";
4630
4647
  import { WebSocketServer, WebSocket } from "ws";
4631
- import path14 from "path";
4648
+ import path15 from "path";
4632
4649
 
4633
4650
  // src/cli/copyResources.ts
4634
- import path13 from "path";
4635
- import fs11 from "fs";
4651
+ import path14 from "path";
4652
+ import fs12 from "fs";
4636
4653
  var RESOURCES_OUTPUT_DIR = "resources";
4637
4654
  function resolveResourcesDir(rootDir, dist) {
4638
- return path13.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
4655
+ return path14.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
4639
4656
  }
4640
4657
 
4641
4658
  // src/server/serverUtils.ts
@@ -4694,7 +4711,7 @@ async function loadWsHandler(filePath, ctx, rootDir) {
4694
4711
  const dist = getDevDist();
4695
4712
  if (dist) {
4696
4713
  const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
4697
- if (sourcePath && fs12.existsSync(sourcePath)) {
4714
+ if (sourcePath && fs13.existsSync(sourcePath)) {
4698
4715
  await ensureCompiled(sourcePath, rootDir, dist);
4699
4716
  }
4700
4717
  }
@@ -4836,7 +4853,7 @@ function attachWebSocket(options) {
4836
4853
  let upgraded = false;
4837
4854
  const finalHandler = async () => {
4838
4855
  const schemaPath = getRuntimeSchemaPath(route.filePath, dist, rootDir);
4839
- if (fs12.existsSync(schemaPath)) {
4856
+ if (fs13.existsSync(schemaPath)) {
4840
4857
  if (isDevOnDemandEnabled()) {
4841
4858
  const devDist = getDevDist();
4842
4859
  if (devDist) {
@@ -4875,7 +4892,7 @@ function attachWebSocket(options) {
4875
4892
  }
4876
4893
  let handlers;
4877
4894
  try {
4878
- const absoluteFilePath = path14.resolve(rootDir, route.filePath);
4895
+ const absoluteFilePath = path15.resolve(rootDir, route.filePath);
4879
4896
  handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
4880
4897
  } catch (err) {
4881
4898
  const reason = err instanceof Error ? err.message : String(err);
@@ -5137,7 +5154,7 @@ function getRoutePaths(route, rootDir, dist) {
5137
5154
  let cached = routePathCache.get(route);
5138
5155
  if (!cached) {
5139
5156
  cached = {
5140
- absFilePath: path15.resolve(rootDir, route.filePath),
5157
+ absFilePath: path16.resolve(rootDir, route.filePath),
5141
5158
  schemaPath: getRuntimeSchemaPath(route.filePath, dist, rootDir)
5142
5159
  };
5143
5160
  routePathCache.set(route, cached);
@@ -5346,7 +5363,7 @@ async function createTestServer(options) {
5346
5363
  } = options;
5347
5364
  const { routes, wsRoutes } = await scanRoutes(rootDir, patterns);
5348
5365
  const sorted = sortRoutes(routes);
5349
- const schemaDist = dist ? path16.isAbsolute(dist) ? dist : path16.resolve(rootDir, dist) : await fs13.mkdtemp(path16.join(os.tmpdir(), "faapi-test-schema-"));
5366
+ const schemaDist = dist ? path17.isAbsolute(dist) ? dist : path17.resolve(rootDir, dist) : await fs14.mkdtemp(path17.join(os.tmpdir(), "faapi-test-schema-"));
5350
5367
  await generateSchemaFiles(sorted, rootDir, schemaDist);
5351
5368
  const { server } = createServer({
5352
5369
  routes: sorted,
@@ -5378,7 +5395,7 @@ async function createTestServer(options) {
5378
5395
  await new Promise((resolve) => {
5379
5396
  server.close(() => resolve());
5380
5397
  });
5381
- await fs13.rm(schemaDist, { recursive: true, force: true }).catch(() => {
5398
+ await fs14.rm(schemaDist, { recursive: true, force: true }).catch(() => {
5382
5399
  });
5383
5400
  invalidateSchemaCache();
5384
5401
  }