@lolyjs/core 0.2.0-alpha.27 → 0.2.0-alpha.29

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.js CHANGED
@@ -9871,7 +9871,7 @@ var require_built3 = __commonJS({
9871
9871
  });
9872
9872
 
9873
9873
  // modules/cli/index.ts
9874
- import path28 from "path";
9874
+ import path30 from "path";
9875
9875
  import process2 from "process";
9876
9876
 
9877
9877
  // modules/router/loader-pages.ts
@@ -9883,10 +9883,17 @@ var PAGE_FILE_REGEX = /^page\.(tsx|ts|jsx|js)$/;
9883
9883
  var LAYOUT_FILE_BASENAME = "layout";
9884
9884
 
9885
9885
  // modules/router/path.ts
9886
+ function isRouteGroup(dirName) {
9887
+ return dirName.startsWith("(") && dirName.endsWith(")");
9888
+ }
9886
9889
  function buildRoutePathFromDir(relDir) {
9887
9890
  if (!relDir || relDir === ".") return "/";
9888
9891
  const clean = relDir.replace(/\\/g, "/");
9889
- return "/" + clean;
9892
+ const segments = clean.split("/").filter((seg) => {
9893
+ return !isRouteGroup(seg);
9894
+ });
9895
+ if (segments.length === 0) return "/";
9896
+ return "/" + segments.join("/");
9890
9897
  }
9891
9898
  function buildRegexFromRoutePath(routePath) {
9892
9899
  const segments = routePath.split("/").filter(Boolean);
@@ -10102,13 +10109,17 @@ function validateRoutes(routes, appDir) {
10102
10109
  }
10103
10110
  for (const [pattern, duplicateRoutes] of routePatterns.entries()) {
10104
10111
  if (duplicateRoutes.length > 1) {
10105
- const files = duplicateRoutes.map(
10106
- (r) => r.pageFile ? path3.relative(appDir, r.pageFile) : "unknown"
10107
- ).join(", ");
10112
+ const files = duplicateRoutes.map((r) => {
10113
+ const relPath = r.pageFile ? path3.relative(appDir, r.pageFile) : "unknown";
10114
+ const segments = relPath.split(path3.sep);
10115
+ const hasRouteGroup = segments.some((seg) => isRouteGroup(seg));
10116
+ return hasRouteGroup ? `${relPath} (inside route group)` : relPath;
10117
+ }).join(", ");
10108
10118
  errors.push(
10109
10119
  `Duplicate route pattern "${pattern}" found in multiple files:
10110
10120
  ${files}
10111
- \u{1F4A1} Suggestion: Ensure each route has a unique path pattern`
10121
+ \u{1F4A1} Suggestion: Route groups (directories in parentheses) don't appear in URLs.
10122
+ Ensure each route has a unique path pattern after route groups are ignored.`
10112
10123
  );
10113
10124
  }
10114
10125
  }
@@ -10385,12 +10396,13 @@ function loadApiRoutes(appDir) {
10385
10396
 
10386
10397
  // modules/router/matcher.ts
10387
10398
  function matchRoute(routes, urlPath) {
10399
+ const normalizedPath = urlPath.replace(/\/$/, "") || "/";
10388
10400
  for (const route of routes) {
10389
- const match = route.regex.exec(urlPath);
10401
+ const match = route.regex.exec(normalizedPath);
10390
10402
  if (!match) continue;
10391
10403
  const params = {};
10392
10404
  route.paramNames.forEach((name, idx) => {
10393
- params[name] = match[idx + 1];
10405
+ params[name] = decodeURIComponent(match[idx + 1] || "");
10394
10406
  });
10395
10407
  return { route, params };
10396
10408
  }
@@ -11400,34 +11412,504 @@ function loadErrorRouteFromFilesystem(appDir) {
11400
11412
  };
11401
11413
  }
11402
11414
 
11415
+ // modules/router/rewrites.ts
11416
+ function parseRewritePattern(pattern) {
11417
+ const cleanPattern = pattern.replace(/^\/+|\/+$/g, "") || "";
11418
+ if (!cleanPattern) {
11419
+ return {
11420
+ regex: /^\/?$/,
11421
+ paramNames: []
11422
+ };
11423
+ }
11424
+ const segments = cleanPattern.split("/").filter(Boolean);
11425
+ const paramNames = [];
11426
+ const regexParts = [];
11427
+ for (let i = 0; i < segments.length; i++) {
11428
+ const seg = segments[i];
11429
+ if (seg === "*") {
11430
+ if (i !== segments.length - 1) {
11431
+ throw new Error(
11432
+ `Catch-all "*" in "${pattern}" must be the last segment.`
11433
+ );
11434
+ }
11435
+ regexParts.push("(.+)");
11436
+ continue;
11437
+ }
11438
+ if (seg.endsWith("*") && seg.startsWith(":")) {
11439
+ const paramName = seg.slice(1, -1);
11440
+ if (i !== segments.length - 1) {
11441
+ throw new Error(
11442
+ `Catch-all segment "${seg}" in "${pattern}" must be the last segment.`
11443
+ );
11444
+ }
11445
+ paramNames.push(paramName);
11446
+ regexParts.push("(.+)");
11447
+ continue;
11448
+ }
11449
+ if (seg.startsWith(":") && seg.length > 1) {
11450
+ const paramName = seg.slice(1);
11451
+ paramNames.push(paramName);
11452
+ regexParts.push("([^/]+)");
11453
+ continue;
11454
+ }
11455
+ const escaped = seg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
11456
+ regexParts.push(escaped);
11457
+ }
11458
+ const regexSource = "^/?" + regexParts.join("/") + "/?$";
11459
+ const regex = new RegExp(regexSource);
11460
+ return { regex, paramNames };
11461
+ }
11462
+ function extractHostParams(hostPattern, actualHost) {
11463
+ const regexPattern = hostPattern.replace(/:([^.]+)/g, "([^.]+)").replace(/\./g, "\\.").replace(/\*/g, ".*");
11464
+ const regex = new RegExp(`^${regexPattern}$`);
11465
+ const match = regex.exec(actualHost);
11466
+ if (!match) return null;
11467
+ const paramNames = [];
11468
+ const paramPattern = /:([^.]+)/g;
11469
+ let paramMatch;
11470
+ while ((paramMatch = paramPattern.exec(hostPattern)) !== null) {
11471
+ paramNames.push(paramMatch[1]);
11472
+ }
11473
+ const params = {};
11474
+ paramNames.forEach((name, idx) => {
11475
+ params[name] = match[idx + 1] || "";
11476
+ });
11477
+ return params;
11478
+ }
11479
+ function evaluateRewriteConditions(conditions, req) {
11480
+ const extractedParams = {};
11481
+ for (const condition of conditions) {
11482
+ switch (condition.type) {
11483
+ case "host": {
11484
+ const hostWithPort = req.get("host") || req.hostname || req.get("x-forwarded-host")?.split(",")[0] || "";
11485
+ const host = hostWithPort.split(":")[0];
11486
+ if (process.env.NODE_ENV === "development") {
11487
+ console.log("[rewrites] Host matching:", {
11488
+ pattern: condition.value,
11489
+ actualHost: host,
11490
+ hostWithPort,
11491
+ reqHost: req.get("host"),
11492
+ reqHostname: req.hostname
11493
+ });
11494
+ }
11495
+ const hostParams = extractHostParams(condition.value, host);
11496
+ if (!hostParams) {
11497
+ if (process.env.NODE_ENV === "development") {
11498
+ console.log("[rewrites] Host params extraction failed:", {
11499
+ pattern: condition.value,
11500
+ actualHost: host
11501
+ });
11502
+ }
11503
+ return { matches: false, params: {} };
11504
+ }
11505
+ Object.assign(extractedParams, hostParams);
11506
+ break;
11507
+ }
11508
+ case "header": {
11509
+ if (!condition.key) {
11510
+ return { matches: false, params: {} };
11511
+ }
11512
+ const headerValue = req.get(condition.key.toLowerCase());
11513
+ if (!headerValue || headerValue !== condition.value) {
11514
+ return { matches: false, params: {} };
11515
+ }
11516
+ break;
11517
+ }
11518
+ case "cookie": {
11519
+ if (!condition.key) {
11520
+ return { matches: false, params: {} };
11521
+ }
11522
+ const cookieValue = req.cookies?.[condition.key];
11523
+ if (!cookieValue || cookieValue !== condition.value) {
11524
+ return { matches: false, params: {} };
11525
+ }
11526
+ break;
11527
+ }
11528
+ case "query": {
11529
+ if (!condition.key) {
11530
+ return { matches: false, params: {} };
11531
+ }
11532
+ const queryValue = req.query[condition.key];
11533
+ if (!queryValue || String(queryValue) !== condition.value) {
11534
+ return { matches: false, params: {} };
11535
+ }
11536
+ break;
11537
+ }
11538
+ default:
11539
+ return { matches: false, params: {} };
11540
+ }
11541
+ }
11542
+ return { matches: true, params: extractedParams };
11543
+ }
11544
+ function replaceDestinationParams(destination, params) {
11545
+ let result = destination;
11546
+ for (const [key, value] of Object.entries(params)) {
11547
+ const pattern = new RegExp(`:${key}(?:\\*)?`, "g");
11548
+ result = result.replace(pattern, value);
11549
+ }
11550
+ return result;
11551
+ }
11552
+ async function processRewrites(urlPath, compiledRewrites, req) {
11553
+ const normalizedPath = urlPath.replace(/\/$/, "") || "/";
11554
+ if (normalizedPath.startsWith("/static/") || // Static assets (client.js, client.css, etc.)
11555
+ normalizedPath.startsWith("/__fw/") || // Framework internal routes (hot reload, etc.)
11556
+ normalizedPath === "/favicon.ico" || // Favicon
11557
+ normalizedPath.startsWith("/wss/")) {
11558
+ if (process.env.NODE_ENV === "development") {
11559
+ console.log("[rewrites] Skipping rewrite for system route:", normalizedPath);
11560
+ }
11561
+ return null;
11562
+ }
11563
+ if (process.env.NODE_ENV === "development") {
11564
+ console.log("[rewrites] Processing rewrites:", {
11565
+ urlPath,
11566
+ normalizedPath,
11567
+ host: req.get("host"),
11568
+ hostname: req.hostname,
11569
+ compiledRewritesCount: compiledRewrites.length
11570
+ });
11571
+ }
11572
+ for (const rewrite of compiledRewrites) {
11573
+ let conditionParams = {};
11574
+ if (rewrite.has && rewrite.has.length > 0) {
11575
+ const conditionResult = evaluateRewriteConditions(rewrite.has, req);
11576
+ if (!conditionResult.matches) {
11577
+ if (process.env.NODE_ENV === "development") {
11578
+ console.log("[rewrites] Condition not matched:", {
11579
+ source: rewrite.source,
11580
+ conditions: rewrite.has
11581
+ });
11582
+ }
11583
+ continue;
11584
+ }
11585
+ conditionParams = conditionResult.params;
11586
+ if (process.env.NODE_ENV === "development") {
11587
+ console.log("[rewrites] Condition matched:", {
11588
+ source: rewrite.source,
11589
+ conditionParams
11590
+ });
11591
+ }
11592
+ }
11593
+ const sourceMatch = rewrite.sourceRegex.exec(normalizedPath);
11594
+ if (!sourceMatch) {
11595
+ if (process.env.NODE_ENV === "development") {
11596
+ console.log("[rewrites] Source pattern not matched:", {
11597
+ source: rewrite.source,
11598
+ normalizedPath,
11599
+ sourceRegex: rewrite.sourceRegex.toString()
11600
+ });
11601
+ }
11602
+ continue;
11603
+ }
11604
+ if (process.env.NODE_ENV === "development") {
11605
+ console.log("[rewrites] Source pattern matched:", {
11606
+ source: rewrite.source,
11607
+ normalizedPath,
11608
+ match: sourceMatch[0]
11609
+ });
11610
+ }
11611
+ const sourceParams = {};
11612
+ rewrite.sourceParamNames.forEach((name, idx) => {
11613
+ sourceParams[name] = decodeURIComponent(sourceMatch[idx + 1] || "");
11614
+ });
11615
+ const allParams = { ...sourceParams, ...conditionParams };
11616
+ let destination;
11617
+ if (typeof rewrite.destination === "function") {
11618
+ destination = await rewrite.destination(allParams, req);
11619
+ } else {
11620
+ destination = replaceDestinationParams(rewrite.destination, allParams);
11621
+ }
11622
+ const normalizedDestination = destination.replace(/\/+/g, "/").replace(/^([^/])/, "/$1").replace(/\/$/, "") || "/";
11623
+ if (process.env.NODE_ENV === "development") {
11624
+ console.log("[rewrites] Rewrite successful:", {
11625
+ originalPath: urlPath,
11626
+ rewrittenPath: normalizedDestination,
11627
+ allParams
11628
+ });
11629
+ }
11630
+ return {
11631
+ rewrittenPath: normalizedDestination,
11632
+ extractedParams: allParams
11633
+ };
11634
+ }
11635
+ return null;
11636
+ }
11637
+ function validateRewrites(rules) {
11638
+ for (const rule of rules) {
11639
+ if (typeof rule.destination === "string") {
11640
+ if (rule.source === rule.destination) {
11641
+ console.warn(
11642
+ `[framework][rewrites] Rewrite rule has identical source and destination: "${rule.source}". This may cause issues.`
11643
+ );
11644
+ }
11645
+ }
11646
+ }
11647
+ const sources = /* @__PURE__ */ new Set();
11648
+ for (const rule of rules) {
11649
+ if (sources.has(rule.source)) {
11650
+ console.warn(
11651
+ `[framework][rewrites] Duplicate rewrite source pattern: "${rule.source}". Only the first match will be used.`
11652
+ );
11653
+ }
11654
+ sources.add(rule.source);
11655
+ }
11656
+ }
11657
+ function compileRewriteRules(rules) {
11658
+ validateRewrites(rules);
11659
+ return rules.map((rule) => {
11660
+ const { regex, paramNames } = parseRewritePattern(rule.source);
11661
+ let hostRegex;
11662
+ let hostParamNames;
11663
+ if (rule.has) {
11664
+ const hostCondition = rule.has.find((c) => c.type === "host");
11665
+ if (hostCondition) {
11666
+ const hostPattern = hostCondition.value;
11667
+ const hostRegexPattern = hostPattern.replace(/:([^.]+)/g, "([^.]+)").replace(/\./g, "\\.").replace(/\*/g, ".*");
11668
+ hostRegex = new RegExp(`^${hostRegexPattern}$`);
11669
+ hostParamNames = [];
11670
+ const paramPattern = /:([^.]+)/g;
11671
+ let paramMatch;
11672
+ while ((paramMatch = paramPattern.exec(hostPattern)) !== null) {
11673
+ hostParamNames.push(paramMatch[1]);
11674
+ }
11675
+ }
11676
+ }
11677
+ return {
11678
+ source: rule.source,
11679
+ sourceRegex: regex,
11680
+ sourceParamNames: paramNames,
11681
+ destination: rule.destination,
11682
+ has: rule.has,
11683
+ hostRegex,
11684
+ hostParamNames
11685
+ };
11686
+ });
11687
+ }
11688
+
11689
+ // modules/router/rewrites-loader.ts
11690
+ import fs10 from "fs";
11691
+ import path10 from "path";
11692
+ var FilesystemRewriteLoader = class {
11693
+ // Maximum cache age in ms (1 second fallback)
11694
+ constructor(projectRoot) {
11695
+ this.projectRoot = projectRoot;
11696
+ this.cache = null;
11697
+ this.cacheMaxAge = 1e3;
11698
+ }
11699
+ /**
11700
+ * Invalidates the cache, forcing a reload on next access.
11701
+ */
11702
+ invalidateCache() {
11703
+ this.cache = null;
11704
+ }
11705
+ /**
11706
+ * Finds the rewrites config file.
11707
+ * Looks for rewrites.config.ts, rewrites.config.js, or rewrites.config.json
11708
+ */
11709
+ findRewritesConfig() {
11710
+ const candidates = [
11711
+ path10.join(this.projectRoot, "rewrites.config.ts"),
11712
+ path10.join(this.projectRoot, "rewrites.config.js"),
11713
+ path10.join(this.projectRoot, "rewrites.config.json")
11714
+ ];
11715
+ for (const candidate of candidates) {
11716
+ if (fs10.existsSync(candidate)) {
11717
+ return candidate;
11718
+ }
11719
+ }
11720
+ return null;
11721
+ }
11722
+ /**
11723
+ * Checks if the rewrites config file has changed.
11724
+ */
11725
+ hasConfigChanged(configPath) {
11726
+ if (!this.cache || !this.cache.fileStats) {
11727
+ return true;
11728
+ }
11729
+ if (!fs10.existsSync(configPath)) {
11730
+ return this.cache.rewrites.length > 0;
11731
+ }
11732
+ const stats = fs10.statSync(configPath);
11733
+ const cachedStats = this.cache.fileStats;
11734
+ return stats.mtimeMs !== cachedStats.mtime || stats.size !== cachedStats.size;
11735
+ }
11736
+ /**
11737
+ * Loads rewrites from a config file.
11738
+ */
11739
+ async loadRewritesFromFile(configPath) {
11740
+ const ext = path10.extname(configPath);
11741
+ if (ext === ".json") {
11742
+ const content = fs10.readFileSync(configPath, "utf-8");
11743
+ const config2 = JSON.parse(content);
11744
+ return Array.isArray(config2) ? config2 : [];
11745
+ }
11746
+ delete __require.cache[__require.resolve(configPath)];
11747
+ const mod = __require(configPath);
11748
+ const config = mod.default || mod;
11749
+ if (typeof config === "function") {
11750
+ return await config();
11751
+ }
11752
+ if (Array.isArray(config)) {
11753
+ return config;
11754
+ }
11755
+ throw new Error(
11756
+ `Invalid rewrites config in ${configPath}. Expected array or function returning array.`
11757
+ );
11758
+ }
11759
+ /**
11760
+ * Checks if cache is still valid, invalidates if config changed.
11761
+ */
11762
+ ensureCacheValid() {
11763
+ if (!this.cache) {
11764
+ return;
11765
+ }
11766
+ const now = Date.now();
11767
+ if (now - this.cache.timestamp > this.cacheMaxAge) {
11768
+ const configPath = this.findRewritesConfig();
11769
+ if (configPath && this.hasConfigChanged(configPath)) {
11770
+ this.cache = null;
11771
+ } else {
11772
+ this.cache.timestamp = now;
11773
+ }
11774
+ }
11775
+ }
11776
+ async loadRewrites() {
11777
+ this.ensureCacheValid();
11778
+ const configPath = this.findRewritesConfig();
11779
+ if (!configPath) {
11780
+ if (this.cache && this.cache.rewrites.length === 0) {
11781
+ return this.cache.rewrites;
11782
+ }
11783
+ this.cache = {
11784
+ rewrites: [],
11785
+ fileStats: null,
11786
+ timestamp: Date.now()
11787
+ };
11788
+ return [];
11789
+ }
11790
+ if (!this.cache || this.hasConfigChanged(configPath)) {
11791
+ const rules = await this.loadRewritesFromFile(configPath);
11792
+ const compiled = compileRewriteRules(rules);
11793
+ const stats = fs10.statSync(configPath);
11794
+ const fileStats = {
11795
+ mtime: stats.mtimeMs,
11796
+ size: stats.size
11797
+ };
11798
+ this.cache = {
11799
+ rewrites: compiled,
11800
+ fileStats,
11801
+ timestamp: Date.now()
11802
+ };
11803
+ }
11804
+ return this.cache.rewrites;
11805
+ }
11806
+ };
11807
+ var ManifestRewriteLoader = class {
11808
+ constructor(projectRoot) {
11809
+ this.cache = null;
11810
+ this.manifestPath = path10.join(projectRoot, ".loly", "rewrites-manifest.json");
11811
+ }
11812
+ /**
11813
+ * Reads the rewrites manifest from disk.
11814
+ */
11815
+ readManifest() {
11816
+ if (!fs10.existsSync(this.manifestPath)) {
11817
+ return null;
11818
+ }
11819
+ try {
11820
+ const content = fs10.readFileSync(this.manifestPath, "utf-8");
11821
+ return JSON.parse(content);
11822
+ } catch (error) {
11823
+ console.warn(
11824
+ `Failed to read rewrites manifest from ${this.manifestPath}:`,
11825
+ error
11826
+ );
11827
+ return null;
11828
+ }
11829
+ }
11830
+ async loadRewrites() {
11831
+ if (this.cache) {
11832
+ return this.cache;
11833
+ }
11834
+ const manifest = this.readManifest();
11835
+ if (!manifest || !manifest.rewrites) {
11836
+ this.cache = [];
11837
+ return [];
11838
+ }
11839
+ const compiled = compileRewriteRules(manifest.rewrites);
11840
+ this.cache = compiled;
11841
+ return compiled;
11842
+ }
11843
+ };
11844
+ function createRewriteLoader(projectRoot, isDev) {
11845
+ if (isDev) {
11846
+ return new FilesystemRewriteLoader(projectRoot);
11847
+ } else {
11848
+ return new ManifestRewriteLoader(projectRoot);
11849
+ }
11850
+ }
11851
+
11852
+ // modules/router/rewrites-manifest.ts
11853
+ import fs11 from "fs";
11854
+ import path11 from "path";
11855
+ init_globals();
11856
+ async function writeRewritesManifest(projectRoot) {
11857
+ const buildDir = path11.join(projectRoot, BUILD_FOLDER_NAME);
11858
+ if (!fs11.existsSync(buildDir)) {
11859
+ fs11.mkdirSync(buildDir, { recursive: true });
11860
+ }
11861
+ const manifestPath = path11.join(buildDir, "rewrites-manifest.json");
11862
+ const loader = createRewriteLoader(projectRoot, true);
11863
+ const compiledRewrites = await loader.loadRewrites();
11864
+ const serializableRules = [];
11865
+ for (const compiled of compiledRewrites) {
11866
+ if (typeof compiled.destination === "string") {
11867
+ serializableRules.push({
11868
+ source: compiled.source,
11869
+ destination: compiled.destination,
11870
+ has: compiled.has
11871
+ });
11872
+ } else {
11873
+ console.warn(
11874
+ `[framework][build] Rewrite with source "${compiled.source}" has a function destination and will not be included in the manifest. Only static rewrites are supported in production builds.`
11875
+ );
11876
+ }
11877
+ }
11878
+ const manifest = {
11879
+ version: 1,
11880
+ rewrites: serializableRules
11881
+ };
11882
+ fs11.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
11883
+ }
11884
+
11403
11885
  // modules/build/bundler/client.ts
11404
11886
  import { rspack as rspack2 } from "@rspack/core";
11405
11887
 
11406
11888
  // modules/build/config/client.ts
11407
- import path11 from "path";
11408
- import fs11 from "fs";
11889
+ import path13 from "path";
11890
+ import fs13 from "fs";
11409
11891
  import { rspack } from "@rspack/core";
11410
11892
 
11411
11893
  // modules/build/utils/index.ts
11412
- import fs10 from "fs";
11413
- import path10 from "path";
11894
+ import fs12 from "fs";
11895
+ import path12 from "path";
11414
11896
  function ensureDir(dir) {
11415
- fs10.mkdirSync(dir, { recursive: true });
11897
+ fs12.mkdirSync(dir, { recursive: true });
11416
11898
  }
11417
11899
  function loadAliasesFromTsconfig(projectRoot) {
11418
- const tsconfigPath = path10.join(projectRoot, "tsconfig.json");
11900
+ const tsconfigPath = path12.join(projectRoot, "tsconfig.json");
11419
11901
  const aliases = {};
11420
- if (!fs10.existsSync(tsconfigPath)) {
11421
- aliases["@app"] = path10.resolve(projectRoot, "app");
11902
+ if (!fs12.existsSync(tsconfigPath)) {
11903
+ aliases["@app"] = path12.resolve(projectRoot, "app");
11422
11904
  return aliases;
11423
11905
  }
11424
11906
  let tsconfig;
11425
11907
  try {
11426
- tsconfig = JSON.parse(fs10.readFileSync(tsconfigPath, "utf-8"));
11908
+ tsconfig = JSON.parse(fs12.readFileSync(tsconfigPath, "utf-8"));
11427
11909
  } catch (err) {
11428
11910
  console.warn("\u26A0\uFE0F [framework] Could not read tsconfig.json:", err instanceof Error ? err.message : String(err));
11429
11911
  console.warn("\u{1F4A1} Using default path aliases. For custom aliases, ensure tsconfig.json is valid.");
11430
- aliases["@app"] = path10.resolve(projectRoot, "app");
11912
+ aliases["@app"] = path12.resolve(projectRoot, "app");
11431
11913
  return aliases;
11432
11914
  }
11433
11915
  const compilerOptions = tsconfig.compilerOptions ?? {};
@@ -11438,40 +11920,40 @@ function loadAliasesFromTsconfig(projectRoot) {
11438
11920
  const aliasKey = aliasPattern.replace(/\/\*$/, "");
11439
11921
  const firstTarget = targets[0];
11440
11922
  const targetPath = firstTarget.replace(/\/\*$/, "");
11441
- const resolved = path10.resolve(projectRoot, baseUrl, targetPath);
11923
+ const resolved = path12.resolve(projectRoot, baseUrl, targetPath);
11442
11924
  aliases[aliasKey] = resolved;
11443
11925
  }
11444
11926
  if (!aliases["@app"]) {
11445
- aliases["@app"] = path10.resolve(projectRoot, "app");
11927
+ aliases["@app"] = path12.resolve(projectRoot, "app");
11446
11928
  }
11447
11929
  return aliases;
11448
11930
  }
11449
11931
  function copyDirRecursive(srcDir, destDir) {
11450
- if (!fs10.existsSync(srcDir)) return;
11932
+ if (!fs12.existsSync(srcDir)) return;
11451
11933
  ensureDir(destDir);
11452
- const entries = fs10.readdirSync(srcDir, { withFileTypes: true });
11934
+ const entries = fs12.readdirSync(srcDir, { withFileTypes: true });
11453
11935
  for (const entry of entries) {
11454
- const srcPath = path10.join(srcDir, entry.name);
11455
- const destPath = path10.join(destDir, entry.name);
11936
+ const srcPath = path12.join(srcDir, entry.name);
11937
+ const destPath = path12.join(destDir, entry.name);
11456
11938
  if (entry.isDirectory()) {
11457
11939
  copyDirRecursive(srcPath, destPath);
11458
11940
  } else if (entry.isFile()) {
11459
- fs10.copyFileSync(srcPath, destPath);
11941
+ fs12.copyFileSync(srcPath, destPath);
11460
11942
  }
11461
11943
  }
11462
11944
  }
11463
11945
  function copyStaticAssets(projectRoot, outDir) {
11464
- const assetsSrc = path10.join(projectRoot, "assets");
11465
- const assetsDest = path10.join(outDir, "assets");
11946
+ const assetsSrc = path12.join(projectRoot, "assets");
11947
+ const assetsDest = path12.join(outDir, "assets");
11466
11948
  copyDirRecursive(assetsSrc, assetsDest);
11467
- const publicDir = path10.join(projectRoot, "public");
11949
+ const publicDir = path12.join(projectRoot, "public");
11468
11950
  const candidates = ["favicon.ico", "favicon.png"];
11469
11951
  for (const name of candidates) {
11470
- const fromPublic = path10.join(publicDir, name);
11471
- if (fs10.existsSync(fromPublic)) {
11472
- const dest = path10.join(outDir, name);
11473
- ensureDir(path10.dirname(dest));
11474
- fs10.copyFileSync(fromPublic, dest);
11952
+ const fromPublic = path12.join(publicDir, name);
11953
+ if (fs12.existsSync(fromPublic)) {
11954
+ const dest = path12.join(outDir, name);
11955
+ ensureDir(path12.dirname(dest));
11956
+ fs12.copyFileSync(fromPublic, dest);
11475
11957
  break;
11476
11958
  }
11477
11959
  }
@@ -11481,10 +11963,10 @@ function getFaviconInfo(projectRoot, staticDir = "public", isDev = false) {
11481
11963
  { name: "favicon.ico", type: "image/x-icon" },
11482
11964
  { name: "favicon.png", type: "image/png" }
11483
11965
  ];
11484
- const publicDir = path10.join(projectRoot, staticDir);
11966
+ const publicDir = path12.join(projectRoot, staticDir);
11485
11967
  for (const candidate of candidates) {
11486
- const publicPath = path10.join(publicDir, candidate.name);
11487
- if (fs10.existsSync(publicPath)) {
11968
+ const publicPath = path12.join(publicDir, candidate.name);
11969
+ if (fs12.existsSync(publicPath)) {
11488
11970
  return {
11489
11971
  path: `/${candidate.name}`,
11490
11972
  // Served at root from public/
@@ -11502,10 +11984,10 @@ function generateAssetManifest(outDir, stats) {
11502
11984
  },
11503
11985
  chunks: {}
11504
11986
  };
11505
- if (!fs10.existsSync(outDir)) {
11987
+ if (!fs12.existsSync(outDir)) {
11506
11988
  return manifest;
11507
11989
  }
11508
- const files = fs10.readdirSync(outDir);
11990
+ const files = fs12.readdirSync(outDir);
11509
11991
  if (stats) {
11510
11992
  try {
11511
11993
  const statsJson = stats.toJson({
@@ -11634,12 +12116,12 @@ function generateAssetManifest(outDir, stats) {
11634
12116
  }
11635
12117
  function loadAssetManifest(projectRoot) {
11636
12118
  const { BUILD_FOLDER_NAME: BUILD_FOLDER_NAME2 } = (init_globals(), __toCommonJS(globals_exports));
11637
- const manifestPath = path10.join(projectRoot, BUILD_FOLDER_NAME2, "asset-manifest.json");
11638
- if (!fs10.existsSync(manifestPath)) {
12119
+ const manifestPath = path12.join(projectRoot, BUILD_FOLDER_NAME2, "asset-manifest.json");
12120
+ if (!fs12.existsSync(manifestPath)) {
11639
12121
  return null;
11640
12122
  }
11641
12123
  try {
11642
- const manifest = JSON.parse(fs10.readFileSync(manifestPath, "utf-8"));
12124
+ const manifest = JSON.parse(fs12.readFileSync(manifestPath, "utf-8"));
11643
12125
  return manifest;
11644
12126
  } catch (err) {
11645
12127
  return null;
@@ -11662,11 +12144,11 @@ function getClientCssPath(projectRoot) {
11662
12144
  init_globals();
11663
12145
  import dotenv from "dotenv";
11664
12146
  function createClientConfig(projectRoot, mode) {
11665
- const buildDir = path11.join(projectRoot, BUILD_FOLDER_NAME);
11666
- const clientEntry = path11.join(buildDir, "boostrap.ts");
11667
- const outDir = path11.join(buildDir, "client");
11668
- const envPath2 = path11.join(projectRoot, ".env");
11669
- if (fs11.existsSync(envPath2)) {
12147
+ const buildDir = path13.join(projectRoot, BUILD_FOLDER_NAME);
12148
+ const clientEntry = path13.join(buildDir, "boostrap.ts");
12149
+ const outDir = path13.join(buildDir, "client");
12150
+ const envPath2 = path13.join(projectRoot, ".env");
12151
+ if (fs13.existsSync(envPath2)) {
11670
12152
  dotenv.config({ path: envPath2 });
11671
12153
  }
11672
12154
  const publicEnv = {};
@@ -11787,8 +12269,8 @@ function createClientConfig(projectRoot, mode) {
11787
12269
 
11788
12270
  // modules/build/bundler/client.ts
11789
12271
  init_globals();
11790
- import path12 from "path";
11791
- import fs12 from "fs";
12272
+ import path14 from "path";
12273
+ import fs14 from "fs";
11792
12274
  function startClientBundler(projectRoot, mode = "development") {
11793
12275
  const { config, outDir } = createClientConfig(projectRoot, mode);
11794
12276
  copyStaticAssets(projectRoot, outDir);
@@ -11897,18 +12379,18 @@ function buildClientBundle(projectRoot) {
11897
12379
  }
11898
12380
  copyStaticAssets(projectRoot, outDir);
11899
12381
  const assetManifest = generateAssetManifest(outDir, stats);
11900
- const manifestPath = path12.join(projectRoot, BUILD_FOLDER_NAME, "asset-manifest.json");
11901
- fs12.writeFileSync(manifestPath, JSON.stringify(assetManifest, null, 2), "utf-8");
12382
+ const manifestPath = path14.join(projectRoot, BUILD_FOLDER_NAME, "asset-manifest.json");
12383
+ fs14.writeFileSync(manifestPath, JSON.stringify(assetManifest, null, 2), "utf-8");
11902
12384
  resolve3({ outDir });
11903
12385
  });
11904
12386
  });
11905
12387
  }
11906
12388
 
11907
12389
  // modules/build/ssg/builder.ts
11908
- import path19 from "path";
12390
+ import path21 from "path";
11909
12391
 
11910
12392
  // modules/build/ssg/path.ts
11911
- import path13 from "path";
12393
+ import path15 from "path";
11912
12394
  function buildPathFromPattern(pattern, params) {
11913
12395
  const segments = pattern.split("/").filter(Boolean);
11914
12396
  const parts = [];
@@ -11937,12 +12419,12 @@ function buildPathFromPattern(pattern, params) {
11937
12419
  }
11938
12420
  function pathToOutDir(baseDir, urlPath) {
11939
12421
  const clean = urlPath === "/" ? "" : urlPath.replace(/^\/+/, "");
11940
- return path13.join(baseDir, clean);
12422
+ return path15.join(baseDir, clean);
11941
12423
  }
11942
12424
 
11943
12425
  // modules/build/ssg/renderer.ts
11944
- import fs14 from "fs";
11945
- import path18 from "path";
12426
+ import fs16 from "fs";
12427
+ import path20 from "path";
11946
12428
  import { renderToString } from "react-dom/server";
11947
12429
 
11948
12430
  // modules/rendering/createDocumentTree/index.ts
@@ -12365,7 +12847,7 @@ init_globals();
12365
12847
  import { renderToPipeableStream } from "react-dom/server";
12366
12848
 
12367
12849
  // modules/server/handlers/middleware.ts
12368
- import path14 from "path";
12850
+ import path16 from "path";
12369
12851
 
12370
12852
  // modules/logger/index.ts
12371
12853
  import pino from "pino";
@@ -12497,12 +12979,12 @@ var DEFAULT_IGNORED_PATHS = [
12497
12979
  /^\/sockjs-node/
12498
12980
  // Hot reload websocket
12499
12981
  ];
12500
- function shouldIgnorePath(path29, ignoredPaths) {
12982
+ function shouldIgnorePath(path31, ignoredPaths) {
12501
12983
  return ignoredPaths.some((pattern) => {
12502
12984
  if (typeof pattern === "string") {
12503
- return path29 === pattern || path29.startsWith(pattern);
12985
+ return path31 === pattern || path31.startsWith(pattern);
12504
12986
  }
12505
- return pattern.test(path29);
12987
+ return pattern.test(path31);
12506
12988
  });
12507
12989
  }
12508
12990
  function requestLoggerMiddleware(options = {}) {
@@ -12564,7 +13046,7 @@ async function runRouteMiddlewares(route, ctx) {
12564
13046
  );
12565
13047
  } catch (error) {
12566
13048
  const reqLogger = getRequestLogger(ctx.req);
12567
- const relativePath = route.pageFile ? path14.relative(process.cwd(), route.pageFile) : route.pattern;
13049
+ const relativePath = route.pageFile ? path16.relative(process.cwd(), route.pageFile) : route.pattern;
12568
13050
  reqLogger.error("Route middleware failed", error instanceof Error ? error : new Error(String(error)), {
12569
13051
  route: route.pattern,
12570
13052
  middlewareIndex: i,
@@ -12579,7 +13061,7 @@ async function runRouteMiddlewares(route, ctx) {
12579
13061
  }
12580
13062
 
12581
13063
  // modules/server/handlers/server-hook.ts
12582
- import path15 from "path";
13064
+ import path17 from "path";
12583
13065
  function createServerHookErrorMessage(error, hookType, routePattern, filePath) {
12584
13066
  const errorMessage = error instanceof Error ? error.message : String(error);
12585
13067
  const errorStack = error instanceof Error ? error.stack : void 0;
@@ -12588,7 +13070,7 @@ function createServerHookErrorMessage(error, hookType, routePattern, filePath) {
12588
13070
  message += `Route: ${routePattern}
12589
13071
  `;
12590
13072
  if (filePath) {
12591
- const relativePath = path15.relative(process.cwd(), filePath);
13073
+ const relativePath = path17.relative(process.cwd(), filePath);
12592
13074
  message += `File: ${relativePath}
12593
13075
  `;
12594
13076
  }
@@ -12649,7 +13131,9 @@ function handleDataResponse(res, loaderResult, theme, layoutProps, pageProps, er
12649
13131
  // Combined props for backward compatibility
12650
13132
  props: loaderResult.props ?? {},
12651
13133
  metadata: loaderResult.metadata ?? null,
12652
- theme: loaderResult.theme ?? theme ?? null
13134
+ theme: loaderResult.theme ?? theme ?? null,
13135
+ // Include pathname if provided (for rewrites - client needs to know the rewritten path)
13136
+ ...loaderResult.pathname ? { pathname: loaderResult.pathname } : {}
12653
13137
  };
12654
13138
  if (layoutProps !== void 0 && layoutProps !== null) {
12655
13139
  response.layoutProps = layoutProps;
@@ -12681,24 +13165,24 @@ function handleNotFound(res, urlPath) {
12681
13165
  }
12682
13166
 
12683
13167
  // modules/server/handlers/ssg.ts
12684
- import fs13 from "fs";
12685
- import path16 from "path";
13168
+ import fs15 from "fs";
13169
+ import path18 from "path";
12686
13170
  var logger2 = createModuleLogger("ssg");
12687
13171
  function getSsgDirForPath(baseDir, urlPath) {
12688
13172
  const clean = urlPath === "/" ? "" : urlPath.replace(/^\/+/, "");
12689
- return path16.join(baseDir, clean);
13173
+ return path18.join(baseDir, clean);
12690
13174
  }
12691
13175
  function getSsgHtmlPath(baseDir, urlPath) {
12692
13176
  const dir = getSsgDirForPath(baseDir, urlPath);
12693
- return path16.join(dir, "index.html");
13177
+ return path18.join(dir, "index.html");
12694
13178
  }
12695
13179
  function getSsgDataPath(baseDir, urlPath) {
12696
13180
  const dir = getSsgDirForPath(baseDir, urlPath);
12697
- return path16.join(dir, "data.json");
13181
+ return path18.join(dir, "data.json");
12698
13182
  }
12699
13183
  function tryServeSsgHtml(res, ssgOutDir, urlPath) {
12700
13184
  const ssgHtmlPath = getSsgHtmlPath(ssgOutDir, urlPath);
12701
- if (!fs13.existsSync(ssgHtmlPath)) {
13185
+ if (!fs15.existsSync(ssgHtmlPath)) {
12702
13186
  return false;
12703
13187
  }
12704
13188
  logger2.info("Serving SSG HTML", { urlPath, ssgHtmlPath });
@@ -12708,17 +13192,17 @@ function tryServeSsgHtml(res, ssgOutDir, urlPath) {
12708
13192
  );
12709
13193
  res.statusCode = 200;
12710
13194
  res.setHeader("Content-Type", "text/html; charset=utf-8");
12711
- const stream = fs13.createReadStream(ssgHtmlPath, { encoding: "utf-8" });
13195
+ const stream = fs15.createReadStream(ssgHtmlPath, { encoding: "utf-8" });
12712
13196
  stream.pipe(res);
12713
13197
  return true;
12714
13198
  }
12715
13199
  function tryServeSsgData(res, ssgOutDir, urlPath) {
12716
13200
  const ssgDataPath = getSsgDataPath(ssgOutDir, urlPath);
12717
- if (!fs13.existsSync(ssgDataPath)) {
13201
+ if (!fs15.existsSync(ssgDataPath)) {
12718
13202
  return false;
12719
13203
  }
12720
13204
  try {
12721
- const raw = fs13.readFileSync(ssgDataPath, "utf-8");
13205
+ const raw = fs15.readFileSync(ssgDataPath, "utf-8");
12722
13206
  res.setHeader("Content-Type", "application/json; charset=utf-8");
12723
13207
  res.status(200).end(raw);
12724
13208
  return true;
@@ -12784,7 +13268,7 @@ function sanitizeQuery(query) {
12784
13268
  }
12785
13269
 
12786
13270
  // modules/server/handlers/pages.ts
12787
- import path17 from "path";
13271
+ import path19 from "path";
12788
13272
  function mergeMetadata(base, override) {
12789
13273
  if (!base && !override) return null;
12790
13274
  if (!base) return override;
@@ -12851,8 +13335,43 @@ async function handlePageRequestInternal(options) {
12851
13335
  ssgOutDir,
12852
13336
  theme,
12853
13337
  projectRoot,
12854
- config
13338
+ config,
13339
+ rewriteLoader
12855
13340
  } = options;
13341
+ let finalUrlPath = urlPath;
13342
+ let extractedParams = {};
13343
+ if (rewriteLoader) {
13344
+ try {
13345
+ const compiledRewrites = await rewriteLoader.loadRewrites();
13346
+ const rewriteResult = await processRewrites(urlPath, compiledRewrites, req);
13347
+ if (rewriteResult) {
13348
+ finalUrlPath = rewriteResult.rewrittenPath;
13349
+ extractedParams = rewriteResult.extractedParams;
13350
+ finalUrlPath = finalUrlPath.replace(/\/+/g, "/").replace(/^([^/])/, "/$1").replace(/\/$/, "") || "/";
13351
+ if (env === "dev") {
13352
+ const reqLogger2 = getRequestLogger(req);
13353
+ reqLogger2.debug("Rewrite applied", {
13354
+ originalPath: urlPath,
13355
+ rewrittenPath: finalUrlPath,
13356
+ extractedParams,
13357
+ host: req.get("host")
13358
+ });
13359
+ }
13360
+ Object.assign(req.query, extractedParams);
13361
+ if (!req.locals) {
13362
+ req.locals = {};
13363
+ }
13364
+ Object.assign(req.locals, extractedParams);
13365
+ }
13366
+ } catch (error) {
13367
+ const reqLogger2 = getRequestLogger(req);
13368
+ reqLogger2.error("Error processing rewrites", error, {
13369
+ urlPath,
13370
+ host: req.get("host")
13371
+ });
13372
+ }
13373
+ }
13374
+ finalUrlPath = finalUrlPath.replace(/\/$/, "") || "/";
12856
13375
  const clientJsPath = env === "dev" ? "/static/client.js" : projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
12857
13376
  const clientCssPath = env === "dev" ? "/static/client.css" : projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
12858
13377
  const assetManifest = env === "prod" && projectRoot ? loadAssetManifest(projectRoot) : null;
@@ -12861,18 +13380,43 @@ async function handlePageRequestInternal(options) {
12861
13380
  const skipLayoutHooks = isDataReq && req.headers["x-skip-layout-hooks"] === "true";
12862
13381
  if (env === "prod" && ssgOutDir) {
12863
13382
  if (isDataReq) {
12864
- if (tryServeSsgData(res, ssgOutDir, urlPath)) {
13383
+ if (tryServeSsgData(res, ssgOutDir, finalUrlPath)) {
12865
13384
  return;
12866
13385
  }
12867
13386
  } else {
12868
- if (tryServeSsgHtml(res, ssgOutDir, urlPath)) {
13387
+ if (tryServeSsgHtml(res, ssgOutDir, finalUrlPath)) {
12869
13388
  return;
12870
13389
  }
12871
13390
  }
12872
13391
  }
12873
- const matched = matchRoute(routes, urlPath);
13392
+ const matched = matchRoute(routes, finalUrlPath);
13393
+ if (env === "dev") {
13394
+ const reqLogger2 = getRequestLogger(req);
13395
+ if (finalUrlPath !== urlPath) {
13396
+ reqLogger2.debug("Route matching after rewrite", {
13397
+ originalPath: urlPath,
13398
+ rewrittenPath: finalUrlPath,
13399
+ matched: !!matched,
13400
+ matchedRoute: matched?.route.pattern,
13401
+ matchedParams: matched?.params,
13402
+ availableRoutes: routes.slice(0, 10).map((r) => r.pattern)
13403
+ // Show first 10 routes
13404
+ });
13405
+ } else if (!matched) {
13406
+ reqLogger2.debug("No route match found", {
13407
+ path: finalUrlPath,
13408
+ availableRoutes: routes.slice(0, 10).map((r) => r.pattern)
13409
+ });
13410
+ }
13411
+ }
12874
13412
  const routerData = buildRouterData(req);
12875
13413
  if (!matched) {
13414
+ if (isDataReq) {
13415
+ res.statusCode = 404;
13416
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
13417
+ res.end(JSON.stringify({ notFound: true, pathname: finalUrlPath }));
13418
+ return;
13419
+ }
12876
13420
  if (notFoundPage) {
12877
13421
  const ctx2 = {
12878
13422
  req,
@@ -12896,7 +13440,7 @@ async function handlePageRequestInternal(options) {
12896
13440
  } catch (error) {
12897
13441
  const reqLogger2 = getRequestLogger(req);
12898
13442
  const layoutFile = notFoundPage.layoutFiles[i];
12899
- const relativeLayoutPath = layoutFile ? path17.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
13443
+ const relativeLayoutPath = layoutFile ? path19.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
12900
13444
  reqLogger2.error("Layout middleware failed for not-found page", error instanceof Error ? error : new Error(String(error)), {
12901
13445
  layoutIndex: i,
12902
13446
  layoutFile: relativeLayoutPath
@@ -12917,7 +13461,7 @@ async function handlePageRequestInternal(options) {
12917
13461
  } catch (error) {
12918
13462
  const reqLogger2 = getRequestLogger(req);
12919
13463
  const layoutFile = notFoundPage.layoutFiles[i];
12920
- const relativeLayoutPath = layoutFile ? path17.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
13464
+ const relativeLayoutPath = layoutFile ? path19.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
12921
13465
  reqLogger2.warn("Layout server hook failed for not-found page", {
12922
13466
  error: error instanceof Error ? error.message : String(error),
12923
13467
  stack: error instanceof Error ? error.stack : void 0,
@@ -12951,7 +13495,7 @@ async function handlePageRequestInternal(options) {
12951
13495
  );
12952
13496
  return;
12953
13497
  }
12954
- const initialData2 = buildInitialData(urlPath, {}, combinedLoaderResult2);
13498
+ const initialData2 = buildInitialData(finalUrlPath, {}, combinedLoaderResult2);
12955
13499
  const appTree2 = buildAppTree(notFoundPage, {}, initialData2.props);
12956
13500
  initialData2.notFound = true;
12957
13501
  const nonce2 = res.locals.nonce || void 0;
@@ -13037,7 +13581,7 @@ async function handlePageRequestInternal(options) {
13037
13581
  );
13038
13582
  } catch (error) {
13039
13583
  const layoutFile = route.layoutFiles[i];
13040
- const relativeLayoutPath = layoutFile ? path17.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
13584
+ const relativeLayoutPath = layoutFile ? path19.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
13041
13585
  reqLogger.error("Layout middleware failed", error instanceof Error ? error : new Error(String(error)), {
13042
13586
  route: route.pattern,
13043
13587
  layoutIndex: i,
@@ -13061,7 +13605,7 @@ async function handlePageRequestInternal(options) {
13061
13605
  }
13062
13606
  } catch (error) {
13063
13607
  const layoutFile = route.layoutFiles[i];
13064
- const relativeLayoutPath = layoutFile ? path17.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
13608
+ const relativeLayoutPath = layoutFile ? path19.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
13065
13609
  reqLogger.warn("Layout server hook failed", {
13066
13610
  error: error instanceof Error ? error.message : String(error),
13067
13611
  stack: error instanceof Error ? error.stack : void 0,
@@ -13081,7 +13625,7 @@ async function handlePageRequestInternal(options) {
13081
13625
  loaderResult.theme = theme;
13082
13626
  }
13083
13627
  } catch (error) {
13084
- const relativePagePath = route.pageFile ? path17.relative(projectRoot || process.cwd(), route.pageFile) : "unknown";
13628
+ const relativePagePath = route.pageFile ? path19.relative(projectRoot || process.cwd(), route.pageFile) : "unknown";
13085
13629
  reqLogger.error("Page server hook failed", {
13086
13630
  error: error instanceof Error ? error.message : String(error),
13087
13631
  stack: error instanceof Error ? error.stack : void 0,
@@ -13128,7 +13672,9 @@ async function handlePageRequestInternal(options) {
13128
13672
  const combinedLoaderResult = {
13129
13673
  ...loaderResult,
13130
13674
  props: combinedProps,
13131
- metadata: combinedMetadata
13675
+ metadata: combinedMetadata,
13676
+ pathname: finalUrlPath
13677
+ // Include rewritten pathname for client-side matching
13132
13678
  };
13133
13679
  if (isDataReq) {
13134
13680
  const pagePropsOnly = loaderResult.props || {};
@@ -13153,7 +13699,7 @@ async function handlePageRequestInternal(options) {
13153
13699
  }
13154
13700
  return;
13155
13701
  }
13156
- const initialData = buildInitialData(urlPath, params, combinedLoaderResult);
13702
+ const initialData = buildInitialData(finalUrlPath, params, combinedLoaderResult);
13157
13703
  const appTree = buildAppTree(route, params, initialData.props);
13158
13704
  const chunkName = routeChunks[route.pattern];
13159
13705
  let chunkHref = null;
@@ -13258,7 +13804,7 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
13258
13804
  );
13259
13805
  } catch (error2) {
13260
13806
  const layoutFile = errorPage.layoutFiles[i];
13261
- const relativeLayoutPath = layoutFile ? path17.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
13807
+ const relativeLayoutPath = layoutFile ? path19.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
13262
13808
  reqLogger.error("Layout middleware failed for error page", error2 instanceof Error ? error2 : new Error(String(error2)), {
13263
13809
  layoutIndex: i,
13264
13810
  layoutFile: relativeLayoutPath
@@ -13278,7 +13824,7 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
13278
13824
  }
13279
13825
  } catch (err) {
13280
13826
  const layoutFile = errorPage.layoutFiles[i];
13281
- const relativeLayoutPath = layoutFile ? path17.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
13827
+ const relativeLayoutPath = layoutFile ? path19.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
13282
13828
  reqLogger.warn("Layout server hook failed for error page", {
13283
13829
  error: err instanceof Error ? err.message : String(err),
13284
13830
  stack: err instanceof Error ? err.stack : void 0,
@@ -13515,16 +14061,16 @@ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params,
13515
14061
  const html = "<!DOCTYPE html>" + renderToString(documentTree);
13516
14062
  const dir = pathToOutDir(ssgOutDir, urlPath);
13517
14063
  ensureDir(dir);
13518
- const htmlFile = path18.join(dir, "index.html");
13519
- const dataFile = path18.join(dir, "data.json");
13520
- fs14.writeFileSync(htmlFile, html, "utf-8");
13521
- fs14.writeFileSync(dataFile, JSON.stringify(initialData, null, 2), "utf-8");
14064
+ const htmlFile = path20.join(dir, "index.html");
14065
+ const dataFile = path20.join(dir, "data.json");
14066
+ fs16.writeFileSync(htmlFile, html, "utf-8");
14067
+ fs16.writeFileSync(dataFile, JSON.stringify(initialData, null, 2), "utf-8");
13522
14068
  }
13523
14069
 
13524
14070
  // modules/build/ssg/builder.ts
13525
14071
  init_globals();
13526
14072
  async function buildStaticPages(projectRoot, routes, config) {
13527
- const ssgOutDir = path19.join(projectRoot, BUILD_FOLDER_NAME, "ssg");
14073
+ const ssgOutDir = path21.join(projectRoot, BUILD_FOLDER_NAME, "ssg");
13528
14074
  ensureDir(ssgOutDir);
13529
14075
  for (const route of routes) {
13530
14076
  if (route.dynamic !== "force-static") continue;
@@ -13579,27 +14125,27 @@ async function buildStaticPages(projectRoot, routes, config) {
13579
14125
  }
13580
14126
 
13581
14127
  // modules/build/bundler/server.ts
13582
- import path21 from "path";
13583
- import fs16 from "fs";
14128
+ import path23 from "path";
14129
+ import fs18 from "fs";
13584
14130
  import esbuild from "esbuild";
13585
14131
 
13586
14132
  // modules/server/utils/server-dir.ts
13587
14133
  init_globals();
13588
- import fs15 from "fs";
13589
- import path20 from "path";
14134
+ import fs17 from "fs";
14135
+ import path22 from "path";
13590
14136
  var getServerFile = async (projectRoot, fileName) => {
13591
- const fileTS = path20.join(projectRoot, `${fileName}.ts`);
13592
- const fileJS = path20.join(projectRoot, BUILD_FOLDER_NAME, "server", `${fileName}.js`);
14137
+ const fileTS = path22.join(projectRoot, `${fileName}.ts`);
14138
+ const fileJS = path22.join(projectRoot, BUILD_FOLDER_NAME, "server", `${fileName}.js`);
13593
14139
  const isDev = process.env.NODE_ENV === "development";
13594
14140
  let mod = null;
13595
14141
  if (isDev) {
13596
- if (!fs15.existsSync(fileTS)) {
14142
+ if (!fs17.existsSync(fileTS)) {
13597
14143
  return null;
13598
14144
  }
13599
14145
  __require("tsx/cjs");
13600
14146
  mod = __require(fileTS);
13601
14147
  } else {
13602
- if (!fs15.existsSync(fileJS)) {
14148
+ if (!fs17.existsSync(fileJS)) {
13603
14149
  return null;
13604
14150
  }
13605
14151
  mod = __require(fileJS);
@@ -13781,29 +14327,29 @@ init_globals();
13781
14327
  var SERVER_FILES = [INIT_FILE_NAME, CONFIG_FILE_NAME];
13782
14328
  function createPathAliasPlugin(projectRoot, outDir) {
13783
14329
  const aliases = loadAliasesFromTsconfig(projectRoot);
13784
- const tsconfigPath = path21.join(projectRoot, "tsconfig.json");
14330
+ const tsconfigPath = path23.join(projectRoot, "tsconfig.json");
13785
14331
  let baseUrl = ".";
13786
- if (fs16.existsSync(tsconfigPath)) {
14332
+ if (fs18.existsSync(tsconfigPath)) {
13787
14333
  try {
13788
- const tsconfig = JSON.parse(fs16.readFileSync(tsconfigPath, "utf-8"));
14334
+ const tsconfig = JSON.parse(fs18.readFileSync(tsconfigPath, "utf-8"));
13789
14335
  baseUrl = tsconfig.compilerOptions?.baseUrl ?? ".";
13790
14336
  } catch {
13791
14337
  }
13792
14338
  }
13793
14339
  function resolveAliasToRelative(importPath, sourceFile) {
13794
- if (importPath.startsWith(".") || importPath.startsWith("/") || path21.isAbsolute(importPath) || importPath.includes("node_modules")) {
14340
+ if (importPath.startsWith(".") || importPath.startsWith("/") || path23.isAbsolute(importPath) || importPath.includes("node_modules")) {
13795
14341
  return null;
13796
14342
  }
13797
14343
  for (const [aliasKey, aliasPath] of Object.entries(aliases)) {
13798
14344
  if (importPath.startsWith(aliasKey + "/") || importPath === aliasKey) {
13799
14345
  const restPath = importPath.startsWith(aliasKey + "/") ? importPath.slice(aliasKey.length + 1) : "";
13800
- const resolvedPath = restPath ? path21.join(aliasPath, restPath) : aliasPath;
14346
+ const resolvedPath = restPath ? path23.join(aliasPath, restPath) : aliasPath;
13801
14347
  let actualPath = null;
13802
14348
  const extensions = [".ts", ".tsx", ".js", ".jsx", ".json"];
13803
- if (fs16.existsSync(resolvedPath) && fs16.statSync(resolvedPath).isDirectory()) {
14349
+ if (fs18.existsSync(resolvedPath) && fs18.statSync(resolvedPath).isDirectory()) {
13804
14350
  for (const ext of extensions) {
13805
- const indexPath = path21.join(resolvedPath, `index${ext}`);
13806
- if (fs16.existsSync(indexPath)) {
14351
+ const indexPath = path23.join(resolvedPath, `index${ext}`);
14352
+ if (fs18.existsSync(indexPath)) {
13807
14353
  actualPath = indexPath;
13808
14354
  break;
13809
14355
  }
@@ -13811,20 +14357,20 @@ function createPathAliasPlugin(projectRoot, outDir) {
13811
14357
  } else {
13812
14358
  for (const ext of extensions) {
13813
14359
  const filePath = resolvedPath + ext;
13814
- if (fs16.existsSync(filePath)) {
14360
+ if (fs18.existsSync(filePath)) {
13815
14361
  actualPath = filePath;
13816
14362
  break;
13817
14363
  }
13818
14364
  }
13819
- if (!actualPath && fs16.existsSync(resolvedPath)) {
14365
+ if (!actualPath && fs18.existsSync(resolvedPath)) {
13820
14366
  actualPath = resolvedPath;
13821
14367
  }
13822
14368
  }
13823
14369
  if (actualPath) {
13824
- const relativePath = path21.relative(outDir, actualPath);
14370
+ const relativePath = path23.relative(outDir, actualPath);
13825
14371
  const normalizedPath = relativePath.replace(/\\/g, "/");
13826
14372
  const finalPath = normalizedPath.startsWith(".") ? normalizedPath : `./${normalizedPath}`;
13827
- const ext = path21.extname(finalPath);
14373
+ const ext = path23.extname(finalPath);
13828
14374
  const pathWithoutExt = ext === ".json" ? finalPath : finalPath.slice(0, -ext.length);
13829
14375
  return pathWithoutExt;
13830
14376
  }
@@ -13836,13 +14382,13 @@ function createPathAliasPlugin(projectRoot, outDir) {
13836
14382
  name: "path-alias-resolver",
13837
14383
  setup(build) {
13838
14384
  build.onLoad({ filter: /\.(ts|tsx|js|jsx)$/ }, (args) => {
13839
- const fileName = path21.basename(args.path);
14385
+ const fileName = path23.basename(args.path);
13840
14386
  const isServerFile = SERVER_FILES.some((f) => fileName === `${f}.ts` || fileName === `${f}.tsx` || fileName === `${f}.js` || fileName === `${f}.jsx`);
13841
- const isInProjectRoot = path21.dirname(args.path) === projectRoot;
14387
+ const isInProjectRoot = path23.dirname(args.path) === projectRoot;
13842
14388
  if (!isServerFile || !isInProjectRoot) {
13843
14389
  return null;
13844
14390
  }
13845
- const contents = fs16.readFileSync(args.path, "utf-8");
14391
+ const contents = fs18.readFileSync(args.path, "utf-8");
13846
14392
  let transformed = contents;
13847
14393
  const aliasPatterns = Object.keys(aliases).sort((a, b) => b.length - a.length);
13848
14394
  for (const aliasKey of aliasPatterns) {
@@ -13862,7 +14408,7 @@ function createPathAliasPlugin(projectRoot, outDir) {
13862
14408
  }
13863
14409
  return {
13864
14410
  contents: transformed,
13865
- loader: path21.extname(args.path).slice(1)
14411
+ loader: path23.extname(args.path).slice(1)
13866
14412
  };
13867
14413
  });
13868
14414
  build.onResolve({ filter: /.*/ }, (args) => {
@@ -13881,9 +14427,9 @@ function createPathAliasPlugin(projectRoot, outDir) {
13881
14427
  function collectAppSources(appDir) {
13882
14428
  const entries = [];
13883
14429
  function walk(dir) {
13884
- const items = fs16.readdirSync(dir, { withFileTypes: true });
14430
+ const items = fs18.readdirSync(dir, { withFileTypes: true });
13885
14431
  for (const item of items) {
13886
- const full = path21.join(dir, item.name);
14432
+ const full = path23.join(dir, item.name);
13887
14433
  if (item.isDirectory()) {
13888
14434
  walk(full);
13889
14435
  continue;
@@ -13900,7 +14446,7 @@ function collectAppSources(appDir) {
13900
14446
  return entries;
13901
14447
  }
13902
14448
  async function buildServerApp(projectRoot, appDir) {
13903
- const outDir = path21.join(projectRoot, BUILD_FOLDER_NAME, "server");
14449
+ const outDir = path23.join(projectRoot, BUILD_FOLDER_NAME, "server");
13904
14450
  const entryPoints = collectAppSources(appDir);
13905
14451
  ensureDir(outDir);
13906
14452
  if (entryPoints.length === 0) {
@@ -13918,14 +14464,14 @@ async function buildServerApp(projectRoot, appDir) {
13918
14464
  bundle: true,
13919
14465
  splitting: false,
13920
14466
  logLevel: "info",
13921
- tsconfig: path21.join(projectRoot, "tsconfig.json"),
14467
+ tsconfig: path23.join(projectRoot, "tsconfig.json"),
13922
14468
  packages: "external"
13923
14469
  });
13924
14470
  const pathAliasPlugin = createPathAliasPlugin(projectRoot, outDir);
13925
14471
  for (const fileName of SERVER_FILES) {
13926
- const initTS = path21.join(projectRoot, `${fileName}.ts`);
13927
- const initJS = path21.join(outDir, `${fileName}.js`);
13928
- if (fs16.existsSync(initTS)) {
14472
+ const initTS = path23.join(projectRoot, `${fileName}.ts`);
14473
+ const initJS = path23.join(outDir, `${fileName}.js`);
14474
+ if (fs18.existsSync(initTS)) {
13929
14475
  await esbuild.build({
13930
14476
  entryPoints: [initTS],
13931
14477
  outfile: initJS,
@@ -13936,7 +14482,7 @@ async function buildServerApp(projectRoot, appDir) {
13936
14482
  sourcemap: true,
13937
14483
  bundle: false,
13938
14484
  logLevel: "info",
13939
- tsconfig: path21.join(projectRoot, "tsconfig.json"),
14485
+ tsconfig: path23.join(projectRoot, "tsconfig.json"),
13940
14486
  plugins: [pathAliasPlugin]
13941
14487
  });
13942
14488
  }
@@ -13949,8 +14495,8 @@ init_globals();
13949
14495
 
13950
14496
  // src/config.ts
13951
14497
  init_globals();
13952
- import path22 from "path";
13953
- import fs17 from "fs";
14498
+ import path24 from "path";
14499
+ import fs19 from "fs";
13954
14500
  var DEFAULT_CONFIG2 = {
13955
14501
  directories: {
13956
14502
  app: "app",
@@ -14016,8 +14562,8 @@ function validateConfig(config, projectRoot) {
14016
14562
  if (!config.directories.app || typeof config.directories.app !== "string") {
14017
14563
  errors.push("config.directories.app must be a non-empty string");
14018
14564
  } else {
14019
- const appDir = path22.join(projectRoot, config.directories.app);
14020
- if (!fs17.existsSync(appDir) && process.env.NODE_ENV !== "test") {
14565
+ const appDir = path24.join(projectRoot, config.directories.app);
14566
+ if (!fs19.existsSync(appDir) && process.env.NODE_ENV !== "test") {
14021
14567
  errors.push(
14022
14568
  `App directory not found: ${config.directories.app}
14023
14569
  Expected at: ${appDir}
@@ -14121,17 +14667,17 @@ function validateConfig(config, projectRoot) {
14121
14667
  }
14122
14668
  function loadConfig(projectRoot) {
14123
14669
  const configFiles = [
14124
- path22.join(projectRoot, "loly.config.ts"),
14125
- path22.join(projectRoot, "loly.config.js"),
14126
- path22.join(projectRoot, "loly.config.json")
14670
+ path24.join(projectRoot, "loly.config.ts"),
14671
+ path24.join(projectRoot, "loly.config.js"),
14672
+ path24.join(projectRoot, "loly.config.json")
14127
14673
  ];
14128
14674
  let userConfig = {};
14129
14675
  let loadedConfigFile = null;
14130
14676
  for (const configFile of configFiles) {
14131
- if (fs17.existsSync(configFile)) {
14677
+ if (fs19.existsSync(configFile)) {
14132
14678
  try {
14133
14679
  if (configFile.endsWith(".json")) {
14134
- const content = fs17.readFileSync(configFile, "utf-8");
14680
+ const content = fs19.readFileSync(configFile, "utf-8");
14135
14681
  userConfig = JSON.parse(content);
14136
14682
  } else {
14137
14683
  if (process.env.NODE_ENV === "development") {
@@ -14140,12 +14686,12 @@ function loadConfig(projectRoot) {
14140
14686
  const mod = __require(configFile);
14141
14687
  userConfig = typeof mod.default === "function" ? mod.default(process.env.NODE_ENV) : mod.default || mod.config || mod;
14142
14688
  }
14143
- loadedConfigFile = path22.relative(projectRoot, configFile);
14689
+ loadedConfigFile = path24.relative(projectRoot, configFile);
14144
14690
  break;
14145
14691
  } catch (error) {
14146
14692
  const errorMessage = error instanceof Error ? error.message : String(error);
14147
14693
  throw new ConfigValidationError(
14148
- `Failed to load configuration from ${path22.relative(projectRoot, configFile)}:
14694
+ `Failed to load configuration from ${path24.relative(projectRoot, configFile)}:
14149
14695
  ${errorMessage}
14150
14696
  \u{1F4A1} Suggestion: Check that your config file exports a valid configuration object`
14151
14697
  );
@@ -14169,13 +14715,13 @@ ${error.message}`;
14169
14715
  return config;
14170
14716
  }
14171
14717
  function getAppDir(projectRoot, config) {
14172
- return path22.resolve(projectRoot, config.directories.app);
14718
+ return path24.resolve(projectRoot, config.directories.app);
14173
14719
  }
14174
14720
  function getBuildDir(projectRoot, config) {
14175
- return path22.join(projectRoot, config.directories.build);
14721
+ return path24.join(projectRoot, config.directories.build);
14176
14722
  }
14177
14723
  function getStaticDir(projectRoot, config) {
14178
- return path22.resolve(projectRoot, config.directories.static);
14724
+ return path24.resolve(projectRoot, config.directories.static);
14179
14725
  }
14180
14726
 
14181
14727
  // modules/build/index.ts
@@ -14220,6 +14766,7 @@ async function buildApp(options = {}) {
14220
14766
  });
14221
14767
  writeClientBoostrapManifest(projectRoot);
14222
14768
  writeClientRoutesManifest(routes, projectRoot);
14769
+ await writeRewritesManifest(projectRoot);
14223
14770
  await buildClientBundle(projectRoot);
14224
14771
  await buildStaticPages(projectRoot, routes, config);
14225
14772
  delete process.env.LOLY_BUILD;
@@ -14227,13 +14774,13 @@ async function buildApp(options = {}) {
14227
14774
  }
14228
14775
 
14229
14776
  // src/server.ts
14230
- import fs19 from "fs";
14231
- import path27 from "path";
14777
+ import fs21 from "fs";
14778
+ import path29 from "path";
14232
14779
 
14233
14780
  // modules/server/setup.ts
14234
14781
  import express from "express";
14235
- import path25 from "path";
14236
- import fs18 from "fs";
14782
+ import path27 from "path";
14783
+ import fs20 from "fs";
14237
14784
 
14238
14785
  // ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
14239
14786
  import { stat as statcb } from "fs";
@@ -14311,7 +14858,7 @@ var ReaddirpStream = class extends Readable {
14311
14858
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
14312
14859
  const statMethod = opts.lstat ? lstat : stat;
14313
14860
  if (wantBigintFsStats) {
14314
- this._stat = (path29) => statMethod(path29, { bigint: true });
14861
+ this._stat = (path31) => statMethod(path31, { bigint: true });
14315
14862
  } else {
14316
14863
  this._stat = statMethod;
14317
14864
  }
@@ -14336,8 +14883,8 @@ var ReaddirpStream = class extends Readable {
14336
14883
  const par = this.parent;
14337
14884
  const fil = par && par.files;
14338
14885
  if (fil && fil.length > 0) {
14339
- const { path: path29, depth } = par;
14340
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path29));
14886
+ const { path: path31, depth } = par;
14887
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path31));
14341
14888
  const awaited = await Promise.all(slice);
14342
14889
  for (const entry of awaited) {
14343
14890
  if (!entry)
@@ -14377,20 +14924,20 @@ var ReaddirpStream = class extends Readable {
14377
14924
  this.reading = false;
14378
14925
  }
14379
14926
  }
14380
- async _exploreDir(path29, depth) {
14927
+ async _exploreDir(path31, depth) {
14381
14928
  let files;
14382
14929
  try {
14383
- files = await readdir(path29, this._rdOptions);
14930
+ files = await readdir(path31, this._rdOptions);
14384
14931
  } catch (error) {
14385
14932
  this._onError(error);
14386
14933
  }
14387
- return { files, depth, path: path29 };
14934
+ return { files, depth, path: path31 };
14388
14935
  }
14389
- async _formatEntry(dirent, path29) {
14936
+ async _formatEntry(dirent, path31) {
14390
14937
  let entry;
14391
14938
  const basename3 = this._isDirent ? dirent.name : dirent;
14392
14939
  try {
14393
- const fullPath = presolve(pjoin(path29, basename3));
14940
+ const fullPath = presolve(pjoin(path31, basename3));
14394
14941
  entry = { path: prelative(this._root, fullPath), fullPath, basename: basename3 };
14395
14942
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
14396
14943
  } catch (err) {
@@ -14790,16 +15337,16 @@ var delFromSet = (main, prop, item) => {
14790
15337
  };
14791
15338
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
14792
15339
  var FsWatchInstances = /* @__PURE__ */ new Map();
14793
- function createFsWatchInstance(path29, options, listener, errHandler, emitRaw) {
15340
+ function createFsWatchInstance(path31, options, listener, errHandler, emitRaw) {
14794
15341
  const handleEvent = (rawEvent, evPath) => {
14795
- listener(path29);
14796
- emitRaw(rawEvent, evPath, { watchedPath: path29 });
14797
- if (evPath && path29 !== evPath) {
14798
- fsWatchBroadcast(sysPath.resolve(path29, evPath), KEY_LISTENERS, sysPath.join(path29, evPath));
15342
+ listener(path31);
15343
+ emitRaw(rawEvent, evPath, { watchedPath: path31 });
15344
+ if (evPath && path31 !== evPath) {
15345
+ fsWatchBroadcast(sysPath.resolve(path31, evPath), KEY_LISTENERS, sysPath.join(path31, evPath));
14799
15346
  }
14800
15347
  };
14801
15348
  try {
14802
- return fs_watch(path29, {
15349
+ return fs_watch(path31, {
14803
15350
  persistent: options.persistent
14804
15351
  }, handleEvent);
14805
15352
  } catch (error) {
@@ -14815,12 +15362,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
14815
15362
  listener(val1, val2, val3);
14816
15363
  });
14817
15364
  };
14818
- var setFsWatchListener = (path29, fullPath, options, handlers) => {
15365
+ var setFsWatchListener = (path31, fullPath, options, handlers) => {
14819
15366
  const { listener, errHandler, rawEmitter } = handlers;
14820
15367
  let cont = FsWatchInstances.get(fullPath);
14821
15368
  let watcher;
14822
15369
  if (!options.persistent) {
14823
- watcher = createFsWatchInstance(path29, options, listener, errHandler, rawEmitter);
15370
+ watcher = createFsWatchInstance(path31, options, listener, errHandler, rawEmitter);
14824
15371
  if (!watcher)
14825
15372
  return;
14826
15373
  return watcher.close.bind(watcher);
@@ -14831,7 +15378,7 @@ var setFsWatchListener = (path29, fullPath, options, handlers) => {
14831
15378
  addAndConvert(cont, KEY_RAW, rawEmitter);
14832
15379
  } else {
14833
15380
  watcher = createFsWatchInstance(
14834
- path29,
15381
+ path31,
14835
15382
  options,
14836
15383
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
14837
15384
  errHandler,
@@ -14846,7 +15393,7 @@ var setFsWatchListener = (path29, fullPath, options, handlers) => {
14846
15393
  cont.watcherUnusable = true;
14847
15394
  if (isWindows && error.code === "EPERM") {
14848
15395
  try {
14849
- const fd = await open(path29, "r");
15396
+ const fd = await open(path31, "r");
14850
15397
  await fd.close();
14851
15398
  broadcastErr(error);
14852
15399
  } catch (err) {
@@ -14877,7 +15424,7 @@ var setFsWatchListener = (path29, fullPath, options, handlers) => {
14877
15424
  };
14878
15425
  };
14879
15426
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
14880
- var setFsWatchFileListener = (path29, fullPath, options, handlers) => {
15427
+ var setFsWatchFileListener = (path31, fullPath, options, handlers) => {
14881
15428
  const { listener, rawEmitter } = handlers;
14882
15429
  let cont = FsWatchFileInstances.get(fullPath);
14883
15430
  const copts = cont && cont.options;
@@ -14899,7 +15446,7 @@ var setFsWatchFileListener = (path29, fullPath, options, handlers) => {
14899
15446
  });
14900
15447
  const currmtime = curr.mtimeMs;
14901
15448
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
14902
- foreach(cont.listeners, (listener2) => listener2(path29, curr));
15449
+ foreach(cont.listeners, (listener2) => listener2(path31, curr));
14903
15450
  }
14904
15451
  })
14905
15452
  };
@@ -14927,13 +15474,13 @@ var NodeFsHandler = class {
14927
15474
  * @param listener on fs change
14928
15475
  * @returns closer for the watcher instance
14929
15476
  */
14930
- _watchWithNodeFs(path29, listener) {
15477
+ _watchWithNodeFs(path31, listener) {
14931
15478
  const opts = this.fsw.options;
14932
- const directory = sysPath.dirname(path29);
14933
- const basename3 = sysPath.basename(path29);
15479
+ const directory = sysPath.dirname(path31);
15480
+ const basename3 = sysPath.basename(path31);
14934
15481
  const parent = this.fsw._getWatchedDir(directory);
14935
15482
  parent.add(basename3);
14936
- const absolutePath = sysPath.resolve(path29);
15483
+ const absolutePath = sysPath.resolve(path31);
14937
15484
  const options = {
14938
15485
  persistent: opts.persistent
14939
15486
  };
@@ -14943,12 +15490,12 @@ var NodeFsHandler = class {
14943
15490
  if (opts.usePolling) {
14944
15491
  const enableBin = opts.interval !== opts.binaryInterval;
14945
15492
  options.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
14946
- closer = setFsWatchFileListener(path29, absolutePath, options, {
15493
+ closer = setFsWatchFileListener(path31, absolutePath, options, {
14947
15494
  listener,
14948
15495
  rawEmitter: this.fsw._emitRaw
14949
15496
  });
14950
15497
  } else {
14951
- closer = setFsWatchListener(path29, absolutePath, options, {
15498
+ closer = setFsWatchListener(path31, absolutePath, options, {
14952
15499
  listener,
14953
15500
  errHandler: this._boundHandleError,
14954
15501
  rawEmitter: this.fsw._emitRaw
@@ -14970,7 +15517,7 @@ var NodeFsHandler = class {
14970
15517
  let prevStats = stats;
14971
15518
  if (parent.has(basename3))
14972
15519
  return;
14973
- const listener = async (path29, newStats) => {
15520
+ const listener = async (path31, newStats) => {
14974
15521
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
14975
15522
  return;
14976
15523
  if (!newStats || newStats.mtimeMs === 0) {
@@ -14984,11 +15531,11 @@ var NodeFsHandler = class {
14984
15531
  this.fsw._emit(EV.CHANGE, file, newStats2);
14985
15532
  }
14986
15533
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
14987
- this.fsw._closeFile(path29);
15534
+ this.fsw._closeFile(path31);
14988
15535
  prevStats = newStats2;
14989
15536
  const closer2 = this._watchWithNodeFs(file, listener);
14990
15537
  if (closer2)
14991
- this.fsw._addPathCloser(path29, closer2);
15538
+ this.fsw._addPathCloser(path31, closer2);
14992
15539
  } else {
14993
15540
  prevStats = newStats2;
14994
15541
  }
@@ -15020,7 +15567,7 @@ var NodeFsHandler = class {
15020
15567
  * @param item basename of this item
15021
15568
  * @returns true if no more processing is needed for this entry.
15022
15569
  */
15023
- async _handleSymlink(entry, directory, path29, item) {
15570
+ async _handleSymlink(entry, directory, path31, item) {
15024
15571
  if (this.fsw.closed) {
15025
15572
  return;
15026
15573
  }
@@ -15030,7 +15577,7 @@ var NodeFsHandler = class {
15030
15577
  this.fsw._incrReadyCount();
15031
15578
  let linkPath;
15032
15579
  try {
15033
- linkPath = await fsrealpath(path29);
15580
+ linkPath = await fsrealpath(path31);
15034
15581
  } catch (e) {
15035
15582
  this.fsw._emitReady();
15036
15583
  return true;
@@ -15040,12 +15587,12 @@ var NodeFsHandler = class {
15040
15587
  if (dir.has(item)) {
15041
15588
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
15042
15589
  this.fsw._symlinkPaths.set(full, linkPath);
15043
- this.fsw._emit(EV.CHANGE, path29, entry.stats);
15590
+ this.fsw._emit(EV.CHANGE, path31, entry.stats);
15044
15591
  }
15045
15592
  } else {
15046
15593
  dir.add(item);
15047
15594
  this.fsw._symlinkPaths.set(full, linkPath);
15048
- this.fsw._emit(EV.ADD, path29, entry.stats);
15595
+ this.fsw._emit(EV.ADD, path31, entry.stats);
15049
15596
  }
15050
15597
  this.fsw._emitReady();
15051
15598
  return true;
@@ -15074,9 +15621,9 @@ var NodeFsHandler = class {
15074
15621
  return;
15075
15622
  }
15076
15623
  const item = entry.path;
15077
- let path29 = sysPath.join(directory, item);
15624
+ let path31 = sysPath.join(directory, item);
15078
15625
  current.add(item);
15079
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path29, item)) {
15626
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path31, item)) {
15080
15627
  return;
15081
15628
  }
15082
15629
  if (this.fsw.closed) {
@@ -15085,8 +15632,8 @@ var NodeFsHandler = class {
15085
15632
  }
15086
15633
  if (item === target || !target && !previous.has(item)) {
15087
15634
  this.fsw._incrReadyCount();
15088
- path29 = sysPath.join(dir, sysPath.relative(dir, path29));
15089
- this._addToNodeFs(path29, initialAdd, wh, depth + 1);
15635
+ path31 = sysPath.join(dir, sysPath.relative(dir, path31));
15636
+ this._addToNodeFs(path31, initialAdd, wh, depth + 1);
15090
15637
  }
15091
15638
  }).on(EV.ERROR, this._boundHandleError);
15092
15639
  return new Promise((resolve3, reject) => {
@@ -15155,13 +15702,13 @@ var NodeFsHandler = class {
15155
15702
  * @param depth Child path actually targeted for watch
15156
15703
  * @param target Child path actually targeted for watch
15157
15704
  */
15158
- async _addToNodeFs(path29, initialAdd, priorWh, depth, target) {
15705
+ async _addToNodeFs(path31, initialAdd, priorWh, depth, target) {
15159
15706
  const ready = this.fsw._emitReady;
15160
- if (this.fsw._isIgnored(path29) || this.fsw.closed) {
15707
+ if (this.fsw._isIgnored(path31) || this.fsw.closed) {
15161
15708
  ready();
15162
15709
  return false;
15163
15710
  }
15164
- const wh = this.fsw._getWatchHelpers(path29);
15711
+ const wh = this.fsw._getWatchHelpers(path31);
15165
15712
  if (priorWh) {
15166
15713
  wh.filterPath = (entry) => priorWh.filterPath(entry);
15167
15714
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -15177,8 +15724,8 @@ var NodeFsHandler = class {
15177
15724
  const follow = this.fsw.options.followSymlinks;
15178
15725
  let closer;
15179
15726
  if (stats.isDirectory()) {
15180
- const absPath = sysPath.resolve(path29);
15181
- const targetPath = follow ? await fsrealpath(path29) : path29;
15727
+ const absPath = sysPath.resolve(path31);
15728
+ const targetPath = follow ? await fsrealpath(path31) : path31;
15182
15729
  if (this.fsw.closed)
15183
15730
  return;
15184
15731
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -15188,29 +15735,29 @@ var NodeFsHandler = class {
15188
15735
  this.fsw._symlinkPaths.set(absPath, targetPath);
15189
15736
  }
15190
15737
  } else if (stats.isSymbolicLink()) {
15191
- const targetPath = follow ? await fsrealpath(path29) : path29;
15738
+ const targetPath = follow ? await fsrealpath(path31) : path31;
15192
15739
  if (this.fsw.closed)
15193
15740
  return;
15194
15741
  const parent = sysPath.dirname(wh.watchPath);
15195
15742
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
15196
15743
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
15197
- closer = await this._handleDir(parent, stats, initialAdd, depth, path29, wh, targetPath);
15744
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path31, wh, targetPath);
15198
15745
  if (this.fsw.closed)
15199
15746
  return;
15200
15747
  if (targetPath !== void 0) {
15201
- this.fsw._symlinkPaths.set(sysPath.resolve(path29), targetPath);
15748
+ this.fsw._symlinkPaths.set(sysPath.resolve(path31), targetPath);
15202
15749
  }
15203
15750
  } else {
15204
15751
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
15205
15752
  }
15206
15753
  ready();
15207
15754
  if (closer)
15208
- this.fsw._addPathCloser(path29, closer);
15755
+ this.fsw._addPathCloser(path31, closer);
15209
15756
  return false;
15210
15757
  } catch (error) {
15211
15758
  if (this.fsw._handleError(error)) {
15212
15759
  ready();
15213
- return path29;
15760
+ return path31;
15214
15761
  }
15215
15762
  }
15216
15763
  }
@@ -15253,26 +15800,26 @@ function createPattern(matcher) {
15253
15800
  }
15254
15801
  return () => false;
15255
15802
  }
15256
- function normalizePath(path29) {
15257
- if (typeof path29 !== "string")
15803
+ function normalizePath(path31) {
15804
+ if (typeof path31 !== "string")
15258
15805
  throw new Error("string expected");
15259
- path29 = sysPath2.normalize(path29);
15260
- path29 = path29.replace(/\\/g, "/");
15806
+ path31 = sysPath2.normalize(path31);
15807
+ path31 = path31.replace(/\\/g, "/");
15261
15808
  let prepend = false;
15262
- if (path29.startsWith("//"))
15809
+ if (path31.startsWith("//"))
15263
15810
  prepend = true;
15264
15811
  const DOUBLE_SLASH_RE2 = /\/\//;
15265
- while (path29.match(DOUBLE_SLASH_RE2))
15266
- path29 = path29.replace(DOUBLE_SLASH_RE2, "/");
15812
+ while (path31.match(DOUBLE_SLASH_RE2))
15813
+ path31 = path31.replace(DOUBLE_SLASH_RE2, "/");
15267
15814
  if (prepend)
15268
- path29 = "/" + path29;
15269
- return path29;
15815
+ path31 = "/" + path31;
15816
+ return path31;
15270
15817
  }
15271
15818
  function matchPatterns(patterns, testString, stats) {
15272
- const path29 = normalizePath(testString);
15819
+ const path31 = normalizePath(testString);
15273
15820
  for (let index = 0; index < patterns.length; index++) {
15274
15821
  const pattern = patterns[index];
15275
- if (pattern(path29, stats)) {
15822
+ if (pattern(path31, stats)) {
15276
15823
  return true;
15277
15824
  }
15278
15825
  }
@@ -15312,19 +15859,19 @@ var toUnix = (string) => {
15312
15859
  }
15313
15860
  return str;
15314
15861
  };
15315
- var normalizePathToUnix = (path29) => toUnix(sysPath2.normalize(toUnix(path29)));
15316
- var normalizeIgnored = (cwd = "") => (path29) => {
15317
- if (typeof path29 === "string") {
15318
- return normalizePathToUnix(sysPath2.isAbsolute(path29) ? path29 : sysPath2.join(cwd, path29));
15862
+ var normalizePathToUnix = (path31) => toUnix(sysPath2.normalize(toUnix(path31)));
15863
+ var normalizeIgnored = (cwd = "") => (path31) => {
15864
+ if (typeof path31 === "string") {
15865
+ return normalizePathToUnix(sysPath2.isAbsolute(path31) ? path31 : sysPath2.join(cwd, path31));
15319
15866
  } else {
15320
- return path29;
15867
+ return path31;
15321
15868
  }
15322
15869
  };
15323
- var getAbsolutePath = (path29, cwd) => {
15324
- if (sysPath2.isAbsolute(path29)) {
15325
- return path29;
15870
+ var getAbsolutePath = (path31, cwd) => {
15871
+ if (sysPath2.isAbsolute(path31)) {
15872
+ return path31;
15326
15873
  }
15327
- return sysPath2.join(cwd, path29);
15874
+ return sysPath2.join(cwd, path31);
15328
15875
  };
15329
15876
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
15330
15877
  var DirEntry = class {
@@ -15379,10 +15926,10 @@ var DirEntry = class {
15379
15926
  var STAT_METHOD_F = "stat";
15380
15927
  var STAT_METHOD_L = "lstat";
15381
15928
  var WatchHelper = class {
15382
- constructor(path29, follow, fsw) {
15929
+ constructor(path31, follow, fsw) {
15383
15930
  this.fsw = fsw;
15384
- const watchPath = path29;
15385
- this.path = path29 = path29.replace(REPLACER_RE, "");
15931
+ const watchPath = path31;
15932
+ this.path = path31 = path31.replace(REPLACER_RE, "");
15386
15933
  this.watchPath = watchPath;
15387
15934
  this.fullWatchPath = sysPath2.resolve(watchPath);
15388
15935
  this.dirParts = [];
@@ -15504,20 +16051,20 @@ var FSWatcher = class extends EventEmitter {
15504
16051
  this._closePromise = void 0;
15505
16052
  let paths = unifyPaths(paths_);
15506
16053
  if (cwd) {
15507
- paths = paths.map((path29) => {
15508
- const absPath = getAbsolutePath(path29, cwd);
16054
+ paths = paths.map((path31) => {
16055
+ const absPath = getAbsolutePath(path31, cwd);
15509
16056
  return absPath;
15510
16057
  });
15511
16058
  }
15512
- paths.forEach((path29) => {
15513
- this._removeIgnoredPath(path29);
16059
+ paths.forEach((path31) => {
16060
+ this._removeIgnoredPath(path31);
15514
16061
  });
15515
16062
  this._userIgnored = void 0;
15516
16063
  if (!this._readyCount)
15517
16064
  this._readyCount = 0;
15518
16065
  this._readyCount += paths.length;
15519
- Promise.all(paths.map(async (path29) => {
15520
- const res = await this._nodeFsHandler._addToNodeFs(path29, !_internal, void 0, 0, _origAdd);
16066
+ Promise.all(paths.map(async (path31) => {
16067
+ const res = await this._nodeFsHandler._addToNodeFs(path31, !_internal, void 0, 0, _origAdd);
15521
16068
  if (res)
15522
16069
  this._emitReady();
15523
16070
  return res;
@@ -15539,17 +16086,17 @@ var FSWatcher = class extends EventEmitter {
15539
16086
  return this;
15540
16087
  const paths = unifyPaths(paths_);
15541
16088
  const { cwd } = this.options;
15542
- paths.forEach((path29) => {
15543
- if (!sysPath2.isAbsolute(path29) && !this._closers.has(path29)) {
16089
+ paths.forEach((path31) => {
16090
+ if (!sysPath2.isAbsolute(path31) && !this._closers.has(path31)) {
15544
16091
  if (cwd)
15545
- path29 = sysPath2.join(cwd, path29);
15546
- path29 = sysPath2.resolve(path29);
16092
+ path31 = sysPath2.join(cwd, path31);
16093
+ path31 = sysPath2.resolve(path31);
15547
16094
  }
15548
- this._closePath(path29);
15549
- this._addIgnoredPath(path29);
15550
- if (this._watched.has(path29)) {
16095
+ this._closePath(path31);
16096
+ this._addIgnoredPath(path31);
16097
+ if (this._watched.has(path31)) {
15551
16098
  this._addIgnoredPath({
15552
- path: path29,
16099
+ path: path31,
15553
16100
  recursive: true
15554
16101
  });
15555
16102
  }
@@ -15613,38 +16160,38 @@ var FSWatcher = class extends EventEmitter {
15613
16160
  * @param stats arguments to be passed with event
15614
16161
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
15615
16162
  */
15616
- async _emit(event, path29, stats) {
16163
+ async _emit(event, path31, stats) {
15617
16164
  if (this.closed)
15618
16165
  return;
15619
16166
  const opts = this.options;
15620
16167
  if (isWindows)
15621
- path29 = sysPath2.normalize(path29);
16168
+ path31 = sysPath2.normalize(path31);
15622
16169
  if (opts.cwd)
15623
- path29 = sysPath2.relative(opts.cwd, path29);
15624
- const args = [path29];
16170
+ path31 = sysPath2.relative(opts.cwd, path31);
16171
+ const args = [path31];
15625
16172
  if (stats != null)
15626
16173
  args.push(stats);
15627
16174
  const awf = opts.awaitWriteFinish;
15628
16175
  let pw;
15629
- if (awf && (pw = this._pendingWrites.get(path29))) {
16176
+ if (awf && (pw = this._pendingWrites.get(path31))) {
15630
16177
  pw.lastChange = /* @__PURE__ */ new Date();
15631
16178
  return this;
15632
16179
  }
15633
16180
  if (opts.atomic) {
15634
16181
  if (event === EVENTS.UNLINK) {
15635
- this._pendingUnlinks.set(path29, [event, ...args]);
16182
+ this._pendingUnlinks.set(path31, [event, ...args]);
15636
16183
  setTimeout(() => {
15637
- this._pendingUnlinks.forEach((entry, path30) => {
16184
+ this._pendingUnlinks.forEach((entry, path32) => {
15638
16185
  this.emit(...entry);
15639
16186
  this.emit(EVENTS.ALL, ...entry);
15640
- this._pendingUnlinks.delete(path30);
16187
+ this._pendingUnlinks.delete(path32);
15641
16188
  });
15642
16189
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
15643
16190
  return this;
15644
16191
  }
15645
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path29)) {
16192
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path31)) {
15646
16193
  event = EVENTS.CHANGE;
15647
- this._pendingUnlinks.delete(path29);
16194
+ this._pendingUnlinks.delete(path31);
15648
16195
  }
15649
16196
  }
15650
16197
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -15662,16 +16209,16 @@ var FSWatcher = class extends EventEmitter {
15662
16209
  this.emitWithAll(event, args);
15663
16210
  }
15664
16211
  };
15665
- this._awaitWriteFinish(path29, awf.stabilityThreshold, event, awfEmit);
16212
+ this._awaitWriteFinish(path31, awf.stabilityThreshold, event, awfEmit);
15666
16213
  return this;
15667
16214
  }
15668
16215
  if (event === EVENTS.CHANGE) {
15669
- const isThrottled = !this._throttle(EVENTS.CHANGE, path29, 50);
16216
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path31, 50);
15670
16217
  if (isThrottled)
15671
16218
  return this;
15672
16219
  }
15673
16220
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
15674
- const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path29) : path29;
16221
+ const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path31) : path31;
15675
16222
  let stats2;
15676
16223
  try {
15677
16224
  stats2 = await stat3(fullPath);
@@ -15702,23 +16249,23 @@ var FSWatcher = class extends EventEmitter {
15702
16249
  * @param timeout duration of time to suppress duplicate actions
15703
16250
  * @returns tracking object or false if action should be suppressed
15704
16251
  */
15705
- _throttle(actionType, path29, timeout) {
16252
+ _throttle(actionType, path31, timeout) {
15706
16253
  if (!this._throttled.has(actionType)) {
15707
16254
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
15708
16255
  }
15709
16256
  const action = this._throttled.get(actionType);
15710
16257
  if (!action)
15711
16258
  throw new Error("invalid throttle");
15712
- const actionPath = action.get(path29);
16259
+ const actionPath = action.get(path31);
15713
16260
  if (actionPath) {
15714
16261
  actionPath.count++;
15715
16262
  return false;
15716
16263
  }
15717
16264
  let timeoutObject;
15718
16265
  const clear = () => {
15719
- const item = action.get(path29);
16266
+ const item = action.get(path31);
15720
16267
  const count = item ? item.count : 0;
15721
- action.delete(path29);
16268
+ action.delete(path31);
15722
16269
  clearTimeout(timeoutObject);
15723
16270
  if (item)
15724
16271
  clearTimeout(item.timeoutObject);
@@ -15726,7 +16273,7 @@ var FSWatcher = class extends EventEmitter {
15726
16273
  };
15727
16274
  timeoutObject = setTimeout(clear, timeout);
15728
16275
  const thr = { timeoutObject, clear, count: 0 };
15729
- action.set(path29, thr);
16276
+ action.set(path31, thr);
15730
16277
  return thr;
15731
16278
  }
15732
16279
  _incrReadyCount() {
@@ -15740,44 +16287,44 @@ var FSWatcher = class extends EventEmitter {
15740
16287
  * @param event
15741
16288
  * @param awfEmit Callback to be called when ready for event to be emitted.
15742
16289
  */
15743
- _awaitWriteFinish(path29, threshold, event, awfEmit) {
16290
+ _awaitWriteFinish(path31, threshold, event, awfEmit) {
15744
16291
  const awf = this.options.awaitWriteFinish;
15745
16292
  if (typeof awf !== "object")
15746
16293
  return;
15747
16294
  const pollInterval = awf.pollInterval;
15748
16295
  let timeoutHandler;
15749
- let fullPath = path29;
15750
- if (this.options.cwd && !sysPath2.isAbsolute(path29)) {
15751
- fullPath = sysPath2.join(this.options.cwd, path29);
16296
+ let fullPath = path31;
16297
+ if (this.options.cwd && !sysPath2.isAbsolute(path31)) {
16298
+ fullPath = sysPath2.join(this.options.cwd, path31);
15752
16299
  }
15753
16300
  const now = /* @__PURE__ */ new Date();
15754
16301
  const writes = this._pendingWrites;
15755
16302
  function awaitWriteFinishFn(prevStat) {
15756
16303
  statcb(fullPath, (err, curStat) => {
15757
- if (err || !writes.has(path29)) {
16304
+ if (err || !writes.has(path31)) {
15758
16305
  if (err && err.code !== "ENOENT")
15759
16306
  awfEmit(err);
15760
16307
  return;
15761
16308
  }
15762
16309
  const now2 = Number(/* @__PURE__ */ new Date());
15763
16310
  if (prevStat && curStat.size !== prevStat.size) {
15764
- writes.get(path29).lastChange = now2;
16311
+ writes.get(path31).lastChange = now2;
15765
16312
  }
15766
- const pw = writes.get(path29);
16313
+ const pw = writes.get(path31);
15767
16314
  const df = now2 - pw.lastChange;
15768
16315
  if (df >= threshold) {
15769
- writes.delete(path29);
16316
+ writes.delete(path31);
15770
16317
  awfEmit(void 0, curStat);
15771
16318
  } else {
15772
16319
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
15773
16320
  }
15774
16321
  });
15775
16322
  }
15776
- if (!writes.has(path29)) {
15777
- writes.set(path29, {
16323
+ if (!writes.has(path31)) {
16324
+ writes.set(path31, {
15778
16325
  lastChange: now,
15779
16326
  cancelWait: () => {
15780
- writes.delete(path29);
16327
+ writes.delete(path31);
15781
16328
  clearTimeout(timeoutHandler);
15782
16329
  return event;
15783
16330
  }
@@ -15788,8 +16335,8 @@ var FSWatcher = class extends EventEmitter {
15788
16335
  /**
15789
16336
  * Determines whether user has asked to ignore this path.
15790
16337
  */
15791
- _isIgnored(path29, stats) {
15792
- if (this.options.atomic && DOT_RE.test(path29))
16338
+ _isIgnored(path31, stats) {
16339
+ if (this.options.atomic && DOT_RE.test(path31))
15793
16340
  return true;
15794
16341
  if (!this._userIgnored) {
15795
16342
  const { cwd } = this.options;
@@ -15799,17 +16346,17 @@ var FSWatcher = class extends EventEmitter {
15799
16346
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
15800
16347
  this._userIgnored = anymatch(list, void 0);
15801
16348
  }
15802
- return this._userIgnored(path29, stats);
16349
+ return this._userIgnored(path31, stats);
15803
16350
  }
15804
- _isntIgnored(path29, stat4) {
15805
- return !this._isIgnored(path29, stat4);
16351
+ _isntIgnored(path31, stat4) {
16352
+ return !this._isIgnored(path31, stat4);
15806
16353
  }
15807
16354
  /**
15808
16355
  * Provides a set of common helpers and properties relating to symlink handling.
15809
16356
  * @param path file or directory pattern being watched
15810
16357
  */
15811
- _getWatchHelpers(path29) {
15812
- return new WatchHelper(path29, this.options.followSymlinks, this);
16358
+ _getWatchHelpers(path31) {
16359
+ return new WatchHelper(path31, this.options.followSymlinks, this);
15813
16360
  }
15814
16361
  // Directory helpers
15815
16362
  // -----------------
@@ -15841,63 +16388,63 @@ var FSWatcher = class extends EventEmitter {
15841
16388
  * @param item base path of item/directory
15842
16389
  */
15843
16390
  _remove(directory, item, isDirectory) {
15844
- const path29 = sysPath2.join(directory, item);
15845
- const fullPath = sysPath2.resolve(path29);
15846
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path29) || this._watched.has(fullPath);
15847
- if (!this._throttle("remove", path29, 100))
16391
+ const path31 = sysPath2.join(directory, item);
16392
+ const fullPath = sysPath2.resolve(path31);
16393
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path31) || this._watched.has(fullPath);
16394
+ if (!this._throttle("remove", path31, 100))
15848
16395
  return;
15849
16396
  if (!isDirectory && this._watched.size === 1) {
15850
16397
  this.add(directory, item, true);
15851
16398
  }
15852
- const wp = this._getWatchedDir(path29);
16399
+ const wp = this._getWatchedDir(path31);
15853
16400
  const nestedDirectoryChildren = wp.getChildren();
15854
- nestedDirectoryChildren.forEach((nested) => this._remove(path29, nested));
16401
+ nestedDirectoryChildren.forEach((nested) => this._remove(path31, nested));
15855
16402
  const parent = this._getWatchedDir(directory);
15856
16403
  const wasTracked = parent.has(item);
15857
16404
  parent.remove(item);
15858
16405
  if (this._symlinkPaths.has(fullPath)) {
15859
16406
  this._symlinkPaths.delete(fullPath);
15860
16407
  }
15861
- let relPath = path29;
16408
+ let relPath = path31;
15862
16409
  if (this.options.cwd)
15863
- relPath = sysPath2.relative(this.options.cwd, path29);
16410
+ relPath = sysPath2.relative(this.options.cwd, path31);
15864
16411
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
15865
16412
  const event = this._pendingWrites.get(relPath).cancelWait();
15866
16413
  if (event === EVENTS.ADD)
15867
16414
  return;
15868
16415
  }
15869
- this._watched.delete(path29);
16416
+ this._watched.delete(path31);
15870
16417
  this._watched.delete(fullPath);
15871
16418
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
15872
- if (wasTracked && !this._isIgnored(path29))
15873
- this._emit(eventName, path29);
15874
- this._closePath(path29);
16419
+ if (wasTracked && !this._isIgnored(path31))
16420
+ this._emit(eventName, path31);
16421
+ this._closePath(path31);
15875
16422
  }
15876
16423
  /**
15877
16424
  * Closes all watchers for a path
15878
16425
  */
15879
- _closePath(path29) {
15880
- this._closeFile(path29);
15881
- const dir = sysPath2.dirname(path29);
15882
- this._getWatchedDir(dir).remove(sysPath2.basename(path29));
16426
+ _closePath(path31) {
16427
+ this._closeFile(path31);
16428
+ const dir = sysPath2.dirname(path31);
16429
+ this._getWatchedDir(dir).remove(sysPath2.basename(path31));
15883
16430
  }
15884
16431
  /**
15885
16432
  * Closes only file-specific watchers
15886
16433
  */
15887
- _closeFile(path29) {
15888
- const closers = this._closers.get(path29);
16434
+ _closeFile(path31) {
16435
+ const closers = this._closers.get(path31);
15889
16436
  if (!closers)
15890
16437
  return;
15891
16438
  closers.forEach((closer) => closer());
15892
- this._closers.delete(path29);
16439
+ this._closers.delete(path31);
15893
16440
  }
15894
- _addPathCloser(path29, closer) {
16441
+ _addPathCloser(path31, closer) {
15895
16442
  if (!closer)
15896
16443
  return;
15897
- let list = this._closers.get(path29);
16444
+ let list = this._closers.get(path31);
15898
16445
  if (!list) {
15899
16446
  list = [];
15900
- this._closers.set(path29, list);
16447
+ this._closers.set(path31, list);
15901
16448
  }
15902
16449
  list.push(closer);
15903
16450
  }
@@ -15928,7 +16475,7 @@ var esm_default = { watch, FSWatcher };
15928
16475
 
15929
16476
  // modules/dev/hot-reload-client/index.ts
15930
16477
  init_globals();
15931
- import path23 from "path";
16478
+ import path25 from "path";
15932
16479
  function setupHotReload({
15933
16480
  app,
15934
16481
  appDir,
@@ -15969,7 +16516,7 @@ function setupHotReload({
15969
16516
  });
15970
16517
  });
15971
16518
  console.log(`[hot-reload-server] \u2705 SSE endpoint registered at ${route}`);
15972
- const resolvedProjectRoot = projectRoot ? path23.resolve(projectRoot) : path23.dirname(path23.resolve(appDir));
16519
+ const resolvedProjectRoot = projectRoot ? path25.resolve(projectRoot) : path25.dirname(path25.resolve(appDir));
15973
16520
  const watcher = esm_default.watch(resolvedProjectRoot, {
15974
16521
  ignoreInitial: true,
15975
16522
  ignored: [
@@ -16009,11 +16556,11 @@ function setupHotReload({
16009
16556
  let broadcastTimeout = null;
16010
16557
  const BROADCAST_DEBOUNCE_MS = 300;
16011
16558
  async function broadcastReload(reason, filePath) {
16012
- const normalizedPath = path23.normalize(filePath);
16559
+ const normalizedPath = path25.normalize(filePath);
16013
16560
  if (normalizedPath.includes(BUILD_FOLDER_NAME) || normalizedPath.includes(".loly") || normalizedPath.endsWith(".map") || normalizedPath.endsWith(".log") || normalizedPath.includes("route-chunks.json") || normalizedPath.includes("routes-client.ts") || normalizedPath.includes("/client/route-")) {
16014
16561
  return;
16015
16562
  }
16016
- const rel = path23.relative(appDir, filePath);
16563
+ const rel = path25.relative(appDir, filePath);
16017
16564
  console.log(`[hot-reload] ${reason}: ${rel}`);
16018
16565
  if (broadcastTimeout) {
16019
16566
  clearTimeout(broadcastTimeout);
@@ -16063,9 +16610,9 @@ data: reload:${rel}
16063
16610
  }
16064
16611
 
16065
16612
  // modules/dev/hot-reload-server/index.ts
16066
- import path24 from "path";
16613
+ import path26 from "path";
16067
16614
  function clearAppRequireCache(appDir) {
16068
- const appDirNormalized = path24.resolve(appDir);
16615
+ const appDirNormalized = path26.resolve(appDir);
16069
16616
  for (const id of Object.keys(__require.cache)) {
16070
16617
  if (id.startsWith(appDirNormalized)) {
16071
16618
  delete __require.cache[id];
@@ -16078,7 +16625,7 @@ init_globals();
16078
16625
  function setupStaticFiles(app, projectRoot, config) {
16079
16626
  if (!config) return;
16080
16627
  const staticDir = getStaticDir(projectRoot, config);
16081
- if (fs18.existsSync(staticDir)) {
16628
+ if (fs20.existsSync(staticDir)) {
16082
16629
  app.use(
16083
16630
  express.static(staticDir, {
16084
16631
  // In production, add caching headers for better performance
@@ -16104,7 +16651,7 @@ function setupServer(app, options) {
16104
16651
  var getRoutes = getRoutes2;
16105
16652
  const { outDir, waitForBuild } = startClientBundler(projectRoot, "development");
16106
16653
  const onFileChange = async (filePath) => {
16107
- const rel = path25.relative(appDir, filePath);
16654
+ const rel = path27.relative(appDir, filePath);
16108
16655
  const isPageFile = filePath.includes("page.tsx") || filePath.includes("page.ts") || filePath.includes("layout.tsx") || filePath.includes("layout.ts") || filePath.includes("_not-found") || filePath.includes("_error");
16109
16656
  const isTsFile = filePath.endsWith(".ts") || filePath.endsWith(".tsx");
16110
16657
  if (isTsFile) {
@@ -16140,8 +16687,8 @@ function setupServer(app, options) {
16140
16687
  const wssRoutes = routeLoader.loadWssRoutes();
16141
16688
  const notFoundPage = routeLoader.loadNotFoundRoute();
16142
16689
  const errorPage = routeLoader.loadErrorRoute();
16143
- const buildDir = config ? getBuildDir(projectRoot, config) : path25.join(projectRoot, BUILD_FOLDER_NAME);
16144
- const clientOutDir = path25.join(buildDir, "client");
16690
+ const buildDir = config ? getBuildDir(projectRoot, config) : path27.join(projectRoot, BUILD_FOLDER_NAME);
16691
+ const clientOutDir = path27.join(buildDir, "client");
16145
16692
  app.use(
16146
16693
  "/static",
16147
16694
  express.static(clientOutDir, {
@@ -16268,11 +16815,11 @@ function createStrictRateLimiterFromConfig(config) {
16268
16815
  }
16269
16816
 
16270
16817
  // modules/server/middleware/auto-rate-limit.ts
16271
- function matchesStrictPattern(path29, patterns) {
16818
+ function matchesStrictPattern(path31, patterns) {
16272
16819
  for (const pattern of patterns) {
16273
16820
  const regexPattern = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\//g, "\\/");
16274
16821
  const regex = new RegExp(`^${regexPattern}$`);
16275
- if (regex.test(path29)) {
16822
+ if (regex.test(path31)) {
16276
16823
  return true;
16277
16824
  }
16278
16825
  }
@@ -16307,8 +16854,31 @@ function getAutoRateLimiter(route, strictPatterns = [], rateLimitConfig) {
16307
16854
 
16308
16855
  // modules/server/handlers/api.ts
16309
16856
  async function handleApiRequest(options) {
16310
- const { apiRoutes, urlPath, req, res, env = "dev" } = options;
16311
- const matched = matchApiRoute(apiRoutes, urlPath);
16857
+ const { apiRoutes, urlPath, req, res, env = "dev", rewriteLoader } = options;
16858
+ let finalUrlPath = urlPath;
16859
+ let extractedParams = {};
16860
+ if (rewriteLoader) {
16861
+ try {
16862
+ const compiledRewrites = await rewriteLoader.loadRewrites();
16863
+ const rewriteResult = await processRewrites(urlPath, compiledRewrites, req);
16864
+ if (rewriteResult) {
16865
+ finalUrlPath = rewriteResult.rewrittenPath;
16866
+ extractedParams = rewriteResult.extractedParams;
16867
+ Object.assign(req.query, extractedParams);
16868
+ if (!req.locals) {
16869
+ req.locals = {};
16870
+ }
16871
+ Object.assign(req.locals, extractedParams);
16872
+ }
16873
+ } catch (error) {
16874
+ const reqLogger = getRequestLogger(req);
16875
+ reqLogger.error("Error processing rewrites", error, {
16876
+ urlPath
16877
+ });
16878
+ }
16879
+ }
16880
+ finalUrlPath = finalUrlPath.replace(/\/$/, "") || "/";
16881
+ const matched = matchApiRoute(apiRoutes, finalUrlPath);
16312
16882
  if (!matched) {
16313
16883
  res.status(404).json({ error: "Not Found" });
16314
16884
  return;
@@ -16329,9 +16899,13 @@ async function handleApiRequest(options) {
16329
16899
  Response: (body = {}, status = 200) => res.status(status).json(body),
16330
16900
  NotFound: (body = {}) => res.status(404).json(body),
16331
16901
  params: sanitizedParams,
16332
- pathname: urlPath,
16902
+ pathname: finalUrlPath,
16903
+ // Use rewritten path
16333
16904
  locals: {}
16334
16905
  };
16906
+ if (extractedParams && Object.keys(extractedParams).length > 0) {
16907
+ Object.assign(ctx.locals, extractedParams);
16908
+ }
16335
16909
  req.query = sanitizedQuery;
16336
16910
  try {
16337
16911
  const autoRateLimiter = getAutoRateLimiter(
@@ -16410,7 +16984,19 @@ async function handleApiRequest(options) {
16410
16984
 
16411
16985
  // modules/server/routes.ts
16412
16986
  init_globals();
16413
- import path26 from "path";
16987
+ import path28 from "path";
16988
+ var cachedRewriteLoader = null;
16989
+ var cachedProjectRoot = null;
16990
+ var cachedIsDev = null;
16991
+ function getRewriteLoader(projectRoot, isDev) {
16992
+ if (cachedRewriteLoader && cachedProjectRoot === projectRoot && cachedIsDev === isDev) {
16993
+ return cachedRewriteLoader;
16994
+ }
16995
+ cachedRewriteLoader = createRewriteLoader(projectRoot, isDev);
16996
+ cachedProjectRoot = projectRoot;
16997
+ cachedIsDev = isDev;
16998
+ return cachedRewriteLoader;
16999
+ }
16414
17000
  function setupRoutes(options) {
16415
17001
  const {
16416
17002
  app,
@@ -16425,8 +17011,9 @@ function setupRoutes(options) {
16425
17011
  config
16426
17012
  } = options;
16427
17013
  const routeChunks = routeLoader.loadRouteChunks();
16428
- const ssgOutDir = path26.join(
16429
- config ? getBuildDir(projectRoot, config) : path26.join(projectRoot, BUILD_FOLDER_NAME),
17014
+ const rewriteLoader = getRewriteLoader(projectRoot, isDev);
17015
+ const ssgOutDir = path28.join(
17016
+ config ? getBuildDir(projectRoot, config) : path28.join(projectRoot, BUILD_FOLDER_NAME),
16430
17017
  "ssg"
16431
17018
  );
16432
17019
  app.all("/api/*", async (req, res) => {
@@ -16441,7 +17028,8 @@ function setupRoutes(options) {
16441
17028
  res,
16442
17029
  env: isDev ? "dev" : "prod",
16443
17030
  strictRateLimitPatterns: strictPatterns,
16444
- rateLimitConfig
17031
+ rateLimitConfig,
17032
+ rewriteLoader
16445
17033
  });
16446
17034
  });
16447
17035
  app.get("*", async (req, res) => {
@@ -16464,7 +17052,8 @@ function setupRoutes(options) {
16464
17052
  ssgOutDir,
16465
17053
  theme: req.cookies?.theme || "light",
16466
17054
  projectRoot,
16467
- config
17055
+ config,
17056
+ rewriteLoader
16468
17057
  });
16469
17058
  });
16470
17059
  }
@@ -17653,8 +18242,8 @@ var setupApplication = async ({
17653
18242
 
17654
18243
  // src/server.ts
17655
18244
  import dotenv2 from "dotenv";
17656
- var envPath = path27.join(process.cwd(), ".env");
17657
- if (fs19.existsSync(envPath)) {
18245
+ var envPath = path29.join(process.cwd(), ".env");
18246
+ if (fs21.existsSync(envPath)) {
17658
18247
  dotenv2.config({ path: envPath });
17659
18248
  } else {
17660
18249
  dotenv2.config();
@@ -17675,8 +18264,8 @@ async function startServer(options = {}) {
17675
18264
  }
17676
18265
  const port = options.port ?? (process.env.PORT ? parseInt(process.env.PORT, 10) : void 0) ?? config.server.port;
17677
18266
  const host = process.env.HOST ?? (!isDev ? "0.0.0.0" : void 0) ?? config.server.host;
17678
- const appDir = options.appDir ?? (isDev ? getAppDir(projectRoot, config) : path27.join(getBuildDir(projectRoot, config), "server"));
17679
- if (!isDev && !fs19.existsSync(appDir)) {
18267
+ const appDir = options.appDir ?? (isDev ? getAppDir(projectRoot, config) : path29.join(getBuildDir(projectRoot, config), "server"));
18268
+ if (!isDev && !fs21.existsSync(appDir)) {
17680
18269
  logger4.error("Compiled directory not found", void 0, {
17681
18270
  buildDir: config.directories.build,
17682
18271
  appDir,
@@ -17872,7 +18461,7 @@ async function run() {
17872
18461
  }
17873
18462
  const args = parseArgs(argv.slice(1));
17874
18463
  const projectRoot = process2.cwd();
17875
- const appDir = path28.resolve(projectRoot, args.appDir || "app");
18464
+ const appDir = path30.resolve(projectRoot, args.appDir || "app");
17876
18465
  const port = typeof args.port === "string" && args.port.trim().length > 0 ? Number(args.port) : 3e3;
17877
18466
  switch (command) {
17878
18467
  case "dev": {