@rangojs/router 0.0.0-experimental.002d056c

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 (305) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +899 -0
  3. package/dist/bin/rango.js +1606 -0
  4. package/dist/vite/index.js +5153 -0
  5. package/package.json +177 -0
  6. package/skills/breadcrumbs/SKILL.md +250 -0
  7. package/skills/cache-guide/SKILL.md +262 -0
  8. package/skills/caching/SKILL.md +253 -0
  9. package/skills/composability/SKILL.md +172 -0
  10. package/skills/debug-manifest/SKILL.md +112 -0
  11. package/skills/document-cache/SKILL.md +182 -0
  12. package/skills/fonts/SKILL.md +167 -0
  13. package/skills/hooks/SKILL.md +704 -0
  14. package/skills/host-router/SKILL.md +218 -0
  15. package/skills/intercept/SKILL.md +313 -0
  16. package/skills/layout/SKILL.md +310 -0
  17. package/skills/links/SKILL.md +239 -0
  18. package/skills/loader/SKILL.md +596 -0
  19. package/skills/middleware/SKILL.md +339 -0
  20. package/skills/mime-routes/SKILL.md +128 -0
  21. package/skills/parallel/SKILL.md +305 -0
  22. package/skills/prerender/SKILL.md +643 -0
  23. package/skills/rango/SKILL.md +118 -0
  24. package/skills/response-routes/SKILL.md +411 -0
  25. package/skills/route/SKILL.md +385 -0
  26. package/skills/router-setup/SKILL.md +439 -0
  27. package/skills/tailwind/SKILL.md +129 -0
  28. package/skills/theme/SKILL.md +79 -0
  29. package/skills/typesafety/SKILL.md +623 -0
  30. package/skills/use-cache/SKILL.md +324 -0
  31. package/src/__internal.ts +273 -0
  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/event-controller.ts +899 -0
  36. package/src/browser/history-state.ts +80 -0
  37. package/src/browser/index.ts +18 -0
  38. package/src/browser/intercept-utils.ts +52 -0
  39. package/src/browser/link-interceptor.ts +141 -0
  40. package/src/browser/logging.ts +55 -0
  41. package/src/browser/merge-segment-loaders.ts +134 -0
  42. package/src/browser/navigation-bridge.ts +638 -0
  43. package/src/browser/navigation-client.ts +261 -0
  44. package/src/browser/navigation-store.ts +806 -0
  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 +582 -0
  48. package/src/browser/prefetch/cache.ts +206 -0
  49. package/src/browser/prefetch/fetch.ts +145 -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 +128 -0
  53. package/src/browser/rango-state.ts +112 -0
  54. package/src/browser/react/Link.tsx +368 -0
  55. package/src/browser/react/NavigationProvider.tsx +413 -0
  56. package/src/browser/react/ScrollRestoration.tsx +94 -0
  57. package/src/browser/react/context.ts +59 -0
  58. package/src/browser/react/filter-segment-order.ts +11 -0
  59. package/src/browser/react/index.ts +52 -0
  60. package/src/browser/react/location-state-shared.ts +162 -0
  61. package/src/browser/react/location-state.ts +107 -0
  62. package/src/browser/react/mount-context.ts +37 -0
  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 +218 -0
  66. package/src/browser/react/use-client-cache.ts +58 -0
  67. package/src/browser/react/use-handle.ts +162 -0
  68. package/src/browser/react/use-href.tsx +40 -0
  69. package/src/browser/react/use-link-status.ts +135 -0
  70. package/src/browser/react/use-mount.ts +31 -0
  71. package/src/browser/react/use-navigation.ts +99 -0
  72. package/src/browser/react/use-params.ts +65 -0
  73. package/src/browser/react/use-pathname.ts +47 -0
  74. package/src/browser/react/use-router.ts +63 -0
  75. package/src/browser/react/use-search-params.ts +56 -0
  76. package/src/browser/react/use-segments.ts +171 -0
  77. package/src/browser/response-adapter.ts +73 -0
  78. package/src/browser/rsc-router.tsx +464 -0
  79. package/src/browser/scroll-restoration.ts +397 -0
  80. package/src/browser/segment-reconciler.ts +216 -0
  81. package/src/browser/segment-structure-assert.ts +83 -0
  82. package/src/browser/server-action-bridge.ts +667 -0
  83. package/src/browser/shallow.ts +40 -0
  84. package/src/browser/types.ts +547 -0
  85. package/src/browser/validate-redirect-origin.ts +29 -0
  86. package/src/build/generate-manifest.ts +438 -0
  87. package/src/build/generate-route-types.ts +36 -0
  88. package/src/build/index.ts +35 -0
  89. package/src/build/route-trie.ts +265 -0
  90. package/src/build/route-types/ast-helpers.ts +25 -0
  91. package/src/build/route-types/ast-route-extraction.ts +98 -0
  92. package/src/build/route-types/codegen.ts +102 -0
  93. package/src/build/route-types/include-resolution.ts +411 -0
  94. package/src/build/route-types/param-extraction.ts +48 -0
  95. package/src/build/route-types/per-module-writer.ts +128 -0
  96. package/src/build/route-types/router-processing.ts +479 -0
  97. package/src/build/route-types/scan-filter.ts +78 -0
  98. package/src/build/runtime-discovery.ts +231 -0
  99. package/src/cache/background-task.ts +34 -0
  100. package/src/cache/cache-key-utils.ts +44 -0
  101. package/src/cache/cache-policy.ts +125 -0
  102. package/src/cache/cache-runtime.ts +338 -0
  103. package/src/cache/cache-scope.ts +382 -0
  104. package/src/cache/cf/cf-cache-store.ts +982 -0
  105. package/src/cache/cf/index.ts +29 -0
  106. package/src/cache/document-cache.ts +369 -0
  107. package/src/cache/handle-capture.ts +81 -0
  108. package/src/cache/handle-snapshot.ts +41 -0
  109. package/src/cache/index.ts +44 -0
  110. package/src/cache/memory-segment-store.ts +328 -0
  111. package/src/cache/profile-registry.ts +73 -0
  112. package/src/cache/read-through-swr.ts +134 -0
  113. package/src/cache/segment-codec.ts +256 -0
  114. package/src/cache/taint.ts +98 -0
  115. package/src/cache/types.ts +342 -0
  116. package/src/client.rsc.tsx +85 -0
  117. package/src/client.tsx +601 -0
  118. package/src/component-utils.ts +76 -0
  119. package/src/components/DefaultDocument.tsx +27 -0
  120. package/src/context-var.ts +86 -0
  121. package/src/debug.ts +243 -0
  122. package/src/default-error-boundary.tsx +88 -0
  123. package/src/deps/browser.ts +8 -0
  124. package/src/deps/html-stream-client.ts +2 -0
  125. package/src/deps/html-stream-server.ts +2 -0
  126. package/src/deps/rsc.ts +10 -0
  127. package/src/deps/ssr.ts +2 -0
  128. package/src/errors.ts +365 -0
  129. package/src/handle.ts +135 -0
  130. package/src/handles/MetaTags.tsx +246 -0
  131. package/src/handles/breadcrumbs.ts +66 -0
  132. package/src/handles/index.ts +7 -0
  133. package/src/handles/meta.ts +264 -0
  134. package/src/host/cookie-handler.ts +165 -0
  135. package/src/host/errors.ts +97 -0
  136. package/src/host/index.ts +53 -0
  137. package/src/host/pattern-matcher.ts +214 -0
  138. package/src/host/router.ts +352 -0
  139. package/src/host/testing.ts +79 -0
  140. package/src/host/types.ts +146 -0
  141. package/src/host/utils.ts +25 -0
  142. package/src/href-client.ts +222 -0
  143. package/src/index.rsc.ts +233 -0
  144. package/src/index.ts +277 -0
  145. package/src/internal-debug.ts +11 -0
  146. package/src/loader.rsc.ts +89 -0
  147. package/src/loader.ts +64 -0
  148. package/src/network-error-thrower.tsx +23 -0
  149. package/src/outlet-context.ts +15 -0
  150. package/src/outlet-provider.tsx +45 -0
  151. package/src/prerender/param-hash.ts +37 -0
  152. package/src/prerender/store.ts +185 -0
  153. package/src/prerender.ts +463 -0
  154. package/src/reverse.ts +330 -0
  155. package/src/root-error-boundary.tsx +289 -0
  156. package/src/route-content-wrapper.tsx +196 -0
  157. package/src/route-definition/dsl-helpers.ts +934 -0
  158. package/src/route-definition/helper-factories.ts +200 -0
  159. package/src/route-definition/helpers-types.ts +430 -0
  160. package/src/route-definition/index.ts +52 -0
  161. package/src/route-definition/redirect.ts +93 -0
  162. package/src/route-definition.ts +1 -0
  163. package/src/route-map-builder.ts +281 -0
  164. package/src/route-name.ts +53 -0
  165. package/src/route-types.ts +259 -0
  166. package/src/router/content-negotiation.ts +116 -0
  167. package/src/router/debug-manifest.ts +72 -0
  168. package/src/router/error-handling.ts +287 -0
  169. package/src/router/find-match.ts +160 -0
  170. package/src/router/handler-context.ts +451 -0
  171. package/src/router/intercept-resolution.ts +397 -0
  172. package/src/router/lazy-includes.ts +236 -0
  173. package/src/router/loader-resolution.ts +420 -0
  174. package/src/router/logging.ts +251 -0
  175. package/src/router/manifest.ts +269 -0
  176. package/src/router/match-api.ts +620 -0
  177. package/src/router/match-context.ts +266 -0
  178. package/src/router/match-handlers.ts +440 -0
  179. package/src/router/match-middleware/background-revalidation.ts +223 -0
  180. package/src/router/match-middleware/cache-lookup.ts +634 -0
  181. package/src/router/match-middleware/cache-store.ts +295 -0
  182. package/src/router/match-middleware/index.ts +81 -0
  183. package/src/router/match-middleware/intercept-resolution.ts +306 -0
  184. package/src/router/match-middleware/segment-resolution.ts +193 -0
  185. package/src/router/match-pipelines.ts +179 -0
  186. package/src/router/match-result.ts +219 -0
  187. package/src/router/metrics.ts +282 -0
  188. package/src/router/middleware-cookies.ts +55 -0
  189. package/src/router/middleware-types.ts +222 -0
  190. package/src/router/middleware.ts +749 -0
  191. package/src/router/pattern-matching.ts +563 -0
  192. package/src/router/prerender-match.ts +402 -0
  193. package/src/router/preview-match.ts +170 -0
  194. package/src/router/revalidation.ts +289 -0
  195. package/src/router/router-context.ts +320 -0
  196. package/src/router/router-interfaces.ts +452 -0
  197. package/src/router/router-options.ts +592 -0
  198. package/src/router/router-registry.ts +24 -0
  199. package/src/router/segment-resolution/fresh.ts +570 -0
  200. package/src/router/segment-resolution/helpers.ts +263 -0
  201. package/src/router/segment-resolution/loader-cache.ts +198 -0
  202. package/src/router/segment-resolution/revalidation.ts +1242 -0
  203. package/src/router/segment-resolution/static-store.ts +67 -0
  204. package/src/router/segment-resolution.ts +21 -0
  205. package/src/router/segment-wrappers.ts +291 -0
  206. package/src/router/telemetry-otel.ts +299 -0
  207. package/src/router/telemetry.ts +300 -0
  208. package/src/router/timeout.ts +148 -0
  209. package/src/router/trie-matching.ts +239 -0
  210. package/src/router/types.ts +170 -0
  211. package/src/router.ts +1006 -0
  212. package/src/rsc/handler-context.ts +45 -0
  213. package/src/rsc/handler.ts +1089 -0
  214. package/src/rsc/helpers.ts +198 -0
  215. package/src/rsc/index.ts +36 -0
  216. package/src/rsc/loader-fetch.ts +209 -0
  217. package/src/rsc/manifest-init.ts +86 -0
  218. package/src/rsc/nonce.ts +32 -0
  219. package/src/rsc/origin-guard.ts +141 -0
  220. package/src/rsc/progressive-enhancement.ts +379 -0
  221. package/src/rsc/response-error.ts +37 -0
  222. package/src/rsc/response-route-handler.ts +347 -0
  223. package/src/rsc/rsc-rendering.ts +237 -0
  224. package/src/rsc/runtime-warnings.ts +42 -0
  225. package/src/rsc/server-action.ts +348 -0
  226. package/src/rsc/ssr-setup.ts +128 -0
  227. package/src/rsc/types.ts +263 -0
  228. package/src/search-params.ts +230 -0
  229. package/src/segment-system.tsx +454 -0
  230. package/src/server/context.ts +591 -0
  231. package/src/server/cookie-store.ts +190 -0
  232. package/src/server/fetchable-loader-store.ts +37 -0
  233. package/src/server/handle-store.ts +308 -0
  234. package/src/server/loader-registry.ts +133 -0
  235. package/src/server/request-context.ts +920 -0
  236. package/src/server/root-layout.tsx +10 -0
  237. package/src/server/tsconfig.json +14 -0
  238. package/src/server.ts +51 -0
  239. package/src/ssr/index.tsx +365 -0
  240. package/src/static-handler.ts +114 -0
  241. package/src/theme/ThemeProvider.tsx +297 -0
  242. package/src/theme/ThemeScript.tsx +61 -0
  243. package/src/theme/constants.ts +62 -0
  244. package/src/theme/index.ts +48 -0
  245. package/src/theme/theme-context.ts +44 -0
  246. package/src/theme/theme-script.ts +155 -0
  247. package/src/theme/types.ts +182 -0
  248. package/src/theme/use-theme.ts +44 -0
  249. package/src/types/boundaries.ts +158 -0
  250. package/src/types/cache-types.ts +198 -0
  251. package/src/types/error-types.ts +192 -0
  252. package/src/types/global-namespace.ts +100 -0
  253. package/src/types/handler-context.ts +687 -0
  254. package/src/types/index.ts +88 -0
  255. package/src/types/loader-types.ts +183 -0
  256. package/src/types/route-config.ts +170 -0
  257. package/src/types/route-entry.ts +109 -0
  258. package/src/types/segments.ts +148 -0
  259. package/src/types.ts +1 -0
  260. package/src/urls/include-helper.ts +197 -0
  261. package/src/urls/index.ts +53 -0
  262. package/src/urls/path-helper-types.ts +339 -0
  263. package/src/urls/path-helper.ts +329 -0
  264. package/src/urls/pattern-types.ts +95 -0
  265. package/src/urls/response-types.ts +106 -0
  266. package/src/urls/type-extraction.ts +372 -0
  267. package/src/urls/urls-function.ts +98 -0
  268. package/src/urls.ts +1 -0
  269. package/src/use-loader.tsx +354 -0
  270. package/src/vite/discovery/bundle-postprocess.ts +184 -0
  271. package/src/vite/discovery/discover-routers.ts +344 -0
  272. package/src/vite/discovery/prerender-collection.ts +385 -0
  273. package/src/vite/discovery/route-types-writer.ts +258 -0
  274. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  275. package/src/vite/discovery/state.ts +108 -0
  276. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  277. package/src/vite/index.ts +16 -0
  278. package/src/vite/plugin-types.ts +48 -0
  279. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  280. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  281. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  282. package/src/vite/plugins/expose-action-id.ts +363 -0
  283. package/src/vite/plugins/expose-id-utils.ts +287 -0
  284. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  285. package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
  286. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  287. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  288. package/src/vite/plugins/expose-ids/types.ts +45 -0
  289. package/src/vite/plugins/expose-internal-ids.ts +569 -0
  290. package/src/vite/plugins/refresh-cmd.ts +65 -0
  291. package/src/vite/plugins/use-cache-transform.ts +323 -0
  292. package/src/vite/plugins/version-injector.ts +83 -0
  293. package/src/vite/plugins/version-plugin.ts +266 -0
  294. package/src/vite/plugins/version.d.ts +12 -0
  295. package/src/vite/plugins/virtual-entries.ts +123 -0
  296. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  297. package/src/vite/rango.ts +445 -0
  298. package/src/vite/router-discovery.ts +777 -0
  299. package/src/vite/utils/ast-handler-extract.ts +517 -0
  300. package/src/vite/utils/banner.ts +36 -0
  301. package/src/vite/utils/bundle-analysis.ts +137 -0
  302. package/src/vite/utils/manifest-utils.ts +70 -0
  303. package/src/vite/utils/package-resolution.ts +121 -0
  304. package/src/vite/utils/prerender-utils.ts +189 -0
  305. package/src/vite/utils/shared-utils.ts +169 -0
@@ -0,0 +1,263 @@
1
+ /**
2
+ * RSC Handler Types
3
+ *
4
+ * Type definitions for the RSC request handler, payload structures,
5
+ * and SSR integration.
6
+ */
7
+
8
+ import type { ResolvedSegment, SlotState } from "../types.js";
9
+ import type { HandleData } from "../server/handle-store.js";
10
+ import type { RSCRouterInternal } from "../router/router-interfaces.js";
11
+ import type { ResolvedThemeConfig, Theme } from "../theme/types.js";
12
+
13
+ /**
14
+ * RSC payload sent to the client.
15
+ * The tree is always reconstructed from metadata.segments by consumers
16
+ * (SSR via renderSegments, browser via renderSegments in bridges).
17
+ */
18
+ export interface RscPayload {
19
+ metadata?: {
20
+ pathname: string;
21
+ segments: ResolvedSegment[];
22
+ isPartial?: boolean;
23
+ isError?: boolean;
24
+ matched?: string[];
25
+ diff?: string[];
26
+ /** Merged route params from the matched route */
27
+ params?: Record<string, string>;
28
+ slots?: Record<string, SlotState>;
29
+ /** Root layout component for browser-side re-renders (client component reference) */
30
+ rootLayout?: React.ComponentType<{ children: React.ReactNode }>;
31
+ /** Handle data accumulated across route segments (async generator that yields on each push) */
32
+ handles?: AsyncGenerator<HandleData, void, unknown>;
33
+ /** RSC version string for cache invalidation */
34
+ version?: string;
35
+ /** TTL in milliseconds for the client-side in-memory prefetch cache */
36
+ prefetchCacheTTL?: number;
37
+ /** Theme configuration for FOUC prevention */
38
+ themeConfig?: ResolvedThemeConfig | null;
39
+ /** Initial theme from cookie (for SSR hydration) */
40
+ initialTheme?: Theme;
41
+ /** Whether connection warmup is enabled */
42
+ warmupEnabled?: boolean;
43
+ /** Server-side redirect with optional state (for partial requests) */
44
+ redirect?: { url: string };
45
+ /** Server-set location state to include in history.pushState */
46
+ locationState?: Record<string, unknown>;
47
+ };
48
+ returnValue?: { ok: boolean; data: unknown };
49
+ formState?: unknown;
50
+ }
51
+
52
+ /**
53
+ * React form state type for useActionState progressive enhancement
54
+ */
55
+ export type ReactFormState = unknown;
56
+
57
+ /**
58
+ * RSC dependencies from @vitejs/plugin-rsc/rsc
59
+ */
60
+ export interface RSCDependencies {
61
+ /**
62
+ * renderToReadableStream from @vitejs/plugin-rsc/rsc
63
+ */
64
+ renderToReadableStream: <T>(
65
+ payload: T,
66
+ options?: { temporaryReferences?: unknown },
67
+ ) => ReadableStream<Uint8Array>;
68
+
69
+ /**
70
+ * decodeReply from @vitejs/plugin-rsc/rsc
71
+ */
72
+ decodeReply: (
73
+ body: FormData | string,
74
+ options?: { temporaryReferences?: unknown },
75
+ ) => Promise<unknown[]>;
76
+
77
+ /**
78
+ * createTemporaryReferenceSet from @vitejs/plugin-rsc/rsc
79
+ */
80
+ createTemporaryReferenceSet: () => unknown;
81
+
82
+ /**
83
+ * loadServerAction from @vitejs/plugin-rsc/rsc
84
+ */
85
+ loadServerAction: (actionId: string) => Promise<Function>;
86
+
87
+ /**
88
+ * decodeAction from @vitejs/plugin-rsc/rsc
89
+ * Decodes a FormData into a bound action function (for useActionState forms)
90
+ */
91
+ decodeAction: (body: FormData) => Promise<() => Promise<unknown>>;
92
+
93
+ /**
94
+ * decodeFormState from @vitejs/plugin-rsc/rsc
95
+ * Decodes the action result into a ReactFormState for useActionState progressive enhancement
96
+ */
97
+ decodeFormState: (
98
+ actionResult: unknown,
99
+ body: FormData,
100
+ ) => Promise<ReactFormState | null>;
101
+ }
102
+
103
+ /**
104
+ * Options for SSR HTML rendering
105
+ */
106
+ export interface SSRRenderOptions {
107
+ /**
108
+ * Form state for useActionState progressive enhancement.
109
+ * This is the result of decodeFormState() and should be passed to
110
+ * react-dom's renderToReadableStream to enable useActionState to
111
+ * receive the action result during SSR.
112
+ */
113
+ formState?: ReactFormState | null;
114
+
115
+ /**
116
+ * Nonce for Content Security Policy (CSP)
117
+ */
118
+ nonce?: string;
119
+
120
+ /**
121
+ * SSR stream mode.
122
+ *
123
+ * - `"stream"` (default) — start flushing HTML immediately.
124
+ * - `"allReady"` — await `stream.allReady` before returning.
125
+ */
126
+ streamMode?: import("../router/router-options.js").SSRStreamMode;
127
+ }
128
+
129
+ /**
130
+ * SSR module interface for HTML rendering
131
+ */
132
+ export interface SSRModule {
133
+ renderHTML: (
134
+ rscStream: ReadableStream<Uint8Array>,
135
+ options?: SSRRenderOptions,
136
+ ) => Promise<ReadableStream<Uint8Array>>;
137
+ }
138
+
139
+ /**
140
+ * Function to load SSR module dynamically
141
+ */
142
+ export type LoadSSRModule = () => Promise<SSRModule>;
143
+
144
+ /**
145
+ * Cache configuration for handler.
146
+ * TTL is configured via store.defaults or cache() boundaries.
147
+ */
148
+ export interface HandlerCacheConfig {
149
+ /** Cache store implementation */
150
+ store: import("../cache/types.js").SegmentCacheStore;
151
+ /** Enable/disable caching (default: true) */
152
+ enabled?: boolean;
153
+ }
154
+
155
+ /**
156
+ * Nonce provider function type.
157
+ * Can return a nonce string, or true to auto-generate one.
158
+ */
159
+ export type NonceProvider<TEnv = unknown> = (
160
+ request: Request,
161
+ env: TEnv,
162
+ ) => string | true | Promise<string | true>;
163
+
164
+ /**
165
+ * Options for creating an RSC handler
166
+ */
167
+ export interface CreateRSCHandlerOptions<
168
+ TEnv = unknown,
169
+ TRoutes extends Record<string, string> = Record<string, string>,
170
+ > {
171
+ /**
172
+ * The RSC router instance
173
+ */
174
+ router: RSCRouterInternal<TEnv, TRoutes>;
175
+
176
+ /**
177
+ * RSC dependencies from @vitejs/plugin-rsc/rsc.
178
+ * Defaults to the exports from @vitejs/plugin-rsc/rsc.
179
+ */
180
+ deps?: RSCDependencies;
181
+
182
+ /**
183
+ * Function to load the SSR module for HTML rendering.
184
+ * Defaults to: () => import.meta.viteRsc.loadModule("ssr", "index")
185
+ */
186
+ loadSSRModule?: LoadSSRModule;
187
+
188
+ /**
189
+ * Cache configuration for segment caching.
190
+ *
191
+ * Can be a static config object or a function that receives the env
192
+ * (useful for accessing Cloudflare bindings).
193
+ *
194
+ * If not provided, caching is disabled. TTL is configured via store.defaults
195
+ * or cache() boundaries in the route definition.
196
+ *
197
+ * @example Static config
198
+ * ```typescript
199
+ * cache: {
200
+ * store: new MemorySegmentCacheStore({ defaults: { ttl: 60 } }),
201
+ * }
202
+ * ```
203
+ *
204
+ * @example Dynamic config with env
205
+ * ```typescript
206
+ * cache: (env) => ({
207
+ * store: new KVSegmentCacheStore(env.Bindings.MY_CACHE, { defaults: { ttl: 60 } }),
208
+ * })
209
+ * ```
210
+ */
211
+ cache?: HandlerCacheConfig | ((env: TEnv) => HandlerCacheConfig);
212
+
213
+ /**
214
+ * RSC version string included in metadata.
215
+ * The browser sends this back on partial requests to detect version mismatches.
216
+ *
217
+ * Defaults to the auto-generated VERSION from `rsc-router:version` virtual module.
218
+ * Only set this if you need a custom versioning strategy.
219
+ *
220
+ * @default VERSION from rsc-router:version
221
+ */
222
+ version?: string;
223
+
224
+ /**
225
+ * Nonce provider for Content Security Policy (CSP).
226
+ *
227
+ * Can be:
228
+ * - A function that returns a nonce string
229
+ * - A function that returns `true` to auto-generate a nonce
230
+ * - Undefined to disable nonce (default)
231
+ *
232
+ * The nonce will be applied to inline scripts injected by the RSC payload.
233
+ * It's also available to middleware via the typed `nonce` token:
234
+ * `import { nonce } from "@rangojs/router"; ctx.get(nonce)`
235
+ *
236
+ * @example Auto-generate nonce
237
+ * ```tsx
238
+ * createRSCHandler({
239
+ * router,
240
+ * nonce: () => true,
241
+ * });
242
+ * ```
243
+ *
244
+ * @example Custom nonce from request context
245
+ * ```tsx
246
+ * createRSCHandler({
247
+ * router,
248
+ * nonce: (request, env) => env.nonce,
249
+ * });
250
+ * ```
251
+ *
252
+ * @example Access nonce in middleware
253
+ * ```tsx
254
+ * import { nonce } from "@rangojs/router";
255
+ *
256
+ * const cspMiddleware: Middleware = async (ctx, next) => {
257
+ * const value = ctx.get(nonce); // string | undefined
258
+ * await next();
259
+ * };
260
+ * ```
261
+ */
262
+ nonce?: NonceProvider<TEnv>;
263
+ }
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Search parameter schema types and runtime utilities.
3
+ *
4
+ * Provides a lightweight schema system for typed query parameters.
5
+ * When a route defines a `search` schema, ctx.search provides a typed
6
+ * object with parsed values. ctx.searchParams always remains a standard
7
+ * URLSearchParams instance.
8
+ */
9
+
10
+ // ============================================================================
11
+ // Schema Types
12
+ // ============================================================================
13
+
14
+ /** Supported scalar types for search params (append ? for optional). */
15
+ export type SearchSchemaValue =
16
+ | "string"
17
+ | "number"
18
+ | "boolean"
19
+ | "string?"
20
+ | "number?"
21
+ | "boolean?";
22
+
23
+ /** A search schema maps param names to their type descriptors. */
24
+ export type SearchSchema = Record<string, SearchSchemaValue>;
25
+
26
+ // ============================================================================
27
+ // Type-Level Schema Resolution
28
+ // ============================================================================
29
+
30
+ /** Strip trailing `?` from a schema value to get the base type. */
31
+ type BaseType<T extends string> = T extends `${infer B}?` ? B : T;
32
+
33
+ /** Map a base type string to its TypeScript type. */
34
+ type ResolveBaseType<T extends string> = T extends "string"
35
+ ? string
36
+ : T extends "number"
37
+ ? number
38
+ : T extends "boolean"
39
+ ? boolean
40
+ : never;
41
+
42
+ /** Keys whose schema value does NOT end with `?`. */
43
+ type RequiredKeys<T extends SearchSchema> = {
44
+ [K in keyof T]: T[K] extends `${string}?` ? never : K;
45
+ }[keyof T];
46
+
47
+ /** Keys whose schema value ends with `?`. */
48
+ type OptionalKeys<T extends SearchSchema> = {
49
+ [K in keyof T]: T[K] extends `${string}?` ? K : never;
50
+ }[keyof T];
51
+
52
+ /** Flatten an intersection type into a single object type. */
53
+ type Simplify<T> = { [K in keyof T]: T[K] };
54
+
55
+ /**
56
+ * Resolve a SearchSchema to its typed object.
57
+ *
58
+ * Both required and optional params resolve to `T | undefined` at the handler
59
+ * level. The required/optional distinction is a consumer-facing contract
60
+ * (e.g., for href() and reverse() autocomplete) — it tells callers which
61
+ * params the route expects, but the handler must still check for undefined
62
+ * since the framework cannot trust the client to send all required params.
63
+ *
64
+ * @example
65
+ * type S = { q: "string"; page: "number?"; sort: "string?" };
66
+ * type R = ResolveSearchSchema<S>;
67
+ * // { q: string | undefined; page?: number; sort?: string }
68
+ */
69
+ export type ResolveSearchSchema<T extends SearchSchema> = Simplify<
70
+ {
71
+ [K in RequiredKeys<T> & string]:
72
+ | ResolveBaseType<BaseType<T[K]>>
73
+ | undefined;
74
+ } & {
75
+ [K in OptionalKeys<T> & string]?: ResolveBaseType<BaseType<T[K]>>;
76
+ }
77
+ >;
78
+
79
+ // ============================================================================
80
+ // Route-Level Type Extraction
81
+ // ============================================================================
82
+
83
+ /** Resolve the global route map from RegisteredRoutes or GeneratedRouteMap. */
84
+ type GlobalRouteMap = keyof RSCRouter.RegisteredRoutes extends never
85
+ ? keyof RSCRouter.GeneratedRouteMap extends never
86
+ ? Record<string, string>
87
+ : RSCRouter.GeneratedRouteMap
88
+ : RSCRouter.RegisteredRoutes;
89
+
90
+ /**
91
+ * Extract the resolved search params type for a named route.
92
+ * Looks up the search schema from the route map and resolves it.
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * // Given: path("/search", handler, { name: "search", search: { q: "string", page: "number?" } })
97
+ * type Params = RouteSearchParams<"search">;
98
+ * // { q: string; page?: number }
99
+ * ```
100
+ */
101
+ export type RouteSearchParams<TName extends string, TRouteMap = never> = [
102
+ TRouteMap,
103
+ ] extends [never]
104
+ ? ExtractAndResolveSearch<GlobalRouteMap, TName>
105
+ : ExtractAndResolveSearch<TRouteMap, TName>;
106
+
107
+ type ExtractAndResolveSearch<TRouteMap, TName> = TName extends keyof TRouteMap
108
+ ? TRouteMap[TName] extends { readonly search: infer S extends SearchSchema }
109
+ ? ResolveSearchSchema<S>
110
+ : {}
111
+ : {};
112
+
113
+ /**
114
+ * Extract the route params type for a named route.
115
+ * Looks up the path pattern from the route map and extracts params.
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * // Given: path("/blog/:slug", handler, { name: "blogPost" })
120
+ * type Params = RouteParams<"blogPost">;
121
+ * // { slug: string }
122
+ * ```
123
+ */
124
+ export type RouteParams<TName extends string, TRouteMap = never> = [
125
+ TRouteMap,
126
+ ] extends [never]
127
+ ? ExtractRouteParamsFromMap<GlobalRouteMap, TName>
128
+ : ExtractRouteParamsFromMap<TRouteMap, TName>;
129
+
130
+ type ExtractRouteParamsFromMap<TRouteMap, TName> = TName extends keyof TRouteMap
131
+ ? TRouteMap[TName] extends string
132
+ ? ExtractParamsFromPattern<TRouteMap[TName]>
133
+ : TRouteMap[TName] extends { readonly path: infer P extends string }
134
+ ? ExtractParamsFromPattern<P>
135
+ : {}
136
+ : {};
137
+
138
+ /** Parse "a|b|c" into "a" | "b" | "c" */
139
+ type ParseConstraint<T extends string> =
140
+ T extends `${infer First}|${infer Rest}` ? First | ParseConstraint<Rest> : T;
141
+
142
+ /** Minimal inline param extraction (avoids importing from types.ts to prevent circular deps). */
143
+ type ExtractParamsFromPattern<T extends string> =
144
+ T extends `${string}:${infer Param}/${infer Rest}`
145
+ ? Param extends `${infer Name}(${infer C})?`
146
+ ? {
147
+ [K in Name]?: ParseConstraint<C>;
148
+ } & ExtractParamsFromPattern<`/${Rest}`>
149
+ : Param extends `${infer Name}(${infer C})`
150
+ ? {
151
+ [K in Name]: ParseConstraint<C>;
152
+ } & ExtractParamsFromPattern<`/${Rest}`>
153
+ : Param extends `${infer Name}?`
154
+ ? { [K in Name]?: string } & ExtractParamsFromPattern<`/${Rest}`>
155
+ : { [K in Param]: string } & ExtractParamsFromPattern<`/${Rest}`>
156
+ : T extends `${string}:${infer Param}`
157
+ ? Param extends `${infer Name}(${infer C})?`
158
+ ? { [K in Name]?: ParseConstraint<C> }
159
+ : Param extends `${infer Name}(${infer C})`
160
+ ? { [K in Name]: ParseConstraint<C> }
161
+ : Param extends `${infer Name}?`
162
+ ? { [K in Name]?: string }
163
+ : { [K in Param]: string }
164
+ : {};
165
+
166
+ // ============================================================================
167
+ // Runtime Parser
168
+ // ============================================================================
169
+
170
+ /**
171
+ * Parse URLSearchParams into a typed object using the given schema.
172
+ *
173
+ * - `"string"` / `"string?"` - kept as-is
174
+ * - `"number"` / `"number?"` - coerced via `Number()`; NaN treated as missing
175
+ * - `"boolean"` / `"boolean?"` - `"true"` / `"1"` -> true, `"false"` / `"0"` / `""` -> false
176
+ *
177
+ * Missing params (both required and optional) are omitted from the result
178
+ * (undefined). The required/optional distinction is a consumer-facing contract
179
+ * only — the handler must check for undefined.
180
+ */
181
+ export function parseSearchParams<T extends SearchSchema>(
182
+ searchParams: URLSearchParams,
183
+ schema: T,
184
+ ): ResolveSearchSchema<T> {
185
+ const result: Record<string, unknown> = {};
186
+
187
+ for (const [key, descriptor] of Object.entries(schema)) {
188
+ const isOptional = descriptor.endsWith("?");
189
+ const baseType = isOptional ? descriptor.slice(0, -1) : descriptor;
190
+ const raw = searchParams.get(key);
191
+
192
+ if (raw === null) {
193
+ // Missing params are omitted (undefined) regardless of required/optional
194
+ continue;
195
+ }
196
+
197
+ if (baseType === "string") {
198
+ result[key] = raw;
199
+ } else if (baseType === "number") {
200
+ const num = Number(raw);
201
+ if (!Number.isNaN(num)) {
202
+ result[key] = num;
203
+ }
204
+ // NaN treated as missing (undefined)
205
+ } else if (baseType === "boolean") {
206
+ result[key] = raw === "true" || raw === "1";
207
+ }
208
+ }
209
+
210
+ return result as ResolveSearchSchema<T>;
211
+ }
212
+
213
+ // ============================================================================
214
+ // Runtime Serializer
215
+ // ============================================================================
216
+
217
+ /**
218
+ * Serialize a typed search params object to a query string (without leading `?`).
219
+ * Skips `undefined` and `null` values.
220
+ */
221
+ export function serializeSearchParams(params: Record<string, unknown>): string {
222
+ const parts: string[] = [];
223
+ for (const [key, value] of Object.entries(params)) {
224
+ if (value === undefined || value === null) continue;
225
+ parts.push(
226
+ `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,
227
+ );
228
+ }
229
+ return parts.join("&");
230
+ }