@rangojs/router 0.32.0 → 0.33.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 (180) hide show
  1. package/README.md +3 -2
  2. package/dist/bin/browser-7KIJ5HSV.js +15 -0
  3. package/dist/bin/chunk-3B7CKBRO.js +463 -0
  4. package/dist/bin/chunk-524VACCG.js +71 -0
  5. package/dist/bin/chunk-LD7UBHT4.js +196 -0
  6. package/dist/bin/chunk-TO6CRWLN.js +1429 -0
  7. package/dist/bin/chunk-TTXC2U3G.js +2477 -0
  8. package/dist/bin/client-urls-projection-DQLWPDAT.js +28 -0
  9. package/dist/bin/forward-user-plugins-URBZKJP4.js +62 -0
  10. package/dist/bin/rango.js +42 -10173
  11. package/dist/bin/runtime-EPUDEHO4.js +596 -0
  12. package/dist/bin/runtime-discovery-CZ2QHT4Q.js +352 -0
  13. package/dist/bin/state-ACD2MGKJ.js +16 -0
  14. package/dist/bin/temp-rsc-server-QRR6HD6T.js +3190 -0
  15. package/dist/types/bin/rango.d.ts +1 -0
  16. package/dist/types/browser/action-fence.d.ts +20 -0
  17. package/dist/types/browser/cookie-name.d.ts +51 -10
  18. package/dist/types/browser/invalidate-client-cache.d.ts +8 -6
  19. package/dist/types/browser/navigation-bridge.d.ts +36 -1
  20. package/dist/types/browser/navigation-client.d.ts +19 -0
  21. package/dist/types/browser/navigation-store-handle.d.ts +37 -4
  22. package/dist/types/browser/navigation-store.d.ts +2 -2
  23. package/dist/types/browser/navigation-transaction.d.ts +0 -1
  24. package/dist/types/browser/partial-update.d.ts +13 -0
  25. package/dist/types/browser/prefetch/cache.d.ts +96 -8
  26. package/dist/types/browser/prefetch/fetch.d.ts +26 -2
  27. package/dist/types/browser/prefetch/queue.d.ts +3 -2
  28. package/dist/types/browser/rango-state.d.ts +34 -5
  29. package/dist/types/browser/react/Link.d.ts +15 -6
  30. package/dist/types/browser/types.d.ts +25 -0
  31. package/dist/types/build/generate-route-types.d.ts +1 -1
  32. package/dist/types/build/route-types/include-resolution.d.ts +9 -1
  33. package/dist/types/build/route-types/router-processing.d.ts +3 -1
  34. package/dist/types/cache/cache-key-utils.d.ts +12 -8
  35. package/dist/types/cache/cache-scope.d.ts +4 -2
  36. package/dist/types/cache/cf/cf-cache-types.d.ts +9 -5
  37. package/dist/types/cache/document-cache-policy.d.ts +9 -1
  38. package/dist/types/cache/memory-segment-store.d.ts +3 -2
  39. package/dist/types/cache/segment-codec.d.ts +2 -2
  40. package/dist/types/cache/shell-snapshot.d.ts +1 -1
  41. package/dist/types/cache/types.d.ts +12 -7
  42. package/dist/types/cache/vercel/vercel-cache-store.d.ts +2 -1
  43. package/dist/types/client-urls/types.d.ts +7 -5
  44. package/dist/types/prefetch-markers.d.ts +9 -0
  45. package/dist/types/prefetch-source-scope.d.ts +66 -0
  46. package/dist/types/route-definition/helpers-types.d.ts +8 -5
  47. package/dist/types/router/intercept-resolution.d.ts +25 -11
  48. package/dist/types/router/match-context.d.ts +1 -0
  49. package/dist/types/router/match-handlers.d.ts +1 -1
  50. package/dist/types/router/prefetch-cache-ttl.d.ts +11 -3
  51. package/dist/types/router/router-context.d.ts +1 -1
  52. package/dist/types/router/router-options.d.ts +6 -3
  53. package/dist/types/router/segment-resolution/loader-cache.d.ts +8 -0
  54. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +23 -7
  55. package/dist/types/router/segment-resolution/revalidation.d.ts +19 -0
  56. package/dist/types/router/source-reads.d.ts +53 -0
  57. package/dist/types/router/types.d.ts +1 -1
  58. package/dist/types/rsc/helpers.d.ts +5 -2
  59. package/dist/types/rsc/prefetch-render-error.d.ts +7 -2
  60. package/dist/types/rsc/request-stages.d.ts +2 -0
  61. package/dist/types/rsc/shell-serve.d.ts +6 -1
  62. package/dist/types/server/context.d.ts +23 -6
  63. package/dist/types/server/cookie-store.d.ts +15 -1
  64. package/dist/types/server/document-location-state.d.ts +5 -2
  65. package/dist/types/server/handle-store.d.ts +2 -0
  66. package/dist/types/server/request-context.d.ts +43 -7
  67. package/dist/types/testing/e2e/server.d.ts +16 -1
  68. package/dist/types/testing/render-route.d.ts +66 -2
  69. package/dist/types/testing/serve-shell-request.d.ts +6 -3
  70. package/dist/types/types/handler-context.d.ts +7 -5
  71. package/dist/types/types/loader-types.d.ts +7 -4
  72. package/dist/types/types/segments.d.ts +15 -4
  73. package/dist/types/urls/path-helper-types.d.ts +7 -5
  74. package/dist/types/vite/temp-rsc-server.d.ts +2 -2
  75. package/dist/vite/index.js +449 -189
  76. package/package.json +2 -2
  77. package/skills/app-structure/SKILL.md +74 -0
  78. package/skills/app-structure/e-commerce.md +10 -9
  79. package/skills/app-structure/large-app.md +15 -2
  80. package/skills/caching/SKILL.md +10 -5
  81. package/skills/client-urls/SKILL.md +18 -11
  82. package/skills/comparison/references/framework-comparison.md +13 -8
  83. package/skills/document-cache/SKILL.md +8 -0
  84. package/skills/hooks/navigation.md +8 -8
  85. package/skills/hooks/state.md +24 -8
  86. package/skills/intercept/SKILL.md +33 -12
  87. package/skills/layout/SKILL.md +11 -0
  88. package/skills/links/SKILL.md +101 -4
  89. package/skills/loader/SKILL.md +49 -22
  90. package/skills/migrate-nextjs/SKILL.md +8 -2
  91. package/skills/migrate-react-router/data-and-actions.md +5 -0
  92. package/skills/ppr/SKILL.md +26 -5
  93. package/skills/prerender/SKILL.md +4 -1
  94. package/skills/route/SKILL.md +6 -6
  95. package/skills/router-setup/SKILL.md +2 -1
  96. package/skills/server-actions/SKILL.md +41 -8
  97. package/skills/testing/client-components.md +29 -13
  98. package/skills/testing/serve-shell-request.md +7 -7
  99. package/skills/testing/server-actions.md +8 -0
  100. package/skills/ux-architecture/SKILL.md +67 -18
  101. package/src/bin/rango.ts +39 -13
  102. package/src/browser/action-fence.ts +72 -0
  103. package/src/browser/cookie-name.ts +82 -14
  104. package/src/browser/invalidate-client-cache.ts +9 -7
  105. package/src/browser/navigation-bridge.ts +164 -32
  106. package/src/browser/navigation-client.ts +95 -20
  107. package/src/browser/navigation-store-handle.ts +67 -5
  108. package/src/browser/navigation-store.ts +86 -17
  109. package/src/browser/navigation-transaction.ts +0 -6
  110. package/src/browser/partial-update.ts +31 -12
  111. package/src/browser/prefetch/cache.ts +188 -11
  112. package/src/browser/prefetch/fetch.ts +211 -51
  113. package/src/browser/prefetch/queue.ts +3 -2
  114. package/src/browser/rango-state.ts +50 -8
  115. package/src/browser/react/Link.tsx +20 -9
  116. package/src/browser/react/use-navigation.ts +1 -1
  117. package/src/browser/rsc-router.tsx +8 -1
  118. package/src/browser/server-action-bridge.ts +3 -3
  119. package/src/browser/types.ts +25 -0
  120. package/src/build/generate-route-types.ts +1 -0
  121. package/src/build/route-types/include-resolution.ts +40 -3
  122. package/src/build/route-types/router-processing.ts +170 -25
  123. package/src/build/route-types/scan-filter.ts +1 -0
  124. package/src/cache/cache-key-utils.ts +12 -8
  125. package/src/cache/cache-runtime.ts +5 -1
  126. package/src/cache/cache-scope.ts +28 -7
  127. package/src/cache/cf/cf-cache-types.ts +9 -5
  128. package/src/cache/document-cache-policy.ts +27 -0
  129. package/src/cache/document-cache.ts +5 -0
  130. package/src/cache/memory-segment-store.ts +3 -2
  131. package/src/cache/segment-codec.ts +2 -2
  132. package/src/cache/shell-snapshot.ts +1 -1
  133. package/src/cache/types.ts +12 -7
  134. package/src/cache/vercel/vercel-cache-store.ts +2 -1
  135. package/src/client-urls/types.ts +7 -5
  136. package/src/prefetch-markers.ts +10 -0
  137. package/src/prefetch-source-scope.ts +137 -0
  138. package/src/route-definition/helpers-types.ts +8 -5
  139. package/src/router/intercept-resolution.ts +94 -50
  140. package/src/router/loader-resolution.ts +8 -6
  141. package/src/router/match-api.ts +33 -29
  142. package/src/router/match-context.ts +5 -0
  143. package/src/router/match-handlers.ts +2 -1
  144. package/src/router/match-middleware/cache-lookup.ts +21 -13
  145. package/src/router/match-result.ts +39 -87
  146. package/src/router/navigation-snapshot.ts +18 -3
  147. package/src/router/prefetch-cache-ttl.ts +15 -3
  148. package/src/router/revalidation.ts +53 -23
  149. package/src/router/router-context.ts +2 -1
  150. package/src/router/router-options.ts +6 -3
  151. package/src/router/segment-resolution/loader-cache.ts +21 -3
  152. package/src/router/segment-resolution/prefetch-deferral.ts +38 -31
  153. package/src/router/segment-resolution/revalidation.ts +40 -12
  154. package/src/router/source-reads.ts +122 -0
  155. package/src/router/types.ts +2 -1
  156. package/src/router.ts +11 -12
  157. package/src/rsc/helpers.ts +8 -3
  158. package/src/rsc/prefetch-render-error.ts +7 -2
  159. package/src/rsc/progressive-enhancement.ts +3 -2
  160. package/src/rsc/request-stages.ts +59 -0
  161. package/src/rsc/rsc-rendering.ts +49 -33
  162. package/src/rsc/server-action.ts +2 -1
  163. package/src/rsc/shell-capture.ts +4 -5
  164. package/src/rsc/shell-serve.ts +12 -1
  165. package/src/segment-system.tsx +1 -1
  166. package/src/server/context.ts +37 -6
  167. package/src/server/cookie-store.ts +22 -1
  168. package/src/server/document-location-state.ts +23 -2
  169. package/src/server/handle-store.ts +2 -0
  170. package/src/server/request-context.ts +113 -28
  171. package/src/testing/dispatch.ts +3 -0
  172. package/src/testing/e2e/fixture.ts +4 -12
  173. package/src/testing/e2e/server.ts +91 -4
  174. package/src/testing/render-route.tsx +269 -4
  175. package/src/testing/serve-shell-request.ts +6 -3
  176. package/src/types/handler-context.ts +7 -5
  177. package/src/types/loader-types.ts +7 -4
  178. package/src/types/segments.ts +15 -4
  179. package/src/urls/path-helper-types.ts +7 -5
  180. package/src/vite/temp-rsc-server.ts +2 -2
@@ -0,0 +1,2477 @@
1
+ import {
2
+ notifyListeners,
3
+ prefetchDirect,
4
+ prefetchQueued,
5
+ schedulePrefetchWhenRouterIdle
6
+ } from "./chunk-3B7CKBRO.js";
7
+ import {
8
+ findTsFiles,
9
+ firstCodeMatchIndex,
10
+ prefixBasename
11
+ } from "./chunk-LD7UBHT4.js";
12
+
13
+ // src/vite/discovery/client-urls-projection.ts
14
+ import { createHash as createHash2 } from "node:crypto";
15
+ import { existsSync, readFileSync } from "node:fs";
16
+ import { isAbsolute, relative as relative2, resolve } from "node:path";
17
+ import { normalizePath, parseAst as parseAst2 } from "vite";
18
+
19
+ // src/client-urls/server-projection.ts
20
+ import * as React4 from "react";
21
+
22
+ // src/server/context.ts
23
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
24
+
25
+ // src/rsc/shell-capture-constants.ts
26
+ var PPR_LANE_HINT = 'Lane rule: only loader(Def, { ssr: false }) executes at capture and bakes its non-promise data; every other loader is live (masked at capture, fresh per request) and needs loading() or an inline <Suspense> above its reader. See the /ppr skill, "The loader lane rule" (node_modules/@rangojs/router/skills/ppr/SKILL.md).';
27
+
28
+ // src/cache/cache-exec-scope.ts
29
+ import { AsyncLocalStorage } from "node:async_hooks";
30
+
31
+ // src/cache/taint.ts
32
+ var cacheExecScopeProbe = () => false;
33
+ function _setCacheExecScopeProbe(probe) {
34
+ cacheExecScopeProbe = probe;
35
+ }
36
+
37
+ // src/cache/cache-exec-scope.ts
38
+ var cacheExecStorage = new AsyncLocalStorage();
39
+ var IDENTITY_EXEMPT_KEY = /* @__PURE__ */ Symbol.for("rangojs-router:identity-exempt");
40
+ var identityExemptStorage = globalThis[IDENTITY_EXEMPT_KEY] ??= new AsyncLocalStorage();
41
+ function isInsideCacheExecScope() {
42
+ return cacheExecStorage.getStore() !== void 0;
43
+ }
44
+ _setCacheExecScopeProbe(isInsideCacheExecScope);
45
+
46
+ // src/server/context.ts
47
+ var RSC_CONTEXT_KEY = /* @__PURE__ */ Symbol.for("rangojs-router:rsc-context");
48
+ var RangoContext = globalThis[RSC_CONTEXT_KEY] ??= new AsyncLocalStorage2();
49
+ var LOADER_SCOPE_KEY = /* @__PURE__ */ Symbol.for("rangojs-router:loader-scope");
50
+ var loaderScopeALS = globalThis[LOADER_SCOPE_KEY] ??= new AsyncLocalStorage2();
51
+ var LOADER_BODY_SCOPE_KEY = /* @__PURE__ */ Symbol.for("rangojs-router:loader-body-scope");
52
+ var loaderBodyScopeALS = globalThis[LOADER_BODY_SCOPE_KEY] ??= new AsyncLocalStorage2();
53
+ function requestReadCaptureFix(what) {
54
+ return {
55
+ capture: `The captured shell is served to every user of this URL, so request-scoped data read here would leak one user's ${what} to others. Read it inside a loader without ssr: false and consume it with useLoader, e.g. createLoader(async () => getUser(cookies().get("session")?.value)). ${PPR_LANE_HINT}`,
56
+ warning: "Read it in a loader without ssr: false and consume it with useLoader under loading() or an inline <Suspense> (a live hole). A promise the handler passes or pushes does not help: the capture waits for it."
57
+ };
58
+ }
59
+ var NON_CACHEABLE_READ = {
60
+ verb: "called",
61
+ fix: {
62
+ useCache: "The variable was created with { cache: false } or set with { cache: false }, and the cache key does not include its value, so the first caller's value would be served to later callers. Read it before calling the cached function and pass the value in as an argument so it becomes part of the cache key.",
63
+ cacheScope: "The variable was created with { cache: false } or set with { cache: false }, and its value would be stale on cache hit. Move the read outside the cached scope.",
64
+ ...requestReadCaptureFix("per-request variables")
65
+ }
66
+ };
67
+ var loaderRunALS = globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:loader-run-identity")] ??= new AsyncLocalStorage2();
68
+ function getLoaderBodyTags() {
69
+ return loaderBodyScopeALS.getStore()?.tags;
70
+ }
71
+ function getCurrentLoaderBodyId() {
72
+ return loaderBodyScopeALS.getStore()?.loaderId;
73
+ }
74
+ var segmentPinALS = globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:segment-pin")] ??= new AsyncLocalStorage2();
75
+ var PUSH_CALLBACK_SCOPE_KEY = /* @__PURE__ */ Symbol.for(
76
+ "rangojs-router:push-callback-scope"
77
+ );
78
+ var pushCallbackScopeALS = globalThis[PUSH_CALLBACK_SCOPE_KEY] ??= new AsyncLocalStorage2();
79
+
80
+ // src/transition-when-ref.ts
81
+ var TransitionWhenError = class extends Error {
82
+ constructor() {
83
+ super(...arguments);
84
+ this.name = "TransitionWhenError";
85
+ }
86
+ };
87
+
88
+ // src/runtime-env.ts
89
+ function isUnderTestRunner() {
90
+ return !!globalThis.process?.env?.VITEST;
91
+ }
92
+
93
+ // src/client.tsx
94
+ import {
95
+ Component as Component3,
96
+ createElement as createElement4,
97
+ isValidElement as isValidElement2,
98
+ useContext as useContext18,
99
+ useMemo as useMemo9,
100
+ Suspense as Suspense2
101
+ } from "react";
102
+
103
+ // src/browser/react/use-handle.ts
104
+ import { useContext as useContext2, useState as useState2, useEffect as useEffect2, useRef as useRef2 } from "react";
105
+
106
+ // src/missing-id-error.ts
107
+ var SELF_FILES = /* @__PURE__ */ new Set([
108
+ "missing-id-error",
109
+ "loader",
110
+ "loader.rsc",
111
+ "handle"
112
+ ]);
113
+ function findUserCallSite() {
114
+ try {
115
+ const stack = new Error().stack;
116
+ if (!stack) return void 0;
117
+ for (const frame of stack.split("\n").slice(1)) {
118
+ const m = frame.match(
119
+ /(?:\(|@|\s)(?:file:\/\/)?((?:\/|[A-Za-z]:[\\/])[^()\s]+?\.(?:ts|tsx|js|jsx|mts|cts)):(\d+):(\d+)\)?/
120
+ );
121
+ if (!m) continue;
122
+ const path = m[1];
123
+ if (path.includes("node_modules") || path.includes("@rangojs/router")) {
124
+ continue;
125
+ }
126
+ const base = path.split(/[\\/]/).pop().replace(/\.(?:ts|tsx|js|jsx|mts|cts)$/, "");
127
+ if (SELF_FILES.has(base)) continue;
128
+ return `${path}:${m[2]}:${m[3]}`;
129
+ }
130
+ } catch {
131
+ }
132
+ return void 0;
133
+ }
134
+ function missingInjectedIdError(kind, fnName) {
135
+ const site = findUserCallSite();
136
+ const at = site ? ` (created at ${site})` : "";
137
+ return new Error(
138
+ `[rango] ${kind} is missing $$id${at}.
139
+ The @rangojs/router:expose-internal-ids Vite transform injects ${fnName}()'s stable $$id from an EXPORTED const declaration only:
140
+ export const X = ${fnName}(...)
141
+ const X = ${fnName}(...); export { X }
142
+ A non-exported const, an \`export let/var\`, or an inline ${fnName}(...) call gets no $$id \u2014 export it as \`export const\`. (A matching "Unsupported ${fnName} shape" warning names the exact file:line.)`
143
+ );
144
+ }
145
+
146
+ // src/handle.ts
147
+ function defaultCollect(segments) {
148
+ return segments;
149
+ }
150
+ var collectRegistry = /* @__PURE__ */ new Map();
151
+ var runtimeHandleIdCounter = 0;
152
+ function createHandle(collect, __injectedId) {
153
+ let handleId = __injectedId ?? "";
154
+ if (!handleId) {
155
+ if (isUnderTestRunner()) {
156
+ handleId = `__rango_runtime_handle_${runtimeHandleIdCounter++}`;
157
+ } else if (process.env.NODE_ENV !== "production") {
158
+ throw missingInjectedIdError("Handle", "createHandle");
159
+ } else {
160
+ throw new Error(
161
+ "[rango] Handle is missing $$id \u2014 the build plugin did not inject one. Export it as `export const X = createHandle(...)`."
162
+ );
163
+ }
164
+ }
165
+ const collectFn = collect ?? defaultCollect;
166
+ collectRegistry.set(
167
+ handleId,
168
+ collectFn
169
+ );
170
+ return {
171
+ __brand: "handle",
172
+ $$id: handleId
173
+ };
174
+ }
175
+
176
+ // src/browser/react/context.ts
177
+ import { createContext } from "react";
178
+ var NavigationStoreContext = createContext(null);
179
+ var LocationStateContext = createContext(void 0);
180
+ var HydrationBarrierContext = createContext(0);
181
+
182
+ // src/browser/react/use-route-state.ts
183
+ import {
184
+ useContext,
185
+ useEffect,
186
+ useLayoutEffect,
187
+ useRef,
188
+ useState
189
+ } from "react";
190
+ var NO_ROUTE = {
191
+ location: new URL("/", "http://localhost"),
192
+ params: Object.freeze({})
193
+ };
194
+
195
+ // src/handles/meta.ts
196
+ function isUnsetDescriptor(descriptor) {
197
+ return typeof descriptor === "object" && descriptor !== null && "unset" in descriptor && typeof descriptor.unset === "string";
198
+ }
199
+ function isTitleDescriptor(descriptor) {
200
+ return typeof descriptor === "object" && descriptor !== null && "title" in descriptor;
201
+ }
202
+ function isTitleTemplate(title) {
203
+ return typeof title === "object" && title !== null && "template" in title && "default" in title;
204
+ }
205
+ function isAbsoluteTitle(title) {
206
+ return typeof title === "object" && title !== null && "absolute" in title;
207
+ }
208
+ function getMetaKey(descriptor) {
209
+ if (isUnsetDescriptor(descriptor)) {
210
+ return void 0;
211
+ }
212
+ if ("charSet" in descriptor) {
213
+ return "charSet";
214
+ }
215
+ if ("title" in descriptor) {
216
+ return "title";
217
+ }
218
+ if ("name" in descriptor && "content" in descriptor) {
219
+ return `name:${descriptor.name}`;
220
+ }
221
+ if ("property" in descriptor && "content" in descriptor) {
222
+ return `property:${descriptor.property}`;
223
+ }
224
+ if ("httpEquiv" in descriptor && "content" in descriptor) {
225
+ return `httpEquiv:${descriptor.httpEquiv}`;
226
+ }
227
+ if ("script:ld+json" in descriptor) {
228
+ return void 0;
229
+ }
230
+ if ("tagName" in descriptor) {
231
+ if (descriptor.tagName === "link" && "rel" in descriptor) {
232
+ const uniqueRels = ["canonical", "icon", "apple-touch-icon"];
233
+ if (uniqueRels.includes(descriptor.rel)) {
234
+ return `link:${descriptor.rel}`;
235
+ }
236
+ }
237
+ return void 0;
238
+ }
239
+ return void 0;
240
+ }
241
+ var defaultMetaDescriptors = [
242
+ { charSet: "utf-8" },
243
+ { name: "viewport", content: "width=device-width, initial-scale=1" }
244
+ ];
245
+ function addOrReplace(result, keyToIndex, descriptor, key) {
246
+ if (key !== void 0 && keyToIndex.has(key)) {
247
+ result[keyToIndex.get(key)] = descriptor;
248
+ } else {
249
+ if (key !== void 0) {
250
+ keyToIndex.set(key, result.length);
251
+ }
252
+ result.push(descriptor);
253
+ }
254
+ }
255
+ function updateIndicesAfterRemoval(keyToIndex, removedIndex) {
256
+ for (const [key, index] of keyToIndex) {
257
+ if (index > removedIndex) {
258
+ keyToIndex.set(key, index - 1);
259
+ }
260
+ }
261
+ }
262
+ function collectMeta(segments) {
263
+ const result = [];
264
+ const keyToIndex = /* @__PURE__ */ new Map();
265
+ let titleTemplate;
266
+ for (const descriptor of defaultMetaDescriptors) {
267
+ const key = getMetaKey(descriptor);
268
+ if (key !== void 0) {
269
+ keyToIndex.set(key, result.length);
270
+ }
271
+ result.push(descriptor);
272
+ }
273
+ for (const descriptors of segments) {
274
+ for (const descriptor of descriptors) {
275
+ if (isUnsetDescriptor(descriptor)) {
276
+ const keyToRemove = descriptor.unset;
277
+ if (keyToIndex.has(keyToRemove)) {
278
+ const idx = keyToIndex.get(keyToRemove);
279
+ result.splice(idx, 1);
280
+ keyToIndex.delete(keyToRemove);
281
+ updateIndicesAfterRemoval(keyToIndex, idx);
282
+ }
283
+ continue;
284
+ }
285
+ if (isTitleDescriptor(descriptor)) {
286
+ const titleValue = descriptor.title;
287
+ if (isTitleTemplate(titleValue)) {
288
+ titleTemplate = titleValue.template;
289
+ addOrReplace(
290
+ result,
291
+ keyToIndex,
292
+ { title: titleValue.default },
293
+ "title"
294
+ );
295
+ continue;
296
+ }
297
+ if (isAbsoluteTitle(titleValue)) {
298
+ addOrReplace(
299
+ result,
300
+ keyToIndex,
301
+ { title: titleValue.absolute },
302
+ "title"
303
+ );
304
+ continue;
305
+ }
306
+ const finalTitle = titleTemplate ? titleTemplate.split("%s").join(titleValue) : titleValue;
307
+ addOrReplace(
308
+ result,
309
+ keyToIndex,
310
+ { title: finalTitle },
311
+ "title"
312
+ );
313
+ continue;
314
+ }
315
+ const key = getMetaKey(descriptor);
316
+ addOrReplace(result, keyToIndex, descriptor, key);
317
+ }
318
+ }
319
+ return result;
320
+ }
321
+ var Meta = createHandle(collectMeta, "__rsc_router_meta__");
322
+
323
+ // src/theme/theme-context.ts
324
+ import { createContext as createContext2, useContext as useContext3 } from "react";
325
+ var ThemeContext = createContext2(null);
326
+
327
+ // src/browser/react/nonce-context.ts
328
+ import { createContext as createContext3, useContext as useContext4 } from "react";
329
+ var NonceContext = createContext3(void 0);
330
+
331
+ // src/handles/MetaTags.tsx
332
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
333
+
334
+ // src/handles/Scripts.tsx
335
+ import { useState as useState3 } from "react";
336
+
337
+ // src/handles/script.ts
338
+ function validateConfigDev(config) {
339
+ if (process.env.NODE_ENV === "production") return;
340
+ const c = config;
341
+ if (c.src != null && c.children != null) {
342
+ console.warn(
343
+ `[Script] A config has both "src" and "children"; they are mutually exclusive \u2014 "src" wins and the inline body is ignored.`
344
+ );
345
+ } else if (c.src == null && c.children == null) {
346
+ console.warn(
347
+ `[Script] A config has neither "src" nor "children"; it injects nothing.`
348
+ );
349
+ } else if (c.src == null && c.id == null) {
350
+ console.warn(
351
+ `[Script] An inline script was pushed without an "id" and cannot be deduplicated. Pass an "id" so a layout + child pushing the same script inject it only once.`
352
+ );
353
+ }
354
+ if (c.async && c.defer) {
355
+ console.warn(
356
+ `[Script] A config has both "async" and "defer"; they are mutually exclusive.`
357
+ );
358
+ }
359
+ }
360
+ function collectScripts(segments) {
361
+ const result = [];
362
+ const keyToIndex = /* @__PURE__ */ new Map();
363
+ for (const configs of segments) {
364
+ for (const config of configs) {
365
+ validateConfigDev(config);
366
+ const isAsyncResource = config.src != null && config.async === true;
367
+ const key = isAsyncResource ? config.src : config.id ?? config.src;
368
+ if (key === void 0) {
369
+ result.push(config);
370
+ continue;
371
+ }
372
+ const existing = keyToIndex.get(key);
373
+ if (existing !== void 0) {
374
+ result[existing] = config;
375
+ } else {
376
+ keyToIndex.set(key, result.length);
377
+ result.push(config);
378
+ }
379
+ }
380
+ }
381
+ return result;
382
+ }
383
+ var Script = createHandle(collectScripts, "__rsc_router_script__");
384
+
385
+ // src/handles/Scripts.tsx
386
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
387
+
388
+ // src/browser/react/ScrollRestoration.tsx
389
+ import { useEffect as useEffect3 } from "react";
390
+
391
+ // src/outlet-context.ts
392
+ import { createContext as createContext4 } from "react";
393
+ var OutletContext = createContext4(null);
394
+
395
+ // src/route-content-wrapper.tsx
396
+ import { Component, Suspense, use as use2, useMemo as useMemo3 } from "react";
397
+
398
+ // src/outlet-provider.tsx
399
+ import {
400
+ useContext as useContext5,
401
+ useMemo
402
+ } from "react";
403
+
404
+ // src/suspense-audit-react.tsx
405
+ import { useEffect as useEffect4, useLayoutEffect as useLayoutEffect2, useRef as useRef3 } from "react";
406
+
407
+ // src/internal-suspense-audit.ts
408
+ var INTERNAL_RANGO_SUSPENSE_AUDIT = typeof process !== "undefined" && Boolean(process.env?.INTERNAL_RANGO_SUSPENSE_AUDIT);
409
+
410
+ // src/outlet-provider.tsx
411
+ import { jsx as jsx3 } from "react/jsx-runtime";
412
+
413
+ // src/decode-loader-results.ts
414
+ import { createElement as createElement2 } from "react";
415
+
416
+ // src/loader-redirect.tsx
417
+ import { useEffect as useEffect5 } from "react";
418
+
419
+ // src/browser/react/use-router.ts
420
+ import { useContext as useContext7, useMemo as useMemo2 } from "react";
421
+
422
+ // src/browser/react/use-mount.ts
423
+ import { useContext as useContext6 } from "react";
424
+
425
+ // src/browser/react/mount-context.ts
426
+ import {
427
+ createContext as createContext5,
428
+ createElement
429
+ } from "react";
430
+ var MountContext = createContext5("/");
431
+
432
+ // src/browser/app-version.ts
433
+ var currentVersion;
434
+ function getAppVersion() {
435
+ return currentVersion;
436
+ }
437
+
438
+ // src/href-client.ts
439
+ function href(path, mount) {
440
+ if (mount && mount !== "/") {
441
+ const normalizedMount = mount.endsWith("/") ? mount.slice(0, -1) : mount;
442
+ return normalizedMount + path;
443
+ }
444
+ return path;
445
+ }
446
+ function createResponseHrefTag() {
447
+ return (path, mount) => ({
448
+ to: href(path, mount),
449
+ "data-external": ""
450
+ });
451
+ }
452
+ ((href2) => {
453
+ href2.json = createResponseHrefTag();
454
+ href2.text = createResponseHrefTag();
455
+ href2.html = createResponseHrefTag();
456
+ href2.xml = createResponseHrefTag();
457
+ href2.md = createResponseHrefTag();
458
+ href2.image = createResponseHrefTag();
459
+ href2.stream = createResponseHrefTag();
460
+ href2.any = createResponseHrefTag();
461
+ })(href || (href = {}));
462
+
463
+ // src/browser/defer.ts
464
+ import { use } from "react";
465
+
466
+ // src/thenable-status.ts
467
+ var SETTLED_THENABLE = Object.assign(
468
+ Promise.resolve(void 0),
469
+ { status: "fulfilled", value: void 0, _debugInfo: [] }
470
+ );
471
+
472
+ // src/route-content-wrapper.tsx
473
+ import { jsx as jsx4 } from "react/jsx-runtime";
474
+ import { createElement as createElement3 } from "react";
475
+
476
+ // src/use-loader.tsx
477
+ import {
478
+ isValidElement,
479
+ startTransition,
480
+ use as use3,
481
+ useCallback,
482
+ useContext as useContext8,
483
+ useEffect as useEffect6,
484
+ useMemo as useMemo4,
485
+ useOptimistic,
486
+ useRef as useRef4,
487
+ useState as useState4
488
+ } from "react";
489
+
490
+ // src/loader-store.ts
491
+ var EMPTY_SNAPSHOT = Object.freeze({
492
+ value: void 0,
493
+ hasValue: false,
494
+ error: null,
495
+ isLoading: false,
496
+ requestId: 0
497
+ });
498
+
499
+ // src/client-urls/hoisted-revalidate.ts
500
+ var HOISTED_REVALIDATE_KEY = "$$rangoRevalidate";
501
+ function isHoistedRevalidateRef(value) {
502
+ return typeof value === "object" && value !== null && typeof value[HOISTED_REVALIDATE_KEY] === "string";
503
+ }
504
+
505
+ // src/browser/react/use-navigation.ts
506
+ import { useContext as useContext9, useEffect as useEffect7, useRef as useRef5 } from "react";
507
+
508
+ // src/browser/react/use-pathname.ts
509
+ import { useContext as useContext10 } from "react";
510
+
511
+ // src/client-urls/optimistic-location.ts
512
+ import { createContext as createContext6 } from "react";
513
+ var OptimisticLocationContext = createContext6(null);
514
+
515
+ // src/browser/react/use-search-params.ts
516
+ import { useCallback as useCallback2, useContext as useContext11, useMemo as useMemo5 } from "react";
517
+
518
+ // src/browser/react/use-params.ts
519
+ import { useContext as useContext12 } from "react";
520
+
521
+ // src/browser/react/use-action.ts
522
+ import { useContext as useContext13, useState as useState5, useEffect as useEffect8, useRef as useRef6 } from "react";
523
+
524
+ // src/browser/react/location-state-shared.ts
525
+ function isLocationStateDefinition(value) {
526
+ return typeof value === "function" && "__rsc_ls_flash" in value;
527
+ }
528
+
529
+ // src/browser/event-controller.ts
530
+ if (typeof Symbol.dispose === "undefined") {
531
+ Symbol.dispose = /* @__PURE__ */ Symbol("Symbol.dispose");
532
+ }
533
+ if (typeof Symbol.asyncDispose === "undefined") {
534
+ Symbol.asyncDispose = /* @__PURE__ */ Symbol("Symbol.asyncDispose");
535
+ }
536
+ var locationChangeSubscriptions = /* @__PURE__ */ new WeakMap();
537
+ function subscribeToLocationChange(eventController, listener) {
538
+ let subscription = locationChangeSubscriptions.get(eventController);
539
+ if (!subscription) {
540
+ subscription = {
541
+ registrations: /* @__PURE__ */ new Map(),
542
+ notificationVersion: 0,
543
+ unsubscribe: () => {
544
+ }
545
+ };
546
+ locationChangeSubscriptions.set(eventController, subscription);
547
+ const currentSubscription = subscription;
548
+ subscription.unsubscribe = eventController.subscribe(() => {
549
+ const notificationVersion = ++currentSubscription.notificationVersion;
550
+ const nextHref = eventController.getState().location.href;
551
+ notifyListeners(
552
+ [...currentSubscription.registrations],
553
+ ([, registration]) => {
554
+ if (registration.href === nextHref) return;
555
+ registration.href = nextHref;
556
+ registration.listener(nextHref);
557
+ },
558
+ ([token2, registration]) => currentSubscription.registrations.get(token2) === registration,
559
+ () => notificationVersion === currentSubscription.notificationVersion
560
+ );
561
+ });
562
+ }
563
+ const token = /* @__PURE__ */ Symbol();
564
+ subscription.registrations.set(token, {
565
+ href: eventController.getState().location.href,
566
+ listener
567
+ });
568
+ let active = true;
569
+ return () => {
570
+ if (!active) return;
571
+ active = false;
572
+ subscription.registrations.delete(token);
573
+ if (subscription.registrations.size > 0) return;
574
+ if (locationChangeSubscriptions.get(eventController) === subscription) {
575
+ locationChangeSubscriptions.delete(eventController);
576
+ }
577
+ subscription.unsubscribe();
578
+ };
579
+ }
580
+
581
+ // src/browser/react/use-segments.ts
582
+ import { useContext as useContext14, useEffect as useEffect9, useRef as useRef7 } from "react";
583
+
584
+ // src/browser/react/NavigationProvider.tsx
585
+ import {
586
+ useState as useState8,
587
+ useEffect as useEffect11,
588
+ useLayoutEffect as useLayoutEffect4,
589
+ useCallback as useCallback4,
590
+ useMemo as useMemo7,
591
+ useRef as useRef9,
592
+ use as use4,
593
+ startTransition as startTransition2
594
+ } from "react";
595
+
596
+ // src/root-error-boundary.tsx
597
+ import { Component as Component2, useState as useState6 } from "react";
598
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
599
+
600
+ // src/theme/ThemeProvider.tsx
601
+ import {
602
+ useCallback as useCallback3,
603
+ useEffect as useEffect10,
604
+ useLayoutEffect as useLayoutEffect3,
605
+ useMemo as useMemo6,
606
+ useState as useState7
607
+ } from "react";
608
+
609
+ // src/theme/constants.ts
610
+ var THEME_COOKIE = {
611
+ maxAge: 60 * 60 * 24 * 365,
612
+ // 1 year
613
+ path: "/",
614
+ sameSite: "lax"
615
+ };
616
+
617
+ // src/theme/ThemeProvider.tsx
618
+ import { jsx as jsx6 } from "react/jsx-runtime";
619
+
620
+ // src/browser/react/NavigationProvider.tsx
621
+ import { jsx as jsx7 } from "react/jsx-runtime";
622
+
623
+ // src/browser/react/Link.tsx
624
+ import {
625
+ forwardRef,
626
+ useCallback as useCallback5,
627
+ useContext as useContext16,
628
+ useEffect as useEffect13,
629
+ useMemo as useMemo8,
630
+ useRef as useRef10
631
+ } from "react";
632
+
633
+ // src/browser/react/use-link-status.ts
634
+ import {
635
+ createContext as createContext7,
636
+ useContext as useContext15,
637
+ useState as useState9,
638
+ useEffect as useEffect12
639
+ } from "react";
640
+ var LinkContext = createContext7(
641
+ null
642
+ );
643
+
644
+ // src/browser/prefetch/default-strategy.ts
645
+ var ENVIRONMENT_DEFAULT_PREFETCH = process.env.NODE_ENV === "production" ? "viewport" : "none";
646
+ function hoverNoneQuery() {
647
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function")
648
+ return null;
649
+ return window.matchMedia("(hover: none)");
650
+ }
651
+ function resolveAdaptiveStrategy(strategy) {
652
+ if (strategy !== "adaptive") return strategy;
653
+ return hoverNoneQuery()?.matches ? "viewport" : "hover";
654
+ }
655
+ function subscribeToAdaptiveStrategyChange(listener) {
656
+ const query = hoverNoneQuery();
657
+ if (!query) return () => {
658
+ };
659
+ if (typeof query.addEventListener === "function") {
660
+ query.addEventListener("change", listener);
661
+ return () => query.removeEventListener("change", listener);
662
+ }
663
+ query.addListener(listener);
664
+ return () => query.removeListener(listener);
665
+ }
666
+
667
+ // src/browser/prefetch/observer.ts
668
+ var callbacks = /* @__PURE__ */ new Map();
669
+ var observer = null;
670
+ function getObserver() {
671
+ if (!observer) {
672
+ observer = new IntersectionObserver(
673
+ (entries, currentObserver) => {
674
+ function* intersectingCallbacks() {
675
+ for (const entry of entries) {
676
+ if (entry.isIntersecting) {
677
+ const subscriptions = callbacks.get(entry.target);
678
+ if (subscriptions) {
679
+ currentObserver.unobserve(entry.target);
680
+ callbacks.delete(entry.target);
681
+ for (const [subscription, callback] of subscriptions) {
682
+ yield [subscriptions, subscription, callback];
683
+ }
684
+ }
685
+ }
686
+ }
687
+ }
688
+ notifyListeners(
689
+ intersectingCallbacks(),
690
+ ([, , callback]) => callback(),
691
+ ([subscriptions, subscription]) => subscriptions.has(subscription)
692
+ );
693
+ },
694
+ { rootMargin: "200px" }
695
+ );
696
+ for (const element of callbacks.keys()) observer.observe(element);
697
+ }
698
+ return observer;
699
+ }
700
+ function observeForPrefetch(element, onVisible) {
701
+ if (typeof IntersectionObserver === "undefined") return () => {
702
+ };
703
+ const currentObserver = getObserver();
704
+ let subscriptions = callbacks.get(element);
705
+ if (!subscriptions) {
706
+ subscriptions = /* @__PURE__ */ new Map();
707
+ callbacks.set(element, subscriptions);
708
+ }
709
+ const subscription = /* @__PURE__ */ Symbol();
710
+ subscriptions.set(subscription, onVisible);
711
+ if (subscriptions.size === 1) currentObserver.observe(element);
712
+ return () => {
713
+ const current = callbacks.get(element);
714
+ subscriptions.delete(subscription);
715
+ if (current !== subscriptions) return;
716
+ if (current.size > 0) return;
717
+ callbacks.delete(element);
718
+ observer?.unobserve(element);
719
+ };
720
+ }
721
+
722
+ // src/browser/link-interceptor.ts
723
+ var ELIGIBILITY_ATTRIBUTES = {
724
+ href: "href",
725
+ target: "target",
726
+ download: "download",
727
+ noIntercept: "data-no-intercept",
728
+ linkComponent: "data-link-component",
729
+ external: "data-external",
730
+ prefetch: "data-prefetch",
731
+ prefetchScope: "data-prefetch-scope"
732
+ };
733
+ var ELIGIBILITY_ATTRIBUTE_FILTER = Object.values(ELIGIBILITY_ATTRIBUTES);
734
+ var ELIGIBLE_ANCHOR_SELECTOR = `a[${ELIGIBILITY_ATTRIBUTES.href}]`;
735
+ var LINK_COMPONENT_SELECTOR = `a[${ELIGIBILITY_ATTRIBUTES.linkComponent}]`;
736
+ var PREFETCH_SCOPE_OPT_OUT_SELECTOR = `[${ELIGIBILITY_ATTRIBUTES.prefetchScope}="false"],[${ELIGIBILITY_ATTRIBUTES.prefetchScope}="none"]`;
737
+ function isElementNode(value) {
738
+ return typeof value === "object" && value !== null && value.nodeType === 1 && typeof value.matches === "function";
739
+ }
740
+ var prefetchScopeObservers = /* @__PURE__ */ new WeakMap();
741
+ function createPrefetchScopeObserverState(ownerDocument) {
742
+ if (typeof MutationObserver === "undefined" || !ownerDocument.documentElement) {
743
+ return void 0;
744
+ }
745
+ const subscriptions = /* @__PURE__ */ new Map();
746
+ const observer2 = new MutationObserver((mutations) => {
747
+ const affected = /* @__PURE__ */ new Set();
748
+ const collect = (element) => {
749
+ subscriptions.get(element)?.forEach((listener) => affected.add(listener));
750
+ };
751
+ for (const mutation of mutations) {
752
+ if (!isElementNode(mutation.target)) continue;
753
+ collect(mutation.target);
754
+ mutation.target.querySelectorAll(LINK_COMPONENT_SELECTOR).forEach(collect);
755
+ }
756
+ notifyListeners(affected, (listener) => listener());
757
+ });
758
+ observer2.observe(ownerDocument.documentElement, {
759
+ subtree: true,
760
+ attributes: true,
761
+ attributeFilter: [ELIGIBILITY_ATTRIBUTES.prefetchScope]
762
+ });
763
+ return { observer: observer2, subscriptions };
764
+ }
765
+ function subscribeToPrefetchScopeChange(element, listener) {
766
+ const ownerDocument = element.ownerDocument;
767
+ let state = prefetchScopeObservers.get(ownerDocument);
768
+ if (!state) {
769
+ state = createPrefetchScopeObserverState(ownerDocument);
770
+ if (!state) return () => {
771
+ };
772
+ prefetchScopeObservers.set(ownerDocument, state);
773
+ }
774
+ let listeners = state.subscriptions.get(element);
775
+ if (!listeners) {
776
+ listeners = /* @__PURE__ */ new Set();
777
+ state.subscriptions.set(element, listeners);
778
+ }
779
+ listeners.add(listener);
780
+ let active = true;
781
+ return () => {
782
+ if (!active) return;
783
+ active = false;
784
+ listeners.delete(listener);
785
+ if (listeners.size === 0 && state.subscriptions.get(element) === listeners) {
786
+ state.subscriptions.delete(element);
787
+ }
788
+ if (state.subscriptions.size === 0 && prefetchScopeObservers.get(ownerDocument) === state) {
789
+ state.observer.disconnect();
790
+ prefetchScopeObservers.delete(ownerDocument);
791
+ }
792
+ };
793
+ }
794
+ function isHashOnlyNavigationToPath(anchor, pathname) {
795
+ return pathname === window.location.pathname && anchor.search === window.location.search && !!anchor.hash;
796
+ }
797
+ function isHashOnlyNavigation(anchor) {
798
+ return isHashOnlyNavigationToPath(anchor, anchor.pathname);
799
+ }
800
+ function isPrefetchScopeDisabled(element) {
801
+ return typeof element.closest === "function" && element.closest(PREFETCH_SCOPE_OPT_OUT_SELECTOR) !== null;
802
+ }
803
+
804
+ // src/browser/react/Link.tsx
805
+ import { jsx as jsx8 } from "react/jsx-runtime";
806
+ function isExternalUrl(href2, origin) {
807
+ if (href2.startsWith("//")) return true;
808
+ if (href2.startsWith("http://") || href2.startsWith("https://")) {
809
+ if (!origin) return false;
810
+ try {
811
+ return new URL(href2).origin !== origin;
812
+ } catch {
813
+ return false;
814
+ }
815
+ }
816
+ if (/^[a-z][a-z0-9+.-]*:/i.test(href2)) {
817
+ return true;
818
+ }
819
+ return false;
820
+ }
821
+ var Link = forwardRef(function Link2({
822
+ to,
823
+ replace = false,
824
+ scroll = true,
825
+ reloadDocument = false,
826
+ revalidate: revalidate3,
827
+ transition: transition3,
828
+ prefetch,
829
+ prefetchKey,
830
+ state,
831
+ children,
832
+ onClick,
833
+ ...props
834
+ }, ref) {
835
+ const ctx = useContext16(NavigationStoreContext);
836
+ const isExternal = isExternalUrl(to, ctx?.origin);
837
+ const resolvedTo = useMemo8(
838
+ () => isExternal ? to : prefixBasename(to, ctx?.basename),
839
+ [to, isExternal, ctx?.basename]
840
+ );
841
+ const configuredStrategy = prefetch ?? ctx?.defaultPrefetch ?? ENVIRONMENT_DEFAULT_PREFETCH;
842
+ const internalRef = useRef10(null);
843
+ const setRef = useCallback5(
844
+ (node) => {
845
+ internalRef.current = node;
846
+ if (typeof ref === "function") {
847
+ ref(node);
848
+ } else if (ref) {
849
+ ref.current = node;
850
+ }
851
+ },
852
+ [ref]
853
+ );
854
+ const stateRef = useRef10(state);
855
+ stateRef.current = state;
856
+ const handleClick = useCallback5(
857
+ (e) => {
858
+ onClick?.(e);
859
+ if (e.defaultPrevented) return;
860
+ if (isExternal) return;
861
+ if (reloadDocument) return;
862
+ if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
863
+ if (e.currentTarget.hasAttribute("download"))
864
+ return;
865
+ const target = e.currentTarget.target;
866
+ if (target && target !== "_self") return;
867
+ if (isHashOnlyNavigation(e.currentTarget)) {
868
+ return;
869
+ }
870
+ if (!ctx?.navigate) {
871
+ return;
872
+ }
873
+ e.preventDefault();
874
+ e.stopPropagation();
875
+ const currentState = stateRef.current;
876
+ const state2 = typeof currentState === "function" && !(process.env.NODE_ENV !== "production" && isLocationStateDefinition(currentState)) ? currentState() : currentState ?? void 0;
877
+ ctx.navigate(resolvedTo, {
878
+ replace,
879
+ scroll,
880
+ state: state2,
881
+ revalidate: revalidate3,
882
+ transition: transition3
883
+ });
884
+ },
885
+ [
886
+ resolvedTo,
887
+ isExternal,
888
+ reloadDocument,
889
+ replace,
890
+ scroll,
891
+ revalidate3,
892
+ transition3,
893
+ ctx,
894
+ onClick
895
+ ]
896
+ );
897
+ const handleMouseEnter = useCallback5(() => {
898
+ const element = internalRef.current;
899
+ const strategy = resolveAdaptiveStrategy(configuredStrategy);
900
+ if ((strategy === "hover" || strategy === "viewport") && !isExternal && ctx?.store && (!element || !isHashOnlyNavigation(element) && !isPrefetchScopeDisabled(element))) {
901
+ const segmentState = ctx.store.getSegmentState();
902
+ prefetchDirect(
903
+ resolvedTo,
904
+ segmentState.currentSegmentIds,
905
+ getAppVersion(),
906
+ ctx.store.getRouterId?.(),
907
+ prefetchKey
908
+ );
909
+ }
910
+ }, [configuredStrategy, resolvedTo, isExternal, ctx, prefetchKey]);
911
+ useEffect13(() => {
912
+ if (isExternal || !ctx?.store) return;
913
+ if (configuredStrategy !== "viewport" && configuredStrategy !== "render" && configuredStrategy !== "adaptive") {
914
+ return;
915
+ }
916
+ const armPrefetch = () => {
917
+ const strategy = resolveAdaptiveStrategy(configuredStrategy);
918
+ const isViewport = strategy === "viewport";
919
+ const isRender = strategy === "render";
920
+ if (!isViewport && !isRender) return () => {
921
+ };
922
+ const element2 = internalRef.current;
923
+ if (element2 && (isHashOnlyNavigation(element2) || isPrefetchScopeDisabled(element2))) {
924
+ return () => {
925
+ };
926
+ }
927
+ let cancelled = false;
928
+ let unsubIdle;
929
+ let stopObserving;
930
+ const triggerPrefetch = () => {
931
+ if (cancelled) return;
932
+ const currentElement = internalRef.current;
933
+ if (currentElement && isPrefetchScopeDisabled(currentElement)) return;
934
+ const segmentState = ctx.store.getSegmentState();
935
+ prefetchQueued(
936
+ resolvedTo,
937
+ segmentState.currentSegmentIds,
938
+ getAppVersion(),
939
+ ctx.store.getRouterId?.(),
940
+ prefetchKey
941
+ );
942
+ };
943
+ if (isRender) {
944
+ unsubIdle = schedulePrefetchWhenRouterIdle(
945
+ ctx.eventController,
946
+ triggerPrefetch
947
+ );
948
+ } else {
949
+ const viewportElement = internalRef.current;
950
+ if (viewportElement) {
951
+ stopObserving = observeForPrefetch(viewportElement, () => {
952
+ unsubIdle = schedulePrefetchWhenRouterIdle(
953
+ ctx.eventController,
954
+ triggerPrefetch
955
+ );
956
+ });
957
+ }
958
+ }
959
+ return () => {
960
+ cancelled = true;
961
+ unsubIdle?.();
962
+ stopObserving?.();
963
+ };
964
+ };
965
+ let disarmPrefetch = armPrefetch();
966
+ const rearm = () => {
967
+ disarmPrefetch();
968
+ disarmPrefetch = armPrefetch();
969
+ };
970
+ const element = internalRef.current;
971
+ const unsubscribeScope = element ? subscribeToPrefetchScopeChange(element, rearm) : void 0;
972
+ const unsubscribeLocation = subscribeToLocationChange(
973
+ ctx.eventController,
974
+ rearm
975
+ );
976
+ const unsubscribeAdaptive = configuredStrategy === "adaptive" ? subscribeToAdaptiveStrategyChange(rearm) : void 0;
977
+ return () => {
978
+ unsubscribeScope?.();
979
+ unsubscribeLocation();
980
+ unsubscribeAdaptive?.();
981
+ disarmPrefetch();
982
+ };
983
+ }, [configuredStrategy, resolvedTo, isExternal, ctx, prefetchKey]);
984
+ return /* @__PURE__ */ jsx8(
985
+ "a",
986
+ {
987
+ ref: setRef,
988
+ href: resolvedTo,
989
+ onClick: handleClick,
990
+ onMouseEnter: handleMouseEnter,
991
+ "data-link-component": true,
992
+ "data-external": isExternal ? "" : void 0,
993
+ "data-scroll": scroll === false ? "false" : void 0,
994
+ "data-replace": replace ? "true" : void 0,
995
+ "data-revalidate": revalidate3 === false ? "false" : void 0,
996
+ "data-transition": transition3 === false ? "false" : void 0,
997
+ ...props,
998
+ children: /* @__PURE__ */ jsx8(LinkContext.Provider, { value: resolvedTo, children })
999
+ }
1000
+ );
1001
+ });
1002
+
1003
+ // src/handles/breadcrumbs.ts
1004
+ function collectBreadcrumbs(segments) {
1005
+ const all = segments.flat();
1006
+ const hasHref = (item) => item != null && typeof item === "object" && typeof item.href === "string";
1007
+ const valueByHref = /* @__PURE__ */ new Map();
1008
+ for (const item of all) {
1009
+ if (hasHref(item)) valueByHref.set(item.href, item);
1010
+ }
1011
+ const result = [];
1012
+ const emitted = /* @__PURE__ */ new Set();
1013
+ for (const item of all) {
1014
+ if (!hasHref(item)) {
1015
+ result.push(item);
1016
+ continue;
1017
+ }
1018
+ if (!emitted.has(item.href)) {
1019
+ emitted.add(item.href);
1020
+ result.push(valueByHref.get(item.href));
1021
+ }
1022
+ }
1023
+ return result;
1024
+ }
1025
+ var Breadcrumbs = createHandle(
1026
+ collectBreadcrumbs,
1027
+ "__rsc_router_breadcrumbs__"
1028
+ );
1029
+
1030
+ // src/browser/react/location-state.ts
1031
+ import { useContext as useContext17, useEffect as useEffect14 } from "react";
1032
+
1033
+ // src/browser/react/use-href.tsx
1034
+ import { useCallback as useCallback6 } from "react";
1035
+
1036
+ // src/browser/react/use-reverse.ts
1037
+ import { useCallback as useCallback7 } from "react";
1038
+
1039
+ // src/client.tsx
1040
+ import { jsx as jsx9 } from "react/jsx-runtime";
1041
+
1042
+ // src/server/root-layout.tsx
1043
+ import { Fragment as Fragment3, jsx as jsx10 } from "react/jsx-runtime";
1044
+
1045
+ // src/prerender.ts
1046
+ var PRERENDER_PASSTHROUGH = Object.freeze({
1047
+ __brand: "prerenderPassthrough"
1048
+ });
1049
+
1050
+ // src/route-definition/use-item-types.ts
1051
+ var USE_ITEM_TYPES = {
1052
+ layout: true,
1053
+ route: true,
1054
+ middleware: true,
1055
+ revalidate: true,
1056
+ parallel: true,
1057
+ intercept: true,
1058
+ loader: true,
1059
+ loading: true,
1060
+ errorBoundary: true,
1061
+ notFoundBoundary: true,
1062
+ cache: true,
1063
+ transition: true,
1064
+ include: true
1065
+ };
1066
+ var ALL_USE_ITEM_TYPES = new Set(
1067
+ Object.keys(USE_ITEM_TYPES)
1068
+ );
1069
+
1070
+ // src/server/slot-accessors.ts
1071
+ function slotAccessor(slot, enumerable) {
1072
+ return {
1073
+ get() {
1074
+ return this[slot]();
1075
+ },
1076
+ enumerable,
1077
+ configurable: true
1078
+ };
1079
+ }
1080
+
1081
+ // src/router/logging.ts
1082
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
1083
+ var routerLogContext = new AsyncLocalStorage3();
1084
+
1085
+ // src/server/request-context.ts
1086
+ import { AsyncLocalStorage as AsyncLocalStorage6 } from "node:async_hooks";
1087
+
1088
+ // src/context-var.ts
1089
+ function createVar(options) {
1090
+ return {
1091
+ __brand: "context-var",
1092
+ key: /* @__PURE__ */ Symbol(),
1093
+ cache: options?.cache !== false
1094
+ };
1095
+ }
1096
+
1097
+ // src/router/segment-resolution/mask-nested.ts
1098
+ import { cloneElement, isValidElement as isValidElement3 } from "react";
1099
+
1100
+ // src/server/handle-store.ts
1101
+ var LOADER_SLOT = Object.freeze({ loader: true });
1102
+ var RECORD_SLOT = Object.freeze({ record: true });
1103
+
1104
+ // src/cache/cache-tag.ts
1105
+ import { AsyncLocalStorage as AsyncLocalStorage4 } from "node:async_hooks";
1106
+ var cacheTagStorage = new AsyncLocalStorage4();
1107
+ var segmentOwnerStorage = new AsyncLocalStorage4();
1108
+ var recordedTagCapture = globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:recorded-tag-capture")] ??= new AsyncLocalStorage4();
1109
+ var identityReads = globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:identity-reads")] ??= /* @__PURE__ */ new WeakMap();
1110
+ function activeTagSet() {
1111
+ const capture = recordedTagCapture.getStore();
1112
+ const body = getLoaderBodyTags();
1113
+ if (capture && capture.outer === body) return capture.into;
1114
+ return body ?? capture?.into;
1115
+ }
1116
+ globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:identity-read-recorder")] = (surface, verb) => {
1117
+ const set = activeTagSet();
1118
+ if (set === void 0 || identityReads.has(set)) return;
1119
+ identityReads.set(set, { surface, verb, bodyId: getCurrentLoaderBodyId() });
1120
+ };
1121
+ var loaderRuns = globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:loader-runs")] ??= /* @__PURE__ */ new WeakMap();
1122
+
1123
+ // src/router/router-context.ts
1124
+ import { AsyncLocalStorage as AsyncLocalStorage5 } from "async_hooks";
1125
+ var routerContext = new AsyncLocalStorage5();
1126
+
1127
+ // src/server/cookie-store.ts
1128
+ var REQUEST_READ_CACHE_FIX = {
1129
+ useCache: 'Request-scoped data (cookies, headers) varies per request but is not reflected in the cache key, so cached results would be served to the wrong users. Extract the value before the cached function and pass it as an argument:\n\n const locale = cookies().get("locale")?.value ?? "en";\n const data = await getCachedData(locale); // locale is now in the cache key',
1130
+ cacheScope: 'A cache() scope caches everything except loaders, so request-scoped data (cookies, headers) read here would be frozen into the shared cached shell and served to other users. Read it inside a loader instead \u2014 loaders always run fresh on every request, even on a cache hit:\n\n loader("user", () => getUser(cookies().get("session")?.value));'
1131
+ };
1132
+ function requestReadWording(what) {
1133
+ return {
1134
+ verb: "called",
1135
+ fix: { ...REQUEST_READ_CACHE_FIX, ...requestReadCaptureFix(what) },
1136
+ record: false
1137
+ };
1138
+ }
1139
+ var COOKIES_READ = requestReadWording("cookies");
1140
+ var HEADERS_READ = requestReadWording("headers");
1141
+ var REQUEST_HEADERS_READ = {
1142
+ verb: "read",
1143
+ fix: HEADERS_READ.fix
1144
+ };
1145
+ var RAW_COOKIES_READ = {
1146
+ verb: "called",
1147
+ fix: COOKIES_READ.fix
1148
+ };
1149
+ var THEME_READ_FIX = "On ppr and cache() routes, read the theme with useTheme() in a client component, or in a live loader (no ssr: false) with cookies().get(<storageKey>). The <html> theme class needs neither: the theme script sets it before paint. See the /theme skill (node_modules/@rangojs/router/skills/theme/SKILL.md).";
1150
+ var THEME_READ = {
1151
+ verb: "read",
1152
+ fix: {
1153
+ useCache: "The theme comes from the visitor's cookie and is not in the cache key, so the first caller's theme would be served to later callers. Read it before the cached function and pass it in as an argument.",
1154
+ cacheScope: "The theme comes from the visitor's cookie, so the first visitor's theme would be stored in the shared entry and served to everyone. " + THEME_READ_FIX,
1155
+ capture: `The captured shell is served to every visitor of this URL, so the capturing visitor's theme would reach everyone. ${THEME_READ_FIX}`,
1156
+ warning: THEME_READ_FIX
1157
+ }
1158
+ };
1159
+
1160
+ // src/server/rewrite-trail.ts
1161
+ var REWRITE_TRAIL = createVar();
1162
+ var REWRITE_SHELL = createVar();
1163
+
1164
+ // src/cache/invalidation-order.ts
1165
+ var order = globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:tag-invalidation-order")] ??= { seq: 0, tags: /* @__PURE__ */ new Map(), forgotten: 0 };
1166
+ var responseStarts = globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:response-execution-start")] ??= /* @__PURE__ */ new WeakMap();
1167
+
1168
+ // src/server/request-context.ts
1169
+ var requestContextStorage = new AsyncLocalStorage6();
1170
+ var RES_SLOT = /* @__PURE__ */ Symbol("rango.requestContext.res");
1171
+ var RENDER_BARRIER_SLOT = /* @__PURE__ */ Symbol(
1172
+ "rango.requestContext.renderBarrier"
1173
+ );
1174
+ var RES_DESCRIPTOR = {
1175
+ ...slotAccessor(RES_SLOT, true),
1176
+ set(_) {
1177
+ throw new Error(
1178
+ "ctx.res is read-only. Use ctx.header() to set response headers, or cookies() for cookie mutations."
1179
+ );
1180
+ }
1181
+ };
1182
+ var RENDER_BARRIER_DESCRIPTOR = slotAccessor(
1183
+ RENDER_BARRIER_SLOT,
1184
+ true
1185
+ );
1186
+ var DERIVED_RENDER_BARRIER_DESCRIPTOR = {
1187
+ ...RENDER_BARRIER_DESCRIPTOR,
1188
+ enumerable: false
1189
+ };
1190
+ var backgroundWork = new AsyncLocalStorage6();
1191
+
1192
+ // src/client-urls/client-root.tsx
1193
+ import {
1194
+ createElement as createElement5,
1195
+ Fragment as Fragment4,
1196
+ Suspense as Suspense3,
1197
+ useDeferredValue,
1198
+ useLayoutEffect as useLayoutEffect5,
1199
+ useMemo as useMemo10,
1200
+ useState as useState10
1201
+ } from "react";
1202
+
1203
+ // src/client-urls/navigation.ts
1204
+ import { startTransition as startTransition3 } from "react";
1205
+
1206
+ // src/client-urls/client-root.tsx
1207
+ import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
1208
+ var PENDING_FOREVER = new Promise(() => {
1209
+ });
1210
+
1211
+ // src/client-urls/server-projection.ts
1212
+ var SEARCH_SCHEMA_VALUES = /* @__PURE__ */ new Set([
1213
+ "string",
1214
+ "number",
1215
+ "boolean",
1216
+ "string?",
1217
+ "number?",
1218
+ "boolean?"
1219
+ ]);
1220
+ var PROJECTION_OPTIONS = /* @__PURE__ */ new Set([
1221
+ "name",
1222
+ "search",
1223
+ "trailingSlash",
1224
+ "ppr"
1225
+ ]);
1226
+ var PPR_NUMBER_KEYS = /* @__PURE__ */ new Set([
1227
+ "ttl",
1228
+ "swr",
1229
+ "captureTimeout",
1230
+ "maxSnapshotBytes"
1231
+ ]);
1232
+ function routeDescription(route2) {
1233
+ return `route "${route2.pattern}" (${route2.id})`;
1234
+ }
1235
+ function projectionError(route2, message) {
1236
+ return new Error(
1237
+ `clientUrls() cannot create a server projection for ${routeDescription(route2)}: ${message}`
1238
+ );
1239
+ }
1240
+ function serializeSearchSchema(route2, value) {
1241
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
1242
+ throw projectionError(route2, 'path option "search" must be an object');
1243
+ }
1244
+ const entries = [];
1245
+ for (const key of Object.keys(value)) {
1246
+ const schemaValue = value[key];
1247
+ if (typeof schemaValue !== "string" || !SEARCH_SCHEMA_VALUES.has(schemaValue)) {
1248
+ throw projectionError(
1249
+ route2,
1250
+ `path option "search.${key}" has unsupported value ${JSON.stringify(schemaValue)}`
1251
+ );
1252
+ }
1253
+ entries.push([key, schemaValue]);
1254
+ }
1255
+ return Object.freeze(Object.fromEntries(entries));
1256
+ }
1257
+ function serializeOptions(route2) {
1258
+ const source = route2.options;
1259
+ if (!source) return Object.freeze({});
1260
+ for (const key of Reflect.ownKeys(source)) {
1261
+ if (!PROJECTION_OPTIONS.has(key)) {
1262
+ throw projectionError(
1263
+ route2,
1264
+ `path option ${JSON.stringify(String(key))} is not supported`
1265
+ );
1266
+ }
1267
+ }
1268
+ const options = {};
1269
+ if (source.search !== void 0) {
1270
+ options.search = serializeSearchSchema(route2, source.search);
1271
+ }
1272
+ if (source.trailingSlash !== void 0) {
1273
+ options.trailingSlash = source.trailingSlash;
1274
+ }
1275
+ if (source.ppr !== void 0) {
1276
+ options.ppr = serializePpr(route2, source.ppr);
1277
+ }
1278
+ return Object.freeze(options);
1279
+ }
1280
+ function serializePpr(route2, source) {
1281
+ if (source === true) return true;
1282
+ if (typeof source !== "object" || source === null || Array.isArray(source)) {
1283
+ throw projectionError(
1284
+ route2,
1285
+ 'path option "ppr" must be true or a PartialPrerenderProps object'
1286
+ );
1287
+ }
1288
+ const out = {};
1289
+ for (const key of Reflect.ownKeys(source)) {
1290
+ if (PPR_NUMBER_KEYS.has(key)) {
1291
+ const value = source[key];
1292
+ if (typeof value !== "number" || !Number.isFinite(value)) {
1293
+ throw projectionError(
1294
+ route2,
1295
+ `path option "ppr.${String(key)}" must be a finite number`
1296
+ );
1297
+ }
1298
+ out[key] = value;
1299
+ continue;
1300
+ }
1301
+ if (key === "tags") {
1302
+ const tags = source.tags;
1303
+ if (!Array.isArray(tags) || tags.some((tag) => typeof tag !== "string" || tag === "")) {
1304
+ throw projectionError(
1305
+ route2,
1306
+ 'path option "ppr.tags" must be an array of non-empty strings'
1307
+ );
1308
+ }
1309
+ out.tags = Object.freeze([...tags]);
1310
+ continue;
1311
+ }
1312
+ throw projectionError(
1313
+ route2,
1314
+ `path option "ppr.${String(key)}" is not supported`
1315
+ );
1316
+ }
1317
+ return Object.freeze(out);
1318
+ }
1319
+ function serializeTransition(route2) {
1320
+ const source = route2.transition;
1321
+ if (!source) return void 0;
1322
+ const config = {};
1323
+ for (const [key, value] of Object.entries(source)) {
1324
+ if (value === void 0 || key === "when") continue;
1325
+ config[key] = typeof value === "object" && value !== null ? Object.freeze({ ...value }) : value;
1326
+ }
1327
+ return Object.freeze(config);
1328
+ }
1329
+ function indicesWhere(items, pred) {
1330
+ return items.flatMap((item, index) => pred(item) ? [index] : []);
1331
+ }
1332
+ function serializeRoute(route2, options, ordinals) {
1333
+ const layoutLoaders = route2.layoutLoaders.map((record) => {
1334
+ if (!ordinals.has(record)) ordinals.set(record, ordinals.size);
1335
+ return ordinals.get(record);
1336
+ });
1337
+ const loaderIds = route2.loaders.map(({ loader: loader3 }, index) => {
1338
+ if (typeof loader3.$$id !== "string" || loader3.$$id.length === 0) {
1339
+ throw projectionError(
1340
+ route2,
1341
+ `loader at index ${index} is missing a non-empty $$id`
1342
+ );
1343
+ }
1344
+ return loader3.$$id;
1345
+ });
1346
+ const awaitedLoaderIndices = indicesWhere(
1347
+ route2.loaders,
1348
+ ({ ssr }) => ssr === false
1349
+ );
1350
+ const transition3 = serializeTransition(route2);
1351
+ return Object.freeze({
1352
+ id: route2.id,
1353
+ pattern: route2.pattern,
1354
+ name: route2.name ?? null,
1355
+ options: serializeOptions(route2),
1356
+ loaderIds: Object.freeze(loaderIds),
1357
+ hasLoading: route2.loading !== void 0,
1358
+ ...awaitedLoaderIndices.length > 0 ? { awaitedLoaderIndices: Object.freeze(awaitedLoaderIndices) } : {},
1359
+ ...serializeLoaderOptions(
1360
+ route2.loaders,
1361
+ `route "${route2.pattern}"`,
1362
+ options
1363
+ ),
1364
+ ...layoutLoaders.length > 0 ? { layoutLoaders: Object.freeze(layoutLoaders) } : {},
1365
+ ...transition3 ? { transition: transition3 } : {},
1366
+ ...typeof route2.transition?.when === "function" ? { transitionWhen: true } : {}
1367
+ });
1368
+ }
1369
+ function serializeLoaderOptions(loaders, owner, options) {
1370
+ const loaderRevalidate = loaders.map(
1371
+ ({ loader: loader3, revalidate: revalidate3 }) => revalidate3.flatMap((entry) => {
1372
+ if (isHoistedRevalidateRef(entry)) return [entry.$$rangoRevalidate];
1373
+ if (typeof entry === "boolean") return [entry];
1374
+ if (options.hoisted) {
1375
+ throw new Error(
1376
+ `clientUrls() revalidate() on loader "${loader3.$$id}" of ${owner} was not hoisted to the server: call revalidate() (the builder's helper, or the one "@rangojs/router/client" exports for a component's .use) with an inline function, an imported predicate or a boolean.`
1377
+ );
1378
+ }
1379
+ return [];
1380
+ })
1381
+ );
1382
+ const deferrableLoaderIndices = indicesWhere(
1383
+ loaders,
1384
+ ({ prefetch }) => prefetch === false
1385
+ );
1386
+ return {
1387
+ ...deferrableLoaderIndices.length > 0 ? { deferrableLoaderIndices: Object.freeze(deferrableLoaderIndices) } : {},
1388
+ ...loaderRevalidate.some((keys) => keys.length > 0) ? {
1389
+ loaderRevalidate: Object.freeze(
1390
+ loaderRevalidate.map((keys) => Object.freeze(keys))
1391
+ )
1392
+ } : {}
1393
+ };
1394
+ }
1395
+ function serializeIntercept(record, index, options) {
1396
+ const loaderIds = record.loaders.map(({ loader: loader3 }, loaderIndex) => {
1397
+ if (typeof loader3.$$id !== "string" || loader3.$$id.length === 0) {
1398
+ throw new Error(
1399
+ `clientUrls() cannot create a server projection for intercept ".${record.targetName}" (index ${index}): loader at index ${loaderIndex} is missing a non-empty $$id`
1400
+ );
1401
+ }
1402
+ return loader3.$$id;
1403
+ });
1404
+ return Object.freeze({
1405
+ slotName: record.slotName,
1406
+ targetName: record.targetName,
1407
+ loaderIds: Object.freeze(loaderIds),
1408
+ hasLoading: record.loading !== void 0,
1409
+ ...serializeLoaderOptions(
1410
+ record.loaders,
1411
+ `intercept ".${record.targetName}"`,
1412
+ options
1413
+ )
1414
+ });
1415
+ }
1416
+ function serializeClientUrlPatterns(patterns, options = {}) {
1417
+ const ordinals = /* @__PURE__ */ new Map();
1418
+ return Object.freeze({
1419
+ version: 1,
1420
+ routes: Object.freeze(
1421
+ patterns.routes.map((route2) => serializeRoute(route2, options, ordinals))
1422
+ ),
1423
+ intercepts: Object.freeze(
1424
+ (patterns.intercepts ?? []).map(
1425
+ (record, index) => serializeIntercept(record, index, options)
1426
+ )
1427
+ )
1428
+ });
1429
+ }
1430
+ function projectClientUrlsModule(namespace, options = {}) {
1431
+ const definition = namespace.default;
1432
+ if (typeof definition !== "object" && typeof definition !== "function" || definition === null || definition.__brand !== "client-urls") {
1433
+ return void 0;
1434
+ }
1435
+ return serializeClientUrlPatterns(definition, options);
1436
+ }
1437
+
1438
+ // src/vite/plugins/client-ref-hashing.ts
1439
+ import { relative } from "node:path";
1440
+ import { createHash } from "node:crypto";
1441
+
1442
+ // src/vite/debug.ts
1443
+ import debugFactory from "debug";
1444
+ var NS = {
1445
+ config: "rango:config",
1446
+ discovery: "rango:discovery",
1447
+ routes: "rango:routes",
1448
+ prerender: "rango:prerender",
1449
+ build: "rango:build",
1450
+ dev: "rango:dev",
1451
+ transform: "rango:transform",
1452
+ chunks: "rango:chunks"
1453
+ };
1454
+ if (process.env.INTERNAL_RANGO_DEBUG) {
1455
+ const existing = debugFactory.disable();
1456
+ debugFactory.enable(existing ? `${existing},rango:*` : "rango:*");
1457
+ }
1458
+ function createRangoDebugger(namespace) {
1459
+ const primary = debugFactory(namespace);
1460
+ const shadow = debugFactory(`vite:${namespace}`);
1461
+ if (primary.enabled) return primary;
1462
+ if (shadow.enabled) return shadow;
1463
+ return void 0;
1464
+ }
1465
+ function createCounter(debug3, label) {
1466
+ if (!debug3) return void 0;
1467
+ let n = 0;
1468
+ let totalMs = 0;
1469
+ let slowestMs = 0;
1470
+ let slowestFile = "";
1471
+ const record = (file, ms) => {
1472
+ n++;
1473
+ totalMs += ms;
1474
+ if (ms > slowestMs) {
1475
+ slowestMs = ms;
1476
+ slowestFile = file;
1477
+ }
1478
+ };
1479
+ return {
1480
+ record,
1481
+ time(file, fn) {
1482
+ const start = performance.now();
1483
+ let out;
1484
+ try {
1485
+ out = fn();
1486
+ } catch (err) {
1487
+ record(file, performance.now() - start);
1488
+ throw err;
1489
+ }
1490
+ if (out && typeof out.then === "function") {
1491
+ return out.finally(
1492
+ () => record(file, performance.now() - start)
1493
+ );
1494
+ }
1495
+ record(file, performance.now() - start);
1496
+ return out;
1497
+ },
1498
+ flush() {
1499
+ if (n === 0) return;
1500
+ debug3(
1501
+ "%s: %d files, %sms total, slowest %sms %s",
1502
+ label,
1503
+ n,
1504
+ totalMs.toFixed(1),
1505
+ slowestMs.toFixed(1),
1506
+ slowestFile
1507
+ );
1508
+ n = 0;
1509
+ totalMs = 0;
1510
+ slowestMs = 0;
1511
+ slowestFile = "";
1512
+ }
1513
+ };
1514
+ }
1515
+
1516
+ // src/vite/plugins/client-ref-hashing.ts
1517
+ var debug = createRangoDebugger(NS.transform);
1518
+ var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
1519
+ var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
1520
+ var FS_PREFIX = "/@fs/";
1521
+ function hashRefKey(relativeId) {
1522
+ return createHash("sha256").update(relativeId).digest("hex").slice(0, 12);
1523
+ }
1524
+ function computeProductionHash(projectRoot, refKey) {
1525
+ let toHash;
1526
+ if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
1527
+ toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
1528
+ } else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
1529
+ const absPath = decodeURIComponent(
1530
+ refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
1531
+ );
1532
+ toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
1533
+ } else if (refKey.startsWith(FS_PREFIX)) {
1534
+ const absPath = refKey.slice(FS_PREFIX.length - 1);
1535
+ toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
1536
+ } else if (refKey.startsWith("/")) {
1537
+ toHash = refKey.slice(1);
1538
+ } else {
1539
+ return refKey;
1540
+ }
1541
+ return hashRefKey(toHash);
1542
+ }
1543
+ var REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
1544
+ function transformClientRefs(code, projectRoot) {
1545
+ if (!code.includes("registerClientReference")) return null;
1546
+ let hasReplacement = false;
1547
+ const result = code.replace(
1548
+ REGISTER_CLIENT_REF_RE,
1549
+ (match, refKey) => {
1550
+ const hash = computeProductionHash(projectRoot, refKey);
1551
+ if (hash === refKey) return match;
1552
+ hasReplacement = true;
1553
+ return match.replace(`"${refKey}"`, `"${hash}"`);
1554
+ }
1555
+ );
1556
+ return hasReplacement ? result : null;
1557
+ }
1558
+ function hashClientRefs(projectRoot) {
1559
+ const counter = createCounter(debug, "hash-client-refs");
1560
+ return {
1561
+ name: "@rangojs/router:hash-client-refs",
1562
+ enforce: "post",
1563
+ applyToEnvironment(env) {
1564
+ return env.name === "rsc";
1565
+ },
1566
+ buildEnd() {
1567
+ counter?.flush();
1568
+ },
1569
+ transform(code, id) {
1570
+ const start = counter ? performance.now() : 0;
1571
+ try {
1572
+ const result = transformClientRefs(code, projectRoot);
1573
+ if (result === null) return;
1574
+ return { code: result, map: null };
1575
+ } finally {
1576
+ counter?.record(id, performance.now() - start);
1577
+ }
1578
+ }
1579
+ };
1580
+ }
1581
+
1582
+ // src/vite/utils/directive-prologue.ts
1583
+ import { parseAst } from "vite";
1584
+ function hasUseClientDirective(source) {
1585
+ let program;
1586
+ try {
1587
+ program = parseAst(source, { lang: "tsx" });
1588
+ } catch {
1589
+ return false;
1590
+ }
1591
+ for (const node of program.body ?? []) {
1592
+ if (node?.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
1593
+ if (node.expression.value === "use client") return true;
1594
+ continue;
1595
+ }
1596
+ break;
1597
+ }
1598
+ return false;
1599
+ }
1600
+
1601
+ // src/vite/plugins/hoist/scope.ts
1602
+ var Scope = class {
1603
+ constructor(parent, isFunction, node) {
1604
+ this.parent = parent;
1605
+ this.isFunction = isFunction;
1606
+ this.node = node;
1607
+ this.declarations = /* @__PURE__ */ new Set();
1608
+ }
1609
+ nearestFunction() {
1610
+ return this.isFunction || !this.parent ? this : this.parent.nearestFunction();
1611
+ }
1612
+ lookup(name) {
1613
+ if (this.declarations.has(name)) return this;
1614
+ return this.parent ? this.parent.lookup(name) : null;
1615
+ }
1616
+ };
1617
+ var TYPE_KEYS = /* @__PURE__ */ new Set([
1618
+ "typeAnnotation",
1619
+ "returnType",
1620
+ "typeParameters",
1621
+ "typeArguments",
1622
+ "superTypeArguments",
1623
+ "implements"
1624
+ ]);
1625
+ function jsxNameReference(name) {
1626
+ if (name?.type === "JSXIdentifier") {
1627
+ return /^[a-z]/.test(name.name) || name.name.includes("-") ? null : name;
1628
+ }
1629
+ let root = name;
1630
+ while (root?.type === "JSXMemberExpression") root = root.object;
1631
+ return root?.type === "JSXIdentifier" && root.name !== "this" ? root : null;
1632
+ }
1633
+ function patternNames(pattern, names = []) {
1634
+ if (!pattern) return names;
1635
+ switch (pattern.type) {
1636
+ case "Identifier":
1637
+ names.push(pattern.name);
1638
+ break;
1639
+ case "ObjectPattern":
1640
+ for (const prop of pattern.properties) {
1641
+ patternNames(prop.type === "RestElement" ? prop : prop.value, names);
1642
+ }
1643
+ break;
1644
+ case "ArrayPattern":
1645
+ for (const element of pattern.elements) patternNames(element, names);
1646
+ break;
1647
+ case "RestElement":
1648
+ patternNames(pattern.argument, names);
1649
+ break;
1650
+ case "AssignmentPattern":
1651
+ patternNames(pattern.left, names);
1652
+ break;
1653
+ case "TSParameterProperty":
1654
+ patternNames(pattern.parameter, names);
1655
+ break;
1656
+ }
1657
+ return names;
1658
+ }
1659
+ function analyzeScopes(program) {
1660
+ const moduleScope = new Scope(null, true, program);
1661
+ const scopeOf = /* @__PURE__ */ new Map([[program, moduleScope]]);
1662
+ const references = [];
1663
+ const declarePattern = (pattern, scope) => {
1664
+ for (const name of patternNames(pattern)) scope.declarations.add(name);
1665
+ };
1666
+ const walkPattern = (pattern, scope, typeOnly) => {
1667
+ if (!pattern) return;
1668
+ switch (pattern.type) {
1669
+ case "Identifier":
1670
+ if (pattern.typeAnnotation) walk(pattern.typeAnnotation, scope, true);
1671
+ return;
1672
+ case "ObjectPattern":
1673
+ for (const prop of pattern.properties) {
1674
+ if (prop.type === "RestElement") {
1675
+ walkPattern(prop.argument, scope, typeOnly);
1676
+ } else {
1677
+ if (prop.computed) walk(prop.key, scope, typeOnly);
1678
+ walkPattern(prop.value, scope, typeOnly);
1679
+ }
1680
+ }
1681
+ if (pattern.typeAnnotation) walk(pattern.typeAnnotation, scope, true);
1682
+ return;
1683
+ case "ArrayPattern":
1684
+ for (const element of pattern.elements) {
1685
+ walkPattern(element, scope, typeOnly);
1686
+ }
1687
+ if (pattern.typeAnnotation) walk(pattern.typeAnnotation, scope, true);
1688
+ return;
1689
+ case "RestElement":
1690
+ walkPattern(pattern.argument, scope, typeOnly);
1691
+ return;
1692
+ case "AssignmentPattern":
1693
+ walkPattern(pattern.left, scope, typeOnly);
1694
+ walk(pattern.right, scope, typeOnly);
1695
+ return;
1696
+ case "TSParameterProperty":
1697
+ walkPattern(pattern.parameter, scope, typeOnly);
1698
+ return;
1699
+ default:
1700
+ walk(pattern, scope, typeOnly);
1701
+ }
1702
+ };
1703
+ const hoistDeclarations = (statements, scope) => {
1704
+ for (const statement of statements) {
1705
+ const node = statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration" ? statement.declaration : statement;
1706
+ if (!node) continue;
1707
+ switch (node.type) {
1708
+ case "ImportDeclaration":
1709
+ for (const spec of node.specifiers) {
1710
+ scope.declarations.add(spec.local.name);
1711
+ }
1712
+ break;
1713
+ case "FunctionDeclaration":
1714
+ case "ClassDeclaration":
1715
+ case "TSEnumDeclaration":
1716
+ case "TSTypeAliasDeclaration":
1717
+ case "TSInterfaceDeclaration":
1718
+ case "TSModuleDeclaration":
1719
+ if (node.id?.type === "Identifier") {
1720
+ scope.declarations.add(node.id.name);
1721
+ }
1722
+ break;
1723
+ case "VariableDeclaration":
1724
+ for (const declarator of node.declarations) {
1725
+ declarePattern(
1726
+ declarator.id,
1727
+ node.kind === "var" ? scope.nearestFunction() : scope
1728
+ );
1729
+ }
1730
+ break;
1731
+ }
1732
+ }
1733
+ };
1734
+ const walk = (node, scope, typeOnly) => {
1735
+ if (!node || typeof node !== "object") return;
1736
+ if (Array.isArray(node)) {
1737
+ for (const item of node) walk(item, scope, typeOnly);
1738
+ return;
1739
+ }
1740
+ if (typeof node.type !== "string") return;
1741
+ switch (node.type) {
1742
+ case "Identifier":
1743
+ references.push({ node, scope, typeOnly });
1744
+ if (node.typeAnnotation) walk(node.typeAnnotation, scope, true);
1745
+ return;
1746
+ case "ImportDeclaration":
1747
+ case "ExportAllDeclaration":
1748
+ return;
1749
+ case "ExportNamedDeclaration":
1750
+ if (node.declaration) walk(node.declaration, scope, typeOnly);
1751
+ else if (!node.source) {
1752
+ for (const spec of node.specifiers) {
1753
+ walk(spec.local, scope, typeOnly || node.exportKind === "type");
1754
+ }
1755
+ }
1756
+ return;
1757
+ case "MemberExpression":
1758
+ walk(node.object, scope, typeOnly);
1759
+ if (node.computed) walk(node.property, scope, typeOnly);
1760
+ return;
1761
+ case "Property":
1762
+ case "MethodDefinition":
1763
+ case "PropertyDefinition":
1764
+ case "TSPropertySignature":
1765
+ case "TSMethodSignature":
1766
+ if (node.computed) walk(node.key, scope, typeOnly);
1767
+ walk(node.value, scope, typeOnly);
1768
+ if (node.typeAnnotation) walk(node.typeAnnotation, scope, true);
1769
+ return;
1770
+ case "LabeledStatement":
1771
+ walk(node.body, scope, typeOnly);
1772
+ return;
1773
+ case "BreakStatement":
1774
+ case "ContinueStatement":
1775
+ case "MetaProperty":
1776
+ return;
1777
+ case "JSXOpeningElement":
1778
+ case "JSXClosingElement": {
1779
+ const ref = jsxNameReference(node.name);
1780
+ if (ref) references.push({ node: ref, scope, typeOnly });
1781
+ walk(node.typeArguments, scope, true);
1782
+ walk(node.attributes, scope, typeOnly);
1783
+ return;
1784
+ }
1785
+ case "TSQualifiedName":
1786
+ walk(node.left, scope, typeOnly);
1787
+ return;
1788
+ case "TSEnumMember":
1789
+ walk(node.initializer, scope, typeOnly);
1790
+ return;
1791
+ case "TSTypeAliasDeclaration":
1792
+ case "TSInterfaceDeclaration":
1793
+ walk(node.typeParameters, scope, true);
1794
+ walk(node.typeAnnotation ?? node.body, scope, true);
1795
+ walk(node.extends, scope, true);
1796
+ return;
1797
+ case "VariableDeclarator":
1798
+ walkPattern(node.id, scope, typeOnly);
1799
+ walk(node.init, scope, typeOnly);
1800
+ return;
1801
+ case "FunctionDeclaration":
1802
+ case "FunctionExpression":
1803
+ case "ArrowFunctionExpression": {
1804
+ const fnScope = new Scope(scope, true, node);
1805
+ scopeOf.set(node, fnScope);
1806
+ if (node.type === "FunctionExpression" && node.id) {
1807
+ fnScope.declarations.add(node.id.name);
1808
+ }
1809
+ for (const param of node.params) declarePattern(param, fnScope);
1810
+ walk(node.typeParameters, fnScope, true);
1811
+ for (const param of node.params) walkPattern(param, fnScope, typeOnly);
1812
+ walk(node.returnType, fnScope, true);
1813
+ if (node.body?.type === "BlockStatement") {
1814
+ hoistDeclarations(node.body.body, fnScope);
1815
+ walk(node.body.body, fnScope, typeOnly);
1816
+ } else {
1817
+ walk(node.body, fnScope, typeOnly);
1818
+ }
1819
+ return;
1820
+ }
1821
+ case "ClassDeclaration":
1822
+ case "ClassExpression": {
1823
+ let classScope = scope;
1824
+ if (node.type === "ClassExpression" && node.id) {
1825
+ classScope = new Scope(scope, false, node);
1826
+ classScope.declarations.add(node.id.name);
1827
+ scopeOf.set(node, classScope);
1828
+ }
1829
+ walk(node.superClass, classScope, typeOnly);
1830
+ walk(node.superTypeArguments, classScope, true);
1831
+ walk(node.typeParameters, classScope, true);
1832
+ walk(node.implements, classScope, true);
1833
+ walk(node.body, classScope, typeOnly);
1834
+ return;
1835
+ }
1836
+ case "BlockStatement":
1837
+ case "StaticBlock": {
1838
+ const blockScope = new Scope(scope, false, node);
1839
+ scopeOf.set(node, blockScope);
1840
+ hoistDeclarations(node.body, blockScope);
1841
+ walk(node.body, blockScope, typeOnly);
1842
+ return;
1843
+ }
1844
+ case "ForStatement":
1845
+ case "ForInStatement":
1846
+ case "ForOfStatement": {
1847
+ const loopScope = new Scope(scope, false, node);
1848
+ scopeOf.set(node, loopScope);
1849
+ const head = node.type === "ForStatement" ? node.init : node.left;
1850
+ if (head?.type === "VariableDeclaration") {
1851
+ hoistDeclarations([head], loopScope);
1852
+ }
1853
+ for (const key of ["init", "left", "right", "test", "update", "body"]) {
1854
+ walk(node[key], loopScope, typeOnly);
1855
+ }
1856
+ return;
1857
+ }
1858
+ case "SwitchStatement": {
1859
+ walk(node.discriminant, scope, typeOnly);
1860
+ const switchScope = new Scope(scope, false, node);
1861
+ scopeOf.set(node, switchScope);
1862
+ hoistDeclarations(
1863
+ node.cases.flatMap((c) => c.consequent),
1864
+ switchScope
1865
+ );
1866
+ for (const c of node.cases) {
1867
+ walk(c.test, switchScope, typeOnly);
1868
+ walk(c.consequent, switchScope, typeOnly);
1869
+ }
1870
+ return;
1871
+ }
1872
+ case "CatchClause": {
1873
+ const catchScope = new Scope(scope, false, node);
1874
+ scopeOf.set(node, catchScope);
1875
+ if (node.param) {
1876
+ declarePattern(node.param, catchScope);
1877
+ walkPattern(node.param, catchScope, typeOnly);
1878
+ }
1879
+ walk(node.body, catchScope, typeOnly);
1880
+ return;
1881
+ }
1882
+ }
1883
+ for (const key of Object.keys(node)) {
1884
+ if (key === "type" || key === "start" || key === "end") continue;
1885
+ walk(node[key], scope, typeOnly || TYPE_KEYS.has(key));
1886
+ }
1887
+ };
1888
+ hoistDeclarations(program.body, moduleScope);
1889
+ walk(program.body, moduleScope, false);
1890
+ return { moduleScope, references, scopeOf };
1891
+ }
1892
+ function collectImports(program) {
1893
+ const imports = /* @__PURE__ */ new Map();
1894
+ for (const statement of program.body) {
1895
+ if (statement.type !== "ImportDeclaration") continue;
1896
+ const declTypeOnly = statement.importKind === "type";
1897
+ for (const spec of statement.specifiers) {
1898
+ imports.set(spec.local.name, {
1899
+ source: statement.source.value,
1900
+ imported: spec.type === "ImportDefaultSpecifier" ? "default" : spec.type === "ImportNamespaceSpecifier" ? "*" : spec.imported.type === "Identifier" ? spec.imported.name : String(spec.imported.value),
1901
+ typeOnly: declTypeOnly || spec.importKind === "type"
1902
+ });
1903
+ }
1904
+ }
1905
+ return imports;
1906
+ }
1907
+
1908
+ // src/vite/plugins/hoist/literal.ts
1909
+ function directivePrologueEnd(program) {
1910
+ let end = 0;
1911
+ for (const statement of program.body) {
1912
+ if (statement.type !== "ExpressionStatement" || typeof statement.directive !== "string") {
1913
+ break;
1914
+ }
1915
+ end = statement.end;
1916
+ }
1917
+ return end;
1918
+ }
1919
+ function parseLang(file) {
1920
+ if (/\.[cm]?ts$/.test(file)) return "ts";
1921
+ if (/\.[cm]?jsx?$/.test(file)) return "jsx";
1922
+ return "tsx";
1923
+ }
1924
+ var EXPRESSION_WRAPPERS = /* @__PURE__ */ new Set([
1925
+ "TSAsExpression",
1926
+ "TSSatisfiesExpression",
1927
+ "TSNonNullExpression",
1928
+ "TSTypeAssertion",
1929
+ "ParenthesizedExpression"
1930
+ ]);
1931
+ function unwrapExpression(node) {
1932
+ while (node && EXPRESSION_WRAPPERS.has(node.type)) node = node.expression;
1933
+ return node;
1934
+ }
1935
+ function isFunctionLiteral(node) {
1936
+ return node?.type === "ArrowFunctionExpression" || node?.type === "FunctionExpression";
1937
+ }
1938
+ function propertyKeyIs(prop, name) {
1939
+ return prop?.type === "Property" && !prop.computed && (prop.key.type === "Identifier" && prop.key.name === name || prop.key.type === "Literal" && prop.key.value === name);
1940
+ }
1941
+ function findHelperCalls(program, scopeOf, moduleScope, imports, spec) {
1942
+ const calls = [];
1943
+ const helpers = /* @__PURE__ */ new Map();
1944
+ const sourceExport = (callee, scope) => {
1945
+ const sourceImport = (id) => {
1946
+ if (id?.type !== "Identifier") return null;
1947
+ if (scope.lookup(id.name) !== moduleScope) return null;
1948
+ const binding = imports.get(id.name);
1949
+ return binding && spec.sources.has(binding.source) && !binding.typeOnly ? binding : null;
1950
+ };
1951
+ if (callee.type === "Identifier") {
1952
+ const imported = sourceImport(callee)?.imported;
1953
+ return imported && imported !== "*" && imported !== "default" ? imported : null;
1954
+ }
1955
+ if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier" && sourceImport(callee.object)?.imported === "*") {
1956
+ return callee.property.name;
1957
+ }
1958
+ return null;
1959
+ };
1960
+ const registerBuilderCallback = (callback) => {
1961
+ const fnScope = scopeOf.get(callback);
1962
+ let param = callback.params[0];
1963
+ if (param?.type === "AssignmentPattern") param = param.left;
1964
+ if (!fnScope || !param) return;
1965
+ const bindings = { names: /* @__PURE__ */ new Set(), objects: /* @__PURE__ */ new Set() };
1966
+ if (param.type === "Identifier") bindings.objects.add(param.name);
1967
+ if (param.type === "ObjectPattern") {
1968
+ for (const prop of param.properties) {
1969
+ if (!propertyKeyIs(prop, spec.helper)) continue;
1970
+ const target = prop.value.type === "AssignmentPattern" ? prop.value.left : prop.value;
1971
+ if (target.type === "Identifier") bindings.names.add(target.name);
1972
+ }
1973
+ }
1974
+ helpers.set(fnScope, bindings);
1975
+ };
1976
+ const isHelper = (callee, scope) => {
1977
+ if (spec.directImport && sourceExport(callee, scope) === spec.helper) {
1978
+ return true;
1979
+ }
1980
+ if (callee.type === "Identifier") {
1981
+ const decl = scope.lookup(callee.name);
1982
+ return !!decl && !!helpers.get(decl)?.names.has(callee.name);
1983
+ }
1984
+ if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier" && callee.property.name === spec.helper && callee.object.type === "Identifier") {
1985
+ const decl = scope.lookup(callee.object.name);
1986
+ return !!decl && !!helpers.get(decl)?.objects.has(callee.object.name);
1987
+ }
1988
+ return false;
1989
+ };
1990
+ const visit = (node, scope) => {
1991
+ if (!node || typeof node !== "object") return;
1992
+ if (Array.isArray(node)) {
1993
+ for (const item of node) visit(item, scope);
1994
+ return;
1995
+ }
1996
+ if (typeof node.type !== "string") return;
1997
+ const own = scopeOf.get(node) ?? scope;
1998
+ if (node.type === "CallExpression") {
1999
+ const callback = node.arguments[0];
2000
+ if (isFunctionLiteral(callback) && sourceExport(node.callee, own) === spec.builder) {
2001
+ registerBuilderCallback(callback);
2002
+ }
2003
+ if (isHelper(node.callee, own)) calls.push({ call: node, scope: own });
2004
+ }
2005
+ for (const key of Object.keys(node)) {
2006
+ if (key === "type" || key === "start" || key === "end") continue;
2007
+ visit(node[key], own);
2008
+ }
2009
+ };
2010
+ visit(program.body, moduleScope);
2011
+ return calls;
2012
+ }
2013
+ function findLexicalCapture(literal, references, code, messages) {
2014
+ const ownArguments = [];
2015
+ let found = null;
2016
+ const capture = (node, what) => {
2017
+ found = {
2018
+ node,
2019
+ detail: `${messages.lexical[what]} ${messages.captureHint}`
2020
+ };
2021
+ };
2022
+ const loads = (node, expression, why) => {
2023
+ found = {
2024
+ node,
2025
+ detail: `\`${expression}\` ${why} ${messages.loadsHint}`
2026
+ };
2027
+ };
2028
+ const visit = (node, boundary) => {
2029
+ if (found || !node || typeof node !== "object") return;
2030
+ if (Array.isArray(node)) {
2031
+ for (const item of node) visit(item, boundary);
2032
+ return;
2033
+ }
2034
+ if (typeof node.type !== "string") return;
2035
+ switch (node.type) {
2036
+ case "FunctionExpression":
2037
+ case "FunctionDeclaration":
2038
+ ownArguments.push(node);
2039
+ boundary = node;
2040
+ break;
2041
+ case "ClassBody":
2042
+ boundary = node;
2043
+ break;
2044
+ case "ThisExpression":
2045
+ if (!boundary) capture(node, "this");
2046
+ return;
2047
+ case "Super":
2048
+ if (!boundary || boundary === literal) capture(node, "super");
2049
+ return;
2050
+ case "JSXMemberExpression": {
2051
+ let root = node;
2052
+ while (root.type === "JSXMemberExpression") root = root.object;
2053
+ if (root.name === "this" && !boundary) capture(root, "this");
2054
+ return;
2055
+ }
2056
+ case "MetaProperty":
2057
+ if (node.meta.name === "import") {
2058
+ loads(node, "import.meta", messages.importMetaWhy);
2059
+ } else if (!boundary) {
2060
+ capture(node, "new.target");
2061
+ }
2062
+ return;
2063
+ case "MemberExpression":
2064
+ if (node.object?.type === "MetaProperty") {
2065
+ if (node.object.meta.name !== "import") break;
2066
+ if (!node.computed && node.property.name === "env") return;
2067
+ loads(
2068
+ node,
2069
+ node.computed ? "import.meta[...]" : `import.meta.${node.property.name}`,
2070
+ messages.importMetaMemberWhy
2071
+ );
2072
+ return;
2073
+ }
2074
+ break;
2075
+ case "ImportExpression":
2076
+ loads(
2077
+ node,
2078
+ `import(${code.slice(node.source.start, node.source.end)})`,
2079
+ messages.dynamicImportWhy
2080
+ );
2081
+ return;
2082
+ }
2083
+ for (const key of Object.keys(node)) {
2084
+ if (key === "type" || key === "start" || key === "end") continue;
2085
+ if (TYPE_KEYS.has(key)) continue;
2086
+ visit(node[key], boundary);
2087
+ }
2088
+ };
2089
+ visit(literal, null);
2090
+ if (found) return found;
2091
+ for (const ref of references) {
2092
+ if (ref.typeOnly || ref.node.name !== "arguments") continue;
2093
+ if (ref.node.start < literal.start || ref.node.end > literal.end) continue;
2094
+ const owned = ownArguments.some(
2095
+ (fn) => fn.start <= ref.node.start && ref.node.end <= fn.end
2096
+ );
2097
+ if (!owned) {
2098
+ capture(ref.node, "arguments");
2099
+ return found;
2100
+ }
2101
+ }
2102
+ return null;
2103
+ }
2104
+ function collectFreeReferences(literal, references, moduleScope, imports) {
2105
+ const used = /* @__PURE__ */ new Map();
2106
+ const bindings = [];
2107
+ const globals = [];
2108
+ for (const ref of references) {
2109
+ if (ref.node.start < literal.start || ref.node.end > literal.end) continue;
2110
+ const decl = ref.scope.lookup(ref.node.name);
2111
+ if (!decl) {
2112
+ if (!ref.typeOnly) globals.push(ref);
2113
+ continue;
2114
+ }
2115
+ if (decl.node.start >= literal.start && decl.node.end <= literal.end && decl !== moduleScope) {
2116
+ continue;
2117
+ }
2118
+ if (decl === moduleScope && imports.has(ref.node.name)) {
2119
+ const valueUse = !ref.typeOnly && !imports.get(ref.node.name).typeOnly;
2120
+ used.set(ref.node.name, (used.get(ref.node.name) ?? false) || valueUse);
2121
+ continue;
2122
+ }
2123
+ if (ref.typeOnly) continue;
2124
+ bindings.push(ref);
2125
+ }
2126
+ return { imports: used, bindings, globals };
2127
+ }
2128
+ async function emitImports(used, imports, checkValueImport) {
2129
+ const bySource = /* @__PURE__ */ new Map();
2130
+ for (const [local, valueUse] of used) {
2131
+ const binding = imports.get(local);
2132
+ if (valueUse) await checkValueImport(local, binding);
2133
+ const lines = bySource.get(binding.source) ?? [];
2134
+ const typePrefix = valueUse ? "" : "type ";
2135
+ if (binding.imported === "*") {
2136
+ lines.push(
2137
+ `import ${typePrefix}* as ${local} from ${JSON.stringify(binding.source)};`
2138
+ );
2139
+ } else if (binding.imported === "default") {
2140
+ lines.push(
2141
+ `import ${typePrefix}${local} from ${JSON.stringify(binding.source)};`
2142
+ );
2143
+ } else {
2144
+ const spec = binding.imported === local ? local : `${JSON.stringify(binding.imported)} as ${local}`;
2145
+ lines.push(
2146
+ `import ${typePrefix}{ ${spec} } from ${JSON.stringify(binding.source)};`
2147
+ );
2148
+ }
2149
+ bySource.set(binding.source, lines);
2150
+ }
2151
+ return [...bySource.values()].flat();
2152
+ }
2153
+
2154
+ // src/vite/discovery/client-urls-projection.ts
2155
+ var debug2 = createRangoDebugger(NS.discovery);
2156
+ var CLIENT_URLS_REVALIDATE_QUERY = "rango-revalidate";
2157
+ function hoistedRevalidateId(file) {
2158
+ return `${file}?${CLIENT_URLS_REVALIDATE_QUERY}`;
2159
+ }
2160
+ function hasDefaultExport(code) {
2161
+ let program;
2162
+ try {
2163
+ program = parseAst2(code, { lang: "tsx" });
2164
+ } catch {
2165
+ return false;
2166
+ }
2167
+ for (const node of program.body ?? []) {
2168
+ if (node?.type === "ExportDefaultDeclaration") return true;
2169
+ if (node?.type !== "ExportNamedDeclaration") continue;
2170
+ for (const specifier of node.specifiers ?? []) {
2171
+ const exportedName = specifier?.exported?.name ?? specifier?.exported?.value;
2172
+ if (exportedName === "default") return true;
2173
+ }
2174
+ }
2175
+ return false;
2176
+ }
2177
+ function normalizeSource(state, id) {
2178
+ const cleanId = id.split("?", 1)[0];
2179
+ const absoluteId = isAbsolute(cleanId) ? cleanId : resolve(state.projectRoot, cleanId);
2180
+ return normalizePath(absoluteId);
2181
+ }
2182
+ function referenceId(referenceKey) {
2183
+ return `${referenceKey}#default`;
2184
+ }
2185
+ function withoutReferenceQuery(reference) {
2186
+ const exportIndex = reference.lastIndexOf("#");
2187
+ const moduleId = exportIndex === -1 ? reference : reference.slice(0, exportIndex);
2188
+ const exportName = exportIndex === -1 ? "" : reference.slice(exportIndex);
2189
+ const queryIndex = moduleId.indexOf("?");
2190
+ return `${queryIndex === -1 ? moduleId : moduleId.slice(0, queryIndex)}${exportName}`;
2191
+ }
2192
+ function recordClientUrlsModule(state, code, id) {
2193
+ if (!code.includes("clientUrls(") || !hasUseClientDirective(code) || !hasDefaultExport(code)) {
2194
+ return;
2195
+ }
2196
+ const source = normalizeSource(state, id);
2197
+ const projectRoot = normalizePath(resolve(state.projectRoot));
2198
+ const relativeId = normalizePath(relative2(projectRoot, source));
2199
+ const outsideProject = relativeId === ".." || relativeId.startsWith("../") || isAbsolute(relativeId);
2200
+ const devReferenceKey = outsideProject ? `/@fs${source}` : `/${relativeId}`;
2201
+ const sourceByReferenceId = state.clientUrlSourceByReferenceId ??= /* @__PURE__ */ new Map();
2202
+ sourceByReferenceId.set(referenceId(devReferenceKey), source);
2203
+ const productionReferenceKeys = /* @__PURE__ */ new Set([
2204
+ hashRefKey(relativeId),
2205
+ computeProductionHash(projectRoot, devReferenceKey)
2206
+ ]);
2207
+ for (const productionReferenceKey of productionReferenceKeys) {
2208
+ sourceByReferenceId.set(referenceId(productionReferenceKey), source);
2209
+ }
2210
+ }
2211
+ var CLIENT_IMPORT_RE = /["']@rangojs\/router\/client["']/;
2212
+ function isClientUrlsComponentUseSource(source) {
2213
+ return source.includes(".use") && CLIENT_IMPORT_RE.test(source) && firstCodeMatchIndex(source, /\.use\s*=(?!=)/g) >= 0;
2214
+ }
2215
+ function componentUseSignature(source, file) {
2216
+ if (!isClientUrlsComponentUseSource(source)) return void 0;
2217
+ const hash = createHash2("sha256");
2218
+ let program;
2219
+ try {
2220
+ program = parseAst2(source, { lang: parseLang(file) });
2221
+ } catch {
2222
+ return hash.update(source).digest("base64");
2223
+ }
2224
+ const visit = (node) => {
2225
+ if (typeof node !== "object" || node === null) return;
2226
+ if (Array.isArray(node)) {
2227
+ for (const child of node) visit(child);
2228
+ return;
2229
+ }
2230
+ const { type, left } = node;
2231
+ if (type === "AssignmentExpression" && left.type === "MemberExpression" && !left.computed && left.property.type === "Identifier" && left.property.name === "use") {
2232
+ const { start, end } = node;
2233
+ hash.update(source.slice(start, end)).update("\0");
2234
+ return;
2235
+ }
2236
+ for (const value of Object.values(node)) visit(value);
2237
+ };
2238
+ visit(program.body);
2239
+ return hash.digest("base64");
2240
+ }
2241
+ function resolveClientUrlsSource(state, referenceId2) {
2242
+ return state.clientUrlSourceByReferenceId?.get(
2243
+ withoutReferenceQuery(referenceId2)
2244
+ );
2245
+ }
2246
+ function scanForClientUrlModules(state) {
2247
+ if (!state.projectRoot) return;
2248
+ for (const filePath of findTsFiles(state.projectRoot, state.scanFilter)) {
2249
+ let code;
2250
+ try {
2251
+ code = readFileSync(filePath, "utf-8");
2252
+ } catch {
2253
+ continue;
2254
+ }
2255
+ recordClientUrlsModule(state, code, filePath);
2256
+ }
2257
+ }
2258
+ function projectionError2(referenceId2, source, message, cause) {
2259
+ const sourceDescription = source ? ` from source "${source}"` : "";
2260
+ const errorMessage = `Cannot discover client URL projection for reference "${referenceId2}"${sourceDescription}: ${message}`;
2261
+ return cause === void 0 ? new Error(errorMessage) : new Error(errorMessage, { cause });
2262
+ }
2263
+ async function refreshRecordedClientUrlProjections(state, ssrEnv, serverMod, rscEnv) {
2264
+ const sourceByReferenceId = state.clientUrlSourceByReferenceId;
2265
+ if (!sourceByReferenceId?.size || typeof ssrEnv?.runner?.import !== "function") {
2266
+ return;
2267
+ }
2268
+ const referenceIdsBySource = /* @__PURE__ */ new Map();
2269
+ for (const [refId, source] of sourceByReferenceId) {
2270
+ const ids = referenceIdsBySource.get(source);
2271
+ if (ids) {
2272
+ ids.push(refId);
2273
+ } else {
2274
+ referenceIdsBySource.set(source, [refId]);
2275
+ }
2276
+ }
2277
+ const refreshed = /* @__PURE__ */ new Map();
2278
+ for (const [source, referenceIds] of referenceIdsBySource) {
2279
+ let module;
2280
+ try {
2281
+ module = await ssrEnv.runner.import(source);
2282
+ } catch {
2283
+ continue;
2284
+ }
2285
+ let projection;
2286
+ try {
2287
+ projection = projectClientUrlsModule(module, { hoisted: true });
2288
+ } catch {
2289
+ continue;
2290
+ }
2291
+ if (!projection) continue;
2292
+ debug2?.(
2293
+ "pre-entry refresh %s -> [%s]",
2294
+ source,
2295
+ projection.routes.map((route2) => route2.pattern).join(", ")
2296
+ );
2297
+ for (const referenceId2 of referenceIds) {
2298
+ refreshed.set(referenceId2, projection);
2299
+ }
2300
+ }
2301
+ if (refreshed.size === 0) return;
2302
+ try {
2303
+ await installClientUrlProjections(
2304
+ state,
2305
+ rscEnv,
2306
+ serverMod,
2307
+ refreshed,
2308
+ false
2309
+ );
2310
+ } catch (error) {
2311
+ debug2?.(
2312
+ "pre-entry refresh: predicate registrations failed to load: %s",
2313
+ error instanceof Error ? error.message : String(error)
2314
+ );
2315
+ }
2316
+ }
2317
+ async function discoverClientUrlProjections(state, ssrEnv, serverMod, rscEnv) {
2318
+ scanForClientUrlModules(state);
2319
+ const sourceByReferenceId = state.clientUrlSourceByReferenceId;
2320
+ if (!sourceByReferenceId?.size) {
2321
+ await installClientUrlProjections(
2322
+ state,
2323
+ rscEnv,
2324
+ serverMod,
2325
+ /* @__PURE__ */ new Map(),
2326
+ true
2327
+ );
2328
+ return;
2329
+ }
2330
+ const referenceIdsBySource = /* @__PURE__ */ new Map();
2331
+ for (const [referenceId2, source] of sourceByReferenceId) {
2332
+ const ids = referenceIdsBySource.get(source);
2333
+ if (ids) {
2334
+ ids.push(referenceId2);
2335
+ } else {
2336
+ referenceIdsBySource.set(source, [referenceId2]);
2337
+ }
2338
+ }
2339
+ if (typeof ssrEnv?.runner?.import !== "function") {
2340
+ const [source, ids] = referenceIdsBySource.entries().next().value;
2341
+ throw projectionError2(
2342
+ ids[0],
2343
+ source,
2344
+ "the SSR module runner is unavailable"
2345
+ );
2346
+ }
2347
+ const nextProjections = /* @__PURE__ */ new Map();
2348
+ const removedSources = [];
2349
+ for (const [source, referenceIds] of referenceIdsBySource) {
2350
+ let module;
2351
+ try {
2352
+ module = await ssrEnv.runner.import(source);
2353
+ } catch (cause) {
2354
+ if (!existsSync(source)) {
2355
+ removedSources.push(source);
2356
+ continue;
2357
+ }
2358
+ throw projectionError2(
2359
+ referenceIds[0],
2360
+ source,
2361
+ "failed to import the source module",
2362
+ cause
2363
+ );
2364
+ }
2365
+ let projection;
2366
+ try {
2367
+ projection = projectClientUrlsModule(module, { hoisted: true });
2368
+ } catch (cause) {
2369
+ throw projectionError2(
2370
+ referenceIds[0],
2371
+ source,
2372
+ cause instanceof Error ? cause.message : String(cause),
2373
+ cause
2374
+ );
2375
+ }
2376
+ if (!projection) {
2377
+ throw projectionError2(
2378
+ referenceIds[0],
2379
+ source,
2380
+ 'the module default export must be created by clientUrls() and have __brand === "client-urls"'
2381
+ );
2382
+ }
2383
+ for (const referenceId2 of referenceIds) {
2384
+ nextProjections.set(referenceId2, projection);
2385
+ }
2386
+ }
2387
+ for (const source of removedSources) {
2388
+ for (const [referenceId2, recorded] of sourceByReferenceId) {
2389
+ if (recorded === source) sourceByReferenceId.delete(referenceId2);
2390
+ }
2391
+ }
2392
+ await installClientUrlProjections(
2393
+ state,
2394
+ rscEnv,
2395
+ serverMod,
2396
+ nextProjections,
2397
+ true
2398
+ );
2399
+ }
2400
+ async function installClientUrlProjections(state, rscEnv, serverMod, projections, replace) {
2401
+ const next = new Map(replace ? void 0 : state.clientUrlProjectionMap);
2402
+ for (const [id, projection] of projections) next.set(id, projection);
2403
+ await assignClientUrlRevalidateFiles(state, rscEnv, next);
2404
+ if (replace) serverMod.clearClientUrlProjections();
2405
+ for (const [id, projection] of projections) {
2406
+ serverMod.setClientUrlProjection(id, projection);
2407
+ }
2408
+ state.clientUrlProjectionMap = next;
2409
+ }
2410
+ async function assignClientUrlRevalidateFiles(state, rscEnv, projections) {
2411
+ const { fileByKey, filesByGroup } = state.clientUrlRevalidate;
2412
+ const next = /* @__PURE__ */ new Map();
2413
+ for (const [referenceId2, projection] of projections) {
2414
+ const group = state.clientUrlSourceByReferenceId?.get(referenceId2);
2415
+ if (group === void 0 || next.has(group)) continue;
2416
+ const files = /* @__PURE__ */ new Set();
2417
+ for (const owner of [
2418
+ ...projection.routes,
2419
+ ...projection.intercepts ?? []
2420
+ ]) {
2421
+ for (const key of owner.loaderRevalidate?.flat() ?? []) {
2422
+ const file = typeof key === "string" ? fileByKey.get(key) : void 0;
2423
+ if (file !== void 0 && file !== group) files.add(file);
2424
+ }
2425
+ }
2426
+ next.set(group, [...files].sort());
2427
+ }
2428
+ await Promise.all(
2429
+ [...new Set([...next.values()].flat())].map(
2430
+ (file) => rscEnv.runner.import(hoistedRevalidateId(file))
2431
+ )
2432
+ );
2433
+ const graph = rscEnv.moduleGraph;
2434
+ for (const [group, files] of next) {
2435
+ if ((filesByGroup.get(group) ?? []).join("\0") === files.join("\0")) {
2436
+ continue;
2437
+ }
2438
+ const mod = graph?.getModuleById(hoistedRevalidateId(group));
2439
+ if (graph && mod) graph.invalidateModule(mod);
2440
+ }
2441
+ filesByGroup.clear();
2442
+ for (const [group, files] of next) filesByGroup.set(group, files);
2443
+ }
2444
+
2445
+ export {
2446
+ hasUseClientDirective,
2447
+ NS,
2448
+ createRangoDebugger,
2449
+ createCounter,
2450
+ computeProductionHash,
2451
+ hashClientRefs,
2452
+ TransitionWhenError,
2453
+ HOISTED_REVALIDATE_KEY,
2454
+ TYPE_KEYS,
2455
+ analyzeScopes,
2456
+ collectImports,
2457
+ directivePrologueEnd,
2458
+ parseLang,
2459
+ unwrapExpression,
2460
+ isFunctionLiteral,
2461
+ propertyKeyIs,
2462
+ findHelperCalls,
2463
+ findLexicalCapture,
2464
+ collectFreeReferences,
2465
+ emitImports,
2466
+ CLIENT_URLS_REVALIDATE_QUERY,
2467
+ hoistedRevalidateId,
2468
+ recordClientUrlsModule,
2469
+ CLIENT_IMPORT_RE,
2470
+ isClientUrlsComponentUseSource,
2471
+ componentUseSignature,
2472
+ resolveClientUrlsSource,
2473
+ scanForClientUrlModules,
2474
+ refreshRecordedClientUrlProjections,
2475
+ discoverClientUrlProjections,
2476
+ assignClientUrlRevalidateFiles
2477
+ };