@lolyjs/core 0.2.0-alpha.26 → 0.2.0-alpha.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -9871,8 +9871,8 @@ var require_built3 = __commonJS({
9871
9871
  });
9872
9872
 
9873
9873
  // src/server.ts
9874
- import fs17 from "fs";
9875
- import path23 from "path";
9874
+ import fs19 from "fs";
9875
+ import path25 from "path";
9876
9876
 
9877
9877
  // modules/server/utils/server-dir.ts
9878
9878
  init_globals();
@@ -9912,8 +9912,8 @@ async function runInitIfExists(projectRoot, serverData) {
9912
9912
 
9913
9913
  // modules/server/setup.ts
9914
9914
  import express from "express";
9915
- import path17 from "path";
9916
- import fs15 from "fs";
9915
+ import path19 from "path";
9916
+ import fs17 from "fs";
9917
9917
 
9918
9918
  // modules/router/loader-pages.ts
9919
9919
  import fs4 from "fs";
@@ -9924,10 +9924,17 @@ var PAGE_FILE_REGEX = /^page\.(tsx|ts|jsx|js)$/;
9924
9924
  var LAYOUT_FILE_BASENAME = "layout";
9925
9925
 
9926
9926
  // modules/router/path.ts
9927
+ function isRouteGroup(dirName) {
9928
+ return dirName.startsWith("(") && dirName.endsWith(")");
9929
+ }
9927
9930
  function buildRoutePathFromDir(relDir) {
9928
9931
  if (!relDir || relDir === ".") return "/";
9929
9932
  const clean = relDir.replace(/\\/g, "/");
9930
- return "/" + clean;
9933
+ const segments = clean.split("/").filter((seg) => {
9934
+ return !isRouteGroup(seg);
9935
+ });
9936
+ if (segments.length === 0) return "/";
9937
+ return "/" + segments.join("/");
9931
9938
  }
9932
9939
  function buildRegexFromRoutePath(routePath) {
9933
9940
  const segments = routePath.split("/").filter(Boolean);
@@ -10143,13 +10150,17 @@ function validateRoutes(routes, appDir) {
10143
10150
  }
10144
10151
  for (const [pattern, duplicateRoutes] of routePatterns.entries()) {
10145
10152
  if (duplicateRoutes.length > 1) {
10146
- const files = duplicateRoutes.map(
10147
- (r) => r.pageFile ? path4.relative(appDir, r.pageFile) : "unknown"
10148
- ).join(", ");
10153
+ const files = duplicateRoutes.map((r) => {
10154
+ const relPath = r.pageFile ? path4.relative(appDir, r.pageFile) : "unknown";
10155
+ const segments = relPath.split(path4.sep);
10156
+ const hasRouteGroup = segments.some((seg) => isRouteGroup(seg));
10157
+ return hasRouteGroup ? `${relPath} (inside route group)` : relPath;
10158
+ }).join(", ");
10149
10159
  errors.push(
10150
10160
  `Duplicate route pattern "${pattern}" found in multiple files:
10151
10161
  ${files}
10152
- \u{1F4A1} Suggestion: Ensure each route has a unique path pattern`
10162
+ \u{1F4A1} Suggestion: Route groups (directories in parentheses) don't appear in URLs.
10163
+ Ensure each route has a unique path pattern after route groups are ignored.`
10153
10164
  );
10154
10165
  }
10155
10166
  }
@@ -10426,12 +10437,13 @@ function loadApiRoutes(appDir) {
10426
10437
 
10427
10438
  // modules/router/matcher.ts
10428
10439
  function matchRoute(routes, urlPath) {
10440
+ const normalizedPath = urlPath.replace(/\/$/, "") || "/";
10429
10441
  for (const route of routes) {
10430
- const match = route.regex.exec(urlPath);
10442
+ const match = route.regex.exec(normalizedPath);
10431
10443
  if (!match) continue;
10432
10444
  const params = {};
10433
10445
  route.paramNames.forEach((name, idx) => {
10434
- params[name] = match[idx + 1];
10446
+ params[name] = decodeURIComponent(match[idx + 1] || "");
10435
10447
  });
10436
10448
  return { route, params };
10437
10449
  }
@@ -11441,34 +11453,504 @@ function loadErrorRouteFromFilesystem(appDir) {
11441
11453
  };
11442
11454
  }
11443
11455
 
11456
+ // modules/router/rewrites.ts
11457
+ function parseRewritePattern(pattern) {
11458
+ const cleanPattern = pattern.replace(/^\/+|\/+$/g, "") || "";
11459
+ if (!cleanPattern) {
11460
+ return {
11461
+ regex: /^\/?$/,
11462
+ paramNames: []
11463
+ };
11464
+ }
11465
+ const segments = cleanPattern.split("/").filter(Boolean);
11466
+ const paramNames = [];
11467
+ const regexParts = [];
11468
+ for (let i = 0; i < segments.length; i++) {
11469
+ const seg = segments[i];
11470
+ if (seg === "*") {
11471
+ if (i !== segments.length - 1) {
11472
+ throw new Error(
11473
+ `Catch-all "*" in "${pattern}" must be the last segment.`
11474
+ );
11475
+ }
11476
+ regexParts.push("(.+)");
11477
+ continue;
11478
+ }
11479
+ if (seg.endsWith("*") && seg.startsWith(":")) {
11480
+ const paramName = seg.slice(1, -1);
11481
+ if (i !== segments.length - 1) {
11482
+ throw new Error(
11483
+ `Catch-all segment "${seg}" in "${pattern}" must be the last segment.`
11484
+ );
11485
+ }
11486
+ paramNames.push(paramName);
11487
+ regexParts.push("(.+)");
11488
+ continue;
11489
+ }
11490
+ if (seg.startsWith(":") && seg.length > 1) {
11491
+ const paramName = seg.slice(1);
11492
+ paramNames.push(paramName);
11493
+ regexParts.push("([^/]+)");
11494
+ continue;
11495
+ }
11496
+ const escaped = seg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
11497
+ regexParts.push(escaped);
11498
+ }
11499
+ const regexSource = "^/?" + regexParts.join("/") + "/?$";
11500
+ const regex = new RegExp(regexSource);
11501
+ return { regex, paramNames };
11502
+ }
11503
+ function extractHostParams(hostPattern, actualHost) {
11504
+ const regexPattern = hostPattern.replace(/:([^.]+)/g, "([^.]+)").replace(/\./g, "\\.").replace(/\*/g, ".*");
11505
+ const regex = new RegExp(`^${regexPattern}$`);
11506
+ const match = regex.exec(actualHost);
11507
+ if (!match) return null;
11508
+ const paramNames = [];
11509
+ const paramPattern = /:([^.]+)/g;
11510
+ let paramMatch;
11511
+ while ((paramMatch = paramPattern.exec(hostPattern)) !== null) {
11512
+ paramNames.push(paramMatch[1]);
11513
+ }
11514
+ const params = {};
11515
+ paramNames.forEach((name, idx) => {
11516
+ params[name] = match[idx + 1] || "";
11517
+ });
11518
+ return params;
11519
+ }
11520
+ function evaluateRewriteConditions(conditions, req) {
11521
+ const extractedParams = {};
11522
+ for (const condition of conditions) {
11523
+ switch (condition.type) {
11524
+ case "host": {
11525
+ const hostWithPort = req.get("host") || req.hostname || req.get("x-forwarded-host")?.split(",")[0] || "";
11526
+ const host = hostWithPort.split(":")[0];
11527
+ if (process.env.NODE_ENV === "development") {
11528
+ console.log("[rewrites] Host matching:", {
11529
+ pattern: condition.value,
11530
+ actualHost: host,
11531
+ hostWithPort,
11532
+ reqHost: req.get("host"),
11533
+ reqHostname: req.hostname
11534
+ });
11535
+ }
11536
+ const hostParams = extractHostParams(condition.value, host);
11537
+ if (!hostParams) {
11538
+ if (process.env.NODE_ENV === "development") {
11539
+ console.log("[rewrites] Host params extraction failed:", {
11540
+ pattern: condition.value,
11541
+ actualHost: host
11542
+ });
11543
+ }
11544
+ return { matches: false, params: {} };
11545
+ }
11546
+ Object.assign(extractedParams, hostParams);
11547
+ break;
11548
+ }
11549
+ case "header": {
11550
+ if (!condition.key) {
11551
+ return { matches: false, params: {} };
11552
+ }
11553
+ const headerValue = req.get(condition.key.toLowerCase());
11554
+ if (!headerValue || headerValue !== condition.value) {
11555
+ return { matches: false, params: {} };
11556
+ }
11557
+ break;
11558
+ }
11559
+ case "cookie": {
11560
+ if (!condition.key) {
11561
+ return { matches: false, params: {} };
11562
+ }
11563
+ const cookieValue = req.cookies?.[condition.key];
11564
+ if (!cookieValue || cookieValue !== condition.value) {
11565
+ return { matches: false, params: {} };
11566
+ }
11567
+ break;
11568
+ }
11569
+ case "query": {
11570
+ if (!condition.key) {
11571
+ return { matches: false, params: {} };
11572
+ }
11573
+ const queryValue = req.query[condition.key];
11574
+ if (!queryValue || String(queryValue) !== condition.value) {
11575
+ return { matches: false, params: {} };
11576
+ }
11577
+ break;
11578
+ }
11579
+ default:
11580
+ return { matches: false, params: {} };
11581
+ }
11582
+ }
11583
+ return { matches: true, params: extractedParams };
11584
+ }
11585
+ function replaceDestinationParams(destination, params) {
11586
+ let result = destination;
11587
+ for (const [key, value] of Object.entries(params)) {
11588
+ const pattern = new RegExp(`:${key}(?:\\*)?`, "g");
11589
+ result = result.replace(pattern, value);
11590
+ }
11591
+ return result;
11592
+ }
11593
+ async function processRewrites(urlPath, compiledRewrites, req) {
11594
+ const normalizedPath = urlPath.replace(/\/$/, "") || "/";
11595
+ if (normalizedPath.startsWith("/static/") || // Static assets (client.js, client.css, etc.)
11596
+ normalizedPath.startsWith("/__fw/") || // Framework internal routes (hot reload, etc.)
11597
+ normalizedPath === "/favicon.ico" || // Favicon
11598
+ normalizedPath.startsWith("/wss/")) {
11599
+ if (process.env.NODE_ENV === "development") {
11600
+ console.log("[rewrites] Skipping rewrite for system route:", normalizedPath);
11601
+ }
11602
+ return null;
11603
+ }
11604
+ if (process.env.NODE_ENV === "development") {
11605
+ console.log("[rewrites] Processing rewrites:", {
11606
+ urlPath,
11607
+ normalizedPath,
11608
+ host: req.get("host"),
11609
+ hostname: req.hostname,
11610
+ compiledRewritesCount: compiledRewrites.length
11611
+ });
11612
+ }
11613
+ for (const rewrite of compiledRewrites) {
11614
+ let conditionParams = {};
11615
+ if (rewrite.has && rewrite.has.length > 0) {
11616
+ const conditionResult = evaluateRewriteConditions(rewrite.has, req);
11617
+ if (!conditionResult.matches) {
11618
+ if (process.env.NODE_ENV === "development") {
11619
+ console.log("[rewrites] Condition not matched:", {
11620
+ source: rewrite.source,
11621
+ conditions: rewrite.has
11622
+ });
11623
+ }
11624
+ continue;
11625
+ }
11626
+ conditionParams = conditionResult.params;
11627
+ if (process.env.NODE_ENV === "development") {
11628
+ console.log("[rewrites] Condition matched:", {
11629
+ source: rewrite.source,
11630
+ conditionParams
11631
+ });
11632
+ }
11633
+ }
11634
+ const sourceMatch = rewrite.sourceRegex.exec(normalizedPath);
11635
+ if (!sourceMatch) {
11636
+ if (process.env.NODE_ENV === "development") {
11637
+ console.log("[rewrites] Source pattern not matched:", {
11638
+ source: rewrite.source,
11639
+ normalizedPath,
11640
+ sourceRegex: rewrite.sourceRegex.toString()
11641
+ });
11642
+ }
11643
+ continue;
11644
+ }
11645
+ if (process.env.NODE_ENV === "development") {
11646
+ console.log("[rewrites] Source pattern matched:", {
11647
+ source: rewrite.source,
11648
+ normalizedPath,
11649
+ match: sourceMatch[0]
11650
+ });
11651
+ }
11652
+ const sourceParams = {};
11653
+ rewrite.sourceParamNames.forEach((name, idx) => {
11654
+ sourceParams[name] = decodeURIComponent(sourceMatch[idx + 1] || "");
11655
+ });
11656
+ const allParams = { ...sourceParams, ...conditionParams };
11657
+ let destination;
11658
+ if (typeof rewrite.destination === "function") {
11659
+ destination = await rewrite.destination(allParams, req);
11660
+ } else {
11661
+ destination = replaceDestinationParams(rewrite.destination, allParams);
11662
+ }
11663
+ const normalizedDestination = destination.replace(/\/+/g, "/").replace(/^([^/])/, "/$1").replace(/\/$/, "") || "/";
11664
+ if (process.env.NODE_ENV === "development") {
11665
+ console.log("[rewrites] Rewrite successful:", {
11666
+ originalPath: urlPath,
11667
+ rewrittenPath: normalizedDestination,
11668
+ allParams
11669
+ });
11670
+ }
11671
+ return {
11672
+ rewrittenPath: normalizedDestination,
11673
+ extractedParams: allParams
11674
+ };
11675
+ }
11676
+ return null;
11677
+ }
11678
+ function validateRewrites(rules) {
11679
+ for (const rule of rules) {
11680
+ if (typeof rule.destination === "string") {
11681
+ if (rule.source === rule.destination) {
11682
+ console.warn(
11683
+ `[framework][rewrites] Rewrite rule has identical source and destination: "${rule.source}". This may cause issues.`
11684
+ );
11685
+ }
11686
+ }
11687
+ }
11688
+ const sources = /* @__PURE__ */ new Set();
11689
+ for (const rule of rules) {
11690
+ if (sources.has(rule.source)) {
11691
+ console.warn(
11692
+ `[framework][rewrites] Duplicate rewrite source pattern: "${rule.source}". Only the first match will be used.`
11693
+ );
11694
+ }
11695
+ sources.add(rule.source);
11696
+ }
11697
+ }
11698
+ function compileRewriteRules(rules) {
11699
+ validateRewrites(rules);
11700
+ return rules.map((rule) => {
11701
+ const { regex, paramNames } = parseRewritePattern(rule.source);
11702
+ let hostRegex;
11703
+ let hostParamNames;
11704
+ if (rule.has) {
11705
+ const hostCondition = rule.has.find((c) => c.type === "host");
11706
+ if (hostCondition) {
11707
+ const hostPattern = hostCondition.value;
11708
+ const hostRegexPattern = hostPattern.replace(/:([^.]+)/g, "([^.]+)").replace(/\./g, "\\.").replace(/\*/g, ".*");
11709
+ hostRegex = new RegExp(`^${hostRegexPattern}$`);
11710
+ hostParamNames = [];
11711
+ const paramPattern = /:([^.]+)/g;
11712
+ let paramMatch;
11713
+ while ((paramMatch = paramPattern.exec(hostPattern)) !== null) {
11714
+ hostParamNames.push(paramMatch[1]);
11715
+ }
11716
+ }
11717
+ }
11718
+ return {
11719
+ source: rule.source,
11720
+ sourceRegex: regex,
11721
+ sourceParamNames: paramNames,
11722
+ destination: rule.destination,
11723
+ has: rule.has,
11724
+ hostRegex,
11725
+ hostParamNames
11726
+ };
11727
+ });
11728
+ }
11729
+
11730
+ // modules/router/rewrites-loader.ts
11731
+ import fs11 from "fs";
11732
+ import path11 from "path";
11733
+ var FilesystemRewriteLoader = class {
11734
+ // Maximum cache age in ms (1 second fallback)
11735
+ constructor(projectRoot) {
11736
+ this.projectRoot = projectRoot;
11737
+ this.cache = null;
11738
+ this.cacheMaxAge = 1e3;
11739
+ }
11740
+ /**
11741
+ * Invalidates the cache, forcing a reload on next access.
11742
+ */
11743
+ invalidateCache() {
11744
+ this.cache = null;
11745
+ }
11746
+ /**
11747
+ * Finds the rewrites config file.
11748
+ * Looks for rewrites.config.ts, rewrites.config.js, or rewrites.config.json
11749
+ */
11750
+ findRewritesConfig() {
11751
+ const candidates = [
11752
+ path11.join(this.projectRoot, "rewrites.config.ts"),
11753
+ path11.join(this.projectRoot, "rewrites.config.js"),
11754
+ path11.join(this.projectRoot, "rewrites.config.json")
11755
+ ];
11756
+ for (const candidate of candidates) {
11757
+ if (fs11.existsSync(candidate)) {
11758
+ return candidate;
11759
+ }
11760
+ }
11761
+ return null;
11762
+ }
11763
+ /**
11764
+ * Checks if the rewrites config file has changed.
11765
+ */
11766
+ hasConfigChanged(configPath) {
11767
+ if (!this.cache || !this.cache.fileStats) {
11768
+ return true;
11769
+ }
11770
+ if (!fs11.existsSync(configPath)) {
11771
+ return this.cache.rewrites.length > 0;
11772
+ }
11773
+ const stats = fs11.statSync(configPath);
11774
+ const cachedStats = this.cache.fileStats;
11775
+ return stats.mtimeMs !== cachedStats.mtime || stats.size !== cachedStats.size;
11776
+ }
11777
+ /**
11778
+ * Loads rewrites from a config file.
11779
+ */
11780
+ async loadRewritesFromFile(configPath) {
11781
+ const ext = path11.extname(configPath);
11782
+ if (ext === ".json") {
11783
+ const content = fs11.readFileSync(configPath, "utf-8");
11784
+ const config2 = JSON.parse(content);
11785
+ return Array.isArray(config2) ? config2 : [];
11786
+ }
11787
+ delete __require.cache[__require.resolve(configPath)];
11788
+ const mod = __require(configPath);
11789
+ const config = mod.default || mod;
11790
+ if (typeof config === "function") {
11791
+ return await config();
11792
+ }
11793
+ if (Array.isArray(config)) {
11794
+ return config;
11795
+ }
11796
+ throw new Error(
11797
+ `Invalid rewrites config in ${configPath}. Expected array or function returning array.`
11798
+ );
11799
+ }
11800
+ /**
11801
+ * Checks if cache is still valid, invalidates if config changed.
11802
+ */
11803
+ ensureCacheValid() {
11804
+ if (!this.cache) {
11805
+ return;
11806
+ }
11807
+ const now = Date.now();
11808
+ if (now - this.cache.timestamp > this.cacheMaxAge) {
11809
+ const configPath = this.findRewritesConfig();
11810
+ if (configPath && this.hasConfigChanged(configPath)) {
11811
+ this.cache = null;
11812
+ } else {
11813
+ this.cache.timestamp = now;
11814
+ }
11815
+ }
11816
+ }
11817
+ async loadRewrites() {
11818
+ this.ensureCacheValid();
11819
+ const configPath = this.findRewritesConfig();
11820
+ if (!configPath) {
11821
+ if (this.cache && this.cache.rewrites.length === 0) {
11822
+ return this.cache.rewrites;
11823
+ }
11824
+ this.cache = {
11825
+ rewrites: [],
11826
+ fileStats: null,
11827
+ timestamp: Date.now()
11828
+ };
11829
+ return [];
11830
+ }
11831
+ if (!this.cache || this.hasConfigChanged(configPath)) {
11832
+ const rules = await this.loadRewritesFromFile(configPath);
11833
+ const compiled = compileRewriteRules(rules);
11834
+ const stats = fs11.statSync(configPath);
11835
+ const fileStats = {
11836
+ mtime: stats.mtimeMs,
11837
+ size: stats.size
11838
+ };
11839
+ this.cache = {
11840
+ rewrites: compiled,
11841
+ fileStats,
11842
+ timestamp: Date.now()
11843
+ };
11844
+ }
11845
+ return this.cache.rewrites;
11846
+ }
11847
+ };
11848
+ var ManifestRewriteLoader = class {
11849
+ constructor(projectRoot) {
11850
+ this.cache = null;
11851
+ this.manifestPath = path11.join(projectRoot, ".loly", "rewrites-manifest.json");
11852
+ }
11853
+ /**
11854
+ * Reads the rewrites manifest from disk.
11855
+ */
11856
+ readManifest() {
11857
+ if (!fs11.existsSync(this.manifestPath)) {
11858
+ return null;
11859
+ }
11860
+ try {
11861
+ const content = fs11.readFileSync(this.manifestPath, "utf-8");
11862
+ return JSON.parse(content);
11863
+ } catch (error) {
11864
+ console.warn(
11865
+ `Failed to read rewrites manifest from ${this.manifestPath}:`,
11866
+ error
11867
+ );
11868
+ return null;
11869
+ }
11870
+ }
11871
+ async loadRewrites() {
11872
+ if (this.cache) {
11873
+ return this.cache;
11874
+ }
11875
+ const manifest = this.readManifest();
11876
+ if (!manifest || !manifest.rewrites) {
11877
+ this.cache = [];
11878
+ return [];
11879
+ }
11880
+ const compiled = compileRewriteRules(manifest.rewrites);
11881
+ this.cache = compiled;
11882
+ return compiled;
11883
+ }
11884
+ };
11885
+ function createRewriteLoader(projectRoot, isDev) {
11886
+ if (isDev) {
11887
+ return new FilesystemRewriteLoader(projectRoot);
11888
+ } else {
11889
+ return new ManifestRewriteLoader(projectRoot);
11890
+ }
11891
+ }
11892
+
11893
+ // modules/router/rewrites-manifest.ts
11894
+ import fs12 from "fs";
11895
+ import path12 from "path";
11896
+ init_globals();
11897
+ async function writeRewritesManifest(projectRoot) {
11898
+ const buildDir = path12.join(projectRoot, BUILD_FOLDER_NAME);
11899
+ if (!fs12.existsSync(buildDir)) {
11900
+ fs12.mkdirSync(buildDir, { recursive: true });
11901
+ }
11902
+ const manifestPath = path12.join(buildDir, "rewrites-manifest.json");
11903
+ const loader = createRewriteLoader(projectRoot, true);
11904
+ const compiledRewrites = await loader.loadRewrites();
11905
+ const serializableRules = [];
11906
+ for (const compiled of compiledRewrites) {
11907
+ if (typeof compiled.destination === "string") {
11908
+ serializableRules.push({
11909
+ source: compiled.source,
11910
+ destination: compiled.destination,
11911
+ has: compiled.has
11912
+ });
11913
+ } else {
11914
+ console.warn(
11915
+ `[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.`
11916
+ );
11917
+ }
11918
+ }
11919
+ const manifest = {
11920
+ version: 1,
11921
+ rewrites: serializableRules
11922
+ };
11923
+ fs12.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
11924
+ }
11925
+
11444
11926
  // modules/build/bundler/client.ts
11445
11927
  import { rspack as rspack2 } from "@rspack/core";
11446
11928
 
11447
11929
  // modules/build/config/client.ts
11448
- import path12 from "path";
11449
- import fs12 from "fs";
11930
+ import path14 from "path";
11931
+ import fs14 from "fs";
11450
11932
  import { rspack } from "@rspack/core";
11451
11933
 
11452
11934
  // modules/build/utils/index.ts
11453
- import fs11 from "fs";
11454
- import path11 from "path";
11935
+ import fs13 from "fs";
11936
+ import path13 from "path";
11455
11937
  function ensureDir(dir) {
11456
- fs11.mkdirSync(dir, { recursive: true });
11938
+ fs13.mkdirSync(dir, { recursive: true });
11457
11939
  }
11458
11940
  function loadAliasesFromTsconfig(projectRoot) {
11459
- const tsconfigPath = path11.join(projectRoot, "tsconfig.json");
11941
+ const tsconfigPath = path13.join(projectRoot, "tsconfig.json");
11460
11942
  const aliases = {};
11461
- if (!fs11.existsSync(tsconfigPath)) {
11462
- aliases["@app"] = path11.resolve(projectRoot, "app");
11943
+ if (!fs13.existsSync(tsconfigPath)) {
11944
+ aliases["@app"] = path13.resolve(projectRoot, "app");
11463
11945
  return aliases;
11464
11946
  }
11465
11947
  let tsconfig;
11466
11948
  try {
11467
- tsconfig = JSON.parse(fs11.readFileSync(tsconfigPath, "utf-8"));
11949
+ tsconfig = JSON.parse(fs13.readFileSync(tsconfigPath, "utf-8"));
11468
11950
  } catch (err) {
11469
11951
  console.warn("\u26A0\uFE0F [framework] Could not read tsconfig.json:", err instanceof Error ? err.message : String(err));
11470
11952
  console.warn("\u{1F4A1} Using default path aliases. For custom aliases, ensure tsconfig.json is valid.");
11471
- aliases["@app"] = path11.resolve(projectRoot, "app");
11953
+ aliases["@app"] = path13.resolve(projectRoot, "app");
11472
11954
  return aliases;
11473
11955
  }
11474
11956
  const compilerOptions = tsconfig.compilerOptions ?? {};
@@ -11479,40 +11961,40 @@ function loadAliasesFromTsconfig(projectRoot) {
11479
11961
  const aliasKey = aliasPattern.replace(/\/\*$/, "");
11480
11962
  const firstTarget = targets[0];
11481
11963
  const targetPath = firstTarget.replace(/\/\*$/, "");
11482
- const resolved = path11.resolve(projectRoot, baseUrl, targetPath);
11964
+ const resolved = path13.resolve(projectRoot, baseUrl, targetPath);
11483
11965
  aliases[aliasKey] = resolved;
11484
11966
  }
11485
11967
  if (!aliases["@app"]) {
11486
- aliases["@app"] = path11.resolve(projectRoot, "app");
11968
+ aliases["@app"] = path13.resolve(projectRoot, "app");
11487
11969
  }
11488
11970
  return aliases;
11489
11971
  }
11490
11972
  function copyDirRecursive(srcDir, destDir) {
11491
- if (!fs11.existsSync(srcDir)) return;
11973
+ if (!fs13.existsSync(srcDir)) return;
11492
11974
  ensureDir(destDir);
11493
- const entries = fs11.readdirSync(srcDir, { withFileTypes: true });
11975
+ const entries = fs13.readdirSync(srcDir, { withFileTypes: true });
11494
11976
  for (const entry of entries) {
11495
- const srcPath = path11.join(srcDir, entry.name);
11496
- const destPath = path11.join(destDir, entry.name);
11977
+ const srcPath = path13.join(srcDir, entry.name);
11978
+ const destPath = path13.join(destDir, entry.name);
11497
11979
  if (entry.isDirectory()) {
11498
11980
  copyDirRecursive(srcPath, destPath);
11499
11981
  } else if (entry.isFile()) {
11500
- fs11.copyFileSync(srcPath, destPath);
11982
+ fs13.copyFileSync(srcPath, destPath);
11501
11983
  }
11502
11984
  }
11503
11985
  }
11504
11986
  function copyStaticAssets(projectRoot, outDir) {
11505
- const assetsSrc = path11.join(projectRoot, "assets");
11506
- const assetsDest = path11.join(outDir, "assets");
11987
+ const assetsSrc = path13.join(projectRoot, "assets");
11988
+ const assetsDest = path13.join(outDir, "assets");
11507
11989
  copyDirRecursive(assetsSrc, assetsDest);
11508
- const publicDir = path11.join(projectRoot, "public");
11990
+ const publicDir = path13.join(projectRoot, "public");
11509
11991
  const candidates = ["favicon.ico", "favicon.png"];
11510
11992
  for (const name of candidates) {
11511
- const fromPublic = path11.join(publicDir, name);
11512
- if (fs11.existsSync(fromPublic)) {
11513
- const dest = path11.join(outDir, name);
11514
- ensureDir(path11.dirname(dest));
11515
- fs11.copyFileSync(fromPublic, dest);
11993
+ const fromPublic = path13.join(publicDir, name);
11994
+ if (fs13.existsSync(fromPublic)) {
11995
+ const dest = path13.join(outDir, name);
11996
+ ensureDir(path13.dirname(dest));
11997
+ fs13.copyFileSync(fromPublic, dest);
11516
11998
  break;
11517
11999
  }
11518
12000
  }
@@ -11522,10 +12004,10 @@ function getFaviconInfo(projectRoot, staticDir = "public", isDev = false) {
11522
12004
  { name: "favicon.ico", type: "image/x-icon" },
11523
12005
  { name: "favicon.png", type: "image/png" }
11524
12006
  ];
11525
- const publicDir = path11.join(projectRoot, staticDir);
12007
+ const publicDir = path13.join(projectRoot, staticDir);
11526
12008
  for (const candidate of candidates) {
11527
- const publicPath = path11.join(publicDir, candidate.name);
11528
- if (fs11.existsSync(publicPath)) {
12009
+ const publicPath = path13.join(publicDir, candidate.name);
12010
+ if (fs13.existsSync(publicPath)) {
11529
12011
  return {
11530
12012
  path: `/${candidate.name}`,
11531
12013
  // Served at root from public/
@@ -11543,10 +12025,10 @@ function generateAssetManifest(outDir, stats) {
11543
12025
  },
11544
12026
  chunks: {}
11545
12027
  };
11546
- if (!fs11.existsSync(outDir)) {
12028
+ if (!fs13.existsSync(outDir)) {
11547
12029
  return manifest;
11548
12030
  }
11549
- const files = fs11.readdirSync(outDir);
12031
+ const files = fs13.readdirSync(outDir);
11550
12032
  if (stats) {
11551
12033
  try {
11552
12034
  const statsJson = stats.toJson({
@@ -11675,12 +12157,12 @@ function generateAssetManifest(outDir, stats) {
11675
12157
  }
11676
12158
  function loadAssetManifest(projectRoot) {
11677
12159
  const { BUILD_FOLDER_NAME: BUILD_FOLDER_NAME2 } = (init_globals(), __toCommonJS(globals_exports));
11678
- const manifestPath = path11.join(projectRoot, BUILD_FOLDER_NAME2, "asset-manifest.json");
11679
- if (!fs11.existsSync(manifestPath)) {
12160
+ const manifestPath = path13.join(projectRoot, BUILD_FOLDER_NAME2, "asset-manifest.json");
12161
+ if (!fs13.existsSync(manifestPath)) {
11680
12162
  return null;
11681
12163
  }
11682
12164
  try {
11683
- const manifest = JSON.parse(fs11.readFileSync(manifestPath, "utf-8"));
12165
+ const manifest = JSON.parse(fs13.readFileSync(manifestPath, "utf-8"));
11684
12166
  return manifest;
11685
12167
  } catch (err) {
11686
12168
  return null;
@@ -11703,11 +12185,11 @@ function getClientCssPath(projectRoot) {
11703
12185
  init_globals();
11704
12186
  import dotenv from "dotenv";
11705
12187
  function createClientConfig(projectRoot, mode) {
11706
- const buildDir = path12.join(projectRoot, BUILD_FOLDER_NAME);
11707
- const clientEntry = path12.join(buildDir, "boostrap.ts");
11708
- const outDir = path12.join(buildDir, "client");
11709
- const envPath2 = path12.join(projectRoot, ".env");
11710
- if (fs12.existsSync(envPath2)) {
12188
+ const buildDir = path14.join(projectRoot, BUILD_FOLDER_NAME);
12189
+ const clientEntry = path14.join(buildDir, "boostrap.ts");
12190
+ const outDir = path14.join(buildDir, "client");
12191
+ const envPath2 = path14.join(projectRoot, ".env");
12192
+ if (fs14.existsSync(envPath2)) {
11711
12193
  dotenv.config({ path: envPath2 });
11712
12194
  }
11713
12195
  const publicEnv = {};
@@ -11828,8 +12310,8 @@ function createClientConfig(projectRoot, mode) {
11828
12310
 
11829
12311
  // modules/build/bundler/client.ts
11830
12312
  init_globals();
11831
- import path13 from "path";
11832
- import fs13 from "fs";
12313
+ import path15 from "path";
12314
+ import fs15 from "fs";
11833
12315
  function startClientBundler(projectRoot, mode = "development") {
11834
12316
  const { config, outDir } = createClientConfig(projectRoot, mode);
11835
12317
  copyStaticAssets(projectRoot, outDir);
@@ -11938,8 +12420,8 @@ function buildClientBundle(projectRoot) {
11938
12420
  }
11939
12421
  copyStaticAssets(projectRoot, outDir);
11940
12422
  const assetManifest = generateAssetManifest(outDir, stats);
11941
- const manifestPath = path13.join(projectRoot, BUILD_FOLDER_NAME, "asset-manifest.json");
11942
- fs13.writeFileSync(manifestPath, JSON.stringify(assetManifest, null, 2), "utf-8");
12423
+ const manifestPath = path15.join(projectRoot, BUILD_FOLDER_NAME, "asset-manifest.json");
12424
+ fs15.writeFileSync(manifestPath, JSON.stringify(assetManifest, null, 2), "utf-8");
11943
12425
  resolve3({ outDir });
11944
12426
  });
11945
12427
  });
@@ -12021,7 +12503,7 @@ var ReaddirpStream = class extends Readable {
12021
12503
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
12022
12504
  const statMethod = opts.lstat ? lstat : stat;
12023
12505
  if (wantBigintFsStats) {
12024
- this._stat = (path28) => statMethod(path28, { bigint: true });
12506
+ this._stat = (path30) => statMethod(path30, { bigint: true });
12025
12507
  } else {
12026
12508
  this._stat = statMethod;
12027
12509
  }
@@ -12046,8 +12528,8 @@ var ReaddirpStream = class extends Readable {
12046
12528
  const par = this.parent;
12047
12529
  const fil = par && par.files;
12048
12530
  if (fil && fil.length > 0) {
12049
- const { path: path28, depth } = par;
12050
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path28));
12531
+ const { path: path30, depth } = par;
12532
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path30));
12051
12533
  const awaited = await Promise.all(slice);
12052
12534
  for (const entry of awaited) {
12053
12535
  if (!entry)
@@ -12087,20 +12569,20 @@ var ReaddirpStream = class extends Readable {
12087
12569
  this.reading = false;
12088
12570
  }
12089
12571
  }
12090
- async _exploreDir(path28, depth) {
12572
+ async _exploreDir(path30, depth) {
12091
12573
  let files;
12092
12574
  try {
12093
- files = await readdir(path28, this._rdOptions);
12575
+ files = await readdir(path30, this._rdOptions);
12094
12576
  } catch (error) {
12095
12577
  this._onError(error);
12096
12578
  }
12097
- return { files, depth, path: path28 };
12579
+ return { files, depth, path: path30 };
12098
12580
  }
12099
- async _formatEntry(dirent, path28) {
12581
+ async _formatEntry(dirent, path30) {
12100
12582
  let entry;
12101
12583
  const basename3 = this._isDirent ? dirent.name : dirent;
12102
12584
  try {
12103
- const fullPath = presolve(pjoin(path28, basename3));
12585
+ const fullPath = presolve(pjoin(path30, basename3));
12104
12586
  entry = { path: prelative(this._root, fullPath), fullPath, basename: basename3 };
12105
12587
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
12106
12588
  } catch (err) {
@@ -12500,16 +12982,16 @@ var delFromSet = (main, prop, item) => {
12500
12982
  };
12501
12983
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
12502
12984
  var FsWatchInstances = /* @__PURE__ */ new Map();
12503
- function createFsWatchInstance(path28, options, listener, errHandler, emitRaw) {
12985
+ function createFsWatchInstance(path30, options, listener, errHandler, emitRaw) {
12504
12986
  const handleEvent = (rawEvent, evPath) => {
12505
- listener(path28);
12506
- emitRaw(rawEvent, evPath, { watchedPath: path28 });
12507
- if (evPath && path28 !== evPath) {
12508
- fsWatchBroadcast(sysPath.resolve(path28, evPath), KEY_LISTENERS, sysPath.join(path28, evPath));
12987
+ listener(path30);
12988
+ emitRaw(rawEvent, evPath, { watchedPath: path30 });
12989
+ if (evPath && path30 !== evPath) {
12990
+ fsWatchBroadcast(sysPath.resolve(path30, evPath), KEY_LISTENERS, sysPath.join(path30, evPath));
12509
12991
  }
12510
12992
  };
12511
12993
  try {
12512
- return fs_watch(path28, {
12994
+ return fs_watch(path30, {
12513
12995
  persistent: options.persistent
12514
12996
  }, handleEvent);
12515
12997
  } catch (error) {
@@ -12525,12 +13007,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
12525
13007
  listener(val1, val2, val3);
12526
13008
  });
12527
13009
  };
12528
- var setFsWatchListener = (path28, fullPath, options, handlers) => {
13010
+ var setFsWatchListener = (path30, fullPath, options, handlers) => {
12529
13011
  const { listener, errHandler, rawEmitter } = handlers;
12530
13012
  let cont = FsWatchInstances.get(fullPath);
12531
13013
  let watcher;
12532
13014
  if (!options.persistent) {
12533
- watcher = createFsWatchInstance(path28, options, listener, errHandler, rawEmitter);
13015
+ watcher = createFsWatchInstance(path30, options, listener, errHandler, rawEmitter);
12534
13016
  if (!watcher)
12535
13017
  return;
12536
13018
  return watcher.close.bind(watcher);
@@ -12541,7 +13023,7 @@ var setFsWatchListener = (path28, fullPath, options, handlers) => {
12541
13023
  addAndConvert(cont, KEY_RAW, rawEmitter);
12542
13024
  } else {
12543
13025
  watcher = createFsWatchInstance(
12544
- path28,
13026
+ path30,
12545
13027
  options,
12546
13028
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
12547
13029
  errHandler,
@@ -12556,7 +13038,7 @@ var setFsWatchListener = (path28, fullPath, options, handlers) => {
12556
13038
  cont.watcherUnusable = true;
12557
13039
  if (isWindows && error.code === "EPERM") {
12558
13040
  try {
12559
- const fd = await open(path28, "r");
13041
+ const fd = await open(path30, "r");
12560
13042
  await fd.close();
12561
13043
  broadcastErr(error);
12562
13044
  } catch (err) {
@@ -12587,7 +13069,7 @@ var setFsWatchListener = (path28, fullPath, options, handlers) => {
12587
13069
  };
12588
13070
  };
12589
13071
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
12590
- var setFsWatchFileListener = (path28, fullPath, options, handlers) => {
13072
+ var setFsWatchFileListener = (path30, fullPath, options, handlers) => {
12591
13073
  const { listener, rawEmitter } = handlers;
12592
13074
  let cont = FsWatchFileInstances.get(fullPath);
12593
13075
  const copts = cont && cont.options;
@@ -12609,7 +13091,7 @@ var setFsWatchFileListener = (path28, fullPath, options, handlers) => {
12609
13091
  });
12610
13092
  const currmtime = curr.mtimeMs;
12611
13093
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
12612
- foreach(cont.listeners, (listener2) => listener2(path28, curr));
13094
+ foreach(cont.listeners, (listener2) => listener2(path30, curr));
12613
13095
  }
12614
13096
  })
12615
13097
  };
@@ -12637,13 +13119,13 @@ var NodeFsHandler = class {
12637
13119
  * @param listener on fs change
12638
13120
  * @returns closer for the watcher instance
12639
13121
  */
12640
- _watchWithNodeFs(path28, listener) {
13122
+ _watchWithNodeFs(path30, listener) {
12641
13123
  const opts = this.fsw.options;
12642
- const directory = sysPath.dirname(path28);
12643
- const basename3 = sysPath.basename(path28);
13124
+ const directory = sysPath.dirname(path30);
13125
+ const basename3 = sysPath.basename(path30);
12644
13126
  const parent = this.fsw._getWatchedDir(directory);
12645
13127
  parent.add(basename3);
12646
- const absolutePath = sysPath.resolve(path28);
13128
+ const absolutePath = sysPath.resolve(path30);
12647
13129
  const options = {
12648
13130
  persistent: opts.persistent
12649
13131
  };
@@ -12653,12 +13135,12 @@ var NodeFsHandler = class {
12653
13135
  if (opts.usePolling) {
12654
13136
  const enableBin = opts.interval !== opts.binaryInterval;
12655
13137
  options.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
12656
- closer = setFsWatchFileListener(path28, absolutePath, options, {
13138
+ closer = setFsWatchFileListener(path30, absolutePath, options, {
12657
13139
  listener,
12658
13140
  rawEmitter: this.fsw._emitRaw
12659
13141
  });
12660
13142
  } else {
12661
- closer = setFsWatchListener(path28, absolutePath, options, {
13143
+ closer = setFsWatchListener(path30, absolutePath, options, {
12662
13144
  listener,
12663
13145
  errHandler: this._boundHandleError,
12664
13146
  rawEmitter: this.fsw._emitRaw
@@ -12680,7 +13162,7 @@ var NodeFsHandler = class {
12680
13162
  let prevStats = stats;
12681
13163
  if (parent.has(basename3))
12682
13164
  return;
12683
- const listener = async (path28, newStats) => {
13165
+ const listener = async (path30, newStats) => {
12684
13166
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
12685
13167
  return;
12686
13168
  if (!newStats || newStats.mtimeMs === 0) {
@@ -12694,11 +13176,11 @@ var NodeFsHandler = class {
12694
13176
  this.fsw._emit(EV.CHANGE, file, newStats2);
12695
13177
  }
12696
13178
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
12697
- this.fsw._closeFile(path28);
13179
+ this.fsw._closeFile(path30);
12698
13180
  prevStats = newStats2;
12699
13181
  const closer2 = this._watchWithNodeFs(file, listener);
12700
13182
  if (closer2)
12701
- this.fsw._addPathCloser(path28, closer2);
13183
+ this.fsw._addPathCloser(path30, closer2);
12702
13184
  } else {
12703
13185
  prevStats = newStats2;
12704
13186
  }
@@ -12730,7 +13212,7 @@ var NodeFsHandler = class {
12730
13212
  * @param item basename of this item
12731
13213
  * @returns true if no more processing is needed for this entry.
12732
13214
  */
12733
- async _handleSymlink(entry, directory, path28, item) {
13215
+ async _handleSymlink(entry, directory, path30, item) {
12734
13216
  if (this.fsw.closed) {
12735
13217
  return;
12736
13218
  }
@@ -12740,7 +13222,7 @@ var NodeFsHandler = class {
12740
13222
  this.fsw._incrReadyCount();
12741
13223
  let linkPath;
12742
13224
  try {
12743
- linkPath = await fsrealpath(path28);
13225
+ linkPath = await fsrealpath(path30);
12744
13226
  } catch (e) {
12745
13227
  this.fsw._emitReady();
12746
13228
  return true;
@@ -12750,12 +13232,12 @@ var NodeFsHandler = class {
12750
13232
  if (dir.has(item)) {
12751
13233
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
12752
13234
  this.fsw._symlinkPaths.set(full, linkPath);
12753
- this.fsw._emit(EV.CHANGE, path28, entry.stats);
13235
+ this.fsw._emit(EV.CHANGE, path30, entry.stats);
12754
13236
  }
12755
13237
  } else {
12756
13238
  dir.add(item);
12757
13239
  this.fsw._symlinkPaths.set(full, linkPath);
12758
- this.fsw._emit(EV.ADD, path28, entry.stats);
13240
+ this.fsw._emit(EV.ADD, path30, entry.stats);
12759
13241
  }
12760
13242
  this.fsw._emitReady();
12761
13243
  return true;
@@ -12784,9 +13266,9 @@ var NodeFsHandler = class {
12784
13266
  return;
12785
13267
  }
12786
13268
  const item = entry.path;
12787
- let path28 = sysPath.join(directory, item);
13269
+ let path30 = sysPath.join(directory, item);
12788
13270
  current.add(item);
12789
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path28, item)) {
13271
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path30, item)) {
12790
13272
  return;
12791
13273
  }
12792
13274
  if (this.fsw.closed) {
@@ -12795,8 +13277,8 @@ var NodeFsHandler = class {
12795
13277
  }
12796
13278
  if (item === target || !target && !previous.has(item)) {
12797
13279
  this.fsw._incrReadyCount();
12798
- path28 = sysPath.join(dir, sysPath.relative(dir, path28));
12799
- this._addToNodeFs(path28, initialAdd, wh, depth + 1);
13280
+ path30 = sysPath.join(dir, sysPath.relative(dir, path30));
13281
+ this._addToNodeFs(path30, initialAdd, wh, depth + 1);
12800
13282
  }
12801
13283
  }).on(EV.ERROR, this._boundHandleError);
12802
13284
  return new Promise((resolve3, reject) => {
@@ -12865,13 +13347,13 @@ var NodeFsHandler = class {
12865
13347
  * @param depth Child path actually targeted for watch
12866
13348
  * @param target Child path actually targeted for watch
12867
13349
  */
12868
- async _addToNodeFs(path28, initialAdd, priorWh, depth, target) {
13350
+ async _addToNodeFs(path30, initialAdd, priorWh, depth, target) {
12869
13351
  const ready = this.fsw._emitReady;
12870
- if (this.fsw._isIgnored(path28) || this.fsw.closed) {
13352
+ if (this.fsw._isIgnored(path30) || this.fsw.closed) {
12871
13353
  ready();
12872
13354
  return false;
12873
13355
  }
12874
- const wh = this.fsw._getWatchHelpers(path28);
13356
+ const wh = this.fsw._getWatchHelpers(path30);
12875
13357
  if (priorWh) {
12876
13358
  wh.filterPath = (entry) => priorWh.filterPath(entry);
12877
13359
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -12887,8 +13369,8 @@ var NodeFsHandler = class {
12887
13369
  const follow = this.fsw.options.followSymlinks;
12888
13370
  let closer;
12889
13371
  if (stats.isDirectory()) {
12890
- const absPath = sysPath.resolve(path28);
12891
- const targetPath = follow ? await fsrealpath(path28) : path28;
13372
+ const absPath = sysPath.resolve(path30);
13373
+ const targetPath = follow ? await fsrealpath(path30) : path30;
12892
13374
  if (this.fsw.closed)
12893
13375
  return;
12894
13376
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -12898,29 +13380,29 @@ var NodeFsHandler = class {
12898
13380
  this.fsw._symlinkPaths.set(absPath, targetPath);
12899
13381
  }
12900
13382
  } else if (stats.isSymbolicLink()) {
12901
- const targetPath = follow ? await fsrealpath(path28) : path28;
13383
+ const targetPath = follow ? await fsrealpath(path30) : path30;
12902
13384
  if (this.fsw.closed)
12903
13385
  return;
12904
13386
  const parent = sysPath.dirname(wh.watchPath);
12905
13387
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
12906
13388
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
12907
- closer = await this._handleDir(parent, stats, initialAdd, depth, path28, wh, targetPath);
13389
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path30, wh, targetPath);
12908
13390
  if (this.fsw.closed)
12909
13391
  return;
12910
13392
  if (targetPath !== void 0) {
12911
- this.fsw._symlinkPaths.set(sysPath.resolve(path28), targetPath);
13393
+ this.fsw._symlinkPaths.set(sysPath.resolve(path30), targetPath);
12912
13394
  }
12913
13395
  } else {
12914
13396
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
12915
13397
  }
12916
13398
  ready();
12917
13399
  if (closer)
12918
- this.fsw._addPathCloser(path28, closer);
13400
+ this.fsw._addPathCloser(path30, closer);
12919
13401
  return false;
12920
13402
  } catch (error) {
12921
13403
  if (this.fsw._handleError(error)) {
12922
13404
  ready();
12923
- return path28;
13405
+ return path30;
12924
13406
  }
12925
13407
  }
12926
13408
  }
@@ -12963,26 +13445,26 @@ function createPattern(matcher) {
12963
13445
  }
12964
13446
  return () => false;
12965
13447
  }
12966
- function normalizePath(path28) {
12967
- if (typeof path28 !== "string")
13448
+ function normalizePath(path30) {
13449
+ if (typeof path30 !== "string")
12968
13450
  throw new Error("string expected");
12969
- path28 = sysPath2.normalize(path28);
12970
- path28 = path28.replace(/\\/g, "/");
13451
+ path30 = sysPath2.normalize(path30);
13452
+ path30 = path30.replace(/\\/g, "/");
12971
13453
  let prepend = false;
12972
- if (path28.startsWith("//"))
13454
+ if (path30.startsWith("//"))
12973
13455
  prepend = true;
12974
13456
  const DOUBLE_SLASH_RE2 = /\/\//;
12975
- while (path28.match(DOUBLE_SLASH_RE2))
12976
- path28 = path28.replace(DOUBLE_SLASH_RE2, "/");
13457
+ while (path30.match(DOUBLE_SLASH_RE2))
13458
+ path30 = path30.replace(DOUBLE_SLASH_RE2, "/");
12977
13459
  if (prepend)
12978
- path28 = "/" + path28;
12979
- return path28;
13460
+ path30 = "/" + path30;
13461
+ return path30;
12980
13462
  }
12981
13463
  function matchPatterns(patterns, testString, stats) {
12982
- const path28 = normalizePath(testString);
13464
+ const path30 = normalizePath(testString);
12983
13465
  for (let index = 0; index < patterns.length; index++) {
12984
13466
  const pattern = patterns[index];
12985
- if (pattern(path28, stats)) {
13467
+ if (pattern(path30, stats)) {
12986
13468
  return true;
12987
13469
  }
12988
13470
  }
@@ -13022,19 +13504,19 @@ var toUnix = (string) => {
13022
13504
  }
13023
13505
  return str;
13024
13506
  };
13025
- var normalizePathToUnix = (path28) => toUnix(sysPath2.normalize(toUnix(path28)));
13026
- var normalizeIgnored = (cwd = "") => (path28) => {
13027
- if (typeof path28 === "string") {
13028
- return normalizePathToUnix(sysPath2.isAbsolute(path28) ? path28 : sysPath2.join(cwd, path28));
13507
+ var normalizePathToUnix = (path30) => toUnix(sysPath2.normalize(toUnix(path30)));
13508
+ var normalizeIgnored = (cwd = "") => (path30) => {
13509
+ if (typeof path30 === "string") {
13510
+ return normalizePathToUnix(sysPath2.isAbsolute(path30) ? path30 : sysPath2.join(cwd, path30));
13029
13511
  } else {
13030
- return path28;
13512
+ return path30;
13031
13513
  }
13032
13514
  };
13033
- var getAbsolutePath = (path28, cwd) => {
13034
- if (sysPath2.isAbsolute(path28)) {
13035
- return path28;
13515
+ var getAbsolutePath = (path30, cwd) => {
13516
+ if (sysPath2.isAbsolute(path30)) {
13517
+ return path30;
13036
13518
  }
13037
- return sysPath2.join(cwd, path28);
13519
+ return sysPath2.join(cwd, path30);
13038
13520
  };
13039
13521
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
13040
13522
  var DirEntry = class {
@@ -13089,10 +13571,10 @@ var DirEntry = class {
13089
13571
  var STAT_METHOD_F = "stat";
13090
13572
  var STAT_METHOD_L = "lstat";
13091
13573
  var WatchHelper = class {
13092
- constructor(path28, follow, fsw) {
13574
+ constructor(path30, follow, fsw) {
13093
13575
  this.fsw = fsw;
13094
- const watchPath = path28;
13095
- this.path = path28 = path28.replace(REPLACER_RE, "");
13576
+ const watchPath = path30;
13577
+ this.path = path30 = path30.replace(REPLACER_RE, "");
13096
13578
  this.watchPath = watchPath;
13097
13579
  this.fullWatchPath = sysPath2.resolve(watchPath);
13098
13580
  this.dirParts = [];
@@ -13214,20 +13696,20 @@ var FSWatcher = class extends EventEmitter {
13214
13696
  this._closePromise = void 0;
13215
13697
  let paths = unifyPaths(paths_);
13216
13698
  if (cwd) {
13217
- paths = paths.map((path28) => {
13218
- const absPath = getAbsolutePath(path28, cwd);
13699
+ paths = paths.map((path30) => {
13700
+ const absPath = getAbsolutePath(path30, cwd);
13219
13701
  return absPath;
13220
13702
  });
13221
13703
  }
13222
- paths.forEach((path28) => {
13223
- this._removeIgnoredPath(path28);
13704
+ paths.forEach((path30) => {
13705
+ this._removeIgnoredPath(path30);
13224
13706
  });
13225
13707
  this._userIgnored = void 0;
13226
13708
  if (!this._readyCount)
13227
13709
  this._readyCount = 0;
13228
13710
  this._readyCount += paths.length;
13229
- Promise.all(paths.map(async (path28) => {
13230
- const res = await this._nodeFsHandler._addToNodeFs(path28, !_internal, void 0, 0, _origAdd);
13711
+ Promise.all(paths.map(async (path30) => {
13712
+ const res = await this._nodeFsHandler._addToNodeFs(path30, !_internal, void 0, 0, _origAdd);
13231
13713
  if (res)
13232
13714
  this._emitReady();
13233
13715
  return res;
@@ -13249,17 +13731,17 @@ var FSWatcher = class extends EventEmitter {
13249
13731
  return this;
13250
13732
  const paths = unifyPaths(paths_);
13251
13733
  const { cwd } = this.options;
13252
- paths.forEach((path28) => {
13253
- if (!sysPath2.isAbsolute(path28) && !this._closers.has(path28)) {
13734
+ paths.forEach((path30) => {
13735
+ if (!sysPath2.isAbsolute(path30) && !this._closers.has(path30)) {
13254
13736
  if (cwd)
13255
- path28 = sysPath2.join(cwd, path28);
13256
- path28 = sysPath2.resolve(path28);
13737
+ path30 = sysPath2.join(cwd, path30);
13738
+ path30 = sysPath2.resolve(path30);
13257
13739
  }
13258
- this._closePath(path28);
13259
- this._addIgnoredPath(path28);
13260
- if (this._watched.has(path28)) {
13740
+ this._closePath(path30);
13741
+ this._addIgnoredPath(path30);
13742
+ if (this._watched.has(path30)) {
13261
13743
  this._addIgnoredPath({
13262
- path: path28,
13744
+ path: path30,
13263
13745
  recursive: true
13264
13746
  });
13265
13747
  }
@@ -13323,38 +13805,38 @@ var FSWatcher = class extends EventEmitter {
13323
13805
  * @param stats arguments to be passed with event
13324
13806
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
13325
13807
  */
13326
- async _emit(event, path28, stats) {
13808
+ async _emit(event, path30, stats) {
13327
13809
  if (this.closed)
13328
13810
  return;
13329
13811
  const opts = this.options;
13330
13812
  if (isWindows)
13331
- path28 = sysPath2.normalize(path28);
13813
+ path30 = sysPath2.normalize(path30);
13332
13814
  if (opts.cwd)
13333
- path28 = sysPath2.relative(opts.cwd, path28);
13334
- const args = [path28];
13815
+ path30 = sysPath2.relative(opts.cwd, path30);
13816
+ const args = [path30];
13335
13817
  if (stats != null)
13336
13818
  args.push(stats);
13337
13819
  const awf = opts.awaitWriteFinish;
13338
13820
  let pw;
13339
- if (awf && (pw = this._pendingWrites.get(path28))) {
13821
+ if (awf && (pw = this._pendingWrites.get(path30))) {
13340
13822
  pw.lastChange = /* @__PURE__ */ new Date();
13341
13823
  return this;
13342
13824
  }
13343
13825
  if (opts.atomic) {
13344
13826
  if (event === EVENTS.UNLINK) {
13345
- this._pendingUnlinks.set(path28, [event, ...args]);
13827
+ this._pendingUnlinks.set(path30, [event, ...args]);
13346
13828
  setTimeout(() => {
13347
- this._pendingUnlinks.forEach((entry, path29) => {
13829
+ this._pendingUnlinks.forEach((entry, path31) => {
13348
13830
  this.emit(...entry);
13349
13831
  this.emit(EVENTS.ALL, ...entry);
13350
- this._pendingUnlinks.delete(path29);
13832
+ this._pendingUnlinks.delete(path31);
13351
13833
  });
13352
13834
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
13353
13835
  return this;
13354
13836
  }
13355
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path28)) {
13837
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path30)) {
13356
13838
  event = EVENTS.CHANGE;
13357
- this._pendingUnlinks.delete(path28);
13839
+ this._pendingUnlinks.delete(path30);
13358
13840
  }
13359
13841
  }
13360
13842
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -13372,16 +13854,16 @@ var FSWatcher = class extends EventEmitter {
13372
13854
  this.emitWithAll(event, args);
13373
13855
  }
13374
13856
  };
13375
- this._awaitWriteFinish(path28, awf.stabilityThreshold, event, awfEmit);
13857
+ this._awaitWriteFinish(path30, awf.stabilityThreshold, event, awfEmit);
13376
13858
  return this;
13377
13859
  }
13378
13860
  if (event === EVENTS.CHANGE) {
13379
- const isThrottled = !this._throttle(EVENTS.CHANGE, path28, 50);
13861
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path30, 50);
13380
13862
  if (isThrottled)
13381
13863
  return this;
13382
13864
  }
13383
13865
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
13384
- const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path28) : path28;
13866
+ const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path30) : path30;
13385
13867
  let stats2;
13386
13868
  try {
13387
13869
  stats2 = await stat3(fullPath);
@@ -13412,23 +13894,23 @@ var FSWatcher = class extends EventEmitter {
13412
13894
  * @param timeout duration of time to suppress duplicate actions
13413
13895
  * @returns tracking object or false if action should be suppressed
13414
13896
  */
13415
- _throttle(actionType, path28, timeout) {
13897
+ _throttle(actionType, path30, timeout) {
13416
13898
  if (!this._throttled.has(actionType)) {
13417
13899
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
13418
13900
  }
13419
13901
  const action = this._throttled.get(actionType);
13420
13902
  if (!action)
13421
13903
  throw new Error("invalid throttle");
13422
- const actionPath = action.get(path28);
13904
+ const actionPath = action.get(path30);
13423
13905
  if (actionPath) {
13424
13906
  actionPath.count++;
13425
13907
  return false;
13426
13908
  }
13427
13909
  let timeoutObject;
13428
13910
  const clear = () => {
13429
- const item = action.get(path28);
13911
+ const item = action.get(path30);
13430
13912
  const count = item ? item.count : 0;
13431
- action.delete(path28);
13913
+ action.delete(path30);
13432
13914
  clearTimeout(timeoutObject);
13433
13915
  if (item)
13434
13916
  clearTimeout(item.timeoutObject);
@@ -13436,7 +13918,7 @@ var FSWatcher = class extends EventEmitter {
13436
13918
  };
13437
13919
  timeoutObject = setTimeout(clear, timeout);
13438
13920
  const thr = { timeoutObject, clear, count: 0 };
13439
- action.set(path28, thr);
13921
+ action.set(path30, thr);
13440
13922
  return thr;
13441
13923
  }
13442
13924
  _incrReadyCount() {
@@ -13450,44 +13932,44 @@ var FSWatcher = class extends EventEmitter {
13450
13932
  * @param event
13451
13933
  * @param awfEmit Callback to be called when ready for event to be emitted.
13452
13934
  */
13453
- _awaitWriteFinish(path28, threshold, event, awfEmit) {
13935
+ _awaitWriteFinish(path30, threshold, event, awfEmit) {
13454
13936
  const awf = this.options.awaitWriteFinish;
13455
13937
  if (typeof awf !== "object")
13456
13938
  return;
13457
13939
  const pollInterval = awf.pollInterval;
13458
13940
  let timeoutHandler;
13459
- let fullPath = path28;
13460
- if (this.options.cwd && !sysPath2.isAbsolute(path28)) {
13461
- fullPath = sysPath2.join(this.options.cwd, path28);
13941
+ let fullPath = path30;
13942
+ if (this.options.cwd && !sysPath2.isAbsolute(path30)) {
13943
+ fullPath = sysPath2.join(this.options.cwd, path30);
13462
13944
  }
13463
13945
  const now = /* @__PURE__ */ new Date();
13464
13946
  const writes = this._pendingWrites;
13465
13947
  function awaitWriteFinishFn(prevStat) {
13466
13948
  statcb(fullPath, (err, curStat) => {
13467
- if (err || !writes.has(path28)) {
13949
+ if (err || !writes.has(path30)) {
13468
13950
  if (err && err.code !== "ENOENT")
13469
13951
  awfEmit(err);
13470
13952
  return;
13471
13953
  }
13472
13954
  const now2 = Number(/* @__PURE__ */ new Date());
13473
13955
  if (prevStat && curStat.size !== prevStat.size) {
13474
- writes.get(path28).lastChange = now2;
13956
+ writes.get(path30).lastChange = now2;
13475
13957
  }
13476
- const pw = writes.get(path28);
13958
+ const pw = writes.get(path30);
13477
13959
  const df = now2 - pw.lastChange;
13478
13960
  if (df >= threshold) {
13479
- writes.delete(path28);
13961
+ writes.delete(path30);
13480
13962
  awfEmit(void 0, curStat);
13481
13963
  } else {
13482
13964
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
13483
13965
  }
13484
13966
  });
13485
13967
  }
13486
- if (!writes.has(path28)) {
13487
- writes.set(path28, {
13968
+ if (!writes.has(path30)) {
13969
+ writes.set(path30, {
13488
13970
  lastChange: now,
13489
13971
  cancelWait: () => {
13490
- writes.delete(path28);
13972
+ writes.delete(path30);
13491
13973
  clearTimeout(timeoutHandler);
13492
13974
  return event;
13493
13975
  }
@@ -13498,8 +13980,8 @@ var FSWatcher = class extends EventEmitter {
13498
13980
  /**
13499
13981
  * Determines whether user has asked to ignore this path.
13500
13982
  */
13501
- _isIgnored(path28, stats) {
13502
- if (this.options.atomic && DOT_RE.test(path28))
13983
+ _isIgnored(path30, stats) {
13984
+ if (this.options.atomic && DOT_RE.test(path30))
13503
13985
  return true;
13504
13986
  if (!this._userIgnored) {
13505
13987
  const { cwd } = this.options;
@@ -13509,17 +13991,17 @@ var FSWatcher = class extends EventEmitter {
13509
13991
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
13510
13992
  this._userIgnored = anymatch(list, void 0);
13511
13993
  }
13512
- return this._userIgnored(path28, stats);
13994
+ return this._userIgnored(path30, stats);
13513
13995
  }
13514
- _isntIgnored(path28, stat4) {
13515
- return !this._isIgnored(path28, stat4);
13996
+ _isntIgnored(path30, stat4) {
13997
+ return !this._isIgnored(path30, stat4);
13516
13998
  }
13517
13999
  /**
13518
14000
  * Provides a set of common helpers and properties relating to symlink handling.
13519
14001
  * @param path file or directory pattern being watched
13520
14002
  */
13521
- _getWatchHelpers(path28) {
13522
- return new WatchHelper(path28, this.options.followSymlinks, this);
14003
+ _getWatchHelpers(path30) {
14004
+ return new WatchHelper(path30, this.options.followSymlinks, this);
13523
14005
  }
13524
14006
  // Directory helpers
13525
14007
  // -----------------
@@ -13551,63 +14033,63 @@ var FSWatcher = class extends EventEmitter {
13551
14033
  * @param item base path of item/directory
13552
14034
  */
13553
14035
  _remove(directory, item, isDirectory) {
13554
- const path28 = sysPath2.join(directory, item);
13555
- const fullPath = sysPath2.resolve(path28);
13556
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path28) || this._watched.has(fullPath);
13557
- if (!this._throttle("remove", path28, 100))
14036
+ const path30 = sysPath2.join(directory, item);
14037
+ const fullPath = sysPath2.resolve(path30);
14038
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path30) || this._watched.has(fullPath);
14039
+ if (!this._throttle("remove", path30, 100))
13558
14040
  return;
13559
14041
  if (!isDirectory && this._watched.size === 1) {
13560
14042
  this.add(directory, item, true);
13561
14043
  }
13562
- const wp = this._getWatchedDir(path28);
14044
+ const wp = this._getWatchedDir(path30);
13563
14045
  const nestedDirectoryChildren = wp.getChildren();
13564
- nestedDirectoryChildren.forEach((nested) => this._remove(path28, nested));
14046
+ nestedDirectoryChildren.forEach((nested) => this._remove(path30, nested));
13565
14047
  const parent = this._getWatchedDir(directory);
13566
14048
  const wasTracked = parent.has(item);
13567
14049
  parent.remove(item);
13568
14050
  if (this._symlinkPaths.has(fullPath)) {
13569
14051
  this._symlinkPaths.delete(fullPath);
13570
14052
  }
13571
- let relPath = path28;
14053
+ let relPath = path30;
13572
14054
  if (this.options.cwd)
13573
- relPath = sysPath2.relative(this.options.cwd, path28);
14055
+ relPath = sysPath2.relative(this.options.cwd, path30);
13574
14056
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
13575
14057
  const event = this._pendingWrites.get(relPath).cancelWait();
13576
14058
  if (event === EVENTS.ADD)
13577
14059
  return;
13578
14060
  }
13579
- this._watched.delete(path28);
14061
+ this._watched.delete(path30);
13580
14062
  this._watched.delete(fullPath);
13581
14063
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
13582
- if (wasTracked && !this._isIgnored(path28))
13583
- this._emit(eventName, path28);
13584
- this._closePath(path28);
14064
+ if (wasTracked && !this._isIgnored(path30))
14065
+ this._emit(eventName, path30);
14066
+ this._closePath(path30);
13585
14067
  }
13586
14068
  /**
13587
14069
  * Closes all watchers for a path
13588
14070
  */
13589
- _closePath(path28) {
13590
- this._closeFile(path28);
13591
- const dir = sysPath2.dirname(path28);
13592
- this._getWatchedDir(dir).remove(sysPath2.basename(path28));
14071
+ _closePath(path30) {
14072
+ this._closeFile(path30);
14073
+ const dir = sysPath2.dirname(path30);
14074
+ this._getWatchedDir(dir).remove(sysPath2.basename(path30));
13593
14075
  }
13594
14076
  /**
13595
14077
  * Closes only file-specific watchers
13596
14078
  */
13597
- _closeFile(path28) {
13598
- const closers = this._closers.get(path28);
14079
+ _closeFile(path30) {
14080
+ const closers = this._closers.get(path30);
13599
14081
  if (!closers)
13600
14082
  return;
13601
14083
  closers.forEach((closer) => closer());
13602
- this._closers.delete(path28);
14084
+ this._closers.delete(path30);
13603
14085
  }
13604
- _addPathCloser(path28, closer) {
14086
+ _addPathCloser(path30, closer) {
13605
14087
  if (!closer)
13606
14088
  return;
13607
- let list = this._closers.get(path28);
14089
+ let list = this._closers.get(path30);
13608
14090
  if (!list) {
13609
14091
  list = [];
13610
- this._closers.set(path28, list);
14092
+ this._closers.set(path30, list);
13611
14093
  }
13612
14094
  list.push(closer);
13613
14095
  }
@@ -13638,7 +14120,7 @@ var esm_default = { watch, FSWatcher };
13638
14120
 
13639
14121
  // modules/dev/hot-reload-client/index.ts
13640
14122
  init_globals();
13641
- import path14 from "path";
14123
+ import path16 from "path";
13642
14124
  function setupHotReload({
13643
14125
  app,
13644
14126
  appDir,
@@ -13679,7 +14161,7 @@ function setupHotReload({
13679
14161
  });
13680
14162
  });
13681
14163
  console.log(`[hot-reload-server] \u2705 SSE endpoint registered at ${route}`);
13682
- const resolvedProjectRoot = projectRoot ? path14.resolve(projectRoot) : path14.dirname(path14.resolve(appDir));
14164
+ const resolvedProjectRoot = projectRoot ? path16.resolve(projectRoot) : path16.dirname(path16.resolve(appDir));
13683
14165
  const watcher = esm_default.watch(resolvedProjectRoot, {
13684
14166
  ignoreInitial: true,
13685
14167
  ignored: [
@@ -13719,11 +14201,11 @@ function setupHotReload({
13719
14201
  let broadcastTimeout = null;
13720
14202
  const BROADCAST_DEBOUNCE_MS = 300;
13721
14203
  async function broadcastReload(reason, filePath) {
13722
- const normalizedPath = path14.normalize(filePath);
14204
+ const normalizedPath = path16.normalize(filePath);
13723
14205
  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-")) {
13724
14206
  return;
13725
14207
  }
13726
- const rel = path14.relative(appDir, filePath);
14208
+ const rel = path16.relative(appDir, filePath);
13727
14209
  console.log(`[hot-reload] ${reason}: ${rel}`);
13728
14210
  if (broadcastTimeout) {
13729
14211
  clearTimeout(broadcastTimeout);
@@ -13773,9 +14255,9 @@ data: reload:${rel}
13773
14255
  }
13774
14256
 
13775
14257
  // modules/dev/hot-reload-server/index.ts
13776
- import path15 from "path";
14258
+ import path17 from "path";
13777
14259
  function clearAppRequireCache(appDir) {
13778
- const appDirNormalized = path15.resolve(appDir);
14260
+ const appDirNormalized = path17.resolve(appDir);
13779
14261
  for (const id of Object.keys(__require.cache)) {
13780
14262
  if (id.startsWith(appDirNormalized)) {
13781
14263
  delete __require.cache[id];
@@ -13788,8 +14270,8 @@ init_globals();
13788
14270
 
13789
14271
  // src/config.ts
13790
14272
  init_globals();
13791
- import path16 from "path";
13792
- import fs14 from "fs";
14273
+ import path18 from "path";
14274
+ import fs16 from "fs";
13793
14275
  var DEFAULT_CONFIG = {
13794
14276
  directories: {
13795
14277
  app: "app",
@@ -13855,8 +14337,8 @@ function validateConfig(config, projectRoot) {
13855
14337
  if (!config.directories.app || typeof config.directories.app !== "string") {
13856
14338
  errors.push("config.directories.app must be a non-empty string");
13857
14339
  } else {
13858
- const appDir = path16.join(projectRoot, config.directories.app);
13859
- if (!fs14.existsSync(appDir) && process.env.NODE_ENV !== "test") {
14340
+ const appDir = path18.join(projectRoot, config.directories.app);
14341
+ if (!fs16.existsSync(appDir) && process.env.NODE_ENV !== "test") {
13860
14342
  errors.push(
13861
14343
  `App directory not found: ${config.directories.app}
13862
14344
  Expected at: ${appDir}
@@ -13960,17 +14442,17 @@ function validateConfig(config, projectRoot) {
13960
14442
  }
13961
14443
  function loadConfig(projectRoot) {
13962
14444
  const configFiles = [
13963
- path16.join(projectRoot, "loly.config.ts"),
13964
- path16.join(projectRoot, "loly.config.js"),
13965
- path16.join(projectRoot, "loly.config.json")
14445
+ path18.join(projectRoot, "loly.config.ts"),
14446
+ path18.join(projectRoot, "loly.config.js"),
14447
+ path18.join(projectRoot, "loly.config.json")
13966
14448
  ];
13967
14449
  let userConfig = {};
13968
14450
  let loadedConfigFile = null;
13969
14451
  for (const configFile of configFiles) {
13970
- if (fs14.existsSync(configFile)) {
14452
+ if (fs16.existsSync(configFile)) {
13971
14453
  try {
13972
14454
  if (configFile.endsWith(".json")) {
13973
- const content = fs14.readFileSync(configFile, "utf-8");
14455
+ const content = fs16.readFileSync(configFile, "utf-8");
13974
14456
  userConfig = JSON.parse(content);
13975
14457
  } else {
13976
14458
  if (process.env.NODE_ENV === "development") {
@@ -13979,12 +14461,12 @@ function loadConfig(projectRoot) {
13979
14461
  const mod = __require(configFile);
13980
14462
  userConfig = typeof mod.default === "function" ? mod.default(process.env.NODE_ENV) : mod.default || mod.config || mod;
13981
14463
  }
13982
- loadedConfigFile = path16.relative(projectRoot, configFile);
14464
+ loadedConfigFile = path18.relative(projectRoot, configFile);
13983
14465
  break;
13984
14466
  } catch (error) {
13985
14467
  const errorMessage = error instanceof Error ? error.message : String(error);
13986
14468
  throw new ConfigValidationError(
13987
- `Failed to load configuration from ${path16.relative(projectRoot, configFile)}:
14469
+ `Failed to load configuration from ${path18.relative(projectRoot, configFile)}:
13988
14470
  ${errorMessage}
13989
14471
  \u{1F4A1} Suggestion: Check that your config file exports a valid configuration object`
13990
14472
  );
@@ -14008,20 +14490,20 @@ ${error.message}`;
14008
14490
  return config;
14009
14491
  }
14010
14492
  function getAppDir(projectRoot, config) {
14011
- return path16.resolve(projectRoot, config.directories.app);
14493
+ return path18.resolve(projectRoot, config.directories.app);
14012
14494
  }
14013
14495
  function getBuildDir(projectRoot, config) {
14014
- return path16.join(projectRoot, config.directories.build);
14496
+ return path18.join(projectRoot, config.directories.build);
14015
14497
  }
14016
14498
  function getStaticDir(projectRoot, config) {
14017
- return path16.resolve(projectRoot, config.directories.static);
14499
+ return path18.resolve(projectRoot, config.directories.static);
14018
14500
  }
14019
14501
 
14020
14502
  // modules/server/setup.ts
14021
14503
  function setupStaticFiles(app, projectRoot, config) {
14022
14504
  if (!config) return;
14023
14505
  const staticDir = getStaticDir(projectRoot, config);
14024
- if (fs15.existsSync(staticDir)) {
14506
+ if (fs17.existsSync(staticDir)) {
14025
14507
  app.use(
14026
14508
  express.static(staticDir, {
14027
14509
  // In production, add caching headers for better performance
@@ -14047,7 +14529,7 @@ function setupServer(app, options) {
14047
14529
  var getRoutes = getRoutes2;
14048
14530
  const { outDir, waitForBuild } = startClientBundler(projectRoot, "development");
14049
14531
  const onFileChange = async (filePath) => {
14050
- const rel = path17.relative(appDir, filePath);
14532
+ const rel = path19.relative(appDir, filePath);
14051
14533
  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");
14052
14534
  const isTsFile = filePath.endsWith(".ts") || filePath.endsWith(".tsx");
14053
14535
  if (isTsFile) {
@@ -14083,8 +14565,8 @@ function setupServer(app, options) {
14083
14565
  const wssRoutes = routeLoader.loadWssRoutes();
14084
14566
  const notFoundPage = routeLoader.loadNotFoundRoute();
14085
14567
  const errorPage = routeLoader.loadErrorRoute();
14086
- const buildDir = config ? getBuildDir(projectRoot, config) : path17.join(projectRoot, BUILD_FOLDER_NAME);
14087
- const clientOutDir = path17.join(buildDir, "client");
14568
+ const buildDir = config ? getBuildDir(projectRoot, config) : path19.join(projectRoot, BUILD_FOLDER_NAME);
14569
+ const clientOutDir = path19.join(buildDir, "client");
14088
14570
  app.use(
14089
14571
  "/static",
14090
14572
  express.static(clientOutDir, {
@@ -14293,12 +14775,12 @@ var DEFAULT_IGNORED_PATHS = [
14293
14775
  /^\/sockjs-node/
14294
14776
  // Hot reload websocket
14295
14777
  ];
14296
- function shouldIgnorePath(path28, ignoredPaths) {
14778
+ function shouldIgnorePath(path30, ignoredPaths) {
14297
14779
  return ignoredPaths.some((pattern) => {
14298
14780
  if (typeof pattern === "string") {
14299
- return path28 === pattern || path28.startsWith(pattern);
14781
+ return path30 === pattern || path30.startsWith(pattern);
14300
14782
  }
14301
- return pattern.test(path28);
14783
+ return pattern.test(path30);
14302
14784
  });
14303
14785
  }
14304
14786
  function requestLoggerMiddleware(options = {}) {
@@ -14457,11 +14939,11 @@ function createStrictRateLimiterFromConfig(config) {
14457
14939
  }
14458
14940
 
14459
14941
  // modules/server/middleware/auto-rate-limit.ts
14460
- function matchesStrictPattern(path28, patterns) {
14942
+ function matchesStrictPattern(path30, patterns) {
14461
14943
  for (const pattern of patterns) {
14462
14944
  const regexPattern = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\//g, "\\/");
14463
14945
  const regex = new RegExp(`^${regexPattern}$`);
14464
- if (regex.test(path28)) {
14946
+ if (regex.test(path30)) {
14465
14947
  return true;
14466
14948
  }
14467
14949
  }
@@ -14496,8 +14978,31 @@ function getAutoRateLimiter(route, strictPatterns = [], rateLimitConfig) {
14496
14978
 
14497
14979
  // modules/server/handlers/api.ts
14498
14980
  async function handleApiRequest(options) {
14499
- const { apiRoutes, urlPath, req, res, env = "dev" } = options;
14500
- const matched = matchApiRoute(apiRoutes, urlPath);
14981
+ const { apiRoutes, urlPath, req, res, env = "dev", rewriteLoader } = options;
14982
+ let finalUrlPath = urlPath;
14983
+ let extractedParams = {};
14984
+ if (rewriteLoader) {
14985
+ try {
14986
+ const compiledRewrites = await rewriteLoader.loadRewrites();
14987
+ const rewriteResult = await processRewrites(urlPath, compiledRewrites, req);
14988
+ if (rewriteResult) {
14989
+ finalUrlPath = rewriteResult.rewrittenPath;
14990
+ extractedParams = rewriteResult.extractedParams;
14991
+ Object.assign(req.query, extractedParams);
14992
+ if (!req.locals) {
14993
+ req.locals = {};
14994
+ }
14995
+ Object.assign(req.locals, extractedParams);
14996
+ }
14997
+ } catch (error) {
14998
+ const reqLogger = getRequestLogger(req);
14999
+ reqLogger.error("Error processing rewrites", error, {
15000
+ urlPath
15001
+ });
15002
+ }
15003
+ }
15004
+ finalUrlPath = finalUrlPath.replace(/\/$/, "") || "/";
15005
+ const matched = matchApiRoute(apiRoutes, finalUrlPath);
14501
15006
  if (!matched) {
14502
15007
  res.status(404).json({ error: "Not Found" });
14503
15008
  return;
@@ -14518,9 +15023,13 @@ async function handleApiRequest(options) {
14518
15023
  Response: (body = {}, status = 200) => res.status(status).json(body),
14519
15024
  NotFound: (body = {}) => res.status(404).json(body),
14520
15025
  params: sanitizedParams,
14521
- pathname: urlPath,
15026
+ pathname: finalUrlPath,
15027
+ // Use rewritten path
14522
15028
  locals: {}
14523
15029
  };
15030
+ if (extractedParams && Object.keys(extractedParams).length > 0) {
15031
+ Object.assign(ctx.locals, extractedParams);
15032
+ }
14524
15033
  req.query = sanitizedQuery;
14525
15034
  try {
14526
15035
  const autoRateLimiter = getAutoRateLimiter(
@@ -15014,7 +15523,7 @@ var buildRouterData = (req) => {
15014
15523
  };
15015
15524
 
15016
15525
  // modules/server/handlers/middleware.ts
15017
- import path18 from "path";
15526
+ import path20 from "path";
15018
15527
  async function runRouteMiddlewares(route, ctx) {
15019
15528
  for (let i = 0; i < route.middlewares.length; i++) {
15020
15529
  const mw = route.middlewares[i];
@@ -15025,7 +15534,7 @@ async function runRouteMiddlewares(route, ctx) {
15025
15534
  );
15026
15535
  } catch (error) {
15027
15536
  const reqLogger = getRequestLogger(ctx.req);
15028
- const relativePath = route.pageFile ? path18.relative(process.cwd(), route.pageFile) : route.pattern;
15537
+ const relativePath = route.pageFile ? path20.relative(process.cwd(), route.pageFile) : route.pattern;
15029
15538
  reqLogger.error("Route middleware failed", error instanceof Error ? error : new Error(String(error)), {
15030
15539
  route: route.pattern,
15031
15540
  middlewareIndex: i,
@@ -15040,7 +15549,7 @@ async function runRouteMiddlewares(route, ctx) {
15040
15549
  }
15041
15550
 
15042
15551
  // modules/server/handlers/server-hook.ts
15043
- import path19 from "path";
15552
+ import path21 from "path";
15044
15553
  function createServerHookErrorMessage(error, hookType, routePattern, filePath) {
15045
15554
  const errorMessage = error instanceof Error ? error.message : String(error);
15046
15555
  const errorStack = error instanceof Error ? error.stack : void 0;
@@ -15049,7 +15558,7 @@ function createServerHookErrorMessage(error, hookType, routePattern, filePath) {
15049
15558
  message += `Route: ${routePattern}
15050
15559
  `;
15051
15560
  if (filePath) {
15052
- const relativePath = path19.relative(process.cwd(), filePath);
15561
+ const relativePath = path21.relative(process.cwd(), filePath);
15053
15562
  message += `File: ${relativePath}
15054
15563
  `;
15055
15564
  }
@@ -15110,7 +15619,9 @@ function handleDataResponse(res, loaderResult, theme, layoutProps, pageProps, er
15110
15619
  // Combined props for backward compatibility
15111
15620
  props: loaderResult.props ?? {},
15112
15621
  metadata: loaderResult.metadata ?? null,
15113
- theme: loaderResult.theme ?? theme ?? null
15622
+ theme: loaderResult.theme ?? theme ?? null,
15623
+ // Include pathname if provided (for rewrites - client needs to know the rewritten path)
15624
+ ...loaderResult.pathname ? { pathname: loaderResult.pathname } : {}
15114
15625
  };
15115
15626
  if (layoutProps !== void 0 && layoutProps !== null) {
15116
15627
  response.layoutProps = layoutProps;
@@ -15142,24 +15653,24 @@ function handleNotFound(res, urlPath) {
15142
15653
  }
15143
15654
 
15144
15655
  // modules/server/handlers/ssg.ts
15145
- import fs16 from "fs";
15146
- import path20 from "path";
15656
+ import fs18 from "fs";
15657
+ import path22 from "path";
15147
15658
  var logger3 = createModuleLogger("ssg");
15148
15659
  function getSsgDirForPath(baseDir, urlPath) {
15149
15660
  const clean = urlPath === "/" ? "" : urlPath.replace(/^\/+/, "");
15150
- return path20.join(baseDir, clean);
15661
+ return path22.join(baseDir, clean);
15151
15662
  }
15152
15663
  function getSsgHtmlPath(baseDir, urlPath) {
15153
15664
  const dir = getSsgDirForPath(baseDir, urlPath);
15154
- return path20.join(dir, "index.html");
15665
+ return path22.join(dir, "index.html");
15155
15666
  }
15156
15667
  function getSsgDataPath(baseDir, urlPath) {
15157
15668
  const dir = getSsgDirForPath(baseDir, urlPath);
15158
- return path20.join(dir, "data.json");
15669
+ return path22.join(dir, "data.json");
15159
15670
  }
15160
15671
  function tryServeSsgHtml(res, ssgOutDir, urlPath) {
15161
15672
  const ssgHtmlPath = getSsgHtmlPath(ssgOutDir, urlPath);
15162
- if (!fs16.existsSync(ssgHtmlPath)) {
15673
+ if (!fs18.existsSync(ssgHtmlPath)) {
15163
15674
  return false;
15164
15675
  }
15165
15676
  logger3.info("Serving SSG HTML", { urlPath, ssgHtmlPath });
@@ -15169,17 +15680,17 @@ function tryServeSsgHtml(res, ssgOutDir, urlPath) {
15169
15680
  );
15170
15681
  res.statusCode = 200;
15171
15682
  res.setHeader("Content-Type", "text/html; charset=utf-8");
15172
- const stream = fs16.createReadStream(ssgHtmlPath, { encoding: "utf-8" });
15683
+ const stream = fs18.createReadStream(ssgHtmlPath, { encoding: "utf-8" });
15173
15684
  stream.pipe(res);
15174
15685
  return true;
15175
15686
  }
15176
15687
  function tryServeSsgData(res, ssgOutDir, urlPath) {
15177
15688
  const ssgDataPath = getSsgDataPath(ssgOutDir, urlPath);
15178
- if (!fs16.existsSync(ssgDataPath)) {
15689
+ if (!fs18.existsSync(ssgDataPath)) {
15179
15690
  return false;
15180
15691
  }
15181
15692
  try {
15182
- const raw = fs16.readFileSync(ssgDataPath, "utf-8");
15693
+ const raw = fs18.readFileSync(ssgDataPath, "utf-8");
15183
15694
  res.setHeader("Content-Type", "application/json; charset=utf-8");
15184
15695
  res.status(200).end(raw);
15185
15696
  return true;
@@ -15191,7 +15702,7 @@ function tryServeSsgData(res, ssgOutDir, urlPath) {
15191
15702
 
15192
15703
  // modules/server/handlers/pages.ts
15193
15704
  init_globals();
15194
- import path21 from "path";
15705
+ import path23 from "path";
15195
15706
  function mergeMetadata(base, override) {
15196
15707
  if (!base && !override) return null;
15197
15708
  if (!base) return override;
@@ -15258,8 +15769,43 @@ async function handlePageRequestInternal(options) {
15258
15769
  ssgOutDir,
15259
15770
  theme,
15260
15771
  projectRoot,
15261
- config
15772
+ config,
15773
+ rewriteLoader
15262
15774
  } = options;
15775
+ let finalUrlPath = urlPath;
15776
+ let extractedParams = {};
15777
+ if (rewriteLoader) {
15778
+ try {
15779
+ const compiledRewrites = await rewriteLoader.loadRewrites();
15780
+ const rewriteResult = await processRewrites(urlPath, compiledRewrites, req);
15781
+ if (rewriteResult) {
15782
+ finalUrlPath = rewriteResult.rewrittenPath;
15783
+ extractedParams = rewriteResult.extractedParams;
15784
+ finalUrlPath = finalUrlPath.replace(/\/+/g, "/").replace(/^([^/])/, "/$1").replace(/\/$/, "") || "/";
15785
+ if (env === "dev") {
15786
+ const reqLogger2 = getRequestLogger(req);
15787
+ reqLogger2.debug("Rewrite applied", {
15788
+ originalPath: urlPath,
15789
+ rewrittenPath: finalUrlPath,
15790
+ extractedParams,
15791
+ host: req.get("host")
15792
+ });
15793
+ }
15794
+ Object.assign(req.query, extractedParams);
15795
+ if (!req.locals) {
15796
+ req.locals = {};
15797
+ }
15798
+ Object.assign(req.locals, extractedParams);
15799
+ }
15800
+ } catch (error) {
15801
+ const reqLogger2 = getRequestLogger(req);
15802
+ reqLogger2.error("Error processing rewrites", error, {
15803
+ urlPath,
15804
+ host: req.get("host")
15805
+ });
15806
+ }
15807
+ }
15808
+ finalUrlPath = finalUrlPath.replace(/\/$/, "") || "/";
15263
15809
  const clientJsPath = env === "dev" ? "/static/client.js" : projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
15264
15810
  const clientCssPath = env === "dev" ? "/static/client.css" : projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
15265
15811
  const assetManifest = env === "prod" && projectRoot ? loadAssetManifest(projectRoot) : null;
@@ -15268,18 +15814,43 @@ async function handlePageRequestInternal(options) {
15268
15814
  const skipLayoutHooks = isDataReq && req.headers["x-skip-layout-hooks"] === "true";
15269
15815
  if (env === "prod" && ssgOutDir) {
15270
15816
  if (isDataReq) {
15271
- if (tryServeSsgData(res, ssgOutDir, urlPath)) {
15817
+ if (tryServeSsgData(res, ssgOutDir, finalUrlPath)) {
15272
15818
  return;
15273
15819
  }
15274
15820
  } else {
15275
- if (tryServeSsgHtml(res, ssgOutDir, urlPath)) {
15821
+ if (tryServeSsgHtml(res, ssgOutDir, finalUrlPath)) {
15276
15822
  return;
15277
15823
  }
15278
15824
  }
15279
15825
  }
15280
- const matched = matchRoute(routes, urlPath);
15826
+ const matched = matchRoute(routes, finalUrlPath);
15827
+ if (env === "dev") {
15828
+ const reqLogger2 = getRequestLogger(req);
15829
+ if (finalUrlPath !== urlPath) {
15830
+ reqLogger2.debug("Route matching after rewrite", {
15831
+ originalPath: urlPath,
15832
+ rewrittenPath: finalUrlPath,
15833
+ matched: !!matched,
15834
+ matchedRoute: matched?.route.pattern,
15835
+ matchedParams: matched?.params,
15836
+ availableRoutes: routes.slice(0, 10).map((r) => r.pattern)
15837
+ // Show first 10 routes
15838
+ });
15839
+ } else if (!matched) {
15840
+ reqLogger2.debug("No route match found", {
15841
+ path: finalUrlPath,
15842
+ availableRoutes: routes.slice(0, 10).map((r) => r.pattern)
15843
+ });
15844
+ }
15845
+ }
15281
15846
  const routerData = buildRouterData(req);
15282
15847
  if (!matched) {
15848
+ if (isDataReq) {
15849
+ res.statusCode = 404;
15850
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
15851
+ res.end(JSON.stringify({ notFound: true, pathname: finalUrlPath }));
15852
+ return;
15853
+ }
15283
15854
  if (notFoundPage) {
15284
15855
  const ctx2 = {
15285
15856
  req,
@@ -15303,7 +15874,7 @@ async function handlePageRequestInternal(options) {
15303
15874
  } catch (error) {
15304
15875
  const reqLogger2 = getRequestLogger(req);
15305
15876
  const layoutFile = notFoundPage.layoutFiles[i];
15306
- const relativeLayoutPath = layoutFile ? path21.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
15877
+ const relativeLayoutPath = layoutFile ? path23.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
15307
15878
  reqLogger2.error("Layout middleware failed for not-found page", error instanceof Error ? error : new Error(String(error)), {
15308
15879
  layoutIndex: i,
15309
15880
  layoutFile: relativeLayoutPath
@@ -15324,7 +15895,7 @@ async function handlePageRequestInternal(options) {
15324
15895
  } catch (error) {
15325
15896
  const reqLogger2 = getRequestLogger(req);
15326
15897
  const layoutFile = notFoundPage.layoutFiles[i];
15327
- const relativeLayoutPath = layoutFile ? path21.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
15898
+ const relativeLayoutPath = layoutFile ? path23.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
15328
15899
  reqLogger2.warn("Layout server hook failed for not-found page", {
15329
15900
  error: error instanceof Error ? error.message : String(error),
15330
15901
  stack: error instanceof Error ? error.stack : void 0,
@@ -15358,7 +15929,7 @@ async function handlePageRequestInternal(options) {
15358
15929
  );
15359
15930
  return;
15360
15931
  }
15361
- const initialData2 = buildInitialData(urlPath, {}, combinedLoaderResult2);
15932
+ const initialData2 = buildInitialData(finalUrlPath, {}, combinedLoaderResult2);
15362
15933
  const appTree2 = buildAppTree(notFoundPage, {}, initialData2.props);
15363
15934
  initialData2.notFound = true;
15364
15935
  const nonce2 = res.locals.nonce || void 0;
@@ -15444,7 +16015,7 @@ async function handlePageRequestInternal(options) {
15444
16015
  );
15445
16016
  } catch (error) {
15446
16017
  const layoutFile = route.layoutFiles[i];
15447
- const relativeLayoutPath = layoutFile ? path21.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
16018
+ const relativeLayoutPath = layoutFile ? path23.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
15448
16019
  reqLogger.error("Layout middleware failed", error instanceof Error ? error : new Error(String(error)), {
15449
16020
  route: route.pattern,
15450
16021
  layoutIndex: i,
@@ -15468,7 +16039,7 @@ async function handlePageRequestInternal(options) {
15468
16039
  }
15469
16040
  } catch (error) {
15470
16041
  const layoutFile = route.layoutFiles[i];
15471
- const relativeLayoutPath = layoutFile ? path21.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
16042
+ const relativeLayoutPath = layoutFile ? path23.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
15472
16043
  reqLogger.warn("Layout server hook failed", {
15473
16044
  error: error instanceof Error ? error.message : String(error),
15474
16045
  stack: error instanceof Error ? error.stack : void 0,
@@ -15488,7 +16059,7 @@ async function handlePageRequestInternal(options) {
15488
16059
  loaderResult.theme = theme;
15489
16060
  }
15490
16061
  } catch (error) {
15491
- const relativePagePath = route.pageFile ? path21.relative(projectRoot || process.cwd(), route.pageFile) : "unknown";
16062
+ const relativePagePath = route.pageFile ? path23.relative(projectRoot || process.cwd(), route.pageFile) : "unknown";
15492
16063
  reqLogger.error("Page server hook failed", {
15493
16064
  error: error instanceof Error ? error.message : String(error),
15494
16065
  stack: error instanceof Error ? error.stack : void 0,
@@ -15535,7 +16106,9 @@ async function handlePageRequestInternal(options) {
15535
16106
  const combinedLoaderResult = {
15536
16107
  ...loaderResult,
15537
16108
  props: combinedProps,
15538
- metadata: combinedMetadata
16109
+ metadata: combinedMetadata,
16110
+ pathname: finalUrlPath
16111
+ // Include rewritten pathname for client-side matching
15539
16112
  };
15540
16113
  if (isDataReq) {
15541
16114
  const pagePropsOnly = loaderResult.props || {};
@@ -15560,7 +16133,7 @@ async function handlePageRequestInternal(options) {
15560
16133
  }
15561
16134
  return;
15562
16135
  }
15563
- const initialData = buildInitialData(urlPath, params, combinedLoaderResult);
16136
+ const initialData = buildInitialData(finalUrlPath, params, combinedLoaderResult);
15564
16137
  const appTree = buildAppTree(route, params, initialData.props);
15565
16138
  const chunkName = routeChunks[route.pattern];
15566
16139
  let chunkHref = null;
@@ -15665,7 +16238,7 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
15665
16238
  );
15666
16239
  } catch (error2) {
15667
16240
  const layoutFile = errorPage.layoutFiles[i];
15668
- const relativeLayoutPath = layoutFile ? path21.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
16241
+ const relativeLayoutPath = layoutFile ? path23.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
15669
16242
  reqLogger.error("Layout middleware failed for error page", error2 instanceof Error ? error2 : new Error(String(error2)), {
15670
16243
  layoutIndex: i,
15671
16244
  layoutFile: relativeLayoutPath
@@ -15685,7 +16258,7 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
15685
16258
  }
15686
16259
  } catch (err) {
15687
16260
  const layoutFile = errorPage.layoutFiles[i];
15688
- const relativeLayoutPath = layoutFile ? path21.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
16261
+ const relativeLayoutPath = layoutFile ? path23.relative(projectRoot || process.cwd(), layoutFile) : "unknown";
15689
16262
  reqLogger.warn("Layout server hook failed for error page", {
15690
16263
  error: err instanceof Error ? err.message : String(err),
15691
16264
  stack: err instanceof Error ? err.stack : void 0,
@@ -15961,7 +16534,19 @@ function validateRealtimeConfig(config) {
15961
16534
  }
15962
16535
 
15963
16536
  // modules/server/routes.ts
15964
- import path22 from "path";
16537
+ import path24 from "path";
16538
+ var cachedRewriteLoader = null;
16539
+ var cachedProjectRoot = null;
16540
+ var cachedIsDev = null;
16541
+ function getRewriteLoader(projectRoot, isDev) {
16542
+ if (cachedRewriteLoader && cachedProjectRoot === projectRoot && cachedIsDev === isDev) {
16543
+ return cachedRewriteLoader;
16544
+ }
16545
+ cachedRewriteLoader = createRewriteLoader(projectRoot, isDev);
16546
+ cachedProjectRoot = projectRoot;
16547
+ cachedIsDev = isDev;
16548
+ return cachedRewriteLoader;
16549
+ }
15965
16550
  function setupRoutes(options) {
15966
16551
  const {
15967
16552
  app,
@@ -15976,8 +16561,9 @@ function setupRoutes(options) {
15976
16561
  config
15977
16562
  } = options;
15978
16563
  const routeChunks = routeLoader.loadRouteChunks();
15979
- const ssgOutDir = path22.join(
15980
- config ? getBuildDir(projectRoot, config) : path22.join(projectRoot, BUILD_FOLDER_NAME),
16564
+ const rewriteLoader = getRewriteLoader(projectRoot, isDev);
16565
+ const ssgOutDir = path24.join(
16566
+ config ? getBuildDir(projectRoot, config) : path24.join(projectRoot, BUILD_FOLDER_NAME),
15981
16567
  "ssg"
15982
16568
  );
15983
16569
  app.all("/api/*", async (req, res) => {
@@ -15992,7 +16578,8 @@ function setupRoutes(options) {
15992
16578
  res,
15993
16579
  env: isDev ? "dev" : "prod",
15994
16580
  strictRateLimitPatterns: strictPatterns,
15995
- rateLimitConfig
16581
+ rateLimitConfig,
16582
+ rewriteLoader
15996
16583
  });
15997
16584
  });
15998
16585
  app.get("*", async (req, res) => {
@@ -16015,7 +16602,8 @@ function setupRoutes(options) {
16015
16602
  ssgOutDir,
16016
16603
  theme: req.cookies?.theme || "light",
16017
16604
  projectRoot,
16018
- config
16605
+ config,
16606
+ rewriteLoader
16019
16607
  });
16020
16608
  });
16021
16609
  }
@@ -17204,8 +17792,8 @@ var setupApplication = async ({
17204
17792
 
17205
17793
  // src/server.ts
17206
17794
  import dotenv2 from "dotenv";
17207
- var envPath = path23.join(process.cwd(), ".env");
17208
- if (fs17.existsSync(envPath)) {
17795
+ var envPath = path25.join(process.cwd(), ".env");
17796
+ if (fs19.existsSync(envPath)) {
17209
17797
  dotenv2.config({ path: envPath });
17210
17798
  } else {
17211
17799
  dotenv2.config();
@@ -17226,8 +17814,8 @@ async function startServer(options = {}) {
17226
17814
  }
17227
17815
  const port = options.port ?? (process.env.PORT ? parseInt(process.env.PORT, 10) : void 0) ?? config.server.port;
17228
17816
  const host = process.env.HOST ?? (!isDev ? "0.0.0.0" : void 0) ?? config.server.host;
17229
- const appDir = options.appDir ?? (isDev ? getAppDir(projectRoot, config) : path23.join(getBuildDir(projectRoot, config), "server"));
17230
- if (!isDev && !fs17.existsSync(appDir)) {
17817
+ const appDir = options.appDir ?? (isDev ? getAppDir(projectRoot, config) : path25.join(getBuildDir(projectRoot, config), "server"));
17818
+ if (!isDev && !fs19.existsSync(appDir)) {
17231
17819
  logger4.error("Compiled directory not found", void 0, {
17232
17820
  buildDir: config.directories.build,
17233
17821
  appDir,
@@ -17298,10 +17886,10 @@ async function startProdServer(options = {}) {
17298
17886
  }
17299
17887
 
17300
17888
  // modules/build/ssg/builder.ts
17301
- import path26 from "path";
17889
+ import path28 from "path";
17302
17890
 
17303
17891
  // modules/build/ssg/path.ts
17304
- import path24 from "path";
17892
+ import path26 from "path";
17305
17893
  function buildPathFromPattern(pattern, params) {
17306
17894
  const segments = pattern.split("/").filter(Boolean);
17307
17895
  const parts = [];
@@ -17330,12 +17918,12 @@ function buildPathFromPattern(pattern, params) {
17330
17918
  }
17331
17919
  function pathToOutDir(baseDir, urlPath) {
17332
17920
  const clean = urlPath === "/" ? "" : urlPath.replace(/^\/+/, "");
17333
- return path24.join(baseDir, clean);
17921
+ return path26.join(baseDir, clean);
17334
17922
  }
17335
17923
 
17336
17924
  // modules/build/ssg/renderer.ts
17337
- import fs18 from "fs";
17338
- import path25 from "path";
17925
+ import fs20 from "fs";
17926
+ import path27 from "path";
17339
17927
  import { renderToString } from "react-dom/server";
17340
17928
  init_globals();
17341
17929
  async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params, config) {
@@ -17459,16 +18047,16 @@ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params,
17459
18047
  const html = "<!DOCTYPE html>" + renderToString(documentTree);
17460
18048
  const dir = pathToOutDir(ssgOutDir, urlPath);
17461
18049
  ensureDir(dir);
17462
- const htmlFile = path25.join(dir, "index.html");
17463
- const dataFile = path25.join(dir, "data.json");
17464
- fs18.writeFileSync(htmlFile, html, "utf-8");
17465
- fs18.writeFileSync(dataFile, JSON.stringify(initialData, null, 2), "utf-8");
18050
+ const htmlFile = path27.join(dir, "index.html");
18051
+ const dataFile = path27.join(dir, "data.json");
18052
+ fs20.writeFileSync(htmlFile, html, "utf-8");
18053
+ fs20.writeFileSync(dataFile, JSON.stringify(initialData, null, 2), "utf-8");
17466
18054
  }
17467
18055
 
17468
18056
  // modules/build/ssg/builder.ts
17469
18057
  init_globals();
17470
18058
  async function buildStaticPages(projectRoot, routes, config) {
17471
- const ssgOutDir = path26.join(projectRoot, BUILD_FOLDER_NAME, "ssg");
18059
+ const ssgOutDir = path28.join(projectRoot, BUILD_FOLDER_NAME, "ssg");
17472
18060
  ensureDir(ssgOutDir);
17473
18061
  for (const route of routes) {
17474
18062
  if (route.dynamic !== "force-static") continue;
@@ -17523,36 +18111,36 @@ async function buildStaticPages(projectRoot, routes, config) {
17523
18111
  }
17524
18112
 
17525
18113
  // modules/build/bundler/server.ts
17526
- import path27 from "path";
17527
- import fs19 from "fs";
18114
+ import path29 from "path";
18115
+ import fs21 from "fs";
17528
18116
  import esbuild from "esbuild";
17529
18117
  init_globals();
17530
18118
  var SERVER_FILES = [INIT_FILE_NAME, CONFIG_FILE_NAME];
17531
18119
  function createPathAliasPlugin(projectRoot, outDir) {
17532
18120
  const aliases = loadAliasesFromTsconfig(projectRoot);
17533
- const tsconfigPath = path27.join(projectRoot, "tsconfig.json");
18121
+ const tsconfigPath = path29.join(projectRoot, "tsconfig.json");
17534
18122
  let baseUrl = ".";
17535
- if (fs19.existsSync(tsconfigPath)) {
18123
+ if (fs21.existsSync(tsconfigPath)) {
17536
18124
  try {
17537
- const tsconfig = JSON.parse(fs19.readFileSync(tsconfigPath, "utf-8"));
18125
+ const tsconfig = JSON.parse(fs21.readFileSync(tsconfigPath, "utf-8"));
17538
18126
  baseUrl = tsconfig.compilerOptions?.baseUrl ?? ".";
17539
18127
  } catch {
17540
18128
  }
17541
18129
  }
17542
18130
  function resolveAliasToRelative(importPath, sourceFile) {
17543
- if (importPath.startsWith(".") || importPath.startsWith("/") || path27.isAbsolute(importPath) || importPath.includes("node_modules")) {
18131
+ if (importPath.startsWith(".") || importPath.startsWith("/") || path29.isAbsolute(importPath) || importPath.includes("node_modules")) {
17544
18132
  return null;
17545
18133
  }
17546
18134
  for (const [aliasKey, aliasPath] of Object.entries(aliases)) {
17547
18135
  if (importPath.startsWith(aliasKey + "/") || importPath === aliasKey) {
17548
18136
  const restPath = importPath.startsWith(aliasKey + "/") ? importPath.slice(aliasKey.length + 1) : "";
17549
- const resolvedPath = restPath ? path27.join(aliasPath, restPath) : aliasPath;
18137
+ const resolvedPath = restPath ? path29.join(aliasPath, restPath) : aliasPath;
17550
18138
  let actualPath = null;
17551
18139
  const extensions = [".ts", ".tsx", ".js", ".jsx", ".json"];
17552
- if (fs19.existsSync(resolvedPath) && fs19.statSync(resolvedPath).isDirectory()) {
18140
+ if (fs21.existsSync(resolvedPath) && fs21.statSync(resolvedPath).isDirectory()) {
17553
18141
  for (const ext of extensions) {
17554
- const indexPath = path27.join(resolvedPath, `index${ext}`);
17555
- if (fs19.existsSync(indexPath)) {
18142
+ const indexPath = path29.join(resolvedPath, `index${ext}`);
18143
+ if (fs21.existsSync(indexPath)) {
17556
18144
  actualPath = indexPath;
17557
18145
  break;
17558
18146
  }
@@ -17560,20 +18148,20 @@ function createPathAliasPlugin(projectRoot, outDir) {
17560
18148
  } else {
17561
18149
  for (const ext of extensions) {
17562
18150
  const filePath = resolvedPath + ext;
17563
- if (fs19.existsSync(filePath)) {
18151
+ if (fs21.existsSync(filePath)) {
17564
18152
  actualPath = filePath;
17565
18153
  break;
17566
18154
  }
17567
18155
  }
17568
- if (!actualPath && fs19.existsSync(resolvedPath)) {
18156
+ if (!actualPath && fs21.existsSync(resolvedPath)) {
17569
18157
  actualPath = resolvedPath;
17570
18158
  }
17571
18159
  }
17572
18160
  if (actualPath) {
17573
- const relativePath = path27.relative(outDir, actualPath);
18161
+ const relativePath = path29.relative(outDir, actualPath);
17574
18162
  const normalizedPath = relativePath.replace(/\\/g, "/");
17575
18163
  const finalPath = normalizedPath.startsWith(".") ? normalizedPath : `./${normalizedPath}`;
17576
- const ext = path27.extname(finalPath);
18164
+ const ext = path29.extname(finalPath);
17577
18165
  const pathWithoutExt = ext === ".json" ? finalPath : finalPath.slice(0, -ext.length);
17578
18166
  return pathWithoutExt;
17579
18167
  }
@@ -17585,13 +18173,13 @@ function createPathAliasPlugin(projectRoot, outDir) {
17585
18173
  name: "path-alias-resolver",
17586
18174
  setup(build) {
17587
18175
  build.onLoad({ filter: /\.(ts|tsx|js|jsx)$/ }, (args) => {
17588
- const fileName = path27.basename(args.path);
18176
+ const fileName = path29.basename(args.path);
17589
18177
  const isServerFile = SERVER_FILES.some((f) => fileName === `${f}.ts` || fileName === `${f}.tsx` || fileName === `${f}.js` || fileName === `${f}.jsx`);
17590
- const isInProjectRoot = path27.dirname(args.path) === projectRoot;
18178
+ const isInProjectRoot = path29.dirname(args.path) === projectRoot;
17591
18179
  if (!isServerFile || !isInProjectRoot) {
17592
18180
  return null;
17593
18181
  }
17594
- const contents = fs19.readFileSync(args.path, "utf-8");
18182
+ const contents = fs21.readFileSync(args.path, "utf-8");
17595
18183
  let transformed = contents;
17596
18184
  const aliasPatterns = Object.keys(aliases).sort((a, b) => b.length - a.length);
17597
18185
  for (const aliasKey of aliasPatterns) {
@@ -17611,7 +18199,7 @@ function createPathAliasPlugin(projectRoot, outDir) {
17611
18199
  }
17612
18200
  return {
17613
18201
  contents: transformed,
17614
- loader: path27.extname(args.path).slice(1)
18202
+ loader: path29.extname(args.path).slice(1)
17615
18203
  };
17616
18204
  });
17617
18205
  build.onResolve({ filter: /.*/ }, (args) => {
@@ -17630,9 +18218,9 @@ function createPathAliasPlugin(projectRoot, outDir) {
17630
18218
  function collectAppSources(appDir) {
17631
18219
  const entries = [];
17632
18220
  function walk(dir) {
17633
- const items = fs19.readdirSync(dir, { withFileTypes: true });
18221
+ const items = fs21.readdirSync(dir, { withFileTypes: true });
17634
18222
  for (const item of items) {
17635
- const full = path27.join(dir, item.name);
18223
+ const full = path29.join(dir, item.name);
17636
18224
  if (item.isDirectory()) {
17637
18225
  walk(full);
17638
18226
  continue;
@@ -17649,7 +18237,7 @@ function collectAppSources(appDir) {
17649
18237
  return entries;
17650
18238
  }
17651
18239
  async function buildServerApp(projectRoot, appDir) {
17652
- const outDir = path27.join(projectRoot, BUILD_FOLDER_NAME, "server");
18240
+ const outDir = path29.join(projectRoot, BUILD_FOLDER_NAME, "server");
17653
18241
  const entryPoints = collectAppSources(appDir);
17654
18242
  ensureDir(outDir);
17655
18243
  if (entryPoints.length === 0) {
@@ -17667,14 +18255,14 @@ async function buildServerApp(projectRoot, appDir) {
17667
18255
  bundle: true,
17668
18256
  splitting: false,
17669
18257
  logLevel: "info",
17670
- tsconfig: path27.join(projectRoot, "tsconfig.json"),
18258
+ tsconfig: path29.join(projectRoot, "tsconfig.json"),
17671
18259
  packages: "external"
17672
18260
  });
17673
18261
  const pathAliasPlugin = createPathAliasPlugin(projectRoot, outDir);
17674
18262
  for (const fileName of SERVER_FILES) {
17675
- const initTS = path27.join(projectRoot, `${fileName}.ts`);
17676
- const initJS = path27.join(outDir, `${fileName}.js`);
17677
- if (fs19.existsSync(initTS)) {
18263
+ const initTS = path29.join(projectRoot, `${fileName}.ts`);
18264
+ const initJS = path29.join(outDir, `${fileName}.js`);
18265
+ if (fs21.existsSync(initTS)) {
17678
18266
  await esbuild.build({
17679
18267
  entryPoints: [initTS],
17680
18268
  outfile: initJS,
@@ -17685,7 +18273,7 @@ async function buildServerApp(projectRoot, appDir) {
17685
18273
  sourcemap: true,
17686
18274
  bundle: false,
17687
18275
  logLevel: "info",
17688
- tsconfig: path27.join(projectRoot, "tsconfig.json"),
18276
+ tsconfig: path29.join(projectRoot, "tsconfig.json"),
17689
18277
  plugins: [pathAliasPlugin]
17690
18278
  });
17691
18279
  }
@@ -17736,6 +18324,7 @@ async function buildApp(options = {}) {
17736
18324
  });
17737
18325
  writeClientBoostrapManifest(projectRoot);
17738
18326
  writeClientRoutesManifest(routes, projectRoot);
18327
+ await writeRewritesManifest(projectRoot);
17739
18328
  await buildClientBundle(projectRoot);
17740
18329
  await buildStaticPages(projectRoot, routes, config);
17741
18330
  delete process.env.LOLY_BUILD;
@@ -18444,13 +19033,22 @@ async function handleNormalRoute(nextUrl, json, routes, setState) {
18444
19033
  theme
18445
19034
  // Always include theme
18446
19035
  };
18447
- const matched = matchRouteClient(nextUrl, routes);
19036
+ const pathnameForMatch = json.pathname || nextUrl;
19037
+ let matched = matchRouteClient(pathnameForMatch, routes);
19038
+ if (!matched) {
19039
+ matched = matchRouteClient(nextUrl, routes);
19040
+ }
18448
19041
  if (!matched) {
19042
+ console.warn(
19043
+ `[client] Server returned data for ${nextUrl} but no route match found. Available routes:`,
19044
+ routes.map((r) => r.pattern)
19045
+ );
18449
19046
  window.location.href = nextUrl;
18450
19047
  return false;
18451
19048
  }
19049
+ const finalPathname = json.pathname || nextUrl;
18452
19050
  const windowData = {
18453
- pathname: nextUrl,
19051
+ pathname: finalPathname,
18454
19052
  params: matched.params,
18455
19053
  props: combinedProps,
18456
19054
  metadata: json.metadata ?? null,
@@ -18849,8 +19447,9 @@ function initializeRouterData(initialUrl, initialData) {
18849
19447
  let routerData = getRouterData();
18850
19448
  if (!routerData) {
18851
19449
  const url = new URL(initialUrl, window.location.origin);
19450
+ const pathname = initialData?.pathname || url.pathname;
18852
19451
  routerData = {
18853
- pathname: url.pathname,
19452
+ pathname,
18854
19453
  params: initialData?.params || {},
18855
19454
  searchParams: Object.fromEntries(url.searchParams.entries())
18856
19455
  };
@@ -18909,11 +19508,12 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
18909
19508
  return;
18910
19509
  }
18911
19510
  const initialData = getWindowData();
18912
- const initialUrl = window.location.pathname + window.location.search;
19511
+ const initialUrl = (initialData?.pathname || window.location.pathname) + window.location.search;
18913
19512
  if (initialData?.props) {
18914
19513
  setPreservedLayoutProps(initialData.props);
18915
19514
  }
18916
- initializeRouterData(initialUrl, initialData);
19515
+ const routerPathname = initialData?.pathname || window.location.pathname;
19516
+ initializeRouterData(routerPathname + window.location.search, initialData);
18917
19517
  await hydrateInitialRoute(
18918
19518
  container,
18919
19519
  initialUrl,
@@ -18960,11 +19560,11 @@ var ValidationError = class extends Error {
18960
19560
  format() {
18961
19561
  const formatted = {};
18962
19562
  for (const error of this.errors) {
18963
- const path28 = error.path.join(".");
18964
- if (!formatted[path28]) {
18965
- formatted[path28] = [];
19563
+ const path30 = error.path.join(".");
19564
+ if (!formatted[path30]) {
19565
+ formatted[path30] = [];
18966
19566
  }
18967
- formatted[path28].push(error.message);
19567
+ formatted[path30].push(error.message);
18968
19568
  }
18969
19569
  return formatted;
18970
19570
  }