@rangojs/router 0.19.1 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/dist/bin/rango.js +26 -14
  2. package/dist/types/browser/event-controller.d.ts +32 -0
  3. package/dist/types/browser/history-state.d.ts +16 -4
  4. package/dist/types/browser/navigation-transaction.d.ts +7 -0
  5. package/dist/types/browser/rango-state.d.ts +3 -1
  6. package/dist/types/browser/react/context.d.ts +11 -0
  7. package/dist/types/browser/react/location-state-shared.d.ts +84 -10
  8. package/dist/types/browser/react/location-state.d.ts +7 -2
  9. package/dist/types/browser/react/subscribe-to-nothing.d.ts +7 -0
  10. package/dist/types/cache/cache-scope.d.ts +4 -5
  11. package/dist/types/cache/cf/cf-cache-store.d.ts +27 -6
  12. package/dist/types/cache/cf/cf-cache-types.d.ts +12 -4
  13. package/dist/types/cache/handle-snapshot.d.ts +36 -50
  14. package/dist/types/cache/index.d.ts +2 -0
  15. package/dist/types/cache/shell-snapshot.d.ts +19 -3
  16. package/dist/types/cache/types.d.ts +21 -10
  17. package/dist/types/cache/vercel/vercel-cache-store.d.ts +28 -16
  18. package/dist/types/client-urls/navigation.d.ts +7 -1
  19. package/dist/types/client-urls/optimistic-location.d.ts +10 -4
  20. package/dist/types/handles/deferred-resolution.d.ts +11 -1
  21. package/dist/types/prerender/build-shell-capture.d.ts +8 -6
  22. package/dist/types/router/match-middleware/cache-lookup.d.ts +1 -1
  23. package/dist/types/router/navigation-snapshot.d.ts +8 -1
  24. package/dist/types/router/router-interfaces.d.ts +2 -1
  25. package/dist/types/router/router-options.d.ts +17 -7
  26. package/dist/types/router/segment-resolution/loader-cache.d.ts +21 -9
  27. package/dist/types/router-versions.d.ts +39 -0
  28. package/dist/types/rsc/handler-context.d.ts +5 -0
  29. package/dist/types/rsc/shell-build-manifest.d.ts +3 -2
  30. package/dist/types/rsc/types.d.ts +4 -6
  31. package/dist/types/server/build-version-table.d.ts +44 -0
  32. package/dist/types/server/handle-store.d.ts +87 -46
  33. package/dist/types/server/request-context.d.ts +22 -8
  34. package/dist/types/ssr/entry-preload-priority.d.ts +69 -0
  35. package/dist/types/ssr/index.d.ts +1 -0
  36. package/dist/types/ssr/preinit-client-references.d.ts +17 -5
  37. package/dist/types/testing/build-versions.d.ts +32 -0
  38. package/dist/types/testing/dom.entry.d.ts +1 -1
  39. package/dist/types/testing/flight.entry.d.ts +1 -1
  40. package/dist/types/testing/index.d.ts +2 -0
  41. package/dist/types/testing/internal/seed-vars.d.ts +7 -2
  42. package/dist/types/testing/location-state-key.d.ts +5 -1
  43. package/dist/types/testing/render-route.d.ts +77 -6
  44. package/dist/types/testing/serve-shell-request.d.ts +21 -0
  45. package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
  46. package/dist/types/types/handler-context.d.ts +8 -5
  47. package/dist/types/vite/discovery/build-versions.d.ts +393 -0
  48. package/dist/types/vite/discovery/installed-packages.d.ts +26 -0
  49. package/dist/types/vite/discovery/router-versions-phase.d.ts +52 -0
  50. package/dist/types/vite/discovery/shell-prerender-phase.d.ts +7 -17
  51. package/dist/types/vite/discovery/state.d.ts +14 -0
  52. package/dist/types/vite/encryption-key.d.ts +18 -0
  53. package/dist/types/vite/plugin-types.d.ts +47 -6
  54. package/dist/types/vite/plugins/{version-injector.d.ts → entry-bootstrap-injector.d.ts} +4 -6
  55. package/dist/types/vite/plugins/expose-ids/export-analysis.d.ts +1 -0
  56. package/dist/types/vite/plugins/expose-ids/router-transform.d.ts +14 -0
  57. package/dist/types/vite/plugins/stable-rsc-output.d.ts +51 -0
  58. package/dist/types/vite/plugins/version-plugin.d.ts +9 -11
  59. package/dist/types/vite/plugins/virtual-entries.d.ts +21 -2
  60. package/dist/types/vite/router-discovery.d.ts +6 -0
  61. package/dist/types/vite/utils/client-chunks.d.ts +24 -2
  62. package/dist/types/vite/utils/compare-strings.d.ts +7 -0
  63. package/dist/types/vite/utils/package-resolution.d.ts +8 -0
  64. package/dist/types/vite/utils/prerender-utils.d.ts +2 -0
  65. package/dist/vite/index.js +1544 -420
  66. package/package.json +1 -2
  67. package/skills/bundle-analysis/SKILL.md +1 -1
  68. package/skills/cache-guide/SKILL.md +84 -20
  69. package/skills/caching/SKILL.md +16 -5
  70. package/skills/client-urls/SKILL.md +16 -0
  71. package/skills/cloudflare/SKILL.md +2 -1
  72. package/skills/comparison/references/framework-comparison.md +16 -12
  73. package/skills/hooks/SKILL.md +3 -0
  74. package/skills/hooks/handle-and-actions.md +6 -0
  75. package/skills/hooks/navigation.md +28 -0
  76. package/skills/hooks/state.md +209 -8
  77. package/skills/hooks/urls.md +40 -1
  78. package/skills/host-router/SKILL.md +13 -0
  79. package/skills/intercept/SKILL.md +6 -0
  80. package/skills/loader/SKILL.md +19 -1
  81. package/skills/middleware/SKILL.md +2 -0
  82. package/skills/ppr/SKILL.md +119 -40
  83. package/skills/prerender/SKILL.md +7 -3
  84. package/skills/rango/SKILL.md +8 -7
  85. package/skills/router-setup/SKILL.md +23 -3
  86. package/skills/testing/SKILL.md +30 -26
  87. package/skills/testing/client-components.md +193 -8
  88. package/skills/testing/handles.md +2 -0
  89. package/skills/testing/loader.md +1 -1
  90. package/skills/testing/middleware.md +1 -1
  91. package/skills/testing/render-handler.md +18 -18
  92. package/skills/testing/serve-shell-request.md +63 -14
  93. package/skills/testing/server-actions.md +17 -17
  94. package/skills/testing/server-tree.md +1 -1
  95. package/skills/typesafety/generated-files-and-cli.md +1 -1
  96. package/skills/use-cache/SKILL.md +16 -5
  97. package/skills/vercel/SKILL.md +3 -3
  98. package/src/bin/rango.ts +1 -1
  99. package/src/browser/event-controller.ts +75 -2
  100. package/src/browser/history-state.ts +39 -17
  101. package/src/browser/navigation-bridge.ts +41 -18
  102. package/src/browser/navigation-transaction.ts +15 -10
  103. package/src/browser/partial-update.ts +10 -2
  104. package/src/browser/rango-state.ts +3 -1
  105. package/src/browser/react/Link.tsx +2 -3
  106. package/src/browser/react/NavigationProvider.tsx +25 -1
  107. package/src/browser/react/context.ts +13 -0
  108. package/src/browser/react/location-state-shared.ts +200 -34
  109. package/src/browser/react/location-state.ts +40 -75
  110. package/src/browser/react/subscribe-to-nothing.ts +7 -0
  111. package/src/browser/react/use-handle.ts +20 -1
  112. package/src/browser/rsc-router.tsx +33 -11
  113. package/src/browser/server-action-bridge.ts +17 -1
  114. package/src/cache/cache-scope.ts +18 -8
  115. package/src/cache/cf/cf-cache-store.ts +75 -55
  116. package/src/cache/cf/cf-cache-types.ts +12 -4
  117. package/src/cache/handle-snapshot.ts +69 -87
  118. package/src/cache/index.ts +4 -0
  119. package/src/cache/shell-snapshot.ts +35 -5
  120. package/src/cache/types.ts +21 -10
  121. package/src/cache/vercel/vercel-cache-store.ts +48 -20
  122. package/src/client-urls/client-root.tsx +1 -0
  123. package/src/client-urls/navigation.ts +10 -0
  124. package/src/client-urls/optimistic-location.ts +10 -4
  125. package/src/handles/deferred-resolution.ts +31 -0
  126. package/src/prerender/build-shell-capture.ts +11 -9
  127. package/src/router/manifest.ts +2 -0
  128. package/src/router/match-middleware/cache-lookup.ts +11 -18
  129. package/src/router/navigation-snapshot.ts +25 -6
  130. package/src/router/request-classification.ts +15 -12
  131. package/src/router/router-interfaces.ts +2 -1
  132. package/src/router/router-options.ts +17 -7
  133. package/src/router/segment-resolution/loader-cache.ts +95 -60
  134. package/src/router-versions.ts +60 -0
  135. package/src/rsc/full-payload.ts +6 -2
  136. package/src/rsc/handler-context.ts +5 -0
  137. package/src/rsc/handler.ts +14 -4
  138. package/src/rsc/rsc-rendering.ts +12 -1
  139. package/src/rsc/shell-build-manifest.ts +10 -7
  140. package/src/rsc/shell-capture.ts +36 -26
  141. package/src/rsc/types.ts +4 -6
  142. package/src/server/build-version-table.ts +115 -0
  143. package/src/server/handle-store.ts +344 -127
  144. package/src/server/request-context.ts +62 -11
  145. package/src/ssr/entry-preload-priority.ts +308 -0
  146. package/src/ssr/index.tsx +46 -9
  147. package/src/ssr/preinit-client-references.ts +17 -5
  148. package/src/ssr/ssr-root.tsx +16 -4
  149. package/src/testing/build-versions.ts +64 -0
  150. package/src/testing/dispatch.ts +6 -0
  151. package/src/testing/dom.entry.ts +1 -0
  152. package/src/testing/flight.entry.ts +1 -0
  153. package/src/testing/index.ts +3 -0
  154. package/src/testing/internal/context.ts +2 -1
  155. package/src/testing/internal/seed-vars.ts +14 -2
  156. package/src/testing/location-state-key.ts +18 -8
  157. package/src/testing/render-handler.ts +2 -1
  158. package/src/testing/render-route.tsx +277 -43
  159. package/src/testing/serve-shell-request.ts +80 -11
  160. package/src/testing/vitest-stubs/version.ts +4 -1
  161. package/src/types/handler-context.ts +8 -5
  162. package/src/vite/discovery/build-versions.ts +1281 -0
  163. package/src/vite/discovery/installed-packages.ts +159 -0
  164. package/src/vite/discovery/prerender-collection.ts +38 -1
  165. package/src/vite/discovery/router-versions-phase.ts +336 -0
  166. package/src/vite/discovery/shell-prerender-phase.ts +28 -38
  167. package/src/vite/discovery/state.ts +19 -0
  168. package/src/vite/discovery/virtual-module-codegen.ts +7 -2
  169. package/src/vite/encryption-key.ts +101 -9
  170. package/src/vite/plugin-types.ts +48 -6
  171. package/src/vite/plugins/{version-injector.ts → entry-bootstrap-injector.ts} +7 -22
  172. package/src/vite/plugins/expose-ids/export-analysis.ts +1 -1
  173. package/src/vite/plugins/expose-ids/router-transform.ts +36 -15
  174. package/src/vite/plugins/expose-internal-ids.ts +12 -3
  175. package/src/vite/plugins/stable-rsc-output.ts +147 -0
  176. package/src/vite/plugins/version-plugin.ts +19 -24
  177. package/src/vite/plugins/version.d.ts +17 -2
  178. package/src/vite/plugins/virtual-entries.ts +40 -7
  179. package/src/vite/rango.ts +30 -3
  180. package/src/vite/router-discovery.ts +82 -13
  181. package/src/vite/utils/client-chunks.ts +84 -14
  182. package/src/vite/utils/compare-strings.ts +9 -0
  183. package/src/vite/utils/package-resolution.ts +9 -0
  184. package/src/vite/utils/prerender-utils.ts +4 -1
  185. package/src/vite/utils/shared-utils.ts +1 -1
@@ -22,26 +22,26 @@ function createRangoDebugger(namespace) {
22
22
  if (shadow.enabled) return shadow;
23
23
  return void 0;
24
24
  }
25
- async function timed(debug13, label, fn) {
26
- if (!debug13) return await fn();
25
+ async function timed(debug14, label, fn) {
26
+ if (!debug14) return await fn();
27
27
  const start = performance.now();
28
28
  try {
29
29
  return await fn();
30
30
  } finally {
31
- debug13("%s (%sms)", label, (performance.now() - start).toFixed(1));
31
+ debug14("%s (%sms)", label, (performance.now() - start).toFixed(1));
32
32
  }
33
33
  }
34
- function timedSync(debug13, label, fn) {
35
- if (!debug13) return fn();
34
+ function timedSync(debug14, label, fn) {
35
+ if (!debug14) return fn();
36
36
  const start = performance.now();
37
37
  try {
38
38
  return fn();
39
39
  } finally {
40
- debug13("%s (%sms)", label, (performance.now() - start).toFixed(1));
40
+ debug14("%s (%sms)", label, (performance.now() - start).toFixed(1));
41
41
  }
42
42
  }
43
- function createCounter(debug13, label) {
44
- if (!debug13) return void 0;
43
+ function createCounter(debug14, label) {
44
+ if (!debug14) return void 0;
45
45
  let n = 0;
46
46
  let totalMs = 0;
47
47
  let slowestMs = 0;
@@ -75,7 +75,7 @@ function createCounter(debug13, label) {
75
75
  },
76
76
  flush() {
77
77
  if (n === 0) return;
78
- debug13(
78
+ debug14(
79
79
  "%s: %d files, %sms total, slowest %sms %s",
80
80
  label,
81
81
  n,
@@ -119,7 +119,7 @@ __export(client_ref_hashing_exports, {
119
119
  hashRefKey: () => hashRefKey,
120
120
  transformClientRefs: () => transformClientRefs
121
121
  });
122
- import { relative as relative3 } from "node:path";
122
+ import { relative as relative2 } from "node:path";
123
123
  import { createHash as createHash2 } from "node:crypto";
124
124
  function hashRefKey(relativeId) {
125
125
  return createHash2("sha256").update(relativeId).digest("hex").slice(0, 12);
@@ -132,10 +132,10 @@ function computeProductionHash(projectRoot, refKey) {
132
132
  const absPath = decodeURIComponent(
133
133
  refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
134
134
  );
135
- toHash = relative3(projectRoot, absPath).replaceAll("\\", "/");
135
+ toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
136
136
  } else if (refKey.startsWith(FS_PREFIX)) {
137
137
  const absPath = refKey.slice(FS_PREFIX.length - 1);
138
- toHash = relative3(projectRoot, absPath).replaceAll("\\", "/");
138
+ toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
139
139
  } else if (refKey.startsWith("/")) {
140
140
  toHash = refKey.slice(1);
141
141
  } else {
@@ -158,7 +158,7 @@ function transformClientRefs(code, projectRoot) {
158
158
  return hasReplacement ? result : null;
159
159
  }
160
160
  function hashClientRefs(projectRoot) {
161
- const counter = createCounter(debug6, "hash-client-refs");
161
+ const counter = createCounter(debug5, "hash-client-refs");
162
162
  return {
163
163
  name: "@rangojs/router:hash-client-refs",
164
164
  enforce: "post",
@@ -180,12 +180,12 @@ function hashClientRefs(projectRoot) {
180
180
  }
181
181
  };
182
182
  }
183
- var debug6, CLIENT_PKG_PROXY_PREFIX, CLIENT_IN_SERVER_PKG_PROXY_PREFIX, FS_PREFIX, REGISTER_CLIENT_REF_RE;
183
+ var debug5, CLIENT_PKG_PROXY_PREFIX, CLIENT_IN_SERVER_PKG_PROXY_PREFIX, FS_PREFIX, REGISTER_CLIENT_REF_RE;
184
184
  var init_client_ref_hashing = __esm({
185
185
  "src/vite/plugins/client-ref-hashing.ts"() {
186
186
  "use strict";
187
187
  init_debug();
188
- debug6 = createRangoDebugger(NS.transform);
188
+ debug5 = createRangoDebugger(NS.transform);
189
189
  CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
190
190
  CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
191
191
  FS_PREFIX = "/@fs/";
@@ -492,12 +492,12 @@ function waitForViewportImages() {
492
492
  return rect.bottom > 0 && rect.right > 0 && rect.top < window.innerHeight && rect.left < window.innerWidth;
493
493
  });
494
494
  if (pending.length === 0) return Promise.resolve();
495
- return new Promise((resolve14) => {
495
+ return new Promise((resolve15) => {
496
496
  const settled = /* @__PURE__ */ new Set();
497
497
  const settle = (img) => {
498
498
  if (settled.has(img)) return;
499
499
  settled.add(img);
500
- if (settled.size >= pending.length) resolve14();
500
+ if (settled.size >= pending.length) resolve15();
501
501
  };
502
502
  for (const img of pending) {
503
503
  img.addEventListener("load", () => settle(img), { once: true });
@@ -507,16 +507,16 @@ function waitForViewportImages() {
507
507
  });
508
508
  }
509
509
  function wait(ms) {
510
- return new Promise((resolve14) => setTimeout(resolve14, ms));
510
+ return new Promise((resolve15) => setTimeout(resolve15, ms));
511
511
  }
512
512
  function waitForIdle(timeout = 200) {
513
513
  if (typeof window !== "undefined" && "requestIdleCallback" in window) {
514
- return new Promise((resolve14) => {
515
- window.requestIdleCallback(() => resolve14(), { timeout });
514
+ return new Promise((resolve15) => {
515
+ window.requestIdleCallback(() => resolve15(), { timeout });
516
516
  });
517
517
  }
518
- return new Promise((resolve14) => {
519
- setTimeout(resolve14, 0);
518
+ return new Promise((resolve15) => {
519
+ setTimeout(resolve15, 0);
520
520
  });
521
521
  }
522
522
  var init_resource_ready = __esm({
@@ -766,7 +766,7 @@ function isSamePage(url) {
766
766
  return false;
767
767
  }
768
768
  }
769
- function buildPrefetchUrl(url, segmentIds, version, routerId) {
769
+ function buildPrefetchUrl(url, segmentIds, version, routerId2) {
770
770
  let targetUrl;
771
771
  try {
772
772
  targetUrl = new URL(url, window.location.origin);
@@ -783,8 +783,8 @@ function buildPrefetchUrl(url, segmentIds, version, routerId) {
783
783
  if (version) {
784
784
  targetUrl.searchParams.set("_rsc_v", version);
785
785
  }
786
- if (routerId) {
787
- targetUrl.searchParams.set("_rsc_rid", routerId);
786
+ if (routerId2) {
787
+ targetUrl.searchParams.set("_rsc_rid", routerId2);
788
788
  }
789
789
  return targetUrl;
790
790
  }
@@ -843,8 +843,8 @@ function executePrefetchFetch(wildcardKey, sourceKey, fetchUrl, forceSourceScope
843
843
  const storageKey = scope === "source" ? sourceKey : wildcardKey;
844
844
  let resolveStreamComplete;
845
845
  let endedCleanly = false;
846
- const streamComplete = new Promise((resolve14) => {
847
- resolveStreamComplete = resolve14;
846
+ const streamComplete = new Promise((resolve15) => {
847
+ resolveStreamComplete = resolve15;
848
848
  });
849
849
  const tracked = teeWithCompletion(
850
850
  response,
@@ -908,9 +908,9 @@ function executePrefetchFetch(wildcardKey, sourceKey, fetchUrl, forceSourceScope
908
908
  function hasPrefetchHit(forceSourceScope, wildcardKey, sourceKey) {
909
909
  return forceSourceScope ? hasPrefetch(sourceKey) : hasPrefetch(wildcardKey) || hasPrefetch(sourceKey);
910
910
  }
911
- function prefetchDirect(url, segmentIds, version, routerId, prefetchKey) {
911
+ function prefetchDirect(url, segmentIds, version, routerId2, prefetchKey) {
912
912
  if (!shouldPrefetch()) return;
913
- const targetUrl = buildPrefetchUrl(url, segmentIds, version, routerId);
913
+ const targetUrl = buildPrefetchUrl(url, segmentIds, version, routerId2);
914
914
  if (!targetUrl) return;
915
915
  const forceSourceScope = prefetchKey === ":source";
916
916
  if (!forceSourceScope && isSamePage(url)) {
@@ -946,12 +946,12 @@ function prefetchDirect(url, segmentIds, version, routerId, prefetchKey) {
946
946
  targetUrl.toString(),
947
947
  forceSourceScope,
948
948
  rangoState,
949
- routerId
949
+ routerId2
950
950
  );
951
951
  }
952
- function prefetchQueued(url, segmentIds, version, routerId, prefetchKey) {
952
+ function prefetchQueued(url, segmentIds, version, routerId2, prefetchKey) {
953
953
  if (!shouldPrefetch()) return "";
954
- const targetUrl = buildPrefetchUrl(url, segmentIds, version, routerId);
954
+ const targetUrl = buildPrefetchUrl(url, segmentIds, version, routerId2);
955
955
  if (!targetUrl) return "";
956
956
  const forceSourceScope = prefetchKey === ":source";
957
957
  if (!forceSourceScope && isSamePage(url)) {
@@ -987,7 +987,7 @@ function prefetchQueued(url, segmentIds, version, routerId, prefetchKey) {
987
987
  fetchUrlStr,
988
988
  forceSourceScope,
989
989
  rangoState,
990
- routerId,
990
+ routerId2,
991
991
  signal
992
992
  ).then(() => {
993
993
  });
@@ -1061,14 +1061,14 @@ function withRuntime(run) {
1061
1061
  }).catch(() => {
1062
1062
  });
1063
1063
  }
1064
- function prefetchDirect2(url, segmentIds, version, routerId, prefetchKey) {
1064
+ function prefetchDirect2(url, segmentIds, version, routerId2, prefetchKey) {
1065
1065
  withRuntime(
1066
- (loaded) => loaded.prefetchDirect(url, segmentIds, version, routerId, prefetchKey)
1066
+ (loaded) => loaded.prefetchDirect(url, segmentIds, version, routerId2, prefetchKey)
1067
1067
  );
1068
1068
  }
1069
- function prefetchQueued2(url, segmentIds, version, routerId, prefetchKey) {
1069
+ function prefetchQueued2(url, segmentIds, version, routerId2, prefetchKey) {
1070
1070
  withRuntime(
1071
- (loaded) => loaded.prefetchQueued(url, segmentIds, version, routerId, prefetchKey)
1071
+ (loaded) => loaded.prefetchQueued(url, segmentIds, version, routerId2, prefetchKey)
1072
1072
  );
1073
1073
  }
1074
1074
  function schedulePrefetchWhenRouterIdle(eventController, callback) {
@@ -1098,8 +1098,8 @@ var init_loader = __esm({
1098
1098
  });
1099
1099
 
1100
1100
  // src/vite/rango.ts
1101
- import { readFileSync as readFileSync10, existsSync as existsSync11 } from "node:fs";
1102
- import { resolve as resolve13 } from "node:path";
1101
+ import { readFileSync as readFileSync12, existsSync as existsSync13 } from "node:fs";
1102
+ import { resolve as resolve14 } from "node:path";
1103
1103
 
1104
1104
  // src/vite/plugins/expose-action-id.ts
1105
1105
  import { getPluginApi } from "@vitejs/plugin-rsc";
@@ -1569,10 +1569,56 @@ function exposeActionId() {
1569
1569
 
1570
1570
  // src/vite/encryption-key.ts
1571
1571
  import { randomBytes } from "node:crypto";
1572
- var cachedKey;
1572
+ var AES_KEY_BYTES = /* @__PURE__ */ new Set([16, 24, 32]);
1573
+ var EXPECTED = "a base64-encoded AES key of 16, 24 or 32 bytes (openssl rand -base64 32)";
1574
+ var resolvedKey;
1575
+ function assertValidEncryptionKey(value, source) {
1576
+ if (typeof value !== "string") {
1577
+ throw new Error(
1578
+ `[rango] ${source} must be a string, received ${typeof value}. Expected ${EXPECTED}.`
1579
+ );
1580
+ }
1581
+ if (value === "") {
1582
+ throw new Error(
1583
+ `[rango] ${source} is an empty string. Unset it to generate a key per build, or set it to ${EXPECTED}.`
1584
+ );
1585
+ }
1586
+ const bytes = /^[A-Za-z0-9+/]+={0,2}$/.test(value) ? Buffer.from(value, "base64") : void 0;
1587
+ if (!bytes || bytes.toString("base64").replace(/=+$/, "") !== value.replace(/=+$/, "")) {
1588
+ throw new Error(
1589
+ `[rango] ${source} is not valid base64. Expected ${EXPECTED}.`
1590
+ );
1591
+ }
1592
+ if (!AES_KEY_BYTES.has(bytes.length)) {
1593
+ throw new Error(
1594
+ `[rango] ${source} decodes to ${bytes.length} bytes. Expected ${EXPECTED}.`
1595
+ );
1596
+ }
1597
+ }
1598
+ function configureEncryptionKey(option) {
1599
+ if (option !== void 0) {
1600
+ assertValidEncryptionKey(option, "rango({ encryptionKey })");
1601
+ resolvedKey = { key: option, stable: true };
1602
+ return;
1603
+ }
1604
+ const fromEnv = process.env.RANGO_ENCRYPTION_KEY;
1605
+ if (fromEnv !== void 0) {
1606
+ assertValidEncryptionKey(fromEnv, "RANGO_ENCRYPTION_KEY");
1607
+ resolvedKey = { key: fromEnv, stable: true };
1608
+ return;
1609
+ }
1610
+ if (resolvedKey && !resolvedKey.stable) return;
1611
+ resolvedKey = { key: randomBytes(32).toString("base64"), stable: false };
1612
+ }
1613
+ function resolved() {
1614
+ if (!resolvedKey) configureEncryptionKey(void 0);
1615
+ return resolvedKey;
1616
+ }
1573
1617
  function buildEncryptionKey() {
1574
- cachedKey ??= process.env.RANGO_ENCRYPTION_KEY ?? randomBytes(32).toString("base64");
1575
- return cachedKey;
1618
+ return resolved().key;
1619
+ }
1620
+ function isEncryptionKeyStable() {
1621
+ return resolved().stable;
1576
1622
  }
1577
1623
  function defineEncryptionKeyExpr() {
1578
1624
  return JSON.stringify(buildEncryptionKey());
@@ -1587,10 +1633,10 @@ import path4 from "node:path";
1587
1633
  function isDirectivePrologueStatement(node) {
1588
1634
  return node?.type === "ExpressionStatement" && typeof node.directive === "string";
1589
1635
  }
1590
- function findImportInsertionPos(code, parseAst7) {
1636
+ function findImportInsertionPos(code, parseAst8) {
1591
1637
  let program;
1592
1638
  try {
1593
- program = parseAst7(code, { lang: "tsx" });
1639
+ program = parseAst8(code, { lang: "tsx" });
1594
1640
  } catch {
1595
1641
  return 0;
1596
1642
  }
@@ -1627,10 +1673,10 @@ function walkNode(node, parent, ancestors, enter) {
1627
1673
  }
1628
1674
  ancestors.pop();
1629
1675
  }
1630
- function findHandlerCalls(code, fnName, parseAst7) {
1676
+ function findHandlerCalls(code, fnName, parseAst8) {
1631
1677
  let program;
1632
1678
  try {
1633
- program = parseAst7(code, { lang: "tsx" });
1679
+ program = parseAst8(code, { lang: "tsx" });
1634
1680
  } catch {
1635
1681
  return [];
1636
1682
  }
@@ -1702,18 +1748,18 @@ function getImportedLocalNamesFromProgram(program, importedName) {
1702
1748
  }
1703
1749
  return localNames;
1704
1750
  }
1705
- function getImportedLocalNames(code, importedName, parseAst7) {
1751
+ function getImportedLocalNames(code, importedName, parseAst8) {
1706
1752
  try {
1707
- const program = parseAst7(code, { lang: "tsx" });
1753
+ const program = parseAst8(code, { lang: "tsx" });
1708
1754
  return getImportedLocalNamesFromProgram(program, importedName);
1709
1755
  } catch {
1710
1756
  return /* @__PURE__ */ new Set();
1711
1757
  }
1712
1758
  }
1713
- function extractImportDeclarations(code, parseAst7) {
1759
+ function extractImportDeclarations(code, parseAst8) {
1714
1760
  let program;
1715
1761
  try {
1716
- program = parseAst7(code, { lang: "tsx" });
1762
+ program = parseAst8(code, { lang: "tsx" });
1717
1763
  } catch {
1718
1764
  return [];
1719
1765
  }
@@ -1770,10 +1816,10 @@ function isSafeVariableDeclaration(node, handlerNames) {
1770
1816
  (d) => isSafeDeclaratorInit(d.init) && !(d.init?.type === "CallExpression" && d.init.callee?.type === "Identifier" && handlerNames.has(d.init.callee.name))
1771
1817
  );
1772
1818
  }
1773
- function extractModuleLevelDeclarations(code, parseAst7, handlerNames) {
1819
+ function extractModuleLevelDeclarations(code, parseAst8, handlerNames) {
1774
1820
  let program;
1775
1821
  try {
1776
- program = parseAst7(code, { lang: "tsx" });
1822
+ program = parseAst8(code, { lang: "tsx" });
1777
1823
  } catch {
1778
1824
  return [];
1779
1825
  }
@@ -1804,17 +1850,17 @@ function extractModuleLevelDeclarations(code, parseAst7, handlerNames) {
1804
1850
  }
1805
1851
  return declarations;
1806
1852
  }
1807
- function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId, parseAst7) {
1808
- const sites = findHandlerCalls(code, fnName, parseAst7);
1853
+ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId, parseAst8) {
1854
+ const sites = findHandlerCalls(code, fnName, parseAst8);
1809
1855
  const inlineSites = sites.filter((site) => site.exportInfo === null);
1810
1856
  if (inlineSites.length === 0) return false;
1811
- const imports = extractImportDeclarations(code, parseAst7);
1812
- const staticNames = getImportedLocalNames(code, "Static", parseAst7);
1813
- const prerenderNames = getImportedLocalNames(code, "Prerender", parseAst7);
1857
+ const imports = extractImportDeclarations(code, parseAst8);
1858
+ const staticNames = getImportedLocalNames(code, "Static", parseAst8);
1859
+ const prerenderNames = getImportedLocalNames(code, "Prerender", parseAst8);
1814
1860
  const handlerNames = /* @__PURE__ */ new Set([...staticNames, ...prerenderNames]);
1815
1861
  const declarations = extractModuleLevelDeclarations(
1816
1862
  code,
1817
- parseAst7,
1863
+ parseAst8,
1818
1864
  handlerNames
1819
1865
  );
1820
1866
  const importStatements = [];
@@ -1837,7 +1883,7 @@ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtu
1837
1883
  }
1838
1884
  if (importStatements.length > 0) {
1839
1885
  const importBlock = importStatements.join("\n") + "\n";
1840
- const insertionPos = findImportInsertionPos(code, parseAst7);
1886
+ const insertionPos = findImportInsertionPos(code, parseAst8);
1841
1887
  if (insertionPos === 0) {
1842
1888
  s.prepend(importBlock);
1843
1889
  } else {
@@ -2379,6 +2425,57 @@ ${binding.localName}.$$id = "${handlerId}";`;
2379
2425
  // src/vite/plugins/expose-internal-ids.ts
2380
2426
  init_debug();
2381
2427
 
2428
+ // src/vite/utils/compare-strings.ts
2429
+ function compareStrings(a, b) {
2430
+ return a < b ? -1 : a > b ? 1 : 0;
2431
+ }
2432
+
2433
+ // src/vite/discovery/state.ts
2434
+ var VIRTUAL_ROUTES_MANIFEST_ID = "virtual:rsc-router/routes-manifest";
2435
+ var VIRTUAL_LOADER_MANIFEST_ID = "virtual:rsc-router/loader-manifest";
2436
+ function createDiscoveryState(entryPath, opts) {
2437
+ return {
2438
+ resolvedEntryPath: entryPath,
2439
+ projectRoot: "",
2440
+ isBuildMode: false,
2441
+ userResolveAlias: void 0,
2442
+ userRunnerConfig: void 0,
2443
+ userResolvePlugins: [],
2444
+ scanFilter: void 0,
2445
+ cachedRouterFiles: void 0,
2446
+ opts,
2447
+ mergedRouteManifest: null,
2448
+ perRouterManifests: [],
2449
+ perRouterTrieMap: /* @__PURE__ */ new Map(),
2450
+ perRouterPrecomputedMap: /* @__PURE__ */ new Map(),
2451
+ perRouterManifestDataMap: /* @__PURE__ */ new Map(),
2452
+ clientUrlSourceByReferenceId: /* @__PURE__ */ new Map(),
2453
+ clientUrlProjectionMap: /* @__PURE__ */ new Map(),
2454
+ prerenderManifestEntries: null,
2455
+ staticManifestEntries: null,
2456
+ shellCandidates: null,
2457
+ prerenderPayloadValues: null,
2458
+ shellPhaseTempServer: null,
2459
+ serverBuildGraph: null,
2460
+ clientBuildGraph: null,
2461
+ ssrBundle: null,
2462
+ versionModuleFiles: /* @__PURE__ */ new Map(),
2463
+ buildData: [],
2464
+ handlerChunkInfoMap: /* @__PURE__ */ new Map(),
2465
+ staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
2466
+ rscEntryFileName: null,
2467
+ resolvedPrerenderModules: void 0,
2468
+ resolvedStaticModules: void 0,
2469
+ discoveryDone: null,
2470
+ devDiscoveryEpoch: opts?.preset === "cloudflare" ? Date.now() : void 0,
2471
+ devServerOrigin: null,
2472
+ devServer: null,
2473
+ selfWrittenGenFiles: /* @__PURE__ */ new Map(),
2474
+ SELF_WRITE_WINDOW_MS: 5e3,
2475
+ lastDiscoveryError: null
2476
+ };
2477
+ }
2478
+
2382
2479
  // src/vite/plugins/expose-ids/router-transform.ts
2383
2480
  import MagicString2 from "magic-string";
2384
2481
  import path3 from "node:path";
@@ -2401,15 +2498,16 @@ function skipLeadingTrivia(code, start, end) {
2401
2498
  }
2402
2499
  return i;
2403
2500
  }
2501
+ function routerId(filePath, callIndex) {
2502
+ return createHash("sha256").update(`${filePath}#${callIndex}`).digest("hex").slice(0, 8);
2503
+ }
2404
2504
  function transformRouter(code, filePath, routerFnNames, absolutePath, warn) {
2405
- const pat = new RegExp(
2406
- `\\b(?:${routerFnNames.map(escapeRegExp).join("|")})\\b`,
2407
- "g"
2408
- );
2505
+ const pat = createCallPattern(routerFnNames);
2409
2506
  let match;
2410
2507
  const s = new MagicString2(code);
2411
2508
  let changed = false;
2412
2509
  const unsupportedSites = [];
2510
+ let callIndex = -1;
2413
2511
  const basename2 = path3.basename(filePath).replace(/\.(tsx?|jsx?)$/, "");
2414
2512
  const routeNamesImport = `./${basename2}.named-routes.gen.js`;
2415
2513
  const routeNamesVar = `__rsc_rn`;
@@ -2421,13 +2519,12 @@ function transformRouter(code, filePath, routerFnNames, absolutePath, warn) {
2421
2519
  const calleeEnd = match.index + match[0].length;
2422
2520
  const parenPos = findCallParenAfterGenerics(code, calleeEnd);
2423
2521
  if (parenPos === -1) continue;
2522
+ callIndex++;
2424
2523
  const closeParen = findMatchingParen(code, parenPos + 1);
2425
2524
  const callArgs = code.slice(parenPos + 1, closeParen);
2426
2525
  if (callArgs.includes(`$$routeNames: ${routeNamesVar}`)) continue;
2427
2526
  const sourceFilePath = absolutePath ?? filePath;
2428
- const lineNumber = code.slice(0, callStart).split("\n").length;
2429
- const hash = createHash("sha256").update(`${filePath}:${lineNumber}`).digest("hex").slice(0, 8);
2430
- const injected = ` $$id: "${hash}", $$sourceFile: "${sourceFilePath}", $$routeNames: ${routeNamesVar},`;
2527
+ const injected = ` $$id: "${routerId(filePath, callIndex)}", $$sourceFile: "${sourceFilePath}", $$routeNames: ${routeNamesVar},`;
2431
2528
  const argsContentStart = skipLeadingTrivia(code, parenPos + 1, closeParen);
2432
2529
  const firstArgChar = code[argsContentStart];
2433
2530
  if (firstArgChar === "{") {
@@ -2437,9 +2534,7 @@ function transformRouter(code, filePath, routerFnNames, absolutePath, warn) {
2437
2534
  changed = true;
2438
2535
  s.appendRight(parenPos + 1, `{${injected} }`);
2439
2536
  } else {
2440
- const lastNl = code.lastIndexOf("\n", callStart - 1);
2441
- const column = callStart - (lastNl + 1) + 1;
2442
- unsupportedSites.push({ line: lineNumber, column });
2537
+ unsupportedSites.push(offsetToLineColumn(code, callStart));
2443
2538
  }
2444
2539
  }
2445
2540
  if (unsupportedSites.length > 0 && warn) {
@@ -2459,11 +2554,13 @@ function transformRouter(code, filePath, routerFnNames, absolutePath, warn) {
2459
2554
  }
2460
2555
  function exposeRouterId() {
2461
2556
  let projectRoot = "";
2557
+ let rootRelativeSourceFile = false;
2462
2558
  const counter = createCounter(debug2, "expose-router-id");
2463
2559
  return {
2464
2560
  name: "@rangojs/router:expose-router-id",
2465
2561
  configResolved(config) {
2466
2562
  projectRoot = config.root;
2563
+ rootRelativeSourceFile = config.command === "build";
2467
2564
  },
2468
2565
  buildEnd() {
2469
2566
  counter?.flush();
@@ -2485,7 +2582,7 @@ function exposeRouterId() {
2485
2582
  code,
2486
2583
  filePath,
2487
2584
  routerFnNames,
2488
- normalizePath(id),
2585
+ rootRelativeSourceFile ? void 0 : normalizePath(id),
2489
2586
  warn
2490
2587
  );
2491
2588
  } finally {
@@ -2497,7 +2594,7 @@ function exposeRouterId() {
2497
2594
 
2498
2595
  // src/vite/plugins/expose-internal-ids.ts
2499
2596
  var debug3 = createRangoDebugger(NS.transform);
2500
- var VIRTUAL_LOADER_MANIFEST = "virtual:rsc-router/loader-manifest";
2597
+ var VIRTUAL_LOADER_MANIFEST = VIRTUAL_LOADER_MANIFEST_ID;
2501
2598
  var RESOLVED_VIRTUAL_LOADER_MANIFEST = "\0" + VIRTUAL_LOADER_MANIFEST;
2502
2599
  var VIRTUAL_HANDLER_PREFIX = "virtual:handler-extract:";
2503
2600
  function createLoaderScanStubPlugin() {
@@ -2568,8 +2665,8 @@ function exposeInternalIds(options) {
2568
2665
  prerenderHandlerModules,
2569
2666
  staticHandlerModules
2570
2667
  },
2571
- configResolved(resolved) {
2572
- config = resolved;
2668
+ configResolved(resolved2) {
2669
+ config = resolved2;
2573
2670
  isBuild = options?.forceBuild || config.command === "build";
2574
2671
  projectRoot = config.root;
2575
2672
  },
@@ -2607,7 +2704,10 @@ setLoaderImports({});
2607
2704
  `;
2608
2705
  }
2609
2706
  const lazyImports = [];
2610
- for (const [hashedId, { filePath, exportName }] of loaderRegistry) {
2707
+ const sortedLoaders = [...loaderRegistry].sort(
2708
+ ([a], [b]) => compareStrings(a, b)
2709
+ );
2710
+ for (const [hashedId, { filePath, exportName }] of sortedLoaders) {
2611
2711
  lazyImports.push(
2612
2712
  ` "${hashedId}": () => import("/${filePath}").then(m => m.${exportName})`
2613
2713
  );
@@ -3103,8 +3203,8 @@ async function transformUseCache(code, id, options) {
3103
3203
  const { hasDirective: hasDirective2, transformWrapExport, transformHoistInlineDirective } = rscTransforms;
3104
3204
  let ast;
3105
3205
  try {
3106
- const { parseAst: parseAst7 } = await import("vite");
3107
- ast = parseAst7(code, { lang: "tsx" });
3206
+ const { parseAst: parseAst8 } = await import("vite");
3207
+ ast = parseAst8(code, { lang: "tsx" });
3108
3208
  } catch {
3109
3209
  return;
3110
3210
  }
@@ -3395,37 +3495,37 @@ function analyzeScopes(program) {
3395
3495
  if (!pattern) return;
3396
3496
  switch (pattern.type) {
3397
3497
  case "Identifier":
3398
- if (pattern.typeAnnotation) walk2(pattern.typeAnnotation, scope, true);
3498
+ if (pattern.typeAnnotation) walk3(pattern.typeAnnotation, scope, true);
3399
3499
  return;
3400
3500
  case "ObjectPattern":
3401
3501
  for (const prop of pattern.properties) {
3402
3502
  if (prop.type === "RestElement") {
3403
3503
  walkPattern(prop.argument, scope, typeOnly);
3404
3504
  } else {
3405
- if (prop.computed) walk2(prop.key, scope, typeOnly);
3505
+ if (prop.computed) walk3(prop.key, scope, typeOnly);
3406
3506
  walkPattern(prop.value, scope, typeOnly);
3407
3507
  }
3408
3508
  }
3409
- if (pattern.typeAnnotation) walk2(pattern.typeAnnotation, scope, true);
3509
+ if (pattern.typeAnnotation) walk3(pattern.typeAnnotation, scope, true);
3410
3510
  return;
3411
3511
  case "ArrayPattern":
3412
3512
  for (const element of pattern.elements) {
3413
3513
  walkPattern(element, scope, typeOnly);
3414
3514
  }
3415
- if (pattern.typeAnnotation) walk2(pattern.typeAnnotation, scope, true);
3515
+ if (pattern.typeAnnotation) walk3(pattern.typeAnnotation, scope, true);
3416
3516
  return;
3417
3517
  case "RestElement":
3418
3518
  walkPattern(pattern.argument, scope, typeOnly);
3419
3519
  return;
3420
3520
  case "AssignmentPattern":
3421
3521
  walkPattern(pattern.left, scope, typeOnly);
3422
- walk2(pattern.right, scope, typeOnly);
3522
+ walk3(pattern.right, scope, typeOnly);
3423
3523
  return;
3424
3524
  case "TSParameterProperty":
3425
3525
  walkPattern(pattern.parameter, scope, typeOnly);
3426
3526
  return;
3427
3527
  default:
3428
- walk2(pattern, scope, typeOnly);
3528
+ walk3(pattern, scope, typeOnly);
3429
3529
  }
3430
3530
  };
3431
3531
  const hoistDeclarations = (statements, scope) => {
@@ -3459,44 +3559,44 @@ function analyzeScopes(program) {
3459
3559
  }
3460
3560
  }
3461
3561
  };
3462
- const walk2 = (node, scope, typeOnly) => {
3562
+ const walk3 = (node, scope, typeOnly) => {
3463
3563
  if (!node || typeof node !== "object") return;
3464
3564
  if (Array.isArray(node)) {
3465
- for (const item of node) walk2(item, scope, typeOnly);
3565
+ for (const item of node) walk3(item, scope, typeOnly);
3466
3566
  return;
3467
3567
  }
3468
3568
  if (typeof node.type !== "string") return;
3469
3569
  switch (node.type) {
3470
3570
  case "Identifier":
3471
3571
  references.push({ node, scope, typeOnly });
3472
- if (node.typeAnnotation) walk2(node.typeAnnotation, scope, true);
3572
+ if (node.typeAnnotation) walk3(node.typeAnnotation, scope, true);
3473
3573
  return;
3474
3574
  case "ImportDeclaration":
3475
3575
  case "ExportAllDeclaration":
3476
3576
  return;
3477
3577
  case "ExportNamedDeclaration":
3478
- if (node.declaration) walk2(node.declaration, scope, typeOnly);
3578
+ if (node.declaration) walk3(node.declaration, scope, typeOnly);
3479
3579
  else if (!node.source) {
3480
3580
  for (const spec of node.specifiers) {
3481
- walk2(spec.local, scope, typeOnly || node.exportKind === "type");
3581
+ walk3(spec.local, scope, typeOnly || node.exportKind === "type");
3482
3582
  }
3483
3583
  }
3484
3584
  return;
3485
3585
  case "MemberExpression":
3486
- walk2(node.object, scope, typeOnly);
3487
- if (node.computed) walk2(node.property, scope, typeOnly);
3586
+ walk3(node.object, scope, typeOnly);
3587
+ if (node.computed) walk3(node.property, scope, typeOnly);
3488
3588
  return;
3489
3589
  case "Property":
3490
3590
  case "MethodDefinition":
3491
3591
  case "PropertyDefinition":
3492
3592
  case "TSPropertySignature":
3493
3593
  case "TSMethodSignature":
3494
- if (node.computed) walk2(node.key, scope, typeOnly);
3495
- walk2(node.value, scope, typeOnly);
3496
- if (node.typeAnnotation) walk2(node.typeAnnotation, scope, true);
3594
+ if (node.computed) walk3(node.key, scope, typeOnly);
3595
+ walk3(node.value, scope, typeOnly);
3596
+ if (node.typeAnnotation) walk3(node.typeAnnotation, scope, true);
3497
3597
  return;
3498
3598
  case "LabeledStatement":
3499
- walk2(node.body, scope, typeOnly);
3599
+ walk3(node.body, scope, typeOnly);
3500
3600
  return;
3501
3601
  case "BreakStatement":
3502
3602
  case "ContinueStatement":
@@ -3506,25 +3606,25 @@ function analyzeScopes(program) {
3506
3606
  case "JSXClosingElement": {
3507
3607
  const ref = jsxNameReference(node.name);
3508
3608
  if (ref) references.push({ node: ref, scope, typeOnly });
3509
- walk2(node.typeArguments, scope, true);
3510
- walk2(node.attributes, scope, typeOnly);
3609
+ walk3(node.typeArguments, scope, true);
3610
+ walk3(node.attributes, scope, typeOnly);
3511
3611
  return;
3512
3612
  }
3513
3613
  case "TSQualifiedName":
3514
- walk2(node.left, scope, typeOnly);
3614
+ walk3(node.left, scope, typeOnly);
3515
3615
  return;
3516
3616
  case "TSEnumMember":
3517
- walk2(node.initializer, scope, typeOnly);
3617
+ walk3(node.initializer, scope, typeOnly);
3518
3618
  return;
3519
3619
  case "TSTypeAliasDeclaration":
3520
3620
  case "TSInterfaceDeclaration":
3521
- walk2(node.typeParameters, scope, true);
3522
- walk2(node.typeAnnotation ?? node.body, scope, true);
3523
- walk2(node.extends, scope, true);
3621
+ walk3(node.typeParameters, scope, true);
3622
+ walk3(node.typeAnnotation ?? node.body, scope, true);
3623
+ walk3(node.extends, scope, true);
3524
3624
  return;
3525
3625
  case "VariableDeclarator":
3526
3626
  walkPattern(node.id, scope, typeOnly);
3527
- walk2(node.init, scope, typeOnly);
3627
+ walk3(node.init, scope, typeOnly);
3528
3628
  return;
3529
3629
  case "FunctionDeclaration":
3530
3630
  case "FunctionExpression":
@@ -3535,14 +3635,14 @@ function analyzeScopes(program) {
3535
3635
  fnScope.declarations.add(node.id.name);
3536
3636
  }
3537
3637
  for (const param of node.params) declarePattern(param, fnScope);
3538
- walk2(node.typeParameters, fnScope, true);
3638
+ walk3(node.typeParameters, fnScope, true);
3539
3639
  for (const param of node.params) walkPattern(param, fnScope, typeOnly);
3540
- walk2(node.returnType, fnScope, true);
3640
+ walk3(node.returnType, fnScope, true);
3541
3641
  if (node.body?.type === "BlockStatement") {
3542
3642
  hoistDeclarations(node.body.body, fnScope);
3543
- walk2(node.body.body, fnScope, typeOnly);
3643
+ walk3(node.body.body, fnScope, typeOnly);
3544
3644
  } else {
3545
- walk2(node.body, fnScope, typeOnly);
3645
+ walk3(node.body, fnScope, typeOnly);
3546
3646
  }
3547
3647
  return;
3548
3648
  }
@@ -3554,11 +3654,11 @@ function analyzeScopes(program) {
3554
3654
  classScope.declarations.add(node.id.name);
3555
3655
  scopeOf.set(node, classScope);
3556
3656
  }
3557
- walk2(node.superClass, classScope, typeOnly);
3558
- walk2(node.superTypeArguments, classScope, true);
3559
- walk2(node.typeParameters, classScope, true);
3560
- walk2(node.implements, classScope, true);
3561
- walk2(node.body, classScope, typeOnly);
3657
+ walk3(node.superClass, classScope, typeOnly);
3658
+ walk3(node.superTypeArguments, classScope, true);
3659
+ walk3(node.typeParameters, classScope, true);
3660
+ walk3(node.implements, classScope, true);
3661
+ walk3(node.body, classScope, typeOnly);
3562
3662
  return;
3563
3663
  }
3564
3664
  case "BlockStatement":
@@ -3566,7 +3666,7 @@ function analyzeScopes(program) {
3566
3666
  const blockScope = new Scope(scope, false, node);
3567
3667
  scopeOf.set(node, blockScope);
3568
3668
  hoistDeclarations(node.body, blockScope);
3569
- walk2(node.body, blockScope, typeOnly);
3669
+ walk3(node.body, blockScope, typeOnly);
3570
3670
  return;
3571
3671
  }
3572
3672
  case "ForStatement":
@@ -3579,12 +3679,12 @@ function analyzeScopes(program) {
3579
3679
  hoistDeclarations([head], loopScope);
3580
3680
  }
3581
3681
  for (const key of ["init", "left", "right", "test", "update", "body"]) {
3582
- walk2(node[key], loopScope, typeOnly);
3682
+ walk3(node[key], loopScope, typeOnly);
3583
3683
  }
3584
3684
  return;
3585
3685
  }
3586
3686
  case "SwitchStatement": {
3587
- walk2(node.discriminant, scope, typeOnly);
3687
+ walk3(node.discriminant, scope, typeOnly);
3588
3688
  const switchScope = new Scope(scope, false, node);
3589
3689
  scopeOf.set(node, switchScope);
3590
3690
  hoistDeclarations(
@@ -3592,8 +3692,8 @@ function analyzeScopes(program) {
3592
3692
  switchScope
3593
3693
  );
3594
3694
  for (const c of node.cases) {
3595
- walk2(c.test, switchScope, typeOnly);
3596
- walk2(c.consequent, switchScope, typeOnly);
3695
+ walk3(c.test, switchScope, typeOnly);
3696
+ walk3(c.consequent, switchScope, typeOnly);
3597
3697
  }
3598
3698
  return;
3599
3699
  }
@@ -3604,17 +3704,17 @@ function analyzeScopes(program) {
3604
3704
  declarePattern(node.param, catchScope);
3605
3705
  walkPattern(node.param, catchScope, typeOnly);
3606
3706
  }
3607
- walk2(node.body, catchScope, typeOnly);
3707
+ walk3(node.body, catchScope, typeOnly);
3608
3708
  return;
3609
3709
  }
3610
3710
  }
3611
3711
  for (const key of Object.keys(node)) {
3612
3712
  if (key === "type" || key === "start" || key === "end") continue;
3613
- walk2(node[key], scope, typeOnly || TYPE_KEYS.has(key));
3713
+ walk3(node[key], scope, typeOnly || TYPE_KEYS.has(key));
3614
3714
  }
3615
3715
  };
3616
3716
  hoistDeclarations(program.body, moduleScope);
3617
- walk2(program.body, moduleScope, false);
3717
+ walk3(program.body, moduleScope, false);
3618
3718
  return { moduleScope, references, scopeOf };
3619
3719
  }
3620
3720
  function collectImports(program) {
@@ -4044,9 +4144,9 @@ function transitionWhenHoistPlugin() {
4044
4144
  emitted.delete(file);
4045
4145
  const result = await hoistTransitionWhens(code, id, {
4046
4146
  isServerOnlyImport: async (source) => {
4047
- const resolved = await this.resolve(source, id);
4048
- if (!resolved || resolved.external) return false;
4049
- const target = resolved.id.split("?", 1)[0];
4147
+ const resolved2 = await this.resolve(source, id);
4148
+ if (!resolved2 || resolved2.external) return false;
4149
+ const target = resolved2.id.split("?", 1)[0];
4050
4150
  if (target.includes("/node_modules/") || target.startsWith("\0")) {
4051
4151
  return false;
4052
4152
  }
@@ -4207,9 +4307,9 @@ async function resolvePublicSpecifier(source, metadata, installedSpecifier, reso
4207
4307
  source
4208
4308
  )) {
4209
4309
  try {
4210
- const resolved = await resolvePackage(candidate, importer);
4211
- if (!resolved) continue;
4212
- const resolvedId = stripQueryAndHash(resolved);
4310
+ const resolved2 = await resolvePackage(candidate, importer);
4311
+ if (!resolved2) continue;
4312
+ const resolvedId = stripQueryAndHash(resolved2);
4213
4313
  if (normalize(resolvedId) === normalize(source) && belongsToPackage(resolvedId, metadata.root)) {
4214
4314
  return candidate;
4215
4315
  }
@@ -4309,6 +4409,26 @@ function clientRefDedup() {
4309
4409
  };
4310
4410
  }
4311
4411
 
4412
+ // src/vite/plugins/stable-rsc-output.ts
4413
+ import { parseAst as parseAst4 } from "vite";
4414
+
4415
+ // src/vite/discovery/build-versions.ts
4416
+ import { createHash as createHash3 } from "node:crypto";
4417
+ import { isBuiltin } from "node:module";
4418
+ import { posix, relative as relative3 } from "node:path";
4419
+
4420
+ // src/router-versions.ts
4421
+ var DEFAULT_ROUTER_VERSIONS_KEY = "*";
4422
+ function uniformVersions(version) {
4423
+ return { data: version, document: version };
4424
+ }
4425
+ function resolveVersionsFrom(table, routerId2, override) {
4426
+ if (override !== void 0) return uniformVersions(override);
4427
+ if (!table) return void 0;
4428
+ const pair = (routerId2 !== void 0 && Object.hasOwn(table, routerId2) ? table[routerId2] : void 0) ?? table[DEFAULT_ROUTER_VERSIONS_KEY];
4429
+ return pair ? { data: pair[0], document: pair[1] } : void 0;
4430
+ }
4431
+
4312
4432
  // src/vite/plugins/virtual-entries.ts
4313
4433
  var VIRTUAL_ENTRY_BROWSER = `
4314
4434
  import {
@@ -4369,7 +4489,12 @@ function emitProgressiveChunkSize(value) {
4369
4489
  return JSON.stringify(value);
4370
4490
  }
4371
4491
  function getVirtualEntrySSR(headScripts = "preinit", progressiveChunkSize) {
4372
- const preinit = headScripts !== "preload";
4492
+ if (headScripts !== "preinit" && headScripts !== "preload") {
4493
+ throw new Error(
4494
+ `rango({ headScripts }) must be "preinit" or "preload", received ${JSON.stringify(headScripts)}`
4495
+ );
4496
+ }
4497
+ const preinit = headScripts === "preinit";
4373
4498
  const depsImportNames = preinit ? "createFromReadableStream,\n setOnClientReference,\n getClientEntryUrl," : "createFromReadableStream,";
4374
4499
  const ssrImportNames = preinit ? "\n installClientReferencePreinit," : "";
4375
4500
  const install = preinit ? `
@@ -4452,12 +4577,11 @@ import {
4452
4577
  // consults them at router-module evaluation. Router-first would silently push
4453
4578
  // every clientUrls() app onto the deferred-subscription path and change mount
4454
4579
  // registration order with no error. The custom-entry injector keeps the same
4455
- // guarantee by PREPENDING this list at file top (version-injector.ts).
4580
+ // guarantee by PREPENDING this list at file top (entry-bootstrap-injector.ts).
4456
4581
  ${bootstrapImports}
4457
4582
 
4458
4583
  import { router } from "${routerPath}";
4459
4584
  import { createRSCHandler } from "@rangojs/router/internal/rsc-handler";
4460
- import { VERSION } from "@rangojs/router:version";
4461
4585
 
4462
4586
  // Lazily create the handler on first request so that ESM live bindings
4463
4587
  // have resolved by the time we read \`router\`. During HMR the module may
@@ -4467,7 +4591,6 @@ export default function handler(request, env) {
4467
4591
  if (!_handler) {
4468
4592
  _handler = createRSCHandler({
4469
4593
  router,
4470
- version: VERSION,
4471
4594
  // Forward the router's CSP nonce provider. createRSCHandler reads the
4472
4595
  // provider only from options.nonce; without this, createRouter({ nonce })
4473
4596
  // is silently dropped on the Node preset (the Cloudflare path wires it via
@@ -4567,7 +4690,726 @@ var VIRTUAL_IDS = {
4567
4690
  version: "@rangojs/router:version"
4568
4691
  };
4569
4692
  function getVirtualVersionContent(version) {
4570
- return `export const VERSION = ${JSON.stringify(version)};`;
4693
+ return [
4694
+ `export const VERSION = ${JSON.stringify(version)};`,
4695
+ `export const ROUTER_VERSIONS = undefined;`
4696
+ ].join("\n");
4697
+ }
4698
+ var ROUTER_VERSIONS_PLACEHOLDER = "__RANGO_ROUTER_VERSIONS__";
4699
+ function getVirtualBuildVersionContent() {
4700
+ return [
4701
+ `export const ROUTER_VERSIONS = ${ROUTER_VERSIONS_PLACEHOLDER};`,
4702
+ `export const VERSION = ROUTER_VERSIONS[${JSON.stringify(DEFAULT_ROUTER_VERSIONS_KEY)}][1];`
4703
+ ].join("\n");
4704
+ }
4705
+
4706
+ // src/vite/utils/client-chunks.ts
4707
+ init_debug();
4708
+ init_client_ref_hashing();
4709
+ import { gzipSync } from "node:zlib";
4710
+ var debugChunks = createRangoDebugger(NS.chunks);
4711
+ function isSharedRuntime(meta) {
4712
+ return [meta.id, meta.normalizedId].some(
4713
+ (path6) => path6.includes("/node_modules/") || /\/@rangojs\/router\//.test(path6) || /\/packages\/(rangojs-router|rsc-router)\/(src|dist)\//.test(path6)
4714
+ );
4715
+ }
4716
+ function sanitizeGroup(name) {
4717
+ return name.replace(/[^a-zA-Z0-9_-]+/g, "_").replace(/^_+|_+$/g, "") || "app";
4718
+ }
4719
+ var ROUTE_ROOT_DIRS = /* @__PURE__ */ new Set([
4720
+ "routes",
4721
+ "route",
4722
+ "pages",
4723
+ "page",
4724
+ "app",
4725
+ "features",
4726
+ "feature",
4727
+ "views",
4728
+ "view",
4729
+ "handlers",
4730
+ "urls",
4731
+ "modules",
4732
+ "screens",
4733
+ "sections"
4734
+ ]);
4735
+ var SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set(["app"]);
4736
+ function directoryClientChunks(meta, ctx) {
4737
+ if (isSharedRuntime(meta)) {
4738
+ return void 0;
4739
+ }
4740
+ if (ctx?.fallbackRefs.size && ctx.fallbackRefs.has(hashRefKey(meta.normalizedId))) {
4741
+ debugChunks?.("fallback %s -> app-fallback", meta.normalizedId);
4742
+ return "app-fallback";
4743
+ }
4744
+ const segments = meta.normalizedId.split("/").filter(Boolean);
4745
+ const dirCount = segments.length - 1;
4746
+ const isMarkerAt = (i) => i < dirCount - 1 && ROUTE_ROOT_DIRS.has(segments[i].toLowerCase());
4747
+ for (let i = 0; i < dirCount - 1; i++) {
4748
+ if (!isMarkerAt(i)) continue;
4749
+ const marker = SOURCE_ROOT_DIRS.has(segments[i].toLowerCase()) && isMarkerAt(i + 1) ? i + 1 : i;
4750
+ const group = `app-${sanitizeGroup(segments[marker + 1])}`;
4751
+ debugChunks?.("split %s -> %s", meta.normalizedId, group);
4752
+ return group;
4753
+ }
4754
+ debugChunks?.(
4755
+ "shared %s (no route-root marker; inherits default grouping)",
4756
+ meta.normalizedId
4757
+ );
4758
+ return void 0;
4759
+ }
4760
+ function resolveClientChunks(option, ctx) {
4761
+ if (!option) return void 0;
4762
+ if (option === true) return (meta) => directoryClientChunks(meta, ctx);
4763
+ return option;
4764
+ }
4765
+ var CLIENT_REFERENCES_MODULE_ID = "\0virtual:vite-rsc/client-references";
4766
+ var CLIENT_GROUP_PREFIX = `${CLIENT_REFERENCES_MODULE_ID}/group/`;
4767
+ function clientChunksReport(log = debugChunks) {
4768
+ if (!log) return void 0;
4769
+ return {
4770
+ name: "@rangojs/router:client-chunks-report",
4771
+ apply: "build",
4772
+ applyToEnvironment: (env) => env.name === "client",
4773
+ generateBundle(_options, bundle) {
4774
+ for (const chunk of Object.values(bundle)) {
4775
+ if (chunk.type !== "chunk") continue;
4776
+ const facade = chunk.facadeModuleId;
4777
+ if (!facade?.startsWith(CLIENT_GROUP_PREFIX)) continue;
4778
+ log(
4779
+ "group %s: %d client reference(s), %d B (%d B gzip) -> %s",
4780
+ facade.slice(CLIENT_GROUP_PREFIX.length).replaceAll("\0", "\\0"),
4781
+ this.getModuleInfo(facade)?.importedIds.length ?? 0,
4782
+ Buffer.byteLength(chunk.code),
4783
+ gzipSync(chunk.code).length,
4784
+ chunk.fileName
4785
+ );
4786
+ }
4787
+ }
4788
+ };
4789
+ }
4790
+
4791
+ // src/vite/discovery/build-versions.ts
4792
+ function identifier(name) {
4793
+ return new RegExp(`(?<![\\w$.])${escapeRegExp(name)}(?![\\w$])`, "g");
4794
+ }
4795
+ var ENCRYPTION_RUNTIME_ID = "/utils/encryption-runtime";
4796
+ var ENCRYPTION_RUNTIME_IMPORT = /import\s*\*\s*as\s+([A-Za-z_$][\w$]*)\s+from\s*["'][^"'\n]*\/utils\/encryption-runtime[^"'\n]*["']/;
4797
+ function usesEncryptionRuntime(code) {
4798
+ if (code == null) return true;
4799
+ const local = code.match(ENCRYPTION_RUNTIME_IMPORT)?.[1];
4800
+ if (local === void 0) return true;
4801
+ let occurrences = 0;
4802
+ for (const _ of code.matchAll(identifier(local))) {
4803
+ if (++occurrences > 1) return true;
4804
+ }
4805
+ return false;
4806
+ }
4807
+ function recordModuleEdges(context) {
4808
+ const modules = /* @__PURE__ */ new Map();
4809
+ for (const id of context.getModuleIds()) {
4810
+ const info = context.getModuleInfo(id);
4811
+ const imports = info?.importedIds ?? [];
4812
+ const encryptsBoundArgs = imports.some((imported) => imported.includes(ENCRYPTION_RUNTIME_ID)) && usesEncryptionRuntime(info?.code);
4813
+ modules.set(id, {
4814
+ imports,
4815
+ dynamicImports: info?.dynamicallyImportedIds ?? [],
4816
+ ...encryptsBoundArgs ? { encryptsBoundArgs } : void 0
4817
+ });
4818
+ }
4819
+ return modules;
4820
+ }
4821
+ function recordBundleFiles(bundle) {
4822
+ const chunks = [];
4823
+ const assets = [];
4824
+ for (const file of Object.values(bundle)) {
4825
+ if (file.type === "chunk") {
4826
+ chunks.push({
4827
+ fileName: file.fileName,
4828
+ name: file.name ?? file.fileName,
4829
+ moduleIds: file.moduleIds ?? [],
4830
+ externalImports: [
4831
+ ...file.imports ?? [],
4832
+ ...file.dynamicImports ?? []
4833
+ ].filter((specifier) => !Object.hasOwn(bundle, specifier))
4834
+ });
4835
+ } else {
4836
+ assets.push({
4837
+ fileName: file.fileName,
4838
+ name: file.names?.[0] ?? file.fileName
4839
+ });
4840
+ }
4841
+ }
4842
+ return { chunks, assets };
4843
+ }
4844
+ function recordServerGraph(context, bundle) {
4845
+ return { modules: recordModuleEdges(context), ...recordBundleFiles(bundle) };
4846
+ }
4847
+ function recordClientGraph(context, bundle) {
4848
+ return {
4849
+ modules: recordModuleEdges(context),
4850
+ fileNames: Object.values(bundle).map((file) => file.fileName)
4851
+ };
4852
+ }
4853
+ var SERVER_REFERENCES_MODULE_ID = "\0virtual:vite-rsc/server-references";
4854
+ var LOADER_REGISTRY = "\0" + VIRTUAL_LOADER_MANIFEST_ID;
4855
+ var ROUTES_REGISTRY = "\0" + VIRTUAL_ROUTES_MANIFEST_ID;
4856
+ var VERSION_MODULE = "\0" + VIRTUAL_IDS.version;
4857
+ var ENCRYPTION_KEY_FILE = "__vite_rsc_encryption_key.js";
4858
+ function isRegistryModule(id) {
4859
+ return id === SERVER_REFERENCES_MODULE_ID || id === LOADER_REGISTRY || id === ROUTES_REGISTRY || id.startsWith(ROUTES_REGISTRY + "/") || id === CLIENT_REFERENCES_MODULE_ID || id.startsWith(CLIENT_REFERENCES_MODULE_ID + "/");
4860
+ }
4861
+ function routeManifestModuleId(routerId2) {
4862
+ return `${ROUTES_REGISTRY}/${routerId2}`;
4863
+ }
4864
+ function walk(modules, roots, reached) {
4865
+ const stack = [...roots];
4866
+ while (stack.length > 0) {
4867
+ const id = stack.pop();
4868
+ if (reached.has(id)) continue;
4869
+ reached.add(id);
4870
+ if (isRegistryModule(id)) continue;
4871
+ const edges = modules.get(id);
4872
+ if (!edges) continue;
4873
+ for (const next of edges.imports) {
4874
+ if (!reached.has(next)) stack.push(next);
4875
+ }
4876
+ for (const next of edges.dynamicImports) {
4877
+ if (!reached.has(next)) stack.push(next);
4878
+ }
4879
+ }
4880
+ }
4881
+ function registryTargets(server) {
4882
+ const targets = /* @__PURE__ */ new Set();
4883
+ for (const id of [SERVER_REFERENCES_MODULE_ID, LOADER_REGISTRY]) {
4884
+ for (const target of server.modules.get(id)?.dynamicImports ?? []) {
4885
+ targets.add(target);
4886
+ }
4887
+ }
4888
+ return targets;
4889
+ }
4890
+ function ownersOf(subjects, reachOf) {
4891
+ const owners = /* @__PURE__ */ new Set();
4892
+ for (const [routerId2, reached] of reachOf) {
4893
+ if (subjects.some((id) => reached.has(id))) owners.add(routerId2);
4894
+ }
4895
+ return owners.size > 0 ? owners : void 0;
4896
+ }
4897
+ function extendReach(server, client, targets, reach, roots) {
4898
+ walk(server.modules, roots, reach.server);
4899
+ if (!client || targets.size === 0) return;
4900
+ for (; ; ) {
4901
+ const seeds = [];
4902
+ for (const id of reach.server) {
4903
+ if (!reach.client.has(id) && client.modules.has(id)) seeds.push(id);
4904
+ }
4905
+ if (seeds.length === 0) return;
4906
+ walk(client.modules, seeds, reach.client);
4907
+ const found = [];
4908
+ for (const target of targets) {
4909
+ if (reach.client.has(target) && !reach.server.has(target)) {
4910
+ found.push(target);
4911
+ }
4912
+ }
4913
+ if (found.length === 0) return;
4914
+ walk(server.modules, found, reach.server);
4915
+ }
4916
+ }
4917
+ function findModuleId(modules, path6) {
4918
+ if (modules.has(path6)) return path6;
4919
+ for (const id of modules.keys()) {
4920
+ const query = id.indexOf("?");
4921
+ if (query !== -1 && id.slice(0, query) === path6) return id;
4922
+ }
4923
+ return void 0;
4924
+ }
4925
+ function staticImporters(modules) {
4926
+ const importers = /* @__PURE__ */ new Map();
4927
+ for (const [id, edges] of modules) {
4928
+ if (isRegistryModule(id)) continue;
4929
+ for (const imported of edges.imports) {
4930
+ const list = importers.get(imported);
4931
+ if (list) list.push(id);
4932
+ else importers.set(imported, [id]);
4933
+ }
4934
+ }
4935
+ return importers;
4936
+ }
4937
+ function resolveRouterMembers(server, client, routers) {
4938
+ const targets = registryTargets(server);
4939
+ const importers = staticImporters(server.modules);
4940
+ const reachByRouter = /* @__PURE__ */ new Map();
4941
+ for (const router of routers) {
4942
+ const moduleId = router.moduleId !== void 0 ? findModuleId(server.modules, router.moduleId) : void 0;
4943
+ if (moduleId === void 0) continue;
4944
+ const climbed = /* @__PURE__ */ new Set();
4945
+ const stack = [moduleId];
4946
+ while (stack.length > 0) {
4947
+ const id = stack.pop();
4948
+ if (climbed.has(id)) continue;
4949
+ climbed.add(id);
4950
+ for (const importer of importers.get(id) ?? []) stack.push(importer);
4951
+ }
4952
+ const reach = { server: /* @__PURE__ */ new Set(), client: /* @__PURE__ */ new Set() };
4953
+ extendReach(server, client, targets, reach, climbed);
4954
+ reachByRouter.set(router.id, reach);
4955
+ }
4956
+ const serverReach = new Map(
4957
+ [...reachByRouter].map(([routerId2, reach]) => [routerId2, reach.server])
4958
+ );
4959
+ const unattributed = [...targets].filter(
4960
+ (target) => ownersOf([target], serverReach) === void 0
4961
+ );
4962
+ if (unattributed.length > 0) {
4963
+ for (const reach of reachByRouter.values()) {
4964
+ extendReach(server, client, targets, reach, unattributed);
4965
+ }
4966
+ }
4967
+ const chunkOfModule = /* @__PURE__ */ new Map();
4968
+ for (const chunk of server.chunks) {
4969
+ for (const id of chunk.moduleIds) chunkOfModule.set(id, chunk.fileName);
4970
+ }
4971
+ const members = /* @__PURE__ */ new Map();
4972
+ for (const [routerId2, { server: modules }] of reachByRouter) {
4973
+ const chunkFiles = /* @__PURE__ */ new Set();
4974
+ for (const id of modules) {
4975
+ const fileName = chunkOfModule.get(id);
4976
+ if (fileName !== void 0) chunkFiles.add(fileName);
4977
+ }
4978
+ const manifestChunk = chunkOfModule.get(routeManifestModuleId(routerId2));
4979
+ if (manifestChunk !== void 0) chunkFiles.add(manifestChunk);
4980
+ members.set(routerId2, { modules, chunkFiles });
4981
+ }
4982
+ return members;
4983
+ }
4984
+ function sha256(value) {
4985
+ return createHash3("sha256").update(value).digest("hex");
4986
+ }
4987
+ var baseName = posix.basename;
4988
+ function isAbsolutePath(path6) {
4989
+ return path6.startsWith("/") || /^[A-Za-z]:[\\/]/.test(path6);
4990
+ }
4991
+ var PNPM_PEER_SUFFIX = /(\/\.pnpm\/[^/]+?@[^/_]+)_[^/]+(?=\/)/g;
4992
+ function withoutWorkingDirectory(id) {
4993
+ const kind = /(?:facade|shared):/.exec(id);
4994
+ const virtual = id.indexOf("\0");
4995
+ if (!kind || virtual === -1) return id;
4996
+ const facade = kind.index + kind[0].length;
4997
+ return virtual < facade ? id : id.slice(0, facade) + id.slice(virtual);
4998
+ }
4999
+ function portableModuleId(id, projectRoot) {
5000
+ const path6 = id.startsWith("\0") ? id.slice(1) : id;
5001
+ const nodeModules = path6.indexOf("/node_modules/");
5002
+ if (nodeModules !== -1) {
5003
+ return path6.slice(nodeModules + 1).replace(PNPM_PEER_SUFFIX, "$1");
5004
+ }
5005
+ if (isAbsolutePath(path6)) {
5006
+ return relative3(projectRoot, path6).replaceAll("\\", "/");
5007
+ }
5008
+ return withoutWorkingDirectory(path6).replace(
5009
+ /([?&][^=&]+=)([^&]+)/g,
5010
+ (whole, name, value) => {
5011
+ let decoded;
5012
+ try {
5013
+ decoded = decodeURIComponent(value);
5014
+ } catch {
5015
+ return whole;
5016
+ }
5017
+ return isAbsolutePath(decoded) ? name + portableModuleId(decoded, projectRoot) : whole;
5018
+ }
5019
+ );
5020
+ }
5021
+ var SERVER_CSS_MODULE = /^virtual:vite-rsc\/css\?type=rsc&id=([^&]+)/;
5022
+ function isSourceMap(fileName) {
5023
+ return fileName.endsWith(".map");
5024
+ }
5025
+ var SERVER_REFERENCES_REGION_START = `//#region \\0${SERVER_REFERENCES_MODULE_ID.slice(1)}
5026
+ `;
5027
+ var REGION_END = "//#endregion";
5028
+ function stripServerReferenceMap(source) {
5029
+ const start = source.indexOf(SERVER_REFERENCES_REGION_START);
5030
+ if (start === -1) return source;
5031
+ const bodyStart = start + SERVER_REFERENCES_REGION_START.length;
5032
+ const end = source.indexOf(REGION_END, bodyStart);
5033
+ if (end === -1) return source;
5034
+ return source.slice(0, bodyStart) + source.slice(end);
5035
+ }
5036
+ var REGION_LINE = /^\/\/#region .*$/gm;
5037
+ function stripRegionPaths(source) {
5038
+ return source.replace(REGION_LINE, "//#region");
5039
+ }
5040
+ var FILE_REFERENCE = "\0";
5041
+ var FOREIGN_FILE = "~";
5042
+ function digestBundle(bundle, projectRoot, read, label) {
5043
+ const named = [];
5044
+ for (const chunk of bundle.chunks) {
5045
+ const ids = chunk.moduleIds.map((id) => portableModuleId(id, projectRoot)).sort();
5046
+ const ext = posix.extname(chunk.fileName);
5047
+ named.push({
5048
+ fileName: chunk.fileName,
5049
+ identity: `${chunk.name}~${sha256(ids.join("\n")).slice(0, 8)}${ext}`,
5050
+ hashedName: baseName(chunk.fileName) !== chunk.name + ext,
5051
+ chunk
5052
+ });
5053
+ }
5054
+ for (const asset of bundle.assets) {
5055
+ if (isSourceMap(asset.fileName)) continue;
5056
+ named.push({
5057
+ fileName: asset.fileName,
5058
+ identity: asset.name,
5059
+ hashedName: baseName(asset.fileName) !== baseName(asset.name)
5060
+ });
5061
+ }
5062
+ const fileOfBaseName = /* @__PURE__ */ new Map();
5063
+ for (const file of named) {
5064
+ if (file.hashedName) {
5065
+ fileOfBaseName.set(baseName(file.fileName), file.fileName);
5066
+ }
5067
+ }
5068
+ const reference = fileOfBaseName.size > 0 ? new RegExp(
5069
+ [...fileOfBaseName.keys()].sort((a, b) => b.length - a.length).map(escapeRegExp).join("|"),
5070
+ "g"
5071
+ ) : void 0;
5072
+ const decoder3 = new TextDecoder();
5073
+ return named.map(({ fileName, identity, chunk }) => {
5074
+ const bytes = read(fileName);
5075
+ if (bytes === void 0) {
5076
+ throw new Error(
5077
+ `the ${label} bundle lists ${fileName}, which is not in its output directory`
5078
+ );
5079
+ }
5080
+ if (!chunk) {
5081
+ return {
5082
+ fileName,
5083
+ identity,
5084
+ base: sha256(bytes),
5085
+ references: [],
5086
+ externalImports: []
5087
+ };
5088
+ }
5089
+ const references = [];
5090
+ const text = stripRegionPaths(
5091
+ stripServerReferenceMap(decoder3.decode(bytes))
5092
+ );
5093
+ const blanked = reference ? text.replace(reference, (name) => {
5094
+ references.push(fileOfBaseName.get(name));
5095
+ return FILE_REFERENCE;
5096
+ }) : text;
5097
+ return {
5098
+ fileName,
5099
+ identity,
5100
+ base: sha256(blanked),
5101
+ references,
5102
+ externalImports: chunk.externalImports ?? []
5103
+ };
5104
+ });
5105
+ }
5106
+ function digestAsOwned(file, identityOf, owned) {
5107
+ if (file.references.length === 0) return file.base;
5108
+ return sha256(
5109
+ JSON.stringify([
5110
+ file.base,
5111
+ ...file.references.map(
5112
+ (name) => owned.has(name) ? identityOf.get(name) : FOREIGN_FILE
5113
+ )
5114
+ ])
5115
+ );
5116
+ }
5117
+ var RUNTIME_SCHEME = /^(?:node|cloudflare|workerd|bun):/;
5118
+ var REPLACED_MARKER = /^(?:__CLOUDFLARE_MODULE__.*__CLOUDFLARE_MODULE__|virtual:vite-rsc\/assets-manifest)$/;
5119
+ var PACKAGE_NAME = /^(?:@[\w.~-]+\/)?[A-Za-z0-9~-][\w.~-]*$/;
5120
+ function classifyExternal(specifier) {
5121
+ if (/^[./\\]/.test(specifier) || isAbsolutePath(specifier)) {
5122
+ return { kind: "file" };
5123
+ }
5124
+ if (RUNTIME_SCHEME.test(specifier) || specifier.startsWith("data:") || isBuiltin(specifier) || REPLACED_MARKER.test(specifier)) {
5125
+ return { kind: "provided" };
5126
+ }
5127
+ if (specifier.includes(":")) return { kind: "unknown" };
5128
+ const parts = specifier.split("/");
5129
+ const name = specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
5130
+ return PACKAGE_NAME.test(name) ? { kind: "package", name } : { kind: "unknown" };
5131
+ }
5132
+ function externalInputs(file, context) {
5133
+ const { externals, undetermined } = context;
5134
+ const inputs = [];
5135
+ const add = (name, value) => {
5136
+ if (value === void 0) undetermined.add(name);
5137
+ inputs.push([
5138
+ `external ${name}`,
5139
+ sha256(value ?? `undetermined ${externals.buildId}`)
5140
+ ]);
5141
+ };
5142
+ for (const specifier of file.externalImports) {
5143
+ const external = classifyExternal(specifier);
5144
+ if (external.kind === "package") {
5145
+ add(external.name, externals.describePackage(external.name));
5146
+ } else if (external.kind === "file") {
5147
+ if (isAbsolutePath(specifier)) {
5148
+ const inProject = portableModuleId(specifier, context.projectRoot);
5149
+ add(
5150
+ inProject.startsWith("..") ? specifier : inProject,
5151
+ externals.readFile(specifier)
5152
+ );
5153
+ } else {
5154
+ const fileName = posix.join(
5155
+ posix.dirname(file.fileName),
5156
+ specifier.replaceAll("\\", "/")
5157
+ );
5158
+ add(fileName, context.read(fileName));
5159
+ }
5160
+ } else if (external.kind === "unknown") {
5161
+ add(specifier, void 0);
5162
+ }
5163
+ }
5164
+ return inputs;
5165
+ }
5166
+ var VERSION_HEX_LENGTH = 16;
5167
+ function byName(a, b) {
5168
+ return compareStrings(a[0], b[0]) || compareStrings(a[1], b[1]);
5169
+ }
5170
+ function distinct(inputs) {
5171
+ const sorted = [...inputs].sort(byName);
5172
+ return sorted.filter(
5173
+ (item, index) => index === 0 || byName(item, sorted[index - 1]) !== 0
5174
+ );
5175
+ }
5176
+ function hashInputs(label, inputs) {
5177
+ return sha256(`${label}
5178
+ ${JSON.stringify(inputs)}`).slice(
5179
+ 0,
5180
+ VERSION_HEX_LENGTH
5181
+ );
5182
+ }
5183
+ function serverCssRecords(server, projectRoot, serverResources) {
5184
+ if (serverResources.size === 0) return [];
5185
+ const moduleOf = /* @__PURE__ */ new Map();
5186
+ for (const id of server.modules.keys()) {
5187
+ const key = portableModuleId(id, projectRoot).match(SERVER_CSS_MODULE)?.[1];
5188
+ if (key !== void 0) moduleOf.set(key, id);
5189
+ }
5190
+ return [...serverResources].map(([key, entry]) => ({
5191
+ kind: "server-css",
5192
+ key,
5193
+ digest: sha256(entry),
5194
+ moduleId: moduleOf.get(key)
5195
+ }));
5196
+ }
5197
+ function computeRouterVersions(input) {
5198
+ const { server, projectRoot } = input;
5199
+ const undetermined = /* @__PURE__ */ new Set();
5200
+ const files = digestBundle(server, projectRoot, input.readServerFile, "RSC");
5201
+ const identityOf = new Map(
5202
+ files.map((file) => [file.fileName, file.identity])
5203
+ );
5204
+ const assetFiles = new Set(server.assets.map((asset) => asset.fileName));
5205
+ const externalContext = {
5206
+ projectRoot,
5207
+ externals: input.externals,
5208
+ read: input.readServerFile,
5209
+ undetermined
5210
+ };
5211
+ const externalsOf = new Map(
5212
+ files.map((file) => [file.fileName, externalInputs(file, externalContext)])
5213
+ );
5214
+ const members = resolveRouterMembers(server, input.client, input.routers);
5215
+ const reachOf = new Map(
5216
+ [...members].map(([routerId2, member]) => [routerId2, member.modules])
5217
+ );
5218
+ const owned = [
5219
+ ...input.buildData,
5220
+ ...serverCssRecords(
5221
+ server,
5222
+ projectRoot,
5223
+ input.serverResources ?? /* @__PURE__ */ new Map()
5224
+ )
5225
+ ].map(
5226
+ (record) => ({
5227
+ input: [`${record.kind} ${record.key}`, record.digest],
5228
+ version: record.kind === "prerender" ? "document" : "data",
5229
+ owners: record.routerId !== void 0 ? /* @__PURE__ */ new Set([record.routerId]) : ownersOf(
5230
+ record.moduleId === void 0 ? [] : [record.moduleId],
5231
+ reachOf
5232
+ )
5233
+ })
5234
+ );
5235
+ const encrypting = [...server.modules].filter(([, edges]) => edges.encryptsBoundArgs).map(([id]) => id);
5236
+ const keyFile = input.readServerFile(ENCRYPTION_KEY_FILE);
5237
+ if (keyFile !== void 0) {
5238
+ owned.push({
5239
+ input: ["encryption-key", sha256(keyFile)],
5240
+ version: "data",
5241
+ owners: ownersOf(encrypting, reachOf)
5242
+ });
5243
+ } else if (encrypting.length > 0) {
5244
+ throw new Error(
5245
+ `${encrypting.length} server module(s) encrypt action arguments (${portableModuleId(encrypting[0], projectRoot)}), but ${ENCRYPTION_KEY_FILE} is not in the RSC output directory, so the key cannot be made part of their cache version. The installed @vitejs/plugin-rsc keeps the key somewhere @rangojs/router does not know. Report it with the plugin-rsc version.`
5246
+ );
5247
+ }
5248
+ const keyInput = owned.find((item) => item.input[0] === "encryption-key");
5249
+ const ssrFiles = digestBundle(
5250
+ input.ssr,
5251
+ projectRoot,
5252
+ input.readSsrFile,
5253
+ "SSR"
5254
+ );
5255
+ const ssrIdentityOf = new Map(
5256
+ ssrFiles.map((file) => [file.fileName, file.identity])
5257
+ );
5258
+ const everySsrFile = new Set(ssrFiles.map((file) => file.fileName));
5259
+ const ssrAndClient = {
5260
+ base: input.base,
5261
+ ssr: distinct(
5262
+ ssrFiles.map((file) => [
5263
+ file.identity,
5264
+ digestAsOwned(file, ssrIdentityOf, everySsrFile)
5265
+ ])
5266
+ ),
5267
+ externals: distinct(
5268
+ ssrFiles.flatMap(
5269
+ (file) => externalInputs(file, { ...externalContext, read: input.readSsrFile })
5270
+ )
5271
+ ),
5272
+ client: [...input.client.fileNames].sort()
5273
+ };
5274
+ const documentDigest = sha256(JSON.stringify(ssrAndClient));
5275
+ const table = {};
5276
+ const details = [];
5277
+ const ownedByARouter = /* @__PURE__ */ new Set();
5278
+ const add = (routerId2, chunkFiles) => {
5279
+ const whole = chunkFiles === void 0;
5280
+ const ownedFiles = new Set(
5281
+ chunkFiles ?? files.map((file) => file.fileName)
5282
+ );
5283
+ for (const file of files) {
5284
+ if (!ownedFiles.has(file.fileName)) continue;
5285
+ for (const name of file.references) {
5286
+ if (assetFiles.has(name)) ownedFiles.add(name);
5287
+ }
5288
+ }
5289
+ const inputs = {
5290
+ data: [],
5291
+ document: [["ssr-and-client", documentDigest]]
5292
+ };
5293
+ for (const file of files) {
5294
+ if (!ownedFiles.has(file.fileName)) continue;
5295
+ if (!whole) ownedByARouter.add(file.fileName);
5296
+ inputs.data.push(
5297
+ [`file ${file.identity}`, digestAsOwned(file, identityOf, ownedFiles)],
5298
+ ...externalsOf.get(file.fileName)
5299
+ );
5300
+ }
5301
+ for (const item of owned) {
5302
+ if (whole || item.owners === void 0 || item.owners.has(routerId2)) {
5303
+ inputs[item.version].push(item.input);
5304
+ }
5305
+ }
5306
+ const dataInputs = distinct(inputs.data);
5307
+ const documentInputs = distinct(inputs.document);
5308
+ const data = hashInputs("rango-data-version", dataInputs);
5309
+ const document2 = hashInputs(
5310
+ `rango-document-version
5311
+ ${data}`,
5312
+ documentInputs
5313
+ );
5314
+ table[routerId2] = [data, document2];
5315
+ details.push({
5316
+ routerId: routerId2,
5317
+ data,
5318
+ document: document2,
5319
+ dataInputs,
5320
+ documentInputs,
5321
+ usesEncryptionKey: keyInput !== void 0 && (whole || keyInput.owners === void 0 || keyInput.owners.has(routerId2))
5322
+ });
5323
+ };
5324
+ for (const router of input.routers) {
5325
+ const member = members.get(router.id);
5326
+ if (member) add(router.id, member.chunkFiles);
5327
+ }
5328
+ add(DEFAULT_ROUTER_VERSIONS_KEY);
5329
+ return {
5330
+ table,
5331
+ details,
5332
+ ssrAndClient,
5333
+ unownedFiles: files.filter((file) => !ownedByARouter.has(file.fileName)).map((file) => file.identity).sort(),
5334
+ undetermined: [...undetermined].sort()
5335
+ };
5336
+ }
5337
+ function recordVersionModuleFiles(bundle) {
5338
+ return Object.values(bundle).filter(
5339
+ (file) => file.type === "chunk" && file.moduleIds?.includes(VERSION_MODULE)
5340
+ ).map((file) => file.fileName);
5341
+ }
5342
+ function fillRouterVersions(source, table) {
5343
+ if (!source.includes(ROUTER_VERSIONS_PLACEHOLDER)) return void 0;
5344
+ const json = JSON.stringify(table);
5345
+ return source.replaceAll(ROUTER_VERSIONS_PLACEHOLDER, () => json);
5346
+ }
5347
+
5348
+ // src/vite/plugins/stable-rsc-output.ts
5349
+ function literalProperties(object) {
5350
+ if (object?.type !== "ObjectExpression") return void 0;
5351
+ const properties = [];
5352
+ for (const property of object.properties ?? []) {
5353
+ const key = property?.type === "Property" && !property.computed ? property.key?.value ?? property.key?.name : void 0;
5354
+ if (typeof key !== "string") return void 0;
5355
+ properties.push({
5356
+ key,
5357
+ start: property.start,
5358
+ end: property.end,
5359
+ value: property.value
5360
+ });
5361
+ }
5362
+ return properties;
5363
+ }
5364
+ function defaultExportProperties(code) {
5365
+ let program;
5366
+ try {
5367
+ program = parseAst4(code);
5368
+ } catch {
5369
+ return void 0;
5370
+ }
5371
+ return literalProperties(
5372
+ (program.body ?? []).find(
5373
+ (node) => node?.type === "ExportDefaultDeclaration"
5374
+ )?.declaration
5375
+ );
5376
+ }
5377
+ function sortDefaultExportProperties(code) {
5378
+ const properties = defaultExportProperties(code);
5379
+ if (!properties || properties.length < 2) return void 0;
5380
+ const sorted = [...properties].sort((a, b) => compareStrings(a.key, b.key));
5381
+ if (sorted.every((property, index) => property === properties[index])) {
5382
+ return void 0;
5383
+ }
5384
+ return code.slice(0, properties[0].start) + sorted.map((property) => code.slice(property.start, property.end)).join(",\n") + code.slice(properties[properties.length - 1].end);
5385
+ }
5386
+ var ASSETS_MANIFEST_ID = "virtual:vite-rsc/assets-manifest";
5387
+ var ASSETS_MANIFEST_IMPORT = /import\s+([A-Za-z_$][\w$]*)\s+from\s*["']virtual:vite-rsc\/assets-manifest["']/;
5388
+ var ASSETS_MANIFEST_BINDING = "assetsManifest";
5389
+ var GENERATED_BINDINGS = /* @__PURE__ */ new Set([
5390
+ "__vite_rsc_assets_manifest__",
5391
+ "__vite_rsc_assets_manifest"
5392
+ ]);
5393
+ function identifier2(name) {
5394
+ return new RegExp(`(?<![\\w$.])${escapeRegExp(name)}(?![\\w$])`, "g");
5395
+ }
5396
+ function canonicalAssetsManifestBinding(code) {
5397
+ const local = code.match(ASSETS_MANIFEST_IMPORT)?.[1];
5398
+ if (local === void 0 || !GENERATED_BINDINGS.has(local)) return void 0;
5399
+ if (identifier2(ASSETS_MANIFEST_BINDING).test(code)) return void 0;
5400
+ return code.replace(identifier2(local), ASSETS_MANIFEST_BINDING);
5401
+ }
5402
+ function stableRscOutput() {
5403
+ return {
5404
+ name: "@rangojs/router:stable-rsc-output",
5405
+ apply: "build",
5406
+ // After plugin-rsc's transforms, which add the manifest import.
5407
+ enforce: "post",
5408
+ transform(code, id) {
5409
+ const stable = id === SERVER_REFERENCES_MODULE_ID ? sortDefaultExportProperties(code) : code.includes(ASSETS_MANIFEST_ID) ? canonicalAssetsManifestBinding(code) : void 0;
5410
+ return stable === void 0 ? null : { code: stable, map: null };
5411
+ }
5412
+ };
4571
5413
  }
4572
5414
 
4573
5415
  // src/vite/utils/package-resolution.ts
@@ -4578,7 +5420,7 @@ import { resolve } from "node:path";
4578
5420
  // package.json
4579
5421
  var package_default = {
4580
5422
  name: "@rangojs/router",
4581
- version: "0.19.1",
5423
+ version: "0.21.0",
4582
5424
  description: "Django-inspired RSC router with composable URL patterns",
4583
5425
  keywords: [
4584
5426
  "react",
@@ -4809,7 +5651,6 @@ var package_default = {
4809
5651
  "@playwright/test": "^1.49.1",
4810
5652
  "@testing-library/react": ">=16",
4811
5653
  "@vercel/functions": "^3.0.0",
4812
- "@vitejs/plugin-rsc": "^0.5.35",
4813
5654
  react: ">=19.2.8 <20",
4814
5655
  "react-dom": ">=19.2.8 <20",
4815
5656
  vite: "^8.0.16",
@@ -4889,7 +5730,8 @@ function getVendorAliases() {
4889
5730
  const specs = [
4890
5731
  "@vitejs/plugin-rsc/vendor/react-server-dom/client.browser",
4891
5732
  "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
4892
- "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
5733
+ "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
5734
+ "@vitejs/plugin-rsc/vendor/react-server-dom/static.edge"
4893
5735
  ];
4894
5736
  const aliases = {};
4895
5737
  for (const spec of specs) {
@@ -5028,7 +5870,7 @@ declare global {
5028
5870
  }
5029
5871
 
5030
5872
  // src/build/route-types/scan-filter.ts
5031
- import { join as join2, relative as relative2 } from "node:path";
5873
+ import { join as join2, relative as relative4 } from "node:path";
5032
5874
  import { readdirSync } from "node:fs";
5033
5875
  import picomatch from "picomatch";
5034
5876
  var DEFAULT_EXCLUDE_PATTERNS = [
@@ -5048,7 +5890,7 @@ function createScanFilter(root, opts) {
5048
5890
  const includeMatcher = hasInclude ? picomatch(include) : null;
5049
5891
  const excludeMatcher = effectiveExclude.length > 0 ? picomatch(effectiveExclude) : null;
5050
5892
  return (absolutePath) => {
5051
- const rel = relative2(root, absolutePath);
5893
+ const rel = relative4(root, absolutePath);
5052
5894
  if (excludeMatcher && excludeMatcher(rel)) return false;
5053
5895
  if (includeMatcher) return includeMatcher(rel);
5054
5896
  return true;
@@ -5227,7 +6069,7 @@ function extractIncludesWithDiagnostics(code, sourceFileArg) {
5227
6069
  true,
5228
6070
  ts3.ScriptKind.TSX
5229
6071
  );
5230
- const resolved = [];
6072
+ const resolved2 = [];
5231
6073
  const unresolvable = [];
5232
6074
  function visit(node) {
5233
6075
  if (ts3.isCallExpression(node)) {
@@ -5246,13 +6088,13 @@ function extractIncludesWithDiagnostics(code, sourceFileArg) {
5246
6088
  const namePrefix = extractNamePrefixFromInclude(node);
5247
6089
  const dynamicImportSpec = extractDynamicImportSpecifier(secondArg);
5248
6090
  if (ts3.isIdentifier(secondArg)) {
5249
- resolved.push({
6091
+ resolved2.push({
5250
6092
  pathPrefix,
5251
6093
  variableName: secondArg.text,
5252
6094
  namePrefix
5253
6095
  });
5254
6096
  } else if (dynamicImportSpec !== null) {
5255
- resolved.push({
6097
+ resolved2.push({
5256
6098
  pathPrefix,
5257
6099
  moduleSpecifier: dynamicImportSpec,
5258
6100
  namePrefix
@@ -5278,7 +6120,7 @@ function extractIncludesWithDiagnostics(code, sourceFileArg) {
5278
6120
  ts3.forEachChild(node, visit);
5279
6121
  }
5280
6122
  visit(sourceFile);
5281
- return { resolved, unresolvable };
6123
+ return { resolved: resolved2, unresolvable };
5282
6124
  }
5283
6125
  function resolveImportedVariable(code, localName) {
5284
6126
  const defaultImportRegex = /import\s+([\w$]+)\s*(?:,\s*\{[^}]*\})?\s+from\s*["']([^"']+)["']/g;
@@ -5419,7 +6261,7 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
5419
6261
  );
5420
6262
  } else {
5421
6263
  const variableName = def.variableName;
5422
- const resolved = resolveIncludedVariable({
6264
+ const resolved2 = resolveIncludedVariable({
5423
6265
  variableName,
5424
6266
  resolutionFile: targetFile,
5425
6267
  resolutionSource: targetSource,
@@ -5432,12 +6274,12 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
5432
6274
  fileNotFoundDetail: (specifier) => `import("${inc.moduleSpecifier}") default re-exports "${variableName}" from "${specifier}", which resolved to no file`,
5433
6275
  notFoundDetail: () => `import("${inc.moduleSpecifier}") default "${variableName}" not found in its imports or same-file scope`
5434
6276
  });
5435
- if (!resolved) continue;
5436
- childResult = resolved;
6277
+ if (!resolved2) continue;
6278
+ childResult = resolved2;
5437
6279
  }
5438
6280
  } else if (inc.variableName) {
5439
6281
  const variableName = inc.variableName;
5440
- const resolved = resolveIncludedVariable({
6282
+ const resolved2 = resolveIncludedVariable({
5441
6283
  variableName,
5442
6284
  resolutionFile: filePath,
5443
6285
  resolutionSource: fullSource,
@@ -5450,8 +6292,8 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
5450
6292
  fileNotFoundDetail: (specifier) => `import "${specifier}" resolved to no file`,
5451
6293
  notFoundDetail: () => `variable "${variableName}" not found in imports or same-file scope`
5452
6294
  });
5453
- if (!resolved) continue;
5454
- childResult = resolved;
6295
+ if (!resolved2) continue;
6296
+ childResult = resolved2;
5455
6297
  } else {
5456
6298
  continue;
5457
6299
  }
@@ -6036,14 +6878,14 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
6036
6878
  }
6037
6879
 
6038
6880
  // src/vite/plugins/version-plugin.ts
6039
- import { parseAst as parseAst5 } from "vite";
6881
+ import { parseAst as parseAst6 } from "vite";
6040
6882
 
6041
6883
  // src/vite/utils/directive-prologue.ts
6042
- import { parseAst as parseAst4 } from "vite";
6884
+ import { parseAst as parseAst5 } from "vite";
6043
6885
  function hasUseClientDirective2(source) {
6044
6886
  let program;
6045
6887
  try {
6046
- program = parseAst4(source, { lang: "tsx" });
6888
+ program = parseAst5(source, { lang: "tsx" });
6047
6889
  } catch {
6048
6890
  return false;
6049
6891
  }
@@ -6068,7 +6910,7 @@ function getClientModuleSignature(source) {
6068
6910
  if (!hasUseClientDirective2(source)) return void 0;
6069
6911
  let program;
6070
6912
  try {
6071
- program = parseAst5(source, { lang: "tsx" });
6913
+ program = parseAst6(source, { lang: "tsx" });
6072
6914
  } catch {
6073
6915
  return void 0;
6074
6916
  }
@@ -6136,8 +6978,7 @@ function getClientModuleSignature(source) {
6136
6978
  };
6137
6979
  }
6138
6980
  function createVersionPlugin() {
6139
- const buildVersion = Date.now().toString(16);
6140
- let currentVersion3 = buildVersion;
6981
+ let currentVersion3 = Date.now().toString(16);
6141
6982
  let isDev = false;
6142
6983
  let server = null;
6143
6984
  let resolvedCacheDir;
@@ -6157,13 +6998,6 @@ function createVersionPlugin() {
6157
6998
  return {
6158
6999
  name: "@rangojs/router:version",
6159
7000
  enforce: "pre",
6160
- // The build-time shell capture phase (producer B, #699) stamps entries
6161
- // with THIS instance's version — the value folded into the shipped worker
6162
- // — never the discovery temp server's own version-plugin value (a
6163
- // different Date.now() stamp that would fail the serve-side gate).
6164
- api: {
6165
- getBuildVersion: () => currentVersion3
6166
- },
6167
7001
  configResolved(config) {
6168
7002
  isDev = config.command === "serve";
6169
7003
  resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
@@ -6185,7 +7019,7 @@ function createVersionPlugin() {
6185
7019
  },
6186
7020
  load(id) {
6187
7021
  if (id === "\0" + VIRTUAL_IDS.version) {
6188
- return getVirtualVersionContent(currentVersion3);
7022
+ return isDev ? getVirtualVersionContent(currentVersion3) : getVirtualBuildVersionContent();
6189
7023
  }
6190
7024
  return null;
6191
7025
  },
@@ -6256,7 +7090,7 @@ import { isAbsolute as isAbsolute2, resolve as resolve4 } from "node:path";
6256
7090
  // src/vite/plugins/performance-tracks.ts
6257
7091
  init_debug();
6258
7092
  import { readFile as readFile2 } from "node:fs/promises";
6259
- var debug5 = createRangoDebugger(NS.transform);
7093
+ var debug6 = createRangoDebugger(NS.transform);
6260
7094
  var RSDW_PATCH_RE = /((?:var|let|const)\s+\w+\s*=\s*root\._children\s*,\s*(\w+)\s*=\s*root\._debugInfo\s*[;,])/;
6261
7095
  function buildPatchReplacement(match, debugInfoVar) {
6262
7096
  return `${match}
@@ -6291,7 +7125,7 @@ function performanceTracksOptimizeDepsPlugin() {
6291
7125
  };
6292
7126
  }
6293
7127
  function performanceTracksPlugin() {
6294
- const counter = createCounter(debug5, "performance-tracks");
7128
+ const counter = createCounter(debug6, "performance-tracks");
6295
7129
  return {
6296
7130
  name: "@rangojs/router:performance-tracks",
6297
7131
  buildEnd() {
@@ -6303,7 +7137,7 @@ function performanceTracksPlugin() {
6303
7137
  try {
6304
7138
  const patched = patchRsdwClientDebugInfoRecovery(code);
6305
7139
  if (!patched.debugInfoVar) return;
6306
- debug5?.("patched RSDW client (var: %s)", patched.debugInfoVar);
7140
+ debug6?.("patched RSDW client (var: %s)", patched.debugInfoVar);
6307
7141
  return patched.code;
6308
7142
  } finally {
6309
7143
  counter?.record(id, performance.now() - start);
@@ -6440,65 +7274,6 @@ function getManualChunks(id) {
6440
7274
  return void 0;
6441
7275
  }
6442
7276
 
6443
- // src/vite/utils/client-chunks.ts
6444
- init_debug();
6445
- init_client_ref_hashing();
6446
- var debugChunks = createRangoDebugger(NS.chunks);
6447
- function isSharedRuntime(meta) {
6448
- return [meta.id, meta.normalizedId].some(
6449
- (path6) => path6.includes("/node_modules/") || /\/@rangojs\/router\//.test(path6) || /\/packages\/(rangojs-router|rsc-router)\/(src|dist)\//.test(path6)
6450
- );
6451
- }
6452
- function sanitizeGroup(name) {
6453
- return name.replace(/[^a-zA-Z0-9_-]+/g, "_").replace(/^_+|_+$/g, "") || "app";
6454
- }
6455
- var ROUTE_ROOT_DIRS = /* @__PURE__ */ new Set([
6456
- "routes",
6457
- "route",
6458
- "pages",
6459
- "page",
6460
- "app",
6461
- "features",
6462
- "feature",
6463
- "views",
6464
- "view",
6465
- "handlers",
6466
- "urls",
6467
- "modules",
6468
- "screens",
6469
- "sections"
6470
- ]);
6471
- function directoryClientChunks(meta, ctx) {
6472
- if (isSharedRuntime(meta)) {
6473
- return void 0;
6474
- }
6475
- if (ctx?.fallbackRefs.size && ctx.fallbackRefs.has(hashRefKey(meta.normalizedId))) {
6476
- debugChunks?.("fallback %s -> app-fallback", meta.normalizedId);
6477
- return "app-fallback";
6478
- }
6479
- const segments = meta.normalizedId.split("/").filter(Boolean);
6480
- const dirCount = segments.length - 1;
6481
- if (dirCount >= 1) {
6482
- for (let i = 0; i < dirCount - 1; i++) {
6483
- if (ROUTE_ROOT_DIRS.has(segments[i].toLowerCase())) {
6484
- const group = `app-${sanitizeGroup(segments[i + 1])}`;
6485
- debugChunks?.("split %s -> %s", meta.normalizedId, group);
6486
- return group;
6487
- }
6488
- }
6489
- }
6490
- debugChunks?.(
6491
- "shared %s (no route-root marker; inherits default grouping)",
6492
- meta.normalizedId
6493
- );
6494
- return void 0;
6495
- }
6496
- function resolveClientChunks(option, ctx) {
6497
- if (!option) return void 0;
6498
- if (option === true) return (meta) => directoryClientChunks(meta, ctx);
6499
- return option;
6500
- }
6501
-
6502
7277
  // src/vite/plugins/vercel-output.ts
6503
7278
  import { rm, mkdir, cp, writeFile } from "node:fs/promises";
6504
7279
  import { existsSync as existsSync5 } from "node:fs";
@@ -6775,13 +7550,13 @@ ${dim} ${reset}${bold}\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550$
6775
7550
  console.log(banner);
6776
7551
  }
6777
7552
 
6778
- // src/vite/plugins/version-injector.ts
7553
+ // src/vite/plugins/entry-bootstrap-injector.ts
6779
7554
  import { resolve as resolve6 } from "node:path";
6780
7555
  import * as Vite2 from "vite";
6781
- function createVersionInjectorPlugin(rscEntryPath) {
7556
+ function createEntryBootstrapInjectorPlugin(rscEntryPath) {
6782
7557
  let resolvedEntryPath = "";
6783
7558
  return {
6784
- name: "@rangojs/router:version-injector",
7559
+ name: "@rangojs/router:entry-bootstrap-injector",
6785
7560
  enforce: "pre",
6786
7561
  configResolved(config) {
6787
7562
  let entryPath = rscEntryPath;
@@ -6800,16 +7575,7 @@ function createVersionInjectorPlugin(rscEntryPath) {
6800
7575
  const prepend = RSC_ENTRY_BOOTSTRAP_IMPORTS.map(
6801
7576
  (id2) => `import "${id2}";`
6802
7577
  );
6803
- let newCode = code;
6804
- const needsVersion = code.includes("createRSCHandler") && !code.includes("@rangojs/router:version") && /createRSCHandler\s*\(\s*\{/.test(code);
6805
- if (needsVersion) {
6806
- prepend.push(`import { VERSION } from "@rangojs/router:version";`);
6807
- newCode = newCode.replace(
6808
- /createRSCHandler\s*\(\s*\{/,
6809
- "createRSCHandler({\n version: VERSION,"
6810
- );
6811
- }
6812
- const lines = newCode.split("\n");
7578
+ const lines = code.split("\n");
6813
7579
  let insertAt = 0;
6814
7580
  while (insertAt < lines.length) {
6815
7581
  const trimmed = lines[insertAt].trim();
@@ -6819,7 +7585,7 @@ function createVersionInjectorPlugin(rscEntryPath) {
6819
7585
  break;
6820
7586
  }
6821
7587
  }
6822
- newCode = [
7588
+ const newCode = [
6823
7589
  ...lines.slice(0, insertAt),
6824
7590
  ...prepend,
6825
7591
  ...lines.slice(insertAt)
@@ -6897,8 +7663,8 @@ function createCjsToEsmPlugin() {
6897
7663
 
6898
7664
  // src/vite/router-discovery.ts
6899
7665
  import { createServer as createViteServer } from "vite";
6900
- import { resolve as resolve12 } from "node:path";
6901
- import { readFileSync as readFileSync9 } from "node:fs";
7666
+ import { dirname as dirname7, join as join10, resolve as resolve13 } from "node:path";
7667
+ import { existsSync as existsSync12, readFileSync as readFileSync11 } from "node:fs";
6902
7668
  import { createRequire as createRequire3, register } from "node:module";
6903
7669
  import { pathToFileURL as pathToFileURL2 } from "node:url";
6904
7670
 
@@ -7081,7 +7847,7 @@ function createCloudflareProtocolStubPlugin() {
7081
7847
  return null;
7082
7848
  }
7083
7849
  const hits = [];
7084
- walk(ast, (node) => {
7850
+ walk2(ast, (node) => {
7085
7851
  if (!IMPORT_NODE_TYPES.has(node.type)) return;
7086
7852
  const source = node.source;
7087
7853
  if (!source || source.type !== "Literal") return;
@@ -7119,10 +7885,10 @@ function createCloudflareProtocolStubPlugin() {
7119
7885
  }
7120
7886
  };
7121
7887
  }
7122
- function walk(node, visit) {
7888
+ function walk2(node, visit) {
7123
7889
  if (!node || typeof node !== "object") return;
7124
7890
  if (Array.isArray(node)) {
7125
- for (const child of node) walk(child, visit);
7891
+ for (const child of node) walk2(child, visit);
7126
7892
  return;
7127
7893
  }
7128
7894
  const n = node;
@@ -7132,7 +7898,7 @@ function walk(node, visit) {
7132
7898
  if (key === "loc" || key === "start" || key === "end" || key === "range") {
7133
7899
  continue;
7134
7900
  }
7135
- walk(n[key], visit);
7901
+ walk2(n[key], visit);
7136
7902
  }
7137
7903
  }
7138
7904
 
@@ -7264,51 +8030,11 @@ function evictHandlerCode(code, exports, fnName, brand) {
7264
8030
  };
7265
8031
  }
7266
8032
 
7267
- // src/vite/discovery/state.ts
7268
- var VIRTUAL_ROUTES_MANIFEST_ID = "virtual:rsc-router/routes-manifest";
7269
- function createDiscoveryState(entryPath, opts) {
7270
- return {
7271
- resolvedEntryPath: entryPath,
7272
- projectRoot: "",
7273
- isBuildMode: false,
7274
- userResolveAlias: void 0,
7275
- userRunnerConfig: void 0,
7276
- userResolvePlugins: [],
7277
- scanFilter: void 0,
7278
- cachedRouterFiles: void 0,
7279
- opts,
7280
- mergedRouteManifest: null,
7281
- perRouterManifests: [],
7282
- perRouterTrieMap: /* @__PURE__ */ new Map(),
7283
- perRouterPrecomputedMap: /* @__PURE__ */ new Map(),
7284
- perRouterManifestDataMap: /* @__PURE__ */ new Map(),
7285
- clientUrlSourceByReferenceId: /* @__PURE__ */ new Map(),
7286
- clientUrlProjectionMap: /* @__PURE__ */ new Map(),
7287
- prerenderManifestEntries: null,
7288
- staticManifestEntries: null,
7289
- shellCandidates: null,
7290
- prerenderPayloadValues: null,
7291
- shellPhaseTempServer: null,
7292
- handlerChunkInfoMap: /* @__PURE__ */ new Map(),
7293
- staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
7294
- rscEntryFileName: null,
7295
- resolvedPrerenderModules: void 0,
7296
- resolvedStaticModules: void 0,
7297
- discoveryDone: null,
7298
- devDiscoveryEpoch: opts?.preset === "cloudflare" ? Date.now() : void 0,
7299
- devServerOrigin: null,
7300
- devServer: null,
7301
- selfWrittenGenFiles: /* @__PURE__ */ new Map(),
7302
- SELF_WRITE_WINDOW_MS: 5e3,
7303
- lastDiscoveryError: null
7304
- };
7305
- }
7306
-
7307
8033
  // src/vite/discovery/self-gen-tracking.ts
7308
- import { createHash as createHash3 } from "node:crypto";
8034
+ import { createHash as createHash4 } from "node:crypto";
7309
8035
  import { readFileSync as readFileSync4 } from "node:fs";
7310
8036
  function markSelfGenWrite(state, filePath, content) {
7311
- const hash = createHash3("sha256").update(content).digest("hex");
8037
+ const hash = createHash4("sha256").update(content).digest("hex");
7312
8038
  state.selfWrittenGenFiles.set(filePath, { at: Date.now(), hash });
7313
8039
  }
7314
8040
  function consumeSelfGenWrite(state, filePath) {
@@ -7326,7 +8052,7 @@ function checkSelfGenWrite(state, filePath, consume) {
7326
8052
  }
7327
8053
  try {
7328
8054
  const current = readFileSync4(filePath, "utf-8");
7329
- const currentHash = createHash3("sha256").update(current).digest("hex");
8055
+ const currentHash = createHash4("sha256").update(current).digest("hex");
7330
8056
  if (currentHash === info.hash) {
7331
8057
  if (consume) state.selfWrittenGenFiles.delete(filePath);
7332
8058
  return true;
@@ -7820,7 +8546,7 @@ function contextSet(variables, keyOrVar, value, options) {
7820
8546
  }
7821
8547
 
7822
8548
  // src/vite/utils/prerender-utils.ts
7823
- import { createHash as createHash4 } from "node:crypto";
8549
+ import { createHash as createHash5 } from "node:crypto";
7824
8550
  import {
7825
8551
  copyFileSync,
7826
8552
  existsSync as existsSync6,
@@ -7984,15 +8710,16 @@ function resolvePrerenderError(registry, error, onError, label, elapsed, phase,
7984
8710
  notifyOnError(registry, error, phase, routeKey, pathname);
7985
8711
  throw error;
7986
8712
  }
8713
+ var RANGO_BUILD_DIR = "node_modules/.rangojs-router-build";
7987
8714
  function getStagedAssetDir(projectRoot) {
7988
- return resolve7(projectRoot, "node_modules/.rangojs-router-build/rsc-assets");
8715
+ return resolve7(projectRoot, RANGO_BUILD_DIR, "rsc-assets");
7989
8716
  }
7990
8717
  function resetStagedBuildAssets(projectRoot) {
7991
8718
  rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
7992
8719
  }
7993
8720
  function writeBuildAssetModule(dir, prefix, exportValue) {
7994
8721
  mkdirSync(dir, { recursive: true });
7995
- const contentHash = createHash4("sha256").update(exportValue).digest("hex").slice(0, 8);
8722
+ const contentHash = createHash5("sha256").update(exportValue).digest("hex").slice(0, 8);
7996
8723
  const fileName = `${prefix}-${contentHash}.js`;
7997
8724
  const filePath = resolve7(dir, fileName);
7998
8725
  if (!existsSync6(filePath)) {
@@ -8025,6 +8752,14 @@ function copyStagedBuildAssets(projectRoot, fileNames) {
8025
8752
  // src/vite/discovery/prerender-collection.ts
8026
8753
  init_debug();
8027
8754
  var debug9 = createRangoDebugger(NS.prerender);
8755
+ function recordBuildData(state, kind, key, value, owner) {
8756
+ state.buildData.push({
8757
+ kind,
8758
+ key,
8759
+ digest: sha256(value),
8760
+ ...owner
8761
+ });
8762
+ }
8028
8763
  async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
8029
8764
  if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
8030
8765
  const overallStart = debug9 ? performance.now() : 0;
@@ -8201,7 +8936,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
8201
8936
  group.concurrency,
8202
8937
  async (entry) => {
8203
8938
  const startUrl = performance.now();
8204
- for (const [, routerInstance] of registry) {
8939
+ for (const [routerId2, routerInstance] of registry) {
8205
8940
  if (!routerInstance.matchForPrerender) continue;
8206
8941
  try {
8207
8942
  const result = await routerInstance.matchForPrerender(
@@ -8231,6 +8966,9 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
8231
8966
  "__pr",
8232
8967
  mainValue
8233
8968
  );
8969
+ recordBuildData(state, "prerender", mainKey, mainValue, {
8970
+ routerId: routerId2
8971
+ });
8234
8972
  if (result.ppr !== void 0 && result.ppr !== false) {
8235
8973
  (state.shellCandidates ??= []).push({
8236
8974
  urlPath: entry.urlPath,
@@ -8256,6 +8994,15 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
8256
8994
  "__pr",
8257
8995
  interceptValue
8258
8996
  );
8997
+ recordBuildData(
8998
+ state,
8999
+ "prerender",
9000
+ interceptKey,
9001
+ interceptValue,
9002
+ {
9003
+ routerId: routerId2
9004
+ }
9005
+ );
8259
9006
  }
8260
9007
  const elapsed = (performance.now() - startUrl).toFixed(0);
8261
9008
  console.log(
@@ -8358,6 +9105,9 @@ async function renderStaticHandlers(state, rscEnv, registry) {
8358
9105
  "__st",
8359
9106
  exportValue
8360
9107
  );
9108
+ recordBuildData(state, "static", def.$$id, exportValue, {
9109
+ moduleId
9110
+ });
8361
9111
  const elapsed = (performance.now() - startHandler).toFixed(0);
8362
9112
  console.log(`[rango] OK ${name.padEnd(40)} (${elapsed}ms)`);
8363
9113
  staticDone++;
@@ -8504,8 +9254,8 @@ init_client_ref_hashing();
8504
9254
 
8505
9255
  // src/vite/discovery/client-urls-projection.ts
8506
9256
  import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
8507
- import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve8 } from "node:path";
8508
- import { normalizePath as normalizePath5, parseAst as parseAst6 } from "vite";
9257
+ import { isAbsolute as isAbsolute3, relative as relative5, resolve as resolve8 } from "node:path";
9258
+ import { normalizePath as normalizePath5, parseAst as parseAst7 } from "vite";
8509
9259
 
8510
9260
  // src/client-urls/server-projection.ts
8511
9261
  import * as React5 from "react";
@@ -8519,7 +9269,7 @@ function isUnderTestRunner() {
8519
9269
  import {
8520
9270
  Component as Component3,
8521
9271
  createElement as createElement3,
8522
- useContext as useContext16,
9272
+ useContext as useContext17,
8523
9273
  useMemo as useMemo8,
8524
9274
  Suspense as Suspense2
8525
9275
  } from "react";
@@ -8531,6 +9281,7 @@ import {
8531
9281
  useEffect,
8532
9282
  useRef,
8533
9283
  useOptimistic,
9284
+ useSyncExternalStore,
8534
9285
  startTransition
8535
9286
  } from "react";
8536
9287
 
@@ -8607,6 +9358,11 @@ function createHandle(collect, __injectedId) {
8607
9358
  // src/browser/react/context.ts
8608
9359
  import { createContext } from "react";
8609
9360
  var NavigationStoreContext = createContext(null);
9361
+ var LocationStateContext = createContext(void 0);
9362
+
9363
+ // src/browser/react/subscribe-to-nothing.ts
9364
+ var subscribeToNothing = () => () => {
9365
+ };
8610
9366
 
8611
9367
  // src/handles/meta.ts
8612
9368
  function isUnsetDescriptor(descriptor) {
@@ -9375,7 +10131,7 @@ import {
9375
10131
  useEffect as useEffect14,
9376
10132
  useMemo as useMemo7,
9377
10133
  useRef as useRef12,
9378
- useSyncExternalStore
10134
+ useSyncExternalStore as useSyncExternalStore2
9379
10135
  } from "react";
9380
10136
 
9381
10137
  // src/browser/react/use-link-status.ts
@@ -9617,8 +10373,6 @@ function isPrefetchScopeDisabled(element) {
9617
10373
  // src/browser/react/Link.tsx
9618
10374
  init_loader();
9619
10375
  import { jsx as jsx8 } from "react/jsx-runtime";
9620
- var IGNORE_STRATEGY_CHANGES = (_listener) => () => {
9621
- };
9622
10376
  function isExternalUrl(href2, origin) {
9623
10377
  if (href2.startsWith("//")) return true;
9624
10378
  if (href2.startsWith("http://") || href2.startsWith("https://")) {
@@ -9660,8 +10414,8 @@ var Link = forwardRef(function Link2({
9660
10414
  return to === "/" ? bn : bn + to;
9661
10415
  }, [to, isExternal, ctx?.basename]);
9662
10416
  const configuredStrategy = prefetch ?? ctx?.defaultPrefetch ?? getDefaultPrefetchStrategy();
9663
- const resolvedStrategy = useSyncExternalStore(
9664
- configuredStrategy === "adaptive" ? subscribeToAdaptiveStrategyChange : IGNORE_STRATEGY_CHANGES,
10417
+ const resolvedStrategy = useSyncExternalStore2(
10418
+ configuredStrategy === "adaptive" ? subscribeToAdaptiveStrategyChange : subscribeToNothing,
9665
10419
  () => resolveAdaptiveStrategy(configuredStrategy),
9666
10420
  () => configuredStrategy === "adaptive" ? "hover" : configuredStrategy
9667
10421
  );
@@ -9848,7 +10602,7 @@ var Breadcrumbs = createHandle(
9848
10602
  );
9849
10603
 
9850
10604
  // src/browser/react/location-state.ts
9851
- import { useState as useState14, useEffect as useEffect15, useRef as useRef13 } from "react";
10605
+ import { useContext as useContext16, useEffect as useEffect15, useSyncExternalStore as useSyncExternalStore3 } from "react";
9852
10606
 
9853
10607
  // src/href-client.ts
9854
10608
  function href(path6, mount) {
@@ -9995,7 +10749,7 @@ import {
9995
10749
  useDeferredValue,
9996
10750
  useEffect as useEffect16,
9997
10751
  useMemo as useMemo9,
9998
- useState as useState15
10752
+ useState as useState14
9999
10753
  } from "react";
10000
10754
 
10001
10755
  // src/client-urls/navigation.ts
@@ -10181,7 +10935,7 @@ var debug10 = createRangoDebugger(NS.discovery);
10181
10935
  function hasDefaultExport(code) {
10182
10936
  let program;
10183
10937
  try {
10184
- program = parseAst6(code, { lang: "tsx" });
10938
+ program = parseAst7(code, { lang: "tsx" });
10185
10939
  } catch {
10186
10940
  return false;
10187
10941
  }
@@ -10209,7 +10963,7 @@ function recordClientUrlsModule(state, code, id) {
10209
10963
  }
10210
10964
  const source = normalizeSource(state, id);
10211
10965
  const projectRoot = normalizePath5(resolve8(state.projectRoot));
10212
- const relativeId = normalizePath5(relative4(projectRoot, source));
10966
+ const relativeId = normalizePath5(relative5(projectRoot, source));
10213
10967
  const outsideProject = relativeId === ".." || relativeId.startsWith("../") || isAbsolute3(relativeId);
10214
10968
  const devReferenceKey = outsideProject ? `/@fs${source}` : `/${relativeId}`;
10215
10969
  const sourceByReferenceId = state.clientUrlSourceByReferenceId ??= /* @__PURE__ */ new Map();
@@ -10544,7 +11298,7 @@ async function discoverRouters(state, rscEnv, ssrEnv) {
10544
11298
  for (const [map2, fn] of perRouterSetters) {
10545
11299
  const setter = serverMod[fn];
10546
11300
  if (typeof setter !== "function") continue;
10547
- for (const [routerId, value] of map2) setter(routerId, value);
11301
+ for (const [routerId2, value] of map2) setter(routerId2, value);
10548
11302
  }
10549
11303
  await expandPrerenderRoutes(state, rscEnv, registry, allManifests);
10550
11304
  await renderStaticHandlers(state, rscEnv, registry);
@@ -10552,20 +11306,337 @@ async function discoverRouters(state, rscEnv, ssrEnv) {
10552
11306
  }
10553
11307
 
10554
11308
  // src/vite/discovery/shell-prerender-phase.ts
10555
- import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "node:fs";
10556
- import { join as join5, resolve as resolve9 } from "node:path";
11309
+ import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
11310
+ import { join as join7, resolve as resolve10 } from "node:path";
10557
11311
 
10558
11312
  // src/prerender/shell-manifest-key.ts
10559
11313
  function buildShellManifestKey(pathname) {
10560
11314
  return pathname;
10561
11315
  }
10562
11316
 
11317
+ // src/vite/discovery/router-versions-phase.ts
11318
+ import { randomUUID } from "node:crypto";
11319
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
11320
+ import { dirname as dirname4, join as join6, resolve as resolve9 } from "node:path";
11321
+ init_debug();
11322
+
11323
+ // src/vite/discovery/installed-packages.ts
11324
+ import { createHash as createHash6 } from "node:crypto";
11325
+ import {
11326
+ existsSync as existsSync8,
11327
+ readdirSync as readdirSync3,
11328
+ readFileSync as readFileSync6,
11329
+ realpathSync,
11330
+ statSync as statSync2
11331
+ } from "node:fs";
11332
+ import { dirname as dirname3, join as join5, sep as sep2 } from "node:path";
11333
+ function linkTarget(path6) {
11334
+ try {
11335
+ return statSync2(path6);
11336
+ } catch {
11337
+ return void 0;
11338
+ }
11339
+ }
11340
+ function digestDirectory(dir) {
11341
+ const hash = createHash6("sha256");
11342
+ const entered = /* @__PURE__ */ new Set();
11343
+ const visit = (current, prefix) => {
11344
+ const real = realpathSync(current);
11345
+ if (entered.has(real)) return;
11346
+ entered.add(real);
11347
+ const entries = readdirSync3(current, { withFileTypes: true }).sort(
11348
+ (a, b) => compareStrings(a.name, b.name)
11349
+ );
11350
+ for (const entry of entries) {
11351
+ if (entry.name === "node_modules" || entry.name === ".git") continue;
11352
+ const path6 = join5(current, entry.name);
11353
+ const name = `${prefix}${entry.name}`;
11354
+ const kind = entry.isSymbolicLink() ? linkTarget(path6) : entry;
11355
+ if (kind?.isDirectory()) {
11356
+ visit(path6, `${name}/`);
11357
+ } else if (kind?.isFile()) {
11358
+ const bytes = readFileSync6(path6);
11359
+ hash.update(`${name}\0${bytes.byteLength}\0`);
11360
+ hash.update(bytes);
11361
+ }
11362
+ }
11363
+ };
11364
+ visit(dir, "");
11365
+ return hash.digest("hex");
11366
+ }
11367
+ function findPackageDir(name, from) {
11368
+ for (let dir = from; ; ) {
11369
+ const candidate = join5(dir, "node_modules", name);
11370
+ if (existsSync8(join5(candidate, "package.json"))) {
11371
+ return realpathSync(candidate);
11372
+ }
11373
+ const parent = dirname3(dir);
11374
+ if (parent === dir) return void 0;
11375
+ dir = parent;
11376
+ }
11377
+ }
11378
+ function createInstalledPackageDescriber(projectRoot) {
11379
+ const packages = /* @__PURE__ */ new Map();
11380
+ const read = (dir) => {
11381
+ if (packages.has(dir)) return packages.get(dir);
11382
+ let manifest;
11383
+ try {
11384
+ manifest = JSON.parse(readFileSync6(join5(dir, "package.json"), "utf-8"));
11385
+ } catch {
11386
+ packages.set(dir, void 0);
11387
+ return void 0;
11388
+ }
11389
+ const linked = !dir.split(sep2).includes("node_modules");
11390
+ const found = {
11391
+ label: `${manifest.name}@${manifest.version}` + (linked ? ` files:${digestDirectory(dir)}` : ""),
11392
+ dependencies: Object.keys({
11393
+ ...manifest.dependencies,
11394
+ ...manifest.optionalDependencies,
11395
+ ...manifest.peerDependencies
11396
+ })
11397
+ };
11398
+ packages.set(dir, found);
11399
+ return found;
11400
+ };
11401
+ const located = /* @__PURE__ */ new Map();
11402
+ const locate = (name, from) => {
11403
+ const key = `${from}\0${name}`;
11404
+ if (!located.has(key)) located.set(key, findPackageDir(name, from));
11405
+ return located.get(key);
11406
+ };
11407
+ const described = /* @__PURE__ */ new Map();
11408
+ return (name) => {
11409
+ if (described.has(name)) return described.get(name);
11410
+ const labels = /* @__PURE__ */ new Set();
11411
+ const seen = /* @__PURE__ */ new Set();
11412
+ const pending = [[name, projectRoot]];
11413
+ while (pending.length > 0) {
11414
+ const [dependency, from] = pending.pop();
11415
+ const dir = locate(dependency, from);
11416
+ if (dir === void 0 || seen.has(dir)) continue;
11417
+ seen.add(dir);
11418
+ const installed = read(dir);
11419
+ if (!installed) continue;
11420
+ labels.add(installed.label);
11421
+ for (const next of installed.dependencies) pending.push([next, dir]);
11422
+ }
11423
+ const text = labels.size > 0 ? [...labels].sort().join("\n") : void 0;
11424
+ described.set(name, text);
11425
+ return text;
11426
+ };
11427
+ }
11428
+
11429
+ // src/vite/discovery/router-versions-phase.ts
11430
+ var debug12 = createRangoDebugger(NS.build);
11431
+ var ASSETS_MANIFEST_FILE = "__vite_rsc_assets_manifest.js";
11432
+ var EMPTY_SERVER_RESOURCES = /"serverResources":\s*\{\s*\}/;
11433
+ function environmentOutDir(builder, projectRoot, environment) {
11434
+ return resolve9(
11435
+ projectRoot,
11436
+ builder?.environments?.[environment]?.config?.build?.outDir ?? join6("dist", environment)
11437
+ );
11438
+ }
11439
+ var VERSIONS_REPORT_FILE = `${RANGO_BUILD_DIR}/cache-versions.json`;
11440
+ function readIfPresent(path6) {
11441
+ try {
11442
+ return readFileSync7(path6);
11443
+ } catch (err) {
11444
+ if (err?.code === "ENOENT") return void 0;
11445
+ throw err;
11446
+ }
11447
+ }
11448
+ function readServerResources(manifest) {
11449
+ if (EMPTY_SERVER_RESOURCES.test(manifest)) return /* @__PURE__ */ new Map();
11450
+ const entries = literalProperties(
11451
+ defaultExportProperties(manifest)?.find(
11452
+ (property) => property.key === "serverResources"
11453
+ )?.value
11454
+ );
11455
+ if (!entries) {
11456
+ throw new Error(
11457
+ `${ASSETS_MANIFEST_FILE} has no serverResources object literal: the installed @vitejs/plugin-rsc writes a manifest @rangojs/router cannot read. Report it with the plugin-rsc version.`
11458
+ );
11459
+ }
11460
+ return new Map(
11461
+ entries.map((entry) => [
11462
+ entry.key,
11463
+ manifest.slice(entry.value.start, entry.value.end)
11464
+ ])
11465
+ );
11466
+ }
11467
+ function clientUrlRecords(s) {
11468
+ const projectionOf = /* @__PURE__ */ new Map();
11469
+ for (const [referenceId2, projection] of s.clientUrlProjectionMap ?? []) {
11470
+ projectionOf.set(
11471
+ s.clientUrlSourceByReferenceId?.get(referenceId2) ?? referenceId2,
11472
+ JSON.stringify(projection)
11473
+ );
11474
+ }
11475
+ return [...projectionOf].map(([source, projection]) => ({
11476
+ kind: "client-urls",
11477
+ key: portableModuleId(source, s.projectRoot),
11478
+ digest: sha256(projection),
11479
+ moduleId: source
11480
+ }));
11481
+ }
11482
+ function writeVersionsReport(projectRoot, computed, sourceOf) {
11483
+ const routers = {};
11484
+ for (const detail of computed.details) {
11485
+ routers[detail.routerId] = {
11486
+ source: sourceOf.get(detail.routerId) ?? "",
11487
+ data: detail.data,
11488
+ document: detail.document,
11489
+ dataInputs: Object.fromEntries(detail.dataInputs),
11490
+ documentInputs: Object.fromEntries(detail.documentInputs)
11491
+ };
11492
+ }
11493
+ const report = {
11494
+ routers,
11495
+ ssrAndClient: {
11496
+ base: computed.ssrAndClient.base,
11497
+ ssr: Object.fromEntries(computed.ssrAndClient.ssr),
11498
+ externals: Object.fromEntries(computed.ssrAndClient.externals),
11499
+ client: computed.ssrAndClient.client
11500
+ },
11501
+ unownedFiles: computed.unownedFiles
11502
+ };
11503
+ try {
11504
+ const path6 = resolve9(projectRoot, VERSIONS_REPORT_FILE);
11505
+ mkdirSync2(dirname4(path6), { recursive: true });
11506
+ writeFileSync3(path6, JSON.stringify(report, null, 2) + "\n");
11507
+ } catch (err) {
11508
+ debug12?.("could not write %s: %s", VERSIONS_REPORT_FILE, err?.message);
11509
+ }
11510
+ }
11511
+ function runRouterVersionsPhase(s, builder) {
11512
+ if (!s.isBuildMode) return void 0;
11513
+ const { serverBuildGraph: server, clientBuildGraph: client } = s;
11514
+ const ssr = s.ssrBundle;
11515
+ const rscVersionFiles = s.versionModuleFiles.get("rsc") ?? [];
11516
+ if (!server || !client || !ssr || rscVersionFiles.length === 0) {
11517
+ const missing = [
11518
+ !server && "the RSC bundle",
11519
+ !client && "the client bundle",
11520
+ !ssr && "the SSR bundle",
11521
+ rscVersionFiles.length === 0 && "the RSC chunk that holds the version module"
11522
+ ].filter(Boolean);
11523
+ throw new Error(
11524
+ `[rango] The build did not record ${missing.join(", ")}, so the cache versions cannot be computed. This is a bug in @rangojs/router; please report it.`
11525
+ );
11526
+ }
11527
+ const start = performance.now();
11528
+ const rscOutDir = environmentOutDir(builder, s.projectRoot, "rsc");
11529
+ const ssrOutDir = environmentOutDir(builder, s.projectRoot, "ssr");
11530
+ let computed;
11531
+ try {
11532
+ const assetsManifest = readIfPresent(join6(rscOutDir, ASSETS_MANIFEST_FILE));
11533
+ if (assetsManifest === void 0) {
11534
+ throw new Error(
11535
+ `${ASSETS_MANIFEST_FILE} is not in the RSC output directory, so the stylesheets server components link cannot be read`
11536
+ );
11537
+ }
11538
+ computed = computeRouterVersions({
11539
+ projectRoot: s.projectRoot,
11540
+ server,
11541
+ client,
11542
+ // plugin-rsc writes its manifest next to the SSR bundle, not into it.
11543
+ ssr: {
11544
+ chunks: ssr.chunks,
11545
+ assets: [
11546
+ ...ssr.assets.filter(
11547
+ (asset) => asset.fileName !== ASSETS_MANIFEST_FILE
11548
+ ),
11549
+ { fileName: ASSETS_MANIFEST_FILE, name: ASSETS_MANIFEST_FILE }
11550
+ ]
11551
+ },
11552
+ routers: s.perRouterManifests.map((entry) => ({
11553
+ id: entry.id,
11554
+ moduleId: entry.sourceFile
11555
+ })),
11556
+ buildData: [...s.buildData, ...clientUrlRecords(s)],
11557
+ readServerFile: (fileName) => readIfPresent(join6(rscOutDir, fileName)),
11558
+ readSsrFile: (fileName) => readIfPresent(join6(ssrOutDir, fileName)),
11559
+ base: builder?.config?.base ?? "/",
11560
+ serverResources: readServerResources(assetsManifest.toString("utf-8")),
11561
+ externals: {
11562
+ describePackage: createInstalledPackageDescriber(s.projectRoot),
11563
+ readFile: readIfPresent,
11564
+ buildId: randomUUID()
11565
+ }
11566
+ });
11567
+ } catch (err) {
11568
+ throw new Error(
11569
+ `[rango] Could not compute the cache versions: ${err?.message ?? err}`,
11570
+ { cause: err }
11571
+ );
11572
+ }
11573
+ const { table, details } = computed;
11574
+ for (const [environment, fileNames] of s.versionModuleFiles) {
11575
+ const outDir = environmentOutDir(builder, s.projectRoot, environment);
11576
+ let filled = 0;
11577
+ for (const fileName of fileNames) {
11578
+ const path6 = join6(outDir, fileName);
11579
+ const source = readIfPresent(path6);
11580
+ const next = source === void 0 ? void 0 : fillRouterVersions(source.toString("utf-8"), table);
11581
+ if (next === void 0) continue;
11582
+ writeFileSync3(path6, next);
11583
+ filled++;
11584
+ }
11585
+ if (environment === "rsc" && filled === 0) {
11586
+ throw new Error(
11587
+ `[rango] Could not write the cache versions into the server build: no placeholder in ${fileNames.join(", ")} under ${outDir}. The build would fail to start. This is a bug in @rangojs/router; please report it.`
11588
+ );
11589
+ }
11590
+ }
11591
+ const elapsed = (performance.now() - start).toFixed(1);
11592
+ const sourceOf = new Map(
11593
+ s.perRouterManifests.map((entry) => [
11594
+ entry.id,
11595
+ entry.sourceFile ? portableModuleId(entry.sourceFile, s.projectRoot) : ""
11596
+ ])
11597
+ );
11598
+ const detailOf = new Map(details.map((detail) => [detail.routerId, detail]));
11599
+ const wholeBuild = detailOf.get(DEFAULT_ROUTER_VERSIONS_KEY);
11600
+ let keyed = 0;
11601
+ if (s.perRouterManifests.length > 0) {
11602
+ console.log(
11603
+ `[rango] Cache versions for ${s.perRouterManifests.length} router(s), data / document (${elapsed}ms):`
11604
+ );
11605
+ for (const { id } of s.perRouterManifests) {
11606
+ const own = detailOf.get(id);
11607
+ const detail = own ?? wholeBuild;
11608
+ if (detail.usesEncryptionKey) keyed++;
11609
+ console.log(
11610
+ `[rango] ${detail.data} / ${detail.document} ${sourceOf.get(id) || id}${own ? "" : " (whole build)"}`
11611
+ );
11612
+ }
11613
+ }
11614
+ debug12?.(
11615
+ "router versions: %d server file(s), %sms, table=%o",
11616
+ server.chunks.length + server.assets.length,
11617
+ elapsed,
11618
+ table
11619
+ );
11620
+ writeVersionsReport(s.projectRoot, computed, sourceOf);
11621
+ if (computed.undetermined.length > 0) {
11622
+ console.log(
11623
+ `[rango] ${computed.undetermined.length} import(s) the server build leaves external could not be read at build time (${computed.undetermined.join(", ")}): a package that is not installed where the build can find it, a path that does not resolve, or a URL. What they resolve to at run time is unknown, so the routers importing them get a new cache version on every build.`
11624
+ );
11625
+ }
11626
+ if (keyed > 0 && !isEncryptionKeyStable()) {
11627
+ console.log(
11628
+ `[rango] No stable encryption key: ${keyed} router(s) encrypt server-action arguments with a key generated for this build, so their cache version changes on every build and each deploy clears their cache. To keep it, set rango({ encryptionKey: process.env.RANGO_ENCRYPTION_KEY }) with a base64 32-byte key (openssl rand -base64 32).`
11629
+ );
11630
+ }
11631
+ return table;
11632
+ }
11633
+
10563
11634
  // src/vite/discovery/shell-prerender-phase.ts
10564
11635
  init_debug();
10565
- var debug12 = createRangoDebugger(NS.prerender);
10566
- async function runShellPrerenderPhase(s, builder) {
11636
+ var debug13 = createRangoDebugger(NS.prerender);
11637
+ async function runShellPrerenderPhase(s, builder, versionsTable) {
10567
11638
  const tempServer = s.shellPhaseTempServer;
10568
- if (!s.isBuildMode || !s.shellCandidates?.length || !tempServer) return;
11639
+ if (!versionsTable || !s.shellCandidates?.length || !tempServer) return;
10569
11640
  const candidates = s.shellCandidates;
10570
11641
  const startTotal = performance.now();
10571
11642
  console.log(`[rango] Shell-prerendering ${candidates.length} URL(s)...`);
@@ -10581,16 +11652,6 @@ async function runShellPrerenderPhase(s, builder) {
10581
11652
  );
10582
11653
  return;
10583
11654
  }
10584
- const versionPlugin = (builder?.config?.plugins ?? []).find(
10585
- (p) => p?.name === "@rangojs/router:version"
10586
- );
10587
- const buildVersion = versionPlugin?.api?.getBuildVersion?.();
10588
- if (!buildVersion) {
10589
- console.warn(
10590
- "[rango] shell prerender: main build version unavailable; skipping \u2014 routes keep runtime shell capture."
10591
- );
10592
- return;
10593
- }
10594
11655
  const payloads = s.prerenderPayloadValues ?? /* @__PURE__ */ new Map();
10595
11656
  const fetchedKeys = /* @__PURE__ */ new Set();
10596
11657
  globalThis.__loadPrerenderManifestModule = async () => ({
@@ -10608,9 +11669,9 @@ async function runShellPrerenderPhase(s, builder) {
10608
11669
  const htmlStream = await ssrRunner.import(
10609
11670
  "@rangojs/router/internal/deps/html-stream-server"
10610
11671
  );
10611
- const clientOutDir = builder?.environments?.client?.config?.build?.outDir ?? resolve9(s.projectRoot, "dist/client");
10612
- const clientAssetsDir = join5(clientOutDir, "assets");
10613
- const entryFile = existsSync8(clientAssetsDir) ? readdirSync3(clientAssetsDir).find((f) => /^index-.*\.js$/.test(f)) : void 0;
11672
+ const clientOutDir = environmentOutDir(builder, s.projectRoot, "client");
11673
+ const clientAssetsDir = join7(clientOutDir, "assets");
11674
+ const entryFile = existsSync9(clientAssetsDir) ? readdirSync4(clientAssetsDir).find((f) => /^index-.*\.js$/.test(f)) : void 0;
10614
11675
  if (!entryFile) {
10615
11676
  console.warn(
10616
11677
  `[rango] shell prerender: built client entry not found under ${clientAssetsDir}; skipping \u2014 routes keep runtime shell capture.`
@@ -10620,7 +11681,7 @@ async function runShellPrerenderPhase(s, builder) {
10620
11681
  const base = builder?.config?.base ?? "/";
10621
11682
  const normalizedBase = base.endsWith("/") ? base : `${base}/`;
10622
11683
  const bootstrapContent = `import("${normalizedBase}assets/${entryFile}")`;
10623
- debug12?.("shell prerender bootstrap: %s", bootstrapContent);
11684
+ debug13?.("shell prerender bootstrap: %s", bootstrapContent);
10624
11685
  const minimalPlugin = (tempServer.config?.plugins ?? []).find(
10625
11686
  (p) => p?.name === "rsc:minimal"
10626
11687
  );
@@ -10691,8 +11752,13 @@ async function runShellPrerenderPhase(s, builder) {
10691
11752
  const mainKey = `${cand.routeName}/${cand.paramHash}`;
10692
11753
  let handled = false;
10693
11754
  const mismatches = [];
10694
- for (const [, routerInstance] of registry) {
11755
+ for (const [routerId2, routerInstance] of registry) {
10695
11756
  if (typeof routerInstance.match !== "function") continue;
11757
+ const versions = resolveVersionsFrom(
11758
+ versionsTable,
11759
+ routerId2,
11760
+ routerInstance.version
11761
+ );
10696
11762
  try {
10697
11763
  const res = await captureMod.captureShellForBuild({
10698
11764
  router: routerInstance,
@@ -10705,9 +11771,9 @@ async function runShellPrerenderPhase(s, builder) {
10705
11771
  maxSnapshotBytes: policy.maxSnapshotBytes,
10706
11772
  captureTimeout: policy.captureTimeout,
10707
11773
  buildEnv: s.resolvedBuildEnv,
10708
- buildVersion,
11774
+ versions,
10709
11775
  captureShellHTML,
10710
- debug: !!debug12
11776
+ debug: !!debug13
10711
11777
  });
10712
11778
  if (res.outcome === "route-mismatch") {
10713
11779
  mismatches.push(res.matchedRouteName ?? "(no match)");
@@ -10760,8 +11826,11 @@ async function runShellPrerenderPhase(s, builder) {
10760
11826
  }
10761
11827
  }
10762
11828
  if (staged.length > 0) {
10763
- const rscOutDir = builder?.environments?.rsc?.config?.build?.outDir ?? resolve9(s.projectRoot, "dist/rsc");
10764
- writeShellManifest(s, rscOutDir, staged);
11829
+ writeShellManifest(
11830
+ s,
11831
+ environmentOutDir(builder, s.projectRoot, "rsc"),
11832
+ staged
11833
+ );
10765
11834
  }
10766
11835
  const totalElapsed = (performance.now() - startTotal).toFixed(0);
10767
11836
  const parts = [`${staged.length} done`];
@@ -10780,14 +11849,14 @@ async function runShellPrerenderPhase(s, builder) {
10780
11849
  }
10781
11850
  }
10782
11851
  function writeShellManifest(s, rscOutDir, staged) {
10783
- const rscEntryPath = resolve9(rscOutDir, s.rscEntryFileName ?? "index.js");
10784
- if (!existsSync8(rscEntryPath)) {
11852
+ const rscEntryPath = resolve10(rscOutDir, s.rscEntryFileName ?? "index.js");
11853
+ if (!existsSync9(rscEntryPath)) {
10785
11854
  console.warn(
10786
11855
  `[rango] shell prerender: RSC entry not found at ${rscEntryPath}; entries not persisted \u2014 routes keep runtime capture.`
10787
11856
  );
10788
11857
  return;
10789
11858
  }
10790
- const assetsDir = resolve9(rscOutDir, "assets");
11859
+ const assetsDir = resolve10(rscOutDir, "assets");
10791
11860
  let totalBytes = 0;
10792
11861
  const manifestMap = {};
10793
11862
  const countedFiles = /* @__PURE__ */ new Set();
@@ -10805,13 +11874,13 @@ function writeShellManifest(s, rscOutDir, staged) {
10805
11874
  `export default m;`,
10806
11875
  ""
10807
11876
  ].join("\n");
10808
- writeFileSync3(resolve9(rscOutDir, "__shell-manifest.js"), manifestCode);
11877
+ writeFileSync4(resolve10(rscOutDir, "__shell-manifest.js"), manifestCode);
10809
11878
  totalBytes += Buffer.byteLength(manifestCode);
10810
- const rscCode = readFileSync6(rscEntryPath, "utf-8");
11879
+ const rscCode = readFileSync8(rscEntryPath, "utf-8");
10811
11880
  if (!rscCode.includes("__shell-manifest.js")) {
10812
11881
  const injection = `globalThis.__loadShellManifestModule = () => import("./__shell-manifest.js");
10813
11882
  `;
10814
- writeFileSync3(rscEntryPath, injection + rscCode);
11883
+ writeFileSync4(rscEntryPath, injection + rscCode);
10815
11884
  }
10816
11885
  const totalKB = (totalBytes / 1024).toFixed(1);
10817
11886
  console.log(
@@ -10857,8 +11926,8 @@ function createDevPrerenderCache(maxEntriesPerRouter = MAX_ENTRIES_PER_ROUTER) {
10857
11926
  }
10858
11927
 
10859
11928
  // src/vite/discovery/route-types-writer.ts
10860
- import { dirname as dirname3, join as join6, resolve as resolve10 } from "node:path";
10861
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync9, unlinkSync as unlinkSync2 } from "node:fs";
11929
+ import { dirname as dirname5, join as join8, resolve as resolve11 } from "node:path";
11930
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync10, unlinkSync as unlinkSync2 } from "node:fs";
10862
11931
  function filterUserNamedRoutes(manifest) {
10863
11932
  const filtered = {};
10864
11933
  for (const [name, pattern] of Object.entries(manifest)) {
@@ -10869,10 +11938,10 @@ function filterUserNamedRoutes(manifest) {
10869
11938
  return filtered;
10870
11939
  }
10871
11940
  function writeGenFileIfChanged(state, outPath, source, opts) {
10872
- const existing = existsSync9(outPath) ? readFileSync7(outPath, "utf-8") : null;
11941
+ const existing = existsSync10(outPath) ? readFileSync9(outPath, "utf-8") : null;
10873
11942
  if (existing === source) return;
10874
11943
  markSelfGenWrite(state, outPath, source);
10875
- writeFileSync4(outPath, source);
11944
+ writeFileSync5(outPath, source);
10876
11945
  if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
10877
11946
  }
10878
11947
  function writeCombinedRouteTypesWithTracking(state, opts) {
@@ -10886,11 +11955,11 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
10886
11955
  function writeRouteTypesFiles(state) {
10887
11956
  if (state.perRouterManifests.length === 0) return;
10888
11957
  try {
10889
- const entryDir = dirname3(
10890
- resolve10(state.projectRoot, state.resolvedEntryPath)
11958
+ const entryDir = dirname5(
11959
+ resolve11(state.projectRoot, state.resolvedEntryPath)
10891
11960
  );
10892
- const oldCombinedPath = join6(entryDir, "named-routes.gen.ts");
10893
- if (existsSync9(oldCombinedPath)) {
11961
+ const oldCombinedPath = join8(entryDir, "named-routes.gen.ts");
11962
+ if (existsSync10(oldCombinedPath)) {
10894
11963
  unlinkSync2(oldCombinedPath);
10895
11964
  console.log(
10896
11965
  `[rango] Removed stale combined route types: ${oldCombinedPath}`
@@ -10971,8 +12040,8 @@ function supplementGenFilesWithRuntimeRoutes(state) {
10971
12040
  }
10972
12041
 
10973
12042
  // src/vite/discovery/virtual-module-codegen.ts
10974
- import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync5 } from "node:fs";
10975
- import { dirname as dirname4, basename, join as join7 } from "node:path";
12043
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync6 } from "node:fs";
12044
+ import { dirname as dirname6, basename, join as join9 } from "node:path";
10976
12045
  var MANIFEST_EXTERNALIZE_THRESHOLD = 512 * 1024;
10977
12046
  var TRANSITION_WHEN_VALIDATION = `enableTransitionWhenValidation();`;
10978
12047
  function devDiscoveryBootstrap(state) {
@@ -10991,12 +12060,12 @@ function generateRoutesManifestModule(state) {
10991
12060
  let varIdx = 0;
10992
12061
  for (const entry of state.perRouterManifests) {
10993
12062
  if (entry.sourceFile) {
10994
- const routerDir = dirname4(entry.sourceFile);
12063
+ const routerDir = dirname6(entry.sourceFile);
10995
12064
  const routerBasename = basename(entry.sourceFile).replace(
10996
12065
  /\.(tsx?|jsx?)$/,
10997
12066
  ""
10998
12067
  );
10999
- const genPath = join7(
12068
+ const genPath = join9(
11000
12069
  routerDir,
11001
12070
  `${routerBasename}.named-routes.gen.js`
11002
12071
  ).replaceAll("\\", "/");
@@ -11030,7 +12099,10 @@ function generateRoutesManifestModule(state) {
11030
12099
  ];
11031
12100
  if (hasClientUrlModules) {
11032
12101
  lines2.push(`clearClientUrlProjections();`);
11033
- for (const [referenceId2, projection] of state.clientUrlProjectionMap ?? []) {
12102
+ const projections = [...state.clientUrlProjectionMap ?? []].sort(
12103
+ ([a], [b]) => compareStrings(a, b)
12104
+ );
12105
+ for (const [referenceId2, projection] of projections) {
11034
12106
  lines2.push(
11035
12107
  `setClientUrlProjection(${JSON.stringify(referenceId2)}, ${jsonParseExpression(projection)});`
11036
12108
  );
@@ -11062,9 +12134,9 @@ function generateRoutesManifestModule(state) {
11062
12134
  );
11063
12135
  }
11064
12136
  if (state.isBuildMode) {
11065
- for (const routerId of state.perRouterManifestDataMap.keys()) {
12137
+ for (const routerId2 of state.perRouterManifestDataMap.keys()) {
11066
12138
  lines2.push(
11067
- `registerRouterManifestLoader(${JSON.stringify(routerId)}, () => import(${JSON.stringify(VIRTUAL_ROUTES_MANIFEST_ID + "/" + routerId)}));`
12139
+ `registerRouterManifestLoader(${JSON.stringify(routerId2)}, () => import(${JSON.stringify(VIRTUAL_ROUTES_MANIFEST_ID + "/" + routerId2)}));`
11068
12140
  );
11069
12141
  }
11070
12142
  }
@@ -11101,17 +12173,17 @@ function shortHash(input) {
11101
12173
  }
11102
12174
  return (h >>> 0).toString(36);
11103
12175
  }
11104
- function generatePerRouterModule(state, routerId) {
12176
+ function generatePerRouterModule(state, routerId2) {
11105
12177
  const sourceFile = state.perRouterManifests.find(
11106
- (e) => e.id === routerId
12178
+ (e) => e.id === routerId2
11107
12179
  )?.sourceFile;
11108
- const trie = state.perRouterTrieMap.get(routerId);
11109
- const entries = state.perRouterPrecomputedMap.get(routerId);
12180
+ const trie = state.perRouterTrieMap.get(routerId2);
12181
+ const entries = state.perRouterPrecomputedMap.get(routerId2);
11110
12182
  const lines = [];
11111
12183
  if (sourceFile) {
11112
- const routerDir = dirname4(sourceFile);
12184
+ const routerDir = dirname6(sourceFile);
11113
12185
  const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
11114
- const genPath = join7(
12186
+ const genPath = join9(
11115
12187
  routerDir,
11116
12188
  `${routerBasename}.named-routes.gen.js`
11117
12189
  ).replaceAll("\\", "/");
@@ -11125,11 +12197,11 @@ function generatePerRouterModule(state, routerId) {
11125
12197
  const payloadJson = hasTrie || hasEntries ? JSON.stringify(payload) : "";
11126
12198
  const useTextModule = state.isBuildMode && preset === "cloudflare" && override !== "0" && (hasTrie || hasEntries) && (override === "1" || payloadJson.length >= MANIFEST_EXTERNALIZE_THRESHOLD);
11127
12199
  if (useTextModule) {
11128
- const dir = join7(state.projectRoot, "node_modules", ".rango");
11129
- mkdirSync2(dir, { recursive: true });
11130
- const safeId = `${routerId.replace(/[^a-zA-Z0-9_-]/g, "_")}-${shortHash(routerId)}`;
11131
- const filePath = join7(dir, `manifest-${safeId}.txt`).replaceAll("\\", "/");
11132
- writeFileSync5(filePath, payloadJson);
12200
+ const dir = join9(state.projectRoot, "node_modules", ".rango");
12201
+ mkdirSync3(dir, { recursive: true });
12202
+ const safeId = `${routerId2.replace(/[^a-zA-Z0-9_-]/g, "_")}-${shortHash(routerId2)}`;
12203
+ const filePath = join9(dir, `manifest-${safeId}.txt`).replaceAll("\\", "/");
12204
+ writeFileSync6(filePath, payloadJson);
11133
12205
  lines.push(`import __manifestJson from ${JSON.stringify(filePath)};`);
11134
12206
  lines.push(`const __manifestData = JSON.parse(__manifestJson);`);
11135
12207
  emitManifestExports(lines, hasTrie, hasEntries);
@@ -11158,13 +12230,13 @@ function emitManifestExports(lines, hasTrie, hasEntries) {
11158
12230
  }
11159
12231
 
11160
12232
  // src/vite/discovery/bundle-postprocess.ts
11161
- import { resolve as resolve11 } from "node:path";
11162
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync10 } from "node:fs";
12233
+ import { resolve as resolve12 } from "node:path";
12234
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync11 } from "node:fs";
11163
12235
  function postprocessBundle(state) {
11164
12236
  const hasPrerenderData = state.prerenderManifestEntries && Object.keys(state.prerenderManifestEntries).length > 0;
11165
12237
  const hasStaticData = state.staticManifestEntries && Object.keys(state.staticManifestEntries).length > 0;
11166
12238
  if (!hasPrerenderData && !hasStaticData) return;
11167
- const rscEntryPath = resolve11(
12239
+ const rscEntryPath = resolve12(
11168
12240
  state.projectRoot,
11169
12241
  "dist/rsc",
11170
12242
  state.rscEntryFileName ?? "index.js"
@@ -11185,9 +12257,9 @@ function postprocessBundle(state) {
11185
12257
  ];
11186
12258
  for (const target of evictionTargets) {
11187
12259
  for (const info of target.infos) {
11188
- const chunkPath = resolve11(state.projectRoot, "dist/rsc", info.fileName);
12260
+ const chunkPath = resolve12(state.projectRoot, "dist/rsc", info.fileName);
11189
12261
  try {
11190
- const code = readFileSync8(chunkPath, "utf-8");
12262
+ const code = readFileSync10(chunkPath, "utf-8");
11191
12263
  const result = evictHandlerCode(
11192
12264
  code,
11193
12265
  info.exports,
@@ -11195,7 +12267,7 @@ function postprocessBundle(state) {
11195
12267
  target.brand
11196
12268
  );
11197
12269
  if (result) {
11198
- writeFileSync6(chunkPath, result.code);
12270
+ writeFileSync7(chunkPath, result.code);
11199
12271
  const savedKB = (result.savedBytes / 1024).toFixed(1);
11200
12272
  console.log(
11201
12273
  `[rango] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
@@ -11210,8 +12282,8 @@ function postprocessBundle(state) {
11210
12282
  }
11211
12283
  state.handlerChunkInfoMap.clear();
11212
12284
  state.staticHandlerChunkInfoMap.clear();
11213
- if (hasPrerenderData && existsSync10(rscEntryPath)) {
11214
- const rscCode = readFileSync8(rscEntryPath, "utf-8");
12285
+ if (hasPrerenderData && existsSync11(rscEntryPath)) {
12286
+ const rscCode = readFileSync10(rscEntryPath, "utf-8");
11215
12287
  if (!rscCode.includes("__prerender-manifest.js")) {
11216
12288
  try {
11217
12289
  let totalBytes = copyStagedBuildAssets(
@@ -11230,15 +12302,15 @@ function postprocessBundle(state) {
11230
12302
  `export default m;`,
11231
12303
  ""
11232
12304
  ].join("\n");
11233
- const manifestPath = resolve11(
12305
+ const manifestPath = resolve12(
11234
12306
  state.projectRoot,
11235
12307
  "dist/rsc/__prerender-manifest.js"
11236
12308
  );
11237
- writeFileSync6(manifestPath, manifestCode);
12309
+ writeFileSync7(manifestPath, manifestCode);
11238
12310
  totalBytes += Buffer.byteLength(manifestCode);
11239
12311
  const injection = `globalThis.__loadPrerenderManifestModule = () => import("./__prerender-manifest.js");
11240
12312
  `;
11241
- writeFileSync6(rscEntryPath, injection + rscCode);
12313
+ writeFileSync7(rscEntryPath, injection + rscCode);
11242
12314
  const totalKB = (totalBytes / 1024).toFixed(1);
11243
12315
  console.log(
11244
12316
  `[rango] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
@@ -11250,8 +12322,8 @@ function postprocessBundle(state) {
11250
12322
  }
11251
12323
  }
11252
12324
  }
11253
- if (hasStaticData && existsSync10(rscEntryPath)) {
11254
- const rscCode = readFileSync8(rscEntryPath, "utf-8");
12325
+ if (hasStaticData && existsSync11(rscEntryPath)) {
12326
+ const rscCode = readFileSync10(rscEntryPath, "utf-8");
11255
12327
  if (!rscCode.includes("__static-manifest.js")) {
11256
12328
  try {
11257
12329
  const manifestEntries = [];
@@ -11268,15 +12340,15 @@ function postprocessBundle(state) {
11268
12340
  }
11269
12341
  const manifestCode = `const m={${manifestEntries.join(",")}};globalThis.__STATIC_MANIFEST=m;export default m;
11270
12342
  `;
11271
- const manifestPath = resolve11(
12343
+ const manifestPath = resolve12(
11272
12344
  state.projectRoot,
11273
12345
  "dist/rsc/__static-manifest.js"
11274
12346
  );
11275
- writeFileSync6(manifestPath, manifestCode);
12347
+ writeFileSync7(manifestPath, manifestCode);
11276
12348
  totalBytes += Buffer.byteLength(manifestCode);
11277
12349
  const injection = `globalThis.__loadStaticManifestModule = () => import("./__static-manifest.js");
11278
12350
  `;
11279
- writeFileSync6(rscEntryPath, injection + rscCode);
12351
+ writeFileSync7(rscEntryPath, injection + rscCode);
11280
12352
  const totalKB = (totalBytes / 1024).toFixed(1);
11281
12353
  console.log(
11282
12354
  `[rango] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
@@ -11291,7 +12363,7 @@ function postprocessBundle(state) {
11291
12363
  }
11292
12364
 
11293
12365
  // src/vite/discovery/gate-state.ts
11294
- function createDiscoveryGate(s, debug13) {
12366
+ function createDiscoveryGate(s, debug14) {
11295
12367
  let gatePending = false;
11296
12368
  let gateResolver = () => {
11297
12369
  };
@@ -11300,15 +12372,15 @@ function createDiscoveryGate(s, debug13) {
11300
12372
  let pendingEvents = false;
11301
12373
  const beginGate = () => {
11302
12374
  if (gatePending) return;
11303
- s.discoveryDone = new Promise((resolve14) => {
11304
- gateResolver = resolve14;
12375
+ s.discoveryDone = new Promise((resolve15) => {
12376
+ gateResolver = resolve15;
11305
12377
  });
11306
12378
  gatePending = true;
11307
12379
  };
11308
12380
  const resolveGate = () => {
11309
12381
  if (!gatePending) return;
11310
12382
  if (inProgress || queued2 || pendingEvents) {
11311
- debug13?.(
12383
+ debug14?.(
11312
12384
  "hmr: resolveGate deferred \u2014 work in flight (inProgress=%s queued=%s pendingEvents=%s)",
11313
12385
  inProgress,
11314
12386
  queued2,
@@ -11317,7 +12389,7 @@ function createDiscoveryGate(s, debug13) {
11317
12389
  return;
11318
12390
  }
11319
12391
  gatePending = false;
11320
- debug13?.("hmr: discoveryDone resolved");
12392
+ debug14?.("hmr: discoveryDone resolved");
11321
12393
  gateResolver();
11322
12394
  };
11323
12395
  const noteRouteEvent = () => {
@@ -11327,7 +12399,7 @@ function createDiscoveryGate(s, debug13) {
11327
12399
  const runRefreshCycle = async (work) => {
11328
12400
  if (inProgress) {
11329
12401
  queued2 = true;
11330
- debug13?.("hmr: rediscovery in flight \u2014 queued for a follow-up cycle");
12402
+ debug14?.("hmr: rediscovery in flight \u2014 queued for a follow-up cycle");
11331
12403
  return;
11332
12404
  }
11333
12405
  pendingEvents = false;
@@ -11338,16 +12410,16 @@ function createDiscoveryGate(s, debug13) {
11338
12410
  inProgress = false;
11339
12411
  if (queued2) {
11340
12412
  queued2 = false;
11341
- debug13?.("hmr: consuming queued rediscovery");
12413
+ debug14?.("hmr: consuming queued rediscovery");
11342
12414
  runRefreshCycle(work).catch((err) => {
11343
- debug13?.(
12415
+ debug14?.(
11344
12416
  "hmr: queued cycle rejected \u2014 releasing gate (%s)",
11345
12417
  err instanceof Error ? err.message : String(err)
11346
12418
  );
11347
12419
  resolveGate();
11348
12420
  });
11349
12421
  } else if (pendingEvents) {
11350
- debug13?.(
12422
+ debug14?.(
11351
12423
  "hmr: holding gate for pending events (debounce not yet fired)"
11352
12424
  );
11353
12425
  } else {
@@ -11393,15 +12465,15 @@ function selectForwardableResolvePlugins(plugins) {
11393
12465
  }
11394
12466
  function pickForwardedRunnerConfig(config) {
11395
12467
  const r = config.resolve ?? {};
11396
- const resolve14 = {};
11397
- if (r.alias !== void 0) resolve14.alias = r.alias;
11398
- if (r.dedupe !== void 0) resolve14.dedupe = r.dedupe;
11399
- if (r.conditions !== void 0) resolve14.conditions = r.conditions;
11400
- if (r.mainFields !== void 0) resolve14.mainFields = r.mainFields;
11401
- if (r.extensions !== void 0) resolve14.extensions = r.extensions;
12468
+ const resolve15 = {};
12469
+ if (r.alias !== void 0) resolve15.alias = r.alias;
12470
+ if (r.dedupe !== void 0) resolve15.dedupe = r.dedupe;
12471
+ if (r.conditions !== void 0) resolve15.conditions = r.conditions;
12472
+ if (r.mainFields !== void 0) resolve15.mainFields = r.mainFields;
12473
+ if (r.extensions !== void 0) resolve15.extensions = r.extensions;
11402
12474
  if (r.preserveSymlinks !== void 0)
11403
- resolve14.preserveSymlinks = r.preserveSymlinks;
11404
- if (r.tsconfigPaths !== void 0) resolve14.tsconfigPaths = r.tsconfigPaths;
12475
+ resolve15.preserveSymlinks = r.preserveSymlinks;
12476
+ if (r.tsconfigPaths !== void 0) resolve15.tsconfigPaths = r.tsconfigPaths;
11405
12477
  const userOxc = config.oxc;
11406
12478
  const userJsx = userOxc && typeof userOxc === "object" && typeof userOxc.jsx === "object" && userOxc.jsx !== null ? userOxc.jsx : {};
11407
12479
  const oxc = userOxc && typeof userOxc === "object" ? {
@@ -11409,7 +12481,7 @@ function pickForwardedRunnerConfig(config) {
11409
12481
  jsx: { ...userJsx, runtime: "automatic", importSource: "react" }
11410
12482
  } : { jsx: { runtime: "automatic", importSource: "react" } };
11411
12483
  return {
11412
- resolve: resolve14,
12484
+ resolve: resolve15,
11413
12485
  define: config.define,
11414
12486
  oxc
11415
12487
  };
@@ -11531,6 +12603,26 @@ async function createTempRscServer(state, options = {}) {
11531
12603
  ]
11532
12604
  });
11533
12605
  }
12606
+ var WRANGLER_CONFIG_NAMES = [
12607
+ "wrangler.json",
12608
+ "wrangler.jsonc",
12609
+ "wrangler.toml"
12610
+ ];
12611
+ function wranglerProxyOptions(root) {
12612
+ const viteRoot = resolve13(root);
12613
+ for (let dir = viteRoot; ; dir = dirname7(dir)) {
12614
+ for (const name of WRANGLER_CONFIG_NAMES) {
12615
+ const configPath = join10(dir, name);
12616
+ if (existsSync12(configPath)) {
12617
+ return {
12618
+ configPath,
12619
+ persist: { path: join10(viteRoot, ".wrangler", "state", "v3") }
12620
+ };
12621
+ }
12622
+ }
12623
+ if (dirname7(dir) === dir) return void 0;
12624
+ }
12625
+ }
11534
12626
  async function resolveBuildEnv(option, factoryCtx) {
11535
12627
  if (!option) return null;
11536
12628
  if (option === "auto") {
@@ -11541,11 +12633,13 @@ async function resolveBuildEnv(option, factoryCtx) {
11541
12633
  }
11542
12634
  try {
11543
12635
  const userRequire = createRequire3(
11544
- resolve12(factoryCtx.root, "package.json")
12636
+ resolve13(factoryCtx.root, "package.json")
11545
12637
  );
11546
12638
  const wranglerPath = userRequire.resolve("wrangler");
11547
12639
  const { getPlatformProxy } = await import(pathToFileURL2(wranglerPath).href);
11548
- const proxy = await getPlatformProxy();
12640
+ const proxy = await getPlatformProxy(
12641
+ wranglerProxyOptions(factoryCtx.root)
12642
+ );
11549
12643
  return {
11550
12644
  env: proxy.env,
11551
12645
  dispose: proxy.dispose
@@ -11583,6 +12677,7 @@ function resetPrerenderCollection(s) {
11583
12677
  s.staticManifestEntries = null;
11584
12678
  s.shellCandidates = null;
11585
12679
  s.prerenderPayloadValues = null;
12680
+ s.buildData = [];
11586
12681
  }
11587
12682
  async function releaseBuildEnv(s) {
11588
12683
  if (s.buildEnvDispose) {
@@ -11727,8 +12822,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
11727
12822
  }
11728
12823
  server.middlewares.use(internalDebugNoCacheMiddleware());
11729
12824
  let resolveDiscovery;
11730
- const discoveryPromise = new Promise((resolve14) => {
11731
- resolveDiscovery = resolve14;
12825
+ const discoveryPromise = new Promise((resolve15) => {
12826
+ resolveDiscovery = resolve15;
11732
12827
  });
11733
12828
  const gate = createDiscoveryGate(s, debugDiscovery);
11734
12829
  const beginDiscoveryGate = gate.beginGate;
@@ -12027,7 +13122,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12027
13122
  for (const [map2, fn] of perRouterSetters) {
12028
13123
  const setter = serverMod[fn];
12029
13124
  if (typeof setter !== "function") continue;
12030
- for (const [routerId, value] of map2) setter(routerId, value);
13125
+ for (const [routerId2, value] of map2) setter(routerId2, value);
12031
13126
  }
12032
13127
  };
12033
13128
  server.middlewares.use("/__rsc_prerender", async (req, res) => {
@@ -12310,7 +13405,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12310
13405
  maxSnapshotBytes,
12311
13406
  captureTimeout,
12312
13407
  buildEnv: s.resolvedBuildEnv,
12313
- buildVersion: version,
13408
+ versions: uniformVersions(version),
12314
13409
  captureShellHTML: ssrModule.captureShellHTML,
12315
13410
  debug: !!debugDiscovery
12316
13411
  });
@@ -12495,7 +13590,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12495
13590
  if (devServerClosed || expectedEpoch !== s.devDiscoveryEpoch) {
12496
13591
  return;
12497
13592
  }
12498
- await new Promise((resolve14) => setTimeout(resolve14, 25));
13593
+ await new Promise((resolve15) => setTimeout(resolve15, 25));
12499
13594
  if (devServerClosed || expectedEpoch !== s.devDiscoveryEpoch) {
12500
13595
  return;
12501
13596
  }
@@ -12613,7 +13708,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12613
13708
  }
12614
13709
  const inRecoveryMode = !!s.lastDiscoveryError;
12615
13710
  try {
12616
- const source = readFileSync9(filePath, "utf-8");
13711
+ const source = readFileSync11(filePath, "utf-8");
12617
13712
  const trimmed = source.trimStart();
12618
13713
  const isUseClient = trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'");
12619
13714
  let hasClientUrls = source.includes("clientUrls(");
@@ -12655,11 +13750,11 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12655
13750
  if (rscGraph?.getModulesByFile) {
12656
13751
  const routerSourceFiles = /* @__PURE__ */ new Set();
12657
13752
  if (s.resolvedEntryPath) {
12658
- routerSourceFiles.add(resolve12(s.resolvedEntryPath));
13753
+ routerSourceFiles.add(resolve13(s.resolvedEntryPath));
12659
13754
  }
12660
13755
  for (const entry of s.perRouterManifests) {
12661
13756
  if (entry.sourceFile) {
12662
- routerSourceFiles.add(resolve12(entry.sourceFile));
13757
+ routerSourceFiles.add(resolve13(entry.sourceFile));
12663
13758
  }
12664
13759
  }
12665
13760
  const seen = /* @__PURE__ */ new Set();
@@ -12688,7 +13783,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12688
13783
  if (hasCreateRouter) {
12689
13784
  const nestedRouterConflict = findNestedRouterConflict([
12690
13785
  ...s.cachedRouterFiles ?? [],
12691
- resolve12(filePath)
13786
+ resolve13(filePath)
12692
13787
  ]);
12693
13788
  if (nestedRouterConflict) {
12694
13789
  server.config.logger.error(
@@ -12811,18 +13906,27 @@ ${details}`,
12811
13906
  );
12812
13907
  }
12813
13908
  },
12814
- // Post-build PPR shell capture (producer B, #699): runs after EVERY
12815
- // environment bundle is written — the shell prelude embeds built client
12816
- // asset URLs (bootstrap entry), which do not exist at buildStart. The
12817
- // kept temp server and the buildEnv were deferred AS A PAIR in
12818
- // buildStart's finally; this finally is the pair's success-path owner
12819
- // (buildEnd below owns the aborted-build path) — the phase itself is a
12820
- // pure producer and tears down only the globals it installs.
13909
+ // Post-build phases, after EVERY environment bundle is written.
13910
+ //
13911
+ // 1. Cache versions (discovery/router-versions-phase.ts): hashes the
13912
+ // server output as postprocessBundle left it and writes the per-router
13913
+ // table into the built version module. First, because phase 2 stamps
13914
+ // its entries with these versions and reads the same RSC out dir.
13915
+ // 2. PPR shell capture (producer B, #699): the shell prelude embeds built
13916
+ // client asset URLs (bootstrap entry), which do not exist at
13917
+ // buildStart. The kept temp server and the buildEnv were deferred AS A
13918
+ // PAIR in buildStart's finally; this finally is the pair's success-path
13919
+ // owner (buildEnd below owns the aborted-build path) — the phase itself
13920
+ // is a pure producer and tears down only the globals it installs.
12821
13921
  buildApp: {
12822
13922
  order: "post",
12823
13923
  async handler(builder) {
12824
13924
  try {
12825
- await runShellPrerenderPhase(s, builder);
13925
+ await runShellPrerenderPhase(
13926
+ s,
13927
+ builder,
13928
+ runRouterVersionsPhase(s, builder)
13929
+ );
12826
13930
  } finally {
12827
13931
  if (s.isBuildMode) {
12828
13932
  const tempServer = s.shellPhaseTempServer;
@@ -12911,11 +14015,11 @@ ${details}`,
12911
14015
  () => s.discoveryDone
12912
14016
  );
12913
14017
  }
12914
- const routerId = id.slice(perRouterPrefix.length);
14018
+ const routerId2 = id.slice(perRouterPrefix.length);
12915
14019
  const code = await timed(
12916
14020
  debugRoutes,
12917
- `generatePerRouterModule ${routerId}`,
12918
- () => generatePerRouterModule(s, routerId)
14021
+ `generatePerRouterModule ${routerId2}`,
14022
+ () => generatePerRouterModule(s, routerId2)
12919
14023
  );
12920
14024
  return code;
12921
14025
  }
@@ -12924,6 +14028,19 @@ ${details}`,
12924
14028
  // Record handler chunk metadata and RSC entry filename during RSC build.
12925
14029
  // Used by closeBundle for handler code eviction and prerender data injection.
12926
14030
  generateBundle(_options, bundle) {
14031
+ if (s.isBuildMode) {
14032
+ const envName = this.environment?.name;
14033
+ if (envName) {
14034
+ s.versionModuleFiles.set(envName, recordVersionModuleFiles(bundle));
14035
+ }
14036
+ if (envName === "rsc") {
14037
+ s.serverBuildGraph = recordServerGraph(this, bundle);
14038
+ } else if (envName === "client") {
14039
+ s.clientBuildGraph = recordClientGraph(this, bundle);
14040
+ } else if (envName === "ssr") {
14041
+ s.ssrBundle = recordBundleFiles(bundle);
14042
+ }
14043
+ }
12927
14044
  if (this.environment?.name !== "rsc") return;
12928
14045
  const genStart = debugBuild ? performance.now() : 0;
12929
14046
  for (const [fileName, chunk] of Object.entries(bundle)) {
@@ -13013,10 +14130,12 @@ ${details}`,
13013
14130
  init_debug();
13014
14131
  var debugConfig = createRangoDebugger(NS.config);
13015
14132
  var SERVER_BUILD_TARGET = "esnext";
14133
+ var RSC_ENTRY_SIGNATURES = "strict";
13016
14134
  async function rango(options) {
13017
14135
  const rangoStart = performance.now();
13018
14136
  const resolvedOptions = options ?? { preset: "node" };
13019
14137
  const preset = resolvedOptions.preset ?? "node";
14138
+ configureEncryptionKey(resolvedOptions.encryptionKey);
13020
14139
  const showBanner = resolvedOptions.banner ?? true;
13021
14140
  const clientChunksOption = resolvedOptions.clientChunks ?? true;
13022
14141
  const useBuiltInClientChunks = clientChunksOption === true;
@@ -13160,14 +14279,14 @@ async function rango(options) {
13160
14279
  name: "@rangojs/router:auto-discover",
13161
14280
  config(userConfig) {
13162
14281
  if (routerRef.path) return;
13163
- const root = userConfig.root ? resolve13(process.cwd(), userConfig.root) : process.cwd();
14282
+ const root = userConfig.root ? resolve14(process.cwd(), userConfig.root) : process.cwd();
13164
14283
  const toRootRelative = (abs) => (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
13165
14284
  const bulletList = (files) => files.map((f) => " - " + toRootRelative(f)).join("\n");
13166
14285
  if (explicitHostRouter) {
13167
14286
  routerRef.path = normalizeHostRouterEntry(
13168
14287
  explicitHostRouter,
13169
14288
  root,
13170
- existsSync11
14289
+ existsSync13
13171
14290
  );
13172
14291
  routerRef.kind = "host";
13173
14292
  return;
@@ -13287,7 +14406,10 @@ If this is a multi-app host router, export a createHostRouter() instance and set
13287
14406
  rsc: {
13288
14407
  ...vercelServerEnv ?? {},
13289
14408
  build: {
13290
- target: SERVER_BUILD_TARGET
14409
+ target: SERVER_BUILD_TARGET,
14410
+ rollupOptions: {
14411
+ preserveEntrySignatures: RSC_ENTRY_SIGNATURES
14412
+ }
13291
14413
  },
13292
14414
  optimizeDeps: {
13293
14415
  entries: [VIRTUAL_IDS.rsc],
@@ -13349,6 +14471,8 @@ If this is a multi-app host router, export a createHostRouter() instance and set
13349
14471
  );
13350
14472
  plugins.push(clientRefDedup());
13351
14473
  }
14474
+ plugins.push(clientChunksReport());
14475
+ plugins.push(stableRscOutput());
13352
14476
  plugins.push({
13353
14477
  name: "@rangojs/router:client-component-hmr",
13354
14478
  hotUpdate(ctx) {
@@ -13358,7 +14482,7 @@ If this is a multi-app host router, export a createHostRouter() instance and set
13358
14482
  if (!file.endsWith(".tsx") && !file.endsWith(".ts") && !file.endsWith(".jsx") && !file.endsWith(".js"))
13359
14483
  return;
13360
14484
  try {
13361
- const source = readFileSync10(file, "utf-8");
14485
+ const source = readFileSync12(file, "utf-8");
13362
14486
  if (hasUseClientDirective2(source)) {
13363
14487
  return [];
13364
14488
  }
@@ -13381,7 +14505,7 @@ If this is a multi-app host router, export a createHostRouter() instance and set
13381
14505
  const discoveryEntryPath = preset !== "cloudflare" ? routerRef.path : void 0;
13382
14506
  const discoveryRouterRef = preset !== "cloudflare" ? routerRef : void 0;
13383
14507
  if (preset === "cloudflare") {
13384
- plugins.push(createVersionInjectorPlugin(void 0));
14508
+ plugins.push(createEntryBootstrapInjectorPlugin(void 0));
13385
14509
  }
13386
14510
  plugins.push(createCjsToEsmPlugin());
13387
14511
  plugins.push(
@@ -13418,7 +14542,7 @@ function poke() {
13418
14542
  apply: "serve",
13419
14543
  configureServer(server) {
13420
14544
  const stdin = process.stdin;
13421
- const debug13 = process.env.RANGO_POKE_DEBUG === "1";
14545
+ const debug14 = process.env.RANGO_POKE_DEBUG === "1";
13422
14546
  const triggerReload = (source) => {
13423
14547
  server.hot.send({ type: "full-reload", path: "*" });
13424
14548
  server.config.logger.info(` browser reload (${source})`, {
@@ -13451,7 +14575,7 @@ function poke() {
13451
14575
  lines.pop();
13452
14576
  return lines;
13453
14577
  };
13454
- if (debug13) {
14578
+ if (debug14) {
13455
14579
  server.config.logger.info(
13456
14580
  ` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
13457
14581
  { timestamp: true }
@@ -13464,7 +14588,7 @@ function poke() {
13464
14588
  );
13465
14589
  }
13466
14590
  const onData = (data) => {
13467
- if (debug13) {
14591
+ if (debug14) {
13468
14592
  server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
13469
14593
  timestamp: true
13470
14594
  });