@rangojs/router 0.0.0-experimental.7 → 0.0.0-experimental.70

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 (307) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +942 -4
  3. package/dist/bin/rango.js +1689 -0
  4. package/dist/vite/index.js +4951 -930
  5. package/package.json +70 -60
  6. package/skills/breadcrumbs/SKILL.md +250 -0
  7. package/skills/cache-guide/SKILL.md +294 -0
  8. package/skills/caching/SKILL.md +93 -23
  9. package/skills/composability/SKILL.md +172 -0
  10. package/skills/debug-manifest/SKILL.md +12 -8
  11. package/skills/document-cache/SKILL.md +18 -16
  12. package/skills/fonts/SKILL.md +167 -0
  13. package/skills/hooks/SKILL.md +334 -72
  14. package/skills/host-router/SKILL.md +218 -0
  15. package/skills/intercept/SKILL.md +131 -8
  16. package/skills/layout/SKILL.md +100 -3
  17. package/skills/links/SKILL.md +92 -31
  18. package/skills/loader/SKILL.md +404 -44
  19. package/skills/middleware/SKILL.md +173 -34
  20. package/skills/mime-routes/SKILL.md +128 -0
  21. package/skills/parallel/SKILL.md +204 -1
  22. package/skills/prerender/SKILL.md +685 -0
  23. package/skills/rango/SKILL.md +85 -16
  24. package/skills/response-routes/SKILL.md +411 -0
  25. package/skills/route/SKILL.md +257 -14
  26. package/skills/router-setup/SKILL.md +210 -32
  27. package/skills/tailwind/SKILL.md +129 -0
  28. package/skills/theme/SKILL.md +9 -8
  29. package/skills/typesafety/SKILL.md +328 -89
  30. package/skills/use-cache/SKILL.md +324 -0
  31. package/src/__internal.ts +102 -4
  32. package/src/bin/rango.ts +321 -0
  33. package/src/browser/action-coordinator.ts +97 -0
  34. package/src/browser/action-response-classifier.ts +99 -0
  35. package/src/browser/app-version.ts +14 -0
  36. package/src/browser/event-controller.ts +92 -64
  37. package/src/browser/history-state.ts +80 -0
  38. package/src/browser/intercept-utils.ts +52 -0
  39. package/src/browser/link-interceptor.ts +24 -4
  40. package/src/browser/logging.ts +55 -0
  41. package/src/browser/merge-segment-loaders.ts +20 -12
  42. package/src/browser/navigation-bridge.ts +296 -558
  43. package/src/browser/navigation-client.ts +179 -69
  44. package/src/browser/navigation-store.ts +73 -55
  45. package/src/browser/navigation-transaction.ts +297 -0
  46. package/src/browser/network-error-handler.ts +61 -0
  47. package/src/browser/partial-update.ts +328 -313
  48. package/src/browser/prefetch/cache.ts +206 -0
  49. package/src/browser/prefetch/fetch.ts +150 -0
  50. package/src/browser/prefetch/observer.ts +65 -0
  51. package/src/browser/prefetch/policy.ts +48 -0
  52. package/src/browser/prefetch/queue.ts +160 -0
  53. package/src/browser/prefetch/resource-ready.ts +77 -0
  54. package/src/browser/rango-state.ts +112 -0
  55. package/src/browser/react/Link.tsx +230 -74
  56. package/src/browser/react/NavigationProvider.tsx +87 -11
  57. package/src/browser/react/context.ts +11 -0
  58. package/src/browser/react/filter-segment-order.ts +11 -0
  59. package/src/browser/react/index.ts +12 -12
  60. package/src/browser/react/location-state-shared.ts +95 -53
  61. package/src/browser/react/location-state.ts +60 -15
  62. package/src/browser/react/mount-context.ts +6 -1
  63. package/src/browser/react/nonce-context.ts +23 -0
  64. package/src/browser/react/shallow-equal.ts +27 -0
  65. package/src/browser/react/use-action.ts +29 -51
  66. package/src/browser/react/use-client-cache.ts +5 -3
  67. package/src/browser/react/use-handle.ts +30 -126
  68. package/src/browser/react/use-href.tsx +2 -2
  69. package/src/browser/react/use-link-status.ts +6 -5
  70. package/src/browser/react/use-navigation.ts +22 -63
  71. package/src/browser/react/use-params.ts +65 -0
  72. package/src/browser/react/use-pathname.ts +47 -0
  73. package/src/browser/react/use-router.ts +76 -0
  74. package/src/browser/react/use-search-params.ts +56 -0
  75. package/src/browser/react/use-segments.ts +80 -97
  76. package/src/browser/response-adapter.ts +73 -0
  77. package/src/browser/rsc-router.tsx +214 -58
  78. package/src/browser/scroll-restoration.ts +127 -52
  79. package/src/browser/segment-reconciler.ts +221 -0
  80. package/src/browser/segment-structure-assert.ts +16 -0
  81. package/src/browser/server-action-bridge.ts +510 -603
  82. package/src/browser/shallow.ts +6 -1
  83. package/src/browser/types.ts +141 -48
  84. package/src/browser/validate-redirect-origin.ts +29 -0
  85. package/src/build/generate-manifest.ts +235 -24
  86. package/src/build/generate-route-types.ts +39 -0
  87. package/src/build/index.ts +13 -0
  88. package/src/build/route-trie.ts +265 -0
  89. package/src/build/route-types/ast-helpers.ts +25 -0
  90. package/src/build/route-types/ast-route-extraction.ts +98 -0
  91. package/src/build/route-types/codegen.ts +102 -0
  92. package/src/build/route-types/include-resolution.ts +418 -0
  93. package/src/build/route-types/param-extraction.ts +48 -0
  94. package/src/build/route-types/per-module-writer.ts +128 -0
  95. package/src/build/route-types/router-processing.ts +618 -0
  96. package/src/build/route-types/scan-filter.ts +85 -0
  97. package/src/build/runtime-discovery.ts +231 -0
  98. package/src/cache/background-task.ts +34 -0
  99. package/src/cache/cache-key-utils.ts +44 -0
  100. package/src/cache/cache-policy.ts +125 -0
  101. package/src/cache/cache-runtime.ts +342 -0
  102. package/src/cache/cache-scope.ts +167 -309
  103. package/src/cache/cf/cf-cache-store.ts +571 -17
  104. package/src/cache/cf/index.ts +13 -3
  105. package/src/cache/document-cache.ts +116 -77
  106. package/src/cache/handle-capture.ts +81 -0
  107. package/src/cache/handle-snapshot.ts +41 -0
  108. package/src/cache/index.ts +1 -15
  109. package/src/cache/memory-segment-store.ts +191 -13
  110. package/src/cache/profile-registry.ts +73 -0
  111. package/src/cache/read-through-swr.ts +134 -0
  112. package/src/cache/segment-codec.ts +256 -0
  113. package/src/cache/taint.ts +153 -0
  114. package/src/cache/types.ts +72 -122
  115. package/src/client.rsc.tsx +3 -1
  116. package/src/client.tsx +105 -179
  117. package/src/component-utils.ts +4 -4
  118. package/src/components/DefaultDocument.tsx +5 -1
  119. package/src/context-var.ts +156 -0
  120. package/src/debug.ts +19 -9
  121. package/src/errors.ts +108 -2
  122. package/src/handle.ts +55 -29
  123. package/src/handles/MetaTags.tsx +73 -20
  124. package/src/handles/breadcrumbs.ts +66 -0
  125. package/src/handles/index.ts +1 -0
  126. package/src/handles/meta.ts +30 -13
  127. package/src/host/cookie-handler.ts +21 -15
  128. package/src/host/errors.ts +8 -8
  129. package/src/host/index.ts +4 -7
  130. package/src/host/pattern-matcher.ts +27 -27
  131. package/src/host/router.ts +61 -39
  132. package/src/host/testing.ts +8 -8
  133. package/src/host/types.ts +15 -7
  134. package/src/host/utils.ts +1 -1
  135. package/src/href-client.ts +119 -29
  136. package/src/index.rsc.ts +155 -19
  137. package/src/index.ts +223 -30
  138. package/src/internal-debug.ts +11 -0
  139. package/src/loader.rsc.ts +26 -157
  140. package/src/loader.ts +27 -10
  141. package/src/network-error-thrower.tsx +3 -1
  142. package/src/outlet-provider.tsx +45 -0
  143. package/src/prerender/param-hash.ts +37 -0
  144. package/src/prerender/store.ts +186 -0
  145. package/src/prerender.ts +524 -0
  146. package/src/reverse.ts +351 -0
  147. package/src/root-error-boundary.tsx +41 -29
  148. package/src/route-content-wrapper.tsx +7 -4
  149. package/src/route-definition/dsl-helpers.ts +982 -0
  150. package/src/route-definition/helper-factories.ts +200 -0
  151. package/src/route-definition/helpers-types.ts +434 -0
  152. package/src/route-definition/index.ts +55 -0
  153. package/src/route-definition/redirect.ts +101 -0
  154. package/src/route-definition/resolve-handler-use.ts +149 -0
  155. package/src/route-definition.ts +1 -1428
  156. package/src/route-map-builder.ts +217 -123
  157. package/src/route-name.ts +53 -0
  158. package/src/route-types.ts +70 -8
  159. package/src/router/content-negotiation.ts +215 -0
  160. package/src/router/debug-manifest.ts +72 -0
  161. package/src/router/error-handling.ts +9 -9
  162. package/src/router/find-match.ts +160 -0
  163. package/src/router/handler-context.ts +435 -86
  164. package/src/router/intercept-resolution.ts +402 -0
  165. package/src/router/lazy-includes.ts +237 -0
  166. package/src/router/loader-resolution.ts +356 -128
  167. package/src/router/logging.ts +251 -0
  168. package/src/router/manifest.ts +154 -35
  169. package/src/router/match-api.ts +555 -0
  170. package/src/router/match-context.ts +5 -3
  171. package/src/router/match-handlers.ts +440 -0
  172. package/src/router/match-middleware/background-revalidation.ts +108 -93
  173. package/src/router/match-middleware/cache-lookup.ts +459 -10
  174. package/src/router/match-middleware/cache-store.ts +98 -26
  175. package/src/router/match-middleware/intercept-resolution.ts +57 -17
  176. package/src/router/match-middleware/segment-resolution.ts +80 -6
  177. package/src/router/match-pipelines.ts +10 -45
  178. package/src/router/match-result.ts +55 -33
  179. package/src/router/metrics.ts +240 -15
  180. package/src/router/middleware-cookies.ts +55 -0
  181. package/src/router/middleware-types.ts +220 -0
  182. package/src/router/middleware.ts +324 -369
  183. package/src/router/navigation-snapshot.ts +182 -0
  184. package/src/router/pattern-matching.ts +211 -43
  185. package/src/router/prerender-match.ts +502 -0
  186. package/src/router/preview-match.ts +98 -0
  187. package/src/router/request-classification.ts +310 -0
  188. package/src/router/revalidation.ts +137 -38
  189. package/src/router/route-snapshot.ts +245 -0
  190. package/src/router/router-context.ts +41 -21
  191. package/src/router/router-interfaces.ts +484 -0
  192. package/src/router/router-options.ts +618 -0
  193. package/src/router/router-registry.ts +24 -0
  194. package/src/router/segment-resolution/fresh.ts +743 -0
  195. package/src/router/segment-resolution/helpers.ts +268 -0
  196. package/src/router/segment-resolution/loader-cache.ts +199 -0
  197. package/src/router/segment-resolution/revalidation.ts +1373 -0
  198. package/src/router/segment-resolution/static-store.ts +67 -0
  199. package/src/router/segment-resolution.ts +21 -0
  200. package/src/router/segment-wrappers.ts +291 -0
  201. package/src/router/telemetry-otel.ts +299 -0
  202. package/src/router/telemetry.ts +300 -0
  203. package/src/router/timeout.ts +148 -0
  204. package/src/router/trie-matching.ts +239 -0
  205. package/src/router/types.ts +78 -3
  206. package/src/router.ts +740 -4252
  207. package/src/rsc/handler-context.ts +45 -0
  208. package/src/rsc/handler.ts +907 -797
  209. package/src/rsc/helpers.ts +140 -6
  210. package/src/rsc/index.ts +0 -20
  211. package/src/rsc/loader-fetch.ts +229 -0
  212. package/src/rsc/manifest-init.ts +90 -0
  213. package/src/rsc/nonce.ts +14 -0
  214. package/src/rsc/origin-guard.ts +141 -0
  215. package/src/rsc/progressive-enhancement.ts +391 -0
  216. package/src/rsc/response-error.ts +37 -0
  217. package/src/rsc/response-route-handler.ts +347 -0
  218. package/src/rsc/rsc-rendering.ts +246 -0
  219. package/src/rsc/runtime-warnings.ts +42 -0
  220. package/src/rsc/server-action.ts +356 -0
  221. package/src/rsc/ssr-setup.ts +128 -0
  222. package/src/rsc/types.ts +46 -11
  223. package/src/search-params.ts +230 -0
  224. package/src/segment-system.tsx +165 -17
  225. package/src/server/context.ts +315 -58
  226. package/src/server/cookie-store.ts +190 -0
  227. package/src/server/fetchable-loader-store.ts +37 -0
  228. package/src/server/handle-store.ts +113 -15
  229. package/src/server/loader-registry.ts +24 -64
  230. package/src/server/request-context.ts +607 -81
  231. package/src/server.ts +35 -130
  232. package/src/ssr/index.tsx +103 -30
  233. package/src/static-handler.ts +126 -0
  234. package/src/theme/ThemeProvider.tsx +21 -15
  235. package/src/theme/ThemeScript.tsx +5 -5
  236. package/src/theme/constants.ts +5 -2
  237. package/src/theme/index.ts +4 -14
  238. package/src/theme/theme-context.ts +4 -30
  239. package/src/theme/theme-script.ts +21 -18
  240. package/src/types/boundaries.ts +158 -0
  241. package/src/types/cache-types.ts +198 -0
  242. package/src/types/error-types.ts +192 -0
  243. package/src/types/global-namespace.ts +100 -0
  244. package/src/types/handler-context.ts +791 -0
  245. package/src/types/index.ts +88 -0
  246. package/src/types/loader-types.ts +210 -0
  247. package/src/types/route-config.ts +170 -0
  248. package/src/types/route-entry.ts +109 -0
  249. package/src/types/segments.ts +150 -0
  250. package/src/types.ts +1 -1623
  251. package/src/urls/include-helper.ts +197 -0
  252. package/src/urls/index.ts +53 -0
  253. package/src/urls/path-helper-types.ts +346 -0
  254. package/src/urls/path-helper.ts +364 -0
  255. package/src/urls/pattern-types.ts +107 -0
  256. package/src/urls/response-types.ts +116 -0
  257. package/src/urls/type-extraction.ts +372 -0
  258. package/src/urls/urls-function.ts +98 -0
  259. package/src/urls.ts +1 -802
  260. package/src/use-loader.tsx +161 -81
  261. package/src/vite/discovery/bundle-postprocess.ts +181 -0
  262. package/src/vite/discovery/discover-routers.ts +348 -0
  263. package/src/vite/discovery/prerender-collection.ts +439 -0
  264. package/src/vite/discovery/route-types-writer.ts +258 -0
  265. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  266. package/src/vite/discovery/state.ts +117 -0
  267. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  268. package/src/vite/index.ts +15 -1129
  269. package/src/vite/plugin-types.ts +103 -0
  270. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  271. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  272. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  273. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
  274. package/src/vite/plugins/expose-id-utils.ts +299 -0
  275. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  276. package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
  277. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  278. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  279. package/src/vite/plugins/expose-ids/types.ts +45 -0
  280. package/src/vite/plugins/expose-internal-ids.ts +786 -0
  281. package/src/vite/plugins/performance-tracks.ts +88 -0
  282. package/src/vite/plugins/refresh-cmd.ts +127 -0
  283. package/src/vite/plugins/use-cache-transform.ts +323 -0
  284. package/src/vite/plugins/version-injector.ts +83 -0
  285. package/src/vite/plugins/version-plugin.ts +266 -0
  286. package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
  287. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  288. package/src/vite/rango.ts +462 -0
  289. package/src/vite/router-discovery.ts +918 -0
  290. package/src/vite/utils/ast-handler-extract.ts +517 -0
  291. package/src/vite/utils/banner.ts +36 -0
  292. package/src/vite/utils/bundle-analysis.ts +137 -0
  293. package/src/vite/utils/manifest-utils.ts +70 -0
  294. package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
  295. package/src/vite/utils/prerender-utils.ts +207 -0
  296. package/src/vite/utils/shared-utils.ts +170 -0
  297. package/CLAUDE.md +0 -43
  298. package/src/browser/lru-cache.ts +0 -69
  299. package/src/browser/request-controller.ts +0 -164
  300. package/src/cache/memory-store.ts +0 -253
  301. package/src/href-context.ts +0 -33
  302. package/src/href.ts +0 -255
  303. package/src/server/route-manifest-cache.ts +0 -173
  304. package/src/vite/expose-handle-id.ts +0 -209
  305. package/src/vite/expose-loader-id.ts +0 -426
  306. package/src/vite/expose-location-state-id.ts +0 -177
  307. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -0,0 +1,524 @@
1
+ /**
2
+ * Pre-render handler definition for build-time rendering of route segments.
3
+ *
4
+ * Prerender wraps a handler so that in production (phase 2)
5
+ * it can be pre-rendered at build time and served as a static Flight payload.
6
+ * In dev mode (phase 1), it behaves as a normal handler — the handler runs
7
+ * on every request just like a regular path() handler.
8
+ *
9
+ * The $$id is auto-generated by the Vite exposeInternalIds plugin
10
+ * based on file path and export name. No manual naming required.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * // Static page — no params
15
+ * export const DocsPage = Prerender(async (ctx) => {
16
+ * return <div>Documentation</div>;
17
+ * });
18
+ *
19
+ * // Dynamic page — params first, handler second
20
+ * export const DocsArticle = Prerender(
21
+ * async () => [{ slug: "getting-started" }, { slug: "api-reference" }],
22
+ * async (ctx) => {
23
+ * return <div>{ctx.params.slug}</div>;
24
+ * }
25
+ * );
26
+ * ```
27
+ */
28
+ import type { ReactNode } from "react";
29
+ import type {
30
+ Handler,
31
+ HandlerContext,
32
+ DefaultEnv,
33
+ ExtractParams,
34
+ } from "./types.js";
35
+ import type { Handle } from "./handle.js";
36
+ import type { ContextVar } from "./context-var.js";
37
+ import type { ReverseFunction } from "./reverse.js";
38
+ import type { DefaultReverseRouteMap } from "./types/global-namespace.js";
39
+ import type { UseItems, HandlerUseItem } from "./route-types.js";
40
+ import { isCachedFunction } from "./cache/taint.js";
41
+
42
+ // -- Named route resolution types -------------------------------------------
43
+
44
+ /**
45
+ * Reverse function for build contexts (BuildContext, StaticBuildContext, GetParamsContext).
46
+ * Global names get full autocomplete and param validation from the generated route map.
47
+ * Local `.name` calls are accepted but not validated (the include() scope is unknown
48
+ * at the type level).
49
+ */
50
+ type BuildReverseFunction = [DefaultReverseRouteMap] extends [
51
+ Record<string, string>,
52
+ ]
53
+ ? // No generated route map — permissive fallback
54
+ (
55
+ name: string,
56
+ params?: Record<string, string>,
57
+ search?: Record<string, unknown>,
58
+ ) => string
59
+ : // Generated route map available — typed globals + permissive locals
60
+ ReverseFunction<DefaultReverseRouteMap> & {
61
+ (
62
+ name: `.${string}`,
63
+ params?: Record<string, string>,
64
+ search?: Record<string, unknown>,
65
+ ): string;
66
+ };
67
+
68
+ /**
69
+ * Default route map for Prerender named route resolution.
70
+ * Uses GeneratedRouteMap (from gen file) to avoid circular dependencies.
71
+ */
72
+ type DefaultPrerenderRouteMap = keyof RSCRouter.GeneratedRouteMap extends never
73
+ ? {}
74
+ : RSCRouter.GeneratedRouteMap;
75
+
76
+ /** Extract params from a route map entry (string pattern or { path } object). */
77
+ type ExtractParamsFromEntry<TEntry> = TEntry extends string
78
+ ? ExtractParams<TEntry>
79
+ : TEntry extends { readonly path: infer P extends string }
80
+ ? ExtractParams<P>
81
+ : Record<string, string>;
82
+
83
+ /**
84
+ * Resolve params from Prerender's type parameter.
85
+ * Accepts named routes (global or .local) and explicit param objects.
86
+ *
87
+ * Resolution order:
88
+ * 1. ".local" string → look up in TRouteMap
89
+ * 2. Global route name string → look up in DefaultPrerenderRouteMap
90
+ * 3. Record<string, any> object → use as-is (explicit params)
91
+ * 4. Fallback → {}
92
+ */
93
+ type ResolvePrerenderParams<
94
+ T,
95
+ TRouteMap extends {} = DefaultPrerenderRouteMap,
96
+ > = T extends `.${infer Local}`
97
+ ? Local extends keyof TRouteMap
98
+ ? ExtractParamsFromEntry<TRouteMap[Local]>
99
+ : Record<string, string>
100
+ : T extends keyof DefaultPrerenderRouteMap
101
+ ? ExtractParamsFromEntry<DefaultPrerenderRouteMap[T]>
102
+ : T extends Record<string, any>
103
+ ? T
104
+ : {};
105
+
106
+ // -- Types ------------------------------------------------------------------
107
+
108
+ export interface PrerenderOptions {
109
+ /**
110
+ * Maximum number of param sets to render in parallel (default: 1).
111
+ * Only applies to dynamic Prerender handlers with getParams().
112
+ * Set to higher values to speed up builds with many routes.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * export const BlogPost = Prerender(
117
+ * async () => allPosts.map(p => ({ slug: p.slug })),
118
+ * async (ctx) => <PostPage slug={ctx.params.slug} />,
119
+ * { concurrency: 4 },
120
+ * );
121
+ * ```
122
+ */
123
+ concurrency?: number;
124
+ }
125
+
126
+ /**
127
+ * Context passed to Prerender() handlers at build time.
128
+ * Has a synthetic URL from getParams, params, pathname, and optionally env.
129
+ * No request, headers, cookies.
130
+ */
131
+ export interface BuildContext<TParams> {
132
+ /** Params extracted from the route pattern (populated from getParams). */
133
+ params: TParams;
134
+
135
+ /** True during build-time pre-rendering, false during passthrough live render. */
136
+ build: true;
137
+
138
+ /**
139
+ * True when running in Vite dev mode (on-demand prerender), false during
140
+ * production `vite build`. Use this to branch on runtime mode without
141
+ * changing build semantics.
142
+ */
143
+ dev: boolean;
144
+
145
+ /**
146
+ * Build-time environment bindings (KV, D1, etc.) supplied by the Vite plugin.
147
+ * Only available when `buildEnv` is configured in rango() options.
148
+ * Throws with a clear error if not configured.
149
+ *
150
+ * This is NOT the live request env — it is shared across all prerender
151
+ * invocations for the build.
152
+ */
153
+ env: DefaultEnv;
154
+
155
+ /** Read a variable set by getParams or a parent handler. */
156
+ get: {
157
+ <T>(contextVar: ContextVar<T>): T | undefined;
158
+ (key: string): any;
159
+ };
160
+
161
+ /** Set a variable readable by child layouts and parallels. */
162
+ set: {
163
+ <T>(contextVar: ContextVar<T>, value: T): void;
164
+ (key: string, value: any): void;
165
+ };
166
+
167
+ /** Push handle data (frozen into pre-rendered output at build time). */
168
+ use: <T>(handle: Handle<T>) => (data: T) => void;
169
+
170
+ /** Synthetic URL built from pattern + params (no real request). */
171
+ url: URL;
172
+
173
+ /** Pathname portion of the synthetic URL. */
174
+ pathname: string;
175
+
176
+ /** URLSearchParams from the synthetic URL (always empty for prerender). */
177
+ searchParams: URLSearchParams;
178
+
179
+ /** Typed search params — always {} for prerender (no real query string). */
180
+ search: {};
181
+
182
+ /** URL generation by route name. */
183
+ reverse: BuildReverseFunction;
184
+
185
+ /**
186
+ * Signal that this param set should not produce a local prerender artifact.
187
+ * At runtime the live handler runs instead. Only valid on routes wrapped
188
+ * with `Passthrough()`.
189
+ */
190
+ passthrough: () => PrerenderPassthroughResult;
191
+ }
192
+
193
+ /**
194
+ * Context passed to Static() handlers at build time.
195
+ * No URL, no params, no pathname — just renders content.
196
+ */
197
+ export interface StaticBuildContext {
198
+ /** Always true for Static handlers at build time. */
199
+ build: true;
200
+
201
+ /**
202
+ * True when running in Vite dev mode, false during production build.
203
+ */
204
+ dev: boolean;
205
+
206
+ /**
207
+ * Build-time environment bindings supplied by the Vite plugin.
208
+ * Only available when `buildEnv` is configured in rango() options.
209
+ */
210
+ env: DefaultEnv;
211
+
212
+ /** Read a variable (available for type consistency with BuildContext). */
213
+ get: {
214
+ <T>(contextVar: ContextVar<T>): T | undefined;
215
+ (key: string): any;
216
+ };
217
+
218
+ /** Set a variable (available for type consistency with BuildContext). */
219
+ set: {
220
+ <T>(contextVar: ContextVar<T>, value: T): void;
221
+ (key: string, value: any): void;
222
+ };
223
+
224
+ /** Push handle data (frozen into pre-rendered output at build time). */
225
+ use: <T>(handle: Handle<T>) => (data: T) => void;
226
+
227
+ /** URL generation by route name. */
228
+ reverse: BuildReverseFunction;
229
+ }
230
+
231
+ /**
232
+ * Context passed to getParams() at build time.
233
+ * Allows sharing data with handler invocations via set().
234
+ */
235
+ export interface GetParamsContext {
236
+ /** Always true during build-time getParams execution. */
237
+ build: true;
238
+
239
+ /**
240
+ * True when running in Vite dev mode, false during production build.
241
+ */
242
+ dev: boolean;
243
+
244
+ /**
245
+ * Build-time environment bindings supplied by the Vite plugin.
246
+ * Only available when `buildEnv` is configured in rango() options.
247
+ */
248
+ env: DefaultEnv;
249
+
250
+ /** Set a variable that will be available to each handler invocation via ctx.get(). */
251
+ set: {
252
+ <T>(contextVar: ContextVar<T>, value: T): void;
253
+ (key: string, value: any): void;
254
+ };
255
+
256
+ /** URL generation by route name. */
257
+ reverse: BuildReverseFunction;
258
+ }
259
+
260
+ export interface PrerenderHandlerDefinition<
261
+ TParams extends Record<string, any> = any,
262
+ > {
263
+ readonly __brand: "prerenderHandler";
264
+ /** Auto-generated unique ID (injected by Vite plugin). */
265
+ $$id: string;
266
+ /** In dev mode, the actual handler function that path() can call. */
267
+ handler: Handler<TParams>;
268
+ /** Returns the list of param objects to pre-render (dynamic routes). */
269
+ getParams?: (ctx: GetParamsContext) => Promise<TParams[]> | TParams[];
270
+ /** Pre-render options. */
271
+ options?: PrerenderOptions;
272
+ /** Composable default DSL items merged when the handler is mounted. */
273
+ use?: () => UseItems<HandlerUseItem>;
274
+ }
275
+
276
+ // -- Overloads --------------------------------------------------------------
277
+ //
278
+ // T accepts: named route string (global or .local) OR explicit param object.
279
+ // Named routes resolve params from GeneratedRouteMap, e.g.:
280
+ // Prerender<"locale.detail"> → params = { locale: string; slug: string }
281
+ // Explicit params work as before:
282
+ // Prerender<{ slug: string }> → params = { slug: string }
283
+
284
+ // Overload 1: Static handler (build-time only)
285
+ export function Prerender<
286
+ T extends
287
+ | keyof DefaultPrerenderRouteMap
288
+ | `.${keyof TRouteMap & string}`
289
+ | Record<string, any> = {},
290
+ TRouteMap extends {} = DefaultPrerenderRouteMap,
291
+ >(
292
+ handler: (
293
+ ctx: BuildContext<ResolvePrerenderParams<T, TRouteMap>>,
294
+ ) =>
295
+ | ReactNode
296
+ | PrerenderPassthroughResult
297
+ | Promise<ReactNode | PrerenderPassthroughResult>,
298
+ options?: PrerenderOptions,
299
+ __injectedId?: string,
300
+ ): PrerenderHandlerDefinition<ResolvePrerenderParams<T, TRouteMap>>;
301
+
302
+ // Overload 2: Dynamic handler (build-time only)
303
+ export function Prerender<
304
+ T extends
305
+ | keyof DefaultPrerenderRouteMap
306
+ | `.${keyof TRouteMap & string}`
307
+ | Record<string, any>,
308
+ TRouteMap extends {} = DefaultPrerenderRouteMap,
309
+ >(
310
+ getParams: (
311
+ ctx: GetParamsContext,
312
+ ) =>
313
+ | Promise<ResolvePrerenderParams<T, TRouteMap>[]>
314
+ | ResolvePrerenderParams<T, TRouteMap>[],
315
+ handler: (
316
+ ctx: BuildContext<ResolvePrerenderParams<T, TRouteMap>>,
317
+ ) =>
318
+ | ReactNode
319
+ | PrerenderPassthroughResult
320
+ | Promise<ReactNode | PrerenderPassthroughResult>,
321
+ options?: PrerenderOptions,
322
+ __injectedId?: string,
323
+ ): PrerenderHandlerDefinition<ResolvePrerenderParams<T, TRouteMap>>;
324
+
325
+ // -- Implementation ---------------------------------------------------------
326
+
327
+ export function Prerender<TParams extends Record<string, any>>(
328
+ handlerOrGetParams: Function,
329
+ handlerOrOptions?: Function | PrerenderOptions,
330
+ optionsOrId?: PrerenderOptions | string,
331
+ maybeId?: string,
332
+ ): PrerenderHandlerDefinition<TParams> {
333
+ // Resolve overloads:
334
+ // 1 fn arg: Prerender(handler, options?, __injectedId?)
335
+ // 2 fn args: Prerender(getParams, handler, options?, __injectedId?)
336
+ let handler: Handler<TParams>;
337
+ let getParams: (() => Promise<TParams[]> | TParams[]) | undefined;
338
+ let options: PrerenderOptions | undefined;
339
+ let id: string;
340
+
341
+ if (typeof handlerOrOptions === "function") {
342
+ // Two function args: getParams + handler
343
+ getParams = handlerOrGetParams as () => Promise<TParams[]> | TParams[];
344
+ handler = handlerOrOptions as Handler<TParams>;
345
+ if (typeof optionsOrId === "string") {
346
+ id = optionsOrId;
347
+ } else {
348
+ options = optionsOrId as PrerenderOptions | undefined;
349
+ id = maybeId ?? "";
350
+ }
351
+ } else {
352
+ // Single function arg: handler only
353
+ handler = handlerOrGetParams as Handler<TParams>;
354
+ if (typeof handlerOrOptions === "object" && handlerOrOptions !== null) {
355
+ options = handlerOrOptions as PrerenderOptions;
356
+ }
357
+ if (typeof optionsOrId === "string") {
358
+ id = optionsOrId;
359
+ } else {
360
+ id = maybeId ?? "";
361
+ }
362
+ }
363
+
364
+ if (isCachedFunction(handler)) {
365
+ throw new Error(
366
+ 'A "use cache" function cannot be used as a Prerender() handler. ' +
367
+ "Prerender handlers are rendered at build time. Remove the " +
368
+ '"use cache" directive — Prerender already provides caching.',
369
+ );
370
+ }
371
+ if (getParams && isCachedFunction(getParams)) {
372
+ throw new Error(
373
+ 'A "use cache" function cannot be used as Prerender() getParams. ' +
374
+ "getParams runs at build time to enumerate params. Remove the " +
375
+ '"use cache" directive.',
376
+ );
377
+ }
378
+
379
+ if (!id) {
380
+ throw new Error(
381
+ "[rsc-router] Prerender: missing $$id. " +
382
+ "Ensure the exposeInternalIds Vite plugin is configured.",
383
+ );
384
+ }
385
+
386
+ return {
387
+ __brand: "prerenderHandler" as const,
388
+ $$id: id,
389
+ handler,
390
+ ...(getParams ? { getParams } : {}),
391
+ ...(options ? { options } : {}),
392
+ };
393
+ }
394
+
395
+ // -- Passthrough sentinel ---------------------------------------------------
396
+
397
+ /**
398
+ * Sentinel returned by `ctx.passthrough()` to signal that a specific param set
399
+ * should not produce a local prerender artifact. The build skips writing the
400
+ * entry; at runtime the Passthrough live handler runs instead.
401
+ */
402
+ export const PRERENDER_PASSTHROUGH: Readonly<{
403
+ __brand: "prerenderPassthrough";
404
+ }> = Object.freeze({
405
+ __brand: "prerenderPassthrough" as const,
406
+ });
407
+
408
+ export type PrerenderPassthroughResult = typeof PRERENDER_PASSTHROUGH;
409
+
410
+ /**
411
+ * Type guard to check if a value is the passthrough sentinel.
412
+ */
413
+ export function isPrerenderPassthrough(
414
+ value: unknown,
415
+ ): value is PrerenderPassthroughResult {
416
+ return (
417
+ typeof value === "object" &&
418
+ value !== null &&
419
+ "__brand" in value &&
420
+ (value as { __brand: unknown }).__brand === "prerenderPassthrough"
421
+ );
422
+ }
423
+
424
+ // -- Type guards ------------------------------------------------------------
425
+
426
+ /**
427
+ * Type guard to check if a value is a PrerenderHandlerDefinition.
428
+ */
429
+ export function isPrerenderHandler(
430
+ value: unknown,
431
+ ): value is PrerenderHandlerDefinition {
432
+ return (
433
+ typeof value === "object" &&
434
+ value !== null &&
435
+ "__brand" in value &&
436
+ (value as { __brand: unknown }).__brand === "prerenderHandler"
437
+ );
438
+ }
439
+
440
+ // -- Passthrough wrapper ----------------------------------------------------
441
+
442
+ /**
443
+ * A prerender route with a live fallback handler for unknown params at runtime.
444
+ *
445
+ * Wraps a `Prerender(...)` definition with a separate handler that runs at
446
+ * request time for params not covered by `getParams()`.
447
+ *
448
+ * - Build time: `prerenderDef` provides getParams + build handler.
449
+ * - Runtime: `liveHandler` runs for unknown params with full HandlerContext.
450
+ *
451
+ * @example
452
+ * ```ts
453
+ * const BlogPrerender = Prerender(
454
+ * async () => [{ slug: "getting-started" }, { slug: "api-reference" }],
455
+ * async (ctx) => <BlogPost slug={ctx.params.slug} />,
456
+ * );
457
+ *
458
+ * // In route definition:
459
+ * path("/blog/:slug", Passthrough(BlogPrerender, async (ctx) => {
460
+ * const post = await ctx.env.DB.get(ctx.params.slug);
461
+ * return <BlogPost slug={ctx.params.slug} post={post} />;
462
+ * }))
463
+ * ```
464
+ */
465
+ export interface PassthroughHandlerDefinition<
466
+ TParams extends Record<string, any> = any,
467
+ TEnv = DefaultEnv,
468
+ > {
469
+ readonly __brand: "passthroughHandler";
470
+ /** The underlying prerender definition (build-time rendering). */
471
+ prerenderDef: PrerenderHandlerDefinition<TParams>;
472
+ /** Live handler for runtime fallback on unknown params. */
473
+ liveHandler: (
474
+ ctx: HandlerContext<TParams, TEnv>,
475
+ ) => ReactNode | Promise<ReactNode> | Response | Promise<Response>;
476
+ /** Composable default DSL items merged when the handler is mounted. */
477
+ use?: () => UseItems<HandlerUseItem>;
478
+ }
479
+
480
+ export function Passthrough<
481
+ TParams extends Record<string, any>,
482
+ TEnv = DefaultEnv,
483
+ >(
484
+ prerenderDef: PrerenderHandlerDefinition<TParams>,
485
+ liveHandler: (
486
+ ctx: HandlerContext<TParams, TEnv>,
487
+ ) => ReactNode | Promise<ReactNode> | Response | Promise<Response>,
488
+ ): PassthroughHandlerDefinition<TParams, TEnv>;
489
+
490
+ // Implementation
491
+ export function Passthrough<
492
+ TParams extends Record<string, any>,
493
+ TEnv = DefaultEnv,
494
+ >(
495
+ prerenderDef: PrerenderHandlerDefinition<TParams>,
496
+ liveHandler: (
497
+ ctx: HandlerContext<TParams, TEnv>,
498
+ ) => ReactNode | Promise<ReactNode> | Response | Promise<Response>,
499
+ ): PassthroughHandlerDefinition<TParams, TEnv> {
500
+ if (!isPrerenderHandler(prerenderDef)) {
501
+ throw new Error(
502
+ "[rsc-router] Passthrough: first argument must be a Prerender() definition.",
503
+ );
504
+ }
505
+ return {
506
+ __brand: "passthroughHandler" as const,
507
+ prerenderDef,
508
+ liveHandler,
509
+ };
510
+ }
511
+
512
+ /**
513
+ * Type guard to check if a value is a PassthroughHandlerDefinition.
514
+ */
515
+ export function isPassthroughHandler(
516
+ value: unknown,
517
+ ): value is PassthroughHandlerDefinition {
518
+ return (
519
+ typeof value === "object" &&
520
+ value !== null &&
521
+ "__brand" in value &&
522
+ (value as { __brand: unknown }).__brand === "passthroughHandler"
523
+ );
524
+ }