@rangojs/router 0.24.4 → 0.25.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 (267) hide show
  1. package/README.md +1 -0
  2. package/dist/bin/rango.js +363 -39
  3. package/dist/testing/vitest.js +37 -4
  4. package/dist/types/browser/event-controller.d.ts +24 -5
  5. package/dist/types/browser/intercept-utils.d.ts +5 -2
  6. package/dist/types/browser/merge-segment-loaders.d.ts +0 -23
  7. package/dist/types/browser/navigation-transaction.d.ts +5 -5
  8. package/dist/types/browser/partial-update.d.ts +21 -13
  9. package/dist/types/browser/prefetch/cache.d.ts +8 -0
  10. package/dist/types/browser/rango-marker.d.ts +7 -0
  11. package/dist/types/browser/react/filter-segment-order.d.ts +10 -0
  12. package/dist/types/browser/react/use-handle.d.ts +20 -0
  13. package/dist/types/browser/react/use-href.d.ts +6 -0
  14. package/dist/types/browser/react/use-router.d.ts +6 -1
  15. package/dist/types/browser/response-adapter.d.ts +5 -3
  16. package/dist/types/browser/scroll-restoration.d.ts +9 -3
  17. package/dist/types/browser/segment-reconciler.d.ts +10 -13
  18. package/dist/types/browser/types.d.ts +38 -8
  19. package/dist/types/build/route-types/per-module-writer.d.ts +12 -0
  20. package/dist/types/cache/cf/cf-shell-frame.d.ts +2 -0
  21. package/dist/types/cache/types.d.ts +8 -0
  22. package/dist/types/client-urls/client-urls.d.ts +6 -2
  23. package/dist/types/client-urls/revalidate-registry.d.ts +1 -1
  24. package/dist/types/client-urls/server-projection.d.ts +9 -5
  25. package/dist/types/client-urls/types.d.ts +29 -16
  26. package/dist/types/client.d.ts +2 -2
  27. package/dist/types/client.rsc.d.ts +2 -2
  28. package/dist/types/decode-loader-results.d.ts +28 -7
  29. package/dist/types/href-client.d.ts +3 -1
  30. package/dist/types/index.rsc.d.ts +1 -1
  31. package/dist/types/loader-redirect.d.ts +2 -3
  32. package/dist/types/outlet-context.d.ts +7 -6
  33. package/dist/types/prefetch-markers.d.ts +14 -5
  34. package/dist/types/route-content-wrapper.d.ts +17 -14
  35. package/dist/types/route-definition/helpers-types.d.ts +7 -2
  36. package/dist/types/route-definition/resolve-handler-use.d.ts +6 -1
  37. package/dist/types/route-definition/rewrite.d.ts +48 -5
  38. package/dist/types/route-types.d.ts +2 -2
  39. package/dist/types/router/handler-context.d.ts +14 -2
  40. package/dist/types/router/intercept-resolution.d.ts +19 -46
  41. package/dist/types/router/lazy-includes.d.ts +7 -0
  42. package/dist/types/router/match-middleware/intercept-resolution.d.ts +2 -2
  43. package/dist/types/router/middleware.d.ts +0 -16
  44. package/dist/types/router/navigation-snapshot.d.ts +2 -0
  45. package/dist/types/router/prefetch-cache-ttl.d.ts +8 -11
  46. package/dist/types/router/revalidation.d.ts +8 -1
  47. package/dist/types/router/router-context.d.ts +4 -16
  48. package/dist/types/router/router-interfaces.d.ts +0 -6
  49. package/dist/types/router/router-options.d.ts +4 -7
  50. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +31 -8
  51. package/dist/types/router/segment-resolution/revalidation.d.ts +38 -4
  52. package/dist/types/router/segment-resolution.d.ts +1 -1
  53. package/dist/types/router/segment-wrappers.d.ts +3 -5
  54. package/dist/types/router/substitute-pattern-params.d.ts +3 -2
  55. package/dist/types/router/tracing.d.ts +2 -2
  56. package/dist/types/rsc/full-payload.d.ts +14 -2
  57. package/dist/types/rsc/helpers.d.ts +8 -0
  58. package/dist/types/rsc/manifest-init.d.ts +20 -0
  59. package/dist/types/rsc/prefetch-render-error.d.ts +22 -0
  60. package/dist/types/rsc/progressive-enhancement.d.ts +20 -0
  61. package/dist/types/rsc/rewrite-passes.d.ts +12 -2
  62. package/dist/types/rsc/server-action.d.ts +6 -0
  63. package/dist/types/rsc/shell-capture-constants.d.ts +10 -1
  64. package/dist/types/rsc/shell-capture.d.ts +7 -0
  65. package/dist/types/rsc/types.d.ts +5 -0
  66. package/dist/types/segment-system.d.ts +15 -0
  67. package/dist/types/server/context.d.ts +64 -4
  68. package/dist/types/server/request-context.d.ts +41 -4
  69. package/dist/types/server/request-headers.d.ts +12 -0
  70. package/dist/types/server/rewrite-trail.d.ts +8 -1
  71. package/dist/types/testing/e2e/index.d.ts +1 -1
  72. package/dist/types/testing/flight.entry.d.ts +1 -1
  73. package/dist/types/testing/index.d.ts +1 -1
  74. package/dist/types/testing/internal/client-urls-projection.d.ts +4 -3
  75. package/dist/types/testing/render-route.d.ts +21 -11
  76. package/dist/types/testing/run-loader.d.ts +7 -0
  77. package/dist/types/testing/run-middleware.d.ts +7 -0
  78. package/dist/types/testing/run-revalidate.d.ts +5 -4
  79. package/dist/types/testing/serve-shell-request.d.ts +41 -4
  80. package/dist/types/testing/shell-status.d.ts +17 -0
  81. package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
  82. package/dist/types/testing/vitest.d.ts +10 -1
  83. package/dist/types/thenable-status.d.ts +0 -6
  84. package/dist/types/types/handler-context.d.ts +12 -1
  85. package/dist/types/types/loader-types.d.ts +4 -3
  86. package/dist/types/types/route-entry.d.ts +2 -1
  87. package/dist/types/urls/path-helper-types.d.ts +4 -2
  88. package/dist/types/vite/discovery/client-urls-projection.d.ts +55 -5
  89. package/dist/types/vite/discovery/state.d.ts +20 -0
  90. package/dist/types/vite/plugins/client-urls-revalidate-hoist.d.ts +28 -16
  91. package/dist/types/vite/plugins/hoist/source.d.ts +8 -7
  92. package/dist/types/vite/plugins/virtual-entries.d.ts +6 -0
  93. package/dist/types/vite/utils/prerender-utils.d.ts +7 -0
  94. package/dist/vite/index.js +6816 -6547
  95. package/package.json +1 -1
  96. package/skills/app-structure/SKILL.md +255 -0
  97. package/skills/app-structure/content-site.md +333 -0
  98. package/skills/app-structure/e-commerce.md +435 -0
  99. package/skills/app-structure/large-app.md +885 -0
  100. package/skills/app-structure/multi-app.md +280 -0
  101. package/skills/breadcrumbs/SKILL.md +6 -1
  102. package/skills/caching/SKILL.md +3 -1
  103. package/skills/catalog.json +12 -0
  104. package/skills/client-urls/SKILL.md +185 -32
  105. package/skills/composability/SKILL.md +10 -8
  106. package/skills/handler-use/SKILL.md +48 -9
  107. package/skills/hooks/handle-and-actions.md +104 -0
  108. package/skills/hooks/navigation.md +24 -10
  109. package/skills/hooks/urls.md +1 -1
  110. package/skills/i18n/SKILL.md +2 -1
  111. package/skills/intercept/SKILL.md +60 -29
  112. package/skills/layout/SKILL.md +6 -3
  113. package/skills/links/SKILL.md +151 -17
  114. package/skills/loader/SKILL.md +32 -10
  115. package/skills/middleware/SKILL.md +111 -15
  116. package/skills/observability/SKILL.md +11 -0
  117. package/skills/parallel/SKILL.md +5 -5
  118. package/skills/ppr/SKILL.md +43 -8
  119. package/skills/prerender/SKILL.md +1 -2
  120. package/skills/rango/SKILL.md +3 -0
  121. package/skills/response-routes/SKILL.md +4 -1
  122. package/skills/scripts/SKILL.md +12 -1
  123. package/skills/server-actions/SKILL.md +60 -20
  124. package/skills/testing/SKILL.md +1 -0
  125. package/skills/testing/client-components.md +13 -10
  126. package/skills/testing/loader.md +25 -24
  127. package/skills/testing/middleware.md +11 -11
  128. package/skills/testing/response-routes.md +4 -1
  129. package/skills/testing/serve-shell-request.md +85 -21
  130. package/skills/ux-architecture/SKILL.md +980 -0
  131. package/skills/view-transitions/SKILL.md +43 -10
  132. package/src/__augment-tests__/augmented.check.ts +28 -0
  133. package/src/browser/event-controller.ts +44 -18
  134. package/src/browser/intercept-utils.ts +3 -2
  135. package/src/browser/merge-segment-loaders.ts +0 -85
  136. package/src/browser/navigation-bridge.ts +112 -84
  137. package/src/browser/navigation-client.ts +20 -15
  138. package/src/browser/navigation-store.ts +4 -2
  139. package/src/browser/navigation-transaction.ts +9 -8
  140. package/src/browser/partial-update.ts +90 -32
  141. package/src/browser/prefetch/cache.ts +8 -0
  142. package/src/browser/prefetch/fetch.ts +13 -3
  143. package/src/browser/rango-marker.ts +13 -0
  144. package/src/browser/react/NavigationProvider.tsx +25 -7
  145. package/src/browser/react/filter-segment-order.ts +13 -0
  146. package/src/browser/react/use-action.ts +9 -15
  147. package/src/browser/react/use-handle.ts +63 -71
  148. package/src/browser/react/use-href.tsx +24 -5
  149. package/src/browser/react/use-link-status.ts +1 -1
  150. package/src/browser/react/use-navigation.ts +30 -40
  151. package/src/browser/react/use-router.ts +37 -6
  152. package/src/browser/react/use-segments.ts +8 -12
  153. package/src/browser/response-adapter.ts +11 -5
  154. package/src/browser/rsc-router.tsx +3 -1
  155. package/src/browser/scroll-restoration.ts +34 -20
  156. package/src/browser/segment-reconciler.ts +11 -29
  157. package/src/browser/server-action-bridge.ts +52 -16
  158. package/src/browser/types.ts +40 -8
  159. package/src/build/generate-manifest.ts +12 -1
  160. package/src/build/route-types/codegen.ts +6 -2
  161. package/src/build/route-types/per-module-writer.ts +94 -61
  162. package/src/cache/cache-runtime.ts +9 -0
  163. package/src/cache/cache-scope.ts +2 -1
  164. package/src/cache/cf/cf-cache-store.ts +2 -0
  165. package/src/cache/cf/cf-shell-frame.ts +3 -0
  166. package/src/cache/types.ts +8 -0
  167. package/src/cache/vercel/vercel-cache-store.ts +6 -1
  168. package/src/client-urls/client-urls.ts +202 -153
  169. package/src/client-urls/revalidate-registry.ts +12 -3
  170. package/src/client-urls/server-projection.ts +137 -66
  171. package/src/client-urls/types.ts +30 -15
  172. package/src/client.rsc.tsx +11 -1
  173. package/src/client.tsx +9 -1
  174. package/src/decode-loader-results.ts +64 -31
  175. package/src/href-client.ts +3 -1
  176. package/src/index.rsc.ts +1 -0
  177. package/src/index.ts +12 -4
  178. package/src/loader-redirect.tsx +2 -3
  179. package/src/outlet-context.ts +7 -6
  180. package/src/prefetch-markers.ts +15 -5
  181. package/src/reverse.ts +3 -3
  182. package/src/route-content-wrapper.tsx +19 -17
  183. package/src/route-definition/dsl-helpers.ts +27 -7
  184. package/src/route-definition/helpers-types.ts +7 -2
  185. package/src/route-definition/resolve-handler-use.ts +23 -10
  186. package/src/route-definition/rewrite.ts +86 -19
  187. package/src/route-types.ts +1 -2
  188. package/src/router/find-match.ts +37 -1
  189. package/src/router/handler-context.ts +85 -40
  190. package/src/router/intercept-resolution.ts +161 -307
  191. package/src/router/lazy-includes.ts +43 -27
  192. package/src/router/loader-resolution.ts +21 -1
  193. package/src/router/manifest.ts +6 -8
  194. package/src/router/match-api.ts +11 -1
  195. package/src/router/match-middleware/background-revalidation.ts +2 -4
  196. package/src/router/match-middleware/cache-lookup.ts +16 -20
  197. package/src/router/match-middleware/intercept-resolution.ts +41 -60
  198. package/src/router/match-result.ts +31 -2
  199. package/src/router/middleware.ts +6 -147
  200. package/src/router/navigation-snapshot.ts +38 -2
  201. package/src/router/prefetch-cache-ttl.ts +10 -18
  202. package/src/router/prerender-match.ts +2 -1
  203. package/src/router/revalidation.ts +24 -3
  204. package/src/router/router-context.ts +5 -18
  205. package/src/router/router-interfaces.ts +0 -7
  206. package/src/router/router-options.ts +4 -7
  207. package/src/router/segment-resolution/fresh.ts +6 -2
  208. package/src/router/segment-resolution/helpers.ts +7 -1
  209. package/src/router/segment-resolution/prefetch-deferral.ts +62 -12
  210. package/src/router/segment-resolution/revalidation.ts +75 -35
  211. package/src/router/segment-resolution.ts +0 -1
  212. package/src/router/segment-wrappers.ts +8 -13
  213. package/src/router/substitute-pattern-params.ts +3 -2
  214. package/src/router/tracing.ts +2 -2
  215. package/src/router.ts +2 -9
  216. package/src/rsc/full-payload.ts +26 -4
  217. package/src/rsc/handler.ts +83 -41
  218. package/src/rsc/helpers.ts +13 -0
  219. package/src/rsc/manifest-init.ts +56 -3
  220. package/src/rsc/prefetch-render-error.ts +38 -0
  221. package/src/rsc/progressive-enhancement.ts +161 -211
  222. package/src/rsc/rewrite-passes.ts +56 -9
  223. package/src/rsc/rsc-rendering.ts +79 -23
  224. package/src/rsc/server-action.ts +25 -2
  225. package/src/rsc/shell-capture-constants.ts +22 -0
  226. package/src/rsc/shell-capture.ts +11 -0
  227. package/src/rsc/types.ts +5 -0
  228. package/src/segment-system.tsx +125 -119
  229. package/src/server/context.ts +96 -5
  230. package/src/server/handle-store.ts +3 -2
  231. package/src/server/request-context.ts +42 -3
  232. package/src/server/request-headers.ts +32 -0
  233. package/src/server/rewrite-trail.ts +55 -9
  234. package/src/ssr/ssr-root.tsx +6 -10
  235. package/src/testing/dispatch.ts +4 -5
  236. package/src/testing/e2e/index.ts +1 -0
  237. package/src/testing/flight.entry.ts +1 -0
  238. package/src/testing/index.ts +1 -0
  239. package/src/testing/internal/client-urls-projection.ts +31 -11
  240. package/src/testing/render-route.tsx +83 -40
  241. package/src/testing/run-loader.ts +26 -2
  242. package/src/testing/run-middleware.ts +10 -0
  243. package/src/testing/run-revalidate.ts +13 -6
  244. package/src/testing/serve-shell-request.ts +77 -4
  245. package/src/testing/shell-status.ts +40 -0
  246. package/src/testing/vitest-stubs/version.ts +1 -0
  247. package/src/testing/vitest.ts +74 -7
  248. package/src/thenable-status.ts +0 -11
  249. package/src/types/handler-context.ts +12 -1
  250. package/src/types/loader-types.ts +4 -3
  251. package/src/types/route-entry.ts +2 -1
  252. package/src/urls/include-helper.ts +38 -11
  253. package/src/urls/path-helper-types.ts +4 -2
  254. package/src/vite/discovery/client-urls-projection.ts +205 -16
  255. package/src/vite/discovery/discover-routers.ts +2 -2
  256. package/src/vite/discovery/prerender-collection.ts +2 -6
  257. package/src/vite/discovery/state.ts +26 -0
  258. package/src/vite/plugins/client-urls-revalidate-hoist.ts +190 -77
  259. package/src/vite/plugins/expose-internal-ids.ts +46 -40
  260. package/src/vite/plugins/hoist/source.ts +8 -7
  261. package/src/vite/plugins/transition-when-hoist.ts +1 -0
  262. package/src/vite/plugins/version-plugin.ts +7 -0
  263. package/src/vite/plugins/version.d.ts +7 -0
  264. package/src/vite/plugins/virtual-entries.ts +20 -0
  265. package/src/vite/rango.ts +4 -1
  266. package/src/vite/router-discovery.ts +39 -7
  267. package/src/vite/utils/prerender-utils.ts +17 -0
package/src/vite/rango.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  import { useCacheTransform } from "./plugins/use-cache-transform.js";
16
16
  import { transitionWhenHoistPlugin } from "./plugins/transition-when-hoist.js";
17
17
  import { clientUrlsRevalidateHoistPlugin } from "./plugins/client-urls-revalidate-hoist.js";
18
+ import { createClientUrlRevalidateIndex } from "./discovery/state.js";
18
19
  import { clientRefDedup } from "./plugins/client-ref-dedup.js";
19
20
  import { stableRscOutput } from "./plugins/stable-rsc-output.js";
20
21
  import { VIRTUAL_IDS } from "./plugins/virtual-entries.js";
@@ -593,7 +594,8 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
593
594
 
594
595
  plugins.push(createLoaderDirectiveGuardPlugin());
595
596
  plugins.push(transitionWhenHoistPlugin());
596
- plugins.push(...clientUrlsRevalidateHoistPlugin());
597
+ const clientUrlRevalidate = createClientUrlRevalidateIndex();
598
+ plugins.push(...clientUrlsRevalidateHoistPlugin(clientUrlRevalidate));
597
599
  plugins.push(createLoaderScanStubPlugin());
598
600
  plugins.push(exposeActionId());
599
601
  plugins.push(
@@ -623,6 +625,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
623
625
  prerenderOnError: options?.prerender?.onError,
624
626
  discovery: options?.discovery,
625
627
  clientChunkCtx,
628
+ clientUrlRevalidate,
626
629
  headScripts: resolvedOptions.headScripts,
627
630
  progressiveChunkSize: resolvedOptions.progressiveChunkSize,
628
631
  }),
@@ -64,6 +64,7 @@ import {
64
64
  } from "./discovery/self-gen-tracking.js";
65
65
  import { discoverRouters } from "./discovery/discover-routers.js";
66
66
  import {
67
+ componentUseSignature,
67
68
  recordClientUrlsModule,
68
69
  refreshRecordedClientUrlProjections,
69
70
  } from "./discovery/client-urls-projection.js";
@@ -334,8 +335,9 @@ export async function createTempRscServer(
334
335
  transitionWhenHoistPlugin(),
335
336
  // clientUrls() revalidate() predicates move to the server here too:
336
337
  // discovery serializes the SSR copy's markers and the RSC realm
337
- // registers the predicates the materialized stubs call.
338
- ...clientUrlsRevalidateHoistPlugin(),
338
+ // registers the predicates the materialized stubs call. The index is
339
+ // the main plugin's, so its group modules import the files assigned here.
340
+ ...clientUrlsRevalidateHoistPlugin(state.clientUrlRevalidate),
339
341
  // Dev prerender must use dev-mode IDs (path-based) to match the workerd
340
342
  // runtime. forceBuild produces hashed IDs for production bundle consistency.
341
343
  exposeInternalIds(options.forceBuild ? { forceBuild: true } : undefined),
@@ -1982,6 +1984,7 @@ export function createRouterDiscoveryPlugin(
1982
1984
  s,
1983
1985
  (server.environments as any)?.ssr,
1984
1986
  serverMod,
1987
+ rscEnv,
1985
1988
  );
1986
1989
  // Force the routes-manifest virtual module to re-transform:
1987
1990
  // its generated code REPLAYS projections (clear + set) on
@@ -2043,6 +2046,17 @@ export function createRouterDiscoveryPlugin(
2043
2046
  }, 100);
2044
2047
  };
2045
2048
 
2049
+ // The `.use` signature of each component-use module at its last
2050
+ // save: a save that keeps it (markup, hooks) re-projects nothing.
2051
+ const componentUseSignatures = new Map<string, string>();
2052
+ const componentUseChanged = (file: string, source: string) => {
2053
+ const next = componentUseSignature(source, file);
2054
+ const changed = next !== componentUseSignatures.get(file);
2055
+ if (next === undefined) componentUseSignatures.delete(file);
2056
+ else componentUseSignatures.set(file, next);
2057
+ return changed;
2058
+ };
2059
+
2046
2060
  const handleRouteFileChange = (filePath: string) => {
2047
2061
  if (isOutsideApp(filePath)) {
2048
2062
  debugDiscovery?.(
@@ -2105,7 +2119,18 @@ export function createRouterDiscoveryPlugin(
2105
2119
  hasClientUrls =
2106
2120
  firstCodeMatchIndex(source, /\bclientUrls\(/g) >= 0;
2107
2121
  }
2108
- if (!inRecoveryMode && isUseClient && !hasClientUrls) return;
2122
+ // A component whose `.use` a group reads changes the group's
2123
+ // projection too (its loaders, loading(), revalidate() keys):
2124
+ // on its first save, and when a `.use` changed, came or went.
2125
+ const hasComponentUse = componentUseChanged(filePath, source);
2126
+ if (
2127
+ !inRecoveryMode &&
2128
+ isUseClient &&
2129
+ !hasClientUrls &&
2130
+ !hasComponentUse
2131
+ ) {
2132
+ return;
2133
+ }
2109
2134
  // Cheap raw pre-check first; only when a candidate token is present
2110
2135
  // do we confirm it occurs in real code (not a comment/string) via a
2111
2136
  // single allocation-free code-region scan. Most saved files contain
@@ -2127,7 +2152,8 @@ export function createRouterDiscoveryPlugin(
2127
2152
  !inRecoveryMode &&
2128
2153
  !hasUrls &&
2129
2154
  !hasCreateRouter &&
2130
- !hasClientUrls
2155
+ !hasClientUrls &&
2156
+ !hasComponentUse
2131
2157
  ) {
2132
2158
  return;
2133
2159
  }
@@ -2143,11 +2169,12 @@ export function createRouterDiscoveryPlugin(
2143
2169
  );
2144
2170
  } else {
2145
2171
  debugDiscovery?.(
2146
- "watcher: %s matches (urls=%s, router=%s, clientUrls=%s)",
2172
+ "watcher: %s matches (urls=%s, router=%s, clientUrls=%s, componentUse=%s)",
2147
2173
  filePath,
2148
2174
  hasUrls,
2149
2175
  hasCreateRouter,
2150
2176
  hasClientUrls,
2177
+ hasComponentUse,
2151
2178
  );
2152
2179
  }
2153
2180
  // A "use client" clientUrls module is an HMR-accepted client
@@ -2159,7 +2186,10 @@ export function createRouterDiscoveryPlugin(
2159
2186
  // against the refreshed projection (installed by the pre-entry
2160
2187
  // refresh in discover-routers.ts).
2161
2188
  const mainRscEnv = (server.environments as any)?.rsc;
2162
- if (isUseClient && hasClientUrls && mainRscEnv?.runner) {
2189
+ if (
2190
+ ((isUseClient && hasClientUrls) || hasComponentUse) &&
2191
+ mainRscEnv?.runner
2192
+ ) {
2163
2193
  const rscGraph = mainRscEnv.moduleGraph;
2164
2194
  if (rscGraph?.getModulesByFile) {
2165
2195
  // Importers must be invalidated too: the virtual RSC entry
@@ -2483,7 +2513,9 @@ export function createRouterDiscoveryPlugin(
2483
2513
  () => generateRoutesManifestModule(s),
2484
2514
  );
2485
2515
  debugRoutes?.("manifest module emitted (%d bytes)", code?.length ?? 0);
2486
- return code;
2516
+ // Only ever a bare import (the RSC entry's), so a build whose
2517
+ // treeshake.moduleSideEffects is false would drop it; load outranks it.
2518
+ return { code, moduleSideEffects: "no-treeshake" };
2487
2519
  }
2488
2520
  // Per-router virtual modules: pure data exports (no side effects).
2489
2521
  // ensureRouterManifest() imports the module and stores the data.
@@ -10,12 +10,29 @@ import {
10
10
  import { resolve } from "node:path";
11
11
 
12
12
  import { escapeRegExp } from "../../regex-escape.js";
13
+ import { substitutePatternParams } from "../../router/substitute-pattern-params.js";
13
14
  import { encodePathRemainder } from "../../router/url-params.js";
14
15
 
15
16
  export function encodePathParam(value: unknown): string {
16
17
  return encodePathRemainder(String(value), encodeURIComponent);
17
18
  }
18
19
 
20
+ /**
21
+ * `ctx.reverse` of a build-time `getParams()`. Substitutes like the dev-mode
22
+ * one (`createReverseFunction`, router/prerender-match.ts): a missing required
23
+ * param throws `Missing param`, with or without a params object, instead of
24
+ * leaving a literal `:param` in the URL.
25
+ */
26
+ export function createGetParamsReverse(
27
+ routes: Record<string, string>,
28
+ ): (name: string, params?: Record<string, string>) => string {
29
+ return (name, params) => {
30
+ const pattern = routes[name];
31
+ if (!pattern) throw new Error(`Unknown route: "${name}"`);
32
+ return substitutePatternParams(pattern, params ?? {}, name);
33
+ };
34
+ }
35
+
19
36
  export function substituteRouteParams(
20
37
  pattern: string,
21
38
  params: Record<string, string>,