@rangojs/router 0.20.0 → 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 (178) 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/testing/build-versions.d.ts +32 -0
  35. package/dist/types/testing/dom.entry.d.ts +1 -1
  36. package/dist/types/testing/flight.entry.d.ts +1 -1
  37. package/dist/types/testing/index.d.ts +2 -0
  38. package/dist/types/testing/internal/seed-vars.d.ts +7 -2
  39. package/dist/types/testing/location-state-key.d.ts +5 -1
  40. package/dist/types/testing/render-route.d.ts +77 -6
  41. package/dist/types/testing/serve-shell-request.d.ts +21 -0
  42. package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
  43. package/dist/types/types/handler-context.d.ts +8 -5
  44. package/dist/types/vite/discovery/build-versions.d.ts +393 -0
  45. package/dist/types/vite/discovery/installed-packages.d.ts +26 -0
  46. package/dist/types/vite/discovery/router-versions-phase.d.ts +52 -0
  47. package/dist/types/vite/discovery/shell-prerender-phase.d.ts +7 -17
  48. package/dist/types/vite/discovery/state.d.ts +14 -0
  49. package/dist/types/vite/encryption-key.d.ts +18 -0
  50. package/dist/types/vite/plugin-types.d.ts +27 -0
  51. package/dist/types/vite/plugins/{version-injector.d.ts → entry-bootstrap-injector.d.ts} +4 -6
  52. package/dist/types/vite/plugins/expose-ids/export-analysis.d.ts +1 -0
  53. package/dist/types/vite/plugins/expose-ids/router-transform.d.ts +14 -0
  54. package/dist/types/vite/plugins/stable-rsc-output.d.ts +51 -0
  55. package/dist/types/vite/plugins/version-plugin.d.ts +9 -11
  56. package/dist/types/vite/plugins/virtual-entries.d.ts +18 -1
  57. package/dist/types/vite/router-discovery.d.ts +6 -0
  58. package/dist/types/vite/utils/client-chunks.d.ts +2 -0
  59. package/dist/types/vite/utils/compare-strings.d.ts +7 -0
  60. package/dist/types/vite/utils/package-resolution.d.ts +8 -0
  61. package/dist/types/vite/utils/prerender-utils.d.ts +2 -0
  62. package/dist/vite/index.js +1537 -444
  63. package/package.json +1 -2
  64. package/skills/cache-guide/SKILL.md +84 -20
  65. package/skills/caching/SKILL.md +16 -5
  66. package/skills/client-urls/SKILL.md +16 -0
  67. package/skills/cloudflare/SKILL.md +2 -1
  68. package/skills/comparison/references/framework-comparison.md +16 -12
  69. package/skills/hooks/SKILL.md +3 -0
  70. package/skills/hooks/handle-and-actions.md +6 -0
  71. package/skills/hooks/navigation.md +28 -0
  72. package/skills/hooks/state.md +209 -8
  73. package/skills/hooks/urls.md +40 -1
  74. package/skills/host-router/SKILL.md +13 -0
  75. package/skills/intercept/SKILL.md +6 -0
  76. package/skills/loader/SKILL.md +19 -1
  77. package/skills/middleware/SKILL.md +2 -0
  78. package/skills/ppr/SKILL.md +119 -40
  79. package/skills/prerender/SKILL.md +7 -3
  80. package/skills/rango/SKILL.md +8 -7
  81. package/skills/router-setup/SKILL.md +15 -1
  82. package/skills/testing/SKILL.md +30 -26
  83. package/skills/testing/client-components.md +193 -8
  84. package/skills/testing/handles.md +2 -0
  85. package/skills/testing/loader.md +1 -1
  86. package/skills/testing/middleware.md +1 -1
  87. package/skills/testing/render-handler.md +18 -18
  88. package/skills/testing/serve-shell-request.md +63 -14
  89. package/skills/testing/server-actions.md +17 -17
  90. package/skills/testing/server-tree.md +1 -1
  91. package/skills/typesafety/generated-files-and-cli.md +1 -1
  92. package/skills/use-cache/SKILL.md +16 -5
  93. package/skills/vercel/SKILL.md +3 -3
  94. package/src/bin/rango.ts +1 -1
  95. package/src/browser/event-controller.ts +75 -2
  96. package/src/browser/history-state.ts +39 -17
  97. package/src/browser/navigation-bridge.ts +41 -18
  98. package/src/browser/navigation-transaction.ts +15 -10
  99. package/src/browser/partial-update.ts +10 -2
  100. package/src/browser/rango-state.ts +3 -1
  101. package/src/browser/react/Link.tsx +2 -3
  102. package/src/browser/react/NavigationProvider.tsx +25 -1
  103. package/src/browser/react/context.ts +13 -0
  104. package/src/browser/react/location-state-shared.ts +200 -34
  105. package/src/browser/react/location-state.ts +40 -75
  106. package/src/browser/react/subscribe-to-nothing.ts +7 -0
  107. package/src/browser/react/use-handle.ts +20 -1
  108. package/src/browser/rsc-router.tsx +33 -11
  109. package/src/browser/server-action-bridge.ts +17 -1
  110. package/src/cache/cache-scope.ts +18 -8
  111. package/src/cache/cf/cf-cache-store.ts +75 -55
  112. package/src/cache/cf/cf-cache-types.ts +12 -4
  113. package/src/cache/handle-snapshot.ts +69 -87
  114. package/src/cache/index.ts +4 -0
  115. package/src/cache/shell-snapshot.ts +35 -5
  116. package/src/cache/types.ts +21 -10
  117. package/src/cache/vercel/vercel-cache-store.ts +48 -20
  118. package/src/client-urls/client-root.tsx +1 -0
  119. package/src/client-urls/navigation.ts +10 -0
  120. package/src/client-urls/optimistic-location.ts +10 -4
  121. package/src/handles/deferred-resolution.ts +31 -0
  122. package/src/prerender/build-shell-capture.ts +11 -9
  123. package/src/router/manifest.ts +2 -0
  124. package/src/router/match-middleware/cache-lookup.ts +11 -18
  125. package/src/router/navigation-snapshot.ts +25 -6
  126. package/src/router/request-classification.ts +15 -12
  127. package/src/router/router-interfaces.ts +2 -1
  128. package/src/router/router-options.ts +17 -7
  129. package/src/router/segment-resolution/loader-cache.ts +95 -60
  130. package/src/router-versions.ts +60 -0
  131. package/src/rsc/full-payload.ts +6 -2
  132. package/src/rsc/handler-context.ts +5 -0
  133. package/src/rsc/handler.ts +14 -4
  134. package/src/rsc/rsc-rendering.ts +12 -1
  135. package/src/rsc/shell-build-manifest.ts +10 -7
  136. package/src/rsc/shell-capture.ts +36 -26
  137. package/src/rsc/types.ts +4 -6
  138. package/src/server/build-version-table.ts +115 -0
  139. package/src/server/handle-store.ts +344 -127
  140. package/src/server/request-context.ts +62 -11
  141. package/src/ssr/ssr-root.tsx +16 -4
  142. package/src/testing/build-versions.ts +64 -0
  143. package/src/testing/dispatch.ts +6 -0
  144. package/src/testing/dom.entry.ts +1 -0
  145. package/src/testing/flight.entry.ts +1 -0
  146. package/src/testing/index.ts +3 -0
  147. package/src/testing/internal/context.ts +2 -1
  148. package/src/testing/internal/seed-vars.ts +14 -2
  149. package/src/testing/location-state-key.ts +18 -8
  150. package/src/testing/render-handler.ts +2 -1
  151. package/src/testing/render-route.tsx +277 -43
  152. package/src/testing/serve-shell-request.ts +80 -11
  153. package/src/testing/vitest-stubs/version.ts +4 -1
  154. package/src/types/handler-context.ts +8 -5
  155. package/src/vite/discovery/build-versions.ts +1281 -0
  156. package/src/vite/discovery/installed-packages.ts +159 -0
  157. package/src/vite/discovery/prerender-collection.ts +38 -1
  158. package/src/vite/discovery/router-versions-phase.ts +336 -0
  159. package/src/vite/discovery/shell-prerender-phase.ts +28 -38
  160. package/src/vite/discovery/state.ts +19 -0
  161. package/src/vite/discovery/virtual-module-codegen.ts +7 -2
  162. package/src/vite/encryption-key.ts +101 -9
  163. package/src/vite/plugin-types.ts +28 -0
  164. package/src/vite/plugins/{version-injector.ts → entry-bootstrap-injector.ts} +7 -22
  165. package/src/vite/plugins/expose-ids/export-analysis.ts +1 -1
  166. package/src/vite/plugins/expose-ids/router-transform.ts +36 -15
  167. package/src/vite/plugins/expose-internal-ids.ts +12 -3
  168. package/src/vite/plugins/stable-rsc-output.ts +147 -0
  169. package/src/vite/plugins/version-plugin.ts +19 -24
  170. package/src/vite/plugins/version.d.ts +17 -2
  171. package/src/vite/plugins/virtual-entries.ts +31 -5
  172. package/src/vite/rango.ts +28 -3
  173. package/src/vite/router-discovery.ts +82 -13
  174. package/src/vite/utils/client-chunks.ts +5 -1
  175. package/src/vite/utils/compare-strings.ts +9 -0
  176. package/src/vite/utils/package-resolution.ts +9 -0
  177. package/src/vite/utils/prerender-utils.ts +4 -1
  178. 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 {
@@ -4457,12 +4577,11 @@ import {
4457
4577
  // consults them at router-module evaluation. Router-first would silently push
4458
4578
  // every clientUrls() app onto the deferred-subscription path and change mount
4459
4579
  // registration order with no error. The custom-entry injector keeps the same
4460
- // guarantee by PREPENDING this list at file top (version-injector.ts).
4580
+ // guarantee by PREPENDING this list at file top (entry-bootstrap-injector.ts).
4461
4581
  ${bootstrapImports}
4462
4582
 
4463
4583
  import { router } from "${routerPath}";
4464
4584
  import { createRSCHandler } from "@rangojs/router/internal/rsc-handler";
4465
- import { VERSION } from "@rangojs/router:version";
4466
4585
 
4467
4586
  // Lazily create the handler on first request so that ESM live bindings
4468
4587
  // have resolved by the time we read \`router\`. During HMR the module may
@@ -4472,7 +4591,6 @@ export default function handler(request, env) {
4472
4591
  if (!_handler) {
4473
4592
  _handler = createRSCHandler({
4474
4593
  router,
4475
- version: VERSION,
4476
4594
  // Forward the router's CSP nonce provider. createRSCHandler reads the
4477
4595
  // provider only from options.nonce; without this, createRouter({ nonce })
4478
4596
  // is silently dropped on the Node preset (the Cloudflare path wires it via
@@ -4572,7 +4690,726 @@ var VIRTUAL_IDS = {
4572
4690
  version: "@rangojs/router:version"
4573
4691
  };
4574
4692
  function getVirtualVersionContent(version) {
4575
- 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
+ };
4576
5413
  }
4577
5414
 
4578
5415
  // src/vite/utils/package-resolution.ts
@@ -4583,7 +5420,7 @@ import { resolve } from "node:path";
4583
5420
  // package.json
4584
5421
  var package_default = {
4585
5422
  name: "@rangojs/router",
4586
- version: "0.20.0",
5423
+ version: "0.21.0",
4587
5424
  description: "Django-inspired RSC router with composable URL patterns",
4588
5425
  keywords: [
4589
5426
  "react",
@@ -4814,7 +5651,6 @@ var package_default = {
4814
5651
  "@playwright/test": "^1.49.1",
4815
5652
  "@testing-library/react": ">=16",
4816
5653
  "@vercel/functions": "^3.0.0",
4817
- "@vitejs/plugin-rsc": "^0.5.35",
4818
5654
  react: ">=19.2.8 <20",
4819
5655
  "react-dom": ">=19.2.8 <20",
4820
5656
  vite: "^8.0.16",
@@ -4894,7 +5730,8 @@ function getVendorAliases() {
4894
5730
  const specs = [
4895
5731
  "@vitejs/plugin-rsc/vendor/react-server-dom/client.browser",
4896
5732
  "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
4897
- "@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"
4898
5735
  ];
4899
5736
  const aliases = {};
4900
5737
  for (const spec of specs) {
@@ -5033,7 +5870,7 @@ declare global {
5033
5870
  }
5034
5871
 
5035
5872
  // src/build/route-types/scan-filter.ts
5036
- import { join as join2, relative as relative2 } from "node:path";
5873
+ import { join as join2, relative as relative4 } from "node:path";
5037
5874
  import { readdirSync } from "node:fs";
5038
5875
  import picomatch from "picomatch";
5039
5876
  var DEFAULT_EXCLUDE_PATTERNS = [
@@ -5053,7 +5890,7 @@ function createScanFilter(root, opts) {
5053
5890
  const includeMatcher = hasInclude ? picomatch(include) : null;
5054
5891
  const excludeMatcher = effectiveExclude.length > 0 ? picomatch(effectiveExclude) : null;
5055
5892
  return (absolutePath) => {
5056
- const rel = relative2(root, absolutePath);
5893
+ const rel = relative4(root, absolutePath);
5057
5894
  if (excludeMatcher && excludeMatcher(rel)) return false;
5058
5895
  if (includeMatcher) return includeMatcher(rel);
5059
5896
  return true;
@@ -5232,7 +6069,7 @@ function extractIncludesWithDiagnostics(code, sourceFileArg) {
5232
6069
  true,
5233
6070
  ts3.ScriptKind.TSX
5234
6071
  );
5235
- const resolved = [];
6072
+ const resolved2 = [];
5236
6073
  const unresolvable = [];
5237
6074
  function visit(node) {
5238
6075
  if (ts3.isCallExpression(node)) {
@@ -5251,13 +6088,13 @@ function extractIncludesWithDiagnostics(code, sourceFileArg) {
5251
6088
  const namePrefix = extractNamePrefixFromInclude(node);
5252
6089
  const dynamicImportSpec = extractDynamicImportSpecifier(secondArg);
5253
6090
  if (ts3.isIdentifier(secondArg)) {
5254
- resolved.push({
6091
+ resolved2.push({
5255
6092
  pathPrefix,
5256
6093
  variableName: secondArg.text,
5257
6094
  namePrefix
5258
6095
  });
5259
6096
  } else if (dynamicImportSpec !== null) {
5260
- resolved.push({
6097
+ resolved2.push({
5261
6098
  pathPrefix,
5262
6099
  moduleSpecifier: dynamicImportSpec,
5263
6100
  namePrefix
@@ -5283,7 +6120,7 @@ function extractIncludesWithDiagnostics(code, sourceFileArg) {
5283
6120
  ts3.forEachChild(node, visit);
5284
6121
  }
5285
6122
  visit(sourceFile);
5286
- return { resolved, unresolvable };
6123
+ return { resolved: resolved2, unresolvable };
5287
6124
  }
5288
6125
  function resolveImportedVariable(code, localName) {
5289
6126
  const defaultImportRegex = /import\s+([\w$]+)\s*(?:,\s*\{[^}]*\})?\s+from\s*["']([^"']+)["']/g;
@@ -5424,7 +6261,7 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
5424
6261
  );
5425
6262
  } else {
5426
6263
  const variableName = def.variableName;
5427
- const resolved = resolveIncludedVariable({
6264
+ const resolved2 = resolveIncludedVariable({
5428
6265
  variableName,
5429
6266
  resolutionFile: targetFile,
5430
6267
  resolutionSource: targetSource,
@@ -5437,12 +6274,12 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
5437
6274
  fileNotFoundDetail: (specifier) => `import("${inc.moduleSpecifier}") default re-exports "${variableName}" from "${specifier}", which resolved to no file`,
5438
6275
  notFoundDetail: () => `import("${inc.moduleSpecifier}") default "${variableName}" not found in its imports or same-file scope`
5439
6276
  });
5440
- if (!resolved) continue;
5441
- childResult = resolved;
6277
+ if (!resolved2) continue;
6278
+ childResult = resolved2;
5442
6279
  }
5443
6280
  } else if (inc.variableName) {
5444
6281
  const variableName = inc.variableName;
5445
- const resolved = resolveIncludedVariable({
6282
+ const resolved2 = resolveIncludedVariable({
5446
6283
  variableName,
5447
6284
  resolutionFile: filePath,
5448
6285
  resolutionSource: fullSource,
@@ -5455,8 +6292,8 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
5455
6292
  fileNotFoundDetail: (specifier) => `import "${specifier}" resolved to no file`,
5456
6293
  notFoundDetail: () => `variable "${variableName}" not found in imports or same-file scope`
5457
6294
  });
5458
- if (!resolved) continue;
5459
- childResult = resolved;
6295
+ if (!resolved2) continue;
6296
+ childResult = resolved2;
5460
6297
  } else {
5461
6298
  continue;
5462
6299
  }
@@ -6041,14 +6878,14 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
6041
6878
  }
6042
6879
 
6043
6880
  // src/vite/plugins/version-plugin.ts
6044
- import { parseAst as parseAst5 } from "vite";
6881
+ import { parseAst as parseAst6 } from "vite";
6045
6882
 
6046
6883
  // src/vite/utils/directive-prologue.ts
6047
- import { parseAst as parseAst4 } from "vite";
6884
+ import { parseAst as parseAst5 } from "vite";
6048
6885
  function hasUseClientDirective2(source) {
6049
6886
  let program;
6050
6887
  try {
6051
- program = parseAst4(source, { lang: "tsx" });
6888
+ program = parseAst5(source, { lang: "tsx" });
6052
6889
  } catch {
6053
6890
  return false;
6054
6891
  }
@@ -6073,7 +6910,7 @@ function getClientModuleSignature(source) {
6073
6910
  if (!hasUseClientDirective2(source)) return void 0;
6074
6911
  let program;
6075
6912
  try {
6076
- program = parseAst5(source, { lang: "tsx" });
6913
+ program = parseAst6(source, { lang: "tsx" });
6077
6914
  } catch {
6078
6915
  return void 0;
6079
6916
  }
@@ -6141,8 +6978,7 @@ function getClientModuleSignature(source) {
6141
6978
  };
6142
6979
  }
6143
6980
  function createVersionPlugin() {
6144
- const buildVersion = Date.now().toString(16);
6145
- let currentVersion3 = buildVersion;
6981
+ let currentVersion3 = Date.now().toString(16);
6146
6982
  let isDev = false;
6147
6983
  let server = null;
6148
6984
  let resolvedCacheDir;
@@ -6162,13 +6998,6 @@ function createVersionPlugin() {
6162
6998
  return {
6163
6999
  name: "@rangojs/router:version",
6164
7000
  enforce: "pre",
6165
- // The build-time shell capture phase (producer B, #699) stamps entries
6166
- // with THIS instance's version — the value folded into the shipped worker
6167
- // — never the discovery temp server's own version-plugin value (a
6168
- // different Date.now() stamp that would fail the serve-side gate).
6169
- api: {
6170
- getBuildVersion: () => currentVersion3
6171
- },
6172
7001
  configResolved(config) {
6173
7002
  isDev = config.command === "serve";
6174
7003
  resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
@@ -6190,7 +7019,7 @@ function createVersionPlugin() {
6190
7019
  },
6191
7020
  load(id) {
6192
7021
  if (id === "\0" + VIRTUAL_IDS.version) {
6193
- return getVirtualVersionContent(currentVersion3);
7022
+ return isDev ? getVirtualVersionContent(currentVersion3) : getVirtualBuildVersionContent();
6194
7023
  }
6195
7024
  return null;
6196
7025
  },
@@ -6261,7 +7090,7 @@ import { isAbsolute as isAbsolute2, resolve as resolve4 } from "node:path";
6261
7090
  // src/vite/plugins/performance-tracks.ts
6262
7091
  init_debug();
6263
7092
  import { readFile as readFile2 } from "node:fs/promises";
6264
- var debug5 = createRangoDebugger(NS.transform);
7093
+ var debug6 = createRangoDebugger(NS.transform);
6265
7094
  var RSDW_PATCH_RE = /((?:var|let|const)\s+\w+\s*=\s*root\._children\s*,\s*(\w+)\s*=\s*root\._debugInfo\s*[;,])/;
6266
7095
  function buildPatchReplacement(match, debugInfoVar) {
6267
7096
  return `${match}
@@ -6296,7 +7125,7 @@ function performanceTracksOptimizeDepsPlugin() {
6296
7125
  };
6297
7126
  }
6298
7127
  function performanceTracksPlugin() {
6299
- const counter = createCounter(debug5, "performance-tracks");
7128
+ const counter = createCounter(debug6, "performance-tracks");
6300
7129
  return {
6301
7130
  name: "@rangojs/router:performance-tracks",
6302
7131
  buildEnd() {
@@ -6308,7 +7137,7 @@ function performanceTracksPlugin() {
6308
7137
  try {
6309
7138
  const patched = patchRsdwClientDebugInfoRecovery(code);
6310
7139
  if (!patched.debugInfoVar) return;
6311
- debug5?.("patched RSDW client (var: %s)", patched.debugInfoVar);
7140
+ debug6?.("patched RSDW client (var: %s)", patched.debugInfoVar);
6312
7141
  return patched.code;
6313
7142
  } finally {
6314
7143
  counter?.record(id, performance.now() - start);
@@ -6445,90 +7274,6 @@ function getManualChunks(id) {
6445
7274
  return void 0;
6446
7275
  }
6447
7276
 
6448
- // src/vite/utils/client-chunks.ts
6449
- init_debug();
6450
- init_client_ref_hashing();
6451
- import { gzipSync } from "node:zlib";
6452
- var debugChunks = createRangoDebugger(NS.chunks);
6453
- function isSharedRuntime(meta) {
6454
- return [meta.id, meta.normalizedId].some(
6455
- (path6) => path6.includes("/node_modules/") || /\/@rangojs\/router\//.test(path6) || /\/packages\/(rangojs-router|rsc-router)\/(src|dist)\//.test(path6)
6456
- );
6457
- }
6458
- function sanitizeGroup(name) {
6459
- return name.replace(/[^a-zA-Z0-9_-]+/g, "_").replace(/^_+|_+$/g, "") || "app";
6460
- }
6461
- var ROUTE_ROOT_DIRS = /* @__PURE__ */ new Set([
6462
- "routes",
6463
- "route",
6464
- "pages",
6465
- "page",
6466
- "app",
6467
- "features",
6468
- "feature",
6469
- "views",
6470
- "view",
6471
- "handlers",
6472
- "urls",
6473
- "modules",
6474
- "screens",
6475
- "sections"
6476
- ]);
6477
- var SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set(["app"]);
6478
- function directoryClientChunks(meta, ctx) {
6479
- if (isSharedRuntime(meta)) {
6480
- return void 0;
6481
- }
6482
- if (ctx?.fallbackRefs.size && ctx.fallbackRefs.has(hashRefKey(meta.normalizedId))) {
6483
- debugChunks?.("fallback %s -> app-fallback", meta.normalizedId);
6484
- return "app-fallback";
6485
- }
6486
- const segments = meta.normalizedId.split("/").filter(Boolean);
6487
- const dirCount = segments.length - 1;
6488
- const isMarkerAt = (i) => i < dirCount - 1 && ROUTE_ROOT_DIRS.has(segments[i].toLowerCase());
6489
- for (let i = 0; i < dirCount - 1; i++) {
6490
- if (!isMarkerAt(i)) continue;
6491
- const marker = SOURCE_ROOT_DIRS.has(segments[i].toLowerCase()) && isMarkerAt(i + 1) ? i + 1 : i;
6492
- const group = `app-${sanitizeGroup(segments[marker + 1])}`;
6493
- debugChunks?.("split %s -> %s", meta.normalizedId, group);
6494
- return group;
6495
- }
6496
- debugChunks?.(
6497
- "shared %s (no route-root marker; inherits default grouping)",
6498
- meta.normalizedId
6499
- );
6500
- return void 0;
6501
- }
6502
- function resolveClientChunks(option, ctx) {
6503
- if (!option) return void 0;
6504
- if (option === true) return (meta) => directoryClientChunks(meta, ctx);
6505
- return option;
6506
- }
6507
- var CLIENT_GROUP_PREFIX = "\0virtual:vite-rsc/client-references/group/";
6508
- function clientChunksReport(log = debugChunks) {
6509
- if (!log) return void 0;
6510
- return {
6511
- name: "@rangojs/router:client-chunks-report",
6512
- apply: "build",
6513
- applyToEnvironment: (env) => env.name === "client",
6514
- generateBundle(_options, bundle) {
6515
- for (const chunk of Object.values(bundle)) {
6516
- if (chunk.type !== "chunk") continue;
6517
- const facade = chunk.facadeModuleId;
6518
- if (!facade?.startsWith(CLIENT_GROUP_PREFIX)) continue;
6519
- log(
6520
- "group %s: %d client reference(s), %d B (%d B gzip) -> %s",
6521
- facade.slice(CLIENT_GROUP_PREFIX.length).replaceAll("\0", "\\0"),
6522
- this.getModuleInfo(facade)?.importedIds.length ?? 0,
6523
- Buffer.byteLength(chunk.code),
6524
- gzipSync(chunk.code).length,
6525
- chunk.fileName
6526
- );
6527
- }
6528
- }
6529
- };
6530
- }
6531
-
6532
7277
  // src/vite/plugins/vercel-output.ts
6533
7278
  import { rm, mkdir, cp, writeFile } from "node:fs/promises";
6534
7279
  import { existsSync as existsSync5 } from "node:fs";
@@ -6805,13 +7550,13 @@ ${dim} ${reset}${bold}\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550$
6805
7550
  console.log(banner);
6806
7551
  }
6807
7552
 
6808
- // src/vite/plugins/version-injector.ts
7553
+ // src/vite/plugins/entry-bootstrap-injector.ts
6809
7554
  import { resolve as resolve6 } from "node:path";
6810
7555
  import * as Vite2 from "vite";
6811
- function createVersionInjectorPlugin(rscEntryPath) {
7556
+ function createEntryBootstrapInjectorPlugin(rscEntryPath) {
6812
7557
  let resolvedEntryPath = "";
6813
7558
  return {
6814
- name: "@rangojs/router:version-injector",
7559
+ name: "@rangojs/router:entry-bootstrap-injector",
6815
7560
  enforce: "pre",
6816
7561
  configResolved(config) {
6817
7562
  let entryPath = rscEntryPath;
@@ -6830,16 +7575,7 @@ function createVersionInjectorPlugin(rscEntryPath) {
6830
7575
  const prepend = RSC_ENTRY_BOOTSTRAP_IMPORTS.map(
6831
7576
  (id2) => `import "${id2}";`
6832
7577
  );
6833
- let newCode = code;
6834
- const needsVersion = code.includes("createRSCHandler") && !code.includes("@rangojs/router:version") && /createRSCHandler\s*\(\s*\{/.test(code);
6835
- if (needsVersion) {
6836
- prepend.push(`import { VERSION } from "@rangojs/router:version";`);
6837
- newCode = newCode.replace(
6838
- /createRSCHandler\s*\(\s*\{/,
6839
- "createRSCHandler({\n version: VERSION,"
6840
- );
6841
- }
6842
- const lines = newCode.split("\n");
7578
+ const lines = code.split("\n");
6843
7579
  let insertAt = 0;
6844
7580
  while (insertAt < lines.length) {
6845
7581
  const trimmed = lines[insertAt].trim();
@@ -6849,7 +7585,7 @@ function createVersionInjectorPlugin(rscEntryPath) {
6849
7585
  break;
6850
7586
  }
6851
7587
  }
6852
- newCode = [
7588
+ const newCode = [
6853
7589
  ...lines.slice(0, insertAt),
6854
7590
  ...prepend,
6855
7591
  ...lines.slice(insertAt)
@@ -6927,8 +7663,8 @@ function createCjsToEsmPlugin() {
6927
7663
 
6928
7664
  // src/vite/router-discovery.ts
6929
7665
  import { createServer as createViteServer } from "vite";
6930
- import { resolve as resolve12 } from "node:path";
6931
- 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";
6932
7668
  import { createRequire as createRequire3, register } from "node:module";
6933
7669
  import { pathToFileURL as pathToFileURL2 } from "node:url";
6934
7670
 
@@ -7111,7 +7847,7 @@ function createCloudflareProtocolStubPlugin() {
7111
7847
  return null;
7112
7848
  }
7113
7849
  const hits = [];
7114
- walk(ast, (node) => {
7850
+ walk2(ast, (node) => {
7115
7851
  if (!IMPORT_NODE_TYPES.has(node.type)) return;
7116
7852
  const source = node.source;
7117
7853
  if (!source || source.type !== "Literal") return;
@@ -7149,10 +7885,10 @@ function createCloudflareProtocolStubPlugin() {
7149
7885
  }
7150
7886
  };
7151
7887
  }
7152
- function walk(node, visit) {
7888
+ function walk2(node, visit) {
7153
7889
  if (!node || typeof node !== "object") return;
7154
7890
  if (Array.isArray(node)) {
7155
- for (const child of node) walk(child, visit);
7891
+ for (const child of node) walk2(child, visit);
7156
7892
  return;
7157
7893
  }
7158
7894
  const n = node;
@@ -7162,7 +7898,7 @@ function walk(node, visit) {
7162
7898
  if (key === "loc" || key === "start" || key === "end" || key === "range") {
7163
7899
  continue;
7164
7900
  }
7165
- walk(n[key], visit);
7901
+ walk2(n[key], visit);
7166
7902
  }
7167
7903
  }
7168
7904
 
@@ -7294,51 +8030,11 @@ function evictHandlerCode(code, exports, fnName, brand) {
7294
8030
  };
7295
8031
  }
7296
8032
 
7297
- // src/vite/discovery/state.ts
7298
- var VIRTUAL_ROUTES_MANIFEST_ID = "virtual:rsc-router/routes-manifest";
7299
- function createDiscoveryState(entryPath, opts) {
7300
- return {
7301
- resolvedEntryPath: entryPath,
7302
- projectRoot: "",
7303
- isBuildMode: false,
7304
- userResolveAlias: void 0,
7305
- userRunnerConfig: void 0,
7306
- userResolvePlugins: [],
7307
- scanFilter: void 0,
7308
- cachedRouterFiles: void 0,
7309
- opts,
7310
- mergedRouteManifest: null,
7311
- perRouterManifests: [],
7312
- perRouterTrieMap: /* @__PURE__ */ new Map(),
7313
- perRouterPrecomputedMap: /* @__PURE__ */ new Map(),
7314
- perRouterManifestDataMap: /* @__PURE__ */ new Map(),
7315
- clientUrlSourceByReferenceId: /* @__PURE__ */ new Map(),
7316
- clientUrlProjectionMap: /* @__PURE__ */ new Map(),
7317
- prerenderManifestEntries: null,
7318
- staticManifestEntries: null,
7319
- shellCandidates: null,
7320
- prerenderPayloadValues: null,
7321
- shellPhaseTempServer: null,
7322
- handlerChunkInfoMap: /* @__PURE__ */ new Map(),
7323
- staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
7324
- rscEntryFileName: null,
7325
- resolvedPrerenderModules: void 0,
7326
- resolvedStaticModules: void 0,
7327
- discoveryDone: null,
7328
- devDiscoveryEpoch: opts?.preset === "cloudflare" ? Date.now() : void 0,
7329
- devServerOrigin: null,
7330
- devServer: null,
7331
- selfWrittenGenFiles: /* @__PURE__ */ new Map(),
7332
- SELF_WRITE_WINDOW_MS: 5e3,
7333
- lastDiscoveryError: null
7334
- };
7335
- }
7336
-
7337
8033
  // src/vite/discovery/self-gen-tracking.ts
7338
- import { createHash as createHash3 } from "node:crypto";
8034
+ import { createHash as createHash4 } from "node:crypto";
7339
8035
  import { readFileSync as readFileSync4 } from "node:fs";
7340
8036
  function markSelfGenWrite(state, filePath, content) {
7341
- const hash = createHash3("sha256").update(content).digest("hex");
8037
+ const hash = createHash4("sha256").update(content).digest("hex");
7342
8038
  state.selfWrittenGenFiles.set(filePath, { at: Date.now(), hash });
7343
8039
  }
7344
8040
  function consumeSelfGenWrite(state, filePath) {
@@ -7356,7 +8052,7 @@ function checkSelfGenWrite(state, filePath, consume) {
7356
8052
  }
7357
8053
  try {
7358
8054
  const current = readFileSync4(filePath, "utf-8");
7359
- const currentHash = createHash3("sha256").update(current).digest("hex");
8055
+ const currentHash = createHash4("sha256").update(current).digest("hex");
7360
8056
  if (currentHash === info.hash) {
7361
8057
  if (consume) state.selfWrittenGenFiles.delete(filePath);
7362
8058
  return true;
@@ -7850,7 +8546,7 @@ function contextSet(variables, keyOrVar, value, options) {
7850
8546
  }
7851
8547
 
7852
8548
  // src/vite/utils/prerender-utils.ts
7853
- import { createHash as createHash4 } from "node:crypto";
8549
+ import { createHash as createHash5 } from "node:crypto";
7854
8550
  import {
7855
8551
  copyFileSync,
7856
8552
  existsSync as existsSync6,
@@ -8014,15 +8710,16 @@ function resolvePrerenderError(registry, error, onError, label, elapsed, phase,
8014
8710
  notifyOnError(registry, error, phase, routeKey, pathname);
8015
8711
  throw error;
8016
8712
  }
8713
+ var RANGO_BUILD_DIR = "node_modules/.rangojs-router-build";
8017
8714
  function getStagedAssetDir(projectRoot) {
8018
- return resolve7(projectRoot, "node_modules/.rangojs-router-build/rsc-assets");
8715
+ return resolve7(projectRoot, RANGO_BUILD_DIR, "rsc-assets");
8019
8716
  }
8020
8717
  function resetStagedBuildAssets(projectRoot) {
8021
8718
  rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
8022
8719
  }
8023
8720
  function writeBuildAssetModule(dir, prefix, exportValue) {
8024
8721
  mkdirSync(dir, { recursive: true });
8025
- const contentHash = createHash4("sha256").update(exportValue).digest("hex").slice(0, 8);
8722
+ const contentHash = createHash5("sha256").update(exportValue).digest("hex").slice(0, 8);
8026
8723
  const fileName = `${prefix}-${contentHash}.js`;
8027
8724
  const filePath = resolve7(dir, fileName);
8028
8725
  if (!existsSync6(filePath)) {
@@ -8055,6 +8752,14 @@ function copyStagedBuildAssets(projectRoot, fileNames) {
8055
8752
  // src/vite/discovery/prerender-collection.ts
8056
8753
  init_debug();
8057
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
+ }
8058
8763
  async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
8059
8764
  if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
8060
8765
  const overallStart = debug9 ? performance.now() : 0;
@@ -8231,7 +8936,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
8231
8936
  group.concurrency,
8232
8937
  async (entry) => {
8233
8938
  const startUrl = performance.now();
8234
- for (const [, routerInstance] of registry) {
8939
+ for (const [routerId2, routerInstance] of registry) {
8235
8940
  if (!routerInstance.matchForPrerender) continue;
8236
8941
  try {
8237
8942
  const result = await routerInstance.matchForPrerender(
@@ -8261,6 +8966,9 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
8261
8966
  "__pr",
8262
8967
  mainValue
8263
8968
  );
8969
+ recordBuildData(state, "prerender", mainKey, mainValue, {
8970
+ routerId: routerId2
8971
+ });
8264
8972
  if (result.ppr !== void 0 && result.ppr !== false) {
8265
8973
  (state.shellCandidates ??= []).push({
8266
8974
  urlPath: entry.urlPath,
@@ -8286,6 +8994,15 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
8286
8994
  "__pr",
8287
8995
  interceptValue
8288
8996
  );
8997
+ recordBuildData(
8998
+ state,
8999
+ "prerender",
9000
+ interceptKey,
9001
+ interceptValue,
9002
+ {
9003
+ routerId: routerId2
9004
+ }
9005
+ );
8289
9006
  }
8290
9007
  const elapsed = (performance.now() - startUrl).toFixed(0);
8291
9008
  console.log(
@@ -8388,6 +9105,9 @@ async function renderStaticHandlers(state, rscEnv, registry) {
8388
9105
  "__st",
8389
9106
  exportValue
8390
9107
  );
9108
+ recordBuildData(state, "static", def.$$id, exportValue, {
9109
+ moduleId
9110
+ });
8391
9111
  const elapsed = (performance.now() - startHandler).toFixed(0);
8392
9112
  console.log(`[rango] OK ${name.padEnd(40)} (${elapsed}ms)`);
8393
9113
  staticDone++;
@@ -8534,8 +9254,8 @@ init_client_ref_hashing();
8534
9254
 
8535
9255
  // src/vite/discovery/client-urls-projection.ts
8536
9256
  import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
8537
- import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve8 } from "node:path";
8538
- 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";
8539
9259
 
8540
9260
  // src/client-urls/server-projection.ts
8541
9261
  import * as React5 from "react";
@@ -8549,7 +9269,7 @@ function isUnderTestRunner() {
8549
9269
  import {
8550
9270
  Component as Component3,
8551
9271
  createElement as createElement3,
8552
- useContext as useContext16,
9272
+ useContext as useContext17,
8553
9273
  useMemo as useMemo8,
8554
9274
  Suspense as Suspense2
8555
9275
  } from "react";
@@ -8561,6 +9281,7 @@ import {
8561
9281
  useEffect,
8562
9282
  useRef,
8563
9283
  useOptimistic,
9284
+ useSyncExternalStore,
8564
9285
  startTransition
8565
9286
  } from "react";
8566
9287
 
@@ -8637,6 +9358,11 @@ function createHandle(collect, __injectedId) {
8637
9358
  // src/browser/react/context.ts
8638
9359
  import { createContext } from "react";
8639
9360
  var NavigationStoreContext = createContext(null);
9361
+ var LocationStateContext = createContext(void 0);
9362
+
9363
+ // src/browser/react/subscribe-to-nothing.ts
9364
+ var subscribeToNothing = () => () => {
9365
+ };
8640
9366
 
8641
9367
  // src/handles/meta.ts
8642
9368
  function isUnsetDescriptor(descriptor) {
@@ -9405,7 +10131,7 @@ import {
9405
10131
  useEffect as useEffect14,
9406
10132
  useMemo as useMemo7,
9407
10133
  useRef as useRef12,
9408
- useSyncExternalStore
10134
+ useSyncExternalStore as useSyncExternalStore2
9409
10135
  } from "react";
9410
10136
 
9411
10137
  // src/browser/react/use-link-status.ts
@@ -9647,8 +10373,6 @@ function isPrefetchScopeDisabled(element) {
9647
10373
  // src/browser/react/Link.tsx
9648
10374
  init_loader();
9649
10375
  import { jsx as jsx8 } from "react/jsx-runtime";
9650
- var IGNORE_STRATEGY_CHANGES = (_listener) => () => {
9651
- };
9652
10376
  function isExternalUrl(href2, origin) {
9653
10377
  if (href2.startsWith("//")) return true;
9654
10378
  if (href2.startsWith("http://") || href2.startsWith("https://")) {
@@ -9690,8 +10414,8 @@ var Link = forwardRef(function Link2({
9690
10414
  return to === "/" ? bn : bn + to;
9691
10415
  }, [to, isExternal, ctx?.basename]);
9692
10416
  const configuredStrategy = prefetch ?? ctx?.defaultPrefetch ?? getDefaultPrefetchStrategy();
9693
- const resolvedStrategy = useSyncExternalStore(
9694
- configuredStrategy === "adaptive" ? subscribeToAdaptiveStrategyChange : IGNORE_STRATEGY_CHANGES,
10417
+ const resolvedStrategy = useSyncExternalStore2(
10418
+ configuredStrategy === "adaptive" ? subscribeToAdaptiveStrategyChange : subscribeToNothing,
9695
10419
  () => resolveAdaptiveStrategy(configuredStrategy),
9696
10420
  () => configuredStrategy === "adaptive" ? "hover" : configuredStrategy
9697
10421
  );
@@ -9878,7 +10602,7 @@ var Breadcrumbs = createHandle(
9878
10602
  );
9879
10603
 
9880
10604
  // src/browser/react/location-state.ts
9881
- 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";
9882
10606
 
9883
10607
  // src/href-client.ts
9884
10608
  function href(path6, mount) {
@@ -10025,7 +10749,7 @@ import {
10025
10749
  useDeferredValue,
10026
10750
  useEffect as useEffect16,
10027
10751
  useMemo as useMemo9,
10028
- useState as useState15
10752
+ useState as useState14
10029
10753
  } from "react";
10030
10754
 
10031
10755
  // src/client-urls/navigation.ts
@@ -10211,7 +10935,7 @@ var debug10 = createRangoDebugger(NS.discovery);
10211
10935
  function hasDefaultExport(code) {
10212
10936
  let program;
10213
10937
  try {
10214
- program = parseAst6(code, { lang: "tsx" });
10938
+ program = parseAst7(code, { lang: "tsx" });
10215
10939
  } catch {
10216
10940
  return false;
10217
10941
  }
@@ -10239,7 +10963,7 @@ function recordClientUrlsModule(state, code, id) {
10239
10963
  }
10240
10964
  const source = normalizeSource(state, id);
10241
10965
  const projectRoot = normalizePath5(resolve8(state.projectRoot));
10242
- const relativeId = normalizePath5(relative4(projectRoot, source));
10966
+ const relativeId = normalizePath5(relative5(projectRoot, source));
10243
10967
  const outsideProject = relativeId === ".." || relativeId.startsWith("../") || isAbsolute3(relativeId);
10244
10968
  const devReferenceKey = outsideProject ? `/@fs${source}` : `/${relativeId}`;
10245
10969
  const sourceByReferenceId = state.clientUrlSourceByReferenceId ??= /* @__PURE__ */ new Map();
@@ -10574,7 +11298,7 @@ async function discoverRouters(state, rscEnv, ssrEnv) {
10574
11298
  for (const [map2, fn] of perRouterSetters) {
10575
11299
  const setter = serverMod[fn];
10576
11300
  if (typeof setter !== "function") continue;
10577
- for (const [routerId, value] of map2) setter(routerId, value);
11301
+ for (const [routerId2, value] of map2) setter(routerId2, value);
10578
11302
  }
10579
11303
  await expandPrerenderRoutes(state, rscEnv, registry, allManifests);
10580
11304
  await renderStaticHandlers(state, rscEnv, registry);
@@ -10582,20 +11306,337 @@ async function discoverRouters(state, rscEnv, ssrEnv) {
10582
11306
  }
10583
11307
 
10584
11308
  // src/vite/discovery/shell-prerender-phase.ts
10585
- import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "node:fs";
10586
- 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";
10587
11311
 
10588
11312
  // src/prerender/shell-manifest-key.ts
10589
11313
  function buildShellManifestKey(pathname) {
10590
11314
  return pathname;
10591
11315
  }
10592
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
+
10593
11634
  // src/vite/discovery/shell-prerender-phase.ts
10594
11635
  init_debug();
10595
- var debug12 = createRangoDebugger(NS.prerender);
10596
- async function runShellPrerenderPhase(s, builder) {
11636
+ var debug13 = createRangoDebugger(NS.prerender);
11637
+ async function runShellPrerenderPhase(s, builder, versionsTable) {
10597
11638
  const tempServer = s.shellPhaseTempServer;
10598
- if (!s.isBuildMode || !s.shellCandidates?.length || !tempServer) return;
11639
+ if (!versionsTable || !s.shellCandidates?.length || !tempServer) return;
10599
11640
  const candidates = s.shellCandidates;
10600
11641
  const startTotal = performance.now();
10601
11642
  console.log(`[rango] Shell-prerendering ${candidates.length} URL(s)...`);
@@ -10611,16 +11652,6 @@ async function runShellPrerenderPhase(s, builder) {
10611
11652
  );
10612
11653
  return;
10613
11654
  }
10614
- const versionPlugin = (builder?.config?.plugins ?? []).find(
10615
- (p) => p?.name === "@rangojs/router:version"
10616
- );
10617
- const buildVersion = versionPlugin?.api?.getBuildVersion?.();
10618
- if (!buildVersion) {
10619
- console.warn(
10620
- "[rango] shell prerender: main build version unavailable; skipping \u2014 routes keep runtime shell capture."
10621
- );
10622
- return;
10623
- }
10624
11655
  const payloads = s.prerenderPayloadValues ?? /* @__PURE__ */ new Map();
10625
11656
  const fetchedKeys = /* @__PURE__ */ new Set();
10626
11657
  globalThis.__loadPrerenderManifestModule = async () => ({
@@ -10638,9 +11669,9 @@ async function runShellPrerenderPhase(s, builder) {
10638
11669
  const htmlStream = await ssrRunner.import(
10639
11670
  "@rangojs/router/internal/deps/html-stream-server"
10640
11671
  );
10641
- const clientOutDir = builder?.environments?.client?.config?.build?.outDir ?? resolve9(s.projectRoot, "dist/client");
10642
- const clientAssetsDir = join5(clientOutDir, "assets");
10643
- 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;
10644
11675
  if (!entryFile) {
10645
11676
  console.warn(
10646
11677
  `[rango] shell prerender: built client entry not found under ${clientAssetsDir}; skipping \u2014 routes keep runtime shell capture.`
@@ -10650,7 +11681,7 @@ async function runShellPrerenderPhase(s, builder) {
10650
11681
  const base = builder?.config?.base ?? "/";
10651
11682
  const normalizedBase = base.endsWith("/") ? base : `${base}/`;
10652
11683
  const bootstrapContent = `import("${normalizedBase}assets/${entryFile}")`;
10653
- debug12?.("shell prerender bootstrap: %s", bootstrapContent);
11684
+ debug13?.("shell prerender bootstrap: %s", bootstrapContent);
10654
11685
  const minimalPlugin = (tempServer.config?.plugins ?? []).find(
10655
11686
  (p) => p?.name === "rsc:minimal"
10656
11687
  );
@@ -10721,8 +11752,13 @@ async function runShellPrerenderPhase(s, builder) {
10721
11752
  const mainKey = `${cand.routeName}/${cand.paramHash}`;
10722
11753
  let handled = false;
10723
11754
  const mismatches = [];
10724
- for (const [, routerInstance] of registry) {
11755
+ for (const [routerId2, routerInstance] of registry) {
10725
11756
  if (typeof routerInstance.match !== "function") continue;
11757
+ const versions = resolveVersionsFrom(
11758
+ versionsTable,
11759
+ routerId2,
11760
+ routerInstance.version
11761
+ );
10726
11762
  try {
10727
11763
  const res = await captureMod.captureShellForBuild({
10728
11764
  router: routerInstance,
@@ -10735,9 +11771,9 @@ async function runShellPrerenderPhase(s, builder) {
10735
11771
  maxSnapshotBytes: policy.maxSnapshotBytes,
10736
11772
  captureTimeout: policy.captureTimeout,
10737
11773
  buildEnv: s.resolvedBuildEnv,
10738
- buildVersion,
11774
+ versions,
10739
11775
  captureShellHTML,
10740
- debug: !!debug12
11776
+ debug: !!debug13
10741
11777
  });
10742
11778
  if (res.outcome === "route-mismatch") {
10743
11779
  mismatches.push(res.matchedRouteName ?? "(no match)");
@@ -10790,8 +11826,11 @@ async function runShellPrerenderPhase(s, builder) {
10790
11826
  }
10791
11827
  }
10792
11828
  if (staged.length > 0) {
10793
- const rscOutDir = builder?.environments?.rsc?.config?.build?.outDir ?? resolve9(s.projectRoot, "dist/rsc");
10794
- writeShellManifest(s, rscOutDir, staged);
11829
+ writeShellManifest(
11830
+ s,
11831
+ environmentOutDir(builder, s.projectRoot, "rsc"),
11832
+ staged
11833
+ );
10795
11834
  }
10796
11835
  const totalElapsed = (performance.now() - startTotal).toFixed(0);
10797
11836
  const parts = [`${staged.length} done`];
@@ -10810,14 +11849,14 @@ async function runShellPrerenderPhase(s, builder) {
10810
11849
  }
10811
11850
  }
10812
11851
  function writeShellManifest(s, rscOutDir, staged) {
10813
- const rscEntryPath = resolve9(rscOutDir, s.rscEntryFileName ?? "index.js");
10814
- if (!existsSync8(rscEntryPath)) {
11852
+ const rscEntryPath = resolve10(rscOutDir, s.rscEntryFileName ?? "index.js");
11853
+ if (!existsSync9(rscEntryPath)) {
10815
11854
  console.warn(
10816
11855
  `[rango] shell prerender: RSC entry not found at ${rscEntryPath}; entries not persisted \u2014 routes keep runtime capture.`
10817
11856
  );
10818
11857
  return;
10819
11858
  }
10820
- const assetsDir = resolve9(rscOutDir, "assets");
11859
+ const assetsDir = resolve10(rscOutDir, "assets");
10821
11860
  let totalBytes = 0;
10822
11861
  const manifestMap = {};
10823
11862
  const countedFiles = /* @__PURE__ */ new Set();
@@ -10835,13 +11874,13 @@ function writeShellManifest(s, rscOutDir, staged) {
10835
11874
  `export default m;`,
10836
11875
  ""
10837
11876
  ].join("\n");
10838
- writeFileSync3(resolve9(rscOutDir, "__shell-manifest.js"), manifestCode);
11877
+ writeFileSync4(resolve10(rscOutDir, "__shell-manifest.js"), manifestCode);
10839
11878
  totalBytes += Buffer.byteLength(manifestCode);
10840
- const rscCode = readFileSync6(rscEntryPath, "utf-8");
11879
+ const rscCode = readFileSync8(rscEntryPath, "utf-8");
10841
11880
  if (!rscCode.includes("__shell-manifest.js")) {
10842
11881
  const injection = `globalThis.__loadShellManifestModule = () => import("./__shell-manifest.js");
10843
11882
  `;
10844
- writeFileSync3(rscEntryPath, injection + rscCode);
11883
+ writeFileSync4(rscEntryPath, injection + rscCode);
10845
11884
  }
10846
11885
  const totalKB = (totalBytes / 1024).toFixed(1);
10847
11886
  console.log(
@@ -10887,8 +11926,8 @@ function createDevPrerenderCache(maxEntriesPerRouter = MAX_ENTRIES_PER_ROUTER) {
10887
11926
  }
10888
11927
 
10889
11928
  // src/vite/discovery/route-types-writer.ts
10890
- import { dirname as dirname3, join as join6, resolve as resolve10 } from "node:path";
10891
- 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";
10892
11931
  function filterUserNamedRoutes(manifest) {
10893
11932
  const filtered = {};
10894
11933
  for (const [name, pattern] of Object.entries(manifest)) {
@@ -10899,10 +11938,10 @@ function filterUserNamedRoutes(manifest) {
10899
11938
  return filtered;
10900
11939
  }
10901
11940
  function writeGenFileIfChanged(state, outPath, source, opts) {
10902
- const existing = existsSync9(outPath) ? readFileSync7(outPath, "utf-8") : null;
11941
+ const existing = existsSync10(outPath) ? readFileSync9(outPath, "utf-8") : null;
10903
11942
  if (existing === source) return;
10904
11943
  markSelfGenWrite(state, outPath, source);
10905
- writeFileSync4(outPath, source);
11944
+ writeFileSync5(outPath, source);
10906
11945
  if (opts?.log) console.log(`[rango] Generated route types -> ${outPath}`);
10907
11946
  }
10908
11947
  function writeCombinedRouteTypesWithTracking(state, opts) {
@@ -10916,11 +11955,11 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
10916
11955
  function writeRouteTypesFiles(state) {
10917
11956
  if (state.perRouterManifests.length === 0) return;
10918
11957
  try {
10919
- const entryDir = dirname3(
10920
- resolve10(state.projectRoot, state.resolvedEntryPath)
11958
+ const entryDir = dirname5(
11959
+ resolve11(state.projectRoot, state.resolvedEntryPath)
10921
11960
  );
10922
- const oldCombinedPath = join6(entryDir, "named-routes.gen.ts");
10923
- if (existsSync9(oldCombinedPath)) {
11961
+ const oldCombinedPath = join8(entryDir, "named-routes.gen.ts");
11962
+ if (existsSync10(oldCombinedPath)) {
10924
11963
  unlinkSync2(oldCombinedPath);
10925
11964
  console.log(
10926
11965
  `[rango] Removed stale combined route types: ${oldCombinedPath}`
@@ -11001,8 +12040,8 @@ function supplementGenFilesWithRuntimeRoutes(state) {
11001
12040
  }
11002
12041
 
11003
12042
  // src/vite/discovery/virtual-module-codegen.ts
11004
- import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync5 } from "node:fs";
11005
- 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";
11006
12045
  var MANIFEST_EXTERNALIZE_THRESHOLD = 512 * 1024;
11007
12046
  var TRANSITION_WHEN_VALIDATION = `enableTransitionWhenValidation();`;
11008
12047
  function devDiscoveryBootstrap(state) {
@@ -11021,12 +12060,12 @@ function generateRoutesManifestModule(state) {
11021
12060
  let varIdx = 0;
11022
12061
  for (const entry of state.perRouterManifests) {
11023
12062
  if (entry.sourceFile) {
11024
- const routerDir = dirname4(entry.sourceFile);
12063
+ const routerDir = dirname6(entry.sourceFile);
11025
12064
  const routerBasename = basename(entry.sourceFile).replace(
11026
12065
  /\.(tsx?|jsx?)$/,
11027
12066
  ""
11028
12067
  );
11029
- const genPath = join7(
12068
+ const genPath = join9(
11030
12069
  routerDir,
11031
12070
  `${routerBasename}.named-routes.gen.js`
11032
12071
  ).replaceAll("\\", "/");
@@ -11060,7 +12099,10 @@ function generateRoutesManifestModule(state) {
11060
12099
  ];
11061
12100
  if (hasClientUrlModules) {
11062
12101
  lines2.push(`clearClientUrlProjections();`);
11063
- 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) {
11064
12106
  lines2.push(
11065
12107
  `setClientUrlProjection(${JSON.stringify(referenceId2)}, ${jsonParseExpression(projection)});`
11066
12108
  );
@@ -11092,9 +12134,9 @@ function generateRoutesManifestModule(state) {
11092
12134
  );
11093
12135
  }
11094
12136
  if (state.isBuildMode) {
11095
- for (const routerId of state.perRouterManifestDataMap.keys()) {
12137
+ for (const routerId2 of state.perRouterManifestDataMap.keys()) {
11096
12138
  lines2.push(
11097
- `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)}));`
11098
12140
  );
11099
12141
  }
11100
12142
  }
@@ -11131,17 +12173,17 @@ function shortHash(input) {
11131
12173
  }
11132
12174
  return (h >>> 0).toString(36);
11133
12175
  }
11134
- function generatePerRouterModule(state, routerId) {
12176
+ function generatePerRouterModule(state, routerId2) {
11135
12177
  const sourceFile = state.perRouterManifests.find(
11136
- (e) => e.id === routerId
12178
+ (e) => e.id === routerId2
11137
12179
  )?.sourceFile;
11138
- const trie = state.perRouterTrieMap.get(routerId);
11139
- const entries = state.perRouterPrecomputedMap.get(routerId);
12180
+ const trie = state.perRouterTrieMap.get(routerId2);
12181
+ const entries = state.perRouterPrecomputedMap.get(routerId2);
11140
12182
  const lines = [];
11141
12183
  if (sourceFile) {
11142
- const routerDir = dirname4(sourceFile);
12184
+ const routerDir = dirname6(sourceFile);
11143
12185
  const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
11144
- const genPath = join7(
12186
+ const genPath = join9(
11145
12187
  routerDir,
11146
12188
  `${routerBasename}.named-routes.gen.js`
11147
12189
  ).replaceAll("\\", "/");
@@ -11155,11 +12197,11 @@ function generatePerRouterModule(state, routerId) {
11155
12197
  const payloadJson = hasTrie || hasEntries ? JSON.stringify(payload) : "";
11156
12198
  const useTextModule = state.isBuildMode && preset === "cloudflare" && override !== "0" && (hasTrie || hasEntries) && (override === "1" || payloadJson.length >= MANIFEST_EXTERNALIZE_THRESHOLD);
11157
12199
  if (useTextModule) {
11158
- const dir = join7(state.projectRoot, "node_modules", ".rango");
11159
- mkdirSync2(dir, { recursive: true });
11160
- const safeId = `${routerId.replace(/[^a-zA-Z0-9_-]/g, "_")}-${shortHash(routerId)}`;
11161
- const filePath = join7(dir, `manifest-${safeId}.txt`).replaceAll("\\", "/");
11162
- 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);
11163
12205
  lines.push(`import __manifestJson from ${JSON.stringify(filePath)};`);
11164
12206
  lines.push(`const __manifestData = JSON.parse(__manifestJson);`);
11165
12207
  emitManifestExports(lines, hasTrie, hasEntries);
@@ -11188,13 +12230,13 @@ function emitManifestExports(lines, hasTrie, hasEntries) {
11188
12230
  }
11189
12231
 
11190
12232
  // src/vite/discovery/bundle-postprocess.ts
11191
- import { resolve as resolve11 } from "node:path";
11192
- 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";
11193
12235
  function postprocessBundle(state) {
11194
12236
  const hasPrerenderData = state.prerenderManifestEntries && Object.keys(state.prerenderManifestEntries).length > 0;
11195
12237
  const hasStaticData = state.staticManifestEntries && Object.keys(state.staticManifestEntries).length > 0;
11196
12238
  if (!hasPrerenderData && !hasStaticData) return;
11197
- const rscEntryPath = resolve11(
12239
+ const rscEntryPath = resolve12(
11198
12240
  state.projectRoot,
11199
12241
  "dist/rsc",
11200
12242
  state.rscEntryFileName ?? "index.js"
@@ -11215,9 +12257,9 @@ function postprocessBundle(state) {
11215
12257
  ];
11216
12258
  for (const target of evictionTargets) {
11217
12259
  for (const info of target.infos) {
11218
- const chunkPath = resolve11(state.projectRoot, "dist/rsc", info.fileName);
12260
+ const chunkPath = resolve12(state.projectRoot, "dist/rsc", info.fileName);
11219
12261
  try {
11220
- const code = readFileSync8(chunkPath, "utf-8");
12262
+ const code = readFileSync10(chunkPath, "utf-8");
11221
12263
  const result = evictHandlerCode(
11222
12264
  code,
11223
12265
  info.exports,
@@ -11225,7 +12267,7 @@ function postprocessBundle(state) {
11225
12267
  target.brand
11226
12268
  );
11227
12269
  if (result) {
11228
- writeFileSync6(chunkPath, result.code);
12270
+ writeFileSync7(chunkPath, result.code);
11229
12271
  const savedKB = (result.savedBytes / 1024).toFixed(1);
11230
12272
  console.log(
11231
12273
  `[rango] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
@@ -11240,8 +12282,8 @@ function postprocessBundle(state) {
11240
12282
  }
11241
12283
  state.handlerChunkInfoMap.clear();
11242
12284
  state.staticHandlerChunkInfoMap.clear();
11243
- if (hasPrerenderData && existsSync10(rscEntryPath)) {
11244
- const rscCode = readFileSync8(rscEntryPath, "utf-8");
12285
+ if (hasPrerenderData && existsSync11(rscEntryPath)) {
12286
+ const rscCode = readFileSync10(rscEntryPath, "utf-8");
11245
12287
  if (!rscCode.includes("__prerender-manifest.js")) {
11246
12288
  try {
11247
12289
  let totalBytes = copyStagedBuildAssets(
@@ -11260,15 +12302,15 @@ function postprocessBundle(state) {
11260
12302
  `export default m;`,
11261
12303
  ""
11262
12304
  ].join("\n");
11263
- const manifestPath = resolve11(
12305
+ const manifestPath = resolve12(
11264
12306
  state.projectRoot,
11265
12307
  "dist/rsc/__prerender-manifest.js"
11266
12308
  );
11267
- writeFileSync6(manifestPath, manifestCode);
12309
+ writeFileSync7(manifestPath, manifestCode);
11268
12310
  totalBytes += Buffer.byteLength(manifestCode);
11269
12311
  const injection = `globalThis.__loadPrerenderManifestModule = () => import("./__prerender-manifest.js");
11270
12312
  `;
11271
- writeFileSync6(rscEntryPath, injection + rscCode);
12313
+ writeFileSync7(rscEntryPath, injection + rscCode);
11272
12314
  const totalKB = (totalBytes / 1024).toFixed(1);
11273
12315
  console.log(
11274
12316
  `[rango] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
@@ -11280,8 +12322,8 @@ function postprocessBundle(state) {
11280
12322
  }
11281
12323
  }
11282
12324
  }
11283
- if (hasStaticData && existsSync10(rscEntryPath)) {
11284
- const rscCode = readFileSync8(rscEntryPath, "utf-8");
12325
+ if (hasStaticData && existsSync11(rscEntryPath)) {
12326
+ const rscCode = readFileSync10(rscEntryPath, "utf-8");
11285
12327
  if (!rscCode.includes("__static-manifest.js")) {
11286
12328
  try {
11287
12329
  const manifestEntries = [];
@@ -11298,15 +12340,15 @@ function postprocessBundle(state) {
11298
12340
  }
11299
12341
  const manifestCode = `const m={${manifestEntries.join(",")}};globalThis.__STATIC_MANIFEST=m;export default m;
11300
12342
  `;
11301
- const manifestPath = resolve11(
12343
+ const manifestPath = resolve12(
11302
12344
  state.projectRoot,
11303
12345
  "dist/rsc/__static-manifest.js"
11304
12346
  );
11305
- writeFileSync6(manifestPath, manifestCode);
12347
+ writeFileSync7(manifestPath, manifestCode);
11306
12348
  totalBytes += Buffer.byteLength(manifestCode);
11307
12349
  const injection = `globalThis.__loadStaticManifestModule = () => import("./__static-manifest.js");
11308
12350
  `;
11309
- writeFileSync6(rscEntryPath, injection + rscCode);
12351
+ writeFileSync7(rscEntryPath, injection + rscCode);
11310
12352
  const totalKB = (totalBytes / 1024).toFixed(1);
11311
12353
  console.log(
11312
12354
  `[rango] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
@@ -11321,7 +12363,7 @@ function postprocessBundle(state) {
11321
12363
  }
11322
12364
 
11323
12365
  // src/vite/discovery/gate-state.ts
11324
- function createDiscoveryGate(s, debug13) {
12366
+ function createDiscoveryGate(s, debug14) {
11325
12367
  let gatePending = false;
11326
12368
  let gateResolver = () => {
11327
12369
  };
@@ -11330,15 +12372,15 @@ function createDiscoveryGate(s, debug13) {
11330
12372
  let pendingEvents = false;
11331
12373
  const beginGate = () => {
11332
12374
  if (gatePending) return;
11333
- s.discoveryDone = new Promise((resolve14) => {
11334
- gateResolver = resolve14;
12375
+ s.discoveryDone = new Promise((resolve15) => {
12376
+ gateResolver = resolve15;
11335
12377
  });
11336
12378
  gatePending = true;
11337
12379
  };
11338
12380
  const resolveGate = () => {
11339
12381
  if (!gatePending) return;
11340
12382
  if (inProgress || queued2 || pendingEvents) {
11341
- debug13?.(
12383
+ debug14?.(
11342
12384
  "hmr: resolveGate deferred \u2014 work in flight (inProgress=%s queued=%s pendingEvents=%s)",
11343
12385
  inProgress,
11344
12386
  queued2,
@@ -11347,7 +12389,7 @@ function createDiscoveryGate(s, debug13) {
11347
12389
  return;
11348
12390
  }
11349
12391
  gatePending = false;
11350
- debug13?.("hmr: discoveryDone resolved");
12392
+ debug14?.("hmr: discoveryDone resolved");
11351
12393
  gateResolver();
11352
12394
  };
11353
12395
  const noteRouteEvent = () => {
@@ -11357,7 +12399,7 @@ function createDiscoveryGate(s, debug13) {
11357
12399
  const runRefreshCycle = async (work) => {
11358
12400
  if (inProgress) {
11359
12401
  queued2 = true;
11360
- 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");
11361
12403
  return;
11362
12404
  }
11363
12405
  pendingEvents = false;
@@ -11368,16 +12410,16 @@ function createDiscoveryGate(s, debug13) {
11368
12410
  inProgress = false;
11369
12411
  if (queued2) {
11370
12412
  queued2 = false;
11371
- debug13?.("hmr: consuming queued rediscovery");
12413
+ debug14?.("hmr: consuming queued rediscovery");
11372
12414
  runRefreshCycle(work).catch((err) => {
11373
- debug13?.(
12415
+ debug14?.(
11374
12416
  "hmr: queued cycle rejected \u2014 releasing gate (%s)",
11375
12417
  err instanceof Error ? err.message : String(err)
11376
12418
  );
11377
12419
  resolveGate();
11378
12420
  });
11379
12421
  } else if (pendingEvents) {
11380
- debug13?.(
12422
+ debug14?.(
11381
12423
  "hmr: holding gate for pending events (debounce not yet fired)"
11382
12424
  );
11383
12425
  } else {
@@ -11423,15 +12465,15 @@ function selectForwardableResolvePlugins(plugins) {
11423
12465
  }
11424
12466
  function pickForwardedRunnerConfig(config) {
11425
12467
  const r = config.resolve ?? {};
11426
- const resolve14 = {};
11427
- if (r.alias !== void 0) resolve14.alias = r.alias;
11428
- if (r.dedupe !== void 0) resolve14.dedupe = r.dedupe;
11429
- if (r.conditions !== void 0) resolve14.conditions = r.conditions;
11430
- if (r.mainFields !== void 0) resolve14.mainFields = r.mainFields;
11431
- 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;
11432
12474
  if (r.preserveSymlinks !== void 0)
11433
- resolve14.preserveSymlinks = r.preserveSymlinks;
11434
- if (r.tsconfigPaths !== void 0) resolve14.tsconfigPaths = r.tsconfigPaths;
12475
+ resolve15.preserveSymlinks = r.preserveSymlinks;
12476
+ if (r.tsconfigPaths !== void 0) resolve15.tsconfigPaths = r.tsconfigPaths;
11435
12477
  const userOxc = config.oxc;
11436
12478
  const userJsx = userOxc && typeof userOxc === "object" && typeof userOxc.jsx === "object" && userOxc.jsx !== null ? userOxc.jsx : {};
11437
12479
  const oxc = userOxc && typeof userOxc === "object" ? {
@@ -11439,7 +12481,7 @@ function pickForwardedRunnerConfig(config) {
11439
12481
  jsx: { ...userJsx, runtime: "automatic", importSource: "react" }
11440
12482
  } : { jsx: { runtime: "automatic", importSource: "react" } };
11441
12483
  return {
11442
- resolve: resolve14,
12484
+ resolve: resolve15,
11443
12485
  define: config.define,
11444
12486
  oxc
11445
12487
  };
@@ -11561,6 +12603,26 @@ async function createTempRscServer(state, options = {}) {
11561
12603
  ]
11562
12604
  });
11563
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
+ }
11564
12626
  async function resolveBuildEnv(option, factoryCtx) {
11565
12627
  if (!option) return null;
11566
12628
  if (option === "auto") {
@@ -11571,11 +12633,13 @@ async function resolveBuildEnv(option, factoryCtx) {
11571
12633
  }
11572
12634
  try {
11573
12635
  const userRequire = createRequire3(
11574
- resolve12(factoryCtx.root, "package.json")
12636
+ resolve13(factoryCtx.root, "package.json")
11575
12637
  );
11576
12638
  const wranglerPath = userRequire.resolve("wrangler");
11577
12639
  const { getPlatformProxy } = await import(pathToFileURL2(wranglerPath).href);
11578
- const proxy = await getPlatformProxy();
12640
+ const proxy = await getPlatformProxy(
12641
+ wranglerProxyOptions(factoryCtx.root)
12642
+ );
11579
12643
  return {
11580
12644
  env: proxy.env,
11581
12645
  dispose: proxy.dispose
@@ -11613,6 +12677,7 @@ function resetPrerenderCollection(s) {
11613
12677
  s.staticManifestEntries = null;
11614
12678
  s.shellCandidates = null;
11615
12679
  s.prerenderPayloadValues = null;
12680
+ s.buildData = [];
11616
12681
  }
11617
12682
  async function releaseBuildEnv(s) {
11618
12683
  if (s.buildEnvDispose) {
@@ -11757,8 +12822,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
11757
12822
  }
11758
12823
  server.middlewares.use(internalDebugNoCacheMiddleware());
11759
12824
  let resolveDiscovery;
11760
- const discoveryPromise = new Promise((resolve14) => {
11761
- resolveDiscovery = resolve14;
12825
+ const discoveryPromise = new Promise((resolve15) => {
12826
+ resolveDiscovery = resolve15;
11762
12827
  });
11763
12828
  const gate = createDiscoveryGate(s, debugDiscovery);
11764
12829
  const beginDiscoveryGate = gate.beginGate;
@@ -12057,7 +13122,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12057
13122
  for (const [map2, fn] of perRouterSetters) {
12058
13123
  const setter = serverMod[fn];
12059
13124
  if (typeof setter !== "function") continue;
12060
- for (const [routerId, value] of map2) setter(routerId, value);
13125
+ for (const [routerId2, value] of map2) setter(routerId2, value);
12061
13126
  }
12062
13127
  };
12063
13128
  server.middlewares.use("/__rsc_prerender", async (req, res) => {
@@ -12340,7 +13405,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12340
13405
  maxSnapshotBytes,
12341
13406
  captureTimeout,
12342
13407
  buildEnv: s.resolvedBuildEnv,
12343
- buildVersion: version,
13408
+ versions: uniformVersions(version),
12344
13409
  captureShellHTML: ssrModule.captureShellHTML,
12345
13410
  debug: !!debugDiscovery
12346
13411
  });
@@ -12525,7 +13590,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12525
13590
  if (devServerClosed || expectedEpoch !== s.devDiscoveryEpoch) {
12526
13591
  return;
12527
13592
  }
12528
- await new Promise((resolve14) => setTimeout(resolve14, 25));
13593
+ await new Promise((resolve15) => setTimeout(resolve15, 25));
12529
13594
  if (devServerClosed || expectedEpoch !== s.devDiscoveryEpoch) {
12530
13595
  return;
12531
13596
  }
@@ -12643,7 +13708,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12643
13708
  }
12644
13709
  const inRecoveryMode = !!s.lastDiscoveryError;
12645
13710
  try {
12646
- const source = readFileSync9(filePath, "utf-8");
13711
+ const source = readFileSync11(filePath, "utf-8");
12647
13712
  const trimmed = source.trimStart();
12648
13713
  const isUseClient = trimmed.startsWith('"use client"') || trimmed.startsWith("'use client'");
12649
13714
  let hasClientUrls = source.includes("clientUrls(");
@@ -12685,11 +13750,11 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12685
13750
  if (rscGraph?.getModulesByFile) {
12686
13751
  const routerSourceFiles = /* @__PURE__ */ new Set();
12687
13752
  if (s.resolvedEntryPath) {
12688
- routerSourceFiles.add(resolve12(s.resolvedEntryPath));
13753
+ routerSourceFiles.add(resolve13(s.resolvedEntryPath));
12689
13754
  }
12690
13755
  for (const entry of s.perRouterManifests) {
12691
13756
  if (entry.sourceFile) {
12692
- routerSourceFiles.add(resolve12(entry.sourceFile));
13757
+ routerSourceFiles.add(resolve13(entry.sourceFile));
12693
13758
  }
12694
13759
  }
12695
13760
  const seen = /* @__PURE__ */ new Set();
@@ -12718,7 +13783,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
12718
13783
  if (hasCreateRouter) {
12719
13784
  const nestedRouterConflict = findNestedRouterConflict([
12720
13785
  ...s.cachedRouterFiles ?? [],
12721
- resolve12(filePath)
13786
+ resolve13(filePath)
12722
13787
  ]);
12723
13788
  if (nestedRouterConflict) {
12724
13789
  server.config.logger.error(
@@ -12841,18 +13906,27 @@ ${details}`,
12841
13906
  );
12842
13907
  }
12843
13908
  },
12844
- // Post-build PPR shell capture (producer B, #699): runs after EVERY
12845
- // environment bundle is written — the shell prelude embeds built client
12846
- // asset URLs (bootstrap entry), which do not exist at buildStart. The
12847
- // kept temp server and the buildEnv were deferred AS A PAIR in
12848
- // buildStart's finally; this finally is the pair's success-path owner
12849
- // (buildEnd below owns the aborted-build path) — the phase itself is a
12850
- // 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.
12851
13921
  buildApp: {
12852
13922
  order: "post",
12853
13923
  async handler(builder) {
12854
13924
  try {
12855
- await runShellPrerenderPhase(s, builder);
13925
+ await runShellPrerenderPhase(
13926
+ s,
13927
+ builder,
13928
+ runRouterVersionsPhase(s, builder)
13929
+ );
12856
13930
  } finally {
12857
13931
  if (s.isBuildMode) {
12858
13932
  const tempServer = s.shellPhaseTempServer;
@@ -12941,11 +14015,11 @@ ${details}`,
12941
14015
  () => s.discoveryDone
12942
14016
  );
12943
14017
  }
12944
- const routerId = id.slice(perRouterPrefix.length);
14018
+ const routerId2 = id.slice(perRouterPrefix.length);
12945
14019
  const code = await timed(
12946
14020
  debugRoutes,
12947
- `generatePerRouterModule ${routerId}`,
12948
- () => generatePerRouterModule(s, routerId)
14021
+ `generatePerRouterModule ${routerId2}`,
14022
+ () => generatePerRouterModule(s, routerId2)
12949
14023
  );
12950
14024
  return code;
12951
14025
  }
@@ -12954,6 +14028,19 @@ ${details}`,
12954
14028
  // Record handler chunk metadata and RSC entry filename during RSC build.
12955
14029
  // Used by closeBundle for handler code eviction and prerender data injection.
12956
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
+ }
12957
14044
  if (this.environment?.name !== "rsc") return;
12958
14045
  const genStart = debugBuild ? performance.now() : 0;
12959
14046
  for (const [fileName, chunk] of Object.entries(bundle)) {
@@ -13043,10 +14130,12 @@ ${details}`,
13043
14130
  init_debug();
13044
14131
  var debugConfig = createRangoDebugger(NS.config);
13045
14132
  var SERVER_BUILD_TARGET = "esnext";
14133
+ var RSC_ENTRY_SIGNATURES = "strict";
13046
14134
  async function rango(options) {
13047
14135
  const rangoStart = performance.now();
13048
14136
  const resolvedOptions = options ?? { preset: "node" };
13049
14137
  const preset = resolvedOptions.preset ?? "node";
14138
+ configureEncryptionKey(resolvedOptions.encryptionKey);
13050
14139
  const showBanner = resolvedOptions.banner ?? true;
13051
14140
  const clientChunksOption = resolvedOptions.clientChunks ?? true;
13052
14141
  const useBuiltInClientChunks = clientChunksOption === true;
@@ -13190,14 +14279,14 @@ async function rango(options) {
13190
14279
  name: "@rangojs/router:auto-discover",
13191
14280
  config(userConfig) {
13192
14281
  if (routerRef.path) return;
13193
- const root = userConfig.root ? resolve13(process.cwd(), userConfig.root) : process.cwd();
14282
+ const root = userConfig.root ? resolve14(process.cwd(), userConfig.root) : process.cwd();
13194
14283
  const toRootRelative = (abs) => (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
13195
14284
  const bulletList = (files) => files.map((f) => " - " + toRootRelative(f)).join("\n");
13196
14285
  if (explicitHostRouter) {
13197
14286
  routerRef.path = normalizeHostRouterEntry(
13198
14287
  explicitHostRouter,
13199
14288
  root,
13200
- existsSync11
14289
+ existsSync13
13201
14290
  );
13202
14291
  routerRef.kind = "host";
13203
14292
  return;
@@ -13317,7 +14406,10 @@ If this is a multi-app host router, export a createHostRouter() instance and set
13317
14406
  rsc: {
13318
14407
  ...vercelServerEnv ?? {},
13319
14408
  build: {
13320
- target: SERVER_BUILD_TARGET
14409
+ target: SERVER_BUILD_TARGET,
14410
+ rollupOptions: {
14411
+ preserveEntrySignatures: RSC_ENTRY_SIGNATURES
14412
+ }
13321
14413
  },
13322
14414
  optimizeDeps: {
13323
14415
  entries: [VIRTUAL_IDS.rsc],
@@ -13380,6 +14472,7 @@ If this is a multi-app host router, export a createHostRouter() instance and set
13380
14472
  plugins.push(clientRefDedup());
13381
14473
  }
13382
14474
  plugins.push(clientChunksReport());
14475
+ plugins.push(stableRscOutput());
13383
14476
  plugins.push({
13384
14477
  name: "@rangojs/router:client-component-hmr",
13385
14478
  hotUpdate(ctx) {
@@ -13389,7 +14482,7 @@ If this is a multi-app host router, export a createHostRouter() instance and set
13389
14482
  if (!file.endsWith(".tsx") && !file.endsWith(".ts") && !file.endsWith(".jsx") && !file.endsWith(".js"))
13390
14483
  return;
13391
14484
  try {
13392
- const source = readFileSync10(file, "utf-8");
14485
+ const source = readFileSync12(file, "utf-8");
13393
14486
  if (hasUseClientDirective2(source)) {
13394
14487
  return [];
13395
14488
  }
@@ -13412,7 +14505,7 @@ If this is a multi-app host router, export a createHostRouter() instance and set
13412
14505
  const discoveryEntryPath = preset !== "cloudflare" ? routerRef.path : void 0;
13413
14506
  const discoveryRouterRef = preset !== "cloudflare" ? routerRef : void 0;
13414
14507
  if (preset === "cloudflare") {
13415
- plugins.push(createVersionInjectorPlugin(void 0));
14508
+ plugins.push(createEntryBootstrapInjectorPlugin(void 0));
13416
14509
  }
13417
14510
  plugins.push(createCjsToEsmPlugin());
13418
14511
  plugins.push(
@@ -13449,7 +14542,7 @@ function poke() {
13449
14542
  apply: "serve",
13450
14543
  configureServer(server) {
13451
14544
  const stdin = process.stdin;
13452
- const debug13 = process.env.RANGO_POKE_DEBUG === "1";
14545
+ const debug14 = process.env.RANGO_POKE_DEBUG === "1";
13453
14546
  const triggerReload = (source) => {
13454
14547
  server.hot.send({ type: "full-reload", path: "*" });
13455
14548
  server.config.logger.info(` browser reload (${source})`, {
@@ -13482,7 +14575,7 @@ function poke() {
13482
14575
  lines.pop();
13483
14576
  return lines;
13484
14577
  };
13485
- if (debug13) {
14578
+ if (debug14) {
13486
14579
  server.config.logger.info(
13487
14580
  ` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
13488
14581
  { timestamp: true }
@@ -13495,7 +14588,7 @@ function poke() {
13495
14588
  );
13496
14589
  }
13497
14590
  const onData = (data) => {
13498
- if (debug13) {
14591
+ if (debug14) {
13499
14592
  server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
13500
14593
  timestamp: true
13501
14594
  });