@rangojs/router 0.0.0-experimental.110 → 0.0.0-experimental.112

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.
Files changed (65) hide show
  1. package/dist/bin/rango.js +41 -37
  2. package/dist/vite/index.js +144 -191
  3. package/package.json +17 -14
  4. package/skills/handler-use/SKILL.md +1 -1
  5. package/skills/rango/SKILL.md +20 -0
  6. package/src/browser/action-coordinator.ts +53 -36
  7. package/src/browser/event-controller.ts +42 -66
  8. package/src/browser/navigation-bridge.ts +4 -0
  9. package/src/browser/navigation-client.ts +12 -15
  10. package/src/browser/navigation-store.ts +7 -8
  11. package/src/browser/navigation-transaction.ts +7 -21
  12. package/src/browser/partial-update.ts +8 -16
  13. package/src/browser/react/NavigationProvider.tsx +29 -40
  14. package/src/browser/react/use-params.ts +3 -4
  15. package/src/browser/response-adapter.ts +25 -0
  16. package/src/browser/rsc-router.tsx +16 -2
  17. package/src/browser/server-action-bridge.ts +23 -30
  18. package/src/browser/types.ts +2 -0
  19. package/src/build/generate-manifest.ts +29 -31
  20. package/src/build/generate-route-types.ts +2 -0
  21. package/src/build/route-types/router-processing.ts +37 -9
  22. package/src/build/runtime-discovery.ts +9 -20
  23. package/src/decode-loader-results.ts +36 -0
  24. package/src/errors.ts +29 -0
  25. package/src/index.rsc.ts +1 -0
  26. package/src/index.ts +1 -0
  27. package/src/response-utils.ts +9 -0
  28. package/src/route-content-wrapper.tsx +6 -28
  29. package/src/route-definition/dsl-helpers.ts +231 -259
  30. package/src/route-definition/helper-factories.ts +29 -139
  31. package/src/route-definition/use-item-types.ts +32 -0
  32. package/src/route-types.ts +19 -41
  33. package/src/router/content-negotiation.ts +15 -2
  34. package/src/router/intercept-resolution.ts +4 -18
  35. package/src/router/match-result.ts +32 -30
  36. package/src/router/middleware.ts +46 -78
  37. package/src/router/preview-match.ts +3 -1
  38. package/src/router/request-classification.ts +4 -28
  39. package/src/rsc/handler.ts +20 -65
  40. package/src/rsc/helpers.ts +3 -2
  41. package/src/rsc/origin-guard.ts +28 -10
  42. package/src/rsc/response-route-handler.ts +32 -52
  43. package/src/rsc/rsc-rendering.ts +27 -53
  44. package/src/rsc/runtime-warnings.ts +9 -10
  45. package/src/rsc/server-action.ts +13 -37
  46. package/src/rsc/ssr-setup.ts +16 -0
  47. package/src/segment-system.tsx +5 -39
  48. package/src/server/context.ts +76 -35
  49. package/src/urls/include-helper.ts +10 -53
  50. package/src/urls/index.ts +0 -3
  51. package/src/urls/path-helper.ts +17 -52
  52. package/src/urls/pattern-types.ts +2 -19
  53. package/src/urls/response-types.ts +20 -19
  54. package/src/urls/type-extraction.ts +20 -115
  55. package/src/urls/urls-function.ts +1 -5
  56. package/src/vite/discovery/discover-routers.ts +10 -22
  57. package/src/vite/discovery/route-types-writer.ts +38 -82
  58. package/src/vite/plugins/cjs-to-esm.ts +3 -7
  59. package/src/vite/plugins/expose-ids/handler-transform.ts +8 -61
  60. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -5
  61. package/src/vite/plugins/expose-internal-ids.ts +34 -62
  62. package/src/vite/plugins/version-injector.ts +2 -12
  63. package/src/vite/router-discovery.ts +71 -26
  64. package/src/vite/utils/shared-utils.ts +13 -1
  65. package/src/browser/action-response-classifier.ts +0 -99
@@ -465,7 +465,7 @@ function exposeActionId() {
465
465
 
466
466
  // src/vite/plugins/expose-internal-ids.ts
467
467
  import { parseAst as parseAst2 } from "vite";
468
- import MagicString4 from "magic-string";
468
+ import MagicString3 from "magic-string";
469
469
  import path4 from "node:path";
470
470
 
471
471
  // src/vite/utils/ast-handler-extract.ts
@@ -960,7 +960,7 @@ function generateClientLoaderStubs(bindings, code, filePath, isBuild) {
960
960
  const lines = [];
961
961
  for (const binding of bindings) {
962
962
  for (const name of binding.exportNames) {
963
- const loaderId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
963
+ const loaderId = makeStubId(filePath, name, isBuild);
964
964
  lines.push(
965
965
  `export const ${name} = { __brand: "loader", $$id: "${loaderId}" };`
966
966
  );
@@ -972,7 +972,7 @@ function transformLoaders(bindings, s, filePath, isBuild) {
972
972
  let hasChanges = false;
973
973
  for (const binding of bindings) {
974
974
  const exportName = binding.exportNames[0];
975
- const loaderId = isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
975
+ const loaderId = makeStubId(filePath, exportName, isBuild);
976
976
  const paramInjection = binding.argCount === 1 ? `, undefined, "${loaderId}"` : `, "${loaderId}"`;
977
977
  s.appendLeft(binding.callCloseParenPos, paramInjection);
978
978
  const propInjection = `
@@ -984,7 +984,6 @@ ${binding.localName}.$$id = "${loaderId}";`;
984
984
  }
985
985
 
986
986
  // src/vite/plugins/expose-ids/handler-transform.ts
987
- import MagicString2 from "magic-string";
988
987
  function analyzeCreateHandleArgs(code, startPos, endPos) {
989
988
  const content = code.slice(startPos, endPos).trim();
990
989
  return { hasArgs: content.length > 0 };
@@ -998,7 +997,7 @@ function transformHandles(bindings, s, code, filePath, isBuild) {
998
997
  binding.callOpenParenPos + 1,
999
998
  binding.callCloseParenPos
1000
999
  );
1001
- const handleId = isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
1000
+ const handleId = makeStubId(filePath, exportName, isBuild);
1002
1001
  let paramInjection;
1003
1002
  if (!args.hasArgs) {
1004
1003
  paramInjection = `undefined, "${handleId}"`;
@@ -1017,7 +1016,7 @@ function transformLocationState(bindings, s, filePath, isBuild) {
1017
1016
  let hasChanges = false;
1018
1017
  for (const binding of bindings) {
1019
1018
  const exportName = binding.exportNames[0];
1020
- const stateKey = isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
1019
+ const stateKey = makeStubId(filePath, exportName, isBuild);
1021
1020
  const propInjection = `
1022
1021
  ${binding.localName}.__rsc_ls_key = "__rsc_ls_${stateKey}";`;
1023
1022
  s.appendRight(binding.statementEnd, propInjection);
@@ -1029,7 +1028,7 @@ function generateWholeFileStubs(cfg, bindings, code, filePath, isBuild) {
1029
1028
  if (!isExportOnlyFile(code, bindings)) return null;
1030
1029
  const exportNames = bindings.flatMap((b) => b.exportNames);
1031
1030
  const stubs = exportNames.map((name) => {
1032
- const handlerId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
1031
+ const handlerId = makeStubId(filePath, name, isBuild);
1033
1032
  return `export const ${name} = { __brand: "${cfg.brand}", $$id: "${handlerId}" };`;
1034
1033
  });
1035
1034
  return { code: stubs.join("\n") + "\n", map: null };
@@ -1038,7 +1037,7 @@ function stubHandlerExprs(cfg, bindings, s, filePath, isBuild) {
1038
1037
  let hasChanges = false;
1039
1038
  for (const binding of bindings) {
1040
1039
  const exportName = binding.exportNames[0];
1041
- const handlerId = isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
1040
+ const handlerId = makeStubId(filePath, exportName, isBuild);
1042
1041
  s.overwrite(
1043
1042
  binding.callExprStart,
1044
1043
  binding.callCloseParenPos + 1,
@@ -1052,7 +1051,7 @@ function transformHandlerIds(cfg, bindings, s, filePath, isBuild) {
1052
1051
  let hasChanges = false;
1053
1052
  for (const binding of bindings) {
1054
1053
  const exportName = binding.exportNames[0];
1055
- const handlerId = isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
1054
+ const handlerId = makeStubId(filePath, exportName, isBuild);
1056
1055
  let paramInjection;
1057
1056
  if (binding.argCount === 0) {
1058
1057
  paramInjection = `undefined, "${handlerId}"`;
@@ -1071,7 +1070,7 @@ ${binding.localName}.$$id = "${handlerId}";`;
1071
1070
  }
1072
1071
 
1073
1072
  // src/vite/plugins/expose-ids/router-transform.ts
1074
- import MagicString3 from "magic-string";
1073
+ import MagicString2 from "magic-string";
1075
1074
  import path3 from "node:path";
1076
1075
  import { createHash } from "node:crypto";
1077
1076
  var debug2 = createRangoDebugger(NS.transform);
@@ -1081,10 +1080,10 @@ function transformRouter(code, filePath, routerFnNames, absolutePath) {
1081
1080
  "g"
1082
1081
  );
1083
1082
  let match;
1084
- const s = new MagicString3(code);
1083
+ const s = new MagicString2(code);
1085
1084
  let changed = false;
1086
- const basename3 = path3.basename(filePath).replace(/\.(tsx?|jsx?)$/, "");
1087
- const routeNamesImport = `./${basename3}.named-routes.gen.js`;
1085
+ const basename2 = path3.basename(filePath).replace(/\.(tsx?|jsx?)$/, "");
1086
+ const routeNamesImport = `./${basename2}.named-routes.gen.js`;
1088
1087
  const routeNamesVar = `__rsc_rn`;
1089
1088
  while ((match = pat.exec(code)) !== null) {
1090
1089
  const callStart = match.index;
@@ -1410,15 +1409,6 @@ ${lazyImports.join(",\n")}
1410
1409
  );
1411
1410
  if (wholeFile) return wholeFile;
1412
1411
  }
1413
- if (hasPrerenderHandlerCode && isRscEnv && isBuild) {
1414
- const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
1415
- const exportNames = getBindings(code, fnNames).map(
1416
- (b) => b.exportNames[0]
1417
- );
1418
- if (exportNames.length > 0) {
1419
- prerenderHandlerModules.set(id, exportNames);
1420
- }
1421
- }
1422
1412
  let changed = false;
1423
1413
  const handlerConfigs = [
1424
1414
  hasStaticHandlerCode && STATIC_CONFIG,
@@ -1431,7 +1421,7 @@ ${lazyImports.join(",\n")}
1431
1421
  const totalCalls = countCreateCallsForNames(code, fnNames);
1432
1422
  const supportedBindings = getBindings(code, fnNames).length;
1433
1423
  if (totalCalls > supportedBindings) {
1434
- const iterS = new MagicString4(code);
1424
+ const iterS = new MagicString3(code);
1435
1425
  const result = transformInlineHandlers(
1436
1426
  cfg.fnName,
1437
1427
  VIRTUAL_HANDLER_PREFIX,
@@ -1596,16 +1586,24 @@ ${lazyImports.join(",\n")}
1596
1586
  return { code: lines.join("\n") + "\n", map: null };
1597
1587
  }
1598
1588
  }
1599
- if (hasStaticHandlerCode && isRscEnv && isBuild) {
1600
- const fnNames = getFnNames(STATIC_CONFIG.fnName);
1601
- const exportNames = getBindings(code, fnNames).map(
1602
- (b) => b.exportNames[0]
1603
- );
1604
- if (exportNames.length > 0) {
1605
- staticHandlerModules.set(id, exportNames);
1589
+ if (isRscEnv && isBuild) {
1590
+ const trackTypes = [
1591
+ [
1592
+ hasPrerenderHandlerCode,
1593
+ PRERENDER_CONFIG,
1594
+ prerenderHandlerModules
1595
+ ],
1596
+ [hasStaticHandlerCode, STATIC_CONFIG, staticHandlerModules]
1597
+ ];
1598
+ for (const [has2, cfg, trackMap] of trackTypes) {
1599
+ if (!has2) continue;
1600
+ const exportNames = getBindings(code, getFnNames(cfg.fnName)).map(
1601
+ (b) => b.exportNames[0]
1602
+ );
1603
+ if (exportNames.length > 0) trackMap.set(id, exportNames);
1606
1604
  }
1607
1605
  }
1608
- const s = new MagicString4(code);
1606
+ const s = new MagicString3(code);
1609
1607
  if (hasLoaderCode) {
1610
1608
  const fnNames = getFnNames("createLoader");
1611
1609
  changed = transformLoaders(
@@ -1634,41 +1632,13 @@ ${lazyImports.join(",\n")}
1634
1632
  isBuild
1635
1633
  ) || changed;
1636
1634
  }
1637
- if (hasPrerenderHandlerCode) {
1638
- const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
1639
- const bindings = getBindings(code, fnNames);
1640
- if (isRscEnv) {
1641
- changed = transformHandlerIds(
1642
- PRERENDER_CONFIG,
1643
- bindings,
1644
- s,
1645
- filePath,
1646
- isBuild
1647
- ) || changed;
1648
- } else {
1649
- changed = stubHandlerExprs(
1650
- PRERENDER_CONFIG,
1651
- bindings,
1652
- s,
1653
- filePath,
1654
- isBuild
1655
- ) || changed;
1656
- }
1657
- }
1658
- if (hasStaticHandlerCode) {
1659
- const fnNames = getFnNames(STATIC_CONFIG.fnName);
1660
- const bindings = getBindings(code, fnNames);
1661
- if (isRscEnv) {
1662
- changed = transformHandlerIds(
1663
- STATIC_CONFIG,
1664
- bindings,
1665
- s,
1666
- filePath,
1667
- isBuild
1668
- ) || changed;
1669
- } else {
1670
- changed = stubHandlerExprs(STATIC_CONFIG, bindings, s, filePath, isBuild) || changed;
1671
- }
1635
+ const finalHandlerConfigs = [
1636
+ hasPrerenderHandlerCode && PRERENDER_CONFIG,
1637
+ hasStaticHandlerCode && STATIC_CONFIG
1638
+ ].filter((c) => !!c);
1639
+ for (const cfg of finalHandlerConfigs) {
1640
+ const bindings = getBindings(code, getFnNames(cfg.fnName));
1641
+ changed = (isRscEnv ? transformHandlerIds(cfg, bindings, s, filePath, isBuild) : stubHandlerExprs(cfg, bindings, s, filePath, isBuild)) || changed;
1672
1642
  }
1673
1643
  if (!changed) return;
1674
1644
  return {
@@ -1684,7 +1654,7 @@ ${lazyImports.join(",\n")}
1684
1654
 
1685
1655
  // src/vite/plugins/use-cache-transform.ts
1686
1656
  import path5 from "node:path";
1687
- import MagicString5 from "magic-string";
1657
+ import MagicString4 from "magic-string";
1688
1658
  var debug4 = createRangoDebugger(NS.transform);
1689
1659
  var CACHE_RUNTIME_IMPORT = "@rangojs/router/cache-runtime";
1690
1660
  var LAYOUT_TEMPLATE_PATTERN = /\/(layout|template)\.(tsx?|jsx?)$/;
@@ -1781,7 +1751,7 @@ function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLa
1781
1751
  );
1782
1752
  }
1783
1753
  if (exportNames.length === 0) {
1784
- const s = new MagicString5(code);
1754
+ const s = new MagicString4(code);
1785
1755
  const directive2 = findFileLevelDirective(ast);
1786
1756
  if (directive2) {
1787
1757
  s.overwrite(
@@ -2049,7 +2019,7 @@ import { resolve } from "node:path";
2049
2019
  // package.json
2050
2020
  var package_default = {
2051
2021
  name: "@rangojs/router",
2052
- version: "0.0.0-experimental.110",
2022
+ version: "0.0.0-experimental.112",
2053
2023
  description: "Django-inspired RSC router with composable URL patterns",
2054
2024
  keywords: [
2055
2025
  "react",
@@ -2187,6 +2157,7 @@ var package_default = {
2187
2157
  typecheck: "tsc --noEmit && tsc -p tsconfig.strict-check.json --noEmit && tsc -p tsconfig.augment-check.json --noEmit",
2188
2158
  test: "playwright test",
2189
2159
  "test:ui": "playwright test --ui",
2160
+ "test:hmr-local": "playwright test --project=dev-warmup --project=hmr-routes --project=hmr-basename --project=hmr-prerender --no-deps --workers=1",
2190
2161
  "test:unit": "vitest run",
2191
2162
  "test:unit:watch": "vitest"
2192
2163
  },
@@ -2200,6 +2171,7 @@ var package_default = {
2200
2171
  },
2201
2172
  devDependencies: {
2202
2173
  "@playwright/test": "^1.49.1",
2174
+ "@shared/e2e": "workspace:*",
2203
2175
  "@types/node": "^24.10.1",
2204
2176
  "@types/react": "catalog:",
2205
2177
  "@types/react-dom": "catalog:",
@@ -2866,19 +2838,38 @@ function extractBasenameFromRouter(code) {
2866
2838
  visit(sourceFile);
2867
2839
  return result;
2868
2840
  }
2869
- function applyBasenameToRoutes(result, basename3) {
2841
+ function applyBasenameToRoutes(result, basename2) {
2870
2842
  const prefixed = {};
2871
2843
  for (const [name, pattern] of Object.entries(result.routes)) {
2872
2844
  if (pattern === "/") {
2873
- prefixed[name] = basename3;
2874
- } else if (basename3.endsWith("/") && pattern.startsWith("/")) {
2875
- prefixed[name] = basename3 + pattern.slice(1);
2845
+ prefixed[name] = basename2;
2846
+ } else if (basename2.endsWith("/") && pattern.startsWith("/")) {
2847
+ prefixed[name] = basename2 + pattern.slice(1);
2876
2848
  } else {
2877
- prefixed[name] = basename3 + pattern;
2849
+ prefixed[name] = basename2 + pattern;
2878
2850
  }
2879
2851
  }
2880
2852
  return { routes: prefixed, searchSchemas: result.searchSchemas };
2881
2853
  }
2854
+ function genFileTsPath(sourceFile) {
2855
+ const base = pathBasename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
2856
+ return join(dirname2(sourceFile), `${base}.named-routes.gen.ts`);
2857
+ }
2858
+ function resolveSearchSchemas(publicRouteNames, runtimeSchemas, sourceFile) {
2859
+ if (runtimeSchemas && Object.keys(runtimeSchemas).length > 0) {
2860
+ return runtimeSchemas;
2861
+ }
2862
+ const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
2863
+ if (Object.keys(staticParsed.searchSchemas).length === 0) {
2864
+ return runtimeSchemas;
2865
+ }
2866
+ const filtered = {};
2867
+ for (const name of publicRouteNames) {
2868
+ const schema = staticParsed.searchSchemas[name];
2869
+ if (schema) filtered[name] = schema;
2870
+ }
2871
+ return Object.keys(filtered).length > 0 ? filtered : runtimeSchemas;
2872
+ }
2882
2873
  function buildCombinedRouteMapForRouterFile(routerFilePath) {
2883
2874
  let routerSource;
2884
2875
  try {
@@ -2891,7 +2882,7 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
2891
2882
  return { routes: {}, searchSchemas: {} };
2892
2883
  }
2893
2884
  const rawBasename = extractBasenameFromRouter(routerSource);
2894
- const basename3 = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
2885
+ const basename2 = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
2895
2886
  let result;
2896
2887
  if (extraction.kind === "inline") {
2897
2888
  result = buildCombinedRouteMapWithSearch(
@@ -2916,8 +2907,8 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
2916
2907
  result = buildCombinedRouteMapWithSearch(routerFilePath, extraction.name);
2917
2908
  }
2918
2909
  }
2919
- if (basename3) {
2920
- result = applyBasenameToRoutes(result, basename3);
2910
+ if (basename2) {
2911
+ result = applyBasenameToRoutes(result, basename2);
2921
2912
  }
2922
2913
  return result;
2923
2914
  }
@@ -2954,18 +2945,12 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
2954
2945
  }
2955
2946
  if (!extractUrlsFromRouter(routerSource)) continue;
2956
2947
  }
2957
- const routerBasename = pathBasename(routerFilePath).replace(
2958
- /\.(tsx?|jsx?)$/,
2959
- ""
2960
- );
2961
- const outPath = join(
2962
- dirname2(routerFilePath),
2963
- `${routerBasename}.named-routes.gen.ts`
2964
- );
2948
+ const outPath = genFileTsPath(routerFilePath);
2965
2949
  const existing = existsSync3(outPath) ? readFileSync2(outPath, "utf-8") : null;
2966
2950
  if (Object.keys(result.routes).length === 0) {
2967
2951
  if (!existing) {
2968
2952
  const emptySource = generateRouteTypesSource({});
2953
+ opts?.onWrite?.(outPath, emptySource);
2969
2954
  writeFileSync(outPath, emptySource);
2970
2955
  }
2971
2956
  continue;
@@ -2985,6 +2970,7 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
2985
2970
  continue;
2986
2971
  }
2987
2972
  }
2973
+ opts?.onWrite?.(outPath, source);
2988
2974
  writeFileSync(outPath, source);
2989
2975
  console.log(
2990
2976
  `[rango] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`
@@ -3255,6 +3241,12 @@ function performanceTracksPlugin() {
3255
3241
  }
3256
3242
 
3257
3243
  // src/vite/utils/shared-utils.ts
3244
+ function resolveRscEntryFromConfig(config) {
3245
+ const entries = config.environments?.["rsc"]?.optimizeDeps?.entries;
3246
+ if (typeof entries === "string") return entries;
3247
+ if (Array.isArray(entries) && entries.length > 0) return entries[0];
3248
+ return void 0;
3249
+ }
3258
3250
  var versionRolldownPlugin = {
3259
3251
  name: "@rangojs/router-version",
3260
3252
  resolveId(id) {
@@ -3373,15 +3365,7 @@ function createVersionInjectorPlugin(rscEntryPath) {
3373
3365
  enforce: "pre",
3374
3366
  configResolved(config) {
3375
3367
  let entryPath = rscEntryPath;
3376
- if (!entryPath) {
3377
- const rscEnvConfig = config.environments?.["rsc"];
3378
- const entries = rscEnvConfig?.optimizeDeps?.entries;
3379
- if (typeof entries === "string") {
3380
- entryPath = entries;
3381
- } else if (Array.isArray(entries) && entries.length > 0) {
3382
- entryPath = entries[0];
3383
- }
3384
- }
3368
+ if (!entryPath) entryPath = resolveRscEntryFromConfig(config);
3385
3369
  if (entryPath) {
3386
3370
  resolvedEntryPath = resolve4(config.root, entryPath);
3387
3371
  }
@@ -3435,8 +3419,8 @@ function createCjsToEsmPlugin() {
3435
3419
  name: "@rangojs/router:cjs-to-esm",
3436
3420
  enforce: "pre",
3437
3421
  transform(code, id) {
3438
- const cleanId = id.split("?")[0];
3439
- if (cleanId.includes("vendor/react-server-dom/client.browser.js") || cleanId.includes("vendor\\react-server-dom\\client.browser.js")) {
3422
+ const cleanId = id.split("?")[0].replaceAll("\\", "/");
3423
+ if (cleanId.includes("vendor/react-server-dom/client.browser.js")) {
3440
3424
  const isProd = process.env.NODE_ENV === "production";
3441
3425
  const cjsFile = isProd ? "./cjs/react-server-dom-webpack-client.browser.production.js" : "./cjs/react-server-dom-webpack-client.browser.development.js";
3442
3426
  debug7?.("cjs-to-esm entry redirect %s", id);
@@ -3445,7 +3429,7 @@ function createCjsToEsmPlugin() {
3445
3429
  map: null
3446
3430
  };
3447
3431
  }
3448
- if ((cleanId.includes("vendor/react-server-dom/cjs/") || cleanId.includes("vendor\\react-server-dom\\cjs\\")) && cleanId.includes("client.browser")) {
3432
+ if (cleanId.includes("vendor/react-server-dom/cjs/") && cleanId.includes("client.browser")) {
3449
3433
  let transformed = code;
3450
3434
  const licenseMatch = transformed.match(/^\/\*\*[\s\S]*?\*\//);
3451
3435
  const license = licenseMatch ? licenseMatch[0] : "";
@@ -4696,10 +4680,10 @@ async function discoverRouters(state, rscEnv) {
4696
4680
  newMergedRouteManifest,
4697
4681
  mergedRouteAncestry,
4698
4682
  routeToStaticPrefix,
4699
- Object.keys(mergedRouteTrailingSlash).length > 0 ? mergedRouteTrailingSlash : void 0,
4700
- prerenderRouteNames.size > 0 ? prerenderRouteNames : void 0,
4701
- passthroughRouteNames.size > 0 ? passthroughRouteNames : void 0,
4702
- Object.keys(mergedResponseTypeRoutes).length > 0 ? mergedResponseTypeRoutes : void 0
4683
+ mergedRouteTrailingSlash,
4684
+ prerenderRouteNames,
4685
+ passthroughRouteNames,
4686
+ mergedResponseTypeRoutes
4703
4687
  );
4704
4688
  for (const { id, manifest } of allManifests) {
4705
4689
  if (!manifest._routeAncestry || Object.keys(manifest._routeAncestry).length === 0)
@@ -4715,10 +4699,10 @@ async function discoverRouters(state, rscEnv) {
4715
4699
  manifest.routeManifest,
4716
4700
  manifest._routeAncestry,
4717
4701
  perRouterStaticPrefix,
4718
- manifest.routeTrailingSlash && Object.keys(manifest.routeTrailingSlash).length > 0 ? manifest.routeTrailingSlash : void 0,
4719
- perRouterPrerenderNames && perRouterPrerenderNames.size > 0 ? perRouterPrerenderNames : void 0,
4720
- perRouterPassthroughNames && perRouterPassthroughNames.size > 0 ? perRouterPassthroughNames : void 0,
4721
- manifest.responseTypeRoutes && Object.keys(manifest.responseTypeRoutes).length > 0 ? manifest.responseTypeRoutes : void 0
4702
+ manifest.routeTrailingSlash,
4703
+ perRouterPrerenderNames,
4704
+ perRouterPassthroughNames,
4705
+ manifest.responseTypeRoutes
4722
4706
  );
4723
4707
  newPerRouterTrieMap.set(id, perRouterTrie);
4724
4708
  }
@@ -4741,7 +4725,7 @@ async function discoverRouters(state, rscEnv) {
4741
4725
  }
4742
4726
 
4743
4727
  // src/vite/discovery/route-types-writer.ts
4744
- import { dirname as dirname3, basename, join as join2, resolve as resolve6 } from "node:path";
4728
+ import { dirname as dirname3, join as join2, resolve as resolve6 } from "node:path";
4745
4729
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, unlinkSync as unlinkSync2 } from "node:fs";
4746
4730
  function filterUserNamedRoutes(manifest) {
4747
4731
  const filtered = {};
@@ -4752,39 +4736,20 @@ function filterUserNamedRoutes(manifest) {
4752
4736
  }
4753
4737
  return filtered;
4754
4738
  }
4739
+ function writeGenFileIfChanged(state, outPath, source, opts) {
4740
+ const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
4741
+ if (existing === source) return;
4742
+ markSelfGenWrite(state, outPath, source);
4743
+ writeFileSync3(outPath, source);
4744
+ if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
4745
+ }
4755
4746
  function writeCombinedRouteTypesWithTracking(state, opts) {
4756
4747
  const routerFiles = state.cachedRouterFiles ?? findRouterFiles(state.projectRoot, state.scanFilter);
4757
4748
  state.cachedRouterFiles = routerFiles;
4758
- const preContent = /* @__PURE__ */ new Map();
4759
- for (const routerFilePath of routerFiles) {
4760
- const routerDir = dirname3(routerFilePath);
4761
- const routerBasename = basename(routerFilePath).replace(
4762
- /\.(tsx?|jsx?)$/,
4763
- ""
4764
- );
4765
- const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
4766
- try {
4767
- preContent.set(outPath, readFileSync4(outPath, "utf-8"));
4768
- } catch {
4769
- }
4770
- }
4771
- writeCombinedRouteTypes(state.projectRoot, routerFiles, opts);
4772
- for (const routerFilePath of routerFiles) {
4773
- const routerDir = dirname3(routerFilePath);
4774
- const routerBasename = basename(routerFilePath).replace(
4775
- /\.(tsx?|jsx?)$/,
4776
- ""
4777
- );
4778
- const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
4779
- if (!existsSync5(outPath)) continue;
4780
- try {
4781
- const content = readFileSync4(outPath, "utf-8");
4782
- if (content !== preContent.get(outPath)) {
4783
- markSelfGenWrite(state, outPath, content);
4784
- }
4785
- } catch {
4786
- }
4787
- }
4749
+ writeCombinedRouteTypes(state.projectRoot, routerFiles, {
4750
+ ...opts,
4751
+ onWrite: (outPath, content) => markSelfGenWrite(state, outPath, content)
4752
+ });
4788
4753
  }
4789
4754
  function writeRouteTypesFiles(state) {
4790
4755
  if (state.perRouterManifests.length === 0) return;
@@ -4815,34 +4780,18 @@ This means createRouter() stack trace parsing matched a Vite internal frame.
4815
4780
  Set an explicit \`id\` on createRouter() or check the call site.`
4816
4781
  );
4817
4782
  }
4818
- const routerDir = dirname3(sourceFile);
4819
- const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
4820
- const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
4783
+ const outPath = genFileTsPath(sourceFile);
4821
4784
  const userRoutes = filterUserNamedRoutes(routeManifest);
4822
- let effectiveSearchSchemas = routeSearchSchemas;
4823
- if ((!effectiveSearchSchemas || Object.keys(effectiveSearchSchemas).length === 0) && sourceFile) {
4824
- const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
4825
- if (Object.keys(staticParsed.searchSchemas).length > 0) {
4826
- const filtered = {};
4827
- for (const name of Object.keys(userRoutes)) {
4828
- const schema = staticParsed.searchSchemas[name];
4829
- if (schema) filtered[name] = schema;
4830
- }
4831
- if (Object.keys(filtered).length > 0) {
4832
- effectiveSearchSchemas = filtered;
4833
- }
4834
- }
4835
- }
4785
+ const effectiveSearchSchemas = resolveSearchSchemas(
4786
+ Object.keys(userRoutes),
4787
+ routeSearchSchemas,
4788
+ sourceFile
4789
+ );
4836
4790
  const source = generateRouteTypesSource(
4837
4791
  userRoutes,
4838
4792
  effectiveSearchSchemas && Object.keys(effectiveSearchSchemas).length > 0 ? effectiveSearchSchemas : void 0
4839
4793
  );
4840
- const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
4841
- if (existing !== source) {
4842
- markSelfGenWrite(state, outPath, source);
4843
- writeFileSync3(outPath, source);
4844
- console.log(`[rango] Generated route types -> ${outPath}`);
4845
- }
4794
+ writeGenFileIfChanged(state, outPath, source, { log: true });
4846
4795
  }
4847
4796
  }
4848
4797
  function supplementGenFilesWithRuntimeRoutes(state) {
@@ -4880,23 +4829,17 @@ function supplementGenFilesWithRuntimeRoutes(state) {
4880
4829
  }
4881
4830
  }
4882
4831
  }
4883
- const routerDir = dirname3(sourceFile);
4884
- const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
4885
- const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
4832
+ const outPath = genFileTsPath(sourceFile);
4886
4833
  const source = generateRouteTypesSource(
4887
4834
  mergedRoutes,
4888
4835
  Object.keys(mergedSearchSchemas).length > 0 ? mergedSearchSchemas : void 0
4889
4836
  );
4890
- const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
4891
- if (existing !== source) {
4892
- markSelfGenWrite(state, outPath, source);
4893
- writeFileSync3(outPath, source);
4894
- }
4837
+ writeGenFileIfChanged(state, outPath, source);
4895
4838
  }
4896
4839
  }
4897
4840
 
4898
4841
  // src/vite/discovery/virtual-module-codegen.ts
4899
- import { dirname as dirname4, basename as basename2, join as join3 } from "node:path";
4842
+ import { dirname as dirname4, basename, join as join3 } from "node:path";
4900
4843
  function generateRoutesManifestModule(state) {
4901
4844
  const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
4902
4845
  if (hasManifest) {
@@ -4907,7 +4850,7 @@ function generateRoutesManifestModule(state) {
4907
4850
  for (const entry of state.perRouterManifests) {
4908
4851
  if (entry.sourceFile) {
4909
4852
  const routerDir = dirname4(entry.sourceFile);
4910
- const routerBasename = basename2(entry.sourceFile).replace(
4853
+ const routerBasename = basename(entry.sourceFile).replace(
4911
4854
  /\.(tsx?|jsx?)$/,
4912
4855
  ""
4913
4856
  );
@@ -4992,7 +4935,7 @@ function generatePerRouterModule(state, routerId) {
4992
4935
  const lines = [];
4993
4936
  if (routerEntry?.sourceFile) {
4994
4937
  const routerDir = dirname4(routerEntry.sourceFile);
4995
- const routerBasename = basename2(routerEntry.sourceFile).replace(
4938
+ const routerBasename = basename(routerEntry.sourceFile).replace(
4996
4939
  /\.(tsx?|jsx?)$/,
4997
4940
  ""
4998
4941
  );
@@ -5430,13 +5373,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
5430
5373
  s.resolvedEntryPath = opts.routerPathRef.path;
5431
5374
  }
5432
5375
  if (!s.resolvedEntryPath) {
5433
- const rscEnvConfig = config.environments?.["rsc"];
5434
- const entries = rscEnvConfig?.optimizeDeps?.entries;
5435
- if (typeof entries === "string") {
5436
- s.resolvedEntryPath = entries;
5437
- } else if (Array.isArray(entries) && entries.length > 0) {
5438
- s.resolvedEntryPath = entries[0];
5439
- }
5376
+ const entry = resolveRscEntryFromConfig(config);
5377
+ if (entry) s.resolvedEntryPath = entry;
5440
5378
  }
5441
5379
  if (opts?.staticRouteTypesGeneration !== false) {
5442
5380
  s.cachedRouterFiles = findRouterFiles(s.projectRoot, s.scanFilter);
@@ -5727,20 +5665,15 @@ ${err.stack}`
5727
5665
  if (s.mergedRouteTrie && serverMod.setRouteTrie) {
5728
5666
  serverMod.setRouteTrie(s.mergedRouteTrie);
5729
5667
  }
5730
- if (serverMod.setRouterManifest) {
5731
- for (const [routerId, manifest] of s.perRouterManifestDataMap) {
5732
- serverMod.setRouterManifest(routerId, manifest);
5733
- }
5734
- }
5735
- if (serverMod.setRouterTrie) {
5736
- for (const [routerId, trie] of s.perRouterTrieMap) {
5737
- serverMod.setRouterTrie(routerId, trie);
5738
- }
5739
- }
5740
- if (serverMod.setRouterPrecomputedEntries) {
5741
- for (const [routerId, entries] of s.perRouterPrecomputedMap) {
5742
- serverMod.setRouterPrecomputedEntries(routerId, entries);
5743
- }
5668
+ const perRouterSetters = [
5669
+ [s.perRouterManifestDataMap, "setRouterManifest"],
5670
+ [s.perRouterTrieMap, "setRouterTrie"],
5671
+ [s.perRouterPrecomputedMap, "setRouterPrecomputedEntries"]
5672
+ ];
5673
+ for (const [map, fn] of perRouterSetters) {
5674
+ const setter = serverMod[fn];
5675
+ if (typeof setter !== "function") continue;
5676
+ for (const [routerId, value] of map) setter(routerId, value);
5744
5677
  }
5745
5678
  };
5746
5679
  server.middlewares.use("/__rsc_prerender", async (req, res) => {
@@ -5910,6 +5843,7 @@ ${err.stack}`
5910
5843
  );
5911
5844
  s.lastDiscoveryError = null;
5912
5845
  }
5846
+ if (rscEnv && !rscEnv.runner) forceCloudflareWorkerReload(rscEnv);
5913
5847
  } catch (err) {
5914
5848
  s.lastDiscoveryError = {
5915
5849
  message: err?.message ?? String(err),
@@ -5930,6 +5864,25 @@ ${err.stack}`
5930
5864
  }
5931
5865
  });
5932
5866
  };
5867
+ const forceCloudflareWorkerReload = (rscEnv) => {
5868
+ if (!rscEnv?.hot) return;
5869
+ try {
5870
+ const graph = rscEnv.moduleGraph;
5871
+ if (graph?.invalidateAll) {
5872
+ graph.invalidateAll();
5873
+ debugDiscovery?.("hmr: invalidated workerd rsc module graph");
5874
+ }
5875
+ rscEnv.hot.send({ type: "full-reload" });
5876
+ debugDiscovery?.(
5877
+ "hmr: forced workerd rsc env reload (full-reload)"
5878
+ );
5879
+ } catch (err) {
5880
+ debugDiscovery?.(
5881
+ "hmr: workerd reload failed: %s",
5882
+ err?.message ?? err
5883
+ );
5884
+ }
5885
+ };
5933
5886
  const scheduleRouteRegeneration = () => {
5934
5887
  clearTimeout(routeChangeTimer);
5935
5888
  routeChangeTimer = setTimeout(() => {