@rangojs/router 0.31.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 (192) 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 -10143
  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/history-state.d.ts +13 -2
  19. package/dist/types/browser/invalidate-client-cache.d.ts +8 -6
  20. package/dist/types/browser/navigation-bridge.d.ts +36 -1
  21. package/dist/types/browser/navigation-client.d.ts +19 -0
  22. package/dist/types/browser/navigation-store-handle.d.ts +37 -4
  23. package/dist/types/browser/navigation-store.d.ts +2 -2
  24. package/dist/types/browser/navigation-transaction.d.ts +0 -1
  25. package/dist/types/browser/partial-update.d.ts +13 -0
  26. package/dist/types/browser/prefetch/cache.d.ts +96 -8
  27. package/dist/types/browser/prefetch/fetch.d.ts +26 -2
  28. package/dist/types/browser/prefetch/queue.d.ts +3 -2
  29. package/dist/types/browser/rango-state.d.ts +34 -5
  30. package/dist/types/browser/react/Link.d.ts +19 -13
  31. package/dist/types/browser/react/location-state-shared.d.ts +2 -1
  32. package/dist/types/browser/types.d.ts +25 -0
  33. package/dist/types/build/generate-route-types.d.ts +1 -1
  34. package/dist/types/build/route-types/include-resolution.d.ts +9 -1
  35. package/dist/types/build/route-types/router-processing.d.ts +3 -1
  36. package/dist/types/cache/cache-key-utils.d.ts +12 -8
  37. package/dist/types/cache/cache-scope.d.ts +4 -2
  38. package/dist/types/cache/cf/cf-cache-types.d.ts +9 -5
  39. package/dist/types/cache/document-cache-policy.d.ts +9 -1
  40. package/dist/types/cache/memory-segment-store.d.ts +3 -2
  41. package/dist/types/cache/segment-codec.d.ts +2 -2
  42. package/dist/types/cache/shell-snapshot.d.ts +1 -1
  43. package/dist/types/cache/types.d.ts +12 -7
  44. package/dist/types/cache/vercel/vercel-cache-store.d.ts +2 -1
  45. package/dist/types/client-urls/types.d.ts +7 -5
  46. package/dist/types/prefetch-markers.d.ts +9 -0
  47. package/dist/types/prefetch-source-scope.d.ts +66 -0
  48. package/dist/types/route-definition/helpers-types.d.ts +8 -5
  49. package/dist/types/route-definition/redirect.d.ts +5 -0
  50. package/dist/types/router/intercept-resolution.d.ts +25 -11
  51. package/dist/types/router/match-context.d.ts +1 -0
  52. package/dist/types/router/match-handlers.d.ts +1 -1
  53. package/dist/types/router/middleware-types.d.ts +6 -0
  54. package/dist/types/router/prefetch-cache-ttl.d.ts +11 -3
  55. package/dist/types/router/router-context.d.ts +1 -1
  56. package/dist/types/router/router-options.d.ts +6 -3
  57. package/dist/types/router/segment-resolution/loader-cache.d.ts +8 -0
  58. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +23 -7
  59. package/dist/types/router/segment-resolution/revalidation.d.ts +19 -0
  60. package/dist/types/router/source-reads.d.ts +53 -0
  61. package/dist/types/router/types.d.ts +1 -1
  62. package/dist/types/rsc/helpers.d.ts +8 -3
  63. package/dist/types/rsc/prefetch-render-error.d.ts +7 -2
  64. package/dist/types/rsc/request-stages.d.ts +4 -0
  65. package/dist/types/rsc/shell-serve.d.ts +6 -1
  66. package/dist/types/server/context.d.ts +23 -6
  67. package/dist/types/server/cookie-store.d.ts +15 -1
  68. package/dist/types/server/document-location-state.d.ts +59 -0
  69. package/dist/types/server/handle-store.d.ts +2 -0
  70. package/dist/types/server/request-context.d.ts +65 -12
  71. package/dist/types/testing/e2e/server.d.ts +16 -1
  72. package/dist/types/testing/render-route.d.ts +83 -2
  73. package/dist/types/testing/serve-shell-request.d.ts +15 -3
  74. package/dist/types/types/handler-context.d.ts +21 -4
  75. package/dist/types/types/loader-types.d.ts +7 -4
  76. package/dist/types/types/segments.d.ts +18 -1
  77. package/dist/types/urls/path-helper-types.d.ts +7 -5
  78. package/dist/types/vite/temp-rsc-server.d.ts +2 -2
  79. package/dist/types/vite/utils/forward-user-plugins.d.ts +32 -2
  80. package/dist/vite/index.js +451 -191
  81. package/package.json +2 -2
  82. package/skills/app-structure/SKILL.md +74 -0
  83. package/skills/app-structure/e-commerce.md +10 -9
  84. package/skills/app-structure/large-app.md +15 -2
  85. package/skills/caching/SKILL.md +10 -5
  86. package/skills/client-urls/SKILL.md +18 -11
  87. package/skills/comparison/references/framework-comparison.md +16 -10
  88. package/skills/document-cache/SKILL.md +13 -0
  89. package/skills/hooks/navigation.md +8 -8
  90. package/skills/hooks/state.md +132 -12
  91. package/skills/intercept/SKILL.md +33 -11
  92. package/skills/layout/SKILL.md +11 -0
  93. package/skills/links/SKILL.md +101 -4
  94. package/skills/loader/SKILL.md +49 -22
  95. package/skills/migrate-nextjs/SKILL.md +8 -2
  96. package/skills/migrate-react-router/data-and-actions.md +5 -0
  97. package/skills/ppr/SKILL.md +38 -5
  98. package/skills/prerender/SKILL.md +4 -1
  99. package/skills/route/SKILL.md +6 -6
  100. package/skills/router-setup/SKILL.md +2 -1
  101. package/skills/server-actions/SKILL.md +49 -8
  102. package/skills/testing/client-components.md +73 -32
  103. package/skills/testing/serve-shell-request.md +45 -20
  104. package/skills/testing/server-actions.md +8 -0
  105. package/skills/ux-architecture/SKILL.md +67 -15
  106. package/src/bin/rango.ts +39 -13
  107. package/src/browser/action-fence.ts +72 -0
  108. package/src/browser/cookie-name.ts +82 -14
  109. package/src/browser/history-state.ts +24 -2
  110. package/src/browser/invalidate-client-cache.ts +9 -7
  111. package/src/browser/navigation-bridge.ts +164 -32
  112. package/src/browser/navigation-client.ts +95 -20
  113. package/src/browser/navigation-store-handle.ts +67 -5
  114. package/src/browser/navigation-store.ts +86 -17
  115. package/src/browser/navigation-transaction.ts +0 -6
  116. package/src/browser/partial-update.ts +31 -12
  117. package/src/browser/prefetch/cache.ts +188 -11
  118. package/src/browser/prefetch/fetch.ts +211 -51
  119. package/src/browser/prefetch/queue.ts +3 -2
  120. package/src/browser/rango-state.ts +50 -8
  121. package/src/browser/react/Link.tsx +24 -16
  122. package/src/browser/react/location-state-shared.ts +8 -1
  123. package/src/browser/react/use-navigation.ts +1 -1
  124. package/src/browser/rsc-router.tsx +13 -3
  125. package/src/browser/server-action-bridge.ts +3 -3
  126. package/src/browser/types.ts +25 -0
  127. package/src/build/generate-route-types.ts +1 -0
  128. package/src/build/route-types/include-resolution.ts +40 -3
  129. package/src/build/route-types/router-processing.ts +170 -25
  130. package/src/build/route-types/scan-filter.ts +1 -0
  131. package/src/build/runtime-discovery.ts +46 -8
  132. package/src/cache/cache-key-utils.ts +12 -8
  133. package/src/cache/cache-runtime.ts +5 -1
  134. package/src/cache/cache-scope.ts +28 -7
  135. package/src/cache/cf/cf-cache-types.ts +9 -5
  136. package/src/cache/document-cache-policy.ts +37 -1
  137. package/src/cache/document-cache.ts +12 -0
  138. package/src/cache/memory-segment-store.ts +3 -2
  139. package/src/cache/segment-codec.ts +2 -2
  140. package/src/cache/shell-snapshot.ts +1 -1
  141. package/src/cache/types.ts +12 -7
  142. package/src/cache/vercel/vercel-cache-store.ts +2 -1
  143. package/src/client-urls/types.ts +7 -5
  144. package/src/prefetch-markers.ts +10 -0
  145. package/src/prefetch-source-scope.ts +137 -0
  146. package/src/route-definition/helpers-types.ts +8 -5
  147. package/src/route-definition/redirect.ts +5 -0
  148. package/src/router/intercept-resolution.ts +94 -50
  149. package/src/router/loader-resolution.ts +8 -6
  150. package/src/router/match-api.ts +33 -29
  151. package/src/router/match-context.ts +5 -0
  152. package/src/router/match-handlers.ts +2 -1
  153. package/src/router/match-middleware/cache-lookup.ts +39 -14
  154. package/src/router/match-result.ts +45 -85
  155. package/src/router/middleware-types.ts +6 -0
  156. package/src/router/navigation-snapshot.ts +18 -3
  157. package/src/router/prefetch-cache-ttl.ts +15 -3
  158. package/src/router/revalidation.ts +63 -13
  159. package/src/router/router-context.ts +2 -1
  160. package/src/router/router-options.ts +6 -3
  161. package/src/router/segment-resolution/loader-cache.ts +21 -3
  162. package/src/router/segment-resolution/prefetch-deferral.ts +38 -31
  163. package/src/router/segment-resolution/revalidation.ts +40 -12
  164. package/src/router/source-reads.ts +122 -0
  165. package/src/router/types.ts +2 -1
  166. package/src/router.ts +11 -12
  167. package/src/rsc/helpers.ts +20 -6
  168. package/src/rsc/prefetch-render-error.ts +7 -2
  169. package/src/rsc/progressive-enhancement.ts +8 -2
  170. package/src/rsc/request-stages.ts +87 -1
  171. package/src/rsc/rsc-rendering.ts +78 -32
  172. package/src/rsc/server-action.ts +2 -1
  173. package/src/rsc/shell-capture.ts +4 -5
  174. package/src/rsc/shell-serve.ts +12 -1
  175. package/src/segment-system.tsx +1 -1
  176. package/src/server/context.ts +37 -6
  177. package/src/server/cookie-store.ts +22 -1
  178. package/src/server/document-location-state.ts +334 -0
  179. package/src/server/handle-store.ts +2 -0
  180. package/src/server/request-context.ts +137 -33
  181. package/src/testing/dispatch.ts +6 -0
  182. package/src/testing/e2e/fixture.ts +4 -12
  183. package/src/testing/e2e/server.ts +91 -4
  184. package/src/testing/render-route.tsx +309 -10
  185. package/src/testing/run-revalidate.ts +11 -1
  186. package/src/testing/serve-shell-request.ts +22 -3
  187. package/src/types/handler-context.ts +21 -4
  188. package/src/types/loader-types.ts +7 -4
  189. package/src/types/segments.ts +18 -1
  190. package/src/urls/path-helper-types.ts +7 -5
  191. package/src/vite/temp-rsc-server.ts +2 -2
  192. package/src/vite/utils/forward-user-plugins.ts +13 -5
@@ -138,11 +138,11 @@ var init_logging = __esm({
138
138
  // src/browser/notify-listeners.ts
139
139
  function notifyListeners(entries, notify, isActive, shouldContinue) {
140
140
  const errors = [];
141
- for (const entry of entries) {
141
+ for (const entry2 of entries) {
142
142
  if (shouldContinue && !shouldContinue()) break;
143
- if (isActive && !isActive(entry)) continue;
143
+ if (isActive && !isActive(entry2)) continue;
144
144
  try {
145
- notify(entry);
145
+ notify(entry2);
146
146
  } catch (error) {
147
147
  errors.push(error);
148
148
  }
@@ -179,21 +179,36 @@ function getRawCookieValue(cookieString, name) {
179
179
  }
180
180
  return null;
181
181
  }
182
- function encodeStateValue(version, timestamp) {
183
- return `${encodeURIComponent(version)}:${timestamp}`;
182
+ function encodeStateValue(version, timestamp, write = 0) {
183
+ const base = `${encodeURIComponent(version)}:${timestamp}`;
184
+ return write === 0 ? base : `${base}:${write}`;
184
185
  }
185
186
  function decodeStateValue(raw) {
186
187
  const colon = raw.indexOf(":");
187
188
  if (colon <= 0) return null;
188
- const timestamp = Number(raw.slice(colon + 1));
189
- if (!Number.isFinite(timestamp)) return null;
189
+ const parts = raw.slice(colon + 1).split(":");
190
+ if (parts.length > 2) return null;
191
+ const timestamp = parseStatePart(parts[0]);
192
+ const write = parts.length === 2 ? parseStatePart(parts[1]) : 0;
193
+ if (timestamp === null || write === null) return null;
190
194
  let version;
191
195
  try {
192
196
  version = decodeURIComponent(raw.slice(0, colon));
193
197
  } catch {
194
198
  return null;
195
199
  }
196
- return { version, timestamp };
200
+ return { version, timestamp, write };
201
+ }
202
+ function parseStatePart(part) {
203
+ if (part === "") return null;
204
+ const value = Number(part);
205
+ return Number.isFinite(value) ? value : null;
206
+ }
207
+ function stateEpoch(raw) {
208
+ const first = raw.indexOf(":");
209
+ if (first < 0) return raw;
210
+ const second = raw.indexOf(":", first + 1);
211
+ return second < 0 ? raw : raw.slice(0, second);
197
212
  }
198
213
  function mintStateValue(version, prevRaw) {
199
214
  const prevTs = prevRaw ? decodeStateValue(prevRaw)?.timestamp ?? 0 : 0;
@@ -246,9 +261,11 @@ function getRangoState() {
246
261
  }
247
262
  if (read.value !== null) {
248
263
  if (read.value !== mirror) {
264
+ const rotated = mirror === null || stateEpoch(mirror) !== stateEpoch(read.value);
249
265
  mirror = read.value;
250
266
  cookieBacked = true;
251
- notifyExternalRotation(read.value);
267
+ if (rotated) notifyExternalRotation(read.value);
268
+ else externalWriteObserver?.();
252
269
  } else {
253
270
  cookieBacked = true;
254
271
  }
@@ -265,7 +282,7 @@ function getRangoState() {
265
282
  }
266
283
  return mirror;
267
284
  }
268
- var cookieName, currentVersion, mirror, cookieBacked, externalRotationObserver;
285
+ var cookieName, currentVersion, mirror, cookieBacked, externalRotationObserver, externalWriteObserver;
269
286
  var init_rango_state = __esm({
270
287
  "src/browser/rango-state.ts"() {
271
288
  "use strict";
@@ -275,6 +292,7 @@ var init_rango_state = __esm({
275
292
  mirror = null;
276
293
  cookieBacked = false;
277
294
  externalRotationObserver = null;
295
+ externalWriteObserver = null;
278
296
  }
279
297
  });
280
298
 
@@ -318,6 +336,52 @@ var init_wire_params = __esm({
318
336
  }
319
337
  });
320
338
 
339
+ // src/prefetch-source-scope.ts
340
+ function formatSourceLabel(shape, page) {
341
+ const parts = [];
342
+ if (shape.keys) {
343
+ parts.push(
344
+ "$k=" + Object.keys(page.params).sort().map(encodeURIComponent).join(",")
345
+ );
346
+ }
347
+ if (shape.route) parts.push(entry("$r", page.routeName));
348
+ for (const name of shape.names) {
349
+ parts.push(entry(encodeURIComponent(name), page.params[name]));
350
+ }
351
+ return parts.join("&");
352
+ }
353
+ function entry(name, value) {
354
+ return value === void 0 ? name : name + "=" + encodeURIComponent(value);
355
+ }
356
+ function paramsScopeLabel(header) {
357
+ if (!header?.startsWith(PARAMS_SCOPE_PREFIX)) return void 0;
358
+ return header.slice(PARAMS_SCOPE_PREFIX.length);
359
+ }
360
+ function parseSourceShape(label) {
361
+ let keys = false;
362
+ let route2 = false;
363
+ const names = [];
364
+ for (const part of label.split("&")) {
365
+ if (part === "") continue;
366
+ const eq = part.indexOf("=");
367
+ const name = eq === -1 ? part : part.slice(0, eq);
368
+ if (name === "$k") keys = true;
369
+ else if (name === "$r") route2 = true;
370
+ else names.push(decodeURIComponent(name));
371
+ }
372
+ return { keys, route: route2, names: names.sort() };
373
+ }
374
+ function sourceShapeId(shape) {
375
+ return (shape.keys ? "k" : "") + (shape.route ? "r" : "") + ":" + shape.names.map(encodeURIComponent).join(",");
376
+ }
377
+ var PARAMS_SCOPE_PREFIX;
378
+ var init_prefetch_source_scope = __esm({
379
+ "src/prefetch-source-scope.ts"() {
380
+ "use strict";
381
+ PARAMS_SCOPE_PREFIX = "params; ";
382
+ }
383
+ });
384
+
321
385
  // src/browser/prefetch/cache.ts
322
386
  function isPrefetchCacheDisabled() {
323
387
  return cacheTTL <= 0;
@@ -330,6 +394,31 @@ function buildPrefetchKey(prefix, targetUrl) {
330
394
  function buildSourceKey(rangoState, sourceHref, targetUrl) {
331
395
  return rangoState + "\0" + sourceHref + "\0" + targetUrl.pathname + targetUrl.search;
332
396
  }
397
+ function buildParamsKey(rangoState, label, targetUrl) {
398
+ return buildPrefetchKey(rangoState + "\0p:" + label, targetUrl);
399
+ }
400
+ function rememberParamsShape(targetUrl, label) {
401
+ const target = buildPrefetchKey("", targetUrl);
402
+ const shape = parseSourceShape(label);
403
+ let shapes = paramsShapes.get(target);
404
+ if (!shapes) {
405
+ if (paramsShapes.size >= maxPrefetchCacheSize) {
406
+ const oldest = paramsShapes.keys().next().value;
407
+ if (oldest !== void 0) paramsShapes.delete(oldest);
408
+ }
409
+ shapes = /* @__PURE__ */ new Map();
410
+ paramsShapes.set(target, shapes);
411
+ }
412
+ shapes.set(sourceShapeId(shape), shape);
413
+ }
414
+ function paramsCandidateKeys(rangoState, targetUrl, page) {
415
+ if (!page) return [];
416
+ const shapes = paramsShapes.get(buildPrefetchKey("", targetUrl));
417
+ if (!shapes) return [];
418
+ return [...shapes.values()].sort((a, b) => weightOf(b) - weightOf(a)).map(
419
+ (shape) => buildParamsKey(rangoState, formatSourceLabel(shape, page), targetUrl)
420
+ );
421
+ }
333
422
  function forEachAlias(key, fn) {
334
423
  const aliases = inflightAliases.get(key);
335
424
  if (aliases) {
@@ -341,20 +430,20 @@ function forEachAlias(key, fn) {
341
430
  function hasPrefetch(key) {
342
431
  if (inflight.has(key)) return true;
343
432
  if (cacheTTL <= 0) return false;
344
- const entry = cache.get(key);
345
- if (!entry) return false;
346
- if (Date.now() - entry.timestamp > cacheTTL) {
347
- entry.entry.dispose?.();
433
+ const entry2 = cache.get(key);
434
+ if (!entry2) return false;
435
+ if (Date.now() - entry2.timestamp > cacheTTL || isPrefetchStale(entry2.entry)) {
436
+ entry2.entry.dispose?.();
348
437
  cache.delete(key);
349
438
  return false;
350
439
  }
351
440
  return true;
352
441
  }
353
- function storePrefetch(key, entry, fetchGeneration) {
442
+ function storePrefetch(key, entry2, fetchGeneration, inflightKey = key) {
354
443
  if (cacheTTL <= 0) return;
355
444
  if (fetchGeneration !== generation) return;
356
- if (adoptedKeys.has(key)) {
357
- forEachAlias(key, (k) => adoptedKeys.delete(k));
445
+ if (adoptedKeys.has(inflightKey)) {
446
+ forEachAlias(inflightKey, (k) => adoptedKeys.delete(k));
358
447
  return;
359
448
  }
360
449
  const now = Date.now();
@@ -377,18 +466,24 @@ function storePrefetch(key, entry, fetchGeneration) {
377
466
  cache.delete(oldest);
378
467
  }
379
468
  }
380
- cache.set(key, { entry, timestamp: now });
469
+ cache.set(key, { entry: entry2, timestamp: now });
381
470
  if (now < earliestTimestamp) earliestTimestamp = now;
382
471
  }
383
- function removePrefetch(key, entry) {
384
- if (cache.get(key)?.entry === entry) {
385
- entry.dispose?.();
472
+ function removePrefetch(key, entry2) {
473
+ if (cache.get(key)?.entry === entry2) {
474
+ entry2.dispose?.();
386
475
  cache.delete(key);
387
476
  }
388
477
  }
389
478
  function currentGeneration() {
390
479
  return generation;
391
480
  }
481
+ function currentPrefetchEpoch() {
482
+ return staleEpoch;
483
+ }
484
+ function isPrefetchStale(entry2) {
485
+ return entry2.epoch < staleEpoch;
486
+ }
392
487
  function markPrefetchInflight(key) {
393
488
  inflight.add(key);
394
489
  }
@@ -409,7 +504,7 @@ function clearPrefetchInflight(key) {
409
504
  function isFragmentPassthroughEnabled() {
410
505
  return fragmentPassthroughEnabled;
411
506
  }
412
- var cacheTTL, fragmentPassthroughEnabled, maxPrefetchCacheSize, cache, inflight, earliestTimestamp, inflightPromises, inflightAliases, adoptedKeys, generation;
507
+ var cacheTTL, fragmentPassthroughEnabled, maxPrefetchCacheSize, cache, inflight, earliestTimestamp, inflightPromises, inflightAliases, adoptedKeys, paramsShapes, generation, staleEpoch, weightOf;
413
508
  var init_cache = __esm({
414
509
  "src/browser/prefetch/cache.ts"() {
415
510
  "use strict";
@@ -417,6 +512,7 @@ var init_cache = __esm({
417
512
  init_invalidation();
418
513
  init_rango_state();
419
514
  init_wire_params();
515
+ init_prefetch_source_scope();
420
516
  cacheTTL = 3e5;
421
517
  fragmentPassthroughEnabled = true;
422
518
  maxPrefetchCacheSize = 100;
@@ -426,7 +522,10 @@ var init_cache = __esm({
426
522
  inflightPromises = /* @__PURE__ */ new Map();
427
523
  inflightAliases = /* @__PURE__ */ new Map();
428
524
  adoptedKeys = /* @__PURE__ */ new Set();
525
+ paramsShapes = /* @__PURE__ */ new Map();
429
526
  generation = 0;
527
+ staleEpoch = 0;
528
+ weightOf = (shape) => shape.names.length + (shape.route ? 1 : 0) + (shape.keys ? 1 : 0);
430
529
  }
431
530
  });
432
531
 
@@ -627,11 +726,12 @@ var init_validate_redirect_origin = __esm({
627
726
  });
628
727
 
629
728
  // src/prefetch-markers.ts
630
- var PREFETCH_HEADER, PREFETCH_FAILED_ROW;
729
+ var PREFETCH_HEADER, PREFETCH_INTENT, PREFETCH_FAILED_ROW;
631
730
  var init_prefetch_markers = __esm({
632
731
  "src/prefetch-markers.ts"() {
633
732
  "use strict";
634
733
  PREFETCH_HEADER = "X-Rango-Prefetch";
734
+ PREFETCH_INTENT = "intent";
635
735
  PREFETCH_FAILED_ROW = ":H_0\n";
636
736
  }
637
737
  });
@@ -710,12 +810,17 @@ var init_segment_fragments = __esm({
710
810
  function getRegisteredStore() {
711
811
  return registeredStore;
712
812
  }
713
- var registeredStore;
813
+ function getCommittedPage() {
814
+ return readCommittedPage ? readCommittedPage() : null;
815
+ }
816
+ var registeredStore, readCommittedPage;
714
817
  var init_navigation_store_handle = __esm({
715
818
  "src/browser/navigation-store-handle.ts"() {
716
819
  "use strict";
820
+ init_action_fence();
717
821
  init_rango_state();
718
822
  registeredStore = null;
823
+ readCommittedPage = null;
719
824
  }
720
825
  });
721
826
 
@@ -746,31 +851,42 @@ var init_wire_protocol = __esm({
746
851
  function setPrefetchDecoder(fn) {
747
852
  decoder = fn;
748
853
  }
749
- function makeRespawn(storageKey, reserve, scope) {
854
+ function makeRespawn(storageKey, reserve, slot, epoch) {
750
855
  return () => {
751
856
  const [body, nextReserve] = reserve.tee();
752
857
  const payload = decoder(Promise.resolve(new Response(body)));
753
858
  payload.catch(() => {
754
859
  });
755
- const entry = {
860
+ const entry2 = {
756
861
  payload,
757
862
  streamComplete: Promise.resolve(),
758
- scope,
863
+ scope: slot.scope,
864
+ paramsLabel: slot.paramsLabel,
865
+ epoch,
759
866
  complete: true,
760
867
  dispose: () => {
761
868
  nextReserve.cancel().catch(() => {
762
869
  });
763
870
  }
764
871
  };
765
- entry.respawn = makeRespawn(storageKey, nextReserve, scope);
766
- payload.catch(() => removePrefetch(storageKey, entry));
767
- return entry;
872
+ entry2.respawn = makeRespawn(storageKey, nextReserve, slot, epoch);
873
+ payload.catch(() => removePrefetch(storageKey, entry2));
874
+ return entry2;
768
875
  };
769
876
  }
770
- function isSamePage(url) {
877
+ function committedHref() {
878
+ const committed = getRegisteredStore()?.getSegmentState().currentUrl;
879
+ return committed ? new URL(committed, window.location.origin).href : window.location.href;
880
+ }
881
+ function withoutHash(href2) {
882
+ const hash = href2.indexOf("#");
883
+ return hash === -1 ? href2 : href2.slice(0, hash);
884
+ }
885
+ function isSamePage(url, sourceHref) {
771
886
  try {
772
887
  const target = new URL(url, window.location.origin);
773
- return target.pathname + target.search === window.location.pathname + window.location.search;
888
+ const source = new URL(sourceHref, window.location.origin);
889
+ return target.pathname + target.search === source.pathname + source.search;
774
890
  } catch {
775
891
  return false;
776
892
  }
@@ -793,8 +909,21 @@ function buildPrefetchUrl(url, segmentIds, version, routerId2) {
793
909
  rewriteTarget: getRegisteredStore()?.getHistoryEntryMemory()?.rewriteTarget
794
910
  });
795
911
  }
796
- function executePrefetchFetch(wildcardKey, sourceKey, fetchUrl, forceSourceScope, rangoState, expectedRouterId, signal) {
912
+ function prefetchStorageSlot(forceSourceScope, scopeHeader, sourceKey, wildcardKey, stateKey, targetUrl) {
913
+ if (forceSourceScope || scopeHeader === "source") {
914
+ return { scope: "source", key: sourceKey };
915
+ }
916
+ const label = paramsScopeLabel(scopeHeader);
917
+ if (label === void 0) return { scope: "wildcard", key: wildcardKey };
918
+ return {
919
+ scope: "params",
920
+ key: buildParamsKey(stateKey, label, targetUrl),
921
+ paramsLabel: label
922
+ };
923
+ }
924
+ function executePrefetchFetch(wildcardKey, sourceKey, sourceHref, targetUrl, forceSourceScope, rangoState, intent, expectedRouterId, signal) {
797
925
  const gen = currentGeneration();
926
+ const epoch = currentPrefetchEpoch();
798
927
  const inflightKeys = forceSourceScope ? [sourceKey] : [wildcardKey, sourceKey];
799
928
  for (const k of inflightKeys) markPrefetchInflight(k);
800
929
  let publishedKey;
@@ -819,7 +948,7 @@ function executePrefetchFetch(wildcardKey, sourceKey, fetchUrl, forceSourceScope
819
948
  once: true
820
949
  });
821
950
  }
822
- const promise = fetch(fetchUrl, {
951
+ const promise = fetch(targetUrl.toString(), {
823
952
  priority: "low",
824
953
  // During an action's flight the state is not rotated, so the old
825
954
  // X-Rango-State still matches the Vary-keyed HTTP-cache entry; bypass it so
@@ -830,8 +959,8 @@ function executePrefetchFetch(wildcardKey, sourceKey, fetchUrl, forceSourceScope
830
959
  signal: effectiveSignal,
831
960
  headers: {
832
961
  "X-Rango-State": rangoState,
833
- "X-RSC-Router-Client-Path": window.location.href,
834
- [PREFETCH_HEADER]: "1",
962
+ "X-RSC-Router-Client-Path": sourceHref,
963
+ [PREFETCH_HEADER]: intent ? PREFETCH_INTENT : "1",
835
964
  ...isFragmentPassthroughEnabled() && {
836
965
  [SEGMENT_FRAGMENT_CAPABILITY_HEADER]: "1"
837
966
  }
@@ -844,8 +973,15 @@ function executePrefetchFetch(wildcardKey, sourceKey, fetchUrl, forceSourceScope
844
973
  if (isForeignRouterId(response, expectedRouterId)) {
845
974
  return null;
846
975
  }
847
- const scope = forceSourceScope || response.headers.get("x-rsc-prefetch-scope") === "source" ? "source" : "wildcard";
848
- const storageKey = scope === "source" ? sourceKey : wildcardKey;
976
+ const slot = prefetchStorageSlot(
977
+ forceSourceScope,
978
+ response.headers.get("x-rsc-prefetch-scope"),
979
+ sourceKey,
980
+ wildcardKey,
981
+ stateEpoch(rangoState),
982
+ targetUrl
983
+ );
984
+ const storageKey = slot.key;
849
985
  let resolveStreamComplete;
850
986
  let endedCleanly = false;
851
987
  const streamComplete = new Promise((resolve16) => {
@@ -871,10 +1007,12 @@ function executePrefetchFetch(wildcardKey, sourceKey, fetchUrl, forceSourceScope
871
1007
  const payload = decoder(Promise.resolve(decodeSource));
872
1008
  payload.catch(() => {
873
1009
  });
874
- const entry = {
1010
+ const entry2 = {
875
1011
  payload,
876
1012
  streamComplete,
877
- scope,
1013
+ scope: slot.scope,
1014
+ paramsLabel: slot.paramsLabel,
1015
+ epoch,
878
1016
  complete: false,
879
1017
  stallTimer: timeoutId,
880
1018
  ...reserve && {
@@ -884,26 +1022,29 @@ function executePrefetchFetch(wildcardKey, sourceKey, fetchUrl, forceSourceScope
884
1022
  }
885
1023
  }
886
1024
  };
887
- storePrefetch(storageKey, entry, gen);
1025
+ storePrefetch(storageKey, entry2, gen, inflightKeys[0]);
1026
+ if (slot.paramsLabel !== void 0) {
1027
+ rememberParamsShape(targetUrl, slot.paramsLabel);
1028
+ }
888
1029
  publishedKey = storageKey;
889
- publishedEntry = entry;
890
- payload.catch(() => removePrefetch(storageKey, entry));
1030
+ publishedEntry = entry2;
1031
+ payload.catch(() => removePrefetch(storageKey, entry2));
891
1032
  streamComplete.then(() => {
892
- if (!endedCleanly) removePrefetch(storageKey, entry);
1033
+ if (!endedCleanly) removePrefetch(storageKey, entry2);
893
1034
  });
894
1035
  Promise.allSettled([payload, streamComplete]).then(([decode]) => {
895
1036
  clearTimeout(timeoutId);
896
1037
  if (decode.status === "fulfilled" && endedCleanly) {
897
- entry.complete = true;
1038
+ entry2.complete = true;
898
1039
  if (reserve) {
899
- entry.respawn = makeRespawn(storageKey, reserve, scope);
900
- if (!hasPrefetch(storageKey)) {
901
- storePrefetch(storageKey, entry.respawn(), gen);
1040
+ entry2.respawn = makeRespawn(storageKey, reserve, slot, epoch);
1041
+ if (!isPrefetchStale(entry2) && !hasPrefetch(storageKey)) {
1042
+ storePrefetch(storageKey, entry2.respawn(), gen);
902
1043
  }
903
1044
  }
904
1045
  }
905
1046
  });
906
- return entry;
1047
+ return entry2;
907
1048
  }).catch(() => null).finally(() => {
908
1049
  clearPrefetchInflight(inflightKeys[0]);
909
1050
  if (publishedKey === void 0) clearTimeout(timeoutId);
@@ -911,22 +1052,32 @@ function executePrefetchFetch(wildcardKey, sourceKey, fetchUrl, forceSourceScope
911
1052
  setInflightPromiseWithAliases(inflightKeys, promise);
912
1053
  return promise;
913
1054
  }
914
- function hasPrefetchHit(forceSourceScope, wildcardKey, sourceKey) {
915
- return forceSourceScope ? hasPrefetch(sourceKey) : hasPrefetch(wildcardKey) || hasPrefetch(sourceKey);
1055
+ function hasPrefetchHit(forceSourceScope, wildcardKey, sourceKey, stateKey, targetUrl) {
1056
+ if (forceSourceScope) return hasPrefetch(sourceKey);
1057
+ return hasPrefetch(wildcardKey) || hasPrefetch(sourceKey) || paramsCandidateKeys(stateKey, targetUrl, getCommittedPage()).some(
1058
+ hasPrefetch
1059
+ );
916
1060
  }
917
1061
  function prefetchDirect(url, segmentIds, version, routerId2, prefetchKey) {
918
1062
  if (!shouldPrefetch()) return;
919
1063
  const targetUrl = buildPrefetchUrl(url, segmentIds, version, routerId2);
920
1064
  if (!targetUrl) return;
921
1065
  const forceSourceScope = prefetchKey === ":source";
922
- if (!forceSourceScope && isSamePage(url)) {
1066
+ const sourceHref = committedHref();
1067
+ if (!forceSourceScope && isSamePage(url, sourceHref)) {
923
1068
  return;
924
1069
  }
925
- const sourceHref = window.location.href;
926
1070
  const rangoState = getRangoState();
927
- const wildcardKey = buildPrefetchKey(rangoState, targetUrl);
928
- const sourceKey = buildSourceKey(rangoState, sourceHref, targetUrl);
929
- if (hasPrefetchHit(forceSourceScope, wildcardKey, sourceKey)) {
1071
+ const stateKey = stateEpoch(rangoState);
1072
+ const wildcardKey = buildPrefetchKey(stateKey, targetUrl);
1073
+ const sourceKey = buildSourceKey(stateKey, sourceHref, targetUrl);
1074
+ if (hasPrefetchHit(
1075
+ forceSourceScope,
1076
+ wildcardKey,
1077
+ sourceKey,
1078
+ stateKey,
1079
+ targetUrl
1080
+ )) {
930
1081
  if (IS_BROWSER_DEBUG) {
931
1082
  debugLog("[prefetch] direct dedup (key already exists)", {
932
1083
  url,
@@ -949,9 +1100,11 @@ function prefetchDirect(url, segmentIds, version, routerId2, prefetchKey) {
949
1100
  executePrefetchFetch(
950
1101
  wildcardKey,
951
1102
  sourceKey,
952
- targetUrl.toString(),
1103
+ sourceHref,
1104
+ targetUrl,
953
1105
  forceSourceScope,
954
1106
  rangoState,
1107
+ true,
955
1108
  routerId2
956
1109
  );
957
1110
  }
@@ -960,15 +1113,22 @@ function prefetchQueued(url, segmentIds, version, routerId2, prefetchKey) {
960
1113
  const targetUrl = buildPrefetchUrl(url, segmentIds, version, routerId2);
961
1114
  if (!targetUrl) return "";
962
1115
  const forceSourceScope = prefetchKey === ":source";
963
- if (!forceSourceScope && isSamePage(url)) {
1116
+ const sourceHref = committedHref();
1117
+ if (!forceSourceScope && isSamePage(url, sourceHref)) {
964
1118
  return "";
965
1119
  }
966
- const sourceHref = window.location.href;
967
1120
  const rangoState = getRangoState();
968
- const wildcardKey = buildPrefetchKey(rangoState, targetUrl);
969
- const sourceKey = buildSourceKey(rangoState, sourceHref, targetUrl);
1121
+ const stateKey = stateEpoch(rangoState);
1122
+ const wildcardKey = buildPrefetchKey(stateKey, targetUrl);
1123
+ const sourceKey = buildSourceKey(stateKey, sourceHref, targetUrl);
970
1124
  const queueKey = forceSourceScope ? sourceKey : wildcardKey;
971
- if (hasPrefetchHit(forceSourceScope, wildcardKey, sourceKey)) {
1125
+ if (hasPrefetchHit(
1126
+ forceSourceScope,
1127
+ wildcardKey,
1128
+ sourceKey,
1129
+ stateKey,
1130
+ targetUrl
1131
+ )) {
972
1132
  if (IS_BROWSER_DEBUG) {
973
1133
  debugLog("[prefetch] queued dedup (key already exists)", {
974
1134
  url,
@@ -979,20 +1139,30 @@ function prefetchQueued(url, segmentIds, version, routerId2, prefetchKey) {
979
1139
  }
980
1140
  return queueKey;
981
1141
  }
982
- const fetchUrlStr = targetUrl.toString();
983
1142
  enqueuePrefetch(queueKey, (signal) => {
984
- if (hasPrefetchHit(forceSourceScope, wildcardKey, sourceKey)) {
1143
+ const liveState = getRangoState();
1144
+ if (stateEpoch(liveState) !== stateKey) return Promise.resolve();
1145
+ if (hasPrefetchHit(
1146
+ forceSourceScope,
1147
+ wildcardKey,
1148
+ sourceKey,
1149
+ stateKey,
1150
+ targetUrl
1151
+ )) {
985
1152
  return Promise.resolve();
986
1153
  }
987
- if (!forceSourceScope && isSamePage(url)) {
1154
+ const committed = committedHref();
1155
+ if (withoutHash(committed) !== withoutHash(sourceHref) || !forceSourceScope && isSamePage(url, committed)) {
988
1156
  return Promise.resolve();
989
1157
  }
990
1158
  return executePrefetchFetch(
991
1159
  wildcardKey,
992
1160
  sourceKey,
993
- fetchUrlStr,
1161
+ sourceHref,
1162
+ targetUrl,
994
1163
  forceSourceScope,
995
- rangoState,
1164
+ liveState,
1165
+ false,
996
1166
  routerId2,
997
1167
  signal
998
1168
  ).then(() => {
@@ -1005,7 +1175,9 @@ var init_fetch = __esm({
1005
1175
  "src/browser/prefetch/fetch.ts"() {
1006
1176
  "use strict";
1007
1177
  init_cache();
1178
+ init_prefetch_source_scope();
1008
1179
  init_rango_state();
1180
+ init_cookie_name();
1009
1181
  init_action_fence();
1010
1182
  init_queue();
1011
1183
  init_policy();
@@ -1994,6 +2166,7 @@ var DEFAULT_EXCLUDE_PATTERNS = [
1994
2166
  "**/dist/**",
1995
2167
  "**/coverage/**",
1996
2168
  "**/*.test.{ts,tsx,js,jsx}",
2169
+ "**/*.rsc-test.{ts,tsx,js,jsx}",
1997
2170
  "**/*.spec.{ts,tsx,js,jsx}"
1998
2171
  ];
1999
2172
  function createScanFilter(root, opts) {
@@ -2035,12 +2208,12 @@ function findTsFiles(dir, filter) {
2035
2208
  );
2036
2209
  return results;
2037
2210
  }
2038
- for (const entry of entries) {
2039
- const fullPath = join(dir, entry.name);
2040
- if (entry.isDirectory()) {
2041
- if (isSkippedSourceScanDir(entry.name)) continue;
2211
+ for (const entry2 of entries) {
2212
+ const fullPath = join(dir, entry2.name);
2213
+ if (entry2.isDirectory()) {
2214
+ if (isSkippedSourceScanDir(entry2.name)) continue;
2042
2215
  results.push(...findTsFiles(fullPath, filter));
2043
- } else if ((entry.name.endsWith(".ts") || entry.name.endsWith(".tsx") || entry.name.endsWith(".js") || entry.name.endsWith(".jsx")) && !entry.name.includes(".gen.")) {
2216
+ } else if ((entry2.name.endsWith(".ts") || entry2.name.endsWith(".tsx") || entry2.name.endsWith(".js") || entry2.name.endsWith(".jsx")) && !entry2.name.includes(".gen.")) {
2044
2217
  if (filter && !filter(fullPath)) continue;
2045
2218
  results.push(fullPath);
2046
2219
  }
@@ -2883,20 +3056,20 @@ ${lazyImports.join(",\n")}
2883
3056
  return "\0" + id;
2884
3057
  }
2885
3058
  if (importer?.startsWith("\0" + VIRTUAL_HANDLER_PREFIX)) {
2886
- const entry = virtualHandlers.get(importer);
2887
- if (entry) {
2888
- return this.resolve(id, entry.originalModuleId, { skipSelf: true });
3059
+ const entry2 = virtualHandlers.get(importer);
3060
+ if (entry2) {
3061
+ return this.resolve(id, entry2.originalModuleId, { skipSelf: true });
2889
3062
  }
2890
3063
  }
2891
3064
  },
2892
3065
  load(id) {
2893
3066
  if (id.startsWith("\0" + VIRTUAL_HANDLER_PREFIX)) {
2894
- const entry = virtualHandlers.get(id);
2895
- if (!entry) return null;
3067
+ const entry2 = virtualHandlers.get(id);
3068
+ if (!entry2) return null;
2896
3069
  return [
2897
- ...entry.imports,
2898
- ...entry.declarations,
2899
- `export const ${entry.exportName} = ${entry.handlerCode};`
3070
+ ...entry2.imports,
3071
+ ...entry2.declarations,
3072
+ `export const ${entry2.exportName} = ${entry2.handlerCode};`
2900
3073
  ].join("\n") + "\n";
2901
3074
  }
2902
3075
  if (id !== RESOLVED_VIRTUAL_LOADER_MANIFEST) return;
@@ -2911,13 +3084,13 @@ ${lazyImports.join(",\n")}
2911
3084
  const results = [];
2912
3085
  try {
2913
3086
  const entries = await fs2.readdir(dir, { withFileTypes: true });
2914
- for (const entry of entries) {
2915
- const fullPath = path4.join(dir, entry.name);
2916
- if (entry.isDirectory()) {
2917
- if (!isSkippedSourceScanDir(entry.name)) {
3087
+ for (const entry2 of entries) {
3088
+ const fullPath = path4.join(dir, entry2.name);
3089
+ if (entry2.isDirectory()) {
3090
+ if (!isSkippedSourceScanDir(entry2.name)) {
2918
3091
  results.push(...await scanDir(fullPath));
2919
3092
  }
2920
- } else if (/\.(ts|tsx|js|jsx)$/.test(entry.name)) {
3093
+ } else if (/\.(ts|tsx|js|jsx)$/.test(entry2.name)) {
2921
3094
  results.push(fullPath);
2922
3095
  }
2923
3096
  }
@@ -4181,8 +4354,8 @@ async function recordEmitted(emitted, file, value) {
4181
4354
  emitted.set(file, { disk: await readSource(file), value });
4182
4355
  }
4183
4356
  async function loadEmittedOrDisk(emitted, hoistedFile, disk, rehoist) {
4184
- const entry = emitted.get(normalizePath2(hoistedFile));
4185
- if (entry && (disk === null || entry.disk === disk)) return entry.value;
4357
+ const entry2 = emitted.get(normalizePath2(hoistedFile));
4358
+ if (entry2 && (disk === null || entry2.disk === disk)) return entry2.value;
4186
4359
  return disk === null ? void 0 : rehoist(disk);
4187
4360
  }
4188
4361
 
@@ -4476,6 +4649,7 @@ function getLoaderBodyTags() {
4476
4649
  function getCurrentLoaderBodyId() {
4477
4650
  return loaderBodyScopeALS.getStore()?.loaderId;
4478
4651
  }
4652
+ var segmentPinALS = globalThis[/* @__PURE__ */ Symbol.for("rangojs-router:segment-pin")] ??= new AsyncLocalStorage2();
4479
4653
  var PUSH_CALLBACK_SCOPE_KEY = /* @__PURE__ */ Symbol.for(
4480
4654
  "rangojs-router:push-callback-scope"
4481
4655
  );
@@ -5315,6 +5489,7 @@ init_logging();
5315
5489
 
5316
5490
  // src/browser/navigation-store.ts
5317
5491
  init_cache();
5492
+ init_action_fence();
5318
5493
  init_rango_state();
5319
5494
 
5320
5495
  // src/browser/react/NavigationProvider.tsx
@@ -5373,12 +5548,12 @@ function getObserver() {
5373
5548
  observer = new IntersectionObserver(
5374
5549
  (entries, currentObserver) => {
5375
5550
  function* intersectingCallbacks() {
5376
- for (const entry of entries) {
5377
- if (entry.isIntersecting) {
5378
- const subscriptions = callbacks.get(entry.target);
5551
+ for (const entry2 of entries) {
5552
+ if (entry2.isIntersecting) {
5553
+ const subscriptions = callbacks.get(entry2.target);
5379
5554
  if (subscriptions) {
5380
- currentObserver.unobserve(entry.target);
5381
- callbacks.delete(entry.target);
5555
+ currentObserver.unobserve(entry2.target);
5556
+ callbacks.delete(entry2.target);
5382
5557
  for (const [subscription, callback] of subscriptions) {
5383
5558
  yield [subscriptions, subscription, callback];
5384
5559
  }
@@ -5937,6 +6112,12 @@ var DERIVED_RENDER_BARRIER_DESCRIPTOR = {
5937
6112
  };
5938
6113
  var backgroundWork = new AsyncLocalStorage6();
5939
6114
 
6115
+ // src/router/revalidation.ts
6116
+ init_prefetch_source_scope();
6117
+
6118
+ // src/router/source-reads.ts
6119
+ init_prefetch_source_scope();
6120
+
5940
6121
  // src/route-definition/redirect.ts
5941
6122
  init_redirect_origin();
5942
6123
 
@@ -6119,9 +6300,9 @@ function serializeRoute(route2, options, ordinals) {
6119
6300
  }
6120
6301
  function serializeLoaderOptions(loaders, owner, options) {
6121
6302
  const loaderRevalidate = loaders.map(
6122
- ({ loader: loader3, revalidate: revalidate3 }) => revalidate3.flatMap((entry) => {
6123
- if (isHoistedRevalidateRef(entry)) return [entry.$$rangoRevalidate];
6124
- if (typeof entry === "boolean") return [entry];
6303
+ ({ loader: loader3, revalidate: revalidate3 }) => revalidate3.flatMap((entry2) => {
6304
+ if (isHoistedRevalidateRef(entry2)) return [entry2.$$rangoRevalidate];
6305
+ if (typeof entry2 === "boolean") return [entry2];
6125
6306
  if (options.hoisted) {
6126
6307
  throw new Error(
6127
6308
  `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.`
@@ -6562,25 +6743,25 @@ function fingerprint(node) {
6562
6743
  out.push(JSON.stringify(typeof value === "bigint" ? `${value}n` : value));
6563
6744
  return;
6564
6745
  }
6565
- let entry = value;
6566
- if (typeof entry.type === "string") {
6567
- entry = unwrapExpression(entry);
6568
- if (entry.type.startsWith("TS")) {
6569
- visit(entry.expression);
6746
+ let entry2 = value;
6747
+ if (typeof entry2.type === "string") {
6748
+ entry2 = unwrapExpression(entry2);
6749
+ if (entry2.type.startsWith("TS")) {
6750
+ visit(entry2.expression);
6570
6751
  return;
6571
6752
  }
6572
- out.push(entry.type, "(");
6573
- if (entry.type === "TemplateElement") {
6574
- out.push(JSON.stringify(entry.value.raw));
6753
+ out.push(entry2.type, "(");
6754
+ if (entry2.type === "TemplateElement") {
6755
+ out.push(JSON.stringify(entry2.value.raw));
6575
6756
  }
6576
6757
  }
6577
- for (const key of Object.keys(entry)) {
6758
+ for (const key of Object.keys(entry2)) {
6578
6759
  if (FINGERPRINT_SKIP.has(key)) continue;
6579
- if (key === "optional" && entry.type === "Identifier") continue;
6760
+ if (key === "optional" && entry2.type === "Identifier") continue;
6580
6761
  out.push(key);
6581
- visit(entry[key]);
6762
+ visit(entry2[key]);
6582
6763
  }
6583
- if (typeof entry.type === "string") out.push(")");
6764
+ if (typeof entry2.type === "string") out.push(")");
6584
6765
  };
6585
6766
  visit(node);
6586
6767
  return out.join(" ");
@@ -7146,7 +7327,7 @@ function resolveVersionsFrom(table, routerId2) {
7146
7327
  // package.json
7147
7328
  var package_default = {
7148
7329
  name: "@rangojs/router",
7149
- version: "0.31.0",
7330
+ version: "0.33.0",
7150
7331
  description: "Django-inspired RSC router with composable URL patterns",
7151
7332
  keywords: [
7152
7333
  "react",
@@ -7339,7 +7520,7 @@ var package_default = {
7339
7520
  tag: "latest"
7340
7521
  },
7341
7522
  scripts: {
7342
- build: "pnpm run build:types && pnpm exec esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && mkdir -p dist/vite/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/vite/plugins/cloudflare-protocol-loader-hook.mjs && pnpm exec esbuild src/testing/vitest.ts --bundle --format=esm --outfile=dist/testing/vitest.js --platform=node --packages=external && pnpm exec esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js && mkdir -p dist/bin/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/bin/plugins/cloudflare-protocol-loader-hook.mjs",
7523
+ build: "pnpm run build:types && pnpm exec esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && mkdir -p dist/vite/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/vite/plugins/cloudflare-protocol-loader-hook.mjs && pnpm exec esbuild src/testing/vitest.ts --bundle --format=esm --outfile=dist/testing/vitest.js --platform=node --packages=external && rm -rf dist/bin && pnpm exec esbuild src/bin/rango.ts --bundle --format=esm --splitting --outdir=dist/bin --platform=node --packages=external && chmod +x dist/bin/rango.js && mkdir -p dist/bin/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/bin/plugins/cloudflare-protocol-loader-hook.mjs",
7343
7524
  "build:types": "rm -rf dist/types && pnpm exec tsc -p tsconfig.types.json",
7344
7525
  prepublishOnly: "pnpm build",
7345
7526
  typecheck: "tsc --noEmit && tsc -p tsconfig.strict-check.json --noEmit && tsc -p tsconfig.augment-check.json --noEmit",
@@ -8243,10 +8424,10 @@ function serverCssRecords(server, projectRoot, serverResources) {
8243
8424
  const key = portableModuleId(id, projectRoot).match(SERVER_CSS_MODULE)?.[1];
8244
8425
  if (key !== void 0) moduleOf.set(key, id);
8245
8426
  }
8246
- return [...serverResources].map(([key, entry]) => ({
8427
+ return [...serverResources].map(([key, entry2]) => ({
8247
8428
  kind: "server-css",
8248
8429
  key,
8249
- digest: sha256(entry),
8430
+ digest: sha256(entry2),
8250
8431
  moduleId: moduleOf.get(key)
8251
8432
  }));
8252
8433
  }
@@ -8485,8 +8666,8 @@ function isWorkspaceDevelopment() {
8485
8666
  return !isInstalledFromNpm();
8486
8667
  }
8487
8668
  var SOURCE_EXPORT_SUBPATHS = Object.keys(package_default.exports).filter((key) => {
8488
- const entry = package_default.exports[key];
8489
- return Object.entries(entry).some(
8669
+ const entry2 = package_default.exports[key];
8670
+ return Object.entries(entry2).some(
8490
8671
  ([condition, path6]) => condition !== "types" && typeof path6 === "string" && /\.tsx?$/.test(path6)
8491
8672
  );
8492
8673
  }).map((key) => key.replace(/^\./, ""));
@@ -8690,9 +8871,26 @@ function readSourceMemoized(memo, realPath) {
8690
8871
  if (memo) memo.files.set(realPath, source);
8691
8872
  return source;
8692
8873
  }
8693
- function isUrlsDefinitionCall(node) {
8874
+ function isUrlsDefinitionCall(node, aliases) {
8694
8875
  const callee = node.expression;
8695
- return ts3.isIdentifier(callee) && (callee.text === "urls" || callee.text === "clientUrls");
8876
+ return ts3.isIdentifier(callee) && (callee.text === "urls" || callee.text === "clientUrls" || aliases?.has(callee.text) === true);
8877
+ }
8878
+ function collectUrlsImportAliases(sourceFile) {
8879
+ const aliases = /* @__PURE__ */ new Set();
8880
+ for (const stmt of sourceFile.statements) {
8881
+ if (!ts3.isImportDeclaration(stmt) || !ts3.isStringLiteral(stmt.moduleSpecifier) || stmt.moduleSpecifier.text !== "@rangojs/router" && stmt.moduleSpecifier.text !== "@rangojs/router/client") {
8882
+ continue;
8883
+ }
8884
+ const bindings = stmt.importClause?.namedBindings;
8885
+ if (!bindings || !ts3.isNamedImports(bindings)) continue;
8886
+ for (const el of bindings.elements) {
8887
+ const imported = (el.propertyName ?? el.name).text;
8888
+ if (imported === "urls" || imported === "clientUrls") {
8889
+ aliases.add(el.name.text);
8890
+ }
8891
+ }
8892
+ }
8893
+ return aliases;
8696
8894
  }
8697
8895
  function extractNamePrefixFromInclude(node) {
8698
8896
  if (node.arguments.length >= 3) {
@@ -8939,8 +9137,8 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
8939
9137
  blockSourceFile
8940
9138
  );
8941
9139
  if (diagnosticsOut) {
8942
- for (const entry of unresolvable) {
8943
- diagnosticsOut.push({ ...entry, sourceFile: filePath });
9140
+ for (const entry2 of unresolvable) {
9141
+ diagnosticsOut.push({ ...entry2, sourceFile: filePath });
8944
9142
  }
8945
9143
  }
8946
9144
  for (const inc of includes) {
@@ -9227,7 +9425,7 @@ function countPublicRouteEntries(source) {
9227
9425
  var ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
9228
9426
  var ROUTER_CALL_PATTERN_G = /\bcreateRouter\s*[<(]/g;
9229
9427
  function isRoutableSourceFile(name) {
9230
- return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
9428
+ return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".rsc-test.") && !name.includes(".spec.");
9231
9429
  }
9232
9430
  function isExcludedScanDir(name) {
9233
9431
  return isUniversallySkippedScanDir(name) || name === "__tests__" || name === "__mocks__";
@@ -9244,13 +9442,13 @@ function findCallSiteFilesRecursive(dir, pattern, patternG, stopAtMatchDir, filt
9244
9442
  }
9245
9443
  const childDirs = [];
9246
9444
  const matchesInDir = [];
9247
- for (const entry of entries) {
9248
- const fullPath = join3(dir, entry.name);
9249
- if (entry.isDirectory()) {
9250
- if (!isExcludedScanDir(entry.name)) childDirs.push(fullPath);
9445
+ for (const entry2 of entries) {
9446
+ const fullPath = join3(dir, entry2.name);
9447
+ if (entry2.isDirectory()) {
9448
+ if (!isExcludedScanDir(entry2.name)) childDirs.push(fullPath);
9251
9449
  continue;
9252
9450
  }
9253
- if (!isRoutableSourceFile(entry.name)) continue;
9451
+ if (!isRoutableSourceFile(entry2.name)) continue;
9254
9452
  if (filter && !filter(fullPath)) continue;
9255
9453
  try {
9256
9454
  const source = readFileSync4(fullPath, "utf-8");
@@ -9309,11 +9507,12 @@ function isCreateRouterCall(node) {
9309
9507
  const callee = node.expression;
9310
9508
  return ts5.isIdentifier(callee) && callee.text === "createRouter";
9311
9509
  }
9312
- function extractUrlsArgument(node, sourceFile) {
9510
+ function extractUrlsArgument(arg, sourceFile, urlsAliases) {
9511
+ const node = unwrapTypeOperators(arg);
9313
9512
  if (ts5.isIdentifier(node)) {
9314
9513
  return { kind: "variable", name: node.text };
9315
9514
  }
9316
- if (ts5.isArrowFunction(node) || ts5.isFunctionExpression(node)) {
9515
+ if (ts5.isArrowFunction(node) || ts5.isFunctionExpression(node) || ts5.isCallExpression(node) && isUrlsDefinitionCall(node, urlsAliases)) {
9317
9516
  return { kind: "inline", block: node.getText(sourceFile) };
9318
9517
  }
9319
9518
  return null;
@@ -9330,23 +9529,77 @@ function collectCreateRouterCallChain(endpoint) {
9330
9529
  current = receiver;
9331
9530
  }
9332
9531
  }
9532
+ function collectExportedLocalNames(sourceFile) {
9533
+ const names = /* @__PURE__ */ new Set();
9534
+ const addIdentifier = (expr) => {
9535
+ const node = expr && unwrapTypeOperators(expr);
9536
+ if (node && ts5.isIdentifier(node)) names.add(node.text);
9537
+ };
9538
+ for (const statement of sourceFile.statements) {
9539
+ if (ts5.isExportAssignment(statement)) {
9540
+ addIdentifier(statement.expression);
9541
+ } else if (ts5.isExportDeclaration(statement) && !statement.moduleSpecifier && !statement.isTypeOnly && statement.exportClause && ts5.isNamedExports(statement.exportClause)) {
9542
+ for (const element of statement.exportClause.elements) {
9543
+ if (!element.isTypeOnly) {
9544
+ names.add((element.propertyName ?? element.name).text);
9545
+ }
9546
+ }
9547
+ } else if (ts5.isVariableStatement(statement) && hasModifier(statement, ts5.SyntaxKind.ExportKeyword)) {
9548
+ for (const decl of statement.declarationList.declarations) {
9549
+ addIdentifier(decl.initializer);
9550
+ }
9551
+ }
9552
+ }
9553
+ return names;
9554
+ }
9555
+ function isExportedChain(chainEnd, exportedNames) {
9556
+ let current = chainEnd;
9557
+ while (current.parent && (ts5.isAsExpression(current.parent) || ts5.isSatisfiesExpression(current.parent) || ts5.isParenthesizedExpression(current.parent))) {
9558
+ current = current.parent;
9559
+ }
9560
+ const parent = current.parent;
9561
+ if (!parent) return false;
9562
+ if (ts5.isExportAssignment(parent))
9563
+ return parent.parent === current.getSourceFile();
9564
+ if (!ts5.isVariableDeclaration(parent) || parent.initializer !== current || !ts5.isIdentifier(parent.name)) {
9565
+ return false;
9566
+ }
9567
+ const statement = parent.parent.parent;
9568
+ if (!ts5.isVariableStatement(statement) || !ts5.isSourceFile(statement.parent)) {
9569
+ return false;
9570
+ }
9571
+ return hasModifier(statement, ts5.SyntaxKind.ExportKeyword) || exportedNames.has(parent.name.text);
9572
+ }
9333
9573
  function findRouterUrls(sourceFile) {
9334
- let result = null;
9574
+ const exported = [];
9575
+ const local = [];
9576
+ let anyExported = false;
9577
+ const seen = /* @__PURE__ */ new Set();
9578
+ const urlsAliases = collectUrlsImportAliases(sourceFile);
9579
+ const exportedNames = collectExportedLocalNames(sourceFile);
9335
9580
  function visit(node) {
9336
- if (result) return;
9337
9581
  if (ts5.isCallExpression(node)) {
9338
9582
  const chain = collectCreateRouterCallChain(node);
9339
- if (chain) {
9583
+ if (chain && !seen.has(chain[0])) {
9340
9584
  const extracted = [];
9585
+ const unreadable = [];
9341
9586
  const createRouterCall = chain[0];
9587
+ seen.add(createRouterCall);
9588
+ const addMount = (arg, mount) => {
9589
+ const urls2 = extractUrlsArgument(arg, sourceFile, urlsAliases);
9590
+ if (urls2) extracted.push(urls2);
9591
+ else
9592
+ unreadable.push(
9593
+ mount(arg.getText(sourceFile).replace(/\s+/g, " "))
9594
+ );
9595
+ };
9342
9596
  for (const callArg of createRouterCall.arguments) {
9343
9597
  if (!ts5.isObjectLiteralExpression(callArg)) continue;
9344
9598
  for (const prop of callArg.properties) {
9345
9599
  if (!ts5.isPropertyAssignment(prop) || !ts5.isIdentifier(prop.name) || prop.name.text !== "urls") {
9346
9600
  continue;
9347
9601
  }
9348
- const urls2 = extractUrlsArgument(prop.initializer, sourceFile);
9349
- if (urls2) extracted.push(urls2);
9602
+ addMount(prop.initializer, (text) => `urls: ${text}`);
9350
9603
  break;
9351
9604
  }
9352
9605
  }
@@ -9354,36 +9607,43 @@ function findRouterUrls(sourceFile) {
9354
9607
  if (!ts5.isPropertyAccessExpression(call.expression) || call.expression.name.text !== "routes" || call.arguments.length === 0) {
9355
9608
  continue;
9356
9609
  }
9357
- const urls2 = extractUrlsArgument(call.arguments[0], sourceFile);
9358
- if (urls2) extracted.push(urls2);
9359
- }
9360
- if (extracted.length > 0) {
9361
- result = { createRouterCall, extractions: extracted };
9362
- return;
9610
+ addMount(call.arguments[0], (text) => `.routes(${text})`);
9611
+ }
9612
+ const isExported = isExportedChain(node, exportedNames);
9613
+ if (isExported) anyExported = true;
9614
+ if (extracted.length > 0 || unreadable.length > 0) {
9615
+ (isExported ? exported : local).push({
9616
+ createRouterCall,
9617
+ extractions: extracted,
9618
+ unreadable
9619
+ });
9363
9620
  }
9364
9621
  }
9365
9622
  }
9366
9623
  ts5.forEachChild(node, visit);
9367
9624
  }
9368
9625
  visit(sourceFile);
9369
- return result;
9626
+ const candidates = anyExported ? exported : local;
9627
+ return candidates.find((c) => c.extractions.length > 0) ?? candidates[0] ?? null;
9370
9628
  }
9371
- function extractAllUrlsFromRouter(code) {
9372
- const sourceFile = ts5.createSourceFile(
9629
+ function parseRouterSource(code) {
9630
+ return ts5.createSourceFile(
9373
9631
  "router.tsx",
9374
9632
  code,
9375
9633
  ts5.ScriptTarget.Latest,
9376
9634
  true,
9377
9635
  ts5.ScriptKind.TSX
9378
9636
  );
9379
- return findRouterUrls(sourceFile)?.extractions ?? [];
9637
+ }
9638
+ function extractAllUrlsFromRouter(code) {
9639
+ return findRouterUrls(parseRouterSource(code))?.extractions ?? [];
9380
9640
  }
9381
9641
  function extractUrlsFromRouter(code) {
9382
9642
  const extractions = extractAllUrlsFromRouter(code);
9383
9643
  return extractions[extractions.length - 1] ?? null;
9384
9644
  }
9385
9645
  function unwrapTypeOperators(expr) {
9386
- while (ts5.isAsExpression(expr) || ts5.isSatisfiesExpression(expr)) {
9646
+ while (ts5.isAsExpression(expr) || ts5.isSatisfiesExpression(expr) || ts5.isParenthesizedExpression(expr)) {
9387
9647
  expr = expr.expression;
9388
9648
  }
9389
9649
  return expr;
@@ -10701,10 +10961,10 @@ function generateRoutesManifestModule(state) {
10701
10961
  const genFileImports = [];
10702
10962
  const genFileVarByEntry = [];
10703
10963
  let varIdx = 0;
10704
- for (const entry of state.perRouterManifests) {
10705
- if (entry.sourceFile) {
10706
- const routerDir = dirname4(entry.sourceFile);
10707
- const routerBasename = basename(entry.sourceFile).replace(
10964
+ for (const entry2 of state.perRouterManifests) {
10965
+ if (entry2.sourceFile) {
10966
+ const routerDir = dirname4(entry2.sourceFile);
10967
+ const routerBasename = basename(entry2.sourceFile).replace(
10708
10968
  /\.(tsx?|jsx?)$/,
10709
10969
  ""
10710
10970
  );
@@ -10747,10 +11007,10 @@ function generateRoutesManifestModule(state) {
10747
11007
  );
10748
11008
  }
10749
11009
  const routerMapVars = [];
10750
- for (const [i, entry] of state.perRouterManifests.entries()) {
11010
+ for (const [i, entry2] of state.perRouterManifests.entries()) {
10751
11011
  const mapVar = `__m${i}`;
10752
11012
  const genVar = genFileVarByEntry[i];
10753
- const init = genVar ? `__flat(${genVar})` : jsonParseExpression(entry.routeManifest);
11013
+ const init = genVar ? `__flat(${genVar})` : jsonParseExpression(entry2.routeManifest);
10754
11014
  lines2.push(`const ${mapVar} = ${init};`);
10755
11015
  routerMapVars.push(mapVar);
10756
11016
  }
@@ -10761,9 +11021,9 @@ function generateRoutesManifestModule(state) {
10761
11021
  `setCachedManifest({ ${routerMapVars.map((v) => `...${v}`).join(", ")} });`
10762
11022
  );
10763
11023
  }
10764
- for (const [i, entry] of state.perRouterManifests.entries()) {
11024
+ for (const [i, entry2] of state.perRouterManifests.entries()) {
10765
11025
  lines2.push(
10766
- `setRouterManifest(${JSON.stringify(entry.id)}, ${routerMapVars[i]});`
11026
+ `setRouterManifest(${JSON.stringify(entry2.id)}, ${routerMapVars[i]});`
10767
11027
  );
10768
11028
  }
10769
11029
  if (state.isBuildMode) {
@@ -11041,14 +11301,14 @@ async function runWithConcurrency(items, concurrency2, fn) {
11041
11301
  }
11042
11302
  function groupByConcurrency(entries) {
11043
11303
  const map2 = /* @__PURE__ */ new Map();
11044
- for (const entry of entries) {
11045
- const key = entry.concurrency;
11304
+ for (const entry2 of entries) {
11305
+ const key = entry2.concurrency;
11046
11306
  let group = map2.get(key);
11047
11307
  if (!group) {
11048
11308
  group = [];
11049
11309
  map2.set(key, group);
11050
11310
  }
11051
- group.push(entry);
11311
+ group.push(entry2);
11052
11312
  }
11053
11313
  return Array.from(map2.entries(), ([concurrency2, items]) => ({
11054
11314
  concurrency: concurrency2,
@@ -11726,23 +11986,23 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
11726
11986
  await runWithConcurrency(
11727
11987
  group.entries,
11728
11988
  group.concurrency,
11729
- async (entry) => {
11989
+ async (entry2) => {
11730
11990
  const startUrl = performance.now();
11731
11991
  for (const [routerId2, routerInstance] of registry) {
11732
11992
  if (!routerInstance.matchForPrerender) continue;
11733
11993
  try {
11734
11994
  const result = await routerInstance.matchForPrerender(
11735
- entry.urlPath,
11995
+ entry2.urlPath,
11736
11996
  {},
11737
- entry.buildVars,
11738
- entry.isPassthroughRoute,
11997
+ entry2.buildVars,
11998
+ entry2.isPassthroughRoute,
11739
11999
  state.resolvedBuildEnv
11740
12000
  );
11741
12001
  if (!result) continue;
11742
12002
  if (result.passthrough) {
11743
12003
  const elapsed2 = (performance.now() - startUrl).toFixed(0);
11744
12004
  console.log(
11745
- `[rango] PASS ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - live fallback`
12005
+ `[rango] PASS ${entry2.urlPath.padEnd(40)} (${elapsed2}ms) - live fallback`
11746
12006
  );
11747
12007
  doneCount++;
11748
12008
  break;
@@ -11763,7 +12023,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
11763
12023
  stage(main);
11764
12024
  if (result.ppr !== void 0 && result.ppr !== false) {
11765
12025
  (state.shellCandidates ??= []).push({
11766
- urlPath: entry.urlPath,
12026
+ urlPath: entry2.urlPath,
11767
12027
  routeName: result.routeName,
11768
12028
  paramHash,
11769
12029
  ppr: result.ppr === true ? true : result.ppr
@@ -11773,13 +12033,13 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
11773
12033
  if (intercept2) stage(intercept2);
11774
12034
  const elapsed = (performance.now() - startUrl).toFixed(0);
11775
12035
  console.log(
11776
- `[rango] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`
12036
+ `[rango] OK ${entry2.urlPath.padEnd(40)} (${elapsed}ms)`
11777
12037
  );
11778
12038
  warnLiveIntercepts(
11779
12039
  warnedLiveIntercepts,
11780
12040
  routerId2,
11781
12041
  result.routeName,
11782
- entry.urlPath,
12042
+ entry2.urlPath,
11783
12043
  result.liveIntercepts
11784
12044
  );
11785
12045
  doneCount++;
@@ -11790,11 +12050,11 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
11790
12050
  registry,
11791
12051
  err,
11792
12052
  prerenderOnError,
11793
- entry.urlPath.padEnd(40),
12053
+ entry2.urlPath.padEnd(40),
11794
12054
  elapsed,
11795
12055
  "prerender",
11796
- entry.routeName,
11797
- entry.urlPath
12056
+ entry2.routeName,
12057
+ entry2.urlPath
11798
12058
  );
11799
12059
  skipCount++;
11800
12060
  break;
@@ -11942,8 +12202,8 @@ function isLazyMount(route2) {
11942
12202
  }
11943
12203
  async function resolveHostRouterHandlers(hostRegistry) {
11944
12204
  const errors = [];
11945
- for (const [hostId, entry] of hostRegistry) {
11946
- for (const route2 of entry.routes) {
12205
+ for (const [hostId, entry2] of hostRegistry) {
12206
+ for (const route2 of entry2.routes) {
11947
12207
  if (isLazyMount(route2)) {
11948
12208
  await invokeLazyMount(
11949
12209
  route2.handler,
@@ -11952,9 +12212,9 @@ async function resolveHostRouterHandlers(hostRegistry) {
11952
12212
  );
11953
12213
  }
11954
12214
  }
11955
- if (isLazyMount(entry.fallback)) {
12215
+ if (isLazyMount(entry2.fallback)) {
11956
12216
  await invokeLazyMount(
11957
- entry.fallback.handler,
12217
+ entry2.fallback.handler,
11958
12218
  `host "${hostId}" fallback handler`,
11959
12219
  errors
11960
12220
  );
@@ -12001,17 +12261,17 @@ var DiscoveryError = class _DiscoveryError extends Error {
12001
12261
  };
12002
12262
  function describeDiscoveryFailure(err, opts = {}) {
12003
12263
  if (err instanceof DiscoveryError && err.caught.length === 0) {
12004
- const entry = err.entryPath ?? "the router entry";
12264
+ const entry2 = err.entryPath ?? "the router entry";
12005
12265
  if (opts.reoptimizeObserved) {
12006
12266
  return {
12007
12267
  level: "warn",
12008
- message: `[rango] No routers found while Vite was re-optimizing dependencies on dev boot. This is transient: routes are served per-request and discovery re-runs automatically, so it clears on the next boot. If routes still 404, confirm ${entry} calls createRouter().`
12268
+ message: `[rango] No routers found while Vite was re-optimizing dependencies on dev boot. This is transient: routes are served per-request and discovery re-runs automatically, so it clears on the next boot. If routes still 404, confirm ${entry2} calls createRouter().`
12009
12269
  };
12010
12270
  }
12011
12271
  return {
12012
12272
  level: "error",
12013
12273
  message: `${err.message}
12014
- Ensure ${entry} calls createRouter() at module top level and that the configured router entry path is correct.`
12274
+ Ensure ${entry2} calls createRouter() at module top level and that the configured router entry path is correct.`
12015
12275
  };
12016
12276
  }
12017
12277
  const e = err;
@@ -13809,9 +14069,9 @@ function devServerPhase(s, server) {
13809
14069
  if (s.resolvedEntryPath) {
13810
14070
  routerSourceFiles.add(resolve12(s.resolvedEntryPath));
13811
14071
  }
13812
- for (const entry of s.perRouterManifests) {
13813
- if (entry.sourceFile) {
13814
- routerSourceFiles.add(resolve12(entry.sourceFile));
14072
+ for (const entry2 of s.perRouterManifests) {
14073
+ if (entry2.sourceFile) {
14074
+ routerSourceFiles.add(resolve12(entry2.sourceFile));
13815
14075
  }
13816
14076
  }
13817
14077
  const seen = /* @__PURE__ */ new Set();
@@ -13916,11 +14176,11 @@ function digestDirectory(dir) {
13916
14176
  const entries = readdirSync3(current, { withFileTypes: true }).sort(
13917
14177
  (a, b) => compareStrings(a.name, b.name)
13918
14178
  );
13919
- for (const entry of entries) {
13920
- if (entry.name === "node_modules" || entry.name === ".git") continue;
13921
- const path6 = join8(current, entry.name);
13922
- const name = `${prefix}${entry.name}`;
13923
- const kind = entry.isSymbolicLink() ? linkTarget(path6) : entry;
14179
+ for (const entry2 of entries) {
14180
+ if (entry2.name === "node_modules" || entry2.name === ".git") continue;
14181
+ const path6 = join8(current, entry2.name);
14182
+ const name = `${prefix}${entry2.name}`;
14183
+ const kind = entry2.isSymbolicLink() ? linkTarget(path6) : entry2;
13924
14184
  if (kind?.isDirectory()) {
13925
14185
  visit(path6, `${name}/`);
13926
14186
  } else if (kind?.isFile()) {
@@ -14027,9 +14287,9 @@ function readServerResources(manifest) {
14027
14287
  );
14028
14288
  }
14029
14289
  return new Map(
14030
- entries.map((entry) => [
14031
- entry.key,
14032
- manifest.slice(entry.value.start, entry.value.end)
14290
+ entries.map((entry2) => [
14291
+ entry2.key,
14292
+ manifest.slice(entry2.value.start, entry2.value.end)
14033
14293
  ])
14034
14294
  );
14035
14295
  }
@@ -14118,9 +14378,9 @@ function runRouterVersionsPhase(s, builder) {
14118
14378
  { fileName: ASSETS_MANIFEST_FILE, name: ASSETS_MANIFEST_FILE }
14119
14379
  ]
14120
14380
  },
14121
- routers: s.perRouterManifests.map((entry) => ({
14122
- id: entry.id,
14123
- moduleId: entry.sourceFile
14381
+ routers: s.perRouterManifests.map((entry2) => ({
14382
+ id: entry2.id,
14383
+ moduleId: entry2.sourceFile
14124
14384
  })),
14125
14385
  buildData: [...s.buildData, ...clientUrlRecords(s)],
14126
14386
  readServerFile: (fileName) => readIfPresent(join9(rscOutDir, fileName)),
@@ -14159,9 +14419,9 @@ function runRouterVersionsPhase(s, builder) {
14159
14419
  }
14160
14420
  const elapsed = (performance.now() - start).toFixed(1);
14161
14421
  const sourceOf = new Map(
14162
- s.perRouterManifests.map((entry) => [
14163
- entry.id,
14164
- entry.sourceFile ? portableModuleId(entry.sourceFile, s.projectRoot) : ""
14422
+ s.perRouterManifests.map((entry2) => [
14423
+ entry2.id,
14424
+ entry2.sourceFile ? portableModuleId(entry2.sourceFile, s.projectRoot) : ""
14165
14425
  ])
14166
14426
  );
14167
14427
  const detailOf = new Map(details.map((detail) => [detail.routerId, detail]));
@@ -14666,7 +14926,7 @@ function bundleScanPhase(s, context, bundle) {
14666
14926
  }
14667
14927
 
14668
14928
  // src/vite/utils/forward-user-plugins.ts
14669
- function isDenied(name) {
14929
+ function isFrameworkPlugin(name) {
14670
14930
  return name.startsWith("vite:") || name === "rsc" || name.startsWith("rsc:") || name.startsWith("@rangojs/router") || name.startsWith("@cloudflare/vite-plugin") || name.startsWith("vite-plugin-cloudflare");
14671
14931
  }
14672
14932
  var IMPORT_REWRITE_PLUGINS = /* @__PURE__ */ new Set([
@@ -14693,7 +14953,7 @@ function selectForwardableResolvePlugins(plugins) {
14693
14953
  const forwarded = [];
14694
14954
  for (const p of plugins) {
14695
14955
  const name = p?.name;
14696
- if (!name || isDenied(name)) continue;
14956
+ if (!name || isFrameworkPlugin(name)) continue;
14697
14957
  if (!isForwardable(p)) continue;
14698
14958
  forwarded.push(stripToResolutionHooks(p));
14699
14959
  }
@@ -14759,8 +15019,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
14759
15019
  s.resolvedEntryPath = opts.routerPathRef.path;
14760
15020
  }
14761
15021
  if (!s.resolvedEntryPath) {
14762
- const entry = resolveRscEntryFromConfig(config);
14763
- if (entry) s.resolvedEntryPath = entry;
15022
+ const entry2 = resolveRscEntryFromConfig(config);
15023
+ if (entry2) s.resolvedEntryPath = entry2;
14764
15024
  }
14765
15025
  if (opts?.staticRouteTypesGeneration !== false) {
14766
15026
  s.cachedRouterFiles = findRouterFiles(s.projectRoot, s.scanFilter);